Skip to content

Commit

Permalink
[flang] Generate PDT runtime type info in the type definition scope
Browse files Browse the repository at this point in the history
This patches modifies PDT runtime type info generation so that it is
easier to handle derived type descriptor in lowering. It changes three
aspects:

1. The symbol name suffix of runtime type info for PDT instantiation is
   changed from a serial number unrelated to the types to an encoding of
   the instantiated KIND parameters.
2. New runtime type info is not created for each instantiation of PDT without
   KIND parameters (only length parameters). Instead, the runtime type
   info of the type definition is always used. It is updated to contain
   the component descriptions.
3. Runtime type info of PDT instantiation is now always generated in the
   scope where the type is defined. If several PDT type instantiation
   are made in different scope with the same kind parameters, they will
   use the same runtime type info.

Rational of the change:

In lowering, derived type descriptors are not mapped when instantiating derived
type objects. They are mapped later when symbol knowledge is not available anymore.
This mapping is based on the FIR representation of derived types. For
PDT, the FIR type information does not allow deducing the instantiation
scope, it only allows retrieving the type name, the type _definition_
scope, and the kind parameter values. Therefore, in order to be able to
retrieve the derived type descriptor from a FIR type, the derived type
descriptor must be generated in the definition scope and must reflect
the kind parameters. This justifies the need for changes 1. and 3.
above (suffix and scope change). Changes 2. comes from the fact that
all runtime type info of type without kind parameters can be generated
from the type definition, and that because of the suffix change, the
symbol name for type definition and type instantiation are the same.

Although this change is first motivated by how lowering handles derived
types, I believe it is also an improvement from a functional point of
view since this change will allow reducing the number of generated
runtime type info for PDTs, since redundant information (different
instantiations with same kind parameters) will only be generated once.

Differential Revision: https://reviews.llvm.org/D120801
  • Loading branch information
jeanPerier committed Mar 3, 2022
1 parent 392cba8 commit f88a949
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 29 deletions.
1 change: 1 addition & 0 deletions flang/include/flang/Semantics/scope.h
Expand Up @@ -104,6 +104,7 @@ class Scope {
bool IsParameterizedDerivedTypeInstantiation() const {
return kind_ == Kind::DerivedType && !symbol_;
}
bool IsKindParameterizedDerivedType() const;
Symbol *symbol() { return symbol_; }
const Symbol *symbol() const { return symbol_; }
SemanticsContext &context() const { return context_; }
Expand Down
4 changes: 2 additions & 2 deletions flang/lib/Semantics/compute-offsets.cpp
Expand Up @@ -68,8 +68,8 @@ void ComputeOffsetsHelper::Compute(Scope &scope) {
for (Scope &child : scope.children()) {
ComputeOffsets(context_, child);
}
if (scope.symbol() && scope.IsParameterizedDerivedType()) {
return; // only process instantiations of parameterized derived types
if (scope.symbol() && scope.IsKindParameterizedDerivedType()) {
return; // only process instantiations of kind parameterized derived types
}
if (scope.alignment().has_value()) {
return; // prevent infinite recursion in error cases
Expand Down
72 changes: 57 additions & 15 deletions flang/lib/Semantics/runtime-type-info.cpp
Expand Up @@ -114,7 +114,6 @@ class RuntimeTableBuilder {
SemanticsContext &context_;
RuntimeDerivedTypeTables &tables_;
std::map<const Symbol *, SymbolVector> orderedTypeParameters_;
int anonymousTypes_{0};

const DeclTypeSpec &derivedTypeSchema_; // TYPE(DerivedType)
const DeclTypeSpec &componentSchema_; // TYPE(Component)
Expand Down Expand Up @@ -339,12 +338,38 @@ template <int KIND> static SomeExpr IntExpr(std::int64_t n) {
evaluate::Constant<evaluate::Type<TypeCategory::Integer, KIND>>{n});
}

static std::optional<std::string> GetSuffixIfTypeKindParameters(
const DerivedTypeSpec &derivedTypeSpec, const SymbolVector *parameters) {
if (parameters) {
std::optional<std::string> suffix;
for (SymbolRef ref : *parameters) {
const auto &tpd{ref->get<TypeParamDetails>()};
if (tpd.attr() == common::TypeParamAttr::Kind) {
if (const auto *pv{derivedTypeSpec.FindParameter(ref->name())}) {
if (pv->GetExplicit()) {
if (auto instantiatedValue{evaluate::ToInt64(*pv->GetExplicit())}) {
if (suffix.has_value()) {
*suffix += "."s + std::to_string(*instantiatedValue);
} else {
suffix = "."s + std::to_string(*instantiatedValue);
;
}
}
}
}
}
}
return suffix;
}
return std::nullopt;
}

const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
if (const Symbol * info{dtScope.runtimeDerivedTypeDescription()}) {
return info;
}
const DerivedTypeSpec *derivedTypeSpec{dtScope.derivedTypeSpec()};
if (!derivedTypeSpec && !dtScope.IsParameterizedDerivedType() &&
if (!derivedTypeSpec && !dtScope.IsKindParameterizedDerivedType() &&
dtScope.symbol()) {
// This derived type was declared (obviously, there's a Scope) but never
// used in this compilation (no instantiated DerivedTypeSpec points here).
Expand All @@ -353,6 +378,16 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
// a module but used only by clients and submodules, enabling the
// run-time "no initialization needed here" flag to work.
DerivedTypeSpec derived{dtScope.symbol()->name(), *dtScope.symbol()};
if (const SymbolVector *
lenParameters{GetTypeParameters(*dtScope.symbol())}) {
// Create dummy deferred values for the length parameters so that the
// DerivedTypeSpec is complete and can be used in helpers.
for (SymbolRef lenParam : *lenParameters) {
derived.AddRawParamValue(
std::nullopt, ParamValue::Deferred(common::TypeParamAttr::Len));
}
derived.CookParameters(context_.foldingContext());
}
DeclTypeSpec &decl{
dtScope.MakeDerivedType(DeclTypeSpec::TypeDerived, std::move(derived))};
derivedTypeSpec = &decl.derivedTypeSpec();
Expand All @@ -369,28 +404,36 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
(typeName.front() == '.' && !context_.IsTempName(typeName))) {
return nullptr;
}
const SymbolVector *parameters{GetTypeParameters(*dtSymbol)};
std::string distinctName{typeName};
if (&dtScope != dtSymbol->scope()) {
distinctName += "."s + std::to_string(anonymousTypes_++);
if (&dtScope != dtSymbol->scope() && derivedTypeSpec) {
// Only create new type descriptions for different kind parameter values.
// Type with different length parameters/same kind parameters can all
// share the same type description available in the current scope.
if (auto suffix{
GetSuffixIfTypeKindParameters(*derivedTypeSpec, parameters)}) {
distinctName += *suffix;
}
}
std::string dtDescName{".dt."s + distinctName};
Scope &scope{GetContainingNonDerivedScope(dtScope)};
if (distinctName == typeName && scope.IsModule()) {
if (const Symbol * description{scope.FindSymbol(SourceName{dtDescName})}) {
dtScope.set_runtimeDerivedTypeDescription(*description);
return description;
}
Scope *dtSymbolScope{const_cast<Scope *>(dtSymbol->scope())};
Scope &scope{
GetContainingNonDerivedScope(dtSymbolScope ? *dtSymbolScope : dtScope)};
if (const auto it{scope.find(SourceName{dtDescName})}; it != scope.end()) {
dtScope.set_runtimeDerivedTypeDescription(*it->second);
return &*it->second;
}

// Create a new description object before populating it so that mutual
// references will work as pointer targets.
Symbol &dtObject{CreateObject(dtDescName, derivedTypeSchema_, scope)};
dtScope.set_runtimeDerivedTypeDescription(dtObject);
evaluate::StructureConstructorValues dtValues;
AddValue(dtValues, derivedTypeSchema_, "name"s,
SaveNameAsPointerTarget(scope, typeName));
bool isPDTdefinition{
!derivedTypeSpec && dtScope.IsParameterizedDerivedType()};
if (!isPDTdefinition) {
bool isPDTdefinitionWithKindParameters{
!derivedTypeSpec && dtScope.IsKindParameterizedDerivedType()};
if (!isPDTdefinitionWithKindParameters) {
auto sizeInBytes{static_cast<common::ConstantSubscript>(dtScope.size())};
if (auto alignment{dtScope.alignment().value_or(0)}) {
sizeInBytes += alignment - 1;
Expand All @@ -417,7 +460,6 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
using Int1 = evaluate::Type<TypeCategory::Integer, 1>;
std::vector<Int8::Scalar> kinds;
std::vector<Int1::Scalar> lenKinds;
const SymbolVector *parameters{GetTypeParameters(*dtSymbol)};
if (parameters) {
// Package the derived type's parameters in declaration order for
// each category of parameter. KIND= type parameters are described
Expand Down Expand Up @@ -450,7 +492,7 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
SaveNumericPointerTarget<Int1>(
scope, SaveObjectName(".lpk."s + distinctName), std::move(lenKinds)));
// Traverse the components of the derived type
if (!isPDTdefinition) {
if (!isPDTdefinitionWithKindParameters) {
std::vector<const Symbol *> dataComponentSymbols;
std::vector<evaluate::StructureConstructor> procPtrComponents;
std::map<int, evaluate::StructureConstructor> specials;
Expand Down
19 changes: 19 additions & 0 deletions flang/lib/Semantics/scope.cpp
Expand Up @@ -374,6 +374,25 @@ bool Scope::IsParameterizedDerivedType() const {
return false;
}

bool Scope::IsKindParameterizedDerivedType() const {
if (!IsDerivedType()) {
return false;
}
if (const Scope * parent{GetDerivedTypeParent()}) {
if (parent->IsKindParameterizedDerivedType()) {
return true;
}
}
for (const auto &pair : symbols_) {
if (const auto *typeParam{pair.second->detailsIf<TypeParamDetails>()}) {
if (typeParam->attr() == common::TypeParamAttr::Kind) {
return true;
}
}
}
return false;
}

const DeclTypeSpec *Scope::FindInstantiatedDerivedType(
const DerivedTypeSpec &spec, DeclTypeSpec::Category category) const {
DeclTypeSpec type{category, spec};
Expand Down
22 changes: 10 additions & 12 deletions flang/test/Semantics/typeinfo01.f90
Expand Up @@ -32,11 +32,11 @@ module m03
real(kind=k) :: a
end type
type(kpdt(4)) :: x
!CHECK: .c.kpdt.0, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.a,genre=1_1,category=1_1,kind=4_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())]
!CHECK: .c.kpdt.4, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(component) shape: 0_8:0_8 init:[component::component(name=.n.a,genre=1_1,category=1_1,kind=4_1,rank=0_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL())]
!CHECK: .dt.kpdt, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(name=.n.kpdt,uninstantiated=NULL(),kindparameter=.kp.kpdt,lenparameterkind=NULL())
!CHECK: .dt.kpdt.0, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.kpdt,sizeinbytes=4_8,uninstantiated=.dt.kpdt,kindparameter=.kp.kpdt.0,lenparameterkind=NULL(),component=.c.kpdt.0,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
!CHECK: .dt.kpdt.4, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.kpdt,sizeinbytes=4_8,uninstantiated=.dt.kpdt,kindparameter=.kp.kpdt.4,lenparameterkind=NULL(),component=.c.kpdt.4,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
!CHECK: .kp.kpdt, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: INTEGER(8) shape: 0_8:0_8 init:[INTEGER(8)::1_8]
!CHECK: .kp.kpdt.0, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: INTEGER(8) shape: 0_8:0_8 init:[INTEGER(8)::4_8]
!CHECK: .kp.kpdt.4, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: INTEGER(8) shape: 0_8:0_8 init:[INTEGER(8)::4_8]
end module

module m04
Expand Down Expand Up @@ -227,18 +227,16 @@ module m11
character(len=len) :: chauto
real :: automatic(len)
end type
!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(name=.n.t,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=.lpk.t)
!CHECK: .b.t.automatic, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(value) shape: 0_8:1_8,0_8:0_8 init:reshape([value::value(genre=2_1,value=1_8),value(genre=3_1,value=0_8)],shape=[2,1])
!CHECK: .c.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(component) shape: 0_8:3_8 init:[component::component(name=.n.allocatable,genre=3_1,category=1_1,kind=4_1,rank=1_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.pointer,genre=2_1,category=1_1,kind=4_1,rank=0_1,offset=48_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=.di.t.pointer),component(name=.n.chauto,genre=4_1,category=3_1,kind=1_1,rank=0_1,offset=72_8,characterlen=value(genre=3_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.automatic,genre=4_1,category=1_1,kind=4_1,rank=1_1,offset=96_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=.b.t.automatic,initialization=NULL())]
!CHECK: .di.t.pointer, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(.dp.t.pointer) init:.dp.t.pointer(pointer=target)
!CHECK: .dp.t.pointer (CompilerCreated): DerivedType components: pointer
!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=144_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=.lpk.t,component=.c.t,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1)
!CHECK: .lpk.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: INTEGER(1) shape: 0_8:0_8 init:[INTEGER(1)::8_1]
!CHECK: DerivedType scope: .dp.t.pointer size=24 alignment=8 instantiation of .dp.t.pointer
!CHECK: pointer, POINTER size=24 offset=0: ObjectEntity type: REAL(4)
contains
subroutine s1(x)
!CHECK: .b.t.1.automatic, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(value) shape: 0_8:1_8,0_8:0_8 init:reshape([value::value(genre=2_1,value=1_8),value(genre=3_1,value=0_8)],shape=[2,1])
!CHECK: .c.t.1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(component) shape: 0_8:3_8 init:[component::component(name=.n.allocatable,genre=3_1,category=1_1,kind=4_1,rank=1_1,offset=0_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.pointer,genre=2_1,category=1_1,kind=4_1,rank=0_1,offset=48_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=.di.t.1.pointer),component(name=.n.chauto,genre=4_1,category=3_1,kind=1_1,rank=0_1,offset=72_8,characterlen=value(genre=3_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=NULL(),initialization=NULL()),component(name=.n.automatic,genre=4_1,category=1_1,kind=4_1,rank=1_1,offset=96_8,characterlen=value(genre=1_1,value=0_8),derived=NULL(),lenvalue=NULL(),bounds=.b.t.1.automatic,initialization=NULL())]
!CHECK: .di.t.1.pointer, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(.dp.t.1.pointer) init:.dp.t.1.pointer(pointer=target)
!CHECK: .dp.t.1.pointer (CompilerCreated): DerivedType components: pointer
!CHECK: .dt.t.1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=144_8,uninstantiated=.dt.t,kindparameter=NULL(),lenparameterkind=.lpk.t.1,component=.c.t.1,procptr=NULL(),special=NULL(),specialbitset=0_4,hasparent=0_1,noinitializationneeded=0_1,nodestructionneeded=0_1,nofinalizationneeded=1_1)
!CHECK: .lpk.t.1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: INTEGER(1) shape: 0_8:0_8 init:[INTEGER(1)::8_1]
!CHECK: DerivedType scope: .dp.t.1.pointer size=24 alignment=8 instantiation of .dp.t.1.pointer
!CHECK: pointer, POINTER size=24 offset=0: ObjectEntity type: REAL(4)
type(t(*)), intent(in) :: x
end subroutine
end module
Expand Down

0 comments on commit f88a949

Please sign in to comment.