diff --git a/flang/runtime/CMakeLists.txt b/flang/runtime/CMakeLists.txt index 5a4276afdacd..756c2973fa05 100644 --- a/flang/runtime/CMakeLists.txt +++ b/flang/runtime/CMakeLists.txt @@ -14,4 +14,5 @@ add_library(FortranRuntime ISO_Fortran_binding.cc + descriptor.cc ) diff --git a/flang/runtime/descriptor.cc b/flang/runtime/descriptor.cc index e14936c7b156..b5a4c5a6cc20 100644 --- a/flang/runtime/descriptor.cc +++ b/flang/runtime/descriptor.cc @@ -18,36 +18,33 @@ namespace Fortran::runtime { -Descriptor::Descriptor(const DerivedType &t, int rank = 0) { +Descriptor::Descriptor(const DerivedTypeSpecialization &dts, int rank) { raw_.base_addr = nullptr; - raw_.elem_len = t.SizeInBytes(); + raw_.elem_len = dts.SizeInBytes(); raw_.version = CFI_VERSION; raw_.rank = rank; raw_.type = CFI_type_struct; raw_.attribute = ADDENDUM; - new (GetAddendum()) DescriptorAddendum{t}; + Addendum()->set_derivedTypeSpecialization(&dts); } std::size_t Descriptor::SizeInBytes() const { - const DescriptorAddendum *addendum{GetAddendum()}; + const DescriptorAddendum *addendum{Addendum()}; return sizeof *this + raw_.rank * sizeof(Dimension) + - (addendum ? addendum->AddendumSizeInBytes() : 0); + (addendum ? addendum->SizeOfAddendumInBytes() : 0); } -std::int64_t DerivedTypeParameter::Value( - const DescriptorAddendum *addendum) const { - if (isLenTypeParameter_) { - return addendum->GetLenParameterValue(value_); - } else { - return value_; - } +std::int64_t TypeParameter::KindParameterValue( + const DerivedTypeSpecialization &specialization) const { + return specialization.KindParameterValue(which_); } -std::int64_t DerivedTypeParameter::Value(const Descriptor *descriptor) const { +std::int64_t TypeParameter::Value(const Descriptor &descriptor) const { + const DescriptorAddendum &addendum{*descriptor.Addendum()}; if (isLenTypeParameter_) { - return descriptor->GetAddendum()->GetLenTypeParameterValue(value_); + return addendum.LenParameterValue(which_); } else { - return value_; + return KindParameterValue(*addendum.derivedTypeSpecialization()); } } } // namespace Fortran::runtime diff --git a/flang/runtime/descriptor.h b/flang/runtime/descriptor.h index ff4794e34b21..d5f0429f2502 100644 --- a/flang/runtime/descriptor.h +++ b/flang/runtime/descriptor.h @@ -16,13 +16,13 @@ #define FORTRAN_RUNTIME_DESCRIPTOR_H_ // Defines data structures used during execution of a Fortran program -// to implement pointers, allocatables, arguments, function results, -// and the special behaviors of instances of derived types. +// to implement nontrivial dummy arguments, pointers, allocatables, +// function results, and the special behaviors of instances of derived types. // This header file includes and extends the published language // interoperability header that is required by the Fortran 2018 standard // as a subset of definitions suitable for exposure to user C/C++ code. -// User C code can depend on that ISO_Fortran_binding.h file, but should -// never reference this internal header. +// User C code is welcome to depend on that ISO_Fortran_binding.h file, +// but should never reference this internal header. #include "../include/flang/ISO_Fortran_binding.h" #include @@ -31,16 +31,18 @@ namespace Fortran::runtime { // Fortran requires that default INTEGER values occupy a single numeric -// storage unit, just like default REAL. So the default INTEGER type, -// which is what the type of an intrinsic type's KIND type parameter has, -// is basically forced to be a 32-bit int. +// storage unit, just like default REAL. Since there's no reasonable way +// that default REAL can be anything but 32-bit IEEE-754 today, the default +// INTEGER type is also forced; and default INTEGER is required to be the +// type of the kind type parameters of the intrinsic types. using DefaultKindInteger = std::int32_t; class DerivedType; class DerivedTypeSpecialization; class DescriptorAddendum; -// A C++ view of the ISO descriptor and its type and per-dimension information. +// This next section implements a C++ view of the sole interoperable +// descriptor (ISO_cdesc_t) and its type and per-dimension information. class TypeCode { public: @@ -102,8 +104,9 @@ public: std::int64_t ByteStride() const { return raw_.sm; } private: - ISO::CFI_dim_t raw_; // must be first and only member + ISO::CFI_dim_t raw_; }; +static_assert(sizeof(Dimension) == sizeof(ISO::CFI_dim_t)); class Descriptor { public: @@ -134,25 +137,36 @@ public: bool IsAllocatable() const { return (raw_.attribute & CFI_attribute_allocatable) != 0; } - bool IsLenParameterDependent() const { - return (raw_.attribute & LEN_PARAMETER_DEPENDENT) != 0; + bool IsImplicitlyAllocated() const { + return (raw_.attribute & IMPLICITLY_ALLOCATED) != 0; } - bool IsStaticDescriptor() const { + bool IsDescriptorStatic() const { return (raw_.attribute & STATIC_DESCRIPTOR) != 0; } bool IsTarget() const { return (raw_.attribute & (CFI_attribute_pointer | TARGET)) != 0; } bool IsContiguous() const { return (raw_.attribute & CONTIGUOUS) != 0; } - bool IsNotFinalizable() const { - return (raw_.attribute & NOT_FINALIZABLE) != 0; + bool IsColumnContiguous() const { + return (raw_.attribute & COLUMN_CONTIGUOUS) != 0; } + bool IsTemporary() const { return (raw_.attribute & TEMPORARY) != 0; } + Dimension &GetDimension(int dim) { + return *reinterpret_cast(&raw_.dim[dim]); + } const Dimension &GetDimension(int dim) const { return *reinterpret_cast(&raw_.dim[dim]); } - const DescriptorAddendum *GetAddendum() const { + DescriptorAddendum *Addendum() { + if ((raw_.attribute & ADDENDUM) != 0) { + return reinterpret_cast(&GetDimension(rank())); + } else { + return nullptr; + } + } + const DescriptorAddendum *Addendum() const { if ((raw_.attribute & ADDENDUM) != 0) { return reinterpret_cast( &GetDimension(rank())); @@ -165,22 +179,25 @@ public: private: // These values must coexist with the ISO_Fortran_binding.h definitions - // for CFI_attribute_... + // for CFI_attribute_... values and fit in the "attribute" field of + // CFI_cdesc_t. enum AdditionalAttributes { // non-pointer nonallocatable derived type component implemented as // an implicit allocatable due to dependence on LEN type parameters - LEN_PARAMETER_DEPENDENT = 0x4, // implicitly allocated object - ADDENDUM = 0x8, // last dim[] entry is followed by DescriptorAddendum - STATIC_DESCRIPTOR = 0x10, // base_addr is null, get base address elsewhere - TARGET = 0x20, // TARGET attribute; also implied by CFI_attribute_pointer - CONTIGUOUS = 0x40, - NOT_FINALIZABLE = 0x80, // do not finalize, this is a compiler temp + IMPLICITLY_ALLOCATED = 0x100, // bounds depend on LEN type parameter + ADDENDUM = 0x200, // last dim[] entry is followed by DescriptorAddendum + STATIC_DESCRIPTOR = 0x400, // base_addr is null, get base address elsewhere + TARGET = 0x800, // TARGET attribute; also implied by CFI_attribute_pointer + CONTIGUOUS = 0x1000, + COLUMN_CONTIGUOUS = 0x2000, // first dimension is contiguous + TEMPORARY = 0x4000, // compiler temp, do not finalize }; - ISO::CFI_cdesc_t raw_; // must be first and only member + ISO::CFI_cdesc_t raw_; }; +static_assert(sizeof(Descriptor) == sizeof(ISO::CFI_cdesc_t)); -// Static type information resides in a read-only section. +// Static type information is suitable for loading in a read-only section. // Information about intrinsic types is inferable from raw CFI_type_t // type codes (packaged as TypeCode above). // Information about derived types and their KIND parameter specializations @@ -189,15 +206,19 @@ private: class TypeParameter { public: const char *name() const { return name_; } - const TypeCode type() const { return typeCode_; } - std::int64_t Value(const DescriptorAddendum *) const; - std::int64_t Value(const Descriptor *) const; - std::int64_t Value(const DerivedTypeSpecialization *) const; + const TypeCode typeCode() const { return typeCode_; } + bool isLenTypeParameter() const { return isLenTypeParameter_; } + std::size_t which() const { return which_; } + std::int64_t defaultValue() const { return defaultValue_; } + + std::int64_t KindParameterValue(const DerivedTypeSpecialization &) const; + std::int64_t Value(const Descriptor &) const; private: const char *name_; - TypeCode typeCode_; // not necessarily default INTEGER + TypeCode typeCode_; // INTEGER, but not necessarily default kind bool isLenTypeParameter_; // whether value is in dynamic descriptor + std::size_t which_; // index of this parameter in kind/len array std::int64_t defaultValue_; }; @@ -346,14 +367,16 @@ public: : derivedType_{dt}, bytes_{n}, initializer_{init}, kindParameterValue_{kp}, componentSpecialization_{cs} {} const DerivedType &derivedType() const { return derivedType_; } + std::size_t SizeInBytes() const { return bytes_; } std::int64_t KindParameterValue(int n) const { return kindParameterValue_[n]; } - const ComponentSpecialization &componentSpecialization(int n) const { + const ComponentSpecialization &GetComponent(int n) const { return componentSpecialization_[n]; } - bool IsSameType(const DerivedTypeSpecialization &); + bool IsSameType(const DerivedTypeSpecialization &) const; + // TODO: initialization // TODO: sourced allocation initialization @@ -378,16 +401,27 @@ public: explicit DescriptorAddendum(const DerivedTypeSpecialization *dts) : derivedTypeSpecialization_{dts} {} + DescriptorAddendum &set_derivedTypeSpecialization( + const DerivedTypeSpecialization *dts) { + derivedTypeSpecialization_ = dts; + return *this; + } + const DerivedTypeSpecialization *derivedTypeSpecialization() const { return derivedTypeSpecialization_; } - std::int64_t GetLenParameterValue(std::size_t n) const { return len_[n]; } + + std::int64_t LenParameterValue(std::size_t n) const { return len_[n]; } std::size_t SizeOfAddendumInBytes() const { return sizeof *this - sizeof len_[0] + derivedTypeSpecialization_->derivedType().lenParameters() * sizeof len_[0]; } + void SetLenParameterValue(std::size_t which, std::int64_t x) { + len_[which] = x; + } + private: const DerivedTypeSpecialization *derivedTypeSpecialization_{nullptr}; std::int64_t len_[1]; // must be the last component