16#ifndef MLIR_ANALYSIS_DATAFLOWFRAMEWORK_H
17#define MLIR_ANALYSIS_DATAFLOWFRAMEWORK_H
21#include "llvm/ADT/DenseSet.h"
22#include "llvm/ADT/EquivalenceClasses.h"
23#include "llvm/ADT/Hashing.h"
24#include "llvm/ADT/STLFunctionalExtras.h"
25#include "llvm/ADT/SetVector.h"
26#include "llvm/Support/Compiler.h"
27#include "llvm/Support/TypeName.h"
62 : block(parentBlock), point(pp) {}
69 using KeyTy = std::tuple<Block *, Block::iterator, Operation *>;
81 if (std::get<0>(key)) {
89 bool isNull()
const {
return block ==
nullptr && op ==
nullptr; }
93 return block == std::get<0>(key) && point == std::get<1>(key) &&
94 op == std::get<2>(key);
98 return block == pp.block && point == pp.point && op == pp.op;
116 if (block ==
nullptr) {
128 if (block ==
nullptr) {
136 bool isBlockEnd()
const {
return block && block->end() == point; }
142 Block *block =
nullptr;
199template <
typename ConcreteT,
typename Value>
210 template <
typename ValueT>
213 value(std::forward<ValueT>(value)) {}
217 template <
typename... Args>
219 return uniquer.
get<ConcreteT>({}, std::forward<Args>(args)...);
223 template <
typename ValueT>
226 return new (alloc.
allocate<ConcreteT>())
227 ConcreteT(std::forward<ValueT>(value));
252 :
public PointerUnion<GenericLatticeAnchor *, ProgramPoint *, Value> {
255 using ParentTy::PointerUnion;
267class DataFlowAnalysis;
292 interprocedural = enable;
300 bool interprocedural =
true;
333 template <
typename AnalysisT,
typename... Args>
334 AnalysisT *
load(Args &&...args);
349 template <
typename StateT,
typename AnchorT>
353 const auto &mapIt = analysisStates.find(latticeAnchor);
354 if (mapIt == analysisStates.end())
357 if (it == mapIt->second.end())
359 return static_cast<const StateT *
>(it->second.get());
363 template <
typename AnchorT>
368 analysisStates.clear();
369 equivalentAnchorMap.clear();
374 template <
typename AnchorT,
typename... Args>
376 return AnchorT::get(uniquer, std::forward<Args>(args)...);
411 using WorkItem = std::pair<ProgramPoint *, DataFlowAnalysis *>;
414 if (pending.insert(item).second)
421 assert(!worklist.empty());
422 auto item = worklist.front();
431 template <
typename StateT,
typename AnchorT>
437 template <
typename StateT>
441 template <
typename StateT,
typename AnchorT>
445 template <
typename StateT>
446 bool isEquivalent(LatticeAnchor lhs, LatticeAnchor rhs)
const;
462 bool isRunning =
false;
467 std::queue<WorkItem> worklist;
524 LLVM_DUMP_METHOD
void dump()
const;
544#if LLVM_ENABLE_ABI_BREAKING_CHECKS
570template <
typename AnchorT>
575 for (
auto &&[TypeId, eqClass] : equivalentAnchorMap) {
576 if (!eqClass.contains(latticeAnchor)) {
579 llvm::EquivalenceClasses<LatticeAnchor>::member_iterator leaderIt =
580 eqClass.findLeader(latticeAnchor);
583 if (*leaderIt == latticeAnchor && ++leaderIt != eqClass.member_end()) {
584 analysisStates[*leaderIt][TypeId] =
585 std::move(analysisStates[latticeAnchor][TypeId]);
588 eqClass.erase(latticeAnchor);
592 analysisStates.erase(latticeAnchor);
680 template <
typename AnchorT>
682 solver.uniquer.registerParametricStorageType<AnchorT>();
686 template <
typename AnchorT,
typename... Args>
688 return solver.getLatticeAnchor<AnchorT>(std::forward<Args>(args)...);
692 template <
typename StateT,
typename AnchorT>
694 return solver.unionLatticeAnchors<StateT>(anchor, other);
700 template <
typename StateT,
typename AnchorT>
702 return solver.getOrCreateState<StateT>(anchor);
708 template <
typename StateT,
typename AnchorT>
719 return solver.getProgramPointBefore(op);
723 return solver.getProgramPointBefore(block);
727 return solver.getProgramPointAfter(op);
731 return solver.getProgramPointAfter(block);
737#if LLVM_ENABLE_ABI_BREAKING_CHECKS
755template <
typename AnalysisT,
typename... Args>
757 childAnalyses.emplace_back(
new AnalysisT(*
this, std::forward<Args>(args)...));
759#if LLVM_ENABLE_ABI_BREAKING_CHECKS
760 childAnalyses.back()->debugName = llvm::getTypeName<AnalysisT>();
762 return static_cast<AnalysisT *
>(childAnalyses.back().
get());
765template <
typename StateT>
769 return latticeAnchor;
771 const llvm::EquivalenceClasses<LatticeAnchor> &eqClass =
773 llvm::EquivalenceClasses<LatticeAnchor>::member_iterator leaderIt =
774 eqClass.findLeader(latticeAnchor);
775 if (leaderIt != eqClass.member_end()) {
778 return latticeAnchor;
781template <
typename StateT,
typename AnchorT>
786 std::unique_ptr<AnalysisState> &state =
789 state = std::unique_ptr<StateT>(
new StateT(anchor));
790#if LLVM_ENABLE_ABI_BREAKING_CHECKS
791 state->debugName = llvm::getTypeName<StateT>();
794 return static_cast<StateT *
>(state.get());
797template <
typename StateT>
802 const llvm::EquivalenceClasses<LatticeAnchor> &eqClass =
804 if (!eqClass.contains(lhs) || !eqClass.contains(rhs))
806 return eqClass.isEquivalent(lhs, rhs);
809template <
typename StateT,
typename AnchorT>
811 llvm::EquivalenceClasses<LatticeAnchor> &eqClass =
841template <
typename To>
843 :
public CastInfo<To, mlir::LatticeAnchor::PointerUnion> {};
845template <
typename To>
847 :
public CastInfo<To, const mlir::LatticeAnchor::PointerUnion> {};
Base class for generic analysis states.
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.
AnalysisState(LatticeAnchor anchor)
Create the analysis state on the given lattice anchor.
LatticeAnchor anchor
The lattice anchor to which the state belongs.
friend class DataFlowSolver
Allow the framework to access the dependents.
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 unionLatticeAnchors(AnchorT anchor, AnchorT other)
Union input anchors under the given state.
TypeID getTypeID() const
Return the TypeID of the concrete analysis class.
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.
ProgramPoint * getProgramPointBefore(Block *block)
ProgramPoint * getProgramPointAfter(Block *block)
const DataFlowConfig & getSolverConfig() const
Return the configuration of the solver used for this analysis.
StateT * getOrCreate(AnchorT anchor)
Get the analysis state associated with the lattice anchor.
ProgramPoint * getProgramPointAfter(Operation *op)
virtual void initializeEquivalentLatticeAnchor(Operation *top)
Initialize lattice anchor equivalence class from the provided top-level operation.
virtual ~DataFlowAnalysis()
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...
virtual LogicalResult visit(ProgramPoint *point)=0
Visit the given program point.
AnchorT * getLatticeAnchor(Args &&...args)
Get or create a custom lattice anchor.
void registerAnchorKind()
Register a custom lattice anchor class.
friend class DataFlowSolver
Allow the data-flow solver to access the internals of this class.
const StateT * getOrCreateFor(ProgramPoint *dependent, AnchorT anchor)
Get a read-only analysis state for the given point and create a dependency on dependent.
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.
LogicalResult initializeAndRun(Operation *top, llvm::function_ref< bool(DataFlowAnalysis &)> analysisFilter=nullptr)
Initialize analyses starting from the provided top-level operation and run the analysis until fixpoin...
void unionLatticeAnchors(AnchorT anchor, AnchorT other)
Union input anchors under the given state.
void enqueue(WorkItem item)
Push a work item onto the worklist, if it is not already there.
bool isEquivalent(LatticeAnchor lhs, LatticeAnchor rhs) const
Return given lattice is equivalent on given state.
friend class DataFlowAnalysis
Allow the base child analysis class to access the internals of the solver.
ProgramPoint * getProgramPointBefore(Operation *op)
Get a uniqued program point instance.
ProgramPoint * getProgramPointAfter(Block *block)
void eraseState(AnchorT anchor)
Erase any analysis state associated with the given lattice anchor.
ProgramPoint * getProgramPointAfter(Operation *op)
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...
AnchorT * getLatticeAnchor(Args &&...args)
Get a uniqued lattice anchor instance.
const StateT * lookupState(AnchorT anchor) const
Lookup an analysis state for the given lattice anchor.
ProgramPoint * getProgramPointBefore(Block *block)
void eraseAllStates()
Erase all analysis states.
StateT * getOrCreateState(AnchorT anchor)
Get the state associated with the given lattice anchor.
const DataFlowConfig & getConfig() const
Get the configuration of the solver.
LatticeAnchor getLeaderAnchorOrSelf(LatticeAnchor latticeAnchor) const
Get leader lattice anchor in equivalence lattice anchor group, return input lattice anchor if input n...
AnalysisT * load(Args &&...args)
Load an analysis into the solver. Return the analysis instance.
DataFlowSolver(const DataFlowConfig &config=DataFlowConfig())
std::pair< ProgramPoint *, DataFlowAnalysis * > WorkItem
A work item on the solver queue is a program point, child analysis pair.
bool operator==(const Value &value) const
Two lattice anchors are equal if their values are equal.
GenericLatticeAnchorBase< ConcreteT, Value > Base
Alias for the base class.
const Value & getValue() const
Get the contents of the lattice anchor.
static bool classof(const GenericLatticeAnchor *point)
Provide LLVM-style RTTI using type IDs.
static ConcreteT * construct(StorageUniquer::StorageAllocator &alloc, ValueT &&value)
Allocate space for a lattice anchor and construct it in-place.
static ConcreteT * get(StorageUniquer &uniquer, Args &&...args)
Get a uniqued instance of this lattice anchor class with the given arguments.
GenericLatticeAnchorBase(ValueT &&value)
Construct an instance of the lattice anchor using the provided value and the type ID of the concrete ...
Value KeyTy
The concrete key type used by the storage uniquer.
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'.
This class provides an efficient unique identifier for a specific C++ type.
static TypeID get()
Construct a type info object for the given type T.
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.
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
ChangeResult
A result type used to indicate if a change happened.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
ChangeResult operator&(ChangeResult lhs, ChangeResult rhs)
ChangeResult operator|(ChangeResult lhs, ChangeResult rhs)
llvm::SetVector< T, Vector, Set, N > SetVector
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
ChangeResult & operator|=(ChangeResult &lhs, ChangeResult rhs)
static unsigned getHashValue(mlir::ProgramPoint pp)
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.
PointerUnion< GenericLatticeAnchor *, ProgramPoint *, Value > ParentTy
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.
Block * getBlock() const
Get the block contains this program point.
Operation * getNextOp() const
Get the next operation of this program point.
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.
static ProgramPoint * construct(StorageUniquer::StorageAllocator &alloc, KeyTy &&key)
Operation * getPrevOp() const
Get the previous operation of this program point.
Operation * getOperation() const
Get the the iterator this program point refers to.
ProgramPoint(Operation *op)
Creates a new program point at the given operation.