#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/Support/ConstantRange.h"
#include "llvm/Support/PatternMatch.h"
#include "llvm/Support/ValueHandle.h"
#include "llvm/Target/TargetData.h"
// See if we are doing a comparison with a constant integer.
if (ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
- switch (Pred) {
- default: break;
- case ICmpInst::ICMP_UGT:
- if (CI->isMaxValue(false)) // A >u MAX -> FALSE
- return ConstantInt::getFalse(CI->getContext());
- break;
- case ICmpInst::ICMP_UGE:
- if (CI->isMinValue(false)) // A >=u MIN -> TRUE
- return ConstantInt::getTrue(CI->getContext());
- break;
- case ICmpInst::ICMP_ULT:
- if (CI->isMinValue(false)) // A <u MIN -> FALSE
- return ConstantInt::getFalse(CI->getContext());
- break;
- case ICmpInst::ICMP_ULE:
- if (CI->isMaxValue(false)) // A <=u MAX -> TRUE
- return ConstantInt::getTrue(CI->getContext());
- break;
- case ICmpInst::ICMP_SGT:
- if (CI->isMaxValue(true)) // A >s MAX -> FALSE
- return ConstantInt::getFalse(CI->getContext());
- break;
- case ICmpInst::ICMP_SGE:
- if (CI->isMinValue(true)) // A >=s MIN -> TRUE
- return ConstantInt::getTrue(CI->getContext());
- break;
- case ICmpInst::ICMP_SLT:
- if (CI->isMinValue(true)) // A <s MIN -> FALSE
- return ConstantInt::getFalse(CI->getContext());
- break;
- case ICmpInst::ICMP_SLE:
- if (CI->isMaxValue(true)) // A <=s MAX -> TRUE
- return ConstantInt::getTrue(CI->getContext());
- break;
+ // Rule out tautological comparisons (eg., ult 0 or uge 0).
+ ConstantRange RHS_CR = ICmpInst::makeConstantRange(Pred, CI->getValue());
+ if (RHS_CR.isEmptySet())
+ return ConstantInt::getFalse(CI->getContext());
+ if (RHS_CR.isFullSet())
+ return ConstantInt::getTrue(CI->getContext());
+
+ // Many binary operators with constant RHS have easy to compute constant
+ // range. Use them to check whether the comparison is a tautology.
+ uint32_t Width = CI->getBitWidth();
+ APInt Lower = APInt(Width, 0);
+ APInt Upper = APInt(Width, 0);
+ ConstantInt *CI2;
+ if (match(LHS, m_URem(m_Value(), m_ConstantInt(CI2)))) {
+ // 'urem x, CI2' produces [0, CI2).
+ Upper = CI2->getValue();
+ } else if (match(LHS, m_SRem(m_Value(), m_ConstantInt(CI2)))) {
+ // 'srem x, CI2' produces (-|CI2|, |CI2|).
+ Upper = CI2->getValue().abs();
+ Lower = (-Upper) + 1;
+ } else if (match(LHS, m_UDiv(m_Value(), m_ConstantInt(CI2)))) {
+ // 'udiv x, CI2' produces [0, UINT_MAX / CI2].
+ APInt NegOne = APInt::getAllOnesValue(Width);
+ if (!CI2->isZero())
+ Upper = NegOne.udiv(CI2->getValue()) + 1;
+ } else if (match(LHS, m_SDiv(m_Value(), m_ConstantInt(CI2)))) {
+ // 'sdiv x, CI2' produces [INT_MIN / CI2, INT_MAX / CI2].
+ APInt IntMin = APInt::getSignedMinValue(Width);
+ APInt IntMax = APInt::getSignedMaxValue(Width);
+ APInt Val = CI2->getValue().abs();
+ if (!Val.isMinValue()) {
+ Lower = IntMin.sdiv(Val);
+ Upper = IntMax.sdiv(Val) + 1;
+ }
+ } else if (match(LHS, m_LShr(m_Value(), m_ConstantInt(CI2)))) {
+ // 'lshr x, CI2' produces [0, UINT_MAX >> CI2].
+ APInt NegOne = APInt::getAllOnesValue(Width);
+ if (CI2->getValue().ult(Width))
+ Upper = NegOne.lshr(CI2->getValue()) + 1;
+ } else if (match(LHS, m_AShr(m_Value(), m_ConstantInt(CI2)))) {
+ // 'ashr x, CI2' produces [INT_MIN >> CI2, INT_MAX >> CI2].
+ APInt IntMin = APInt::getSignedMinValue(Width);
+ APInt IntMax = APInt::getSignedMaxValue(Width);
+ if (CI2->getValue().ult(Width)) {
+ Lower = IntMin.ashr(CI2->getValue());
+ Upper = IntMax.ashr(CI2->getValue()) + 1;
+ }
+ } else if (match(LHS, m_Or(m_Value(), m_ConstantInt(CI2)))) {
+ // 'or x, CI2' produces [CI2, UINT_MAX].
+ Lower = CI2->getValue();
+ } else if (match(LHS, m_And(m_Value(), m_ConstantInt(CI2)))) {
+ // 'and x, CI2' produces [0, CI2].
+ Upper = CI2->getValue() + 1;
+ }
+ if (Lower != Upper) {
+ ConstantRange LHS_CR = ConstantRange(Lower, Upper);
+ if (RHS_CR.contains(LHS_CR))
+ return ConstantInt::getTrue(RHS->getContext());
+ if (RHS_CR.inverse().contains(LHS_CR))
+ return ConstantInt::getFalse(RHS->getContext());
}
-
- // TODO: integer div and rem with constant RHS all produce values in a
- // constant range. We should check whether the comparison is a tautology.
}
// Compare of cast, for example (zext X) != 0 -> X != 0
; CHECK: ret i1 false
}
-define i1 @lshr(i32 %x) {
-; CHECK: @lshr
+define i1 @lshr1(i32 %x) {
+; CHECK: @lshr1
%s = lshr i32 -1, %x
%c = icmp eq i32 %s, 0
ret i1 %c
; CHECK: ret i1 false
}
-define i1 @ashr(i32 %x) {
-; CHECK: @ashr
+define i1 @lshr2(i32 %x) {
+; CHECK: @lshr2
+ %s = lshr i32 %x, 30
+ %c = icmp ugt i32 %s, 8
+ ret i1 %c
+; CHECK: ret i1 false
+}
+
+define i1 @ashr1(i32 %x) {
+; CHECK: @ashr1
%s = ashr i32 -1, %x
%c = icmp eq i32 %s, 0
ret i1 %c
; CHECK: ret i1 false
}
+define i1 @ashr2(i32 %x) {
+; CHECK: @ashr2
+ %s = ashr i32 %x, 30
+ %c = icmp slt i32 %s, -5
+ ret i1 %c
+; CHECK: ret i1 false
+}
+
define i1 @select1(i1 %cond) {
; CHECK: @select1
%s = select i1 %cond, i32 1, i32 0
ret i1 %B
; CHECK ret i1 false
}
+
+define i1 @urem3(i32 %X) {
+; CHECK: @urem3
+ %A = urem i32 %X, 10
+ %B = icmp ult i32 %A, 15
+ ret i1 %B
+; CHECK: ret i1 true
+}
+
+define i1 @urem4(i32 %X) {
+; CHECK: @urem4
+ %A = urem i32 %X, 15
+ %B = icmp ult i32 %A, 10
+ ret i1 %B
+; CHECK: ret i1 %B
+}
+
+define i1 @srem1(i32 %X) {
+; CHECK: @srem1
+ %A = srem i32 %X, -5
+ %B = icmp sgt i32 %A, 5
+ ret i1 %B
+; CHECK: ret i1 false
+}
+
+define i1 @udiv1(i32 %X) {
+; CHECK: @udiv1
+ %A = udiv i32 %X, 1000000
+ %B = icmp ult i32 %A, 5000
+ ret i1 %B
+; CHECK: ret i1 true
+}
+
+define i1 @sdiv1(i32 %X) {
+; CHECK: @sdiv1
+ %A = sdiv i32 %X, 1000000
+ %B = icmp slt i32 %A, 3000
+ ret i1 %B
+; CHECK: ret i1 true
+}
+
+define i1 @or1(i32 %X) {
+; CHECK: @or1
+ %A = or i32 %X, 62
+ %B = icmp ult i32 %A, 50
+ ret i1 %B
+; CHECK: ret i1 false
+}
+
+define i1 @and1(i32 %X) {
+; CHECK: @and1
+ %A = and i32 %X, 62
+ %B = icmp ugt i32 %A, 70
+ ret i1 %B
+; CHECK: ret i1 false
+}