50 uint64_t ElementSize =
DL.getTypeAllocSize(ScalarTy).getFixedValue();
51 APInt Bytes = CI->getValue() * ElementSize;
52 return ConstantInt::get(CI->getContext(), IsReverse ? -Bytes : Bytes);
57 bool CompareOpcodes) {
63 return (!GEP1 || GEP1->getNumOperands() == 2) &&
64 (!GEP2 || GEP2->getNumOperands() == 2) &&
65 (((!GEP1 ||
isConstant(GEP1->getOperand(1))) &&
69 getSameOpcode({GEP1->getOperand(1), GEP2->getOperand(1)}, TLI)));
77 return CommonAlignment;
87 const SCEV *PtrSCEVLowest =
nullptr;
88 const SCEV *PtrSCEVHighest =
nullptr;
91 for (
Value *Ptr : PointerOps) {
96 if (!PtrSCEVLowest && !PtrSCEVHighest) {
97 PtrSCEVLowest = PtrSCEVHighest = PtrSCEV;
104 PtrSCEVLowest = PtrSCEV;
111 PtrSCEVHighest = PtrSCEV;
120 auto TryGetStride = [&](
const SCEV *Dist,
121 const SCEV *Multiplier) ->
const SCEV * {
123 if (M->getOperand(0) == Multiplier)
124 return M->getOperand(1);
125 if (M->getOperand(1) == Multiplier)
126 return M->getOperand(0);
129 if (Multiplier == Dist)
134 const SCEV *Stride =
nullptr;
135 if (
Size != 1 || SCEVs.
size() > 1) {
137 Stride = TryGetStride(Dist, Sz);
145 using DistOrdPair = std::pair<int64_t, int>;
147 std::set<DistOrdPair,
decltype(Compare)> Offsets(Compare);
148 bool IsConsecutive =
true;
149 for (
const auto [Idx, PtrSCEV] :
enumerate(SCEVs)) {
151 if (PtrSCEV != PtrSCEVLowest) {
153 const SCEV *Coeff = TryGetStride(Diff, Stride);
163 Dist = SC->getAPInt().getZExtValue();
168 auto Res = Offsets.emplace(Dist, Idx);
172 IsConsecutive = IsConsecutive && std::next(Res.first) == Offsets.end();
174 SortedIndices.
clear();
175 if (!IsConsecutive) {
178 for (
const auto [Idx, Pair] :
enumerate(Offsets))
179 SortedIndices[Idx] = Pair.second;
191 const unsigned Sz = PointerOps.
size();
196 std::optional<unsigned> Stride = 0;
199 Value *Ptr = Order.
empty() ? PointerOps[
I] : PointerOps[Order[
I]];
200 std::optional<int64_t> OptPos =
202 if (!OptPos || OptPos > std::numeric_limits<unsigned>::max())
204 unsigned Pos =
static_cast<unsigned>(*OptPos);
205 CompressMask[
I] = Pos;
212 if (Pos != *Stride *
I)
215 return Stride.has_value();
227 bool &IsMasked,
unsigned &InterleaveFactor,
229 InterleaveFactor = 0;
231 const size_t Sz = VL.
size();
238 if (AreAllUsersVectorized(V))
241 TTI.getVectorInstrCost(Instruction::ExtractElement, VecTy,
CostKind,
242 Mask.empty() ?
I : Mask[
I]);
245 if (ExtractCost <= ScalarCost)
251 Ptr0 = PointerOps.
front();
252 PtrN = PointerOps.
back();
254 Ptr0 = PointerOps[Order.
front()];
255 PtrN = PointerOps[Order.
back()];
257 std::optional<int64_t> Diff =
261 const size_t MaxRegSize =
265 if (*Diff / Sz >= MaxRegSize / 8)
269 Align CommonAlignment = LI->getAlign();
274 if (IsMasked && !
TTI.isLegalMaskedLoad(LoadVecTy, CommonAlignment,
275 LI->getPointerAddressSpace()))
281 assert(CompressMask.
size() >= 2 &&
"At least two elements are required");
285 auto [ScalarGEPCost, VectorGEPCost] =
287 Instruction::Load,
CostKind, ScalarTy, LoadVecTy);
304 LoadCost =
TTI.getMemIntrinsicInstrCost(
307 LI->getPointerAddressSpace()),
311 TTI.getMemoryOpCost(Instruction::Load, LoadVecTy, CommonAlignment,
312 LI->getPointerAddressSpace(),
CostKind,
315 if (IsStrided && !IsMasked && Order.
empty()) {
323 AlignedLoadVecTy = LoadVecTy;
324 if (
TTI.isLegalInterleavedAccessType(AlignedLoadVecTy, CompressMask[1],
326 LI->getPointerAddressSpace())) {
328 VectorGEPCost +
TTI.getInterleavedMemoryOpCost(
329 Instruction::Load, AlignedLoadVecTy,
330 CompressMask[1], {}, CommonAlignment,
331 LI->getPointerAddressSpace(),
CostKind, IsMasked);
332 if (InterleavedCost < GatherCost) {
333 InterleaveFactor = CompressMask[1];
334 LoadVecTy = AlignedLoadVecTy;
345 if (VectorGEPCost + LoadCost >= GatherCost)
349 if (!Order.
empty()) {
352 NewMask[
I] = CompressMask[Mask[
I]];
354 CompressMask.
swap(NewMask);
356 InstructionCost TotalVecCost = VectorGEPCost + LoadCost + CompressCost;
357 return TotalVecCost < GatherCost;
370 unsigned InterleaveFactor;
374 CostKind, AreAllUsersVectorized, ReVec, IsMasked,
375 InterleaveFactor, CompressMask, LoadVecTy);
389 const size_t Sz = VL.
size();
395 std::optional<int64_t> Diff =
397 if (!Diff || *Diff <= 0)
400 const unsigned MaxRegSize =
403 const unsigned ScalarBits =
DL.getTypeSizeInBits(ScalarTy).getFixedValue();
404 if (ScalarBits == 0 ||
405 static_cast<uint64_t
>(*Diff) / Sz >= MaxRegSize / ScalarBits)
409 if (!
TTI.isLegalMaskedStore(StoreVecTy, CommonAlignment, AS,
417 Value *Ptr = Order.
empty() ? PointerOps[
I] : PointerOps[Order[
I]];
418 std::optional<int64_t>
Off =
422 ReuseShuffleIndices[*
Off] =
static_cast<int>(
I);
433 all_of(VL, [](
const Value *V) {
return V->getType()->isPointerTy(); }) &&
434 "Expected list of pointer operands.");
439 std::pair<BasicBlock *, Value *>,
443 .try_emplace(std::make_pair(BBs.
front(),
446 .emplace_back(VL.
front(), 0U, 0U);
448 SortedIndices.
clear();
451 bool Found =
any_of(Bases.try_emplace(
Key).first->second,
452 [&, &Cnt = Cnt, &Ptr = Ptr](
auto &
Base) {
453 std::optional<int64_t> Diff =
454 getPointersDiff(ElemTy, std::get<0>(Base.front()),
460 Base.emplace_back(Ptr, *Diff, Cnt + 1);
466 if (Bases.size() > VL.
size() / 2 - 1)
470 Bases.find(
Key)->second.emplace_back().emplace_back(Ptr, 0, Cnt + 1);
474 if (Bases.size() == VL.
size())
477 if (Bases.size() == 1 && (Bases.front().second.size() == 1 ||
478 Bases.front().second.size() == VL.
size()))
483 auto ComparePointers = [MaxDepth](
Value *Ptr1,
Value *Ptr2) {
490 if (P1 == P2 ||
Depth > MaxDepth)
493 SecondPointers.
insert(P2);
499 "Unable to find matching root.");
502 for (
auto &
Base : Bases) {
503 for (
auto &Vec :
Base.second) {
504 if (Vec.size() > 1) {
506 int64_t InitialOffset = std::get<1>(Vec[0]);
507 bool AnyConsecutive =
509 return std::get<1>(
P.value()) ==
510 int64_t(
P.index()) + InitialOffset;
519 return ComparePointers(std::get<0>(V1.front()), std::get<0>(V2.front()));
523 for (
auto &
T : Bases)
524 for (
const auto &Vec :
T.second)
525 for (
const auto &
P : Vec)
529 "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")
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,...
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.
This is the shared class of boolean and integer constants.
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)
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.
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.
auto dyn_cast_or_null(const Y &Val)
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:...