[fir] Add fir.box type conversion
authorValentin Clement <clementval@gmail.com>
Mon, 8 Nov 2021 13:17:26 +0000 (14:17 +0100)
committerValentin Clement <clementval@gmail.com>
Mon, 8 Nov 2021 13:18:11 +0000 (14:18 +0100)
This patch add the `!fir.box` type conversion to llvm.
`fir.box` is converted to the descriptor as defined in the ISO_Fortran_binding.h
and the addendum defined in descriptor.h.

This patch is part of the upstreaming effort from fir-dev branch.

Reviewed By: awarzynski

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

Co-authored-by: Jean Perier <jperier@nvidia.com>
Co-authored-by: Eric Schweitz <eschweitz@nvidia.com>
Co-authored-by: V Donaldson <vdonaldson@nvidia.com>
flang/lib/Optimizer/CodeGen/TypeConverter.h
flang/test/Fir/types-to-llvm.fir

index 9f0b5b299e9175f87b7054a604258838fecb9823..9067af7dd99b00d160088defebe24203b7e63ba0 100644 (file)
@@ -29,6 +29,7 @@ public:
     LLVM_DEBUG(llvm::dbgs() << "FIR type converter\n");
 
     // Each conversion should return a value of type mlir::Type.
+    addConversion([&](BoxType box) { return convertBoxType(box); });
     addConversion(
         [&](fir::RecordType derived) { return convertRecordType(derived); });
     addConversion(
@@ -60,6 +61,78 @@ public:
     return mlir::Type();
   }
 
+  // Is an extended descriptor needed given the element type of a fir.box type ?
+  // Extended descriptors are required for derived types.
+  bool requiresExtendedDesc(mlir::Type boxElementType) {
+    auto eleTy = fir::unwrapSequenceType(boxElementType);
+    return eleTy.isa<fir::RecordType>();
+  }
+
+  // Magic value to indicate we do not know the rank of an entity, either
+  // because it is assumed rank or because we have not determined it yet.
+  static constexpr int unknownRank() { return -1; }
+
+  // This corresponds to the descriptor as defined in ISO_Fortran_binding.h and
+  // the addendum defined in descriptor.h.
+  mlir::Type convertBoxType(BoxType box, int rank = unknownRank()) {
+    // (base_addr*, elem_len, version, rank, type, attribute, f18Addendum, [dim]
+    SmallVector<mlir::Type> dataDescFields;
+    mlir::Type ele = box.getEleTy();
+    // remove fir.heap/fir.ref/fir.ptr
+    if (auto removeIndirection = fir::dyn_cast_ptrEleTy(ele))
+      ele = removeIndirection;
+    auto eleTy = convertType(ele);
+    // base_addr*
+    if (ele.isa<SequenceType>() && eleTy.isa<mlir::LLVM::LLVMPointerType>())
+      dataDescFields.push_back(eleTy);
+    else
+      dataDescFields.push_back(mlir::LLVM::LLVMPointerType::get(eleTy));
+    // elem_len
+    dataDescFields.push_back(getDescFieldTypeModel<1>()(&getContext()));
+    // version
+    dataDescFields.push_back(getDescFieldTypeModel<2>()(&getContext()));
+    // rank
+    dataDescFields.push_back(getDescFieldTypeModel<3>()(&getContext()));
+    // type
+    dataDescFields.push_back(getDescFieldTypeModel<4>()(&getContext()));
+    // attribute
+    dataDescFields.push_back(getDescFieldTypeModel<5>()(&getContext()));
+    // f18Addendum
+    dataDescFields.push_back(getDescFieldTypeModel<6>()(&getContext()));
+    // [dims]
+    if (rank == unknownRank()) {
+      if (auto seqTy = ele.dyn_cast<SequenceType>())
+        rank = seqTy.getDimension();
+      else
+        rank = 0;
+    }
+    if (rank > 0) {
+      auto rowTy = getDescFieldTypeModel<7>()(&getContext());
+      dataDescFields.push_back(mlir::LLVM::LLVMArrayType::get(rowTy, rank));
+    }
+    // opt-type-ptr: i8* (see fir.tdesc)
+    if (requiresExtendedDesc(ele)) {
+      dataDescFields.push_back(
+          getExtendedDescFieldTypeModel<8>()(&getContext()));
+      auto rowTy = getExtendedDescFieldTypeModel<9>()(&getContext());
+      dataDescFields.push_back(mlir::LLVM::LLVMArrayType::get(rowTy, 1));
+      if (auto recTy = fir::unwrapSequenceType(ele).dyn_cast<fir::RecordType>())
+        if (recTy.getNumLenParams() > 0) {
+          // The descriptor design needs to be clarified regarding the number of
+          // length parameters in the addendum. Since it can change for
+          // polymorphic allocatables, it seems all length parameters cannot
+          // always possibly be placed in the addendum.
+          TODO_NOLOC("extended descriptor derived with length parameters");
+          unsigned numLenParams = recTy.getNumLenParams();
+          dataDescFields.push_back(
+              mlir::LLVM::LLVMArrayType::get(rowTy, numLenParams));
+        }
+    }
+    return mlir::LLVM::LLVMPointerType::get(
+        mlir::LLVM::LLVMStructType::getLiteral(&getContext(), dataDescFields,
+                                               /*isPacked=*/false));
+  }
+
   template <typename A>
   mlir::Type convertPointerLike(A &ty) {
     mlir::Type eleTy = ty.getEleTy();
index 5817b2cce90b0822bdd79d9bde473099240b45a5..8ddee11f3b9da3b214f41ff24101e112a5e1ce5b 100644 (file)
@@ -29,3 +29,22 @@ func private @foo1(%arg0: !fir.ref<!fir.array<10xf32>>)
 // CHECK-LABEL: foo1
 // CHECK-SAME: !llvm.ptr<array<10 x f32>>
 
+// -----
+
+// Test box types `!fir.box`
+
+func private @foo0(%arg0: !fir.box<!fir.array<?xf32>>)
+// CHECK-LABEL: foo0
+// CHECK-SAME: !llvm.ptr<struct<(ptr<f32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>)>>
+
+func private @foo1(%arg0: !fir.box<!fir.array<10xf32>>)
+// CHECK-LABEL: foo1
+// CHECK-SAME: !llvm.ptr<struct<(ptr<array<10 x f32>>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>)>>
+
+func private @foo2(%arg0: !fir.box<!fir.ref<i64>>)
+// CHECK-LABEL: foo2
+// CHECK-SAME: !llvm.ptr<struct<(ptr<i64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>
+
+func private @foo3(%arg0: !fir.box<!fir.type<derived{f:f32}>>)
+// CHECK-LABEL: foo3
+// CHECK-SAME: !llvm.ptr<struct<(ptr<struct<"derived", (f32)>>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr<i{{.*}}>, array<1 x i{{.*}}>)>>