// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef FORTRAN_RUNTIME_DERIVED_TYPE_H_ #define FORTRAN_RUNTIME_DERIVED_TYPE_H_ #include "type-code.h" #include "../include/flang/ISO_Fortran_binding.h" #include #include namespace Fortran::runtime { class Descriptor; // Static type information about derived type specializations, // suitable for residence in read-only storage. using TypeParameterValue = ISO::CFI_index_t; class TypeParameter { public: const char *name() const { return name_; } const TypeCode typeCode() const { return typeCode_; } bool IsLenTypeParameter() const { return which_ < 0; } // Returns the static value of a KIND type parameter, or the default // value of a LEN type parameter. TypeParameterValue StaticValue() const { return value_; } // Returns the static value of a KIND type parameter, or an // instantiated value of LEN type parameter. TypeParameterValue GetValue(const Descriptor &) const; private: const char *name_; TypeCode typeCode_; // INTEGER, but not necessarily default kind int which_{-1}; // index into DescriptorAddendum LEN type parameter values TypeParameterValue value_; // default in the case of LEN type parameter }; // Components that have any need for a descriptor will either reference // a static descriptor that applies to all instances, or will *be* a // descriptor. Be advised: the base addresses in static descriptors // are null. Most runtime interfaces separate the data address from that // of the descriptor, and ignore the encapsulated base address in the // descriptor. Some interfaces, e.g. calls to interoperable procedures, // cannot pass a separate data address, and any static descriptor being used // in that kind of situation must be copied and customized. // Static descriptors are flagged in their attributes. class Component { public: const char *name() const { return name_; } TypeCode typeCode() const { return typeCode_; } const Descriptor *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; } template A *Locate(char *dtInstance) const { return reinterpret_cast(dtInstance + offset_); } template const A *Locate(const char *dtInstance) const { return reinterpret_cast(dtInstance + offset_); } Descriptor *GetDescriptor(char *dtInstance) const { if (IsDescriptor()) { return Locate(dtInstance); } else { return nullptr; } } const Descriptor *GetDescriptor(const char *dtInstance) const { if (staticDescriptor_ != nullptr) { return staticDescriptor_; } else if (IsDescriptor()) { return Locate(dtInstance); } else { return nullptr; } } private: enum Flag { PARENT = 1, PRIVATE = 2, IS_DESCRIPTOR = 4 }; const char *name_{nullptr}; std::uint32_t flags_{0}; TypeCode typeCode_{CFI_type_other}; const Descriptor *staticDescriptor_{nullptr}; std::size_t offset_{0}; // byte offset in derived type instance }; struct ExecutableCode { ExecutableCode() {} ExecutableCode(const ExecutableCode &) = default; ExecutableCode &operator=(const ExecutableCode &) = default; std::intptr_t host{0}; std::intptr_t device{0}; }; struct TypeBoundProcedure { const char *name; ExecutableCode code; }; // Represents a specialization of a derived type; i.e., any KIND type // parameters have values set at compilation time. // Extended derived types have the EXTENDS flag set and place their base // component first in the component descriptions, which is significant for // 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 sz) : name_{n}, kindParameters_{kps}, lenParameters_{lps}, typeParameter_{tp}, components_{cs}, component_{ca}, typeBoundProcedures_{tbps}, typeBoundProcedure_{tbp}, bytes_{sz} { if (IsNontrivialAnalysis()) { flags_ |= NONTRIVIAL; } } const char *name() const { return name_; } std::size_t kindParameters() const { return kindParameters_; } std::size_t lenParameters() const { return lenParameters_; } // KIND type parameters come first. const TypeParameter &typeParameter(int n) const { return typeParameter_[n]; } std::size_t components() const { return components_; } // The first few type-bound procedure indices are special. enum SpecialTBP { InitializerTBP, CopierTBP, FinalTBP }; std::size_t typeBoundProcedures() const { return typeBoundProcedures_; } const TypeBoundProcedure &typeBoundProcedure(int n) const { return typeBoundProcedure_[n]; } DerivedType &set_sequence() { flags_ |= SEQUENCE; return *this; } DerivedType &set_bind_c() { flags_ |= BIND_C; return *this; } std::size_t SizeInBytes() const { return bytes_; } bool Extends() const { return components_ > 0 && component_[0].IsParent(); } bool AnyPrivate() const; bool IsSequence() const { return (flags_ & SEQUENCE) != 0; } bool IsBindC() const { return (flags_ & BIND_C) != 0; } bool IsNontrivial() const { return (flags_ & NONTRIVIAL) != 0; } bool IsSameType(const DerivedType &) const; void Initialize(char *instance) const; void Destroy(char *instance, bool finalize = true) const; private: enum Flag { SEQUENCE = 1, BIND_C = 2, NONTRIVIAL = 4 }; // True when any descriptor of data of this derived type will require // an addendum pointing to a DerivedType, possibly with values of // LEN type parameters. Conservative. bool IsNontrivialAnalysis() const; const char *name_{""}; // NUL-terminated constant text std::size_t kindParameters_{0}; std::size_t lenParameters_{0}; const TypeParameter *typeParameter_{nullptr}; // array std::size_t components_{0}; // *not* including type parameters const Component *component_{nullptr}; // array std::size_t typeBoundProcedures_{0}; const TypeBoundProcedure *typeBoundProcedure_{nullptr}; // array std::uint64_t flags_{0}; std::size_t bytes_{0}; }; } // namespace Fortran::runtime #endif // FORTRAN_RUNTIME_DERIVED_TYPE_H_