[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