CIRCT 20.0.0git
Loading...
Searching...
No Matches
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
30using namespace mlir;
31using namespace mlir::affine;
32using namespace circt;
33using namespace circt::analysis;
34using namespace circt::scheduling;
35
36//===----------------------------------------------------------------------===//
37// DebugAnalysis
38//===----------------------------------------------------------------------===//
39
40namespace {
41struct 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
53void 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
65namespace {
66struct 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
79void 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
116namespace {
117struct 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
130void 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
153namespace {
154struct 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
167void 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
187namespace {
188struct 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
202static llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const bool a) {
203 if (a)
204 return os << "true";
205 return os << "false";
206}
207
208static 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
227static 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
257void 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
270namespace circt {
271namespace 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
assert(baseType &&"element must be base type")
static Block * getBodyBlock(FModuleLike mod)
static void printModuleInfo(igraph::ModuleOpInterface op, firrtl::InstanceInfo &iInfo)
static void printCircuitInfo(firrtl::CircuitOp op, firrtl::InstanceInfo &iInfo)
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.
Operation * getParent()
Return the parent under which all nodes are nested.
FailureOr< llvm::ArrayRef< InstanceGraphNode * > > getInferredTopLevelNodes()
Get the nodes corresponding to the inferred top-level modules of a circuit.
This class models a cyclic scheduling problem.
Definition Problems.h:286
OS & operator<<(OS &os, const InnerSymTarget &target)
Printing InnerSymTarget's.
void registerAnalysisTestPasses()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
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...