[flang-commits] [flang] 1e6d9c0 - [fir] Add !fir.alloca conversion

Diana Picus via flang-commits flang-commits at lists.llvm.org
Thu Nov 11 03:28:03 PST 2021


Author: Diana Picus
Date: 2021-11-11T11:26:33Z
New Revision: 1e6d9c06a5d20b65499b74a891a0e79cada3803e

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

LOG: [fir] Add !fir.alloca conversion

Convert !fir.alloca into !llvm.alloca.

This also contains a fix for verifyInType in FIROps.cpp, to make sure we
can handle a !fir.ptr<!fir.array<?xN>>.

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

Co-authored-by: Eric Schweitz <eschweitz at nvidia.com>
Co-authored-by: Jean Perier <jperier at nvidia.com>

Added: 
    

Modified: 
    flang/lib/Optimizer/CodeGen/CodeGen.cpp
    flang/lib/Optimizer/CodeGen/TypeConverter.h
    flang/lib/Optimizer/Dialect/FIROps.cpp
    flang/test/Fir/convert-to-llvm.fir

Removed: 
    


################################################################################
diff  --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 6018429ac51c..a95306983ae1 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -32,6 +32,14 @@
 static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
 static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
 
+static mlir::LLVM::ConstantOp
+genConstantIndex(mlir::Location loc, mlir::Type ity,
+                 mlir::ConversionPatternRewriter &rewriter,
+                 std::int64_t offset) {
+  auto cattr = rewriter.getI64IntegerAttr(offset);
+  return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
+}
+
 namespace {
 /// FIR conversion pattern template
 template <typename FromOp>
@@ -145,6 +153,27 @@ class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
   }
 
+  /// Perform an extension or truncation as needed on an integer value. Lowering
+  /// to the specific target may involve some sign-extending or truncation of
+  /// values, particularly to fit them from abstract box types to the
+  /// appropriate reified structures.
+  mlir::Value integerCast(mlir::Location loc,
+                          mlir::ConversionPatternRewriter &rewriter,
+                          mlir::Type ty, mlir::Value val) const {
+    auto valTy = val.getType();
+    // If the value was not yet lowered, lower its type so that it can
+    // be used in getPrimitiveTypeSizeInBits.
+    if (!valTy.isa<mlir::IntegerType>())
+      valTy = convertType(valTy);
+    auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
+    auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
+    if (toSize < fromSize)
+      return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
+    if (toSize > fromSize)
+      return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
+    return val;
+  }
+
   fir::LLVMTypeConverter &lowerTy() const {
     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
   }
@@ -182,6 +211,92 @@ struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
     return success();
   }
 };
+} // namespace
+
+/// Lookup the function to compute the memory size of this parametric derived
+/// type. The size of the object may depend on the LEN type parameters of the
+/// derived type.
+static mlir::LLVM::LLVMFuncOp
+getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
+                          mlir::ConversionPatternRewriter &rewriter) {
+  auto module = op->getParentOfType<mlir::ModuleOp>();
+  std::string name = recTy.getName().str() + "P.mem.size";
+  return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name);
+}
+
+namespace {
+/// convert to LLVM IR dialect `alloca`
+struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
+  using FIROpConversion::FIROpConversion;
+
+  mlir::LogicalResult
+  matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
+                  mlir::ConversionPatternRewriter &rewriter) const override {
+    mlir::ValueRange operands = adaptor.getOperands();
+    auto loc = alloc.getLoc();
+    mlir::Type ity = lowerTy().indexType();
+    unsigned i = 0;
+    mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
+    mlir::Type ty = convertType(alloc.getType());
+    mlir::Type resultTy = ty;
+    if (alloc.hasLenParams()) {
+      unsigned end = alloc.numLenParams();
+      llvm::SmallVector<mlir::Value> lenParams;
+      for (; i < end; ++i)
+        lenParams.push_back(operands[i]);
+      mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
+      if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
+        fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
+            chrTy.getContext(), chrTy.getFKind());
+        ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
+        assert(end == 1);
+        size = integerCast(loc, rewriter, ity, lenParams[0]);
+      } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
+        mlir::LLVM::LLVMFuncOp memSizeFn =
+            getDependentTypeMemSizeFn(recTy, alloc, rewriter);
+        if (!memSizeFn)
+          emitError(loc, "did not find allocation function");
+        mlir::NamedAttribute attr = rewriter.getNamedAttr(
+            "callee", mlir::SymbolRefAttr::get(memSizeFn));
+        auto call = rewriter.create<mlir::LLVM::CallOp>(
+            loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
+        size = call.getResult(0);
+        ty = mlir::LLVM::LLVMPointerType::get(
+            mlir::IntegerType::get(alloc.getContext(), 8));
+      } else {
+        return emitError(loc, "unexpected type ")
+               << scalarType << " with type parameters";
+      }
+    }
+    if (alloc.hasShapeOperands()) {
+      mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType());
+      // Scale the size by constant factors encoded in the array type.
+      if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) {
+        fir::SequenceType::Extent constSize = 1;
+        for (auto extent : seqTy.getShape())
+          if (extent != fir::SequenceType::getUnknownExtent())
+            constSize *= extent;
+        mlir::Value constVal{
+            genConstantIndex(loc, ity, rewriter, constSize).getResult()};
+        size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal);
+      }
+      unsigned end = operands.size();
+      for (; i < end; ++i)
+        size = rewriter.create<mlir::LLVM::MulOp>(
+            loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
+    }
+    if (ty == resultTy) {
+      // Do not emit the bitcast if ty and resultTy are the same.
+      rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
+                                                        alloc->getAttrs());
+    } else {
+      auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
+                                                      alloc->getAttrs());
+      rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
+    }
+    return success();
+  }
+};
 
 /// Lower `fir.box_addr` to the sequence of operations to extract the first
 /// element of the box.
@@ -1070,16 +1185,16 @@ class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
     fir::LLVMTypeConverter typeConverter{getModule()};
     mlir::OwningRewritePatternList pattern(context);
     pattern.insert<
-        AddcOpConversion, AddrOfOpConversion, BoxAddrOpConversion,
-        BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion,
-        BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxRankOpConversion,
-        CallOpConversion, ConvertOpConversion, DivcOpConversion,
-        ExtractValueOpConversion, HasValueOpConversion, GlobalOpConversion,
-        InsertOnRangeOpConversion, InsertValueOpConversion, LoadOpConversion,
-        NegcOpConversion, MulcOpConversion, SelectOpConversion,
-        SelectRankOpConversion, StoreOpConversion, SubcOpConversion,
-        UndefOpConversion, UnreachableOpConversion, ZeroOpConversion>(
-        typeConverter);
+        AddcOpConversion, AddrOfOpConversion, AllocaOpConversion,
+        BoxAddrOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
+        BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
+        BoxRankOpConversion, CallOpConversion, ConvertOpConversion,
+        DivcOpConversion, ExtractValueOpConversion, HasValueOpConversion,
+        GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
+        LoadOpConversion, NegcOpConversion, MulcOpConversion,
+        SelectOpConversion, SelectRankOpConversion, StoreOpConversion,
+        SubcOpConversion, UndefOpConversion, UnreachableOpConversion,
+        ZeroOpConversion>(typeConverter);
     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
                                                             pattern);

diff  --git a/flang/lib/Optimizer/CodeGen/TypeConverter.h b/flang/lib/Optimizer/CodeGen/TypeConverter.h
index 21e65a2f289e..8595513c84b9 100644
--- a/flang/lib/Optimizer/CodeGen/TypeConverter.h
+++ b/flang/lib/Optimizer/CodeGen/TypeConverter.h
@@ -93,6 +93,9 @@ class LLVMTypeConverter : public mlir::LLVMTypeConverter {
   // types. Indexing into other aggregate types is more flexible.
   mlir::Type offsetType() { return mlir::IntegerType::get(&getContext(), 32); }
 
+  // i64 can be used to index into aggregates like arrays
+  mlir::Type indexType() { return mlir::IntegerType::get(&getContext(), 64); }
+
   // fir.type<name(p : TY'...){f : TY...}>  -->  llvm<"%name = { ty... }">
   mlir::Type convertRecordType(fir::RecordType derived) {
     auto name = derived.getName();

diff  --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index 62d04b30c694..dab873809bcf 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -57,8 +57,6 @@ static bool verifyInType(mlir::Type inType,
       if (verifyInType(field.second, visited))
         return true;
     visited.pop_back();
-  } else if (auto rt = inType.dyn_cast<fir::PointerType>()) {
-    return verifyInType(rt.getEleTy(), visited);
   }
   return false;
 }

diff  --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir
index 4b0fac6ad49c..08621052051e 100644
--- a/flang/test/Fir/convert-to-llvm.fir
+++ b/flang/test/Fir/convert-to-llvm.fir
@@ -329,6 +329,7 @@ func @insert_tuple(%a : tuple<i32, f32>) {
 // CHECK:         llvm.return
 
 // -----
+
 // Test `fir.call` -> `llvm.call` conversion for functions that take no arguments
 // and return nothing
 
@@ -829,3 +830,134 @@ func @box_isptr(%arg0: !fir.box<!fir.array<*:f64>>) -> i1 {
 // CHECK:         %[[CMP_C0:.*]] = llvm.mlir.constant(0 : i32) : i32
 // CHECK:         %[[IS_ALLOC:.*]] = llvm.icmp "ne" %[[AND]], %[[CMP_C0]] : i32
 // CHECK:         llvm.return %[[IS_ALLOC]] : i1
+
+// -----
+
+// Test fir.alloca of one element
+
+func @alloca_one() -> !fir.ref<i32> {
+  %1 = fir.alloca i32
+  return %1 : !fir.ref<i32>
+}
+
+// CHECK-LABEL: llvm.func @alloca_one() -> !llvm.ptr<i32>
+// CHECK: [[N:%.*]] = llvm.mlir.constant(1 : i64) : i64
+// CHECK: [[A:%.*]] = llvm.alloca [[N]] x i32
+// CHECK: llvm.return [[A]] : !llvm.ptr<i32>
+
+// -----
+
+// Test fir.alloca of several elements
+
+func @alloca_several() -> !fir.ref<i32> {
+  %0 = arith.constant 100 : index
+  %1 = fir.alloca i32, %0
+  return %1 : !fir.ref<i32>
+}
+
+// CHECK-LABEL: llvm.func @alloca_several() -> !llvm.ptr<i32>
+// CHECK: [[N:%.*]] = llvm.mlir.constant(100 : index) : i64
+// CHECK: [[ONE:%.*]] = llvm.mlir.constant(1 : i64) : i64
+// CHECK: [[TOTAL:%.*]] = llvm.mul [[ONE]], [[N]] : i64
+// CHECK: [[A:%.*]] = llvm.alloca [[TOTAL]] x i32
+// CHECK: llvm.return [[A]] : !llvm.ptr<i32>
+
+// -----
+
+// Test fir.alloca of pointer to array
+
+func @alloca_ptr_to_array() -> !fir.ref<!fir.ptr<!fir.array<?xi32>>> {
+  %1 = fir.alloca !fir.ptr<!fir.array<?xi32>>
+  return %1 : !fir.ref<!fir.ptr<!fir.array<?xi32>>>
+}
+
+// CHECK-LABEL: llvm.func @alloca_ptr_to_array() -> !llvm.ptr<ptr<i32>>
+// CHECK: [[ONE:%.*]] = llvm.mlir.constant(1 : i64) : i64
+// CHECK: [[A:%.*]] = llvm.alloca [[ONE]] x !llvm.ptr<i32>
+// CHECK: llvm.return [[A]] : !llvm.ptr<ptr<i32>>
+
+// -----
+
+// Test fir.alloca of char array
+
+func @alloca_char_array(%l: i32, %e : index) -> !fir.ref<!fir.array<?x?x!fir.char<1,?>>> {
+  %a = fir.alloca !fir.array<?x?x!fir.char<1,?>>(%l : i32), %e, %e
+  return %a :  !fir.ref<!fir.array<?x?x!fir.char<1,?>>>
+}
+
+// CHECK-LABEL: llvm.func @alloca_char_array
+// CHECK-SAME: ([[L:%.*]]: i32, [[E:%.*]]: i64) -> !llvm.ptr<i8>
+// CHECK-DAG: [[UNUSEDONE:%.*]] = llvm.mlir.constant(1 : i64) : i64
+// CHECK-DAG: [[LCAST:%.*]] = llvm.sext [[L]] : i32 to i64
+// CHECK-DAG: [[ONE:%.*]] = llvm.mlir.constant(1 : i64) : i64
+// CHECK: [[PROD1:%.*]] = llvm.mul [[LCAST]], [[ONE]] : i64
+// CHECK: [[PROD2:%.*]] = llvm.mul [[PROD1]], [[E]] : i64
+// CHECK: [[PROD3:%.*]] = llvm.mul [[PROD2]], [[E]] : i64
+// CHECK: [[A:%.*]] = llvm.alloca [[PROD3]] x i8 {in_type = !fir.array<?x?x!fir.char<1,?>>
+// CHECK: return [[A]] : !llvm.ptr<i8>
+
+// -----
+
+// Test fir.alloca of record type with LEN parameters
+//   type t(p1,p2)
+//      integer, len :: p1
+//      integer(kind=2), len :: p2
+//      integer f1
+//      real f2
+//   end type t
+
+func private @_QTtP.mem.size(%0 : i32, %1 : i16) -> index
+
+func @alloca_record(%arg0 : i32, %arg1 : i16) -> !fir.ref<!fir.type<_QTt(p1:i32,p2:i16){f1:i32,f2:f32}>> {
+  %0 = fir.alloca !fir.type<_QTt(p1:i32,p2:i16){f1:i32,f2:f32}>(%arg0, %arg1 : i32, i16) {name = "_QEvar"}
+  return %0 : !fir.ref<!fir.type<_QTt(p1:i32,p2:i16){f1:i32,f2:f32}>>
+}
+
+// CHECK-LABEL: llvm.func @alloca_record
+// CHECK-SAME: ([[ARG0:%.*]]: i32, [[ARG1:%.*]]: i16)
+// CHECK-SAME: -> !llvm.ptr<struct<"_QTt", (i32, f32)>>
+// CHECK: [[SIZE:%.*]] = llvm.call @_QTtP.mem.size([[ARG0]], [[ARG1]]) : (i32, i16) -> i64
+// CHECK: [[ALLOC:%.*]] = llvm.alloca [[SIZE]] x i8
+// CHECK: [[A:%.*]] = llvm.bitcast [[ALLOC]] : !llvm.ptr<i8> to !llvm.ptr<struct<"_QTt", (i32, f32)>>
+// CHECK: llvm.return [[A]] : !llvm.ptr<struct<"_QTt", (i32, f32)>>
+
+// -----
+
+// Test fir.alloca of a multidimensional array, with operands
+
+func @alloca_multidim_array(%0 : index) -> !fir.ref<!fir.array<8x16x32xf32>> {
+  %1 = arith.constant 24 : index
+  %2 = fir.alloca !fir.array<8x16x32xf32>, %0, %1
+  return %2 : !fir.ref<!fir.array<8x16x32xf32>>
+}
+
+// CHECK-LABEL: llvm.func @alloca_multidim_array
+// CHECK-SAME: ([[OP1:%.*]]: i64) -> !llvm.ptr<array<32 x array<16 x array<8 x f32>
+// CHECK: [[OP2:%.*]] = llvm.mlir.constant(24 : index) : i64
+// CHECK: [[ONE:%.*]] = llvm.mlir.constant(1 : i64) : i64
+// CHECK: [[ALL:%.*]] = llvm.mlir.constant(4096 : i64) : i64
+// CHECK: [[MUL1:%.*]] = llvm.mul [[ONE]], [[ALL]] : i64
+// CHECK: [[MUL2:%.*]] = llvm.mul [[MUL1]], [[OP1]] : i64
+// CHECK: [[TOTAL:%.*]] = llvm.mul [[MUL2]], [[OP2]] : i64
+// CHECK: [[A:%.*]] = llvm.alloca [[TOTAL]] x !llvm.array<32 x array<16 x array<8 x f32>
+// CHECK: llvm.return [[A]] : !llvm.ptr<array<32 x array<16 x array<8 x f32>
+
+// -----
+
+// Test alloca with an array with holes.
+// Constant factor of 60 (4*3*5) must be included.
+
+func @alloca_array_with_holes(%0 : index, %1 : index) -> !fir.ref<!fir.array<4x?x3x?x5xi32>> {
+  %a = fir.alloca !fir.array<4x?x3x?x5xi32>, %0, %1
+  return %a : !fir.ref<!fir.array<4x?x3x?x5xi32>>
+}
+
+// CHECK-LABEL: llvm.func @alloca_array_with_holes
+// CHECK-SAME: ([[A:%.*]]: i64, [[B:%.*]]: i64) -> !llvm.ptr<i32>
+// CHECK-DAG: [[ONE:%.*]] = llvm.mlir.constant(1 : i64) : i64
+// CHECK-DAG: [[FIXED:%.*]] = llvm.mlir.constant(60 : i64) : i64
+// CHECK: [[PROD1:%.*]] = llvm.mul [[ONE]], [[FIXED]] : i64
+// CHECK: [[PROD2:%.*]] = llvm.mul [[PROD1]], [[A]] : i64
+// CHECK: [[PROD3:%.*]] = llvm.mul [[PROD2]], [[B]] : i64
+// CHECK: [[RES:%.*]] = llvm.alloca [[PROD3]] x i32 {in_type = !fir.array<4x?x3x?x5xi32>
+// CHECK: llvm.return [[RES]] : !llvm.ptr<i32>


        


More information about the flang-commits mailing list