summaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
diff options
context:
space:
mode:
authorFlorian Hahn <flo@fhahn.com>2025-06-20 13:05:19 +0100
committerGitHub <noreply@github.com>2025-06-20 13:05:19 +0100
commitfd97dfbb78e3c9aea16873617b6d61b5b8a64474 (patch)
tree0b4f76ae3c1a05137bc20e715c9515d21667232b /llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
parent5835f1e0a33afcae46a6ca4854373785eb3e7fd6 (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.cpp41
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());