[llvm] [TwoAddressInstruction] Drop physreg ranges after unfolding a load (PR #227538)

Vitaly Buka via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 29 19:48:22 PDT 2026


https://github.com/vitalybuka created https://github.com/llvm/llvm-project/pull/227538

Since #225174 LiveIntervals is computed before TwoAddressInstructions.
When tryInstructionTransform() unfolds a load, e.g. OR64rm into
MOV64rm + OR64rr, it calls repairIntervalsInRange(). That function
only repairs virtual registers. If the regunit range of a physreg def
of the original instruction ($eflags here) was already cached, it
keeps a value defined at the slot of the erased instruction.

The machine verifier then reports "No instruction at VNInfo def index"
and later passes hit `LR.verify()` in LiveIntervals::HMEditor. This
broke the MSan bootstrap build of clang/lib/Sema/SemaAPINotes.cpp.

Drop the cached regunit ranges for the physregs of the unfolded
instruction so they are recomputed on demand. MachineBasicBlock.cpp
already does the same after repairIntervalsInRange().

Assisted-by: Gemini


>From 77a181735485f1387a349f6212d1934f4299cbaa Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Tue, 29 Sep 2026 19:47:55 -0700
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
 =?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.7
---
 .../lib/CodeGen/TwoAddressInstructionPass.cpp |  8 +++
 ...oaddr-unfold-load-eflags-liveintervals.mir | 55 +++++++++++++++++++
 2 files changed, 63 insertions(+)
 create mode 100644 llvm/test/CodeGen/X86/twoaddr-unfold-load-eflags-liveintervals.mir

diff --git a/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp b/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp
index b84391817893d..9adc5a27e223b 100644
--- a/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp
+++ b/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp
@@ -1530,6 +1530,14 @@ bool TwoAddressInstructionImpl::tryInstructionTransform(
             MachineBasicBlock::iterator Begin(NewMIs[0]);
             MachineBasicBlock::iterator End(NewMIs[1]);
             LIS->repairIntervalsInRange(MBB, Begin, End, OrigRegs);
+
+            // repairIntervalsInRange() does not update physregs; clear their
+            // ranges since the original instruction's defs (e.g. of EFLAGS)
+            // were replaced.
+            for (Register Reg : OrigRegs) {
+              if (Reg.isPhysical())
+                LIS->removeAllRegUnitsForPhysReg(Reg.asMCReg());
+            }
           }
 
           mi = NewMIs[1];
diff --git a/llvm/test/CodeGen/X86/twoaddr-unfold-load-eflags-liveintervals.mir b/llvm/test/CodeGen/X86/twoaddr-unfold-load-eflags-liveintervals.mir
new file mode 100644
index 0000000000000..48c2aac654ed6
--- /dev/null
+++ b/llvm/test/CodeGen/X86/twoaddr-unfold-load-eflags-liveintervals.mir
@@ -0,0 +1,55 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=x86_64-- -run-pass=liveintervals,twoaddressinstruction -verify-machineinstrs -o - %s | FileCheck %s
+
+# Unfolding the load out of OR64rm replaces the instruction defining $eflags.
+# The cached $eflags regunit live range must not keep pointing at the erased
+# instruction.
+
+---
+name:            unfold_load_eflags
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: unfold_load_eflags
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.2(0x40000000)
+  ; CHECK-NEXT:   liveins: $eflags, $rdi, $rsi
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gr64 = COPY $rdi
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gr64 = COPY $rsi
+  ; CHECK-NEXT:   [[MOV64rm:%[0-9]+]]:gr64 = MOV64rm [[COPY]], 1, $noreg, 0, $noreg :: (load (s64))
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gr64 = COPY [[MOV64rm]]
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:gr64 = OR64rr [[COPY2]], [[COPY1]], implicit-def $eflags
+  ; CHECK-NEXT:   JCC_1 %bb.2, 4, implicit $eflags
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   liveins: $eflags
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[SETCCr:%[0-9]+]]:gr8 = SETCCr 5, implicit $eflags
+  ; CHECK-NEXT:   $al = COPY [[SETCCr]]
+  ; CHECK-NEXT:   $rdx = COPY [[COPY1]]
+  ; CHECK-NEXT:   RET 0, implicit $al, implicit $rdx
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   $rax = COPY [[COPY2]]
+  ; CHECK-NEXT:   RET 0, implicit $rax
+  bb.0:
+    successors: %bb.1, %bb.2
+    liveins: $eflags, $rdi, $rsi
+
+    %0:gr64 = COPY $rdi
+    %1:gr64 = COPY $rsi
+    %2:gr64 = OR64rm %1, %0, 1, $noreg, 0, $noreg, implicit-def $eflags :: (load (s64))
+    JCC_1 %bb.2, 4, implicit $eflags
+
+  bb.1:
+    liveins: $eflags
+
+    %3:gr8 = SETCCr 5, implicit killed $eflags
+    $al = COPY %3
+    $rdx = COPY %1
+    RET 0, implicit $al, implicit $rdx
+
+  bb.2:
+    $rax = COPY %2
+    RET 0, implicit $rax
+...



More information about the llvm-commits mailing list