[llvm] X86: Remove stale EFLAGS live range when converting ADD to LEA (PR #222029)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 23:34:53 PDT 2026


https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/222029

>From 83ca7067b298d20f79fc4e3184869f033819021a Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 8 Sep 2026 17:11:51 +0200
Subject: [PATCH 1/2] X86: Remove stale EFLAGS live range when converting ADD
 to LEA

convertToThreeAddress may rewrite an EFLAGS-clobbering ADD into an LEA, which
does not define EFLAGS. hasLiveCondCodeDef guarantees the EFLAGS def was dead, so
drop its LiveIntervals value, otherwise the verifier would fail.

Fixes verifier errors with -early-live-intervals.

Co-authored-by: Claude (Claude-Opus-4.8)
---
 llvm/lib/Target/X86/X86InstrInfo.cpp          | 15 ++++++
 .../X86/twoaddr-lea-eflags-liveintervals.ll   | 51 +++++++++++++++++++
 2 files changed, 66 insertions(+)
 create mode 100644 llvm/test/CodeGen/X86/twoaddr-lea-eflags-liveintervals.ll

diff --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp
index 11a37efd28948..6471be97b62e9 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.cpp
+++ b/llvm/lib/Target/X86/X86InstrInfo.cpp
@@ -1360,8 +1360,15 @@ MachineInstr *X86InstrInfo::convertToThreeAddressWithLEA(unsigned MIOpc,
     SlotIndex Ins2Idx;
     if (InsMI2)
       Ins2Idx = LIS->InsertMachineInstrInMaps(*InsMI2);
+    bool DefinedEFLAGS = MI.definesRegister(X86::EFLAGS, /*TRI=*/nullptr) &&
+                         !NewMI->definesRegister(X86::EFLAGS, /*TRI=*/nullptr);
     SlotIndex NewIdx = LIS->ReplaceMachineInstrInMaps(MI, *NewMI);
     SlotIndex ExtIdx = LIS->InsertMachineInstrInMaps(*ExtMI);
+
+    // Drop the dead EFLAGS def MI had; the replacement does not define EFLAGS.
+    if (DefinedEFLAGS)
+      LIS->removePhysRegDefAt(X86::EFLAGS, NewIdx.getRegSlot());
+
     LIS->getInterval(InRegLEA);
     LIS->getInterval(OutRegLEA);
     if (InRegLEA2)
@@ -2042,7 +2049,15 @@ MachineInstr *X86InstrInfo::convertToThreeAddress(MachineInstr &MI,
   MBB.insert(MI.getIterator(), NewMI); // Insert the new inst
 
   if (LIS) {
+    // The replacement does not define EFLAGS; drop the dead EFLAGS def MI had.
+    SlotIndex Idx = LIS->getInstructionIndex(MI);
+    bool DefinedEFLAGS = MI.definesRegister(X86::EFLAGS, /*TRI=*/nullptr) &&
+                         !NewMI->definesRegister(X86::EFLAGS, /*TRI=*/nullptr);
+
     LIS->ReplaceMachineInstrInMaps(MI, *NewMI);
+
+    if (DefinedEFLAGS)
+      LIS->removePhysRegDefAt(X86::EFLAGS, Idx.getRegSlot());
     if (SrcReg)
       LIS->getInterval(SrcReg);
     if (SrcReg2)
diff --git a/llvm/test/CodeGen/X86/twoaddr-lea-eflags-liveintervals.ll b/llvm/test/CodeGen/X86/twoaddr-lea-eflags-liveintervals.ll
new file mode 100644
index 0000000000000..0f7860fe2ddf1
--- /dev/null
+++ b/llvm/test/CodeGen/X86/twoaddr-lea-eflags-liveintervals.ll
@@ -0,0 +1,51 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=i686-- -verify-machineinstrs -precompute-phys-liveness \
+; RUN:     -early-live-intervals < %s | FileCheck --check-prefix=X86 %s
+; RUN: llc -mtriple=x86_64-- -verify-machineinstrs -precompute-phys-liveness \
+; RUN:     -early-live-intervals < %s | FileCheck --check-prefix=X64 %s
+
+; Converting an EFLAGS-clobbering ADD into an LEA must drop the dead EFLAGS
+; reg-unit value in LiveIntervals; the verifier rejects it otherwise.
+
+define void @eflags_lea(i32 %arg) {
+; X86-LABEL: eflags_lea:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    leal -5(%eax), %ecx
+; X86-NEXT:    cmpl $2, %ecx
+; X86-NEXT:    jb .LBB0_3
+; X86-NEXT:  # %bb.1: # %entry
+; X86-NEXT:    cmpl $4, %eax
+; X86-NEXT:    je .LBB0_2
+; X86-NEXT:  .LBB0_3: # %default
+; X86-NEXT:    retl
+; X86-NEXT:  .LBB0_2: # %unreach
+;
+; X64-LABEL: eflags_lea:
+; X64:       # %bb.0: # %entry
+; X64-NEXT:    # kill: def $edi killed $edi def $rdi
+; X64-NEXT:    leal -5(%rdi), %eax
+; X64-NEXT:    cmpl $2, %eax
+; X64-NEXT:    jb .LBB0_3
+; X64-NEXT:  # %bb.1: # %entry
+; X64-NEXT:    cmpl $4, %edi
+; X64-NEXT:    je .LBB0_2
+; X64-NEXT:  .LBB0_3: # %default
+; X64-NEXT:    retq
+; X64-NEXT:  .LBB0_2: # %unreach
+entry:
+  switch i32 %arg, label %default [
+    i32 4, label %unreach
+    i32 6, label %exit
+    i32 5, label %exit
+  ]
+
+unreach:
+  unreachable
+
+exit:
+  ret void
+
+default:
+  ret void
+}

>From b5cdef27f10b6d2a80000e2888b6941c055ab577 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 9 Sep 2026 08:34:20 +0200
Subject: [PATCH 2/2] review feedback

---
 llvm/lib/Target/X86/X86InstrInfo.cpp                  | 11 ++---------
 .../CodeGen/X86/twoaddr-lea-eflags-liveintervals.ll   |  3 +++
 2 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp
index 6471be97b62e9..ca864d02b3399 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.cpp
+++ b/llvm/lib/Target/X86/X86InstrInfo.cpp
@@ -1360,14 +1360,11 @@ MachineInstr *X86InstrInfo::convertToThreeAddressWithLEA(unsigned MIOpc,
     SlotIndex Ins2Idx;
     if (InsMI2)
       Ins2Idx = LIS->InsertMachineInstrInMaps(*InsMI2);
-    bool DefinedEFLAGS = MI.definesRegister(X86::EFLAGS, /*TRI=*/nullptr) &&
-                         !NewMI->definesRegister(X86::EFLAGS, /*TRI=*/nullptr);
     SlotIndex NewIdx = LIS->ReplaceMachineInstrInMaps(MI, *NewMI);
     SlotIndex ExtIdx = LIS->InsertMachineInstrInMaps(*ExtMI);
 
     // Drop the dead EFLAGS def MI had; the replacement does not define EFLAGS.
-    if (DefinedEFLAGS)
-      LIS->removePhysRegDefAt(X86::EFLAGS, NewIdx.getRegSlot());
+    LIS->removePhysRegDefAt(X86::EFLAGS, NewIdx.getRegSlot());
 
     LIS->getInterval(InRegLEA);
     LIS->getInterval(OutRegLEA);
@@ -2051,13 +2048,9 @@ MachineInstr *X86InstrInfo::convertToThreeAddress(MachineInstr &MI,
   if (LIS) {
     // The replacement does not define EFLAGS; drop the dead EFLAGS def MI had.
     SlotIndex Idx = LIS->getInstructionIndex(MI);
-    bool DefinedEFLAGS = MI.definesRegister(X86::EFLAGS, /*TRI=*/nullptr) &&
-                         !NewMI->definesRegister(X86::EFLAGS, /*TRI=*/nullptr);
-
     LIS->ReplaceMachineInstrInMaps(MI, *NewMI);
 
-    if (DefinedEFLAGS)
-      LIS->removePhysRegDefAt(X86::EFLAGS, Idx.getRegSlot());
+    LIS->removePhysRegDefAt(X86::EFLAGS, Idx.getRegSlot());
     if (SrcReg)
       LIS->getInterval(SrcReg);
     if (SrcReg2)
diff --git a/llvm/test/CodeGen/X86/twoaddr-lea-eflags-liveintervals.ll b/llvm/test/CodeGen/X86/twoaddr-lea-eflags-liveintervals.ll
index 0f7860fe2ddf1..296110099cb8e 100644
--- a/llvm/test/CodeGen/X86/twoaddr-lea-eflags-liveintervals.ll
+++ b/llvm/test/CodeGen/X86/twoaddr-lea-eflags-liveintervals.ll
@@ -1,3 +1,6 @@
+; REQUIRES: asserts
+; -precompute-phys-liveness is only available in asserts builds
+
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc -mtriple=i686-- -verify-machineinstrs -precompute-phys-liveness \
 ; RUN:     -early-live-intervals < %s | FileCheck --check-prefix=X86 %s



More information about the llvm-commits mailing list