From: peter klausler Date: Thu, 26 Jul 2018 23:07:50 +0000 (-0700) Subject: [flang] checkpoint work on descriptors X-Git-Tag: 2020.06-alpha~50^2~2673^2~2292 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=adc597b032cd5aaca22d64e6f605af5226d1c1a0;p=platform%2Fupstream%2Fllvm.git [flang] checkpoint work on descriptors Original-commit: flang-compiler/f18@5e68ebea25c2c1bef73270bf8d43144cd9d59c9f Reviewed-on: https://github.com/flang-compiler/f18/pull/162 Tree-same-pre-rewrite: false --- diff --git a/flang/runtime/ISO_Fortran_binding.cc b/flang/runtime/ISO_Fortran_binding.cc index 8d2e62a98176..3fa70dbfa3e6 100644 --- a/flang/runtime/ISO_Fortran_binding.cc +++ b/flang/runtime/ISO_Fortran_binding.cc @@ -48,7 +48,10 @@ int CFI_allocate(CFI_cdesc_t *descriptor, const CFI_index_t lower_bounds[], if (descriptor->rank > CFI_MAX_RANK) { return CFI_INVALID_RANK; } - // TODO: CFI_INVALID_TYPE? + if (descriptor->type < CFI_type_signed_char || + descriptor->type > CFI_type_struct) { + return CFI_INVALID_TYPE; + } if (descriptor->type != CFI_type_cptr) { elem_len = descriptor->elem_len; if (elem_len <= 0) { @@ -72,6 +75,7 @@ int CFI_allocate(CFI_cdesc_t *descriptor, const CFI_index_t lower_bounds[], return CFI_ERROR_MEM_ALLOCATION; } descriptor->base_addr = p; + descriptor->elem_len = elem_len; return CFI_SUCCESS; } @@ -92,6 +96,48 @@ int CFI_deallocate(CFI_cdesc_t *descriptor) { return CFI_SUCCESS; } +static constexpr std::size_t MinElemLen(CFI_type_t type) { + std::size_t minElemLen{0}; + switch (type) { + case CFI_type_signed_char: minElemLen = sizeof(signed char); break; + case CFI_type_short: minElemLen = sizeof(short); break; + case CFI_type_int: minElemLen = sizeof(int); break; + case CFI_type_long: minElemLen = sizeof(long); break; + case CFI_type_long_long: minElemLen = sizeof(long long); break; + case CFI_type_size_t: minElemLen = sizeof(std::size_t); break; + case CFI_type_int8_t: minElemLen = sizeof(std::int8_t); break; + case CFI_type_int16_t: minElemLen = sizeof(std::int16_t); break; + case CFI_type_int32_t: minElemLen = sizeof(std::int32_t); break; + case CFI_type_int64_t: minElemLen = sizeof(std::int64_t); break; + case CFI_type_int128_t: minElemLen = 2 * sizeof(std::int64_t); break; + case CFI_type_int_least8_t: minElemLen = sizeof(std::int_least8_t); break; + case CFI_type_int_least16_t: minElemLen = sizeof(std::int_least16_t); break; + case CFI_type_int_least32_t: minElemLen = sizeof(std::int_least32_t); break; + case CFI_type_int_least64_t: minElemLen = sizeof(std::int_least64_t); break; + case CFI_type_int_least128_t: + minElemLen = 2 * sizeof(std::int_least64_t); + break; + case CFI_type_int_fast8_t: minElemLen = sizeof(std::int_fast8_t); break; + case CFI_type_int_fast16_t: minElemLen = sizeof(std::int_fast16_t); break; + case CFI_type_int_fast32_t: minElemLen = sizeof(std::int_fast32_t); break; + case CFI_type_int_fast64_t: minElemLen = sizeof(std::int_fast64_t); break; + case CFI_type_intmax_t: minElemLen = sizeof(std::intmax_t); break; + case CFI_type_intptr_t: minElemLen = sizeof(std::intptr_t); break; + case CFI_type_ptrdiff_t: minElemLen = sizeof(std::ptrdiff_t); break; + case CFI_type_float: minElemLen = sizeof(float); break; + case CFI_type_double: minElemLen = sizeof(double); break; + case CFI_type_long_double: minElemLen = sizeof(long double); break; + case CFI_type_float_Complex: minElemLen = 2 * sizeof(float); break; + case CFI_type_double_Complex: minElemLen = 2 * sizeof(double); break; + case CFI_type_long_double_Complex: + minElemLen = 2 * sizeof(long double); + break; + case CFI_type_Bool: minElemLen = 1; break; + case CFI_type_char: minElemLen = sizeof(char); break; + } + return minElemLen; +} + int CFI_establish(CFI_cdesc_t *descriptor, void *base_addr, CFI_attribute_t attribute, CFI_type_t type, std::size_t elem_len, CFI_rank_t rank, const CFI_index_t extents[]) { @@ -107,9 +153,14 @@ int CFI_establish(CFI_cdesc_t *descriptor, void *base_addr, if (rank > 0 && base_addr != nullptr && extents == nullptr) { return CFI_INVALID_EXTENT; } - if (type != CFI_type_struct && type != CFI_type_other && - type != CFI_type_cptr) { - // TODO: force value of elem_len + if (type < CFI_type_signed_char || type > CFI_type_struct) { + return CFI_INVALID_TYPE; + } + std::size_t minElemLen{MinElemLen(type)}; + if (minElemLen > 0) { + elem_len = minElemLen; + } else if (elem_len <= 0) { + return CFI_INVALID_ELEM_LEN; } descriptor->base_addr = base_addr; descriptor->elem_len = elem_len; diff --git a/flang/runtime/descriptor.cc b/flang/runtime/descriptor.cc index b5a4c5a6cc20..24bf7f2e4422 100644 --- a/flang/runtime/descriptor.cc +++ b/flang/runtime/descriptor.cc @@ -15,31 +15,108 @@ // TODO: Not complete; exists to check compilability of descriptor.h #include "descriptor.h" +#include namespace Fortran::runtime { -Descriptor::Descriptor(const DerivedTypeSpecialization &dts, int rank) { - raw_.base_addr = nullptr; - raw_.elem_len = dts.SizeInBytes(); - raw_.version = CFI_VERSION; - raw_.rank = rank; - raw_.type = CFI_type_struct; - raw_.attribute = ADDENDUM; - Addendum()->set_derivedTypeSpecialization(&dts); +TypeCode::TypeCode(TypeCode::Form f, int kind) { + switch (f) { + case Form::Integer: + switch (kind) { + case 1: raw_ = CFI_type_int8_t; break; + case 2: raw_ = CFI_type_int16_t; break; + case 4: raw_ = CFI_type_int32_t; break; + case 8: raw_ = CFI_type_int64_t; break; + case 16: raw_ = CFI_type_int128_t; break; + } + break; + case Form::Real: + switch (kind) { + case 4: raw_ = CFI_type_float; break; + case 8: raw_ = CFI_type_double; break; + case 10: + case 16: raw_ = CFI_type_long_double; break; + } + break; + case Form::Complex: + switch (kind) { + case 4: raw_ = CFI_type_float_Complex; break; + case 8: raw_ = CFI_type_double_Complex; break; + case 10: + case 16: raw_ = CFI_type_long_double_Complex; break; + } + break; + case Form::Character: + if (kind == 1) { + raw_ = CFI_type_cptr; + } + break; + case Form::Logical: + switch (kind) { + case 1: raw_ = CFI_type_Bool; break; + case 2: raw_ = CFI_type_int16_t; break; + case 4: raw_ = CFI_type_int32_t; break; + case 8: raw_ = CFI_type_int64_t; break; + } + break; + case Form::Derived: raw_ = CFI_type_struct; break; + } +} + +std::size_t DescriptorAddendum::SizeInBytes() const { + return SizeInBytes(derivedTypeSpecialization_->derivedType().lenParameters()); +} + +void DescriptorView::SetDerivedTypeSpecialization( + const DerivedTypeSpecialization &dts) { + raw_.attribute |= ADDENDUM; + Addendum()->set_derivedTypeSpecialization(dts); +} + +void DescriptorView::SetLenParameterValue(int which, TypeParameterValue x) { + raw_.attribute |= ADDENDUM; + Addendum()->SetLenParameterValue(which, x); } -std::size_t Descriptor::SizeInBytes() const { +std::size_t DescriptorView::SizeInBytes() const { const DescriptorAddendum *addendum{Addendum()}; - return sizeof *this + raw_.rank * sizeof(Dimension) + - (addendum ? addendum->SizeOfAddendumInBytes() : 0); + return sizeof *this - sizeof(Dimension) + raw_.rank * sizeof(Dimension) + + (addendum ? addendum->SizeInBytes() : 0); +} + +int DescriptorView::Establish(TypeCode t, std::size_t elementBytes, void *p, + int rank, const SubscriptValue *extent) { + return CFI_establish( + &raw_, p, CFI_attribute_other, t.raw(), elementBytes, rank, extent); +} + +int DescriptorView::Establish(TypeCode::Form f, int kind, void *p, int rank, + const SubscriptValue *extent) { + std::size_t elementBytes = kind; + if (f == TypeCode::Form::Complex) { + elementBytes *= 2; + } + return ISO::CFI_establish(&raw_, p, CFI_attribute_other, + TypeCode(f, kind).raw(), elementBytes, rank, extent); +} + +int DescriptorView::Establish(const DerivedTypeSpecialization &dts, void *p, + int rank, const SubscriptValue *extent) { + int result{ISO::CFI_establish( + &raw_, p, ADDENDUM, CFI_type_struct, dts.SizeInBytes(), rank, extent)}; + if (result == CFI_SUCCESS) { + Addendum()->set_derivedTypeSpecialization(dts); + } + return result; } -std::int64_t TypeParameter::KindParameterValue( +TypeParameterValue TypeParameter::KindParameterValue( const DerivedTypeSpecialization &specialization) const { return specialization.KindParameterValue(which_); } -std::int64_t TypeParameter::Value(const Descriptor &descriptor) const { +TypeParameterValue TypeParameter::Value( + const DescriptorView &descriptor) const { const DescriptorAddendum &addendum{*descriptor.Addendum()}; if (isLenTypeParameter_) { return addendum.LenParameterValue(which_); @@ -47,4 +124,64 @@ std::int64_t TypeParameter::Value(const Descriptor &descriptor) const { return KindParameterValue(*addendum.derivedTypeSpecialization()); } } + +bool DerivedType::IsNonTrivial() const { + if (kindParameters_ > 0 || lenParameters_ > 0 || typeBoundProcedures_ > 0 || + definedAssignments_ > 0 || finalSubroutine_.host != 0) { + return true; + } + for (int j{0}; j < components_; ++j) { + if (component_[j].IsDescriptor()) { + return true; + } + if (const DescriptorView * + staticDescriptor{component_[j].staticDescriptor()}) { + if (const DescriptorAddendum * addendum{staticDescriptor->Addendum()}) { + if (const DerivedTypeSpecialization * + dts{addendum->derivedTypeSpecialization()}) { + if (dts->derivedType().IsNonTrivial()) { + return true; + } + } + } + } + } + return false; +} + +Object::~Object() { + if (p_ != nullptr) { + // TODO final procedure calls and component destruction + delete reinterpret_cast(p_); + p_ = nullptr; + } +} + +bool Object::Create( + TypeCode::Form f, int kind, int rank, const SubscriptValue *extent) { + if (f == TypeCode::Form::Character || f == TypeCode::Form::Derived) { + // TODO support these... + return false; + } + std::size_t descriptorBytes{DescriptorView::SizeInBytes(rank)}; + std::size_t elementBytes = kind; + if (f == TypeCode::Form::Complex) { + elementBytes *= 2; + } + std::size_t elements{1}; + for (int j{0}; j < rank; ++j) { + if (extent[j] < 0) { + return false; + } + elements *= static_cast(extent[j]); + } + std::size_t totalBytes{descriptorBytes + elements * elementBytes}; + char *p{reinterpret_cast(std::malloc(totalBytes))}; + if (p == nullptr) { + return false; + } + p_ = reinterpret_cast(p); + p_->Establish(f, kind, p + descriptorBytes, rank, extent); + return true; +} } // namespace Fortran::runtime diff --git a/flang/runtime/descriptor.h b/flang/runtime/descriptor.h index 8e341a22e8fa..ff26c01ff341 100644 --- a/flang/runtime/descriptor.h +++ b/flang/runtime/descriptor.h @@ -31,17 +31,21 @@ namespace Fortran::runtime { class DerivedTypeSpecialization; -class DescriptorAddendum; + +using TypeParameterValue = ISO::CFI_index_t; +using SubscriptValue = ISO::CFI_index_t; // A C++ view of the sole interoperable standard descriptor (ISO_cdesc_t) // and its type and per-dimension information. class TypeCode { public: - enum class Form { Integer, Real, Complex, Logical, Character, Derived }; + enum class Form { Integer, Real, Complex, Character, Logical, Derived }; TypeCode() {} explicit TypeCode(ISO::CFI_type_t t) : raw_{t} {} + TypeCode(Form, int); + int raw() const { return raw_; } constexpr bool IsValid() const { @@ -57,13 +61,11 @@ public: return raw_ >= CFI_type_float_Complex && raw_ <= CFI_type_long_double_Complex; } - constexpr bool IsLogical() const { return raw_ == CFI_type_Bool; } constexpr bool IsCharacter() const { return raw_ == CFI_type_cptr; } + constexpr bool IsLogical() const { return raw_ == CFI_type_Bool; } constexpr bool IsDerived() const { return raw_ == CFI_type_struct; } - constexpr bool IsIntrinsic() const { - return IsValid() && !IsDerived(); - } + constexpr bool IsIntrinsic() const { return IsValid() && !IsDerived(); } constexpr Form GetForm() const { if (IsInteger()) { @@ -75,12 +77,12 @@ public: if (IsComplex()) { return Form::Complex; } - if (IsLogical()) { - return Form::Logical; - } if (IsCharacter()) { return Form::Character; } + if (IsLogical()) { + return Form::Logical; + } return Form::Derived; } @@ -90,39 +92,78 @@ private: class Dimension { public: - std::int64_t LowerBound() const { return raw_.lower_bound; } - std::int64_t Extent() const { return raw_.extent; } - std::int64_t UpperBound() const { return LowerBound() + Extent() - 1; } - std::int64_t ByteStride() const { return raw_.sm; } + SubscriptValue LowerBound() const { return raw_.lower_bound; } + SubscriptValue Extent() const { return raw_.extent; } + SubscriptValue UpperBound() const { return LowerBound() + Extent() - 1; } + SubscriptValue ByteStride() const { return raw_.sm; } private: ISO::CFI_dim_t raw_; }; static_assert(sizeof(Dimension) == sizeof(ISO::CFI_dim_t)); -class Descriptor { +// The storage for this object follows the last used dim[] entry in a +// DescriptorView (CFI_cdesc_t) generic descriptor; this is why that class +// cannot be defined as a derivation or encapsulation of the standard +// argument descriptor. Space matters here, since dynamic descriptors +// can serve as components of derived type instances. The presence of +// this structure is implied by (CFI_cdesc_t.attribute & ADDENDUM) != 0, +// and the number of elements in the len_[] array is determined by +// DerivedType::lenParameters(). +class DescriptorAddendum { public: - Descriptor(TypeCode t, std::size_t elementBytes, int rank = 0) { - raw_.base_addr = nullptr; - raw_.elem_len = elementBytes; - raw_.version = CFI_VERSION; - raw_.rank = rank; - raw_.type = t.raw(); - raw_.attribute = 0; + explicit DescriptorAddendum(const DerivedTypeSpecialization &dts) + : derivedTypeSpecialization_{&dts} {} + + DescriptorAddendum &set_derivedTypeSpecialization( + const DerivedTypeSpecialization &dts) { + derivedTypeSpecialization_ = &dts; + return *this; } - Descriptor(const DerivedTypeSpecialization &, int rank = 0); - void Check() const; + const DerivedTypeSpecialization *derivedTypeSpecialization() const { + return derivedTypeSpecialization_; + } - template A &Element(std::size_t offset = 0) const { - auto p = reinterpret_cast(raw_.base_addr); - return *reinterpret_cast(p + offset); + TypeParameterValue LenParameterValue(int which) const { return len_[which]; } + static constexpr std::size_t SizeInBytes(int lenParameters) { + return sizeof(DescriptorAddendum) - sizeof(TypeParameterValue) + + lenParameters * sizeof(TypeParameterValue); + } + std::size_t SizeInBytes() const; + + void SetLenParameterValue(int which, TypeParameterValue x) { + len_[which] = x; } +private: + const DerivedTypeSpecialization *derivedTypeSpecialization_{nullptr}; + TypeParameterValue len_[1]; // must be the last component + // The LEN type parameter values can also include captured values of + // specification expressions that were used for bounds and for LEN type + // parameters of components. The values have been truncated to the LEN + // type parameter's type, if shorter than 64 bits, then sign-extended. +}; + +// A C++ view of a standard descriptor object. Do not use for actually +// allocating a descriptor, as its size cannot be known at compilation +// time -- see Descriptor below for that. +class DescriptorView { +public: + DescriptorView() = delete; + ~DescriptorView() = delete; + + ISO::CFI_cdesc_t &raw() { return raw_; } + const ISO::CFI_cdesc_t &raw() const { return raw_; } std::size_t ElementBytes() const { return raw_.elem_len; } int rank() const { return raw_.rank; } TypeCode type() const { return TypeCode{raw_.type}; } + DescriptorView &set_base_addr(void *p) { + raw_.base_addr = p; + return *this; + } + bool IsPointer() const { return (raw_.attribute & CFI_attribute_pointer) != 0; } @@ -151,6 +192,12 @@ public: return *reinterpret_cast(&raw_.dim[dim]); } + std::size_t SubscriptByteOffset( + int dim, SubscriptValue subscriptValue) const { + const Dimension &dimension{GetDimension(dim)}; + return (subscriptValue - dimension.LowerBound()) * dimension.ByteStride(); + } + DescriptorAddendum *Addendum() { if ((raw_.attribute & ADDENDUM) != 0) { return reinterpret_cast(&GetDimension(rank())); @@ -167,8 +214,36 @@ public: } } + void SetDerivedTypeSpecialization(const DerivedTypeSpecialization &); + + void SetLenParameterValue(int, TypeParameterValue); + + static constexpr std::size_t SizeInBytes( + int rank, bool nontrivialType = false, int lengthTypeParameters = 0) { + std::size_t bytes{sizeof(DescriptorView) - sizeof(Dimension)}; + bytes += rank * sizeof(Dimension); + if (nontrivialType || lengthTypeParameters > 0) { + bytes += DescriptorAddendum::SizeInBytes(lengthTypeParameters); + } + return bytes; + } std::size_t SizeInBytes() const; + void Check() const; + + int Establish(TypeCode t, std::size_t elementBytes, void *p = nullptr, + int rank = 0, const SubscriptValue *extent = nullptr); + int Establish(TypeCode::Form f, int kind, void *p = nullptr, int rank = 0, + const SubscriptValue *extent = nullptr); + int Establish(const DerivedTypeSpecialization &, void *p = nullptr, + int rank = 0, const SubscriptValue *extent = nullptr); + // TODO: creation of sections + + template A &Element(std::size_t offset = 0) const { + auto p = reinterpret_cast(raw_.base_addr); + return *reinterpret_cast(p + offset); + } + private: // These values must coexist with the ISO_Fortran_binding.h definitions // for CFI_attribute_... values and fit in the "attribute" field of @@ -187,7 +262,7 @@ private: ISO::CFI_cdesc_t raw_; }; -static_assert(sizeof(Descriptor) == sizeof(ISO::CFI_cdesc_t)); +static_assert(sizeof(DescriptorView) == sizeof(ISO::CFI_cdesc_t)); // Static type information is suitable for loading in a read-only section. // Information about intrinsic types is inferable from raw CFI_type_t @@ -200,18 +275,19 @@ public: const char *name() const { return name_; } 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_; } + int which() const { return which_; } + TypeParameterValue defaultValue() const { return defaultValue_; } - std::int64_t KindParameterValue(const DerivedTypeSpecialization &) const; - std::int64_t Value(const Descriptor &) const; + TypeParameterValue KindParameterValue( + const DerivedTypeSpecialization &) const; + TypeParameterValue Value(const DescriptorView &) const; private: const char *name_; 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_; + int which_; // index of this parameter in kind/len array + TypeParameterValue defaultValue_; }; // Components that have any need for a descriptor will either reference @@ -227,7 +303,7 @@ class Component { public: const char *name() const { return name_; } TypeCode typeCode() const { return typeCode_; } - const Descriptor *staticDescriptor() const { return staticDescriptor_; } + const DescriptorView *staticDescriptor() const { return staticDescriptor_; } bool IsParent() const { return (flags_ & PARENT) != 0; } bool IsPrivate() const { return (flags_ & PRIVATE) != 0; } bool IsDescriptor() const { return (flags_ & IS_DESCRIPTOR) != 0; } @@ -237,7 +313,7 @@ private: const char *name_{nullptr}; std::uint32_t flags_{0}; TypeCode typeCode_{CFI_type_other}; - const Descriptor *staticDescriptor_{nullptr}; + const DescriptorView *staticDescriptor_{nullptr}; }; struct ExecutableCode { @@ -267,20 +343,19 @@ struct DefinedAssignment { // the execution of FINAL subroutines. class DerivedType { public: - DerivedType(const char *n, std::size_t kps, std::size_t lps, - const TypeParameter *tp, std::size_t cs, const Component *ca, - std::size_t tbps, const TypeBoundProcedure *tbp, std::size_t das, + DerivedType(const char *n, int kps, int lps, const TypeParameter *tp, int cs, + const Component *ca, int tbps, const TypeBoundProcedure *tbp, int das, const DefinedAssignment *da) : name_{n}, kindParameters_{kps}, lenParameters_{lps}, components_{cs}, - typeParameter_{tp}, typeBoundProcedure_{tbp}, definedAssignments_{das}, - definedAssignment_{da} {} + typeParameter_{tp}, typeBoundProcedures_{tbps}, typeBoundProcedure_{tbp}, + definedAssignments_{das}, definedAssignment_{da} {} const char *name() const { return name_; } - std::size_t kindParameters() const { return kindParameters_; } - std::size_t lenParameters() const { return lenParameters_; } + int kindParameters() const { return kindParameters_; } + int lenParameters() const { return lenParameters_; } const TypeParameter &typeParameter(int n) const { return typeParameter_[n]; } - std::size_t components() const { return components_; } - std::size_t typeBoundProcedures() const { return typeBoundProcedures_; } + int components() const { return components_; } + int typeBoundProcedures() const { return typeBoundProcedures_; } const TypeBoundProcedure &typeBoundProcedure(int n) const { return typeBoundProcedure_[n]; } @@ -302,6 +377,7 @@ public: bool AnyPrivate() const; bool IsSequence() const { return (flags_ & SEQUENCE) != 0; } bool IsBindC() const { return (flags_ & BIND_C) != 0; } + bool IsNonTrivial() const; // TODO: assignment // TODO: finalization @@ -309,19 +385,19 @@ public: private: enum Flag { SEQUENCE = 1, BIND_C = 2 }; - const char *name_; // NUL-terminated constant text + const char *name_{""}; // NUL-terminated constant text std::uint64_t flags_{0}; // needed for IsSameType() correct semantics - std::size_t kindParameters_; - std::size_t lenParameters_; - std::size_t components_; // *not* including type parameters - std::size_t typeBoundProcedures_; - const TypeParameter *typeParameter_; // array - const Component *component_; // array - const TypeBoundProcedure - *typeBoundProcedure_; // array of overridable TBP bindings + int kindParameters_{0}; + int lenParameters_{0}; + int components_{0}; // *not* including type parameters + const TypeParameter *typeParameter_{nullptr}; // array + const Component *component_{nullptr}; // array + int typeBoundProcedures_{0}; + const TypeBoundProcedure *typeBoundProcedure_{ + nullptr}; // array of overridable TBP bindings ExecutableCode finalSubroutine_; // can be null - std::size_t definedAssignments_; - const DefinedAssignment *definedAssignment_; // array + int definedAssignments_{0}; + const DefinedAssignment *definedAssignment_{nullptr}; // array }; class ComponentSpecialization { @@ -332,12 +408,12 @@ public: template const A *Locate(const char *instance) const { return reinterpret_cast(instance + offset_); } - const Descriptor *GetDescriptor( + const DescriptorView *GetDescriptorView( const Component &c, const char *instance) const { - if (const Descriptor * staticDescriptor{c.staticDescriptor()}) { + if (const DescriptorView * staticDescriptor{c.staticDescriptor()}) { return staticDescriptor; } else if (c.IsDescriptor()) { - return Locate(instance); + return Locate(instance); } else { return nullptr; } @@ -354,14 +430,14 @@ private: class DerivedTypeSpecialization { public: DerivedTypeSpecialization(const DerivedType &dt, std::size_t n, - const char *init, const std::int64_t *kp, + const char *init, const TypeParameterValue *kp, const ComponentSpecialization *cs) : 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 { + TypeParameterValue KindParameterValue(int n) const { return kindParameterValue_[n]; } const ComponentSpecialization &GetComponent(int n) const { @@ -376,61 +452,69 @@ private: const DerivedType &derivedType_; std::size_t bytes_; // allocation size of one scalar instance, w/ alignment const char *initializer_; // can be null; includes base components - const std::int64_t *kindParameterValue_; // array + const TypeParameterValue *kindParameterValue_; // array const ComponentSpecialization *componentSpecialization_; // array }; -// The storage for this object follows the last used dim[] entry in a -// Descriptor (CFI_cdesc_t) generic descriptor; that is why this class -// cannot be defined as a derivation or encapsulation of the standard -// argument descriptor. Space matters here, since dynamic descriptors -// can serve as components of derived type instances. The presence of -// this structure is implied by (CFI_cdesc_t.attribute & ADDENDUM) != 0, -// and the number of elements in the len_[] array is determined by -// DerivedType::lenParameters(). -class DescriptorAddendum { -public: - explicit DescriptorAddendum(const DerivedTypeSpecialization *dts) - : derivedTypeSpecialization_{dts} {} +// Procedure pointers have static links for host association. +// TODO: define the target data structure of that static link +struct ProcedurePointer { + ExecutableCode entryAddresses; + void *staticLink; +}; - DescriptorAddendum &set_derivedTypeSpecialization( - const DerivedTypeSpecialization *dts) { - derivedTypeSpecialization_ = dts; - return *this; - } +// TODO: coarray hooks - const DerivedTypeSpecialization *derivedTypeSpecialization() const { - return derivedTypeSpecialization_; +template +class alignas(DescriptorView) Descriptor { +public: + static constexpr int maxRank{MAX_RANK}; + static constexpr int maxLengthTypeParameters{MAX_LEN_PARMS}; + static constexpr bool hasAddendum{ + NONTRIVIAL_DERIVED_TYPE_ALLOWED || MAX_LEN_PARMS > 0}; + + Descriptor(TypeCode t, std::size_t elementBytes, int rank = maxRank, + const SubscriptValue *extent = nullptr) { + View().Establish(t, elementBytes, rank, extent); } - - 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]; + Descriptor(TypeCode::Form f, int kind, int rank = maxRank, + const SubscriptValue *extent = nullptr) { + View().Establish(f, kind, rank, extent); + } + Descriptor(const DerivedTypeSpecialization &dts, int rank = maxRank, + const SubscriptValue *extent = nullptr) { + View().Establish(dts, rank, extent); } - void SetLenParameterValue(std::size_t which, std::int64_t x) { - len_[which] = x; + DescriptorView &View() { + return *reinterpret_cast(storage_); + } + const DescriptorView &View() const { + return *reinterpret_cast(storage_); } private: - const DerivedTypeSpecialization *derivedTypeSpecialization_{nullptr}; - std::int64_t len_[1]; // must be the last component - // The LEN type parameter values can also include captured values of - // specification expressions that were used for bounds and for LEN type - // parameters of components. The values have been truncated to the LEN - // type parameter's type, if shorter than 64 bits, then sign-extended. + static constexpr std::size_t byteSize{DescriptorView::SizeInBytes( + maxRank, hasAddendum, maxLengthTypeParameters)}; + char storage_[byteSize]; }; -// Procedure pointers have static links for host association. -// TODO: define the target data structure of that static link -struct ProcedurePointer { - ExecutableCode entryAddresses; - void *staticLink; -}; +// A owning pointer to a whole object whose data are contiguous with and +// preceded in memory by a descriptor. +class Object { +public: + ~Object(); + bool Create(TypeCode::Form f, int kind, int rank = 0, + const SubscriptValue *extent = nullptr); + bool Create(const DerivedTypeSpecialization &, int rank = 0, + const SubscriptValue *lenParamsAndExtents = nullptr); + bool Exists() const { return p_ != nullptr; } + const DescriptorView &descriptorView() const { return *p_; } -// TODO: coarray hooks +private: + DescriptorView *p_; +}; } // namespace Fortran::runtime #endif // FORTRAN_RUNTIME_DESCRIPTOR_H_