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:
Dinesh Dwivedi 2014-08-26 08:53:32 +00:00
parent 24c6f5763a
commit 4919bbe29d
2 changed files with 45 additions and 54 deletions

View File

@ -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

View File

@ -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.