[llvm] [SLP]Fix dominance failure when value is copyable in one PHI entry but non-copyable in another (PR #191724)
Alexey Bataev via llvm-commits
llvm-commits at lists.llvm.org
Sun Apr 12 09:00:14 PDT 2026
https://github.com/alexey-bataev created https://github.com/llvm/llvm-project/pull/191724
When a value is treated as a copyable element in one tree entry and as a
non-copyable element in another, both feeding into PHI nodes, the
scheduler could produce vectorized IR where an instruction does not
dominate all its uses. Bail out of scheduling in tryScheduleBundle when
this conflict is detected to prevent generating broken modules.
Fixes #191714
>From 84ed043d0b42d212b5e0bcc36b81e68d9025504b Mon Sep 17 00:00:00 2001
From: Alexey Bataev <a.bataev at outlook.com>
Date: Sun, 12 Apr 2026 09:00:00 -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
---
.../Transforms/Vectorize/SLPVectorizer.cpp | 12 +++++
.../X86/copyable-phi-used-non-copyable.ll | 53 +++++++++++++++++++
2 files changed, 65 insertions(+)
create mode 100644 llvm/test/Transforms/SLPVectorizer/X86/copyable-phi-used-non-copyable.ll
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index d32c925794f1c..201d8337dd83f 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -23679,6 +23679,18 @@ BoUpSLP::BlockScheduling::tryScheduleBundle(ArrayRef<Value *> VL, BoUpSLP *SLP,
auto *I = dyn_cast<Instruction>(V);
if (!I || (HasCopyables && S.isCopyableElement(V)))
continue;
+ 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-used-non-copyable.ll b/llvm/test/Transforms/SLPVectorizer/X86/copyable-phi-used-non-copyable.ll
new file mode 100644
index 0000000000000..4880a02543a21
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/copyable-phi-used-non-copyable.ll
@@ -0,0 +1,53 @@
+; 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: [[TMP0:%.*]] = insertelement <2 x i32> <i32 0, i32 poison>, i32 [[ARG]], i32 1
+; CHECK-NEXT: br label %[[BB4:.*]]
+; CHECK: [[BB1:.*]]:
+; CHECK-NEXT: [[SUB2:%.*]] = sub i32 0, 0
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[SUB2]], 0
+; CHECK-NEXT: [[TMP1:%.*]] = sub <2 x i32> <i32 1, i32 0>, [[TMP0]]
+; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <4 x i32> <i32 0, i32 poison, i32 0, i32 0>, <4 x i32> [[TMP2]], <4 x i32> <i32 0, i32 5, i32 2, i32 3>
+; CHECK-NEXT: [[TMP4:%.*]] = add <4 x i32> zeroinitializer, [[TMP3]]
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <4 x i32> [[TMP2]], <4 x i32> [[TMP4]], <4 x i32> <i32 0, i32 1, i32 6, i32 poison>
+; CHECK-NEXT: [[TMP6:%.*]] = insertelement <4 x i32> [[TMP5]], i32 [[OR]], i32 3
+; CHECK-NEXT: br i1 false, label %[[BB8:.*]], label %[[BB4]]
+; CHECK: [[BB4]]:
+; CHECK-NEXT: [[TMP7:%.*]] = phi <4 x i32> [ zeroinitializer, %[[BB]] ], [ [[TMP4]], %[[BB1]] ]
+; CHECK-NEXT: [[TMP8:%.*]] = or <4 x i32> [[TMP7]], zeroinitializer
+; CHECK-NEXT: br i1 false, label %[[BB8]], label %[[BB1]]
+; CHECK: [[BB8]]:
+; CHECK-NEXT: [[TMP9:%.*]] = phi <4 x i32> [ [[TMP8]], %[[BB4]] ], [ [[TMP6]], %[[BB1]] ]
+; CHECK-NEXT: ret void
+;
+bb:
+ br label %bb4
+
+bb1:
+ %sub = sub i32 0, %arg
+ %sub2 = sub i32 0, 0
+ %or = or i32 %sub2, 0
+ %or3 = or i32 1, 0
+ %add = add i32 0, 0
+ br i1 false, label %bb8, label %bb4
+
+bb4:
+ %phi = phi i32 [ 0, %bb ], [ %add, %bb1 ]
+ %phi5 = phi i32 [ 0, %bb ], [ %sub, %bb1 ]
+ %phi6 = phi i32 [ 0, %bb ], [ 0, %bb1 ]
+ %or7 = or i32 %phi6, 0
+ br i1 false, label %bb8, label %bb1
+
+bb8:
+ %phi9 = phi i32 [ %phi5, %bb4 ], [ %sub, %bb1 ]
+ %phi10 = phi i32 [ %phi, %bb4 ], [ %or, %bb1 ]
+ %phi11 = phi i32 [ %or7, %bb4 ], [ %or3, %bb1 ]
+ %phi12 = phi i32 [ %phi, %bb4 ], [ %add, %bb1 ]
+ ret void
+}
+
More information about the llvm-commits
mailing list