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 TTI::getOperandInfo(LI->getPointerOperand()));
302 }
303 if (IsStrided && !IsMasked && Order.empty()) {
304 // Check for potential segmented(interleaved) loads.
305 VectorType *AlignedLoadVecTy = cast<VectorType>(getWidenedType(
306 ScalarTy,
307 getFullVectorNumberOfElements(TTI, ScalarTy, *Diff + 1, ReVec)));
308 SimplifyQuery SQ(DL, &TLI, &DT, &AC, cast<LoadInst>(VL.back()));
309 if (!isSafeToLoadUnconditionally(Ptr0, AlignedLoadVecTy, CommonAlignment,
310 SQ))
311 AlignedLoadVecTy = LoadVecTy;
312 if (TTI.isLegalInterleavedAccessType(AlignedLoadVecTy, CompressMask[1],
313 CommonAlignment,
314 LI->getPointerAddressSpace())) {
315 InstructionCost InterleavedCost =
316 VectorGEPCost + TTI.getInterleavedMemoryOpCost(
317 Instruction::Load, AlignedLoadVecTy,
318 CompressMask[1], {}, CommonAlignment,
319 LI->getPointerAddressSpace(), CostKind, IsMasked);
320 if (InterleavedCost < GatherCost) {
321 InterleaveFactor = CompressMask[1];
322 LoadVecTy = AlignedLoadVecTy;
323 return true;
324 }
325 }
326 }
327 // Estimating the compression shuffle cost below can be extremely expensive
328 // for a very wide LoadVecTy, which is split into a large number of vector
329 // registers (see processShuffleMasks). The shuffle cost is always
330 // non-negative, so if the load cost alone already reaches the gather cost the
331 // masked-load-compress cannot be profitable. Bail out before the costly
332 // shuffle cost estimation in that case.
333 if (VectorGEPCost + LoadCost >= GatherCost)
334 return false;
335 InstructionCost CompressCost = getShuffleCost(
336 TTI, TTI::SK_PermuteSingleSrc, LoadVecTy, CostKind, CompressMask);
337 if (!Order.empty()) {
338 SmallVector<int> NewMask(Sz, PoisonMaskElem);
339 for (unsigned I : seq<unsigned>(Sz)) {
340 NewMask[I] = CompressMask[Mask[I]];
341 }
342 CompressMask.swap(NewMask);
343 }
344 InstructionCost TotalVecCost = VectorGEPCost + LoadCost + CompressCost;
345 return TotalVecCost < GatherCost;
346}
347
348/// Checks if the \p VL can be transformed to a (masked)load + compress or
349/// (masked) interleaved load.
354 const DominatorTree &DT, const TargetLibraryInfo &TLI,
356 const function_ref<bool(Value *)> AreAllUsersVectorized, bool ReVec) {
357 bool IsMasked;
358 unsigned InterleaveFactor;
359 SmallVector<int> CompressMask;
360 VectorType *LoadVecTy;
361 return isMaskedLoadCompress(VL, PointerOps, Order, TTI, DL, SE, AC, DT, TLI,
362 CostKind, AreAllUsersVectorized, ReVec, IsMasked,
363 InterleaveFactor, CompressMask, LoadVecTy);
364}
365
366/// Checks if the stores \p VL with pointers \p PointerOps can be lowered as a
367/// single masked store. On success \p StoreVecTy is the widened store type and
368/// \p ReuseShuffleIndices is the expand mask that places each stored value at
369/// its element offset from the base (poison in the gaps).
371 ArrayRef<unsigned> Order,
372 const TargetTransformInfo &TTI, const DataLayout &DL,
373 ScalarEvolution &SE, Align CommonAlignment,
374 SmallVectorImpl<int> &ReuseShuffleIndices,
375 FixedVectorType *&StoreVecTy) {
376 Type *ScalarTy = cast<StoreInst>(VL.front())->getValueOperand()->getType();
377 const size_t Sz = VL.size();
378 // Only simple scalar element types are supported.
379 if (Sz < 2 || (!ScalarTy->isIntOrPtrTy() && !ScalarTy->isFloatingPointTy()))
380 return false;
381 Value *Ptr0 = Order.empty() ? PointerOps.front() : PointerOps[Order.front()];
382 Value *PtrN = Order.empty() ? PointerOps.back() : PointerOps[Order.back()];
383 std::optional<int64_t> Diff =
384 getPointersDiff(ScalarTy, Ptr0, ScalarTy, PtrN, DL, SE);
385 if (!Diff || *Diff <= 0)
386 return false;
387 // Avoid widened vectors with very large gaps between the stored elements.
388 const unsigned MaxRegSize =
390 .getFixedValue();
391 const unsigned ScalarBits = DL.getTypeSizeInBits(ScalarTy).getFixedValue();
392 if (ScalarBits == 0 ||
393 static_cast<uint64_t>(*Diff) / Sz >= MaxRegSize / ScalarBits)
394 return false;
395 StoreVecTy = cast<FixedVectorType>(getWidenedType(ScalarTy, *Diff + 1));
396 unsigned AS = cast<StoreInst>(VL.front())->getPointerAddressSpace();
397 if (!TTI.isLegalMaskedStore(StoreVecTy, CommonAlignment, AS,
399 return false;
400 // Build the expand mask: store I (in address-sorted order) is placed at its
401 // element offset from the base, other widened lanes are poison.
402 ReuseShuffleIndices.assign(*Diff + 1, PoisonMaskElem);
403 int64_t Prev = -1;
404 for (unsigned I : seq<unsigned>(Sz)) {
405 Value *Ptr = Order.empty() ? PointerOps[I] : PointerOps[Order[I]];
406 std::optional<int64_t> Off =
407 getPointersDiff(ScalarTy, Ptr0, ScalarTy, Ptr, DL, SE);
408 if (!Off || *Off <= Prev || *Off > *Diff)
409 return false;
410 ReuseShuffleIndices[*Off] = static_cast<int>(I);
411 Prev = *Off;
412 }
413 return true;
414}
415
417 Type *ElemTy, const DataLayout &DL,
418 ScalarEvolution &SE, unsigned MaxDepth,
419 SmallVectorImpl<unsigned> &SortedIndices) {
420 assert(
421 all_of(VL, [](const Value *V) { return V->getType()->isPointerTy(); }) &&
422 "Expected list of pointer operands.");
423 // Map from bases to a vector of (Ptr, Offset, OrigIdx), which we insert each
424 // Ptr into, sort and return the sorted indices with values next to one
425 // another.
427 std::pair<BasicBlock *, Value *>,
429 Bases;
430 Bases
431 .try_emplace(std::make_pair(BBs.front(),
432 getUnderlyingObject(VL.front(), MaxDepth)))
433 .first->second.emplace_back()
434 .emplace_back(VL.front(), 0U, 0U);
435
436 SortedIndices.clear();
437 for (auto [Cnt, Ptr] : enumerate(VL.drop_front())) {
438 auto Key = std::make_pair(BBs[Cnt + 1], getUnderlyingObject(Ptr, MaxDepth));
439 bool Found = any_of(Bases.try_emplace(Key).first->second,
440 [&, &Cnt = Cnt, &Ptr = Ptr](auto &Base) {
441 std::optional<int64_t> Diff =
442 getPointersDiff(ElemTy, std::get<0>(Base.front()),
443 ElemTy, Ptr, DL, SE,
444 /*StrictCheck=*/true);
445 if (!Diff)
446 return false;
447
448 Base.emplace_back(Ptr, *Diff, Cnt + 1);
449 return true;
450 });
451
452 if (!Found) {
453 // If we haven't found enough to usefully cluster, return early.
454 if (Bases.size() > VL.size() / 2 - 1)
455 return false;
456
457 // Not found already - add a new Base
458 Bases.find(Key)->second.emplace_back().emplace_back(Ptr, 0, Cnt + 1);
459 }
460 }
461
462 if (Bases.size() == VL.size())
463 return false;
464
465 if (Bases.size() == 1 && (Bases.front().second.size() == 1 ||
466 Bases.front().second.size() == VL.size()))
467 return false;
468
469 // For each of the bases sort the pointers by Offset and check if any of the
470 // base become consecutively allocated.
471 auto ComparePointers = [MaxDepth](Value *Ptr1, Value *Ptr2) {
472 SmallPtrSet<Value *, 13> FirstPointers;
473 SmallPtrSet<Value *, 13> SecondPointers;
474 Value *P1 = Ptr1;
475 Value *P2 = Ptr2;
476 unsigned Depth = 0;
477 while (!FirstPointers.contains(P2) && !SecondPointers.contains(P1)) {
478 if (P1 == P2 || Depth > MaxDepth)
479 return false;
480 FirstPointers.insert(P1);
481 SecondPointers.insert(P2);
482 P1 = getUnderlyingObject(P1, /*MaxLookup=*/1);
483 P2 = getUnderlyingObject(P2, /*MaxLookup=*/1);
484 ++Depth;
485 }
486 assert((FirstPointers.contains(P2) || SecondPointers.contains(P1)) &&
487 "Unable to find matching root.");
488 return FirstPointers.contains(P2) && !SecondPointers.contains(P1);
489 };
490 for (auto &Base : Bases) {
491 for (auto &Vec : Base.second) {
492 if (Vec.size() > 1) {
494 int64_t InitialOffset = std::get<1>(Vec[0]);
495 bool AnyConsecutive =
496 all_of(enumerate(Vec), [InitialOffset](const auto &P) {
497 return std::get<1>(P.value()) ==
498 int64_t(P.index()) + InitialOffset;
499 });
500 // Fill SortedIndices array only if it looks worth-while to sort the
501 // ptrs.
502 if (!AnyConsecutive)
503 return false;
504 }
505 }
506 stable_sort(Base.second, [&](const auto &V1, const auto &V2) {
507 return ComparePointers(std::get<0>(V1.front()), std::get<0>(V2.front()));
508 });
509 }
510
511 for (auto &T : Bases)
512 for (const auto &Vec : T.second)
513 for (const auto &P : Vec)
514 SortedIndices.push_back(std::get<2>(P));
515
516 assert(SortedIndices.size() == VL.size() &&
517 "Expected SortedIndices to be the size of VL");
518 return true;
519}
520
521} // 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: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
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 * 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
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:308
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)
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:299
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: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
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
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
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