CIRCT  19.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 
18 #include "mlir/Dialect/Affine/IR/AffineMemoryOpInterfaces.h"
19 #include "mlir/Dialect/Affine/IR/AffineOps.h"
20 #include "mlir/Dialect/Func/IR/FuncOps.h"
21 #include "mlir/IR/BuiltinOps.h"
22 #include "mlir/IR/Value.h"
23 #include "mlir/Pass/Pass.h"
24 #include "llvm/Support/Debug.h"
25 
26 using namespace mlir;
27 using namespace mlir::affine;
28 using namespace circt;
29 using namespace circt::analysis;
30 using namespace circt::scheduling;
31 
32 //===----------------------------------------------------------------------===//
33 // DebugAnalysis
34 //===----------------------------------------------------------------------===//
35 
36 namespace {
37 struct TestDebugAnalysisPass
38  : public PassWrapper<TestDebugAnalysisPass, OperationPass<mlir::ModuleOp>> {
39  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDebugAnalysisPass)
40 
41  void runOnOperation() override;
42  StringRef getArgument() const override { return "test-debug-analysis"; }
43  StringRef getDescription() const override {
44  return "Perform debug analysis and emit results as attributes";
45  }
46 };
47 } // namespace
48 
49 void TestDebugAnalysisPass::runOnOperation() {
50  auto *context = &getContext();
51  auto &analysis = getAnalysis<DebugAnalysis>();
52  for (auto *op : analysis.debugOps) {
53  op->setAttr("debug.only", UnitAttr::get(context));
54  }
55 }
56 
57 //===----------------------------------------------------------------------===//
58 // DependenceAnalysis
59 //===----------------------------------------------------------------------===//
60 
61 namespace {
62 struct TestDependenceAnalysisPass
63  : public PassWrapper<TestDependenceAnalysisPass,
64  OperationPass<func::FuncOp>> {
65  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDependenceAnalysisPass)
66 
67  void runOnOperation() override;
68  StringRef getArgument() const override { return "test-dependence-analysis"; }
69  StringRef getDescription() const override {
70  return "Perform dependence analysis and emit results as attributes";
71  }
72 };
73 } // namespace
74 
75 void TestDependenceAnalysisPass::runOnOperation() {
76  MLIRContext *context = &getContext();
77 
78  MemoryDependenceAnalysis analysis(getOperation());
79 
80  getOperation().walk([&](Operation *op) {
81  if (!isa<AffineReadOpInterface, AffineWriteOpInterface>(op))
82  return;
83 
84  SmallVector<Attribute> deps;
85 
86  for (auto dep : analysis.getDependences(op)) {
87  if (dep.dependenceType != DependenceResult::HasDependence)
88  continue;
89 
90  SmallVector<Attribute> comps;
91  for (auto comp : dep.dependenceComponents) {
92  SmallVector<Attribute> vector;
93  vector.push_back(
94  IntegerAttr::get(IntegerType::get(context, 64), *comp.lb));
95  vector.push_back(
96  IntegerAttr::get(IntegerType::get(context, 64), *comp.ub));
97  comps.push_back(ArrayAttr::get(context, vector));
98  }
99 
100  deps.push_back(ArrayAttr::get(context, comps));
101  }
102 
103  auto dependences = ArrayAttr::get(context, deps);
104  op->setAttr("dependences", dependences);
105  });
106 }
107 
108 //===----------------------------------------------------------------------===//
109 // SchedulingAnalysis
110 //===----------------------------------------------------------------------===//
111 
112 namespace {
113 struct TestSchedulingAnalysisPass
114  : public PassWrapper<TestSchedulingAnalysisPass,
115  OperationPass<func::FuncOp>> {
116  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestSchedulingAnalysisPass)
117 
118  void runOnOperation() override;
119  StringRef getArgument() const override { return "test-scheduling-analysis"; }
120  StringRef getDescription() const override {
121  return "Perform scheduling analysis and emit results as attributes";
122  }
123 };
124 } // namespace
125 
126 void TestSchedulingAnalysisPass::runOnOperation() {
127  MLIRContext *context = &getContext();
128 
129  CyclicSchedulingAnalysis analysis = getAnalysis<CyclicSchedulingAnalysis>();
130 
131  getOperation().walk([&](AffineForOp forOp) {
132  if (isa<AffineForOp>(forOp.getBody()->front()))
133  return;
134  CyclicProblem problem = analysis.getProblem(forOp);
135  forOp.getBody()->walk([&](Operation *op) {
136  for (auto dep : problem.getDependences(op)) {
137  assert(!dep.isInvalid());
138  if (dep.isAuxiliary())
139  op->setAttr("dependence", UnitAttr::get(context));
140  }
141  });
142  });
143 }
144 
145 //===----------------------------------------------------------------------===//
146 // InstanceGraph
147 //===----------------------------------------------------------------------===//
148 
149 namespace {
150 struct InferTopModulePass
151  : public PassWrapper<InferTopModulePass, OperationPass<mlir::ModuleOp>> {
152  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(InferTopModulePass)
153 
154  void runOnOperation() override;
155  StringRef getArgument() const override { return "test-infer-top-level"; }
156  StringRef getDescription() const override {
157  return "Perform top level module inference and emit results as attributes "
158  "on the enclosing module.";
159  }
160 };
161 } // namespace
162 
163 void InferTopModulePass::runOnOperation() {
164  circt::hw::InstanceGraph &analysis = getAnalysis<circt::hw::InstanceGraph>();
165  auto res = analysis.getInferredTopLevelNodes();
166  if (failed(res)) {
167  signalPassFailure();
168  return;
169  }
170 
171  llvm::SmallVector<Attribute, 4> attrs;
172  for (auto *node : *res)
173  attrs.push_back(node->getModule().getModuleNameAttr());
174 
175  analysis.getParent()->setAttr("test.top",
176  ArrayAttr::get(&getContext(), attrs));
177 }
178 
179 //===----------------------------------------------------------------------===//
180 // Pass registration
181 //===----------------------------------------------------------------------===//
182 
183 namespace circt {
184 namespace test {
186  registerPass([]() -> std::unique_ptr<Pass> {
187  return std::make_unique<TestDependenceAnalysisPass>();
188  });
189  registerPass([]() -> std::unique_ptr<Pass> {
190  return std::make_unique<TestSchedulingAnalysisPass>();
191  });
192  registerPass([]() -> std::unique_ptr<Pass> {
193  return std::make_unique<TestDebugAnalysisPass>();
194  });
195  registerPass([]() -> std::unique_ptr<Pass> {
196  return std::make_unique<InferTopModulePass>();
197  });
198 }
199 } // namespace test
200 } // namespace circt
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:292
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:54
void registerAnalysisTestPasses()
Definition: TestPasses.cpp:185
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...