1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 12:12:47 +01:00

[KnownBits] Move AND, OR and XOR logic into KnownBits

Summary:
There are at least three clients for KnownBits calculations:
ValueTracking, SelectionDAG and GlobalISel. To reduce duplication the
common logic should be moved out of these clients and into KnownBits
itself.

This patch does this for AND, OR and XOR calculations by implementing
and using appropriate operator overloads KnownBits::operator& etc.

Subscribers: hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D74060
This commit is contained in:
Jay Foad 2020-02-05 16:15:53 +00:00
parent 98b95eeb1c
commit 87d37f4776
10 changed files with 144 additions and 121 deletions

View File

@ -240,8 +240,47 @@ public:
/// 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

View File

@ -745,8 +745,7 @@ Constant *SymbolicallyEvaluateBinop(unsigned Opc, Constant *Op0, Constant *Op1,
return Op1;
}
Known0.Zero |= Known1.Zero;
Known0.One &= Known1.One;
Known0 &= Known1;
if (Known0.isConstant())
return ConstantInt::get(Op0->getType(), Known0.getConstant());
}

View File

@ -1134,10 +1134,7 @@ static void computeKnownBitsFromOperator(const Operator *I,
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 @@ static void computeKnownBitsFromOperator(const Operator *I,
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,

View File

@ -233,11 +233,7 @@ void GISelKnownBits::computeKnownBitsImpl(Register R, KnownBits &Known,
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 @@ void GISelKnownBits::computeKnownBitsImpl(Register R, KnownBits &Known,
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 @@ void GISelKnownBits::computeKnownBitsImpl(Register R, KnownBits &Known,
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: {

View File

@ -2757,35 +2757,23 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
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);

View File

@ -861,7 +861,7 @@ bool TargetLowering::SimplifyDemandedBits(
return false;
}
KnownBits Known2, KnownOut;
KnownBits Known2;
switch (Op.getOpcode()) {
case ISD::TargetConstant:
llvm_unreachable("Can't simplify this node");
@ -1171,10 +1171,7 @@ bool TargetLowering::SimplifyDemandedBits(
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 @@ bool TargetLowering::SimplifyDemandedBits(
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 @@ bool TargetLowering::SimplifyDemandedBits(
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 @@ bool TargetLowering::SimplifyDemandedBits(
}
}
Known = std::move(KnownOut);
Known ^= Known2;
break;
}
case ISD::SELECT:

View File

@ -82,3 +82,28 @@ KnownBits KnownBits::computeForAddSub(bool Add, bool NSW,
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;
}

View File

@ -33256,10 +33256,7 @@ void X86TargetLowering::computeKnownBitsForTargetNode(const SDValue Op,
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: {

View File

@ -176,15 +176,12 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
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 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
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 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
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 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
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 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
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 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
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 @@ Value *InstCombiner::SimplifyMultipleUseDemandedBits(Instruction *I,
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 @@ Value *InstCombiner::SimplifyMultipleUseDemandedBits(Instruction *I,
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 @@ Value *InstCombiner::SimplifyMultipleUseDemandedBits(Instruction *I,
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 @@ Value *InstCombiner::SimplifyMultipleUseDemandedBits(Instruction *I,
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 @@ Value *InstCombiner::SimplifyMultipleUseDemandedBits(Instruction *I,
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 @@ Value *InstCombiner::SimplifyMultipleUseDemandedBits(Instruction *I,
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:

View File

@ -127,6 +127,51 @@ TEST(KnownBitsTest, AddSubExhaustive) {
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) {