18#include "mlir/Dialect/Func/IR/FuncOps.h"
19#include "mlir/Dialect/LLVMIR/FunctionCallUtils.h"
20#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
21#include "mlir/Pass/Pass.h"
22#include "mlir/Transforms/DialectConversion.h"
23#include "llvm/ADT/PostOrderIterator.h"
24#include "llvm/ADT/Twine.h"
30using namespace igraph;
33#define GEN_PASS_DEF_EXTERNALIZEREGISTERS
34#include "circt/Tools/circt-bmc/Passes.h.inc"
42struct ExternalizeRegistersPass
43 :
public circt::impl::ExternalizeRegistersBase<ExternalizeRegistersPass> {
44 using ExternalizeRegistersBase::ExternalizeRegistersBase;
45 void runOnOperation()
override;
49void ExternalizeRegistersPass::runOnOperation() {
50 auto &instanceGraph = getAnalysis<hw::InstanceGraph>();
51 DenseSet<Operation *> handled;
52 DenseMap<StringAttr, SmallVector<Type>> addedInputs;
53 DenseMap<StringAttr, SmallVector<StringAttr>> addedInputNames;
54 DenseMap<StringAttr, SmallVector<Type>> addedOutputs;
55 DenseMap<StringAttr, SmallVector<StringAttr>> addedOutputNames;
56 DenseMap<StringAttr, SmallVector<Attribute>> initialValues;
60 for (
auto *startNode : instanceGraph) {
61 if (handled.count(startNode->getModule().getOperation()))
68 if (!handled.insert(node->getModule().getOperation()).second)
72 dyn_cast_or_null<HWModuleOp>(node->getModule().getOperation());
77 bool foundClk =
false;
78 for (
auto ty : module.getInputTypes()) {
79 if (isa<seq::ClockType>(ty)) {
81 module.emitError("modules with multiple clocks not yet supported");
82 return signalPassFailure();
87 module->walk([&](Operation *op) {
88 if (auto regOp = dyn_cast<seq::CompRegOp>(op)) {
89 if (!isa<BlockArgument>(regOp.getClk())) {
90 regOp.emitError("only clocks directly given as block arguments "
92 return signalPassFailure();
94 mlir::Attribute initState;
95 if (
auto initVal = regOp.getInitialValue()) {
98 if (!initVal.getDefiningOp<seq::InitialOp>()) {
99 regOp.emitError(
"registers with initial values not directly "
100 "defined by a seq.initial op not yet supported");
101 return signalPassFailure();
104 .getDefiningOp<hw::ConstantOp>()) {
107 initState = constantOp.getValueAttr();
109 regOp.emitError(
"registers with initial values not directly "
110 "defined by a hw.constant op in a seq.initial op "
111 "not yet supported");
112 return signalPassFailure();
117 initState = mlir::UnitAttr::get(&getContext());
119 addedInputs[
module.getSymNameAttr()].push_back(regOp.getType());
120 addedOutputs[
module.getSymNameAttr()].push_back(
121 regOp.getInput().getType());
122 OpBuilder builder(regOp);
123 auto regName = regOp.getName();
124 StringAttr newInputName, newOutputName;
125 if (regName && !regName.value().empty()) {
126 newInputName = builder.getStringAttr(regName.value() +
"_state");
127 newOutputName = builder.getStringAttr(regName.value() +
"_input");
130 builder.getStringAttr(
"reg_" + Twine(numRegs) +
"_state");
132 builder.getStringAttr(
"reg_" + Twine(numRegs) +
"_input");
134 addedInputNames[
module.getSymNameAttr()].push_back(newInputName);
135 addedOutputNames[
module.getSymNameAttr()].push_back(newOutputName);
136 initialValues[
module.getSymNameAttr()].push_back(initState);
138 regOp.getResult().replaceAllUsesWith(
139 module.appendInput(newInputName, regOp.getType()).second);
140 if (
auto reset = regOp.getReset()) {
141 auto resetValue = regOp.getResetValue();
143 regOp.getLoc(), regOp.getType(), reset, resetValue,
145 module.appendOutput(newOutputName, mux);
147 module.appendOutput(newOutputName, regOp.getInput());
153 if (
auto instanceOp = dyn_cast<InstanceOp>(op)) {
154 OpBuilder builder(instanceOp);
156 addedInputs[instanceOp.getModuleNameAttr().getAttr()];
158 addedInputNames[instanceOp.getModuleNameAttr().getAttr()];
160 addedOutputs[instanceOp.getModuleNameAttr().getAttr()];
161 auto newOutputNames =
162 addedOutputNames[instanceOp.getModuleNameAttr().getAttr()];
163 addedInputs[
module.getSymNameAttr()].append(newInputs);
164 addedInputNames[
module.getSymNameAttr()].append(newInputNames);
165 addedOutputs[
module.getSymNameAttr()].append(newOutputs);
166 addedOutputNames[
module.getSymNameAttr()].append(newOutputNames);
167 initialValues[
module.getSymNameAttr()].append(
168 initialValues[instanceOp.getModuleNameAttr().getAttr()]);
169 SmallVector<Attribute> argNames(
170 instanceOp.getInputNames().getValue());
171 SmallVector<Attribute> resultNames(
172 instanceOp.getOutputNames().getValue());
174 for (
auto [input, name] : zip_equal(newInputs, newInputNames)) {
175 instanceOp.getInputsMutable().append(
176 module.appendInput(name, input).second);
177 argNames.push_back(name);
179 for (
auto outputName : newOutputNames) {
180 resultNames.push_back(outputName);
182 SmallVector<Type> resTypes(instanceOp->getResultTypes());
183 resTypes.append(newOutputs);
184 auto newInst = builder.create<InstanceOp>(
185 instanceOp.getLoc(), resTypes, instanceOp.getInstanceNameAttr(),
186 instanceOp.getModuleNameAttr(), instanceOp.getInputs(),
187 builder.getArrayAttr(argNames), builder.getArrayAttr(resultNames),
188 instanceOp.getParametersAttr(), instanceOp.getInnerSymAttr(),
189 instanceOp.getDoNotPrintAttr());
190 for (
auto [output, name] :
191 zip(newInst->getResults().take_back(newOutputs.size()),
193 module.appendOutput(name, output);
194 numRegs += newInputs.size();
195 instanceOp.replaceAllUsesWith(
196 newInst.getResults().take_front(instanceOp->getNumResults()));
197 instanceGraph.replaceInstance(instanceOp, newInst);
205 IntegerAttr::get(IntegerType::get(&getContext(), 32), numRegs));
207 module->setAttr("initial_values",
208 ArrayAttr::get(&getContext(),
209 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.