[llvm] [SLP]Fix dominance crash for scheduled copyable PHI-operand bundles (PR #205372)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 23 09:19:24 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-vectorizers

Author: Alexey Bataev (alexey-bataev)

<details>
<summary>Changes</summary>

Extend the copyable/non-copyable PHI conflict bail-out in
tryScheduleBundle to the scheduled path, not just the non-schedulable
one.

Fixes #<!-- -->205327


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


2 Files Affected:

- (modified) llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp (+21-12) 
- (added) llvm/test/Transforms/SLPVectorizer/X86/copyable-phi-scheduled-non-copyable.ll (+47) 


``````````diff
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 52566c094f6a6..1d7e8e5ddf50f 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -25549,6 +25549,27 @@ BoUpSLP::BlockScheduling::tryScheduleBundle(ArrayRef<Value *> VL, BoUpSLP *SLP,
         return std::nullopt;
     }
   }
+  // A scalar that is a non-copyable (i.e. really vectorized) element in this
+  // PHI-operand node, but a copyable element in another PHI-operand node, is
+  // vectorized here and only gathered/reused there. Both nodes feed different
+  // incoming values of the same vectorized PHI and may be emitted in different
+  // predecessor blocks, so the gathered reuse can end up not dominated by the
+  // vectorized value, producing broken IR. Bail out of scheduling to avoid it.
+  if (EI && EI.UserTE->State == TreeEntry::Vectorize &&
+      EI.UserTE->getOpcode() == Instruction::PHI && any_of(VL, [&](Value *V) {
+        auto *I = dyn_cast<Instruction>(V);
+        if (!I || (HasCopyables && S.isCopyableElement(V)))
+          return false;
+        return any_of(
+            SLP->VectorizableTree, [&](const std::unique_ptr<TreeEntry> &TE) {
+              return TE->UserTreeIndex &&
+                     TE->UserTreeIndex.UserTE->State == TreeEntry::Vectorize &&
+                     TE->UserTreeIndex.UserTE->getOpcode() ==
+                         Instruction::PHI &&
+                     TE->hasCopyableElements() && TE->isCopyableElement(V);
+            });
+      }))
+    return std::nullopt;
   if (DoesNotRequireScheduling) {
     // If all operands were replaced by copyables, the operands of this node
     // might be not, so need to recalculate dependencies for schedule data,
@@ -25579,18 +25600,6 @@ BoUpSLP::BlockScheduling::tryScheduleBundle(ArrayRef<Value *> VL, BoUpSLP *SLP,
             return SD && SD->hasValidDependencies();
           }))
         return std::nullopt;
-      if (EI && EI.UserTE->State == TreeEntry::Vectorize &&
-          EI.UserTE->getOpcode() == Instruction::PHI &&
-          any_of(SLP->VectorizableTree,
-                 [&](const std::unique_ptr<TreeEntry> &TE) {
-                   return TE->UserTreeIndex &&
-                          TE->UserTreeIndex.UserTE->State ==
-                              TreeEntry::Vectorize &&
-                          TE->UserTreeIndex.UserTE->getOpcode() ==
-                              Instruction::PHI &&
-                          TE->hasCopyableElements() && TE->isCopyableElement(V);
-                 }))
-        return std::nullopt;
       SmallDenseMap<std::pair<Instruction *, Value *>, unsigned> UserOpToNumOps;
       for (const Use &U : I->operands()) {
         unsigned &NumOps =
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/copyable-phi-scheduled-non-copyable.ll b/llvm/test/Transforms/SLPVectorizer/X86/copyable-phi-scheduled-non-copyable.ll
new file mode 100644
index 0000000000000..762366cb3b623
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/copyable-phi-scheduled-non-copyable.ll
@@ -0,0 +1,47 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S --passes=slp-vectorizer -mtriple=x86_64-unknown-linux-gnu -slp-threshold=-99999 < %s | FileCheck %s
+
+define void @test(i32 %arg) {
+; CHECK-LABEL: define void @test(
+; CHECK-SAME: i32 [[ARG:%.*]]) {
+; CHECK-NEXT:  [[BB:.*:]]
+; CHECK-NEXT:    br label %[[BB1:.*]]
+; CHECK:       [[BB1]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <2 x i32> <i32 poison, i32 0>, i32 [[ARG]], i32 0
+; CHECK-NEXT:    [[TMP1:%.*]] = shufflevector <2 x i32> [[TMP0]], <2 x i32> <i32 0, i32 poison>, <2 x i32> <i32 2, i32 0>
+; CHECK-NEXT:    [[TMP2:%.*]] = sub <2 x i32> [[TMP0]], [[TMP1]]
+; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <2 x i32> [[TMP2]], <2 x i32> poison, <4 x i32> <i32 0, i32 poison, i32 1, i32 poison>
+; CHECK-NEXT:    [[TMP4:%.*]] = shufflevector <4 x i32> <i32 poison, i32 1, i32 poison, i32 0>, <4 x i32> [[TMP3]], <4 x i32> <i32 4, i32 1, i32 6, i32 3>
+; CHECK-NEXT:    [[TMP5:%.*]] = add <4 x i32> zeroinitializer, [[TMP4]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp sgt i32 0, 0
+; CHECK-NEXT:    [[TMP6:%.*]] = shufflevector <4 x i32> [[TMP5]], <4 x i32> <i32 poison, i32 poison, i32 poison, i32 1>, <4 x i32> <i32 0, i32 1, i32 2, i32 7>
+; CHECK-NEXT:    [[TMP7:%.*]] = insertelement <4 x i32> [[TMP6]], i32 0, i32 1
+; CHECK-NEXT:    br i1 false, label %[[BB5:.*]], label %[[BB4:.*]]
+; CHECK:       [[BB4]]:
+; CHECK-NEXT:    br label %[[BB5]]
+; CHECK:       [[BB5]]:
+; CHECK-NEXT:    [[TMP8:%.*]] = phi <4 x i32> [ [[TMP5]], %[[BB4]] ], [ [[TMP7]], %[[BB1]] ]
+; CHECK-NEXT:    ret void
+;
+bb:
+  br label %bb1
+
+bb1:
+  %sub = sub i32 0, %arg
+  %or = or i32 %arg, 0
+  %add = add i32 %or, 0
+  %add2 = add i32 0, 0
+  %icmp = icmp sgt i32 %add2, 0
+  %add3 = add i32 0, 1
+  br i1 false, label %bb5, label %bb4
+
+bb4:
+  br label %bb5
+
+bb5:
+  %phi = phi i32 [ 0, %bb4 ], [ 1, %bb1 ]
+  %phi6 = phi i32 [ %sub, %bb4 ], [ %sub, %bb1 ]
+  %phi7 = phi i32 [ %add, %bb4 ], [ %add, %bb1 ]
+  %phi8 = phi i32 [ %add3, %bb4 ], [ %add2, %bb1 ]
+  ret void
+}

``````````

</details>


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


More information about the llvm-commits mailing list