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"
38static Block *getOrCreateConditionBlock(OpBuilder &builder, Location loc,
40 Value &prevConditionValue,
41 Block *&prevConditionBlock) {
42 if (condition != prevConditionValue)
43 prevConditionBlock =
nullptr;
45 if (prevConditionBlock)
46 return prevConditionBlock;
48 auto ifOp = mlir::scf::IfOp::create(builder, loc, TypeRange{}, condition,
50 builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
51 mlir::scf::YieldOp::create(builder, loc);
52 prevConditionValue = condition;
53 prevConditionBlock = builder.getBlock();
54 return prevConditionBlock;
57static void moveBodyOperations(Block *source, Block *dest,
58 Block::iterator insertPt) {
59 dest->getOperations().splice(insertPt, source->getOperations(),
60 source->begin(), source->end());
63static void finalizeHWTriggered(hw::TriggeredOp op) {
64 mlir::IRRewriter builder(op->getContext());
65 auto captures = mlir::makeRegionIsolatedFromAbove(builder, op.getBody());
66 op.getInputsMutable().append(captures);
69struct SquashSimTriggeredPass
70 : impl::SquashSimTriggeredBase<SquashSimTriggeredPass> {
72 using SquashSimTriggeredBase::SquashSimTriggeredBase;
73 void runOnOperation()
override;
76 bool squashTriggeredOpsInBlock(Block &block);
81bool SquashSimTriggeredPass::squashTriggeredOpsInBlock(Block &block) {
84 for (Operation &op : block)
85 if (auto triggered = dyn_cast<TriggeredOp>(op))
86 triggerMap[triggered.getClock()].push_back(triggered);
89 for (
auto &[clock, triggers] : triggerMap) {
90 if (triggers.size() < 2 && !convertToHW)
93 SmallVector<Location> locs;
94 locs.reserve(triggers.size());
96 bool hasUnconditionalTrigger =
false;
97 Value commonCondition;
98 bool allConditionsIdentical =
true;
99 for (
auto triggered : triggers) {
100 locs.push_back(triggered.getLoc());
101 if (
auto condition = triggered.getCondition()) {
102 if (!commonCondition)
103 commonCondition = condition;
104 else if (condition != commonCondition)
105 allConditionsIdentical =
false;
107 hasUnconditionalTrigger =
true;
113 Value outerCondition;
114 if (!convertToHW && !hasUnconditionalTrigger && allConditionsIdentical)
115 outerCondition = commonCondition;
117 OpBuilder builder(triggers.back());
118 auto fusedLoc = builder.getFusedLoc(locs);
120 Block *mergedBlock =
nullptr;
121 hw::TriggeredOp hwTriggered;
122 TriggeredOp mergedTriggered;
124 auto event = hw::EventControlAttr::get(builder.getContext(),
125 hw::EventControl::AtPosEdge);
126 auto trigger = builder.createOrFold<seq::FromClockOp>(fusedLoc, clock);
127 hwTriggered = hw::TriggeredOp::create(builder, fusedLoc, event, trigger,
129 mergedBlock = hwTriggered.getBodyBlock();
132 TriggeredOp::create(builder, fusedLoc, clock, outerCondition);
133 mergedBlock = mergedTriggered.getBodyBlock();
136 Value prevConditionValue;
137 Block *prevConditionBlock =
nullptr;
138 for (
auto triggered : triggers) {
139 auto condition = triggered.getCondition();
140 auto *sourceBlock = triggered.getBodyBlock();
143 if (!sourceBlock->empty() && condition && condition != outerCondition) {
144 builder.setInsertionPointToEnd(mergedBlock);
146 getOrCreateConditionBlock(builder, triggered.getLoc(), condition,
147 prevConditionValue, prevConditionBlock);
148 moveBodyOperations(sourceBlock, condBlock,
149 Block::iterator(condBlock->getTerminator()));
151 prevConditionValue = Value();
152 prevConditionBlock =
nullptr;
153 moveBodyOperations(sourceBlock, mergedBlock, mergedBlock->end());
159 finalizeHWTriggered(hwTriggered);
166void SquashSimTriggeredPass::runOnOperation() {
168 bool changed = squashTriggeredOpsInBlock(*module.getBodyBlock());
170 markAllAnalysesPreserved();
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.