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

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


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: Vitaly Buka (vitalybuka)

<details>
<summary>Changes</summary>

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


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


2 Files Affected:

- (modified) llvm/lib/CodeGen/TwoAddressInstructionPass.cpp (+8) 
- (added) llvm/test/CodeGen/X86/twoaddr-unfold-load-eflags-liveintervals.mir (+55) 


``````````diff
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
+...

``````````

</details>


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


More information about the llvm-commits mailing list