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"
34using namespace mlir::dataflow;
44struct TestDebugAnalysisPass
45 :
public PassWrapper<TestDebugAnalysisPass, OperationPass<mlir::ModuleOp>> {
46 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDebugAnalysisPass)
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";
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));
69struct TestDependenceAnalysisPass
70 :
public PassWrapper<TestDependenceAnalysisPass,
71 OperationPass<func::FuncOp>> {
72 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDependenceAnalysisPass)
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";
82void TestDependenceAnalysisPass::runOnOperation() {
83 MLIRContext *context = &getContext();
87 getOperation().walk([&](Operation *op) {
88 if (!isa<AffineReadOpInterface, AffineWriteOpInterface>(op))
91 SmallVector<Attribute> deps;
93 for (
auto dep : analysis.getDependences(op)) {
94 if (dep.dependenceType != DependenceResult::HasDependence)
97 SmallVector<Attribute> comps;
98 for (
auto comp : dep.dependenceComponents) {
99 SmallVector<Attribute> vector;
101 IntegerAttr::get(IntegerType::get(context, 64), *comp.lb));
103 IntegerAttr::get(IntegerType::get(context, 64), *comp.ub));
104 comps.push_back(ArrayAttr::get(context, vector));
107 deps.push_back(ArrayAttr::get(context, comps));
110 auto dependences = ArrayAttr::get(context, deps);
111 op->setAttr(
"dependences", dependences);
120struct TestSchedulingAnalysisPass
121 :
public PassWrapper<TestSchedulingAnalysisPass,
122 OperationPass<func::FuncOp>> {
123 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestSchedulingAnalysisPass)
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";
133void TestSchedulingAnalysisPass::runOnOperation() {
134 MLIRContext *context = &getContext();
138 getOperation().walk([&](AffineForOp forOp) {
139 if (isa<AffineForOp>(forOp.getBody()->front()))
142 forOp.getBody()->walk([&](Operation *op) {
143 for (
auto dep : problem.getDependences(op)) {
145 if (dep.isAuxiliary())
146 op->setAttr(
"dependence", UnitAttr::get(context));
157struct InferTopModulePass
158 :
public PassWrapper<InferTopModulePass, OperationPass<mlir::ModuleOp>> {
159 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(InferTopModulePass)
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.";
170void InferTopModulePass::runOnOperation() {
178 llvm::SmallVector<Attribute, 4> attrs;
179 for (
auto *node : *res)
180 attrs.push_back(node->getModule().getModuleNameAttr());
182 analysis.
getParent()->setAttr(
"test.top",
183 ArrayAttr::get(&getContext(), attrs));
191struct FIRRTLInstanceInfoPass
192 :
public PassWrapper<FIRRTLInstanceInfoPass,
193 OperationPass<firrtl::CircuitOp>> {
194 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(FIRRTLInstanceInfoPass)
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.";
205static llvm::raw_ostream &
operator<<(llvm::raw_ostream &os,
const bool a) {
208 return os <<
"false";
205static llvm::raw_ostream &
operator<<(llvm::raw_ostream &os,
const bool a) {
…}
213 OpPrintingFlags flags;
215 llvm::errs() <<
" - operation: ";
216 op->print(llvm::errs(), flags);
218 <<
" hasDut: " << iInfo.
hasDut() <<
"\n"
220 if (
auto dutNode = iInfo.
getDut())
221 dutNode->print(llvm::errs(), flags);
223 llvm::errs() <<
"null";
225 <<
" effectiveDut: ";
227 llvm::errs() <<
"\n";
232 OpPrintingFlags flags;
234 llvm::errs() <<
" - operation: ";
235 op->print(llvm::errs(), flags);
237 <<
" isDut: " << iInfo.
isDut(op) <<
"\n"
242 <<
" anyInstanceUnderEffectiveDut: "
244 <<
" allInstancesUnderEffectiveDut: "
246 <<
" anyInstanceUnderLayer: "
248 <<
" allInstancesUnderLayer: "
254 <<
" anyInstanceInEffectiveDesign: "
256 <<
" allInstancesInEffectiveDesign: "
260void FIRRTLInstanceInfoPass::runOnOperation() {
261 auto &iInfo = getAnalysis<firrtl::InstanceInfo>();
265 getOperation().
getBodyBlock()->getOps<igraph::ModuleOpInterface>())
274struct TestCombIntegerRangeAnalysisPass
275 :
public PassWrapper<TestCombIntegerRangeAnalysisPass,
276 OperationPass<mlir::ModuleOp>> {
277 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestCombIntegerRangeAnalysisPass)
279 void runOnOperation()
override;
280 StringRef getArgument()
const override {
281 return "test-comb-int-range-analysis";
283 StringRef getDescription()
const override {
284 return "Perform integer range analysis on comb dialect and set results as "
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();
300 op->walk([&](Operation *op) {
301 for (
auto value : op->getResults()) {
302 if (
auto *range = solver.lookupState<IntegerValueRangeLattice>(value)) {
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();
311 IntegerAttr::get(IntegerType::get(ctx, smax.getBitWidth()), smax);
312 op->setAttr(
"smax", smaxAttr);
313 auto smin = interval.smin();
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),
321 op->setAttr(
"umax", umaxAttr);
322 auto umin = interval.umin();
323 auto uminAttr = IntegerAttr::get(
324 IntegerType::get(ctx, umin.getBitWidth(), IntegerType::Unsigned),
326 op->setAttr(
"umin", uminAttr);
339 registerPass([]() -> std::unique_ptr<Pass> {
340 return std::make_unique<TestDependenceAnalysisPass>();
342 registerPass([]() -> std::unique_ptr<Pass> {
343 return std::make_unique<TestSchedulingAnalysisPass>();
345 registerPass([]() -> std::unique_ptr<Pass> {
346 return std::make_unique<TestDebugAnalysisPass>();
348 registerPass([]() -> std::unique_ptr<Pass> {
349 return std::make_unique<InferTopModulePass>();
351 registerPass([]() -> std::unique_ptr<Pass> {
352 return std::make_unique<FIRRTLInstanceInfoPass>();
354 registerPass([]() -> std::unique_ptr<Pass> {
355 return std::make_unique<TestCombIntegerRangeAnalysisPass>();
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.
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...