/// Compute known bits resulting from adding LHS and RHS.
static KnownBits computeForAddSub(bool Add, bool NSW, const KnownBits &LHS,
KnownBits RHS);
+
+ /// Update known bits based on ANDing with RHS.
+ KnownBits &operator&=(const KnownBits &RHS);
+
+ /// Update known bits based on ORing with RHS.
+ KnownBits &operator|=(const KnownBits &RHS);
+
+ /// Update known bits based on XORing with RHS.
+ KnownBits &operator^=(const KnownBits &RHS);
};
+inline KnownBits operator&(KnownBits LHS, const KnownBits &RHS) {
+ LHS &= RHS;
+ return LHS;
+}
+
+inline KnownBits operator&(const KnownBits &LHS, KnownBits &&RHS) {
+ RHS &= LHS;
+ return std::move(RHS);
+}
+
+inline KnownBits operator|(KnownBits LHS, const KnownBits &RHS) {
+ LHS |= RHS;
+ return LHS;
+}
+
+inline KnownBits operator|(const KnownBits &LHS, KnownBits &&RHS) {
+ RHS |= LHS;
+ return std::move(RHS);
+}
+
+inline KnownBits operator^(KnownBits LHS, const KnownBits &RHS) {
+ LHS ^= RHS;
+ return LHS;
+}
+
+inline KnownBits operator^(const KnownBits &LHS, KnownBits &&RHS) {
+ RHS ^= LHS;
+ return std::move(RHS);
+}
+
} // end namespace llvm
#endif
return Op1;
}
- Known0.Zero |= Known1.Zero;
- Known0.One &= Known1.One;
+ Known0 &= Known1;
if (Known0.isConstant())
return ConstantInt::get(Op0->getType(), Known0.getConstant());
}
computeKnownBits(I->getOperand(1), DemandedElts, Known, Depth + 1, Q);
computeKnownBits(I->getOperand(0), DemandedElts, Known2, Depth + 1, Q);
- // Output known-1 bits are only known if set in both the LHS & RHS.
- Known.One &= Known2.One;
- // Output known-0 are known to be clear if zero in either the LHS | RHS.
- Known.Zero |= Known2.Zero;
+ Known &= Known2;
// and(x, add (x, -1)) is a common idiom that always clears the low bit;
// here we handle the more general case of adding any odd number by
computeKnownBits(I->getOperand(1), DemandedElts, Known, Depth + 1, Q);
computeKnownBits(I->getOperand(0), DemandedElts, Known2, Depth + 1, Q);
- // Output known-0 bits are only known if clear in both the LHS & RHS.
- Known.Zero &= Known2.Zero;
- // Output known-1 are known to be set if set in either the LHS | RHS.
- Known.One |= Known2.One;
+ Known |= Known2;
break;
- case Instruction::Xor: {
+ case Instruction::Xor:
computeKnownBits(I->getOperand(1), DemandedElts, Known, Depth + 1, Q);
computeKnownBits(I->getOperand(0), DemandedElts, Known2, Depth + 1, Q);
- // Output known-0 bits are known if clear or set in both the LHS & RHS.
- APInt KnownZeroOut = (Known.Zero & Known2.Zero) | (Known.One & Known2.One);
- // Output known-1 are known to be set if set in only one of the LHS, RHS.
- Known.One = (Known.Zero & Known2.One) | (Known.One & Known2.Zero);
- Known.Zero = std::move(KnownZeroOut);
+ Known ^= Known2;
break;
- }
case Instruction::Mul: {
bool NSW = Q.IIQ.hasNoSignedWrap(cast<OverflowingBinaryOperator>(I));
computeKnownBitsMul(I->getOperand(0), I->getOperand(1), NSW, DemandedElts,
computeKnownBitsImpl(MI.getOperand(1).getReg(), Known2, DemandedElts,
Depth + 1);
- // Output known-0 bits are known if clear or set in both the LHS & RHS.
- APInt KnownZeroOut = (Known.Zero & Known2.Zero) | (Known.One & Known2.One);
- // Output known-1 are known to be set if set in only one of the LHS, RHS.
- Known.One = (Known.Zero & Known2.One) | (Known.One & Known2.Zero);
- Known.Zero = KnownZeroOut;
+ Known ^= Known2;
break;
}
case TargetOpcode::G_PTR_ADD: {
computeKnownBitsImpl(MI.getOperand(1).getReg(), Known2, DemandedElts,
Depth + 1);
- // Output known-1 bits are only known if set in both the LHS & RHS.
- Known.One &= Known2.One;
- // Output known-0 are known to be clear if zero in either the LHS | RHS.
- Known.Zero |= Known2.Zero;
+ Known &= Known2;
break;
}
case TargetOpcode::G_OR: {
computeKnownBitsImpl(MI.getOperand(1).getReg(), Known2, DemandedElts,
Depth + 1);
- // Output known-0 bits are only known if clear in both the LHS & RHS.
- Known.Zero &= Known2.Zero;
- // Output known-1 are known to be set if set in either the LHS | RHS.
- Known.One |= Known2.One;
+ Known |= Known2;
break;
}
case TargetOpcode::G_MUL: {
break;
}
case ISD::AND:
- // If either the LHS or the RHS are Zero, the result is zero.
Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);
Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
- // Output known-1 bits are only known if set in both the LHS & RHS.
- Known.One &= Known2.One;
- // Output known-0 are known to be clear if zero in either the LHS | RHS.
- Known.Zero |= Known2.Zero;
+ Known &= Known2;
break;
case ISD::OR:
Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);
Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
- // Output known-0 bits are only known if clear in both the LHS & RHS.
- Known.Zero &= Known2.Zero;
- // Output known-1 are known to be set if set in either the LHS | RHS.
- Known.One |= Known2.One;
+ Known |= Known2;
break;
- case ISD::XOR: {
+ case ISD::XOR:
Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);
Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
- // Output known-0 bits are known if clear or set in both the LHS & RHS.
- APInt KnownZeroOut = (Known.Zero & Known2.Zero) | (Known.One & Known2.One);
- // Output known-1 are known to be set if set in only one of the LHS, RHS.
- Known.One = (Known.Zero & Known2.One) | (Known.One & Known2.Zero);
- Known.Zero = KnownZeroOut;
+ Known ^= Known2;
break;
- }
case ISD::MUL: {
Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);
Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
return false;
}
- KnownBits Known2, KnownOut;
+ KnownBits Known2;
switch (Op.getOpcode()) {
case ISD::TargetConstant:
llvm_unreachable("Can't simplify this node");
if (ShrinkDemandedOp(Op, BitWidth, DemandedBits, TLO))
return true;
- // Output known-1 bits are only known if set in both the LHS & RHS.
- Known.One &= Known2.One;
- // Output known-0 are known to be clear if zero in either the LHS | RHS.
- Known.Zero |= Known2.Zero;
+ Known &= Known2;
break;
}
case ISD::OR: {
if (ShrinkDemandedOp(Op, BitWidth, DemandedBits, TLO))
return true;
- // Output known-0 bits are only known if clear in both the LHS & RHS.
- Known.Zero &= Known2.Zero;
- // Output known-1 are known to be set if set in either the LHS | RHS.
- Known.One |= Known2.One;
+ Known |= Known2;
break;
}
case ISD::XOR: {
if (DemandedBits.isSubsetOf(Known.Zero | Known2.Zero))
return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::OR, dl, VT, Op0, Op1));
- // Output known-0 bits are known if clear or set in both the LHS & RHS.
- KnownOut.Zero = (Known.Zero & Known2.Zero) | (Known.One & Known2.One);
- // Output known-1 are known to be set if set in only one of the LHS, RHS.
- KnownOut.One = (Known.Zero & Known2.One) | (Known.One & Known2.Zero);
-
if (ConstantSDNode *C = isConstOrConstSplat(Op1)) {
// If one side is a constant, and all of the known set bits on the other
// side are also set in the constant, turn this into an AND, as we know
}
}
- Known = std::move(KnownOut);
+ Known ^= Known2;
break;
}
case ISD::SELECT:
return KnownOut;
}
+
+KnownBits &KnownBits::operator&=(const KnownBits &RHS) {
+ // Result bit is 0 if either operand bit is 0.
+ Zero |= RHS.Zero;
+ // Result bit is 1 if both operand bits are 1.
+ One &= RHS.One;
+ return *this;
+}
+
+KnownBits &KnownBits::operator|=(const KnownBits &RHS) {
+ // Result bit is 0 if both operand bits are 0.
+ Zero &= RHS.Zero;
+ // Result bit is 1 if either operand bit is 1.
+ One |= RHS.One;
+ return *this;
+}
+
+KnownBits &KnownBits::operator^=(const KnownBits &RHS) {
+ // Result bit is 0 if both operand bits are 0 or both are 1.
+ APInt Z = (Zero & RHS.Zero) | (One & RHS.One);
+ // Result bit is 1 if one operand bit is 0 and the other is 1.
+ One = (Zero & RHS.One) | (One & RHS.Zero);
+ Zero = std::move(Z);
+ return *this;
+}
Known = DAG.computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);
Known2 = DAG.computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
- // Output known-0 bits are only known if clear in both the LHS & RHS.
- Known.Zero &= Known2.Zero;
- // Output known-1 are known to be set if set in either the LHS | RHS.
- Known.One |= Known2.One;
+ Known |= Known2;
break;
}
case X86ISD::PSADBW: {
assert(!RHSKnown.hasConflict() && "Bits known to be one AND zero?");
assert(!LHSKnown.hasConflict() && "Bits known to be one AND zero?");
- // Output known-0 are known to be clear if zero in either the LHS | RHS.
- APInt IKnownZero = RHSKnown.Zero | LHSKnown.Zero;
- // Output known-1 bits are only known if set in both the LHS & RHS.
- APInt IKnownOne = RHSKnown.One & LHSKnown.One;
+ Known = LHSKnown & RHSKnown;
// If the client is only demanding bits that we know, return the known
// constant.
- if (DemandedMask.isSubsetOf(IKnownZero|IKnownOne))
- return Constant::getIntegerValue(VTy, IKnownOne);
+ if (DemandedMask.isSubsetOf(Known.Zero | Known.One))
+ return Constant::getIntegerValue(VTy, Known.One);
// If all of the demanded bits are known 1 on one side, return the other.
// These bits cannot contribute to the result of the 'and'.
if (ShrinkDemandedConstant(I, 1, DemandedMask & ~LHSKnown.Zero))
return I;
- Known.Zero = std::move(IKnownZero);
- Known.One = std::move(IKnownOne);
break;
}
case Instruction::Or: {
assert(!RHSKnown.hasConflict() && "Bits known to be one AND zero?");
assert(!LHSKnown.hasConflict() && "Bits known to be one AND zero?");
- // Output known-0 bits are only known if clear in both the LHS & RHS.
- APInt IKnownZero = RHSKnown.Zero & LHSKnown.Zero;
- // Output known-1 are known. to be set if s.et in either the LHS | RHS.
- APInt IKnownOne = RHSKnown.One | LHSKnown.One;
+ Known = LHSKnown | RHSKnown;
// If the client is only demanding bits that we know, return the known
// constant.
- if (DemandedMask.isSubsetOf(IKnownZero|IKnownOne))
- return Constant::getIntegerValue(VTy, IKnownOne);
+ if (DemandedMask.isSubsetOf(Known.Zero | Known.One))
+ return Constant::getIntegerValue(VTy, Known.One);
// If all of the demanded bits are known zero on one side, return the other.
// These bits cannot contribute to the result of the 'or'.
if (ShrinkDemandedConstant(I, 1, DemandedMask))
return I;
- Known.Zero = std::move(IKnownZero);
- Known.One = std::move(IKnownOne);
break;
}
case Instruction::Xor: {
assert(!RHSKnown.hasConflict() && "Bits known to be one AND zero?");
assert(!LHSKnown.hasConflict() && "Bits known to be one AND zero?");
- // Output known-0 bits are known if clear or set in both the LHS & RHS.
- APInt IKnownZero = (RHSKnown.Zero & LHSKnown.Zero) |
- (RHSKnown.One & LHSKnown.One);
- // Output known-1 are known to be set if set in only one of the LHS, RHS.
- APInt IKnownOne = (RHSKnown.Zero & LHSKnown.One) |
- (RHSKnown.One & LHSKnown.Zero);
+ Known = LHSKnown ^ RHSKnown;
// If the client is only demanding bits that we know, return the known
// constant.
- if (DemandedMask.isSubsetOf(IKnownZero|IKnownOne))
- return Constant::getIntegerValue(VTy, IKnownOne);
+ if (DemandedMask.isSubsetOf(Known.Zero | Known.One))
+ return Constant::getIntegerValue(VTy, Known.One);
// If all of the demanded bits are known zero on one side, return the other.
// These bits cannot contribute to the result of the 'xor'.
return InsertNewInstWith(NewXor, *I);
}
- // Output known-0 bits are known if clear or set in both the LHS & RHS.
- Known.Zero = std::move(IKnownZero);
- // Output known-1 are known to be set if set in only one of the LHS, RHS.
- Known.One = std::move(IKnownOne);
break;
}
case Instruction::Select: {
computeKnownBits(I->getOperand(0), LHSKnown, Depth + 1,
CxtI);
- // Output known-0 are known to be clear if zero in either the LHS | RHS.
- APInt IKnownZero = RHSKnown.Zero | LHSKnown.Zero;
- // Output known-1 bits are only known if set in both the LHS & RHS.
- APInt IKnownOne = RHSKnown.One & LHSKnown.One;
+ Known = LHSKnown & RHSKnown;
// If the client is only demanding bits that we know, return the known
// constant.
- if (DemandedMask.isSubsetOf(IKnownZero|IKnownOne))
- return Constant::getIntegerValue(ITy, IKnownOne);
+ if (DemandedMask.isSubsetOf(Known.Zero | Known.One))
+ return Constant::getIntegerValue(ITy, Known.One);
// If all of the demanded bits are known 1 on one side, return the other.
// These bits cannot contribute to the result of the 'and' in this
if (DemandedMask.isSubsetOf(RHSKnown.Zero | LHSKnown.One))
return I->getOperand(1);
- Known.Zero = std::move(IKnownZero);
- Known.One = std::move(IKnownOne);
break;
}
case Instruction::Or: {
computeKnownBits(I->getOperand(0), LHSKnown, Depth + 1,
CxtI);
- // Output known-0 bits are only known if clear in both the LHS & RHS.
- APInt IKnownZero = RHSKnown.Zero & LHSKnown.Zero;
- // Output known-1 are known to be set if set in either the LHS | RHS.
- APInt IKnownOne = RHSKnown.One | LHSKnown.One;
+ Known = LHSKnown | RHSKnown;
// If the client is only demanding bits that we know, return the known
// constant.
- if (DemandedMask.isSubsetOf(IKnownZero|IKnownOne))
- return Constant::getIntegerValue(ITy, IKnownOne);
+ if (DemandedMask.isSubsetOf(Known.Zero | Known.One))
+ return Constant::getIntegerValue(ITy, Known.One);
// If all of the demanded bits are known zero on one side, return the
// other. These bits cannot contribute to the result of the 'or' in this
if (DemandedMask.isSubsetOf(RHSKnown.One | LHSKnown.Zero))
return I->getOperand(1);
- Known.Zero = std::move(IKnownZero);
- Known.One = std::move(IKnownOne);
break;
}
case Instruction::Xor: {
computeKnownBits(I->getOperand(0), LHSKnown, Depth + 1,
CxtI);
- // Output known-0 bits are known if clear or set in both the LHS & RHS.
- APInt IKnownZero = (RHSKnown.Zero & LHSKnown.Zero) |
- (RHSKnown.One & LHSKnown.One);
- // Output known-1 are known to be set if set in only one of the LHS, RHS.
- APInt IKnownOne = (RHSKnown.Zero & LHSKnown.One) |
- (RHSKnown.One & LHSKnown.Zero);
+ Known = LHSKnown ^ RHSKnown;
// If the client is only demanding bits that we know, return the known
// constant.
- if (DemandedMask.isSubsetOf(IKnownZero|IKnownOne))
- return Constant::getIntegerValue(ITy, IKnownOne);
+ if (DemandedMask.isSubsetOf(Known.Zero | Known.One))
+ return Constant::getIntegerValue(ITy, Known.One);
// If all of the demanded bits are known zero on one side, return the
// other.
if (DemandedMask.isSubsetOf(LHSKnown.Zero))
return I->getOperand(1);
- // Output known-0 bits are known if clear or set in both the LHS & RHS.
- Known.Zero = std::move(IKnownZero);
- // Output known-1 are known to be set if set in only one of the LHS, RHS.
- Known.One = std::move(IKnownOne);
break;
}
default:
TestAddSubExhaustive(false);
}
+TEST(KnownBitsTest, BinaryExhaustive) {
+ unsigned Bits = 4;
+ ForeachKnownBits(Bits, [&](const KnownBits &Known1) {
+ ForeachKnownBits(Bits, [&](const KnownBits &Known2) {
+ KnownBits KnownAnd(Bits), KnownOr(Bits), KnownXor(Bits);
+ KnownAnd.Zero.setAllBits();
+ KnownAnd.One.setAllBits();
+ KnownOr.Zero.setAllBits();
+ KnownOr.One.setAllBits();
+ KnownXor.Zero.setAllBits();
+ KnownXor.One.setAllBits();
+
+ ForeachNumInKnownBits(Known1, [&](const APInt &N1) {
+ ForeachNumInKnownBits(Known2, [&](const APInt &N2) {
+ APInt Res;
+
+ Res = N1 & N2;
+ KnownAnd.One &= Res;
+ KnownAnd.Zero &= ~Res;
+
+ Res = N1 | N2;
+ KnownOr.One &= Res;
+ KnownOr.Zero &= ~Res;
+
+ Res = N1 ^ N2;
+ KnownXor.One &= Res;
+ KnownXor.Zero &= ~Res;
+ });
+ });
+
+ KnownBits ComputedAnd = Known1 & Known2;
+ EXPECT_EQ(KnownAnd.Zero, ComputedAnd.Zero);
+ EXPECT_EQ(KnownAnd.One, ComputedAnd.One);
+
+ KnownBits ComputedOr = Known1 | Known2;
+ EXPECT_EQ(KnownOr.Zero, ComputedOr.Zero);
+ EXPECT_EQ(KnownOr.One, ComputedOr.One);
+
+ KnownBits ComputedXor = Known1 ^ Known2;
+ EXPECT_EQ(KnownXor.Zero, ComputedXor.Zero);
+ EXPECT_EQ(KnownXor.One, ComputedXor.One);
+ });
+ });
+}
+
TEST(KnownBitsTest, GetMinMaxVal) {
unsigned Bits = 4;
ForeachKnownBits(Bits, [&](const KnownBits &Known) {