195aff23eSKrzysztof Drewniak //===- InferIntRangeInterface.cpp - Integer range inference interface ---===//
295aff23eSKrzysztof Drewniak //
395aff23eSKrzysztof Drewniak // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
495aff23eSKrzysztof Drewniak // See https://llvm.org/LICENSE.txt for license information.
595aff23eSKrzysztof Drewniak // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
695aff23eSKrzysztof Drewniak //
795aff23eSKrzysztof Drewniak //===----------------------------------------------------------------------===//
895aff23eSKrzysztof Drewniak
995aff23eSKrzysztof Drewniak #include "mlir/Interfaces/InferIntRangeInterface.h"
1095aff23eSKrzysztof Drewniak #include "mlir/IR/BuiltinTypes.h"
1195aff23eSKrzysztof Drewniak #include "mlir/Interfaces/InferIntRangeInterface.cpp.inc"
1295aff23eSKrzysztof Drewniak
1395aff23eSKrzysztof Drewniak using namespace mlir;
1495aff23eSKrzysztof Drewniak
operator ==(const ConstantIntRanges & other) const1595aff23eSKrzysztof Drewniak bool ConstantIntRanges::operator==(const ConstantIntRanges &other) const {
1695aff23eSKrzysztof Drewniak return umin().getBitWidth() == other.umin().getBitWidth() &&
1795aff23eSKrzysztof Drewniak umin() == other.umin() && umax() == other.umax() &&
1895aff23eSKrzysztof Drewniak smin() == other.smin() && smax() == other.smax();
1995aff23eSKrzysztof Drewniak }
2095aff23eSKrzysztof Drewniak
umin() const2195aff23eSKrzysztof Drewniak const APInt &ConstantIntRanges::umin() const { return uminVal; }
2295aff23eSKrzysztof Drewniak
umax() const2395aff23eSKrzysztof Drewniak const APInt &ConstantIntRanges::umax() const { return umaxVal; }
2495aff23eSKrzysztof Drewniak
smin() const2595aff23eSKrzysztof Drewniak const APInt &ConstantIntRanges::smin() const { return sminVal; }
2695aff23eSKrzysztof Drewniak
smax() const2795aff23eSKrzysztof Drewniak const APInt &ConstantIntRanges::smax() const { return smaxVal; }
2895aff23eSKrzysztof Drewniak
getStorageBitwidth(Type type)2995aff23eSKrzysztof Drewniak unsigned ConstantIntRanges::getStorageBitwidth(Type type) {
3095aff23eSKrzysztof Drewniak if (type.isIndex())
3195aff23eSKrzysztof Drewniak return IndexType::kInternalStorageBitWidth;
3295aff23eSKrzysztof Drewniak if (auto integerType = type.dyn_cast<IntegerType>())
3395aff23eSKrzysztof Drewniak return integerType.getWidth();
3495aff23eSKrzysztof Drewniak // Non-integer types have their bounds stored in width 0 `APInt`s.
3595aff23eSKrzysztof Drewniak return 0;
3695aff23eSKrzysztof Drewniak }
3795aff23eSKrzysztof Drewniak
maxRange(unsigned bitwidth)38*75bfc6f2SKrzysztof Drewniak ConstantIntRanges ConstantIntRanges::maxRange(unsigned bitwidth) {
39*75bfc6f2SKrzysztof Drewniak return fromUnsigned(APInt::getZero(bitwidth), APInt::getMaxValue(bitwidth));
40*75bfc6f2SKrzysztof Drewniak }
41*75bfc6f2SKrzysztof Drewniak
constant(const APInt & value)42*75bfc6f2SKrzysztof Drewniak ConstantIntRanges ConstantIntRanges::constant(const APInt &value) {
43*75bfc6f2SKrzysztof Drewniak return {value, value, value, value};
44*75bfc6f2SKrzysztof Drewniak }
45*75bfc6f2SKrzysztof Drewniak
range(const APInt & min,const APInt & max,bool isSigned)46*75bfc6f2SKrzysztof Drewniak ConstantIntRanges ConstantIntRanges::range(const APInt &min, const APInt &max,
47*75bfc6f2SKrzysztof Drewniak bool isSigned) {
48*75bfc6f2SKrzysztof Drewniak if (isSigned)
49*75bfc6f2SKrzysztof Drewniak return fromSigned(min, max);
50*75bfc6f2SKrzysztof Drewniak return fromUnsigned(min, max);
5195aff23eSKrzysztof Drewniak }
5295aff23eSKrzysztof Drewniak
fromSigned(const APInt & smin,const APInt & smax)5395aff23eSKrzysztof Drewniak ConstantIntRanges ConstantIntRanges::fromSigned(const APInt &smin,
5495aff23eSKrzysztof Drewniak const APInt &smax) {
5595aff23eSKrzysztof Drewniak unsigned int width = smin.getBitWidth();
5695aff23eSKrzysztof Drewniak APInt umin, umax;
5795aff23eSKrzysztof Drewniak if (smin.isNonNegative() == smax.isNonNegative()) {
5895aff23eSKrzysztof Drewniak umin = smin.ult(smax) ? smin : smax;
5995aff23eSKrzysztof Drewniak umax = smin.ugt(smax) ? smin : smax;
6095aff23eSKrzysztof Drewniak } else {
6195aff23eSKrzysztof Drewniak umin = APInt::getMinValue(width);
6295aff23eSKrzysztof Drewniak umax = APInt::getMaxValue(width);
6395aff23eSKrzysztof Drewniak }
6495aff23eSKrzysztof Drewniak return {umin, umax, smin, smax};
6595aff23eSKrzysztof Drewniak }
6695aff23eSKrzysztof Drewniak
fromUnsigned(const APInt & umin,const APInt & umax)6795aff23eSKrzysztof Drewniak ConstantIntRanges ConstantIntRanges::fromUnsigned(const APInt &umin,
6895aff23eSKrzysztof Drewniak const APInt &umax) {
6995aff23eSKrzysztof Drewniak unsigned int width = umin.getBitWidth();
7095aff23eSKrzysztof Drewniak APInt smin, smax;
7195aff23eSKrzysztof Drewniak if (umin.isNonNegative() == umax.isNonNegative()) {
7295aff23eSKrzysztof Drewniak smin = umin.slt(umax) ? umin : umax;
7395aff23eSKrzysztof Drewniak smax = umin.sgt(umax) ? umin : umax;
7495aff23eSKrzysztof Drewniak } else {
7595aff23eSKrzysztof Drewniak smin = APInt::getSignedMinValue(width);
7695aff23eSKrzysztof Drewniak smax = APInt::getSignedMaxValue(width);
7795aff23eSKrzysztof Drewniak }
7895aff23eSKrzysztof Drewniak return {umin, umax, smin, smax};
7995aff23eSKrzysztof Drewniak }
8095aff23eSKrzysztof Drewniak
8195aff23eSKrzysztof Drewniak ConstantIntRanges
rangeUnion(const ConstantIntRanges & other) const8295aff23eSKrzysztof Drewniak ConstantIntRanges::rangeUnion(const ConstantIntRanges &other) const {
8395aff23eSKrzysztof Drewniak // "Not an integer" poisons everything and also cannot be fed to comparison
8495aff23eSKrzysztof Drewniak // operators.
8595aff23eSKrzysztof Drewniak if (umin().getBitWidth() == 0)
8695aff23eSKrzysztof Drewniak return *this;
8795aff23eSKrzysztof Drewniak if (other.umin().getBitWidth() == 0)
8895aff23eSKrzysztof Drewniak return other;
8995aff23eSKrzysztof Drewniak
9095aff23eSKrzysztof Drewniak const APInt &uminUnion = umin().ult(other.umin()) ? umin() : other.umin();
9195aff23eSKrzysztof Drewniak const APInt &umaxUnion = umax().ugt(other.umax()) ? umax() : other.umax();
9295aff23eSKrzysztof Drewniak const APInt &sminUnion = smin().slt(other.smin()) ? smin() : other.smin();
9395aff23eSKrzysztof Drewniak const APInt &smaxUnion = smax().sgt(other.smax()) ? smax() : other.smax();
9495aff23eSKrzysztof Drewniak
9595aff23eSKrzysztof Drewniak return {uminUnion, umaxUnion, sminUnion, smaxUnion};
9695aff23eSKrzysztof Drewniak }
9795aff23eSKrzysztof Drewniak
98*75bfc6f2SKrzysztof Drewniak ConstantIntRanges
intersection(const ConstantIntRanges & other) const99*75bfc6f2SKrzysztof Drewniak ConstantIntRanges::intersection(const ConstantIntRanges &other) const {
100*75bfc6f2SKrzysztof Drewniak // "Not an integer" poisons everything and also cannot be fed to comparison
101*75bfc6f2SKrzysztof Drewniak // operators.
102*75bfc6f2SKrzysztof Drewniak if (umin().getBitWidth() == 0)
103*75bfc6f2SKrzysztof Drewniak return *this;
104*75bfc6f2SKrzysztof Drewniak if (other.umin().getBitWidth() == 0)
105*75bfc6f2SKrzysztof Drewniak return other;
106*75bfc6f2SKrzysztof Drewniak
107*75bfc6f2SKrzysztof Drewniak const APInt &uminIntersect = umin().ugt(other.umin()) ? umin() : other.umin();
108*75bfc6f2SKrzysztof Drewniak const APInt &umaxIntersect = umax().ult(other.umax()) ? umax() : other.umax();
109*75bfc6f2SKrzysztof Drewniak const APInt &sminIntersect = smin().sgt(other.smin()) ? smin() : other.smin();
110*75bfc6f2SKrzysztof Drewniak const APInt &smaxIntersect = smax().slt(other.smax()) ? smax() : other.smax();
111*75bfc6f2SKrzysztof Drewniak
112*75bfc6f2SKrzysztof Drewniak return {uminIntersect, umaxIntersect, sminIntersect, smaxIntersect};
113*75bfc6f2SKrzysztof Drewniak }
114*75bfc6f2SKrzysztof Drewniak
getConstantValue() const11595aff23eSKrzysztof Drewniak Optional<APInt> ConstantIntRanges::getConstantValue() const {
11695aff23eSKrzysztof Drewniak // Note: we need to exclude the trivially-equal width 0 values here.
11795aff23eSKrzysztof Drewniak if (umin() == umax() && umin().getBitWidth() != 0)
11895aff23eSKrzysztof Drewniak return umin();
11995aff23eSKrzysztof Drewniak if (smin() == smax() && smin().getBitWidth() != 0)
12095aff23eSKrzysztof Drewniak return smin();
12195aff23eSKrzysztof Drewniak return None;
12295aff23eSKrzysztof Drewniak }
12395aff23eSKrzysztof Drewniak
operator <<(raw_ostream & os,const ConstantIntRanges & range)12495aff23eSKrzysztof Drewniak raw_ostream &mlir::operator<<(raw_ostream &os, const ConstantIntRanges &range) {
12595aff23eSKrzysztof Drewniak return os << "unsigned : [" << range.umin() << ", " << range.umax()
12695aff23eSKrzysztof Drewniak << "] signed : [" << range.smin() << ", " << range.smax() << "]";
12795aff23eSKrzysztof Drewniak }
128