MLIR  20.0.0git
DataFlowFramework.cpp
Go to the documentation of this file.
1 //===- DataFlowFramework.cpp - A generic framework for data-flow analysis -===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 #include "mlir/IR/Location.h"
11 #include "mlir/IR/Operation.h"
12 #include "mlir/IR/Value.h"
13 #include "llvm/ADT/iterator.h"
14 #include "llvm/Config/abi-breaking.h"
15 #include "llvm/Support/Casting.h"
16 #include "llvm/Support/Debug.h"
17 #include "llvm/Support/raw_ostream.h"
18 
19 #define DEBUG_TYPE "dataflow"
20 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
21 #define DATAFLOW_DEBUG(X) LLVM_DEBUG(X)
22 #else
23 #define DATAFLOW_DEBUG(X)
24 #endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
25 
26 using namespace mlir;
27 
28 //===----------------------------------------------------------------------===//
29 // GenericLatticeAnchor
30 //===----------------------------------------------------------------------===//
31 
33 
34 //===----------------------------------------------------------------------===//
35 // AnalysisState
36 //===----------------------------------------------------------------------===//
37 
39 
41  DataFlowAnalysis *analysis) {
42  auto inserted = dependents.insert({dependent, analysis});
43  (void)inserted;
45  if (inserted) {
46  llvm::dbgs() << "Creating dependency between " << debugName << " of "
47  << anchor << "\nand " << debugName << " on " << dependent
48  << "\n";
49  }
50  });
51 }
52 
53 void AnalysisState::dump() const { print(llvm::errs()); }
54 
55 //===----------------------------------------------------------------------===//
56 // LatticeAnchor
57 //===----------------------------------------------------------------------===//
58 
59 void ProgramPoint::print(raw_ostream &os) const {
60  if (isNull()) {
61  os << "<NULL POINT>";
62  return;
63  }
64  if (Operation *op = llvm::dyn_cast<Operation *>(*this)) {
65  return op->print(os, OpPrintingFlags().skipRegions());
66  }
67  return get<Block *>()->print(os);
68 }
69 
70 void LatticeAnchor::print(raw_ostream &os) const {
71  if (isNull()) {
72  os << "<NULL POINT>";
73  return;
74  }
75  if (auto *LatticeAnchor = llvm::dyn_cast<GenericLatticeAnchor *>(*this))
76  return LatticeAnchor->print(os);
77  if (auto value = llvm::dyn_cast<Value>(*this)) {
78  return value.print(os, OpPrintingFlags().skipRegions());
79  }
80 
81  return get<ProgramPoint>().print(os);
82 }
83 
85  if (auto *LatticeAnchor = llvm::dyn_cast<GenericLatticeAnchor *>(*this))
86  return LatticeAnchor->getLoc();
87  if (auto value = llvm::dyn_cast<Value>(*this))
88  return value.getLoc();
89 
90  ProgramPoint pp = get<ProgramPoint>();
91  if (auto *op = llvm::dyn_cast<Operation *>(pp))
92  return op->getLoc();
93  return pp.get<Block *>()->getParent()->getLoc();
94 }
95 
96 //===----------------------------------------------------------------------===//
97 // DataFlowSolver
98 //===----------------------------------------------------------------------===//
99 
101  // Initialize the analyses.
102  for (DataFlowAnalysis &analysis : llvm::make_pointee_range(childAnalyses)) {
103  DATAFLOW_DEBUG(llvm::dbgs()
104  << "Priming analysis: " << analysis.debugName << "\n");
105  if (failed(analysis.initialize(top)))
106  return failure();
107  }
108 
109  // Run the analysis until fixpoint.
110  do {
111  // Exhaust the worklist.
112  while (!worklist.empty()) {
113  auto [point, analysis] = worklist.front();
114  worklist.pop();
115 
116  DATAFLOW_DEBUG(llvm::dbgs() << "Invoking '" << analysis->debugName
117  << "' on: " << point << "\n");
118  if (failed(analysis->visit(point)))
119  return failure();
120  }
121 
122  // Iterate until all states are in some initialized state and the worklist
123  // is exhausted.
124  } while (!worklist.empty());
125 
126  return success();
127 }
128 
130  ChangeResult changed) {
131  if (changed == ChangeResult::Change) {
132  DATAFLOW_DEBUG(llvm::dbgs() << "Propagating update to " << state->debugName
133  << " of " << state->anchor << "\n"
134  << "Value: " << *state << "\n");
135  state->onUpdate(this);
136  }
137 }
138 
139 //===----------------------------------------------------------------------===//
140 // DataFlowAnalysis
141 //===----------------------------------------------------------------------===//
142 
144 
146 
148  state->addDependency(point, this);
149 }
150 
152  ChangeResult changed) {
153  solver.propagateIfChanged(state, changed);
154 }
#define DATAFLOW_DEBUG(X)
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 ~AnalysisState()
LatticeAnchor anchor
The lattice anchor to which the state belongs.
Block represents an ordered list of Operations.
Definition: Block.h:31
Base class for all data-flow analyses.
void propagateIfChanged(AnalysisState *state, ChangeResult changed)
Propagate an update to a state if it changed.
DataFlowAnalysis(DataFlowSolver &solver)
Create an analysis with a reference to the parent solver.
void addDependency(AnalysisState *state, ProgramPoint point)
Create a dependency between the given analysis state and lattice anchor on this analysis.
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...
LogicalResult initializeAndRun(Operation *top)
Initialize the children analyses starting from the provided top-level operation and run the analysis ...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
Set of flags used to control the behavior of the various IR print methods (e.g.
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
void print(raw_ostream &os, const OpPrintingFlags &flags=std::nullopt)
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:223
Include the generated interface declarations.
ChangeResult
A result type used to indicate if a change happened.
Fundamental IR components are supported as first-class lattice anchor.
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.
void print(raw_ostream &os) const
Print the program point.