[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