[llvm-branch-commits] [llvm] 8c94eae - [DWARFLinker] Consider module units when creating the type unit (#215731)
Douglas Yung via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sat Aug 15 08:44:17 PDT 2026
Author: Jonas Devlieghere
Date: 2026-08-15T15:44:04Z
New Revision: 8c94eaedf6e9cb0d22c291454e3b77a1f2aec6f7
URL: https://github.com/llvm/llvm-project/commit/8c94eaedf6e9cb0d22c291454e3b77a1f2aec6f7
DIFF: https://github.com/llvm/llvm-project/commit/8c94eaedf6e9cb0d22c291454e3b77a1f2aec6f7.diff
LOG: [DWARFLinker] Consider module units when creating the type unit (#215731)
The parallel linker creates the artificial type unit only when some
compile unit uses an ODR language, but it looks for that language in the
compile units of the object files alone. A clang module unit decides its
own ODR availability from its own DW_AT_language, so a module built as
C++ or ObjC++ imported from an object file whose units are all C, ObjC
or Swift places DIEs in the type table which does not exist, asserting
in CompileUnit::cloneDIE and dereferencing null without assertions.
Scan the languages of the module units as well, so a module which
deduplicates types always has a type unit to hold them.
rdar://182719465
(cherry picked from commit 58599fe7d593ddd4d4e9f95cfd9348a48ddf8492)
Added:
llvm/test/tools/dsymutil/Inputs/module-odr-language/1.ll
llvm/test/tools/dsymutil/Inputs/module-odr-language/M.ll
llvm/test/tools/dsymutil/Inputs/module-odr-language/debug-map.map
llvm/test/tools/dsymutil/X86/module-odr-language.test
Modified:
llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.h
llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp
Removed:
################################################################################
diff --git a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.h b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.h
index 7f2f8d4a77b99..8a1d64617be86 100644
--- a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.h
+++ b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerCompileUnit.h
@@ -98,6 +98,9 @@ class alignas(8) CompileUnit : public DwarfUnit {
/// Returns stage of overall processing.
Stage getStage() const { return Stage; }
+ /// Returns raw DW_AT_language of the input compile unit.
+ std::optional<uint16_t> getLanguage() const { return Language; }
+
/// Set stage of overall processing.
void setStage(Stage Stage) { this->Stage = Stage; }
diff --git a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp
index 1f977fe64fdd5..8fd0bf7d2995f 100644
--- a/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp
+++ b/llvm/lib/DWARFLinker/Parallel/DWARFLinkerImpl.cpp
@@ -151,6 +151,19 @@ Error DWARFLinkerImpl::link() {
Language = static_cast<uint16_t>(*LangVal);
}
}
+
+ // Clang module units decide their ODR availability from their own
+ // language, so they have to be part of this scan as well. A module unit
+ // can be the only ODR unit of a link, and any unit which deduplicates
+ // types requires the artificial type unit to exist.
+ for (const LinkContext::RefModuleUnit &Module :
+ Context->ModulesCompileUnits) {
+ if (!Language) {
+ if (std::optional<uint16_t> LangVal = Module.Unit->getLanguage())
+ if (isODRLanguage(*LangVal))
+ Language = *LangVal;
+ }
+ }
}
if (GlobalFormat.AddrSize == 0) {
diff --git a/llvm/test/tools/dsymutil/Inputs/module-odr-language/1.ll b/llvm/test/tools/dsymutil/Inputs/module-odr-language/1.ll
new file mode 100644
index 0000000000000..39affd1888899
--- /dev/null
+++ b/llvm/test/tools/dsymutil/Inputs/module-odr-language/1.ll
@@ -0,0 +1,33 @@
+; Test input for ../X86/module-odr-language.test.
+;
+; The object file: a C compile unit, whose language does not allow ODR
+; deduplication, and the gmodules skeleton unit referring to the C++ module.
+
+target triple = "x86_64-apple-darwin"
+
+define void @main() !dbg !100 { ret void }
+
+!llvm.dbg.cu = !{!0, !20}
+!llvm.module.flags = !{!10, !11}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "test",
+ emissionKind: FullDebug, imports: !30)
+!1 = !DIFile(filename: "1.c", directory: "")
+!100 = distinct !DISubprogram(name: "main", scope: !0, file: !1, line: 1,
+ type: !101, unit: !0,
+ spFlags: DISPFlagDefinition)
+!101 = !DISubroutineType(types: !102)
+!102 = !{null}
+!30 = !{!31}
+!31 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0,
+ entity: !32, line: 1)
+!32 = !DIModule(scope: !0, name: "M", includePath: ".")
+
+; The skeleton unit for module M: DW_AT_GNU_dwo_name and DW_AT_GNU_dwo_id.
+!20 = distinct !DICompileUnit(language: DW_LANG_C99, file: !21,
+ producer: "test", emissionKind: FullDebug,
+ splitDebugFilename: "M.pcm", dwoId: 42)
+!21 = !DIFile(filename: "M", directory: "")
+
+!10 = !{i32 2, !"Dwarf Version", i32 4}
+!11 = !{i32 2, !"Debug Info Version", i32 3}
diff --git a/llvm/test/tools/dsymutil/Inputs/module-odr-language/M.ll b/llvm/test/tools/dsymutil/Inputs/module-odr-language/M.ll
new file mode 100644
index 0000000000000..ba3ddc4d4f847
--- /dev/null
+++ b/llvm/test/tools/dsymutil/Inputs/module-odr-language/M.ll
@@ -0,0 +1,35 @@
+; Test input for ../X86/module-odr-language.test.
+;
+; Stands in for a Clang module built as C++: one compile unit whose language
+; is an ODR language, holding the module's type definitions, a forward
+; declaration and a member function declaration under DW_TAG_module.
+
+target triple = "x86_64-apple-darwin"
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!10, !11}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1,
+ producer: "test", emissionKind: FullDebug,
+ retainedTypes: !2, dwoId: 42)
+!1 = !DIFile(filename: "M", directory: "")
+!2 = !{!3, !30}
+!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", scope: !4,
+ file: !1, line: 1, size: 32, elements: !5,
+ identifier: "_ZTS1S")
+!4 = !DIModule(scope: null, name: "M", includePath: ".")
+!5 = !{!6, !20}
+!6 = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: !3, file: !1,
+ line: 2, baseType: !7, size: 32)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!20 = !DISubprogram(name: "get", linkageName: "_ZN1S3getEv", scope: !3,
+ file: !1, line: 3, type: !21, scopeLine: 3,
+ flags: DIFlagPrototyped, spFlags: 0)
+!21 = !DISubroutineType(types: !22)
+!22 = !{!7, !23}
+!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3, size: 64)
+!30 = !DICompositeType(tag: DW_TAG_structure_type, name: "T", scope: !4,
+ file: !1, line: 5, flags: DIFlagFwdDecl,
+ identifier: "_ZTS1T")
+!10 = !{i32 2, !"Dwarf Version", i32 4}
+!11 = !{i32 2, !"Debug Info Version", i32 3}
diff --git a/llvm/test/tools/dsymutil/Inputs/module-odr-language/debug-map.map b/llvm/test/tools/dsymutil/Inputs/module-odr-language/debug-map.map
new file mode 100644
index 0000000000000..e61271124a851
--- /dev/null
+++ b/llvm/test/tools/dsymutil/Inputs/module-odr-language/debug-map.map
@@ -0,0 +1,7 @@
+---
+triple: 'x86_64-apple-darwin'
+objects:
+ - filename: 1.o
+ symbols:
+ - { sym: _main, objAddr: 0x0, binAddr: 0x10000, size: 0x10 }
+...
diff --git a/llvm/test/tools/dsymutil/X86/module-odr-language.test b/llvm/test/tools/dsymutil/X86/module-odr-language.test
new file mode 100644
index 0000000000000..d2c79ccd272cb
--- /dev/null
+++ b/llvm/test/tools/dsymutil/X86/module-odr-language.test
@@ -0,0 +1,37 @@
+# A Clang module compile unit decides its ODR availability from its own
+# language, so a module built as C++ places its types in the artificial type
+# unit even when every compile unit of the object files uses a language
+# without ODR. The type unit has to exist for those links as well.
+
+RUN: rm -rf %t && mkdir -p %t
+RUN: llc -O0 -mtriple=x86_64-apple-darwin -filetype=obj \
+RUN: -o %t/M.pcm %p/../Inputs/module-odr-language/M.ll
+RUN: llc -O0 -mtriple=x86_64-apple-darwin -filetype=obj \
+RUN: -o %t/1.o %p/../Inputs/module-odr-language/1.ll
+RUN: dsymutil --linker parallel -f \
+RUN: -y %p/../Inputs/module-odr-language/debug-map.map \
+RUN: -oso-prepend-path %t -o %t/out.dwarf
+RUN: llvm-dwarfdump --verify %t/out.dwarf
+RUN: llvm-dwarfdump --debug-info %t/out.dwarf | FileCheck %s
+
+# The module's type definition, the member function declaration it holds and
+# the forward declaration all land in the artificial type unit.
+
+CHECK: DW_AT_name {{.*}}"__artificial_type_unit"
+CHECK: DW_TAG_module
+CHECK-NEXT: DW_AT_name {{.*}}"M"
+CHECK: DW_TAG_structure_type
+CHECK-NEXT: DW_AT_name {{.*}}"S"
+CHECK-NEXT: DW_AT_byte_size
+CHECK: DW_TAG_member
+CHECK-NEXT: DW_AT_name {{.*}}"value"
+CHECK: DW_TAG_subprogram
+CHECK: DW_AT_name {{.*}}"get"
+CHECK: DW_TAG_structure_type
+CHECK-NEXT: DW_AT_name {{.*}}"T"
+
+# The compile unit of the object file keeps its own language.
+
+CHECK: DW_AT_language {{.*}}(DW_LANG_C99)
+CHECK: DW_TAG_subprogram
+CHECK: DW_AT_name {{.*}}"main"
More information about the llvm-branch-commits
mailing list