Skip to content

[CloneFunction][DebugInfo] Avoid cloning DILocalVariables of inlined functions#75385

Merged
dzhidzhoev merged 1 commit intollvm:mainfrom
dzhidzhoev:new-4-squashed
Jan 11, 2024
Merged

[CloneFunction][DebugInfo] Avoid cloning DILocalVariables of inlined functions#75385
dzhidzhoev merged 1 commit intollvm:mainfrom
dzhidzhoev:new-4-squashed

Conversation

@dzhidzhoev
Copy link
Copy Markdown
Member

  • [DebugMetadata][DwarfDebug] Support function-local types in lexical block scopes (4/7)
  • [CloneFunction][DebugInfo] Avoid cloning DILocalVariables of inlined functions

This is a follow-up for https://reviews.llvm.org/D144006, fixing a crash reported
in Chromium (https://reviews.llvm.org/D144006#4651955).

The first commit is added for convenience, as it has already been accepted.

If DISubpogram was not cloned (e.g. we are cloning a function that has other
functions inlined into it, and subprograms of the inlined functions are
not supposed to be cloned), it doesn't make sense to clone its
DILocalVariables as well.
Otherwise get duplicated DILocalVariables not tracked in their
subprogram's retainedNodes, that crash LTO with Chromium.

This is meant to be committed along with https://reviews.llvm.org/D144006.

@llvmbot llvmbot added clang Clang issues not falling into any other category debuginfo llvm:ir llvm:transforms labels Dec 13, 2023
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Dec 13, 2023

@llvm/pr-subscribers-llvm-transforms
@llvm/pr-subscribers-debuginfo
@llvm/pr-subscribers-llvm-ir

@llvm/pr-subscribers-clang

Author: Vladislav Dzhidzhoev (dzhidzhoev)

Changes
  • [DebugMetadata][DwarfDebug] Support function-local types in lexical block scopes (4/7)
  • [CloneFunction][DebugInfo] Avoid cloning DILocalVariables of inlined functions

This is a follow-up for https://reviews.llvm.org/D144006, fixing a crash reported
in Chromium (https://reviews.llvm.org/D144006#4651955).

The first commit is added for convenience, as it has already been accepted.

If DISubpogram was not cloned (e.g. we are cloning a function that has other
functions inlined into it, and subprograms of the inlined functions are
not supposed to be cloned), it doesn't make sense to clone its
DILocalVariables as well.
Otherwise get duplicated DILocalVariables not tracked in their
subprogram's retainedNodes, that crash LTO with Chromium.

This is meant to be committed along with https://reviews.llvm.org/D144006.


Patch is 97.26 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/75385.diff

31 Files Affected:

  • (modified) clang/test/CodeGen/debug-info-codeview-unnamed.c (+8-8)
  • (modified) clang/test/CodeGen/debug-info-unused-types.c (+9-7)
  • (modified) clang/test/CodeGen/debug-info-unused-types.cpp (+8-6)
  • (modified) clang/test/CodeGenCXX/debug-info-access.cpp (+1-1)
  • (modified) clang/test/CodeGenCXX/debug-info-anon-union-vars.cpp (+6-6)
  • (modified) clang/test/CodeGenCXX/debug-info-codeview-unnamed.cpp (+62-48)
  • (modified) clang/test/CodeGenCXX/debug-info-gline-tables-only-codeview.cpp (+2-2)
  • (modified) clang/test/CodeGenCXX/debug-lambda-this.cpp (+2-2)
  • (modified) llvm/include/llvm/IR/DIBuilder.h (+3-3)
  • (modified) llvm/include/llvm/IR/DebugInfo.h (+9-1)
  • (modified) llvm/lib/Bitcode/Reader/MetadataLoader.cpp (+78-33)
  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp (+40-20)
  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h (+8-8)
  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (+10-3)
  • (modified) llvm/lib/IR/DIBuilder.cpp (+27-10)
  • (modified) llvm/lib/IR/DebugInfo.cpp (+10-4)
  • (modified) llvm/lib/IR/Verifier.cpp (+3-3)
  • (modified) llvm/lib/Transforms/Utils/CloneFunction.cpp (+13-1)
  • (added) llvm/test/Bitcode/clone-local-types.ll (+46)
  • (modified) llvm/test/Bitcode/upgrade-cu-locals.ll (+41-27)
  • (modified) llvm/test/Bitcode/upgrade-cu-locals.ll.bc ()
  • (added) llvm/test/DebugInfo/Generic/inlined-local-type.ll (+128)
  • (added) llvm/test/DebugInfo/Generic/lexical-block-retained-types.ll (+55)
  • (added) llvm/test/DebugInfo/Generic/lexical-block-types.ll (+425)
  • (modified) llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll (+1-1)
  • (added) llvm/test/DebugInfo/X86/local-type-as-template-parameter.ll (+161)
  • (modified) llvm/test/DebugInfo/X86/set.ll (+2-2)
  • (renamed) llvm/test/DebugInfo/X86/split-dwarf-local-import.ll (-1)
  • (renamed) llvm/test/DebugInfo/X86/split-dwarf-local-import2.ll (-1)
  • (renamed) llvm/test/DebugInfo/X86/split-dwarf-local-import3.ll ()
  • (modified) llvm/unittests/Transforms/Utils/CloningTest.cpp (+105)
diff --git a/clang/test/CodeGen/debug-info-codeview-unnamed.c b/clang/test/CodeGen/debug-info-codeview-unnamed.c
index bd2a7543e56b2b..16ffb3682236f1 100644
--- a/clang/test/CodeGen/debug-info-codeview-unnamed.c
+++ b/clang/test/CodeGen/debug-info-codeview-unnamed.c
@@ -8,23 +8,23 @@ int main(int argc, char* argv[], char* arge[]) {
   //
   struct { int bar; } one = {42};
   //
-  // LINUX:      !{{[0-9]+}} = !DILocalVariable(name: "one"
-  // LINUX-SAME:     type: [[TYPE_OF_ONE:![0-9]+]]
-  // LINUX-SAME:     )
-  // LINUX:      [[TYPE_OF_ONE]] = distinct !DICompositeType(
+  // LINUX:      [[TYPE_OF_ONE:![0-9]+]] = distinct !DICompositeType(
   // LINUX-SAME:     tag: DW_TAG_structure_type
   // LINUX-NOT:      name:
   // LINUX-NOT:      identifier:
   // LINUX-SAME:     )
+  // LINUX:      !{{[0-9]+}} = !DILocalVariable(name: "one"
+  // LINUX-SAME:     type: [[TYPE_OF_ONE]]
+  // LINUX-SAME:     )
   //
-  // MSVC:       !{{[0-9]+}} = !DILocalVariable(name: "one"
-  // MSVC-SAME:      type: [[TYPE_OF_ONE:![0-9]+]]
-  // MSVC-SAME:      )
-  // MSVC:       [[TYPE_OF_ONE]] = distinct !DICompositeType
+  // MSVC:       [[TYPE_OF_ONE:![0-9]+]] = distinct !DICompositeType
   // MSVC-SAME:      tag: DW_TAG_structure_type
   // MSVC-NOT:       name:
   // MSVC-NOT:       identifier:
   // MSVC-SAME:      )
+  // MSVC:       !{{[0-9]+}} = !DILocalVariable(name: "one"
+  // MSVC-SAME:      type: [[TYPE_OF_ONE]]
+  // MSVC-SAME:      )
 
   return 0;
 }
diff --git a/clang/test/CodeGen/debug-info-unused-types.c b/clang/test/CodeGen/debug-info-unused-types.c
index 3e9f7b07658e36..31d608d92a06b4 100644
--- a/clang/test/CodeGen/debug-info-unused-types.c
+++ b/clang/test/CodeGen/debug-info-unused-types.c
@@ -18,13 +18,15 @@ void quux(void) {
 // CHECK: !DICompileUnit{{.+}}retainedTypes: [[RETTYPES:![0-9]+]]
 // CHECK: [[TYPE0:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "bar"
 // CHECK: [[TYPE1:![0-9]+]] = !DIEnumerator(name: "BAR"
-// CHECK: [[TYPE2:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "z"
-// CHECK: [[TYPE3:![0-9]+]] = !DIEnumerator(name: "Z"
-// CHECK: [[RETTYPES]] = !{[[TYPE4:![0-9]+]], [[TYPE5:![0-9]+]], [[TYPE0]], [[TYPE6:![0-9]+]], {{![0-9]+}}, [[TYPE7:![0-9]+]], [[TYPE2]], [[TYPE8:![0-9]+]]}
-// CHECK: [[TYPE4]] = !DIDerivedType(tag: DW_TAG_typedef, name: "my_int"
-// CHECK: [[TYPE5]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
-// CHECK: [[TYPE6]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "baz"
-// CHECK: [[TYPE7]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "y"
+// CHECK: [[RETTYPES]] = !{[[TYPE2:![0-9]+]], [[TYPE3:![0-9]+]], [[TYPE0]], [[TYPE4:![0-9]+]], {{![0-9]+}}}
+// CHECK: [[TYPE2]] = !DIDerivedType(tag: DW_TAG_typedef, name: "my_int"
+// CHECK: [[TYPE3]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
+// CHECK: [[TYPE4]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "baz"
+// CHECK: [[SP:![0-9]+]] = distinct !DISubprogram(name: "quux", {{.*}}, retainedNodes: [[SPRETNODES:![0-9]+]]
+// CHECK: [[SPRETNODES]] = !{[[TYPE5:![0-9]+]], [[TYPE6:![0-9]+]], [[TYPE8:![0-9]+]]}
+// CHECK: [[TYPE5]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "y"
+// CHECK: [[TYPE6]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "z"
+// CHECK: [[TYPE7:![0-9]+]] = !DIEnumerator(name: "Z"
 // CHECK: [[TYPE8]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "w"
 
 // Check that debug info is not emitted for the typedef, struct, enum, and
diff --git a/clang/test/CodeGen/debug-info-unused-types.cpp b/clang/test/CodeGen/debug-info-unused-types.cpp
index 023cac159faa4b..5b01c6dbb39414 100644
--- a/clang/test/CodeGen/debug-info-unused-types.cpp
+++ b/clang/test/CodeGen/debug-info-unused-types.cpp
@@ -13,12 +13,14 @@ void quux() {
 // CHECK: !DICompileUnit{{.+}}retainedTypes: [[RETTYPES:![0-9]+]]
 // CHECK: [[TYPE0:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "baz"
 // CHECK: [[TYPE1:![0-9]+]] = !DIEnumerator(name: "BAZ"
-// CHECK: [[TYPE2:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "z"
-// CHECK: [[TYPE3:![0-9]+]] = !DIEnumerator(name: "Z"
-// CHECK: [[RETTYPES]] = !{[[TYPE4:![0-9]+]], [[TYPE5:![0-9]+]], [[TYPE0]], {{![0-9]+}}, [[TYPE6:![0-9]+]], [[TYPE2]]}
-// CHECK: [[TYPE4]] = !DIDerivedType(tag: DW_TAG_typedef, name: "foo"
-// CHECK: [[TYPE5]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "bar"
-// CHECK: [[TYPE6]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "y"
+// CHECK: [[RETTYPES]] = !{[[TYPE2:![0-9]+]], [[TYPE3:![0-9]+]], [[TYPE0]], {{![0-9]+}}}
+// CHECK: [[TYPE2]] = !DIDerivedType(tag: DW_TAG_typedef, name: "foo"
+// CHECK: [[TYPE3]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "bar"
+// CHECK: [[SP:![0-9]+]] = distinct !DISubprogram(name: "quux", {{.*}}, retainedNodes: [[SPRETNODES:![0-9]+]]
+// CHECK: [[SPRETNODES]] = !{[[TYPE4:![0-9]+]], [[TYPE5:![0-9]+]]}
+// CHECK: [[TYPE4]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "y", scope: [[SP]]
+// CHECK: [[TYPE5]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "z", scope: [[SP]]
+// CHECK: [[TYPE6:![0-9]+]] = !DIEnumerator(name: "Z"
 
 // NODBG-NOT: !DI{{CompositeType|Enumerator|DerivedType}}
 
diff --git a/clang/test/CodeGenCXX/debug-info-access.cpp b/clang/test/CodeGenCXX/debug-info-access.cpp
index 9f2c044843d0f0..7c0bf8ccb03842 100644
--- a/clang/test/CodeGenCXX/debug-info-access.cpp
+++ b/clang/test/CodeGenCXX/debug-info-access.cpp
@@ -18,9 +18,9 @@ class B : public A {
   static int public_static;
 
 protected:
+  // CHECK-DAG: !DIDerivedType(tag: DW_TAG_typedef, name: "prot_using",{{.*}} line: [[@LINE+3]],{{.*}} flags: DIFlagProtected)
   // CHECK-DAG: !DIDerivedType(tag: DW_TAG_typedef, name: "prot_typedef",{{.*}} line: [[@LINE+1]],{{.*}} flags: DIFlagProtected)
   typedef int prot_typedef;
-  // CHECK-DAG: !DIDerivedType(tag: DW_TAG_typedef, name: "prot_using",{{.*}} line: [[@LINE+1]],{{.*}} flags: DIFlagProtected)
   using prot_using = prot_typedef;
   prot_using prot_member;
 
diff --git a/clang/test/CodeGenCXX/debug-info-anon-union-vars.cpp b/clang/test/CodeGenCXX/debug-info-anon-union-vars.cpp
index 61b3c7c0526c8e..c91cf83c0405fe 100644
--- a/clang/test/CodeGenCXX/debug-info-anon-union-vars.cpp
+++ b/clang/test/CodeGenCXX/debug-info-anon-union-vars.cpp
@@ -51,13 +51,13 @@ void instantiate(int x) {
 // CHECK: !DIGlobalVariable(name: "b",{{.*}} file: [[FILE]], line: 6,{{.*}} isLocal: true, isDefinition: true
 // CHECK: !DIGlobalVariable(name: "result", {{.*}} isLocal: false, isDefinition: true
 // CHECK: !DIGlobalVariable(name: "value", {{.*}} isLocal: false, isDefinition: true
-// CHECK: !DILocalVariable(name: "i", {{.*}}, flags: DIFlagArtificial
-// CHECK: !DILocalVariable(name: "c", {{.*}}, flags: DIFlagArtificial
-// CHECK: !DILocalVariable(
-// CHECK-NOT: name:
-// CHECK: type: ![[UNION:[0-9]+]]
-// CHECK: ![[UNION]] = distinct !DICompositeType(tag: DW_TAG_union_type,
+// CHECK: ![[UNION:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_union_type,
 // CHECK-NOT: name:
 // CHECK: elements
 // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "i", scope: ![[UNION]],
 // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "c", scope: ![[UNION]],
+// CHECK: !DILocalVariable(name: "i", {{.*}}, flags: DIFlagArtificial
+// CHECK: !DILocalVariable(name: "c", {{.*}}, flags: DIFlagArtificial
+// CHECK: !DILocalVariable(
+// CHECK-NOT: name:
+// CHECK: type: ![[UNION]]
diff --git a/clang/test/CodeGenCXX/debug-info-codeview-unnamed.cpp b/clang/test/CodeGenCXX/debug-info-codeview-unnamed.cpp
index b4c79936ab33e6..9602ac1b024973 100644
--- a/clang/test/CodeGenCXX/debug-info-codeview-unnamed.cpp
+++ b/clang/test/CodeGenCXX/debug-info-codeview-unnamed.cpp
@@ -3,6 +3,60 @@
 
 int main(int argc, char* argv[], char* arge[]) {
   //
+  // LINUX:      [[TYPE_OF_ONE:![0-9]+]] = distinct !DICompositeType(
+  // LINUX-SAME:     tag: DW_TAG_structure_type
+  // LINUX-NOT:      name:
+  // LINUX-NOT:      identifier:
+  // LINUX-SAME:     )
+  //
+  // MSVC:       [[TYPE_OF_ONE:![0-9]+]] = distinct !DICompositeType
+  // MSVC-SAME:      tag: DW_TAG_structure_type
+  // MSVC-SAME:      name: "<unnamed-type-one>"
+  // MSVC-SAME:      identifier: ".?AU<unnamed-type-one>@?1??main@@9@"
+  // MSVC-SAME:      )
+
+
+  //
+  // LINUX:      [[TYPE_OF_TWO:![0-9]+]] = distinct !DICompositeType(
+  // LINUX-SAME:     tag: DW_TAG_structure_type
+  // LINUX-NOT:      name:
+  // LINUX-NOT:      identifier:
+  // LINUX-SAME:     )
+  //
+  // MSVC:       [[TYPE_OF_TWO:![0-9]+]] = distinct !DICompositeType
+  // MSVC-SAME:      tag: DW_TAG_structure_type
+  // MSVC-SAME:      name: "<unnamed-type-two>"
+  // MSVC-SAME:      identifier: ".?AU<unnamed-type-two>@?2??main@@9@"
+  // MSVC-SAME:      )
+
+
+  //
+  // LINUX:      [[TYPE_OF_THREE:![0-9]+]] = distinct !DICompositeType(
+  // LINUX-SAME:     tag: DW_TAG_structure_type
+  // LINUX-SAME:     name: "named"
+  // LINUX-NOT:      identifier:
+  // LINUX-SAME:     )
+  //
+  // MSVC:       [[TYPE_OF_THREE:![0-9]+]] = distinct !DICompositeType
+  // MSVC-SAME:      tag: DW_TAG_structure_type
+  // MSVC-SAME:      name: "named"
+  // MSVC-SAME:      identifier: ".?AUnamed@?1??main@@9@"
+  // MSVC-SAME:      )
+
+  //
+  // LINUX:      [[TYPE_OF_FOUR:![0-9]+]] = distinct !DICompositeType(
+  // LINUX-SAME:     tag: DW_TAG_class_type
+  // LINUX-NOT:      name:
+  // LINUX-NOT:      identifier:
+  // LINUX-SAME:     )
+  //
+  // MSVC:       [[TYPE_OF_FOUR:![0-9]+]] = distinct !DICompositeType
+  // MSVC-SAME:      tag: DW_TAG_class_type
+  // MSVC-SAME:      name: "<lambda_0>"
+  // MSVC-SAME:      identifier: ".?AV<lambda_0>@?0??main@@9@"
+  // MSVC-SAME:      )
+
+
   // In CodeView, the LF_MFUNCTION entry for "bar()" refers to the forward
   // reference of the unnamed struct. Visual Studio requires a unique
   // identifier to match the LF_STRUCTURE forward reference to the definition.
@@ -10,21 +64,11 @@ int main(int argc, char* argv[], char* arge[]) {
   struct { void bar() {} } one;
   //
   // LINUX:      !{{[0-9]+}} = !DILocalVariable(name: "one"
-  // LINUX-SAME:     type: [[TYPE_OF_ONE:![0-9]+]]
-  // LINUX-SAME:     )
-  // LINUX:      [[TYPE_OF_ONE]] = distinct !DICompositeType(
-  // LINUX-SAME:     tag: DW_TAG_structure_type
-  // LINUX-NOT:      name:
-  // LINUX-NOT:      identifier:
+  // LINUX-SAME:     type: [[TYPE_OF_ONE]]
   // LINUX-SAME:     )
   //
   // MSVC:       !{{[0-9]+}} = !DILocalVariable(name: "one"
-  // MSVC-SAME:      type: [[TYPE_OF_ONE:![0-9]+]]
-  // MSVC-SAME:      )
-  // MSVC:       [[TYPE_OF_ONE]] = distinct !DICompositeType
-  // MSVC-SAME:      tag: DW_TAG_structure_type
-  // MSVC-SAME:      name: "<unnamed-type-one>"
-  // MSVC-SAME:      identifier: ".?AU<unnamed-type-one>@?1??main@@9@"
+  // MSVC-SAME:      type: [[TYPE_OF_ONE]]
   // MSVC-SAME:      )
 
 
@@ -36,21 +80,11 @@ int main(int argc, char* argv[], char* arge[]) {
   int decltype(two)::*ptr2unnamed = &decltype(two)::bar;
   //
   // LINUX:      !{{[0-9]+}} = !DILocalVariable(name: "two"
-  // LINUX-SAME:     type: [[TYPE_OF_TWO:![0-9]+]]
-  // LINUX-SAME:     )
-  // LINUX:      [[TYPE_OF_TWO]] = distinct !DICompositeType(
-  // LINUX-SAME:     tag: DW_TAG_structure_type
-  // LINUX-NOT:      name:
-  // LINUX-NOT:      identifier:
+  // LINUX-SAME:     type: [[TYPE_OF_TWO]]
   // LINUX-SAME:     )
   //
   // MSVC:       !{{[0-9]+}} = !DILocalVariable(name: "two"
-  // MSVC-SAME:      type: [[TYPE_OF_TWO:![0-9]+]]
-  // MSVC-SAME:      )
-  // MSVC:       [[TYPE_OF_TWO]] = distinct !DICompositeType
-  // MSVC-SAME:      tag: DW_TAG_structure_type
-  // MSVC-SAME:      name: "<unnamed-type-two>"
-  // MSVC-SAME:      identifier: ".?AU<unnamed-type-two>@?2??main@@9@"
+  // MSVC-SAME:      type: [[TYPE_OF_TWO]]
   // MSVC-SAME:      )
 
 
@@ -61,21 +95,11 @@ int main(int argc, char* argv[], char* arge[]) {
   struct named { int bar; int named::* p2mem; } three = { 42, &named::bar };
   //
   // LINUX:      !{{[0-9]+}} = !DILocalVariable(name: "three"
-  // LINUX-SAME:     type: [[TYPE_OF_THREE:![0-9]+]]
-  // LINUX-SAME:     )
-  // LINUX:      [[TYPE_OF_THREE]] = distinct !DICompositeType(
-  // LINUX-SAME:     tag: DW_TAG_structure_type
-  // LINUX-SAME:     name: "named"
-  // LINUX-NOT:      identifier:
+  // LINUX-SAME:     type: [[TYPE_OF_THREE]]
   // LINUX-SAME:     )
   //
   // MSVC:       !{{[0-9]+}} = !DILocalVariable(name: "three"
-  // MSVC-SAME:      type: [[TYPE_OF_THREE:![0-9]+]]
-  // MSVC-SAME:      )
-  // MSVC:       [[TYPE_OF_THREE]] = distinct !DICompositeType
-  // MSVC-SAME:      tag: DW_TAG_structure_type
-  // MSVC-SAME:      name: "named"
-  // MSVC-SAME:      identifier: ".?AUnamed@?1??main@@9@"
+  // MSVC-SAME:      type: [[TYPE_OF_THREE]]
   // MSVC-SAME:      )
 
 
@@ -87,21 +111,11 @@ int main(int argc, char* argv[], char* arge[]) {
   auto four = [argc](int i) -> int { return argc == i ? 1 : 0; };
   //
   // LINUX:      !{{[0-9]+}} = !DILocalVariable(name: "four"
-  // LINUX-SAME:     type: [[TYPE_OF_FOUR:![0-9]+]]
-  // LINUX-SAME:     )
-  // LINUX:      [[TYPE_OF_FOUR]] = distinct !DICompositeType(
-  // LINUX-SAME:     tag: DW_TAG_class_type
-  // LINUX-NOT:      name:
-  // LINUX-NOT:      identifier:
+  // LINUX-SAME:     type: [[TYPE_OF_FOUR]]
   // LINUX-SAME:     )
   //
   // MSVC:       !{{[0-9]+}} = !DILocalVariable(name: "four"
-  // MSVC-SAME:      type: [[TYPE_OF_FOUR:![0-9]+]]
-  // MSVC-SAME:      )
-  // MSVC:       [[TYPE_OF_FOUR]] = distinct !DICompositeType
-  // MSVC-SAME:      tag: DW_TAG_class_type
-  // MSVC-SAME:      name: "<lambda_0>"
-  // MSVC-SAME:      identifier: ".?AV<lambda_0>@?0??main@@9@"
+  // MSVC-SAME:      type: [[TYPE_OF_FOUR]]
   // MSVC-SAME:      )
 
   return 0;
diff --git a/clang/test/CodeGenCXX/debug-info-gline-tables-only-codeview.cpp b/clang/test/CodeGenCXX/debug-info-gline-tables-only-codeview.cpp
index 6b9c9a243decd1..122e4aa62ea7df 100644
--- a/clang/test/CodeGenCXX/debug-info-gline-tables-only-codeview.cpp
+++ b/clang/test/CodeGenCXX/debug-info-gline-tables-only-codeview.cpp
@@ -51,9 +51,9 @@ void test() {
   // CHECK-SAME:                              name: "<lambda_2_1>",
   c.lambda_params();
 
-  // CHECK: !DISubprogram(name: "operator()", scope: ![[LAMBDA1:[0-9]+]],
-  // CHECK: ![[LAMBDA1]] = !DICompositeType(tag: DW_TAG_class_type,
+  // CHECK: ![[LAMBDA1:[0-9]+]] = !DICompositeType(tag: DW_TAG_class_type,
   // CHECK-SAME:                            name: "<lambda_1>",
   // CHECK-SAME:                            flags: DIFlagFwdDecl
+  // CHECK: !DISubprogram(name: "operator()", scope: ![[LAMBDA1]],
   c.lambda2();
 }
diff --git a/clang/test/CodeGenCXX/debug-lambda-this.cpp b/clang/test/CodeGenCXX/debug-lambda-this.cpp
index eecbac6520ac97..3d659e7bfd004a 100644
--- a/clang/test/CodeGenCXX/debug-lambda-this.cpp
+++ b/clang/test/CodeGenCXX/debug-lambda-this.cpp
@@ -13,10 +13,10 @@ int D::d(int x) {
 }
 
 // CHECK: ![[D:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "D",
-// CHECK: ![[POINTER:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[D]], size: 64)
 // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "this",
 // CHECK-SAME:           line: 11
-// CHECK-SAME:           baseType: ![[POINTER]]
+// CHECK-SAME:           baseType: ![[POINTER:[0-9]+]]
 // CHECK-SAME:           size: 64
 // CHECK-NOT:            offset: 0
 // CHECK-SAME:           ){{$}}
+// CHECK: ![[POINTER]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[D]], size: 64)
diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h
index edec161b397155..166cd664aec1de 100644
--- a/llvm/include/llvm/IR/DIBuilder.h
+++ b/llvm/include/llvm/IR/DIBuilder.h
@@ -49,7 +49,7 @@ namespace llvm {
     Function *LabelFn;       ///< llvm.dbg.label
     Function *AssignFn;      ///< llvm.dbg.assign
 
-    SmallVector<TrackingMDNodeRef, 4> AllEnumTypes;
+    SmallVector<TrackingMDNodeRef, 4> EnumTypes;
     /// Track the RetainTypes, since they can be updated later on.
     SmallVector<TrackingMDNodeRef, 4> AllRetainTypes;
     SmallVector<DISubprogram *, 4> AllSubprograms;
@@ -64,8 +64,8 @@ namespace llvm {
     SmallVector<TrackingMDNodeRef, 4> UnresolvedNodes;
     bool AllowUnresolvedNodes;
 
-    /// Each subprogram's preserved local variables, labels and imported
-    /// entities.
+    /// Each subprogram's preserved local variables, labels, imported entities,
+    /// and types.
     ///
     /// Do not use a std::vector.  Some versions of libc++ apparently copy
     /// instead of move on grow operations, and TrackingMDRef is expensive to
diff --git a/llvm/include/llvm/IR/DebugInfo.h b/llvm/include/llvm/IR/DebugInfo.h
index 36ef77f9505bc1..d60011e14ed172 100644
--- a/llvm/include/llvm/IR/DebugInfo.h
+++ b/llvm/include/llvm/IR/DebugInfo.h
@@ -104,7 +104,7 @@ class DebugInfoFinder {
   void processInstruction(const Module &M, const Instruction &I);
 
   /// Process a DILocalVariable.
-  void processVariable(const Module &M, const DILocalVariable *DVI);
+  void processVariable(DILocalVariable *DVI);
   /// Process debug info location.
   void processLocation(const Module &M, const DILocation *Loc);
   // Process a DPValue, much like a DbgVariableIntrinsic.
@@ -120,6 +120,7 @@ class DebugInfoFinder {
   void processCompileUnit(DICompileUnit *CU);
   void processScope(DIScope *Scope);
   void processType(DIType *DT);
+  void processLocalVariable(DILocalVariable *DV);
   bool addCompileUnit(DICompileUnit *CU);
   bool addGlobalVariable(DIGlobalVariableExpression *DIG);
   bool addScope(DIScope *Scope);
@@ -134,6 +135,7 @@ class DebugInfoFinder {
       SmallVectorImpl<DIGlobalVariableExpression *>::const_iterator;
   using type_iterator = SmallVectorImpl<DIType *>::const_iterator;
   using scope_iterator = SmallVectorImpl<DIScope *>::const_iterator;
+  using local_variable_iterator = SmallVectorImpl<DILocalVariable *>::const_iterator;
 
   iterator_range<compile_unit_iterator> compile_units() const {
     return make_range(CUs.begin(), CUs.end());
@@ -147,6 +149,10 @@ class DebugInfoFinder {
     return make_range(GVs.begin(), GVs.end());
   }
 
+  iterator_range<local_variable_iterator> local_variables() const {
+    return make_range(LVs.begin(), LVs.end());
+  }
+
   iterator_range<type_iterator> types() const {
     return make_range(TYs.begin(), TYs.end());
   }
@@ -157,6 +163,7 @@ class DebugInfoFinder {
 
   unsigned compile_unit_count() const { return CUs.size(); }
   unsigned global_variable_count() const { return GVs.size(); }
+  unsigned local_variable_count() const { return LVs.size(); }
   unsigned subprogram_count() const { return SPs.size(); }
   unsigned type_count() const { return TYs.size(); }
   unsigned scope_count() const { return Scopes.size(); }
@@ -165,6 +172,7 @@ class DebugInfoFinder {
   SmallVector<DICompileUnit *, 8> CUs;
   SmallVector<DISubprogram *, 8> SPs;
   SmallVector<DIGlobalVariableExpression *, 8> GVs;
+  SmallVector<DILocalVariable *, 8> LVs;
   SmallVector<DIType *, 8> TYs;
   SmallVector<DIScope *, 8> Scopes;
   SmallPtrSet<const MDNode *, 32> NodesSeen;
diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
index 910e97489dbbe0..d118695b431c5a 100644
--- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
+++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
@@ -547,6 +547,8 @@ class MetadataLoader::MetadataLoaderImpl {
 
   /// Move local imports from DICompileUnit's 'imports' field to
   /// DISubprogram's retainedNodes.
+  /// Move fucntion-local enums from DICompileUnit's enums
+  /// to DISubprogram's retainedNodes.
   void upgradeCULocals() {
     if (NamedMDNode *CUNodes = TheModule.getNamedMetadata("llvm.dbg.cu")) {
       for (unsigned I = 0, E = CUNodes->getNumOperands(); I != E; ++I) {
@@ -554,48 +556,66 @@ class MetadataLoader::MetadataLoaderImpl {
         if (!CU)
           continue;
 
-        if (CU->getRawImportedEntities()) {
-          // Collect a set of imported entities to be moved.
-          SetVector<Metadata *> EntitiesToRemove;
+        SetVector<Metadata *> MetadataToRemove;
+        // Collect imported entities to be moved.
+        if (CU->getRawImportedEntities())
           for (Metadata *Op : CU->getImportedEntities()->operands()) {
             auto *IE = cast<DIImportedEntity>(Op);
-            if (dyn_cast_or_null<DILocalScope>(IE->g...
[truncated]

@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 13, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a sentence explaining why some subprograms won't be cloned? Is it because they are inlined and a copy already exists?

Copy link
Copy Markdown
Collaborator

@adrian-prantl adrian-prantl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this LGTM, but it would be good if someone else also took a look.

@dzhidzhoev
Copy link
Copy Markdown
Member Author

@dwblaikie
Could you please take a look at this when you have a chance?

Copy link
Copy Markdown
Collaborator

@dwblaikie dwblaikie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, looks OK to me - sorry for the delay.

…lock scopes (4/7)

RFC https://discourse.llvm.org/t/rfc-dwarfdebug-fix-and-improve-handling-imported-entities-types-and-static-local-in-subprogram-and-lexical-block-scopes/68544

Similar to imported declarations, the patch tracks function-local types in
DISubprogram's 'retainedNodes' field. DwarfDebug is adjusted in accordance with
the aforementioned metadata change and provided a support of function-local
types scoped within a lexical block.

The patch assumes that DICompileUnit's 'enums field' no longer tracks local
types and DwarfDebug would assert if any locally-scoped types get placed there.

Additionally, if DISubprogram is not cloned in CloneFunctionInto(),
cloning of its DILocalVariables is avoided.
Otherwise we get duplicated DILocalVariables not tracked in their
subprogram's retainedNodes, that crash LTO with Chromium.

Reviewed By: jmmartinez
Authored-by: Kristina Bessonova <[email protected]>
Differential Revision: https://reviews.llvm.org/D144006
@dzhidzhoev dzhidzhoev merged commit fc6faa1 into llvm:main Jan 11, 2024
@jmorse
Copy link
Copy Markdown
Member

jmorse commented Jan 16, 2024

Hi,

We're seeing a crash with this commit and reproducer https://gist.github.com/jmorse/b0248c3c9f9195487ffd7c7431a8d15e

llc: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp:2338: virtual void llvm::DwarfDebug::endFunctionImpl(const llvm::MachineFunction *): Assertion `LScopes.getAbstractScopesList().size() == NumAbstractSubprograms && "getOrCreateAbstractScope() inserted an abstract subprogram scope"' failed.

I'd previously posted the reproducer on https://reviews.llvm.org/D144006#4656728 , however I'd anonymised the IR too much to the point where it was broken in unrelated ways. Revision 2 of the gist, as linked, should produce the crash. I suspect the extra lexical scopes reachable through the retained-nodes list also need to be explored when the LexicalScopes object gets constructed, to avoid scopes being added late and causing containers to invalidate iterators. (Which is what that assertion is there to detect).

@zmodem
Copy link
Copy Markdown
Collaborator

zmodem commented Jan 16, 2024

We're hitting the same assert (tracking in https://crbug.com/1518841) but don't have a good reproducer to share (it's during lto of a large binary). Jeremy's reproducer seems good though.

Can we revert this while it's being investigated, please?

@dcci
Copy link
Copy Markdown
Member

dcci commented Jan 17, 2024

Hitting the same problem on a bunch of services. I am going to revert this to unblock people, our repro is similar enough to the one Jeremy shared.

$ ./exe
clang -cc1 version 18.0.0git based upon LLVM 18.0.0git default target x86_64-redhat-linux-gnu
clang++: /home/davidino/llvm-project/llvm/include/llvm/Support/Casting.h:109: static bool llvm::isa_impl_cl<llvm::DILocalScope, const llvm::DIScope *>::doit(const From *) [To = llvm::DILocalScope, From = const llvm::DIScope *]: Assertion `Val && "isa<> used on a null pointer"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
0.      Program arguments: /home/davidino/llvm-build-upstream/bin/clang++ @/tmp/fbcc.4ddf7_1j/compiler.argsfile
1.      Running pass 'Function Pass Manager' on module 'buck-out/v2/gen/fbcode/349d8ab5ad6260b7/dsi/logger/configs/CacheClientFciRequestLoggerConfig/__logger__/__objects__/Logger.cpp.o'.
2.      Running pass 'X86 Assembly Printer' on function '@_ZN8facebook6logger27CacheClientFciRequestLogger9invokeLogIDnDnEEibT_PKciT0_'
 #0 0x00007f123a20a448 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/davidino/llvm-build-upstream/bin/../lib/libLLVMSupport.so.18git+0x20a448)
 #1 0x00007f123a207eee llvm::sys::RunSignalHandlers() (/home/davidino/llvm-build-upstream/bin/../lib/libLLVMSupport.so.18git+0x207eee)
 #2 0x00007f123a20ab18 SignalHandler(int) Signals.cpp:0:0
 #3 0x00007f1239854db0 __restore_rt (/lib64/libc.so.6+0x54db0)
 #4 0x00007f12398a365c __pthread_kill_implementation (/lib64/libc.so.6+0xa365c)
 #5 0x00007f1239854d06 gsignal (/lib64/libc.so.6+0x54d06)
 #6 0x00007f12398287f3 abort (/lib64/libc.so.6+0x287f3)
 #7 0x00007f123982871b _nl_load_domain.cold (/lib64/libc.so.6+0x2871b)
 #8 0x00007f123984dca6 (/lib64/libc.so.6+0x4dca6)
 #9 0x00007f123d3f54c3 getRetainedNodeScope(llvm::MDNode const*) DwarfDebug.cpp:0:0
#10 0x00007f123d3f686a llvm::DwarfDebug::endFunctionImpl(llvm::MachineFunction const*) (/home/davidino/llvm-build-upstream/bin/../lib/../lib/libLLVMAsmPrinter.so.18git+0x10086a)
#11 0x00007f123d3ce46f llvm::DebugHandlerBase::endFunction(llvm::MachineFunction const*) (/home/davidino/llvm-build-upstream/bin/../lib/../lib/libLLVMAsmPrinter.so.18git+0xd846f)
#12 0x00007f123d3a70fb llvm::AsmPrinter::emitFunctionBody() (/home/davidino/llvm-build-upstream/bin/../lib/../lib/libLLVMAsmPrinter.so.18git+0xb10fb)
#13 0x00007f1240c3db08 llvm::X86AsmPrinter::runOnMachineFunction(llvm::MachineFunction&) X86AsmPrinter.cpp:0:0
#14 0x00007f123e1de48d llvm::MachineFunctionPass::runOnFunction(llvm::Function&) (/home/davidino/llvm-build-upstream/bin/../lib/libLLVMCodeGen.so.18git+0x5de48d)
#15 0x00007f123a8a0842 llvm::FPPassManager::runOnFunction(llvm::Function&) (/home/davidino/llvm-build-upstream/bin/../lib/libLLVMCore.so.18git+0x4a0842)
#16 0x00007f123a8a7542 llvm::FPPassManager::runOnModule(llvm::Module&) (/home/davidino/llvm-build-upstream/bin/../lib/libLLVMCore.so.18git+0x4a7542)
#17 0x00007f123a8a0f56 llvm::legacy::PassManagerImpl::run(llvm::Module&) (/home/davidino/llvm-build-upstream/bin/../lib/libLLVMCore.so.18git+0x4a0f56)
#18 0x00007f123cbd248a codegen(llvm::lto::Config const&, llvm::TargetMachine*, std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, unsigned int, llvm::Module&, llvm::ModuleSummaryIndex const&) LTOBackend.cpp:0:0
#19 0x00007f123cbd35cb llvm::lto::thinBackend(llvm::lto::Config const&, unsigned int, std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, llvm::Module&, llvm::ModuleSummaryIndex const&, llvm::DenseMap<llvm::StringRef, std::unordered_set<unsigned long, std::hash<unsigned long>, std::equal_to<unsigned long>, std::allocator<unsigned long>>, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, std::unordered_set<unsigned long, std::hash<unsigned long>, std::equal_to<unsigned long>, std::allocator<unsigned long>>>> const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>*, std::vector<unsigned char, std::allocator<unsigned char>> const&)::$_6::operator()(llvm::Module&, llvm::TargetMachine*, std::unique_ptr<llvm::ToolOutputFile, std::default_delete<llvm::ToolOutputFile>>) const LTOBackend.cpp:0:0
#20 0x00007f123cbd3329 llvm::lto::thinBackend(llvm::lto::Config const&, unsigned int, std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, llvm::Module&, llvm::ModuleSummaryIndex const&, llvm::DenseMap<llvm::StringRef, std::unordered_set<unsigned long, std::hash<unsigned long>, std::equal_to<unsigned long>, std::allocator<unsigned long>>, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, std::unordered_set<unsigned long, std::hash<unsigned long>, std::equal_to<unsigned long>, std::allocator<unsigned long>>>> const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>*, std::vector<unsigned char, std::allocator<unsigned char>> const&) (/home/davidino/llvm-build-upstream/bin/../lib/../lib/libLLVMLTO.so.18git+0x5a329)
#21 0x00007f123e8a1d0a clang::EmitBackendOutput(clang::DiagnosticsEngine&, clang::HeaderSearchOptions const&, clang::CodeGenOptions const&, clang::TargetOptions const&, clang::LangOptions const&, llvm::StringRef, llvm::Module*, clang::BackendAction, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream>>, clang::BackendConsumer*) (/home/davidino/llvm-build-upstream/bin/../lib/libclangCodeGen.so.18git+0x2a1d0a)
#22 0x00007f123ed589dc clang::CodeGenAction::ExecuteAction() (/home/davidino/llvm-build-upstream/bin/../lib/libclangCodeGen.so.18git+0x7589dc)
#23 0x00007f123cd98aaf clang::FrontendAction::Execute() (/home/davidino/llvm-build-upstream/bin/../lib/libclangFrontend.so.18git+0x198aaf)
#24 0x00007f123ccfb21d clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/home/davidino/llvm-build-upstream/bin/../lib/libclangFrontend.so.18git+0xfb21d)
#25 0x00007f1240ff67fa clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/home/davidino/llvm-build-upstream/bin/../lib/libclangFrontendTool.so.18git+0x57fa)
#26 0x0000000000216d0f cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/home/davidino/llvm-build-upstream/bin/clang+++0x216d0f)
#27 0x00000000002131df ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#28 0x0000000000212497 clang_main(int, char**, llvm::ToolContext const&) (/home/davidino/llvm-build-upstream/bin/clang+++0x212497)

dcci added a commit that referenced this pull request Jan 17, 2024
@dcci
Copy link
Copy Markdown
Member

dcci commented Jan 17, 2024

Reverted in b6f922f

@jmorse
Copy link
Copy Markdown
Member

jmorse commented Dec 6, 2024

I've placed a re-application of this code in #119001, along with a commit that attempts to fix the matter discovered here. To avoid multiple DICompositeTypes in multiple DISubprograms being ODRUnique'd, we instead put them in the declaration DISubprogram which should be unique'd anyway.

dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Sep 17, 2025
…subprogram DIEs

With this change, construction of abstract subprogram DIEs is split in two stages/functions:
creation of DIE (in DwarfCompileUnit::getOrCreateAbstractSubprogramDIE) and its population
with children (in DwarfCompileUnit::constructAbstractSubprogramScopeDIE).
With that, abstract subprograms can be created/referenced from DwarfDebug::beginModule, which
should solve the issue with static local variables DIE creation of inlined functons
with optimized-out definitions. It fixes llvm#29985.

LexicalScopes class now stores mapping from DISubprograms to their corresponding llvm::Function's.
It is supposed to be built before processing of each function (so, now it has a method for "module
initialization" alongside the method for "function initialization"). It is used by DwarfCompileUnit
to determine whether a DISubprogram needs an abstract DIE before DwarfDebug::beginFunction is invoked.

DwarfCompileUnit::getOrCreateSubprogramDIE method is added, which can create an abstract or a concrete
DIE for a subprogram. It accepts llvm::Function* argument to determine whether a concrete DIE must be created.

This is a temporary fix for llvm#29985. Ideally, it will be fixed by
moving global variables and types emission to DwarfDebug::endModule (https://reviews.llvm.org/D144007, https://reviews.llvm.org/D144005).
However, I'm not sure if these patches can be merged before llvm#75385.
The last attempt to make it mergeable was llvm#142166.
@dwblaikie came up with an idea of making DISubprograms unique in LLVM IR. To implement that,
I've tried making a patch that allows DwarfDebug to handle multiple llvm::Functions referring
to the same DISubprogram, and it also needs parts of the functionality of this patch.

Some changes made by @ellishg in llvm#90523 were taken for this commit.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Oct 10, 2025
…o multiple Functions

Depends on:
* TODO

In llvm#75385 (and the following
tries), an attempt was made, to support attaching local types to
DILocalScopes, and to store function local types in DISubprogram's
`retainedNodes:` field.

That patch failed to land due to issues arising during LTO process.
If two definition DISubprograms from different compile units
represent, essentially, the same source code function, and have
common local DICompositeType, and if this DICompositeType is uniqued
(due to ODRUniquingDebugTypes feature), the subprograms end up
having wrong retainedNodes list/scoping relationship.

To tackle this issue, in
llvm#142166, it was proposed
to force-unique all DISubporgrams even if they don't contain odr-uniqued types
(llvm#142166 (comment)).
It should establish one-to-one-to-many relationship between
DISubprograms, abstract DIEs and function clones (from different CUs, in
case of LTO).

To implement that, AsmPrinter should support correct emission of debug info
for DISubprograms attached to multiple functions. This is the goal of
this commit.

Here, LexicalScope's function map is changed to multimap between
DISubprogram and (possible multiple) functions attached to it.
LexicalScope is modified to create an abstract scope for a DISubprogram
having multiple lllvm::Function attachments.
`DwarfCompileUnit::getOrCreateSubprogramDIE` can recognize the case of
DISubprogram attached to multiple Functions, and return abstract DIE
when needed.

CodeViewDebug is adopted as well. UDTs are ensured to be emmited properly in
the cases that are addressed here. Please let me know if more changes
to CodeView needed, as I'm not very familiar with the format.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Oct 10, 2025
…o multiple Functions

Depends on:
* llvm#152680
* llvm#162852

In llvm#75385 (and the following
tries), an attempt was made, to support attaching local types to
DILocalScopes, and to store function local types in DISubprogram's
`retainedNodes:` field.

That patch failed to land due to issues arising during LTO process.
If two definition DISubprograms from different compile units
represent, essentially, the same source code function, and have
common local DICompositeType, and if this DICompositeType is uniqued
(due to ODRUniquingDebugTypes feature), the subprograms end up
having wrong retainedNodes list/scoping relationship.

To tackle this issue, in
llvm#142166, it was proposed
to force-unique all DISubporgrams even if they don't contain odr-uniqued types
(llvm#142166 (comment)).
It should establish one-to-one-to-many relationship between
DISubprograms, abstract DIEs and function clones (from different CUs, in
case of LTO).

To implement that, AsmPrinter should support correct emission of debug info
for DISubprograms attached to multiple functions. This is the goal of
this commit.

Here, LexicalScope's function map is changed to multimap between
DISubprogram and (possible multiple) functions attached to it.
LexicalScope is modified to create an abstract scope for a DISubprogram
having multiple lllvm::Function attachments.
`DwarfCompileUnit::getOrCreateSubprogramDIE` can recognize the case of
DISubprogram attached to multiple Functions, and return abstract DIE
when needed.

CodeViewDebug is adopted as well. UDTs are ensured to be emmited properly in
the cases that are addressed here. Please let me know if more changes
to CodeView needed, as I'm not very familiar with the format.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Oct 10, 2025
…o multiple Functions

Depends on:
* llvm#152680
* llvm#162852

In llvm#75385 (and the following
tries), an attempt was made, to support attaching local types to
DILocalScopes, and to store function local types in DISubprogram's
`retainedNodes:` field.

That patch failed to land due to issues arising during LTO process.
If two definition DISubprograms from different compile units
represent, essentially, the same source code function, and have
common local DICompositeType, and if this DICompositeType is uniqued
(due to ODRUniquingDebugTypes feature), the subprograms end up
having wrong retainedNodes list/scoping relationship.

To tackle this issue, in
llvm#142166, it was proposed
to force-unique all DISubporgrams even if they don't contain odr-uniqued types
(llvm#142166 (comment)).
It should establish one-to-one-to-many relationship between
DISubprograms, abstract DIEs and function clones (from different CUs, in
case of LTO).

To implement that, AsmPrinter should support correct emission of debug info
for DISubprograms attached to multiple functions. This is the goal of
this commit.

Here, LexicalScope's function map is changed to multimap between
DISubprogram and (possible multiple) functions attached to it.
LexicalScope is modified to create an abstract scope for a DISubprogram
having multiple lllvm::Function attachments.
`DwarfCompileUnit::getOrCreateSubprogramDIE` can recognize the case of
DISubprogram attached to multiple Functions, and return abstract DIE
when needed.

CodeViewDebug is adopted as well. UDTs are ensured to be emmited properly in
the cases that are addressed here. Please let me know if more changes
to CodeView needed, as I'm not very familiar with the format.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Oct 15, 2025
…o multiple Functions

Depends on:
* llvm#152680
* llvm#162852

In llvm#75385 (and the following
tries), an attempt was made, to support attaching local types to
DILocalScopes, and to store function local types in DISubprogram's
`retainedNodes:` field.

That patch failed to land due to issues arising during LTO process.
If two definition DISubprograms from different compile units
represent, essentially, the same source code function, and have
common local DICompositeType, and if this DICompositeType is uniqued
(due to ODRUniquingDebugTypes feature), the subprograms end up
having wrong retainedNodes list/scoping relationship.

To tackle this issue, in
llvm#142166, it was proposed
to force-unique all DISubporgrams even if they don't contain odr-uniqued types
(llvm#142166 (comment)).
It should establish one-to-one-to-many relationship between
DISubprograms, abstract DIEs and function clones (from different CUs, in
case of LTO).

To implement that, AsmPrinter should support correct emission of debug info
for DISubprograms attached to multiple functions. This is the goal of
this commit.

Here, LexicalScope's function map is changed to multimap between
DISubprogram and (possible multiple) functions attached to it.
LexicalScope is modified to create an abstract scope for a DISubprogram
having multiple lllvm::Function attachments.
`DwarfCompileUnit::getOrCreateSubprogramDIE` can recognize the case of
DISubprogram attached to multiple Functions, and return abstract DIE
when needed.

CodeViewDebug is adopted as well. UDTs are ensured to be emmited properly in
the cases that are addressed here. Please let me know if more changes
to CodeView needed, as I'm not very familiar with the format.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Oct 23, 2025
…exical block scopes (4/7)"

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was llvm#75385.
The issue with it was investigated in
llvm#75385 (comment).
If the same (in the sense of ODR identifier/ODR uniquing rules) local type
is present in two modules, and these modules are linked together, the type
gets uniqued. A DIType, that happens to be loaded first, survives linking,
and the references on other types with the same ODR identifier from the modules
loaded later are replaced with the references on the DIType loaded first.
Since defintion subprograms, in scope of which these types are located,
are not deduplicated, the linker output may contain multiple
DISubprogram's having the same (uniqued) type in their retainedNodes
lists.
Further compilation of such modules causes crashes.

To tackle that,
(1) previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
(2) for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another subprogram
are removed.

With this approach, clang builds without crashes in FullLTO (which is not
the case for llvm#75385).

Additionally:
- a check is added to Verifier to report about local types located
in a wrong retainedNodes list,
- DIBuilder's methods for type creation are updated, as https://reviews.llvm.org/D144006
has gotten slightly out-of-date.

Commit llvm#75385 is separated from
the new changes to simplify review process.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Oct 23, 2025
…exical block scopes (4/7)"

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was llvm#75385.
The issue with it was investigated in
llvm#75385 (comment).
If the same (in the sense of ODR identifier/ODR uniquing rules) local type
is present in two modules, and these modules are linked together, the type
gets uniqued. A DIType, that happens to be loaded first, survives linking,
and the references on other types with the same ODR identifier from the modules
loaded later are replaced with the references on the DIType loaded first.
Since defintion subprograms, in scope of which these types are located,
are not deduplicated, the linker output may contain multiple
DISubprogram's having the same (uniqued) type in their retainedNodes
lists.
Further compilation of such modules causes crashes.

To tackle that,
(1) previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
(2) for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another subprogram
are removed. If something from a Function corresponding to the
DISubprogram references uniqued type, we rely on cross-CU links.

With this approach, clang builds without crashes in FullLTO (which is not
the case for llvm#75385).

Additionally:
- a check is added to Verifier to report about local types located
in a wrong retainedNodes list,
- DIBuilder's methods for type creation are updated, as https://reviews.llvm.org/D144006
has gotten slightly out-of-date.

Commit llvm#75385 and the new changes
are placed in separate commits to simplify review process.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Oct 23, 2025
…exical block scopes (4/7)"

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was llvm#75385.
The issue with it was investigated in
llvm#75385 (comment).
If the same (in the sense of ODR identifier/ODR uniquing rules) local type
is present in two modules, and these modules are linked together, the type
gets uniqued. A DIType, that happens to be loaded first, survives linking,
and the references on other types with the same ODR identifier from the modules
loaded later are replaced with the references on the DIType loaded first.
Since defintion subprograms, in scope of which these types are located,
are not deduplicated, the linker output may contain multiple
DISubprogram's having the same (uniqued) type in their retainedNodes
lists.
Further compilation of such modules causes crashes.

To tackle that,
* previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
* for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another subprogram
are removed. If something from a Function corresponding to the
DISubprogram references uniqued type, we rely on cross-CU links.

With this approach, clang builds without crashes in FullLTO (which is not
the case for llvm#75385).

Additionally:
* a check is added to Verifier to report about local types located
in a wrong retainedNodes list,
* DIBuilder's methods for type creation are updated, as https://reviews.llvm.org/D144006
has gotten slightly out-of-date.

Commit llvm#75385 and the new changes
are placed in separate commits to simplify review process.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Oct 27, 2025
…exical block scopes (4/7)"

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was llvm#75385.
The issue with it was investigated in
llvm#75385 (comment).
If the same (in the sense of ODR identifier/ODR uniquing rules) local type
is present in two modules, and these modules are linked together, the type
gets uniqued. A DIType, that happens to be loaded first, survives linking,
and the references on other types with the same ODR identifier from the modules
loaded later are replaced with the references on the DIType loaded first.
Since defintion subprograms, in scope of which these types are located,
are not deduplicated, the linker output may contain multiple
DISubprogram's having the same (uniqued) type in their retainedNodes
lists.
Further compilation of such modules causes crashes.

To tackle that,
* previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
* for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another subprogram
are removed. If something from a Function corresponding to the
DISubprogram references uniqued type, we rely on cross-CU links.

With this approach, clang builds without crashes in FullLTO (which is not
the case for llvm#75385).

Additionally:
* a check is added to Verifier to report about local types located
in a wrong retainedNodes list,
* DIBuilder's methods for type creation are updated, as https://reviews.llvm.org/D144006
has gotten slightly out-of-date.

Commit llvm#75385 and the new changes
are placed in separate commits to simplify review process.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Oct 27, 2025
…exical block scopes (4/7)"

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was llvm#75385.
The issue with it was investigated in
llvm#75385 (comment).
If the same (in the sense of ODR identifier/ODR uniquing rules) local type
is present in two modules, and these modules are linked together, the type
gets uniqued. A DIType, that happens to be loaded first, survives linking,
and the references on other types with the same ODR identifier from the modules
loaded later are replaced with the references on the DIType loaded first.
Since defintion subprograms, in scope of which these types are located,
are not deduplicated, the linker output may contain multiple
DISubprogram's having the same (uniqued) type in their retainedNodes
lists.
Further compilation of such modules causes crashes.

To tackle that,
* previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
* for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another subprogram
are removed. If something from a Function corresponding to the
DISubprogram references uniqued type, we rely on cross-CU links.

With this approach, clang builds without crashes in FullLTO (which is not
the case for llvm#75385).

Additionally:
* a check is added to Verifier to report about local types located
in a wrong retainedNodes list,
* DIBuilder's methods for type creation are updated, as https://reviews.llvm.org/D144006
has gotten slightly out-of-date.

Commit llvm#75385 and the new changes
are placed in separate commits to simplify review process.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Nov 6, 2025
These checks ensure that retained nodes of a DISubprogram belong
to the subprogram.

This was helpful to find issues with https://reviews.llvm.org/D144004,
llvm#75385,
llvm#165032.

Also, interface for accessing DISubprogram's retained nodes is slightly
refactored. `DISubprogram::visitRetainedNodes` and
`DISubprogram::forEachRetainedNode` are added to avoid repeating
checks like
```
if (const auto *LV = dyn_cast<DILocalVariable>(N))
  ...
else if (const auto *L = dyn_cast<DILabel>(N))
  ...
else if (const auto *IE = dyn_cast<DIImportedEntity>(N))
  ...
```

Tests with wrongly scoped retained nodes are fixed.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Nov 10, 2025
…exical block scopes (4/7)"

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was llvm#75385.
The issue with it was investigated in
llvm#75385 (comment).
If the same (in the sense of ODR identifier/ODR uniquing rules) local type
is present in two modules, and these modules are linked together, the type
gets uniqued. A DIType, that happens to be loaded first, survives linking,
and the references on other types with the same ODR identifier from the modules
loaded later are replaced with the references on the DIType loaded first.
Since defintion subprograms, in scope of which these types are located,
are not deduplicated, the linker output may contain multiple
DISubprogram's having the same (uniqued) type in their retainedNodes
lists.
Further compilation of such modules causes crashes.

To tackle that,
* previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
* for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another subprogram
are removed. If something from a Function corresponding to the
DISubprogram references uniqued type, we rely on cross-CU links.

With this approach, clang builds without crashes in FullLTO (which is not
the case for llvm#75385).

Additionally:
* a check is added to Verifier to report about local types located
in a wrong retainedNodes list,
* DIBuilder's methods for type creation are updated, as https://reviews.llvm.org/D144006
has gotten slightly out-of-date.

Commit llvm#75385 and the new changes
are placed in separate commits to simplify review process.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Nov 11, 2025
…exical block scopes (4/7)"

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was llvm#75385.
The issue with it was investigated in
llvm#75385 (comment).
If the same (in the sense of ODR identifier/ODR uniquing rules) local type
is present in two modules, and these modules are linked together, the type
gets uniqued. A DIType, that happens to be loaded first, survives linking,
and the references on other types with the same ODR identifier from the modules
loaded later are replaced with the references on the DIType loaded first.
Since defintion subprograms, in scope of which these types are located,
are not deduplicated, the linker output may contain multiple
DISubprogram's having the same (uniqued) type in their retainedNodes
lists.
Further compilation of such modules causes crashes.

To tackle that,
* previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
* for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another subprogram
are removed. If something from a Function corresponding to the
DISubprogram references uniqued type, we rely on cross-CU links.

With this approach, clang builds without crashes in FullLTO (which is not
the case for llvm#75385).

Additionally:
* a check is added to Verifier to report about local types located
in a wrong retainedNodes list,
* DIBuilder's methods for type creation are updated, as https://reviews.llvm.org/D144006
has gotten slightly out-of-date.

Commit llvm#75385 and the new changes
are placed in separate commits to simplify review process.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Nov 20, 2025
…exical block scopes (4/7)"

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was llvm#75385.
The issue with it was investigated in
llvm#75385 (comment).
If the same (in the sense of ODR identifier/ODR uniquing rules) local type
is present in two modules, and these modules are linked together, the type
gets uniqued. A DIType, that happens to be loaded first, survives linking,
and the references on other types with the same ODR identifier from the modules
loaded later are replaced with the references on the DIType loaded first.
Since defintion subprograms, in scope of which these types are located,
are not deduplicated, the linker output may contain multiple
DISubprogram's having the same (uniqued) type in their retainedNodes
lists.
Further compilation of such modules causes crashes.

To tackle that,
* previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
* for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another subprogram
are removed. If something from a Function corresponding to the
DISubprogram references uniqued type, we rely on cross-CU links.

With this approach, clang builds without crashes in FullLTO (which is not
the case for llvm#75385).

Additionally:
* a check is added to Verifier to report about local types located
in a wrong retainedNodes list,
* DIBuilder's methods for type creation are updated, as https://reviews.llvm.org/D144006
has gotten slightly out-of-date.

Commit llvm#75385 and the new changes
are placed in separate commits to simplify review process.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Dec 3, 2025
…exical block scopes (4/7)"

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was llvm#75385.
The issue with it was investigated in
llvm#75385 (comment).
If the same (in the sense of ODR identifier/ODR uniquing rules) local type
is present in two modules, and these modules are linked together, the type
gets uniqued. A DIType, that happens to be loaded first, survives linking,
and the references on other types with the same ODR identifier from the modules
loaded later are replaced with the references on the DIType loaded first.
Since defintion subprograms, in scope of which these types are located,
are not deduplicated, the linker output may contain multiple
DISubprogram's having the same (uniqued) type in their retainedNodes
lists.
Further compilation of such modules causes crashes.

To tackle that,
* previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
* for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another subprogram
are removed. If something from a Function corresponding to the
DISubprogram references uniqued type, we rely on cross-CU links.

With this approach, clang builds without crashes in FullLTO (which is not
the case for llvm#75385).

Additionally:
* a check is added to Verifier to report about local types located
in a wrong retainedNodes list,
* DIBuilder's methods for type creation are updated, as https://reviews.llvm.org/D144006
has gotten slightly out-of-date.

Commit llvm#75385 and the new changes
are placed in separate commits to simplify review process.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Jan 23, 2026
…exical block scopes (4/7)"

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was llvm#75385.
The issue with it was investigated in
llvm#75385 (comment).
If the same (in the sense of ODR identifier/ODR uniquing rules) local type
is present in two modules, and these modules are linked together, the type
gets uniqued. A DIType, that happens to be loaded first, survives linking,
and the references on other types with the same ODR identifier from the modules
loaded later are replaced with the references on the DIType loaded first.
Since defintion subprograms, in scope of which these types are located,
are not deduplicated, the linker output may contain multiple
DISubprogram's having the same (uniqued) type in their retainedNodes
lists.
Further compilation of such modules causes crashes.

To tackle that,
* previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
* for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another subprogram
are removed. If something from a Function corresponding to the
DISubprogram references uniqued type, we rely on cross-CU links.

With this approach, clang builds without crashes in FullLTO (which is not
the case for llvm#75385).

Additionally:
* a check is added to Verifier to report about local types located
in a wrong retainedNodes list,
* DIBuilder's methods for type creation are updated, as https://reviews.llvm.org/D144006
has gotten slightly out-of-date.

Commit llvm#75385 and the new changes
are placed in separate commits to simplify review process.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Jan 27, 2026
…exical block scopes (4/7)"

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was llvm#75385.
The issue with it was investigated in
llvm#75385 (comment).
If the same (in the sense of ODR identifier/ODR uniquing rules) local type
is present in two modules, and these modules are linked together, the type
gets uniqued. A DIType, that happens to be loaded first, survives linking,
and the references on other types with the same ODR identifier from the modules
loaded later are replaced with the references on the DIType loaded first.
Since defintion subprograms, in scope of which these types are located,
are not deduplicated, the linker output may contain multiple
DISubprogram's having the same (uniqued) type in their retainedNodes
lists.
Further compilation of such modules causes crashes.

To tackle that,
* previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
* for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another subprogram
are removed. If something from a Function corresponding to the
DISubprogram references uniqued type, we rely on cross-CU links.

With this approach, clang builds without crashes in FullLTO (which is not
the case for llvm#75385).

Additionally:
* a check is added to Verifier to report about local types located
in a wrong retainedNodes list,
* DIBuilder's methods for type creation are updated, as https://reviews.llvm.org/D144006
has gotten slightly out-of-date.

Commit llvm#75385 and the new changes
are placed in separate commits to simplify review process.
dzhidzhoev added a commit to dzhidzhoev/llvm-project that referenced this pull request Jan 30, 2026
…exical block scopes (4/7)"

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was llvm#75385.
The issue with it was investigated in
llvm#75385 (comment).
If the same (in the sense of ODR identifier/ODR uniquing rules) local type
is present in two modules, and these modules are linked together, the type
gets uniqued. A DIType, that happens to be loaded first, survives linking,
and the references on other types with the same ODR identifier from the modules
loaded later are replaced with the references on the DIType loaded first.
Since defintion subprograms, in scope of which these types are located,
are not deduplicated, the linker output may contain multiple
DISubprogram's having the same (uniqued) type in their retainedNodes
lists.
Further compilation of such modules causes crashes.

To tackle that,
* previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
* for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another subprogram
are removed. If something from a Function corresponding to the
DISubprogram references uniqued type, we rely on cross-CU links.

With this approach, clang builds without crashes in FullLTO (which is not
the case for llvm#75385).

Additionally:
* a check is added to Verifier to report about local types located
in a wrong retainedNodes list,
* DIBuilder's methods for type creation are updated, as https://reviews.llvm.org/D144006
has gotten slightly out-of-date.

Commit llvm#75385 and the new changes
are placed in separate commits to simplify review process.
dzhidzhoev added a commit that referenced this pull request Feb 3, 2026
…exical block scopes (4/7)" (#165032)

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was
#75385.
The issue with it was investigated in
#75385 (comment).
The problem happens when 
1. Several modules are being linked.
2. There are several DISubprograms that initially belong to different
modules but represent the same source code function (for example, a
function included from the same source code file).
3. Some of such DISubprograms survive IR linking. It may happen if one
of them is inlined somewhere or if the functions that have these
DISubprograms attached have internal linkage.
4. Each of these DISubprograms has a local type that corresponds to the
same source code type. These types are initially from different modules,
but have the same ODR identifier.

If the same (in the sense of ODR identifier/ODR uniquing rules) local
type is present in two modules, and these modules are linked together,
the type gets uniqued. A DIType, that happens to be loaded first,
survives linking, and the references on other types with the same ODR
identifier from the modules loaded later are replaced with the
references on the DIType loaded first. Since defintion subprograms, in
scope of which these types are located, are not deduplicated, the linker
output may contain multiple DISubprogram's having the same (uniqued)
type in their retainedNodes lists.
Further compilation of such modules causes crashes.

To tackle that,
* previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
* for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another
subprogram are removed. If something from a Function corresponding to
the DISubprogram references uniqued type, we rely on cross-CU links.

Additionally:
* a check is added to Verifier to report about local types located in a
wrong retainedNodes list,

Original commit message follows.
---------

RFC https://discourse.llvm.org/t/rfc-dwarfdebug-fix-and-improve-handling-imported-entities-types-and-static-local-in-subprogram-and-lexical-block-scopes/68544

Similar to imported declarations, the patch tracks function-local types in
DISubprogram's 'retainedNodes' field. DwarfDebug is adjusted in accordance with
the aforementioned metadata change and provided a support of function-local
types scoped within a lexical block.

The patch assumes that DICompileUnit's 'enums field' no longer tracks local
types and DwarfDebug would assert if any locally-scoped types get placed there.

Authored-by: Kristina Bessonova <[email protected]>
Co-authored-by: Jeremy Morse <[email protected]>
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Feb 3, 2026
… types in lexical block scopes (4/7)" (#165032)

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was
llvm/llvm-project#75385.
The issue with it was investigated in
llvm/llvm-project#75385 (comment).
The problem happens when
1. Several modules are being linked.
2. There are several DISubprograms that initially belong to different
modules but represent the same source code function (for example, a
function included from the same source code file).
3. Some of such DISubprograms survive IR linking. It may happen if one
of them is inlined somewhere or if the functions that have these
DISubprograms attached have internal linkage.
4. Each of these DISubprograms has a local type that corresponds to the
same source code type. These types are initially from different modules,
but have the same ODR identifier.

If the same (in the sense of ODR identifier/ODR uniquing rules) local
type is present in two modules, and these modules are linked together,
the type gets uniqued. A DIType, that happens to be loaded first,
survives linking, and the references on other types with the same ODR
identifier from the modules loaded later are replaced with the
references on the DIType loaded first. Since defintion subprograms, in
scope of which these types are located, are not deduplicated, the linker
output may contain multiple DISubprogram's having the same (uniqued)
type in their retainedNodes lists.
Further compilation of such modules causes crashes.

To tackle that,
* previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
* for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another
subprogram are removed. If something from a Function corresponding to
the DISubprogram references uniqued type, we rely on cross-CU links.

Additionally:
* a check is added to Verifier to report about local types located in a
wrong retainedNodes list,

Original commit message follows.
---------

RFC https://discourse.llvm.org/t/rfc-dwarfdebug-fix-and-improve-handling-imported-entities-types-and-static-local-in-subprogram-and-lexical-block-scopes/68544

Similar to imported declarations, the patch tracks function-local types in
DISubprogram's 'retainedNodes' field. DwarfDebug is adjusted in accordance with
the aforementioned metadata change and provided a support of function-local
types scoped within a lexical block.

The patch assumes that DICompileUnit's 'enums field' no longer tracks local
types and DwarfDebug would assert if any locally-scoped types get placed there.

Authored-by: Kristina Bessonova <[email protected]>
Co-authored-by: Jeremy Morse <[email protected]>
rishabhmadan19 pushed a commit to rishabhmadan19/llvm-project that referenced this pull request Feb 9, 2026
…exical block scopes (4/7)" (llvm#165032)

This is an attempt to merge https://reviews.llvm.org/D144006 with LTO
fix.

The last merge attempt was
llvm#75385.
The issue with it was investigated in
llvm#75385 (comment).
The problem happens when 
1. Several modules are being linked.
2. There are several DISubprograms that initially belong to different
modules but represent the same source code function (for example, a
function included from the same source code file).
3. Some of such DISubprograms survive IR linking. It may happen if one
of them is inlined somewhere or if the functions that have these
DISubprograms attached have internal linkage.
4. Each of these DISubprograms has a local type that corresponds to the
same source code type. These types are initially from different modules,
but have the same ODR identifier.

If the same (in the sense of ODR identifier/ODR uniquing rules) local
type is present in two modules, and these modules are linked together,
the type gets uniqued. A DIType, that happens to be loaded first,
survives linking, and the references on other types with the same ODR
identifier from the modules loaded later are replaced with the
references on the DIType loaded first. Since defintion subprograms, in
scope of which these types are located, are not deduplicated, the linker
output may contain multiple DISubprogram's having the same (uniqued)
type in their retainedNodes lists.
Further compilation of such modules causes crashes.

To tackle that,
* previous solution to handle LTO linking with local types in
retainedNodes is removed (cloneLocalTypes() function),
* for each loaded distinct (definition) DISubprogram, its retainedNodes
list is scanned after loading, and DITypes with a scope of another
subprogram are removed. If something from a Function corresponding to
the DISubprogram references uniqued type, we rely on cross-CU links.

Additionally:
* a check is added to Verifier to report about local types located in a
wrong retainedNodes list,

Original commit message follows.
---------

RFC https://discourse.llvm.org/t/rfc-dwarfdebug-fix-and-improve-handling-imported-entities-types-and-static-local-in-subprogram-and-lexical-block-scopes/68544

Similar to imported declarations, the patch tracks function-local types in
DISubprogram's 'retainedNodes' field. DwarfDebug is adjusted in accordance with
the aforementioned metadata change and provided a support of function-local
types scoped within a lexical block.

The patch assumes that DICompileUnit's 'enums field' no longer tracks local
types and DwarfDebug would assert if any locally-scoped types get placed there.

Authored-by: Kristina Bessonova <[email protected]>
Co-authored-by: Jeremy Morse <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category debuginfo llvm:ir llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants