aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Transforms/Scalar/InstructionCombining.cpp77
1 files changed, 53 insertions, 24 deletions
diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp
index cd02410705..d1a70c88fc 100644
--- a/lib/Transforms/Scalar/InstructionCombining.cpp
+++ b/lib/Transforms/Scalar/InstructionCombining.cpp
@@ -1572,9 +1572,26 @@ Instruction *InstCombiner::InsertRangeTest(Value *V, Constant *Lo, Constant *Hi,
return new SetCondInst(Instruction::SetGT, OffsetVal, AddCST);
}
-/// FoldLogicalPlusAnd - We know that Mask is of the form 0+1+, and that this is
-/// part of an expression (LHS +/- RHS) & Mask, where isSub determines whether
-/// the operator is a sub. If we can fold one of the following xforms:
+// isRunOfOnes - Returns true iff Val consists of one contiguous run of 1s with
+// any number of 0s on either side. The 1s are allowed to wrap from LSB to
+// MSB, so 0x000FFF0, 0x0000FFFF, and 0xFF0000FF are all runs. 0x0F0F0000 is
+// not, since all 1s are not contiguous.
+static bool isRunOfOnes(ConstantIntegral *Val, unsigned &MB, unsigned &ME) {
+ uint64_t V = Val->getRawValue();
+ if (!isShiftedMask_64(V)) return false;
+
+ // look for the first zero bit after the run of ones
+ MB = 64-CountLeadingZeros_64((V - 1) ^ V);
+ // look for the first non-zero bit
+ ME = 64-CountLeadingZeros_64(V);
+ return true;
+}
+
+
+
+/// FoldLogicalPlusAnd - This is part of an expression (LHS +/- RHS) & Mask,
+/// where isSub determines whether the operator is a sub. If we can fold one of
+/// the following xforms:
///
/// ((A & N) +/- B) & Mask -> (A +/- B) & Mask iff N&Mask == Mask
/// ((A | N) +/- B) & Mask -> (A +/- B) & Mask iff N&Mask == 0
@@ -1594,12 +1611,30 @@ Value *InstCombiner::FoldLogicalPlusAnd(Value *LHS, Value *RHS,
switch (LHSI->getOpcode()) {
default: return 0;
case Instruction::And:
- if (ConstantExpr::getAnd(N, Mask) == Mask)
- break;
+ if (ConstantExpr::getAnd(N, Mask) == Mask) {
+ // If the AndRHS is a power of two minus one (0+1+), this is simple.
+ if ((Mask->getRawValue() & Mask->getRawValue()+1) == 0)
+ break;
+
+ // Otherwise, if Mask is 0+1+0+, and if B is known to have the low 0+
+ // part, we don't need any explicit masks to take them out of A. If that
+ // is all N is, ignore it.
+ unsigned MB, ME;
+ if (isRunOfOnes(Mask, MB, ME)) { // begin/end bit of run, inclusive
+ Constant *Mask = ConstantInt::getAllOnesValue(RHS->getType());
+ Mask = ConstantExpr::getUShr(Mask,
+ ConstantInt::get(Type::UByteTy,
+ (64-MB+1)));
+ if (MaskedValueIsZero(RHS, cast<ConstantIntegral>(Mask)))
+ break;
+ }
+ }
return 0;
case Instruction::Or:
case Instruction::Xor:
- if (ConstantExpr::getAnd(N, Mask)->isNullValue())
+ // If the AndRHS is a power of two minus one (0+1+), and N&Mask == 0
+ if ((Mask->getRawValue() & Mask->getRawValue()+1) == 0 &&
+ ConstantExpr::getAnd(N, Mask)->isNullValue())
break;
return 0;
}
@@ -1683,27 +1718,21 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) {
return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType()));
break;
case Instruction::Add:
- // If the AndRHS is a power of two minus one (0+1+).
- if ((AndRHS->getRawValue() & AndRHS->getRawValue()+1) == 0) {
- // ((A & N) + B) & AndRHS -> (A + B) & AndRHS iff N&AndRHS == AndRHS.
- // ((A | N) + B) & AndRHS -> (A + B) & AndRHS iff N&AndRHS == 0
- // ((A ^ N) + B) & AndRHS -> (A + B) & AndRHS iff N&AndRHS == 0
- if (Value *V = FoldLogicalPlusAnd(Op0LHS, Op0RHS, AndRHS, false, I))
- return BinaryOperator::createAnd(V, AndRHS);
- if (Value *V = FoldLogicalPlusAnd(Op0RHS, Op0LHS, AndRHS, false, I))
- return BinaryOperator::createAnd(V, AndRHS); // Add commutes
- }
+ // ((A & N) + B) & AndRHS -> (A + B) & AndRHS iff N&AndRHS == AndRHS.
+ // ((A | N) + B) & AndRHS -> (A + B) & AndRHS iff N&AndRHS == 0
+ // ((A ^ N) + B) & AndRHS -> (A + B) & AndRHS iff N&AndRHS == 0
+ if (Value *V = FoldLogicalPlusAnd(Op0LHS, Op0RHS, AndRHS, false, I))
+ return BinaryOperator::createAnd(V, AndRHS);
+ if (Value *V = FoldLogicalPlusAnd(Op0RHS, Op0LHS, AndRHS, false, I))
+ return BinaryOperator::createAnd(V, AndRHS); // Add commutes
break;
case Instruction::Sub:
- // If the AndRHS is a power of two minus one (0+1+).
- if ((AndRHS->getRawValue() & AndRHS->getRawValue()+1) == 0) {
- // ((A & N) - B) & AndRHS -> (A - B) & AndRHS iff N&AndRHS == AndRHS.
- // ((A | N) - B) & AndRHS -> (A - B) & AndRHS iff N&AndRHS == 0
- // ((A ^ N) - B) & AndRHS -> (A - B) & AndRHS iff N&AndRHS == 0
- if (Value *V = FoldLogicalPlusAnd(Op0LHS, Op0RHS, AndRHS, true, I))
- return BinaryOperator::createAnd(V, AndRHS);
- }
+ // ((A & N) - B) & AndRHS -> (A - B) & AndRHS iff N&AndRHS == AndRHS.
+ // ((A | N) - B) & AndRHS -> (A - B) & AndRHS iff N&AndRHS == 0
+ // ((A ^ N) - B) & AndRHS -> (A - B) & AndRHS iff N&AndRHS == 0
+ if (Value *V = FoldLogicalPlusAnd(Op0LHS, Op0RHS, AndRHS, true, I))
+ return BinaryOperator::createAnd(V, AndRHS);
break;
}