[SelectionDAG] ComputeKnownBits - add support for SMIN+SMAX clamp patterns

If we have a clamp pattern, SMIN(SMAX(X, LO),HI) or SMAX(SMIN(X, HI),LO) then we can deduce that the number of signbits (zeros/ones) will be at least the minimum of the LO and HI constants.

ComputeKnownBits equivalent of D43338.

Differential Revision: https://reviews.llvm.org/D43463

llvm-svn: 325521
This commit is contained in:
Simon Pilgrim 2018-02-19 18:08:16 +00:00
parent 4c4a9835a2
commit 70eb508605
2 changed files with 733 additions and 802 deletions

View File

@ -2920,11 +2920,38 @@ void SelectionDAG::computeKnownBits(SDValue Op, KnownBits &Known,
}
case ISD::SMIN:
case ISD::SMAX: {
computeKnownBits(Op.getOperand(0), Known, DemandedElts,
Depth + 1);
// If we don't know any bits, early out.
if (Known.isUnknown())
break;
// If we have a clamp pattern, we know that the number of sign bits will be
// the minimum of the clamp min/max range.
bool IsMax = (Opcode == ISD::SMAX);
ConstantSDNode *CstLow = nullptr, *CstHigh = nullptr;
if ((CstLow = isConstOrDemandedConstSplat(Op.getOperand(1), DemandedElts)))
if (Op.getOperand(0).getOpcode() == (IsMax ? ISD::SMIN : ISD::SMAX))
CstHigh = isConstOrDemandedConstSplat(Op.getOperand(0).getOperand(1),
DemandedElts);
if (CstLow && CstHigh) {
if (!IsMax)
std::swap(CstLow, CstHigh);
const APInt &ValueLow = CstLow->getAPIntValue();
const APInt &ValueHigh = CstHigh->getAPIntValue();
if (ValueLow.sle(ValueHigh)) {
unsigned LowSignBits = ValueLow.getNumSignBits();
unsigned HighSignBits = ValueHigh.getNumSignBits();
unsigned MinSignBits = std::min(LowSignBits, HighSignBits);
if (ValueLow.isNegative() && ValueHigh.isNegative()) {
Known.One.setHighBits(MinSignBits);
break;
}
if (ValueLow.isNonNegative() && ValueHigh.isNonNegative()) {
Known.Zero.setHighBits(MinSignBits);
break;
}
}
}
// Fallback - just get the shared known bits of the operands.
computeKnownBits(Op.getOperand(0), Known, DemandedElts, Depth + 1);
if (Known.isUnknown()) break; // Early-out
computeKnownBits(Op.getOperand(1), Known2, DemandedElts, Depth + 1);
Known.Zero &= Known2.Zero;
Known.One &= Known2.One;

File diff suppressed because it is too large Load Diff