[llvm] adfe869 - [RegisterCoalescer] Fix crash coalescing COPY from erasable IMPLICIT_DEF (#196895)

via llvm-commits llvm-commits at lists.llvm.org
Wed May 13 03:01:46 PDT 2026


Author: 陈子昂
Date: 2026-05-13T18:01:40+08:00
New Revision: adfe8697bad31b1f4752b1f703daa78b7f2773fd

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

LOG: [RegisterCoalescer] Fix crash coalescing COPY from erasable IMPLICIT_DEF (#196895)

When a CR_Erase value's source is an erasable IMPLICIT_DEF, discard the
endpoint from pruneValue instead of adding it to EndPoints, and mark any
full-register DstReg uses with no live coverage as undef in
updateRegDefsUses.

Fixes: https://github.com/llvm/llvm-project/issues/195587.

Added: 
    llvm/test/CodeGen/X86/coalescer-copy-from-erasable-implicit-def.ll
    llvm/test/CodeGen/X86/coalescer-copy-from-erasable-implicit-def.mir

Modified: 
    llvm/lib/CodeGen/RegisterCoalescer.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/CodeGen/RegisterCoalescer.cpp b/llvm/lib/CodeGen/RegisterCoalescer.cpp
index a8405f8a729c8..eb43eddfa081e 100644
--- a/llvm/lib/CodeGen/RegisterCoalescer.cpp
+++ b/llvm/lib/CodeGen/RegisterCoalescer.cpp
@@ -1884,19 +1884,27 @@ void RegisterCoalescer::updateRegDefsUses(Register SrcReg, Register DstReg,
   bool DstIsPhys = DstReg.isPhysical();
   LiveInterval *DstInt = DstIsPhys ? nullptr : &LIS->getInterval(DstReg);
 
-  if (DstInt && DstInt->hasSubRanges() && DstReg != SrcReg) {
-    for (MachineOperand &MO : MRI->reg_operands(DstReg)) {
+  if (DstInt && DstReg != SrcReg) {
+    bool HasSubRanges = DstInt->hasSubRanges();
+    for (MachineOperand &MO : MRI->reg_nodbg_operands(DstReg)) {
       if (MO.isUndef())
         continue;
       unsigned SubReg = MO.getSubReg();
       if (SubReg == 0 && MO.isDef())
         continue;
 
-      MachineInstr &MI = *MO.getParent();
-      if (MI.isDebugInstr())
-        continue;
-      SlotIndex UseIdx = LIS->getInstructionIndex(MI).getRegSlot(true);
-      addUndefFlag(*DstInt, UseIdx, MO, SubReg);
+      SlotIndex UseIdx =
+          LIS->getInstructionIndex(*MO.getParent()).getRegSlot(true);
+      if (HasSubRanges) {
+        addUndefFlag(*DstInt, UseIdx, MO, SubReg);
+      } else if (MO.isUse() && SubReg == 0 && !DstInt->liveAt(UseIdx)) {
+        // A full-register use already referencing DstReg (not renamed from
+        // SrcReg) may have no reaching def after the join if its feeding COPY
+        // and erasable IMPLICIT_DEF were removed. Mark such uses undef; the
+        // SrcReg rename loop below only visits SrcReg operands and will miss
+        // these.
+        MO.setIsUndef(true);
+      }
     }
   }
 
@@ -3328,7 +3336,12 @@ void JoinVals::pruneValues(JoinVals &Other,
         // We can no longer trust the value mapping computed by
         // computeAssignment(), the value that was originally copied could have
         // been replaced.
-        LIS->pruneValue(LR, Def, &EndPoints);
+        Val &OtherV = Other.Vals[Vals[i].OtherVNI->id];
+        bool EraseImpDef =
+            OtherV.ErasableImplicitDef && OtherV.Resolution == CR_Keep;
+        // If the source is an erasable IMPLICIT_DEF, the pruned endpoint is
+        // the next def boundary, not a real use — discard it.
+        LIS->pruneValue(LR, Def, EraseImpDef ? nullptr : &EndPoints);
         LLVM_DEBUG(dbgs() << "\t\tpruned all of " << printReg(Reg) << " at "
                           << Def << ": " << LR << '\n');
       }

diff  --git a/llvm/test/CodeGen/X86/coalescer-copy-from-erasable-implicit-def.ll b/llvm/test/CodeGen/X86/coalescer-copy-from-erasable-implicit-def.ll
new file mode 100644
index 0000000000000..9100bc2bcf980
--- /dev/null
+++ b/llvm/test/CodeGen/X86/coalescer-copy-from-erasable-implicit-def.ll
@@ -0,0 +1,85 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=x86_64-unknown-linux -o - %s | FileCheck %s
+
+; Regression test for https://github.com/llvm/llvm-project/issues/195587.
+; Register coalescer crashed coalescing a COPY from an erasable IMPLICIT_DEF
+; when a tied-def redef immediately followed. Reduced from C reproducer via
+; llvm-reduce.
+
+define <16 x i32> @f1() {
+; CHECK-LABEL: f1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    xorl %eax, %eax
+; CHECK-NEXT:    testb %al, %al
+; CHECK-NEXT:    jne .LBB0_1
+; CHECK-NEXT:  # %bb.2:
+; CHECK-NEXT:    xorl %eax, %eax
+; CHECK-NEXT:    testb %al, %al
+; CHECK-NEXT:    movl $0, 0
+; CHECK-NEXT:    xorps %xmm0, %xmm0
+; CHECK-NEXT:    .p2align 4
+; CHECK-NEXT:  .LBB0_3: # =>This Inner Loop Header: Depth=1
+; CHECK-NEXT:    # implicit-def: $xmm1
+; CHECK-NEXT:    # implicit-def: $xmm1
+; CHECK-NEXT:    # implicit-def: $xmm1
+; CHECK-NEXT:    xorps %xmm1, %xmm1
+; CHECK-NEXT:    movss {{.*#+}} xmm0 = xmm1[0],xmm0[1,2,3]
+; CHECK-NEXT:    movb $1, %al
+; CHECK-NEXT:    testb %al, %al
+; CHECK-NEXT:    jne .LBB0_3
+; CHECK-NEXT:  # %bb.4:
+; CHECK-NEXT:    je .LBB0_5
+; CHECK-NEXT:  # %bb.6:
+; CHECK-NEXT:    xorps %xmm0, %xmm0
+; CHECK-NEXT:    xorps %xmm1, %xmm1
+; CHECK-NEXT:    xorps %xmm2, %xmm2
+; CHECK-NEXT:    xorps %xmm3, %xmm3
+; CHECK-NEXT:    retq
+; CHECK-NEXT:  .LBB0_1:
+; CHECK-NEXT:    xorps %xmm0, %xmm0
+; CHECK-NEXT:  .LBB0_5:
+; CHECK-NEXT:    movaps {{.*#+}} xmm1 = [1,1,1,1]
+; CHECK-NEXT:    movaps %xmm0, %xmm2
+; CHECK-NEXT:    shufps {{.*#+}} xmm2 = xmm2[2,0],xmm1[3,0]
+; CHECK-NEXT:    shufps {{.*#+}} xmm0 = xmm0[0,1],xmm2[0,2]
+; CHECK-NEXT:    shufps {{.*#+}} xmm1 = xmm1[0,0,1,0]
+; CHECK-NEXT:    shufps {{.*#+}} xmm1 = xmm1[0,2,2,3]
+; CHECK-NEXT:    # implicit-def: $xmm2
+; CHECK-NEXT:    # implicit-def: $xmm3
+; CHECK-NEXT:    retq
+  switch i8 0, label %2 [
+    i8 2, label %2
+    i8 8, label %7
+    i8 0, label %1
+  ]
+
+1:
+  store i32 0, ptr null, align 4
+  br label %4
+
+2:
+  store i32 0, ptr null, align 4
+  br label %4
+
+3:
+  ret <16 x i32> zeroinitializer
+
+4:
+  %5 = phi <16 x i32> [ <i32 0, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>, %1 ],
+                       [ <i32 0, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>, %2 ],
+                       [ %6, %4 ]
+  %6 = insertelement <16 x i32> %5, i32 0, i64 0
+  switch i8 0, label %3 [
+    i8 2, label %3
+    i8 8, label %7
+    i8 0, label %4
+  ]
+
+7:
+  %8 = phi <16 x i32> [ <i32 0, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>, %0 ],
+                       [ %6, %4 ]
+  %9 = shufflevector <16 x i32> %8, <16 x i32> splat (i32 1),
+                     <16 x i32> <i32 0, i32 1, i32 2, i32 19, i32 4, i32 21, i32 6, i32 7,
+                                  i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+  ret <16 x i32> %9
+}

diff  --git a/llvm/test/CodeGen/X86/coalescer-copy-from-erasable-implicit-def.mir b/llvm/test/CodeGen/X86/coalescer-copy-from-erasable-implicit-def.mir
new file mode 100644
index 0000000000000..30722da90c1e4
--- /dev/null
+++ b/llvm/test/CodeGen/X86/coalescer-copy-from-erasable-implicit-def.mir
@@ -0,0 +1,29 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=x86_64-unknown-linux-gnu -run-pass=register-coalescer -verify-coalescing -o - %s | FileCheck %s
+
+# Regression test for https://github.com/llvm/llvm-project/issues/195587.
+# Register coalescer crashed coalescing a COPY from an erasable IMPLICIT_DEF
+# when a tied-def redef immediately followed: the pruned segment endpoint was
+# incorrectly added to EndPoints, causing extendToIndices to walk the CFG for
+# a reaching def that does not exist.
+
+---
+name: coalesce_copy_from_erasable_implicit_def
+tracksRegLiveness: true
+constants:
+  - id:    0
+    value: 'i32 0'
+    alignment: 16
+body:             |
+  bb.0:
+    ; CHECK-LABEL: name: coalesce_copy_from_erasable_implicit_def
+    ; CHECK: [[SHUFPSrmi:%[0-9]+]]:vr128 = SHUFPSrmi undef [[SHUFPSrmi]], $rip, 1, $noreg, %const.0, $noreg, 16 :: (load (s128) from constant-pool)
+    ; CHECK-NEXT: [[SHUFPSrmi:%[0-9]+]]:vr128 = SHUFPSrri [[SHUFPSrmi]], [[SHUFPSrmi]], -24
+    ; CHECK-NEXT: RET 0, implicit [[SHUFPSrmi]]
+    %0:vr128 = IMPLICIT_DEF
+    %1:vr128 = COPY %0
+    %1:vr128 = SHUFPSrmi %1, $rip, 1, $noreg, %const.0, $noreg, 16 :: (load (s128) from constant-pool)
+    %2:vr128 = COPY killed %1
+    %2:vr128 = SHUFPSrri %2, killed %0, -24
+    RET 0, implicit killed %2
+...


        


More information about the llvm-commits mailing list