[flang-commits] [flang] b6e44ec - [fir] Add fir.box_isarray, fir.box_isptr and fir.box_isalloc conversion.

Valentin Clement via flang-commits flang-commits at lists.llvm.org
Thu Nov 11 01:41:15 PST 2021


Author: Valentin Clement
Date: 2021-11-11T10:41:06+01:00
New Revision: b6e44ecd6e0ab7fa3060e2d198cdd09ccda69f24

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

LOG: [fir] Add fir.box_isarray, fir.box_isptr and fir.box_isalloc conversion.

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

Reviewed By: awarzynski

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

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 1fbe76bd1945..9c9fcb204605 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -12,6 +12,7 @@
 
 #include "flang/Optimizer/CodeGen/CodeGen.h"
 #include "PassDetail.h"
+#include "flang/ISO_Fortran_binding.h"
 #include "flang/Optimizer/Dialect/FIROps.h"
 #include "flang/Optimizer/Dialect/FIRType.h"
 #include "flang/Optimizer/Support/FIRContext.h"
@@ -29,6 +30,11 @@
 // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
 #include "TypeConverter.h"
 
+/// `fir.box` attribute values as defined for CFI_attribute_t in
+/// flang/ISO_Fortran_binding.h.
+static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
+static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
+
 namespace {
 /// FIR conversion pattern template
 template <typename FromOp>
@@ -51,16 +57,17 @@ class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
     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 {
+  /// Construct code sequence to extract the specifc value from a `fir.box`.
+  mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
+                              mlir::Type resultTy,
+                              mlir::ConversionPatternRewriter &rewriter,
+                              unsigned boxValue) const {
     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
-    mlir::LLVM::ConstantOp cRank =
-        genConstantOffset(loc, rewriter, kRankPosInBox);
+    mlir::LLVM::ConstantOp cValuePos =
+        genConstantOffset(loc, rewriter, boxValue);
     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
     auto p = rewriter.create<mlir::LLVM::GEPOp>(
-        loc, pty, mlir::ValueRange{box, c0, cRank});
+        loc, pty, mlir::ValueRange{box, c0, cValuePos});
     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
   }
 
@@ -116,6 +123,23 @@ class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
   }
 
+  // Load the attribute from the \p box and perform a check against \p maskValue
+  // The final comparison is implemented as `(attribute & maskValue) != 0`.
+  mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
+                                   mlir::ConversionPatternRewriter &rewriter,
+                                   unsigned maskValue) const {
+    mlir::Type attrTy = rewriter.getI32Type();
+    mlir::Value attribute =
+        getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
+    mlir::LLVM::ConstantOp attrMask =
+        genConstantOffset(loc, rewriter, maskValue);
+    auto maskRes =
+        rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
+    mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
+    return rewriter.create<mlir::LLVM::ICmpOp>(
+        loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
+  }
+
   template <typename... ARGS>
   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
                            mlir::ConversionPatternRewriter &rewriter,
@@ -218,7 +242,60 @@ struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
     mlir::Value a = adaptor.getOperands()[0];
     auto loc = boxelesz.getLoc();
     auto ty = convertType(boxelesz.getType());
-    rewriter.replaceOp(boxelesz, loadElementSizeFromBox(loc, ty, a, rewriter));
+    auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
+    rewriter.replaceOp(boxelesz, elemSize);
+    return success();
+  }
+};
+
+/// Lower `fir.box_isalloc` to a sequence of operations to determine if the
+/// boxed value was from an ALLOCATABLE entity.
+struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
+  using FIROpConversion::FIROpConversion;
+
+  mlir::LogicalResult
+  matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
+                  mlir::ConversionPatternRewriter &rewriter) const override {
+    mlir::Value box = adaptor.getOperands()[0];
+    auto loc = boxisalloc.getLoc();
+    mlir::Value check =
+        genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
+    rewriter.replaceOp(boxisalloc, check);
+    return success();
+  }
+};
+
+/// Lower `fir.box_isarray` to a sequence of operations to determine if the
+/// boxed is an array.
+struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
+  using FIROpConversion::FIROpConversion;
+
+  mlir::LogicalResult
+  matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
+                  mlir::ConversionPatternRewriter &rewriter) const override {
+    mlir::Value a = adaptor.getOperands()[0];
+    auto loc = boxisarray.getLoc();
+    auto rank =
+        getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
+    auto c0 = genConstantOffset(loc, rewriter, 0);
+    rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
+        boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
+    return success();
+  }
+};
+
+/// Lower `fir.box_isptr` to a sequence of operations to determined if the
+/// boxed value was from a POINTER entity.
+struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
+  using FIROpConversion::FIROpConversion;
+
+  mlir::LogicalResult
+  matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
+                  mlir::ConversionPatternRewriter &rewriter) const override {
+    mlir::Value box = adaptor.getOperands()[0];
+    auto loc = boxisptr.getLoc();
+    mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
+    rewriter.replaceOp(boxisptr, check);
     return success();
   }
 };
@@ -234,7 +311,7 @@ struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
     mlir::Value a = adaptor.getOperands()[0];
     auto loc = boxrank.getLoc();
     mlir::Type ty = convertType(boxrank.getType());
-    auto result = getRankFromBox(loc, a, ty, rewriter);
+    auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
     rewriter.replaceOp(boxrank, result);
     return success();
   }
@@ -997,7 +1074,8 @@ class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
     mlir::OwningRewritePatternList pattern(context);
     pattern.insert<
         AddcOpConversion, AddrOfOpConversion, BoxAddrOpConversion,
-        BoxDimsOpConversion, BoxEleSizeOpConversion, BoxRankOpConversion,
+        BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion,
+        BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxRankOpConversion,
         CallOpConversion, ConvertOpConversion, DivcOpConversion,
         ExtractValueOpConversion, HasValueOpConversion, GlobalOpConversion,
         InsertOnRangeOpConversion, InsertValueOpConversion, LoadOpConversion,

diff  --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir
index 902993342c85..4b0fac6ad49c 100644
--- a/flang/test/Fir/convert-to-llvm.fir
+++ b/flang/test/Fir/convert-to-llvm.fir
@@ -763,3 +763,69 @@ func @extract_elesize(%arg0: !fir.box<f32>) -> 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
+
+// -----
+
+// Test `fir.box_isarray` conversion.
+// `rank` is extracted from `fir.box` and compare to 0.
+
+func @box_isarray(%arg0: !fir.box<!fir.array<*:f64>>) -> i1 {
+  %0 = fir.box_isarray %arg0 : (!fir.box<!fir.array<*:f64>>) -> i1
+  return %0 : i1
+}
+
+// CHECK-LABEL: llvm.func @box_isarray(
+// CHECK-SAME:                         %[[ARG0:.*]]: !llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) -> i1
+// CHECK:         %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32
+// CHECK:         %[[RANKPOS:.*]] = llvm.mlir.constant(3 : i32) : i32
+// CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[RANKPOS]]] : (!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:         %[[C0_ISARRAY:.*]] = llvm.mlir.constant(0 : i32) : i32
+// CHECK:         %[[IS_ARRAY:.*]] = llvm.icmp "ne" %[[RANK]], %[[C0_ISARRAY]] : i32
+// CHECK:         llvm.return %[[IS_ARRAY]] : i1
+
+// -----
+
+// Test `fir.box_isalloc` conversion.
+// `attribute` is extracted from `fir.box` and checked against a mask equal to
+// the value of `CFI_attribute_allocatable`.
+
+func @box_isalloc(%arg0: !fir.box<!fir.array<*:f64>>) -> i1 {
+  %0 = fir.box_isalloc %arg0 : (!fir.box<!fir.array<*:f64>>) -> i1
+  return %0 : i1
+}
+
+// CHECK-LABEL: llvm.func @box_isalloc(
+// CHECK-SAME:                         %[[ARG0:.*]]: !llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) -> i1
+// CHECK:         %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32
+// CHECK:         %[[ATTRPOS:.*]] = llvm.mlir.constant(5 : i32) : i32
+// CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[ATTRPOS]]] : (!llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32) -> !llvm.ptr<i32>
+// CHECK:         %[[ATTR:.*]] = llvm.load %[[GEP]] : !llvm.ptr<i32>
+// CHECK:         %[[ATTR_ISALLOC:.*]] = llvm.mlir.constant(2 : i32) : i32
+// CHECK:         %[[AND:.*]] = llvm.and %[[ATTR]], %[[ATTR_ISALLOC]]  : i32
+// 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.box_isptr` conversion.
+// `attribute` is extracted from `fir.box` and checked against a mask equal to
+// the value of `CFI_attribute_pointer`.
+
+func @box_isptr(%arg0: !fir.box<!fir.array<*:f64>>) -> i1 {
+  %0 = fir.box_isptr %arg0 : (!fir.box<!fir.array<*:f64>>) -> i1
+  return %0 : i1
+}
+
+// CHECK-LABEL: llvm.func @box_isptr(
+// CHECK-SAME:                         %[[ARG0:.*]]: !llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) -> i1
+// CHECK:         %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32
+// CHECK:         %[[ATTRPOS:.*]] = llvm.mlir.constant(5 : i32) : i32
+// CHECK:         %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[ATTRPOS]]] : (!llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32) -> !llvm.ptr<i32>
+// CHECK:         %[[ATTR:.*]] = llvm.load %[[GEP]] : !llvm.ptr<i32>
+// CHECK:         %[[ATTR_ISALLOC:.*]] = llvm.mlir.constant(1 : i32) : i32
+// CHECK:         %[[AND:.*]] = llvm.and %[[ATTR]], %[[ATTR_ISALLOC]]  : i32
+// 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


        


More information about the flang-commits mailing list