Loading [MathJax]/extensions/tex2jax.js
CIRCT 21.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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/Analysis/DataFlow/DeadCodeAnalysis.h"
22#include "mlir/Analysis/DataFlow/IntegerRangeAnalysis.h"
23#include "mlir/Dialect/Affine/IR/AffineMemoryOpInterfaces.h"
24#include "mlir/Dialect/Affine/IR/AffineOps.h"
25#include "mlir/Dialect/Func/IR/FuncOps.h"
26#include "mlir/IR/BuiltinOps.h"
27#include "mlir/IR/Value.h"
28#include "mlir/Pass/Pass.h"
29#include "llvm/ADT/DepthFirstIterator.h"
30#include "llvm/Support/Debug.h"
31
32using namespace mlir;
33using namespace mlir::affine;
34using namespace mlir::dataflow;
35using namespace circt;
36using namespace circt::analysis;
37using namespace circt::scheduling;
38
39//===----------------------------------------------------------------------===//
40// DebugAnalysis
41//===----------------------------------------------------------------------===//
42
43namespace {
44struct TestDebugAnalysisPass
45 : public PassWrapper<TestDebugAnalysisPass, OperationPass<mlir::ModuleOp>> {
46 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDebugAnalysisPass)
47
48 void runOnOperation() override;
49 StringRef getArgument() const override { return "test-debug-analysis"; }
50 StringRef getDescription() const override {
51 return "Perform debug analysis and emit results as attributes";
52 }
53};
54} // namespace
55
56void TestDebugAnalysisPass::runOnOperation() {
57 auto *context = &getContext();
58 auto &analysis = getAnalysis<DebugAnalysis>();
59 for (auto *op : analysis.debugOps) {
60 op->setAttr("debug.only", UnitAttr::get(context));
61 }
62}
63
64//===----------------------------------------------------------------------===//
65// DependenceAnalysis
66//===----------------------------------------------------------------------===//
67
68namespace {
69struct TestDependenceAnalysisPass
70 : public PassWrapper<TestDependenceAnalysisPass,
71 OperationPass<func::FuncOp>> {
72 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDependenceAnalysisPass)
73
74 void runOnOperation() override;
75 StringRef getArgument() const override { return "test-dependence-analysis"; }
76 StringRef getDescription() const override {
77 return "Perform dependence analysis and emit results as attributes";
78 }
79};
80} // namespace
81
82void TestDependenceAnalysisPass::runOnOperation() {
83 MLIRContext *context = &getContext();
84
85 MemoryDependenceAnalysis analysis(getOperation());
86
87 getOperation().walk([&](Operation *op) {
88 if (!isa<AffineReadOpInterface, AffineWriteOpInterface>(op))
89 return;
90
91 SmallVector<Attribute> deps;
92
93 for (auto dep : analysis.getDependences(op)) {
94 if (dep.dependenceType != DependenceResult::HasDependence)
95 continue;
96
97 SmallVector<Attribute> comps;
98 for (auto comp : dep.dependenceComponents) {
99 SmallVector<Attribute> vector;
100 vector.push_back(
101 IntegerAttr::get(IntegerType::get(context, 64), *comp.lb));
102 vector.push_back(
103 IntegerAttr::get(IntegerType::get(context, 64), *comp.ub));
104 comps.push_back(ArrayAttr::get(context, vector));
105 }
106
107 deps.push_back(ArrayAttr::get(context, comps));
108 }
109
110 auto dependences = ArrayAttr::get(context, deps);
111 op->setAttr("dependences", dependences);
112 });
113}
114
115//===----------------------------------------------------------------------===//
116// SchedulingAnalysis
117//===----------------------------------------------------------------------===//
118
119namespace {
120struct TestSchedulingAnalysisPass
121 : public PassWrapper<TestSchedulingAnalysisPass,
122 OperationPass<func::FuncOp>> {
123 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestSchedulingAnalysisPass)
124
125 void runOnOperation() override;
126 StringRef getArgument() const override { return "test-scheduling-analysis"; }
127 StringRef getDescription() const override {
128 return "Perform scheduling analysis and emit results as attributes";
129 }
130};
131} // namespace
132
133void TestSchedulingAnalysisPass::runOnOperation() {
134 MLIRContext *context = &getContext();
135
136 CyclicSchedulingAnalysis analysis = getAnalysis<CyclicSchedulingAnalysis>();
137
138 getOperation().walk([&](AffineForOp forOp) {
139 if (isa<AffineForOp>(forOp.getBody()->front()))
140 return;
141 CyclicProblem problem = analysis.getProblem(forOp);
142 forOp.getBody()->walk([&](Operation *op) {
143 for (auto dep : problem.getDependences(op)) {
144 assert(!dep.isInvalid());
145 if (dep.isAuxiliary())
146 op->setAttr("dependence", UnitAttr::get(context));
147 }
148 });
149 });
150}
151
152//===----------------------------------------------------------------------===//
153// InstanceGraph
154//===----------------------------------------------------------------------===//
155
156namespace {
157struct InferTopModulePass
158 : public PassWrapper<InferTopModulePass, OperationPass<mlir::ModuleOp>> {
159 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(InferTopModulePass)
160
161 void runOnOperation() override;
162 StringRef getArgument() const override { return "test-infer-top-level"; }
163 StringRef getDescription() const override {
164 return "Perform top level module inference and emit results as attributes "
165 "on the enclosing module.";
166 }
167};
168} // namespace
169
170void InferTopModulePass::runOnOperation() {
171 circt::hw::InstanceGraph &analysis = getAnalysis<circt::hw::InstanceGraph>();
172 auto res = analysis.getInferredTopLevelNodes();
173 if (failed(res)) {
174 signalPassFailure();
175 return;
176 }
177
178 llvm::SmallVector<Attribute, 4> attrs;
179 for (auto *node : *res)
180 attrs.push_back(node->getModule().getModuleNameAttr());
181
182 analysis.getParent()->setAttr("test.top",
183 ArrayAttr::get(&getContext(), attrs));
184}
185
186//===----------------------------------------------------------------------===//
187// FIRRTL Instance Info
188//===----------------------------------------------------------------------===//
189
190namespace {
191struct FIRRTLInstanceInfoPass
192 : public PassWrapper<FIRRTLInstanceInfoPass,
193 OperationPass<firrtl::CircuitOp>> {
194 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(FIRRTLInstanceInfoPass)
195
196 void runOnOperation() override;
197 StringRef getArgument() const override { return "test-firrtl-instance-info"; }
198 StringRef getDescription() const override {
199 return "Run firrtl::InstanceInfo analysis and show the results. This pass "
200 "is intended to be used for testing purposes only.";
201 }
202};
203} // namespace
204
205static llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const bool a) {
206 if (a)
207 return os << "true";
208 return os << "false";
209}
210
211static void printCircuitInfo(firrtl::CircuitOp op,
212 firrtl::InstanceInfo &iInfo) {
213 OpPrintingFlags flags;
214 flags.skipRegions();
215 llvm::errs() << " - operation: ";
216 op->print(llvm::errs(), flags);
217 llvm::errs() << "\n"
218 << " hasDut: " << iInfo.hasDut() << "\n"
219 << " dut: ";
220 if (auto dutNode = iInfo.getDut())
221 dutNode->print(llvm::errs(), flags);
222 else
223 llvm::errs() << "null";
224 llvm::errs() << "\n"
225 << " effectiveDut: ";
226 iInfo.getEffectiveDut()->print(llvm::errs(), flags);
227 llvm::errs() << "\n";
228}
229
230static void printModuleInfo(igraph::ModuleOpInterface op,
231 firrtl::InstanceInfo &iInfo) {
232 OpPrintingFlags flags;
233 flags.skipRegions();
234 llvm::errs() << " - operation: ";
235 op->print(llvm::errs(), flags);
236 llvm::errs() << "\n"
237 << " isDut: " << iInfo.isDut(op) << "\n"
238 << " anyInstanceUnderDut: " << iInfo.anyInstanceUnderDut(op)
239 << "\n"
240 << " allInstancesUnderDut: " << iInfo.allInstancesUnderDut(op)
241 << "\n"
242 << " anyInstanceUnderEffectiveDut: "
243 << iInfo.anyInstanceUnderEffectiveDut(op) << "\n"
244 << " allInstancesUnderEffectiveDut: "
245 << iInfo.allInstancesUnderEffectiveDut(op) << "\n"
246 << " anyInstanceUnderLayer: "
247 << iInfo.anyInstanceUnderLayer(op) << "\n"
248 << " allInstancesUnderLayer: "
249 << iInfo.allInstancesUnderLayer(op) << "\n"
250 << " anyInstanceInDesign: " << iInfo.anyInstanceInDesign(op)
251 << "\n"
252 << " allInstancesInDesign: " << iInfo.allInstancesInDesign(op)
253 << "\n"
254 << " anyInstanceInEffectiveDesign: "
255 << iInfo.anyInstanceInEffectiveDesign(op) << "\n"
256 << " allInstancesInEffectiveDesign: "
257 << iInfo.allInstancesInEffectiveDesign(op) << "\n";
258}
259
260void FIRRTLInstanceInfoPass::runOnOperation() {
261 auto &iInfo = getAnalysis<firrtl::InstanceInfo>();
262
263 printCircuitInfo(getOperation(), iInfo);
264 for (auto op :
265 getOperation().getBodyBlock()->getOps<igraph::ModuleOpInterface>())
266 printModuleInfo(op, iInfo);
267}
268
269//===----------------------------------------------------------------------===//
270// Comb IntRange Analysis
271//===----------------------------------------------------------------------===//
272
273namespace {
274struct TestCombIntegerRangeAnalysisPass
275 : public PassWrapper<TestCombIntegerRangeAnalysisPass,
276 OperationPass<mlir::ModuleOp>> {
277 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestCombIntegerRangeAnalysisPass)
278
279 void runOnOperation() override;
280 StringRef getArgument() const override {
281 return "test-comb-int-range-analysis";
282 }
283 StringRef getDescription() const override {
284 return "Perform integer range analysis on comb dialect and set results as "
285 "attributes.";
286 }
287};
288} // namespace
289
290void TestCombIntegerRangeAnalysisPass::runOnOperation() {
291 Operation *op = getOperation();
292 MLIRContext *ctx = op->getContext();
293 DataFlowSolver solver;
294 solver.load<DeadCodeAnalysis>();
295 solver.load<IntegerRangeAnalysis>();
296 if (failed(solver.initializeAndRun(op)))
297 return signalPassFailure();
298
299 // Append the integer range analysis as an operation attribute.
300 op->walk([&](Operation *op) {
301 for (auto value : op->getResults()) {
302 if (auto *range = solver.lookupState<IntegerValueRangeLattice>(value)) {
303 // All analyzed comb operations should return a single result.
304 assert(op->getResults().size() == 1 &&
305 "Expected a single result for the operation analysis");
306 assert(!range->getValue().isUninitialized() &&
307 "Expected a valid range for the value");
308 auto interval = range->getValue().getValue();
309 auto smax = interval.smax();
310 auto smaxAttr =
311 IntegerAttr::get(IntegerType::get(ctx, smax.getBitWidth()), smax);
312 op->setAttr("smax", smaxAttr);
313 auto smin = interval.smin();
314 auto sminAttr =
315 IntegerAttr::get(IntegerType::get(ctx, smin.getBitWidth()), smin);
316 op->setAttr("smin", sminAttr);
317 auto umax = interval.umax();
318 auto umaxAttr = IntegerAttr::get(
319 IntegerType::get(ctx, umax.getBitWidth(), IntegerType::Unsigned),
320 umax);
321 op->setAttr("umax", umaxAttr);
322 auto umin = interval.umin();
323 auto uminAttr = IntegerAttr::get(
324 IntegerType::get(ctx, umin.getBitWidth(), IntegerType::Unsigned),
325 umin);
326 op->setAttr("umin", uminAttr);
327 }
328 }
329 });
330}
331
332//===----------------------------------------------------------------------===//
333// Pass registration
334//===----------------------------------------------------------------------===//
335
336namespace circt {
337namespace test {
339 registerPass([]() -> std::unique_ptr<Pass> {
340 return std::make_unique<TestDependenceAnalysisPass>();
341 });
342 registerPass([]() -> std::unique_ptr<Pass> {
343 return std::make_unique<TestSchedulingAnalysisPass>();
344 });
345 registerPass([]() -> std::unique_ptr<Pass> {
346 return std::make_unique<TestDebugAnalysisPass>();
347 });
348 registerPass([]() -> std::unique_ptr<Pass> {
349 return std::make_unique<InferTopModulePass>();
350 });
351 registerPass([]() -> std::unique_ptr<Pass> {
352 return std::make_unique<FIRRTLInstanceInfoPass>();
353 });
354 registerPass([]() -> std::unique_ptr<Pass> {
355 return std::make_unique<TestCombIntegerRangeAnalysisPass>();
356 });
357}
358} // namespace test
359} // 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:359
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...