mirror of
https://github.com/RPCSX/llvm.git
synced 2025-02-03 11:08:32 +00:00
InstSimplify: Simplify trivial and/or of icmps
Some ICmpInsts when anded/ored with another ICmpInst trivially reduces to true or false depending on whether or not all integers or no integers satisfy the intersected/unioned range. This sort of trivial looking code can come about when InstCombine performs a range reduction-type operation on sdiv and the like. This fixes PR20916. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@217750 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
740506d9ca
commit
c3e70ca886
@ -1414,6 +1414,54 @@ Value *llvm::SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
// Simplify (and (icmp ...) (icmp ...)) to true when we can tell that the range
|
||||
// of possible values cannot be satisfied.
|
||||
static Value *SimplifyAndOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
|
||||
ICmpInst::Predicate Pred0, Pred1;
|
||||
ConstantInt *CI1, *CI2;
|
||||
Value *V;
|
||||
if (!match(Op0, m_ICmp(Pred0, m_Add(m_Value(V), m_ConstantInt(CI1)),
|
||||
m_ConstantInt(CI2))))
|
||||
return nullptr;
|
||||
|
||||
if (!match(Op1, m_ICmp(Pred1, m_Specific(V), m_Specific(CI1))))
|
||||
return nullptr;
|
||||
|
||||
Type *ITy = Op0->getType();
|
||||
|
||||
auto *AddInst = cast<BinaryOperator>(Op0->getOperand(0));
|
||||
bool isNSW = AddInst->hasNoSignedWrap();
|
||||
bool isNUW = AddInst->hasNoUnsignedWrap();
|
||||
|
||||
const APInt &CI1V = CI1->getValue();
|
||||
const APInt &CI2V = CI2->getValue();
|
||||
const APInt Delta = CI2V - CI1V;
|
||||
if (CI1V.isStrictlyPositive()) {
|
||||
if (Delta == 2) {
|
||||
if (Pred0 == ICmpInst::ICMP_ULT && Pred1 == ICmpInst::ICMP_SGT)
|
||||
return getFalse(ITy);
|
||||
if (Pred0 == ICmpInst::ICMP_SLT && Pred1 == ICmpInst::ICMP_SGT && isNSW)
|
||||
return getFalse(ITy);
|
||||
}
|
||||
if (Delta == 1) {
|
||||
if (Pred0 == ICmpInst::ICMP_ULE && Pred1 == ICmpInst::ICMP_SGT)
|
||||
return getFalse(ITy);
|
||||
if (Pred0 == ICmpInst::ICMP_SLE && Pred1 == ICmpInst::ICMP_SGT && isNSW)
|
||||
return getFalse(ITy);
|
||||
}
|
||||
}
|
||||
if (CI1V.getBoolValue() && isNUW) {
|
||||
if (Delta == 2)
|
||||
if (Pred0 == ICmpInst::ICMP_ULT && Pred1 == ICmpInst::ICMP_UGT)
|
||||
return getFalse(ITy);
|
||||
if (Delta == 1)
|
||||
if (Pred0 == ICmpInst::ICMP_ULE && Pred1 == ICmpInst::ICMP_UGT)
|
||||
return getFalse(ITy);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// SimplifyAndInst - Given operands for an And, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
static Value *SimplifyAndInst(Value *Op0, Value *Op1, const Query &Q,
|
||||
@ -1470,6 +1518,15 @@ static Value *SimplifyAndInst(Value *Op0, Value *Op1, const Query &Q,
|
||||
return Op1;
|
||||
}
|
||||
|
||||
if (auto *ICILHS = dyn_cast<ICmpInst>(Op0)) {
|
||||
if (auto *ICIRHS = dyn_cast<ICmpInst>(Op1)) {
|
||||
if (Value *V = SimplifyAndOfICmps(ICILHS, ICIRHS))
|
||||
return V;
|
||||
if (Value *V = SimplifyAndOfICmps(ICIRHS, ICILHS))
|
||||
return V;
|
||||
}
|
||||
}
|
||||
|
||||
// Try some generic simplifications for associative operations.
|
||||
if (Value *V = SimplifyAssociativeBinOp(Instruction::And, Op0, Op1, Q,
|
||||
MaxRecurse))
|
||||
@ -1510,6 +1567,54 @@ Value *llvm::SimplifyAndInst(Value *Op0, Value *Op1, const DataLayout *DL,
|
||||
RecursionLimit);
|
||||
}
|
||||
|
||||
// Simplify (or (icmp ...) (icmp ...)) to true when we can tell that the union
|
||||
// contains all possible values.
|
||||
static Value *SimplifyOrOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
|
||||
ICmpInst::Predicate Pred0, Pred1;
|
||||
ConstantInt *CI1, *CI2;
|
||||
Value *V;
|
||||
if (!match(Op0, m_ICmp(Pred0, m_Add(m_Value(V), m_ConstantInt(CI1)),
|
||||
m_ConstantInt(CI2))))
|
||||
return nullptr;
|
||||
|
||||
if (!match(Op1, m_ICmp(Pred1, m_Specific(V), m_Specific(CI1))))
|
||||
return nullptr;
|
||||
|
||||
Type *ITy = Op0->getType();
|
||||
|
||||
auto *AddInst = cast<BinaryOperator>(Op0->getOperand(0));
|
||||
bool isNSW = AddInst->hasNoSignedWrap();
|
||||
bool isNUW = AddInst->hasNoUnsignedWrap();
|
||||
|
||||
const APInt &CI1V = CI1->getValue();
|
||||
const APInt &CI2V = CI2->getValue();
|
||||
const APInt Delta = CI2V - CI1V;
|
||||
if (CI1V.isStrictlyPositive()) {
|
||||
if (Delta == 2) {
|
||||
if (Pred0 == ICmpInst::ICMP_UGE && Pred1 == ICmpInst::ICMP_SLE)
|
||||
return getTrue(ITy);
|
||||
if (Pred0 == ICmpInst::ICMP_SGE && Pred1 == ICmpInst::ICMP_SLE && isNSW)
|
||||
return getTrue(ITy);
|
||||
}
|
||||
if (Delta == 1) {
|
||||
if (Pred0 == ICmpInst::ICMP_UGT && Pred1 == ICmpInst::ICMP_SLE)
|
||||
return getTrue(ITy);
|
||||
if (Pred0 == ICmpInst::ICMP_SGT && Pred1 == ICmpInst::ICMP_SLE && isNSW)
|
||||
return getTrue(ITy);
|
||||
}
|
||||
}
|
||||
if (CI1V.getBoolValue() && isNUW) {
|
||||
if (Delta == 2)
|
||||
if (Pred0 == ICmpInst::ICMP_UGE && Pred1 == ICmpInst::ICMP_ULE)
|
||||
return getTrue(ITy);
|
||||
if (Delta == 1)
|
||||
if (Pred0 == ICmpInst::ICMP_UGT && Pred1 == ICmpInst::ICMP_ULE)
|
||||
return getTrue(ITy);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// SimplifyOrInst - Given operands for an Or, see if we can
|
||||
/// fold the result. If not, this returns null.
|
||||
static Value *SimplifyOrInst(Value *Op0, Value *Op1, const Query &Q,
|
||||
@ -1567,6 +1672,15 @@ static Value *SimplifyOrInst(Value *Op0, Value *Op1, const Query &Q,
|
||||
(A == Op0 || B == Op0))
|
||||
return Constant::getAllOnesValue(Op0->getType());
|
||||
|
||||
if (auto *ICILHS = dyn_cast<ICmpInst>(Op0)) {
|
||||
if (auto *ICIRHS = dyn_cast<ICmpInst>(Op1)) {
|
||||
if (Value *V = SimplifyOrOfICmps(ICILHS, ICIRHS))
|
||||
return V;
|
||||
if (Value *V = SimplifyOrOfICmps(ICIRHS, ICILHS))
|
||||
return V;
|
||||
}
|
||||
}
|
||||
|
||||
// Try some generic simplifications for associative operations.
|
||||
if (Value *V = SimplifyAssociativeBinOp(Instruction::Or, Op0, Op1, Q,
|
||||
MaxRecurse))
|
||||
|
@ -28,3 +28,123 @@ define i32 @sub_neg_nuw(i32 %x, i32 %y) {
|
||||
ret i32 %sub
|
||||
; CHECK: ret i32 %x
|
||||
}
|
||||
|
||||
define i1 @and_of_icmps0(i32 %b) {
|
||||
; CHECK-LABEL: @and_of_icmps0(
|
||||
%1 = add i32 %b, 2
|
||||
%2 = icmp ult i32 %1, 4
|
||||
%cmp3 = icmp sgt i32 %b, 2
|
||||
%cmp = and i1 %2, %cmp3
|
||||
ret i1 %cmp
|
||||
; CHECK: ret i1 false
|
||||
}
|
||||
|
||||
define i1 @and_of_icmps1(i32 %b) {
|
||||
; CHECK-LABEL: @and_of_icmps1(
|
||||
%1 = add nsw i32 %b, 2
|
||||
%2 = icmp slt i32 %1, 4
|
||||
%cmp3 = icmp sgt i32 %b, 2
|
||||
%cmp = and i1 %2, %cmp3
|
||||
ret i1 %cmp
|
||||
; CHECK: ret i1 false
|
||||
}
|
||||
|
||||
define i1 @and_of_icmps2(i32 %b) {
|
||||
; CHECK-LABEL: @and_of_icmps2(
|
||||
%1 = add i32 %b, 2
|
||||
%2 = icmp ule i32 %1, 3
|
||||
%cmp3 = icmp sgt i32 %b, 2
|
||||
%cmp = and i1 %2, %cmp3
|
||||
ret i1 %cmp
|
||||
; CHECK: ret i1 false
|
||||
}
|
||||
|
||||
define i1 @and_of_icmps3(i32 %b) {
|
||||
; CHECK-LABEL: @and_of_icmps3(
|
||||
%1 = add nsw i32 %b, 2
|
||||
%2 = icmp sle i32 %1, 3
|
||||
%cmp3 = icmp sgt i32 %b, 2
|
||||
%cmp = and i1 %2, %cmp3
|
||||
ret i1 %cmp
|
||||
; CHECK: ret i1 false
|
||||
}
|
||||
|
||||
define i1 @and_of_icmps4(i32 %b) {
|
||||
; CHECK-LABEL: @and_of_icmps4(
|
||||
%1 = add nuw i32 %b, 2
|
||||
%2 = icmp ult i32 %1, 4
|
||||
%cmp3 = icmp ugt i32 %b, 2
|
||||
%cmp = and i1 %2, %cmp3
|
||||
ret i1 %cmp
|
||||
; CHECK: ret i1 false
|
||||
}
|
||||
|
||||
define i1 @and_of_icmps5(i32 %b) {
|
||||
; CHECK-LABEL: @and_of_icmps5(
|
||||
%1 = add nuw i32 %b, 2
|
||||
%2 = icmp ule i32 %1, 3
|
||||
%cmp3 = icmp ugt i32 %b, 2
|
||||
%cmp = and i1 %2, %cmp3
|
||||
ret i1 %cmp
|
||||
; CHECK: ret i1 false
|
||||
}
|
||||
|
||||
define i1 @or_of_icmps0(i32 %b) {
|
||||
; CHECK-LABEL: @or_of_icmps0(
|
||||
%1 = add i32 %b, 2
|
||||
%2 = icmp uge i32 %1, 4
|
||||
%cmp3 = icmp sle i32 %b, 2
|
||||
%cmp = or i1 %2, %cmp3
|
||||
ret i1 %cmp
|
||||
; CHECK: ret i1 true
|
||||
}
|
||||
|
||||
define i1 @or_of_icmps1(i32 %b) {
|
||||
; CHECK-LABEL: @or_of_icmps1(
|
||||
%1 = add nsw i32 %b, 2
|
||||
%2 = icmp sge i32 %1, 4
|
||||
%cmp3 = icmp sle i32 %b, 2
|
||||
%cmp = or i1 %2, %cmp3
|
||||
ret i1 %cmp
|
||||
; CHECK: ret i1 true
|
||||
}
|
||||
|
||||
define i1 @or_of_icmps2(i32 %b) {
|
||||
; CHECK-LABEL: @or_of_icmps2(
|
||||
%1 = add i32 %b, 2
|
||||
%2 = icmp ugt i32 %1, 3
|
||||
%cmp3 = icmp sle i32 %b, 2
|
||||
%cmp = or i1 %2, %cmp3
|
||||
ret i1 %cmp
|
||||
; CHECK: ret i1 true
|
||||
}
|
||||
|
||||
define i1 @or_of_icmps3(i32 %b) {
|
||||
; CHECK-LABEL: @or_of_icmps3(
|
||||
%1 = add nsw i32 %b, 2
|
||||
%2 = icmp sgt i32 %1, 3
|
||||
%cmp3 = icmp sle i32 %b, 2
|
||||
%cmp = or i1 %2, %cmp3
|
||||
ret i1 %cmp
|
||||
; CHECK: ret i1 true
|
||||
}
|
||||
|
||||
define i1 @or_of_icmps4(i32 %b) {
|
||||
; CHECK-LABEL: @or_of_icmps4(
|
||||
%1 = add nuw i32 %b, 2
|
||||
%2 = icmp uge i32 %1, 4
|
||||
%cmp3 = icmp ule i32 %b, 2
|
||||
%cmp = or i1 %2, %cmp3
|
||||
ret i1 %cmp
|
||||
; CHECK: ret i1 true
|
||||
}
|
||||
|
||||
define i1 @or_of_icmps5(i32 %b) {
|
||||
; CHECK-LABEL: @or_of_icmps5(
|
||||
%1 = add nuw i32 %b, 2
|
||||
%2 = icmp ugt i32 %1, 3
|
||||
%cmp3 = icmp ule i32 %b, 2
|
||||
%cmp = or i1 %2, %cmp3
|
||||
ret i1 %cmp
|
||||
; CHECK: ret i1 true
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user