[ValueTracking] Add some initial isKnownNonZero DemandedElts support (PR36319)

This commit is contained in:
Simon Pilgrim 2020-03-20 13:29:00 +00:00
parent 960e248f36
commit 7cc5fa5f26
2 changed files with 59 additions and 29 deletions

View File

@ -215,6 +215,9 @@ void llvm::computeKnownBits(const Value *V, KnownBits &Known,
Query(DL, AC, safeCxtI(V, CxtI), DT, UseInstrInfo, ORE));
}
static KnownBits computeKnownBits(const Value *V, const APInt &DemandedElts,
unsigned Depth, const Query &Q);
static KnownBits computeKnownBits(const Value *V, unsigned Depth,
const Query &Q);
@ -275,6 +278,9 @@ bool llvm::isKnownToBeAPowerOfTwo(const Value *V, const DataLayout &DL,
V, OrZero, Depth, Query(DL, AC, safeCxtI(V, CxtI), DT, UseInstrInfo));
}
static bool isKnownNonZero(const Value *V, const APInt &DemandedElts,
unsigned Depth, const Query &Q);
static bool isKnownNonZero(const Value *V, unsigned Depth, const Query &Q);
bool llvm::isKnownNonZero(const Value *V, const DataLayout &DL, unsigned Depth,
@ -1052,7 +1058,8 @@ static void computeKnownBitsFromShiftOperator(
// Early exit if we can't constrain any well-defined shift amount.
if (!(ShiftAmtKZ & (PowerOf2Ceil(BitWidth) - 1)) &&
!(ShiftAmtKO & (PowerOf2Ceil(BitWidth) - 1))) {
ShifterOperandIsNonZero = isKnownNonZero(I->getOperand(1), Depth + 1, Q);
ShifterOperandIsNonZero =
isKnownNonZero(I->getOperand(1), DemandedElts, Depth + 1, Q);
if (!*ShifterOperandIsNonZero)
return;
}
@ -1074,7 +1081,7 @@ static void computeKnownBitsFromShiftOperator(
if (ShiftAmt == 0) {
if (!ShifterOperandIsNonZero.hasValue())
ShifterOperandIsNonZero =
isKnownNonZero(I->getOperand(1), Depth + 1, Q);
isKnownNonZero(I->getOperand(1), DemandedElts, Depth + 1, Q);
if (*ShifterOperandIsNonZero)
continue;
}
@ -1811,6 +1818,15 @@ static void computeKnownBitsFromOperator(const Operator *I,
}
}
/// Determine which bits of V are known to be either zero or one and return
/// them.
KnownBits computeKnownBits(const Value *V, const APInt &DemandedElts,
unsigned Depth, const Query &Q) {
KnownBits Known(getBitWidth(V->getType(), Q.DL));
computeKnownBits(V, DemandedElts, Known, Depth, Q);
return Known;
}
/// Determine which bits of V are known to be either zero or one and return
/// them.
KnownBits computeKnownBits(const Value *V, unsigned Depth, const Query &Q) {
@ -2223,12 +2239,13 @@ static bool rangeMetadataExcludesValue(const MDNode* Ranges, const APInt& Value)
}
/// Return true if the given value is known to be non-zero when defined. For
/// vectors, return true if every element is known to be non-zero when
/// vectors, return true if every demanded element is known to be non-zero when
/// defined. For pointers, if the context instruction and dominator tree are
/// specified, perform context-sensitive analysis and return true if the
/// pointer couldn't possibly be null at the specified instruction.
/// Supports values with integer or pointer type and vectors of integers.
bool isKnownNonZero(const Value *V, unsigned Depth, const Query &Q) {
bool isKnownNonZero(const Value *V, const APInt &DemandedElts, unsigned Depth,
const Query &Q) {
if (auto *C = dyn_cast<Constant>(V)) {
if (C->isNullValue())
return false;
@ -2249,6 +2266,8 @@ bool isKnownNonZero(const Value *V, unsigned Depth, const Query &Q) {
// non-zero to determine that the whole vector is known non-zero.
if (auto *VecTy = dyn_cast<VectorType>(C->getType())) {
for (unsigned i = 0, e = VecTy->getNumElements(); i != e; ++i) {
if (!DemandedElts[i])
continue;
Constant *Elt = C->getAggregateElement(i);
if (!Elt || Elt->isNullValue())
return false;
@ -2349,7 +2368,8 @@ bool isKnownNonZero(const Value *V, unsigned Depth, const Query &Q) {
// X | Y != 0 if X != 0 or Y != 0.
Value *X = nullptr, *Y = nullptr;
if (match(V, m_Or(m_Value(X), m_Value(Y))))
return isKnownNonZero(X, Depth, Q) || isKnownNonZero(Y, Depth, Q);
return isKnownNonZero(X, DemandedElts, Depth, Q) ||
isKnownNonZero(Y, DemandedElts, Depth, Q);
// ext X != 0 if X != 0.
if (isa<SExtInst>(V) || isa<ZExtInst>(V))
@ -2364,7 +2384,7 @@ bool isKnownNonZero(const Value *V, unsigned Depth, const Query &Q) {
return isKnownNonZero(X, Depth, Q);
KnownBits Known(BitWidth);
computeKnownBits(X, Known, Depth, Q);
computeKnownBits(X, DemandedElts, Known, Depth, Q);
if (Known.One[0])
return true;
}
@ -2376,7 +2396,7 @@ bool isKnownNonZero(const Value *V, unsigned Depth, const Query &Q) {
if (BO->isExact())
return isKnownNonZero(X, Depth, Q);
KnownBits Known = computeKnownBits(X, Depth, Q);
KnownBits Known = computeKnownBits(X, DemandedElts, Depth, Q);
if (Known.isNegative())
return true;
@ -2390,22 +2410,23 @@ bool isKnownNonZero(const Value *V, unsigned Depth, const Query &Q) {
return true;
// Are all the bits to be shifted out known zero?
if (Known.countMinTrailingZeros() >= ShiftVal)
return isKnownNonZero(X, Depth, Q);
return isKnownNonZero(X, DemandedElts, Depth, Q);
}
}
// div exact can only produce a zero if the dividend is zero.
else if (match(V, m_Exact(m_IDiv(m_Value(X), m_Value())))) {
return isKnownNonZero(X, Depth, Q);
return isKnownNonZero(X, DemandedElts, Depth, Q);
}
// X + Y.
else if (match(V, m_Add(m_Value(X), m_Value(Y)))) {
KnownBits XKnown = computeKnownBits(X, Depth, Q);
KnownBits YKnown = computeKnownBits(Y, Depth, Q);
KnownBits XKnown = computeKnownBits(X, DemandedElts, Depth, Q);
KnownBits YKnown = computeKnownBits(Y, DemandedElts, Depth, Q);
// If X and Y are both non-negative (as signed values) then their sum is not
// zero unless both X and Y are zero.
if (XKnown.isNonNegative() && YKnown.isNonNegative())
if (isKnownNonZero(X, Depth, Q) || isKnownNonZero(Y, Depth, Q))
if (isKnownNonZero(X, DemandedElts, Depth, Q) ||
isKnownNonZero(Y, DemandedElts, Depth, Q))
return true;
// If X and Y are both negative (as signed values) then their sum is not
@ -2436,13 +2457,14 @@ bool isKnownNonZero(const Value *V, unsigned Depth, const Query &Q) {
// If X and Y are non-zero then so is X * Y as long as the multiplication
// does not overflow.
if ((Q.IIQ.hasNoSignedWrap(BO) || Q.IIQ.hasNoUnsignedWrap(BO)) &&
isKnownNonZero(X, Depth, Q) && isKnownNonZero(Y, Depth, Q))
isKnownNonZero(X, DemandedElts, Depth, Q) &&
isKnownNonZero(Y, DemandedElts, Depth, Q))
return true;
}
// (C ? X : Y) != 0 if X != 0 and Y != 0.
else if (const SelectInst *SI = dyn_cast<SelectInst>(V)) {
if (isKnownNonZero(SI->getTrueValue(), Depth, Q) &&
isKnownNonZero(SI->getFalseValue(), Depth, Q))
if (isKnownNonZero(SI->getTrueValue(), DemandedElts, Depth, Q) &&
isKnownNonZero(SI->getFalseValue(), DemandedElts, Depth, Q))
return true;
}
// PHI
@ -2472,12 +2494,31 @@ bool isKnownNonZero(const Value *V, unsigned Depth, const Query &Q) {
if (AllNonZeroConstants)
return true;
}
// ExtractElement
else if (const auto *EEI = dyn_cast<ExtractElementInst>(V)) {
const Value *Vec = EEI->getVectorOperand();
const Value *Idx = EEI->getIndexOperand();
auto *CIdx = dyn_cast<ConstantInt>(Idx);
unsigned NumElts = Vec->getType()->getVectorNumElements();
APInt DemandedVecElts = APInt::getAllOnesValue(NumElts);
if (CIdx && CIdx->getValue().ult(NumElts))
DemandedVecElts = APInt::getOneBitSet(NumElts, CIdx->getZExtValue());
return isKnownNonZero(Vec, DemandedVecElts, Depth, Q);
}
KnownBits Known(BitWidth);
computeKnownBits(V, Known, Depth, Q);
computeKnownBits(V, DemandedElts, Known, Depth, Q);
return Known.One != 0;
}
bool isKnownNonZero(const Value* V, unsigned Depth, const Query& Q) {
Type *Ty = V->getType();
APInt DemandedElts = Ty->isVectorTy()
? APInt::getAllOnesValue(Ty->getVectorNumElements())
: APInt(1, 1);
return isKnownNonZero(V, DemandedElts, Depth, Q);
}
/// Return true if V2 == V1 + X, where X is known non-zero.
static bool isAddOfNonZero(const Value *V1, const Value *V2, const Query &Q) {
const BinaryOperator *BO = dyn_cast<BinaryOperator>(V1);

View File

@ -379,13 +379,7 @@ define i1 @add(i32 %x, i32 %y) {
define i1 @addv(<2 x i32> %x, <2 x i32> %y) {
; CHECK-LABEL: @addv(
; CHECK-NEXT: [[L:%.*]] = lshr <2 x i32> [[X:%.*]], <i32 1, i32 0>
; CHECK-NEXT: [[Q:%.*]] = lshr <2 x i32> [[Y:%.*]], <i32 1, i32 0>
; CHECK-NEXT: [[R:%.*]] = or <2 x i32> [[Q]], <i32 1, i32 0>
; CHECK-NEXT: [[S:%.*]] = add <2 x i32> [[L]], [[R]]
; CHECK-NEXT: [[E:%.*]] = extractelement <2 x i32> [[S]], i32 0
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[E]], 0
; CHECK-NEXT: ret i1 [[C]]
; CHECK-NEXT: ret i1 false
;
%l = lshr <2 x i32> %x, <i32 1, i32 0>
%q = lshr <2 x i32> %y, <i32 1, i32 0>
@ -409,12 +403,7 @@ define i1 @add2(i8 %x, i8 %y) {
define i1 @add2v(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @add2v(
; CHECK-NEXT: [[L:%.*]] = or <2 x i8> [[X:%.*]], <i8 0, i8 -128>
; CHECK-NEXT: [[R:%.*]] = or <2 x i8> [[Y:%.*]], <i8 0, i8 -127>
; CHECK-NEXT: [[S:%.*]] = add <2 x i8> [[L]], [[R]]
; CHECK-NEXT: [[E:%.*]] = extractelement <2 x i8> [[S]], i32 1
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[E]], 0
; CHECK-NEXT: ret i1 [[C]]
; CHECK-NEXT: ret i1 false
;
%l = or <2 x i8> %x, <i8 0, i8 128>
%r = or <2 x i8> %y, <i8 0, i8 129>