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
225 AssumptionCache *AC) {
226 auto [It, Inserted] = NotPoisonCache.try_emplace(V, false);
227 if (Inserted)
228 It->second = llvm::isGuaranteedNotToBePoison(V, AC);
229 return It->second;
230}
231
232/// Builds compress-like mask for shuffles for the given \p PointerOps, ordered
233/// with \p Order.
234/// \return true if the mask represents strided access, false - otherwise.
236 ArrayRef<unsigned> Order, Type *ScalarTy,
237 const DataLayout &DL, ScalarEvolution &SE,
238 SmallVectorImpl<int> &CompressMask,
239 SLPAnalysisCache &Cache) {
240 const unsigned Sz = PointerOps.size();
241 CompressMask.assign(Sz, PoisonMaskElem);
242 // The first element always set.
243 CompressMask[0] = 0;
244 // Check if the mask represents strided access.
245 std::optional<unsigned> Stride = 0;
246 Value *Ptr0 = Order.empty() ? PointerOps.front() : PointerOps[Order.front()];
247 for (unsigned I : seq<unsigned>(1, Sz)) {
248 Value *Ptr = Order.empty() ? PointerOps[I] : PointerOps[Order[I]];
249 std::optional<int64_t> OptPos =
250 Cache.getPointersDiff(ScalarTy, Ptr0, ScalarTy, Ptr, DL, SE);
251 if (!OptPos || OptPos > std::numeric_limits<unsigned>::max())
252 return false;
253 unsigned Pos = static_cast<unsigned>(*OptPos);
254 CompressMask[I] = Pos;
255 if (!Stride)
256 continue;
257 if (*Stride == 0) {
258 *Stride = Pos;
259 continue;
260 }
261 if (Pos != *Stride * I)
262 Stride.reset();
263 }
264 return Stride.has_value();
265}
266
267/// Checks if the \p VL can be transformed to a (masked)load + compress or
268/// (masked) interleaved load.
273 const DominatorTree &DT, const TargetLibraryInfo &TLI,
275 const function_ref<bool(Value *)> AreAllUsersVectorized, bool ReVec,
276 bool &IsMasked, unsigned &InterleaveFactor,
277 SmallVectorImpl<int> &CompressMask, VectorType *&LoadVecTy,
278 SLPAnalysisCache &Cache) {
279 InterleaveFactor = 0;
280 Type *ScalarTy = VL.front()->getType();
281 const size_t Sz = VL.size();
282 auto *VecTy = cast<VectorType>(getWidenedType(ScalarTy, Sz));
283 SmallVector<int> Mask;
284 if (!Order.empty())
285 inversePermutation(Order, Mask);
286 // Check external uses.
287 for (const auto [I, V] : enumerate(VL)) {
288 if (AreAllUsersVectorized(V))
289 continue;
290 InstructionCost ExtractCost =
291 TTI.getVectorInstrCost(Instruction::ExtractElement, VecTy, CostKind,
292 Mask.empty() ? I : Mask[I]);
293 InstructionCost ScalarCost =
294 TTI.getInstructionCost(cast<Instruction>(V), CostKind);
295 if (ExtractCost <= ScalarCost)
296 return false;
297 }
298 Value *Ptr0;
299 Value *PtrN;
300 if (Order.empty()) {
301 Ptr0 = PointerOps.front();
302 PtrN = PointerOps.back();
303 } else {
304 Ptr0 = PointerOps[Order.front()];
305 PtrN = PointerOps[Order.back()];
306 }
307 std::optional<int64_t> Diff =
308 Cache.getPointersDiff(ScalarTy, Ptr0, ScalarTy, PtrN, DL, SE);
309 if (!Diff)
310 return false;
311 const size_t MaxRegSize =
313 .getFixedValue();
314 // Check for very large distances between elements.
315 if (*Diff / Sz >= MaxRegSize / 8)
316 return false;
317 LoadVecTy = cast<FixedVectorType>(getWidenedType(ScalarTy, *Diff + 1));
318 auto *LI = cast<LoadInst>(Order.empty() ? VL.front() : VL[Order.front()]);
319 Align CommonAlignment = LI->getAlign();
320 SimplifyQuery SQ(
321 DL, &TLI, &DT, &AC,
322 cast<LoadInst>(Order.empty() ? VL.back() : VL[Order.back()]));
323 IsMasked = !isSafeToLoadUnconditionally(Ptr0, LoadVecTy, CommonAlignment, SQ);
324 if (IsMasked && !TTI.isLegalMaskedLoad(LoadVecTy, CommonAlignment,
325 LI->getPointerAddressSpace()))
326 return false;
327 // TODO: perform the analysis of each scalar load for better
328 // safe-load-unconditionally analysis.
329 bool IsStrided = buildCompressMask(PointerOps, Order, ScalarTy, DL, SE,
330 CompressMask, Cache);
331 assert(CompressMask.size() >= 2 && "At least two elements are required");
332 SmallVector<Value *> OrderedPointerOps(PointerOps);
333 if (!Order.empty())
334 reorderScalars(OrderedPointerOps, Mask);
335 auto [ScalarGEPCost, VectorGEPCost] =
336 getGEPCosts(TTI, OrderedPointerOps, OrderedPointerOps.front(),
337 Instruction::Load, CostKind, ScalarTy, LoadVecTy);
338 // The cost of scalar loads.
339 InstructionCost ScalarLoadsCost =
341 [&](InstructionCost C, Value *V) {
342 return C + TTI.getInstructionCost(cast<Instruction>(V),
343 CostKind);
344 }) +
345 ScalarGEPCost;
346 APInt DemandedElts = APInt::getAllOnes(Sz);
347 InstructionCost GatherCost =
348 getScalarizationOverhead(TTI, ReVec, ScalarTy, VecTy, DemandedElts,
349 /*Insert=*/true,
350 /*Extract=*/false, CostKind) +
351 ScalarLoadsCost;
352 InstructionCost LoadCost = 0;
353 if (IsMasked) {
354 LoadCost = TTI.getMemIntrinsicInstrCost(
355 MemIntrinsicCostAttributes(Intrinsic::masked_load, LoadVecTy,
356 CommonAlignment,
357 LI->getPointerAddressSpace()),
358 CostKind);
359 } else {
360 LoadCost =
361 TTI.getMemoryOpCost(Instruction::Load, LoadVecTy, CommonAlignment,
362 LI->getPointerAddressSpace(), CostKind,
363 TTI::getOperandInfo(LI->getPointerOperand()));
364 }
365 if (IsStrided && !IsMasked && Order.empty()) {
366 // Check for potential segmented(interleaved) loads.
367 VectorType *AlignedLoadVecTy = cast<VectorType>(getWidenedType(
368 ScalarTy,
369 getFullVectorNumberOfElements(TTI, ScalarTy, *Diff + 1, ReVec)));
370 SimplifyQuery SQ(DL, &TLI, &DT, &AC, cast<LoadInst>(VL.back()));
371 if (!isSafeToLoadUnconditionally(Ptr0, AlignedLoadVecTy, CommonAlignment,
372 SQ))
373 AlignedLoadVecTy = LoadVecTy;
374 if (TTI.isLegalInterleavedAccessType(AlignedLoadVecTy, CompressMask[1],
375 CommonAlignment,
376 LI->getPointerAddressSpace())) {
377 InstructionCost InterleavedCost =
378 VectorGEPCost + TTI.getInterleavedMemoryOpCost(
379 Instruction::Load, AlignedLoadVecTy,
380 CompressMask[1], {}, CommonAlignment,
381 LI->getPointerAddressSpace(), CostKind, IsMasked);
382 if (InterleavedCost < GatherCost) {
383 InterleaveFactor = CompressMask[1];
384 LoadVecTy = AlignedLoadVecTy;
385 return true;
386 }
387 }
388 }
389 // Estimating the compression shuffle cost below can be extremely expensive
390 // for a very wide LoadVecTy, which is split into a large number of vector
391 // registers (see processShuffleMasks). The shuffle cost is always
392 // non-negative, so if the load cost alone already reaches the gather cost the
393 // masked-load-compress cannot be profitable. Bail out before the costly
394 // shuffle cost estimation in that case.
395 if (VectorGEPCost + LoadCost >= GatherCost)
396 return false;
397 // For REVEC the scalars are vectors, and the emitted shuffle uses the
398 // compress mask expanded to the individual elements. Cost that mask.
399 SmallVector<int> CostMask(CompressMask.begin(), CompressMask.end());
402 LoadVecTy, CostKind, CostMask);
403 if (!Order.empty()) {
404 SmallVector<int> NewMask(Sz, PoisonMaskElem);
405 for (unsigned I : seq<unsigned>(Sz)) {
406 NewMask[I] = CompressMask[Mask[I]];
407 }
408 CompressMask.swap(NewMask);
409 }
410 InstructionCost TotalVecCost = VectorGEPCost + LoadCost + CompressCost;
411 return TotalVecCost < GatherCost;
412}
413
414/// Checks if the \p VL can be transformed to a (masked)load + compress or
415/// (masked) interleaved load.
420 const DominatorTree &DT, const TargetLibraryInfo &TLI,
422 const function_ref<bool(Value *)> AreAllUsersVectorized, bool ReVec,
423 SLPAnalysisCache &Cache) {
424 bool IsMasked;
425 unsigned InterleaveFactor;
426 SmallVector<int> CompressMask;
427 VectorType *LoadVecTy;
428 return isMaskedLoadCompress(VL, PointerOps, Order, TTI, DL, SE, AC, DT, TLI,
429 CostKind, AreAllUsersVectorized, ReVec, IsMasked,
430 InterleaveFactor, CompressMask, LoadVecTy, Cache);
431}
432
435 const DominatorTree &DT,
436 const TargetLibraryInfo &TLI) {
437 if (count_if(VL, IsaPred<LoadInst>) < 2)
438 return false;
439 const auto *FirstIt = find_if(VL, IsaPred<LoadInst>);
440 const unsigned FirstLane = std::distance(VL.begin(), FirstIt);
441 auto *FirstLI = cast<LoadInst>(*FirstIt);
442 // The wide load may read the memory with a different tag.
443 if (FirstLI->getFunction()->hasFnAttribute(Attribute::SanitizeMemTag))
444 return false;
445 Type *ScalarTy = FirstLI->getType();
446 Value *Ptr0 = FirstLI->getPointerOperand();
447 LoadInst *LastLI = FirstLI;
448 for (auto [Lane, V] : enumerate(VL)) {
449 if (isa<UndefValue>(V))
450 continue;
451 auto *LI = dyn_cast<LoadInst>(V);
452 if (!LI || !LI->isSimple() || mustSuppressSpeculation(*LI))
453 return false;
454 std::optional<int64_t> Dist =
455 getPointersDiff(ScalarTy, Ptr0, ScalarTy, LI->getPointerOperand(), DL,
456 SE, /*StrictCheck=*/true);
457 if (!Dist || *Dist != static_cast<int64_t>(Lane) - FirstLane)
458 return false;
459 if (LastLI->comesBefore(LI))
460 LastLI = LI;
461 }
462 // The wide load starts before the first load, so check the range as the one
463 // starting at the underlying object.
464 const uint64_t EltSize = DL.getTypeAllocSize(ScalarTy).getFixedValue();
465 const unsigned BitWidth = DL.getIndexTypeSizeInBits(Ptr0->getType());
468 DL, Offset, /*AllowNonInbounds=*/true);
469 bool Overflow = false;
470 APInt Start = Offset.ssub_ov(APInt(BitWidth, FirstLane * EltSize), Overflow);
471 if (Overflow || Start.isNegative())
472 return false;
473 APInt End = Start.sadd_ov(APInt(BitWidth, VL.size() * EltSize), Overflow);
474 return !Overflow &&
476 Base, Align(1), End, SimplifyQuery(DL, &TLI, &DT, &AC, LastLI));
477}
478
480 const auto *It = find_if(Scalars, IsaPred<LoadInst>);
481 auto *LI = cast<LoadInst>(*It);
482 return std::distance(Scalars.begin(), It) *
483 LI->getDataLayout().getTypeAllocSize(LI->getType()).getFixedValue();
484}
485
486/// Checks if the stores \p VL with pointers \p PointerOps can be lowered as a
487/// single masked store. On success \p StoreVecTy is the widened store type and
488/// \p ReuseShuffleIndices is the expand mask that places each stored value at
489/// its element offset from the base (poison in the gaps).
491 ArrayRef<unsigned> Order,
492 const TargetTransformInfo &TTI, const DataLayout &DL,
493 ScalarEvolution &SE, Align CommonAlignment,
494 SmallVectorImpl<int> &ReuseShuffleIndices,
495 FixedVectorType *&StoreVecTy,
496 SLPAnalysisCache &Cache) {
497 Type *ScalarTy = cast<StoreInst>(VL.front())->getValueOperand()->getType();
498 const size_t Sz = VL.size();
499 // Only simple scalar element types are supported.
500 if (Sz < 2 || (!ScalarTy->isIntOrPtrTy() && !ScalarTy->isFloatingPointTy()))
501 return false;
502 Value *Ptr0 = Order.empty() ? PointerOps.front() : PointerOps[Order.front()];
503 Value *PtrN = Order.empty() ? PointerOps.back() : PointerOps[Order.back()];
504 std::optional<int64_t> Diff =
505 Cache.getPointersDiff(ScalarTy, Ptr0, ScalarTy, PtrN, DL, SE);
506 if (!Diff || *Diff <= 0)
507 return false;
508 // Avoid widened vectors with very large gaps between the stored elements.
509 const unsigned MaxRegSize =
511 .getFixedValue();
512 const unsigned ScalarBits = DL.getTypeSizeInBits(ScalarTy).getFixedValue();
513 if (ScalarBits == 0 ||
514 static_cast<uint64_t>(*Diff) / Sz >= MaxRegSize / ScalarBits)
515 return false;
516 StoreVecTy = cast<FixedVectorType>(getWidenedType(ScalarTy, *Diff + 1));
517 unsigned AS = cast<StoreInst>(VL.front())->getPointerAddressSpace();
518 if (!TTI.isLegalMaskedStore(StoreVecTy, CommonAlignment, AS,
520 return false;
521 // Build the expand mask: store I (in address-sorted order) is placed at its
522 // element offset from the base, other widened lanes are poison.
523 ReuseShuffleIndices.assign(*Diff + 1, PoisonMaskElem);
524 int64_t Prev = -1;
525 for (unsigned I : seq<unsigned>(Sz)) {
526 Value *Ptr = Order.empty() ? PointerOps[I] : PointerOps[Order[I]];
527 std::optional<int64_t> Off =
528 Cache.getPointersDiff(ScalarTy, Ptr0, ScalarTy, Ptr, DL, SE);
529 if (!Off || *Off <= Prev || *Off > *Diff)
530 return false;
531 ReuseShuffleIndices[*Off] = static_cast<int>(I);
532 Prev = *Off;
533 }
534 return true;
535}
536
538 Type *ElemTy, const DataLayout &DL,
539 ScalarEvolution &SE, unsigned MaxDepth,
540 SmallVectorImpl<unsigned> &SortedIndices,
541 SLPAnalysisCache &Cache) {
542 assert(
543 all_of(VL, [](const Value *V) { return V->getType()->isPointerTy(); }) &&
544 "Expected list of pointer operands.");
545 // Map from bases to a vector of (Ptr, Offset, OrigIdx), which we insert each
546 // Ptr into, sort and return the sorted indices with values next to one
547 // another.
549 std::pair<BasicBlock *, Value *>,
551 Bases;
552 Bases
553 .try_emplace(std::make_pair(BBs.front(),
554 getUnderlyingObject(VL.front(), MaxDepth)))
555 .first->second.emplace_back()
556 .emplace_back(VL.front(), 0U, 0U);
557
558 SortedIndices.clear();
559 for (auto [Cnt, Ptr] : enumerate(VL.drop_front())) {
560 auto Key = std::make_pair(BBs[Cnt + 1], getUnderlyingObject(Ptr, MaxDepth));
561 bool Found = any_of(Bases.try_emplace(Key).first->second,
562 [&, &Cnt = Cnt, &Ptr = Ptr](auto &Base) {
563 std::optional<int64_t> Diff = Cache.getPointersDiff(
564 ElemTy, std::get<0>(Base.front()), ElemTy, Ptr,
565 DL, SE, /*StrictCheck=*/true);
566 if (!Diff)
567 return false;
568
569 Base.emplace_back(Ptr, *Diff, Cnt + 1);
570 return true;
571 });
572
573 if (!Found) {
574 // If we haven't found enough to usefully cluster, return early.
575 if (Bases.size() > VL.size() / 2 - 1)
576 return false;
577
578 // Not found already - add a new Base
579 Bases.find(Key)->second.emplace_back().emplace_back(Ptr, 0, Cnt + 1);
580 }
581 }
582
583 if (Bases.size() == VL.size())
584 return false;
585
586 if (Bases.size() == 1 && (Bases.front().second.size() == 1 ||
587 Bases.front().second.size() == VL.size()))
588 return false;
589
590 // For each of the bases sort the pointers by Offset and check if any of the
591 // base become consecutively allocated.
592 auto ComparePointers = [MaxDepth](Value *Ptr1, Value *Ptr2) {
593 SmallPtrSet<Value *, 13> FirstPointers;
594 SmallPtrSet<Value *, 13> SecondPointers;
595 Value *P1 = Ptr1;
596 Value *P2 = Ptr2;
597 unsigned Depth = 0;
598 while (!FirstPointers.contains(P2) && !SecondPointers.contains(P1)) {
599 if (P1 == P2 || Depth > MaxDepth)
600 return false;
601 FirstPointers.insert(P1);
602 SecondPointers.insert(P2);
603 P1 = getUnderlyingObject(P1, /*MaxLookup=*/1);
604 P2 = getUnderlyingObject(P2, /*MaxLookup=*/1);
605 ++Depth;
606 }
607 assert((FirstPointers.contains(P2) || SecondPointers.contains(P1)) &&
608 "Unable to find matching root.");
609 return FirstPointers.contains(P2) && !SecondPointers.contains(P1);
610 };
611 for (auto &Base : Bases) {
612 for (auto &Vec : Base.second) {
613 if (Vec.size() > 1) {
615 int64_t InitialOffset = std::get<1>(Vec[0]);
616 bool AnyConsecutive =
617 all_of(enumerate(Vec), [InitialOffset](const auto &P) {
618 return std::get<1>(P.value()) ==
619 int64_t(P.index()) + InitialOffset;
620 });
621 // Fill SortedIndices array only if it looks worth-while to sort the
622 // ptrs.
623 if (!AnyConsecutive)
624 return false;
625 }
626 }
627 stable_sort(Base.second, [&](const auto &V1, const auto &V2) {
628 return ComparePointers(std::get<0>(V1.front()), std::get<0>(V2.front()));
629 });
630 }
631
632 for (auto &T : Bases)
633 for (const auto &Vec : T.second)
634 for (const auto &P : Vec)
635 SortedIndices.push_back(std::get<2>(P));
636
637 assert(SortedIndices.size() == VL.size() &&
638 "Expected SortedIndices to be the size of VL");
639 return true;
640}
641
642} // 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 cl::opt< OutputCostKind > CostKind("cost-kind", cl::desc("Target cost kind"), cl::init(OutputCostKind::RecipThroughput), cl::values(clEnumValN(OutputCostKind::RecipThroughput, "throughput", "Reciprocal throughput"), clEnumValN(OutputCostKind::Latency, "latency", "Instruction latency"), clEnumValN(OutputCostKind::CodeSize, "code-size", "Code size"), clEnumValN(OutputCostKind::SizeAndLatency, "size-latency", "Code size and latency"), clEnumValN(OutputCostKind::All, "all", "Print all cost kinds")))
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().
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:514
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.
@ 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:448
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:452
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:244
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:267
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