| Issue |
176444
|
| Summary |
Debuginfo lost for local variables in nested lexical blocks on rust generated code for powerpc64le
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
jchecahi
|
Local variables defined in nested lexical blocks lose their debug info on powerpc64le but not on x86_64 when compiling identical LLVM IR, when using any level of optimization.
The problematic LLVM IR is generated from this Rust code (https://rust.godbolt.org/z/5rP4Kj6nj):
```llvm
; ModuleID = 'example.806d4a770b6a1559-cgu.0'
source_filename = "example.806d4a770b6a1559-cgu.0"
target datalayout = "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512"
target triple = "powerpc64le-unknown-linux-gnu"
; Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: read) uwtable
define noundef i32 @test_ref(ptr noalias noundef readonly align 8 captures(none) dereferenceable(16) %ref_foo) unnamed_addr #0 !dbg !6 {
start:
#dbg_value(ptr %ref_foo, !22, !DIExpression(), !31)
#dbg_value(ptr %ref_foo, !23, !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value), !32)
#dbg_value(ptr %ref_foo, !26, !DIExpression(), !33)
#dbg_value(ptr %ref_foo, !29, !DIExpression(DW_OP_plus_uconst, 12, DW_OP_stack_value), !34)
%0 = getelementptr inbounds nuw i8, ptr %ref_foo, i64 8, !dbg !35
%_0 = load i32, ptr %0, align 8, !dbg !35, !noundef !20
ret i32 %_0, !dbg !36
}
attributes #0 = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: read) uwtable "probe-stack"="inline-asm" "target-cpu"="ppc64le" }
!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}
!llvm.dbg.cu = !{!4}
!0 = !{i32 8, !"PIC Level", i32 2}
!1 = !{i32 7, !"Dwarf Version", i32 4}
!2 = !{i32 2, !"Debug Info Version", i32 3}
!3 = !{!"rustc version 1.92.0 (ded5c06cf 2025-12-08)"}
!4 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !5, producer: "clang LLVM (rustc version 1.92.0 (ded5c06cf 2025-12-08))", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
!5 = !DIFile(filename: "/app/example.rs/@/example.806d4a770b6a1559-cgu.0", directory: "/app")
!6 = distinct !DISubprogram(name: "test_ref", scope: !8, file: !7, line: 9, type: !9, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !4, templateParams: !20, retainedNodes: !21)
!7 = !DIFile(filename: "example.rs", directory: "/app", checksumkind: CSK_MD5, checksum: "708e0ef884439ceded7480119c12616a")
!8 = !DINamespace(name: "example", scope: null)
!9 = !DISubroutineType(types: !10)
!10 = !{!11, !12}
!11 = !DIBasicType(name: "i32", size: 32, encoding: DW_ATE_signed)
!12 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "&example::Foo", baseType: !13, size: 64, align: 64, dwarfAddressSpace: 0)
!13 = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", scope: !8, file: !14, size: 128, align: 64, flags: DIFlagPublic, elements: !15, templateParams: !20, identifier: "2473027896704476d31bc2782fb3cf7")
!14 = !DIFile(filename: "<unknown>", directory: "")
!15 = !{!16, !17, !19}
!16 = !DIDerivedType(tag: DW_TAG_member, name: "__0", scope: !13, file: !14, baseType: !11, size: 32, align: 32, offset: 64, flags: DIFlagPrivate)
!17 = !DIDerivedType(tag: DW_TAG_member, name: "__1", scope: !13, file: !14, baseType: !18, size: 64, align: 64, flags: DIFlagPrivate)
!18 = !DIBasicType(name: "i64", size: 64, encoding: DW_ATE_signed)
!19 = !DIDerivedType(tag: DW_TAG_member, name: "__2", scope: !13, file: !14, baseType: !11, size: 32, align: 32, offset: 96, flags: DIFlagPrivate)
!20 = !{}
!21 = !{!22, !23, !26, !29}
!22 = !DILocalVariable(name: "ref_foo", arg: 1, scope: !6, file: !7, line: 9, type: !12)
!23 = !DILocalVariable(name: "ref_v0", scope: !24, file: !7, line: 10, type: !25, align: 64)
!24 = distinct !DILexicalBlock(scope: !6, file: !7, line: 10, column: 5)
!25 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "&i32", baseType: !11, size: 64, align: 64, dwarfAddressSpace: 0)
!26 = !DILocalVariable(name: "ref_v1", scope: !27, file: !7, line: 11, type: !28, align: 64)
!27 = distinct !DILexicalBlock(scope: !24, file: !7, line: 11, column: 5)
!28 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "&i64", baseType: !18, size: 64, align: 64, dwarfAddressSpace: 0)
!29 = !DILocalVariable(name: "ref_v2", scope: !30, file: !7, line: 12, type: !25, align: 64)
!30 = distinct !DILexicalBlock(scope: !27, file: !7, line: 12, column: 5)
!31 = !DILocation(line: 0, scope: !6)
!32 = !DILocation(line: 10, column: 9, scope: !24)
!33 = !DILocation(line: 11, column: 9, scope: !27)
!34 = !DILocation(line: 12, column: 9, scope: !30)
!35 = !DILocation(line: 13, column: 5, scope: !30)
!36 = !DILocation(line: 14, column: 2, scope: !6)
```
The generated LLVM IR is identical for both architectures. When inspecting the resulting object files:
- x86_64: All 4 variables (ref_foo, ref_v0, ref_v1, ref_v2) appear in DWARF
- PowerPC64LE: Only ref_foo appears; ref_v0, ref_v1, ref_v2 are missing
(Full debuginfo seen in https://rust.godbolt.org/z/eEnEhdEG8)
The missing variables are defined in nested `DILexicalBlock` scopes and have `dbg.value` with expressions like `DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value)`.
This issue seems to be related to how PowerPC's optimization passes handle lexical scopes that contain only debug intrinsics with no executable code.
I attempted some investigation, but I'm no expert in the matter. This C equivalent reproducer with nested blocks (https://godbolt.org/z/cnGx7bT5x) preserves the variables as expected in both x86_64 and ppc64le. The LLVM IR is almost identical to the one produced from rust, yet in this case the debuginfo is not dropped.
### Environment
- LLVM: llvm-20.1.8-4.fc42, llvm-21.1.8-1.fc43
- Target: powerpc64le-unknown-linux-gnu
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs