30#include "llvm/ADT/STLExtras.h"
31#include "llvm/Support/Casting.h"
32#include "llvm/Support/Debug.h"
33#include "llvm/Support/DebugLog.h"
38#define DEBUG_TYPE "int-range-analysis"
53 auto nonNegativePred = [&solver](
Value v) ->
bool {
57 llvm::all_of(op->
getResults(), nonNegativePred));
87 auto inferrable = dyn_cast<InferIntRangeInterface>(op);
93 LDBG() <<
"Inferring ranges for "
95 auto argRanges = llvm::map_to_vector(
101 auto result = dyn_cast<OpResult>(v);
106 LDBG() <<
"Inferred range " << attrs;
111 inferrable.inferResultRangesFromOptional(argRanges, joinCallback);
119 assert(nonSuccessorInputs.size() == nonSuccessorInputLattices.size() &&
121 if (
auto inferrable = dyn_cast<InferIntRangeInterface>(op)) {
122 LDBG() <<
"Inferring ranges for "
126 return getLatticeElementFor(getProgramPointAfter(op), value)->getValue();
130 auto arg = dyn_cast<BlockArgument>(v);
136 LDBG() <<
"Inferred range " << attrs;
138 unsigned nonSuccessorInputIdx =
141 nonSuccessorInputLattices[nonSuccessorInputIdx];
145 inferrable.inferResultRangesFromOptional(argRanges, joinCallback);
152 Block *block,
bool getUpper) {
154 if (
auto attr = dyn_cast<Attribute>(loopBound)) {
155 if (
auto bound = dyn_cast<IntegerAttr>(attr))
156 return bound.getValue();
157 }
else if (
auto value = llvm::dyn_cast<Value>(loopBound)) {
167 return getUpper ? APInt::getSignedMaxValue(width)
168 : APInt::getSignedMinValue(width);
172 if (
auto loop = dyn_cast<LoopLikeOpInterface>(op)) {
173 std::optional<llvm::SmallVector<Value>> maybeIvs =
174 loop.getLoopInductionVars();
176 return SparseForwardDataFlowAnalysis ::visitNonControlFlowArguments(
177 op, successor, nonSuccessorInputs, nonSuccessorInputLattices);
182 std::optional<SmallVector<OpFoldResult>> maybeLowerBounds =
183 loop.getLoopLowerBounds();
184 std::optional<SmallVector<OpFoldResult>> maybeUpperBounds =
185 loop.getLoopUpperBounds();
186 std::optional<SmallVector<OpFoldResult>> maybeSteps = loop.getLoopSteps();
187 if (!maybeLowerBounds || !maybeUpperBounds || !maybeSteps) {
189 op, successor, nonSuccessorInputs, nonSuccessorInputLattices);
194 for (
auto [iv, lowerBound, upperBound, step] :
195 llvm::zip_equal(*maybeIvs, lowerBounds, upperBounds, steps)) {
196 Block *block = iv.getParentBlock();
197 APInt
min = getLoopBoundFromFold(lowerBound, iv.getType(), block,
199 APInt
max = getLoopBoundFromFold(upperBound, iv.getType(), block,
203 getLoopBoundFromFold(step, iv.getType(), block,
true);
205 if (stepVal.isNegative()) {
226 op, successor, nonSuccessorInputs, nonSuccessorInputLattices);
static constexpr unsigned kIntegerRangeWideningBudget
Number of merge-site joins a single integer-range lattice element is allowed to absorb before Integer...
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
Block represents an ordered list of Operations.
A set of arbitrary-precision integers representing bounds on a given integer value.
const APInt & smax() const
The maximum value of an integer when it is interpreted as signed.
const APInt & smin() const
The minimum value of an integer when it is interpreted as signed.
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.
ProgramPoint * getProgramPointBefore(Operation *op)
Get a uniqued program point instance.
void propagateIfChanged(AnalysisState *state, ChangeResult changed)
Propagate an update to a state if it changed.
The general data-flow analysis solver.
const StateT * lookupState(AnchorT anchor) const
Lookup an analysis state for the given lattice anchor.
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.
static IntegerValueRange getMaxRange(Value value)
Create a maximal range ([0, uint_max(t)] / [int_min(t), int_max(t)]) range that is used to mark the v...
This class represents a single result from folding an operation.
Set of flags used to control the behavior of the various IR print methods (e.g.
A wrapper class that allows for printing an operation with a set of flags, useful to act as a "stream...
Operation is the basic unit of execution within MLIR.
operand_range getOperands()
Returns an iterator on the underlying Value's.
result_range getResults()
This class represents a successor of a region.
Region * getSuccessor() const
Return the given region successor.
BlockArgListType getArguments()
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
void visitNonControlFlowArguments(Operation *op, const RegionSuccessor &successor, ValueRange nonSuccessorInputs, ArrayRef< IntegerValueRangeLattice * > nonSuccessorInputLattices) override
Visit block arguments or operation results of an operation with region control-flow for which values ...
LogicalResult visitOperation(Operation *op, ArrayRef< const IntegerValueRangeLattice * > operands, ArrayRef< IntegerValueRangeLattice * > results) override
Visit an operation.
This lattice element represents the integer value range of an SSA value.
ChangeResult join(const AbstractSparseLattice &rhs) override
Join the information contained in 'rhs' into this lattice.
ValueT & getValue()
Return the value held by this lattice.
ChangeResult join(const AbstractSparseLattice &rhs) override
Join the information contained in the 'rhs' lattice into this lattice.
AbstractSparseLattice(Value value)
IntegerValueRangeLattice * getLatticeElement(Value value) override
void setAllToEntryStates(ArrayRef< IntegerValueRangeLattice * > lattices)
virtual void visitNonControlFlowArguments(Operation *op, const RegionSuccessor &successor, ValueRange nonSuccessorInputs, ArrayRef< StateT * > nonSuccessorInputLattices)
Given an operation with possible region control-flow, the lattices of the operands,...
const IntegerValueRangeLattice * getLatticeElementFor(ProgramPoint *point, Value value)
LogicalResult staticallyNonNegative(DataFlowSolver &solver, Operation *op)
Succeeds if an op can be converted to its unsigned equivalent without changing its semantics.
Include the generated interface declarations.
ChangeResult
A result type used to indicate if a change happened.