16 #ifndef MLIR_ANALYSIS_DATAFLOWFRAMEWORK_H
17 #define MLIR_ANALYSIS_DATAFLOWFRAMEWORK_H
21 #include "llvm/ADT/Hashing.h"
22 #include "llvm/ADT/SetVector.h"
23 #include "llvm/Support/Compiler.h"
24 #include "llvm/Support/TypeName.h"
59 : block(parentBlock), point(pp) {}
66 using KeyTy = std::tuple<Block *, Block::iterator, Operation *>;
80 if (std::get<0>(key)) {
88 bool isNull()
const {
return block ==
nullptr && op ==
nullptr; }
92 return block == std::get<0>(key) && point == std::get<1>(key) &&
93 op == std::get<2>(key);
97 return block == pp.block && point == pp.point && op == pp.op;
115 if (block ==
nullptr) {
127 if (block ==
nullptr) {
138 void print(raw_ostream &os)
const;
141 Block *block =
nullptr;
177 virtual void print(raw_ostream &os)
const = 0;
198 template <
typename ConcreteT,
typename Value>
209 template <
typename ValueT>
212 value(std::forward<ValueT>(value)) {}
216 template <
typename... Args>
218 return uniquer.
get<ConcreteT>({}, std::forward<Args>(args)...);
222 template <
typename ValueT>
225 return new (alloc.
allocate<ConcreteT>())
226 ConcreteT(std::forward<ValueT>(value));
234 return point->
getTypeID() == TypeID::get<ConcreteT>();
251 :
public PointerUnion<GenericLatticeAnchor *, ProgramPoint *, Value> {
254 using ParentTy::PointerUnion;
259 void print(raw_ostream &os)
const;
266 class DataFlowAnalysis;
283 interprocedural = enable;
291 bool interprocedural =
true;
320 template <
typename AnalysisT,
typename... Args>
321 AnalysisT *
load(Args &&...args);
329 template <
typename StateT,
typename AnchorT>
332 analysisStates.find({
LatticeAnchor(anchor), TypeID::get<StateT>()});
333 if (it == analysisStates.end())
335 return static_cast<const StateT *
>(it->second.get());
339 template <
typename AnchorT>
343 for (
auto it = analysisStates.begin(); it != analysisStates.end(); ++it) {
344 if (it->first.first == la)
345 analysisStates.erase(it);
351 template <
typename AnchorT,
typename... Args>
353 return AnchorT::get(uniquer, std::forward<Args>(args)...);
388 using WorkItem = std::pair<ProgramPoint *, DataFlowAnalysis *>;
394 template <
typename StateT,
typename AnchorT>
411 std::queue<WorkItem> worklist;
458 virtual void print(raw_ostream &os)
const = 0;
459 LLVM_DUMP_METHOD
void dump()
const;
479 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
565 template <
typename AnchorT>
571 template <
typename AnchorT,
typename... Args>
579 template <
typename StateT,
typename AnchorT>
587 template <
typename StateT,
typename AnchorT>
589 StateT *state = getOrCreate<StateT>(anchor);
614 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
627 template <
typename AnalysisT,
typename... Args>
629 childAnalyses.emplace_back(
new AnalysisT(*
this, std::forward<Args>(args)...));
630 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
631 childAnalyses.back().get()->debugName = llvm::getTypeName<AnalysisT>();
633 return static_cast<AnalysisT *
>(childAnalyses.back().get());
636 template <
typename StateT,
typename AnchorT>
638 std::unique_ptr<AnalysisState> &state =
639 analysisStates[{
LatticeAnchor(anchor), TypeID::get<StateT>()}];
641 state = std::unique_ptr<StateT>(
new StateT(anchor));
642 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
643 state->debugName = llvm::getTypeName<StateT>();
646 return static_cast<StateT *
>(state.get());
687 :
public DenseMapInfo<mlir::LatticeAnchor::ParentTy> {};
690 template <
typename To>
692 :
public CastInfo<To, mlir::LatticeAnchor::PointerUnion> {};
694 template <
typename To>
696 :
public CastInfo<To, const mlir::LatticeAnchor::PointerUnion> {};
Base class for generic analysis states.
AnalysisState(LatticeAnchor anchor)
Create the analysis state on the given lattice anchor.
LLVM_DUMP_METHOD void dump() const
LatticeAnchor getAnchor() const
Returns the lattice anchor this state is located at.
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.
Block represents an ordered list of Operations.
OpListType::iterator iterator
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.
const StateT * getOrCreateFor(ProgramPoint *dependent, AnchorT anchor)
Get a read-only analysis state for the given point and create a dependency on dependent.
ProgramPoint * getProgramPointAfter(Operation *op)
ProgramPoint * getProgramPointBefore(Operation *op)
Get a uniqued program point instance.
AnchorT * getLatticeAnchor(Args &&...args)
Get or create a custom lattice anchor.
virtual ~DataFlowAnalysis()
StateT * getOrCreate(AnchorT anchor)
Get the analysis state associated with the lattice anchor.
const DataFlowConfig & getSolverConfig() const
Return the configuration of the solver used for this analysis.
ProgramPoint * getProgramPointAfter(Block *block)
DataFlowAnalysis(DataFlowSolver &solver)
Create an analysis with a reference to the parent solver.
virtual LogicalResult initialize(Operation *top)=0
Initialize the analysis from the provided top-level operation by building an initial dependency graph...
ProgramPoint * getProgramPointBefore(Block *block)
virtual LogicalResult visit(ProgramPoint *point)=0
Visit the given program point.
void registerAnchorKind()
Register a custom lattice anchor class.
Configuration class for data flow solver and child analyses.
DataFlowConfig & setInterprocedural(bool enable)
Set whether the solver should operate interpocedurally, i.e.
bool isInterprocedural() const
Return true if the solver operates interprocedurally, false otherwise.
The general data-flow analysis solver.
void enqueue(WorkItem item)
Push a work item onto the worklist.
void eraseState(AnchorT anchor)
Erase any analysis state associated with the given lattice anchor.
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.
ProgramPoint * getProgramPointAfter(Operation *op)
const DataFlowConfig & getConfig() const
Get the configuration of the solver.
ProgramPoint * getProgramPointBefore(Operation *op)
Get a uniqued program point instance.
AnchorT * getLatticeAnchor(Args &&...args)
Get a uniqued lattice anchor instance.
ProgramPoint * getProgramPointBefore(Block *block)
StateT * getOrCreateState(AnchorT anchor)
Get the state associated with the given lattice anchor.
ProgramPoint * getProgramPointAfter(Block *block)
AnalysisT * load(Args &&...args)
Load an analysis into the solver. Return the analysis instance.
LogicalResult initializeAndRun(Operation *top)
Initialize the children analyses starting from the provided top-level operation and run the analysis ...
DataFlowSolver(const DataFlowConfig &config=DataFlowConfig())
std::pair< ProgramPoint *, DataFlowAnalysis * > WorkItem
A work item on the solver queue is a program point, child analysis pair.
Base class for generic lattice anchor based on a concrete lattice anchor type and a content key.
bool operator==(const Value &value) const
Two lattice anchors are equal if their values are equal.
static ConcreteT * construct(StorageUniquer::StorageAllocator &alloc, ValueT &&value)
Allocate space for a lattice anchor and construct it in-place.
static bool classof(const GenericLatticeAnchor *point)
Provide LLVM-style RTTI using type IDs.
GenericLatticeAnchorBase(ValueT &&value)
Construct an instance of the lattice anchor using the provided value and the type ID of the concrete ...
const Value & getValue() const
Get the contents of the lattice anchor.
static ConcreteT * get(StorageUniquer &uniquer, Args &&...args)
Get a uniqued instance of this lattice anchor class with the given arguments.
Abstract class for generic lattice anchor.
virtual void print(raw_ostream &os) const =0
Print the lattice anchor.
TypeID getTypeID() const
Get the abstract lattice anchor's type identifier.
virtual Location getLoc() const =0
Get a derived source location for the lattice anchor.
GenericLatticeAnchor(TypeID typeID)
Create an abstract lattice anchor with type identifier.
virtual ~GenericLatticeAnchor()
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Operation is the basic unit of execution within MLIR.
Block * getBlock()
Returns the operation block that contains this operation.
This class acts as the base storage that all storage classes must derived from.
This is a utility allocator used to allocate memory for instances of derived types.
T * allocate()
Allocate an instance of the provided type.
A utility class to get or create instances of "storage classes".
Storage * get(function_ref< void(Storage *)> initFn, TypeID id, Args &&...args)
Gets a uniqued instance of 'Storage'.
void registerParametricStorageType(TypeID id)
Register a new parametric storage class, this is necessary to create instances of this class type.
This class provides an efficient unique identifier for a specific C++ type.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Include the generated interface declarations.
ChangeResult & operator|=(ChangeResult &lhs, ChangeResult rhs)
const FrozenRewritePatternSet GreedyRewriteConfig bool * changed
ChangeResult
A result type used to indicate if a change happened.
ChangeResult operator&(ChangeResult lhs, ChangeResult rhs)
ChangeResult operator|(ChangeResult lhs, ChangeResult rhs)
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
static unsigned getHashValue(mlir::ProgramPoint pp)
static mlir::ProgramPoint getEmptyKey()
static mlir::ProgramPoint getTombstoneKey()
static bool isEqual(mlir::ProgramPoint lhs, mlir::ProgramPoint rhs)
Fundamental IR components are supported as first-class lattice anchor.
LatticeAnchor(ParentTy point=nullptr)
Allow implicit conversion from the parent type.
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
ProgramPoint(Block *parentBlock, Block::iterator pp)
Creates a new program point at the given location.
Block::iterator getPoint() const
Get the the iterator this program point refers to.
ProgramPoint()
Create a empty program point.
Operation * getOperation() const
Get the the iterator this program point refers to.
Operation * getPrevOp() const
Get the previous operation of this program point.
static ProgramPoint * construct(StorageUniquer::StorageAllocator &alloc, KeyTy &&key)
bool operator==(const ProgramPoint &pp) const
bool operator==(const KeyTy &key) const
Two program points are equal if their block and iterator are equal.
ProgramPoint(const ProgramPoint &point)
Create a new program point from the given program point.
std::tuple< Block *, Block::iterator, Operation * > KeyTy
The concrete key type used by the storage uniquer.
void print(raw_ostream &os) const
Print the program point.
Operation * getNextOp() const
Get the next operation of this program point.
Block * getBlock() const
Get the block contains this program point.
ProgramPoint(Operation *op)
Creates a new program point at the given operation.