diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-04-14 21:41:27 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-06-22 18:20:56 +0000 |
commit | bdd1243df58e60e85101c09001d9812a789b6bc4 (patch) | |
tree | a1ce621c7301dd47ba2ddc3b8eaa63b441389481 /contrib/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp | |
parent | 781624ca2d054430052c828ba8d2c2eaf2d733e7 (diff) | |
parent | e3b557809604d036af6e00c60f012c2025b59a5e (diff) |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp | 102 |
1 files changed, 62 insertions, 40 deletions
diff --git a/contrib/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/contrib/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp index 183ba86abcb4..cd48c0d57eb3 100644 --- a/contrib/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp +++ b/contrib/llvm-project/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp @@ -295,7 +295,7 @@ void LoopVectorizeHints::setHint(StringRef Name, Metadata *Arg) { Hint *Hints[] = {&Width, &Interleave, &Force, &IsVectorized, &Predicate, &Scalable}; - for (auto H : Hints) { + for (auto *H : Hints) { if (Name == H->Name) { if (H->validate(Val)) H->Value = Val; @@ -456,16 +456,27 @@ int LoopVectorizationLegality::isConsecutivePtr(Type *AccessTy, PGSOQueryType::IRPass); bool CanAddPredicate = !OptForSize; int Stride = getPtrStride(PSE, AccessTy, Ptr, TheLoop, Strides, - CanAddPredicate, false); + CanAddPredicate, false).value_or(0); if (Stride == 1 || Stride == -1) return Stride; return 0; } -bool LoopVectorizationLegality::isUniform(Value *V) { +bool LoopVectorizationLegality::isUniform(Value *V) const { return LAI->isUniform(V); } +bool LoopVectorizationLegality::isUniformMemOp(Instruction &I) const { + Value *Ptr = getLoadStorePointerOperand(&I); + if (!Ptr) + return false; + // Note: There's nothing inherent which prevents predicated loads and + // stores from being uniform. The current lowering simply doesn't handle + // it; in particular, the cost model distinguishes scatter/gather from + // scalar w/predication, and we currently rely on the scalar path. + return isUniform(Ptr) && !blockNeedsPredication(I.getParent()); +} + bool LoopVectorizationLegality::canVectorizeOuterLoop() { assert(!TheLoop->isInnermost() && "We are not vectorizing an outer loop."); // Store the result and return it at the end instead of exiting early, in case @@ -666,7 +677,7 @@ bool LoopVectorizationLegality::canVectorizeInstrs() { // Non-header phi nodes that have outside uses can be vectorized. Add // them to the list of allowed exits. // Unsafe cyclic dependencies with header phis are identified during - // legalization for reduction, induction and first order + // legalization for reduction, induction and fixed order // recurrences. AllowedExit.insert(&I); continue; @@ -689,20 +700,20 @@ bool LoopVectorizationLegality::canVectorizeInstrs() { continue; } - // TODO: Instead of recording the AllowedExit, it would be good to record the - // complementary set: NotAllowedExit. These include (but may not be - // limited to): + // TODO: Instead of recording the AllowedExit, it would be good to + // record the complementary set: NotAllowedExit. These include (but may + // not be limited to): // 1. Reduction phis as they represent the one-before-last value, which - // is not available when vectorized + // is not available when vectorized // 2. Induction phis and increment when SCEV predicates cannot be used // outside the loop - see addInductionPhi // 3. Non-Phis with outside uses when SCEV predicates cannot be used // outside the loop - see call to hasOutsideLoopUser in the non-phi // handling below - // 4. FirstOrderRecurrence phis that can possibly be handled by + // 4. FixedOrderRecurrence phis that can possibly be handled by // extraction. // By recording these, we can then reason about ways to vectorize each - // of these NotAllowedExit. + // of these NotAllowedExit. InductionDescriptor ID; if (InductionDescriptor::isInductionPHI(Phi, TheLoop, PSE, ID)) { addInductionPhi(Phi, ID, AllowedExit); @@ -710,10 +721,10 @@ bool LoopVectorizationLegality::canVectorizeInstrs() { continue; } - if (RecurrenceDescriptor::isFirstOrderRecurrence(Phi, TheLoop, + if (RecurrenceDescriptor::isFixedOrderRecurrence(Phi, TheLoop, SinkAfter, DT)) { AllowedExit.insert(Phi); - FirstOrderRecurrences.insert(Phi); + FixedOrderRecurrences.insert(Phi); continue; } @@ -883,12 +894,12 @@ bool LoopVectorizationLegality::canVectorizeInstrs() { } } - // For first order recurrences, we use the previous value (incoming value from + // For fixed order recurrences, we use the previous value (incoming value from // the latch) to check if it dominates all users of the recurrence. Bail out // if we have to sink such an instruction for another recurrence, as the // dominance requirement may not hold after sinking. BasicBlock *LoopLatch = TheLoop->getLoopLatch(); - if (any_of(FirstOrderRecurrences, [LoopLatch, this](const PHINode *Phi) { + if (any_of(FixedOrderRecurrences, [LoopLatch, this](const PHINode *Phi) { Instruction *V = cast<Instruction>(Phi->getIncomingValueForBlock(LoopLatch)); return SinkAfter.find(V) != SinkAfter.end(); @@ -905,7 +916,7 @@ bool LoopVectorizationLegality::canVectorizeInstrs() { } bool LoopVectorizationLegality::canVectorizeMemory() { - LAI = &(*GetLAA)(*TheLoop); + LAI = &LAIs.getInfo(*TheLoop); const OptimizationRemarkAnalysis *LAR = LAI->getReport(); if (LAR) { ORE->emit([&]() { @@ -922,10 +933,13 @@ bool LoopVectorizationLegality::canVectorizeMemory() { // vectorize loop is made, runtime checks are added so as to make sure that // invariant address won't alias with any other objects. if (!LAI->getStoresToInvariantAddresses().empty()) { - // For each invariant address, check its last stored value is unconditional. + // For each invariant address, check if last stored value is unconditional + // and the address is not calculated inside the loop. for (StoreInst *SI : LAI->getStoresToInvariantAddresses()) { - if (isInvariantStoreOfReduction(SI) && - blockNeedsPredication(SI->getParent())) { + if (!isInvariantStoreOfReduction(SI)) + continue; + + if (blockNeedsPredication(SI->getParent())) { reportVectorizationFailure( "We don't allow storing to uniform addresses", "write of conditional recurring variant value to a loop " @@ -933,6 +947,20 @@ bool LoopVectorizationLegality::canVectorizeMemory() { "CantVectorizeStoreToLoopInvariantAddress", ORE, TheLoop); return false; } + + // Invariant address should be defined outside of loop. LICM pass usually + // makes sure it happens, but in rare cases it does not, we do not want + // to overcomplicate vectorization to support this case. + if (Instruction *Ptr = dyn_cast<Instruction>(SI->getPointerOperand())) { + if (TheLoop->contains(Ptr)) { + reportVectorizationFailure( + "Invariant address is calculated inside the loop", + "write to a loop invariant address could not " + "be vectorized", + "CantVectorizeStoreToLoopInvariantAddress", ORE, TheLoop); + return false; + } + } } if (LAI->hasDependenceInvolvingLoopInvariantAddress()) { @@ -1069,9 +1097,9 @@ bool LoopVectorizationLegality::isInductionVariable(const Value *V) const { return isInductionPhi(V) || isCastedInductionVariable(V); } -bool LoopVectorizationLegality::isFirstOrderRecurrence( +bool LoopVectorizationLegality::isFixedOrderRecurrence( const PHINode *Phi) const { - return FirstOrderRecurrences.count(Phi); + return FixedOrderRecurrences.count(Phi); } bool LoopVectorizationLegality::blockNeedsPredication(BasicBlock *BB) const { @@ -1096,30 +1124,24 @@ bool LoopVectorizationLegality::blockCanBePredicated( if (isa<NoAliasScopeDeclInst>(&I)) continue; - // We might be able to hoist the load. - if (I.mayReadFromMemory()) { - auto *LI = dyn_cast<LoadInst>(&I); - if (!LI) - return false; - if (!SafePtrs.count(LI->getPointerOperand())) { + // Loads are handled via masking (or speculated if safe to do so.) + if (auto *LI = dyn_cast<LoadInst>(&I)) { + if (!SafePtrs.count(LI->getPointerOperand())) MaskedOp.insert(LI); - continue; - } + continue; } - if (I.mayWriteToMemory()) { - auto *SI = dyn_cast<StoreInst>(&I); - if (!SI) - return false; - // Predicated store requires some form of masking: - // 1) masked store HW instruction, - // 2) emulation via load-blend-store (only if safe and legal to do so, - // be aware on the race conditions), or - // 3) element-by-element predicate check and scalar store. + // Predicated store requires some form of masking: + // 1) masked store HW instruction, + // 2) emulation via load-blend-store (only if safe and legal to do so, + // be aware on the race conditions), or + // 3) element-by-element predicate check and scalar store. + if (auto *SI = dyn_cast<StoreInst>(&I)) { MaskedOp.insert(SI); continue; } - if (I.mayThrow()) + + if (I.mayReadFromMemory() || I.mayWriteToMemory() || I.mayThrow()) return false; } @@ -1162,7 +1184,7 @@ bool LoopVectorizationLegality::canVectorizeWithIfConvert() { for (Instruction &I : *BB) { LoadInst *LI = dyn_cast<LoadInst>(&I); if (LI && !LI->getType()->isVectorTy() && !mustSuppressSpeculation(*LI) && - isDereferenceableAndAlignedInLoop(LI, TheLoop, SE, *DT)) + isDereferenceableAndAlignedInLoop(LI, TheLoop, SE, *DT, AC)) SafePointers.insert(LI->getPointerOperand()); } } @@ -1364,7 +1386,7 @@ bool LoopVectorizationLegality::prepareToFoldTailByMasking() { SmallPtrSet<const Value *, 8> ReductionLiveOuts; - for (auto &Reduction : getReductionVars()) + for (const auto &Reduction : getReductionVars()) ReductionLiveOuts.insert(Reduction.second.getLoopExitInstr()); // TODO: handle non-reduction outside users when tail is folded by masking. |