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"
29using namespace igraph;
32#define GEN_PASS_DEF_EXTERNALIZEREGISTERS
33#include "circt/Tools/circt-bmc/Passes.h.inc"
41struct ExternalizeRegistersPass
42 :
public circt::impl::ExternalizeRegistersBase<ExternalizeRegistersPass> {
43 using ExternalizeRegistersBase::ExternalizeRegistersBase;
44 void runOnOperation()
override;
48void 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()) {
101 if (!initVal.getDefiningOp<seq::InitialOp>()) {
102 regOp.emitError(
"registers with initial values not directly "
103 "defined by a seq.initial op not yet supported");
104 return signalPassFailure();
107 .getDefiningOp<hw::ConstantOp>()) {
110 initState = constantOp.getValueAttr();
112 regOp.emitError(
"registers with initial values not directly "
113 "defined by a hw.constant op in a seq.initial op "
114 "not yet supported");
115 return signalPassFailure();
120 initState = mlir::UnitAttr::get(&getContext());
122 addedInputs[
module.getSymNameAttr()].push_back(regOp.getType());
123 addedOutputs[
module.getSymNameAttr()].push_back(
124 regOp.getInput().getType());
125 OpBuilder builder(regOp);
126 auto regName = regOp.getName();
127 StringAttr newInputName, newOutputName;
128 if (regName && !regName.value().empty()) {
129 newInputName = builder.getStringAttr(regName.value() +
"_state");
130 newOutputName = builder.getStringAttr(regName.value() +
"_input");
133 builder.getStringAttr(
"reg_" + Twine(numRegs) +
"_state");
135 builder.getStringAttr(
"reg_" + Twine(numRegs) +
"_input");
137 addedInputNames[
module.getSymNameAttr()].push_back(newInputName);
138 addedOutputNames[
module.getSymNameAttr()].push_back(newOutputName);
139 initialValues[
module.getSymNameAttr()].push_back(initState);
141 regOp.getResult().replaceAllUsesWith(
142 module.appendInput(newInputName, regOp.getType()).second);
143 module.appendOutput(newOutputName, regOp.getInput());
148 if (
auto instanceOp = dyn_cast<InstanceOp>(op)) {
149 OpBuilder builder(instanceOp);
151 addedInputs[instanceOp.getModuleNameAttr().getAttr()];
153 addedInputNames[instanceOp.getModuleNameAttr().getAttr()];
155 addedOutputs[instanceOp.getModuleNameAttr().getAttr()];
156 auto newOutputNames =
157 addedOutputNames[instanceOp.getModuleNameAttr().getAttr()];
158 addedInputs[
module.getSymNameAttr()].append(newInputs);
159 addedInputNames[
module.getSymNameAttr()].append(newInputNames);
160 addedOutputs[
module.getSymNameAttr()].append(newOutputs);
161 addedOutputNames[
module.getSymNameAttr()].append(newOutputNames);
162 initialValues[
module.getSymNameAttr()].append(
163 initialValues[instanceOp.getModuleNameAttr().getAttr()]);
164 SmallVector<Attribute> argNames(
165 instanceOp.getInputNames().getValue());
166 SmallVector<Attribute> resultNames(
167 instanceOp.getOutputNames().getValue());
169 for (
auto [input, name] : zip_equal(newInputs, newInputNames)) {
170 instanceOp.getInputsMutable().append(
171 module.appendInput(name, input).second);
172 argNames.push_back(name);
174 for (
auto outputName : newOutputNames) {
175 resultNames.push_back(outputName);
177 SmallVector<Type> resTypes(instanceOp->getResultTypes());
178 resTypes.append(newOutputs);
179 auto newInst = builder.create<InstanceOp>(
180 instanceOp.getLoc(), resTypes, instanceOp.getInstanceNameAttr(),
181 instanceOp.getModuleNameAttr(), instanceOp.getInputs(),
182 builder.getArrayAttr(argNames), builder.getArrayAttr(resultNames),
183 instanceOp.getParametersAttr(), instanceOp.getInnerSymAttr(),
184 instanceOp.getDoNotPrintAttr());
185 for (
auto [output, name] :
186 zip(newInst->getResults().take_back(newOutputs.size()),
188 module.appendOutput(name, output);
189 numRegs += newInputs.size();
190 instanceOp.replaceAllUsesWith(
191 newInst.getResults().take_front(instanceOp->getNumResults()));
192 instanceGraph.replaceInstance(instanceOp, newInst);
200 IntegerAttr::get(IntegerType::get(&getContext(), 32), numRegs));
202 module->setAttr("initial_values",
203 ArrayAttr::get(&getContext(),
204 initialValues[module.getSymNameAttr()]));
This is a Node in the InstanceGraph.
Value unwrapImmutableValue(mlir::TypedValue< seq::ImmutableType > immutableVal)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.