[InstSimplify] clean up div/rem handling; NFCI

The idea to make an 'isDivZero' helper was suggested for the signed case in D37713:
https://reviews.llvm.org/D37713

This clean-up makes it clear that D37713 is just filling the gap for signed div/rem,
removes unnecessary code, and allows us to remove a bit of duplicated code from the
planned improvement in D37713.

llvm-svn: 313261
This commit is contained in:
Sanjay Patel 2017-09-14 14:09:11 +00:00
parent 3d712c46e6
commit cca8f7853f
1 changed files with 44 additions and 54 deletions

View File

@ -905,6 +905,34 @@ static Value *simplifyDivRem(Value *Op0, Value *Op1, bool IsDiv) {
return nullptr;
}
/// Given a predicate and two operands, return true if the comparison is true.
/// This is a helper for div/rem simplification where we return some other value
/// when we can prove a relationship between the operands.
static bool isICmpTrue(ICmpInst::Predicate Pred, Value *LHS, Value *RHS,
const SimplifyQuery &Q, unsigned MaxRecurse) {
Value *V = SimplifyICmpInst(Pred, LHS, RHS, Q, MaxRecurse);
Constant *C = dyn_cast_or_null<Constant>(V);
return (C && C->isAllOnesValue());
}
/// Return true if we can simplify X / Y to 0. Remainder can adapt that answer
/// to simplify X % Y to X.
static bool isDivZero(Value *Op0, Value *Op1, const SimplifyQuery &Q,
unsigned MaxRecurse, bool IsSigned) {
// Recursion is always used, so bail out at once if we already hit the limit.
if (!MaxRecurse--)
return false;
if (IsSigned) {
// TODO: Handle signed.
return false;
}
// IsSigned == false.
// Is the quotient unsigned less than the divisor?
return isICmpTrue(ICmpInst::ICMP_ULT, Op0, Op1, Q, MaxRecurse);
}
/// These are simplifications common to SDiv and UDiv.
static Value *simplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
const SimplifyQuery &Q, unsigned MaxRecurse) {
@ -914,7 +942,7 @@ static Value *simplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
if (Value *V = simplifyDivRem(Op0, Op1, true))
return V;
bool isSigned = Opcode == Instruction::SDiv;
bool IsSigned = Opcode == Instruction::SDiv;
// (X * Y) / Y -> X if the multiplication does not overflow.
Value *X = nullptr, *Y = nullptr;
@ -922,8 +950,8 @@ static Value *simplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
if (Y != Op1) std::swap(X, Y); // Ensure expression is (X * Y) / Y, Y = Op1
OverflowingBinaryOperator *Mul = cast<OverflowingBinaryOperator>(Op0);
// If the Mul knows it does not overflow, then we are good to go.
if ((isSigned && Mul->hasNoSignedWrap()) ||
(!isSigned && Mul->hasNoUnsignedWrap()))
if ((IsSigned && Mul->hasNoSignedWrap()) ||
(!IsSigned && Mul->hasNoUnsignedWrap()))
return X;
// If X has the form X = A / Y then X * Y cannot overflow.
if (BinaryOperator *Div = dyn_cast<BinaryOperator>(X))
@ -932,13 +960,13 @@ static Value *simplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
}
// (X rem Y) / Y -> 0
if ((isSigned && match(Op0, m_SRem(m_Value(), m_Specific(Op1)))) ||
(!isSigned && match(Op0, m_URem(m_Value(), m_Specific(Op1)))))
if ((IsSigned && match(Op0, m_SRem(m_Value(), m_Specific(Op1)))) ||
(!IsSigned && match(Op0, m_URem(m_Value(), m_Specific(Op1)))))
return Constant::getNullValue(Op0->getType());
// (X /u C1) /u C2 -> 0 if C1 * C2 overflow
ConstantInt *C1, *C2;
if (!isSigned && match(Op0, m_UDiv(m_Value(X), m_ConstantInt(C1))) &&
if (!IsSigned && match(Op0, m_UDiv(m_Value(X), m_ConstantInt(C1))) &&
match(Op1, m_ConstantInt(C2))) {
bool Overflow;
(void)C1->getValue().umul_ov(C2->getValue(), Overflow);
@ -958,6 +986,9 @@ static Value *simplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
if (Value *V = ThreadBinOpOverPHI(Opcode, Op0, Op1, Q, MaxRecurse))
return V;
if (isDivZero(Op0, Op1, Q, MaxRecurse, IsSigned))
return Constant::getNullValue(Op0->getType());
return nullptr;
}
@ -989,32 +1020,9 @@ static Value *simplifyRem(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
if (Value *V = ThreadBinOpOverPHI(Opcode, Op0, Op1, Q, MaxRecurse))
return V;
return nullptr;
}
/// Given a predicate and two operands, return true if the comparison is true.
/// This is a helper for div/rem simplification where we return some other value
/// when we can prove a relationship between the operands.
static bool isICmpTrue(ICmpInst::Predicate Pred, Value *LHS, Value *RHS,
const SimplifyQuery &Q, unsigned MaxRecurse) {
Value *V = SimplifyICmpInst(Pred, LHS, RHS, Q, MaxRecurse);
Constant *C = dyn_cast_or_null<Constant>(V);
return (C && C->isAllOnesValue());
}
static Value *simplifyUnsignedDivRem(Value *Op0, Value *Op1,
const SimplifyQuery &Q,
unsigned MaxRecurse, bool IsDiv) {
// Recursion is always used, so bail out at once if we already hit the limit.
if (!MaxRecurse--)
return nullptr;
// If we can prove that the quotient is unsigned less than the divisor, then
// we know the answer:
// X / Y --> 0
// X % Y --> X
if (isICmpTrue(ICmpInst::ICMP_ULT, Op0, Op1, Q, MaxRecurse))
return IsDiv ? Constant::getNullValue(Op0->getType()) : Op0;
// If X / Y == 0, then X % Y == X.
if (isDivZero(Op0, Op1, Q, MaxRecurse, Opcode == Instruction::SRem))
return Op0;
return nullptr;
}
@ -1023,10 +1031,7 @@ static Value *simplifyUnsignedDivRem(Value *Op0, Value *Op1,
/// If not, this returns null.
static Value *SimplifySDivInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
unsigned MaxRecurse) {
if (Value *V = simplifyDiv(Instruction::SDiv, Op0, Op1, Q, MaxRecurse))
return V;
return nullptr;
return simplifyDiv(Instruction::SDiv, Op0, Op1, Q, MaxRecurse);
}
Value *llvm::SimplifySDivInst(Value *Op0, Value *Op1, const SimplifyQuery &Q) {
@ -1037,13 +1042,7 @@ Value *llvm::SimplifySDivInst(Value *Op0, Value *Op1, const SimplifyQuery &Q) {
/// If not, this returns null.
static Value *SimplifyUDivInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
unsigned MaxRecurse) {
if (Value *V = simplifyDiv(Instruction::UDiv, Op0, Op1, Q, MaxRecurse))
return V;
if (Value *V = simplifyUnsignedDivRem(Op0, Op1, Q, MaxRecurse, true))
return V;
return nullptr;
return simplifyDiv(Instruction::UDiv, Op0, Op1, Q, MaxRecurse);
}
Value *llvm::SimplifyUDivInst(Value *Op0, Value *Op1, const SimplifyQuery &Q) {
@ -1054,10 +1053,7 @@ Value *llvm::SimplifyUDivInst(Value *Op0, Value *Op1, const SimplifyQuery &Q) {
/// If not, this returns null.
static Value *SimplifySRemInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
unsigned MaxRecurse) {
if (Value *V = simplifyRem(Instruction::SRem, Op0, Op1, Q, MaxRecurse))
return V;
return nullptr;
return simplifyRem(Instruction::SRem, Op0, Op1, Q, MaxRecurse);
}
Value *llvm::SimplifySRemInst(Value *Op0, Value *Op1, const SimplifyQuery &Q) {
@ -1068,13 +1064,7 @@ Value *llvm::SimplifySRemInst(Value *Op0, Value *Op1, const SimplifyQuery &Q) {
/// If not, this returns null.
static Value *SimplifyURemInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
unsigned MaxRecurse) {
if (Value *V = simplifyRem(Instruction::URem, Op0, Op1, Q, MaxRecurse))
return V;
if (Value *V = simplifyUnsignedDivRem(Op0, Op1, Q, MaxRecurse, false))
return V;
return nullptr;
return simplifyRem(Instruction::URem, Op0, Op1, Q, MaxRecurse);
}
Value *llvm::SimplifyURemInst(Value *Op0, Value *Op1, const SimplifyQuery &Q) {