This supports the codegen for procedure pointer component in
BoxedProcedure pass. Also fix the FIR in ProcedurePointer.md so that
all the cases can be run using tco to generate the LLVM IR.
Details
Diff Detail
Event Timeline
flang/lib/Optimizer/CodeGen/TypeConverter.h | ||
---|---|---|
63 ↗ | (On Diff #471141) | This TODO is quite old. The fir.boxproc type is actually being rewritten in lib/Optimizer/CodeGen/BoxedProcedure.cpp, and I think it may be better to also do the same for fir.ref<fir.boxproc<T>> to be consistent with the choice regarding what a fir.boxproc should be. |
flang/lib/Optimizer/CodeGen/TypeConverter.h | ||
---|---|---|
63 ↗ | (On Diff #471141) | I guess this is added either for the unimplemented codegen of fir.emboxproc, fir.boxproc_host, fir.unboxproc, or for the conversion of BOXPROCType in procedure component. If BoxedProcedurePass is mature. All these unimplemented codegen may can be removed.
I don't get it. fir.ref<fir.boxproc<T>> is converted to mlir::LLVM::LLVMPointerType::get(convertType(ty.getEleTy())), which is expected. |
flang/lib/Optimizer/CodeGen/TypeConverter.h | ||
---|---|---|
63 ↗ | (On Diff #471141) | What I am saying is that right now, the place that dictates how a fir.boxproc<T> is translated is lib/Optimizer/CodeGen/BoxedProcedure.cpp (here https://github.com/llvm/llvm-project/blob/67d0d7ac0acb0665d6a09f61278fbcf51f0114c2/flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp#L95), so I do not really understand why a conversion needs to be defined again here. From a single point of truth perspective, I would prefer BoxedProcedure.cpp to be the only place dealing with fir.boxproc<T>. |
From a single point of truth perspective, I would prefer BoxedProcedure.cpp to be the only place dealing with fir.boxproc<T>.
Let me try this.
Support codegen of procedure pointer component by support type conversion for boxproc in derived type.
flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp | ||
---|---|---|
136 | Are you sure it is allowed to update the data of an MLIR type on the flight like this ? It is not quite clear to me at which scale the type instances are shared, and if we could ever run in weird bug due to multithreaded passes while updating the storage of an mlir type instance like this. |
Are you sure it is allowed to update the data of an MLIR type on the flight like this ?
It is not quite clear to me at which scale the type instances are shared, and if we could ever run in weird bug due to multithreaded passes while updating the storage of an mlir type> instance like this.
I didn't know these passes can be run in parallel. Thanks for letting me know. Then, one new record type can be created with one mangled name. For performance consideration, only convert the record type once.
I am not very found that a new record type with a new name has to be created, but I do not really see another nice solution. The only alternative I can think of would be to add an integer "version" flag in the recordType that could be increased every time some pass updates derived type, so that we do not touch the mangled name, but an extra string also makes some sense, although we will probably want to make them "offical" in the RecordType definition and add a way to find back the to the original name.
flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp | ||
---|---|---|
129 | Does this work OK with the codegen code that is later using the mangled derived type names to find the derived type descriptor global ? | |
140 | You should probably assert that the original type had no length parameters/add a TODO so that we do not forget about propagating those here. |
Yes, I agree. Usually, adding one flag should be avoided if there is no other way. The record type name _QFtestTmatrix is actually already mangled before codegen. I also checked interoperability with C (Fortran 2018 18.3.3(3) Note 3), and there is no need to keep its original type name. So, there is no real need to keep this type name. What do you think?
flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp | ||
---|---|---|
129 | I don't think out any case which will fail with this change. The test case in flang/test/Fir/boxproc-2.fir can be run using tco to generate LLVM IR. Here is the output with this patch: ; ModuleID = 'FIRModule' source_filename = "FIRModule" target triple = "aarch64-unknown-linux-gnu" %_QFtestTmatrixUnboxProc = type { [2 x [2 x float]], ptr } declare ptr @malloc(i64) declare void @free(ptr) declare void @foo1(ptr) declare void @foo2(ptr) define void @proc_pointer_component(ptr %0, ptr %1) { %3 = alloca %_QFtestTmatrixUnboxProc, i64 1, align 8 %4 = getelementptr %_QFtestTmatrixUnboxProc, ptr %3, i32 0, i32 1 store ptr %0, ptr %4, align 8 %5 = load ptr, ptr %4, align 8 %6 = call float %5(ptr %1) ret void } !llvm.module.flags = !{!0} !0 = !{i32 2, !"Debug Info Version", i32 3} | |
140 | I don't get it. Why does it need one assert or TODO if there is no length parameter? In addition, will there be special handling here if there is length parameter? Will rec.finalize(ps, cs) not work? |
The type name is important for polymorphic entities. It is used to find the type descriptor and the binding tables. So we at least need a way to find back the original type name so we can use the functions in flang/include/flang/Optimizer/Support/InternalNames.h like getTypeDescriptorName and getTypeDescriptorBindingTableName that takes the mangled type name as input.
@clementval Thanks for the notice. I took a look at the case of polymorphic entities. The typeDesc and typeDescBindingTable do not have the boxproc component, and they won't be converted, so the only problem is how to handle the function getDerivedTypeObjectName. The simple method is unwrap the mangledTypeName by removing the suffix string UnboxProc before calling fir::NameUniquer::deconstruct(mangledTypeName). Is that OK with you?
Yeah that should be fine. Can you define the suffix in InternalName.h so it is centralized?
Like this or smth similar.
static constexpr llvm::StringRef boxprocSuffix = "UnboxProc";
flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp | ||
---|---|---|
129 | This test case does not exercise an operation that will require retrieving the type descriptor in codegen. Embox would expose that need: func.func private @bar(!fir.box<!fir.type<_QFtestTmatrix{element:!fir.array<2x2xf32>,solve:!fir.boxproc<() -> ()>}>>) -> () func.func @proc_pointer_component() { %0 = fir.alloca !fir.type<_QFtestTmatrix{element:!fir.array<2x2xf32>,solve:!fir.boxproc<() -> ()>}> %1 = fir.embox %0 : (!fir.ref<!fir.type<_QFtestTmatrix{element:!fir.array<2x2xf32>,solve:!fir.boxproc<() -> ()>}>>) -> !fir.box<!fir.type<_QFtestTmatrix{element:!fir.array<2x2xf32>,solve:!fir.boxproc<() -> ()>}>> call @bar(%1) : (!fir.box<!fir.type<_QFtestTmatrix{element:!fir.array<2x2xf32>,solve:!fir.boxproc<() -> ()>}>>) -> () return } | |
140 | Sorry, I look too quickly, you are indeed copying them, no need to add a TODO. |
flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp | ||
---|---|---|
129 | This case has the same problem as the polymorphic entities. This will be handled later. Thanks for this case. BTW, I hit one error for the following case: func.func private @bar(!fir.box<!fir.type<_QFtestTmatrix2{element:!fir.array<2x2xf32>}>>) -> () func.func @proc_pointer_component2() { %0 = fir.alloca !fir.type<_QFtestTmatrix2{element:!fir.array<2x2xf32>}> %1 = fir.embox %0 : (!fir.ref<!fir.type<_QFtestTmatrix2{element:!fir.array<2x2xf32>}>>) -> !fir.box<!fir.type<_QFtestTmatrix2{element:!fir.array<2x2xf32>}>> call @bar(%1) : (!fir.box<!fir.type<_QFtestTmatrix2{element:!fir.array<2x2xf32>}>>) -> () return } $ tco case01.fir loc("case01.fir":87:8): error: runtime derived type info descriptor was not generated @clementval Is this one bug or TODO or invalid input? |
flang/lib/Optimizer/CodeGen/BoxedProcedure.cpp | ||
---|---|---|
129 | Input is invalid since it does not contains the fir.global that represent the type descriptor. |
Does this work OK with the codegen code that is later using the mangled derived type names to find the derived type descriptor global ?