[llvm] 7e0a4ee - [SLP]Charge spill cost for loop-invariant gathers live over a call

via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 9 06:13:38 PDT 2026


Author: Alexey Bataev
Date: 2026-08-09T09:13:34-04:00
New Revision: 7e0a4eedf0193d28afe7cc892e0c06a93ae7a54f

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

LOG: [SLP]Charge spill cost for loop-invariant gathers live over a call

Loop-invariant gathers hoisted to the preheader by
optimizeGatherSequence are live across calls in the loop body and need
spill/reload on targets with call-clobbered vector registers, but were
skipped by getSpillCost. Charge them like other call-crossing values.

Fixes #214555

Reviewers: 

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

Added: 
    

Modified: 
    llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
    llvm/test/Transforms/SLPVectorizer/RISCV/spillcost-loop-invariant-gather.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index eb9cabe4d745b..a04877d183516 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -18698,9 +18698,22 @@ InstructionCost BoUpSLP::getSpillCost() {
       if (ScalarOrPseudoEntries.contains(Op))
         continue;
       if (Entry->State == TreeEntry::SplitVectorize ||
-          (Entry->getOpcode() != Instruction::PHI && Op->isGather()) ||
           (Op->isGather() && allConstant(Op->Scalars)))
         continue;
+      // A gather with all loop-invariant lanes is hoisted to the loop
+      // preheader by optimizeGatherSequence, so its vector value becomes live
+      // across any non-vectorized call in the loop body. Charge it like any
+      // other vectorized value live over a call instead of skipping it.
+      if (Entry->hasState() && Entry->getOpcode() != Instruction::PHI &&
+          Op->isGather()) {
+        if (const Loop *L = LI->getLoopFor(Parent);
+            L && L->getLoopPreheader() && LoopBodyHasCall(L) &&
+            all_of(Op->Scalars, [&](Value *V) {
+              return !isa<Instruction>(V) || L->isLoopInvariant(V);
+            }))
+          AddCosts(Op);
+        continue;
+      }
       Budget = 0;
       BasicBlock *Pred = nullptr;
       if (auto *Phi = dyn_cast<PHINode>(Entry->getMainOp()))

diff  --git a/llvm/test/Transforms/SLPVectorizer/RISCV/spillcost-loop-invariant-gather.ll b/llvm/test/Transforms/SLPVectorizer/RISCV/spillcost-loop-invariant-gather.ll
index a67a3d22d8cd9..eef5e69113f6e 100644
--- a/llvm/test/Transforms/SLPVectorizer/RISCV/spillcost-loop-invariant-gather.ll
+++ b/llvm/test/Transforms/SLPVectorizer/RISCV/spillcost-loop-invariant-gather.ll
@@ -12,8 +12,6 @@ define void @invariant_gather_over_call(ptr %out, ptr %in, double %a, double %b,
 ; CHECK-LABEL: define void @invariant_gather_over_call(
 ; CHECK-SAME: ptr [[OUT:%.*]], ptr [[IN:%.*]], double [[A:%.*]], double [[B:%.*]], double [[C:%.*]], double [[D:%.*]], i64 [[N:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[TMP0:%.*]] = insertelement <2 x double> poison, double [[B]], i64 0
-; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <2 x double> [[TMP0]], double [[C]], i64 1
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[INC:%.*]], %[[LOOP]] ]
@@ -21,18 +19,24 @@ define void @invariant_gather_over_call(ptr %out, ptr %in, double %a, double %b,
 ; CHECK-NEXT:    [[V0:%.*]] = load double, ptr [[P0]], align 8
 ; CHECK-NEXT:    [[I1:%.*]] = add nuw nsw i64 [[I]], 3
 ; CHECK-NEXT:    [[P1:%.*]] = getelementptr inbounds double, ptr [[IN]], i64 [[I1]]
+; CHECK-NEXT:    [[V1:%.*]] = load double, ptr [[P1]], align 8
+; CHECK-NEXT:    [[I2:%.*]] = add nuw nsw i64 [[I]], 7
+; CHECK-NEXT:    [[P2:%.*]] = getelementptr inbounds double, ptr [[IN]], i64 [[I2]]
+; CHECK-NEXT:    [[V2:%.*]] = load double, ptr [[P2]], align 8
 ; CHECK-NEXT:    [[I3:%.*]] = add nuw nsw i64 [[I]], 100
 ; CHECK-NEXT:    [[P3:%.*]] = getelementptr inbounds double, ptr [[IN]], i64 [[I3]]
 ; CHECK-NEXT:    [[V3:%.*]] = load double, ptr [[P3]], align 8
 ; CHECK-NEXT:    [[R0:%.*]] = fmul double [[V0]], [[A]]
+; CHECK-NEXT:    [[R1:%.*]] = fmul double [[V1]], [[B]]
+; CHECK-NEXT:    [[R2:%.*]] = fmul double [[V2]], [[C]]
 ; CHECK-NEXT:    [[R3:%.*]] = fmul double [[V3]], [[D]]
 ; CHECK-NEXT:    [[O0:%.*]] = getelementptr inbounds double, ptr [[OUT]], i64 [[I]]
 ; CHECK-NEXT:    [[O1:%.*]] = getelementptr inbounds double, ptr [[O0]], i64 1
+; CHECK-NEXT:    [[O2:%.*]] = getelementptr inbounds double, ptr [[O0]], i64 2
 ; CHECK-NEXT:    [[O3:%.*]] = getelementptr inbounds double, ptr [[O0]], i64 3
-; CHECK-NEXT:    [[TMP2:%.*]] = call <2 x double> @llvm.experimental.vp.strided.load.v2f64.p0.i64(ptr align 8 [[P1]], i64 32, <2 x i1> splat (i1 true), i32 2)
-; CHECK-NEXT:    [[TMP3:%.*]] = fmul <2 x double> [[TMP2]], [[TMP1]]
 ; CHECK-NEXT:    store double [[R0]], ptr [[O0]], align 8
-; CHECK-NEXT:    store <2 x double> [[TMP3]], ptr [[O1]], align 8
+; CHECK-NEXT:    store double [[R1]], ptr [[O1]], align 8
+; CHECK-NEXT:    store double [[R2]], ptr [[O2]], align 8
 ; CHECK-NEXT:    store double [[R3]], ptr [[O3]], align 8
 ; CHECK-NEXT:    call void @g()
 ; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[I]], 4


        


More information about the llvm-commits mailing list