Loading [MathJax]/extensions/tex2jax.js
CIRCT 21.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ExternalizeRegisters.cpp
Go to the documentation of this file.
1//===- ExternalizeRegisters.cpp -------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
15#include "circt/Support/LLVM.h"
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"
25#include <optional>
26
27using namespace mlir;
28using namespace circt;
29using namespace hw;
30using namespace igraph;
31
32namespace circt {
33#define GEN_PASS_DEF_EXTERNALIZEREGISTERS
34#include "circt/Tools/circt-bmc/Passes.h.inc"
35} // namespace circt
36
37//===----------------------------------------------------------------------===//
38// Externalize Registers Pass
39//===----------------------------------------------------------------------===//
40
41namespace {
42struct ExternalizeRegistersPass
43 : public circt::impl::ExternalizeRegistersBase<ExternalizeRegistersPass> {
44 using ExternalizeRegistersBase::ExternalizeRegistersBase;
45 void runOnOperation() override;
46};
47} // namespace
48
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;
57
58 // Iterate over all instances in the instance graph. This ensures we visit
59 // every module, even private top modules (private and never instantiated).
60 for (auto *startNode : instanceGraph) {
61 if (handled.count(startNode->getModule().getOperation()))
62 continue;
63
64 // Visit the instance subhierarchy starting at the current module, in a
65 // depth-first manner. This allows us to inline child modules into parents
66 // before we attempt to inline parents into their parents.
67 for (InstanceGraphNode *node : llvm::post_order(startNode)) {
68 if (!handled.insert(node->getModule().getOperation()).second)
69 continue;
70
71 auto module =
72 dyn_cast_or_null<HWModuleOp>(node->getModule().getOperation());
73 if (!module)
74 continue;
75
76 unsigned numRegs = 0;
77 bool foundClk = false;
78 for (auto ty : module.getInputTypes()) {
79 if (isa<seq::ClockType>(ty)) {
80 if (foundClk) {
81 module.emitError("modules with multiple clocks not yet supported");
82 return signalPassFailure();
83 }
84 foundClk = true;
85 }
86 }
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 "
91 "are supported");
92 return signalPassFailure();
93 }
94 mlir::Attribute initState;
95 if (auto initVal = regOp.getInitialValue()) {
96 // Find the constant op that defines the reset value in an initial
97 // block (if it exists)
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();
102 }
103 if (auto constantOp = circt::seq::unwrapImmutableValue(initVal)
104 .getDefiningOp<hw::ConstantOp>()) {
105 // Fetch value from constant op - leave removing the dead op to
106 // DCE
107 initState = constantOp.getValueAttr();
108 } else {
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();
113 }
114 } else {
115 // If there's no initial value just add a unit attribute to maintain
116 // one-to-one correspondence with module ports
117 initState = mlir::UnitAttr::get(&getContext());
118 }
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");
128 } else {
129 newInputName =
130 builder.getStringAttr("reg_" + Twine(numRegs) + "_state");
131 newOutputName =
132 builder.getStringAttr("reg_" + Twine(numRegs) + "_input");
133 }
134 addedInputNames[module.getSymNameAttr()].push_back(newInputName);
135 addedOutputNames[module.getSymNameAttr()].push_back(newOutputName);
136 initialValues[module.getSymNameAttr()].push_back(initState);
137
138 regOp.getResult().replaceAllUsesWith(
139 module.appendInput(newInputName, regOp.getType()).second);
140 if (auto reset = regOp.getReset()) {
141 auto resetValue = regOp.getResetValue();
142 auto mux = builder.create<comb::MuxOp>(
143 regOp.getLoc(), regOp.getType(), reset, resetValue,
144 regOp.getInput());
145 module.appendOutput(newOutputName, mux);
146 } else {
147 module.appendOutput(newOutputName, regOp.getInput());
148 }
149 regOp->erase();
150 ++numRegs;
151 return;
152 }
153 if (auto instanceOp = dyn_cast<InstanceOp>(op)) {
154 OpBuilder builder(instanceOp);
155 auto newInputs =
156 addedInputs[instanceOp.getModuleNameAttr().getAttr()];
157 auto newInputNames =
158 addedInputNames[instanceOp.getModuleNameAttr().getAttr()];
159 auto newOutputs =
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());
173
174 for (auto [input, name] : zip_equal(newInputs, newInputNames)) {
175 instanceOp.getInputsMutable().append(
176 module.appendInput(name, input).second);
177 argNames.push_back(name);
178 }
179 for (auto outputName : newOutputNames) {
180 resultNames.push_back(outputName);
181 }
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()),
192 newOutputNames))
193 module.appendOutput(name, output);
194 numRegs += newInputs.size();
195 instanceOp.replaceAllUsesWith(
196 newInst.getResults().take_front(instanceOp->getNumResults()));
197 instanceGraph.replaceInstance(instanceOp, newInst);
198 instanceOp->erase();
199 return;
200 }
201 });
202
203 module->setAttr(
204 "num_regs",
205 IntegerAttr::get(IntegerType::get(&getContext(), 32), numRegs));
206
207 module->setAttr("initial_values",
208 ArrayAttr::get(&getContext(),
209 initialValues[module.getSymNameAttr()]));
210 }
211 }
212}
This is a Node in the InstanceGraph.
Value unwrapImmutableValue(mlir::TypedValue< seq::ImmutableType > immutableVal)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition hw.py:1