mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-25 21:11:25 +00:00
[fir] Add fir.box_rank, fir.box_addr, fir.box_dims and fir.box_elesize conversion
This patch adds conversion for basic box operations that extract information from the box. This patch is part of the upstreaming effort from fir-dev branch. Reviewed By: awarzynski Differential Revision: https://reviews.llvm.org/D113551 Co-authored-by: Eric Schweitz <eschweitz@nvidia.com>
This commit is contained in:
parent
5eca6ad752
commit
df3b9810c7
@ -42,6 +42,88 @@ protected:
|
||||
return lowerTy().convertType(ty);
|
||||
}
|
||||
|
||||
mlir::LLVM::ConstantOp
|
||||
genConstantOffset(mlir::Location loc,
|
||||
mlir::ConversionPatternRewriter &rewriter,
|
||||
int offset) const {
|
||||
auto ity = lowerTy().offsetType();
|
||||
auto cattr = rewriter.getI32IntegerAttr(offset);
|
||||
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 {
|
||||
mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
|
||||
mlir::LLVM::ConstantOp cRank =
|
||||
genConstantOffset(loc, rewriter, kRankPosInBox);
|
||||
auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
|
||||
auto p = rewriter.create<mlir::LLVM::GEPOp>(
|
||||
loc, pty, mlir::ValueRange{box, c0, cRank});
|
||||
return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
|
||||
}
|
||||
|
||||
/// Method to construct code sequence to get the triple for dimension `dim`
|
||||
/// from a box.
|
||||
SmallVector<mlir::Value, 3>
|
||||
getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys,
|
||||
mlir::Value box, mlir::Value dim,
|
||||
mlir::ConversionPatternRewriter &rewriter) const {
|
||||
mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
|
||||
mlir::LLVM::ConstantOp cDims =
|
||||
genConstantOffset(loc, rewriter, kDimsPosInBox);
|
||||
mlir::LLVM::LoadOp l0 =
|
||||
loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
|
||||
mlir::LLVM::LoadOp l1 =
|
||||
loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
|
||||
mlir::LLVM::LoadOp l2 =
|
||||
loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
|
||||
return {l0.getResult(), l1.getResult(), l2.getResult()};
|
||||
}
|
||||
|
||||
mlir::LLVM::LoadOp
|
||||
loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
|
||||
mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
|
||||
mlir::Type ty,
|
||||
mlir::ConversionPatternRewriter &rewriter) const {
|
||||
auto pty = mlir::LLVM::LLVMPointerType::get(ty);
|
||||
mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
|
||||
mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
|
||||
return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
|
||||
}
|
||||
|
||||
/// Read base address from a fir.box. Returned address has type ty.
|
||||
mlir::Value
|
||||
loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
|
||||
mlir::ConversionPatternRewriter &rewriter) const {
|
||||
mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
|
||||
mlir::LLVM::ConstantOp cAddr =
|
||||
genConstantOffset(loc, rewriter, kAddrPosInBox);
|
||||
auto pty = mlir::LLVM::LLVMPointerType::get(ty);
|
||||
mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
|
||||
return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
|
||||
}
|
||||
|
||||
mlir::Value
|
||||
loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
|
||||
mlir::ConversionPatternRewriter &rewriter) const {
|
||||
mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
|
||||
mlir::LLVM::ConstantOp cElemLen =
|
||||
genConstantOffset(loc, rewriter, kElemLenPosInBox);
|
||||
auto pty = mlir::LLVM::LLVMPointerType::get(ty);
|
||||
mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
|
||||
return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
|
||||
}
|
||||
|
||||
template <typename... ARGS>
|
||||
mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
|
||||
mlir::ConversionPatternRewriter &rewriter,
|
||||
mlir::Value base, ARGS... args) const {
|
||||
SmallVector<mlir::Value> cv{args...};
|
||||
return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
|
||||
}
|
||||
|
||||
fir::LLVMTypeConverter &lowerTy() const {
|
||||
return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
|
||||
}
|
||||
@ -80,6 +162,84 @@ struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
|
||||
}
|
||||
};
|
||||
|
||||
/// Lower `fir.box_addr` to the sequence of operations to extract the first
|
||||
/// element of the box.
|
||||
struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
|
||||
using FIROpConversion::FIROpConversion;
|
||||
|
||||
mlir::LogicalResult
|
||||
matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
|
||||
mlir::ConversionPatternRewriter &rewriter) const override {
|
||||
mlir::Value a = adaptor.getOperands()[0];
|
||||
auto loc = boxaddr.getLoc();
|
||||
mlir::Type ty = convertType(boxaddr.getType());
|
||||
if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) {
|
||||
rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
|
||||
} else {
|
||||
auto c0attr = rewriter.getI32IntegerAttr(0);
|
||||
auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
|
||||
rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
|
||||
c0);
|
||||
}
|
||||
return success();
|
||||
}
|
||||
};
|
||||
|
||||
/// Lower `fir.box_dims` to a sequence of operations to extract the requested
|
||||
/// dimension infomartion from the boxed value.
|
||||
/// Result in a triple set of GEPs and loads.
|
||||
struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
|
||||
using FIROpConversion::FIROpConversion;
|
||||
|
||||
mlir::LogicalResult
|
||||
matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
|
||||
mlir::ConversionPatternRewriter &rewriter) const override {
|
||||
SmallVector<mlir::Type, 3> resultTypes = {
|
||||
convertType(boxdims.getResult(0).getType()),
|
||||
convertType(boxdims.getResult(1).getType()),
|
||||
convertType(boxdims.getResult(2).getType()),
|
||||
};
|
||||
auto results =
|
||||
getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
|
||||
adaptor.getOperands()[1], rewriter);
|
||||
rewriter.replaceOp(boxdims, results);
|
||||
return success();
|
||||
}
|
||||
};
|
||||
|
||||
/// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
|
||||
/// an element in the boxed value.
|
||||
struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
|
||||
using FIROpConversion::FIROpConversion;
|
||||
|
||||
mlir::LogicalResult
|
||||
matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
|
||||
mlir::ConversionPatternRewriter &rewriter) const override {
|
||||
mlir::Value a = adaptor.getOperands()[0];
|
||||
auto loc = boxelesz.getLoc();
|
||||
auto ty = convertType(boxelesz.getType());
|
||||
rewriter.replaceOp(boxelesz, loadElementSizeFromBox(loc, ty, a, rewriter));
|
||||
return success();
|
||||
}
|
||||
};
|
||||
|
||||
/// Lower `fir.box_rank` to the sequence of operation to extract the rank from
|
||||
/// the box.
|
||||
struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
|
||||
using FIROpConversion::FIROpConversion;
|
||||
|
||||
mlir::LogicalResult
|
||||
matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
|
||||
mlir::ConversionPatternRewriter &rewriter) const override {
|
||||
mlir::Value a = adaptor.getOperands()[0];
|
||||
auto loc = boxrank.getLoc();
|
||||
mlir::Type ty = convertType(boxrank.getType());
|
||||
auto result = getRankFromBox(loc, a, ty, rewriter);
|
||||
rewriter.replaceOp(boxrank, result);
|
||||
return success();
|
||||
}
|
||||
};
|
||||
|
||||
// `fir.call` -> `llvm.call`
|
||||
struct CallOpConversion : public FIROpConversion<fir::CallOp> {
|
||||
using FIROpConversion::FIROpConversion;
|
||||
@ -835,14 +995,16 @@ public:
|
||||
auto *context = getModule().getContext();
|
||||
fir::LLVMTypeConverter typeConverter{getModule()};
|
||||
mlir::OwningRewritePatternList pattern(context);
|
||||
pattern.insert<AddcOpConversion, AddrOfOpConversion, CallOpConversion,
|
||||
ConvertOpConversion, DivcOpConversion,
|
||||
ExtractValueOpConversion, HasValueOpConversion,
|
||||
GlobalOpConversion, InsertOnRangeOpConversion,
|
||||
InsertValueOpConversion, LoadOpConversion, NegcOpConversion,
|
||||
MulcOpConversion, SelectOpConversion, SelectRankOpConversion,
|
||||
StoreOpConversion, SubcOpConversion, UndefOpConversion,
|
||||
UnreachableOpConversion, ZeroOpConversion>(typeConverter);
|
||||
pattern.insert<
|
||||
AddcOpConversion, AddrOfOpConversion, BoxAddrOpConversion,
|
||||
BoxDimsOpConversion, BoxEleSizeOpConversion, BoxRankOpConversion,
|
||||
CallOpConversion, ConvertOpConversion, DivcOpConversion,
|
||||
ExtractValueOpConversion, HasValueOpConversion, GlobalOpConversion,
|
||||
InsertOnRangeOpConversion, InsertValueOpConversion, LoadOpConversion,
|
||||
NegcOpConversion, MulcOpConversion, SelectOpConversion,
|
||||
SelectRankOpConversion, StoreOpConversion, SubcOpConversion,
|
||||
UndefOpConversion, UnreachableOpConversion, ZeroOpConversion>(
|
||||
typeConverter);
|
||||
mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
|
||||
mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
|
||||
pattern);
|
||||
|
@ -79,6 +79,10 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
// i32 is used here because LLVM wants i32 constants when indexing into struct
|
||||
// types. Indexing into other aggregate types is more flexible.
|
||||
mlir::Type offsetType() { return mlir::IntegerType::get(&getContext(), 32); }
|
||||
|
||||
// fir.type<name(p : TY'...){f : TY...}> --> llvm<"%name = { ty... }">
|
||||
mlir::Type convertRecordType(fir::RecordType derived) {
|
||||
auto name = derived.getName();
|
||||
|
@ -686,3 +686,80 @@ func @test_load_box(%addr : !fir.ref<!fir.box<!fir.array<10xf32>>>) {
|
||||
// CHECK-SAME: (%{{.*}}: !llvm.ptr<struct<(ptr<array<10 x f{{.*}}>>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, array<1 x array<3 x i{{.*}}>>)>>) {
|
||||
// CHECK-NEXT: llvm.return
|
||||
// CHECK-NEXT: }
|
||||
|
||||
// -----
|
||||
|
||||
// Test `fir.box_rank` conversion.
|
||||
|
||||
func @extract_rank(%arg0: !fir.box<!fir.array<*:f64>>) -> i32 {
|
||||
%0 = fir.box_rank %arg0 : (!fir.box<!fir.array<*:f64>>) -> i32
|
||||
return %0 : i32
|
||||
}
|
||||
|
||||
// CHECK-LABEL: llvm.func @extract_rank(
|
||||
// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) -> i32
|
||||
// CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32
|
||||
// CHECK: %[[CRANK:.*]] = llvm.mlir.constant(3 : i32) : i32
|
||||
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[CRANK]]] : (!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: llvm.return %[[RANK]] : i32
|
||||
|
||||
// -----
|
||||
|
||||
// Test `fir.box_addr` conversion.
|
||||
|
||||
func @extract_addr(%arg0: !fir.box<!fir.array<*:f64>>) -> !fir.ref<f64> {
|
||||
%0 = fir.box_addr %arg0 : (!fir.box<!fir.array<*:f64>>) -> !fir.ref<f64>
|
||||
return %0 : !fir.ref<f64>
|
||||
}
|
||||
|
||||
// CHECK-LABEL: llvm.func @extract_addr(
|
||||
// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) -> !llvm.ptr<f64>
|
||||
// CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32
|
||||
// CHECK: %[[CADDR:.*]] = llvm.mlir.constant(0 : i32) : i32
|
||||
// CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[CADDR]]] : (!llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32) -> !llvm.ptr<ptr<f64>>
|
||||
// CHECK: %[[ADDR:.*]] = llvm.load %[[GEP]] : !llvm.ptr<ptr<f64>>
|
||||
// CHECK: llvm.return %[[ADDR]] : !llvm.ptr<f64>
|
||||
|
||||
// -----
|
||||
|
||||
// Test `fir.box_dims` conversion.
|
||||
|
||||
func @extract_dims(%arg0: !fir.box<!fir.array<*:f64>>) -> index {
|
||||
%c1 = arith.constant 0 : i32
|
||||
%0:3 = fir.box_dims %arg0, %c1 : (!fir.box<!fir.array<*:f64>>, i32) -> (index, index, index)
|
||||
return %0 : index
|
||||
}
|
||||
|
||||
// CHECK-LABEL: llvm.func @extract_dims(
|
||||
// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) -> i64
|
||||
// CHECK: %[[C0_1:.*]] = llvm.mlir.constant(0 : i32) : i32
|
||||
// CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32
|
||||
// CHECK: %[[CDIMS:.*]] = llvm.mlir.constant(7 : i32) : i32
|
||||
// CHECK: %[[C0_2:.*]] = llvm.mlir.constant(0 : i32) : i32
|
||||
// CHECK: %[[GEP0:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[CDIMS]], %[[C0_1]], %[[C0_2]]] : (!llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32, i32, i32) -> !llvm.ptr<i64>
|
||||
// CHECK: %[[LOAD0:.*]] = llvm.load %[[GEP0]] : !llvm.ptr<i64>
|
||||
// CHECK: %[[C1:.*]] = llvm.mlir.constant(1 : i32) : i32
|
||||
// CHECK: %[[GEP1:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[CDIMS]], %[[C0_1]], %[[C1]]] : (!llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32, i32, i32) -> !llvm.ptr<i64>
|
||||
// CHECK: %[[LOAD1:.*]] = llvm.load %[[GEP1]] : !llvm.ptr<i64>
|
||||
// CHECK: %[[C2:.*]] = llvm.mlir.constant(2 : i32) : i32
|
||||
// CHECK: %[[GEP2:.*]] = llvm.getelementptr %[[ARG0]][%[[C0]], %[[CDIMS]], %[[C0_1]], %[[C2]]] : (!llvm.ptr<struct<(ptr<f64>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>, i32, i32, i32, i32) -> !llvm.ptr<i64>
|
||||
// CHECK: %[[LOAD2:.*]] = llvm.load %[[GEP2]] : !llvm.ptr<i64>
|
||||
// CHECK: llvm.return %[[LOAD0]] : i64
|
||||
|
||||
// -----
|
||||
|
||||
// Test `fir.box_elesize` conversion.
|
||||
|
||||
func @extract_elesize(%arg0: !fir.box<f32>) -> i32 {
|
||||
%0 = fir.box_elesize %arg0 : (!fir.box<f32>) -> i32
|
||||
return %0 : i32
|
||||
}
|
||||
|
||||
// CHECK-LABEL: llvm.func @extract_elesize(
|
||||
// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr<struct<(ptr<f32>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}})>>) -> i32
|
||||
// CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : i32) : i32
|
||||
// CHECK: %[[CELESIZE:.*]] = llvm.mlir.constant(1 : i32) : 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user