LLVM 24.0.0git
SLPMemoryUtils.cpp
Go to the documentation of this file.
1//===- SLPMemoryUtils.cpp - SLP pointer/stride helpers --------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "SLPMemoryUtils.h"
11#include "SLPCostAnalysis.h"
12#include "SLPTypeUtils.h"
13#include "SLPUtils.h"
14
15#include "llvm/ADT/APInt.h"
16#include "llvm/ADT/MapVector.h"
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/Sequence.h"
20#include "llvm/Analysis/Loads.h"
26#include "llvm/IR/Constants.h"
27#include "llvm/IR/DataLayout.h"
29#include "llvm/IR/Function.h"
30#include "llvm/IR/IRBuilder.h"
32#include "llvm/IR/Intrinsics.h"
34
35#include <algorithm>
36#include <limits>
37#include <optional>
38#include <set>
39#include <tuple>
40#include <utility>
41
42using namespace llvm;
43
44namespace llvm::slpvectorizer {
45
47 const DataLayout &DL) {
48 bool ToPtr = cast<VectorType>(DstTy)->getElementType()->isPointerTy();
49 if (ToPtr == cast<VectorType>(V->getType())->getElementType()->isPointerTy())
50 return Builder.CreateBitOrPointerCast(V, DstTy);
51 if (ToPtr)
52 return Builder.CreateIntToPtr(
53 Builder.CreateBitCast(V, DL.getIntPtrType(DstTy)), DstTy);
54 return Builder.CreateBitCast(
55 Builder.CreatePtrToInt(V, DL.getIntPtrType(V->getType())), DstTy);
56}
57
59 const DataLayout &DL, bool IsReverse) {
60 auto *CI = dyn_cast_or_null<ConstantInt>(Stride);
61 if (!CI)
62 return nullptr;
63
64 uint64_t ElementSize = DL.getTypeAllocSize(ScalarTy).getFixedValue();
65 APInt Bytes = CI->getValue() * ElementSize;
66 return ConstantInt::get(CI->getContext(), IsReverse ? -Bytes : Bytes);
67}
68
70 const TargetLibraryInfo &TLI, unsigned MaxDepth,
71 bool CompareOpcodes) {
72 if (getUnderlyingObject(Ptr1, MaxDepth) !=
73 getUnderlyingObject(Ptr2, MaxDepth))
74 return false;
75 auto *GEP1 = dyn_cast<GetElementPtrInst>(Ptr1);
76 auto *GEP2 = dyn_cast<GetElementPtrInst>(Ptr2);
77 return (!GEP1 || GEP1->getNumOperands() == 2) &&
78 (!GEP2 || GEP2->getNumOperands() == 2) &&
79 (((!GEP1 || isConstant(GEP1->getOperand(1))) &&
80 (!GEP2 || isConstant(GEP2->getOperand(1)))) ||
81 !CompareOpcodes ||
82 (GEP1 && GEP2 &&
83 getSameOpcode({GEP1->getOperand(1), GEP2->getOperand(1)}, TLI)));
84}
85
86/// Calculates minimal alignment as a common alignment.
88 Align CommonAlignment = cast<T>(VL.consume_front())->getAlign();
89 for (Value *V : VL)
90 CommonAlignment = std::min(CommonAlignment, cast<T>(V)->getAlign());
91 return CommonAlignment;
92}
93
96
98 const DataLayout &DL, ScalarEvolution &SE,
99 SmallVectorImpl<unsigned> &SortedIndices) {
101 const SCEV *PtrSCEVLowest = nullptr;
102 const SCEV *PtrSCEVHighest = nullptr;
103 // Find lower/upper pointers from the PointerOps (i.e. with lowest and highest
104 // addresses).
105 for (Value *Ptr : PointerOps) {
106 const SCEV *PtrSCEV = SE.getSCEV(Ptr);
107 if (!PtrSCEV)
108 return nullptr;
109 SCEVs.push_back(PtrSCEV);
110 if (!PtrSCEVLowest && !PtrSCEVHighest) {
111 PtrSCEVLowest = PtrSCEVHighest = PtrSCEV;
112 continue;
113 }
114 const SCEV *Diff = SE.getMinusSCEV(PtrSCEV, PtrSCEVLowest);
115 if (isa<SCEVCouldNotCompute>(Diff))
116 return nullptr;
117 if (Diff->isNonConstantNegative()) {
118 PtrSCEVLowest = PtrSCEV;
119 continue;
120 }
121 const SCEV *Diff1 = SE.getMinusSCEV(PtrSCEVHighest, PtrSCEV);
122 if (isa<SCEVCouldNotCompute>(Diff1))
123 return nullptr;
124 if (Diff1->isNonConstantNegative()) {
125 PtrSCEVHighest = PtrSCEV;
126 continue;
127 }
128 }
129 // Dist = PtrSCEVHighest - PtrSCEVLowest;
130 const SCEV *Dist = SE.getMinusSCEV(PtrSCEVHighest, PtrSCEVLowest);
131 if (isa<SCEVCouldNotCompute>(Dist))
132 return nullptr;
133 int Size = DL.getTypeStoreSize(ElemTy);
134 auto TryGetStride = [&](const SCEV *Dist,
135 const SCEV *Multiplier) -> const SCEV * {
136 if (const auto *M = dyn_cast<SCEVMulExpr>(Dist)) {
137 if (M->getOperand(0) == Multiplier)
138 return M->getOperand(1);
139 if (M->getOperand(1) == Multiplier)
140 return M->getOperand(0);
141 return nullptr;
142 }
143 if (Multiplier == Dist)
144 return SE.getConstant(Dist->getType(), 1);
145 return SE.getUDivExactExpr(Dist, Multiplier);
146 };
147 // Stride_in_elements = Dist / element_size * (num_elems - 1).
148 const SCEV *Stride = nullptr;
149 if (Size != 1 || SCEVs.size() > 1) {
150 const SCEV *Sz = SE.getConstant(Dist->getType(), Size * (SCEVs.size() - 1));
151 Stride = TryGetStride(Dist, Sz);
152 if (!Stride)
153 return nullptr;
154 }
155 if (!Stride || isa<SCEVConstant>(Stride))
156 return nullptr;
157 // Iterate through all pointers and check if all distances are
158 // unique multiple of Stride.
159 using DistOrdPair = std::pair<int64_t, int>;
160 auto Compare = llvm::less_first();
161 std::set<DistOrdPair, decltype(Compare)> Offsets(Compare);
162 bool IsConsecutive = true;
163 for (const auto [Idx, PtrSCEV] : enumerate(SCEVs)) {
164 unsigned Dist = 0;
165 if (PtrSCEV != PtrSCEVLowest) {
166 const SCEV *Diff = SE.getMinusSCEV(PtrSCEV, PtrSCEVLowest);
167 const SCEV *Coeff = TryGetStride(Diff, Stride);
168 if (!Coeff)
169 return nullptr;
170 const auto *SC = dyn_cast<SCEVConstant>(Coeff);
171 if (!SC || isa<SCEVCouldNotCompute>(SC))
172 return nullptr;
173 if (!SE.getMinusSCEV(PtrSCEV, SE.getAddExpr(PtrSCEVLowest,
174 SE.getMulExpr(Stride, SC)))
175 ->isZero())
176 return nullptr;
177 Dist = SC->getAPInt().getZExtValue();
178 }
179 // If the strides are not the same or repeated, we can't vectorize.
180 if ((Dist / Size) * Size != Dist || (Dist / Size) >= SCEVs.size())
181 return nullptr;
182 auto Res = Offsets.emplace(Dist, Idx);
183 if (!Res.second)
184 return nullptr;
185 // Consecutive order if the inserted element is the last one.
186 IsConsecutive = IsConsecutive && std::next(Res.first) == Offsets.end();
187 }
188 SortedIndices.clear();
189 if (!IsConsecutive) {
190 // Fill SortedIndices array only if it is non-consecutive.
191 SortedIndices.resize(PointerOps.size());
192 for (const auto [Idx, Pair] : enumerate(Offsets))
193 SortedIndices[Idx] = Pair.second;
194 }
195 return Stride;
196}
197
198std::optional<int64_t>
200 Value *PtrB, const DataLayout &DL,
201 ScalarEvolution &SE, bool StrictCheck,
202 bool CheckType) {
203 if (PtrA == PtrB)
204 return 0;
205 unsigned Flags = unsigned(StrictCheck) | (unsigned(CheckType) << 1);
206 PtrsDiffKeyT Key(ElemTyA, PtrA, ElemTyB, PtrB, Flags);
207 auto [It, Inserted] = PtrsDiffCache.try_emplace(Key);
208 if (!Inserted)
209 return It->second;
210 std::optional<int64_t> Diff = llvm::getPointersDiff(
211 ElemTyA, PtrA, ElemTyB, PtrB, DL, SE, StrictCheck, CheckType);
212 // Set before the reverse insertion below, which may rehash.
213 It->second = Diff;
214 // The distance is counted in elements of ElemTyA, so querying the pair the
215 // other way round gives the negation, provided both elements have the same
216 // size. A failed query is recorded for this order only.
217 if (Diff && *Diff != std::numeric_limits<int64_t>::min() &&
218 DL.getTypeStoreSize(ElemTyA) == DL.getTypeStoreSize(ElemTyB))
219 PtrsDiffCache.try_emplace(PtrsDiffKeyT(ElemTyB, PtrB, ElemTyA, PtrA, Flags),
220 -*Diff);
221 return Diff;
222}
223
226 ScalarEvolution &SE, SmallVectorImpl<unsigned> &SortedIndices) {
227 using DistOrdPair = std::pair<int64_t, unsigned>;
228 auto Compare = less_first();
229 std::set<DistOrdPair, decltype(Compare)> Offsets(Compare);
230 Offsets.emplace(0, 0);
231 bool IsConsecutive = true;
232 for (auto [Idx, Ptr] : drop_begin(enumerate(VL))) {
233 std::optional<int64_t> Diff =
234 getPointersDiff(ElemTy, VL.front(), ElemTy, Ptr, DL, SE,
235 /*StrictCheck=*/true);
236 if (!Diff)
237 return false;
238 auto [It, IsInserted] = Offsets.emplace(*Diff, Idx);
239 if (!IsInserted)
240 return false;
241 IsConsecutive &= std::next(It) == Offsets.end();
242 }
243 SortedIndices.clear();
244 if (!IsConsecutive) {
245 SortedIndices.resize(VL.size());
246 for (auto [Idx, Off] : enumerate(Offsets))
247 SortedIndices[Idx] = Off.second;
248 }
249 return true;
250}
251
253 AssumptionCache *AC) {
254 auto [It, Inserted] = NotPoisonCache.try_emplace(V, false);
255 if (Inserted)
256 It->second = llvm::isGuaranteedNotToBePoison(V, AC);
257 return It->second;
258}
259
260/// Builds compress-like mask for shuffles for the given \p PointerOps, ordered
261/// with \p Order.
262/// \return true if the mask represents strided access, false - otherwise.
264 ArrayRef<unsigned> Order, Type *ScalarTy,
265 const DataLayout &DL, ScalarEvolution &SE,
266 SmallVectorImpl<int> &CompressMask,
267 SLPAnalysisCache &Cache) {
268 const unsigned Sz = PointerOps.size();
269 CompressMask.assign(Sz, PoisonMaskElem);
270 // The first element always set.
271 CompressMask[0] = 0;
272 // Check if the mask represents strided access.
273 std::optional<unsigned> Stride = 0;
274 Value *Ptr0 = Order.empty() ? PointerOps.front() : PointerOps[Order.front()];
275 for (unsigned I : seq<unsigned>(1, Sz)) {
276 Value *Ptr = Order.empty() ? PointerOps[I] : PointerOps[Order[I]];
277 std::optional<int64_t> OptPos =
278 Cache.getPointersDiff(ScalarTy, Ptr0, ScalarTy, Ptr, DL, SE);
279 if (!OptPos || OptPos > std::numeric_limits<unsigned>::max())
280 return false;
281 unsigned Pos = static_cast<unsigned>(*OptPos);
282 CompressMask[I] = Pos;
283 if (!Stride)
284 continue;
285 if (*Stride == 0) {
286 *Stride = Pos;
287 continue;
288 }
289 if (Pos != *Stride * I)
290 Stride.reset();
291 }
292 return Stride.has_value();
293}
294
295/// Checks if the \p VL can be transformed to a (masked)load + compress or
296/// (masked) interleaved load.
301 const DominatorTree &DT, const TargetLibraryInfo &TLI,
303 const function_ref<bool(Value *)> AreAllUsersVectorized, bool ReVec,
304 bool &IsMasked, unsigned &InterleaveFactor,
305 SmallVectorImpl<int> &CompressMask, VectorType *&LoadVecTy,
306 SLPAnalysisCache &Cache) {
307 InterleaveFactor = 0;
308 Type *ScalarTy = VL.front()->getType();
309 const size_t Sz = VL.size();
310 auto *VecTy = cast<VectorType>(getWidenedType(ScalarTy, Sz));
311 SmallVector<int> Mask;
312 if (!Order.empty())
313 inversePermutation(Order, Mask);
314 // Check external uses.
315 for (const auto [I, V] : enumerate(VL)) {
316 if (AreAllUsersVectorized(V))
317 continue;
318 InstructionCost ExtractCost =
319 TTI.getVectorInstrCost(Instruction::ExtractElement, VecTy, CostKind,
320 Mask.empty() ? I : Mask[I]);
321 InstructionCost ScalarCost =
322 TTI.getInstructionCost(cast<Instruction>(V), CostKind);
323 if (ExtractCost <= ScalarCost)
324 return false;
325 }
326 Value *Ptr0;
327 Value *PtrN;
328 if (Order.empty()) {
329 Ptr0 = PointerOps.front();
330 PtrN = PointerOps.back();
331 } else {
332 Ptr0 = PointerOps[Order.front()];
333 PtrN = PointerOps[Order.back()];
334 }
335 std::optional<int64_t> Diff =
336 Cache.getPointersDiff(ScalarTy, Ptr0, ScalarTy, PtrN, DL, SE);
337 if (!Diff)
338 return false;
339 const size_t MaxRegSize =
341 .getFixedValue();
342 // Check for very large distances between elements.
343 if (*Diff / Sz >= MaxRegSize / 8)
344 return false;
345 LoadVecTy = cast<FixedVectorType>(getWidenedType(ScalarTy, *Diff + 1));
346 auto *LI = cast<LoadInst>(Order.empty() ? VL.front() : VL[Order.front()]);
347 Align CommonAlignment = LI->getAlign();
348 SimplifyQuery SQ(
349 DL, &TLI, &DT, &AC,
350 cast<LoadInst>(Order.empty() ? VL.back() : VL[Order.back()]));
351 IsMasked = !isSafeToLoadUnconditionally(Ptr0, LoadVecTy, CommonAlignment, SQ);
352 if (IsMasked && !TTI.isLegalMaskedLoad(LoadVecTy, CommonAlignment,
353 LI->getPointerAddressSpace()))
354 return false;
355 // TODO: perform the analysis of each scalar load for better
356 // safe-load-unconditionally analysis.
357 bool IsStrided = buildCompressMask(PointerOps, Order, ScalarTy, DL, SE,
358 CompressMask, Cache);
359 assert(CompressMask.size() >= 2 && "At least two elements are required");
360 SmallVector<Value *> OrderedPointerOps(PointerOps);
361 if (!Order.empty())
362 reorderScalars(OrderedPointerOps, Mask);
363 auto [ScalarGEPCost, VectorGEPCost] =
364 getGEPCosts(TTI, OrderedPointerOps, OrderedPointerOps.front(),
365 Instruction::Load, CostKind, ScalarTy, LoadVecTy);
366 // The cost of scalar loads.
367 InstructionCost ScalarLoadsCost =
369 [&](InstructionCost C, Value *V) {
370 return C + TTI.getInstructionCost(cast<Instruction>(V),
371 CostKind);
372 }) +
373 ScalarGEPCost;
374 APInt DemandedElts = APInt::getAllOnes(Sz);
375 InstructionCost GatherCost =
376 getScalarizationOverhead(TTI, ReVec, ScalarTy, VecTy, DemandedElts,
377 /*Insert=*/true,
378 /*Extract=*/false, CostKind) +
379 ScalarLoadsCost;
380 InstructionCost LoadCost = 0;
381 if (IsMasked) {
382 LoadCost = TTI.getMemIntrinsicInstrCost(
383 MemIntrinsicCostAttributes(Intrinsic::masked_load, LoadVecTy,
384 CommonAlignment,
385 LI->getPointerAddressSpace()),
386 CostKind);
387 } else {
388 LoadCost =
389 TTI.getMemoryOpCost(Instruction::Load, LoadVecTy, CommonAlignment,
390 LI->getPointerAddressSpace(), CostKind,
391 TTI::getOperandInfo(LI->getPointerOperand()));
392 }
393 if (IsStrided && !IsMasked && Order.empty()) {
394 // Check for potential segmented(interleaved) loads.
395 VectorType *AlignedLoadVecTy = cast<VectorType>(getWidenedType(
396 ScalarTy,
397 getFullVectorNumberOfElements(TTI, ScalarTy, *Diff + 1, ReVec)));
398 SimplifyQuery SQ(DL, &TLI, &DT, &AC, cast<LoadInst>(VL.back()));
399 if (!isSafeToLoadUnconditionally(Ptr0, AlignedLoadVecTy, CommonAlignment,
400 SQ))
401 AlignedLoadVecTy = LoadVecTy;
402 if (TTI.isLegalInterleavedAccessType(AlignedLoadVecTy, CompressMask[1],
403 CommonAlignment,
404 LI->getPointerAddressSpace())) {
405 InstructionCost InterleavedCost =
406 VectorGEPCost + TTI.getInterleavedMemoryOpCost(
407 Instruction::Load, AlignedLoadVecTy,
408 CompressMask[1], {}, CommonAlignment,
409 LI->getPointerAddressSpace(), CostKind, IsMasked);
410 if (InterleavedCost < GatherCost) {
411 InterleaveFactor = CompressMask[1];
412 LoadVecTy = AlignedLoadVecTy;
413 return true;
414 }
415 }
416 }
417 // Estimating the compression shuffle cost below can be extremely expensive
418 // for a very wide LoadVecTy, which is split into a large number of vector
419 // registers (see processShuffleMasks). The shuffle cost is always
420 // non-negative, so if the load cost alone already reaches the gather cost the
421 // masked-load-compress cannot be profitable. Bail out before the costly
422 // shuffle cost estimation in that case.
423 if (VectorGEPCost + LoadCost >= GatherCost)
424 return false;
425 // For REVEC the scalars are vectors, and the emitted shuffle uses the
426 // compress mask expanded to the individual elements. Cost that mask.
427 SmallVector<int> CostMask(CompressMask.begin(), CompressMask.end());
430 LoadVecTy, CostKind, CostMask);
431 if (!Order.empty()) {
432 SmallVector<int> NewMask(Sz, PoisonMaskElem);
433 for (unsigned I : seq<unsigned>(Sz)) {
434 NewMask[I] = CompressMask[Mask[I]];
435 }
436 CompressMask.swap(NewMask);
437 }
438 InstructionCost TotalVecCost = VectorGEPCost + LoadCost + CompressCost;
439 return TotalVecCost < GatherCost;
440}
441
442/// Checks if the \p VL can be transformed to a (masked)load + compress or
443/// (masked) interleaved load.
448 const DominatorTree &DT, const TargetLibraryInfo &TLI,
450 const function_ref<bool(Value *)> AreAllUsersVectorized, bool ReVec,
451 SLPAnalysisCache &Cache) {
452 bool IsMasked;
453 unsigned InterleaveFactor;
454 SmallVector<int> CompressMask;
455 VectorType *LoadVecTy;
456 return isMaskedLoadCompress(VL, PointerOps, Order, TTI, DL, SE, AC, DT, TLI,
457 CostKind, AreAllUsersVectorized, ReVec, IsMasked,
458 InterleaveFactor, CompressMask, LoadVecTy, Cache);
459}
460
463 const DominatorTree &DT,
464 const TargetLibraryInfo &TLI) {
465 if (count_if(VL, IsaPred<LoadInst>) < 2)
466 return false;
467 const auto *FirstIt = find_if(VL, IsaPred<LoadInst>);
468 const unsigned FirstLane = std::distance(VL.begin(), FirstIt);
469 auto *FirstLI = cast<LoadInst>(*FirstIt);
470 // The wide load may read the memory with a different tag.
471 if (FirstLI->getFunction()->hasFnAttribute(Attribute::SanitizeMemTag))
472 return false;
473 Type *ScalarTy = FirstLI->getType();
474 Value *Ptr0 = FirstLI->getPointerOperand();
475 LoadInst *LastLI = FirstLI;
476 for (auto [Lane, V] : enumerate(VL)) {
477 if (isa<UndefValue>(V))
478 continue;
479 auto *LI = dyn_cast<LoadInst>(V);
480 if (!LI || !LI->isSimple() || mustSuppressSpeculation(*LI))
481 return false;
482 std::optional<int64_t> Dist =
483 getPointersDiff(ScalarTy, Ptr0, ScalarTy, LI->getPointerOperand(), DL,
484 SE, /*StrictCheck=*/true);
485 if (!Dist || *Dist != static_cast<int64_t>(Lane) - FirstLane)
486 return false;
487 if (LastLI->comesBefore(LI))
488 LastLI = LI;
489 }
490 // The wide load starts before the first load, so check the range as the one
491 // starting at the underlying object.
492 const uint64_t EltSize = DL.getTypeAllocSize(ScalarTy).getFixedValue();
493 const unsigned BitWidth = DL.getIndexTypeSizeInBits(Ptr0->getType());
496 DL, Offset, /*AllowNonInbounds=*/true);
497 bool Overflow = false;
498 APInt Start = Offset.ssub_ov(APInt(BitWidth, FirstLane * EltSize), Overflow);
499 if (Overflow || Start.isNegative())
500 return false;
501 APInt End = Start.sadd_ov(APInt(BitWidth, VL.size() * EltSize), Overflow);
502 return !Overflow &&
504 Base, Align(1), End, SimplifyQuery(DL, &TLI, &DT, &AC, LastLI));
505}
506
508 const auto *It = find_if(Scalars, IsaPred<LoadInst>);
509 auto *LI = cast<LoadInst>(*It);
510 return std::distance(Scalars.begin(), It) *
511 LI->getDataLayout().getTypeAllocSize(LI->getType()).getFixedValue();
512}
513
514/// Checks if the stores \p VL with pointers \p PointerOps can be lowered as a
515/// single masked store. On success \p StoreVecTy is the widened store type and
516/// \p ReuseShuffleIndices is the expand mask that places each stored value at
517/// its element offset from the base (poison in the gaps).
519 ArrayRef<unsigned> Order,
520 const TargetTransformInfo &TTI, const DataLayout &DL,
521 ScalarEvolution &SE, Align CommonAlignment,
522 SmallVectorImpl<int> &ReuseShuffleIndices,
523 FixedVectorType *&StoreVecTy,
524 SLPAnalysisCache &Cache) {
525 Type *ScalarTy = cast<StoreInst>(VL.front())->getValueOperand()->getType();
526 const size_t Sz = VL.size();
527 // Only simple scalar element types are supported.
528 if (Sz < 2 || (!ScalarTy->isIntOrPtrTy() && !ScalarTy->isFloatingPointTy()))
529 return false;
530 Value *Ptr0 = Order.empty() ? PointerOps.front() : PointerOps[Order.front()];
531 Value *PtrN = Order.empty() ? PointerOps.back() : PointerOps[Order.back()];
532 std::optional<int64_t> Diff =
533 Cache.getPointersDiff(ScalarTy, Ptr0, ScalarTy, PtrN, DL, SE);
534 if (!Diff || *Diff <= 0)
535 return false;
536 // Avoid widened vectors with very large gaps between the stored elements.
537 const unsigned MaxRegSize =
539 .getFixedValue();
540 const unsigned ScalarBits = DL.getTypeSizeInBits(ScalarTy).getFixedValue();
541 if (ScalarBits == 0 ||
542 static_cast<uint64_t>(*Diff) / Sz >= MaxRegSize / ScalarBits)
543 return false;
544 StoreVecTy = cast<FixedVectorType>(getWidenedType(ScalarTy, *Diff + 1));
545 unsigned AS = cast<StoreInst>(VL.front())->getPointerAddressSpace();
546 if (!TTI.isLegalMaskedStore(StoreVecTy, CommonAlignment, AS,
548 return false;
549 // Build the expand mask: store I (in address-sorted order) is placed at its
550 // element offset from the base, other widened lanes are poison.
551 ReuseShuffleIndices.assign(*Diff + 1, PoisonMaskElem);
552 int64_t Prev = -1;
553 for (unsigned I : seq<unsigned>(Sz)) {
554 Value *Ptr = Order.empty() ? PointerOps[I] : PointerOps[Order[I]];
555 std::optional<int64_t> Off =
556 Cache.getPointersDiff(ScalarTy, Ptr0, ScalarTy, Ptr, DL, SE);
557 if (!Off || *Off <= Prev || *Off > *Diff)
558 return false;
559 ReuseShuffleIndices[*Off] = static_cast<int>(I);
560 Prev = *Off;
561 }
562 return true;
563}
564
566 Type *ElemTy, const DataLayout &DL,
567 ScalarEvolution &SE, unsigned MaxDepth,
568 SmallVectorImpl<unsigned> &SortedIndices,
569 SLPAnalysisCache &Cache) {
570 assert(
571 all_of(VL, [](const Value *V) { return V->getType()->isPointerTy(); }) &&
572 "Expected list of pointer operands.");
573 // Map from bases to a vector of (Ptr, Offset, OrigIdx), which we insert each
574 // Ptr into, sort and return the sorted indices with values next to one
575 // another.
577 std::pair<BasicBlock *, Value *>,
579 Bases;
580 Bases
581 .try_emplace(std::make_pair(BBs.front(),
582 getUnderlyingObject(VL.front(), MaxDepth)))
583 .first->second.emplace_back()
584 .emplace_back(VL.front(), 0U, 0U);
585
586 SortedIndices.clear();
587 for (auto [Cnt, Ptr] : enumerate(VL.drop_front())) {
588 auto Key = std::make_pair(BBs[Cnt + 1], getUnderlyingObject(Ptr, MaxDepth));
589 bool Found = any_of(Bases.try_emplace(Key).first->second,
590 [&, &Cnt = Cnt, &Ptr = Ptr](auto &Base) {
591 std::optional<int64_t> Diff = Cache.getPointersDiff(
592 ElemTy, std::get<0>(Base.front()), ElemTy, Ptr,
593 DL, SE, /*StrictCheck=*/true);
594 if (!Diff)
595 return false;
596
597 Base.emplace_back(Ptr, *Diff, Cnt + 1);
598 return true;
599 });
600
601 if (!Found) {
602 // If we haven't found enough to usefully cluster, return early.
603 if (Bases.size() > VL.size() / 2 - 1)
604 return false;
605
606 // Not found already - add a new Base
607 Bases.find(Key)->second.emplace_back().emplace_back(Ptr, 0, Cnt + 1);
608 }
609 }
610
611 if (Bases.size() == VL.size())
612 return false;
613
614 if (Bases.size() == 1 && (Bases.front().second.size() == 1 ||
615 Bases.front().second.size() == VL.size()))
616 return false;
617
618 // For each of the bases sort the pointers by Offset and check if any of the
619 // base become consecutively allocated.
620 auto ComparePointers = [MaxDepth](Value *Ptr1, Value *Ptr2) {
621 SmallPtrSet<Value *, 13> FirstPointers;
622 SmallPtrSet<Value *, 13> SecondPointers;
623 Value *P1 = Ptr1;
624 Value *P2 = Ptr2;
625 unsigned Depth = 0;
626 while (!FirstPointers.contains(P2) && !SecondPointers.contains(P1)) {
627 if (P1 == P2 || Depth > MaxDepth)
628 return false;
629 FirstPointers.insert(P1);
630 SecondPointers.insert(P2);
631 P1 = getUnderlyingObject(P1, /*MaxLookup=*/1);
632 P2 = getUnderlyingObject(P2, /*MaxLookup=*/1);
633 ++Depth;
634 }
635 assert((FirstPointers.contains(P2) || SecondPointers.contains(P1)) &&
636 "Unable to find matching root.");
637 return FirstPointers.contains(P2) && !SecondPointers.contains(P1);
638 };
639 for (auto &Base : Bases) {
640 for (auto &Vec : Base.second) {
641 if (Vec.size() > 1) {
643 int64_t InitialOffset = std::get<1>(Vec[0]);
644 bool AnyConsecutive =
645 all_of(enumerate(Vec), [InitialOffset](const auto &P) {
646 return std::get<1>(P.value()) ==
647 int64_t(P.index()) + InitialOffset;
648 });
649 // Fill SortedIndices array only if it looks worth-while to sort the
650 // ptrs.
651 if (!AnyConsecutive)
652 return false;
653 }
654 }
655 stable_sort(Base.second, [&](const auto &V1, const auto &V2) {
656 return ComparePointers(std::get<0>(V1.front()), std::get<0>(V2.front()));
657 });
658 }
659
660 for (auto &T : Bases)
661 for (const auto &Vec : T.second)
662 for (const auto &P : Vec)
663 SortedIndices.push_back(std::get<2>(P));
664
665 assert(SortedIndices.size() == VL.size() &&
666 "Expected SortedIndices to be the size of VL");
667 return true;
668}
669
670} // namespace llvm::slpvectorizer
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static MaybeAlign getAlign(Value *Ptr)
This file defines an InstructionCost class that is used when calculating the cost of an instruction,...
#define I(x, y, z)
Definition MD5.cpp:57
This file implements a map that provides insertion order iteration.
#define T
#define P(N)
This file contains some templates that are useful if you are working with the STL at all.
Provides some synthesis utilities to produce sequences of values.
This file defines the SmallPtrSet class.
This pass exposes codegen information to IR-level passes.
Class for arbitrary precision integers.
Definition APInt.h:78
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:230
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
const T & back() const
Get the last element.
Definition ArrayRef.h:150
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
Definition ArrayRef.h:194
const T & front() const
Get the first element.
Definition ArrayRef.h:144
size_t size() const
Get the array size.
Definition ArrayRef.h:141
iterator begin() const
Definition ArrayRef.h:129
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
const T & consume_front()
consume_front() - Returns the first element and drops it from ArrayRef.
Definition ArrayRef.h:156
A cache of @llvm.assume calls within a function.
This is the shared class of boolean and integer constants.
Definition Constants.h:87
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:122
Class to represent fixed width SIMD vectors.
Common base class shared among various IRBuilders.
Definition IRBuilder.h:111
LLVM_ABI bool comesBefore(const Instruction *Other) const
Given an instruction Other in the same basic block as this instruction, return true if this instructi...
An instruction for reading from memory.
Information for memory intrinsic cost model.
This class represents an analyzed expression in the program.
LLVM_ABI bool isZero() const
Return true if the expression is a constant zero.
LLVM_ABI bool isNonConstantNegative() const
Return true if the specified scev is negated, but not a constant.
Type * getType() const
Return the LLVM type of this SCEV expression.
The main scalar evolution driver.
LLVM_ABI const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEVFlags Flags=SCEV::FlagNone, unsigned Depth=0)
Return LHS-RHS.
LLVM_ABI const SCEV * getConstant(ConstantInt *V)
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI SCEVUse getAddExpr(SmallVectorImpl< SCEVUse > &Ops, SCEVFlagsPair Flags={}, unsigned Depth=0)
Get a canonical add expression, or something simpler if possible.
LLVM_ABI SCEVUse getMulExpr(SmallVectorImpl< SCEVUse > &Ops, SCEVFlagsPair Flags={}, unsigned Depth=0)
Get a canonical multiply expression, or something simpler if possible.
LLVM_ABI const SCEV * getUDivExactExpr(SCEVUse LHS, SCEVUse RHS)
Get a canonical unsigned division expression, or something simpler if possible.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void swap(SmallVectorImpl &RHS)
void resize(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Provides information about what library functions are available for the current target.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
static LLVM_ABI OperandValueInfo getOperandInfo(const Value *V)
Collect properties of V used in cost analysis, e.g. OP_PowerOf2.
TargetCostKind
The kind of cost model.
@ SK_PermuteSingleSrc
Shuffle elements of single source vector with any shuffle mask.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
Definition Type.h:186
bool isIntOrPtrTy() const
Return true if this is an integer type or a pointer type.
Definition Type.h:265
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI const Value * stripAndAccumulateConstantOffsets(const DataLayout &DL, APInt &Offset, bool AllowNonInbounds, bool AllowInvariantGroup=false, function_ref< bool(Value &Value, APInt &Offset)> ExternalAnalysis=nullptr, bool LookThroughIntToPtr=false) const
Accumulate the constant offset this value has compared to a base pointer.
Base class of all SIMD vector types.
An efficient, type-erasing, non-owning reference to a callable.
Caches the results of the expensive analyses that are queried repeatedly for the same values while th...
bool isGuaranteedNotToBePoison(const Value *V, AssumptionCache *AC)
Cached llvm::isGuaranteedNotToBePoison().
bool sortPtrAccesses(ArrayRef< Value * > VL, Type *ElemTy, const DataLayout &DL, ScalarEvolution &SE, SmallVectorImpl< unsigned > &SortedIndices)
llvm::sortPtrAccesses() with the cached pointer distances.
std::optional< int64_t > getPointersDiff(Type *ElemTyA, Value *PtrA, Type *ElemTyB, Value *PtrB, const DataLayout &DL, ScalarEvolution &SE, bool StrictCheck=false, bool CheckType=true)
Cached llvm::getPointersDiff(), a miss may require SCEV analysis.
A private "module" namespace for types and utilities used by this pass.
InstructionCost getShuffleCost(const TargetTransformInfo &TTI, TTI::ShuffleKind Kind, VectorType *Tp, const TTI::TargetCostKind CostKind, ArrayRef< int > Mask, int Index, VectorType *SubTp, ArrayRef< const Value * > Args, TTI::VectorInstrContext VIC)
Returns the cost of the shuffle instructions with the given Kind, vector type Tp and optional Mask.
template Align computeCommonAlignment< StoreInst >(ArrayRef< Value * >)
std::pair< InstructionCost, InstructionCost > getGEPCosts(const TargetTransformInfo &TTI, ArrayRef< Value * > Ptrs, Value *BasePtr, unsigned Opcode, const TTI::TargetCostKind CostKind, Type *ScalarTy, VectorType *VecTy)
Calculate the scalar and the vector costs from vectorizing set of GEPs.
bool clusterSortPtrAccesses(ArrayRef< Value * > VL, ArrayRef< BasicBlock * > BBs, Type *ElemTy, const DataLayout &DL, ScalarEvolution &SE, unsigned MaxDepth, SmallVectorImpl< unsigned > &SortedIndices, SLPAnalysisCache &Cache)
Clusters VL pointers by (basic block, underlying object) pair and sorts each cluster by offset.
void reorderScalars(SmallVectorImpl< Value * > &Scalars, ArrayRef< int > Mask)
Reorders the list of scalars in accordance with the given Mask.
Definition SLPUtils.cpp:333
Value * createWidenedStridedCast(IRBuilderBase &Builder, Value *V, Type *DstTy, const DataLayout &DL)
Casts V between the widened strided access type and the entry vector type DstTy.
Align computeCommonAlignment(ArrayRef< Value * > VL)
Calculates minimal alignment as a common alignment.
template Align computeCommonAlignment< LoadInst >(ArrayRef< Value * >)
unsigned getNumElements(Type *Ty)
Definition SLPUtils.cpp:110
const SCEV * calculateRtStride(ArrayRef< Value * > PointerOps, Type *ElemTy, const DataLayout &DL, ScalarEvolution &SE, SmallVectorImpl< unsigned > &SortedIndices)
Checks if the provided list of pointers Pointers represents the strided pointers for type ElemTy.
Type * getWidenedType(Type *ScalarTy, unsigned VF)
ConstantInt * getStrideBytesIfConstant(Value *Stride, Type *ScalarTy, const DataLayout &DL, bool IsReverse)
Returns Stride scaled by the allocation size of ScalarTy, negated if IsReverse is set,...
void transformScalarShuffleIndiciesToVector(unsigned VecTyNumElements, SmallVectorImpl< int > &Mask)
Definition SLPUtils.cpp:513
bool isMaskedStoreCompress(ArrayRef< Value * > VL, ArrayRef< Value * > PointerOps, ArrayRef< unsigned > Order, const TargetTransformInfo &TTI, const DataLayout &DL, ScalarEvolution &SE, Align CommonAlignment, SmallVectorImpl< int > &ReuseShuffleIndices, FixedVectorType *&StoreVecTy, SLPAnalysisCache &Cache)
Checks if the stores VL with pointers PointerOps can be lowered as a single masked store.
void inversePermutation(ArrayRef< unsigned > Indices, SmallVectorImpl< int > &Mask)
Compute the inverse permutation Mask of Indices.
Definition SLPUtils.cpp:324
uint64_t getVectorLoadShift(ArrayRef< Value * > Scalars)
Returns the distance in bytes from the start of the vector load to the first load of Scalars: the lea...
bool canWidenLoadsOverUndefLanes(ArrayRef< Value * > VL, const DataLayout &DL, ScalarEvolution &SE, AssumptionCache &AC, const DominatorTree &DT, const TargetLibraryInfo &TLI)
Checks if the simple loads of VL, mixed with the undef and poison lanes, can be replaced by a single ...
InstructionCost getScalarizationOverhead(const TargetTransformInfo &TTI, bool ReVec, Type *ScalarTy, VectorType *Ty, const APInt &DemandedElts, bool Insert, bool Extract, const TTI::TargetCostKind CostKind, bool ForPoisonSrc, ArrayRef< Value * > VL, TTI::VectorInstrContext VIC)
This is similar to TargetTransformInfo::getScalarizationOverhead, but if ScalarTy is a FixedVectorTyp...
InstructionsState getSameOpcode(ArrayRef< Value * > VL, const TargetLibraryInfo &TLI)
bool isMaskedLoadCompress(ArrayRef< Value * > VL, ArrayRef< Value * > PointerOps, ArrayRef< unsigned > Order, const TargetTransformInfo &TTI, const DataLayout &DL, ScalarEvolution &SE, AssumptionCache &AC, const DominatorTree &DT, const TargetLibraryInfo &TLI, const TargetTransformInfo::TargetCostKind CostKind, const function_ref< bool(Value *)> AreAllUsersVectorized, bool ReVec, bool &IsMasked, unsigned &InterleaveFactor, SmallVectorImpl< int > &CompressMask, VectorType *&LoadVecTy, SLPAnalysisCache &Cache)
Checks if the VL can be transformed to a (masked)load + compress or (masked) interleaved load.
static bool buildCompressMask(ArrayRef< Value * > PointerOps, ArrayRef< unsigned > Order, Type *ScalarTy, const DataLayout &DL, ScalarEvolution &SE, SmallVectorImpl< int > &CompressMask, SLPAnalysisCache &Cache)
Builds compress-like mask for shuffles for the given PointerOps, ordered with Order.
bool arePointersCompatible(Value *Ptr1, Value *Ptr2, const TargetLibraryInfo &TLI, unsigned MaxDepth, bool CompareOpcodes)
MaxDepth is the recursion limit for getUnderlyingObject.
bool isConstant(Value *V)
Definition SLPUtils.cpp:47
unsigned getFullVectorNumberOfElements(const TargetTransformInfo &TTI, Type *Ty, unsigned Sz, bool ReVec)
Returns the number of elements of the given type Ty, not less than Sz, which forms type,...
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
@ Offset
Definition DWP.cpp:577
void stable_sort(R &&Range)
Definition STLExtras.h:2132
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2570
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
auto accumulate(R &&Range, E &&Init)
Wrapper for std::accumulate.
Definition STLExtras.h:1718
LLVM_ABI bool mustSuppressSpeculation(const LoadInst &LI)
Return true if speculation of the given load must be suppressed to avoid ordering or interfering with...
Definition Loads.cpp:452
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
LLVM_ABI std::optional< int64_t > getPointersDiff(Type *ElemTyA, Value *PtrA, Type *ElemTyB, Value *PtrB, const DataLayout &DL, ScalarEvolution &SE, bool StrictCheck=false, bool CheckType=true)
Returns the distance between the pointers PtrA and PtrB iff they are compatible and it is possible to...
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth, bool MustPreserveProvenance=false)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
constexpr int PoisonMaskElem
TargetTransformInfo TTI
LLVM_ABI bool isSafeToLoadUnconditionally(Value *V, Align Alignment, const APInt &Size, const SimplifyQuery &SQ, bool IgnoreFree=false)
Return true if we know that executing a load from this value cannot trap.
Definition Loads.cpp:456
LLVM_ABI bool isDereferenceableAndAlignedPointer(const Value *V, Type *Ty, Align Alignment, const SimplifyQuery &Q, bool IgnoreFree=false)
Returns true if V is always a dereferenceable pointer with alignment greater or equal than requested.
Definition Loads.cpp:246
constexpr unsigned BitWidth
auto count_if(R &&Range, UnaryPredicate P)
Wrapper function around std::count_if to count the number of times an element satisfying a given pred...
Definition STLExtras.h:2035
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1788
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:341
LLVM_ABI bool isGuaranteedNotToBePoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Returns true if V cannot be poison, but may be undef.
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
constexpr detail::IsaCheckPredicate< Types... > IsaPred
Function object wrapper for the llvm::isa type check.
Definition Casting.h:866
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
A MapVector that performs no allocations if smaller than a certain size.
Definition MapVector.h:342
Function object to check whether the first component of a container supported by std::get (like std::...
Definition STLExtras.h:1455
Function object to check whether the second component of a container supported by std::get (like std:...
Definition STLExtras.h:1464