Loading [MathJax]/extensions/tex2jax.js
CIRCT 21.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
InferIntRangeInterfaceImpls.cpp
Go to the documentation of this file.
1//===- InferIntRangeInterfaceImpls.cpp - Integer range impls for comb -----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Implementation of the interval range analysis interface.
10// The overflow flags are not set for the comb operations since they is
11// no meaningful concept of overflow detection in comb.
12//
13//===----------------------------------------------------------------------===//
14
16
17#include "mlir/Interfaces/InferIntRangeInterface.h"
18#include "mlir/Interfaces/Utils/InferIntRangeCommon.h"
19
20using namespace mlir;
21using namespace mlir::intrange;
22using namespace circt;
23using namespace circt::comb;
24
25//===----------------------------------------------------------------------===//
26// AddOp
27//===----------------------------------------------------------------------===//
28
29void comb::AddOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
30 SetIntRangeFn setResultRange) {
31 auto resultRange = argRanges[0];
32 for (auto argRange : argRanges.drop_front())
33 resultRange =
34 inferAdd({resultRange, argRange}, intrange::OverflowFlags::None);
35
36 setResultRange(getResult(), resultRange);
37}
38
39//===----------------------------------------------------------------------===//
40// SubOp
41//===----------------------------------------------------------------------===//
42
43void comb::SubOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
44 SetIntRangeFn setResultRange) {
45 setResultRange(getResult(),
46 inferSub(argRanges, intrange::OverflowFlags::None));
47}
48
49//===----------------------------------------------------------------------===//
50// MulOp
51//===----------------------------------------------------------------------===//
52
53void comb::MulOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
54 SetIntRangeFn setResultRange) {
55 auto resultRange = argRanges[0];
56 for (auto argRange : argRanges.drop_front())
57 resultRange =
58 inferMul({resultRange, argRange}, intrange::OverflowFlags::None);
59
60 setResultRange(getResult(), resultRange);
61}
62
63//===----------------------------------------------------------------------===//
64// DivUIOp
65//===----------------------------------------------------------------------===//
66
67void comb::DivUOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
68 SetIntRangeFn setResultRange) {
69 setResultRange(getResult(), inferDivU(argRanges));
70}
71
72//===----------------------------------------------------------------------===//
73// DivSIOp
74//===----------------------------------------------------------------------===//
75
76void comb::DivSOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
77 SetIntRangeFn setResultRange) {
78 setResultRange(getResult(), inferDivS(argRanges));
79}
80
81//===----------------------------------------------------------------------===//
82// ModUOp
83//===----------------------------------------------------------------------===//
84
85void comb::ModUOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
86 SetIntRangeFn setResultRange) {
87 setResultRange(getResult(), inferRemU(argRanges));
88}
89
90//===----------------------------------------------------------------------===//
91// ModSOp
92//===----------------------------------------------------------------------===//
93
94void comb::ModSOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
95 SetIntRangeFn setResultRange) {
96 setResultRange(getResult(), inferRemS(argRanges));
97}
98//===----------------------------------------------------------------------===//
99// AndOp
100//===----------------------------------------------------------------------===//
101
102void comb::AndOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
103 SetIntRangeFn setResultRange) {
104 auto resultRange = argRanges[0];
105 for (auto argRange : argRanges.drop_front())
106 resultRange = inferAnd({resultRange, argRange});
107
108 setResultRange(getResult(), resultRange);
109}
110
111//===----------------------------------------------------------------------===//
112// OrOp
113//===----------------------------------------------------------------------===//
114
115void comb::OrOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
116 SetIntRangeFn setResultRange) {
117 auto resultRange = argRanges[0];
118 for (auto argRange : argRanges.drop_front())
119 resultRange = inferOr({resultRange, argRange});
120
121 setResultRange(getResult(), resultRange);
122}
123
124//===----------------------------------------------------------------------===//
125// XorOp
126//===----------------------------------------------------------------------===//
127
128void comb::XorOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
129 SetIntRangeFn setResultRange) {
130 auto resultRange = argRanges[0];
131 for (auto argRange : argRanges.drop_front())
132 resultRange = inferXor({resultRange, argRange});
133
134 setResultRange(getResult(), resultRange);
135}
136
137//===----------------------------------------------------------------------===//
138// ShlOp
139//===----------------------------------------------------------------------===//
140
141void comb::ShlOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
142 SetIntRangeFn setResultRange) {
143 setResultRange(getResult(),
144 inferShl(argRanges, intrange::OverflowFlags::None));
145}
146
147//===----------------------------------------------------------------------===//
148// ShRUIOp
149//===----------------------------------------------------------------------===//
150
151void comb::ShrUOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
152 SetIntRangeFn setResultRange) {
153 setResultRange(getResult(), inferShrU(argRanges));
154}
155
156//===----------------------------------------------------------------------===//
157// ShRSIOp
158//===----------------------------------------------------------------------===//
159
160void comb::ShrSOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
161 SetIntRangeFn setResultRange) {
162 setResultRange(getResult(), inferShrS(argRanges));
163}
164
165//===----------------------------------------------------------------------===//
166// ConcatOp
167//===----------------------------------------------------------------------===//
168
169void comb::ConcatOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
170 SetIntRangeFn setResultRange) {
171 // Compute concat as an unsigned integer of bits
172 const auto resWidth = getResult().getType().getIntOrFloatBitWidth();
173 auto totalWidth = resWidth;
174 APInt umin = APInt::getZero(resWidth);
175 APInt umax = APInt::getZero(resWidth);
176 for (auto [operand, arg] : llvm::zip(getOperands(), argRanges)) {
177 assert(totalWidth >= operand.getType().getIntOrFloatBitWidth() &&
178 "ConcatOp: total width in interval range calculation is negative");
179 totalWidth -= operand.getType().getIntOrFloatBitWidth();
180 auto uminUpd = arg.umin().zext(resWidth).ushl_sat(totalWidth);
181 auto umaxUpd = arg.umax().zext(resWidth).ushl_sat(totalWidth);
182 umin = umin.uadd_sat(uminUpd);
183 umax = umax.uadd_sat(umaxUpd);
184 }
185 auto urange = ConstantIntRanges::fromUnsigned(umin, umax);
186 setResultRange(getResult(), urange);
187}
188
189//===----------------------------------------------------------------------===//
190// ExtractOp
191//===----------------------------------------------------------------------===//
192
193void comb::ExtractOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
194 SetIntRangeFn setResultRange) {
195 // Right-shift and truncate (trunaction implicitly handled)
196 const auto resWidth = getResult().getType().getIntOrFloatBitWidth();
197 const auto lowBit = getLowBit();
198 auto umin = argRanges[0].umin().lshr(lowBit).trunc(resWidth);
199 auto umax = argRanges[0].umax().lshr(lowBit).trunc(resWidth);
200 auto urange = ConstantIntRanges::fromUnsigned(umin, umax);
201 setResultRange(getResult(), urange);
202}
203
204//===----------------------------------------------------------------------===//
205// ReplicateOp
206//===----------------------------------------------------------------------===//
207
208void comb::ReplicateOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
209 SetIntRangeFn setResultRange) {
210 // Compute replicate as an unsigned integer of bits
211 const auto operandWidth = getOperand().getType().getIntOrFloatBitWidth();
212 const auto resWidth = getResult().getType().getIntOrFloatBitWidth();
213 APInt umin = APInt::getZero(resWidth);
214 APInt umax = APInt::getZero(resWidth);
215 auto uminIn = argRanges[0].umin().zext(resWidth);
216 auto umaxIn = argRanges[0].umax().zext(resWidth);
217 for (unsigned int totalWidth = 0; totalWidth < resWidth;
218 totalWidth += operandWidth) {
219 auto uminUpd = uminIn.ushl_sat(totalWidth);
220 auto umaxUpd = umaxIn.ushl_sat(totalWidth);
221 umin = umin.uadd_sat(uminUpd);
222 umax = umax.uadd_sat(umaxUpd);
223 }
224 auto urange = ConstantIntRanges::fromUnsigned(umin, umax);
225 setResultRange(getResult(), urange);
226}
227
228//===----------------------------------------------------------------------===//
229// MuxOp
230//===----------------------------------------------------------------------===//
231
232void comb::MuxOp::inferResultRangesFromOptional(
233 ArrayRef<IntegerValueRange> argRanges, SetIntLatticeFn setResultRange) {
234 std::optional<APInt> mbCondVal =
235 argRanges[0].isUninitialized()
236 ? std::nullopt
237 : argRanges[0].getValue().getConstantValue();
238
239 const IntegerValueRange &trueCase = argRanges[1];
240 const IntegerValueRange &falseCase = argRanges[2];
241
242 if (mbCondVal) {
243 if (mbCondVal->isZero())
244 setResultRange(getResult(), falseCase);
245 else
246 setResultRange(getResult(), trueCase);
247 return;
248 }
249 setResultRange(getResult(), IntegerValueRange::join(trueCase, falseCase));
250}
251
252//===----------------------------------------------------------------------===//
253// ICmpOp
254//===----------------------------------------------------------------------===//
255
256void comb::ICmpOp::inferResultRanges(ArrayRef<ConstantIntRanges> argRanges,
257 SetIntRangeFn setResultRange) {
258 comb::ICmpPredicate combPred = getPredicate();
259
260 APInt min = APInt::getZero(1);
261 APInt max = APInt::getAllOnes(1);
262
263 intrange::CmpPredicate pred;
264 switch (combPred) {
265 case comb::ICmpPredicate::eq:
266 pred = intrange::CmpPredicate::eq;
267 break;
268 case comb::ICmpPredicate::ne:
269 pred = intrange::CmpPredicate::ne;
270 break;
271 case comb::ICmpPredicate::slt:
272 pred = intrange::CmpPredicate::slt;
273 break;
274 case comb::ICmpPredicate::sle:
275 pred = intrange::CmpPredicate::sle;
276 break;
277 case comb::ICmpPredicate::sgt:
278 pred = intrange::CmpPredicate::sgt;
279 break;
280 case comb::ICmpPredicate::sge:
281 pred = intrange::CmpPredicate::sge;
282 break;
283 case comb::ICmpPredicate::ult:
284 pred = intrange::CmpPredicate::ult;
285 break;
286 case comb::ICmpPredicate::ule:
287 pred = intrange::CmpPredicate::ule;
288 break;
289 case comb::ICmpPredicate::ugt:
290 pred = intrange::CmpPredicate::ugt;
291 break;
292 case comb::ICmpPredicate::uge:
293 pred = intrange::CmpPredicate::uge;
294 break;
295 default:
296 // These predicates are not supported for integer range analysis
297 setResultRange(getResult(), ConstantIntRanges::fromUnsigned(min, max));
298 return;
299 }
300
301 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];
302
303 std::optional<bool> truthValue = intrange::evaluatePred(pred, lhs, rhs);
304 if (truthValue.has_value() && *truthValue)
305 min = max;
306 else if (truthValue.has_value() && !(*truthValue))
307 max = min;
308
309 setResultRange(getResult(), ConstantIntRanges::fromUnsigned(min, max));
310}
assert(baseType &&"element must be base type")
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.