Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Changeset View
Standalone View
llvm/lib/Analysis/InstructionSimplify.cpp
Show First 20 Lines • Show All 986 Lines • ▼ Show 20 Lines | static Value *simplifyMulInst(Value *Op0, Value *Op1, bool IsNSW, bool IsNUW, | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
Value *llvm::simplifyMulInst(Value *Op0, Value *Op1, bool IsNSW, bool IsNUW, | Value *llvm::simplifyMulInst(Value *Op0, Value *Op1, bool IsNSW, bool IsNUW, | ||||
const SimplifyQuery &Q) { | const SimplifyQuery &Q) { | ||||
return ::simplifyMulInst(Op0, Op1, IsNSW, IsNUW, Q, RecursionLimit); | return ::simplifyMulInst(Op0, Op1, IsNSW, IsNUW, Q, RecursionLimit); | ||||
} | } | ||||
/// Check for common or similar folds of integer division or integer remainder. | /// Check for common or similar folds of integer division or integer remainder. | ||||
goldstein.w.n: Instead of a new helper maybe this should be in `simplifyRem` which already appears to have… | |||||
I've inlined it into simplifyRem which I think looks a lot neater now. Thank you for the feedback. MattDevereau: I've inlined it into `simplifyRem` which I think looks a lot neater now. Thank you for the… | |||||
/// This applies to all 4 opcodes (sdiv/udiv/srem/urem). | /// This applies to all 4 opcodes (sdiv/udiv/srem/urem). | ||||
static Value *simplifyDivRem(Instruction::BinaryOps Opcode, Value *Op0, | static Value *simplifyDivRem(Instruction::BinaryOps Opcode, Value *Op0, | ||||
Not Done ReplyInline ActionsMaybe add a TODO for the more generalized case of (rem (mul nsw/nuw X, C1), (mul nsw/nuw X, C2) if C1 % C2 == 0 -> 0 We seem to be missing it: https://godbolt.org/z/fzxb4sxb5 goldstein.w.n: Maybe add a `TODO` for the more generalized case of `(rem (mul nsw/nuw X, C1), (mul nsw/nuw X… | |||||
Value *Op1, const SimplifyQuery &Q, | Value *Op1, const SimplifyQuery &Q, | ||||
unsigned MaxRecurse) { | unsigned MaxRecurse) { | ||||
bool IsDiv = (Opcode == Instruction::SDiv || Opcode == Instruction::UDiv); | bool IsDiv = (Opcode == Instruction::SDiv || Opcode == Instruction::UDiv); | ||||
bool IsSigned = (Opcode == Instruction::SDiv || Opcode == Instruction::SRem); | bool IsSigned = (Opcode == Instruction::SDiv || Opcode == Instruction::SRem); | ||||
Type *Ty = Op0->getType(); | Type *Ty = Op0->getType(); | ||||
// X / undef -> poison | // X / undef -> poison | ||||
// X % undef -> poison | // X % undef -> poison | ||||
Not Done ReplyInline ActionsPerhaps you can create a temp variable here to reuse the logic, i.e. bool NoWrap = (IsSigned && Q.IIQ.hasNoSignedWrap(Shift)) || (!IsSigned && Q.IIQ.hasNoUnsignedWrap(Shift)); if (S1 >= S2 && NoWrap) return Constant::getNullValue(Shift->getType()); if (NoWrap) return Op0; david-arm: Perhaps you can create a temp variable here to reuse the logic, i.e.
bool NoWrap = (IsSigned… | |||||
I'm not sure this suggestion is correct, they key thing here being Shift = cast<OverflowingBinaryOperator>(Op1); on line 1010 which changes Shift to be a cast of Op1 instead of Op0 on which the nsw/nuw flags are checked, which is because the larger shift value needs its flags checking. If we went ahead with this, in this example (https://alive2.llvm.org/ce/z/YiFELt) NoWrap would evaluate to true while the transform is not viable. MattDevereau: I'm not sure this suggestion is correct, they key thing here being `Shift =… | |||||
if (Q.isUndefValue(Op1) || isa<PoisonValue>(Op1)) | if (Q.isUndefValue(Op1) || isa<PoisonValue>(Op1)) | ||||
return PoisonValue::get(Ty); | return PoisonValue::get(Ty); | ||||
// X / 0 -> poison | // X / 0 -> poison | ||||
// X % 0 -> poison | // X % 0 -> poison | ||||
// We don't need to preserve faults! | // We don't need to preserve faults! | ||||
if (match(Op1, m_Zero())) | if (match(Op1, m_Zero())) | ||||
return PoisonValue::get(Ty); | return PoisonValue::get(Ty); | ||||
▲ Show 20 Lines • Show All 208 Lines • ▼ Show 20 Lines | static Value *simplifyRem(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1, | ||||
// (X << Y) % X -> 0 | // (X << Y) % X -> 0 | ||||
if (Q.IIQ.UseInstrInfo && | if (Q.IIQ.UseInstrInfo && | ||||
((Opcode == Instruction::SRem && | ((Opcode == Instruction::SRem && | ||||
match(Op0, m_NSWShl(m_Specific(Op1), m_Value()))) || | match(Op0, m_NSWShl(m_Specific(Op1), m_Value()))) || | ||||
(Opcode == Instruction::URem && | (Opcode == Instruction::URem && | ||||
match(Op0, m_NUWShl(m_Specific(Op1), m_Value()))))) | match(Op0, m_NUWShl(m_Specific(Op1), m_Value()))))) | ||||
return Constant::getNullValue(Op0->getType()); | return Constant::getNullValue(Op0->getType()); | ||||
// (X << S1) % (X << S2) | |||||
// (S1 >= S2) ? -> 0 : -> (X << S1) | |||||
Value *ShiftX; | |||||
ConstantInt *S1, *S2; | |||||
if (match(Op0, m_Shl(m_Value(ShiftX), m_ConstantInt(S1))) && | |||||
match(Op1, m_Shl(m_Deferred(ShiftX), m_ConstantInt(S2)))) { | |||||
auto Shl0 = cast<OverflowingBinaryOperator>(Op0); | |||||
if (S1 >= S2 && | |||||
((Opcode == Instruction::SRem && Q.IIQ.hasNoSignedWrap(Shl0)) || | |||||
(Opcode == Instruction::URem && Q.IIQ.hasNoUnsignedWrap(Shl0)))) | |||||
return Constant::getNullValue(Shl0->getType()); | |||||
auto Shl1 = cast<OverflowingBinaryOperator>(Op1); | |||||
if ((Opcode == Instruction::SRem && Q.IIQ.hasNoSignedWrap(Shl1)) || | |||||
(Opcode == Instruction::URem && Q.IIQ.hasNoUnsignedWrap(Shl1))) | |||||
return Op0; | |||||
} | |||||
// If the operation is with the result of a select instruction, check whether | // If the operation is with the result of a select instruction, check whether | ||||
// operating on either branch of the select always yields the same value. | // operating on either branch of the select always yields the same value. | ||||
if (isa<SelectInst>(Op0) || isa<SelectInst>(Op1)) | if (isa<SelectInst>(Op0) || isa<SelectInst>(Op1)) | ||||
if (Value *V = threadBinOpOverSelect(Opcode, Op0, Op1, Q, MaxRecurse)) | if (Value *V = threadBinOpOverSelect(Opcode, Op0, Op1, Q, MaxRecurse)) | ||||
return V; | return V; | ||||
// If the operation is with the result of a phi instruction, check whether | // If the operation is with the result of a phi instruction, check whether | ||||
// operating on all incoming values of the phi always yields the same value. | // operating on all incoming values of the phi always yields the same value. | ||||
▲ Show 20 Lines • Show All 5,601 Lines • Show Last 20 Lines |
Instead of a new helper maybe this should be in simplifyRem which already appears to have:
This is really just a superset of that case, so maybe expanding the existing logic would be simpler?