aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/ValueTracking.cpp
diff options
context:
space:
mode:
authorWilliam Huang <williamjhuang@google.com>2022-06-07 18:48:24 +0000
committerWilliam Huang <williamjhuang@google.com>2022-06-07 18:52:31 +0000
commitba26e45ca9238fe7449f435496ba44750374b30e (patch)
tree7a39d635d73675a4074ffe8e75833fb722d508c6 /llvm/lib/Analysis/ValueTracking.cpp
parent570e76bb6c79bce0718aa55915a4361e361b954f (diff)
downloadllvm-ba26e45ca9238fe7449f435496ba44750374b30e.zip
llvm-ba26e45ca9238fe7449f435496ba44750374b30e.tar.gz
llvm-ba26e45ca9238fe7449f435496ba44750374b30e.tar.bz2
[ValueTracking] Add support to deduce a PHI node being a power of 2 if each incoming value is a power of 2.
Reviewed By: davidxl Differential Revision: https://reviews.llvm.org/D124889
Diffstat (limited to 'llvm/lib/Analysis/ValueTracking.cpp')
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp64
1 files changed, 63 insertions, 1 deletions
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index b27ceee..521f516 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -2036,6 +2036,63 @@ void computeKnownBits(const Value *V, const APInt &DemandedElts,
assert((Known.Zero & Known.One) == 0 && "Bits known to be one AND zero?");
}
+/// Try to detect a recurrence that the value of the induction variable is
+/// always a power of two (or zero).
+static bool isPowerOfTwoRecurrence(const PHINode *PN, bool OrZero,
+ unsigned Depth, Query &Q) {
+ BinaryOperator *BO = nullptr;
+ Value *Start = nullptr, *Step = nullptr;
+ if (!matchSimpleRecurrence(PN, BO, Start, Step))
+ return false;
+
+ // Initial value must be a power of two.
+ for (const Use &U : PN->operands()) {
+ if (U.get() == Start) {
+ // Initial value comes from a different BB, need to adjust context
+ // instruction for analysis.
+ Q.CxtI = PN->getIncomingBlock(U)->getTerminator();
+ if (!isKnownToBeAPowerOfTwo(Start, OrZero, Depth, Q))
+ return false;
+ }
+ }
+
+ // Except for Mul, the induction variable must be on the left side of the
+ // increment expression, otherwise its value can be arbitrary.
+ if (BO->getOpcode() != Instruction::Mul && BO->getOperand(1) != Step)
+ return false;
+
+ Q.CxtI = BO->getParent()->getTerminator();
+ switch (BO->getOpcode()) {
+ case Instruction::Mul:
+ // Power of two is closed under multiplication.
+ return (OrZero || Q.IIQ.hasNoUnsignedWrap(BO) ||
+ Q.IIQ.hasNoSignedWrap(BO)) &&
+ isKnownToBeAPowerOfTwo(Step, OrZero, Depth, Q);
+ case Instruction::SDiv:
+ // Start value must not be signmask for signed division, so simply being a
+ // power of two is not sufficient, and it has to be a constant.
+ if (!match(Start, m_Power2()) || match(Start, m_SignMask()))
+ return false;
+ LLVM_FALLTHROUGH;
+ case Instruction::UDiv:
+ // Divisor must be a power of two.
+ // If OrZero is false, cannot guarantee induction variable is non-zero after
+ // division, same for Shr, unless it is exact division.
+ return (OrZero || Q.IIQ.isExact(BO)) &&
+ isKnownToBeAPowerOfTwo(Step, false, Depth, Q);
+ case Instruction::Shl:
+ return OrZero || Q.IIQ.hasNoUnsignedWrap(BO) || Q.IIQ.hasNoSignedWrap(BO);
+ case Instruction::AShr:
+ if (!match(Start, m_Power2()) || match(Start, m_SignMask()))
+ return false;
+ LLVM_FALLTHROUGH;
+ case Instruction::LShr:
+ return OrZero || Q.IIQ.isExact(BO);
+ default:
+ return false;
+ }
+}
+
/// Return true if the given value is known to have exactly one
/// bit set when defined. For vectors return true if every element is known to
/// be a power of two when defined. Supports values with integer or pointer
@@ -2127,10 +2184,15 @@ bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero, unsigned Depth,
}
}
- // A PHI node is power of two if all incoming values are power of two.
+ // A PHI node is power of two if all incoming values are power of two, or if
+ // it is an induction variable where in each step its value is a power of two.
if (const PHINode *PN = dyn_cast<PHINode>(V)) {
Query RecQ = Q;
+ // Check if it is an induction variable and always power of two.
+ if (isPowerOfTwoRecurrence(PN, OrZero, Depth, RecQ))
+ return true;
+
// Recursively check all incoming values. Limit recursion to 2 levels, so
// that search complexity is limited to number of operands^2.
unsigned NewDepth = std::max(Depth, MaxAnalysisRecursionDepth - 1);