14#include "llvm/ADT/ScopeExit.h"
15#include "llvm/ADT/iterator.h"
16#include "llvm/Config/abi-breaking.h"
17#include "llvm/Support/Casting.h"
18#include "llvm/Support/DebugLog.h"
19#include "llvm/Support/raw_ostream.h"
21#define DEBUG_TYPE "dataflow"
22#if LLVM_ENABLE_ABI_BREAKING_CHECKS
23#define DATAFLOW_DEBUG(X) LLVM_DEBUG(X)
25#define DATAFLOW_DEBUG(X)
44 auto inserted = dependents.insert({dependent, analysis});
48 LDBG() <<
"Creating dependency between " << debugName <<
" of " <<
anchor
49 <<
"\nand " << debugName <<
" on " << *dependent;
66 os <<
"<after operation>:"
70 os <<
"<before operation>:"
83 if (
auto *latticeAnchor = llvm::dyn_cast<GenericLatticeAnchor *>(*
this))
84 return latticeAnchor->print(os);
85 if (
auto value = llvm::dyn_cast<Value>(*
this)) {
89 return llvm::cast<ProgramPoint *>(*this)->print(os);
93 if (
auto *latticeAnchor = llvm::dyn_cast<GenericLatticeAnchor *>(*
this))
94 return latticeAnchor->getLoc();
95 if (
auto value = llvm::dyn_cast<Value>(*
this))
96 return value.getLoc();
111 auto guard = llvm::make_scope_exit([&]() { isRunning =
false; });
113 bool isInterprocedural = config.isInterprocedural();
114 auto restoreInterprocedural = llvm::make_scope_exit(
115 [&]() { config.setInterprocedural(isInterprocedural); });
117 config.setInterprocedural(
false);
120 for (
DataFlowAnalysis &analysis : llvm::make_pointee_range(childAnalyses)) {
121 analysis.initializeEquivalentLatticeAnchor(top);
125 for (
DataFlowAnalysis &analysis : llvm::make_pointee_range(childAnalyses)) {
126 DATAFLOW_DEBUG(LDBG() <<
"Priming analysis: " << analysis.debugName);
127 if (failed(analysis.initialize(top)))
134 while (!worklist.empty()) {
135 auto [point, analysis] = worklist.front();
139 <<
"' on: " << *point);
140 if (failed(analysis->visit(point)))
150 "DataFlowSolver is not running, should not use propagateIfChanged");
152 DATAFLOW_DEBUG(LDBG() <<
"Propagating update to " << state->debugName
153 <<
" of " << state->
anchor <<
"\n"
154 <<
"Value: " << *state);
174 solver.propagateIfChanged(state,
changed);
#define DATAFLOW_DEBUG(X)
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
Base class for generic analysis states.
LLVM_DUMP_METHOD void dump() const
void addDependency(ProgramPoint *point, DataFlowAnalysis *analysis)
Add a dependency to this analysis state on a lattice anchor and an analysis.
virtual void print(raw_ostream &os) const =0
Print the contents of the analysis state.
virtual void onUpdate(DataFlowSolver *solver) const
This function is called by the solver when the analysis state is updated to enqueue more work items.
LatticeAnchor anchor
The lattice anchor to which the state belongs.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
Base class for all data-flow analyses.
void addDependency(AnalysisState *state, ProgramPoint *point)
Create a dependency between the given analysis state and lattice anchor on this analysis.
void propagateIfChanged(AnalysisState *state, ChangeResult changed)
Propagate an update to a state if it changed.
virtual ~DataFlowAnalysis()
DataFlowAnalysis(DataFlowSolver &solver)
Create an analysis with a reference to the parent solver.
friend class DataFlowSolver
Allow the data-flow solver to access the internals of this class.
friend class DataFlowAnalysis
Allow the base child analysis class to access the internals of the 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...
LogicalResult initializeAndRun(Operation *top)
Initialize the children analyses starting from the provided top-level operation and run the analysis ...
virtual ~GenericLatticeAnchor()
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Set of flags used to control the behavior of the various IR print methods (e.g.
A trait used to provide symbol table functionalities to a region operation.
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.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Location getLoc()
The source location the operation was defined or derived from.
Location getLoc()
Return a location for this region.
Include the generated interface declarations.
const FrozenRewritePatternSet GreedyRewriteConfig bool * changed
ChangeResult
A result type used to indicate if a change happened.
Location getLoc() const
Get the source location of the lattice anchor.
void print(raw_ostream &os) const
Print the lattice anchor.
Program point represents a specific location in the execution of a program.
bool isNull() const
Returns true if this program point is set.
bool isBlockStart() const
Block * getBlock() const
Get the block contains this program point.
Operation * getNextOp() const
Get the next operation of this program point.
void print(raw_ostream &os) const
Print the program point.
Operation * getPrevOp() const
Get the previous operation of this program point.