[llvm] [RFC] Emit dwarf data for signature-changed or new functions (PR #157349)

Vladislav Dzhidzhoev via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 24 10:22:18 PDT 2025


dzhidzhoev wrote:

> It could be a case. In order to avoid that, I'd change EmitChangedFuncDebugInfo in the following way:
> 
> 1. When a mismatch between function arguments/return type and original DISubprogram's arguments/return type is detected, a new "trampoline" DISubprogram should be created, which will have updated arguments/return type.
> 2. A new "trampoline" DISubprogram should be attached to the function _instead_ of the original one (but the trampoline subprogram preserves the name/linkage name of the original subprogram in targetFuncName field).
> 3. All DILocations of the function should be updated in the way as if the original DISubprogram is "inlined" into the "trampoline" DISubprogram, simliarly to what is done in llvm/lib/Transforms/Utils/InlineFunction.cpp:{fixupLineNumbers, fixupAssignments} (probably we can just reuse functions of InlineFunction.cpp).
> 4. As the result, we should have the following DIEs:
> 
> * An abstract DIE for the original DISubprogram with original arguments/return type.
> * Concrete DIE for the "trampoline" DISubprogram, having DW_AT_linkage_name, DW_AT_low_pc, DW_AT_high_pc corresponding to the function with modified arguments/return type, and with a children DW_TAG_inlined_subproutine, which will refer to abstract DIE of the original DISubprogram.
> 
> If a function, its DISubprogram and the related metadata is updated according to (1)-(3), no changes/few changes will be needed in DwarfDebug to achieve (4), IMO.

Let's illustrate that with an example.
If we have a function like 
```
define dso_local noundef i32 @_Z3mulii(i32 noundef %0, i32 noundef %1) local_unnamed_addr #0 !dbg !0 {
    #dbg_value(i32 %0, !5, !DIExpression(), !7)
    #dbg_value(i32 %1, !6, !DIExpression(), !7)
  %3 = mul nsw i32 %1, %0, !dbg !8
  ret i32 %3, !dbg !9
}

!0 = distinct !DISubprogram(name: "mul", linkageName: "_Z3mulii", line: 2, type: !1, spFlags: DISPFlagDefinition | DISPFlagOptimized, retainedNodes: !4)
!1 = !DISubroutineType(types: !2)
!2 = !{!3, !3, !3}
!3 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!4 = !{!5, !6}
!5 = !DILocalVariable(name: "num1", arg: 1, scope: !0, line: 2, type: !3)
!6 = !DILocalVariable(name: "num2", arg: 2, scope: !0, line: 2, type: !3)
!7 = !DILocation(line: 0, scope: !10)
!8 = !DILocation(line: 3, column: 17, scope: !0, atomGroup: 1, atomRank: 2)
!9 = !DILocation(line: 3, column: 5, scope: !0, atomGroup: 1, atomRank: 1)
```

And some LLVM passes transform it into something like:
```
define dso_local noundef i32 @_Z3mulii(i32 noundef %0) local_unnamed_addr #0 !dbg !0 {
    #dbg_value(i32 %0, !5, !DIExpression(), !7)
    #dbg_value(i32 undef, !6, !DIExpression(), !7)
  %3 = mul nsw i32 %0, %0, !dbg !8
  ret i32 %3, !dbg !9
}

; Function signature is not synced with metadata.
!0 = distinct !DISubprogram(name: "mul", linkageName: "_Z3mulii", line: 2, type: !1, spFlags: DISPFlagDefinition | DISPFlagOptimized, retainedNodes: !4)
!1 = !DISubroutineType(types: !2)
!2 = !{!3, !3, !3}
!3 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!4 = !{!5, !6}
!5 = !DILocalVariable(name: "num1", arg: 1, scope: !0, line: 2, type: !3)
!6 = !DILocalVariable(name: "num2", arg: 2, scope: !0, line: 2, type: !3)
!7 = !DILocation(line: 0, scope: !10)
!8 = !DILocation(line: 3, column: 17, scope: !0, atomGroup: 1, atomRank: 2)
!9 = !DILocation(line: 3, column: 5, scope: !0, atomGroup: 1, atomRank: 1)
```

Then, EmitChangedFuncDebugInfo should transform debug info metadata into something like:
```
define dso_local noundef i32 @_Z3mulii(i32 noundef %0) local_unnamed_addr #0 !dbg !0 {
    #dbg_value(i32 %0, !14, !DIExpression(), !15)
    #dbg_value(i32 %0, !5, !DIExpression(), !16)
    #dbg_value(i32 %0, !6, !DIExpression(), !16)
  %3 = mul nsw i32 %0, %0, !dbg !18
  ret i32 %3, !dbg !19
}

; Metadata for the original function.
!0 = distinct !DISubprogram(name: "mul", line: 2, type: !1, spFlags: DISPFlagDefinition | DISPFlagOptimized, retainedNodes: !4)
!1 = !DISubroutineType(types: !2)
!2 = !{!3, !3, !3}
!3 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!4 = !{!5, !6}
!5 = !DILocalVariable(name: "num1", arg: 1, scope: !0, line: 2, type: !3)
!6 = !DILocalVariable(name: "num2", arg: 2, scope: !0, line: 2, type: !3)
!8 = !DILocation(line: 3, column: 17, scope: !0, atomGroup: 1, atomRank: 2)
!9 = !DILocation(line: 3, column: 5, scope: !0, atomGroup: 1, atomRank: 1)

; Metadata for modified function.
!10 = distinct !DISubprogram(name: "mul", linkageName: "_Z3mulii" line: 6, type: !11, spFlags: DISPFlagDefinition | DISPFlagOptimized, retainedNodes: !13)
!11 = !DISubroutineType(types: !12)
!12 = !{!3, !3}
!13 = !{!14}
!14 = !DILocalVariable(name: "num1", arg: 1, scope: !10, line: 6, type: !3)
!15 = !DILocation(line: 0, scope: !10)
!16 = !DILocation(line: 0, scope: !0, inlinedAt)
!17 = distinct !DILocation(line: 0, scope: !10)
!18 = !DILocation(line: 3, column: 17, scope: !0, inlinedAt: !17, atomGroup: 1, atomRank: 2)
!19 = !DILocation(line: 7, column: 5, scope: !0, inlinedAt: !17, atomGroup: 1, atomRank: 1)
```

Which should cause the following DWARF to be produced:
```
LOC_A: DW_TAG_subprogram
                DW_AT_name	("mul")
                DW_AT_decl_file	("/app/example.cpp")
                DW_AT_decl_line	(2)
                DW_AT_type	(0x0000003d "int")
                DW_AT_inline	(DW_INL_inlined)

      LOC_B: DW_TAG_formal_parameter
                  DW_AT_name	("num1")
                  DW_AT_decl_file	("/app/example.cpp")
                  DW_AT_decl_line	(2)
                  DW_AT_type	(0x0000003d "int")
      LOC_C: DW_TAG_formal_parameter
                  DW_AT_name	("num2")
                  DW_AT_decl_file	("/app/example.cpp")
                  DW_AT_decl_line	(2)
                  DW_AT_type	(0x0000003d "int")
     NULL

DW_TAG_subprogram
                DW_AT_low_pc	(0x0000000000000000)
                DW_AT_high_pc	(0x0000000000000006)
                DW_AT_frame_base	(DW_OP_reg7 RSP)
                DW_AT_call_all_calls	(true)
                DW_AT_linkage_name	("_Z3mulii")
                DW_AT_name	("mul")
                ...

              DW_TAG_formal_parameter
                  DW_AT_location	(DW_OP_reg5 RDI)
                  DW_AT_name	("num1")
                  DW_AT_decl_file	("/app/example.cpp")
                  DW_AT_decl_line	(6)
                  DW_AT_type	(0x0000003d "int")

              DW_TAG_inlined_subroutine
                  DW_AT_abstract_origin	(LOC_A "mul")
                  DW_AT_low_pc	(0x0000000000000002)
                  DW_AT_high_pc	(0x0000000000000005)
                  DW_AT_call_file	("/app/example.cpp")
                  DW_AT_call_line	(7)
                  DW_AT_call_column	(12)

                    DW_TAG_formal_parameter
                            DW_AT_location	(DW_OP_reg5 RDI)
                            DW_AT_abstract_origin	(LOC_B "num1")
                    DW_TAG_formal_parameter
                            DW_AT_location	(DW_OP_reg5 RDI)
                            DW_AT_abstract_origin	(LOC_C "num2")
             NULL
NULL

```

https://github.com/llvm/llvm-project/pull/157349


More information about the llvm-commits mailing list