[llvm] CodeGen: Mark dead PHI destination copies dead in the LiveIntervals path (PR #225760)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 06:12:12 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-regalloc

Author: Matt Arsenault (arsenm)

<details>
<summary>Changes</summary>

When PHIElimination lowers a PHI whose destination is dead, it records a
dead def in LiveIntervals but did not set the dead flag on the lowered copy's
def operand. The LiveVariables path set this via addVirtualRegisterDead.

Avoids "Instruction ending live segment on dead slot has no dead flag" verifier
errors once LiveVariables is removed.

Co-authored-by: Claude (Opus 4.8) <noreply@<!-- -->anthropic.com>

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


2 Files Affected:

- (modified) llvm/lib/CodeGen/PHIElimination.cpp (+5) 
- (added) llvm/test/CodeGen/X86/phi-elimination-dead-def.mir (+57) 


``````````diff
diff --git a/llvm/lib/CodeGen/PHIElimination.cpp b/llvm/lib/CodeGen/PHIElimination.cpp
index 054e24bc02069..de69ca8d91898 100644
--- a/llvm/lib/CodeGen/PHIElimination.cpp
+++ b/llvm/lib/CodeGen/PHIElimination.cpp
@@ -514,6 +514,11 @@ void PHIEliminationImpl::LowerPHINode(MachineBasicBlock &MBB,
     LiveInterval &DestLI = LIS->getInterval(DestReg);
     assert(!DestLI.empty() && "PHIs should have non-empty LiveIntervals.");
 
+    // Make sure the instruction's dead flag matches the dead range created
+    // below.
+    if (DestLI.endIndex().isDead())
+      PHICopy->getOperand(0).setIsDead();
+
     SlotIndex NewStart = DestCopyIndex.getRegSlot();
 
     SmallVector<LiveRange *> ToUpdate({&DestLI});
diff --git a/llvm/test/CodeGen/X86/phi-elimination-dead-def.mir b/llvm/test/CodeGen/X86/phi-elimination-dead-def.mir
new file mode 100644
index 0000000000000..447f0eff8df99
--- /dev/null
+++ b/llvm/test/CodeGen/X86/phi-elimination-dead-def.mir
@@ -0,0 +1,57 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=x86_64-- -run-pass=liveintervals,phi-node-elimination -o - %s | FileCheck %s
+# RUN: llc -mtriple=x86_64-- --passes='require<live-intervals>,phi-node-elimination -o - %s | FileCheck %s
+
+# A PHI whose result is unused is lowered to a dead
+# copy. PHIElimination records a dead def for it in LiveIntervals, so
+# it must also mark the copy's def operand dead so they are
+# consistent.
+
+---
+name:            dead_phi
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: dead_phi
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.2(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   JCC_1 %bb.2, 4, implicit undef $eflags
+  ; CHECK-NEXT:   JMP_1 %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[MOV32ri:%[0-9]+]]:gr32 = MOV32ri 1
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gr32 = COPY [[MOV32ri]]
+  ; CHECK-NEXT:   JMP_1 %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[MOV32ri1:%[0-9]+]]:gr32 = MOV32ri 2
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gr32 = COPY [[MOV32ri1]]
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3:
+  ; CHECK-NEXT:   dead [[COPY1:%[0-9]+]]:gr32 = COPY [[COPY]]
+  ; CHECK-NEXT:   RET64
+  bb.0:
+    successors: %bb.1, %bb.2
+
+    JCC_1 %bb.2, 4, implicit undef $eflags
+    JMP_1 %bb.1
+
+  bb.1:
+    successors: %bb.3
+
+    %0:gr32 = MOV32ri 1
+    JMP_1 %bb.3
+
+  bb.2:
+    successors: %bb.3
+
+    %1:gr32 = MOV32ri 2
+
+  bb.3:
+    %2:gr32 = PHI %0, %bb.1, %1, %bb.2
+    RET64
+...

``````````

</details>


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


More information about the llvm-commits mailing list