[llvm] [DWARF] Disable generation of cross-CU references for DWARF V2 (PR #192516)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 16 12:07:48 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-debuginfo
Author: Nadharm
<details>
<summary>Changes</summary>
Though LLVM's treatment of DW_FORM_ref_addr for DWARF V2 follows the spec, it does not follow the recommendation of the FAQ. This works for consumers which expect the V2 spec definition, but breaks those which expect producers to follow the FAQ.
The DWARF V2 spec defines DW_FORM_ref_addr as:
"... the address of any debugging information entry within the same executable or shared object... This type of reference (DW_FORM_ref_addr) is the size of an address on the target architecture..."
And the DWARF FAQ says:
"The DWARF V2 definition never made any sense and was a mistake in the DWARF V2 specification: the field DW_FORM_ref_addr defines is an offset, not an address. If you are producing DWARF V2, please use the DWARF V3 definition of DW_FORM_ref_addr."
Currently for DWARF V2, LLVM continues using address-sizing rather than fully adopting the V3 definition (4 bytes for DWARF32, 8 bytes for DWARF64) as directed by the FAQ.
Given that the DWARF V2 is rather old and that the worst case size increase would match that of a non-LTO compilation flow, this MR disables de-duplication of DIEs across CUs to prevent the generation of cross-CU references using DW_FORM_ref_addr for DWARF V2.
Assisted-by: Claude Code (test)
---
Full diff: https://github.com/llvm/llvm-project/pull/192516.diff
2 Files Affected:
- (modified) llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp (+7)
- (added) llvm/test/DebugInfo/Generic/cross-cu-no-ref-addr-dwarf-v2.ll (+47)
``````````diff
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index 35663f2acaae9..98726c30af952 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -185,6 +185,13 @@ bool DwarfUnit::isShareableAcrossCUs(const DINode *D) const {
// level already) but may be implementable for some value in projects
// building multiple independent libraries with LTO and then linking those
// together.
+
+ // Prevent generation of cross-CU references for DWARF v2 due to conflicts
+ // resulting from the FAQ recommendation: "If you are producing DWARF V2,
+ // please use the DWARF V3 definition of DW_FORM_ref_addr."
+ // (https://dwarfstd.org/faq.html)
+ if (DD->getDwarfVersion() == 2)
+ return false;
if (isDwoUnit() && !DD->shareAcrossDWOCUs())
return false;
return (isa<DIType>(D) ||
diff --git a/llvm/test/DebugInfo/Generic/cross-cu-no-ref-addr-dwarf-v2.ll b/llvm/test/DebugInfo/Generic/cross-cu-no-ref-addr-dwarf-v2.ll
new file mode 100644
index 0000000000000..0ed4fac68b99b
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/cross-cu-no-ref-addr-dwarf-v2.ll
@@ -0,0 +1,47 @@
+; RUN: %llc_dwarf -dwarf-version=3 -O0 -filetype=obj < %s | llvm-dwarfdump -v -debug-info - | FileCheck --check-prefix=CHECK-V3 %s
+; RUN: %llc_dwarf -dwarf-version=2 -O0 -filetype=obj < %s | llvm-dwarfdump -v -debug-info - | FileCheck --check-prefix=CHECK-V2 --implicit-check-not=DW_FORM_ref_addr %s
+
+; DWARF V3: Expect cross-CU type deduplication resulting in only one "int"
+; definition and a DW_FORM_ref_addr.
+
+; CHECK-V3: DW_TAG_compile_unit
+; CHECK-V3: DW_AT_name{{.*}}"a.cpp"
+; CHECK-V3: DW_TAG_base_type
+; CHECK-V3: DW_AT_name{{.*}}"int"
+; CHECK-V3: DW_TAG_compile_unit
+; CHECK-V3: DW_AT_name{{.*}}"b.cpp"
+; CHECK-V3: DW_AT_type [DW_FORM_ref_addr]
+
+; DWARF V2: cross-CU type deduplication disabled resulting in two "int"
+; definitions and no DW_FORM_ref_addr (cross-CU ref)
+
+; CHECK-V2: DW_TAG_compile_unit
+; CHECK-V2: DW_AT_name{{.*}}"a.cpp"
+; CHECK-V2: DW_TAG_base_type
+; CHECK-V2: DW_AT_name{{.*}}"int"
+; CHECK-V2: DW_TAG_compile_unit
+; CHECK-V2: DW_AT_name{{.*}}"b.cpp"
+; CHECK-V2: DW_TAG_base_type
+; CHECK-V2: DW_AT_name{{.*}}"int"
+
+ at x = global i32 0, !dbg !0
+ at y = global i32 0, !dbg !7
+
+!llvm.dbg.cu = !{!2, !9}
+!llvm.module.flags = !{!13, !14}
+!llvm.ident = !{!15}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "x", scope: !2, file: !3, line: 1, type: !5, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4)
+!3 = !DIFile(filename: "a.cpp", directory: "/tmp/dbginfo")
+!4 = !{!0}
+!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!7 = !DIGlobalVariableExpression(var: !8, expr: !DIExpression())
+!8 = distinct !DIGlobalVariable(name: "y", scope: !9, file: !10, line: 1, type: !5, isLocal: false, isDefinition: true)
+!9 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !10, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !11)
+!10 = !DIFile(filename: "b.cpp", directory: "/tmp/dbginfo")
+!11 = !{!7}
+!13 = !{i32 2, !"Dwarf Version", i32 4}
+!14 = !{i32 2, !"Debug Info Version", i32 3}
+!15 = !{!"clang"}
``````````
</details>
https://github.com/llvm/llvm-project/pull/192516
More information about the llvm-commits
mailing list