1*95aff23eSKrzysztof Drewniak //===- InferIntRangeInterface.cpp -  Integer range inference interface ---===//
2*95aff23eSKrzysztof Drewniak //
3*95aff23eSKrzysztof Drewniak // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*95aff23eSKrzysztof Drewniak // See https://llvm.org/LICENSE.txt for license information.
5*95aff23eSKrzysztof Drewniak // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*95aff23eSKrzysztof Drewniak //
7*95aff23eSKrzysztof Drewniak //===----------------------------------------------------------------------===//
8*95aff23eSKrzysztof Drewniak 
9*95aff23eSKrzysztof Drewniak #include "mlir/Interfaces/InferIntRangeInterface.h"
10*95aff23eSKrzysztof Drewniak #include "mlir/IR/BuiltinTypes.h"
11*95aff23eSKrzysztof Drewniak #include "mlir/Interfaces/InferIntRangeInterface.cpp.inc"
12*95aff23eSKrzysztof Drewniak 
13*95aff23eSKrzysztof Drewniak using namespace mlir;
14*95aff23eSKrzysztof Drewniak 
15*95aff23eSKrzysztof Drewniak bool ConstantIntRanges::operator==(const ConstantIntRanges &other) const {
16*95aff23eSKrzysztof Drewniak   return umin().getBitWidth() == other.umin().getBitWidth() &&
17*95aff23eSKrzysztof Drewniak          umin() == other.umin() && umax() == other.umax() &&
18*95aff23eSKrzysztof Drewniak          smin() == other.smin() && smax() == other.smax();
19*95aff23eSKrzysztof Drewniak }
20*95aff23eSKrzysztof Drewniak 
21*95aff23eSKrzysztof Drewniak const APInt &ConstantIntRanges::umin() const { return uminVal; }
22*95aff23eSKrzysztof Drewniak 
23*95aff23eSKrzysztof Drewniak const APInt &ConstantIntRanges::umax() const { return umaxVal; }
24*95aff23eSKrzysztof Drewniak 
25*95aff23eSKrzysztof Drewniak const APInt &ConstantIntRanges::smin() const { return sminVal; }
26*95aff23eSKrzysztof Drewniak 
27*95aff23eSKrzysztof Drewniak const APInt &ConstantIntRanges::smax() const { return smaxVal; }
28*95aff23eSKrzysztof Drewniak 
29*95aff23eSKrzysztof Drewniak unsigned ConstantIntRanges::getStorageBitwidth(Type type) {
30*95aff23eSKrzysztof Drewniak   if (type.isIndex())
31*95aff23eSKrzysztof Drewniak     return IndexType::kInternalStorageBitWidth;
32*95aff23eSKrzysztof Drewniak   if (auto integerType = type.dyn_cast<IntegerType>())
33*95aff23eSKrzysztof Drewniak     return integerType.getWidth();
34*95aff23eSKrzysztof Drewniak   // Non-integer types have their bounds stored in width 0 `APInt`s.
35*95aff23eSKrzysztof Drewniak   return 0;
36*95aff23eSKrzysztof Drewniak }
37*95aff23eSKrzysztof Drewniak 
38*95aff23eSKrzysztof Drewniak ConstantIntRanges ConstantIntRanges::range(const APInt &min, const APInt &max) {
39*95aff23eSKrzysztof Drewniak   return {min, max, min, max};
40*95aff23eSKrzysztof Drewniak }
41*95aff23eSKrzysztof Drewniak 
42*95aff23eSKrzysztof Drewniak ConstantIntRanges ConstantIntRanges::fromSigned(const APInt &smin,
43*95aff23eSKrzysztof Drewniak                                                 const APInt &smax) {
44*95aff23eSKrzysztof Drewniak   unsigned int width = smin.getBitWidth();
45*95aff23eSKrzysztof Drewniak   APInt umin, umax;
46*95aff23eSKrzysztof Drewniak   if (smin.isNonNegative() == smax.isNonNegative()) {
47*95aff23eSKrzysztof Drewniak     umin = smin.ult(smax) ? smin : smax;
48*95aff23eSKrzysztof Drewniak     umax = smin.ugt(smax) ? smin : smax;
49*95aff23eSKrzysztof Drewniak   } else {
50*95aff23eSKrzysztof Drewniak     umin = APInt::getMinValue(width);
51*95aff23eSKrzysztof Drewniak     umax = APInt::getMaxValue(width);
52*95aff23eSKrzysztof Drewniak   }
53*95aff23eSKrzysztof Drewniak   return {umin, umax, smin, smax};
54*95aff23eSKrzysztof Drewniak }
55*95aff23eSKrzysztof Drewniak 
56*95aff23eSKrzysztof Drewniak ConstantIntRanges ConstantIntRanges::fromUnsigned(const APInt &umin,
57*95aff23eSKrzysztof Drewniak                                                   const APInt &umax) {
58*95aff23eSKrzysztof Drewniak   unsigned int width = umin.getBitWidth();
59*95aff23eSKrzysztof Drewniak   APInt smin, smax;
60*95aff23eSKrzysztof Drewniak   if (umin.isNonNegative() == umax.isNonNegative()) {
61*95aff23eSKrzysztof Drewniak     smin = umin.slt(umax) ? umin : umax;
62*95aff23eSKrzysztof Drewniak     smax = umin.sgt(umax) ? umin : umax;
63*95aff23eSKrzysztof Drewniak   } else {
64*95aff23eSKrzysztof Drewniak     smin = APInt::getSignedMinValue(width);
65*95aff23eSKrzysztof Drewniak     smax = APInt::getSignedMaxValue(width);
66*95aff23eSKrzysztof Drewniak   }
67*95aff23eSKrzysztof Drewniak   return {umin, umax, smin, smax};
68*95aff23eSKrzysztof Drewniak }
69*95aff23eSKrzysztof Drewniak 
70*95aff23eSKrzysztof Drewniak ConstantIntRanges
71*95aff23eSKrzysztof Drewniak ConstantIntRanges::rangeUnion(const ConstantIntRanges &other) const {
72*95aff23eSKrzysztof Drewniak   // "Not an integer" poisons everything and also cannot be fed to comparison
73*95aff23eSKrzysztof Drewniak   // operators.
74*95aff23eSKrzysztof Drewniak   if (umin().getBitWidth() == 0)
75*95aff23eSKrzysztof Drewniak     return *this;
76*95aff23eSKrzysztof Drewniak   if (other.umin().getBitWidth() == 0)
77*95aff23eSKrzysztof Drewniak     return other;
78*95aff23eSKrzysztof Drewniak 
79*95aff23eSKrzysztof Drewniak   const APInt &uminUnion = umin().ult(other.umin()) ? umin() : other.umin();
80*95aff23eSKrzysztof Drewniak   const APInt &umaxUnion = umax().ugt(other.umax()) ? umax() : other.umax();
81*95aff23eSKrzysztof Drewniak   const APInt &sminUnion = smin().slt(other.smin()) ? smin() : other.smin();
82*95aff23eSKrzysztof Drewniak   const APInt &smaxUnion = smax().sgt(other.smax()) ? smax() : other.smax();
83*95aff23eSKrzysztof Drewniak 
84*95aff23eSKrzysztof Drewniak   return {uminUnion, umaxUnion, sminUnion, smaxUnion};
85*95aff23eSKrzysztof Drewniak }
86*95aff23eSKrzysztof Drewniak 
87*95aff23eSKrzysztof Drewniak Optional<APInt> ConstantIntRanges::getConstantValue() const {
88*95aff23eSKrzysztof Drewniak   // Note: we need to exclude the trivially-equal width 0 values here.
89*95aff23eSKrzysztof Drewniak   if (umin() == umax() && umin().getBitWidth() != 0)
90*95aff23eSKrzysztof Drewniak     return umin();
91*95aff23eSKrzysztof Drewniak   if (smin() == smax() && smin().getBitWidth() != 0)
92*95aff23eSKrzysztof Drewniak     return smin();
93*95aff23eSKrzysztof Drewniak   return None;
94*95aff23eSKrzysztof Drewniak }
95*95aff23eSKrzysztof Drewniak 
96*95aff23eSKrzysztof Drewniak raw_ostream &mlir::operator<<(raw_ostream &os, const ConstantIntRanges &range) {
97*95aff23eSKrzysztof Drewniak   return os << "unsigned : [" << range.umin() << ", " << range.umax()
98*95aff23eSKrzysztof Drewniak             << "] signed : [" << range.smin() << ", " << range.smax() << "]";
99*95aff23eSKrzysztof Drewniak }
100