aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/ValueTracking.cpp
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2021-01-16 15:32:40 +0100
committerNikita Popov <nikita.ppv@gmail.com>2021-01-19 18:04:23 +0100
commit051ec9f5f43a83e23bd3e20e512fc5ec44c19850 (patch)
tree1b43f47a0d8603ffdcf2d87e5a3b19558b2836df /llvm/lib/Analysis/ValueTracking.cpp
parent0808c7009a06773e78772c7b74d254fd3572f0ea (diff)
downloadllvm-051ec9f5f43a83e23bd3e20e512fc5ec44c19850.zip
llvm-051ec9f5f43a83e23bd3e20e512fc5ec44c19850.tar.gz
llvm-051ec9f5f43a83e23bd3e20e512fc5ec44c19850.tar.bz2
[ValueTracking] Strengthen impliesPoison reasoning
Split impliesPoison into two recursive walks, one over V, the other over ValAssumedPoison. This allows us to reason about poison implications in a number of additional cases that are important in practice. This is a generalized form of D94859, which handles the cmp to cmp implication in particular. Differential Revision: https://reviews.llvm.org/D94866
Diffstat (limited to 'llvm/lib/Analysis/ValueTracking.cpp')
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp81
1 files changed, 33 insertions, 48 deletions
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index a9cef91..7f8f101 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -4806,64 +4806,49 @@ bool llvm::canCreatePoison(const Operator *Op) {
return ::canCreateUndefOrPoison(Op, /*PoisonOnly=*/true);
}
-bool llvm::impliesPoison(const Value *ValAssumedPoison, const Value *V) {
- // Construct a set of values which are known to be poison from the knowledge
- // that ValAssumedPoison is poison.
- SmallPtrSet<const Value *, 4> PoisonValues;
- PoisonValues.insert(ValAssumedPoison);
- const Instruction *PoisonI = dyn_cast<Instruction>(ValAssumedPoison);
- unsigned Depth = 0;
- const unsigned MaxDepth = 2;
-
- while (PoisonI && Depth < MaxDepth) {
- // We'd like to know whether an operand of PoisonI is also poison.
- if (canCreatePoison(cast<Operator>(PoisonI)))
- // PoisonI can be a poison-generating instruction, so don't look further
- break;
-
- const Value *NextVal = nullptr;
- bool MoreThanOneCandidate = false;
- // See which operand can be poison
- for (const auto &Op : PoisonI->operands()) {
- if (!isGuaranteedNotToBeUndefOrPoison(Op.get())) {
- // Op can be poison.
- if (NextVal) {
- // There is more than one operand that can make PoisonI poison.
- MoreThanOneCandidate = true;
- break;
- }
- NextVal = Op.get();
- }
- }
+static bool directlyImpliesPoison(const Value *ValAssumedPoison,
+ const Value *V, unsigned Depth) {
+ if (ValAssumedPoison == V)
+ return true;
- if (NextVal == nullptr) {
- // All operands are non-poison, so PoisonI cannot be poison.
- // Since assumption is false, return true
- return true;
- } else if (MoreThanOneCandidate)
- break;
+ const unsigned MaxDepth = 2;
+ if (Depth >= MaxDepth)
+ return false;
- Depth++;
- PoisonValues.insert(NextVal);
- PoisonI = dyn_cast<Instruction>(NextVal);
+ const auto *I = dyn_cast<Instruction>(V);
+ if (I && propagatesPoison(cast<Operator>(I))) {
+ return any_of(I->operands(), [=](const Value *Op) {
+ return directlyImpliesPoison(ValAssumedPoison, Op, Depth + 1);
+ });
}
+ return false;
+}
- if (PoisonValues.contains(V))
+static bool impliesPoison(const Value *ValAssumedPoison, const Value *V,
+ unsigned Depth) {
+ if (isGuaranteedNotToBeUndefOrPoison(ValAssumedPoison))
return true;
- // Let's look one level further, by seeing its arguments if I was an
- // instruction.
- // This happens when I is e.g. 'icmp X, const' where X is in PoisonValues.
- const auto *I = dyn_cast<Instruction>(V);
- if (I && propagatesPoison(cast<Operator>(I))) {
- for (const auto &Op : I->operands())
- if (PoisonValues.count(Op.get()))
- return true;
- }
+ if (directlyImpliesPoison(ValAssumedPoison, V, /* Depth */ 0))
+ return true;
+ const unsigned MaxDepth = 2;
+ if (Depth >= MaxDepth)
+ return false;
+
+ const auto *I = dyn_cast<Instruction>(ValAssumedPoison);
+ if (I && !canCreatePoison(cast<Operator>(I))) {
+ return all_of(I->operands(), [=](const Value *Op) {
+ return impliesPoison(Op, V, Depth + 1);
+ });
+ }
return false;
}
+bool llvm::impliesPoison(const Value *ValAssumedPoison, const Value *V) {
+ return ::impliesPoison(ValAssumedPoison, V, /* Depth */ 0);
+}
+
static bool programUndefinedIfUndefOrPoison(const Value *V,
bool PoisonOnly);