17 #include "mlir/Dialect/Func/IR/FuncOps.h"
18 #include "mlir/Dialect/LLVMIR/FunctionCallUtils.h"
19 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
20 #include "mlir/Pass/Pass.h"
21 #include "mlir/Transforms/DialectConversion.h"
22 #include "llvm/ADT/PostOrderIterator.h"
23 #include "llvm/ADT/Twine.h"
27 using namespace circt;
29 using namespace igraph;
32 #define GEN_PASS_DEF_EXTERNALIZEREGISTERS
33 #include "circt/Tools/circt-bmc/Passes.h.inc"
41 struct ExternalizeRegistersPass
42 :
public circt::impl::ExternalizeRegistersBase<ExternalizeRegistersPass> {
43 using ExternalizeRegistersBase::ExternalizeRegistersBase;
44 void runOnOperation()
override;
48 void ExternalizeRegistersPass::runOnOperation() {
49 auto &instanceGraph = getAnalysis<hw::InstanceGraph>();
50 DenseSet<Operation *> handled;
51 DenseMap<StringAttr, SmallVector<Type>> addedInputs;
52 DenseMap<StringAttr, SmallVector<StringAttr>> addedInputNames;
53 DenseMap<StringAttr, SmallVector<Type>> addedOutputs;
54 DenseMap<StringAttr, SmallVector<StringAttr>> addedOutputNames;
55 DenseMap<StringAttr, SmallVector<Attribute>> initialValues;
59 for (
auto *startNode : instanceGraph) {
60 if (handled.count(startNode->getModule().getOperation()))
67 if (!handled.insert(node->getModule().getOperation()).second)
71 dyn_cast_or_null<HWModuleOp>(node->getModule().getOperation());
76 bool foundClk =
false;
77 for (
auto ty : module.getInputTypes()) {
78 if (isa<seq::ClockType>(ty)) {
80 module.emitError(
"modules with multiple clocks not yet supported");
81 return signalPassFailure();
86 module->walk([&](Operation *op) {
87 if (
auto regOp = dyn_cast<seq::CompRegOp>(op)) {
88 if (!isa<BlockArgument>(regOp.getClk())) {
89 regOp.emitError(
"only clocks directly given as block arguments "
91 return signalPassFailure();
93 if (regOp.getReset()) {
94 regOp.emitError(
"registers with reset signals not yet supported");
95 return signalPassFailure();
97 mlir::Attribute initState;
98 if (
auto initVal = regOp.getInitialValue()) {
102 regOp.getInitialValue().getDefiningOp<seq::InitialOp>();
104 regOp.emitError(
"registers with initial values not directly "
105 "defined by a seq.initial op not yet supported");
106 return signalPassFailure();
108 auto index = cast<OpResult>(initVal).getResultNumber();
110 initialOp->getRegion(0).front().getTerminator()->getOperand(
114 if (
auto constantOp = initValDef.getDefiningOp<
hw::ConstantOp>()) {
117 initState = constantOp.getValueAttr();
119 regOp.emitError(
"registers with initial values not directly "
120 "defined by a hw.constant op in a seq.initial op "
121 "not yet supported");
122 return signalPassFailure();
129 addedInputs[module.getSymNameAttr()].push_back(regOp.getType());
130 addedOutputs[module.getSymNameAttr()].push_back(
131 regOp.getInput().getType());
132 OpBuilder builder(regOp);
133 auto regName = regOp.getName();
134 StringAttr newInputName, newOutputName;
135 if (regName && !regName.value().empty()) {
136 newInputName = builder.getStringAttr(regName.value() +
"_state");
137 newOutputName = builder.getStringAttr(regName.value() +
"_input");
140 builder.getStringAttr(
"reg_" + Twine(numRegs) +
"_state");
142 builder.getStringAttr(
"reg_" + Twine(numRegs) +
"_input");
144 addedInputNames[module.getSymNameAttr()].push_back(newInputName);
145 addedOutputNames[module.getSymNameAttr()].push_back(newOutputName);
146 initialValues[module.getSymNameAttr()].push_back(initState);
148 regOp.getResult().replaceAllUsesWith(
149 module.appendInput(newInputName, regOp.getType()).second);
150 module.appendOutput(newOutputName, regOp.getInput());
155 if (
auto instanceOp = dyn_cast<InstanceOp>(op)) {
156 OpBuilder builder(instanceOp);
158 addedInputs[instanceOp.getModuleNameAttr().getAttr()];
160 addedInputNames[instanceOp.getModuleNameAttr().getAttr()];
162 addedOutputs[instanceOp.getModuleNameAttr().getAttr()];
163 auto newOutputNames =
164 addedOutputNames[instanceOp.getModuleNameAttr().getAttr()];
165 addedInputs[module.getSymNameAttr()].append(newInputs);
166 addedInputNames[module.getSymNameAttr()].append(newInputNames);
167 addedOutputs[module.getSymNameAttr()].append(newOutputs);
168 addedOutputNames[module.getSymNameAttr()].append(newOutputNames);
169 initialValues[module.getSymNameAttr()].append(
170 initialValues[instanceOp.getModuleNameAttr().getAttr()]);
171 SmallVector<Attribute> argNames(
172 instanceOp.getInputNames().getValue());
173 SmallVector<Attribute> resultNames(
174 instanceOp.getOutputNames().getValue());
176 for (
auto [input, name] : zip_equal(newInputs, newInputNames)) {
177 instanceOp.getInputsMutable().append(
178 module.appendInput(name, input).second);
179 argNames.push_back(name);
181 for (
auto outputName : newOutputNames) {
182 resultNames.push_back(outputName);
184 SmallVector<Type> resTypes(instanceOp->getResultTypes());
185 resTypes.append(newOutputs);
186 auto newInst = builder.create<InstanceOp>(
187 instanceOp.getLoc(), resTypes, instanceOp.getInstanceNameAttr(),
188 instanceOp.getModuleNameAttr(), instanceOp.getInputs(),
189 builder.getArrayAttr(argNames), builder.getArrayAttr(resultNames),
190 instanceOp.getParametersAttr(), instanceOp.getInnerSymAttr());
191 for (
auto [output, name] :
192 zip(newInst->getResults().take_back(newOutputs.size()),
194 module.appendOutput(name, output);
195 numRegs += newInputs.size();
196 instanceOp.replaceAllUsesWith(
197 newInst.getResults().take_front(instanceOp->getNumResults()));
198 instanceGraph.replaceInstance(instanceOp, newInst);
208 module->setAttr(
"initial_values",
210 initialValues[module.getSymNameAttr()]));
This is a Node in the InstanceGraph.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.