diff options
| -rw-r--r-- | llvm/lib/Analysis/ValueTracking.cpp | 5 | ||||
| -rw-r--r-- | llvm/test/Analysis/ValueTracking/known-power-of-two.ll | 20 |
2 files changed, 23 insertions, 2 deletions
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 314ec9c1886..d6a78411388 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -1743,9 +1743,10 @@ bool isKnownToBeAPowerOfTwo(Value *V, bool OrZero, unsigned Depth, return false; Value *X = nullptr, *Y = nullptr; - // A shift of a power of two is a power of two or zero. + // A shift left or a logical shift right of a power of two is a power of two + // or zero. if (OrZero && (match(V, m_Shl(m_Value(X), m_Value())) || - match(V, m_Shr(m_Value(X), m_Value())))) + match(V, m_LShr(m_Value(X), m_Value())))) return isKnownToBeAPowerOfTwo(X, /*OrZero*/ true, Depth, Q, DL); if (ZExtInst *ZI = dyn_cast<ZExtInst>(V)) diff --git a/llvm/test/Analysis/ValueTracking/known-power-of-two.ll b/llvm/test/Analysis/ValueTracking/known-power-of-two.ll new file mode 100644 index 00000000000..ed98a8f5361 --- /dev/null +++ b/llvm/test/Analysis/ValueTracking/known-power-of-two.ll @@ -0,0 +1,20 @@ +; RUN: opt -S -instcombine < %s | FileCheck %s + +; https://llvm.org/bugs/show_bug.cgi?id=25900 +; An arithmetic shift right of a power of two is not a power +; of two if the original value is the sign bit. Therefore, +; we can't transform the sdiv into a udiv. + +define i32 @pr25900(i32 %d) { + %and = and i32 %d, -2147483648 +; The next 3 lines prevent another fold from masking the bug. + %ext = zext i32 %and to i64 + %or = or i64 %ext, 4294967296 + %trunc = trunc i64 %or to i32 + %ashr = ashr exact i32 %trunc, 31 + %div = sdiv i32 4, %ashr + ret i32 %div + +; CHECK: sdiv +} + |

