[llvm] e2efa2e - [SLP] Gather wide PHI bundles to avoid compile-time blow-up

via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 3 04:05:53 PDT 2026


Author: Alexey Bataev
Date: 2026-06-03T07:05:48-04:00
New Revision: e2efa2e958270e0f21d9db2aa9a393006c9d6d0b

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

LOG: [SLP] Gather wide PHI bundles to avoid compile-time blow-up

Vectorizing a PHI bundle recurses into one operand bundle per incoming
value, so the analysis cost grows with bundle_size * num_incoming_values.
With revectorization, very wide PHIs from jump threading make
opt -O3 hang for minutes/hours. Such PHIs are not profitable to vectorize,
so gather the bundle once that product exceeds a budget (new hidden option
-slp-phi-vectorization-budget, default 1024).

Fixes #201181

Reviewers: hiraditya, bababuck, RKSimon

Pull Request: https://github.com/llvm/llvm-project/pull/201227

Added: 
    llvm/test/Transforms/SLPVectorizer/X86/phi-vectorization-budget.ll

Modified: 
    llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index a488fdca64074..99ed09cc684b9 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -179,6 +179,12 @@ static cl::opt<unsigned> MinTreeSize(
     "slp-min-tree-size", cl::init(3), cl::Hidden,
     cl::desc("Only vectorize small trees if they are fully vectorizable"));
 
+static cl::opt<unsigned> PHINodeVectorizationBudget(
+    "slp-phi-vectorization-budget", cl::init(1024), cl::Hidden,
+    cl::desc("Do not vectorize a bundle of PHI nodes if the product of the "
+             "bundle size and the number of incoming values exceeds this "
+             "value, to limit the compile time spent on wide PHIs"));
+
 // The maximum depth that the look-ahead score heuristic will explore.
 // The higher this value, the higher the compilation time overhead.
 static cl::opt<int> LookAheadMaxDepth(
@@ -12610,6 +12616,21 @@ BoUpSLP::getScalarsVectorizationLegality(ArrayRef<Value *> VL, unsigned Depth,
   }
   assert(S && "Must be valid.");
 
+  // Gather very wide PHI bundles. Wide PHIs (e.g. produced by
+  // jump threading) are not profitable to vectorize and make this analysis
+  // explode, so gather them to keep the compile time bounded.
+  if (S.getOpcode() == Instruction::PHI) {
+    unsigned NumIncomingValues =
+        cast<PHINode>(S.getMainOp())->getNumIncomingValues();
+    if (static_cast<uint64_t>(VL.size()) * NumIncomingValues >
+        PHINodeVectorizationBudget) {
+      LLVM_DEBUG(dbgs() << "SLP: Gathering due to wide PHI operand fan-out ("
+                        << VL.size() << " lanes x " << NumIncomingValues
+                        << " incoming values).\n");
+      return ScalarsVectorizationLegality(S, /*IsLegal=*/false);
+    }
+  }
+
   // Don't handle vectors.
   if (!SLPReVec && getValueType(VL.front())->isVectorTy()) {
     LLVM_DEBUG(dbgs() << "SLP: Gathering due to vector type.\n");

diff  --git a/llvm/test/Transforms/SLPVectorizer/X86/phi-vectorization-budget.ll b/llvm/test/Transforms/SLPVectorizer/X86/phi-vectorization-budget.ll
new file mode 100644
index 0000000000000..3534498ec5c87
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/phi-vectorization-budget.ll
@@ -0,0 +1,55 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=slp-vectorizer -slp-threshold=-100 -mtriple=x86_64-unknown-linux-gnu -S < %s | FileCheck %s --check-prefixes=VEC
+; RUN: opt -passes=slp-vectorizer -slp-threshold=-100 -slp-phi-vectorization-budget=3 -mtriple=x86_64-unknown-linux-gnu -S < %s | FileCheck %s --check-prefixes=BUDGET
+
+define void @phi_bundle(ptr %A, i32 %k) {
+; VEC-LABEL: @phi_bundle(
+; VEC-NEXT:  entry:
+; VEC-NEXT:    [[TOBOOL:%.*]] = icmp eq i32 [[K:%.*]], 0
+; VEC-NEXT:    br i1 [[TOBOOL]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
+; VEC:       if.else:
+; VEC-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds double, ptr [[A:%.*]], i64 10
+; VEC-NEXT:    [[TMP0:%.*]] = load <2 x double>, ptr [[ARRAYIDX]], align 8
+; VEC-NEXT:    br label [[IF_END]]
+; VEC:       if.end:
+; VEC-NEXT:    [[TMP1:%.*]] = phi <2 x double> [ [[TMP0]], [[IF_ELSE]] ], [ <double 3.000000e+00, double 5.000000e+00>, [[ENTRY:%.*]] ]
+; VEC-NEXT:    store <2 x double> [[TMP1]], ptr [[A]], align 8
+; VEC-NEXT:    ret void
+;
+; BUDGET-LABEL: @phi_bundle(
+; BUDGET-NEXT:  entry:
+; BUDGET-NEXT:    [[TOBOOL:%.*]] = icmp eq i32 [[K:%.*]], 0
+; BUDGET-NEXT:    br i1 [[TOBOOL]], label [[IF_ELSE:%.*]], label [[IF_END:%.*]]
+; BUDGET:       if.else:
+; BUDGET-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds double, ptr [[A:%.*]], i64 10
+; BUDGET-NEXT:    [[TMP0:%.*]] = load double, ptr [[ARRAYIDX]], align 8
+; BUDGET-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds double, ptr [[A]], i64 11
+; BUDGET-NEXT:    [[TMP1:%.*]] = load double, ptr [[ARRAYIDX1]], align 8
+; BUDGET-NEXT:    br label [[IF_END]]
+; BUDGET:       if.end:
+; BUDGET-NEXT:    [[A0_0:%.*]] = phi double [ [[TMP0]], [[IF_ELSE]] ], [ 3.000000e+00, [[ENTRY:%.*]] ]
+; BUDGET-NEXT:    [[A1_0:%.*]] = phi double [ [[TMP1]], [[IF_ELSE]] ], [ 5.000000e+00, [[ENTRY]] ]
+; BUDGET-NEXT:    store double [[A0_0]], ptr [[A]], align 8
+; BUDGET-NEXT:    [[ARRAYIDX3:%.*]] = getelementptr inbounds double, ptr [[A]], i64 1
+; BUDGET-NEXT:    store double [[A1_0]], ptr [[ARRAYIDX3]], align 8
+; BUDGET-NEXT:    ret void
+;
+entry:
+  %tobool = icmp eq i32 %k, 0
+  br i1 %tobool, label %if.else, label %if.end
+
+if.else:
+  %arrayidx = getelementptr inbounds double, ptr %A, i64 10
+  %0 = load double, ptr %arrayidx, align 8
+  %arrayidx1 = getelementptr inbounds double, ptr %A, i64 11
+  %1 = load double, ptr %arrayidx1, align 8
+  br label %if.end
+
+if.end:
+  %A0.0 = phi double [ %0, %if.else ], [ 3.000000e+00, %entry ]
+  %A1.0 = phi double [ %1, %if.else ], [ 5.000000e+00, %entry ]
+  store double %A0.0, ptr %A, align 8
+  %arrayidx3 = getelementptr inbounds double, ptr %A, i64 1
+  store double %A1.0, ptr %arrayidx3, align 8
+  ret void
+}


        


More information about the llvm-commits mailing list