MLIR: lib/Interfaces/Utils/InferIntRangeCommon.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

15

18

19 #include "llvm/ADT/ArrayRef.h"

20 #include "llvm/ADT/STLExtras.h"

21

22 #include "llvm/Support/Debug.h"

23

24 #include

25 #include

26

27 using namespace mlir;

28

29 #define DEBUG_TYPE "int-range-analysis"

30

31

32

33

34

35

36

40 std::function<std::optional(const APInt &, const APInt &)>;

41

42

43

45 const APInt &minRight,

46 const APInt &maxLeft,

47 const APInt &maxRight, bool isSigned) {

48 std::optional maybeMin = op(minLeft, minRight);

49 std::optional maybeMax = op(maxLeft, maxRight);

50 if (maybeMin && maybeMax)

53 }

54

55

56

59 unsigned width = lhs[0].getBitWidth();

60 APInt min =

61 isSigned ? APInt::getSignedMaxValue(width) : APInt::getMaxValue(width);

62 APInt max =

63 isSigned ? APInt::getSignedMinValue(width) : APInt::getZero(width);

64 for (const APInt &left : lhs) {

65 for (const APInt &right : rhs) {

66 std::optional maybeThisResult = op(left, right);

67 if (!maybeThisResult)

69 APInt result = std::move(*maybeThisResult);

70 min = (isSigned ? result.slt(min) : result.ult(min)) ? result : min;

71 max = (isSigned ? result.sgt(max) : result.ugt(max)) ? result : max;

72 }

73 }

75 }

76

77

78

79

80

87 llvm::transform(argRanges, std::back_inserter(truncated),

90 });

96

97 LLVM_DEBUG(llvm::dbgs() << "Index handling: 64-bit result = " << sixtyFour

98 << " 32-bit = " << thirtyTwo << "\n");

99 bool truncEqual = false;

100 switch (mode) {

102 truncEqual = (thirtyTwo == sixtyFourAsThirtyTwo);

103 break;

105 truncEqual = (thirtyTwo.smin() == sixtyFourAsThirtyTwo.smin() &&

106 thirtyTwo.smax() == sixtyFourAsThirtyTwo.smax());

107 break;

109 truncEqual = (thirtyTwo.umin() == sixtyFourAsThirtyTwo.umin() &&

110 thirtyTwo.umax() == sixtyFourAsThirtyTwo.umax());

111 break;

112 }

113 if (truncEqual)

114

115 return sixtyFour;

117 return merged;

118 }

119

121 unsigned int destWidth) {

122 APInt umin = range.umin().zext(destWidth);

123 APInt umax = range.umax().zext(destWidth);

124 APInt smin = range.smin().sext(destWidth);

125 APInt smax = range.smax().sext(destWidth);

126 return {umin, umax, smin, smax};

127 }

128

130 unsigned destWidth) {

131 APInt umin = range.umin().zext(destWidth);

132 APInt umax = range.umax().zext(destWidth);

134 }

135

137 unsigned destWidth) {

138 APInt smin = range.smin().sext(destWidth);

139 APInt smax = range.smax().sext(destWidth);

141 }

142

144 unsigned int destWidth) {

145

146

147

148

149 bool hasUnsignedRollover =

150 range.umin().lshr(destWidth) != range.umax().lshr(destWidth);

151 APInt umin = hasUnsignedRollover ? APInt::getZero(destWidth)

152 : range.umin().trunc(destWidth);

153 APInt umax = hasUnsignedRollover ? APInt::getMaxValue(destWidth)

154 : range.umax().trunc(destWidth);

155

156

157

158

159

160

161

162

163

164

165 APInt sminHighPart = range.smin().ashr(destWidth - 1);

166 APInt smaxHighPart = range.smax().ashr(destWidth - 1);

167 bool hasSignedOverflow =

168 (sminHighPart != smaxHighPart) &&

169 !(sminHighPart.isAllOnes() &&

170 (smaxHighPart.isAllOnes() || smaxHighPart.isZero())) &&

171 !(sminHighPart.isZero() && smaxHighPart.isZero());

172 APInt smin = hasSignedOverflow ? APInt::getSignedMinValue(destWidth)

173 : range.smin().trunc(destWidth);

174 APInt smax = hasSignedOverflow ? APInt::getSignedMaxValue(destWidth)

175 : range.smax().trunc(destWidth);

176 return {umin, umax, smin, smax};

177 }

178

179

180

181

182

186 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

187

189 const APInt &b) -> std::optional {

190 bool overflowed = false;

191 APInt result = any(ovfFlags & OverflowFlags::Nuw)

192 ? a.uadd_sat(b)

193 : a.uadd_ov(b, overflowed);

194 return overflowed ? std::optional() : result;

195 };

197 const APInt &b) -> std::optional {

198 bool overflowed = false;

199 APInt result = any(ovfFlags & OverflowFlags::Nsw)

200 ? a.sadd_sat(b)

201 : a.sadd_ov(b, overflowed);

202 return overflowed ? std::optional() : result;

203 };

204

206 uadd, lhs.umin(), rhs.umin(), lhs.umax(), rhs.umax(), false);

208 sadd, lhs.smin(), rhs.smin(), lhs.smax(), rhs.smax(), true);

210 }

211

212

213

214

215

219 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

220

222 const APInt &b) -> std::optional {

223 bool overflowed = false;

224 APInt result = any(ovfFlags & OverflowFlags::Nuw)

225 ? a.usub_sat(b)

226 : a.usub_ov(b, overflowed);

227 return overflowed ? std::optional() : result;

228 };

230 const APInt &b) -> std::optional {

231 bool overflowed = false;

232 APInt result = any(ovfFlags & OverflowFlags::Nsw)

233 ? a.ssub_sat(b)

234 : a.ssub_ov(b, overflowed);

235 return overflowed ? std::optional() : result;

236 };

238 usub, lhs.umin(), rhs.umax(), lhs.umax(), rhs.umin(), false);

240 ssub, lhs.smin(), rhs.smax(), lhs.smax(), rhs.smin(), true);

242 }

243

244

245

246

247

251 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

252

254 const APInt &b) -> std::optional {

255 bool overflowed = false;

256 APInt result = any(ovfFlags & OverflowFlags::Nuw)

257 ? a.umul_sat(b)

258 : a.umul_ov(b, overflowed);

259 return overflowed ? std::optional() : result;

260 };

262 const APInt &b) -> std::optional {

263 bool overflowed = false;

264 APInt result = any(ovfFlags & OverflowFlags::Nsw)

265 ? a.smul_sat(b)

266 : a.smul_ov(b, overflowed);

267 return overflowed ? std::optional() : result;

268 };

269

271 minMaxBy(umul, {lhs.umin(), lhs.umax()}, {rhs.umin(), rhs.umax()},

272 false);

274 minMaxBy(smul, {lhs.smin(), lhs.smax()}, {rhs.smin(), rhs.smax()},

275 true);

277 }

278

279

280

281

282

283

284

286 const APInt &lhs, const APInt &rhs, const APInt &result)>;

287

291 const APInt &lhsMin = lhs.umin(), &lhsMax = lhs.umax(), &rhsMin = rhs.umin(),

292 &rhsMax = rhs.umax();

293

294 if (!rhsMin.isZero()) {

295 auto udiv = [&fixup](const APInt &a,

296 const APInt &b) -> std::optional {

297 return fixup(a, b, a.udiv(b));

298 };

299 return minMaxBy(udiv, {lhsMin, lhsMax}, {rhsMin, rhsMax},

300 false);

301 }

302

304 if (lhsMin.uge(rhsMax) && !rhsMax.isZero())

305 umin = lhsMin.udiv(rhsMax);

306

307

308 APInt umax = lhsMax;

310 }

311

315 [](const APInt &lhs, const APInt &rhs,

316 const APInt &result) { return result; });

317 }

318

321 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

322

323 auto ceilDivUIFix = [](const APInt &lhs, const APInt &rhs,

324 const APInt &result) -> std::optional {

325 if (!lhs.urem(rhs).isZero()) {

326 bool overflowed = false;

327 APInt corrected =

328 result.uadd_ov(APInt(result.getBitWidth(), 1), overflowed);

329 return overflowed ? std::optional() : corrected;

330 }

331 return result;

332 };

334 }

335

336

337

338

339

343 const APInt &lhsMin = lhs.smin(), &lhsMax = lhs.smax(), &rhsMin = rhs.smin(),

344 &rhsMax = rhs.smax();

345 bool canDivide = rhsMin.isStrictlyPositive() || rhsMax.isNegative();

346

347 if (canDivide) {

348 auto sdiv = [&fixup](const APInt &a,

349 const APInt &b) -> std::optional {

350 bool overflowed = false;

351 APInt result = a.sdiv_ov(b, overflowed);

352 return overflowed ? std::optional() : fixup(a, b, result);

353 };

354 return minMaxBy(sdiv, {lhsMin, lhsMax}, {rhsMin, rhsMax},

355 true);

356 }

358 }

359

363 [](const APInt &lhs, const APInt &rhs,

364 const APInt &result) { return result; });

365 }

366

369 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

370

371 auto ceilDivSIFix = [](const APInt &lhs, const APInt &rhs,

372 const APInt &result) -> std::optional {

373 if (!lhs.srem(rhs).isZero() && lhs.isNonNegative() == rhs.isNonNegative()) {

374 bool overflowed = false;

375 APInt corrected =

376 result.sadd_ov(APInt(result.getBitWidth(), 1), overflowed);

377 return overflowed ? std::optional() : corrected;

378 }

379

380

381

382

383

384

385 if (lhs.isMinSignedValue() && rhs.sgt(1)) {

386 return -result;

387 }

388 return result;

389 };

391 if (lhs.smin().isMinSignedValue() && lhs.smax().sgt(lhs.smin())) {

392

393

394

397 }

398 return result;

399 }

400

403 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

404

405 auto floorDivSIFix = [](const APInt &lhs, const APInt &rhs,

406 const APInt &result) -> std::optional {

407 if (!lhs.srem(rhs).isZero() && lhs.isNonNegative() != rhs.isNonNegative()) {

408 bool overflowed = false;

409 APInt corrected =

410 result.ssub_ov(APInt(result.getBitWidth(), 1), overflowed);

411 return overflowed ? std::optional() : corrected;

412 }

413 return result;

414 };

416 }

417

418

419

420

421

424 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

425 const APInt &lhsMin = lhs.smin(), &lhsMax = lhs.smax(), &rhsMin = rhs.smin(),

426 &rhsMax = rhs.smax();

427

428 unsigned width = rhsMax.getBitWidth();

429 APInt smin = APInt::getSignedMinValue(width);

430 APInt smax = APInt::getSignedMaxValue(width);

431

432 bool canBound = (rhsMin.isStrictlyPositive() || rhsMax.isNegative());

433 if (canBound) {

434 APInt maxDivisor = rhsMin.isStrictlyPositive() ? rhsMax : rhsMin.abs();

435 bool canNegativeDividend = lhsMin.isNegative();

436 bool canPositiveDividend = lhsMax.isStrictlyPositive();

437 APInt zero = APInt::getZero(maxDivisor.getBitWidth());

438 APInt maxPositiveResult = maxDivisor - 1;

439 APInt minNegativeResult = -maxPositiveResult;

440 smin = canNegativeDividend ? minNegativeResult : zero;

441 smax = canPositiveDividend ? maxPositiveResult : zero;

442

443 if (rhsMin == rhsMax) {

444 if ((lhsMax - lhsMin).ult(maxDivisor)) {

445 APInt minRem = lhsMin.srem(maxDivisor);

446 APInt maxRem = lhsMax.srem(maxDivisor);

447 if (minRem.sle(maxRem)) {

448 smin = minRem;

449 smax = maxRem;

450 }

451 }

452 }

453 }

455 }

456

457

458

459

460

463 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

464 const APInt &rhsMin = rhs.umin(), &rhsMax = rhs.umax();

465

466 unsigned width = rhsMin.getBitWidth();

468

469 APInt umax = llvm::APIntOps::umin((rhsMax - 1), lhs.umax());

470

471 if (!rhsMin.isZero()) {

472

473 if (rhsMin == rhsMax) {

474 const APInt &lhsMin = lhs.umin(), &lhsMax = lhs.umax();

475 if ((lhsMax - lhsMin).ult(rhsMax)) {

476 APInt minRem = lhsMin.urem(rhsMax);

477 APInt maxRem = lhsMax.urem(rhsMax);

478 if (minRem.ule(maxRem)) {

479 umin = minRem;

480 umax = maxRem;

481 }

482 }

483 }

484 }

486 }

487

488

489

490

491

494 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

495

496 const APInt &smin = lhs.smin().sgt(rhs.smin()) ? lhs.smin() : rhs.smin();

497 const APInt &smax = lhs.smax().sgt(rhs.smax()) ? lhs.smax() : rhs.smax();

499 }

500

503 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

504

505 const APInt &umin = lhs.umin().ugt(rhs.umin()) ? lhs.umin() : rhs.umin();

506 const APInt &umax = lhs.umax().ugt(rhs.umax()) ? lhs.umax() : rhs.umax();

508 }

509

512 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

513

514 const APInt &smin = lhs.smin().slt(rhs.smin()) ? lhs.smin() : rhs.smin();

515 const APInt &smax = lhs.smax().slt(rhs.smax()) ? lhs.smax() : rhs.smax();

517 }

518

521 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

522

523 const APInt &umin = lhs.umin().ult(rhs.umin()) ? lhs.umin() : rhs.umin();

524 const APInt &umax = lhs.umax().ult(rhs.umax()) ? lhs.umax() : rhs.umax();

526 }

527

528

529

530

531

532

533

534

535

536 static std::tuple<APInt, APInt>

538 APInt leftVal = bound.umin(), rightVal = bound.umax();

539 unsigned bitwidth = leftVal.getBitWidth();

540 unsigned differingBits = bitwidth - (leftVal ^ rightVal).countl_zero();

541 leftVal.clearLowBits(differingBits);

542 rightVal.setLowBits(differingBits);

543 return std::make_tuple(std::move(leftVal), std::move(rightVal));

544 }

545

550 auto andi = [](const APInt &a, const APInt &b) -> std::optional {

551 return a & b;

552 };

553 return minMaxBy(andi, {lhsZeros, lhsOnes}, {rhsZeros, rhsOnes},

554 false);

555 }

556

561 auto ori = [](const APInt &a, const APInt &b) -> std::optional {

562 return a | b;

563 };

564 return minMaxBy(ori, {lhsZeros, lhsOnes}, {rhsZeros, rhsOnes},

565 false);

566 }

567

568

569

571 APInt leftVal = bound.umin(), rightVal = bound.umax();

572 unsigned bitwidth = leftVal.getBitWidth();

573 unsigned differingBits = bitwidth - (leftVal ^ rightVal).countl_zero();

574 return APInt::getLowBitsSet(bitwidth, differingBits);

575 }

576

579

580

583 APInt res = lhs.umin() ^ rhs.umin();

584 APInt min = res & ~mask;

585 APInt max = res | mask;

587 }

588

589

590

591

592

596 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

597 const APInt &rhsUMin = rhs.umin(), &rhsUMax = rhs.umax();

598

599

600

602 const APInt &r) -> std::optional {

603 bool overflowed = false;

604 APInt result = any(ovfFlags & OverflowFlags::Nuw)

605 ? l.ushl_sat(r)

606 : l.ushl_ov(r, overflowed);

607 return overflowed ? std::optional() : result;

608 };

610 const APInt &r) -> std::optional {

611 bool overflowed = false;

612 APInt result = any(ovfFlags & OverflowFlags::Nsw)

613 ? l.sshl_sat(r)

614 : l.sshl_ov(r, overflowed);

615 return overflowed ? std::optional() : result;

616 };

617

620 false);

623 true);

625 }

626

629 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

630

631 auto ashr = [](const APInt &l, const APInt &r) -> std::optional {

632 return r.uge(r.getBitWidth()) ? std::optional() : l.ashr(r);

633 };

634

635 return minMaxBy(ashr, {lhs.smin(), lhs.smax()}, {rhs.umin(), rhs.umax()},

636 true);

637 }

638

641 const ConstantIntRanges &lhs = argRanges[0], &rhs = argRanges[1];

642

643 auto lshr = [](const APInt &l, const APInt &r) -> std::optional {

644 return r.uge(r.getBitWidth()) ? std::optional() : l.lshr(r);

645 };

646 return minMaxBy(lshr, {lhs.umin(), lhs.umax()}, {rhs.umin(), rhs.umax()},

647 false);

648 }

649

650

651

652

653

655 switch (pred) {

676 }

677 llvm_unreachable("unknown cmp predicate value");

678 }

679

683 switch (pred) {

685 return lhs.smax().sle(rhs.smin());

687 return lhs.smax().slt(rhs.smin());

689 return lhs.umax().ule(rhs.umin());

691 return lhs.umax().ult(rhs.umin());

693 return lhs.smin().sge(rhs.smax());

695 return lhs.smin().sgt(rhs.smax());

697 return lhs.umin().uge(rhs.umax());

699 return lhs.umin().ugt(rhs.umax());

703 return lhsConst && rhsConst && lhsConst == rhsConst;

704 }

706

707

708

709

714 return sne && une;

715 }

716 }

717 return false;

718 }

719

724 return true;

726 return false;

727 return std::nullopt;

728 }

729

730

731

732

733

737 unsigned width =

740 APInt typeMax = APInt::getSignedMaxValue(width);

741

742 auto shapedTy = cast(op.getShapedValue().getType());

743 if (!shapedTy.hasRank())

745

746 int64_t rank = shapedTy.getRank();

747 int64_t minDim = 0;

748 int64_t maxDim = rank - 1;

751 minDim = std::max(minDim, dim.smin().getSExtValue());

752 maxDim = std::min(maxDim, dim.smax().getSExtValue());

753 }

754

755 std::optional result;

757 if (!result.has_value())

758 result = thisResult;

759 else

760 result = result->rangeUnion(thisResult);

761 };

762 for (int64_t i = minDim; i <= maxDim; ++i) {

763 int64_t length = shapedTy.getDimSize(i);

764

765 if (ShapedType::isDynamic(length))

767 else

769 }

771 }

static Value getZero(OpBuilder &b, Location loc, Type elementType)

Get zero value for an element type.

static ConstantIntRanges inferDivSRange(const ConstantIntRanges &lhs, const ConstantIntRanges &rhs, DivisionFixupFn fixup)

static bool isStaticallyTrue(intrange::CmpPredicate pred, const ConstantIntRanges &lhs, const ConstantIntRanges &rhs)

static intrange::CmpPredicate invertPredicate(intrange::CmpPredicate pred)

static ConstantIntRanges minMaxBy(ConstArithFn op, ArrayRef< APInt > lhs, ArrayRef< APInt > rhs, bool isSigned)

Compute the minimum and maximum of (op(l, r) for l in lhs for r in rhs), ignoring unbounded values.

static std::tuple< APInt, APInt > widenBitwiseBounds(const ConstantIntRanges &bound)

"Widen" bounds - if 0bvvvvv??? <= a <= 0bvvvvv???, relax the bounds to 0bvvvvv000 <= a <= 0bvvvvv111,...

static ConstantIntRanges inferDivURange(const ConstantIntRanges &lhs, const ConstantIntRanges &rhs, DivisionFixupFn fixup)

std::function< std::optional< APInt >(const APInt &, const APInt &)> ConstArithStdFn

static ConstantIntRanges computeBoundsBy(ConstArithFn op, const APInt &minLeft, const APInt &minRight, const APInt &maxLeft, const APInt &maxRight, bool isSigned)

Compute op(minLeft, minRight) and op(maxLeft, maxRight) if possible, If either computation overflows,...

static APInt getVaryingBitsMask(const ConstantIntRanges &bound)

Get bitmask of all bits which can change while iterating in [bound.umin(), bound.umax()].

static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)

static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)

A set of arbitrary-precision integers representing bounds on a given integer value.

static ConstantIntRanges maxRange(unsigned bitwidth)

Create a ConstantIntRanges with the maximum bounds for the width bitwidth, that is - [0,...

const APInt & smax() const

The maximum value of an integer when it is interpreted as signed.

static ConstantIntRanges constant(const APInt &value)

Create a ConstantIntRanges with a constant value - that is, with the bounds [value,...

static ConstantIntRanges fromUnsigned(const APInt &umin, const APInt &umax)

Create an ConstantIntRanges with the unsigned minimum and maximum equal to umin and umax and the sign...

const APInt & smin() const

The minimum value of an integer when it is interpreted as signed.

static ConstantIntRanges range(const APInt &min, const APInt &max, bool isSigned)

Create a ConstantIntRanges whose minimum is min and maximum is max with isSigned specifying if the mi...

ConstantIntRanges intersection(const ConstantIntRanges &other) const

Returns the intersection (computed separately for signed and unsigned bounds) of this range and other...

static ConstantIntRanges fromSigned(const APInt &smin, const APInt &smax)

Create an ConstantIntRanges with the signed minimum and maximum equal to smin and smax,...

static unsigned getStorageBitwidth(Type type)

Return the bitwidth that should be used for integer ranges describing type.

std::optional< APInt > getConstantValue() const

If either the signed or unsigned interpretations of the range indicate that the value it bounds is a ...

const APInt & umax() const

The maximum value of an integer when it is interpreted as unsigned.

const APInt & umin() const

The minimum value of an integer when it is interpreted as unsigned.

ConstantIntRanges rangeUnion(const ConstantIntRanges &other) const

Returns the union (computed separately for signed and unsigned bounds) of this range and other.

This lattice value represents the integer range of an SSA value.

const ConstantIntRanges & getValue() const

Get the known integer value range.

bool isUninitialized() const

Whether the range is uninitialized.

ConstantIntRanges inferAnd(ArrayRef< ConstantIntRanges > argRanges)

ConstantIntRanges inferShl(ArrayRef< ConstantIntRanges > argRanges, OverflowFlags ovfFlags=OverflowFlags::None)

ConstantIntRanges inferIndexOp(const InferRangeFn &inferFn, ArrayRef< ConstantIntRanges > argRanges, CmpMode mode)

Compute inferFn on ranges, whose size should be the index storage bitwidth.

ConstantIntRanges inferShrS(ArrayRef< ConstantIntRanges > argRanges)

ConstantIntRanges extSIRange(const ConstantIntRanges &range, unsigned destWidth)

Use the signed values in range to sign-extend it to destWidth.

std::optional< bool > evaluatePred(CmpPredicate pred, const ConstantIntRanges &lhs, const ConstantIntRanges &rhs)

Returns a boolean value if pred is statically true or false for anypossible inputs falling within lhs...

ConstantIntRanges inferMinS(ArrayRef< ConstantIntRanges > argRanges)

ConstantIntRanges inferMaxU(ArrayRef< ConstantIntRanges > argRanges)

ConstantIntRanges inferRemS(ArrayRef< ConstantIntRanges > argRanges)

CmpPredicate

Copy of the enum from arith and index to allow the common integer range infrastructure to not depend ...

ConstantIntRanges inferOr(ArrayRef< ConstantIntRanges > argRanges)

ConstantIntRanges extRange(const ConstantIntRanges &range, unsigned destWidth)

Independently zero-extend the unsigned values and sign-extend the signed values in range to destWidth...

ConstantIntRanges inferSub(ArrayRef< ConstantIntRanges > argRanges, OverflowFlags ovfFlags=OverflowFlags::None)

ConstantIntRanges inferAdd(ArrayRef< ConstantIntRanges > argRanges, OverflowFlags ovfFlags=OverflowFlags::None)

ConstantIntRanges truncRange(const ConstantIntRanges &range, unsigned destWidth)

Truncate range to destWidth bits, taking care to handle cases such as the truncation of [255,...

ConstantIntRanges inferDivU(ArrayRef< ConstantIntRanges > argRanges)

ConstantIntRanges inferCeilDivS(ArrayRef< ConstantIntRanges > argRanges)

ConstantIntRanges inferMinU(ArrayRef< ConstantIntRanges > argRanges)

std::function< ConstantIntRanges(ArrayRef< ConstantIntRanges >)> InferRangeFn

Function that performs inference on an array of ConstantIntRanges, abstracted away here to permit wri...

ConstantIntRanges inferMul(ArrayRef< ConstantIntRanges > argRanges, OverflowFlags ovfFlags=OverflowFlags::None)

ConstantIntRanges inferXor(ArrayRef< ConstantIntRanges > argRanges)

ConstantIntRanges inferDivS(ArrayRef< ConstantIntRanges > argRanges)

ConstantIntRanges inferShrU(ArrayRef< ConstantIntRanges > argRanges)

ConstantIntRanges inferRemU(ArrayRef< ConstantIntRanges > argRanges)

static constexpr unsigned indexMinWidth

ConstantIntRanges inferFloorDivS(ArrayRef< ConstantIntRanges > argRanges)

static constexpr unsigned indexMaxWidth

ConstantIntRanges inferCeilDivU(ArrayRef< ConstantIntRanges > argRanges)

ConstantIntRanges extUIRange(const ConstantIntRanges &range, unsigned destWidth)

Use the unsigned values in range to zero-extend it to destWidth.

ConstantIntRanges inferShapedDimOpInterface(ShapedDimOpInterface op, const IntegerValueRange &maybeDim)

Returns the integer range for the result of a ShapedDimOpInterface given the optional inferred ranges...

ConstantIntRanges inferMaxS(ArrayRef< ConstantIntRanges > argRanges)

Include the generated interface declarations.