[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:
Valentin Clement 2021-11-11 10:39:02 +01:00
parent aeb1c8d0ca
commit b6e44ecd6e
No known key found for this signature in database
GPG Key ID: 086D54783C928776
2 changed files with 154 additions and 10 deletions

View File

@ -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,

View File

@ -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