[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