17#include "mlir/IR/Operation.h"
18#include "mlir/IR/Threading.h"
19#include "mlir/Pass/AnalysisManager.h"
20#include "mlir/Pass/Pass.h"
21#include "mlir/Pass/PassManager.h"
22#include "llvm/ADT/SmallVector.h"
28#define GEN_PASS_DEF_HIERARCHICALRUNNER
29#include "circt/Transforms/Passes.h.inc"
33struct HierarchicalRunnerPass
34 :
public circt::impl::HierarchicalRunnerBase<HierarchicalRunnerPass> {
35 using circt::impl::HierarchicalRunnerBase<
36 HierarchicalRunnerPass>::HierarchicalRunnerBase;
37 void runOnOperation()
override;
38 HierarchicalRunnerPass(
const std::string &topName,
39 llvm::function_ref<
void(OpPassManager &)> populateFunc,
40 bool includeBoundInstances) {
41 this->topName = topName;
42 this->includeBoundInstances = includeBoundInstances;
45 populateFunc(dynamicPM);
46 llvm::raw_string_ostream os(pipelineStr);
47 dynamicPM.printAsTextualPipeline(os);
50 LogicalResult initializeOptions(
52 function_ref<LogicalResult(
const Twine &)> errorHandler)
override {
54 HierarchicalRunnerBase::initializeOptions(options, errorHandler)))
57 if (failed(parsePassPipeline(pipelineStr, dynamicPM)))
58 return errorHandler(
"Failed to parse composite pass pipeline");
63 void getDependentDialects(DialectRegistry ®istry)
const override {
64 dynamicPM.getDependentDialects(registry);
68 OpPassManager dynamicPM;
72void HierarchicalRunnerPass::runOnOperation() {
73 auto &instanceGraph = getAnalysis<circt::igraph::InstanceGraph>();
75 auto name = mlir::StringAttr::get(getOperation()->getContext(), topName);
76 auto *top = instanceGraph.lookupOrNull(name);
78 mlir::emitError(mlir::UnknownLoc::get(&getContext()))
79 <<
"top module not found in instance graph " << topName;
80 return signalPassFailure();
83 SmallVector<igraph::InstanceGraphNode *> worklist;
84 llvm::SetVector<Operation *> visited;
85 worklist.push_back(top);
87 auto am = getAnalysisManager();
88 while (!worklist.empty()) {
89 auto *node = worklist.pop_back_val();
90 assert(node &&
"node should not be null");
91 auto op = node->getModule();
92 if (!isa_and_nonnull<hw::HWModuleOp>(op) || !visited.insert(op))
99 for (
auto *child : *node) {
100 auto childOp = child->getInstance();
102 (!includeBoundInstances && childOp->hasAttr(
"doNotPrint")))
105 worklist.push_back(child->getTarget());
114 size_t numThreads = getContext().getNumThreads();
116 llvm::SmallVector<OpPassManager> pipelines(numThreads, dynamicPM);
119 std::vector<std::atomic<bool>> activePMs(pipelines.size());
120 std::fill(activePMs.begin(), activePMs.end(),
false);
121 auto result = mlir::failableParallelForEach(
122 &getContext(), visited, [&](Operation *node) -> LogicalResult {
124 auto it = llvm::find_if(activePMs, [](std::atomic<bool> &isActive) {
125 bool expectedInactive =
false;
126 return isActive.compare_exchange_strong(expectedInactive,
true);
128 assert(it != activePMs.end() &&
129 "could not find inactive pass manager for thread");
130 unsigned pmIndex = it - activePMs.begin();
131 auto result = runPipeline(pipelines[pmIndex], node);
133 activePMs[pmIndex].store(
false);
137 return signalPassFailure();
141 const std::string &topName,
142 llvm::function_ref<
void(mlir::OpPassManager &)> pipeline,
143 bool includeBoundInstances) {
144 return std::make_unique<HierarchicalRunnerPass>(topName, pipeline,
145 includeBoundInstances);
assert(baseType &&"element must be base type")
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::Pass > createHierarchicalRunner(const std::string &topName, llvm::function_ref< void(mlir::OpPassManager &)> pipeline, bool includeBoundInstances=false)