forked from OSchip/llvm-project
pull a large nested conditional out into its own function
llvm-svn: 8605
This commit is contained in:
parent
dbba189f15
commit
ba1cb38c06
|
@ -135,6 +135,9 @@ namespace {
|
||||||
// SimplifyCommutative - This performs a few simplifications for commutative
|
// SimplifyCommutative - This performs a few simplifications for commutative
|
||||||
// operators...
|
// operators...
|
||||||
bool SimplifyCommutative(BinaryOperator &I);
|
bool SimplifyCommutative(BinaryOperator &I);
|
||||||
|
|
||||||
|
Instruction *OptAndOp(Instruction *Op, ConstantIntegral *OpRHS,
|
||||||
|
ConstantIntegral *AndRHS, BinaryOperator &TheAnd);
|
||||||
};
|
};
|
||||||
|
|
||||||
RegisterOpt<InstCombiner> X("instcombine", "Combine redundant instructions");
|
RegisterOpt<InstCombiner> X("instcombine", "Combine redundant instructions");
|
||||||
|
@ -716,6 +719,89 @@ struct FoldSetCCLogical {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// OptAndOp - This handles expressions of the form ((val OP C1) & C2). Where
|
||||||
|
// the Op parameter is 'OP', OpRHS is 'C1', and AndRHS is 'C2'. Op is
|
||||||
|
// guaranteed to be either a shift instruction or a binary operator.
|
||||||
|
Instruction *InstCombiner::OptAndOp(Instruction *Op,
|
||||||
|
ConstantIntegral *OpRHS,
|
||||||
|
ConstantIntegral *AndRHS,
|
||||||
|
BinaryOperator &TheAnd) {
|
||||||
|
Value *X = Op->getOperand(0);
|
||||||
|
switch (Op->getOpcode()) {
|
||||||
|
case Instruction::Xor:
|
||||||
|
if ((*AndRHS & *OpRHS)->isNullValue()) {
|
||||||
|
// (X ^ C1) & C2 --> (X & C2) iff (C1&C2) == 0
|
||||||
|
return BinaryOperator::create(Instruction::And, X, AndRHS);
|
||||||
|
} else if (Op->use_size() == 1) {
|
||||||
|
// (X ^ C1) & C2 --> (X & C2) ^ (C1&C2)
|
||||||
|
std::string OpName = Op->getName(); Op->setName("");
|
||||||
|
Instruction *And = BinaryOperator::create(Instruction::And,
|
||||||
|
X, AndRHS, OpName);
|
||||||
|
InsertNewInstBefore(And, TheAnd);
|
||||||
|
return BinaryOperator::create(Instruction::Xor, And, *AndRHS & *OpRHS);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Instruction::Or:
|
||||||
|
// (X | C1) & C2 --> X & C2 iff C1 & C1 == 0
|
||||||
|
if ((*AndRHS & *OpRHS)->isNullValue())
|
||||||
|
return BinaryOperator::create(Instruction::And, X, AndRHS);
|
||||||
|
else {
|
||||||
|
Constant *Together = *AndRHS & *OpRHS;
|
||||||
|
if (Together == AndRHS) // (X | C) & C --> C
|
||||||
|
return ReplaceInstUsesWith(TheAnd, AndRHS);
|
||||||
|
|
||||||
|
if (Op->use_size() == 1 && Together != OpRHS) {
|
||||||
|
// (X | C1) & C2 --> (X | (C1&C2)) & C2
|
||||||
|
std::string Op0Name = Op->getName(); Op->setName("");
|
||||||
|
Instruction *Or = BinaryOperator::create(Instruction::Or, X,
|
||||||
|
Together, Op0Name);
|
||||||
|
InsertNewInstBefore(Or, TheAnd);
|
||||||
|
return BinaryOperator::create(Instruction::And, Or, AndRHS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Instruction::Add:
|
||||||
|
if (Op->use_size() == 1) {
|
||||||
|
// Adding a one to a single bit bit-field should be turned into an XOR
|
||||||
|
// of the bit. First thing to check is to see if this AND is with a
|
||||||
|
// single bit constant.
|
||||||
|
unsigned long long AndRHSV = cast<ConstantInt>(AndRHS)->getRawValue();
|
||||||
|
|
||||||
|
// Clear bits that are not part of the constant.
|
||||||
|
AndRHSV &= (1ULL << AndRHS->getType()->getPrimitiveSize()*8)-1;
|
||||||
|
|
||||||
|
// If there is only one bit set...
|
||||||
|
if ((AndRHSV & (AndRHSV-1)) == 0) {
|
||||||
|
// Ok, at this point, we know that we are masking the result of the
|
||||||
|
// ADD down to exactly one bit. If the constant we are adding has
|
||||||
|
// no bits set below this bit, then we can eliminate the ADD.
|
||||||
|
unsigned long long AddRHS = cast<ConstantInt>(OpRHS)->getRawValue();
|
||||||
|
|
||||||
|
// Check to see if any bits below the one bit set in AndRHSV are set.
|
||||||
|
if ((AddRHS & (AndRHSV-1)) == 0) {
|
||||||
|
// If not, the only thing that can effect the output of the AND is
|
||||||
|
// the bit specified by AndRHSV. If that bit is set, the effect of
|
||||||
|
// the XOR is to toggle the bit. If it is clear, then the ADD has
|
||||||
|
// no effect.
|
||||||
|
if ((AddRHS & AndRHSV) == 0) { // Bit is not set, noop
|
||||||
|
TheAnd.setOperand(0, X);
|
||||||
|
return &TheAnd;
|
||||||
|
} else {
|
||||||
|
std::string Name = Op->getName(); Op->setName("");
|
||||||
|
// Pull the XOR out of the AND.
|
||||||
|
Instruction *NewAnd =
|
||||||
|
BinaryOperator::create(Instruction::And, X, AndRHS, Name);
|
||||||
|
InsertNewInstBefore(NewAnd, TheAnd);
|
||||||
|
return BinaryOperator::create(Instruction::Xor, NewAnd, AndRHS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
|
Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
|
||||||
bool Changed = SimplifyCommutative(I);
|
bool Changed = SimplifyCommutative(I);
|
||||||
|
@ -730,78 +816,13 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
|
||||||
if (RHS->isAllOnesValue())
|
if (RHS->isAllOnesValue())
|
||||||
return ReplaceInstUsesWith(I, Op0);
|
return ReplaceInstUsesWith(I, Op0);
|
||||||
|
|
||||||
if (BinaryOperator *Op0I = dyn_cast<BinaryOperator>(Op0)) {
|
// Optimize a variety of ((val OP C1) & C2) combinations...
|
||||||
|
if (isa<BinaryOperator>(Op0) || isa<ShiftInst>(Op0)) {
|
||||||
|
Instruction *Op0I = cast<Instruction>(Op0);
|
||||||
Value *X = Op0I->getOperand(0);
|
Value *X = Op0I->getOperand(0);
|
||||||
if (ConstantInt *Op0CI = dyn_cast<ConstantInt>(Op0I->getOperand(1)))
|
if (ConstantInt *Op0CI = dyn_cast<ConstantInt>(Op0I->getOperand(1)))
|
||||||
if (Op0I->getOpcode() == Instruction::Xor) {
|
if (Instruction *Res = OptAndOp(Op0I, Op0CI, RHS, I))
|
||||||
if ((*RHS & *Op0CI)->isNullValue()) {
|
return Res;
|
||||||
// (X ^ C1) & C2 --> (X & C2) iff (C1&C2) == 0
|
|
||||||
return BinaryOperator::create(Instruction::And, X, RHS);
|
|
||||||
} else if (isOnlyUse(Op0)) {
|
|
||||||
// (X ^ C1) & C2 --> (X & C2) ^ (C1&C2)
|
|
||||||
std::string Op0Name = Op0I->getName(); Op0I->setName("");
|
|
||||||
Instruction *And = BinaryOperator::create(Instruction::And,
|
|
||||||
X, RHS, Op0Name);
|
|
||||||
InsertNewInstBefore(And, I);
|
|
||||||
return BinaryOperator::create(Instruction::Xor, And, *RHS & *Op0CI);
|
|
||||||
}
|
|
||||||
} else if (Op0I->getOpcode() == Instruction::Or) {
|
|
||||||
// (X | C1) & C2 --> X & C2 iff C1 & C1 == 0
|
|
||||||
if ((*RHS & *Op0CI)->isNullValue())
|
|
||||||
return BinaryOperator::create(Instruction::And, X, RHS);
|
|
||||||
|
|
||||||
Constant *Together = *RHS & *Op0CI;
|
|
||||||
if (Together == RHS) // (X | C) & C --> C
|
|
||||||
return ReplaceInstUsesWith(I, RHS);
|
|
||||||
|
|
||||||
if (isOnlyUse(Op0)) {
|
|
||||||
if (Together != Op0CI) {
|
|
||||||
// (X | C1) & C2 --> (X | (C1&C2)) & C2
|
|
||||||
std::string Op0Name = Op0I->getName(); Op0I->setName("");
|
|
||||||
Instruction *Or = BinaryOperator::create(Instruction::Or, X,
|
|
||||||
Together, Op0Name);
|
|
||||||
InsertNewInstBefore(Or, I);
|
|
||||||
return BinaryOperator::create(Instruction::And, Or, RHS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (Op0I->getOpcode() == Instruction::Add &&
|
|
||||||
Op0I->use_size() == 1) {
|
|
||||||
// Adding a one to a single bit bit-field should be turned into an XOR
|
|
||||||
// of the bit. First thing to check is to see if this AND is with a
|
|
||||||
// single bit constant.
|
|
||||||
unsigned long long AndRHS = cast<ConstantInt>(RHS)->getRawValue();
|
|
||||||
|
|
||||||
// Clear bits that are not part of the constant.
|
|
||||||
AndRHS &= (1ULL << RHS->getType()->getPrimitiveSize()*8)-1;
|
|
||||||
|
|
||||||
// If there is only one bit set...
|
|
||||||
if ((AndRHS & (AndRHS-1)) == 0) {
|
|
||||||
// Ok, at this point, we know that we are masking the result of the
|
|
||||||
// ADD down to exactly one bit. If the constant we are adding has
|
|
||||||
// no bits set below this bit, then we can eliminate the ADD.
|
|
||||||
unsigned long long AddRHS = cast<ConstantInt>(Op0CI)->getRawValue();
|
|
||||||
|
|
||||||
// Check to see if any bits below the one bit set in AndRHS are set.
|
|
||||||
if ((AddRHS & (AndRHS-1)) == 0) {
|
|
||||||
// If not, the only thing that can effect the output of the AND is
|
|
||||||
// the bit specified by AndRHS. If that bit is set, the effect of
|
|
||||||
// the XOR is to toggle the bit. If it is clear, then the ADD has
|
|
||||||
// no effect.
|
|
||||||
if ((AddRHS & AndRHS) == 0) { // Bit is not set, noop
|
|
||||||
I.setOperand(0, Op0I->getOperand(0));
|
|
||||||
return &I;
|
|
||||||
} else {
|
|
||||||
std::string Name = Op0I->getName(); Op0I->setName("");
|
|
||||||
// Pull the XOR out of the AND.
|
|
||||||
Instruction *NewAnd =
|
|
||||||
BinaryOperator::create(Instruction::And, Op0I->getOperand(0),
|
|
||||||
RHS, Name);
|
|
||||||
InsertNewInstBefore(NewAnd, I);
|
|
||||||
return BinaryOperator::create(Instruction::Xor, NewAnd, RHS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue