20 #include "mlir/IR/BuiltinTypes.h"
21 #include "mlir/IR/OperationSupport.h"
22 #include "mlir/Pass/Pass.h"
23 #include "llvm/ADT/STLExtras.h"
26 #define GEN_PASS_DEF_CALYXREMOVEGROUPSFROMFSM
27 #include "circt/Conversion/Passes.h.inc"
30 using namespace circt;
31 using namespace calyx;
37 struct CalyxRemoveGroupsFromFSM
38 :
public circt::impl::CalyxRemoveGroupsFromFSMBase<
39 CalyxRemoveGroupsFromFSM> {
40 void runOnOperation()
override;
46 LogicalResult outlineMachine();
64 ComponentOp componentOp;
70 DenseMap<StringAttr, Value> groupGoSignals;
74 DenseMap<StringAttr, calyx::WireLibOp> groupDoneWires;
80 auto loc = componentOp.getLoc();
81 for (
auto group : componentOp.getWiresOp().getOps<GroupOp>()) {
82 auto groupGo = group.getGoOp();
85 <<
"This pass does not need `calyx.group_go` operations.";
87 auto groupDone = group.getDoneOp();
89 return emitError(loc) <<
"Group " << group.getSymName()
90 <<
" does not have a `calyx.group_done` operation";
93 auto fsmGroupGo = groupGoSignals.find(group.getSymNameAttr());
94 assert(fsmGroupGo != groupGoSignals.end() &&
95 "Could not find FSM go signal for group");
101 auto doneWireIt = groupDoneWires.find(group.getSymNameAttr());
102 assert(doneWireIt != groupDoneWires.end() &&
103 "Could not find FSM done backedge for group");
104 auto doneWire = doneWireIt->second;
106 b->setInsertionPointToEnd(componentOp.getWiresOp().getBodyBlock());
107 b->create<calyx::AssignOp>(loc, doneWire.getIn(), groupDone.getSrc(),
108 groupDone.getGuard());
117 auto &wiresRegion = componentOp.getWiresOp().getRegion();
118 auto &wireBlocks = wiresRegion.getBlocks();
119 auto lastBlock = wiresRegion.end();
122 wiresRegion.walk([&](GroupOp group) {
123 wireBlocks.splice(lastBlock, group.getRegion().getBlocks());
128 auto firstBlock = wireBlocks.begin();
129 for (
auto it = firstBlock, e = lastBlock; it != e; ++it) {
130 if (it == firstBlock)
132 firstBlock->getOperations().splice(firstBlock->end(), it->getOperations());
136 while (&wiresRegion.front() != &wiresRegion.back())
137 wiresRegion.back().erase();
140 LogicalResult CalyxRemoveGroupsFromFSM::outlineMachine() {
144 llvm::MapVector<Value, SmallVector<Operation *>> referencedValues;
145 machineOp.walk([&](Operation *op) {
146 for (
auto &operand : op->getOpOperands()) {
147 if (auto barg = dyn_cast<BlockArgument>(operand.get())) {
148 if (barg.getOwner()->getParentOp() == machineOp)
152 referencedValues[operand.get()].push_back(op);
154 auto *defOp = operand.get().getDefiningOp();
155 auto machineOpParent = defOp->getParentOfType<MachineOp>();
156 if (machineOpParent && machineOpParent == machineOp)
159 referencedValues[operand.get()].push_back(op);
166 DenseMap<Value, size_t> ssaInputIndices;
167 auto machineOutputTypes = machineOp.getFunctionType().getResults();
168 auto currentInputs = machineOp.getFunctionType().getInputs();
169 llvm::SmallVector<Type> machineInputTypes(currentInputs);
171 for (
auto &[value, users] : referencedValues) {
172 ssaInputIndices[value] = machineOp.getBody().getNumArguments();
173 auto t = value.getType();
174 auto arg = machineOp.getBody().addArgument(t, b->getUnknownLoc());
175 machineInputTypes.push_back(t);
176 for (
auto *user : users) {
177 for (
auto &operand : user->getOpOperands()) {
178 if (operand.get() == value)
184 machineOp.setType(b->getFunctionType(machineInputTypes, machineOutputTypes));
187 machineOp->moveBefore(componentOp);
188 size_t nMachineInputs = machineOp.getBody().getNumArguments();
192 auto groupDoneInputsAttr =
194 auto groupGoOutputsAttr =
196 if (!groupDoneInputsAttr || !groupGoOutputsAttr)
197 return emitError(machineOp.getLoc())
200 <<
" attribute. Was --materialize-calyx-to-fsm run before "
203 b->setInsertionPointToStart(&componentOp.getBody().front());
207 DenseMap<size_t, Value> fsmInputMap;
210 for (
auto &namedAttr : groupDoneInputsAttr.getValue()) {
211 auto name = namedAttr.getName();
212 auto idx = cast<IntegerAttr>(namedAttr.getValue());
213 auto inputIdx = cast<IntegerAttr>(idx).getInt();
214 if (fsmInputMap.count(inputIdx))
215 return emitError(machineOp.getLoc())
216 <<
"MachineOp has duplicate input index " << idx;
219 b->setInsertionPointToStart(&componentOp.getBody().front());
220 auto groupDoneWire = b->create<calyx::WireLibOp>(
221 componentOp.getLoc(), name.str() +
"_done", b->getI1Type());
222 fsmInputMap[inputIdx] = groupDoneWire.getOut();
223 groupDoneWires[name] = groupDoneWire;
227 auto topLevelGoAttr =
230 return emitError(machineOp.getLoc())
233 fsmInputMap[topLevelGoAttr.getInt()] = componentOp.getGoPort();
235 auto topLevelDoneAttr =
237 if (!topLevelDoneAttr)
238 return emitError(machineOp.getLoc())
243 for (
auto [value, idx] : ssaInputIndices) {
244 if (fsmInputMap.count(idx))
245 return emitError(machineOp.getLoc())
246 <<
"MachineOp has duplicate input index " << idx;
247 fsmInputMap[idx] = value;
250 if (fsmInputMap.size() != nMachineInputs)
251 return emitError(machineOp.getLoc())
252 <<
"MachineOp has " << nMachineInputs
253 <<
" inputs, but only recorded " << fsmInputMap.size()
254 <<
" inputs. This either means that --materialize-calyx-to-fsm "
255 "failed or that there is a mismatch in the MachineOp attributes.";
258 llvm::SmallVector<Value> fsmInputs;
259 for (
size_t idx = 0; idx < nMachineInputs; ++idx) {
260 auto it = fsmInputMap.find(idx);
261 assert(it != fsmInputMap.end() &&
"Missing FSM input index");
262 fsmInputs.push_back(it->second);
266 auto clkPort = componentOp.getClkPort();
268 auto fsmInstance = b->create<fsm::HWInstanceOp>(
269 machineOp.getLoc(), machineOutputTypes, b->getStringAttr(
"controller"),
270 machineOp.getSymNameAttr(), fsmInputs,
clk, componentOp.getResetPort());
273 for (
auto namedAttr : groupGoOutputsAttr.getValue()) {
274 auto name = namedAttr.getName();
275 auto idx = cast<IntegerAttr>(namedAttr.getValue()).getInt();
276 groupGoSignals[name] = fsmInstance.getResult(idx);
280 b->setInsertionPointToEnd(componentOp.getWiresOp().getBodyBlock());
281 b->create<calyx::AssignOp>(machineOp.getLoc(), componentOp.getDonePort(),
282 fsmInstance.getResult(topLevelDoneAttr.getInt()));
287 void CalyxRemoveGroupsFromFSM::runOnOperation() {
288 componentOp = getOperation();
289 auto *ctx = componentOp.getContext();
290 auto builder = OpBuilder(ctx);
291 builder.setInsertionPointToStart(&componentOp.getBody().front());
294 bb = &backedgeBuilder;
297 auto machineOps = componentOp.getControlOp().getOps<
fsm::MachineOp>();
298 if (std::distance(machineOps.begin(), machineOps.end()) != 1) {
299 emitError(componentOp.getLoc())
300 <<
"Expected exactly one fsm.MachineOp in the control op";
304 machineOp = *machineOps.begin();
315 return std::make_unique<CalyxRemoveGroupsFromFSM>();
assert(baseType &&"element must be base type")
static void modifyGroupOperations(ComponentOp component)
Makes several modifications to the operations of a GroupOp:
void inlineGroups(ComponentOp component)
Inlines each group in the WiresOp.
Instantiate one of these and use it to build typed backedges.
static constexpr std::string_view sGroupDoneInputs
static constexpr std::string_view sFSMTopLevelGoIndex
static constexpr std::string_view sFSMTopLevelDoneIndex
static constexpr std::string_view sGroupGoOutputs
static constexpr std::string_view clkPort
static void updateGroupAssignmentGuards(OpBuilder &builder, GroupOp &group, Op &op)
Updates the guard of each assignment within a group with op.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::Pass > createRemoveGroupsFromFSMPass()