mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-12 13:30:51 +00:00
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
This commit is contained in:
parent
86d822df6d
commit
3a73e343d0
@ -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<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());
|
||||
|
||||
// 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
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user