[flang][hlfir] Implemented addressing an element of a polymorphic array.

The changes convert hlfir.designate to fir.array_coor/fir.embox
to represent a subscripted element of a polymorphic array.
The type information is conveyed via the fir.embox's source_box.

Reviewed By: tblah

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

GitOrigin-RevId: 4fbaefa246844bd2329712c9dbd20893d4d8f467
diff --git a/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index 4964ef9..22ad537 100644
--- a/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -373,6 +373,31 @@
 
 class DesignateOpConversion
     : public mlir::OpRewritePattern<hlfir::DesignateOp> {
+  // Helper method to generate the coordinate of the first element
+  // of an array section. It is also called for cases of non-section
+  // array element addressing.
+  static mlir::Value genSubscriptBeginAddr(
+      fir::FirOpBuilder &builder, mlir::Location loc,
+      hlfir::DesignateOp designate, mlir::Type baseEleTy, mlir::Value base,
+      mlir::Value shape,
+      const llvm::SmallVector<mlir::Value> &firBaseTypeParameters) {
+    assert(!designate.getIndices().empty());
+    llvm::SmallVector<mlir::Value> firstElementIndices;
+    auto indices = designate.getIndices();
+    int i = 0;
+    for (auto isTriplet : designate.getIsTripletAttr().asArrayRef()) {
+      // Coordinate of the first element are the index and triplets lower
+      // bounds
+      firstElementIndices.push_back(indices[i]);
+      i = i + (isTriplet ? 3 : 1);
+    }
+    mlir::Type arrayCoorType = fir::ReferenceType::get(baseEleTy);
+    base = builder.create<fir::ArrayCoorOp>(
+        loc, arrayCoorType, base, shape,
+        /*slice=*/mlir::Value{}, firstElementIndices, firBaseTypeParameters);
+    return base;
+  }
+
 public:
   explicit DesignateOpConversion(mlir::MLIRContext *ctx)
       : OpRewritePattern{ctx} {}
@@ -436,9 +461,20 @@
 
     if (designateResultType.isa<fir::BaseBoxType>()) {
       // Generate embox or rebox.
-      if (!fir::unwrapPassByRefType(designateResultType)
-               .isa<fir::SequenceType>())
-        TODO(loc, "addressing polymorphic arrays");
+      mlir::Type eleTy = fir::unwrapPassByRefType(designateResultType);
+      bool isScalarDesignator = !eleTy.isa<fir::SequenceType>();
+      mlir::Value sourceBox;
+      if (isScalarDesignator) {
+        // The base box will be used for emboxing the scalar element.
+        sourceBox = base;
+        // Generate the coordinate of the element.
+        base = genSubscriptBeginAddr(builder, loc, designate, baseEleTy, base,
+                                     shape, firBaseTypeParameters);
+        shape = nullptr;
+        // Type information will be taken from the source box,
+        // so the type parameters are not needed.
+        firBaseTypeParameters.clear();
+      }
       llvm::SmallVector<mlir::Value> triples;
       llvm::SmallVector<mlir::Value> sliceFields;
       mlir::Type idxTy = builder.getIndexType();
@@ -462,7 +498,7 @@
                 builder.create<mlir::arith::SubIOp>(loc, iIdx, lbIdx));
           }
         }
-      } else {
+      } else if (!isScalarDesignator) {
         // Otherwise, this is an array section with triplets.
         auto undef = builder.create<fir::UndefOp>(loc, idxTy);
         unsigned i = 0;
@@ -506,8 +542,9 @@
         resultBox =
             builder.create<fir::ReboxOp>(loc, resultType, base, shape, slice);
       else
-        resultBox = builder.create<fir::EmboxOp>(loc, resultType, base, shape,
-                                                 slice, firBaseTypeParameters);
+        resultBox =
+            builder.create<fir::EmboxOp>(loc, resultType, base, shape, slice,
+                                         firBaseTypeParameters, sourceBox);
       rewriter.replaceOp(designate, resultBox);
       return mlir::success();
     }
@@ -525,19 +562,8 @@
       // - scalar%array_comp(indices) [substring|complex_part]
       // This may be a ranked contiguous array section in which case
       // The first element address is being computed.
-      llvm::SmallVector<mlir::Value> firstElementIndices;
-      auto indices = designate.getIndices();
-      int i = 0;
-      for (auto isTriplet : designate.getIsTripletAttr().asArrayRef()) {
-        // Coordinate of the first element are the index and triplets lower
-        // bounds
-        firstElementIndices.push_back(indices[i]);
-        i = i + (isTriplet ? 3 : 1);
-      }
-      mlir::Type arrayCoorType = fir::ReferenceType::get(baseEleTy);
-      base = builder.create<fir::ArrayCoorOp>(
-          loc, arrayCoorType, base, shape,
-          /*slice=*/mlir::Value{}, firstElementIndices, firBaseTypeParameters);
+      base = genSubscriptBeginAddr(builder, loc, designate, baseEleTy, base,
+                                   shape, firBaseTypeParameters);
     }
 
     // Scalar substring (potentially on the previously built array element or
diff --git a/test/HLFIR/designate-codegen.fir b/test/HLFIR/designate-codegen.fir
index 3a5bd70..745416f 100644
--- a/test/HLFIR/designate-codegen.fir
+++ b/test/HLFIR/designate-codegen.fir
@@ -191,3 +191,19 @@
 // CHECK:  %[[VAL_12:.*]] = fir.undefined index
 // CHECK:  %[[VAL_13:.*]] = fir.slice %[[VAL_6]], %[[VAL_8]]#1, %[[VAL_9]] : (index, index, index) -> !fir.slice<1>
 // CHECK:  %[[VAL_14:.*]] = fir.rebox %[[VAL_4]] {{\[}}%[[VAL_13]]] : (!fir.box<!fir.array<?x!fir.char<1,5>>>, !fir.slice<1>) -> !fir.box<!fir.array<?x!fir.char<1,5>>>
+
+func.func @test_polymorphic_array_elt(%arg0: !fir.class<!fir.array<?x!fir.type<_QMtypesTt1>>> {fir.bindc_name = "x"}) {
+  %0:2 = hlfir.declare %arg0 {uniq_name = "_QFtest1Ex"} : (!fir.class<!fir.array<?x!fir.type<_QMtypesTt1>>>) -> (!fir.class<!fir.array<?x!fir.type<_QMtypesTt1>>>, !fir.class<!fir.array<?x!fir.type<_QMtypesTt1>>>)
+  %c7 = arith.constant 7 : index
+  %1 = hlfir.designate %0#0 (%c7)  : (!fir.class<!fir.array<?x!fir.type<_QMtypesTt1>>>, index) -> !fir.class<!fir.type<_QMtypesTt1>>
+  return
+}
+// CHECK-LABEL:   func.func @test_polymorphic_array_elt(
+// CHECK-SAME:        %[[VAL_0:.*]]: !fir.class<!fir.array<?x!fir.type<_QMtypesTt1>>> {fir.bindc_name = "x"}) {
+// CHECK:           %[[VAL_1:.*]] = fir.declare %[[VAL_0]] {uniq_name = "_QFtest1Ex"} : (!fir.class<!fir.array<?x!fir.type<_QMtypesTt1>>>) -> !fir.class<!fir.array<?x!fir.type<_QMtypesTt1>>>
+// CHECK:           %[[VAL_2:.*]] = fir.rebox %[[VAL_1]] : (!fir.class<!fir.array<?x!fir.type<_QMtypesTt1>>>) -> !fir.class<!fir.array<?x!fir.type<_QMtypesTt1>>>
+// CHECK:           %[[VAL_3:.*]] = arith.constant 7 : index
+// CHECK:           %[[VAL_4:.*]] = fir.array_coor %[[VAL_1]] %[[VAL_3]] : (!fir.class<!fir.array<?x!fir.type<_QMtypesTt1>>>, index) -> !fir.ref<!fir.type<_QMtypesTt1>>
+// CHECK:           %[[VAL_5:.*]] = fir.embox %[[VAL_4]] source_box %[[VAL_1]] : (!fir.ref<!fir.type<_QMtypesTt1>>, !fir.class<!fir.array<?x!fir.type<_QMtypesTt1>>>) -> !fir.class<!fir.type<_QMtypesTt1>>
+// CHECK:           return
+// CHECK:         }