19#include "mlir/Dialect/SCF/IR/SCF.h"
20#include "mlir/Pass/Pass.h"
21#include "mlir/Transforms/RegionUtils.h"
22#include "llvm/ADT/MapVector.h"
23#include "llvm/ADT/SetVector.h"
27#define GEN_PASS_DEF_SQUASHSIMTRIGGERED
28#include "circt/Dialect/Sim/SimPasses.h.inc"
37static Block *getOrCreateConditionBlock(OpBuilder &builder, Location loc,
39 Value &prevConditionValue,
40 Block *&prevConditionBlock) {
41 if (condition != prevConditionValue)
42 prevConditionBlock =
nullptr;
44 if (prevConditionBlock)
45 return prevConditionBlock;
47 auto ifOp = mlir::scf::IfOp::create(builder, loc, TypeRange{}, condition,
49 builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
50 mlir::scf::YieldOp::create(builder, loc);
51 prevConditionValue = condition;
52 prevConditionBlock = builder.getBlock();
53 return prevConditionBlock;
56static void moveBodyOperations(Block *source, Block *dest,
57 Block::iterator insertPt) {
58 dest->getOperations().splice(insertPt, source->getOperations(),
59 source->begin(), source->end());
62static void finalizeHWTriggered(hw::TriggeredOp op) {
63 mlir::IRRewriter builder(op->getContext());
64 auto captures = mlir::makeRegionIsolatedFromAbove(builder, op.getBody());
65 op.getInputsMutable().append(captures);
68struct SquashSimTriggeredPass
69 : impl::SquashSimTriggeredBase<SquashSimTriggeredPass> {
71 using SquashSimTriggeredBase::SquashSimTriggeredBase;
72 void runOnOperation()
override;
75 bool squashTriggeredOpsInBlock(Block &block);
80bool SquashSimTriggeredPass::squashTriggeredOpsInBlock(Block &block) {
82 SmallMapVector<Value, SmallVector<TriggeredOp>, 2> triggerMap;
83 for (Operation &op : block)
84 if (
auto triggered = dyn_cast<TriggeredOp>(op))
85 triggerMap[triggered.getClock()].push_back(triggered);
88 for (
auto &[clock, triggers] : triggerMap) {
89 if (triggers.size() < 2 && !convertToHW)
92 SmallVector<Location> locs;
93 locs.reserve(triggers.size());
95 bool hasUnconditionalTrigger =
false;
96 Value commonCondition;
97 bool allConditionsIdentical =
true;
98 for (
auto triggered : triggers) {
99 locs.push_back(triggered.getLoc());
100 if (
auto condition = triggered.getCondition()) {
101 if (!commonCondition)
102 commonCondition = condition;
103 else if (condition != commonCondition)
104 allConditionsIdentical =
false;
106 hasUnconditionalTrigger =
true;
112 Value outerCondition;
113 if (!convertToHW && !hasUnconditionalTrigger && allConditionsIdentical)
114 outerCondition = commonCondition;
116 OpBuilder builder(triggers.back());
117 auto fusedLoc = builder.getFusedLoc(locs);
119 Block *mergedBlock =
nullptr;
120 hw::TriggeredOp hwTriggered;
121 TriggeredOp mergedTriggered;
123 auto event = hw::EventControlAttr::get(builder.getContext(),
124 hw::EventControl::AtPosEdge);
125 auto trigger = builder.createOrFold<seq::FromClockOp>(fusedLoc, clock);
126 hwTriggered = hw::TriggeredOp::create(builder, fusedLoc, event, trigger,
128 mergedBlock = hwTriggered.getBodyBlock();
131 TriggeredOp::create(builder, fusedLoc, clock, outerCondition);
132 mergedBlock = mergedTriggered.getBodyBlock();
135 Value prevConditionValue;
136 Block *prevConditionBlock =
nullptr;
137 for (
auto triggered : triggers) {
138 auto condition = triggered.getCondition();
139 auto *sourceBlock = triggered.getBodyBlock();
142 if (!sourceBlock->empty() && condition && condition != outerCondition) {
143 builder.setInsertionPointToEnd(mergedBlock);
145 getOrCreateConditionBlock(builder, triggered.getLoc(), condition,
146 prevConditionValue, prevConditionBlock);
147 moveBodyOperations(sourceBlock, condBlock,
148 Block::iterator(condBlock->getTerminator()));
150 prevConditionValue = Value();
151 prevConditionBlock =
nullptr;
152 moveBodyOperations(sourceBlock, mergedBlock, mergedBlock->end());
158 finalizeHWTriggered(hwTriggered);
165void SquashSimTriggeredPass::runOnOperation() {
166 hw::HWModuleOp module = getOperation();
167 bool changed = squashTriggeredOpsInBlock(*module.getBodyBlock());
169 markAllAnalysesPreserved();
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.