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