[llvm] [SLP] Fix dep accounting when cancelling a bundle with copyable elements (PR #223174)
Alexey Bataev via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 12 13:56:27 PDT 2026
https://github.com/alexey-bataev created https://github.com/llvm/llvm-project/pull/223174
Restore the parent-edge copyable data as a user of the instruction only
if the cancelled element displaced it at creation (chained copyable
self-use); otherwise the extra user dependency is never released and
scheduling asserts.
Fixes #223139
>From 263b34475474081e53e7170a66268d30f7546a92 Mon Sep 17 00:00:00 2001
From: Alexey Bataev <a.bataev at outlook.com>
Date: Sat, 12 Sep 2026 13:56:16 -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 | 14 ++++-
.../X86/cancelled-copyable-self-use-deps.ll | 58 +++++++++++++++++++
2 files changed, 69 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/Transforms/SLPVectorizer/X86/cancelled-copyable-self-use-deps.ll
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 488bfb36b6ccc..df9ced3e42d27 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -26173,6 +26173,7 @@ BoUpSLP::BlockScheduling::tryScheduleBundle(ArrayRef<Value *> VL, BoUpSLP *SLP,
const auto *It = find(Op, I);
assert(It != Op.end() && "Lane not set");
SmallPtrSet<Instruction *, 4> Visited;
+ bool HadSelfUse = false;
do {
int Lane = std::distance(Op.begin(), It);
assert(Lane >= 0 && "Lane not set");
@@ -26186,14 +26187,21 @@ BoUpSLP::BlockScheduling::tryScheduleBundle(ArrayRef<Value *> VL, BoUpSLP *SLP,
It = find(make_range(std::next(It), Op.end()), I);
break;
}
+ HadSelfUse |= In == I;
ScheduleCopyableDataMapByInstUser
[std::make_pair(std::make_pair(In, EI.EdgeIdx), I)]
.pop_back();
It = find(make_range(std::next(It), Op.end()), I);
} while (It != Op.end());
- EdgeInfo UserEI = EI.UserTE->UserTreeIndex;
- if (ScheduleCopyableData *UserCD = getScheduleCopyableData(UserEI, I))
- ScheduleCopyableDataMapByUsers[I].insert(UserCD);
+ // Restore the parent-edge copyable data as a user of I only if the
+ // cancelled data displaced it at creation (chained copyable
+ // self-use); otherwise the extra user dependency is never released.
+ if (HadSelfUse) {
+ EdgeInfo UserEI = EI.UserTE->UserTreeIndex;
+ if (ScheduleCopyableData *UserCD =
+ getScheduleCopyableData(UserEI, I))
+ ScheduleCopyableDataMapByUsers[I].insert(UserCD);
+ }
}
if (ScheduleCopyableDataMapByUsers[I].empty())
ScheduleCopyableDataMapByUsers.erase(I);
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/cancelled-copyable-self-use-deps.ll b/llvm/test/Transforms/SLPVectorizer/X86/cancelled-copyable-self-use-deps.ll
new file mode 100644
index 0000000000000..cbd7cf8dc1779
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/cancelled-copyable-self-use-deps.ll
@@ -0,0 +1,58 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -passes=slp-vectorizer -S < %s -mtriple=x86_64 | FileCheck %s
+
+; The gather node with copyable elements fails to schedule and its bundle is
+; cancelled. The cancellation must not restore the parent-edge copyable data
+; as a user of %conv: it was displaced by another live copyable element, and
+; restoring it charges %conv's schedule data a dependency that is never
+; released, leaving the real bundle [%conv, %add4] unscheduled.
+
+define i16 @test(i64 %d, ptr %a, i32 %conv3, ptr %h) {
+; CHECK-LABEL: define i16 @test(
+; CHECK-SAME: i64 [[D:%.*]], ptr [[A:%.*]], i32 [[CONV3:%.*]], ptr [[H:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = trunc i64 [[D]] to i32
+; CHECK-NEXT: [[CONV:%.*]] = and i32 [[TMP0]], 1
+; CHECK-NEXT: [[REASS_ADD:%.*]] = shl i32 [[CONV]], 1
+; CHECK-NEXT: [[ADD23:%.*]] = add i32 [[REASS_ADD]], 70
+; CHECK-NEXT: [[XOR4:%.*]] = xor i32 [[ADD23]], 5
+; CHECK-NEXT: [[ADD7:%.*]] = add i32 [[CONV]], [[XOR4]]
+; CHECK-NEXT: [[ADD8:%.*]] = add i32 [[ADD7]], [[CONV3]]
+; CHECK-NEXT: [[TMP12:%.*]] = trunc i32 [[ADD8]] to i16
+; CHECK-NEXT: store i16 [[TMP12]], ptr [[H]], align 2
+; CHECK-NEXT: [[ADD4:%.*]] = shl i32 [[CONV3]], 1
+; CHECK-NEXT: [[ADD13:%.*]] = or i32 [[ADD4]], 1
+; CHECK-NEXT: [[SUB:%.*]] = add i32 [[ADD13]], [[CONV]]
+; CHECK-NEXT: [[ADD14:%.*]] = add i32 [[SUB]], [[CONV3]]
+; CHECK-NEXT: [[TMP13:%.*]] = trunc i32 [[ADD14]] to i16
+; CHECK-NEXT: store i16 [[TMP13]], ptr [[A]], align 2
+; CHECK-NEXT: [[TMP14:%.*]] = trunc i32 [[CONV]] to i16
+; CHECK-NEXT: store i16 [[TMP14]], ptr [[H]], align 2
+; CHECK-NEXT: [[ADD27:%.*]] = add i32 [[ADD13]], [[REASS_ADD]]
+; CHECK-NEXT: [[ADD28:%.*]] = add i32 [[ADD27]], [[CONV3]]
+; CHECK-NEXT: [[TMP15:%.*]] = trunc i32 [[ADD28]] to i16
+; CHECK-NEXT: ret i16 [[TMP15]]
+;
+entry:
+ %0 = trunc i64 %d to i32
+ %conv = and i32 %0, 1
+ %reass.add = shl i32 %conv, 1
+ %add23 = add i32 %reass.add, 70
+ %xor4 = xor i32 %add23, 5
+ %add7 = add i32 %conv, %xor4
+ %add8 = add i32 %add7, %conv3
+ %conv9 = trunc i32 %add8 to i16
+ store i16 %conv9, ptr %h, align 2
+ %add4 = shl i32 %conv3, 1
+ %add13 = or i32 %add4, 1
+ %sub = add i32 %add13, %conv
+ %add14 = add i32 %sub, %conv3
+ %1 = trunc i32 %add14 to i16
+ store i16 %1, ptr %a, align 2
+ %2 = trunc i32 %conv to i16
+ store i16 %2, ptr %h, align 2
+ %add27 = add i32 %add13, %reass.add
+ %add28 = add i32 %add27, %conv3
+ %3 = trunc i32 %add28 to i16
+ ret i16 %3
+}
More information about the llvm-commits
mailing list