[flang-commits] [flang] df3b981 - [fir] Add fir.box_rank, fir.box_addr, fir.box_dims and fir.box_elesize conversion

Valentin Clement via flang-commits flang-commits at lists.llvm.org
Wed Nov 10 06:35:30 PST 2021


Author: Valentin Clement
Date: 2021-11-10T15:35:19+01:00
New Revision: df3b9810c790cb0bfe1a8012ce4cecdfea3c99e3

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

LOG: [fir] Add fir.box_rank, fir.box_addr, fir.box_dims and fir.box_elesize conversion

This patch adds conversion for basic box operations that extract
information from the box.

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

Reviewed By: awarzynski

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

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

Added: 
    

Modified: 
    flang/lib/Optimizer/CodeGen/CodeGen.cpp
    flang/lib/Optimizer/CodeGen/TypeConverter.h
    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 6d48354f9728..1fbe76bd1945 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -42,6 +42,88 @@ class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
     return lowerTy().convertType(ty);
   }
 
+  mlir::LLVM::ConstantOp
+  genConstantOffset(mlir::Location loc,
+                    mlir::ConversionPatternRewriter &rewriter,
+                    int offset) const {
+    auto ity = lowerTy().offsetType();
+    auto cattr = rewriter.getI32IntegerAttr(offset);
+    return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
+  }
+
+  /// Construct code sequence to get the rank from a box.
+  mlir::Value getRankFromBox(mlir::Location loc, mlir::Value box,
+                             mlir::Type resultTy,
+                             mlir::ConversionPatternRewriter &rewriter) const {
+    mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
+    mlir::LLVM::ConstantOp cRank =
+        genConstantOffset(loc, rewriter, kRankPosInBox);
+    auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
+    auto p = rewriter.create<mlir::LLVM::GEPOp>(
+        loc, pty, mlir::ValueRange{box, c0, cRank});
+    return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
+  }
+
+  /// Method to construct code sequence to get the triple for dimension `dim`
+  /// from a box.
+  SmallVector<mlir::Value, 3>
+  getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys,
+                 mlir::Value box, mlir::Value dim,
+                 mlir::ConversionPatternRewriter &rewriter) const {
+    mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
+    mlir::LLVM::ConstantOp cDims =
+        genConstantOffset(loc, rewriter, kDimsPosInBox);
+    mlir::LLVM::LoadOp l0 =
+        loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
+    mlir::LLVM::LoadOp l1 =
+        loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
+    mlir::LLVM::LoadOp l2 =
+        loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
+    return {l0.getResult(), l1.getResult(), l2.getResult()};
+  }
+
+  mlir::LLVM::LoadOp
+  loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
+                 mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
+                 mlir::Type ty,
+                 mlir::ConversionPatternRewriter &rewriter) const {
+    auto pty = mlir::LLVM::LLVMPointerType::get(ty);
+    mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
+    mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
+    return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
+  }
+
+  /// Read base address from a fir.box. Returned address has type ty.
+  mlir::Value
+  loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
+                      mlir::ConversionPatternRewriter &rewriter) const {
+    mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
+    mlir::LLVM::ConstantOp cAddr =
+        genConstantOffset(loc, rewriter, kAddrPosInBox);
+    auto pty = mlir::LLVM::LLVMPointerType::get(ty);
+    mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
+    return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
+  }
+
+  mlir::Value
+  loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
+                         mlir::ConversionPatternRewriter &rewriter) const {
+    mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
+    mlir::LLVM::ConstantOp cElemLen =
+        genConstantOffset(loc, rewriter, kElemLenPosInBox);
+    auto pty = mlir::LLVM::LLVMPointerType::get(ty);
+    mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
+    return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
+  }
+
+  template <typename... ARGS>
+  mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
+                           mlir::ConversionPatternRewriter &rewriter,
+                           mlir::Value base, ARGS... args) const {
+    SmallVector<mlir::Value> cv{args...};
+    return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
+  }
+
   fir::LLVMTypeConverter &lowerTy() const {
     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
   }
@@ -80,6 +162,84 @@ struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
   }
 };
 
+/// Lower `fir.box_addr` to the sequence of operations to extract the first
+/// element of the box.
+struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
+  using FIROpConversion::FIROpConversion;
+
+  mlir::LogicalResult
+  matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
+                  mlir::ConversionPatternRewriter &rewriter) const override {
+    mlir::Value a = adaptor.getOperands()[0];
+    auto loc = boxaddr.getLoc();
+    mlir::Type ty = convertType(boxaddr.getType());
+    if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) {
+      rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
+    } else {
+      auto c0attr = rewriter.getI32IntegerAttr(0);
+      auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
+      rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
+                                                              c0);
+    }
+    return success();
+  }
+};
+
+/// Lower `fir.box_dims` to a sequence of operations to extract the requested
+/// dimension infomartion from the boxed value.
+/// Result in a triple set of GEPs and loads.
+struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
+  using FIROpConversion::FIROpConversion;
+
+  mlir::LogicalResult
+  matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
+                  mlir::ConversionPatternRewriter &rewriter) const override {
+    SmallVector<mlir::Type, 3> resultTypes = {
+        convertType(boxdims.getResult(0).getType()),
+        convertType(boxdims.getResult(1).getType()),
+        convertType(boxdims.getResult(2).getType()),
+    };
+    auto results =
+        getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
+                       adaptor.getOperands()[1], rewriter);
+    rewriter.replaceOp(boxdims, results);
+    return success();
+  }
+};
+
+/// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
+/// an element in the boxed value.
+struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
+  using FIROpConversion::FIROpConversion;
+
+  mlir::LogicalResult
+  matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
+                  mlir::ConversionPatternRewriter &rewriter) const override {
+    mlir::Value a = adaptor.getOperands()[0];
+    auto loc = boxelesz.getLoc();
+    auto ty = convertType(boxelesz.getType());
+    rewriter.replaceOp(boxelesz, loadElementSizeFromBox(loc, ty, a, rewriter));
+    return success();
+  }
+};
+
+/// Lower `fir.box_rank` to the sequence of operation to extract the rank from
+/// the box.
+struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
+  using FIROpConversion::FIROpConversion;
+
+  mlir::LogicalResult
+  matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
+                  mlir::ConversionPatternRewriter &rewriter) const override {
+    mlir::Value a = adaptor.getOperands()[0];
+    auto loc = boxrank.getLoc();
+    mlir::Type ty = convertType(boxrank.getType());
+    auto result = getRankFromBox(loc, a, ty, rewriter);
+    rewriter.replaceOp(boxrank, result);
+    return success();
+  }
+};
+
 // `fir.call` -> `llvm.call`
 struct CallOpConversion : public FIROpConversion<fir::CallOp> {
   using FIROpConversion::FIROpConversion;
@@ -835,14 +995,16 @@ class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
     auto *context = getModule().getContext();
     fir::LLVMTypeConverter typeConverter{getModule()};
     mlir::OwningRewritePatternList pattern(context);
-    pattern.insert<AddcOpConversion, AddrOfOpConversion, CallOpConversion,
-                   ConvertOpConversion, DivcOpConversion,
-                   ExtractValueOpConversion, HasValueOpConversion,
-                   GlobalOpConversion, InsertOnRangeOpConversion,
-                   InsertValueOpConversion, LoadOpConversion, NegcOpConversion,
-                   MulcOpConversion, SelectOpConversion, SelectRankOpConversion,
-                   StoreOpConversion, SubcOpConversion, UndefOpConversion,
-                   UnreachableOpConversion, ZeroOpConversion>(typeConverter);
+    pattern.insert<
+        AddcOpConversion, AddrOfOpConversion, BoxAddrOpConversion,
+        BoxDimsOpConversion, BoxEleSizeOpConversion, 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 39e774bdcd7e..859074e55d5a 100644
--- a/flang/lib/Optimizer/CodeGen/TypeConverter.h
+++ b/flang/lib/Optimizer/CodeGen/TypeConverter.h
@@ -79,6 +79,10 @@ class LLVMTypeConverter : public mlir::LLVMTypeConverter {
     });
   }
 
+  // i32 is used here because LLVM wants i32 constants when indexing into struct
+  // types. Indexing into other aggregate types is more flexible.
+  mlir::Type offsetType() { return mlir::IntegerType::get(&getContext(), 32); }
+
   // fir.type<name(p : TY'...){f : TY...}>  -->  llvm<"%name = { ty... }">
   mlir::Type convertRecordType(fir::RecordType derived) {
     auto name = derived.getName();

diff  --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir
index 91a23d33172e..902993342c85 100644
--- a/flang/test/Fir/convert-to-llvm.fir
+++ b/flang/test/Fir/convert-to-llvm.fir
@@ -686,3 +686,80 @@ func @test_load_box(%addr : !fir.ref<!fir.box<!fir.array<10xf32>>>) {
 // CHECK-SAME: (%{{.*}}: !llvm.ptr<struct<(ptr<array<10 x f{{.*}}>>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>)>>) {
 // CHECK-NEXT:  llvm.return
 // CHECK-NEXT:  }
+
+// -----
+
+// Test `fir.box_rank` conversion.
+
+func @extract_rank(%arg0: !fir.box<!fir.array<*:f64>>) -> i32 {
+  %0 = fir.box_rank %arg0 : (!fir.box<!fir.array<*:f64>>) -> i32
+  return %0 : i32
+}
+
+// CHECK-LABEL: llvm.func @extract_rank(
+// CHECK-SAME:                          %[[ARG0:.*]]: !llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) -> i32
+// CHECK:         %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32
+// CHECK:         %[[CRANK:.*]] = llvm.mlir.constant(3 : i32) : i32
+// CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[CRANK]]] : (!llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32) -> !llvm.ptr<i32>
+// CHECK:         %[[RANK:.*]] = llvm.load %[[GEP]] : !llvm.ptr<i32>
+// CHECK:         llvm.return %[[RANK]] : i32
+
+// -----
+
+// Test `fir.box_addr` conversion.
+
+func @extract_addr(%arg0: !fir.box<!fir.array<*:f64>>) -> !fir.ref<f64> {
+  %0 = fir.box_addr %arg0 : (!fir.box<!fir.array<*:f64>>) -> !fir.ref<f64>
+  return %0 : !fir.ref<f64>
+}
+
+// CHECK-LABEL: llvm.func @extract_addr(
+// CHECK-SAME:                          %[[ARG0:.*]]: !llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) -> !llvm.ptr<f64>
+// CHECK:         %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32
+// CHECK:         %[[CADDR:.*]] = llvm.mlir.constant(0 : i32) : i32
+// CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[CADDR]]] : (!llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32) -> !llvm.ptr<ptr<f64>>
+// CHECK:         %[[ADDR:.*]] = llvm.load %[[GEP]] : !llvm.ptr<ptr<f64>>
+// CHECK:         llvm.return %[[ADDR]] : !llvm.ptr<f64>
+
+// -----
+
+// Test `fir.box_dims` conversion.
+
+func @extract_dims(%arg0: !fir.box<!fir.array<*:f64>>) -> index {
+  %c1 = arith.constant 0 : i32
+  %0:3 = fir.box_dims %arg0, %c1 : (!fir.box<!fir.array<*:f64>>, i32) -> (index, index, index)
+  return %0 : index
+}
+
+// CHECK-LABEL: llvm.func @extract_dims(
+// CHECK-SAME:                          %[[ARG0:.*]]: !llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) -> i64
+// CHECK:         %[[C0_1:.*]] = llvm.mlir.constant(0 : i32) : i32
+// CHECK:         %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32
+// CHECK:         %[[CDIMS:.*]] = llvm.mlir.constant(7 : i32) : i32
+// CHECK:         %[[C0_2:.*]] = llvm.mlir.constant(0 : i32) : i32
+// CHECK:         %[[GEP0:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[CDIMS]], %[[C0_1]], %[[C0_2]]] : (!llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32, i32, i32) -> !llvm.ptr<i64>
+// CHECK:         %[[LOAD0:.*]] = llvm.load %[[GEP0]] : !llvm.ptr<i64>
+// CHECK:         %[[C1:.*]] = llvm.mlir.constant(1 : i32) : i32
+// CHECK:         %[[GEP1:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[CDIMS]], %[[C0_1]], %[[C1]]] : (!llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32, i32, i32) -> !llvm.ptr<i64>
+// CHECK:         %[[LOAD1:.*]] = llvm.load %[[GEP1]] : !llvm.ptr<i64>
+// CHECK:         %[[C2:.*]] = llvm.mlir.constant(2 : i32) : i32
+// CHECK:         %[[GEP2:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[CDIMS]], %[[C0_1]], %[[C2]]] : (!llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32, i32, i32) -> !llvm.ptr<i64>
+// CHECK:         %[[LOAD2:.*]] = llvm.load %[[GEP2]] : !llvm.ptr<i64>
+// CHECK:         llvm.return %[[LOAD0]] : i64
+
+// -----
+
+// Test `fir.box_elesize` conversion.
+
+func @extract_elesize(%arg0: !fir.box<f32>) -> i32 {
+  %0 = fir.box_elesize %arg0 : (!fir.box<f32>) -> i32
+  return %0 : i32
+}
+
+// CHECK-LABEL: llvm.func @extract_elesize(
+// CHECK-SAME:                             %[[ARG0:.*]]: !llvm.ptr<struct<(ptr<f32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) -> i32
+// CHECK:         %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32
+// CHECK:         %[[CELESIZE:.*]] = llvm.mlir.constant(1 : i32) : i32
+// CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[CELESIZE]]] : (!llvm.ptr<struct<(ptr<f32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32) -> !llvm.ptr<i32>
+// CHECK:         %[[ELE_SIZE:.*]] = llvm.load %[[GEP]] : !llvm.ptr<i32>
+// CHECK:         llvm.return %[[ELE_SIZE]] : i32


        


More information about the flang-commits mailing list