[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