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/DataLayout.h"
29#include "llvm/IR/Intrinsics.h"
31
32#include <algorithm>
33#include <limits>
34#include <optional>
35#include <set>
36#include <tuple>
37#include <utility>
38
39using namespace llvm;
40
41namespace llvm::slpvectorizer {
42
44 const TargetLibraryInfo &TLI, unsigned MaxDepth,
45 bool CompareOpcodes) {
46 if (getUnderlyingObject(Ptr1, MaxDepth) !=
47 getUnderlyingObject(Ptr2, MaxDepth))
48 return false;
49 auto *GEP1 = dyn_cast<GetElementPtrInst>(Ptr1);
50 auto *GEP2 = dyn_cast<GetElementPtrInst>(Ptr2);
51 return (!GEP1 || GEP1->getNumOperands() == 2) &&
52 (!GEP2 || GEP2->getNumOperands() == 2) &&
53 (((!GEP1 || isConstant(GEP1->getOperand(1))) &&
54 (!GEP2 || isConstant(GEP2->getOperand(1)))) ||
55 !CompareOpcodes ||
56 (GEP1 && GEP2 &&
57 getSameOpcode({GEP1->getOperand(1), GEP2->getOperand(1)}, TLI)));
58}
59
60/// Calculates minimal alignment as a common alignment.
62 Align CommonAlignment = cast<T>(VL.consume_front())->getAlign();
63 for (Value *V : VL)
64 CommonAlignment = std::min(CommonAlignment, cast<T>(V)->getAlign());
65 return CommonAlignment;
66}
67
70
72 const DataLayout &DL, ScalarEvolution &SE,
73 SmallVectorImpl<unsigned> &SortedIndices) {
75 const SCEV *PtrSCEVLowest = nullptr;
76 const SCEV *PtrSCEVHighest = nullptr;
77 // Find lower/upper pointers from the PointerOps (i.e. with lowest and highest
78 // addresses).
79 for (Value *Ptr : PointerOps) {
80 const SCEV *PtrSCEV = SE.getSCEV(Ptr);
81 if (!PtrSCEV)
82 return nullptr;
83 SCEVs.push_back(PtrSCEV);
84 if (!PtrSCEVLowest && !PtrSCEVHighest) {
85 PtrSCEVLowest = PtrSCEVHighest = PtrSCEV;
86 continue;
87 }
88 const SCEV *Diff = SE.getMinusSCEV(PtrSCEV, PtrSCEVLowest);
90 return nullptr;
91 if (Diff->isNonConstantNegative()) {
92 PtrSCEVLowest = PtrSCEV;
93 continue;
94 }
95 const SCEV *Diff1 = SE.getMinusSCEV(PtrSCEVHighest, PtrSCEV);
96 if (isa<SCEVCouldNotCompute>(Diff1))
97 return nullptr;
98 if (Diff1->isNonConstantNegative()) {
99 PtrSCEVHighest = PtrSCEV;
100 continue;
101 }
102 }
103 // Dist = PtrSCEVHighest - PtrSCEVLowest;
104 const SCEV *Dist = SE.getMinusSCEV(PtrSCEVHighest, PtrSCEVLowest);
105 if (isa<SCEVCouldNotCompute>(Dist))
106 return nullptr;
107 int Size = DL.getTypeStoreSize(ElemTy);
108 auto TryGetStride = [&](const SCEV *Dist,
109 const SCEV *Multiplier) -> const SCEV * {
110 if (const auto *M = dyn_cast<SCEVMulExpr>(Dist)) {
111 if (M->getOperand(0) == Multiplier)
112 return M->getOperand(1);
113 if (M->getOperand(1) == Multiplier)
114 return M->getOperand(0);
115 return nullptr;
116 }
117 if (Multiplier == Dist)
118 return SE.getConstant(Dist->getType(), 1);
119 return SE.getUDivExactExpr(Dist, Multiplier);
120 };
121 // Stride_in_elements = Dist / element_size * (num_elems - 1).
122 const SCEV *Stride = nullptr;
123 if (Size != 1 || SCEVs.size() > 1) {
124 const SCEV *Sz = SE.getConstant(Dist->getType(), Size * (SCEVs.size() - 1));
125 Stride = TryGetStride(Dist, Sz);
126 if (!Stride)
127 return nullptr;
128 }
129 if (!Stride || isa<SCEVConstant>(Stride))
130 return nullptr;
131 // Iterate through all pointers and check if all distances are
132 // unique multiple of Stride.
133 using DistOrdPair = std::pair<int64_t, int>;
134 auto Compare = llvm::less_first();
135 std::set<DistOrdPair, decltype(Compare)> Offsets(Compare);
136 bool IsConsecutive = true;
137 for (const auto [Idx, PtrSCEV] : enumerate(SCEVs)) {
138 unsigned Dist = 0;
139 if (PtrSCEV != PtrSCEVLowest) {
140 const SCEV *Diff = SE.getMinusSCEV(PtrSCEV, PtrSCEVLowest);
141 const SCEV *Coeff = TryGetStride(Diff, Stride);
142 if (!Coeff)
143 return nullptr;
144 const auto *SC = dyn_cast<SCEVConstant>(Coeff);
145 if (!SC || isa<SCEVCouldNotCompute>(SC))
146 return nullptr;
147 if (!SE.getMinusSCEV(PtrSCEV, SE.getAddExpr(PtrSCEVLowest,
148 SE.getMulExpr(Stride, SC)))
149 ->isZero())
150 return nullptr;
151 Dist = SC->getAPInt().getZExtValue();
152 }
153 // If the strides are not the same or repeated, we can't vectorize.
154 if ((Dist / Size) * Size != Dist || (Dist / Size) >= SCEVs.size())
155 return nullptr;
156 auto Res = Offsets.emplace(Dist, Idx);
157 if (!Res.second)
158 return nullptr;
159 // Consecutive order if the inserted element is the last one.
160 IsConsecutive = IsConsecutive && std::next(Res.first) == Offsets.end();
161 }
162 SortedIndices.clear();
163 if (!IsConsecutive) {
164 // Fill SortedIndices array only if it is non-consecutive.
165 SortedIndices.resize(PointerOps.size());
166 for (const auto [Idx, Pair] : enumerate(Offsets))
167 SortedIndices[Idx] = Pair.second;
168 }
169 return Stride;
170}
171
172/// Builds compress-like mask for shuffles for the given \p PointerOps, ordered
173/// with \p Order.
174/// \return true if the mask represents strided access, false - otherwise.
176 ArrayRef<unsigned> Order, Type *ScalarTy,
177 const DataLayout &DL, ScalarEvolution &SE,
178 SmallVectorImpl<int> &CompressMask) {
179 const unsigned Sz = PointerOps.size();
180 CompressMask.assign(Sz, PoisonMaskElem);
181 // The first element always set.
182 CompressMask[0] = 0;
183 // Check if the mask represents strided access.
184 std::optional<unsigned> Stride = 0;
185 Value *Ptr0 = Order.empty() ? PointerOps.front() : PointerOps[Order.front()];
186 for (unsigned I : seq<unsigned>(1, Sz)) {
187 Value *Ptr = Order.empty() ? PointerOps[I] : PointerOps[Order[I]];
188 std::optional<int64_t> OptPos =
189 getPointersDiff(ScalarTy, Ptr0, ScalarTy, Ptr, DL, SE);
190 if (!OptPos || OptPos > std::numeric_limits<unsigned>::max())
191 return false;
192 unsigned Pos = static_cast<unsigned>(*OptPos);
193 CompressMask[I] = Pos;
194 if (!Stride)
195 continue;
196 if (*Stride == 0) {
197 *Stride = Pos;
198 continue;
199 }
200 if (Pos != *Stride * I)
201 Stride.reset();
202 }
203 return Stride.has_value();
204}
205
206/// Checks if the \p VL can be transformed to a (masked)load + compress or
207/// (masked) interleaved load.
212 const DominatorTree &DT, const TargetLibraryInfo &TLI,
214 const function_ref<bool(Value *)> AreAllUsersVectorized, bool ReVec,
215 bool &IsMasked, unsigned &InterleaveFactor,
216 SmallVectorImpl<int> &CompressMask, VectorType *&LoadVecTy) {
217 InterleaveFactor = 0;
218 Type *ScalarTy = VL.front()->getType();
219 const size_t Sz = VL.size();
220 auto *VecTy = cast<VectorType>(getWidenedType(ScalarTy, Sz));
221 SmallVector<int> Mask;
222 if (!Order.empty())
223 inversePermutation(Order, Mask);
224 // Check external uses.
225 for (const auto [I, V] : enumerate(VL)) {
226 if (AreAllUsersVectorized(V))
227 continue;
228 InstructionCost ExtractCost =
229 TTI.getVectorInstrCost(Instruction::ExtractElement, VecTy, CostKind,
230 Mask.empty() ? I : Mask[I]);
231 InstructionCost ScalarCost =
232 TTI.getInstructionCost(cast<Instruction>(V), CostKind);
233 if (ExtractCost <= ScalarCost)
234 return false;
235 }
236 Value *Ptr0;
237 Value *PtrN;
238 if (Order.empty()) {
239 Ptr0 = PointerOps.front();
240 PtrN = PointerOps.back();
241 } else {
242 Ptr0 = PointerOps[Order.front()];
243 PtrN = PointerOps[Order.back()];
244 }
245 std::optional<int64_t> Diff =
246 getPointersDiff(ScalarTy, Ptr0, ScalarTy, PtrN, DL, SE);
247 if (!Diff)
248 return false;
249 const size_t MaxRegSize =
251 .getFixedValue();
252 // Check for very large distances between elements.
253 if (*Diff / Sz >= MaxRegSize / 8)
254 return false;
255 LoadVecTy = cast<FixedVectorType>(getWidenedType(ScalarTy, *Diff + 1));
256 auto *LI = cast<LoadInst>(Order.empty() ? VL.front() : VL[Order.front()]);
257 Align CommonAlignment = LI->getAlign();
258 SimplifyQuery SQ(
259 DL, &TLI, &DT, &AC,
260 cast<LoadInst>(Order.empty() ? VL.back() : VL[Order.back()]));
261 IsMasked = !isSafeToLoadUnconditionally(Ptr0, LoadVecTy, CommonAlignment, SQ);
262 if (IsMasked && !TTI.isLegalMaskedLoad(LoadVecTy, CommonAlignment,
263 LI->getPointerAddressSpace()))
264 return false;
265 // TODO: perform the analysis of each scalar load for better
266 // safe-load-unconditionally analysis.
267 bool IsStrided =
268 buildCompressMask(PointerOps, Order, ScalarTy, DL, SE, CompressMask);
269 assert(CompressMask.size() >= 2 && "At least two elements are required");
270 SmallVector<Value *> OrderedPointerOps(PointerOps);
271 if (!Order.empty())
272 reorderScalars(OrderedPointerOps, Mask);
273 auto [ScalarGEPCost, VectorGEPCost] =
274 getGEPCosts(TTI, OrderedPointerOps, OrderedPointerOps.front(),
275 Instruction::Load, CostKind, ScalarTy, LoadVecTy);
276 // The cost of scalar loads.
277 InstructionCost ScalarLoadsCost =
279 [&](InstructionCost C, Value *V) {
280 return C + TTI.getInstructionCost(cast<Instruction>(V),
281 CostKind);
282 }) +
283 ScalarGEPCost;
284 APInt DemandedElts = APInt::getAllOnes(Sz);
285 InstructionCost GatherCost =
286 getScalarizationOverhead(TTI, ReVec, ScalarTy, VecTy, DemandedElts,
287 /*Insert=*/true,
288 /*Extract=*/false, CostKind) +
289 ScalarLoadsCost;
290 InstructionCost LoadCost = 0;
291 if (IsMasked) {
292 LoadCost = TTI.getMemIntrinsicInstrCost(
293 MemIntrinsicCostAttributes(Intrinsic::masked_load, LoadVecTy,
294 CommonAlignment,
295 LI->getPointerAddressSpace()),
296 CostKind);
297 } else {
298 LoadCost =
299 TTI.getMemoryOpCost(Instruction::Load, LoadVecTy, CommonAlignment,
300 LI->getPointerAddressSpace(), CostKind);
301 }
302 if (IsStrided && !IsMasked && Order.empty()) {
303 // Check for potential segmented(interleaved) loads.
304 VectorType *AlignedLoadVecTy = cast<VectorType>(getWidenedType(
305 ScalarTy,
306 getFullVectorNumberOfElements(TTI, ScalarTy, *Diff + 1, ReVec)));
307 SimplifyQuery SQ(DL, &TLI, &DT, &AC, cast<LoadInst>(VL.back()));
308 if (!isSafeToLoadUnconditionally(Ptr0, AlignedLoadVecTy, CommonAlignment,
309 SQ))
310 AlignedLoadVecTy = LoadVecTy;
311 if (TTI.isLegalInterleavedAccessType(AlignedLoadVecTy, CompressMask[1],
312 CommonAlignment,
313 LI->getPointerAddressSpace())) {
314 InstructionCost InterleavedCost =
315 VectorGEPCost + TTI.getInterleavedMemoryOpCost(
316 Instruction::Load, AlignedLoadVecTy,
317 CompressMask[1], {}, CommonAlignment,
318 LI->getPointerAddressSpace(), CostKind, IsMasked);
319 if (InterleavedCost < GatherCost) {
320 InterleaveFactor = CompressMask[1];
321 LoadVecTy = AlignedLoadVecTy;
322 return true;
323 }
324 }
325 }
326 // Estimating the compression shuffle cost below can be extremely expensive
327 // for a very wide LoadVecTy, which is split into a large number of vector
328 // registers (see processShuffleMasks). The shuffle cost is always
329 // non-negative, so if the load cost alone already reaches the gather cost the
330 // masked-load-compress cannot be profitable. Bail out before the costly
331 // shuffle cost estimation in that case.
332 if (VectorGEPCost + LoadCost >= GatherCost)
333 return false;
334 InstructionCost CompressCost = getShuffleCost(
335 TTI, TTI::SK_PermuteSingleSrc, LoadVecTy, CostKind, CompressMask);
336 if (!Order.empty()) {
337 SmallVector<int> NewMask(Sz, PoisonMaskElem);
338 for (unsigned I : seq<unsigned>(Sz)) {
339 NewMask[I] = CompressMask[Mask[I]];
340 }
341 CompressMask.swap(NewMask);
342 }
343 InstructionCost TotalVecCost = VectorGEPCost + LoadCost + CompressCost;
344 return TotalVecCost < GatherCost;
345}
346
347/// Checks if the \p VL can be transformed to a (masked)load + compress or
348/// (masked) interleaved load.
353 const DominatorTree &DT, const TargetLibraryInfo &TLI,
355 const function_ref<bool(Value *)> AreAllUsersVectorized, bool ReVec) {
356 bool IsMasked;
357 unsigned InterleaveFactor;
358 SmallVector<int> CompressMask;
359 VectorType *LoadVecTy;
360 return isMaskedLoadCompress(VL, PointerOps, Order, TTI, DL, SE, AC, DT, TLI,
361 CostKind, AreAllUsersVectorized, ReVec, IsMasked,
362 InterleaveFactor, CompressMask, LoadVecTy);
363}
364
365/// Checks if the stores \p VL with pointers \p PointerOps can be lowered as a
366/// single masked store. On success \p StoreVecTy is the widened store type and
367/// \p ReuseShuffleIndices is the expand mask that places each stored value at
368/// its element offset from the base (poison in the gaps).
370 ArrayRef<unsigned> Order,
371 const TargetTransformInfo &TTI, const DataLayout &DL,
372 ScalarEvolution &SE, Align CommonAlignment,
373 SmallVectorImpl<int> &ReuseShuffleIndices,
374 FixedVectorType *&StoreVecTy) {
375 Type *ScalarTy = cast<StoreInst>(VL.front())->getValueOperand()->getType();
376 const size_t Sz = VL.size();
377 // Only simple scalar element types are supported.
378 if (Sz < 2 || (!ScalarTy->isIntOrPtrTy() && !ScalarTy->isFloatingPointTy()))
379 return false;
380 Value *Ptr0 = Order.empty() ? PointerOps.front() : PointerOps[Order.front()];
381 Value *PtrN = Order.empty() ? PointerOps.back() : PointerOps[Order.back()];
382 std::optional<int64_t> Diff =
383 getPointersDiff(ScalarTy, Ptr0, ScalarTy, PtrN, DL, SE);
384 if (!Diff || *Diff <= 0)
385 return false;
386 // Avoid widened vectors with very large gaps between the stored elements.
387 const unsigned MaxRegSize =
389 .getFixedValue();
390 const unsigned ScalarBits = DL.getTypeSizeInBits(ScalarTy).getFixedValue();
391 if (ScalarBits == 0 ||
392 static_cast<uint64_t>(*Diff) / Sz >= MaxRegSize / ScalarBits)
393 return false;
394 StoreVecTy = cast<FixedVectorType>(getWidenedType(ScalarTy, *Diff + 1));
395 unsigned AS = cast<StoreInst>(VL.front())->getPointerAddressSpace();
396 if (!TTI.isLegalMaskedStore(StoreVecTy, CommonAlignment, AS,
398 return false;
399 // Build the expand mask: store I (in address-sorted order) is placed at its
400 // element offset from the base, other widened lanes are poison.
401 ReuseShuffleIndices.assign(*Diff + 1, PoisonMaskElem);
402 int64_t Prev = -1;
403 for (unsigned I : seq<unsigned>(Sz)) {
404 Value *Ptr = Order.empty() ? PointerOps[I] : PointerOps[Order[I]];
405 std::optional<int64_t> Off =
406 getPointersDiff(ScalarTy, Ptr0, ScalarTy, Ptr, DL, SE);
407 if (!Off || *Off <= Prev || *Off > *Diff)
408 return false;
409 ReuseShuffleIndices[*Off] = static_cast<int>(I);
410 Prev = *Off;
411 }
412 return true;
413}
414
416 Type *ElemTy, const DataLayout &DL,
417 ScalarEvolution &SE, unsigned MaxDepth,
418 SmallVectorImpl<unsigned> &SortedIndices) {
419 assert(
420 all_of(VL, [](const Value *V) { return V->getType()->isPointerTy(); }) &&
421 "Expected list of pointer operands.");
422 // Map from bases to a vector of (Ptr, Offset, OrigIdx), which we insert each
423 // Ptr into, sort and return the sorted indices with values next to one
424 // another.
426 std::pair<BasicBlock *, Value *>,
428 Bases;
429 Bases
430 .try_emplace(std::make_pair(BBs.front(),
431 getUnderlyingObject(VL.front(), MaxDepth)))
432 .first->second.emplace_back()
433 .emplace_back(VL.front(), 0U, 0U);
434
435 SortedIndices.clear();
436 for (auto [Cnt, Ptr] : enumerate(VL.drop_front())) {
437 auto Key = std::make_pair(BBs[Cnt + 1], getUnderlyingObject(Ptr, MaxDepth));
438 bool Found = any_of(Bases.try_emplace(Key).first->second,
439 [&, &Cnt = Cnt, &Ptr = Ptr](auto &Base) {
440 std::optional<int64_t> Diff =
441 getPointersDiff(ElemTy, std::get<0>(Base.front()),
442 ElemTy, Ptr, DL, SE,
443 /*StrictCheck=*/true);
444 if (!Diff)
445 return false;
446
447 Base.emplace_back(Ptr, *Diff, Cnt + 1);
448 return true;
449 });
450
451 if (!Found) {
452 // If we haven't found enough to usefully cluster, return early.
453 if (Bases.size() > VL.size() / 2 - 1)
454 return false;
455
456 // Not found already - add a new Base
457 Bases.find(Key)->second.emplace_back().emplace_back(Ptr, 0, Cnt + 1);
458 }
459 }
460
461 if (Bases.size() == VL.size())
462 return false;
463
464 if (Bases.size() == 1 && (Bases.front().second.size() == 1 ||
465 Bases.front().second.size() == VL.size()))
466 return false;
467
468 // For each of the bases sort the pointers by Offset and check if any of the
469 // base become consecutively allocated.
470 auto ComparePointers = [MaxDepth](Value *Ptr1, Value *Ptr2) {
471 SmallPtrSet<Value *, 13> FirstPointers;
472 SmallPtrSet<Value *, 13> SecondPointers;
473 Value *P1 = Ptr1;
474 Value *P2 = Ptr2;
475 unsigned Depth = 0;
476 while (!FirstPointers.contains(P2) && !SecondPointers.contains(P1)) {
477 if (P1 == P2 || Depth > MaxDepth)
478 return false;
479 FirstPointers.insert(P1);
480 SecondPointers.insert(P2);
481 P1 = getUnderlyingObject(P1, /*MaxLookup=*/1);
482 P2 = getUnderlyingObject(P2, /*MaxLookup=*/1);
483 ++Depth;
484 }
485 assert((FirstPointers.contains(P2) || SecondPointers.contains(P1)) &&
486 "Unable to find matching root.");
487 return FirstPointers.contains(P2) && !SecondPointers.contains(P1);
488 };
489 for (auto &Base : Bases) {
490 for (auto &Vec : Base.second) {
491 if (Vec.size() > 1) {
493 int64_t InitialOffset = std::get<1>(Vec[0]);
494 bool AnyConsecutive =
495 all_of(enumerate(Vec), [InitialOffset](const auto &P) {
496 return std::get<1>(P.value()) ==
497 int64_t(P.index()) + InitialOffset;
498 });
499 // Fill SortedIndices array only if it looks worth-while to sort the
500 // ptrs.
501 if (!AnyConsecutive)
502 return false;
503 }
504 }
505 stable_sort(Base.second, [&](const auto &V1, const auto &V2) {
506 return ComparePointers(std::get<0>(V1.front()), std::get<0>(V2.front()));
507 });
508 }
509
510 for (auto &T : Bases)
511 for (const auto &Vec : T.second)
512 for (const auto &P : Vec)
513 SortedIndices.push_back(std::get<2>(P));
514
515 assert(SortedIndices.size() == VL.size() &&
516 "Expected SortedIndices to be the size of VL");
517 return true;
518}
519
520} // 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")
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:231
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
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.
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.
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 * getConstant(ConstantInt *V)
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Return LHS-RHS.
LLVM_ABI const SCEV * getMulExpr(SmallVectorImpl< SCEVUse > &Ops, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Get a canonical multiply expression, or something simpler if possible.
LLVM_ABI const SCEV * getAddExpr(SmallVectorImpl< SCEVUse > &Ops, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Get a canonical add 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.
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
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.
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:309
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)
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)
Returns the cost of the shuffle instructions with the given Kind, vector type Tp and optional Mask.
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:300
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.
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:38
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.
void stable_sort(R &&Range)
Definition STLExtras.h:2116
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:1739
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:2554
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:1702
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:1746
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...
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
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
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 isSafeToLoadUnconditionally(Value *V, Align Alignment, const APInt &Size, const SimplifyQuery &SQ)
Return true if we know that executing a load from this value cannot trap.
Definition Loads.cpp:456
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
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:1439
Function object to check whether the second component of a container supported by std::get (like std:...
Definition STLExtras.h:1448