13 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
14 #include "mlir/IR/Dominance.h"
15 #include "mlir/IR/PatternMatch.h"
16 #include "mlir/IR/Region.h"
17 #include "mlir/Pass/Pass.h"
18 #include "mlir/Support/LLVM.h"
19 #include "mlir/Transforms/RegionUtils.h"
20 #include "llvm/ADT/STLExtras.h"
25 #define GEN_PASS_DEF_TEMPORALCODEMOTION
26 #include "circt/Dialect/LLHD/Transforms/Passes.h.inc"
30 using namespace circt;
39 DenseMap<Block *, Value> &mem) {
40 Location loc = driveBlock->getTerminator()->getLoc();
41 if (mem.count(driveBlock))
42 return mem[driveBlock];
44 SmallVector<Block *> worklist;
45 worklist.push_back(driveBlock);
47 while (!worklist.empty()) {
48 Block *curr = worklist.back();
50 if (curr == dominator || curr->getPredecessors().empty()) {
58 bool addedSomething =
false;
59 for (
auto *predBlock : curr->getPredecessors()) {
60 if (!mem.count(predBlock)) {
61 worklist.push_back(predBlock);
62 addedSomething =
true;
70 for (
auto *predBlock : curr->getPredecessors()) {
71 if (predBlock->getTerminator()->getNumSuccessors() != 1) {
72 auto condBr = cast<cf::CondBranchOp>(predBlock->getTerminator());
73 Value cond = condBr.getCondition();
74 if (condBr.getFalseDest() == curr) {
78 Value next = builder.create<
comb::AndOp>(loc, mem[predBlock], cond);
79 runner = builder.create<
comb::OrOp>(loc, runner, next);
81 runner = builder.create<
comb::OrOp>(loc, runner, mem[predBlock]);
88 return mem[driveBlock];
94 Operation *moveBefore,
95 DenseMap<Block *, Value> &mem) {
96 OpBuilder builder(drvOp);
97 builder.setInsertionPoint(moveBefore);
98 Block *drvParentBlock = drvOp->getBlock();
103 builder, drvParentBlock, dominator, mem);
105 if (drvOp.getEnable())
106 finalValue = builder.create<
comb::AndOp>(drvOp.getLoc(), drvOp.getEnable(),
109 drvOp.getEnableMutable().assign(finalValue);
110 drvOp->moveBefore(moveBefore);
114 struct TemporalCodeMotionPass
115 :
public llhd::impl::TemporalCodeMotionBase<TemporalCodeMotionPass> {
116 void runOnOperation()
override;
117 LogicalResult runOnProcess(llhd::ProcessOp procOp);
121 void TemporalCodeMotionPass::runOnOperation() {
122 for (
auto proc : getOperation().getOps<llhd::ProcessOp>())
123 (void)runOnProcess(proc);
126 LogicalResult TemporalCodeMotionPass::runOnProcess(llhd::ProcessOp procOp) {
153 bool seenWait =
false;
154 WalkResult walkResult = procOp.walk([&](llhd::WaitOp op) -> WalkResult {
160 int trId = trAnalysis.
getBlockTR(op->getBlock());
165 return WalkResult::advance();
167 if (walkResult.wasInterrupted())
175 for (
unsigned currTR = 0; currTR < numTRs; ++currTR) {
179 assert((numTRSuccs == 1 ||
181 "only TRs with a single TR as possible successor are "
182 "supported for now.");
195 auxBlock->addArguments(
196 succTREntry->getArgumentTypes(),
197 SmallVector<Location>(succTREntry->getNumArguments(), procOp.getLoc()));
200 procOp.getBody().getBlocks().insertAfter(
206 for (
auto [i, succ] : llvm::enumerate(exit->getSuccessors()))
207 if (trAnalysis.
getBlockTR(succ) !=
static_cast<int>(currTR))
208 exit->getTerminator()->setSuccessor(auxBlock, i);
213 b.setInsertionPointToEnd(auxBlock);
214 b.create<cf::BranchOp>(procOp.getLoc(), succTREntry,
215 auxBlock->getArguments());
222 DenseMap<Operation *, Block *> drvPos;
227 OpBuilder builder(procOp);
229 for (
unsigned currTR = 0; currTR < numTRs; ++currTR) {
230 DenseMap<Block *, Value> mem;
238 DominanceInfo dom(procOp);
239 Block *dominator = exitingBlock;
243 procOp.walk([&](llhd::DrvOp op) {
244 if (trAnalysis.
getBlockTR(op.getOperation()->getBlock()) ==
245 static_cast<int>(currTR)) {
246 Block *parentBlock = op.getOperation()->getBlock();
247 drvPos[op] = parentBlock;
248 dominator = dom.findNearestCommonDominator(dominator, parentBlock);
253 Operation *moveBefore = exitingBlock->getTerminator();
254 exitingBlock->walk([&](llhd::DrvOp op) { moveBefore = op; });
257 "could not find nearest common dominator for TR exiting "
258 "block and the block containing drv");
262 if (trAnalysis.
getBlockTR(dominator) !=
static_cast<int>(currTR))
265 std::queue<Block *> workQueue;
266 SmallPtrSet<Block *, 32> workDone;
268 if (entryBlock != exitingBlock)
269 workQueue.push(entryBlock);
271 while (!workQueue.empty()) {
272 Block *block = workQueue.front();
274 workDone.insert(block);
276 builder.setInsertionPoint(moveBefore);
277 SmallVector<llhd::DrvOp> drives(block->getOps<llhd::DrvOp>());
278 for (
auto drive : drives)
281 for (Block *succ : block->getSuccessors()) {
282 if (succ == exitingBlock ||
283 trAnalysis.
getBlockTR(succ) !=
static_cast<int>(currTR))
286 if (llvm::all_of(succ->getPredecessors(), [&](Block *block) {
287 return workDone.contains(block);
289 workQueue.push(succ);
294 if (entryBlock != exitingBlock) {
295 entryBlock->getTerminator()->erase();
296 entryBlock->getOperations().splice(entryBlock->end(),
297 exitingBlock->getOperations());
301 IRRewriter rewriter(procOp);
302 (void)mlir::eraseUnreachableBlocks(rewriter, procOp->getRegions());
309 DominanceInfo dom(procOp);
310 for (
unsigned currTR = 0; currTR < numTRs; ++currTR) {
315 DenseMap<std::pair<Value, Value>, llhd::DrvOp> sigToDrv;
317 SmallVector<llhd::DrvOp> drives(exitingBlock->getOps<llhd::DrvOp>());
318 for (
auto op : drives) {
319 auto sigTimePair = std::make_pair(op.getSignal(), op.getTime());
320 if (!sigToDrv.count(sigTimePair)) {
321 sigToDrv[sigTimePair] = op;
325 OpBuilder builder(op);
326 if (op.getEnable()) {
328 auto firstDrive = sigToDrv[sigTimePair];
330 op.getLoc(), op.getEnable(), op.getValue(), firstDrive.getValue());
331 op.getValueMutable().assign(muxValue);
334 if (firstDrive.getEnable()) {
335 Value orVal = builder.create<
comb::OrOp>(op.getLoc(), op.getEnable(),
336 firstDrive.getEnable());
337 op.getEnableMutable().assign(orVal);
340 op.getEnableMutable().clear();
344 sigToDrv[sigTimePair]->erase();
345 sigToDrv[sigTimePair] = op;
352 std::unique_ptr<OperationPass<hw::HWModuleOp>>
354 return std::make_unique<TemporalCodeMotionPass>();
assert(baseType &&"element must be base type")
static void moveDriveOpBefore(llhd::DrvOp drvOp, Block *dominator, Operation *moveBefore, DenseMap< Block *, Value > &mem)
More a 'llhd.drv' operation before the 'moveBefore' operation by adjusting the 'enable' operand.
static Value getBranchDecisionsFromDominatorToTarget(OpBuilder &builder, Block *driveBlock, Block *dominator, DenseMap< Block *, Value > &mem)
Explore all paths from the 'driveBlock' to the 'dominator' block and construct a boolean expression a...
def create(data_type, value)
std::unique_ptr< OperationPass< hw::HWModuleOp > > createTemporalCodeMotionPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
int getBlockTR(Block *) const
unsigned getNumTemporalRegions() const
bool isOwnTRSuccessor(int tr)
bool hasSingleExitBlock(int tr) const
SmallVector< Block *, 8 > getExitingBlocksInTR(int) const
SmallVector< int, 8 > getTRSuccessors(int)
Block * getTREntryBlock(int)
unsigned getNumTRSuccessors(int tr)