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

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 06:11:30 PDT 2026


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

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 at anthropic.com>

>From 5a11b16842ae5ddb4412fdf4a61ca75d342764b9 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 22 Sep 2026 23:36:18 +0200
Subject: [PATCH] CodeGen: Mark dead PHI destination copies dead in the
 LiveIntervals path

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 at anthropic.com>
---
 llvm/lib/CodeGen/PHIElimination.cpp           |  5 ++
 .../CodeGen/X86/phi-elimination-dead-def.mir  | 57 +++++++++++++++++++
 2 files changed, 62 insertions(+)
 create mode 100644 llvm/test/CodeGen/X86/phi-elimination-dead-def.mir

diff --git a/llvm/lib/CodeGen/PHIElimination.cpp b/llvm/lib/CodeGen/PHIElimination.cpp
index 054e24bc020692..de69ca8d918986 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 00000000000000..447f0eff8df998
--- /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
+...



More information about the llvm-commits mailing list