forked from OSchip/llvm-project
289 lines
10 KiB
C++
289 lines
10 KiB
C++
//===-- runtime/type-info.h -------------------------------------*- C++ -*-===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef FORTRAN_RUNTIME_TYPE_INFO_H_
|
|
#define FORTRAN_RUNTIME_TYPE_INFO_H_
|
|
|
|
// A C++ perspective of the derived type description schemata in
|
|
// flang/module/__fortran_type_info.f90.
|
|
|
|
#include "terminator.h"
|
|
#include "flang/Common/Fortran.h"
|
|
#include "flang/Common/bit-population-count.h"
|
|
#include "flang/Runtime/descriptor.h"
|
|
#include <cinttypes>
|
|
#include <memory>
|
|
#include <optional>
|
|
|
|
namespace Fortran::runtime::typeInfo {
|
|
|
|
class DerivedType;
|
|
|
|
using ProcedurePointer = void (*)(); // TYPE(C_FUNPTR)
|
|
|
|
struct Binding {
|
|
ProcedurePointer proc;
|
|
StaticDescriptor<0> name; // CHARACTER(:), POINTER
|
|
};
|
|
|
|
class Value {
|
|
public:
|
|
enum class Genre : std::uint8_t {
|
|
Deferred = 1,
|
|
Explicit = 2,
|
|
LenParameter = 3
|
|
};
|
|
|
|
std::optional<TypeParameterValue> GetValue(const Descriptor *) const;
|
|
|
|
private:
|
|
Genre genre_{Genre::Explicit};
|
|
// The value encodes an index into the table of LEN type parameters in
|
|
// a descriptor's addendum for genre == Genre::LenParameter.
|
|
TypeParameterValue value_{0};
|
|
};
|
|
|
|
class Component {
|
|
public:
|
|
enum class Genre : std::uint8_t {
|
|
Data = 1,
|
|
Pointer = 2,
|
|
Allocatable = 3,
|
|
Automatic = 4
|
|
};
|
|
|
|
const Descriptor &name() const { return name_.descriptor(); }
|
|
Genre genre() const { return genre_; }
|
|
TypeCategory category() const { return static_cast<TypeCategory>(category_); }
|
|
int kind() const { return kind_; }
|
|
int rank() const { return rank_; }
|
|
std::uint64_t offset() const { return offset_; }
|
|
const Value &characterLen() const { return characterLen_; }
|
|
const DerivedType *derivedType() const {
|
|
return derivedType_.descriptor().OffsetElement<const DerivedType>();
|
|
}
|
|
const Value *lenValue() const {
|
|
return lenValue_.descriptor().OffsetElement<const Value>();
|
|
}
|
|
const Value *bounds() const {
|
|
return bounds_.descriptor().OffsetElement<const Value>();
|
|
}
|
|
const char *initialization() const { return initialization_; }
|
|
|
|
std::size_t GetElementByteSize(const Descriptor &) const;
|
|
std::size_t GetElements(const Descriptor &) const;
|
|
|
|
// For ocmponents that are descriptors, returns size of descriptor;
|
|
// for Genre::Data, returns elemental byte size times element count.
|
|
std::size_t SizeInBytes(const Descriptor &) const;
|
|
|
|
// Establishes a descriptor from this component description.
|
|
void EstablishDescriptor(
|
|
Descriptor &, const Descriptor &container, Terminator &) const;
|
|
|
|
// Creates a pointer descriptor from this component description, possibly
|
|
// with subscripts
|
|
void CreatePointerDescriptor(Descriptor &, const Descriptor &container,
|
|
Terminator &, const SubscriptValue * = nullptr) const;
|
|
|
|
FILE *Dump(FILE * = stdout) const;
|
|
|
|
private:
|
|
StaticDescriptor<0> name_; // CHARACTER(:), POINTER
|
|
Genre genre_{Genre::Data};
|
|
std::uint8_t category_; // common::TypeCategory
|
|
std::uint8_t kind_{0};
|
|
std::uint8_t rank_{0};
|
|
std::uint64_t offset_{0};
|
|
Value characterLen_; // for TypeCategory::Character
|
|
StaticDescriptor<0, true> derivedType_; // TYPE(DERIVEDTYPE), POINTER
|
|
StaticDescriptor<1, true>
|
|
lenValue_; // TYPE(VALUE), POINTER, DIMENSION(:), CONTIGUOUS
|
|
StaticDescriptor<2, true>
|
|
bounds_; // TYPE(VALUE), POINTER, DIMENSION(2,:), CONTIGUOUS
|
|
const char *initialization_{nullptr}; // for Genre::Data and Pointer
|
|
// TODO: cobounds
|
|
// TODO: `PRIVATE` attribute
|
|
};
|
|
|
|
struct ProcPtrComponent {
|
|
StaticDescriptor<0> name; // CHARACTER(:), POINTER
|
|
std::uint64_t offset{0};
|
|
ProcedurePointer procInitialization;
|
|
};
|
|
|
|
class SpecialBinding {
|
|
public:
|
|
enum class Which : std::uint8_t {
|
|
None = 0,
|
|
ScalarAssignment = 1,
|
|
ElementalAssignment = 2,
|
|
ReadFormatted = 3,
|
|
ReadUnformatted = 4,
|
|
WriteFormatted = 5,
|
|
WriteUnformatted = 6,
|
|
ElementalFinal = 7,
|
|
AssumedRankFinal = 8,
|
|
ScalarFinal = 9,
|
|
// higher-ranked final procedures follow
|
|
};
|
|
|
|
static constexpr Which RankFinal(int rank) {
|
|
return static_cast<Which>(static_cast<int>(Which::ScalarFinal) + rank);
|
|
}
|
|
|
|
Which which() const { return which_; }
|
|
bool IsArgDescriptor(int zeroBasedArg) const {
|
|
return (isArgDescriptorSet_ >> zeroBasedArg) & 1;
|
|
}
|
|
template <typename PROC> PROC GetProc() const {
|
|
return reinterpret_cast<PROC>(proc_);
|
|
}
|
|
|
|
FILE *Dump(FILE *) const;
|
|
|
|
private:
|
|
Which which_{Which::None};
|
|
|
|
// The following little bit-set identifies which dummy arguments are
|
|
// passed via descriptors for their derived type arguments.
|
|
// Which::Assignment and Which::ElementalAssignment:
|
|
// Set to 1, 2, or (usually 3).
|
|
// The passed-object argument (usually the "to") is always passed via a
|
|
// a descriptor in the cases where the runtime will call a defined
|
|
// assignment because these calls are to type-bound generics,
|
|
// not generic interfaces, and type-bound generic defined assigment
|
|
// may appear only in an extensible type and requires a passed-object
|
|
// argument (see C774), and passed-object arguments to TBPs must be
|
|
// both polymorphic and scalar (C760). The non-passed-object argument
|
|
// (usually the "from") is usually, but not always, also a descriptor.
|
|
// Which::Final and Which::ElementalFinal:
|
|
// Set to 1 when dummy argument is assumed-shape; otherwise, the
|
|
// argument can be passed by address. (Fortran guarantees that
|
|
// any finalized object must be whole and contiguous by restricting
|
|
// the use of DEALLOCATE on pointers. The dummy argument of an
|
|
// elemental final subroutine must be scalar and monomorphic, but
|
|
// use a descriptors when the type has LEN parameters.)
|
|
// Which::AssumedRankFinal: flag must necessarily be set
|
|
// User derived type I/O:
|
|
// Set to 1 when "dtv" initial dummy argument is polymorphic, which is
|
|
// the case when and only when the derived type is extensible.
|
|
// When false, the user derived type I/O subroutine must have been
|
|
// called via a generic interface, not a generic TBP.
|
|
std::uint8_t isArgDescriptorSet_{0};
|
|
|
|
ProcedurePointer proc_{nullptr};
|
|
};
|
|
|
|
class DerivedType {
|
|
public:
|
|
~DerivedType(); // never defined
|
|
|
|
const Descriptor &binding() const { return binding_.descriptor(); }
|
|
const Descriptor &name() const { return name_.descriptor(); }
|
|
std::uint64_t sizeInBytes() const { return sizeInBytes_; }
|
|
const Descriptor &uninstatiated() const {
|
|
return uninstantiated_.descriptor();
|
|
}
|
|
const Descriptor &kindParameter() const {
|
|
return kindParameter_.descriptor();
|
|
}
|
|
const Descriptor &lenParameterKind() const {
|
|
return lenParameterKind_.descriptor();
|
|
}
|
|
const Descriptor &component() const { return component_.descriptor(); }
|
|
const Descriptor &procPtr() const { return procPtr_.descriptor(); }
|
|
const Descriptor &special() const { return special_.descriptor(); }
|
|
bool hasParent() const { return hasParent_; }
|
|
bool noInitializationNeeded() const { return noInitializationNeeded_; }
|
|
bool noDestructionNeeded() const { return noDestructionNeeded_; }
|
|
bool noFinalizationNeeded() const { return noFinalizationNeeded_; }
|
|
|
|
std::size_t LenParameters() const { return lenParameterKind().Elements(); }
|
|
|
|
const DerivedType *GetParentType() const;
|
|
|
|
// Finds a data component by name in this derived type or tis ancestors.
|
|
const Component *FindDataComponent(
|
|
const char *name, std::size_t nameLen) const;
|
|
|
|
// O(1) look-up of special procedure bindings
|
|
const SpecialBinding *FindSpecialBinding(SpecialBinding::Which which) const {
|
|
auto bitIndex{static_cast<std::uint32_t>(which)};
|
|
auto bit{std::uint32_t{1} << bitIndex};
|
|
if (specialBitSet_ & bit) {
|
|
// The index of this special procedure in the sorted array is the
|
|
// number of special bindings that are present with smaller "which"
|
|
// code values.
|
|
int offset{common::BitPopulationCount(specialBitSet_ & (bit - 1))};
|
|
const auto *binding{
|
|
special_.descriptor().ZeroBasedIndexedElement<SpecialBinding>(
|
|
offset)};
|
|
INTERNAL_CHECK(binding && binding->which() == which);
|
|
return binding;
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
FILE *Dump(FILE * = stdout) const;
|
|
|
|
private:
|
|
// This member comes first because it's used like a vtable by generated code.
|
|
// It includes all of the ancestor types' bindings, if any, first,
|
|
// with any overrides from descendants already applied to them. Local
|
|
// bindings then follow in alphabetic order of binding name.
|
|
StaticDescriptor<1, true>
|
|
binding_; // TYPE(BINDING), DIMENSION(:), POINTER, CONTIGUOUS
|
|
|
|
StaticDescriptor<0> name_; // CHARACTER(:), POINTER
|
|
|
|
std::uint64_t sizeInBytes_{0};
|
|
|
|
// Instantiations of a parameterized derived type with KIND type
|
|
// parameters will point this data member to the description of
|
|
// the original uninstantiated type, which may be shared from a
|
|
// module via use association. The original uninstantiated derived
|
|
// type description will point to itself. Derived types that have
|
|
// no KIND type parameters will have a null pointer here.
|
|
StaticDescriptor<0, true> uninstantiated_; // TYPE(DERIVEDTYPE), POINTER
|
|
|
|
// These pointer targets include all of the items from the parent, if any.
|
|
StaticDescriptor<1> kindParameter_; // pointer to rank-1 array of INTEGER(8)
|
|
StaticDescriptor<1>
|
|
lenParameterKind_; // pointer to rank-1 array of INTEGER(1)
|
|
|
|
// This array of local data components includes the parent component.
|
|
// Components are in component order, not collation order of their names.
|
|
// It does not include procedure pointer components.
|
|
StaticDescriptor<1, true>
|
|
component_; // TYPE(COMPONENT), POINTER, DIMENSION(:), CONTIGUOUS
|
|
|
|
// Procedure pointer components
|
|
StaticDescriptor<1, true>
|
|
procPtr_; // TYPE(PROCPTR), POINTER, DIMENSION(:), CONTIGUOUS
|
|
|
|
// Packed in ascending order of "which" code values.
|
|
// Does not include special bindings from ancestral types.
|
|
StaticDescriptor<1, true>
|
|
special_; // TYPE(SPECIALBINDING), POINTER, DIMENSION(:), CONTIGUOUS
|
|
|
|
// Little-endian bit-set of special procedure binding "which" code values
|
|
// for O(1) look-up in FindSpecialBinding() above.
|
|
std::uint32_t specialBitSet_{0};
|
|
|
|
// Flags
|
|
bool hasParent_{false};
|
|
bool noInitializationNeeded_{false};
|
|
bool noDestructionNeeded_{false};
|
|
bool noFinalizationNeeded_{false};
|
|
};
|
|
|
|
} // namespace Fortran::runtime::typeInfo
|
|
#endif // FORTRAN_RUNTIME_TYPE_INFO_H_
|