16#include "mlir/IR/Operation.h"
17#include "mlir/IR/Threading.h"
18#include "mlir/Pass/AnalysisManager.h"
19#include "mlir/Pass/Pass.h"
20#include "mlir/Pass/PassManager.h"
21#include "llvm/ADT/SmallVector.h"
27#define GEN_PASS_DEF_HIERARCHICALRUNNER
28#include "circt/Transforms/Passes.h.inc"
32struct HierarchicalRunnerPass
33 :
public circt::impl::HierarchicalRunnerBase<HierarchicalRunnerPass> {
34 using circt::impl::HierarchicalRunnerBase<
35 HierarchicalRunnerPass>::HierarchicalRunnerBase;
36 void runOnOperation()
override;
37 HierarchicalRunnerPass(
const std::string &topName,
38 llvm::function_ref<
void(OpPassManager &)> populateFunc,
39 bool includeBoundInstances) {
40 this->topName = topName;
41 this->includeBoundInstances = includeBoundInstances;
44 populateFunc(dynamicPM);
45 llvm::raw_string_ostream os(pipelineStr);
46 dynamicPM.printAsTextualPipeline(os);
49 LogicalResult initializeOptions(
51 function_ref<LogicalResult(
const Twine &)> errorHandler)
override {
53 HierarchicalRunnerBase::initializeOptions(options, errorHandler)))
56 if (failed(parsePassPipeline(pipelineStr, dynamicPM)))
57 return errorHandler(
"Failed to parse composite pass pipeline");
62 void getDependentDialects(DialectRegistry ®istry)
const override {
63 dynamicPM.getDependentDialects(registry);
67 OpPassManager dynamicPM;
71void HierarchicalRunnerPass::runOnOperation() {
72 auto &instanceGraph = getAnalysis<circt::igraph::InstanceGraph>();
74 auto name = mlir::StringAttr::get(getOperation()->getContext(), topName);
75 auto *top = instanceGraph.lookupOrNull(name);
77 mlir::emitError(mlir::UnknownLoc::get(&getContext()))
78 <<
"top module not found in instance graph " << topName;
79 return signalPassFailure();
82 SmallVector<igraph::InstanceGraphNode *> worklist;
83 llvm::SetVector<Operation *> visited;
84 worklist.push_back(top);
86 auto am = getAnalysisManager();
87 while (!worklist.empty()) {
88 auto *node = worklist.pop_back_val();
89 assert(node &&
"node should not be null");
90 auto op = node->getModule();
91 if (!op || !visited.insert(op))
98 for (
auto *child : *node) {
99 auto childOp = child->getInstance();
101 (!includeBoundInstances && childOp->hasAttr(
"doNotPrint")))
104 worklist.push_back(child->getTarget());
113 size_t numThreads = getContext().getNumThreads();
115 llvm::SmallVector<OpPassManager> pipelines(numThreads, dynamicPM);
118 std::vector<std::atomic<bool>> activePMs(pipelines.size());
119 std::fill(activePMs.begin(), activePMs.end(),
false);
120 auto result = mlir::failableParallelForEach(
121 &getContext(), visited, [&](Operation *node) -> LogicalResult {
123 auto it = llvm::find_if(activePMs, [](std::atomic<bool> &isActive) {
124 bool expectedInactive =
false;
125 return isActive.compare_exchange_strong(expectedInactive,
true);
127 assert(it != activePMs.end() &&
128 "could not find inactive pass manager for thread");
129 unsigned pmIndex = it - activePMs.begin();
130 auto result = runPipeline(pipelines[pmIndex], node);
132 activePMs[pmIndex].store(
false);
136 return signalPassFailure();
140 const std::string &topName,
141 llvm::function_ref<
void(mlir::OpPassManager &)> pipeline,
142 bool includeBoundInstances) {
143 return std::make_unique<HierarchicalRunnerPass>(topName, pipeline,
144 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)