[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:
Andrzej Warzynski 2021-11-16 08:36:05 +00:00
parent fb1a06aa13
commit e6c66ef55e
2 changed files with 92 additions and 10 deletions

View File

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

View File

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