+// 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->hasOneUse()) {
+ // (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->hasOneUse() && 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->hasOneUse()) {
+ // 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;
+
+ case Instruction::Shl: {
+ // We know that the AND will not produce any of the bits shifted in, so if
+ // the anded constant includes them, clear them now!
+ //
+ Constant *AllOne = ConstantIntegral::getAllOnesValue(AndRHS->getType());
+ Constant *CI = *AndRHS & *(*AllOne << *OpRHS);
+ if (CI != AndRHS) {
+ TheAnd.setOperand(1, CI);
+ return &TheAnd;
+ }
+ break;
+ }
+ case Instruction::Shr:
+ // We know that the AND will not produce any of the bits shifted in, so if
+ // the anded constant includes them, clear them now! This only applies to
+ // unsigned shifts, because a signed shr may bring in set bits!
+ //
+ if (AndRHS->getType()->isUnsigned()) {
+ Constant *AllOne = ConstantIntegral::getAllOnesValue(AndRHS->getType());
+ Constant *CI = *AndRHS & *(*AllOne >> *OpRHS);
+ if (CI != AndRHS) {
+ TheAnd.setOperand(1, CI);
+ return &TheAnd;
+ }
+ }
+ break;
+ }
+ return 0;
+}
+