45 bool CompareOpcodes) {
51 return (!GEP1 || GEP1->getNumOperands() == 2) &&
52 (!GEP2 || GEP2->getNumOperands() == 2) &&
53 (((!GEP1 ||
isConstant(GEP1->getOperand(1))) &&
57 getSameOpcode({GEP1->getOperand(1), GEP2->getOperand(1)}, TLI)));
65 return CommonAlignment;
75 const SCEV *PtrSCEVLowest =
nullptr;
76 const SCEV *PtrSCEVHighest =
nullptr;
79 for (
Value *Ptr : PointerOps) {
84 if (!PtrSCEVLowest && !PtrSCEVHighest) {
85 PtrSCEVLowest = PtrSCEVHighest = PtrSCEV;
92 PtrSCEVLowest = PtrSCEV;
99 PtrSCEVHighest = PtrSCEV;
108 auto TryGetStride = [&](
const SCEV *Dist,
109 const SCEV *Multiplier) ->
const SCEV * {
111 if (M->getOperand(0) == Multiplier)
112 return M->getOperand(1);
113 if (M->getOperand(1) == Multiplier)
114 return M->getOperand(0);
117 if (Multiplier == Dist)
122 const SCEV *Stride =
nullptr;
123 if (
Size != 1 || SCEVs.
size() > 1) {
125 Stride = TryGetStride(Dist, Sz);
133 using DistOrdPair = std::pair<int64_t, int>;
135 std::set<DistOrdPair,
decltype(Compare)> Offsets(Compare);
136 bool IsConsecutive =
true;
137 for (
const auto [Idx, PtrSCEV] :
enumerate(SCEVs)) {
139 if (PtrSCEV != PtrSCEVLowest) {
141 const SCEV *Coeff = TryGetStride(Diff, Stride);
151 Dist = SC->getAPInt().getZExtValue();
156 auto Res = Offsets.emplace(Dist, Idx);
160 IsConsecutive = IsConsecutive && std::next(Res.first) == Offsets.end();
162 SortedIndices.
clear();
163 if (!IsConsecutive) {
166 for (
const auto [Idx, Pair] :
enumerate(Offsets))
167 SortedIndices[Idx] = Pair.second;
179 const unsigned Sz = PointerOps.
size();
184 std::optional<unsigned> Stride = 0;
187 Value *Ptr = Order.
empty() ? PointerOps[
I] : PointerOps[Order[
I]];
188 std::optional<int64_t> OptPos =
190 if (!OptPos || OptPos > std::numeric_limits<unsigned>::max())
192 unsigned Pos =
static_cast<unsigned>(*OptPos);
193 CompressMask[
I] = Pos;
200 if (Pos != *Stride *
I)
203 return Stride.has_value();
215 bool &IsMasked,
unsigned &InterleaveFactor,
217 InterleaveFactor = 0;
219 const size_t Sz = VL.
size();
226 if (AreAllUsersVectorized(V))
229 TTI.getVectorInstrCost(Instruction::ExtractElement, VecTy,
CostKind,
230 Mask.empty() ?
I : Mask[
I]);
233 if (ExtractCost <= ScalarCost)
239 Ptr0 = PointerOps.
front();
240 PtrN = PointerOps.
back();
242 Ptr0 = PointerOps[Order.
front()];
243 PtrN = PointerOps[Order.
back()];
245 std::optional<int64_t> Diff =
249 const size_t MaxRegSize =
253 if (*Diff / Sz >= MaxRegSize / 8)
257 Align CommonAlignment = LI->getAlign();
262 if (IsMasked && !
TTI.isLegalMaskedLoad(LoadVecTy, CommonAlignment,
263 LI->getPointerAddressSpace()))
269 assert(CompressMask.
size() >= 2 &&
"At least two elements are required");
273 auto [ScalarGEPCost, VectorGEPCost] =
275 Instruction::Load,
CostKind, ScalarTy, LoadVecTy);
292 LoadCost =
TTI.getMemIntrinsicInstrCost(
295 LI->getPointerAddressSpace()),
299 TTI.getMemoryOpCost(Instruction::Load, LoadVecTy, CommonAlignment,
300 LI->getPointerAddressSpace(),
CostKind,
303 if (IsStrided && !IsMasked && Order.
empty()) {
311 AlignedLoadVecTy = LoadVecTy;
312 if (
TTI.isLegalInterleavedAccessType(AlignedLoadVecTy, CompressMask[1],
314 LI->getPointerAddressSpace())) {
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;
333 if (VectorGEPCost + LoadCost >= GatherCost)
337 if (!Order.
empty()) {
340 NewMask[
I] = CompressMask[Mask[
I]];
342 CompressMask.
swap(NewMask);
344 InstructionCost TotalVecCost = VectorGEPCost + LoadCost + CompressCost;
345 return TotalVecCost < GatherCost;
358 unsigned InterleaveFactor;
362 CostKind, AreAllUsersVectorized, ReVec, IsMasked,
363 InterleaveFactor, CompressMask, LoadVecTy);
377 const size_t Sz = VL.
size();
383 std::optional<int64_t> Diff =
385 if (!Diff || *Diff <= 0)
388 const unsigned MaxRegSize =
391 const unsigned ScalarBits =
DL.getTypeSizeInBits(ScalarTy).getFixedValue();
392 if (ScalarBits == 0 ||
393 static_cast<uint64_t
>(*Diff) / Sz >= MaxRegSize / ScalarBits)
397 if (!
TTI.isLegalMaskedStore(StoreVecTy, CommonAlignment, AS,
405 Value *Ptr = Order.
empty() ? PointerOps[
I] : PointerOps[Order[
I]];
406 std::optional<int64_t> Off =
408 if (!Off || *Off <= Prev || *Off > *Diff)
410 ReuseShuffleIndices[*Off] =
static_cast<int>(
I);
421 all_of(VL, [](
const Value *V) {
return V->getType()->isPointerTy(); }) &&
422 "Expected list of pointer operands.");
427 std::pair<BasicBlock *, Value *>,
431 .try_emplace(std::make_pair(BBs.
front(),
434 .emplace_back(VL.
front(), 0U, 0U);
436 SortedIndices.
clear();
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()),
448 Base.emplace_back(Ptr, *Diff, Cnt + 1);
454 if (Bases.size() > VL.
size() / 2 - 1)
458 Bases.find(
Key)->second.emplace_back().emplace_back(Ptr, 0, Cnt + 1);
462 if (Bases.size() == VL.
size())
465 if (Bases.size() == 1 && (Bases.front().second.size() == 1 ||
466 Bases.front().second.size() == VL.
size()))
471 auto ComparePointers = [MaxDepth](
Value *Ptr1,
Value *Ptr2) {
478 if (P1 == P2 ||
Depth > MaxDepth)
481 SecondPointers.
insert(P2);
487 "Unable to find matching root.");
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 =
497 return std::get<1>(
P.value()) ==
498 int64_t(
P.index()) + InitialOffset;
507 return ComparePointers(std::get<0>(V1.front()), std::get<0>(V2.front()));
511 for (
auto &
T : Bases)
512 for (
const auto &Vec :
T.second)
513 for (
const auto &
P : Vec)
517 "Expected SortedIndices to be the size of VL");
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,...
This file implements a map that provides insertion order iteration.
Provides some synthesis utilities to produce sequences of values.
This file defines the SmallPtrSet class.
Class for arbitrary precision integers.
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
const T & back() const
Get the last element.
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
const T & front() const
Get the first element.
size_t size() const
Get the array size.
bool empty() const
Check if the array is empty.
const T & consume_front()
consume_front() - Returns the first element and drops it from ArrayRef.
A cache of @llvm.assume calls within a function.
A parsed version of the target data layout string in and methods for querying it.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
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 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.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
bool isIntOrPtrTy() const
Return true if this is an integer type or a pointer type.
LLVM Value Representation.
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.
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.
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)
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)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto accumulate(R &&Range, E &&Init)
Wrapper for std::accumulate.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
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...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
constexpr int PoisonMaskElem
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
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.
This struct is a compact representation of a valid (non-zero power of two) alignment.
A MapVector that performs no allocations if smaller than a certain size.
Function object to check whether the first component of a container supported by std::get (like std::...
Function object to check whether the second component of a container supported by std::get (like std:...