forked from OSchip/llvm-project
[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@nvidia.com>
This commit is contained in:
parent
aeb1c8d0ca
commit
b6e44ecd6e
|
@ -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 @@ protected:
|
|||
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 @@ protected:
|
|||
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 @@ public:
|
|||
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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue