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