175bfc6f2SKrzysztof Drewniak //===- InferIntRangeInterfaceImpls.cpp - Integer range impls for arith -===//
275bfc6f2SKrzysztof Drewniak //
375bfc6f2SKrzysztof Drewniak // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
475bfc6f2SKrzysztof Drewniak // See https://llvm.org/LICENSE.txt for license information.
575bfc6f2SKrzysztof Drewniak // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
675bfc6f2SKrzysztof Drewniak //
775bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
875bfc6f2SKrzysztof Drewniak 
975bfc6f2SKrzysztof Drewniak #include "mlir/Dialect/Arithmetic/IR/Arithmetic.h"
1075bfc6f2SKrzysztof Drewniak #include "mlir/Interfaces/InferIntRangeInterface.h"
1175bfc6f2SKrzysztof Drewniak 
1275bfc6f2SKrzysztof Drewniak #include "llvm/Support/Debug.h"
1375bfc6f2SKrzysztof Drewniak 
1475bfc6f2SKrzysztof Drewniak #define DEBUG_TYPE "int-range-analysis"
1575bfc6f2SKrzysztof Drewniak 
1675bfc6f2SKrzysztof Drewniak using namespace mlir;
1775bfc6f2SKrzysztof Drewniak using namespace mlir::arith;
1875bfc6f2SKrzysztof Drewniak 
1975bfc6f2SKrzysztof Drewniak /// Function that evaluates the result of doing something on arithmetic
2075bfc6f2SKrzysztof Drewniak /// constants and returns None on overflow.
2175bfc6f2SKrzysztof Drewniak using ConstArithFn =
2275bfc6f2SKrzysztof Drewniak     function_ref<Optional<APInt>(const APInt &, const APInt &)>;
2375bfc6f2SKrzysztof Drewniak 
2475bfc6f2SKrzysztof Drewniak /// Return the maxmially wide signed or unsigned range for a given bitwidth.
2575bfc6f2SKrzysztof Drewniak 
2675bfc6f2SKrzysztof Drewniak /// Compute op(minLeft, minRight) and op(maxLeft, maxRight) if possible,
2775bfc6f2SKrzysztof Drewniak /// If either computation overflows, make the result unbounded.
computeBoundsBy(ConstArithFn op,const APInt & minLeft,const APInt & minRight,const APInt & maxLeft,const APInt & maxRight,bool isSigned)2875bfc6f2SKrzysztof Drewniak static ConstantIntRanges computeBoundsBy(ConstArithFn op, const APInt &minLeft,
2975bfc6f2SKrzysztof Drewniak                                          const APInt &minRight,
3075bfc6f2SKrzysztof Drewniak                                          const APInt &maxLeft,
3175bfc6f2SKrzysztof Drewniak                                          const APInt &maxRight, bool isSigned) {
3275bfc6f2SKrzysztof Drewniak   Optional<APInt> maybeMin = op(minLeft, minRight);
3375bfc6f2SKrzysztof Drewniak   Optional<APInt> maybeMax = op(maxLeft, maxRight);
34*037f0995SKazu Hirata   if (maybeMin && maybeMax)
3575bfc6f2SKrzysztof Drewniak     return ConstantIntRanges::range(*maybeMin, *maybeMax, isSigned);
3675bfc6f2SKrzysztof Drewniak   return ConstantIntRanges::maxRange(minLeft.getBitWidth());
3775bfc6f2SKrzysztof Drewniak }
3875bfc6f2SKrzysztof Drewniak 
3975bfc6f2SKrzysztof Drewniak /// Compute the minimum and maximum of `(op(l, r) for l in lhs for r in rhs)`,
4075bfc6f2SKrzysztof Drewniak /// ignoring unbounded values. Returns the maximal range if `op` overflows.
minMaxBy(ConstArithFn op,ArrayRef<APInt> lhs,ArrayRef<APInt> rhs,bool isSigned)4175bfc6f2SKrzysztof Drewniak static ConstantIntRanges minMaxBy(ConstArithFn op, ArrayRef<APInt> lhs,
4275bfc6f2SKrzysztof Drewniak                                   ArrayRef<APInt> rhs, bool isSigned) {
4375bfc6f2SKrzysztof Drewniak   unsigned width = lhs[0].getBitWidth();
4475bfc6f2SKrzysztof Drewniak   APInt min =
4575bfc6f2SKrzysztof Drewniak       isSigned ? APInt::getSignedMaxValue(width) : APInt::getMaxValue(width);
4675bfc6f2SKrzysztof Drewniak   APInt max =
4775bfc6f2SKrzysztof Drewniak       isSigned ? APInt::getSignedMinValue(width) : APInt::getZero(width);
4875bfc6f2SKrzysztof Drewniak   for (const APInt &left : lhs) {
4975bfc6f2SKrzysztof Drewniak     for (const APInt &right : rhs) {
5075bfc6f2SKrzysztof Drewniak       Optional<APInt> maybeThisResult = op(left, right);
5175bfc6f2SKrzysztof Drewniak       if (!maybeThisResult)
5275bfc6f2SKrzysztof Drewniak         return ConstantIntRanges::maxRange(width);
5375bfc6f2SKrzysztof Drewniak       APInt result = std::move(*maybeThisResult);
5475bfc6f2SKrzysztof Drewniak       min = (isSigned ? result.slt(min) : result.ult(min)) ? result : min;
5575bfc6f2SKrzysztof Drewniak       max = (isSigned ? result.sgt(max) : result.ugt(max)) ? result : max;
5675bfc6f2SKrzysztof Drewniak     }
5775bfc6f2SKrzysztof Drewniak   }
5875bfc6f2SKrzysztof Drewniak   return ConstantIntRanges::range(min, max, isSigned);
5975bfc6f2SKrzysztof Drewniak }
6075bfc6f2SKrzysztof Drewniak 
6175bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
6275bfc6f2SKrzysztof Drewniak // ConstantOp
6375bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
6475bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)6575bfc6f2SKrzysztof Drewniak void arith::ConstantOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
6675bfc6f2SKrzysztof Drewniak                                           SetIntRangeFn setResultRange) {
6775bfc6f2SKrzysztof Drewniak   auto constAttr = getValue().dyn_cast_or_null<IntegerAttr>();
6875bfc6f2SKrzysztof Drewniak   if (constAttr) {
6975bfc6f2SKrzysztof Drewniak     const APInt &value = constAttr.getValue();
7075bfc6f2SKrzysztof Drewniak     setResultRange(getResult(), ConstantIntRanges::constant(value));
7175bfc6f2SKrzysztof Drewniak   }
7275bfc6f2SKrzysztof Drewniak }
7375bfc6f2SKrzysztof Drewniak 
7475bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
7575bfc6f2SKrzysztof Drewniak // AddIOp
7675bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
7775bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)7875bfc6f2SKrzysztof Drewniak void arith::AddIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
7975bfc6f2SKrzysztof Drewniak                                       SetIntRangeFn setResultRange) {
8075bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
8175bfc6f2SKrzysztof Drewniak   ConstArithFn uadd = [](const APInt &a, const APInt &b) -> Optional<APInt> {
8275bfc6f2SKrzysztof Drewniak     bool overflowed = false;
8375bfc6f2SKrzysztof Drewniak     APInt result = a.uadd_ov(b, overflowed);
8475bfc6f2SKrzysztof Drewniak     return overflowed ? Optional<APInt>() : result;
8575bfc6f2SKrzysztof Drewniak   };
8675bfc6f2SKrzysztof Drewniak   ConstArithFn sadd = [](const APInt &a, const APInt &b) -> Optional<APInt> {
8775bfc6f2SKrzysztof Drewniak     bool overflowed = false;
8875bfc6f2SKrzysztof Drewniak     APInt result = a.sadd_ov(b, overflowed);
8975bfc6f2SKrzysztof Drewniak     return overflowed ? Optional<APInt>() : result;
9075bfc6f2SKrzysztof Drewniak   };
9175bfc6f2SKrzysztof Drewniak 
9275bfc6f2SKrzysztof Drewniak   ConstantIntRanges urange = computeBoundsBy(
9375bfc6f2SKrzysztof Drewniak       uadd, lhs.umin(), rhs.umin(), lhs.umax(), rhs.umax(), /*isSigned=*/false);
9475bfc6f2SKrzysztof Drewniak   ConstantIntRanges srange = computeBoundsBy(
9575bfc6f2SKrzysztof Drewniak       sadd, lhs.smin(), rhs.smin(), lhs.smax(), rhs.smax(), /*isSigned=*/true);
9675bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), urange.intersection(srange));
9775bfc6f2SKrzysztof Drewniak }
9875bfc6f2SKrzysztof Drewniak 
9975bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
10075bfc6f2SKrzysztof Drewniak // SubIOp
10175bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
10275bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)10375bfc6f2SKrzysztof Drewniak void arith::SubIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
10475bfc6f2SKrzysztof Drewniak                                       SetIntRangeFn setResultRange) {
10575bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
10675bfc6f2SKrzysztof Drewniak 
10775bfc6f2SKrzysztof Drewniak   ConstArithFn usub = [](const APInt &a, const APInt &b) -> Optional<APInt> {
10875bfc6f2SKrzysztof Drewniak     bool overflowed = false;
10975bfc6f2SKrzysztof Drewniak     APInt result = a.usub_ov(b, overflowed);
11075bfc6f2SKrzysztof Drewniak     return overflowed ? Optional<APInt>() : result;
11175bfc6f2SKrzysztof Drewniak   };
11275bfc6f2SKrzysztof Drewniak   ConstArithFn ssub = [](const APInt &a, const APInt &b) -> Optional<APInt> {
11375bfc6f2SKrzysztof Drewniak     bool overflowed = false;
11475bfc6f2SKrzysztof Drewniak     APInt result = a.ssub_ov(b, overflowed);
11575bfc6f2SKrzysztof Drewniak     return overflowed ? Optional<APInt>() : result;
11675bfc6f2SKrzysztof Drewniak   };
11775bfc6f2SKrzysztof Drewniak   ConstantIntRanges urange = computeBoundsBy(
11875bfc6f2SKrzysztof Drewniak       usub, lhs.umin(), rhs.umax(), lhs.umax(), rhs.umin(), /*isSigned=*/false);
11975bfc6f2SKrzysztof Drewniak   ConstantIntRanges srange = computeBoundsBy(
12075bfc6f2SKrzysztof Drewniak       ssub, lhs.smin(), rhs.smax(), lhs.smax(), rhs.smin(), /*isSigned=*/true);
12175bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), urange.intersection(srange));
12275bfc6f2SKrzysztof Drewniak }
12375bfc6f2SKrzysztof Drewniak 
12475bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
12575bfc6f2SKrzysztof Drewniak // MulIOp
12675bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
12775bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)12875bfc6f2SKrzysztof Drewniak void arith::MulIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
12975bfc6f2SKrzysztof Drewniak                                       SetIntRangeFn setResultRange) {
13075bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
13175bfc6f2SKrzysztof Drewniak 
13275bfc6f2SKrzysztof Drewniak   ConstArithFn umul = [](const APInt &a, const APInt &b) -> Optional<APInt> {
13375bfc6f2SKrzysztof Drewniak     bool overflowed = false;
13475bfc6f2SKrzysztof Drewniak     APInt result = a.umul_ov(b, overflowed);
13575bfc6f2SKrzysztof Drewniak     return overflowed ? Optional<APInt>() : result;
13675bfc6f2SKrzysztof Drewniak   };
13775bfc6f2SKrzysztof Drewniak   ConstArithFn smul = [](const APInt &a, const APInt &b) -> Optional<APInt> {
13875bfc6f2SKrzysztof Drewniak     bool overflowed = false;
13975bfc6f2SKrzysztof Drewniak     APInt result = a.smul_ov(b, overflowed);
14075bfc6f2SKrzysztof Drewniak     return overflowed ? Optional<APInt>() : result;
14175bfc6f2SKrzysztof Drewniak   };
14275bfc6f2SKrzysztof Drewniak 
14375bfc6f2SKrzysztof Drewniak   ConstantIntRanges urange =
14475bfc6f2SKrzysztof Drewniak       minMaxBy(umul, {lhs.umin(), lhs.umax()}, {rhs.umin(), rhs.umax()},
14575bfc6f2SKrzysztof Drewniak                /*isSigned=*/false);
14675bfc6f2SKrzysztof Drewniak   ConstantIntRanges srange =
14775bfc6f2SKrzysztof Drewniak       minMaxBy(smul, {lhs.smin(), lhs.smax()}, {rhs.smin(), rhs.smax()},
14875bfc6f2SKrzysztof Drewniak                /*isSigned=*/true);
14975bfc6f2SKrzysztof Drewniak 
15075bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), urange.intersection(srange));
15175bfc6f2SKrzysztof Drewniak }
15275bfc6f2SKrzysztof Drewniak 
15375bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
15475bfc6f2SKrzysztof Drewniak // DivUIOp
15575bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
15675bfc6f2SKrzysztof Drewniak 
15775bfc6f2SKrzysztof Drewniak /// Fix up division results (ex. for ceiling and floor), returning an APInt
15875bfc6f2SKrzysztof Drewniak /// if there has been no overflow
15975bfc6f2SKrzysztof Drewniak using DivisionFixupFn = function_ref<Optional<APInt>(
16075bfc6f2SKrzysztof Drewniak     const APInt &lhs, const APInt &rhs, const APInt &result)>;
16175bfc6f2SKrzysztof Drewniak 
inferDivUIRange(const ConstantIntRanges & lhs,const ConstantIntRanges & rhs,DivisionFixupFn fixup)16275bfc6f2SKrzysztof Drewniak static ConstantIntRanges inferDivUIRange(const ConstantIntRanges &lhs,
16375bfc6f2SKrzysztof Drewniak                                          const ConstantIntRanges &rhs,
16475bfc6f2SKrzysztof Drewniak                                          DivisionFixupFn fixup) {
16575bfc6f2SKrzysztof Drewniak   const APInt &lhsMin = lhs.umin(), &lhsMax = lhs.umax(), &rhsMin = rhs.umin(),
16675bfc6f2SKrzysztof Drewniak               &rhsMax = rhs.umax();
16775bfc6f2SKrzysztof Drewniak 
16875bfc6f2SKrzysztof Drewniak   if (!rhsMin.isZero()) {
16975bfc6f2SKrzysztof Drewniak     auto udiv = [&fixup](const APInt &a, const APInt &b) -> Optional<APInt> {
17075bfc6f2SKrzysztof Drewniak       return fixup(a, b, a.udiv(b));
17175bfc6f2SKrzysztof Drewniak     };
17275bfc6f2SKrzysztof Drewniak     return minMaxBy(udiv, {lhsMin, lhsMax}, {rhsMin, rhsMax},
17375bfc6f2SKrzysztof Drewniak                     /*isSigned=*/false);
17475bfc6f2SKrzysztof Drewniak   }
17575bfc6f2SKrzysztof Drewniak   // Otherwise, it's possible we might divide by 0.
17675bfc6f2SKrzysztof Drewniak   return ConstantIntRanges::maxRange(rhsMin.getBitWidth());
17775bfc6f2SKrzysztof Drewniak }
17875bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)17975bfc6f2SKrzysztof Drewniak void arith::DivUIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
18075bfc6f2SKrzysztof Drewniak                                        SetIntRangeFn setResultRange) {
18175bfc6f2SKrzysztof Drewniak   setResultRange(getResult(),
18275bfc6f2SKrzysztof Drewniak                  inferDivUIRange(argRanges[0], argRanges[1],
18375bfc6f2SKrzysztof Drewniak                                  [](const APInt &lhs, const APInt &rhs,
18475bfc6f2SKrzysztof Drewniak                                     const APInt &result) { return result; }));
18575bfc6f2SKrzysztof Drewniak }
18675bfc6f2SKrzysztof Drewniak 
18775bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
18875bfc6f2SKrzysztof Drewniak // DivSIOp
18975bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
19075bfc6f2SKrzysztof Drewniak 
inferDivSIRange(const ConstantIntRanges & lhs,const ConstantIntRanges & rhs,DivisionFixupFn fixup)19175bfc6f2SKrzysztof Drewniak static ConstantIntRanges inferDivSIRange(const ConstantIntRanges &lhs,
19275bfc6f2SKrzysztof Drewniak                                          const ConstantIntRanges &rhs,
19375bfc6f2SKrzysztof Drewniak                                          DivisionFixupFn fixup) {
19475bfc6f2SKrzysztof Drewniak   const APInt &lhsMin = lhs.smin(), &lhsMax = lhs.smax(), &rhsMin = rhs.smin(),
19575bfc6f2SKrzysztof Drewniak               &rhsMax = rhs.smax();
19675bfc6f2SKrzysztof Drewniak   bool canDivide = rhsMin.isStrictlyPositive() || rhsMax.isNegative();
19775bfc6f2SKrzysztof Drewniak 
19875bfc6f2SKrzysztof Drewniak   if (canDivide) {
19975bfc6f2SKrzysztof Drewniak     auto sdiv = [&fixup](const APInt &a, const APInt &b) -> Optional<APInt> {
20075bfc6f2SKrzysztof Drewniak       bool overflowed = false;
20175bfc6f2SKrzysztof Drewniak       APInt result = a.sdiv_ov(b, overflowed);
20275bfc6f2SKrzysztof Drewniak       return overflowed ? Optional<APInt>() : fixup(a, b, result);
20375bfc6f2SKrzysztof Drewniak     };
20475bfc6f2SKrzysztof Drewniak     return minMaxBy(sdiv, {lhsMin, lhsMax}, {rhsMin, rhsMax},
20575bfc6f2SKrzysztof Drewniak                     /*isSigned=*/true);
20675bfc6f2SKrzysztof Drewniak   }
20775bfc6f2SKrzysztof Drewniak   return ConstantIntRanges::maxRange(rhsMin.getBitWidth());
20875bfc6f2SKrzysztof Drewniak }
20975bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)21075bfc6f2SKrzysztof Drewniak void arith::DivSIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
21175bfc6f2SKrzysztof Drewniak                                        SetIntRangeFn setResultRange) {
21275bfc6f2SKrzysztof Drewniak   setResultRange(getResult(),
21375bfc6f2SKrzysztof Drewniak                  inferDivSIRange(argRanges[0], argRanges[1],
21475bfc6f2SKrzysztof Drewniak                                  [](const APInt &lhs, const APInt &rhs,
21575bfc6f2SKrzysztof Drewniak                                     const APInt &result) { return result; }));
21675bfc6f2SKrzysztof Drewniak }
21775bfc6f2SKrzysztof Drewniak 
21875bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
21975bfc6f2SKrzysztof Drewniak // CeilDivUIOp
22075bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
22175bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)22275bfc6f2SKrzysztof Drewniak void arith::CeilDivUIOp::inferResultRanges(
22375bfc6f2SKrzysztof Drewniak     ArrayRef<ConstantIntRanges> argRanges, SetIntRangeFn setResultRange) {
22475bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
22575bfc6f2SKrzysztof Drewniak 
22675bfc6f2SKrzysztof Drewniak   DivisionFixupFn ceilDivUIFix = [](const APInt &lhs, const APInt &rhs,
22775bfc6f2SKrzysztof Drewniak                                     const APInt &result) -> Optional<APInt> {
22875bfc6f2SKrzysztof Drewniak     if (!lhs.urem(rhs).isZero()) {
22975bfc6f2SKrzysztof Drewniak       bool overflowed = false;
23075bfc6f2SKrzysztof Drewniak       APInt corrected =
23175bfc6f2SKrzysztof Drewniak           result.uadd_ov(APInt(result.getBitWidth(), 1), overflowed);
23275bfc6f2SKrzysztof Drewniak       return overflowed ? Optional<APInt>() : corrected;
23375bfc6f2SKrzysztof Drewniak     }
23475bfc6f2SKrzysztof Drewniak     return result;
23575bfc6f2SKrzysztof Drewniak   };
23675bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), inferDivUIRange(lhs, rhs, ceilDivUIFix));
23775bfc6f2SKrzysztof Drewniak }
23875bfc6f2SKrzysztof Drewniak 
23975bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
24075bfc6f2SKrzysztof Drewniak // CeilDivSIOp
24175bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
24275bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)24375bfc6f2SKrzysztof Drewniak void arith::CeilDivSIOp::inferResultRanges(
24475bfc6f2SKrzysztof Drewniak     ArrayRef<ConstantIntRanges> argRanges, SetIntRangeFn setResultRange) {
24575bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
24675bfc6f2SKrzysztof Drewniak 
24775bfc6f2SKrzysztof Drewniak   DivisionFixupFn ceilDivSIFix = [](const APInt &lhs, const APInt &rhs,
24875bfc6f2SKrzysztof Drewniak                                     const APInt &result) -> Optional<APInt> {
24975bfc6f2SKrzysztof Drewniak     if (!lhs.srem(rhs).isZero() && lhs.isNonNegative() == rhs.isNonNegative()) {
25075bfc6f2SKrzysztof Drewniak       bool overflowed = false;
25175bfc6f2SKrzysztof Drewniak       APInt corrected =
25275bfc6f2SKrzysztof Drewniak           result.sadd_ov(APInt(result.getBitWidth(), 1), overflowed);
25375bfc6f2SKrzysztof Drewniak       return overflowed ? Optional<APInt>() : corrected;
25475bfc6f2SKrzysztof Drewniak     }
25575bfc6f2SKrzysztof Drewniak     return result;
25675bfc6f2SKrzysztof Drewniak   };
25775bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), inferDivSIRange(lhs, rhs, ceilDivSIFix));
25875bfc6f2SKrzysztof Drewniak }
25975bfc6f2SKrzysztof Drewniak 
26075bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
26175bfc6f2SKrzysztof Drewniak // FloorDivSIOp
26275bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
26375bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)26475bfc6f2SKrzysztof Drewniak void arith::FloorDivSIOp::inferResultRanges(
26575bfc6f2SKrzysztof Drewniak     ArrayRef<ConstantIntRanges> argRanges, SetIntRangeFn setResultRange) {
26675bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
26775bfc6f2SKrzysztof Drewniak 
26875bfc6f2SKrzysztof Drewniak   DivisionFixupFn floorDivSIFix = [](const APInt &lhs, const APInt &rhs,
26975bfc6f2SKrzysztof Drewniak                                      const APInt &result) -> Optional<APInt> {
27075bfc6f2SKrzysztof Drewniak     if (!lhs.srem(rhs).isZero() && lhs.isNonNegative() != rhs.isNonNegative()) {
27175bfc6f2SKrzysztof Drewniak       bool overflowed = false;
27275bfc6f2SKrzysztof Drewniak       APInt corrected =
27375bfc6f2SKrzysztof Drewniak           result.ssub_ov(APInt(result.getBitWidth(), 1), overflowed);
27475bfc6f2SKrzysztof Drewniak       return overflowed ? Optional<APInt>() : corrected;
27575bfc6f2SKrzysztof Drewniak     }
27675bfc6f2SKrzysztof Drewniak     return result;
27775bfc6f2SKrzysztof Drewniak   };
27875bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), inferDivSIRange(lhs, rhs, floorDivSIFix));
27975bfc6f2SKrzysztof Drewniak }
28075bfc6f2SKrzysztof Drewniak 
28175bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
28275bfc6f2SKrzysztof Drewniak // RemUIOp
28375bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
28475bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)28575bfc6f2SKrzysztof Drewniak void arith::RemUIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
28675bfc6f2SKrzysztof Drewniak                                        SetIntRangeFn setResultRange) {
28775bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
28875bfc6f2SKrzysztof Drewniak   const APInt &rhsMin = rhs.umin(), &rhsMax = rhs.umax();
28975bfc6f2SKrzysztof Drewniak 
29075bfc6f2SKrzysztof Drewniak   unsigned width = rhsMin.getBitWidth();
29175bfc6f2SKrzysztof Drewniak   APInt umin = APInt::getZero(width);
29275bfc6f2SKrzysztof Drewniak   APInt umax = APInt::getMaxValue(width);
29375bfc6f2SKrzysztof Drewniak 
29475bfc6f2SKrzysztof Drewniak   if (!rhsMin.isZero()) {
29575bfc6f2SKrzysztof Drewniak     umax = rhsMax - 1;
29675bfc6f2SKrzysztof Drewniak     // Special case: sweeping out a contiguous range in N/[modulus]
29775bfc6f2SKrzysztof Drewniak     if (rhsMin == rhsMax) {
29875bfc6f2SKrzysztof Drewniak       const APInt &lhsMin = lhs.umin(), &lhsMax = lhs.umax();
29975bfc6f2SKrzysztof Drewniak       if ((lhsMax - lhsMin).ult(rhsMax)) {
30075bfc6f2SKrzysztof Drewniak         APInt minRem = lhsMin.urem(rhsMax);
30175bfc6f2SKrzysztof Drewniak         APInt maxRem = lhsMax.urem(rhsMax);
30275bfc6f2SKrzysztof Drewniak         if (minRem.ule(maxRem)) {
30375bfc6f2SKrzysztof Drewniak           umin = minRem;
30475bfc6f2SKrzysztof Drewniak           umax = maxRem;
30575bfc6f2SKrzysztof Drewniak         }
30675bfc6f2SKrzysztof Drewniak       }
30775bfc6f2SKrzysztof Drewniak     }
30875bfc6f2SKrzysztof Drewniak   }
30975bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), ConstantIntRanges::fromUnsigned(umin, umax));
31075bfc6f2SKrzysztof Drewniak }
31175bfc6f2SKrzysztof Drewniak 
31275bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
31375bfc6f2SKrzysztof Drewniak // RemSIOp
31475bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
31575bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)31675bfc6f2SKrzysztof Drewniak void arith::RemSIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
31775bfc6f2SKrzysztof Drewniak                                        SetIntRangeFn setResultRange) {
31875bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
31975bfc6f2SKrzysztof Drewniak   const APInt &lhsMin = lhs.smin(), &lhsMax = lhs.smax(), &rhsMin = rhs.smin(),
32075bfc6f2SKrzysztof Drewniak               &rhsMax = rhs.smax();
32175bfc6f2SKrzysztof Drewniak 
32275bfc6f2SKrzysztof Drewniak   unsigned width = rhsMax.getBitWidth();
32375bfc6f2SKrzysztof Drewniak   APInt smin = APInt::getSignedMinValue(width);
32475bfc6f2SKrzysztof Drewniak   APInt smax = APInt::getSignedMaxValue(width);
32575bfc6f2SKrzysztof Drewniak   // No bounds if zero could be a divisor.
32675bfc6f2SKrzysztof Drewniak   bool canBound = (rhsMin.isStrictlyPositive() || rhsMax.isNegative());
32775bfc6f2SKrzysztof Drewniak   if (canBound) {
32875bfc6f2SKrzysztof Drewniak     APInt maxDivisor = rhsMin.isStrictlyPositive() ? rhsMax : rhsMin.abs();
32975bfc6f2SKrzysztof Drewniak     bool canNegativeDividend = lhsMin.isNegative();
33075bfc6f2SKrzysztof Drewniak     bool canPositiveDividend = lhsMax.isStrictlyPositive();
33175bfc6f2SKrzysztof Drewniak     APInt zero = APInt::getZero(maxDivisor.getBitWidth());
33275bfc6f2SKrzysztof Drewniak     APInt maxPositiveResult = maxDivisor - 1;
33375bfc6f2SKrzysztof Drewniak     APInt minNegativeResult = -maxPositiveResult;
33475bfc6f2SKrzysztof Drewniak     smin = canNegativeDividend ? minNegativeResult : zero;
33575bfc6f2SKrzysztof Drewniak     smax = canPositiveDividend ? maxPositiveResult : zero;
33675bfc6f2SKrzysztof Drewniak     // Special case: sweeping out a contiguous range in N/[modulus].
33775bfc6f2SKrzysztof Drewniak     if (rhsMin == rhsMax) {
33875bfc6f2SKrzysztof Drewniak       if ((lhsMax - lhsMin).ult(maxDivisor)) {
33975bfc6f2SKrzysztof Drewniak         APInt minRem = lhsMin.srem(maxDivisor);
34075bfc6f2SKrzysztof Drewniak         APInt maxRem = lhsMax.srem(maxDivisor);
34175bfc6f2SKrzysztof Drewniak         if (minRem.sle(maxRem)) {
34275bfc6f2SKrzysztof Drewniak           smin = minRem;
34375bfc6f2SKrzysztof Drewniak           smax = maxRem;
34475bfc6f2SKrzysztof Drewniak         }
34575bfc6f2SKrzysztof Drewniak       }
34675bfc6f2SKrzysztof Drewniak     }
34775bfc6f2SKrzysztof Drewniak   }
34875bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), ConstantIntRanges::fromSigned(smin, smax));
34975bfc6f2SKrzysztof Drewniak }
35075bfc6f2SKrzysztof Drewniak 
35175bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
35275bfc6f2SKrzysztof Drewniak // AndIOp
35375bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
35475bfc6f2SKrzysztof Drewniak 
35575bfc6f2SKrzysztof Drewniak /// "Widen" bounds - if 0bvvvvv??? <= a <= 0bvvvvv???,
35675bfc6f2SKrzysztof Drewniak /// relax the bounds to 0bvvvvv000 <= a <= 0bvvvvv111, where vvvvv are the bits
35775bfc6f2SKrzysztof Drewniak /// that both bonuds have in common. This gives us a consertive approximation
35875bfc6f2SKrzysztof Drewniak /// for what values can be passed to bitwise operations.
35975bfc6f2SKrzysztof Drewniak static std::tuple<APInt, APInt>
widenBitwiseBounds(const ConstantIntRanges & bound)36075bfc6f2SKrzysztof Drewniak widenBitwiseBounds(const ConstantIntRanges &bound) {
36175bfc6f2SKrzysztof Drewniak   APInt leftVal = bound.umin(), rightVal = bound.umax();
36275bfc6f2SKrzysztof Drewniak   unsigned bitwidth = leftVal.getBitWidth();
36375bfc6f2SKrzysztof Drewniak   unsigned differingBits = bitwidth - (leftVal ^ rightVal).countLeadingZeros();
36475bfc6f2SKrzysztof Drewniak   leftVal.clearLowBits(differingBits);
36575bfc6f2SKrzysztof Drewniak   rightVal.setLowBits(differingBits);
366d3b17968SBenjamin Kramer   return std::make_tuple(std::move(leftVal), std::move(rightVal));
36775bfc6f2SKrzysztof Drewniak }
36875bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)36975bfc6f2SKrzysztof Drewniak void arith::AndIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
37075bfc6f2SKrzysztof Drewniak                                       SetIntRangeFn setResultRange) {
37175bfc6f2SKrzysztof Drewniak   APInt lhsZeros, lhsOnes, rhsZeros, rhsOnes;
37275bfc6f2SKrzysztof Drewniak   std::tie(lhsZeros, lhsOnes) = widenBitwiseBounds(argRanges[0]);
37375bfc6f2SKrzysztof Drewniak   std::tie(rhsZeros, rhsOnes) = widenBitwiseBounds(argRanges[1]);
37475bfc6f2SKrzysztof Drewniak   auto andi = [](const APInt &a, const APInt &b) -> Optional<APInt> {
37575bfc6f2SKrzysztof Drewniak     return a & b;
37675bfc6f2SKrzysztof Drewniak   };
37775bfc6f2SKrzysztof Drewniak   setResultRange(getResult(),
37875bfc6f2SKrzysztof Drewniak                  minMaxBy(andi, {lhsZeros, lhsOnes}, {rhsZeros, rhsOnes},
37975bfc6f2SKrzysztof Drewniak                           /*isSigned=*/false));
38075bfc6f2SKrzysztof Drewniak }
38175bfc6f2SKrzysztof Drewniak 
38275bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
38375bfc6f2SKrzysztof Drewniak // OrIOp
38475bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
38575bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)38675bfc6f2SKrzysztof Drewniak void arith::OrIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
38775bfc6f2SKrzysztof Drewniak                                      SetIntRangeFn setResultRange) {
38875bfc6f2SKrzysztof Drewniak   APInt lhsZeros, lhsOnes, rhsZeros, rhsOnes;
38975bfc6f2SKrzysztof Drewniak   std::tie(lhsZeros, lhsOnes) = widenBitwiseBounds(argRanges[0]);
39075bfc6f2SKrzysztof Drewniak   std::tie(rhsZeros, rhsOnes) = widenBitwiseBounds(argRanges[1]);
39175bfc6f2SKrzysztof Drewniak   auto ori = [](const APInt &a, const APInt &b) -> Optional<APInt> {
39275bfc6f2SKrzysztof Drewniak     return a | b;
39375bfc6f2SKrzysztof Drewniak   };
39475bfc6f2SKrzysztof Drewniak   setResultRange(getResult(),
39575bfc6f2SKrzysztof Drewniak                  minMaxBy(ori, {lhsZeros, lhsOnes}, {rhsZeros, rhsOnes},
39675bfc6f2SKrzysztof Drewniak                           /*isSigned=*/false));
39775bfc6f2SKrzysztof Drewniak }
39875bfc6f2SKrzysztof Drewniak 
39975bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
40075bfc6f2SKrzysztof Drewniak // XOrIOp
40175bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
40275bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)40375bfc6f2SKrzysztof Drewniak void arith::XOrIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
40475bfc6f2SKrzysztof Drewniak                                       SetIntRangeFn setResultRange) {
40575bfc6f2SKrzysztof Drewniak   APInt lhsZeros, lhsOnes, rhsZeros, rhsOnes;
40675bfc6f2SKrzysztof Drewniak   std::tie(lhsZeros, lhsOnes) = widenBitwiseBounds(argRanges[0]);
40775bfc6f2SKrzysztof Drewniak   std::tie(rhsZeros, rhsOnes) = widenBitwiseBounds(argRanges[1]);
40875bfc6f2SKrzysztof Drewniak   auto xori = [](const APInt &a, const APInt &b) -> Optional<APInt> {
40975bfc6f2SKrzysztof Drewniak     return a ^ b;
41075bfc6f2SKrzysztof Drewniak   };
41175bfc6f2SKrzysztof Drewniak   setResultRange(getResult(),
41275bfc6f2SKrzysztof Drewniak                  minMaxBy(xori, {lhsZeros, lhsOnes}, {rhsZeros, rhsOnes},
41375bfc6f2SKrzysztof Drewniak                           /*isSigned=*/false));
41475bfc6f2SKrzysztof Drewniak }
41575bfc6f2SKrzysztof Drewniak 
41675bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
41775bfc6f2SKrzysztof Drewniak // MaxSIOp
41875bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
41975bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)42075bfc6f2SKrzysztof Drewniak void arith::MaxSIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
42175bfc6f2SKrzysztof Drewniak                                        SetIntRangeFn setResultRange) {
42275bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
42375bfc6f2SKrzysztof Drewniak 
42475bfc6f2SKrzysztof Drewniak   const APInt &smin = lhs.smin().sgt(rhs.smin()) ? lhs.smin() : rhs.smin();
42575bfc6f2SKrzysztof Drewniak   const APInt &smax = lhs.smax().sgt(rhs.smax()) ? lhs.smax() : rhs.smax();
42675bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), ConstantIntRanges::fromSigned(smin, smax));
42775bfc6f2SKrzysztof Drewniak }
42875bfc6f2SKrzysztof Drewniak 
42975bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
43075bfc6f2SKrzysztof Drewniak // MaxUIOp
43175bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
43275bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)43375bfc6f2SKrzysztof Drewniak void arith::MaxUIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
43475bfc6f2SKrzysztof Drewniak                                        SetIntRangeFn setResultRange) {
43575bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
43675bfc6f2SKrzysztof Drewniak 
43775bfc6f2SKrzysztof Drewniak   const APInt &umin = lhs.umin().ugt(rhs.umin()) ? lhs.umin() : rhs.umin();
43875bfc6f2SKrzysztof Drewniak   const APInt &umax = lhs.umax().ugt(rhs.umax()) ? lhs.umax() : rhs.umax();
43975bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), ConstantIntRanges::fromUnsigned(umin, umax));
44075bfc6f2SKrzysztof Drewniak }
44175bfc6f2SKrzysztof Drewniak 
44275bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
44375bfc6f2SKrzysztof Drewniak // MinSIOp
44475bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
44575bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)44675bfc6f2SKrzysztof Drewniak void arith::MinSIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
44775bfc6f2SKrzysztof Drewniak                                        SetIntRangeFn setResultRange) {
44875bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
44975bfc6f2SKrzysztof Drewniak 
45075bfc6f2SKrzysztof Drewniak   const APInt &smin = lhs.smin().slt(rhs.smin()) ? lhs.smin() : rhs.smin();
45175bfc6f2SKrzysztof Drewniak   const APInt &smax = lhs.smax().slt(rhs.smax()) ? lhs.smax() : rhs.smax();
45275bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), ConstantIntRanges::fromSigned(smin, smax));
45375bfc6f2SKrzysztof Drewniak }
45475bfc6f2SKrzysztof Drewniak 
45575bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
45675bfc6f2SKrzysztof Drewniak // MinUIOp
45775bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
45875bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)45975bfc6f2SKrzysztof Drewniak void arith::MinUIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
46075bfc6f2SKrzysztof Drewniak                                        SetIntRangeFn setResultRange) {
46175bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
46275bfc6f2SKrzysztof Drewniak 
46375bfc6f2SKrzysztof Drewniak   const APInt &umin = lhs.umin().ult(rhs.umin()) ? lhs.umin() : rhs.umin();
46475bfc6f2SKrzysztof Drewniak   const APInt &umax = lhs.umax().ult(rhs.umax()) ? lhs.umax() : rhs.umax();
46575bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), ConstantIntRanges::fromUnsigned(umin, umax));
46675bfc6f2SKrzysztof Drewniak }
46775bfc6f2SKrzysztof Drewniak 
46875bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
46975bfc6f2SKrzysztof Drewniak // ExtUIOp
47075bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
47175bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)47275bfc6f2SKrzysztof Drewniak void arith::ExtUIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
47375bfc6f2SKrzysztof Drewniak                                        SetIntRangeFn setResultRange) {
47475bfc6f2SKrzysztof Drewniak   Type destType = getResult().getType();
47575bfc6f2SKrzysztof Drewniak   unsigned destWidth = ConstantIntRanges::getStorageBitwidth(destType);
47675bfc6f2SKrzysztof Drewniak   APInt umin = argRanges[0].umin().zext(destWidth);
47775bfc6f2SKrzysztof Drewniak   APInt umax = argRanges[0].umax().zext(destWidth);
47875bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), ConstantIntRanges::fromUnsigned(umin, umax));
47975bfc6f2SKrzysztof Drewniak }
48075bfc6f2SKrzysztof Drewniak 
48175bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
48275bfc6f2SKrzysztof Drewniak // ExtSIOp
48375bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
48475bfc6f2SKrzysztof Drewniak 
extSIRange(const ConstantIntRanges & range,Type destType)48575bfc6f2SKrzysztof Drewniak static ConstantIntRanges extSIRange(const ConstantIntRanges &range,
48675bfc6f2SKrzysztof Drewniak                                     Type destType) {
48775bfc6f2SKrzysztof Drewniak   unsigned destWidth = ConstantIntRanges::getStorageBitwidth(destType);
48875bfc6f2SKrzysztof Drewniak   APInt smin = range.smin().sext(destWidth);
48975bfc6f2SKrzysztof Drewniak   APInt smax = range.smax().sext(destWidth);
49075bfc6f2SKrzysztof Drewniak   return ConstantIntRanges::fromSigned(smin, smax);
49175bfc6f2SKrzysztof Drewniak }
49275bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)49375bfc6f2SKrzysztof Drewniak void arith::ExtSIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
49475bfc6f2SKrzysztof Drewniak                                        SetIntRangeFn setResultRange) {
49575bfc6f2SKrzysztof Drewniak   Type destType = getResult().getType();
49675bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), extSIRange(argRanges[0], destType));
49775bfc6f2SKrzysztof Drewniak }
49875bfc6f2SKrzysztof Drewniak 
49975bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
50075bfc6f2SKrzysztof Drewniak // TruncIOp
50175bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
50275bfc6f2SKrzysztof Drewniak 
truncIRange(const ConstantIntRanges & range,Type destType)50375bfc6f2SKrzysztof Drewniak static ConstantIntRanges truncIRange(const ConstantIntRanges &range,
50475bfc6f2SKrzysztof Drewniak                                      Type destType) {
50575bfc6f2SKrzysztof Drewniak   unsigned destWidth = ConstantIntRanges::getStorageBitwidth(destType);
50675bfc6f2SKrzysztof Drewniak   APInt umin = range.umin().trunc(destWidth);
50775bfc6f2SKrzysztof Drewniak   APInt umax = range.umax().trunc(destWidth);
50875bfc6f2SKrzysztof Drewniak   APInt smin = range.smin().trunc(destWidth);
50975bfc6f2SKrzysztof Drewniak   APInt smax = range.smax().trunc(destWidth);
51075bfc6f2SKrzysztof Drewniak   return {umin, umax, smin, smax};
51175bfc6f2SKrzysztof Drewniak }
51275bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)51375bfc6f2SKrzysztof Drewniak void arith::TruncIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
51475bfc6f2SKrzysztof Drewniak                                         SetIntRangeFn setResultRange) {
51575bfc6f2SKrzysztof Drewniak   Type destType = getResult().getType();
51675bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), truncIRange(argRanges[0], destType));
51775bfc6f2SKrzysztof Drewniak }
51875bfc6f2SKrzysztof Drewniak 
51975bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
52075bfc6f2SKrzysztof Drewniak // IndexCastOp
52175bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
52275bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)52375bfc6f2SKrzysztof Drewniak void arith::IndexCastOp::inferResultRanges(
52475bfc6f2SKrzysztof Drewniak     ArrayRef<ConstantIntRanges> argRanges, SetIntRangeFn setResultRange) {
52575bfc6f2SKrzysztof Drewniak   Type sourceType = getOperand().getType();
52675bfc6f2SKrzysztof Drewniak   Type destType = getResult().getType();
52775bfc6f2SKrzysztof Drewniak   unsigned srcWidth = ConstantIntRanges::getStorageBitwidth(sourceType);
52875bfc6f2SKrzysztof Drewniak   unsigned destWidth = ConstantIntRanges::getStorageBitwidth(destType);
52975bfc6f2SKrzysztof Drewniak 
53075bfc6f2SKrzysztof Drewniak   if (srcWidth < destWidth)
53175bfc6f2SKrzysztof Drewniak     setResultRange(getResult(), extSIRange(argRanges[0], destType));
53275bfc6f2SKrzysztof Drewniak   else if (srcWidth > destWidth)
53375bfc6f2SKrzysztof Drewniak     setResultRange(getResult(), truncIRange(argRanges[0], destType));
53475bfc6f2SKrzysztof Drewniak   else
53575bfc6f2SKrzysztof Drewniak     setResultRange(getResult(), argRanges[0]);
53675bfc6f2SKrzysztof Drewniak }
53775bfc6f2SKrzysztof Drewniak 
53875bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
53975bfc6f2SKrzysztof Drewniak // CmpIOp
54075bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
54175bfc6f2SKrzysztof Drewniak 
isStaticallyTrue(arith::CmpIPredicate pred,const ConstantIntRanges & lhs,const ConstantIntRanges & rhs)54275bfc6f2SKrzysztof Drewniak bool isStaticallyTrue(arith::CmpIPredicate pred, const ConstantIntRanges &lhs,
54375bfc6f2SKrzysztof Drewniak                       const ConstantIntRanges &rhs) {
54475bfc6f2SKrzysztof Drewniak   switch (pred) {
54575bfc6f2SKrzysztof Drewniak   case arith::CmpIPredicate::sle:
54675bfc6f2SKrzysztof Drewniak   case arith::CmpIPredicate::slt:
54775bfc6f2SKrzysztof Drewniak     return (applyCmpPredicate(pred, lhs.smax(), rhs.smin()));
54875bfc6f2SKrzysztof Drewniak   case arith::CmpIPredicate::ule:
54975bfc6f2SKrzysztof Drewniak   case arith::CmpIPredicate::ult:
55075bfc6f2SKrzysztof Drewniak     return applyCmpPredicate(pred, lhs.umax(), rhs.umin());
55175bfc6f2SKrzysztof Drewniak   case arith::CmpIPredicate::sge:
55275bfc6f2SKrzysztof Drewniak   case arith::CmpIPredicate::sgt:
55375bfc6f2SKrzysztof Drewniak     return applyCmpPredicate(pred, lhs.smin(), rhs.smax());
55475bfc6f2SKrzysztof Drewniak   case arith::CmpIPredicate::uge:
55575bfc6f2SKrzysztof Drewniak   case arith::CmpIPredicate::ugt:
55675bfc6f2SKrzysztof Drewniak     return applyCmpPredicate(pred, lhs.umin(), rhs.umax());
55775bfc6f2SKrzysztof Drewniak   case arith::CmpIPredicate::eq: {
55875bfc6f2SKrzysztof Drewniak     Optional<APInt> lhsConst = lhs.getConstantValue();
55975bfc6f2SKrzysztof Drewniak     Optional<APInt> rhsConst = rhs.getConstantValue();
56075bfc6f2SKrzysztof Drewniak     return lhsConst && rhsConst && lhsConst == rhsConst;
56175bfc6f2SKrzysztof Drewniak   }
56275bfc6f2SKrzysztof Drewniak   case arith::CmpIPredicate::ne: {
56375bfc6f2SKrzysztof Drewniak     // While equality requires that there is an interpration of the preceeding
56475bfc6f2SKrzysztof Drewniak     // computations that produces equal constants, whether that be signed or
56575bfc6f2SKrzysztof Drewniak     // unsigned, statically determining inequality requires that neither
56675bfc6f2SKrzysztof Drewniak     // interpretation produce potentially overlapping ranges.
56775bfc6f2SKrzysztof Drewniak     bool sne = isStaticallyTrue(CmpIPredicate::slt, lhs, rhs) ||
56875bfc6f2SKrzysztof Drewniak                isStaticallyTrue(CmpIPredicate::sgt, lhs, rhs);
56975bfc6f2SKrzysztof Drewniak     bool une = isStaticallyTrue(CmpIPredicate::ult, lhs, rhs) ||
57075bfc6f2SKrzysztof Drewniak                isStaticallyTrue(CmpIPredicate::ugt, lhs, rhs);
57175bfc6f2SKrzysztof Drewniak     return sne && une;
57275bfc6f2SKrzysztof Drewniak   }
57375bfc6f2SKrzysztof Drewniak   }
57475bfc6f2SKrzysztof Drewniak   return false;
57575bfc6f2SKrzysztof Drewniak }
57675bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)57775bfc6f2SKrzysztof Drewniak void arith::CmpIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
57875bfc6f2SKrzysztof Drewniak                                       SetIntRangeFn setResultRange) {
57975bfc6f2SKrzysztof Drewniak   arith::CmpIPredicate pred = getPredicate();
58075bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
58175bfc6f2SKrzysztof Drewniak 
58275bfc6f2SKrzysztof Drewniak   APInt min = APInt::getZero(1);
58375bfc6f2SKrzysztof Drewniak   APInt max = APInt::getAllOnesValue(1);
58475bfc6f2SKrzysztof Drewniak   if (isStaticallyTrue(pred, lhs, rhs))
58575bfc6f2SKrzysztof Drewniak     min = max;
58675bfc6f2SKrzysztof Drewniak   else if (isStaticallyTrue(invertPredicate(pred), lhs, rhs))
58775bfc6f2SKrzysztof Drewniak     max = min;
58875bfc6f2SKrzysztof Drewniak 
58975bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), ConstantIntRanges::fromUnsigned(min, max));
59075bfc6f2SKrzysztof Drewniak }
59175bfc6f2SKrzysztof Drewniak 
59275bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
59375bfc6f2SKrzysztof Drewniak // SelectOp
59475bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
59575bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)59675bfc6f2SKrzysztof Drewniak void arith::SelectOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
59775bfc6f2SKrzysztof Drewniak                                         SetIntRangeFn setResultRange) {
59875bfc6f2SKrzysztof Drewniak   Optional<APInt> mbCondVal = argRanges[0].getConstantValue();
59975bfc6f2SKrzysztof Drewniak 
60075bfc6f2SKrzysztof Drewniak   if (mbCondVal) {
60175bfc6f2SKrzysztof Drewniak     if (mbCondVal->isZero())
60275bfc6f2SKrzysztof Drewniak       setResultRange(getResult(), argRanges[2]);
60375bfc6f2SKrzysztof Drewniak     else
60475bfc6f2SKrzysztof Drewniak       setResultRange(getResult(), argRanges[1]);
60575bfc6f2SKrzysztof Drewniak     return;
60675bfc6f2SKrzysztof Drewniak   }
60775bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), argRanges[1].rangeUnion(argRanges[2]));
60875bfc6f2SKrzysztof Drewniak }
60975bfc6f2SKrzysztof Drewniak 
61075bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
61175bfc6f2SKrzysztof Drewniak // ShLIOp
61275bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
61375bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)61475bfc6f2SKrzysztof Drewniak void arith::ShLIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
61575bfc6f2SKrzysztof Drewniak                                       SetIntRangeFn setResultRange) {
61675bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
61775bfc6f2SKrzysztof Drewniak   ConstArithFn shl = [](const APInt &l, const APInt &r) -> Optional<APInt> {
61875bfc6f2SKrzysztof Drewniak     return r.uge(r.getBitWidth()) ? Optional<APInt>() : l.shl(r);
61975bfc6f2SKrzysztof Drewniak   };
62075bfc6f2SKrzysztof Drewniak   ConstantIntRanges urange =
62175bfc6f2SKrzysztof Drewniak       minMaxBy(shl, {lhs.umin(), lhs.umax()}, {rhs.umin(), rhs.umax()},
62275bfc6f2SKrzysztof Drewniak                /*isSigned=*/false);
62375bfc6f2SKrzysztof Drewniak   ConstantIntRanges srange =
62475bfc6f2SKrzysztof Drewniak       minMaxBy(shl, {lhs.smin(), lhs.smax()}, {rhs.umin(), rhs.umax()},
62575bfc6f2SKrzysztof Drewniak                /*isSigned=*/true);
62675bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), urange.intersection(srange));
62775bfc6f2SKrzysztof Drewniak }
62875bfc6f2SKrzysztof Drewniak 
62975bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
63075bfc6f2SKrzysztof Drewniak // ShRUIOp
63175bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
63275bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)63375bfc6f2SKrzysztof Drewniak void arith::ShRUIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
63475bfc6f2SKrzysztof Drewniak                                        SetIntRangeFn setResultRange) {
63575bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
63675bfc6f2SKrzysztof Drewniak 
63775bfc6f2SKrzysztof Drewniak   ConstArithFn lshr = [](const APInt &l, const APInt &r) -> Optional<APInt> {
63875bfc6f2SKrzysztof Drewniak     return r.uge(r.getBitWidth()) ? Optional<APInt>() : l.lshr(r);
63975bfc6f2SKrzysztof Drewniak   };
64075bfc6f2SKrzysztof Drewniak   setResultRange(getResult(), minMaxBy(lshr, {lhs.umin(), lhs.umax()},
64175bfc6f2SKrzysztof Drewniak                                        {rhs.umin(), rhs.umax()},
64275bfc6f2SKrzysztof Drewniak                                        /*isSigned=*/false));
64375bfc6f2SKrzysztof Drewniak }
64475bfc6f2SKrzysztof Drewniak 
64575bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
64675bfc6f2SKrzysztof Drewniak // ShRSIOp
64775bfc6f2SKrzysztof Drewniak //===----------------------------------------------------------------------===//
64875bfc6f2SKrzysztof Drewniak 
inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,SetIntRangeFn setResultRange)64975bfc6f2SKrzysztof Drewniak void arith::ShRSIOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
65075bfc6f2SKrzysztof Drewniak                                        SetIntRangeFn setResultRange) {
65175bfc6f2SKrzysztof Drewniak   const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
65275bfc6f2SKrzysztof Drewniak 
65375bfc6f2SKrzysztof Drewniak   ConstArithFn ashr = [](const APInt &l, const APInt &r) -> Optional<APInt> {
65475bfc6f2SKrzysztof Drewniak     return r.uge(r.getBitWidth()) ? Optional<APInt>() : l.ashr(r);
65575bfc6f2SKrzysztof Drewniak   };
65675bfc6f2SKrzysztof Drewniak 
65775bfc6f2SKrzysztof Drewniak   setResultRange(getResult(),
65875bfc6f2SKrzysztof Drewniak                  minMaxBy(ashr, {lhs.smin(), lhs.smax()},
65975bfc6f2SKrzysztof Drewniak                           {rhs.umin(), rhs.umax()}, /*isSigned=*/true));
66075bfc6f2SKrzysztof Drewniak }
661