[flang][CodeGen] Transform `fir.field_index` to a sequence of LLVM MLIR
This patch extends the `FIRToLLVMLowering` pass in Flang by adding a hook to transform `fir.field_index` to a sequence of LLVM MLIR instructions. This is part of the upstreaming effort from the `fir-dev` branch in [1]. [1] https://github.com/flang-compiler/f18-llvm-project Differential Revision: https://reviews.llvm.org/D113988 Co-authored-by: Eric Schweitz <eschweitz@nvidia.com> Co-authored-by: Jean Perier <jperier@nvidia.com>
This commit is contained in:
parent
fb1a06aa13
commit
e6c66ef55e
|
|
@ -2089,6 +2089,48 @@ struct UnboxProcOpConversion : public FIROpConversion<fir::UnboxProcOp> {
|
|||
}
|
||||
};
|
||||
|
||||
/// Convert `fir.field_index`. The conversion depends on whether the size of
|
||||
/// the record is static or dynamic.
|
||||
struct FieldIndexOpConversion : public FIROpConversion<fir::FieldIndexOp> {
|
||||
using FIROpConversion::FIROpConversion;
|
||||
|
||||
// NB: most field references should be resolved by this point
|
||||
mlir::LogicalResult
|
||||
matchAndRewrite(fir::FieldIndexOp field, OpAdaptor adaptor,
|
||||
mlir::ConversionPatternRewriter &rewriter) const override {
|
||||
auto recTy = field.on_type().cast<fir::RecordType>();
|
||||
unsigned index = recTy.getFieldIndex(field.field_id());
|
||||
|
||||
if (!fir::hasDynamicSize(recTy)) {
|
||||
// Derived type has compile-time constant layout. Return index of the
|
||||
// component type in the parent type (to be used in GEP).
|
||||
rewriter.replaceOp(field, mlir::ValueRange{genConstantOffset(
|
||||
field.getLoc(), rewriter, index)});
|
||||
return success();
|
||||
}
|
||||
|
||||
// Derived type has compile-time constant layout. Call the compiler
|
||||
// generated function to determine the byte offset of the field at runtime.
|
||||
// This returns a non-constant.
|
||||
FlatSymbolRefAttr symAttr = mlir::SymbolRefAttr::get(
|
||||
field.getContext(), getOffsetMethodName(recTy, field.field_id()));
|
||||
NamedAttribute callAttr = rewriter.getNamedAttr("callee", symAttr);
|
||||
NamedAttribute fieldAttr = rewriter.getNamedAttr(
|
||||
"field", mlir::IntegerAttr::get(lowerTy().indexType(), index));
|
||||
rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
|
||||
field, lowerTy().offsetType(), adaptor.getOperands(),
|
||||
llvm::ArrayRef<mlir::NamedAttribute>{callAttr, fieldAttr});
|
||||
return success();
|
||||
}
|
||||
|
||||
// Re-Construct the name of the compiler generated method that calculates the
|
||||
// offset
|
||||
inline static std::string getOffsetMethodName(fir::RecordType recTy,
|
||||
llvm::StringRef field) {
|
||||
return recTy.getName().str() + "P." + field.str() + ".offset";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
|
|
@ -2120,16 +2162,17 @@ public:
|
|||
CmpcOpConversion, ConstcOpConversion, ConvertOpConversion,
|
||||
DispatchOpConversion, DispatchTableOpConversion, DTEntryOpConversion,
|
||||
DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion,
|
||||
EmboxProcOpConversion, ExtractValueOpConversion, FirEndOpConversion,
|
||||
HasValueOpConversion, GenTypeDescOpConversion, GlobalLenOpConversion,
|
||||
GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
|
||||
IsPresentOpConversion, LoadOpConversion, NegcOpConversion,
|
||||
MulcOpConversion, SelectCaseOpConversion, SelectOpConversion,
|
||||
SelectRankOpConversion, SelectTypeOpConversion, ShapeOpConversion,
|
||||
ShapeShiftOpConversion, ShiftOpConversion, SliceOpConversion,
|
||||
StoreOpConversion, StringLitOpConversion, SubcOpConversion,
|
||||
UnboxCharOpConversion, UnboxProcOpConversion, UndefOpConversion,
|
||||
UnreachableOpConversion, ZeroOpConversion>(typeConverter);
|
||||
EmboxProcOpConversion, ExtractValueOpConversion, FieldIndexOpConversion,
|
||||
FirEndOpConversion, HasValueOpConversion, GenTypeDescOpConversion,
|
||||
GlobalLenOpConversion, GlobalOpConversion, InsertOnRangeOpConversion,
|
||||
InsertValueOpConversion, IsPresentOpConversion, LoadOpConversion,
|
||||
NegcOpConversion, MulcOpConversion, SelectCaseOpConversion,
|
||||
SelectOpConversion, SelectRankOpConversion, SelectTypeOpConversion,
|
||||
ShapeOpConversion, ShapeShiftOpConversion, ShiftOpConversion,
|
||||
SliceOpConversion, StoreOpConversion, StringLitOpConversion,
|
||||
SubcOpConversion, UnboxCharOpConversion, UnboxProcOpConversion,
|
||||
UndefOpConversion, UnreachableOpConversion, ZeroOpConversion>(
|
||||
typeConverter);
|
||||
mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
|
||||
mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
|
||||
pattern);
|
||||
|
|
|
|||
|
|
@ -1530,3 +1530,42 @@ func @embox1(%arg0: !fir.ref<!fir.type<_QMtest_dinitTtseq{i:i32}>>) {
|
|||
// CHECK: %[[TDESC:.*]] = llvm.mlir.addressof @_QMtest_dinitE.dt.tseq : !llvm.ptr<i8>
|
||||
// CHECK: %[[TDESC_CAST:.*]] = llvm.bitcast %22 : !llvm.ptr<i8> to !llvm.ptr<i8>
|
||||
// CHECK: %{{.*}} = llvm.insertvalue %[[TDESC_CAST]], %{{.*}}[7 : i32] : !llvm.struct<(ptr<struct<"_QMtest_dinitTtseq", (i32)>>, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, ptr<i{{.*}}>, array<1 x i{{.*}}>)>
|
||||
|
||||
// -----
|
||||
|
||||
// Test `fir.field_index`
|
||||
|
||||
func @field_index_static_size_1_elem() -> () {
|
||||
%1 = fir.field_index i, !fir.type<t1{i:i32}>
|
||||
return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @field_index_static_size_1_elem
|
||||
// CHECK-NEXT: %{{.*}} = llvm.mlir.constant(0 : i32) : i32
|
||||
// CHECK-NEXT: llvm.return
|
||||
|
||||
func @field_index_static_size_3_elems() -> () {
|
||||
%1 = fir.field_index k, !fir.type<t2{i:i32, j:f32, k:i8}>
|
||||
return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @field_index_static_size_3_elems
|
||||
// CHECK-NEXT: %{{.*}} = llvm.mlir.constant(2 : i32) : i32
|
||||
// CHECK-NEXT: llvm.return
|
||||
|
||||
// When converting `fir.field_index` for a dynamically sized record, the
|
||||
// offset will be calculated at runtime by calling methods like the ones
|
||||
// below. Note that these methods would normally be generated by the compiler.
|
||||
func private @custom_typeP.field_1.offset() -> i32
|
||||
func private @custom_typeP.field_2.offset() -> i32
|
||||
|
||||
func @field_index_dynamic_size() -> () {
|
||||
%1 = fir.field_index field_1, !fir.type<custom_type{field_1:i32, field_2:!fir.array<?xf32>}>
|
||||
%2 = fir.field_index field_2, !fir.type<custom_type{field_1:i32, field_2:!fir.array<?xf32>}>
|
||||
return
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @field_index_dynamic_size
|
||||
// CHECK-NEXT: %{{.*}} = llvm.call @custom_typeP.field_1.offset() {field = 0 : i64} : () -> i32
|
||||
// CHECK-NEXT: %{{.*}} = llvm.call @custom_typeP.field_2.offset() {field = 1 : i64} : () -> i32
|
||||
// CHECK-NEXT: llvm.return
|
||||
|
|
|
|||
Loading…
Reference in New Issue