[flang-commits] [flang] 88be495 - [flang][hlfir] Lower parent component references

Jean Perier via flang-commits flang-commits at lists.llvm.org
Tue Feb 28 05:11:26 PST 2023


Author: Jean Perier
Date: 2023-02-28T14:10:52+01:00
New Revision: 88be49599f3a899c712bd6a56bad2585bda6388f

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

LOG: [flang][hlfir] Lower parent component references

Skip the parent components when they are not at the end of
designators.
Generate an hlfir.parent_comp for parent component at the end
of designators.

Differential Revision: https://reviews.llvm.org/D144948

Added: 
    flang/test/Lower/HLFIR/parent-component-ref.f90

Modified: 
    flang/lib/Lower/ConvertExprToHLFIR.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 49a2c52629335..68839bacd6ef1 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -163,14 +163,65 @@ class HlfirDesignatorBuilder {
   }
 
   fir::FortranVariableOpInterface
-  gen(const Fortran::evaluate::Component &component) {
+  gen(const Fortran::evaluate::Component &component,
+      bool skipParentComponent = false) {
     if (Fortran::semantics::IsAllocatableOrPointer(component.GetLastSymbol()))
       return genWholeAllocatableOrPointerComponent(component);
+    if (component.GetLastSymbol().test(
+            Fortran::semantics::Symbol::Flag::ParentComp)) {
+      if (skipParentComponent)
+        // Inner parent components can be skipped: x%parent_comp%i is equivalent
+        // to "x%i" in FIR (all the parent components are part of the FIR type
+        // of "x").
+        return genDataRefAndSkipParentComponents(component.base());
+      // This is a leaf "x%parent_comp" or "x(subscripts)%parent_comp" and
+      // cannot be skipped: the designator must be lowered to the parent type.
+      // This cannot be represented with an hlfir.designate since "parent_comp"
+      // name is meaningless in the fir.record type of "x". Instead, an
+      // hlfir.parent_comp is generated.
+      fir::FirOpBuilder &builder = getBuilder();
+      hlfir::Entity base = genDataRefAndSkipParentComponents(component.base());
+      base = derefPointersAndAllocatables(loc, builder, base);
+      mlir::Value shape;
+      if (base.isArray())
+        shape = hlfir::genShape(loc, builder, base);
+      const Fortran::semantics::DeclTypeSpec *declTypeSpec =
+          component.GetLastSymbol().GetType();
+      assert(declTypeSpec && declTypeSpec->AsDerived() &&
+             "parent component symbols must have a derived type");
+      mlir::Type componentType = Fortran::lower::translateDerivedTypeToFIRType(
+          getConverter(), *declTypeSpec->AsDerived());
+      mlir::Type resultType =
+          changeElementType(base.getElementOrSequenceType(), componentType);
+      // Note that the result is monomorphic even if the base is polymorphic:
+      // the dynamic type of the parent component reference is the parent type.
+      // If the base is an array, it is however most likely not contiguous.
+      if (base.isArray() || fir::isRecordWithTypeParameters(componentType))
+        resultType = fir::BoxType::get(resultType);
+      else
+        resultType = fir::ReferenceType::get(resultType);
+      if (fir::isRecordWithTypeParameters(componentType))
+        TODO(loc, "parent component reference with a parametrized parent type");
+      auto parentComp = builder.create<hlfir::ParentComponentOp>(
+          loc, resultType, base, shape, /*typeParams=*/mlir::ValueRange{});
+      return mlir::cast<fir::FortranVariableOpInterface>(
+          parentComp.getOperation());
+    }
     PartInfo partInfo;
     mlir::Type resultType = visit(component, partInfo);
     return genDesignate(resultType, partInfo, component);
   }
 
+  fir::FortranVariableOpInterface
+  genDataRefAndSkipParentComponents(const Fortran::evaluate::DataRef &dataRef) {
+    return std::visit(Fortran::common::visitors{
+                          [&](const Fortran::evaluate::Component &component) {
+                            return gen(component, /*skipParentComponent=*/true);
+                          },
+                          [&](const auto &x) { return gen(x); }},
+                      dataRef.u);
+  }
+
   fir::FortranVariableOpInterface
   gen(const Fortran::evaluate::ArrayRef &arrayRef) {
     PartInfo partInfo;
@@ -508,8 +559,7 @@ class HlfirDesignatorBuilder {
     // coarray-ref, or another component, this creates another hlfir.designate
     // for it.  hlfir.designate is not meant to represent more than one
     // part-ref.
-    partInfo.base =
-        std::visit([&](const auto &x) { return gen(x); }, component.base().u);
+    partInfo.base = genDataRefAndSkipParentComponents(component.base());
     // If the base is an allocatable/pointer, dereference it here since the
     // component ref designates its target.
     partInfo.base =
@@ -523,8 +573,9 @@ class HlfirDesignatorBuilder {
     // Lower the information about the component (type, length parameters and
     // shape).
     const Fortran::semantics::Symbol &componentSym = component.GetLastSymbol();
-    if (componentSym.test(Fortran::semantics::Symbol::Flag::ParentComp))
-      TODO(getLoc(), "Parent component reference in HLFIR");
+    assert(
+        !componentSym.test(Fortran::semantics::Symbol::Flag::ParentComp) &&
+        "parent components are skipped and must not reach visitComponentImpl");
     partInfo.componentName = componentSym.name().ToString();
     auto recordType =
         hlfir::getFortranElementType(baseType).cast<fir::RecordType>();

diff  --git a/flang/test/Lower/HLFIR/parent-component-ref.f90 b/flang/test/Lower/HLFIR/parent-component-ref.f90
new file mode 100644
index 0000000000000..df83771a28159
--- /dev/null
+++ b/flang/test/Lower/HLFIR/parent-component-ref.f90
@@ -0,0 +1,99 @@
+! Test lowering of parent component references to HLFIR.
+! RUN: bbc -emit-fir -hlfir -polymorphic-type -o - %s -I nw | FileCheck %s
+
+module pc_types
+  type t
+    integer :: i
+  end type
+  type, extends(t) :: t2
+    integer :: j
+  end type
+interface
+subroutine takes_t_type_array(x)
+  import :: t
+  type(t) :: x(:)
+end subroutine
+subroutine takes_t_class_array(x)
+  import :: t
+  class(t) :: x(:)
+end subroutine
+subroutine takes_int_array(x)
+  integer :: x(:)
+end subroutine
+end interface
+end module
+
+subroutine test_ignored_inner_parent_comp(x)
+ use pc_types
+ type(t2) :: x
+ call takes_int(x%t%i)
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_ignored_inner_parent_comp(
+! CHECK:  %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ex"
+! CHECK:  %[[VAL_2:.*]] = hlfir.designate %[[VAL_1]]#0{"i"}   : (!fir.ref<!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>) -> !fir.ref<i32>
+! CHECK:  fir.call @_QPtakes_int(%[[VAL_2]])
+
+subroutine test_ignored_inner_parent_comp_2(x)
+ use pc_types
+ type(t2) :: x(:)
+ call takes_int_array(x%t%i)
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_ignored_inner_parent_comp_2(
+! CHECK:  %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ex"
+! CHECK:  %[[VAL_2:.*]] = arith.constant 0 : index
+! CHECK:  %[[VAL_3:.*]]:3 = fir.box_dims %[[VAL_1]]#0, %[[VAL_2]] : (!fir.box<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, index) -> (index, index, index)
+! CHECK:  %[[VAL_4:.*]] = fir.shape %[[VAL_3]]#1 : (index) -> !fir.shape<1>
+! CHECK:  %[[VAL_5:.*]] = hlfir.designate %[[VAL_1]]#0{"i"}   shape %[[VAL_4]] : (!fir.box<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
+! CHECK:  fir.call @_QPtakes_int_array(%[[VAL_5]])
+
+subroutine test_leaf_parent_ref(x)
+ use pc_types
+ type(t2) :: x
+ call takes_parent(x%t)
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_leaf_parent_ref(
+! CHECK:  %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ex"
+! CHECK:  %[[VAL_2:.*]] = hlfir.parent_comp %[[VAL_1]]#0 : (!fir.ref<!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>) -> !fir.ref<!fir.type<_QMpc_typesTt{i:i32}>>
+! CHECK:  fir.call @_QPtakes_parent(%[[VAL_2]])
+
+subroutine test_leaf_parent_ref_array(x)
+ use pc_types
+ class(t2) :: x(42:)
+! CHECK-LABEL: func.func @_QPtest_leaf_parent_ref_array(
+! CHECK:  %[[VAL_4:.*]]:2 = hlfir.declare {{.*}}Ex"
+ call takes_t_type_array(x%t)
+! CHECK:  %[[VAL_5:.*]] = arith.constant 0 : index
+! CHECK:  %[[VAL_6:.*]]:3 = fir.box_dims %[[VAL_4]]#0, %[[VAL_5]] : (!fir.class<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, index) -> (index, index, index)
+! CHECK:  %[[VAL_7:.*]] = fir.shape %[[VAL_6]]#1 : (index) -> !fir.shape<1>
+! CHECK:  %[[VAL_8:.*]] = hlfir.parent_comp %[[VAL_4]]#0 shape %[[VAL_7]] : (!fir.class<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>
+! CHECK:  fir.call @_QPtakes_t_type_array(%[[VAL_8]])
+ call takes_t_class_array(x%t)
+! CHECK:  %[[VAL_12:.*]] = hlfir.parent_comp %[[VAL_4]]#0 shape %{{.*}} : (!fir.class<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>
+! CHECK:  %[[VAL_13:.*]] = fir.convert %[[VAL_12]] : (!fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>) -> !fir.class<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>
+! CHECK:  fir.call @_QPtakes_t_class_array(%[[VAL_13]])
+end subroutine
+
+subroutine test_parent_section_leaf_array(x)
+ use pc_types
+ class(t2) :: x(:)
+ call takes_t_type_array(x(2:11)%t)
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_parent_section_leaf_array(
+! CHECK:  %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ex"
+! CHECK:  %[[VAL_7:.*]] = hlfir.designate %[[VAL_1]]#0 ({{.*}})  shape %[[VAL_6:.*]] : (!fir.class<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, index, index, index, !fir.shape<1>) -> !fir.class<!fir.array<10x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>
+! CHECK:  %[[VAL_8:.*]] = hlfir.parent_comp %[[VAL_7]] shape %[[VAL_6]] : (!fir.class<!fir.array<10x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>, !fir.shape<1>) -> !fir.box<!fir.array<10x!fir.type<_QMpc_typesTt{i:i32}>>>
+! CHECK:  %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.box<!fir.array<10x!fir.type<_QMpc_typesTt{i:i32}>>>) -> !fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>
+! CHECK:  fir.call @_QPtakes_t_type_array(%[[VAL_9]])
+
+subroutine test_pointer_leaf_parent_ref_array(x)
+ use pc_types
+ class(t2), pointer :: x(:)
+ call takes_t_type_array(x%t)
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_pointer_leaf_parent_ref_array(
+! CHECK:  %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ex"
+! CHECK:  %[[VAL_2:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>>>
+! CHECK:  %[[VAL_3:.*]] = arith.constant 0 : index
+! CHECK:  %[[VAL_4:.*]]:3 = fir.box_dims %[[VAL_2]], %[[VAL_3]] : (!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>>, index) -> (index, index, index)
+! CHECK:  %[[VAL_5:.*]] = fir.shape %[[VAL_4]]#1 : (index) -> !fir.shape<1>
+! CHECK:  %[[VAL_6:.*]] = hlfir.parent_comp %[[VAL_2]] shape %[[VAL_5]] : (!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMpc_typesTt2{i:i32,j:i32}>>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.type<_QMpc_typesTt{i:i32}>>>


        


More information about the flang-commits mailing list