31#include "llvm/ADT/STLExtras.h"
32#include "llvm/Support/Casting.h"
33#include "llvm/Support/Debug.h"
34#include "llvm/Support/DebugLog.h"
39#define DEBUG_TYPE "int-range-analysis"
54 auto nonNegativePred = [&solver](
Value v) ->
bool {
58 llvm::all_of(op->
getResults(), nonNegativePred));
68 auto value = cast<Value>(
anchor);
75 if (
auto *parent = value.getDefiningOp())
76 dialect = parent->getDialect();
78 dialect = value.getParentBlock()->getParentOp()->getDialect();
81 if (isa<IntegerType, IndexType>(value.getType())) {
82 cstAttr = IntegerAttr::get(value.getType(), *constant);
83 }
else if (
auto shapedTy = dyn_cast<ShapedType>(value.getType())) {
86 llvm::report_fatal_error(
87 Twine(
"FIXME: Don't know how to create a constant for this type: ") +
96 auto inferrable = dyn_cast<InferIntRangeInterface>(op);
102 LDBG() <<
"Inferring ranges for "
104 auto argRanges = llvm::map_to_vector(
110 auto result = dyn_cast<OpResult>(v);
115 LDBG() <<
"Inferred range " << attrs;
126 return op->hasTrait<OpTrait::IsTerminator>();
129 !(lattice->
getValue() == oldRange)) {
130 LDBG() <<
"Loop variant loop result detected";
136 inferrable.inferResultRangesFromOptional(argRanges, joinCallback);
144 assert(nonSuccessorInputs.size() == nonSuccessorInputLattices.size() &&
146 if (
auto inferrable = dyn_cast<InferIntRangeInterface>(op)) {
147 LDBG() <<
"Inferring ranges for "
151 return getLatticeElementFor(getProgramPointAfter(op), value)->getValue();
155 auto arg = dyn_cast<BlockArgument>(v);
161 LDBG() <<
"Inferred range " << attrs;
163 unsigned nonSuccessorInputIdx =
166 nonSuccessorInputLattices[nonSuccessorInputIdx];
176 return op->hasTrait<OpTrait::IsTerminator>();
179 !(lattice->
getValue() == oldRange)) {
180 LDBG() <<
"Loop variant loop result detected";
186 inferrable.inferResultRangesFromOptional(argRanges, joinCallback);
193 Block *block,
bool getUpper) {
195 if (
auto attr = dyn_cast<Attribute>(loopBound)) {
196 if (
auto bound = dyn_cast<IntegerAttr>(attr))
197 return bound.getValue();
198 }
else if (
auto value = llvm::dyn_cast<Value>(loopBound)) {
208 return getUpper ? APInt::getSignedMaxValue(width)
209 : APInt::getSignedMinValue(width);
213 if (
auto loop = dyn_cast<LoopLikeOpInterface>(op)) {
214 std::optional<llvm::SmallVector<Value>> maybeIvs =
215 loop.getLoopInductionVars();
217 return SparseForwardDataFlowAnalysis ::visitNonControlFlowArguments(
218 op, successor, nonSuccessorInputs, nonSuccessorInputLattices);
224 for (
auto [iv, lowerBound, upperBound, step] :
225 llvm::zip_equal(*maybeIvs, lowerBounds, upperBounds, steps)) {
226 Block *block = iv.getParentBlock();
227 APInt
min = getLoopBoundFromFold(lowerBound, iv.getType(), block,
229 APInt
max = getLoopBoundFromFold(upperBound, iv.getType(), block,
233 getLoopBoundFromFold(step, iv.getType(), block,
true);
235 if (stepVal.isNegative()) {
256 op, successor, nonSuccessorInputs, nonSuccessorInputLattices);
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
LatticeAnchor anchor
The lattice anchor to which the state belongs.
friend class DataFlowSolver
Allow the framework to access the dependents.
Attributes are known-constant values of operations.
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.
std::optional< APInt > getConstantValue() const
If either the signed or unsigned interpretations of the range indicate that the value it bounds is a ...
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.
void propagateIfChanged(AnalysisState *state, ChangeResult changed)
Propagate an update to an analysis state if it changed by pushing dependent work items to the back of...
const StateT * lookupState(AnchorT anchor) const
Lookup an analysis state for the given lattice anchor.
StateT * getOrCreateState(AnchorT anchor)
Get the state associated with the given lattice anchor.
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
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...
user_range getUsers() const
void onUpdate(DataFlowSolver *solver) const override
When the lattice gets updated, propagate an update to users of the value using its use-def chain to s...
This lattice value represents a known constant value of a lattice.
static ConstantValue getUnknownConstant()
The state where the constant value is unknown.
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.
void onUpdate(DataFlowSolver *solver) const override
If the range can be narrowed to an integer constant, update the constant value of the SSA value.
This class represents a lattice holding a specific value of type ValueT.
IntegerValueRange & getValue()
ChangeResult join(const AbstractSparseLattice &rhs) override
Join the information contained in the 'rhs' lattice into this lattice.
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.
const FrozenRewritePatternSet GreedyRewriteConfig bool * changed
ChangeResult
A result type used to indicate if a change happened.
static std::string debugString(T &&op)