From 3a73e343d02ba3a00adf03311183cc0ccc960978 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 4 Mar 2011 07:00:57 +0000 Subject: [PATCH] Teach instruction simplify to use constant ranges to solve problems of the form "icmp pred %X, CI" and a number of examples where "%X = binop %Y, CI2". Some of these cases (div and rem) used to make it through opt -O2, but the others are probably now making code elsewhere redundant (probably instcombine). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@126988 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/InstructionSimplify.cpp | 98 +++++++++++++++---------- test/Transforms/InstSimplify/compare.ll | 80 +++++++++++++++++++- 2 files changed, 137 insertions(+), 41 deletions(-) diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp index c23abb78089..3cfb2b7637e 100644 --- a/lib/Analysis/InstructionSimplify.cpp +++ b/lib/Analysis/InstructionSimplify.cpp @@ -23,6 +23,7 @@ #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" @@ -1399,44 +1400,67 @@ static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, // See if we are doing a comparison with a constant integer. if (ConstantInt *CI = dyn_cast(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 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 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()); - // TODO: integer div and rem with constant RHS all produce values in a - // constant range. We should check whether the comparison is a tautology. + // 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()); + } } // Compare of cast, for example (zext X) != 0 -> X != 0 diff --git a/test/Transforms/InstSimplify/compare.ll b/test/Transforms/InstSimplify/compare.ll index f392d3a5e7c..44c678c6f11 100644 --- a/test/Transforms/InstSimplify/compare.ll +++ b/test/Transforms/InstSimplify/compare.ll @@ -137,22 +137,38 @@ define i1 @shl(i32 %x) { ; 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 @@ -203,3 +219,59 @@ define i1 @urem2(i32 %X, i32 %Y) { 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 +}