diff options
| author | Florian Hahn <flo@fhahn.com> | 2025-06-20 13:05:19 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-06-20 13:05:19 +0100 |
| commit | fd97dfbb78e3c9aea16873617b6d61b5b8a64474 (patch) | |
| tree | 0b4f76ae3c1a05137bc20e715c9515d21667232b /llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp | |
| parent | 5835f1e0a33afcae46a6ca4854373785eb3e7fd6 (diff) | |
[LV] Don't mark ptrs as safe to speculate if fed by UB/poison op. (#143204)
Add additional checks before marking pointers safe to load
speculatively. If some computations feeding the pointer may trigger UB,
we cannot load the pointer speculatively, because we cannot compute the
address speculatively. The UB triggering instructions will be
predicated, but if the predicated block does not execute the result is
poison.
Similarly, we also cannot load the pointer speculatively if it may be
poison. The patch also checks if any of the operands defined outside the
loop may be poison when entering the loop. We *don't* need to check if
any operation inside the loop may produce poison due to flags, as those
will be dropped if needed.
There are some types of instructions inside the loop that can produce
poison independent of flags. Currently loads are also checked, not sure
if there's a convenient API to check for all such operands.
Fixes https://github.com/llvm/llvm-project/issues/142957.
PR: https://github.com/llvm/llvm-project/pull/143204
Diffstat (limited to 'llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp')
| -rw-r--r-- | llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp index 0c4e5bb3d472..969d225c6ef2 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp @@ -1491,10 +1491,51 @@ bool LoopVectorizationLegality::canVectorizeWithIfConvert() { SmallVector<const SCEVPredicate *, 4> Predicates; for (Instruction &I : *BB) { LoadInst *LI = dyn_cast<LoadInst>(&I); + + // Make sure we can execute all computations feeding into Ptr in the loop + // w/o triggering UB and that none of the out-of-loop operands are poison. + // We do not need to check if operations inside the loop can produce + // poison due to flags (e.g. due to an inbounds GEP going out of bounds), + // because flags will be dropped when executing them unconditionally. + // TODO: Results could be improved by considering poison-propagation + // properties of visited ops. + auto CanSpeculatePointerOp = [this](Value *Ptr) { + SmallVector<Value *> Worklist = {Ptr}; + SmallPtrSet<Value *, 4> Visited; + while (!Worklist.empty()) { + Value *CurrV = Worklist.pop_back_val(); + if (!Visited.insert(CurrV).second) + continue; + + auto *CurrI = dyn_cast<Instruction>(CurrV); + if (!CurrI || !TheLoop->contains(CurrI)) { + // If operands from outside the loop may be poison then Ptr may also + // be poison. + if (!isGuaranteedNotToBePoison(CurrV, AC, + TheLoop->getLoopPredecessor() + ->getTerminator() + ->getIterator())) + return false; + continue; + } + + // A loaded value may be poison, independent of any flags. + if (isa<LoadInst>(CurrI) && !isGuaranteedNotToBePoison(CurrV, AC)) + return false; + + // For other ops, assume poison can only be introduced via flags, + // which can be dropped. + if (!isa<PHINode>(CurrI) && !isSafeToSpeculativelyExecute(CurrI)) + return false; + append_range(Worklist, CurrI->operands()); + } + return true; + }; // Pass the Predicates pointer to isDereferenceableAndAlignedInLoop so // that it will consider loops that need guarding by SCEV checks. The // vectoriser will generate these checks if we decide to vectorise. if (LI && !LI->getType()->isVectorTy() && !mustSuppressSpeculation(*LI) && + CanSpeculatePointerOp(LI->getPointerOperand()) && isDereferenceableAndAlignedInLoop(LI, TheLoop, SE, *DT, AC, &Predicates)) SafePointers.insert(LI->getPointerOperand()); |
