#include "llvm/Support/KnownBits.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
using namespace llvm;
static KnownBits computeForAddCarry(
const KnownBits &LHS, const KnownBits &RHS,
bool CarryZero, bool CarryOne) {
assert(!(CarryZero && CarryOne) &&
"Carry can't be zero and one at the same time");
APInt PossibleSumZero = LHS.getMaxValue() + RHS.getMaxValue() + !CarryZero;
APInt PossibleSumOne = LHS.getMinValue() + RHS.getMinValue() + CarryOne;
APInt CarryKnownZero = ~(PossibleSumZero ^ LHS.Zero ^ RHS.Zero);
APInt CarryKnownOne = PossibleSumOne ^ LHS.One ^ RHS.One;
APInt LHSKnownUnion = LHS.Zero | LHS.One;
APInt RHSKnownUnion = RHS.Zero | RHS.One;
APInt CarryKnownUnion = std::move(CarryKnownZero) | CarryKnownOne;
APInt Known = std::move(LHSKnownUnion) & RHSKnownUnion & CarryKnownUnion;
assert((PossibleSumZero & Known) == (PossibleSumOne & Known) &&
"known bits of sum differ");
KnownBits KnownOut;
KnownOut.Zero = ~std::move(PossibleSumZero) & Known;
KnownOut.One = std::move(PossibleSumOne) & Known;
return KnownOut;
}
KnownBits KnownBits::computeForAddCarry(
const KnownBits &LHS, const KnownBits &RHS, const KnownBits &Carry) {
assert(Carry.getBitWidth() == 1 && "Carry must be 1-bit");
return ::computeForAddCarry(
LHS, RHS, Carry.Zero.getBoolValue(), Carry.One.getBoolValue());
}
KnownBits KnownBits::computeForAddSub(bool Add, bool NSW,
const KnownBits &LHS, KnownBits RHS) {
KnownBits KnownOut;
if (Add) {
KnownOut = ::computeForAddCarry(
LHS, RHS, true, false);
} else {
std::swap(RHS.Zero, RHS.One);
KnownOut = ::computeForAddCarry(
LHS, RHS, false, true);
}
if (!KnownOut.isNegative() && !KnownOut.isNonNegative()) {
if (NSW) {
if (LHS.isNonNegative() && RHS.isNonNegative())
KnownOut.makeNonNegative();
else if (LHS.isNegative() && RHS.isNegative())
KnownOut.makeNegative();
}
}
return KnownOut;
}
KnownBits KnownBits::sextInReg(unsigned SrcBitWidth) const {
unsigned BitWidth = getBitWidth();
assert(0 < SrcBitWidth && SrcBitWidth <= BitWidth &&
"Illegal sext-in-register");
if (SrcBitWidth == BitWidth)
return *this;
unsigned ExtBits = BitWidth - SrcBitWidth;
KnownBits Result;
Result.One = One << ExtBits;
Result.Zero = Zero << ExtBits;
Result.One.ashrInPlace(ExtBits);
Result.Zero.ashrInPlace(ExtBits);
return Result;
}
KnownBits KnownBits::makeGE(const APInt &Val) const {
unsigned N = (Zero | Val).countLeadingOnes();
APInt MaskedVal(Val);
MaskedVal.clearLowBits(getBitWidth() - N);
return KnownBits(Zero, One | MaskedVal);
}
KnownBits KnownBits::umax(const KnownBits &LHS, const KnownBits &RHS) {
if (LHS.getMinValue().uge(RHS.getMaxValue()))
return LHS;
if (RHS.getMinValue().uge(LHS.getMaxValue()))
return RHS;
KnownBits L = LHS.makeGE(RHS.getMinValue());
KnownBits R = RHS.makeGE(LHS.getMinValue());
return KnownBits::commonBits(L, R);
}
KnownBits KnownBits::umin(const KnownBits &LHS, const KnownBits &RHS) {
auto Flip = [](const KnownBits &Val) { return KnownBits(Val.One, Val.Zero); };
return Flip(umax(Flip(LHS), Flip(RHS)));
}
KnownBits KnownBits::smax(const KnownBits &LHS, const KnownBits &RHS) {
auto Flip = [](const KnownBits &Val) {
unsigned SignBitPosition = Val.getBitWidth() - 1;
APInt Zero = Val.Zero;
APInt One = Val.One;
Zero.setBitVal(SignBitPosition, Val.One[SignBitPosition]);
One.setBitVal(SignBitPosition, Val.Zero[SignBitPosition]);
return KnownBits(Zero, One);
};
return Flip(umax(Flip(LHS), Flip(RHS)));
}
KnownBits KnownBits::smin(const KnownBits &LHS, const KnownBits &RHS) {
auto Flip = [](const KnownBits &Val) {
unsigned SignBitPosition = Val.getBitWidth() - 1;
APInt Zero = Val.One;
APInt One = Val.Zero;
Zero.setBitVal(SignBitPosition, Val.Zero[SignBitPosition]);
One.setBitVal(SignBitPosition, Val.One[SignBitPosition]);
return KnownBits(Zero, One);
};
return Flip(umax(Flip(LHS), Flip(RHS)));
}
KnownBits KnownBits::shl(const KnownBits &LHS, const KnownBits &RHS) {
unsigned BitWidth = LHS.getBitWidth();
KnownBits Known(BitWidth);
if (RHS.isConstant() && RHS.getConstant().ult(BitWidth)) {
unsigned Shift = RHS.getConstant().getZExtValue();
Known = LHS;
Known.Zero <<= Shift;
Known.One <<= Shift;
Known.Zero.setLowBits(Shift);
return Known;
}
unsigned MinTrailingZeros = LHS.countMinTrailingZeros();
APInt MinShiftAmount = RHS.getMinValue();
if (MinShiftAmount.ult(BitWidth)) {
MinTrailingZeros += MinShiftAmount.getZExtValue();
MinTrailingZeros = std::min(MinTrailingZeros, BitWidth);
}
APInt MaxShiftAmount = RHS.getMaxValue();
if (MaxShiftAmount.ult(BitWidth) && !LHS.isUnknown()) {
uint64_t ShiftAmtZeroMask = (~RHS.Zero).getZExtValue();
uint64_t ShiftAmtOneMask = RHS.One.getZExtValue();
assert(MinShiftAmount.ult(MaxShiftAmount) && "Illegal shift range");
Known.Zero.setAllBits();
Known.One.setAllBits();
for (uint64_t ShiftAmt = MinShiftAmount.getZExtValue(),
MaxShiftAmt = MaxShiftAmount.getZExtValue();
ShiftAmt <= MaxShiftAmt; ++ShiftAmt) {
if ((ShiftAmtZeroMask & ShiftAmt) != ShiftAmt ||
(ShiftAmtOneMask | ShiftAmt) != ShiftAmt)
continue;
KnownBits SpecificShift;
SpecificShift.Zero = LHS.Zero << ShiftAmt;
SpecificShift.One = LHS.One << ShiftAmt;
Known = KnownBits::commonBits(Known, SpecificShift);
if (Known.isUnknown())
break;
}
}
Known.Zero.setLowBits(MinTrailingZeros);
return Known;
}
KnownBits KnownBits::lshr(const KnownBits &LHS, const KnownBits &RHS) {
unsigned BitWidth = LHS.getBitWidth();
KnownBits Known(BitWidth);
if (RHS.isConstant() && RHS.getConstant().ult(BitWidth)) {
unsigned Shift = RHS.getConstant().getZExtValue();
Known = LHS;
Known.Zero.lshrInPlace(Shift);
Known.One.lshrInPlace(Shift);
Known.Zero.setHighBits(Shift);
return Known;
}
unsigned MinLeadingZeros = LHS.countMinLeadingZeros();
APInt MinShiftAmount = RHS.getMinValue();
if (MinShiftAmount.ult(BitWidth)) {
MinLeadingZeros += MinShiftAmount.getZExtValue();
MinLeadingZeros = std::min(MinLeadingZeros, BitWidth);
}
APInt MaxShiftAmount = RHS.getMaxValue();
if (MaxShiftAmount.ult(BitWidth) && !LHS.isUnknown()) {
uint64_t ShiftAmtZeroMask = (~RHS.Zero).getZExtValue();
uint64_t ShiftAmtOneMask = RHS.One.getZExtValue();
assert(MinShiftAmount.ult(MaxShiftAmount) && "Illegal shift range");
Known.Zero.setAllBits();
Known.One.setAllBits();
for (uint64_t ShiftAmt = MinShiftAmount.getZExtValue(),
MaxShiftAmt = MaxShiftAmount.getZExtValue();
ShiftAmt <= MaxShiftAmt; ++ShiftAmt) {
if ((ShiftAmtZeroMask & ShiftAmt) != ShiftAmt ||
(ShiftAmtOneMask | ShiftAmt) != ShiftAmt)
continue;
KnownBits SpecificShift = LHS;
SpecificShift.Zero.lshrInPlace(ShiftAmt);
SpecificShift.One.lshrInPlace(ShiftAmt);
Known = KnownBits::commonBits(Known, SpecificShift);
if (Known.isUnknown())
break;
}
}
Known.Zero.setHighBits(MinLeadingZeros);
return Known;
}
KnownBits KnownBits::ashr(const KnownBits &LHS, const KnownBits &RHS) {
unsigned BitWidth = LHS.getBitWidth();
KnownBits Known(BitWidth);
if (RHS.isConstant() && RHS.getConstant().ult(BitWidth)) {
unsigned Shift = RHS.getConstant().getZExtValue();
Known = LHS;
Known.Zero.ashrInPlace(Shift);
Known.One.ashrInPlace(Shift);
return Known;
}
unsigned MinLeadingZeros = LHS.countMinLeadingZeros();
unsigned MinLeadingOnes = LHS.countMinLeadingOnes();
APInt MinShiftAmount = RHS.getMinValue();
if (MinShiftAmount.ult(BitWidth)) {
if (MinLeadingZeros) {
MinLeadingZeros += MinShiftAmount.getZExtValue();
MinLeadingZeros = std::min(MinLeadingZeros, BitWidth);
}
if (MinLeadingOnes) {
MinLeadingOnes += MinShiftAmount.getZExtValue();
MinLeadingOnes = std::min(MinLeadingOnes, BitWidth);
}
}
APInt MaxShiftAmount = RHS.getMaxValue();
if (MaxShiftAmount.ult(BitWidth) && !LHS.isUnknown()) {
uint64_t ShiftAmtZeroMask = (~RHS.Zero).getZExtValue();
uint64_t ShiftAmtOneMask = RHS.One.getZExtValue();
assert(MinShiftAmount.ult(MaxShiftAmount) && "Illegal shift range");
Known.Zero.setAllBits();
Known.One.setAllBits();
for (uint64_t ShiftAmt = MinShiftAmount.getZExtValue(),
MaxShiftAmt = MaxShiftAmount.getZExtValue();
ShiftAmt <= MaxShiftAmt; ++ShiftAmt) {
if ((ShiftAmtZeroMask & ShiftAmt) != ShiftAmt ||
(ShiftAmtOneMask | ShiftAmt) != ShiftAmt)
continue;
KnownBits SpecificShift = LHS;
SpecificShift.Zero.ashrInPlace(ShiftAmt);
SpecificShift.One.ashrInPlace(ShiftAmt);
Known = KnownBits::commonBits(Known, SpecificShift);
if (Known.isUnknown())
break;
}
}
Known.Zero.setHighBits(MinLeadingZeros);
Known.One.setHighBits(MinLeadingOnes);
return Known;
}
Optional<bool> KnownBits::eq(const KnownBits &LHS, const KnownBits &RHS) {
if (LHS.isConstant() && RHS.isConstant())
return Optional<bool>(LHS.getConstant() == RHS.getConstant());
if (LHS.One.intersects(RHS.Zero) || RHS.One.intersects(LHS.Zero))
return Optional<bool>(false);
return None;
}
Optional<bool> KnownBits::ne(const KnownBits &LHS, const KnownBits &RHS) {
if (Optional<bool> KnownEQ = eq(LHS, RHS))
return Optional<bool>(!*KnownEQ);
return None;
}
Optional<bool> KnownBits::ugt(const KnownBits &LHS, const KnownBits &RHS) {
if (LHS.getMaxValue().ule(RHS.getMinValue()))
return Optional<bool>(false);
if (LHS.getMinValue().ugt(RHS.getMaxValue()))
return Optional<bool>(true);
return None;
}
Optional<bool> KnownBits::uge(const KnownBits &LHS, const KnownBits &RHS) {
if (Optional<bool> IsUGT = ugt(RHS, LHS))
return Optional<bool>(!*IsUGT);
return None;
}
Optional<bool> KnownBits::ult(const KnownBits &LHS, const KnownBits &RHS) {
return ugt(RHS, LHS);
}
Optional<bool> KnownBits::ule(const KnownBits &LHS, const KnownBits &RHS) {
return uge(RHS, LHS);
}
Optional<bool> KnownBits::sgt(const KnownBits &LHS, const KnownBits &RHS) {
if (LHS.getSignedMaxValue().sle(RHS.getSignedMinValue()))
return Optional<bool>(false);
if (LHS.getSignedMinValue().sgt(RHS.getSignedMaxValue()))
return Optional<bool>(true);
return None;
}
Optional<bool> KnownBits::sge(const KnownBits &LHS, const KnownBits &RHS) {
if (Optional<bool> KnownSGT = sgt(RHS, LHS))
return Optional<bool>(!*KnownSGT);
return None;
}
Optional<bool> KnownBits::slt(const KnownBits &LHS, const KnownBits &RHS) {
return sgt(RHS, LHS);
}
Optional<bool> KnownBits::sle(const KnownBits &LHS, const KnownBits &RHS) {
return sge(RHS, LHS);
}
KnownBits KnownBits::abs(bool IntMinIsPoison) const {
if (isNonNegative())
return *this;
KnownBits KnownAbs(getBitWidth());
KnownAbs.Zero.setLowBits(countMinTrailingZeros());
if (IntMinIsPoison || (!One.isZero() && !One.isMinSignedValue()))
KnownAbs.Zero.setSignBit();
return KnownAbs;
}
KnownBits KnownBits::mul(const KnownBits &LHS, const KnownBits &RHS,
bool NoUndefSelfMultiply) {
unsigned BitWidth = LHS.getBitWidth();
assert(BitWidth == RHS.getBitWidth() && !LHS.hasConflict() &&
!RHS.hasConflict() && "Operand mismatch");
assert((!NoUndefSelfMultiply || LHS == RHS) &&
"Self multiplication knownbits mismatch");
APInt UMaxLHS = LHS.getMaxValue();
APInt UMaxRHS = RHS.getMaxValue();
bool HasOverflow;
APInt UMaxResult = UMaxLHS.umul_ov(UMaxRHS, HasOverflow);
unsigned LeadZ = HasOverflow ? 0 : UMaxResult.countLeadingZeros();
const APInt &Bottom0 = LHS.One;
const APInt &Bottom1 = RHS.One;
unsigned TrailBitsKnown0 = (LHS.Zero | LHS.One).countTrailingOnes();
unsigned TrailBitsKnown1 = (RHS.Zero | RHS.One).countTrailingOnes();
unsigned TrailZero0 = LHS.countMinTrailingZeros();
unsigned TrailZero1 = RHS.countMinTrailingZeros();
unsigned TrailZ = TrailZero0 + TrailZero1;
unsigned SmallestOperand =
std::min(TrailBitsKnown0 - TrailZero0, TrailBitsKnown1 - TrailZero1);
unsigned ResultBitsKnown = std::min(SmallestOperand + TrailZ, BitWidth);
APInt BottomKnown =
Bottom0.getLoBits(TrailBitsKnown0) * Bottom1.getLoBits(TrailBitsKnown1);
KnownBits Res(BitWidth);
Res.Zero.setHighBits(LeadZ);
Res.Zero |= (~BottomKnown).getLoBits(ResultBitsKnown);
Res.One = BottomKnown.getLoBits(ResultBitsKnown);
if (NoUndefSelfMultiply && BitWidth > 1) {
assert(Res.One[1] == 0 &&
"Self-multiplication failed Quadratic Reciprocity!");
Res.Zero.setBit(1);
}
return Res;
}
KnownBits KnownBits::mulhs(const KnownBits &LHS, const KnownBits &RHS) {
unsigned BitWidth = LHS.getBitWidth();
assert(BitWidth == RHS.getBitWidth() && !LHS.hasConflict() &&
!RHS.hasConflict() && "Operand mismatch");
KnownBits WideLHS = LHS.sext(2 * BitWidth);
KnownBits WideRHS = RHS.sext(2 * BitWidth);
return mul(WideLHS, WideRHS).extractBits(BitWidth, BitWidth);
}
KnownBits KnownBits::mulhu(const KnownBits &LHS, const KnownBits &RHS) {
unsigned BitWidth = LHS.getBitWidth();
assert(BitWidth == RHS.getBitWidth() && !LHS.hasConflict() &&
!RHS.hasConflict() && "Operand mismatch");
KnownBits WideLHS = LHS.zext(2 * BitWidth);
KnownBits WideRHS = RHS.zext(2 * BitWidth);
return mul(WideLHS, WideRHS).extractBits(BitWidth, BitWidth);
}
KnownBits KnownBits::udiv(const KnownBits &LHS, const KnownBits &RHS) {
unsigned BitWidth = LHS.getBitWidth();
assert(!LHS.hasConflict() && !RHS.hasConflict());
KnownBits Known(BitWidth);
unsigned LeadZ = LHS.countMinLeadingZeros();
unsigned RHSMaxLeadingZeros = RHS.countMaxLeadingZeros();
if (RHSMaxLeadingZeros != BitWidth)
LeadZ = std::min(BitWidth, LeadZ + BitWidth - RHSMaxLeadingZeros - 1);
Known.Zero.setHighBits(LeadZ);
return Known;
}
KnownBits KnownBits::urem(const KnownBits &LHS, const KnownBits &RHS) {
unsigned BitWidth = LHS.getBitWidth();
assert(!LHS.hasConflict() && !RHS.hasConflict());
KnownBits Known(BitWidth);
if (RHS.isConstant() && RHS.getConstant().isPowerOf2()) {
APInt LowBits = RHS.getConstant() - 1;
Known.Zero = LHS.Zero | ~LowBits;
Known.One = LHS.One & LowBits;
return Known;
}
uint32_t Leaders =
std::max(LHS.countMinLeadingZeros(), RHS.countMinLeadingZeros());
Known.Zero.setHighBits(Leaders);
return Known;
}
KnownBits KnownBits::srem(const KnownBits &LHS, const KnownBits &RHS) {
unsigned BitWidth = LHS.getBitWidth();
assert(!LHS.hasConflict() && !RHS.hasConflict());
KnownBits Known(BitWidth);
if (RHS.isConstant() && RHS.getConstant().isPowerOf2()) {
APInt LowBits = RHS.getConstant() - 1;
Known.Zero = LHS.Zero & LowBits;
Known.One = LHS.One & LowBits;
if (LHS.isNonNegative() || LowBits.isSubsetOf(LHS.Zero))
Known.Zero |= ~LowBits;
if (LHS.isNegative() && LowBits.intersects(LHS.One))
Known.One |= ~LowBits;
return Known;
}
Known.Zero.setHighBits(LHS.countMinLeadingZeros());
return Known;
}
KnownBits &KnownBits::operator&=(const KnownBits &RHS) {
Zero |= RHS.Zero;
One &= RHS.One;
return *this;
}
KnownBits &KnownBits::operator|=(const KnownBits &RHS) {
Zero &= RHS.Zero;
One |= RHS.One;
return *this;
}
KnownBits &KnownBits::operator^=(const KnownBits &RHS) {
APInt Z = (Zero & RHS.Zero) | (One & RHS.One);
One = (Zero & RHS.One) | (One & RHS.Zero);
Zero = std::move(Z);
return *this;
}
void KnownBits::print(raw_ostream &OS) const {
OS << "{Zero=" << Zero << ", One=" << One << "}";
}
void KnownBits::dump() const {
print(dbgs());
dbgs() << "\n";
}