[flang-commits] [flang] 420ad7c - [flang][CodeGen] Transform `IsPresentOpConversion` and `AbsentOpConversion`
Andrzej Warzynski via flang-commits
flang-commits at lists.llvm.org
Thu Nov 11 10:08:12 PST 2021
Author: Andrzej Warzynski
Date: 2021-11-11T18:07:51Z
New Revision: 420ad7ce7d5a9a10224efd8045abc0e85af972d9
URL: https://github.com/llvm/llvm-project/commit/420ad7ce7d5a9a10224efd8045abc0e85af972d9
DIFF: https://github.com/llvm/llvm-project/commit/420ad7ce7d5a9a10224efd8045abc0e85af972d9.diff
LOG: [flang][CodeGen] Transform `IsPresentOpConversion` and `AbsentOpConversion`
This patch extends the `FIRToLLVMLowering` pass in Flang by adding
hooks to transform `fir.is_present` and `fir.absent` to the LLVM dialect
of MLIR.
This is part of the upstreaming effort from the `fir-dev` branch in [1].
[1] https://github.com/flang-compiler/f18-llvm-project
Differential Revision: https://reviews.llvm.org/D113395
Originally written by:
Co-authored-by: Jean Perier <jperier at nvidia.com>
Co-authored-by: Eric Schweitz <eschweitz at nvidia.com>
Added:
Modified:
flang/lib/Optimizer/CodeGen/CodeGen.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 fe43d2e8f190..65f044ce58e6 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -206,6 +206,34 @@ class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
mlir::ConversionPatternRewriter &rewriter) const = 0;
};
+/// Create value signaling an absent optional argument in a call, e.g.
+/// `fir.absent !fir.ref<i64>` --> `llvm.mlir.null : !llvm.ptr<i64>`
+struct AbsentOpConversion : public FIROpConversion<fir::AbsentOp> {
+ using FIROpConversion::FIROpConversion;
+
+ mlir::LogicalResult
+ matchAndRewrite(fir::AbsentOp absent, OpAdaptor,
+ mlir::ConversionPatternRewriter &rewriter) const override {
+ mlir::Type ty = convertType(absent.getType());
+ mlir::Location loc = absent.getLoc();
+
+ if (absent.getType().isa<fir::BoxCharType>()) {
+ auto structTy = ty.cast<mlir::LLVM::LLVMStructType>();
+ assert(!structTy.isOpaque() && !structTy.getBody().empty());
+ auto undefStruct = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
+ auto nullField =
+ rewriter.create<mlir::LLVM::NullOp>(loc, structTy.getBody()[0]);
+ mlir::MLIRContext *ctx = absent.getContext();
+ auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
+ rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
+ absent, ty, undefStruct, nullField, c0);
+ } else {
+ rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(absent, ty);
+ }
+ return success();
+ }
+};
+
// Lower `fir.address_of` operation to `llvm.address_of` operation.
struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
using FIROpConversion::FIROpConversion;
@@ -1326,6 +1354,40 @@ struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
}
};
+/// `fir.is_present` -->
+/// ```
+/// %0 = llvm.mlir.constant(0 : i64)
+/// %1 = llvm.ptrtoint %0
+/// %2 = llvm.icmp "ne" %1, %0 : i64
+/// ```
+struct IsPresentOpConversion : public FIROpConversion<fir::IsPresentOp> {
+ using FIROpConversion::FIROpConversion;
+
+ mlir::LogicalResult
+ matchAndRewrite(fir::IsPresentOp isPresent, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const override {
+ mlir::Type idxTy = lowerTy().indexType();
+ mlir::Location loc = isPresent.getLoc();
+ auto ptr = adaptor.getOperands()[0];
+
+ if (isPresent.val().getType().isa<fir::BoxCharType>()) {
+ auto structTy = ptr.getType().cast<mlir::LLVM::LLVMStructType>();
+ assert(!structTy.isOpaque() && !structTy.getBody().empty());
+
+ mlir::Type ty = structTy.getBody()[0];
+ mlir::MLIRContext *ctx = isPresent.getContext();
+ auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
+ ptr = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, ptr, c0);
+ }
+ mlir::LLVM::ConstantOp c0 =
+ genConstantIndex(isPresent.getLoc(), idxTy, rewriter, 0);
+ auto addr = rewriter.create<mlir::LLVM::PtrToIntOp>(loc, idxTy, ptr);
+ rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
+ isPresent, mlir::LLVM::ICmpPredicate::ne, addr, c0);
+
+ return success();
+ }
+};
} // namespace
namespace {
@@ -1349,17 +1411,18 @@ class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
fir::LLVMTypeConverter typeConverter{getModule()};
mlir::OwningRewritePatternList pattern(context);
pattern.insert<
- AddcOpConversion, AddrOfOpConversion, AllocaOpConversion,
- BoxAddrOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
- BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
- BoxRankOpConversion, CallOpConversion, ConvertOpConversion,
- DispatchOpConversion, DispatchTableOpConversion, DTEntryOpConversion,
- DivcOpConversion, ExtractValueOpConversion, HasValueOpConversion,
- GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
- LoadOpConversion, NegcOpConversion, MulcOpConversion,
- SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion,
- StoreOpConversion, SubcOpConversion, UndefOpConversion,
- UnreachableOpConversion, ZeroOpConversion>(typeConverter);
+ AbsentOpConversion, AddcOpConversion, AddrOfOpConversion,
+ AllocaOpConversion, BoxAddrOpConversion, BoxDimsOpConversion,
+ BoxEleSizeOpConversion, BoxIsAllocOpConversion, BoxIsArrayOpConversion,
+ BoxIsPtrOpConversion, BoxRankOpConversion, CallOpConversion,
+ ConvertOpConversion, DispatchOpConversion, DispatchTableOpConversion,
+ DTEntryOpConversion, DivcOpConversion, ExtractValueOpConversion,
+ HasValueOpConversion, GlobalOpConversion, InsertOnRangeOpConversion,
+ InsertValueOpConversion, IsPresentOpConversion, LoadOpConversion,
+ NegcOpConversion, MulcOpConversion, SelectCaseOpConversion,
+ SelectOpConversion, SelectRankOpConversion, StoreOpConversion,
+ SubcOpConversion, UndefOpConversion, UnreachableOpConversion,
+ ZeroOpConversion>(typeConverter);
mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
pattern);
diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir
index 2fd748422207..743a9facc7ec 100644
--- a/flang/test/Fir/convert-to-llvm.fir
+++ b/flang/test/Fir/convert-to-llvm.fir
@@ -1113,3 +1113,87 @@ func @select_case_logical(%arg0: !fir.ref<!fir.logical<4>>) {
// CHECK: llvm.br ^bb5
// CHECK-LABEL: ^bb5:
// CHECK: llvm.return
+
+// -----
+
+// Test `fir.is_present`
+
+func @test_is_present_i64(%arg0: !fir.ref<i64>) -> () {
+ %0 = fir.is_present %arg0 : (!fir.ref<i64>) -> i1
+ return
+}
+
+// CHECK-LABEL: @test_is_present_i64
+// CHECK-SAME: (%[[arg:.*]]: !llvm.ptr<i64>)
+// CHECK-NEXT: %[[constant:.*]] = llvm.mlir.constant(0 : i64) : i64
+// CHECK-NEXT: %[[ptr:.*]] = llvm.ptrtoint %[[arg]] : !llvm.ptr<i64> to i64
+// CHECK-NEXT: %{{.*}} = llvm.icmp "ne" %[[ptr]], %[[constant]] : i64
+// CHECK-NEXT: llvm.return
+// CHECK-NEXT: }
+
+func @test_is_present_box(%arg0: !fir.box<!fir.ref<i64>>) -> () {
+ %0 = fir.is_present %arg0 : (!fir.box<!fir.ref<i64>>) -> i1
+ return
+}
+
+// CHECK-LABEL: @test_is_present_box
+// CHECK-SAME: (%[[arg:.*]]: !llvm.ptr<struct<(ptr<i64>, i64, i32, i8, i8, i8, i8)>>)
+// CHECK-NEXT: %[[constant:.*]] = llvm.mlir.constant(0 : i64) : i64
+// CHECK-NEXT: %[[ptr:.*]] = llvm.ptrtoint %[[arg]] : !llvm.ptr<struct<(ptr<i64>, i64, i32, i8, i8, i8, i8)>> to i64
+// CHECK-NEXT: %{{.*}} = llvm.icmp "ne" %[[ptr]], %[[constant]] : i64
+// CHECK-NEXT: llvm.return
+// CHECK-NEXT: }
+
+
+// -----
+
+// Test `fir.absent`
+
+func @test_absent_i64() -> () {
+ %0 = fir.absent !fir.ref<i64>
+ return
+}
+
+// CHECK-LABEL: @test_absent_i64
+// CHECK-NEXT: %{{.*}} = llvm.mlir.null : !llvm.ptr<i64>
+// CHECK-NEXT: llvm.return
+// CHECK-NEXT: }
+
+func @test_absent_box() -> () {
+ %0 = fir.absent !fir.box<!fir.array<?xf32>>
+ return
+}
+// CHECK-LABEL: @test_absent_box
+// CHECK-NEXT: %{{.*}} = llvm.mlir.null : !llvm.ptr<struct<(ptr<f32>, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>>
+// CHECK-NEXT: llvm.return
+// CHECK-NEXT: }
+
+// -----
+
+// This is a bit more comprehensive test for `fir.is_present` and `fir.absent`
+// when used together
+
+func @is_present(%arg0: !fir.ref<i64>) -> i1 {
+ %0 = fir.is_present %arg0 : (!fir.ref<i64>) -> i1
+ return %0 : i1
+}
+
+// CHECK-LABEL: @is_present
+// CHECK-SAME: (%[[arg:.*]]: !llvm.ptr<i64>) -> i1
+// CHECK-NEXT: %[[constant:.*]] = llvm.mlir.constant(0 : i64) : i64
+// CHECK-NEXT: %[[ptr:.*]] = llvm.ptrtoint %[[arg]] : !llvm.ptr<i64> to i64
+// CHECK-NEXT: %[[ret_val:.*]] = llvm.icmp "ne" %[[ptr]], %[[constant]] : i64
+// CHECK-NEXT: llvm.return %[[ret_val]] : i1
+// CHECK-NEXT: }
+
+func @absent() -> i1 {
+ %0 = fir.absent !fir.ref<i64>
+ %1 = fir.call @is_present(%0) : (!fir.ref<i64>) -> i1
+ return %1 : i1
+}
+
+// CHECK-LABEL: @absent
+// CHECK-SAME: () -> i1
+// CHECK-NEXT: %[[ptr:.*]] = llvm.mlir.null : !llvm.ptr<i64>
+// CHECK-NEXT: %[[ret_val:.*]] = llvm.call @is_present(%[[ptr]]) : (!llvm.ptr<i64>) -> i1
+// CHECK-NEXT: llvm.return %[[ret_val]] : i1
More information about the flang-commits
mailing list