diff --git a/flang/include/flang/Semantics/runtime-type-info.h b/flang/include/flang/Semantics/runtime-type-info.h index 76560b98b1c20..e27091cf32de0 100644 --- a/flang/include/flang/Semantics/runtime-type-info.h +++ b/flang/include/flang/Semantics/runtime-type-info.h @@ -42,6 +42,14 @@ RuntimeDerivedTypeTables BuildRuntimeDerivedTypeTables(SemanticsContext &); /// to describe other derived types at runtime in flang descriptor. constexpr char typeInfoBuiltinModule[]{"__fortran_type_info"}; +/// Name of the bindings descriptor component in the DerivedType type of the +/// __Fortran_type_info module +constexpr char bindingDescCompName[]{"binding"}; + +/// Name of the __builtin_c_funptr component in the Binding type of the +/// __Fortran_type_info module +constexpr char procCompName[]{"proc"}; + SymbolVector CollectBindings(const Scope &dtScope); } // namespace Fortran::semantics diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index 6b4591789c545..8ea8fa7290372 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -104,10 +104,8 @@ template class FIROpConversion : public mlir::ConvertOpToLLVMPattern { public: explicit FIROpConversion(fir::LLVMTypeConverter &lowering, - const fir::FIRToLLVMPassOptions &options, - const fir::BindingTables &bindingTables) - : mlir::ConvertOpToLLVMPattern(lowering), options(options), - bindingTables(bindingTables) {} + const fir::FIRToLLVMPassOptions &options) + : mlir::ConvertOpToLLVMPattern(lowering), options(options) {} protected: mlir::Type convertType(mlir::Type ty) const { @@ -358,7 +356,6 @@ class FIROpConversion : public mlir::ConvertOpToLLVMPattern { } const fir::FIRToLLVMPassOptions &options; - const fir::BindingTables &bindingTables; }; /// FIR conversion pattern template @@ -970,131 +967,6 @@ struct ConvertOpConversion : public FIROpConversion { } }; -/// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch -/// table. -struct DispatchOpConversion : public FIROpConversion { - using FIROpConversion::FIROpConversion; - - mlir::LogicalResult - matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor, - mlir::ConversionPatternRewriter &rewriter) const override { - mlir::Location loc = dispatch.getLoc(); - - if (bindingTables.empty()) - return emitError(loc) << "no binding tables found"; - - // Get derived type information. - mlir::Type declaredType = - fir::getDerivedType(dispatch.getObject().getType().getEleTy()); - assert(declaredType.isa() && "expecting fir.type"); - auto recordType = declaredType.dyn_cast(); - - // Lookup for the binding table. - auto bindingsIter = bindingTables.find(recordType.getName()); - if (bindingsIter == bindingTables.end()) - return emitError(loc) - << "cannot find binding table for " << recordType.getName(); - - // Lookup for the binding. - const fir::BindingTable &bindingTable = bindingsIter->second; - auto bindingIter = bindingTable.find(dispatch.getMethod()); - if (bindingIter == bindingTable.end()) - return emitError(loc) - << "cannot find binding for " << dispatch.getMethod(); - unsigned bindingIdx = bindingIter->second; - - mlir::Value passedObject = dispatch.getObject(); - - auto module = dispatch.getOperation()->getParentOfType(); - mlir::Type typeDescTy; - std::string typeDescName = - fir::NameUniquer::getTypeDescriptorName(recordType.getName()); - if (auto global = module.lookupSymbol(typeDescName)) { - typeDescTy = convertType(global.getType()); - } else if (auto global = - module.lookupSymbol(typeDescName)) { - // The global may have already been translated to LLVM. - typeDescTy = global.getType(); - } - - unsigned typeDescFieldId = getTypeDescFieldId(passedObject.getType()); - - auto descPtr = adaptor.getOperands()[0] - .getType() - .dyn_cast(); - - // TODO: the following loads from the type descriptor related - // data structures must have proper TBAA access tags. - // These loads cannot alias with any real data accesses nor - // with any box accesses. Moreover, they can probably be marked - // as reading from constant memory (fourth operand of a TBAA - // tag may be set to true). These accesses probably deserve - // separate sub-root in the TBAA graph. - - // Load the descriptor. - auto desc = rewriter.create( - loc, descPtr.getElementType(), adaptor.getOperands()[0]); - - // Load the type descriptor. - auto typeDescPtr = - rewriter.create(loc, desc, typeDescFieldId); - auto typeDesc = - rewriter.create(loc, typeDescTy, typeDescPtr); - - // Load the bindings descriptor. - auto typeDescStructTy = typeDescTy.dyn_cast(); - auto bindingDescType = - typeDescStructTy.getBody()[0].dyn_cast(); - auto bindingDesc = - rewriter.create(loc, typeDesc, 0); - - // Load the correct binding. - auto bindingType = - bindingDescType.getBody()[0].dyn_cast(); - auto baseBindingPtr = rewriter.create( - loc, bindingDesc, kAddrPosInBox); - auto bindingPtr = rewriter.create( - loc, bindingType, baseBindingPtr, - llvm::ArrayRef{static_cast(bindingIdx)}); - auto binding = rewriter.create( - loc, bindingType.getElementType(), bindingPtr); - - // Get the function type. - llvm::SmallVector argTypes; - for (mlir::Value operand : adaptor.getOperands().drop_front()) - argTypes.push_back(operand.getType()); - mlir::Type resultType; - if (dispatch.getResults().empty()) - resultType = mlir::LLVM::LLVMVoidType::get(dispatch.getContext()); - else - resultType = convertType(dispatch.getResults()[0].getType()); - auto fctType = mlir::LLVM::LLVMFunctionType::get(resultType, argTypes, - /*isVarArg=*/false); - - // Get the function pointer. - auto builtinFuncPtr = - rewriter.create(loc, binding, 0); - auto funcAddr = - rewriter.create(loc, builtinFuncPtr, 0); - auto funcPtr = rewriter.create( - loc, mlir::LLVM::LLVMPointerType::get(fctType), funcAddr); - - // Indirect calls are done with the function pointer as the first operand. - llvm::SmallVector args; - args.push_back(funcPtr); - for (mlir::Value operand : adaptor.getOperands().drop_front()) - args.push_back(operand); - auto callOp = rewriter.replaceOpWithNewOp( - dispatch, - dispatch.getResults().empty() ? mlir::TypeRange{} - : fctType.getReturnType(), - "", args); - callOp.removeCalleeAttr(); // Indirect calls do not have callee attr. - - return mlir::success(); - } -}; - /// `fir.disptach_table` operation has no specific CodeGen. The operation is /// only used to carry information during FIR to FIR passes. struct DispatchTableOpConversion @@ -3656,9 +3528,8 @@ struct NegcOpConversion : public FIROpConversion { template struct MustBeDeadConversion : public FIROpConversion { explicit MustBeDeadConversion(fir::LLVMTypeConverter &lowering, - const fir::FIRToLLVMPassOptions &options, - const fir::BindingTables &bindingTables) - : FIROpConversion(lowering, options, bindingTables) {} + const fir::FIRToLLVMPassOptions &options) + : FIROpConversion(lowering, options) {} using OpAdaptor = typename FromOp::Adaptor; mlir::LogicalResult @@ -3768,9 +3639,6 @@ class FIRToLLVMLowering if (mlir::failed(runPipeline(mathConvertionPM, mod))) return signalPassFailure(); - fir::BindingTables bindingTables; - fir::buildBindingTables(bindingTables, mod); - auto *context = getModule().getContext(); fir::LLVMTypeConverter typeConverter{getModule(), options.applyTBAA || applyTBAA}; @@ -3783,11 +3651,11 @@ class FIRToLLVMLowering BoxProcHostOpConversion, BoxRankOpConversion, BoxTypeCodeOpConversion, BoxTypeDescOpConversion, CallOpConversion, CmpcOpConversion, ConstcOpConversion, ConvertOpConversion, CoordinateOpConversion, - DispatchOpConversion, DispatchTableOpConversion, DTEntryOpConversion, - DivcOpConversion, EmboxOpConversion, EmboxCharOpConversion, - EmboxProcOpConversion, ExtractValueOpConversion, FieldIndexOpConversion, - FirEndOpConversion, FreeMemOpConversion, GlobalLenOpConversion, - GlobalOpConversion, HasValueOpConversion, InsertOnRangeOpConversion, + DispatchTableOpConversion, DTEntryOpConversion, DivcOpConversion, + EmboxOpConversion, EmboxCharOpConversion, EmboxProcOpConversion, + ExtractValueOpConversion, FieldIndexOpConversion, FirEndOpConversion, + FreeMemOpConversion, GlobalLenOpConversion, GlobalOpConversion, + HasValueOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion, IsPresentOpConversion, LenParamIndexOpConversion, LoadOpConversion, MulcOpConversion, NegcOpConversion, NoReassocOpConversion, SelectCaseOpConversion, @@ -3797,7 +3665,7 @@ class FIRToLLVMLowering SubcOpConversion, TypeDescOpConversion, UnboxCharOpConversion, UnboxProcOpConversion, UndefOpConversion, UnreachableOpConversion, XArrayCoorOpConversion, XEmboxOpConversion, XReboxOpConversion, - ZeroOpConversion>(typeConverter, options, bindingTables); + ZeroOpConversion>(typeConverter, options); mlir::populateFuncToLLVMConversionPatterns(typeConverter, pattern); mlir::populateOpenMPToLLVMConversionPatterns(typeConverter, pattern); mlir::arith::populateArithToLLVMConversionPatterns(typeConverter, pattern); diff --git a/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp b/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp index f7ee2c19d45ac..2f8cdf7934436 100644 --- a/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp +++ b/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp @@ -6,18 +6,25 @@ // //===----------------------------------------------------------------------===// +#include "flang/Lower/BuiltinModules.h" +#include "flang/Optimizer/Builder/Todo.h" #include "flang/Optimizer/Dialect/FIRDialect.h" #include "flang/Optimizer/Dialect/FIROps.h" #include "flang/Optimizer/Dialect/FIROpsSupport.h" +#include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Optimizer/Dialect/Support/FIRContext.h" #include "flang/Optimizer/Dialect/Support/KindMapping.h" #include "flang/Optimizer/Support/InternalNames.h" #include "flang/Optimizer/Support/TypeCode.h" +#include "flang/Optimizer/Support/Utils.h" #include "flang/Optimizer/Transforms/Passes.h" #include "flang/Runtime/derived-api.h" +#include "flang/Semantics/runtime-type-info.h" #include "mlir/Dialect/Affine/IR/AffineOps.h" +#include "mlir/Dialect/Arith/IR/Arith.h" #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h" #include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/IR/BuiltinOps.h" #include "mlir/Pass/Pass.h" #include "mlir/Transforms/DialectConversion.h" #include "llvm/ADT/SmallSet.h" @@ -72,6 +79,147 @@ class SelectTypeConv : public OpConversionPattern { std::mutex *moduleMutex; }; +/// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch +/// table. +struct DispatchOpConv : public OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + DispatchOpConv(mlir::MLIRContext *ctx, const BindingTables &bindingTables) + : mlir::OpConversionPattern(ctx), + bindingTables(bindingTables) {} + + mlir::LogicalResult + matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + mlir::Location loc = dispatch.getLoc(); + + if (bindingTables.empty()) + return emitError(loc) << "no binding tables found"; + + // Get derived type information. + mlir::Type declaredType = + fir::getDerivedType(dispatch.getObject().getType().getEleTy()); + assert(declaredType.isa() && "expecting fir.type"); + auto recordType = declaredType.dyn_cast(); + + // Lookup for the binding table. + auto bindingsIter = bindingTables.find(recordType.getName()); + if (bindingsIter == bindingTables.end()) + return emitError(loc) + << "cannot find binding table for " << recordType.getName(); + + // Lookup for the binding. + const BindingTable &bindingTable = bindingsIter->second; + auto bindingIter = bindingTable.find(dispatch.getMethod()); + if (bindingIter == bindingTable.end()) + return emitError(loc) + << "cannot find binding for " << dispatch.getMethod(); + unsigned bindingIdx = bindingIter->second; + + mlir::Value passedObject = dispatch.getObject(); + + auto module = dispatch.getOperation()->getParentOfType(); + Type typeDescTy; + std::string typeDescName = + NameUniquer::getTypeDescriptorName(recordType.getName()); + if (auto global = module.lookupSymbol(typeDescName)) { + typeDescTy = global.getType(); + } + + // clang-format off + // Before: + // fir.dispatch "proc1"(%11 : + // !fir.class>>) + + // After: + // %12 = fir.box_tdesc %11 : (!fir.class>>) -> !fir.tdesc + // %13 = fir.convert %12 : (!fir.tdesc) -> !fir.ref> + // %14 = fir.field_index binding, !fir.type<_QM__fortran_type_infoTderivedtype> + // %15 = fir.coordinate_of %13, %14 : (!fir.ref>, !fir.field) -> !fir.ref>>>> + // %bindings = fir.load %15 : !fir.ref>>>> + // %16 = fir.box_addr %bindings : (!fir.box>>>) -> !fir.ptr>> + // %17 = fir.coordinate_of %16, %c0 : (!fir.ptr>>, index) -> !fir.ref> + // %18 = fir.field_index proc, !fir.type<_QM__fortran_type_infoTbinding> + // %19 = fir.coordinate_of %17, %18 : (!fir.ref>, !fir.field) -> !fir.ref> + // %20 = fir.field_index __address, !fir.type<_QM__fortran_builtinsT__builtin_c_funptr> + // %21 = fir.coordinate_of %19, %20 : (!fir.ref>, !fir.field) -> !fir.ref + // %22 = fir.load %21 : !fir.ref + // %23 = fir.convert %22 : (i64) -> (() -> ()) + // fir.call %23() : () -> () + // clang-format on + + // Load the descriptor. + mlir::Type fieldTy = fir::FieldType::get(rewriter.getContext()); + mlir::Type tdescType = + fir::TypeDescType::get(mlir::NoneType::get(rewriter.getContext())); + mlir::Value boxDesc = + rewriter.create(loc, tdescType, passedObject); + boxDesc = rewriter.create( + loc, fir::ReferenceType::get(typeDescTy), boxDesc); + + // Load the bindings descriptor. + auto bindingsCompName = Fortran::semantics::bindingDescCompName; + fir::RecordType typeDescRecTy = typeDescTy.cast(); + mlir::Value field = rewriter.create( + loc, fieldTy, bindingsCompName, typeDescRecTy, mlir::ValueRange{}); + mlir::Type coorTy = + fir::ReferenceType::get(typeDescRecTy.getType(bindingsCompName)); + mlir::Value bindingBoxAddr = + rewriter.create(loc, coorTy, boxDesc, field); + mlir::Value bindingBox = rewriter.create(loc, bindingBoxAddr); + + // Load the correct binding. + mlir::Value bindings = rewriter.create(loc, bindingBox); + fir::RecordType bindingTy = + fir::unwrapIfDerived(bindingBox.getType().cast()); + mlir::Type bindingAddrTy = fir::ReferenceType::get(bindingTy); + mlir::Value bindingIdxVal = rewriter.create( + loc, rewriter.getIndexType(), rewriter.getIndexAttr(bindingIdx)); + mlir::Value bindingAddr = rewriter.create( + loc, bindingAddrTy, bindings, bindingIdxVal); + + // Get the function pointer. + auto procCompName = Fortran::semantics::procCompName; + mlir::Value procField = rewriter.create( + loc, fieldTy, procCompName, bindingTy, mlir::ValueRange{}); + fir::RecordType procTy = + bindingTy.getType(procCompName).cast(); + mlir::Type procRefTy = fir::ReferenceType::get(procTy); + mlir::Value procRef = rewriter.create( + loc, procRefTy, bindingAddr, procField); + + auto addressFieldName = Fortran::lower::builtin::cptrFieldName; + mlir::Value addressField = rewriter.create( + loc, fieldTy, addressFieldName, procTy, mlir::ValueRange{}); + mlir::Type addressTy = procTy.getType(addressFieldName); + mlir::Type addressRefTy = fir::ReferenceType::get(addressTy); + mlir::Value addressRef = rewriter.create( + loc, addressRefTy, procRef, addressField); + mlir::Value address = rewriter.create(loc, addressRef); + + // Get the function type. + llvm::SmallVector argTypes; + for (mlir::Value operand : dispatch.getArgs()) + argTypes.push_back(operand.getType()); + llvm::SmallVector resTypes; + if (!dispatch.getResults().empty()) + resTypes.push_back(dispatch.getResults()[0].getType()); + + mlir::Type funTy = + mlir::FunctionType::get(rewriter.getContext(), argTypes, resTypes); + mlir::Value funcPtr = rewriter.create(loc, funTy, address); + + // Make the call. + llvm::SmallVector args{funcPtr}; + args.append(dispatch.getArgs().begin(), dispatch.getArgs().end()); + rewriter.replaceOpWithNewOp(dispatch, resTypes, nullptr, args); + return mlir::success(); + } + +private: + BindingTables bindingTables; +}; + /// Convert FIR structured control flow ops to CFG ops. class PolymorphicOpConversion : public fir::impl::PolymorphicOpConversionBase { @@ -83,14 +231,21 @@ class PolymorphicOpConversion void runOnOperation() override { auto *context = &getContext(); + auto mod = getOperation()->getParentOfType(); mlir::RewritePatternSet patterns(context); + + BindingTables bindingTables; + buildBindingTables(bindingTables, mod); + patterns.insert(context, moduleMutex); + patterns.insert(context, bindingTables); mlir::ConversionTarget target(*context); target.addLegalDialect(); // apply the patterns target.addIllegalOp(); + target.addIllegalOp(); target.markUnknownOpDynamicallyLegal([](Operation *) { return true; }); if (mlir::failed(mlir::applyPartialConversion(getOperation(), target, std::move(patterns)))) { diff --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp index 29f63524b5c07..5e57c70c42fbb 100644 --- a/flang/lib/Semantics/runtime-type-info.cpp +++ b/flang/lib/Semantics/runtime-type-info.cpp @@ -151,7 +151,8 @@ RuntimeTableBuilder::RuntimeTableBuilder( : context_{c}, tables_{t}, derivedTypeSchema_{GetSchema("derivedtype")}, componentSchema_{GetSchema("component")}, procPtrSchema_{GetSchema( "procptrcomponent")}, - valueSchema_{GetSchema("value")}, bindingSchema_{GetSchema("binding")}, + valueSchema_{GetSchema("value")}, bindingSchema_{GetSchema( + bindingDescCompName)}, specialSchema_{GetSchema("specialbinding")}, deferredEnum_{GetEnumValue( "deferred")}, explicitEnum_{GetEnumValue("explicit")}, lenParameterEnum_{GetEnumValue( @@ -562,7 +563,7 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) { if (!isAbstractType) { std::vector bindings{ DescribeBindings(dtScope, scope)}; - AddValue(dtValues, derivedTypeSchema_, "binding"s, + AddValue(dtValues, derivedTypeSchema_, bindingDescCompName, SaveDerivedPointerTarget(scope, SaveObjectName(".v."s + distinctName), std::move(bindings), evaluate::ConstantSubscripts{ @@ -982,7 +983,7 @@ RuntimeTableBuilder::DescribeBindings(const Scope &dtScope, Scope &scope) { std::vector result; for (const SymbolRef &ref : CollectBindings(dtScope)) { evaluate::StructureConstructorValues values; - AddValue(values, bindingSchema_, "proc"s, + AddValue(values, bindingSchema_, procCompName, SomeExpr{evaluate::ProcedureDesignator{ ref.get().get().symbol()}}); AddValue(values, bindingSchema_, "name"s, @@ -1152,7 +1153,7 @@ void RuntimeTableBuilder::DescribeSpecialProc( values, specialSchema_, "which"s, SomeExpr{std::move(which.value())}); AddValue(values, specialSchema_, "isargdescriptorset"s, IntExpr<1>(isArgDescriptorSet)); - AddValue(values, specialSchema_, "proc"s, + AddValue(values, specialSchema_, procCompName, SomeExpr{evaluate::ProcedureDesignator{specific}}); // index might already be present in the case of an override specials.emplace(*index, diff --git a/flang/test/Fir/dispatch.f90 b/flang/test/Fir/dispatch.f90 index dcb52bed7d967..933c769d3e169 100644 --- a/flang/test/Fir/dispatch.f90 +++ b/flang/test/Fir/dispatch.f90 @@ -1,4 +1,4 @@ -! RUN: bbc -polymorphic-type -emit-fir %s -o - | tco | FileCheck %s +! RUN: bbc -polymorphic-type -emit-fir %s -o - | fir-opt --fir-polymorphic-op | FileCheck %s ! RUN: bbc -polymorphic-type -emit-fir %s -o - | FileCheck %s --check-prefix=BT ! Tests codegen of fir.dispatch operation. This test is intentionally run from @@ -182,105 +182,123 @@ program test_type_to_class end -! CHECK-LABEL: define void @_QMdispatch1Pdisplay_class( -! CHECK-SAME: ptr %[[CLASS:.*]]) +! CHECK-LABEL: func.func @_QMdispatch1Pdisplay_class( +! CHECK-SAME: %[[ARG:.*]]: [[CLASS:!fir.class<.*>>]] -! CHECK-DAG: %[[INT32:.*]] = alloca i32, i64 1 -! CHECK-DAG: %[[REAL:.*]] = alloca float, i64 1 -! CHECK-DAG: %[[I:.*]] = alloca i32, i64 1 +! CHECK-DAG: %[[INT32:.*]] = fir.alloca i32 +! CHECK-DAG: %[[REAL:.*]] = fir.alloca f32 +! CHECK-DAG: %[[I:.*]] = fir.alloca i32 ! Check dynamic dispatch equal to `call p%display2()` with binding index = 2. -! CHECK: %[[LOADED_CLASS:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[CLASS]] -! CHECK: %[[TYPEDESCPTR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOADED_CLASS]], 7 -! CHECK: %[[LOADED_TYPEDESC:.*]] = load %_QM__fortran_type_infoTderivedtype, ptr %[[TYPEDESCPTR]] -! CHECK: %[[DT:.*]] = extractvalue %_QM__fortran_type_infoTderivedtype %[[LOADED_TYPEDESC]], 0 -! CHECK: %[[BINDING_BASE_ADDR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } %[[DT]], 0 -! CHECK: %[[BINDING_PTR:.*]] = getelementptr %_QM__fortran_type_infoTbinding, ptr %[[BINDING_BASE_ADDR]], i32 2 -! CHECK: %[[LOADED_BINDING:.*]] = load %_QM__fortran_type_infoTbinding, ptr %[[BINDING_PTR]] -! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = extractvalue %_QM__fortran_type_infoTbinding %[[LOADED_BINDING]], 0 -! CHECK: %[[FUNC_ADDR:.*]] = extractvalue %_QM__fortran_builtinsT__builtin_c_funptr %[[BUILTIN_FUNC_PTR]], 0 -! CHECK: %[[FUNC_PTR:.*]] = inttoptr i64 %[[FUNC_ADDR]] to ptr -! CHECK: call void %[[FUNC_PTR]](ptr %[[CLASS]]) +! CHECK: %[[BOXDESC:.*]] = fir.box_tdesc %[[ARG]] : ([[CLASS]]) -> !fir.tdesc +! CHECK: %[[TYPEDESCPTR:.*]] = fir.convert %[[BOXDESC]] : (!fir.tdesc) -> !fir.ref<[[TYPEINFO:!fir.type<_QM__fortran_type_infoTderivedtype{.*}>]]> +! CHECK: %[[BINDING_FIELD:.*]] = fir.field_index binding, [[TYPEINFO]] +! CHECK: %[[BINDING_BOX_ADDR:.*]] = fir.coordinate_of %[[TYPEDESCPTR]], %[[BINDING_FIELD]] : (!fir.ref<[[TYPEINFO]]>, !fir.field) -> !fir.ref<[[BINDING_BOX_TYPE:.*]]> +! CHECK: %[[BINDING_BOX:.*]] = fir.load %[[BINDING_BOX_ADDR]] : !fir.ref<[[BINDING_BOX_TYPE]]> +! CHECK: %[[BINDING_BASE_ADDR:.*]] = fir.box_addr %[[BINDING_BOX]] : ([[BINDING_BOX_TYPE]]) -> !fir.ptr<[[BINDINGSINFO:.*]]> +! CHECK: %[[BINDING_PTR:.*]] = fir.coordinate_of %[[BINDING_BASE_ADDR]], %c2 : (!fir.ptr<[[BINDINGSINFO]]>, index) -> !fir.ref<[[BINDINGINFO:.*]]> +! CHECK: %[[PROC_FIELD:.*]] = fir.field_index proc, [[BINDINGINFO]] +! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = fir.coordinate_of %[[BINDING_PTR]], %[[PROC_FIELD]] : ({{.*}}) -> !fir.ref<[[BUILTIN_FUNC_TYPE:.*]]> +! CHECK: %[[ADDRESS_FIELD:.*]] = fir.field_index __address, [[BUILTIN_FUNC_TYPE]] +! CHECK: %[[FUNC_ADDR_PTR:.*]] = fir.coordinate_of %[[BUILTIN_FUNC_PTR]], %[[ADDRESS_FIELD]] +! CHECK: %[[FUNC_ADDR:.*]] = fir.load %[[FUNC_ADDR_PTR]] : !fir.ref +! CHECK: %[[FUNC_PTR:.*]] = fir.convert %[[FUNC_ADDR]] : (i64) -> (([[CLASS]]) -> ()) +! CHECK: fir.call %[[FUNC_PTR]](%[[ARG]]) : ([[CLASS]]) -> () ! Check dynamic dispatch equal to `call p%display1()` with binding index = 1. -! CHECK: %[[LOADED_CLASS:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[CLASS]] -! CHECK: %[[TYPEDESCPTR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOADED_CLASS]], 7 -! CHECK: %[[LOADED_TYPEDESC:.*]] = load %_QM__fortran_type_infoTderivedtype, ptr %[[TYPEDESCPTR]] -! CHECK: %[[DT:.*]] = extractvalue %_QM__fortran_type_infoTderivedtype %[[LOADED_TYPEDESC]], 0 -! CHECK: %[[BINDING_BASE_ADDR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } %[[DT]], 0 -! CHECK: %[[BINDING_PTR:.*]] = getelementptr %_QM__fortran_type_infoTbinding, ptr %[[BINDING_BASE_ADDR]], i32 1 -! CHECK: %[[LOADED_BINDING:.*]] = load %_QM__fortran_type_infoTbinding, ptr %[[BINDING_PTR]] -! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = extractvalue %_QM__fortran_type_infoTbinding %[[LOADED_BINDING]], 0 -! CHECK: %[[FUNC_ADDR:.*]] = extractvalue %_QM__fortran_builtinsT__builtin_c_funptr %[[BUILTIN_FUNC_PTR]], 0 -! CHECK: %[[FUNC_PTR:.*]] = inttoptr i64 %[[FUNC_ADDR]] to ptr -! CHECK: call void %[[FUNC_PTR]](ptr %[[CLASS]]) +! CHECK: %[[BOXDESC:.*]] = fir.box_tdesc %[[ARG]] : ([[CLASS]]) -> !fir.tdesc +! CHECK: %[[TYPEDESCPTR:.*]] = fir.convert %[[BOXDESC]] : (!fir.tdesc) -> !fir.ref<[[TYPEINFO:!fir.type<_QM__fortran_type_infoTderivedtype{.*}>]]> +! CHECK: %[[BINDING_FIELD:.*]] = fir.field_index binding, [[TYPEINFO]] +! CHECK: %[[BINDING_BOX_ADDR:.*]] = fir.coordinate_of %[[TYPEDESCPTR]], %[[BINDING_FIELD]] : (!fir.ref<[[TYPEINFO]]>, !fir.field) -> !fir.ref<[[BINDING_BOX_TYPE:.*]]> +! CHECK: %[[BINDING_BOX:.*]] = fir.load %[[BINDING_BOX_ADDR]] : !fir.ref<[[BINDING_BOX_TYPE]]> +! CHECK: %[[BINDING_BASE_ADDR:.*]] = fir.box_addr %[[BINDING_BOX]] : ([[BINDING_BOX_TYPE]]) -> !fir.ptr<[[BINDINGSINFO:.*]]> +! CHECK: %[[BINDING_PTR:.*]] = fir.coordinate_of %[[BINDING_BASE_ADDR]], %c1 : (!fir.ptr<[[BINDINGSINFO]]>, index) -> !fir.ref<[[BINDINGINFO:.*]]> +! CHECK: %[[PROC_FIELD:.*]] = fir.field_index proc, [[BINDINGINFO]] +! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = fir.coordinate_of %[[BINDING_PTR]], %[[PROC_FIELD]] : ({{.*}}) -> !fir.ref<[[BUILTIN_FUNC_TYPE:.*]]> +! CHECK: %[[ADDRESS_FIELD:.*]] = fir.field_index __address, [[BUILTIN_FUNC_TYPE]] +! CHECK: %[[FUNC_ADDR_PTR:.*]] = fir.coordinate_of %[[BUILTIN_FUNC_PTR]], %[[ADDRESS_FIELD]] +! CHECK: %[[FUNC_ADDR:.*]] = fir.load %[[FUNC_ADDR_PTR]] : !fir.ref +! CHECK: %[[FUNC_PTR:.*]] = fir.convert %[[FUNC_ADDR]] : (i64) -> (([[CLASS]]) -> ()) +! CHECK: fir.call %[[FUNC_PTR]](%[[ARG]]) : ([[CLASS]]) -> () ! Check dynamic dispatch equal to `call p%aproc()` with binding index = 0. -! CHECK: %[[LOADED_CLASS:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[CLASS]] -! CHECK: %[[TYPEDESCPTR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOADED_CLASS]], 7 -! CHECK: %[[LOADED_TYPEDESC:.*]] = load %_QM__fortran_type_infoTderivedtype, ptr %[[TYPEDESCPTR]] -! CHECK: %[[DT:.*]] = extractvalue %_QM__fortran_type_infoTderivedtype %[[LOADED_TYPEDESC]], 0 -! CHECK: %[[BINDING_BASE_ADDR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } %[[DT]], 0 -! CHECK: %[[BINDING_PTR:.*]] = getelementptr %_QM__fortran_type_infoTbinding, ptr %[[BINDING_BASE_ADDR]], i32 0 -! CHECK: %[[LOADED_BINDING:.*]] = load %_QM__fortran_type_infoTbinding, ptr %[[BINDING_PTR]] -! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = extractvalue %_QM__fortran_type_infoTbinding %[[LOADED_BINDING]], 0 -! CHECK: %[[FUNC_ADDR:.*]] = extractvalue %_QM__fortran_builtinsT__builtin_c_funptr %[[BUILTIN_FUNC_PTR]], 0 -! CHECK: %[[FUNC_PTR:.*]] = inttoptr i64 %[[FUNC_ADDR]] to ptr -! CHECK: call void %[[FUNC_PTR]](ptr %[[CLASS]]) +! CHECK: %[[BOXDESC:.*]] = fir.box_tdesc %[[ARG]] : ([[CLASS]]) -> !fir.tdesc +! CHECK: %[[TYPEDESCPTR:.*]] = fir.convert %[[BOXDESC]] : (!fir.tdesc) -> !fir.ref<[[TYPEINFO:!fir.type<_QM__fortran_type_infoTderivedtype{.*}>]]> +! CHECK: %[[BINDING_FIELD:.*]] = fir.field_index binding, [[TYPEINFO]] +! CHECK: %[[BINDING_BOX_ADDR:.*]] = fir.coordinate_of %[[TYPEDESCPTR]], %[[BINDING_FIELD]] : (!fir.ref<[[TYPEINFO]]>, !fir.field) -> !fir.ref<[[BINDING_BOX_TYPE:.*]]> +! CHECK: %[[BINDING_BOX:.*]] = fir.load %[[BINDING_BOX_ADDR]] : !fir.ref<[[BINDING_BOX_TYPE]]> +! CHECK: %[[BINDING_BASE_ADDR:.*]] = fir.box_addr %[[BINDING_BOX]] : ([[BINDING_BOX_TYPE]]) -> !fir.ptr<[[BINDINGSINFO:.*]]> +! CHECK: %[[BINDING_PTR:.*]] = fir.coordinate_of %[[BINDING_BASE_ADDR]], %c0 : (!fir.ptr<[[BINDINGSINFO]]>, index) -> !fir.ref<[[BINDINGINFO:.*]]> +! CHECK: %[[PROC_FIELD:.*]] = fir.field_index proc, [[BINDINGINFO]] +! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = fir.coordinate_of %[[BINDING_PTR]], %[[PROC_FIELD]] : ({{.*}}) -> !fir.ref<[[BUILTIN_FUNC_TYPE:.*]]> +! CHECK: %[[ADDRESS_FIELD:.*]] = fir.field_index __address, [[BUILTIN_FUNC_TYPE]] +! CHECK: %[[FUNC_ADDR_PTR:.*]] = fir.coordinate_of %[[BUILTIN_FUNC_PTR]], %[[ADDRESS_FIELD]] +! CHECK: %[[FUNC_ADDR:.*]] = fir.load %[[FUNC_ADDR_PTR]] : !fir.ref +! CHECK: %[[FUNC_PTR:.*]] = fir.convert %[[FUNC_ADDR]] : (i64) -> (([[CLASS]]) -> ()) +! CHECK: fir.call %[[FUNC_PTR]](%[[ARG]]) : ([[CLASS]]) -> () ! Check dynamic dispatch of a function with result. -! CHECK: %[[LOADED_CLASS:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[CLASS]] -! CHECK: %[[TYPEDESCPTR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOADED_CLASS]], 7 -! CHECK: %[[LOADED_TYPEDESC:.*]] = load %_QM__fortran_type_infoTderivedtype, ptr %[[TYPEDESCPTR]] -! CHECK: %[[DT:.*]] = extractvalue %_QM__fortran_type_infoTderivedtype %[[LOADED_TYPEDESC]], 0 -! CHECK: %[[BINDING_BASE_ADDR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } %[[DT]], 0 -! CHECK: %[[BINDING_PTR:.*]] = getelementptr %_QM__fortran_type_infoTbinding, ptr %[[BINDING_BASE_ADDR]], i32 3 -! CHECK: %[[LOADED_BINDING:.*]] = load %_QM__fortran_type_infoTbinding, ptr %[[BINDING_PTR]] -! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = extractvalue %_QM__fortran_type_infoTbinding %[[LOADED_BINDING]], 0 -! CHECK: %[[FUNC_ADDR:.*]] = extractvalue %_QM__fortran_builtinsT__builtin_c_funptr %[[BUILTIN_FUNC_PTR]], 0 -! CHECK: %[[FUNC_PTR:.*]] = inttoptr i64 %[[FUNC_ADDR]] to ptr -! CHECK: %[[RET:.*]] = call i32 %[[FUNC_PTR]](ptr %[[CLASS]]) -! CHECK: store i32 %[[RET]], ptr %[[I]] +! CHECK: %[[BOXDESC:.*]] = fir.box_tdesc %[[ARG]] : ([[CLASS]]) -> !fir.tdesc +! CHECK: %[[TYPEDESCPTR:.*]] = fir.convert %[[BOXDESC]] : (!fir.tdesc) -> !fir.ref<[[TYPEINFO:!fir.type<_QM__fortran_type_infoTderivedtype{.*}>]]> +! CHECK: %[[BINDING_FIELD:.*]] = fir.field_index binding, [[TYPEINFO]] +! CHECK: %[[BINDING_BOX_ADDR:.*]] = fir.coordinate_of %[[TYPEDESCPTR]], %[[BINDING_FIELD]] : (!fir.ref<[[TYPEINFO]]>, !fir.field) -> !fir.ref<[[BINDING_BOX_TYPE:.*]]> +! CHECK: %[[BINDING_BOX:.*]] = fir.load %[[BINDING_BOX_ADDR]] : !fir.ref<[[BINDING_BOX_TYPE]]> +! CHECK: %[[BINDING_BASE_ADDR:.*]] = fir.box_addr %[[BINDING_BOX]] : ([[BINDING_BOX_TYPE]]) -> !fir.ptr<[[BINDINGSINFO:.*]]> +! CHECK: %[[BINDING_PTR:.*]] = fir.coordinate_of %[[BINDING_BASE_ADDR]], %c3 : (!fir.ptr<[[BINDINGSINFO]]>, index) -> !fir.ref<[[BINDINGINFO:.*]]> +! CHECK: %[[PROC_FIELD:.*]] = fir.field_index proc, [[BINDINGINFO]] +! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = fir.coordinate_of %[[BINDING_PTR]], %[[PROC_FIELD]] : ({{.*}}) -> !fir.ref<[[BUILTIN_FUNC_TYPE:.*]]> +! CHECK: %[[ADDRESS_FIELD:.*]] = fir.field_index __address, [[BUILTIN_FUNC_TYPE]] +! CHECK: %[[FUNC_ADDR_PTR:.*]] = fir.coordinate_of %[[BUILTIN_FUNC_PTR]], %[[ADDRESS_FIELD]] +! CHECK: %[[FUNC_ADDR:.*]] = fir.load %[[FUNC_ADDR_PTR]] : !fir.ref +! CHECK: %[[FUNC_PTR:.*]] = fir.convert %[[FUNC_ADDR]] : (i64) -> (([[CLASS]]) -> i32) +! CHECK: %[[RES:.*]] = fir.call %[[FUNC_PTR]](%[[ARG]]) : ([[CLASS]]) -> i32 ! Check dynamic dispatch of call with passed-object and additional argument -! CHECK: store float 2.500000e+00, ptr %[[REAL]] -! CHECK: %[[LOADED_CLASS:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[CLASS]] -! CHECK: %[[TYPEDESCPTR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOADED_CLASS]], 7 -! CHECK: %[[LOADED_TYPEDESC:.*]] = load %_QM__fortran_type_infoTderivedtype, ptr %[[TYPEDESCPTR]] -! CHECK: %[[DT:.*]] = extractvalue %_QM__fortran_type_infoTderivedtype %[[LOADED_TYPEDESC]], 0 -! CHECK: %[[BINDING_BASE_ADDR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } %[[DT]], 0 -! CHECK: %[[BINDING_PTR:.*]] = getelementptr %_QM__fortran_type_infoTbinding, ptr %[[BINDING_BASE_ADDR]], i32 6 -! CHECK: %[[LOADED_BINDING:.*]] = load %_QM__fortran_type_infoTbinding, ptr %[[BINDING_PTR]] -! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = extractvalue %_QM__fortran_type_infoTbinding %[[LOADED_BINDING]], 0 -! CHECK: %[[FUNC_ADDR:.*]] = extractvalue %_QM__fortran_builtinsT__builtin_c_funptr %[[BUILTIN_FUNC_PTR]], 0 -! CHECK: %[[FUNC_PTR:.*]] = inttoptr i64 %[[FUNC_ADDR]] to ptr -! CHECK: call void %[[FUNC_PTR]](ptr %[[CLASS]], ptr %[[REAL]]) +! CHECK: %[[BOXDESC:.*]] = fir.box_tdesc %[[ARG]] : ([[CLASS]]) -> !fir.tdesc +! CHECK: %[[TYPEDESCPTR:.*]] = fir.convert %[[BOXDESC]] : (!fir.tdesc) -> !fir.ref<[[TYPEINFO:!fir.type<_QM__fortran_type_infoTderivedtype{.*}>]]> +! CHECK: %[[BINDING_FIELD:.*]] = fir.field_index binding, [[TYPEINFO]] +! CHECK: %[[BINDING_BOX_ADDR:.*]] = fir.coordinate_of %[[TYPEDESCPTR]], %[[BINDING_FIELD]] : (!fir.ref<[[TYPEINFO]]>, !fir.field) -> !fir.ref<[[BINDING_BOX_TYPE:.*]]> +! CHECK: %[[BINDING_BOX:.*]] = fir.load %[[BINDING_BOX_ADDR]] : !fir.ref<[[BINDING_BOX_TYPE]]> +! CHECK: %[[BINDING_BASE_ADDR:.*]] = fir.box_addr %[[BINDING_BOX]] : ([[BINDING_BOX_TYPE]]) -> !fir.ptr<[[BINDINGSINFO:.*]]> +! CHECK: %[[BINDING_PTR:.*]] = fir.coordinate_of %[[BINDING_BASE_ADDR]], %c6 : (!fir.ptr<[[BINDINGSINFO]]>, index) -> !fir.ref<[[BINDINGINFO:.*]]> +! CHECK: %[[PROC_FIELD:.*]] = fir.field_index proc, [[BINDINGINFO]] +! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = fir.coordinate_of %[[BINDING_PTR]], %[[PROC_FIELD]] : ({{.*}}) -> !fir.ref<[[BUILTIN_FUNC_TYPE:.*]]> +! CHECK: %[[ADDRESS_FIELD:.*]] = fir.field_index __address, [[BUILTIN_FUNC_TYPE]] +! CHECK: %[[FUNC_ADDR_PTR:.*]] = fir.coordinate_of %[[BUILTIN_FUNC_PTR]], %[[ADDRESS_FIELD]] +! CHECK: %[[FUNC_ADDR:.*]] = fir.load %[[FUNC_ADDR_PTR]] : !fir.ref +! CHECK: %[[FUNC_PTR:.*]] = fir.convert %[[FUNC_ADDR]] : (i64) -> (([[CLASS]], !fir.ref) -> ()) +! CHECK: fir.call %[[FUNC_PTR]](%[[ARG]], %[[REAL]]) : ([[CLASS]], !fir.ref) -> () ! Check dynamic dispatch of a call with NOPASS -! CHECK: %[[LOADED_CLASS:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[CLASS]] -! CHECK: %[[TYPEDESCPTR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOADED_CLASS]], 7 -! CHECK: %[[LOADED_TYPEDESC:.*]] = load %_QM__fortran_type_infoTderivedtype, ptr %[[TYPEDESCPTR]] -! CHECK: %[[DT:.*]] = extractvalue %_QM__fortran_type_infoTderivedtype %[[LOADED_TYPEDESC]], 0 -! CHECK: %[[BINDING_BASE_ADDR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } %[[DT]], 0 -! CHECK: %[[BINDING_PTR:.*]] = getelementptr %_QM__fortran_type_infoTbinding, ptr %[[BINDING_BASE_ADDR]], i32 4 -! CHECK: %[[LOADED_BINDING:.*]] = load %_QM__fortran_type_infoTbinding, ptr %[[BINDING_PTR]] -! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = extractvalue %_QM__fortran_type_infoTbinding %[[LOADED_BINDING]], 0 -! CHECK: %[[FUNC_ADDR:.*]] = extractvalue %_QM__fortran_builtinsT__builtin_c_funptr %[[BUILTIN_FUNC_PTR]], 0 -! CHECK: %[[FUNC_PTR:.*]] = inttoptr i64 %[[FUNC_ADDR]] to ptr -! CHECK: call void %[[FUNC_PTR]]() - -! CHECK: store i32 1, ptr %[[INT32]] -! CHECK: %[[LOADED_CLASS:.*]] = load { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[CLASS]] -! CHECK: %[[TYPEDESCPTR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOADED_CLASS]], 7 -! CHECK: %[[LOADED_TYPEDESC:.*]] = load %_QM__fortran_type_infoTderivedtype, ptr %[[TYPEDESCPTR]] -! CHECK: %[[DT:.*]] = extractvalue %_QM__fortran_type_infoTderivedtype %[[LOADED_TYPEDESC]], 0 -! CHECK: %[[BINDING_BASE_ADDR:.*]] = extractvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] } %[[DT]], 0 -! CHECK: %[[BINDING_PTR:.*]] = getelementptr %_QM__fortran_type_infoTbinding, ptr %[[BINDING_BASE_ADDR]], i32 5 -! CHECK: %[[LOADED_BINDING:.*]] = load %_QM__fortran_type_infoTbinding, ptr %[[BINDING_PTR]] -! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = extractvalue %_QM__fortran_type_infoTbinding %[[LOADED_BINDING]], 0 -! CHECK: %[[FUNC_ADDR:.*]] = extractvalue %_QM__fortran_builtinsT__builtin_c_funptr %[[BUILTIN_FUNC_PTR]], 0 -! CHECK: %[[FUNC_PTR:.*]] = inttoptr i64 %[[FUNC_ADDR]] to ptr -! CHECK: call void %[[FUNC_PTR]](ptr %[[INT32]], ptr %[[CLASS]]) +! CHECK: %[[BOXDESC:.*]] = fir.box_tdesc %[[ARG]] : ([[CLASS]]) -> !fir.tdesc +! CHECK: %[[TYPEDESCPTR:.*]] = fir.convert %[[BOXDESC]] : (!fir.tdesc) -> !fir.ref<[[TYPEINFO:!fir.type<_QM__fortran_type_infoTderivedtype{.*}>]]> +! CHECK: %[[BINDING_FIELD:.*]] = fir.field_index binding, [[TYPEINFO]] +! CHECK: %[[BINDING_BOX_ADDR:.*]] = fir.coordinate_of %[[TYPEDESCPTR]], %[[BINDING_FIELD]] : (!fir.ref<[[TYPEINFO]]>, !fir.field) -> !fir.ref<[[BINDING_BOX_TYPE:.*]]> +! CHECK: %[[BINDING_BOX:.*]] = fir.load %[[BINDING_BOX_ADDR]] : !fir.ref<[[BINDING_BOX_TYPE]]> +! CHECK: %[[BINDING_BASE_ADDR:.*]] = fir.box_addr %[[BINDING_BOX]] : ([[BINDING_BOX_TYPE]]) -> !fir.ptr<[[BINDINGSINFO:.*]]> +! CHECK: %[[BINDING_PTR:.*]] = fir.coordinate_of %[[BINDING_BASE_ADDR]], %c4 : (!fir.ptr<[[BINDINGSINFO]]>, index) -> !fir.ref<[[BINDINGINFO:.*]]> +! CHECK: %[[PROC_FIELD:.*]] = fir.field_index proc, [[BINDINGINFO]] +! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = fir.coordinate_of %[[BINDING_PTR]], %[[PROC_FIELD]] : ({{.*}}) -> !fir.ref<[[BUILTIN_FUNC_TYPE:.*]]> +! CHECK: %[[ADDRESS_FIELD:.*]] = fir.field_index __address, [[BUILTIN_FUNC_TYPE]] +! CHECK: %[[FUNC_ADDR_PTR:.*]] = fir.coordinate_of %[[BUILTIN_FUNC_PTR]], %[[ADDRESS_FIELD]] +! CHECK: %[[FUNC_ADDR:.*]] = fir.load %[[FUNC_ADDR_PTR]] : !fir.ref +! CHECK: %[[FUNC_PTR:.*]] = fir.convert %[[FUNC_ADDR]] : (i64) -> (() -> ()) +! CHECK: fir.call %[[FUNC_PTR]]() : () -> () + +! CHECK: %[[BOXDESC:.*]] = fir.box_tdesc %[[ARG]] : ([[CLASS]]) -> !fir.tdesc +! CHECK: %[[TYPEDESCPTR:.*]] = fir.convert %[[BOXDESC]] : (!fir.tdesc) -> !fir.ref<[[TYPEINFO:!fir.type<_QM__fortran_type_infoTderivedtype{.*}>]]> +! CHECK: %[[BINDING_FIELD:.*]] = fir.field_index binding, [[TYPEINFO]] +! CHECK: %[[BINDING_BOX_ADDR:.*]] = fir.coordinate_of %[[TYPEDESCPTR]], %[[BINDING_FIELD]] : (!fir.ref<[[TYPEINFO]]>, !fir.field) -> !fir.ref<[[BINDING_BOX_TYPE:.*]]> +! CHECK: %[[BINDING_BOX:.*]] = fir.load %[[BINDING_BOX_ADDR]] : !fir.ref<[[BINDING_BOX_TYPE]]> +! CHECK: %[[BINDING_BASE_ADDR:.*]] = fir.box_addr %[[BINDING_BOX]] : ([[BINDING_BOX_TYPE]]) -> !fir.ptr<[[BINDINGSINFO:.*]]> +! CHECK: %[[BINDING_PTR:.*]] = fir.coordinate_of %[[BINDING_BASE_ADDR]], %c5 : (!fir.ptr<[[BINDINGSINFO]]>, index) -> !fir.ref<[[BINDINGINFO:.*]]> +! CHECK: %[[PROC_FIELD:.*]] = fir.field_index proc, [[BINDINGINFO]] +! CHECK: %[[BUILTIN_FUNC_PTR:.*]] = fir.coordinate_of %[[BINDING_PTR]], %[[PROC_FIELD]] : ({{.*}}) -> !fir.ref<[[BUILTIN_FUNC_TYPE:.*]]> +! CHECK: %[[ADDRESS_FIELD:.*]] = fir.field_index __address, [[BUILTIN_FUNC_TYPE]] +! CHECK: %[[FUNC_ADDR_PTR:.*]] = fir.coordinate_of %[[BUILTIN_FUNC_PTR]], %[[ADDRESS_FIELD]] +! CHECK: %[[FUNC_ADDR:.*]] = fir.load %[[FUNC_ADDR_PTR]] : !fir.ref +! CHECK: %[[FUNC_PTR:.*]] = fir.convert %[[FUNC_ADDR]] : (i64) -> ((!fir.ref, [[CLASS]]) -> ()) +! CHECK: fir.call %[[FUNC_PTR]](%[[INT32]], %[[ARG]]) : (!fir.ref, [[CLASS]]) -> () ! CHECK-LABEL: _QMdispatch1Pno_pass_array ! CHECK-LABEL: _QMdispatch1Pno_pass_array_allocatable diff --git a/flang/test/Lower/allocatable-polymorphic.f90 b/flang/test/Lower/allocatable-polymorphic.f90 index b129c7c8cdbe1..c3c01a39b8606 100644 --- a/flang/test/Lower/allocatable-polymorphic.f90 +++ b/flang/test/Lower/allocatable-polymorphic.f90 @@ -586,9 +586,9 @@ program test_alloc ! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[C1_LOAD]], ptr %{{.*}} ! LLVM: %[[GEP_TDESC_C1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %{{.*}}, i32 0, i32 7 ! LLVM: %[[TDESC_C1:.*]] = load ptr, ptr %[[GEP_TDESC_C1]] -! LLVM: %[[ELEM_SIZE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %{{.}}, i32 0, i32 1 +! LLVM: %[[ELEM_SIZE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %{{.*}}, i32 0, i32 1 ! LLVM: %[[ELEM_SIZE:.*]] = load i64, ptr %[[ELEM_SIZE_GEP]] -! LLVM: %[[TYPE_CODE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %{{.}}, i32 0, i32 4 +! LLVM: %[[TYPE_CODE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %{{.*}}, i32 0, i32 4 ! LLVM: %[[TYPE_CODE:.*]] = load i32, ptr %[[TYPE_CODE_GEP]] ! LLVM: %{{.*}} = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } undef, i64 %[[ELEM_SIZE]], 1 ! LLVM: %[[TRUNC_TYPE_CODE:.*]] = trunc i32 %[[TYPE_CODE]] to i8 @@ -600,9 +600,9 @@ program test_alloc ! LLVM: store { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } %[[LOAD_C2]], ptr %{{.*}} ! LLVM: %[[GEP_TDESC_C2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %{{.*}}, i32 0, i32 7 ! LLVM: %[[TDESC_C2:.*]] = load ptr, ptr %[[GEP_TDESC_C2]] -! LLVM: %[[ELEM_SIZE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %{{.}}, i32 0, i32 1 +! LLVM: %[[ELEM_SIZE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %{{.*}}, i32 0, i32 1 ! LLVM: %[[ELEM_SIZE:.*]] = load i64, ptr %[[ELEM_SIZE_GEP]] -! LLVM: %[[TYPE_CODE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %{{.}}, i32 0, i32 4 +! LLVM: %[[TYPE_CODE_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %{{.*}}, i32 0, i32 4 ! LLVM: %[[TYPE_CODE:.*]] = load i32, ptr %[[TYPE_CODE_GEP]] ! LLVM: %{{.*}} = insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] } undef, i64 %[[ELEM_SIZE]], 1 ! LLVM: %[[TRUNC_TYPE_CODE:.*]] = trunc i32 %[[TYPE_CODE]] to i8