diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -948,18 +948,13 @@ }) .Default([](mlir::Type t) { return t; }); assert(declaredType.isa() && "expecting fir.type"); - auto recordType = declaredType.dyn_cast(); - std::string typeDescName = - fir::NameUniquer::getTypeDescriptorName(recordType.getName()); - std::string typeDescBindingTableName = - fir::NameUniquer::getTypeDescriptorBindingTableName( - recordType.getName()); + auto recordType = declaredType.dyn_cast(); // Lookup for the binding table. - auto bindingsIter = bindingTables.find(typeDescBindingTableName); + auto bindingsIter = bindingTables.find(recordType.getName()); if (bindingsIter == bindingTables.end()) return emitError(loc) - << "cannot find binding table for " << typeDescBindingTableName; + << "cannot find binding table for " << recordType.getName(); // Lookup for the binding. const BindingTable &bindingTable = bindingsIter->second; @@ -973,6 +968,8 @@ 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 = @@ -3640,29 +3637,22 @@ return signalPassFailure(); // Reconstruct binding tables for dynamic dispatch. The binding tables - // are defined in FIR from semantics as fir.global operation with region - // initializer. Go through each bining tables and store the procedure name + // are defined in FIR from lowering as fir.dispatch_table operation. + // Go through each binding tables and store the procedure name // and binding index for later use by the fir.dispatch conversion pattern. BindingTables bindingTables; - for (auto globalOp : mod.getOps()) { - if (globalOp.getSymName().contains(bindingTableSeparator)) { - unsigned bindingIdx = 0; - BindingTable bindings; - for (auto addrOp : globalOp.getRegion().getOps()) { - if (fir::isa_char(fir::unwrapRefType(addrOp.getType()))) { - if (auto nameGlobal = - mod.lookupSymbol(addrOp.getSymbol())) { - auto stringLit = llvm::to_vector( - nameGlobal.getRegion().getOps())[0]; - auto procName = - stringLit.getValue().dyn_cast().getValue(); - bindings[procName] = bindingIdx; - ++bindingIdx; - } - } - } - bindingTables[globalOp.getSymName()] = bindings; + for (auto dispatchTableOp : mod.getOps()) { + unsigned bindingIdx = 0; + BindingTable bindings; + if (dispatchTableOp.getRegion().empty()) { + bindingTables[dispatchTableOp.getSymName()] = bindings; + continue; + } + for (auto dtEntry : dispatchTableOp.getBlock().getOps()) { + bindings[dtEntry.getMethod()] = bindingIdx; + ++bindingIdx; } + bindingTables[dispatchTableOp.getSymName()] = bindings; } auto *context = getModule().getContext(); diff --git a/flang/test/Fir/dispatch.f90 b/flang/test/Fir/dispatch.f90 --- a/flang/test/Fir/dispatch.f90 +++ b/flang/test/Fir/dispatch.f90 @@ -32,6 +32,18 @@ procedure, pass(this) :: proc_pass => proc_pass_p2 end type + type, abstract :: a1 + integer a + contains + procedure :: a1_proc + end type + + type, extends(a1) :: a2 + integer b + contains + procedure :: a1_proc => a2_proc + end type + contains subroutine display1_p1(this) @@ -135,6 +147,19 @@ call a(1)%proc_nopass() end subroutine + subroutine a1_proc(this) + class(a1) :: this + end subroutine + + subroutine a2_proc(this) + class(a2) :: this + end subroutine + + subroutine call_a1_proc(p) + class(a1), pointer :: p + call p%a1_proc() + end subroutine + end module program test_type_to_class @@ -250,28 +275,36 @@ ! CHECK-LABEL: _QMdispatch1Pno_pass_array ! CHECK-LABEL: _QMdispatch1Pno_pass_array_allocatable ! CHECK-LABEL: _QMdispatch1Pno_pass_array_pointer +! CHECK-LABEL: _QMdispatch1Pcall_a1_proc ! Check the layout of the binding table. This is easier to do in FIR than in ! LLVM IR. -! BT-LABEL: fir.global linkonce_odr @_QMdispatch1E.v.p1 constant target : !fir.array<7x!fir.type<_QM__fortran_type_infoTbinding{proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>,name:!fir.box>>}>> { -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Paproc) : (!fir.class>) -> () -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Pdisplay1_p1) : (!fir.class>) -> () -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Pdisplay2_p1) : (!fir.class>) -> () -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Pget_value_p1) : (!fir.class>) -> i32 -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Pproc_nopass_p1) : () -> () -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Pproc_pass_p1) : (!fir.ref, !fir.class>) -> () -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Pproc_p1) : (!fir.class>, !fir.ref) -> () +! BT-LABEL: fir.dispatch_table @_QMdispatch1Tp1 { +! BT: fir.dt_entry "aproc", @_QMdispatch1Paproc +! BT: fir.dt_entry "display1", @_QMdispatch1Pdisplay1_p1 +! BT: fir.dt_entry "display2", @_QMdispatch1Pdisplay2_p1 +! BT: fir.dt_entry "get_value", @_QMdispatch1Pget_value_p1 +! BT: fir.dt_entry "proc_nopass", @_QMdispatch1Pproc_nopass_p1 +! BT: fir.dt_entry "proc_pass", @_QMdispatch1Pproc_pass_p1 +! BT: fir.dt_entry "proc_with_values", @_QMdispatch1Pproc_p1 ! BT: } -! BT-LABEL: fir.global linkonce_odr @_QMdispatch1E.v.p2 constant target : !fir.array<8x!fir.type<_QM__fortran_type_infoTbinding{proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>,name:!fir.box>>}>> { -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Paproc) : (!fir.class>) -> () -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Pdisplay1_p2) : (!fir.class>) -> () -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Pdisplay2_p2) : (!fir.class>) -> () -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Pget_value_p2) : (!fir.class>) -> i32 -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Pproc_nopass_p2) : () -> () -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Pproc_pass_p2) : (!fir.ref, !fir.class>) -> () -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Pproc_p2) : (!fir.class>, !fir.ref) -> () -! BT: %{{.*}} = fir.address_of(@_QMdispatch1Pdisplay3) : (!fir.class>) -> () +! BT-LABEL: fir.dispatch_table @_QMdispatch1Ta1 { +! BT: fir.dt_entry "a1_proc", @_QMdispatch1Pa1_proc ! BT: } +! BT-LABEL: fir.dispatch_table @_QMdispatch1Ta2 extends("_QMdispatch1Ta1") { +! BT: fir.dt_entry "a1_proc", @_QMdispatch1Pa2_proc +! BT: } + +! BT-LABEL: fir.dispatch_table @_QMdispatch1Tp2 extends("_QMdispatch1Tp1") { +! BT: fir.dt_entry "aproc", @_QMdispatch1Paproc +! BT: fir.dt_entry "display1", @_QMdispatch1Pdisplay1_p2 +! BT: fir.dt_entry "display2", @_QMdispatch1Pdisplay2_p2 +! BT: fir.dt_entry "get_value", @_QMdispatch1Pget_value_p2 +! BT: fir.dt_entry "proc_nopass", @_QMdispatch1Pproc_nopass_p2 +! BT: fir.dt_entry "proc_pass", @_QMdispatch1Pproc_pass_p2 +! BT: fir.dt_entry "proc_with_values", @_QMdispatch1Pproc_p2 +! BT: fir.dt_entry "display3", @_QMdispatch1Pdisplay3 +! BT: }