This RFC proposes a method for generating linetable information in
Flang. The RFC can be extended in future to cover generation of
full Fortran debug.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Thanks for working on this Kiran
flang/docs/DebugGeneration.md | ||
---|---|---|
52 | Are the fortran types and attributes needed here, or just the MLIR types ? If we need actual Fortran type information, we should probably generate that information while the symbols are still here. | |
57 | Is there something to do for line information regarding inlining, or is this handled by MLIR inlining infrastructure ? | |
59 | Could you elaborate a bit here, is there something specific preventing creating CompileUnitAttr in a pass operating on FuncOp or other operations ? |
Thanks @jeanPerier for the comments.
It is good to discuss further where debug line table info generation should be added.
flang/docs/DebugGeneration.md | ||
---|---|---|
52 | Ideally, for a subroutine foo like the following, program mn integer :: arr(10), cnt call foo(arr, cnt) contains subroutine foo( a, n) integer :: a(:), n end subroutine foo end program If we print the type of the function foo in a debugger we should get something like the following. This is what gfortran seems to be doing. ptype foo type = void (integer(kind=4) (:), integer(kind=4)) Accuracy, here is not important for line table generation. Classic-flang only generates C/llvm level types only. It is probably important for full debug generation and a good debug experience. (gdb) ptype foo type = void (integer*8, integer, integer (187651372366496), uinteger*8) Are you suggesting to do this during the lowering process when symbol information is available? | |
57 | MLIR inlining infrastructure should be handling this for line information. | |
59 | I was thinking that the FIRToLLVMConversion is an Operation level pass, but I see that it is a module pass. What I was trying to say above was the general point that Operation level passes should not in general create or modify things at the module level including, creating the CompileUnitAttr which is for the whole module. An option will be to generate and pass a CompileUnitAttr to the FIRToLLVMConversion pass. Additionally, all the information required like File info, details of the compiler, optimisation level, debug level etc that will be provided by the driver will add unnecessary clutter into the FIRToLLVMConversion pass invocation interface. |
BTW, do you plan to work on this after this doc is accepted?
flang/docs/DebugGeneration.md | ||
---|---|---|
8 |
Can you add the reference to this sentence? "Recently" would be confusing as time goes on. | |
52 | Is it OK to do it after HLFIR is created? | |
63 | editor problem? | |
66 | empty line? |
flang/docs/DebugGeneration.md | ||
---|---|---|
52 |
If we want to print Fortran level signatures, we should generate the signature string at the semantics level. But I am not sure what we want here. I am adding @PeteSteinfeld as a reviewer, he may have some insight regarding debugging expectations. I was not able to get gdb print something relevant for ptype foo here compiling with ifort/gfortran or nvfortran. Even if I make foo external, I get "VOID()". Did you break at a particular point to get the classic-flang output for ptype foo ? The main issue I see though with Fortran level signatures is that they would not give much info on the ABI (descriptors, result hoisted as arguments..., passed by value or reference...). Seeing the actual ABI might be relevant for debugging. | |
59 | OK, thanks for explaining. Given the pass adding the attributes on FuncOp would be "shallow" (in the sense that it would no visit what is inside the FuncOp), I am ok with having it be its own separate pass. I am however not sure that the "CompileUnitAttr" is the same for the whole module from a data structure point of view (I agree its content would be similar though). I thought that operations carrying attributes "owned" them, but I may be wrong here. By the way, I am also not sure we should assume that 1 ModuleOp = 1 compile unit, I think we could imagine that several source files could be "concatenated" into a single ModuleOp in certain case to get better inlining/analysis (I do not have a concrete plan here though). |
Thanks @peixin, @jeanPerier for the review.
I have a WIP patch to implement linetable generation as a pass (https://reviews.llvm.org/D137956). I will go ahead and complete it. Then I plan to do a bit of investigation to answer some questions @jeanPerier asked while we were discussing the hlfir.declare/fir.declare for generating debug for variables. But we do not have long-term plans to implement full debug generation.
flang/docs/DebugGeneration.md | ||
---|---|---|
52 | The results might be dependent on the version of gfortran. The version I tried was 9.4. Classic-flang and nvfortran debug might not be in sync since debug went through a lot of changes in classic-flang. I had to set the breakpoint at foo and then run and print the type. Just pasting here exactly what I did. kircha02@ip-10-252-16-6:~$ nvfortran -g r.f90 kircha02@ip-10-252-16-6:~$ gdb a.out GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2 ... Reading symbols from a.out... (gdb) b foo Breakpoint 1 at 0x400c8c: file r.f90, line 5. (gdb) r ... Breakpoint 1, mn::foo () at r.f90:5 5 subroutine foo( a, n) (gdb) ptype foo type = void (integer*8 (16)) kircha02@ip-10-252-16-6:~$ gfortran -g r.f90 kircha02@ip-10-252-16-6:~$ gdb a.out GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2 ... (gdb) b foo Breakpoint 1 at 0x81c: file r.f90, line 7. (gdb) r ... Breakpoint 1, mn::foo (a=..., n=65535) at r.f90:7 7 end subroutine foo (gdb) ptype foo type = void (integer(kind=4) (:), integer(kind=4)) For the Fortran application developer, information about the ABI is probably not relevant. The Fortran developer would possibly prefer to debug with the original Fortran source constructs. | |
52 | HLFIR probably does not have anything regarding function signatures. Are you suggesting recreating it from the dummy arguments? | |
59 | I will have a look regarding multiple CompileUnits. |
flang/docs/DebugGeneration.md | ||
---|---|---|
52 | Thanks ! I was able to reproduce with another version of gfortran/gdb. I think the issue lied in the gdb version I was using (8.2) that mismatch my gfortran version. Well, if we want Fortran level type signature, I thought it would be more correct to produce these strings from the symbols, and keep them around until debug info attributes are generated. But this may be a problem for outlined functions created by the compiler after that though, so going from the argument FIR type might be easier, the main task being mapping back the kind from the mlir integer/real types. |
flang/docs/DebugGeneration.md | ||
---|---|---|
57 | I second Jean's question. I think DIScopeAttr should be preserved during MLIR inlining, i.e. the debug scope defined by the original function remains to be the debug scope for everything inlined from the function at the call site. So I think attaching the debug information late will result in missing access to the inlined function's signature - the line numbers will be correct for the statements, but one will not be able to print type of the original function. It seems to me that generating FusedLoc during lowering is more suitable. I think the outlining passes should update/create debug information themselves based on what they are doing. For example, the intrinsics simplification pass creates new functions that do not have any association with the source code, because they cannot inherit the line numbers from multiple call sites in general. So I would not expect it to create any debug information. Passes that outline MLIR generated for the source code should create FusedLoc for the new functions and set it up properly, e.g. try to create proper function signature for debugging. I am not against the change proposed in D137956, but I think the long-term solution is to create debug attributes in lowering. |
Thanks for doing this, @kiranchandramohan!
flang/docs/DebugGeneration.md | ||
---|---|---|
22 | Should "debug" read "debug information"? | |
25 | "stacktrace" should read "stacktraces". |
flang/docs/DebugGeneration.md | ||
---|---|---|
57 | Thanks @vzakhari. It is a good point that you bring up regarding preserving the Scope/SubroutineAttr for inlined functions. It seems to be preserved in Clang. The MLIR inliner currently saves the location information for inlining in a generic fashion, an eg. below. This is sufficient to generate the inlinedAt field of DILocation. There could be similar ways using FusedLoc to preserve some information regarding function signatures as well. From a quick look, the Inliner pass did not use the FusedLoc of the callee function when it created the CallSiteLoc after inlining at the call. So I guess some extension is required here (unless I missed something). %0 = arith.addi %arg0, %arg0 : i32 loc(callsite("in.mlir":9:8 at "in.mlir":18:8)) //inlined the line at 9 in the callsite at line 18 I see that there is an Inliner Interface with hooks for dialects to do some analysis and handle the terminator. I don't know whether these are sufficient to do custom actions for modifying the llvm debug attributes. The general question for Flang is whether we want to commit to LLVM debug attributes early in the flow (i.e during lowering) or retain as generic information which can be lowered to LLVM-specific debug attributes either before or during conversion to LLVM dialect. |
flang/docs/DebugGeneration.md | ||
---|---|---|
57 | Thank you for the analysis, Kiran! I am also not completely sure whether the dialects are supposed to adjust the debug attributes during MLIR inlining or MLIR inliner is supposed to preserve the debug scope from the FusedLoc. @rriddle, do you have any insights for this? Overall, it does not look like the CallSiteLoc provides direct access to the original scope or the debug function signature. Also, it is not clear what the location information should be in case of sequential inlining (i.e. f1 inlines into f2, and then f2 inlines into f3) - I think CallSiteLoc is not able to represent this currently, but FusedLoc may be able to do this by representing the hierarchy of scopes in its metadata operand. |
I just want to add that lldb is in-tree and they have an extensive test suite written in Python. If you want to test breakpoints, then lldb may be a option.
Can you add the reference to this sentence? "Recently" would be confusing as time goes on.