[llvm] [slp] fix scheduler deadlock for copyable users of vectorized instructions (PR #176661)

via llvm-commits llvm-commits at lists.llvm.org
Sun Jan 18 15:30:32 PST 2026


https://github.com/Serosh-commits updated https://github.com/llvm/llvm-project/pull/176661

>From d099f428252d1207884898af9c7d8986f74e7809 Mon Sep 17 00:00:00 2001
From: Serosh <janmejayapanda400 at gmail.com>
Date: Sun, 18 Jan 2026 23:22:08 +0530
Subject: [PATCH 1/2] [slp] fix scheduler deadlock by correctly tracking
 copyable dependencies

---
 .../Transforms/Vectorize/SLPVectorizer.cpp    | 23 +++++++++++--------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 4c4901c314406..06ed3502cfd89 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -22576,11 +22576,20 @@ void BoUpSLP::scheduleBlock(const BoUpSLP &R, BlockScheduling *BS) {
         if (!Bundle.hasValidDependencies())
           BS->calculateDependencies(Bundle, /*InsertInReadyList=*/false, this);
       }
-      continue;
     }
-    SmallVector<ScheduleCopyableData *> CopyableData =
+    SmallVector<ScheduleCopyableData *> SelfCopyableData =
+        BS->getScheduleCopyableData(I);
+    for (ScheduleCopyableData *SD : reverse(SelfCopyableData)) {
+      ScheduleBundle &Bundle = SD->getBundle();
+      Bundle.setSchedulingPriority(Idx++);
+      if (!Bundle.hasValidDependencies())
+        BS->calculateDependencies(Bundle, /*InsertInReadyList=*/false, this);
+    }
+    SmallVector<ScheduleCopyableData *> UserCopyableData =
         BS->getScheduleCopyableDataUsers(I);
-    if (ScheduleData *SD = BS->getScheduleData(I)) {
+    if (Bundles.empty() && SelfCopyableData.empty()) {
+      ScheduleData *SD = BS->getScheduleData(I);
+      assert(SD && "Expected schedule data");
       [[maybe_unused]] ArrayRef<TreeEntry *> SDTEs = getTreeEntries(I);
       assert((isVectorLikeInstWithConstOps(SD->getInst()) || SDTEs.empty() ||
               SDTEs.front()->doesNotNeedToSchedule() ||
@@ -22588,22 +22597,18 @@ void BoUpSLP::scheduleBlock(const BoUpSLP &R, BlockScheduling *BS) {
              "scheduler and vectorizer bundle mismatch");
       SD->setSchedulingPriority(Idx++);
       if (!SD->hasValidDependencies() &&
-          (!CopyableData.empty() ||
+          (!UserCopyableData.empty() ||
            any_of(R.ValueToGatherNodes.lookup(I), [&](const TreeEntry *TE) {
              assert(TE->isGather() && "expected gather node");
              return TE->hasState() && TE->hasCopyableElements() &&
                     TE->isCopyableElement(I);
            }))) {
-        // Need to calculate deps for these nodes to correctly handle copyable
-        // dependencies, even if they were cancelled.
-        // If copyables bundle was cancelled, the deps are cleared and need to
-        // recalculate them.
         ScheduleBundle Bundle;
         Bundle.add(SD);
         BS->calculateDependencies(Bundle, /*InsertInReadyList=*/false, this);
       }
     }
-    for (ScheduleCopyableData *SD : reverse(CopyableData)) {
+    for (ScheduleCopyableData *SD : reverse(UserCopyableData)) {
       ScheduleBundle &Bundle = SD->getBundle();
       Bundle.setSchedulingPriority(Idx++);
       if (!Bundle.hasValidDependencies())

>From 1907823db5a8da4cf8aa60c400b1b8eb77d2ae19 Mon Sep 17 00:00:00 2001
From: Serosh <janmejayapanda400 at gmail.com>
Date: Sun, 18 Jan 2026 23:23:00 +0530
Subject: [PATCH 2/2] [slp] add regression test for scheduler deadlock

---
 .../Transforms/Vectorize/SLPVectorizer.cpp    | 31 ++++++-----
 .../X86/gh176658-scheduler-deadlock.ll        | 52 +++++++++++++++++++
 2 files changed, 69 insertions(+), 14 deletions(-)
 create mode 100644 llvm/test/Transforms/SLPVectorizer/X86/gh176658-scheduler-deadlock.ll

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 06ed3502cfd89..f6ca401ae653e 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -22233,6 +22233,8 @@ void BoUpSLP::BlockScheduling::calculateDependencies(
             // instruction is non-schedulable.
             if (ScheduleCopyableData *UseSD =
                     getScheduleCopyableData(EI.UserTE->UserTreeIndex, In)) {
+              if (EI.UserTE->doesNotNeedToSchedule())
+                continue;
               CD->incDependencies();
               if (!UseSD->isScheduled())
                 CD->incrementUnscheduledDeps(1);
@@ -22286,6 +22288,10 @@ void BoUpSLP::BlockScheduling::calculateDependencies(
       if (isa<PHINode>(U))
         continue;
       if (ScheduleData *UseSD = getScheduleData(U)) {
+        if (any_of(getScheduleBundles(U), [](const ScheduleBundle *SB) {
+              return SB->getTreeEntry()->doesNotNeedToSchedule();
+            }))
+          continue;
         // The operand is a copyable element - skip.
         unsigned &NumOps = UserToNumOps.try_emplace(U, 0).first->getSecond();
         ++NumOps;
@@ -22302,6 +22308,8 @@ void BoUpSLP::BlockScheduling::calculateDependencies(
     }
     for (ScheduleCopyableData *UseSD :
          getScheduleCopyableDataUsers(BundleMember->getInst())) {
+      if (UseSD->getBundle().getTreeEntry()->doesNotNeedToSchedule())
+        continue;
       BundleMember->incDependencies();
       if (!UseSD->isScheduled())
         BundleMember->incrementUnscheduledDeps(1);
@@ -22576,20 +22584,11 @@ void BoUpSLP::scheduleBlock(const BoUpSLP &R, BlockScheduling *BS) {
         if (!Bundle.hasValidDependencies())
           BS->calculateDependencies(Bundle, /*InsertInReadyList=*/false, this);
       }
+      continue;
     }
-    SmallVector<ScheduleCopyableData *> SelfCopyableData =
-        BS->getScheduleCopyableData(I);
-    for (ScheduleCopyableData *SD : reverse(SelfCopyableData)) {
-      ScheduleBundle &Bundle = SD->getBundle();
-      Bundle.setSchedulingPriority(Idx++);
-      if (!Bundle.hasValidDependencies())
-        BS->calculateDependencies(Bundle, /*InsertInReadyList=*/false, this);
-    }
-    SmallVector<ScheduleCopyableData *> UserCopyableData =
+    SmallVector<ScheduleCopyableData *> CopyableData =
         BS->getScheduleCopyableDataUsers(I);
-    if (Bundles.empty() && SelfCopyableData.empty()) {
-      ScheduleData *SD = BS->getScheduleData(I);
-      assert(SD && "Expected schedule data");
+    if (ScheduleData *SD = BS->getScheduleData(I)) {
       [[maybe_unused]] ArrayRef<TreeEntry *> SDTEs = getTreeEntries(I);
       assert((isVectorLikeInstWithConstOps(SD->getInst()) || SDTEs.empty() ||
               SDTEs.front()->doesNotNeedToSchedule() ||
@@ -22597,18 +22596,22 @@ void BoUpSLP::scheduleBlock(const BoUpSLP &R, BlockScheduling *BS) {
              "scheduler and vectorizer bundle mismatch");
       SD->setSchedulingPriority(Idx++);
       if (!SD->hasValidDependencies() &&
-          (!UserCopyableData.empty() ||
+          (!CopyableData.empty() ||
            any_of(R.ValueToGatherNodes.lookup(I), [&](const TreeEntry *TE) {
              assert(TE->isGather() && "expected gather node");
              return TE->hasState() && TE->hasCopyableElements() &&
                     TE->isCopyableElement(I);
            }))) {
+        // Need to calculate deps for these nodes to correctly handle copyable
+        // dependencies, even if they were cancelled.
+        // If copyables bundle was cancelled, the deps are cleared and need to
+        // recalculate them.
         ScheduleBundle Bundle;
         Bundle.add(SD);
         BS->calculateDependencies(Bundle, /*InsertInReadyList=*/false, this);
       }
     }
-    for (ScheduleCopyableData *SD : reverse(UserCopyableData)) {
+    for (ScheduleCopyableData *SD : reverse(CopyableData)) {
       ScheduleBundle &Bundle = SD->getBundle();
       Bundle.setSchedulingPriority(Idx++);
       if (!Bundle.hasValidDependencies())
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/gh176658-scheduler-deadlock.ll b/llvm/test/Transforms/SLPVectorizer/X86/gh176658-scheduler-deadlock.ll
new file mode 100644
index 0000000000000..6abb8b145c573
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/gh176658-scheduler-deadlock.ll
@@ -0,0 +1,52 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=slp-vectorizer -slp-threshold=-99999 -S | FileCheck %s
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128-ni:1-p2:32:8:8:32-ni:2"
+target triple = "x86_64-unknown-linux-gnu"
+
+define i32 @gh176658() #0 gc "statepoint-example" {
+; CHECK-LABEL: @gh176658(
+; CHECK-NEXT:  bb:
+; CHECK-NEXT:    br label [[BB3:%.*]]
+; CHECK:       bb1:
+; CHECK-NEXT:    [[TMP0:%.*]] = phi <2 x i32> [ [[TMP8:%.*]], [[BB3]] ]
+; CHECK-NEXT:    ret i32 0
+; CHECK:       bb3:
+; CHECK-NEXT:    [[TMP1:%.*]] = phi <2 x i32> [ zeroinitializer, [[BB:%.*]] ], [ [[TMP11:%.*]], [[BB3]] ]
+; CHECK-NEXT:    [[LOAD:%.*]] = load i64, ptr addrspace(1) null, align 8
+; CHECK-NEXT:    [[TMP2:%.*]] = trunc i64 [[LOAD]] to i32
+; CHECK-NEXT:    [[TMP3:%.*]] = insertelement <2 x i32> <i32 0, i32 poison>, i32 [[TMP2]], i32 1
+; CHECK-NEXT:    [[TMP4:%.*]] = and <2 x i32> [[TMP3]], <i32 0, i32 -1>
+; CHECK-NEXT:    [[TMP5:%.*]] = extractelement <2 x i32> [[TMP4]], i32 0
+; CHECK-NEXT:    [[ASHR:%.*]] = ashr i32 0, [[TMP5]]
+; CHECK-NEXT:    [[TMP6:%.*]] = ashr <2 x i32> [[TMP1]], [[TMP4]]
+; CHECK-NEXT:    [[TMP7:%.*]] = or <2 x i32> [[TMP1]], [[TMP4]]
+; CHECK-NEXT:    [[TMP8]] = shufflevector <2 x i32> [[TMP6]], <2 x i32> [[TMP7]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT:    [[TMP9:%.*]] = shufflevector <2 x i32> [[TMP8]], <2 x i32> [[TMP1]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT:    [[TMP10:%.*]] = shufflevector <2 x i32> [[TMP3]], <2 x i32> <i32 0, i32 poison>, <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT:    [[TMP11]] = or <2 x i32> [[TMP9]], [[TMP10]]
+; CHECK-NEXT:    br i1 false, label [[BB1:%.*]], label [[BB3]]
+;
+bb:
+  br label %bb3
+
+bb1:
+  %phi = phi i32 [ %or, %bb3 ]
+  %phi2 = phi i32 [ %ashr7, %bb3 ]
+  ret i32 0
+
+bb3:
+  %phi4 = phi i32 [ 0, %bb ], [ %or, %bb3 ]
+  %phi5 = phi i32 [ 0, %bb ], [ %or8, %bb3 ]
+  %load = load i64, ptr addrspace(1) null, align 8
+  %trunc = trunc i64 %load to i32
+  %or = or i32 %phi4, %trunc
+  %trunc6 = trunc i64 0 to i32
+  %and = and i32 %trunc6, 0
+  %ashr = ashr i32 0, %and
+  %ashr7 = ashr i32 %phi5, %and
+  %or8 = or i32 %ashr7, 0
+  br i1 false, label %bb1, label %bb3
+}
+
+attributes #0 = { "target-features"="+avx2" }



More information about the llvm-commits mailing list