//===- InferIntRangeCommon.cpp - Inference for common ops ------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains implementations of range inference for operations that are // common to both the `arith` and `index` dialects to facilitate reuse. // //===----------------------------------------------------------------------===// #include "mlir/Interfaces/Utils/InferIntRangeCommon.h" #include "mlir/Interfaces/InferIntRangeInterface.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include <iterator> #include <optional> usingnamespacemlir; #define DEBUG_TYPE … //===----------------------------------------------------------------------===// // General utilities //===----------------------------------------------------------------------===// /// Function that evaluates the result of doing something on arithmetic /// constants and returns std::nullopt on overflow. ConstArithFn; ConstArithStdFn; /// Compute op(minLeft, minRight) and op(maxLeft, maxRight) if possible, /// If either computation overflows, make the result unbounded. static ConstantIntRanges computeBoundsBy(ConstArithFn op, const APInt &minLeft, const APInt &minRight, const APInt &maxLeft, const APInt &maxRight, bool isSigned) { … } /// Compute the minimum and maximum of `(op(l, r) for l in lhs for r in rhs)`, /// ignoring unbounded values. Returns the maximal range if `op` overflows. static ConstantIntRanges minMaxBy(ConstArithFn op, ArrayRef<APInt> lhs, ArrayRef<APInt> rhs, bool isSigned) { … } //===----------------------------------------------------------------------===// // Ext, trunc, index op handling //===----------------------------------------------------------------------===// ConstantIntRanges mlir::intrange::inferIndexOp(const InferRangeFn &inferFn, ArrayRef<ConstantIntRanges> argRanges, intrange::CmpMode mode) { … } ConstantIntRanges mlir::intrange::extRange(const ConstantIntRanges &range, unsigned int destWidth) { … } ConstantIntRanges mlir::intrange::extUIRange(const ConstantIntRanges &range, unsigned destWidth) { … } ConstantIntRanges mlir::intrange::extSIRange(const ConstantIntRanges &range, unsigned destWidth) { … } ConstantIntRanges mlir::intrange::truncRange(const ConstantIntRanges &range, unsigned int destWidth) { … } //===----------------------------------------------------------------------===// // Addition //===----------------------------------------------------------------------===// ConstantIntRanges mlir::intrange::inferAdd(ArrayRef<ConstantIntRanges> argRanges, OverflowFlags ovfFlags) { … } //===----------------------------------------------------------------------===// // Subtraction //===----------------------------------------------------------------------===// ConstantIntRanges mlir::intrange::inferSub(ArrayRef<ConstantIntRanges> argRanges, OverflowFlags ovfFlags) { … } //===----------------------------------------------------------------------===// // Multiplication //===----------------------------------------------------------------------===// ConstantIntRanges mlir::intrange::inferMul(ArrayRef<ConstantIntRanges> argRanges, OverflowFlags ovfFlags) { … } //===----------------------------------------------------------------------===// // DivU, CeilDivU (Unsigned division) //===----------------------------------------------------------------------===// /// Fix up division results (ex. for ceiling and floor), returning an APInt /// if there has been no overflow DivisionFixupFn; static ConstantIntRanges inferDivURange(const ConstantIntRanges &lhs, const ConstantIntRanges &rhs, DivisionFixupFn fixup) { … } ConstantIntRanges mlir::intrange::inferDivU(ArrayRef<ConstantIntRanges> argRanges) { … } ConstantIntRanges mlir::intrange::inferCeilDivU(ArrayRef<ConstantIntRanges> argRanges) { … } //===----------------------------------------------------------------------===// // DivS, CeilDivS, FloorDivS (Signed division) //===----------------------------------------------------------------------===// static ConstantIntRanges inferDivSRange(const ConstantIntRanges &lhs, const ConstantIntRanges &rhs, DivisionFixupFn fixup) { … } ConstantIntRanges mlir::intrange::inferDivS(ArrayRef<ConstantIntRanges> argRanges) { … } ConstantIntRanges mlir::intrange::inferCeilDivS(ArrayRef<ConstantIntRanges> argRanges) { … } ConstantIntRanges mlir::intrange::inferFloorDivS(ArrayRef<ConstantIntRanges> argRanges) { … } //===----------------------------------------------------------------------===// // Signed remainder (RemS) //===----------------------------------------------------------------------===// ConstantIntRanges mlir::intrange::inferRemS(ArrayRef<ConstantIntRanges> argRanges) { … } //===----------------------------------------------------------------------===// // Unsigned remainder (RemU) //===----------------------------------------------------------------------===// ConstantIntRanges mlir::intrange::inferRemU(ArrayRef<ConstantIntRanges> argRanges) { … } //===----------------------------------------------------------------------===// // Max and min (MaxS, MaxU, MinS, MinU) //===----------------------------------------------------------------------===// ConstantIntRanges mlir::intrange::inferMaxS(ArrayRef<ConstantIntRanges> argRanges) { … } ConstantIntRanges mlir::intrange::inferMaxU(ArrayRef<ConstantIntRanges> argRanges) { … } ConstantIntRanges mlir::intrange::inferMinS(ArrayRef<ConstantIntRanges> argRanges) { … } ConstantIntRanges mlir::intrange::inferMinU(ArrayRef<ConstantIntRanges> argRanges) { … } //===----------------------------------------------------------------------===// // Bitwise operators (And, Or, Xor) //===----------------------------------------------------------------------===// /// "Widen" bounds - if 0bvvvvv??? <= a <= 0bvvvvv???, /// relax the bounds to 0bvvvvv000 <= a <= 0bvvvvv111, where vvvvv are the bits /// that both bonuds have in common. This gives us a consertive approximation /// for what values can be passed to bitwise operations. static std::tuple<APInt, APInt> widenBitwiseBounds(const ConstantIntRanges &bound) { … } ConstantIntRanges mlir::intrange::inferAnd(ArrayRef<ConstantIntRanges> argRanges) { … } ConstantIntRanges mlir::intrange::inferOr(ArrayRef<ConstantIntRanges> argRanges) { … } ConstantIntRanges mlir::intrange::inferXor(ArrayRef<ConstantIntRanges> argRanges) { … } //===----------------------------------------------------------------------===// // Shifts (Shl, ShrS, ShrU) //===----------------------------------------------------------------------===// ConstantIntRanges mlir::intrange::inferShl(ArrayRef<ConstantIntRanges> argRanges, OverflowFlags ovfFlags) { … } ConstantIntRanges mlir::intrange::inferShrS(ArrayRef<ConstantIntRanges> argRanges) { … } ConstantIntRanges mlir::intrange::inferShrU(ArrayRef<ConstantIntRanges> argRanges) { … } //===----------------------------------------------------------------------===// // Comparisons (Cmp) //===----------------------------------------------------------------------===// static intrange::CmpPredicate invertPredicate(intrange::CmpPredicate pred) { … } static bool isStaticallyTrue(intrange::CmpPredicate pred, const ConstantIntRanges &lhs, const ConstantIntRanges &rhs) { … } std::optional<bool> mlir::intrange::evaluatePred(CmpPredicate pred, const ConstantIntRanges &lhs, const ConstantIntRanges &rhs) { … }