forked from OSchip/llvm-project
[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:
parent
3d712c46e6
commit
cca8f7853f
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue