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() {
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";
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: "
258 <<
" anyInstanceInInstanceChoice: "
262void FIRRTLInstanceInfoPass::runOnOperation() {
263 auto &iInfo = getAnalysis<firrtl::InstanceInfo>();
267 getOperation().
getBodyBlock()->getOps<igraph::ModuleOpInterface>())
276struct TestCombIntegerRangeAnalysisPass
277 :
public PassWrapper<TestCombIntegerRangeAnalysisPass,
278 OperationPass<mlir::ModuleOp>> {
279 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestCombIntegerRangeAnalysisPass)
281 void runOnOperation()
override;
282 StringRef getArgument()
const override {
283 return "test-comb-int-range-analysis";
285 StringRef getDescription()
const override {
286 return "Perform integer range analysis on comb dialect and set results as "
292void TestCombIntegerRangeAnalysisPass::runOnOperation() {
293 Operation *op = getOperation();
294 MLIRContext *ctx = op->getContext();
295 DataFlowSolver solver;
296 solver.load<DeadCodeAnalysis>();
297 solver.load<IntegerRangeAnalysis>();
298 if (failed(solver.initializeAndRun(op)))
299 return signalPassFailure();
302 op->walk([&](Operation *op) {
303 for (
auto value : op->getResults()) {
304 if (
auto *range = solver.lookupState<IntegerValueRangeLattice>(value)) {
306 assert(op->getResults().size() == 1 &&
307 "Expected a single result for the operation analysis");
308 assert(!range->getValue().isUninitialized() &&
309 "Expected a valid range for the value");
310 auto interval = range->getValue().getValue();
311 auto smax = interval.smax();
313 IntegerAttr::get(IntegerType::get(ctx, smax.getBitWidth()), smax);
314 op->setAttr(
"smax", smaxAttr);
315 auto smin = interval.smin();
317 IntegerAttr::get(IntegerType::get(ctx, smin.getBitWidth()), smin);
318 op->setAttr(
"smin", sminAttr);
319 auto umax = interval.umax();
320 auto umaxAttr = IntegerAttr::get(
321 IntegerType::get(ctx, umax.getBitWidth(), IntegerType::Unsigned),
323 op->setAttr(
"umax", umaxAttr);
324 auto umin = interval.umin();
325 auto uminAttr = IntegerAttr::get(
326 IntegerType::get(ctx, umin.getBitWidth(), IntegerType::Unsigned),
328 op->setAttr(
"umin", uminAttr);
341 registerPass([]() -> std::unique_ptr<Pass> {
342 return std::make_unique<TestDependenceAnalysisPass>();
344 registerPass([]() -> std::unique_ptr<Pass> {
345 return std::make_unique<TestSchedulingAnalysisPass>();
347 registerPass([]() -> std::unique_ptr<Pass> {
348 return std::make_unique<TestDebugAnalysisPass>();
350 registerPass([]() -> std::unique_ptr<Pass> {
351 return std::make_unique<InferTopModulePass>();
353 registerPass([]() -> std::unique_ptr<Pass> {
354 return std::make_unique<FIRRTLInstanceInfoPass>();
356 registerPass([]() -> std::unique_ptr<Pass> {
357 return std::make_unique<TestCombIntegerRangeAnalysisPass>();
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
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 anyInstanceInInstanceChoice(igraph::ModuleOpInterface op)
Return true if any instance of this module is within (or transitively within) an instance choice.
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...