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/LLHDPasses.h.inc"
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);
114struct TemporalCodeMotionPass
115 :
public llhd::impl::TemporalCodeMotionBase<TemporalCodeMotionPass> {
116 void runOnOperation()
override;
117 LogicalResult runOnProcess(llhd::ProcessOp procOp);
121void TemporalCodeMotionPass::runOnOperation() {
122 for (
auto proc : getOperation().getOps<llhd::ProcessOp>())
123 (void)runOnProcess(proc);
127 SmallVector<Block *> toCheck(
128 llvm::map_range(procOp.getOps<llhd::WaitOp>(), [](llhd::WaitOp waitOp) {
129 return waitOp.getSuccessor();
131 toCheck.push_back(&procOp.getBody().front());
133 SmallVector<Block *> worklist;
134 DenseSet<Block *> visited;
135 for (
auto *block : toCheck) {
138 worklist.push_back(block);
140 while (!worklist.empty()) {
141 Block *curr = worklist.pop_back_val();
142 if (isa<llhd::WaitOp>(curr->getTerminator()))
145 visited.insert(curr);
147 for (
auto *succ : curr->getSuccessors()) {
148 if (visited.contains(succ))
151 worklist.push_back(succ);
159LogicalResult TemporalCodeMotionPass::runOnProcess(llhd::ProcessOp procOp) {
192 bool seenWait =
false;
193 WalkResult walkResult = procOp.walk([&](llhd::WaitOp op) -> WalkResult {
199 int trId = trAnalysis.
getBlockTR(op->getBlock());
204 return WalkResult::advance();
206 if (walkResult.wasInterrupted())
214 for (
unsigned currTR = 0; currTR < numTRs; ++currTR) {
219 assert((numTRSuccs == 1 ||
221 "only TRs with a single TR as possible successor are "
222 "supported for now.");
235 auxBlock->addArguments(
236 succTREntry->getArgumentTypes(),
237 SmallVector<Location>(succTREntry->getNumArguments(), procOp.getLoc()));
240 procOp.getBody().getBlocks().insertAfter(
245 for (Block *exit : trAnalysis.getExitingBlocksInTR(currTR))
246 for (auto [i, succ] :
llvm::enumerate(exit->getSuccessors()))
247 if (trAnalysis.getBlockTR(succ) != static_cast<int>(currTR))
248 exit->getTerminator()->setSuccessor(auxBlock, i);
253 b.setInsertionPointToEnd(auxBlock);
254 b.create<cf::BranchOp>(procOp.getLoc(), succTREntry,
255 auxBlock->getArguments());
262 DenseMap<Operation *, Block *> drvPos;
267 OpBuilder builder(procOp);
269 for (
unsigned currTR = 0; currTR < numTRs; ++currTR) {
270 DenseMap<Block *, Value> mem;
278 DominanceInfo dom(procOp);
279 Block *dominator = exitingBlock;
283 procOp.walk([&](llhd::DrvOp op) {
284 if (trAnalysis.
getBlockTR(op.getOperation()->getBlock()) ==
285 static_cast<int>(currTR)) {
286 Block *parentBlock = op.getOperation()->getBlock();
287 drvPos[op] = parentBlock;
288 dominator = dom.findNearestCommonDominator(dominator, parentBlock);
293 Operation *moveBefore = exitingBlock->getTerminator();
294 exitingBlock->walk([&](llhd::DrvOp op) { moveBefore = op; });
297 "could not find nearest common dominator for TR exiting "
298 "block and the block containing drv");
302 if (trAnalysis.
getBlockTR(dominator) !=
static_cast<int>(currTR))
305 std::queue<Block *> workQueue;
306 SmallPtrSet<Block *, 32> workDone;
308 if (entryBlock != exitingBlock)
309 workQueue.push(entryBlock);
311 while (!workQueue.empty()) {
312 Block *block = workQueue.front();
314 workDone.insert(block);
316 builder.setInsertionPoint(moveBefore);
317 SmallVector<llhd::DrvOp> drives(block->getOps<llhd::DrvOp>());
318 for (
auto drive : drives)
321 for (Block *succ : block->getSuccessors()) {
322 if (succ == exitingBlock ||
323 trAnalysis.
getBlockTR(succ) !=
static_cast<int>(currTR))
326 if (llvm::all_of(succ->getPredecessors(), [&](Block *block) {
327 return workDone.contains(block);
329 workQueue.push(succ);
334 if (entryBlock != exitingBlock) {
335 entryBlock->getTerminator()->erase();
336 entryBlock->getOperations().splice(entryBlock->end(),
337 exitingBlock->getOperations());
341 IRRewriter rewriter(procOp);
342 (void)mlir::eraseUnreachableBlocks(rewriter, procOp->getRegions());
349 DominanceInfo dom(procOp);
350 for (
unsigned currTR = 0; currTR < numTRs; ++currTR) {
355 DenseMap<std::pair<Value, Value>, llhd::DrvOp> sigToDrv;
357 SmallVector<llhd::DrvOp> drives(exitingBlock->getOps<llhd::DrvOp>());
358 for (
auto op : drives) {
359 auto sigTimePair = std::make_pair(op.getSignal(), op.getTime());
360 if (!sigToDrv.count(sigTimePair)) {
361 sigToDrv[sigTimePair] = op;
365 OpBuilder builder(op);
366 if (op.getEnable()) {
368 auto firstDrive = sigToDrv[sigTimePair];
370 op.getLoc(), op.getEnable(), op.getValue(), firstDrive.getValue());
371 op.getValueMutable().assign(muxValue);
374 if (firstDrive.getEnable()) {
375 Value orVal = builder.create<
comb::OrOp>(op.getLoc(), op.getEnable(),
376 firstDrive.getEnable());
377 op.getEnableMutable().assign(orVal);
380 op.getEnableMutable().clear();
384 sigToDrv[sigTimePair]->erase();
385 sigToDrv[sigTimePair] = op;
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 LogicalResult checkForCFGLoop(llhd::ProcessOp procOp)
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...
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)