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;
 
   48  DenseMap<StringAttr, SmallVector<Type>> addedInputs;
 
   49  DenseMap<StringAttr, SmallVector<StringAttr>> addedInputNames;
 
   50  DenseMap<StringAttr, SmallVector<Type>> addedOutputs;
 
   51  DenseMap<StringAttr, SmallVector<StringAttr>> addedOutputNames;
 
   52  DenseMap<StringAttr, SmallVector<Attribute>> initialValues;
 
   54  LogicalResult externalizeReg(
HWModuleOp module, Operation *op, Twine regName,
 
   55                               Value clock, Attribute initState, Value reset,
 
   56                               bool isAsync, Value resetValue, Value next);
 
   60void ExternalizeRegistersPass::runOnOperation() {
 
   61  auto &instanceGraph = getAnalysis<hw::InstanceGraph>();
 
   62  DenseSet<Operation *> handled;
 
   66  for (
auto *startNode : instanceGraph) {
 
   67    if (handled.count(startNode->getModule().getOperation()))
 
   74      if (!handled.insert(node->getModule().getOperation()).second)
 
   78          dyn_cast_or_null<HWModuleOp>(node->getModule().getOperation());
 
   83      bool foundClk = 
false;
 
   84      for (
auto ty : module.getInputTypes()) {
 
   85        if (isa<seq::ClockType>(ty)) {
 
   87            module.emitError("modules with multiple clocks not yet supported");
 
   88            return signalPassFailure();
 
   93      module->walk([&](Operation *op) {
 
   94        if (auto regOp = dyn_cast<seq::CompRegOp>(op)) {
 
   95          mlir::Attribute initState = {};
 
   96          if (
auto initVal = regOp.getInitialValue()) {
 
   99            if (!initVal.getDefiningOp<seq::InitialOp>()) {
 
  100              regOp.emitError(
"registers with initial values not directly " 
  101                              "defined by a seq.initial op not yet supported");
 
  102              return signalPassFailure();
 
  105                                      .getDefiningOp<hw::ConstantOp>()) {
 
  108              initState = constantOp.getValueAttr();
 
  110              regOp.emitError(
"registers with initial values not directly " 
  111                              "defined by a hw.constant op in a seq.initial op " 
  112                              "not yet supported");
 
  113              return signalPassFailure();
 
  116          Twine regName = regOp.getName() && !(regOp.getName().value().empty())
 
  117                              ? regOp.getName().value()
 
  118                              : 
"reg_" + Twine(numRegs);
 
  120          if (failed(externalizeReg(module, op, regName, regOp.getClk(),
 
  121                                    initState, regOp.getReset(), 
false,
 
  122                                    regOp.getResetValue(), regOp.getInput()))) {
 
  123            return signalPassFailure();
 
  129        if (
auto regOp = dyn_cast<seq::FirRegOp>(op)) {
 
  130          mlir::Attribute initState = {};
 
  131          if (
auto preset = regOp.getPreset()) {
 
  133            initState = mlir::IntegerAttr::get(
 
  134                mlir::IntegerType::get(&getContext(), preset->getBitWidth()),
 
  137          Twine regName = regOp.getName().empty() ? 
"reg_" + Twine(numRegs)
 
  140          if (failed(externalizeReg(module, op, regName, regOp.getClk(),
 
  141                                    initState, regOp.getReset(),
 
  142                                    regOp.getIsAsync(), regOp.getResetValue(),
 
  144            return signalPassFailure();
 
  150        if (
auto instanceOp = dyn_cast<InstanceOp>(op)) {
 
  151          OpBuilder builder(instanceOp);
 
  153              addedInputs[instanceOp.getModuleNameAttr().getAttr()];
 
  155              addedInputNames[instanceOp.getModuleNameAttr().getAttr()];
 
  157              addedOutputs[instanceOp.getModuleNameAttr().getAttr()];
 
  158          auto newOutputNames =
 
  159              addedOutputNames[instanceOp.getModuleNameAttr().getAttr()];
 
  160          addedInputs[
module.getSymNameAttr()].append(newInputs);
 
  161          addedInputNames[
module.getSymNameAttr()].append(newInputNames);
 
  162          addedOutputs[
module.getSymNameAttr()].append(newOutputs);
 
  163          addedOutputNames[
module.getSymNameAttr()].append(newOutputNames);
 
  164          initialValues[
module.getSymNameAttr()].append(
 
  165              initialValues[instanceOp.getModuleNameAttr().getAttr()]);
 
  166          SmallVector<Attribute> argNames(
 
  167              instanceOp.getInputNames().getValue());
 
  168          SmallVector<Attribute> resultNames(
 
  169              instanceOp.getOutputNames().getValue());
 
  171          for (
auto [input, name] : zip_equal(newInputs, newInputNames)) {
 
  172            instanceOp.getInputsMutable().append(
 
  173                module.appendInput(name, input).second);
 
  174            argNames.push_back(name);
 
  176          for (
auto outputName : newOutputNames) {
 
  177            resultNames.push_back(outputName);
 
  179          SmallVector<Type> resTypes(instanceOp->getResultTypes());
 
  180          resTypes.append(newOutputs);
 
  181          auto newInst = InstanceOp::create(
 
  182              builder, instanceOp.getLoc(), resTypes,
 
  183              instanceOp.getInstanceNameAttr(), instanceOp.getModuleNameAttr(),
 
  184              instanceOp.getInputs(), builder.getArrayAttr(argNames),
 
  185              builder.getArrayAttr(resultNames), instanceOp.getParametersAttr(),
 
  186              instanceOp.getInnerSymAttr(), instanceOp.getDoNotPrintAttr());
 
  187          for (
auto [output, name] :
 
  188               zip(newInst->getResults().take_back(newOutputs.size()),
 
  190            module.appendOutput(name, output);
 
  191          numRegs += newInputs.size();
 
  192          instanceOp.replaceAllUsesWith(
 
  193              newInst.getResults().take_front(instanceOp->getNumResults()));
 
  194          instanceGraph.replaceInstance(instanceOp, newInst);
 
  202          IntegerAttr::get(IntegerType::get(&getContext(), 32), numRegs));
 
  204      module->setAttr("initial_values",
 
  205                      ArrayAttr::get(&getContext(),
 
  206                                     initialValues[module.getSymNameAttr()]));
 
  211LogicalResult ExternalizeRegistersPass::externalizeReg(
 
  212    HWModuleOp module, Operation *op, Twine regName, Value clock,
 
  213    Attribute initState, Value reset, 
bool isAsync, Value resetValue,
 
  215  if (!isa<BlockArgument>(clock)) {
 
  216    op->emitError(
"only clocks directly given as block arguments " 
  221  OpBuilder builder(op);
 
  222  auto result = op->getResult(0);
 
  223  auto regType = result.getType();
 
  227  initialValues[
module.getSymNameAttr()].push_back(
 
  228      initState ? initState : mlir::UnitAttr::get(&getContext()));
 
  230  StringAttr newInputName(builder.getStringAttr(regName + 
"_state")),
 
  231      newOutputName(builder.getStringAttr(regName + 
"_next"));
 
  232  addedInputs[
module.getSymNameAttr()].push_back(regType);
 
  233  addedInputNames[
module.getSymNameAttr()].push_back(newInputName);
 
  234  addedOutputs[
module.getSymNameAttr()].push_back(next.getType());
 
  235  addedOutputNames[
module.getSymNameAttr()].push_back(newOutputName);
 
  238  auto newInput = 
module.appendInput(newInputName, regType).second;
 
  239  result.replaceAllUsesWith(newInput);
 
  243      op->emitError(
"registers with an async reset are not yet supported");
 
  247    auto mux = comb::MuxOp::create(builder, op->getLoc(), regType, reset,
 
  249    module.appendOutput(newOutputName, mux);
 
  252    module.appendOutput(newOutputName, next);
 
This is a Node in the InstanceGraph.
 
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
 
Value unwrapImmutableValue(mlir::TypedValue< seq::ImmutableType > immutableVal)
 
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.