22#include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h"
23#include "mlir/Analysis/DataFlow/IntegerRangeAnalysis.h"
24#include "mlir/Dialect/Affine/IR/AffineMemoryOpInterfaces.h"
25#include "mlir/Dialect/Affine/IR/AffineOps.h"
26#include "mlir/Dialect/Func/IR/FuncOps.h"
27#include "mlir/IR/BuiltinOps.h"
28#include "mlir/IR/Value.h"
29#include "mlir/Pass/Pass.h"
30#include "llvm/ADT/DepthFirstIterator.h"
31#include "llvm/Support/Debug.h"
35using namespace mlir::dataflow;
45struct TestDebugAnalysisPass
46 :
public PassWrapper<TestDebugAnalysisPass, OperationPass<mlir::ModuleOp>> {
47 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDebugAnalysisPass)
49 void runOnOperation()
override;
50 StringRef getArgument()
const override {
return "test-debug-analysis"; }
51 StringRef getDescription()
const override {
52 return "Perform debug analysis and emit results as attributes";
57void TestDebugAnalysisPass::runOnOperation() {
59 auto &analysis = getAnalysis<DebugAnalysis>();
60 for (
auto *op : analysis.debugOps) {
61 op->setAttr(
"debug.only", UnitAttr::get(
context));
70struct TestDependenceAnalysisPass
71 :
public PassWrapper<TestDependenceAnalysisPass,
72 OperationPass<func::FuncOp>> {
73 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestDependenceAnalysisPass)
75 void runOnOperation()
override;
76 StringRef getArgument()
const override {
return "test-dependence-analysis"; }
77 StringRef getDescription()
const override {
78 return "Perform dependence analysis and emit results as attributes";
83void TestDependenceAnalysisPass::runOnOperation() {
84 MLIRContext *
context = &getContext();
88 getOperation().walk([&](Operation *op) {
89 if (!isa<AffineReadOpInterface, AffineWriteOpInterface>(op))
92 SmallVector<Attribute> deps;
94 for (
auto dep : analysis.getDependences(op)) {
95 if (dep.dependenceType != DependenceResult::HasDependence)
98 SmallVector<Attribute> comps;
99 for (
auto comp : dep.dependenceComponents) {
100 SmallVector<Attribute> vector;
102 IntegerAttr::get(IntegerType::get(
context, 64), *comp.lb));
104 IntegerAttr::get(IntegerType::get(
context, 64), *comp.ub));
105 comps.push_back(ArrayAttr::get(
context, vector));
108 deps.push_back(ArrayAttr::get(
context, comps));
111 auto dependences = ArrayAttr::get(
context, deps);
112 op->setAttr(
"dependences", dependences);
121struct TestSchedulingAnalysisPass
122 :
public PassWrapper<TestSchedulingAnalysisPass,
123 OperationPass<func::FuncOp>> {
124 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestSchedulingAnalysisPass)
126 void runOnOperation()
override;
127 StringRef getArgument()
const override {
return "test-scheduling-analysis"; }
128 StringRef getDescription()
const override {
129 return "Perform scheduling analysis and emit results as attributes";
134void TestSchedulingAnalysisPass::runOnOperation() {
135 MLIRContext *
context = &getContext();
139 getOperation().walk([&](AffineForOp forOp) {
140 if (isa<AffineForOp>(forOp.getBody()->front()))
143 forOp.getBody()->walk([&](Operation *op) {
144 for (
auto dep : problem.getDependences(op)) {
146 if (dep.isAuxiliary())
147 op->setAttr(
"dependence", UnitAttr::get(
context));
158struct InferTopModulePass
159 :
public PassWrapper<InferTopModulePass, OperationPass<mlir::ModuleOp>> {
160 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(InferTopModulePass)
162 void runOnOperation()
override;
163 StringRef getArgument()
const override {
return "test-infer-top-level"; }
164 StringRef getDescription()
const override {
165 return "Perform top level module inference and emit results as attributes "
166 "on the enclosing module.";
171void InferTopModulePass::runOnOperation() {
179 llvm::SmallVector<Attribute, 4> attrs;
180 for (
auto *node : *res)
181 attrs.push_back(node->getModule().getModuleNameAttr());
183 analysis.
getParent()->setAttr(
"test.top",
184 ArrayAttr::get(&getContext(), attrs));
192struct FIRRTLInstanceInfoPass
193 :
public PassWrapper<FIRRTLInstanceInfoPass,
194 OperationPass<firrtl::CircuitOp>> {
195 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(FIRRTLInstanceInfoPass)
197 void runOnOperation()
override;
198 StringRef getArgument()
const override {
return "test-firrtl-instance-info"; }
199 StringRef getDescription()
const override {
200 return "Run firrtl::InstanceInfo analysis and show the results. This pass "
201 "is intended to be used for testing purposes only.";
206static llvm::raw_ostream &
operator<<(llvm::raw_ostream &os,
const bool a) {
209 return os <<
"false";
214 OpPrintingFlags flags;
216 llvm::errs() <<
" - operation: ";
217 op->print(llvm::errs(), flags);
219 <<
" hasDut: " << iInfo.
hasDut() <<
"\n"
221 if (
auto dutNode = iInfo.
getDut())
222 dutNode->print(llvm::errs(), flags);
224 llvm::errs() <<
"null";
226 <<
" effectiveDut: ";
228 llvm::errs() <<
"\n";
233 OpPrintingFlags flags;
235 llvm::errs() <<
" - operation: ";
236 op->print(llvm::errs(), flags);
239 <<
" isDut: " << iInfo.
isDut(op) <<
"\n"
242 <<
" anyInstanceUnderEffectiveDut: "
244 <<
" allInstancesUnderEffectiveDut: "
252 <<
" anyInstanceInEffectiveDesign: "
254 <<
" allInstancesInEffectiveDesign: "
256 <<
" anyInstanceInInstanceChoice: "
262void FIRRTLInstanceInfoPass::runOnOperation() {
263 auto &iInfo = getAnalysis<firrtl::InstanceInfo>();
267 getOperation().
getBodyBlock()->getOps<igraph::ModuleOpInterface>())
276struct FIRRTLGatedClockConversionPass
277 :
public PassWrapper<FIRRTLGatedClockConversionPass,
278 OperationPass<firrtl::CircuitOp>> {
279 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(FIRRTLGatedClockConversionPass)
281 void runOnOperation()
override;
282 StringRef getArgument()
const override {
283 return "test-firrtl-gated-clock-conversion";
285 StringRef getDescription()
const override {
286 return "Run firrtl::GatedClockConversion utility and show the results. "
287 "This pass is intended to be used for testing purposes only.";
292void FIRRTLGatedClockConversionPass::runOnOperation() {
293 auto circuit = getOperation();
294 auto &instanceGraph = getAnalysis<firrtl::InstanceGraph>();
298 circuit.walk([&](Operation *op) {
299 if (isa<firrtl::RegOp, firrtl::RegResetOp, firrtl::RefForceOp,
300 firrtl::RefReleaseOp>(op)) {
301 if (failed(converter.addRoot(op)))
302 return signalPassFailure();
307 if (failed(converter.run()))
308 return signalPassFailure();
316struct TestCombIntegerRangeAnalysisPass
317 :
public PassWrapper<TestCombIntegerRangeAnalysisPass,
318 OperationPass<mlir::ModuleOp>> {
319 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestCombIntegerRangeAnalysisPass)
321 void runOnOperation()
override;
322 StringRef getArgument()
const override {
323 return "test-comb-int-range-analysis";
325 StringRef getDescription()
const override {
326 return "Perform integer range analysis on comb dialect and set results as "
332void TestCombIntegerRangeAnalysisPass::runOnOperation() {
333 Operation *op = getOperation();
334 MLIRContext *ctx = op->getContext();
335 DataFlowSolver solver;
336 solver.load<DeadCodeAnalysis>();
337 solver.load<IntegerRangeAnalysis>();
338 if (failed(solver.initializeAndRun(op)))
339 return signalPassFailure();
342 op->walk([&](Operation *op) {
343 for (
auto value : op->getResults()) {
344 if (
auto *range = solver.lookupState<IntegerValueRangeLattice>(value)) {
346 assert(op->getResults().size() == 1 &&
347 "Expected a single result for the operation analysis");
348 assert(!range->getValue().isUninitialized() &&
349 "Expected a valid range for the value");
350 auto interval = range->getValue().getValue();
351 auto smax = interval.smax();
353 IntegerAttr::get(IntegerType::get(ctx, smax.getBitWidth()), smax);
354 op->setAttr(
"smax", smaxAttr);
355 auto smin = interval.smin();
357 IntegerAttr::get(IntegerType::get(ctx, smin.getBitWidth()), smin);
358 op->setAttr(
"smin", sminAttr);
359 auto umax = interval.umax();
360 auto umaxAttr = IntegerAttr::get(
361 IntegerType::get(ctx, umax.getBitWidth(), IntegerType::Unsigned),
363 op->setAttr(
"umax", umaxAttr);
364 auto umin = interval.umin();
365 auto uminAttr = IntegerAttr::get(
366 IntegerType::get(ctx, umin.getBitWidth(), IntegerType::Unsigned),
368 op->setAttr(
"umin", uminAttr);
381 registerPass([]() -> std::unique_ptr<Pass> {
382 return std::make_unique<TestDependenceAnalysisPass>();
384 registerPass([]() -> std::unique_ptr<Pass> {
385 return std::make_unique<TestSchedulingAnalysisPass>();
387 registerPass([]() -> std::unique_ptr<Pass> {
388 return std::make_unique<TestDebugAnalysisPass>();
390 registerPass([]() -> std::unique_ptr<Pass> {
391 return std::make_unique<InferTopModulePass>();
393 registerPass([]() -> std::unique_ptr<Pass> {
394 return std::make_unique<FIRRTLInstanceInfoPass>();
396 registerPass([]() -> std::unique_ptr<Pass> {
397 return std::make_unique<FIRRTLGatedClockConversionPass>();
399 registerPass([]() -> std::unique_ptr<Pass> {
400 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)
Sink gated-clock enables into ops across module boundaries.
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 moduleContainsProperties(igraph::ModuleOpInterface op)
Return true if this module contains (or its children transitively contain) any property operations,...
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 within) 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 within) 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...