diff options
author | Antonio Frighetto <me@antoniofrighetto.com> | 2023-02-17 09:50:49 +0100 |
---|---|---|
committer | Nikita Popov <npopov@redhat.com> | 2023-02-17 09:57:35 +0100 |
commit | 65898e526060ae0f02de556c63dd3ce599d08c52 (patch) | |
tree | 2f227c488c9a7313ad009513cd760c4f8b310765 /llvm/lib/IR/ConstantRange.cpp | |
parent | a1e80c69223a091e6f0fc84df33a464604c8bbc1 (diff) | |
download | llvm-65898e526060ae0f02de556c63dd3ce599d08c52.zip llvm-65898e526060ae0f02de556c63dd3ce599d08c52.tar.gz llvm-65898e526060ae0f02de556c63dd3ce599d08c52.tar.bz2 |
[ConstantRange] Handle `Intrinsic::ctlz`
Introduce ConstantRange support for ctlz intrinsic, including
exhaustive testing. Among other things, LVI may now be able to
propagate information about cltz constant ranges lattice values.
Differential Revision: https://reviews.llvm.org/D142234
Diffstat (limited to 'llvm/lib/IR/ConstantRange.cpp')
-rw-r--r-- | llvm/lib/IR/ConstantRange.cpp | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index 0dbccaa..ab94053 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -945,6 +945,7 @@ bool ConstantRange::isIntrinsicSupported(Intrinsic::ID IntrinsicID) { case Intrinsic::smin: case Intrinsic::smax: case Intrinsic::abs: + case Intrinsic::ctlz: return true; default: return false; @@ -976,6 +977,12 @@ ConstantRange ConstantRange::intrinsic(Intrinsic::ID IntrinsicID, assert(IntMinIsPoison->getBitWidth() == 1 && "Must be boolean"); return Ops[0].abs(IntMinIsPoison->getBoolValue()); } + case Intrinsic::ctlz: { + const APInt *ZeroIsPoison = Ops[1].getSingleElement(); + assert(ZeroIsPoison && "Must be known (immarg)"); + assert(ZeroIsPoison->getBitWidth() == 1 && "Must be boolean"); + return Ops[0].ctlz(ZeroIsPoison->getBoolValue()); + } default: assert(!isIntrinsicSupported(IntrinsicID) && "Shouldn't be supported"); llvm_unreachable("Unsupported intrinsic"); @@ -1667,6 +1674,45 @@ ConstantRange ConstantRange::abs(bool IntMinIsPoison) const { APIntOps::umax(-SMin, SMax) + 1); } +ConstantRange ConstantRange::ctlz(bool ZeroIsPoison) const { + if (isEmptySet()) + return getEmpty(); + + APInt Zero = APInt::getZero(getBitWidth()); + if (ZeroIsPoison && contains(Zero)) { + // ZeroIsPoison is set, and zero is contained. We discern three cases, in + // which a zero can appear: + // 1) Lower is zero, handling cases of kind [0, 1), [0, 2), etc. + // 2) Upper is zero, wrapped set, handling cases of kind [3, 0], etc. + // 3) Zero contained in a wrapped set, e.g., [3, 2), [3, 1), etc. + + if (getLower().isZero()) { + if ((getUpper() - 1).isZero()) { + // We have in input interval of kind [0, 1). In this case we cannot + // really help but return empty-set. + return getEmpty(); + } + + // Compute the resulting range by excluding zero from Lower. + return ConstantRange( + APInt(getBitWidth(), (getUpper() - 1).countLeadingZeros()), + APInt(getBitWidth(), (getLower() + 1).countLeadingZeros() + 1)); + } else if ((getUpper() - 1).isZero()) { + // Compute the resulting range by excluding zero from Upper. + return ConstantRange( + Zero, APInt(getBitWidth(), getLower().countLeadingZeros() + 1)); + } else { + return ConstantRange(Zero, APInt(getBitWidth(), getBitWidth())); + } + } + + // Zero is either safe or not in the range. The output range is composed by + // the result of countLeadingZero of the two extremes. + return getNonEmpty( + APInt(getBitWidth(), getUnsignedMax().countLeadingZeros()), + APInt(getBitWidth(), getUnsignedMin().countLeadingZeros() + 1)); +} + ConstantRange::OverflowResult ConstantRange::unsignedAddMayOverflow( const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) |