[llvm] [GlobalISel] Undef debug uses of erased instructions (PR #228906)

via llvm-commits llvm-commits at lists.llvm.org
Sun Oct 4 08:19:08 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v

@llvm/pr-subscribers-backend-aarch64

Author: Aochang Liu (HelloWorldU)

<details>
<summary>Changes</summary>

Erasing an instruction could leave a `DBG_VALUE` referring to its def: salvaging failures were ignored, and defs erased as dead through eraseInstrs were not salvaged at all. On RV32 the dangling s64 asserts in RegBankSelect with -g; other targets keep the dangling reference silently.

Salvage before every erase and undef what cannot be salvaged, skipping defs a combine replaced with a vreg defined elsewhere. The updated tests only change dangling references to `$noreg`.

Fixes #<!-- -->228874

Assisted-by: Claude Opus 5.5

---
Full diff: https://github.com/llvm/llvm-project/pull/228906.diff


7 Files Affected:

- (modified) llvm/lib/CodeGen/GlobalISel/Utils.cpp (+7) 
- (modified) llvm/test/CodeGen/AArch64/GlobalISel/salvage-debug-info-dead.mir (+1-1) 
- (modified) llvm/test/CodeGen/AArch64/GlobalISel/select-dbg-value.mir (+1-1) 
- (modified) llvm/test/CodeGen/AArch64/GlobalISel/uaddo-8-16-bits.mir (+1-1) 
- (added) llvm/test/CodeGen/RISCV/GlobalISel/legalizer-dbg-value-undef.mir (+81) 
- (modified) llvm/test/DebugInfo/AArch64/debug-reg-bank.ll (+1-1) 
- (modified) llvm/test/DebugInfo/X86/debug-reg-bank.ll (+1-1) 


``````````diff
diff --git a/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/llvm/lib/CodeGen/GlobalISel/Utils.cpp
index 9a369bbdced1a..364a70ad8598a 100644
--- a/llvm/lib/CodeGen/GlobalISel/Utils.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/Utils.cpp
@@ -1647,6 +1647,7 @@ void llvm::saveUsesAndErase(MachineInstr &MI, MachineRegisterInfo &MRI,
       DeadInstChain.insert(MRI.getVRegDef(Op.getReg()));
   }
   LLVM_DEBUG(dbgs() << MI << "Is dead; erasing.\n");
+  salvageDebugInfo(MRI, MI);
   DeadInstChain.remove(&MI);
   MI.eraseFromParent();
   if (LocObserver)
@@ -1676,6 +1677,9 @@ void llvm::eraseInstr(MachineInstr &MI, MachineRegisterInfo &MRI,
 void llvm::salvageDebugInfo(const MachineRegisterInfo &MRI, MachineInstr &MI) {
   for (auto &Def : MI.defs()) {
     assert(Def.isReg() && "Must be a reg");
+    // A combine may have replaced Def with a vreg that is defined elsewhere.
+    if (!MRI.hasOneDef(Def.getReg()))
+      continue;
 
     SmallVector<MachineOperand *, 16> DbgUsers;
     for (auto &MOUse : MRI.use_operands(Def.getReg())) {
@@ -1689,6 +1693,9 @@ void llvm::salvageDebugInfo(const MachineRegisterInfo &MRI, MachineInstr &MI) {
     if (!DbgUsers.empty()) {
       salvageDebugInfoForDbgValue(MRI, MI, DbgUsers);
     }
+
+    // MI is about to be erased, so drop the debug uses that were not salvaged.
+    MRI.markUsesInDebugValueAsUndef(Def.getReg());
   }
 }
 
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/salvage-debug-info-dead.mir b/llvm/test/CodeGen/AArch64/GlobalISel/salvage-debug-info-dead.mir
index 6fd24f0af770e..8c6d383b264a0 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/salvage-debug-info-dead.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/salvage-debug-info-dead.mir
@@ -52,7 +52,7 @@ body:             |
   ; CHECK-NEXT:   DBG_VALUE $x0, $noreg, {{.*}}, !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_LLVM_convert, 16, DW_ATE_unsigned, DW_OP_LLVM_convert, 16, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value), debug-location !DILocation(line: 8, column: 7, scope: !6)
   ; CHECK: bb.1:
   ; CHECK-NEXT:   DBG_VALUE $x0, $noreg, {{.*}}, !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned, DW_OP_stack_value), debug-location !DILocation(line: 9, column: 7, scope: !6)
-  ; CHECK-NEXT:   DBG_VALUE %4:_(i32), 0, {{.*}}, !DIExpression(), debug-location !DILocation(line: 9, column: 7, scope: !6)
+  ; CHECK-NEXT:   DBG_VALUE $noreg, 0, {{.*}}, !DIExpression(), debug-location !DILocation(line: 9, column: 7, scope: !6)
   bb.0:
     liveins: $x0
     %0:_(i64) = COPY $x0
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-dbg-value.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-dbg-value.mir
index b28ebbb90a79c..c455539c5b1b5 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/select-dbg-value.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-dbg-value.mir
@@ -65,7 +65,7 @@ body: |
     ; CHECK-LABEL: name: test_dbg_value_dead
     ; CHECK: liveins: $w0
     ; CHECK-NEXT: {{  $}}
-    ; CHECK-NEXT: DBG_VALUE %1:gpr64, $noreg, !7, !DIExpression(),  debug-location !9
+    ; CHECK-NEXT: DBG_VALUE $noreg, $noreg, !7, !DIExpression(),  debug-location !9
     %0:gpr(i32) = COPY $w0
     %1:gpr(i64) = G_ZEXT %0:gpr(i32)
     DBG_VALUE %1(i64), $noreg, !7, !DIExpression(), debug-location !9
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/uaddo-8-16-bits.mir b/llvm/test/CodeGen/AArch64/GlobalISel/uaddo-8-16-bits.mir
index 67f1a85b89844..14041db257ca6 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/uaddo-8-16-bits.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/uaddo-8-16-bits.mir
@@ -310,7 +310,7 @@ body:             |
   ; CHECK-NEXT:   [[AND:%[0-9]+]]:_(i32) = G_AND [[ADD]], [[C]]
   ; CHECK-NEXT:   [[C1:%[0-9]+]]:_(i32) = G_CONSTANT i32 0
   ; CHECK-NEXT:   [[ICMP:%[0-9]+]]:_(i1) = G_ICMP intpred(eq), [[AND]](i32), [[C1]]
-  ; CHECK-NEXT:   DBG_VALUE %6:_(i16)
+  ; CHECK-NEXT:   DBG_VALUE $noreg
   ; CHECK-NEXT:   G_BRCOND [[ICMP]](i1), %bb.2
   ; CHECK-NEXT:   G_BR %bb.1
   ; CHECK-NEXT: {{  $}}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-dbg-value-undef.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-dbg-value-undef.mir
new file mode 100644
index 0000000000000..472f36ca55e4e
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-dbg-value-undef.mir
@@ -0,0 +1,81 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=riscv32 -run-pass=legalizer %s -o - | FileCheck %s
+
+# A DBG_VALUE must not keep referring to a vreg whose def the legalizer
+# erases, both when salvaging fails and when the def dies as an artifact. A
+# DBG_VALUE of an unmerge result that a combine forwarded must be kept.
+
+--- |
+  define void @dead_merge() !dbg !3 {
+    ret void
+  }
+
+  define i64 @narrowed_xor() !dbg !8 {
+    ret i64 0
+  }
+
+  !llvm.dbg.cu = !{!0}
+  !llvm.module.flags = !{!2}
+
+  !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, emissionKind: FullDebug)
+  !1 = !DIFile(filename: "t.c", directory: "/")
+  !2 = !{i32 2, !"Debug Info Version", i32 3}
+  !3 = distinct !DISubprogram(name: "dead_merge", scope: !1, file: !1, type: !4, spFlags: DISPFlagDefinition, unit: !0)
+  !4 = !DISubroutineType(types: !{})
+  !5 = !DILocalVariable(name: "a", scope: !3, file: !1, type: !6)
+  !6 = !DIBasicType(name: "long long", size: 64, encoding: DW_ATE_signed)
+  !7 = !DILocation(line: 1, scope: !3)
+  !8 = distinct !DISubprogram(name: "narrowed_xor", scope: !1, file: !1, type: !4, spFlags: DISPFlagDefinition, unit: !0)
+  !9 = !DILocalVariable(name: "n", scope: !8, file: !1, type: !6)
+  !10 = !DILocation(line: 2, scope: !8)
+...
+---
+name:            dead_merge
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $x10, $x11
+
+    ; CHECK-LABEL: name: dead_merge
+    ; CHECK: liveins: $x10, $x11
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: DBG_VALUE $noreg, $noreg, !7, !DIExpression(), debug-location !DILocation(line: 1, scope: !3)
+    ; CHECK-NEXT: PseudoRET
+    %0:_(s32) = COPY $x10
+    %1:_(s32) = COPY $x11
+    %2:_(s64) = G_MERGE_VALUES %0(s32), %1(s32)
+    DBG_VALUE %2(s64), $noreg, !5, !DIExpression(), debug-location !7
+    PseudoRET
+...
+---
+name:            narrowed_xor
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $x10, $x11
+
+    ; CHECK-LABEL: name: narrowed_xor
+    ; CHECK: liveins: $x10, $x11
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $x10
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s32) = COPY $x11
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 -1
+    ; CHECK-NEXT: [[XOR:%[0-9]+]]:_(s32) = G_XOR [[COPY]], [[C]]
+    ; CHECK-NEXT: [[XOR1:%[0-9]+]]:_(s32) = G_XOR [[COPY1]], [[C]]
+    ; CHECK-NEXT: DBG_VALUE $noreg, $noreg, !7, !DIExpression(), debug-location !DILocation(line: 2, scope: !6)
+    ; CHECK-NEXT: DBG_VALUE [[XOR]](s32), $noreg, !7, !DIExpression(DW_OP_LLVM_fragment, 0, 32), debug-location !DILocation(line: 2, scope: !6)
+    ; CHECK-NEXT: $x10 = COPY [[XOR]](s32)
+    ; CHECK-NEXT: $x11 = COPY [[XOR1]](s32)
+    ; CHECK-NEXT: PseudoRET implicit $x10, implicit $x11
+    %0:_(s32) = COPY $x10
+    %1:_(s32) = COPY $x11
+    %2:_(s64) = G_MERGE_VALUES %0(s32), %1(s32)
+    %3:_(s64) = G_CONSTANT i64 -1
+    %4:_(s64) = G_XOR %2, %3
+    DBG_VALUE %4(s64), $noreg, !9, !DIExpression(), debug-location !10
+    %5:_(s32), %6:_(s32) = G_UNMERGE_VALUES %4(s64)
+    DBG_VALUE %5(s32), $noreg, !9, !DIExpression(DW_OP_LLVM_fragment, 0, 32), debug-location !10
+    $x10 = COPY %5(s32)
+    $x11 = COPY %6(s32)
+    PseudoRET implicit $x10, implicit $x11
+...
diff --git a/llvm/test/DebugInfo/AArch64/debug-reg-bank.ll b/llvm/test/DebugInfo/AArch64/debug-reg-bank.ll
index 19c33b34f4a39..ce6194175d00c 100644
--- a/llvm/test/DebugInfo/AArch64/debug-reg-bank.ll
+++ b/llvm/test/DebugInfo/AArch64/debug-reg-bank.ll
@@ -6,7 +6,7 @@ define void @foo(i32 %n) !dbg !7 {
   ; CHECK: bb.1.entry:
   ; CHECK-NEXT:   liveins: $w0
   ; CHECK-NEXT: {{  $}}
-  ; CHECK-NEXT:   DBG_VALUE %2:gpr32, $noreg, !12, !DIExpression(), debug-location !19
+  ; CHECK-NEXT:   DBG_VALUE $noreg, $noreg, !12, !DIExpression(), debug-location !19
   ; CHECK-NEXT:   RET_ReallyLR debug-location !20
 entry:
   %m = mul i32 %n, 13
diff --git a/llvm/test/DebugInfo/X86/debug-reg-bank.ll b/llvm/test/DebugInfo/X86/debug-reg-bank.ll
index 8d3bd95720a6b..d9eb5bceea260 100644
--- a/llvm/test/DebugInfo/X86/debug-reg-bank.ll
+++ b/llvm/test/DebugInfo/X86/debug-reg-bank.ll
@@ -6,7 +6,7 @@ define void @foo(i32 %n) !dbg !7 {
   ; CHECK: bb.1.entry:
   ; CHECK-NEXT:   liveins: $edi
   ; CHECK-NEXT: {{  $}}
-  ; CHECK-NEXT:   DBG_VALUE %2:gr32, $noreg, !12, !DIExpression(), debug-location !19
+  ; CHECK-NEXT:   DBG_VALUE $noreg, $noreg, !12, !DIExpression(), debug-location !19
   ; CHECK-NEXT:   RET 0, debug-location !20
 entry:
   %m = mul i32 %n, 13

``````````

</details>


https://github.com/llvm/llvm-project/pull/228906


More information about the llvm-commits mailing list