//===-- runtime/descriptor.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "descriptor.h" #include "derived.h" #include "memory.h" #include "terminator.h" #include "type-info.h" #include #include #include namespace Fortran::runtime { Descriptor::Descriptor(const Descriptor &that) { std::memcpy(this, &that, that.SizeInBytes()); } Descriptor::~Descriptor() { if (raw_.attribute != CFI_attribute_pointer) { Deallocate(); } } void Descriptor::Establish(TypeCode t, std::size_t elementBytes, void *p, int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute, bool addendum) { Terminator terminator{__FILE__, __LINE__}; RUNTIME_CHECK(terminator, ISO::CFI_establish(&raw_, p, attribute, t.raw(), elementBytes, rank, extent) == CFI_SUCCESS); raw_.f18Addendum = addendum; DescriptorAddendum *a{Addendum()}; RUNTIME_CHECK(terminator, addendum == (a != nullptr)); if (a) { new (a) DescriptorAddendum{}; } } void Descriptor::Establish(TypeCategory c, int kind, void *p, int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute, bool addendum) { Establish(TypeCode(c, kind), BytesFor(c, kind), p, rank, extent, attribute, addendum); } void Descriptor::Establish(int characterKind, std::size_t characters, void *p, int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute, bool addendum) { Establish(TypeCode{TypeCategory::Character, characterKind}, characterKind * characters, p, rank, extent, attribute, addendum); } void Descriptor::Establish(const typeInfo::DerivedType &dt, void *p, int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute) { Establish(CFI_type_struct, dt.sizeInBytes, p, rank, extent, attribute, true); DescriptorAddendum *a{Addendum()}; Terminator terminator{__FILE__, __LINE__}; RUNTIME_CHECK(terminator, a != nullptr); new (a) DescriptorAddendum{&dt}; } OwningPtr Descriptor::Create(TypeCode t, std::size_t elementBytes, void *p, int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute, int derivedTypeLenParameters) { std::size_t bytes{SizeInBytes(rank, true, derivedTypeLenParameters)}; Terminator terminator{__FILE__, __LINE__}; Descriptor *result{ reinterpret_cast(AllocateMemoryOrCrash(terminator, bytes))}; result->Establish(t, elementBytes, p, rank, extent, attribute, true); return OwningPtr{result}; } OwningPtr Descriptor::Create(TypeCategory c, int kind, void *p, int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute) { return Create( TypeCode(c, kind), BytesFor(c, kind), p, rank, extent, attribute); } OwningPtr Descriptor::Create(int characterKind, SubscriptValue characters, void *p, int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute) { return Create(TypeCode{TypeCategory::Character, characterKind}, characterKind * characters, p, rank, extent, attribute); } OwningPtr Descriptor::Create(const typeInfo::DerivedType &dt, void *p, int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute) { return Create(TypeCode{CFI_type_struct}, dt.sizeInBytes, p, rank, extent, attribute, dt.LenParameters()); } std::size_t Descriptor::SizeInBytes() const { const DescriptorAddendum *addendum{Addendum()}; return sizeof *this - sizeof(Dimension) + raw_.rank * sizeof(Dimension) + (addendum ? addendum->SizeInBytes() : 0); } std::size_t Descriptor::Elements() const { int n{rank()}; std::size_t elements{1}; for (int j{0}; j < n; ++j) { elements *= GetDimension(j).Extent(); } return elements; } int Descriptor::Allocate() { std::size_t byteSize{Elements() * ElementBytes()}; void *p{std::malloc(byteSize)}; if (!p && byteSize) { return CFI_ERROR_MEM_ALLOCATION; } // TODO: image synchronization // TODO: derived type initialization raw_.base_addr = p; if (int dims{rank()}) { std::size_t stride{ElementBytes()}; for (int j{0}; j < dims; ++j) { auto &dimension{GetDimension(j)}; dimension.SetByteStride(stride); stride *= dimension.Extent(); } } return 0; } int Descriptor::Allocate(const SubscriptValue lb[], const SubscriptValue ub[]) { int result{ISO::CFI_allocate(&raw_, lb, ub, ElementBytes())}; if (result == CFI_SUCCESS) { // TODO: derived type initialization } return result; } int Descriptor::Deallocate(bool finalize) { Destroy(finalize); return ISO::CFI_deallocate(&raw_); } void Descriptor::Destroy(bool finalize) const { if (const DescriptorAddendum * addendum{Addendum()}) { if (const typeInfo::DerivedType * dt{addendum->derivedType()}) { if (addendum->flags() & DescriptorAddendum::DoNotFinalize) { finalize = false; } runtime::Destroy(*this, finalize, *dt); } } } bool Descriptor::IncrementSubscripts( SubscriptValue *subscript, const int *permutation) const { for (int j{0}; j < raw_.rank; ++j) { int k{permutation ? permutation[j] : j}; const Dimension &dim{GetDimension(k)}; if (subscript[k]++ < dim.UpperBound()) { return true; } subscript[k] = dim.LowerBound(); } return false; } bool Descriptor::DecrementSubscripts( SubscriptValue *subscript, const int *permutation) const { for (int j{raw_.rank - 1}; j >= 0; --j) { int k{permutation ? permutation[j] : j}; const Dimension &dim{GetDimension(k)}; if (--subscript[k] >= dim.LowerBound()) { return true; } subscript[k] = dim.UpperBound(); } return false; } std::size_t Descriptor::ZeroBasedElementNumber( const SubscriptValue *subscript, const int *permutation) const { std::size_t result{0}; std::size_t coefficient{1}; for (int j{0}; j < raw_.rank; ++j) { int k{permutation ? permutation[j] : j}; const Dimension &dim{GetDimension(k)}; result += coefficient * (subscript[k] - dim.LowerBound()); coefficient *= dim.Extent(); } return result; } bool Descriptor::SubscriptsForZeroBasedElementNumber(SubscriptValue *subscript, std::size_t elementNumber, const int *permutation) const { std::size_t coefficient{1}; std::size_t dimCoefficient[maxRank]; for (int j{0}; j < raw_.rank; ++j) { int k{permutation ? permutation[j] : j}; const Dimension &dim{GetDimension(k)}; dimCoefficient[j] = coefficient; coefficient *= dim.Extent(); } if (elementNumber >= coefficient) { return false; // out of range } for (int j{raw_.rank - 1}; j >= 0; --j) { int k{permutation ? permutation[j] : j}; const Dimension &dim{GetDimension(k)}; std::size_t quotient{j ? elementNumber / dimCoefficient[j] : 0}; subscript[k] = dim.LowerBound() + elementNumber - dimCoefficient[j] * quotient; elementNumber = quotient; } return true; } void Descriptor::Check() const { // TODO } void Descriptor::Dump(FILE *f) const { std::fprintf(f, "Descriptor @ %p:\n", reinterpret_cast(this)); std::fprintf(f, " base_addr %p\n", raw_.base_addr); std::fprintf(f, " elem_len %zd\n", static_cast(raw_.elem_len)); std::fprintf(f, " version %d\n", static_cast(raw_.version)); std::fprintf(f, " rank %d\n", static_cast(raw_.rank)); std::fprintf(f, " type %d\n", static_cast(raw_.type)); std::fprintf(f, " attribute %d\n", static_cast(raw_.attribute)); std::fprintf(f, " addendum %d\n", static_cast(raw_.f18Addendum)); for (int j{0}; j < raw_.rank; ++j) { std::fprintf(f, " dim[%d] lower_bound %jd\n", j, static_cast(raw_.dim[j].lower_bound)); std::fprintf(f, " extent %jd\n", static_cast(raw_.dim[j].extent)); std::fprintf(f, " sm %jd\n", static_cast(raw_.dim[j].sm)); } if (const DescriptorAddendum * addendum{Addendum()}) { addendum->Dump(f); } } std::size_t DescriptorAddendum::SizeInBytes() const { return SizeInBytes(LenParameters()); } std::size_t DescriptorAddendum::LenParameters() const { const auto *type{derivedType()}; return type ? type->LenParameters() : 0; } void DescriptorAddendum::Dump(FILE *f) const { std::fprintf( f, " derivedType @ %p\n", reinterpret_cast(derivedType_)); std::fprintf(f, " flags 0x%jx\n", static_cast(flags_)); // TODO: LEN parameter values } } // namespace Fortran::runtime