11#include "mlir/Analysis/Liveness.h"
12#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
13#include "llvm/Support/Debug.h"
15#define DEBUG_TYPE "llhd-hoist-signals"
19#define GEN_PASS_DEF_HOISTSIGNALSPASS
20#include "circt/Dialect/LLHD/Transforms/LLHDPasses.h.inc"
35 Hoister(Region ®ion) : region(region) {}
38 void findValuesLiveAcrossWait(Liveness &liveness);
46 DenseSet<Value> liveAcrossWait;
49 DenseMap<Value, PrbOp> hoistedProbes;
53void Hoister::hoist() {
54 Liveness liveness(region.getParentOp());
55 findValuesLiveAcrossWait(liveness);
70void Hoister::findValuesLiveAcrossWait(Liveness &liveness) {
73 SmallVector<Value> worklist;
74 for (
auto &block : region)
75 if (isa<WaitOp>(block.getTerminator()))
76 for (auto value : liveness.getLiveOut(&block))
77 if (value.getParentRegion() == ®ion)
78 if (liveAcrossWait.insert(value).second)
79 worklist.push_back(value);
85 while (!worklist.empty()) {
86 auto value = worklist.pop_back_val();
87 if (
auto *defOp = value.getDefiningOp()) {
88 for (
auto operand : defOp->getOperands())
89 if (operand.getParentRegion() == ®ion)
90 if (liveAcrossWait.insert(operand).second)
91 worklist.push_back(operand);
93 auto blockArg = cast<BlockArgument>(value);
94 for (
auto &use : blockArg.getOwner()->getUses()) {
95 auto branch = dyn_cast<BranchOpInterface>(use.getOwner());
98 auto operand = branch.getSuccessorOperands(
99 use.getOperandNumber())[blockArg.getArgNumber()];
100 if (operand.getParentRegion() == ®ion)
101 if (liveAcrossWait.insert(operand).second)
102 worklist.push_back(operand);
107 LLVM_DEBUG(llvm::dbgs() << liveAcrossWait.size()
108 <<
" values live across wait\n");
116void Hoister::hoistProbes() {
117 for (
auto &block : region) {
120 if (!llvm::all_of(block.getPredecessors(), [](
auto *predecessor) {
121 return isa<WaitOp>(predecessor->getTerminator());
125 for (
auto &op :
llvm::make_early_inc_range(block)) {
126 auto probeOp = dyn_cast<PrbOp>(op);
132 if (isMemoryEffectFree(&op))
139 if (liveAcrossWait.contains(probeOp)) {
140 LLVM_DEBUG(llvm::dbgs()
141 <<
"- Skipping (live across wait) " << probeOp <<
"\n");
147 if (!probeOp.getSignal().getParentRegion()->isProperAncestor(®ion)) {
148 LLVM_DEBUG(llvm::dbgs()
149 <<
"- Skipping (local signal) " << probeOp <<
"\n");
155 auto &hoistedOp = hoistedProbes[probeOp.getSignal()];
157 LLVM_DEBUG(llvm::dbgs() <<
"- Replacing " << probeOp <<
"\n");
158 probeOp.replaceAllUsesWith(hoistedOp.getResult());
161 LLVM_DEBUG(llvm::dbgs() <<
"- Hoisting " << probeOp <<
"\n");
162 probeOp->moveBefore(region.getParentOp());
174struct HoistSignalsPass
175 :
public llhd::impl::HoistSignalsPassBase<HoistSignalsPass> {
176 void runOnOperation()
override;
180void HoistSignalsPass::runOnOperation() {
181 SmallVector<Region *> regions;
182 getOperation()->walk<WalkOrder::PreOrder>([&](Operation *op) {
183 if (isa<ProcessOp, FinalOp>(op)) {
184 auto ®ion = op->getRegion(0);
186 regions.push_back(®ion);
187 return WalkResult::skip();
189 return WalkResult::advance();
191 for (
auto *region : regions)
192 Hoister(*region).hoist();
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.