CIRCT  20.0.0git
TestPasses.cpp
Go to the documentation of this file.
1 //===- TestPasses.cpp - Test passes for the analysis infrastructure -------===//
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 //
9 // This file implements test passes for the analysis infrastructure.
10 //
11 //===----------------------------------------------------------------------===//
12 
21 #include "mlir/Dialect/Affine/IR/AffineMemoryOpInterfaces.h"
22 #include "mlir/Dialect/Affine/IR/AffineOps.h"
23 #include "mlir/Dialect/Func/IR/FuncOps.h"
24 #include "mlir/IR/BuiltinOps.h"
25 #include "mlir/IR/Value.h"
26 #include "mlir/Pass/Pass.h"
27 #include "llvm/ADT/DepthFirstIterator.h"
28 #include "llvm/Support/Debug.h"
29 
30 using namespace mlir;
31 using namespace mlir::affine;
32 using namespace circt;
33 using namespace circt::analysis;
34 using namespace circt::scheduling;
35 
36 //===----------------------------------------------------------------------===//
37 // DebugAnalysis
38 //===----------------------------------------------------------------------===//
39 
40 namespace {
41 struct TestDebugAnalysisPass
42  : public PassWrapper<TestDebugAnalysisPass, OperationPass<mlir::ModuleOp>> {
43  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDebugAnalysisPass)
44 
45  void runOnOperation() override;
46  StringRef getArgument() const override { return "test-debug-analysis"; }
47  StringRef getDescription() const override {
48  return "Perform debug analysis and emit results as attributes";
49  }
50 };
51 } // namespace
52 
53 void TestDebugAnalysisPass::runOnOperation() {
54  auto *context = &getContext();
55  auto &analysis = getAnalysis<DebugAnalysis>();
56  for (auto *op : analysis.debugOps) {
57  op->setAttr("debug.only", UnitAttr::get(context));
58  }
59 }
60 
61 //===----------------------------------------------------------------------===//
62 // DependenceAnalysis
63 //===----------------------------------------------------------------------===//
64 
65 namespace {
66 struct TestDependenceAnalysisPass
67  : public PassWrapper<TestDependenceAnalysisPass,
68  OperationPass<func::FuncOp>> {
69  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDependenceAnalysisPass)
70 
71  void runOnOperation() override;
72  StringRef getArgument() const override { return "test-dependence-analysis"; }
73  StringRef getDescription() const override {
74  return "Perform dependence analysis and emit results as attributes";
75  }
76 };
77 } // namespace
78 
79 void TestDependenceAnalysisPass::runOnOperation() {
80  MLIRContext *context = &getContext();
81 
82  MemoryDependenceAnalysis analysis(getOperation());
83 
84  getOperation().walk([&](Operation *op) {
85  if (!isa<AffineReadOpInterface, AffineWriteOpInterface>(op))
86  return;
87 
88  SmallVector<Attribute> deps;
89 
90  for (auto dep : analysis.getDependences(op)) {
91  if (dep.dependenceType != DependenceResult::HasDependence)
92  continue;
93 
94  SmallVector<Attribute> comps;
95  for (auto comp : dep.dependenceComponents) {
96  SmallVector<Attribute> vector;
97  vector.push_back(
98  IntegerAttr::get(IntegerType::get(context, 64), *comp.lb));
99  vector.push_back(
100  IntegerAttr::get(IntegerType::get(context, 64), *comp.ub));
101  comps.push_back(ArrayAttr::get(context, vector));
102  }
103 
104  deps.push_back(ArrayAttr::get(context, comps));
105  }
106 
107  auto dependences = ArrayAttr::get(context, deps);
108  op->setAttr("dependences", dependences);
109  });
110 }
111 
112 //===----------------------------------------------------------------------===//
113 // SchedulingAnalysis
114 //===----------------------------------------------------------------------===//
115 
116 namespace {
117 struct TestSchedulingAnalysisPass
118  : public PassWrapper<TestSchedulingAnalysisPass,
119  OperationPass<func::FuncOp>> {
120  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestSchedulingAnalysisPass)
121 
122  void runOnOperation() override;
123  StringRef getArgument() const override { return "test-scheduling-analysis"; }
124  StringRef getDescription() const override {
125  return "Perform scheduling analysis and emit results as attributes";
126  }
127 };
128 } // namespace
129 
130 void TestSchedulingAnalysisPass::runOnOperation() {
131  MLIRContext *context = &getContext();
132 
133  CyclicSchedulingAnalysis analysis = getAnalysis<CyclicSchedulingAnalysis>();
134 
135  getOperation().walk([&](AffineForOp forOp) {
136  if (isa<AffineForOp>(forOp.getBody()->front()))
137  return;
138  CyclicProblem problem = analysis.getProblem(forOp);
139  forOp.getBody()->walk([&](Operation *op) {
140  for (auto dep : problem.getDependences(op)) {
141  assert(!dep.isInvalid());
142  if (dep.isAuxiliary())
143  op->setAttr("dependence", UnitAttr::get(context));
144  }
145  });
146  });
147 }
148 
149 //===----------------------------------------------------------------------===//
150 // InstanceGraph
151 //===----------------------------------------------------------------------===//
152 
153 namespace {
154 struct InferTopModulePass
155  : public PassWrapper<InferTopModulePass, OperationPass<mlir::ModuleOp>> {
156  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(InferTopModulePass)
157 
158  void runOnOperation() override;
159  StringRef getArgument() const override { return "test-infer-top-level"; }
160  StringRef getDescription() const override {
161  return "Perform top level module inference and emit results as attributes "
162  "on the enclosing module.";
163  }
164 };
165 } // namespace
166 
167 void InferTopModulePass::runOnOperation() {
168  circt::hw::InstanceGraph &analysis = getAnalysis<circt::hw::InstanceGraph>();
169  auto res = analysis.getInferredTopLevelNodes();
170  if (failed(res)) {
171  signalPassFailure();
172  return;
173  }
174 
175  llvm::SmallVector<Attribute, 4> attrs;
176  for (auto *node : *res)
177  attrs.push_back(node->getModule().getModuleNameAttr());
178 
179  analysis.getParent()->setAttr("test.top",
180  ArrayAttr::get(&getContext(), attrs));
181 }
182 
183 //===----------------------------------------------------------------------===//
184 // FIRRTL Instance Info
185 //===----------------------------------------------------------------------===//
186 
187 namespace {
188 struct FIRRTLInstanceInfoPass
189  : public PassWrapper<FIRRTLInstanceInfoPass,
190  OperationPass<firrtl::CircuitOp>> {
191  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(FIRRTLInstanceInfoPass)
192 
193  void runOnOperation() override;
194  StringRef getArgument() const override { return "test-firrtl-instance-info"; }
195  StringRef getDescription() const override {
196  return "Run firrtl::InstanceInfo analysis and show the results. This pass "
197  "is intended to be used for testing purposes only.";
198  }
199 };
200 } // namespace
201 
202 static llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const bool a) {
203  if (a)
204  return os << "true";
205  return os << "false";
206 }
207 
208 static void printCircuitInfo(firrtl::CircuitOp op,
209  firrtl::InstanceInfo &iInfo) {
210  OpPrintingFlags flags;
211  flags.skipRegions();
212  llvm::errs() << " - operation: ";
213  op->print(llvm::errs(), flags);
214  llvm::errs() << "\n"
215  << " hasDut: " << iInfo.hasDut() << "\n"
216  << " dut: ";
217  if (auto dutNode = iInfo.getDut())
218  dutNode->print(llvm::errs(), flags);
219  else
220  llvm::errs() << "null";
221  llvm::errs() << "\n"
222  << " effectiveDut: ";
223  iInfo.getEffectiveDut()->print(llvm::errs(), flags);
224  llvm::errs() << "\n";
225 }
226 
227 static void printModuleInfo(igraph::ModuleOpInterface op,
228  firrtl::InstanceInfo &iInfo) {
229  OpPrintingFlags flags;
230  flags.skipRegions();
231  llvm::errs() << " - operation: ";
232  op->print(llvm::errs(), flags);
233  llvm::errs() << "\n"
234  << " isDut: " << iInfo.isDut(op) << "\n"
235  << " anyInstanceUnderDut: " << iInfo.anyInstanceUnderDut(op)
236  << "\n"
237  << " allInstancesUnderDut: " << iInfo.allInstancesUnderDut(op)
238  << "\n"
239  << " anyInstanceUnderEffectiveDut: "
240  << iInfo.anyInstanceUnderEffectiveDut(op) << "\n"
241  << " allInstancesUnderEffectiveDut: "
242  << iInfo.allInstancesUnderEffectiveDut(op) << "\n"
243  << " anyInstanceUnderLayer: "
244  << iInfo.anyInstanceUnderLayer(op) << "\n"
245  << " allInstancesUnderLayer: "
246  << iInfo.allInstancesUnderLayer(op) << "\n"
247  << " anyInstanceInDesign: " << iInfo.anyInstanceInDesign(op)
248  << "\n"
249  << " allInstancesInDesign: " << iInfo.allInstancesInDesign(op)
250  << "\n"
251  << " anyInstanceInEffectiveDesign: "
252  << iInfo.anyInstanceInEffectiveDesign(op) << "\n"
253  << " allInstancesInEffectiveDesign: "
254  << iInfo.allInstancesInEffectiveDesign(op) << "\n";
255 }
256 
257 void FIRRTLInstanceInfoPass::runOnOperation() {
258  auto &iInfo = getAnalysis<firrtl::InstanceInfo>();
259 
260  printCircuitInfo(getOperation(), iInfo);
261  for (auto op :
262  getOperation().getBodyBlock()->getOps<igraph::ModuleOpInterface>())
263  printModuleInfo(op, iInfo);
264 }
265 
266 //===----------------------------------------------------------------------===//
267 // Pass registration
268 //===----------------------------------------------------------------------===//
269 
270 namespace circt {
271 namespace test {
273  registerPass([]() -> std::unique_ptr<Pass> {
274  return std::make_unique<TestDependenceAnalysisPass>();
275  });
276  registerPass([]() -> std::unique_ptr<Pass> {
277  return std::make_unique<TestSchedulingAnalysisPass>();
278  });
279  registerPass([]() -> std::unique_ptr<Pass> {
280  return std::make_unique<TestDebugAnalysisPass>();
281  });
282  registerPass([]() -> std::unique_ptr<Pass> {
283  return std::make_unique<InferTopModulePass>();
284  });
285  registerPass([]() -> std::unique_ptr<Pass> {
286  return std::make_unique<FIRRTLInstanceInfoPass>();
287  });
288 }
289 } // namespace test
290 } // namespace circt
static Block * getBodyBlock(FModuleLike mod)
static void printModuleInfo(igraph::ModuleOpInterface op, firrtl::InstanceInfo &iInfo)
Definition: TestPasses.cpp:227
static void printCircuitInfo(firrtl::CircuitOp op, firrtl::InstanceInfo &iInfo)
Definition: TestPasses.cpp:208
static llvm::raw_ostream & operator<<(llvm::raw_ostream &os, const bool a)
Definition: TestPasses.cpp:202
bool allInstancesUnderLayer(igraph::ModuleOpInterface op)
Return true if all instances of this module are under (or transitively under) layer blocks.
igraph::ModuleOpInterface getDut()
Return the design-under-test if one is defined for the circuit, otherwise return null.
bool hasDut()
Return true if this circuit has a design-under-test.
bool allInstancesInEffectiveDesign(igraph::ModuleOpInterface op)
Return true if all instances of this module are within (or transitively withiin) the effective design...
bool isDut(igraph::ModuleOpInterface op)
Return true if this module is the design-under-test.
bool anyInstanceUnderDut(igraph::ModuleOpInterface op)
Return true if at least one instance of this module is under (or transitively under) the design-under...
bool anyInstanceUnderEffectiveDut(igraph::ModuleOpInterface op)
Return true if at least one instance is under (or transitively under) the effective design-under-test...
bool allInstancesUnderEffectiveDut(igraph::ModuleOpInterface op)
Return true if all instances are under (or transitively under) the effective design-under-test.
igraph::ModuleOpInterface getEffectiveDut()
Return the "effective" design-under-test.
bool allInstancesUnderDut(igraph::ModuleOpInterface op)
Return true if all instances of this module are under (or transitively under) the design-under-test.
bool anyInstanceInEffectiveDesign(igraph::ModuleOpInterface op)
Return true if any instance of this module is within (or transitively within) the effective design.
bool allInstancesInDesign(igraph::ModuleOpInterface op)
Return true if all instances of this module are within (or transitively withiin) the design.
bool anyInstanceUnderLayer(igraph::ModuleOpInterface op)
Return true if at least one instance of this module is under (or transitively under) a layer.
bool anyInstanceInDesign(igraph::ModuleOpInterface op)
Return true if any instance of this module is within (or transitively within) the design.
HW-specific instance graph with a virtual entry node linking to all publicly visible modules.
FailureOr< llvm::ArrayRef< InstanceGraphNode * > > getInferredTopLevelNodes()
Get the nodes corresponding to the inferred top-level modules of a circuit.
Operation * getParent()
Return the parent under which all nodes are nested.
This class models a cyclic scheduling problem.
Definition: Problems.h:286
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:55
void registerAnalysisTestPasses()
Definition: TestPasses.cpp:272
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
CyclicSchedulingAnalysis constructs a CyclicProblem for each AffineForOp by performing a memory depen...
scheduling::CyclicProblem & getProblem(mlir::affine::AffineForOp forOp)
MemoryDependenceAnalysis traverses any AffineForOps in the FuncOp body and checks for affine memory a...