13 #include "../PassDetail.h"
18 #include "mlir/IR/BuiltinTypes.h"
19 #include "mlir/IR/OperationSupport.h"
20 #include "llvm/ADT/STLExtras.h"
22 using namespace circt;
23 using namespace calyx;
29 struct MaterializeCalyxToFSMPass
30 :
public MaterializeCalyxToFSMBase<MaterializeCalyxToFSMPass> {
31 void runOnOperation()
override;
36 void assignStateOutputOperands(OpBuilder &b, StateOp stateOp,
37 bool topLevelDone =
false) {
38 SmallVector<Value> outputOperands;
39 auto &enabledGroups = stateEnables[stateOp];
40 for (StringAttr group : referencedGroups)
41 outputOperands.push_back(
42 getOrCreateConstant(b, APInt(1, enabledGroups.contains(group))));
44 assert(outputOperands.size() == machineOp.getNumArguments() - 1 &&
45 "Expected exactly one value for each uniquely referenced group in "
47 outputOperands.push_back(getOrCreateConstant(b, APInt(1, topLevelDone)));
48 stateOp.ensureOutput(b);
49 auto outputOp = stateOp.getOutputOp();
50 outputOp->setOperands(outputOperands);
57 void assignStateTransitionGuard(OpBuilder &b, StateOp stateOp,
58 SmallVector<Value> doneGuards = {}) {
59 auto &enabledGroups = stateEnables[stateOp];
60 for (
auto groupIt : llvm::enumerate(referencedGroups))
61 if (enabledGroups.contains(groupIt.value()))
62 doneGuards.push_back(machineOp.getArgument(groupIt.index()));
64 for (
auto transition :
65 stateOp.getTransitions().getOps<fsm::TransitionOp>()) {
67 if (!transition.hasGuard() && doneGuards.empty())
69 transition.ensureGuard(b);
70 auto guardOp = transition.getGuardReturn();
71 llvm::SmallVector<Value> guards;
72 llvm::append_range(guards, doneGuards);
73 if (guardOp.getNumOperands() != 0)
74 guards.push_back(guardOp.getOperand());
79 b.setInsertionPoint(guardOp);
80 Value guardConjunction;
81 if (guards.size() == 1)
82 guardConjunction = guards.front();
85 b.create<comb::AndOp>(transition.getLoc(), guards,
false);
86 guardOp.setOperand(guardConjunction);
90 Value getOrCreateConstant(OpBuilder &b, APInt value) {
91 auto it = constants.find(value);
92 if (it != constants.end())
95 OpBuilder::InsertionGuard g(b);
96 b.setInsertionPointToStart(&machineOp.getBody().front());
97 auto constantOp = b.create<hw::ConstantOp>(machineOp.getLoc(), value);
98 constants[value] = constantOp;
106 SetVector<StringAttr> referencedGroups;
109 DenseMap<fsm::StateOp, DenseSet<StringAttr>> stateEnables;
115 DenseMap<APInt, Value> constants;
119 FSMStateNode *entryState;
120 FSMStateNode *exitState;
126 void materializeGroupIO();
131 void assignAttributes();
136 void MaterializeCalyxToFSMPass::walkMachine() {
139 for (
auto stateOp : machineOp.getOps<fsm::StateOp>()) {
140 for (
auto enableOp : llvm::make_early_inc_range(
141 stateOp.getOutput().getOps<calyx::EnableOp>())) {
142 auto groupName = enableOp.getGroupNameAttr().getAttr();
143 stateEnables[stateOp].insert(groupName);
144 referencedGroups.insert(groupName);
151 void MaterializeCalyxToFSMPass::materializeGroupIO() {
156 SmallVector<Type> ioTypes = SmallVector<Type>(
157 referencedGroups.size() + 1, b->getI1Type());
158 size_t nGroups = ioTypes.size() - 1;
159 machineOp.setType(b->getFunctionType(ioTypes, ioTypes));
160 assert(machineOp.getBody().getNumArguments() == 0 &&
161 "expected no inputs to the FSM");
162 machineOp.getBody().addArguments(
163 ioTypes, SmallVector<Location, 4>(ioTypes.size(), b->getUnknownLoc()));
168 for (
auto stateOp : machineOp.getOps<fsm::StateOp>()) {
169 assignStateOutputOperands(*b, stateOp,
171 assignStateTransitionGuard(*b, stateOp);
175 size_t topLevelGoIdx = nGroups;
176 assignStateTransitionGuard(*b, entryState->getState(),
177 {machineOp.getArgument(topLevelGoIdx)});
180 assignStateOutputOperands(*b, exitState->getState(),
184 void MaterializeCalyxToFSMPass::assignAttributes() {
187 llvm::SmallVector<NamedAttribute> groupDoneInputs;
188 for (
size_t i = 0; i < referencedGroups.size(); ++i)
189 groupDoneInputs.push_back({referencedGroups[i], b->getI64IntegerAttr(i)});
191 b->getDictionaryAttr(groupDoneInputs));
195 llvm::SmallVector<NamedAttribute> groupGoOutputs;
196 for (
size_t i = 0; i < referencedGroups.size(); ++i)
197 groupGoOutputs.push_back({referencedGroups[i], b->getI64IntegerAttr(i)});
199 b->getDictionaryAttr(groupGoOutputs));
203 b->getI64IntegerAttr(referencedGroups.size()));
205 b->getI64IntegerAttr(referencedGroups.size()));
208 void MaterializeCalyxToFSMPass::runOnOperation() {
209 ComponentOp component = getOperation();
210 auto *ctx = &getContext();
213 auto controlOp = component.getControlOp();
215 dyn_cast_or_null<fsm::MachineOp>(controlOp.getBodyBlock()->front());
217 controlOp.emitOpError()
218 <<
"expected an 'fsm.machine' operation as the top-level operation "
219 "within the control region of this component.";
225 auto graph = FSMGraph(machineOp);
229 if (!(entryState && exitState)) {
230 machineOp.emitOpError()
238 materializeGroupIO();
243 return std::make_unique<MaterializeCalyxToFSMPass>();
assert(baseType &&"element must be base type")
static constexpr std::string_view sGroupDoneInputs
static constexpr std::string_view sFSMTopLevelGoIndex
static constexpr std::string_view sExitStateName
static constexpr std::string_view sFSMTopLevelDoneIndex
static constexpr std::string_view sEntryStateName
static constexpr std::string_view sGroupGoOutputs
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
std::unique_ptr< mlir::Pass > createMaterializeCalyxToFSMPass()