[llvm] 18ef19f - [TwoAddressInstruction] Drop physreg ranges after unfolding a load (#227538)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 30 00:10:17 PDT 2026


Author: Vitaly Buka
Date: 2026-09-30T00:10:10-07:00
New Revision: 18ef19fb83d9d3fa369481bb0537be4fdf5552fb

URL: https://github.com/llvm/llvm-project/commit/18ef19fb83d9d3fa369481bb0537be4fdf5552fb
DIFF: https://github.com/llvm/llvm-project/commit/18ef19fb83d9d3fa369481bb0537be4fdf5552fb.diff

LOG: [TwoAddressInstruction] Drop physreg ranges after unfolding a load (#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

Added: 
    llvm/test/CodeGen/X86/twoaddr-unfold-load-eflags-liveintervals.mir

Modified: 
    llvm/lib/CodeGen/TwoAddressInstructionPass.cpp

Removed: 
    


################################################################################
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