aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/IR/ConstantRange.cpp
diff options
context:
space:
mode:
authorAntonio Frighetto <me@antoniofrighetto.com>2023-02-17 09:50:49 +0100
committerNikita Popov <npopov@redhat.com>2023-02-17 09:57:35 +0100
commit65898e526060ae0f02de556c63dd3ce599d08c52 (patch)
tree2f227c488c9a7313ad009513cd760c4f8b310765 /llvm/lib/IR/ConstantRange.cpp
parenta1e80c69223a091e6f0fc84df33a464604c8bbc1 (diff)
downloadllvm-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.cpp46
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())