[flang-commits] [flang] f88a949 - [flang] Generate PDT runtime type info in the type definition scope

Jean Perier via flang-commits flang-commits at lists.llvm.org
Thu Mar 3 01:16:06 PST 2022


Author: Jean Perier
Date: 2022-03-03T10:15:21+01:00
New Revision: f88a9497a2bd731e0e8a6f913954007c9c7b5479

URL: https://github.com/llvm/llvm-project/commit/f88a9497a2bd731e0e8a6f913954007c9c7b5479
DIFF: https://github.com/llvm/llvm-project/commit/f88a9497a2bd731e0e8a6f913954007c9c7b5479.diff

LOG: [flang] Generate PDT runtime type info in the type definition scope

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

Added: 
    

Modified: 
    flang/include/flang/Semantics/scope.h
    flang/lib/Semantics/compute-offsets.cpp
    flang/lib/Semantics/runtime-type-info.cpp
    flang/lib/Semantics/scope.cpp
    flang/test/Semantics/typeinfo01.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/scope.h b/flang/include/flang/Semantics/scope.h
index 97f8f1ccb5747..cd03e66ce0e71 100644
--- a/flang/include/flang/Semantics/scope.h
+++ b/flang/include/flang/Semantics/scope.h
@@ -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_; }

diff  --git a/flang/lib/Semantics/compute-offsets.cpp b/flang/lib/Semantics/compute-offsets.cpp
index 2451f0abdc7d7..99f81940bbbee 100644
--- a/flang/lib/Semantics/compute-offsets.cpp
+++ b/flang/lib/Semantics/compute-offsets.cpp
@@ -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

diff  --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp
index dc302de38e0f6..12dbd78b23c16 100644
--- a/flang/lib/Semantics/runtime-type-info.cpp
+++ b/flang/lib/Semantics/runtime-type-info.cpp
@@ -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)
@@ -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).
@@ -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();
@@ -369,18 +404,26 @@ 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 
diff erent kind parameter values.
+    // Type with 
diff erent 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)};
@@ -388,9 +431,9 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
   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;
@@ -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
@@ -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;

diff  --git a/flang/lib/Semantics/scope.cpp b/flang/lib/Semantics/scope.cpp
index 3eda613ca422a..30bf59e418cf1 100644
--- a/flang/lib/Semantics/scope.cpp
+++ b/flang/lib/Semantics/scope.cpp
@@ -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};

diff  --git a/flang/test/Semantics/typeinfo01.f90 b/flang/test/Semantics/typeinfo01.f90
index 1cac6ec9c399e..570898ca781c2 100644
--- a/flang/test/Semantics/typeinfo01.f90
+++ b/flang/test/Semantics/typeinfo01.f90
@@ -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
@@ -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


        


More information about the flang-commits mailing list