[llvm] [SLP]Pack unique consecutive loads instead of gathering duplicated lanes (PR #228698)
Alexey Bataev via llvm-commits
llvm-commits at lists.llvm.org
Sat Oct 3 04:31:08 PDT 2026
https://github.com/alexey-bataev created https://github.com/llvm/llvm-project/pull/228698
A load bundle with duplicated lanes whose unique loads are consecutive
was kept as is and emitted as a masked gather. Pack the unique loads
into a single wide load plus a reuse shuffle, unless the target reports
the masked gather as cheaper.
>From 7af92a0d904d242715f666e29fa4655de283efde Mon Sep 17 00:00:00 2001
From: Alexey Bataev <a.bataev at outlook.com>
Date: Sat, 3 Oct 2026 04:30:54 -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 | 32 ++++++++++++++++---
.../X86/duplicated-lane-consecutive-loads.ll | 9 +++---
2 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index fcc14be3104bd2..0981c124e3aec4 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -10182,13 +10182,16 @@ static bool tryToFindDuplicates(SmallVectorImpl<Value *> &VL,
!has_single_bit(NumUniqueScalarValues) &&
UniquePositions.size() * 2 < NumUniqueScalarValues)
return std::make_pair(false, false);
- auto CheckLoads = [&](ArrayRef<Value *> Loads, bool IncludeGather) {
+ auto GetLoadsState = [&](ArrayRef<Value *> Loads) {
assert(S && S.getOpcode() == Instruction::Load && "Expected load.");
BoUpSLP::OrdersType Order;
SmallVector<Value *> PointerOps;
BoUpSLP::StridedPtrInfo SPtrInfo;
- BoUpSLP::LoadsState Res = R.canVectorizeLoads(Loads, S.getMainOp(), Order,
- PointerOps, SPtrInfo);
+ return R.canVectorizeLoads(Loads, S.getMainOp(), Order, PointerOps,
+ SPtrInfo);
+ };
+ auto CheckLoads = [&](ArrayRef<Value *> Loads, bool IncludeGather) {
+ BoUpSLP::LoadsState Res = GetLoadsState(Loads);
return (IncludeGather && Res == BoUpSLP::LoadsState::Gather) ||
Res == BoUpSLP::LoadsState::ScatterVectorize ||
Res == BoUpSLP::LoadsState::StridedVectorize ||
@@ -10270,8 +10273,27 @@ static bool tryToFindDuplicates(SmallVectorImpl<Value *> &VL,
if (S && S.getOpcode() == Instruction::Load) {
bool UniquesVectorized =
CheckLoads(UniqueValues, /*IncludeGather=*/false);
- if (UniquesVectorized || CheckLoads(VL, /*IncludeGather=*/false))
- return std::make_pair(true, !UniquesVectorized);
+ if (UniquesVectorized || CheckLoads(VL, /*IncludeGather=*/false)) {
+ bool UseOriginal = !UniquesVectorized;
+ // The unique loads are consecutive: pack them unless the masked
+ // gather of the originals is cheaper than the wide load + reshuffle.
+ if (UseOriginal &&
+ GetLoadsState(UniqueValues) == BoUpSLP::LoadsState::Vectorize) {
+ auto *LI0 = cast<LoadInst>(S.getMainOp());
+ InstructionCost PackCost =
+ ReusesCost + TTI.getMemoryOpCost(
+ Instruction::Load, UniquesVecTy, LI0->getAlign(),
+ LI0->getPointerAddressSpace(), CostKind,
+ TTI::getOperandInfo(LI0->getPointerOperand()));
+ InstructionCost GatherCost = TTI.getMemIntrinsicInstrCost(
+ MemIntrinsicCostAttributes(
+ Intrinsic::masked_gather, VecTy, LI0->getPointerOperand(),
+ /*VariableMask=*/false, computeCommonAlignment<LoadInst>(VL)),
+ CostKind);
+ UseOriginal = GatherCost < PackCost;
+ }
+ return std::make_pair(true, UseOriginal);
+ }
}
bool CanSkipBVCost =
(!BuildGatherOnly && !RequireScheduling) || R.hasSameNode(S, VL);
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/duplicated-lane-consecutive-loads.ll b/llvm/test/Transforms/SLPVectorizer/X86/duplicated-lane-consecutive-loads.ll
index 8a3836a722d32a..1d2fc0c15a6019 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/duplicated-lane-consecutive-loads.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/duplicated-lane-consecutive-loads.ll
@@ -12,14 +12,13 @@ define void @test(i64 %i) {
; CHECK-LABEL: define void @test(
; CHECK-SAME: i64 [[I:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[ENTRY:.*]]:
-; CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x i64> poison, i64 [[I]], i64 0
-; CHECK-NEXT: [[TMP6:%.*]] = shufflevector <4 x i64> [[TMP0]], <4 x i64> poison, <4 x i32> zeroinitializer
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT: [[TMP7:%.*]] = add <4 x i64> [[TMP6]], <i64 6, i64 8, i64 7, i64 7>
-; CHECK-NEXT: [[TMP8:%.*]] = getelementptr double, <4 x ptr> <ptr @src, ptr @src, ptr @src, ptr @src>, <4 x i64> [[TMP7]]
-; CHECK-NEXT: [[TMP1:%.*]] = call <4 x double> @llvm.masked.gather.v4f64.v4p0(<4 x ptr> align 8 [[TMP8]], <4 x i1> splat (i1 true), <4 x double> poison)
+; CHECK-NEXT: [[IDX_0:%.*]] = add i64 [[I]], 6
+; CHECK-NEXT: [[GEP_0:%.*]] = getelementptr double, ptr @src, i64 [[IDX_0]]
+; CHECK-NEXT: [[TMP0:%.*]] = load <3 x double>, ptr [[GEP_0]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <3 x double> [[TMP0]], <3 x double> poison, <4 x i32> <i32 0, i32 2, i32 1, i32 1>
; CHECK-NEXT: [[TMP2:%.*]] = fsub <4 x double> zeroinitializer, [[TMP1]]
; CHECK-NEXT: [[TMP3:%.*]] = fadd <4 x double> [[TMP2]], splat (double 1.000000e+00)
; CHECK-NEXT: [[TMP4:%.*]] = fcmp olt <4 x double> [[TMP3]], zeroinitializer
More information about the llvm-commits
mailing list