17 #include "mlir/IR/BuiltinTypes.h"
18 #include "mlir/IR/OperationSupport.h"
19 #include "mlir/Pass/Pass.h"
20 #include "llvm/ADT/STLExtras.h"
23 #define GEN_PASS_DEF_MATERIALIZECALYXTOFSM
24 #include "circt/Conversion/Passes.h.inc"
27 using namespace circt;
28 using namespace calyx;
34 struct MaterializeCalyxToFSMPass
35 :
public circt::impl::MaterializeCalyxToFSMBase<MaterializeCalyxToFSMPass> {
36 void runOnOperation()
override;
41 void assignStateOutputOperands(OpBuilder &b,
StateOp stateOp,
42 bool topLevelDone =
false) {
43 SmallVector<Value> outputOperands;
44 auto &enabledGroups = stateEnables[stateOp];
45 for (StringAttr group : referencedGroups)
46 outputOperands.push_back(
47 getOrCreateConstant(b, APInt(1, enabledGroups.contains(group))));
49 assert(outputOperands.size() == machineOp.getNumArguments() - 1 &&
50 "Expected exactly one value for each uniquely referenced group in "
52 outputOperands.push_back(getOrCreateConstant(b, APInt(1, topLevelDone)));
53 stateOp.ensureOutput(b);
54 auto outputOp = stateOp.getOutputOp();
55 outputOp->setOperands(outputOperands);
62 void assignStateTransitionGuard(OpBuilder &b,
StateOp stateOp,
63 SmallVector<Value> doneGuards = {}) {
64 auto &enabledGroups = stateEnables[stateOp];
65 for (
auto groupIt : llvm::enumerate(referencedGroups))
66 if (enabledGroups.contains(groupIt.value()))
67 doneGuards.push_back(machineOp.getArgument(groupIt.index()));
69 for (
auto transition :
72 if (!transition.hasGuard() && doneGuards.empty())
74 transition.ensureGuard(b);
75 auto guardOp = transition.getGuardReturn();
76 llvm::SmallVector<Value> guards;
77 llvm::append_range(guards, doneGuards);
78 if (guardOp.getNumOperands() != 0)
79 guards.push_back(guardOp.getOperand());
84 b.setInsertionPoint(guardOp);
85 Value guardConjunction;
86 if (guards.size() == 1)
87 guardConjunction = guards.front();
90 b.create<
comb::AndOp>(transition.getLoc(), guards,
false);
91 guardOp.setOperand(guardConjunction);
95 Value getOrCreateConstant(OpBuilder &b, APInt value) {
96 auto it = constants.find(value);
97 if (it != constants.end())
100 OpBuilder::InsertionGuard g(b);
101 b.setInsertionPointToStart(&machineOp.getBody().front());
102 auto constantOp = b.create<
hw::ConstantOp>(machineOp.getLoc(), value);
103 constants[value] = constantOp;
111 SetVector<StringAttr> referencedGroups;
114 DenseMap<fsm::StateOp, DenseSet<StringAttr>> stateEnables;
120 DenseMap<APInt, Value> constants;
124 FSMStateNode *entryState;
125 FSMStateNode *exitState;
131 void materializeGroupIO();
136 void assignAttributes();
141 void MaterializeCalyxToFSMPass::walkMachine() {
145 for (
auto enableOp : llvm::make_early_inc_range(
146 stateOp.getOutput().getOps<calyx::EnableOp>())) {
147 auto groupName = enableOp.getGroupNameAttr().getAttr();
148 stateEnables[stateOp].insert(groupName);
149 referencedGroups.insert(groupName);
156 void MaterializeCalyxToFSMPass::materializeGroupIO() {
161 SmallVector<Type> ioTypes = SmallVector<Type>(
162 referencedGroups.size() + 1, b->getI1Type());
163 size_t nGroups = ioTypes.size() - 1;
164 machineOp.setType(b->getFunctionType(ioTypes, ioTypes));
165 assert(machineOp.getBody().getNumArguments() == 0 &&
166 "expected no inputs to the FSM");
167 machineOp.getBody().addArguments(
168 ioTypes, SmallVector<Location, 4>(ioTypes.size(), b->getUnknownLoc()));
174 assignStateOutputOperands(*b, stateOp,
176 assignStateTransitionGuard(*b, stateOp);
180 size_t topLevelGoIdx = nGroups;
181 assignStateTransitionGuard(*b, entryState->getState(),
182 {machineOp.getArgument(topLevelGoIdx)});
185 assignStateOutputOperands(*b, exitState->getState(),
189 void MaterializeCalyxToFSMPass::assignAttributes() {
192 llvm::SmallVector<NamedAttribute> groupDoneInputs;
193 for (
size_t i = 0; i < referencedGroups.size(); ++i)
194 groupDoneInputs.push_back({referencedGroups[i], b->getI64IntegerAttr(i)});
196 b->getDictionaryAttr(groupDoneInputs));
200 llvm::SmallVector<NamedAttribute> groupGoOutputs;
201 for (
size_t i = 0; i < referencedGroups.size(); ++i)
202 groupGoOutputs.push_back({referencedGroups[i], b->getI64IntegerAttr(i)});
204 b->getDictionaryAttr(groupGoOutputs));
208 b->getI64IntegerAttr(referencedGroups.size()));
210 b->getI64IntegerAttr(referencedGroups.size()));
213 void MaterializeCalyxToFSMPass::runOnOperation() {
214 ComponentOp component = getOperation();
215 auto *ctx = &getContext();
216 auto builder = OpBuilder(ctx);
218 auto controlOp = component.getControlOp();
220 dyn_cast_or_null<fsm::MachineOp>(controlOp.getBodyBlock()->front());
222 controlOp.emitOpError()
223 <<
"expected an 'fsm.machine' operation as the top-level operation "
224 "within the control region of this component.";
230 auto graph = FSMGraph(machineOp);
234 if (!(entryState && exitState)) {
235 machineOp.emitOpError()
243 materializeGroupIO();
248 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
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::Pass > createMaterializeCalyxToFSMPass()