diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h --- a/llvm/include/llvm/Support/KnownBits.h +++ b/llvm/include/llvm/Support/KnownBits.h @@ -240,8 +240,47 @@ /// 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 diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -745,8 +745,7 @@ return Op1; } - Known0.Zero |= Known1.Zero; - Known0.One &= Known1.One; + Known0 &= Known1; if (Known0.isConstant()) return ConstantInt::get(Op0->getType(), Known0.getConstant()); } diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -1134,10 +1134,7 @@ 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 @@ -1158,22 +1155,14 @@ 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(I)); computeKnownBitsMul(I->getOperand(0), I->getOperand(1), NSW, DemandedElts, diff --git a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp --- a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp @@ -233,11 +233,7 @@ 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: { @@ -263,10 +259,7 @@ 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: { @@ -276,10 +269,7 @@ 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: { diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -2757,35 +2757,23 @@ 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); diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -861,7 +861,7 @@ return false; } - KnownBits Known2, KnownOut; + KnownBits Known2; switch (Op.getOpcode()) { case ISD::TargetConstant: llvm_unreachable("Can't simplify this node"); @@ -1171,10 +1171,7 @@ 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: { @@ -1217,10 +1214,7 @@ 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: { @@ -1266,11 +1260,6 @@ 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 @@ -1298,7 +1287,7 @@ } } - Known = std::move(KnownOut); + Known ^= Known2; break; } case ISD::SELECT: diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp --- a/llvm/lib/Support/KnownBits.cpp +++ b/llvm/lib/Support/KnownBits.cpp @@ -82,3 +82,28 @@ 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; +} diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -33256,10 +33256,7 @@ 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: { diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -176,15 +176,12 @@ 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'. @@ -197,8 +194,6 @@ if (ShrinkDemandedConstant(I, 1, DemandedMask & ~LHSKnown.Zero)) return I; - Known.Zero = std::move(IKnownZero); - Known.One = std::move(IKnownOne); break; } case Instruction::Or: { @@ -210,15 +205,12 @@ 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'. @@ -231,8 +223,6 @@ if (ShrinkDemandedConstant(I, 1, DemandedMask)) return I; - Known.Zero = std::move(IKnownZero); - Known.One = std::move(IKnownOne); break; } case Instruction::Xor: { @@ -242,17 +232,12 @@ 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'. @@ -312,10 +297,6 @@ 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: { @@ -877,15 +858,12 @@ 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 @@ -895,8 +873,6 @@ 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: { @@ -908,15 +884,12 @@ 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 @@ -926,8 +899,6 @@ 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: { @@ -938,17 +909,12 @@ 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. @@ -957,10 +923,6 @@ 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: diff --git a/llvm/unittests/Support/KnownBitsTest.cpp b/llvm/unittests/Support/KnownBitsTest.cpp --- a/llvm/unittests/Support/KnownBitsTest.cpp +++ b/llvm/unittests/Support/KnownBitsTest.cpp @@ -127,6 +127,51 @@ 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) {