forked from OSchip/llvm-project
This patch enables SimplifyUsingDistributiveLaws() to handle following pattens.
(X >> Z) & (Y >> Z) -> (X&Y) >> Z for all shifts. (X >> Z) | (Y >> Z) -> (X|Y) >> Z for all shifts. (X >> Z) ^ (Y >> Z) -> (X^Y) >> Z for all shifts. These patterns were previously handled separately in visitAnd()/visitOr()/visitXor(). Differential Revision: http://reviews.llvm.org/D4951 llvm-svn: 216443
This commit is contained in:
parent
24c6f5763a
commit
4919bbe29d
|
@ -1351,20 +1351,6 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
|
|||
}
|
||||
}
|
||||
|
||||
// (X >> Z) & (Y >> Z) -> (X&Y) >> Z for all shifts.
|
||||
if (BinaryOperator *SI1 = dyn_cast<BinaryOperator>(Op1)) {
|
||||
if (BinaryOperator *SI0 = dyn_cast<BinaryOperator>(Op0))
|
||||
if (SI0->isShift() && SI0->getOpcode() == SI1->getOpcode() &&
|
||||
SI0->getOperand(1) == SI1->getOperand(1) &&
|
||||
(SI0->hasOneUse() || SI1->hasOneUse())) {
|
||||
Value *NewOp =
|
||||
Builder->CreateAnd(SI0->getOperand(0), SI1->getOperand(0),
|
||||
SI0->getName());
|
||||
return BinaryOperator::Create(SI1->getOpcode(), NewOp,
|
||||
SI1->getOperand(1));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Value *X = nullptr;
|
||||
bool OpsSwapped = false;
|
||||
|
@ -2227,19 +2213,6 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) {
|
|||
if (match(Op0, m_And(m_Or(m_Specific(Op1), m_Value(C)), m_Value(A))))
|
||||
return BinaryOperator::CreateOr(Op1, Builder->CreateAnd(A, C));
|
||||
|
||||
// (X >> Z) | (Y >> Z) -> (X|Y) >> Z for all shifts.
|
||||
if (BinaryOperator *SI1 = dyn_cast<BinaryOperator>(Op1)) {
|
||||
if (BinaryOperator *SI0 = dyn_cast<BinaryOperator>(Op0))
|
||||
if (SI0->isShift() && SI0->getOpcode() == SI1->getOpcode() &&
|
||||
SI0->getOperand(1) == SI1->getOperand(1) &&
|
||||
(SI0->hasOneUse() || SI1->hasOneUse())) {
|
||||
Value *NewOp = Builder->CreateOr(SI0->getOperand(0), SI1->getOperand(0),
|
||||
SI0->getName());
|
||||
return BinaryOperator::Create(SI1->getOpcode(), NewOp,
|
||||
SI1->getOperand(1));
|
||||
}
|
||||
}
|
||||
|
||||
// (~A | ~B) == (~(A & B)) - De Morgan's Law
|
||||
if (Value *Op0NotVal = dyn_castNotVal(Op0))
|
||||
if (Value *Op1NotVal = dyn_castNotVal(Op1))
|
||||
|
@ -2585,18 +2558,6 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) {
|
|||
}
|
||||
}
|
||||
|
||||
// (X >> Z) ^ (Y >> Z) -> (X^Y) >> Z for all shifts.
|
||||
if (Op0I && Op1I && Op0I->isShift() &&
|
||||
Op0I->getOpcode() == Op1I->getOpcode() &&
|
||||
Op0I->getOperand(1) == Op1I->getOperand(1) &&
|
||||
(Op0I->hasOneUse() || Op1I->hasOneUse())) {
|
||||
Value *NewOp =
|
||||
Builder->CreateXor(Op0I->getOperand(0), Op1I->getOperand(0),
|
||||
Op0I->getName());
|
||||
return BinaryOperator::Create(Op1I->getOpcode(), NewOp,
|
||||
Op1I->getOperand(1));
|
||||
}
|
||||
|
||||
if (Op0I && Op1I) {
|
||||
Value *A, *B, *C, *D;
|
||||
// (A & B)^(A | B) -> A ^ B
|
||||
|
|
|
@ -390,6 +390,25 @@ static bool RightDistributesOverLeft(Instruction::BinaryOps LOp,
|
|||
Instruction::BinaryOps ROp) {
|
||||
if (Instruction::isCommutative(ROp))
|
||||
return LeftDistributesOverRight(ROp, LOp);
|
||||
|
||||
switch (LOp) {
|
||||
default:
|
||||
return false;
|
||||
// (X >> Z) & (Y >> Z) -> (X&Y) >> Z for all shifts.
|
||||
// (X >> Z) | (Y >> Z) -> (X|Y) >> Z for all shifts.
|
||||
// (X >> Z) ^ (Y >> Z) -> (X^Y) >> Z for all shifts.
|
||||
case Instruction::And:
|
||||
case Instruction::Or:
|
||||
case Instruction::Xor:
|
||||
switch (ROp) {
|
||||
default:
|
||||
return false;
|
||||
case Instruction::Shl:
|
||||
case Instruction::LShr:
|
||||
case Instruction::AShr:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// TODO: It would be nice to handle division, aka "(X + Y)/Z = X/Z + Y/Z",
|
||||
// but this requires knowing that the addition does not overflow and other
|
||||
// such subtleties.
|
||||
|
@ -411,26 +430,37 @@ static Value *getIdentityValue(Instruction::BinaryOps OpCode, Value *V) {
|
|||
}
|
||||
|
||||
/// This function factors binary ops which can be combined using distributive
|
||||
/// laws. This also factor SHL as MUL e.g. SHL(X, 2) ==> MUL(X, 4).
|
||||
/// laws. This function tries to transform 'Op' based TopLevelOpcode to enable
|
||||
/// factorization e.g for ADD(SHL(X , 2), MUL(X, 5)), When this function called
|
||||
/// with TopLevelOpcode == Instruction::Add and Op = SHL(X, 2), transforms
|
||||
/// SHL(X, 2) to MUL(X, 4) i.e. returns Instruction::Mul with LHS set to 'X' and
|
||||
/// RHS to 4.
|
||||
static Instruction::BinaryOps
|
||||
getBinOpsForFactorization(BinaryOperator *Op, Value *&LHS, Value *&RHS) {
|
||||
getBinOpsForFactorization(Instruction::BinaryOps TopLevelOpcode,
|
||||
BinaryOperator *Op, Value *&LHS, Value *&RHS) {
|
||||
if (!Op)
|
||||
return Instruction::BinaryOpsEnd;
|
||||
|
||||
if (Op->getOpcode() == Instruction::Shl) {
|
||||
if (Constant *CST = dyn_cast<Constant>(Op->getOperand(1))) {
|
||||
// The multiplier is really 1 << CST.
|
||||
RHS = ConstantExpr::getShl(ConstantInt::get(Op->getType(), 1), CST);
|
||||
LHS = Op->getOperand(0);
|
||||
return Instruction::Mul;
|
||||
LHS = Op->getOperand(0);
|
||||
RHS = Op->getOperand(1);
|
||||
|
||||
switch (TopLevelOpcode) {
|
||||
default:
|
||||
return Op->getOpcode();
|
||||
|
||||
case Instruction::Add:
|
||||
case Instruction::Sub:
|
||||
if (Op->getOpcode() == Instruction::Shl) {
|
||||
if (Constant *CST = dyn_cast<Constant>(Op->getOperand(1))) {
|
||||
// The multiplier is really 1 << CST.
|
||||
RHS = ConstantExpr::getShl(ConstantInt::get(Op->getType(), 1), CST);
|
||||
return Instruction::Mul;
|
||||
}
|
||||
}
|
||||
return Op->getOpcode();
|
||||
}
|
||||
|
||||
// TODO: We can add other conversions e.g. shr => div etc.
|
||||
|
||||
LHS = Op->getOperand(0);
|
||||
RHS = Op->getOperand(1);
|
||||
return Op->getOpcode();
|
||||
}
|
||||
|
||||
/// This tries to simplify binary operations by factorizing out common terms
|
||||
|
@ -529,8 +559,9 @@ Value *InstCombiner::SimplifyUsingDistributiveLaws(BinaryOperator &I) {
|
|||
|
||||
// Factorization.
|
||||
Value *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr;
|
||||
Instruction::BinaryOps LHSOpcode = getBinOpsForFactorization(Op0, A, B);
|
||||
Instruction::BinaryOps RHSOpcode = getBinOpsForFactorization(Op1, C, D);
|
||||
auto TopLevelOpcode = I.getOpcode();
|
||||
auto LHSOpcode = getBinOpsForFactorization(TopLevelOpcode, Op0, A, B);
|
||||
auto RHSOpcode = getBinOpsForFactorization(TopLevelOpcode, Op1, C, D);
|
||||
|
||||
// The instruction has the form "(A op' B) op (C op' D)". Try to factorize
|
||||
// a common term.
|
||||
|
@ -552,7 +583,6 @@ Value *InstCombiner::SimplifyUsingDistributiveLaws(BinaryOperator &I) {
|
|||
return V;
|
||||
|
||||
// Expansion.
|
||||
Instruction::BinaryOps TopLevelOpcode = I.getOpcode();
|
||||
if (Op0 && RightDistributesOverLeft(Op0->getOpcode(), TopLevelOpcode)) {
|
||||
// The instruction has the form "(A op' B) op C". See if expanding it out
|
||||
// to "(A op C) op' (B op C)" results in simplifications.
|
||||
|
|
Loading…
Reference in New Issue