31#include "mlir/Pass/Pass.h" 
   32#include "llvm/ADT/MapVector.h" 
   33#include "llvm/ADT/TypeSwitch.h" 
   34#include "llvm/Support/raw_ostream.h" 
   37#define GEN_PASS_DEF_CONVERTHWTOBTOR2 
   38#include "circt/Conversion/Passes.h.inc" 
   47struct ConvertHWToBTOR2Pass
 
   48    : 
public circt::impl::ConvertHWToBTOR2Base<ConvertHWToBTOR2Pass>,
 
   56  ConvertHWToBTOR2Pass(raw_ostream &os) : os(os) {}
 
   58  void runOnOperation() 
override;
 
   74  DenseMap<size_t, size_t> sortToLIDMap;
 
   79  DenseMap<APInt, size_t> constToLIDMap;
 
   84  DenseMap<Operation *, size_t> opLIDMap;
 
   88  DenseMap<size_t, size_t> inputLIDs;
 
   94  SmallVector<Operation *> regOps;
 
   98  llvm::SmallMapVector<Operation *, OperandRange::iterator, 16> worklist;
 
  101  DenseSet<Operation *> handledOps;
 
  104  static constexpr size_t noLID = -1UL;
 
  105  [[maybe_unused]] 
static constexpr int64_t noWidth = -1L;
 
  112  size_t getOpLID(Operation *op) {
 
  115    Operation *defOp = op;
 
  116    auto &f = opLIDMap[defOp];
 
  126  size_t setOpLID(Operation *op) {
 
  127    size_t oplid = lid++;
 
  128    opLIDMap[op] = oplid;
 
  135  size_t getOpLID(Value value) {
 
  136    Operation *defOp = value.getDefiningOp();
 
  138    if (
auto it = opLIDMap.find(defOp); it != opLIDMap.end())
 
  143    if (BlockArgument barg = dyn_cast<BlockArgument>(value)) {
 
  145      size_t argIdx = barg.getArgNumber();
 
  148      if (
auto it = inputLIDs.find(argIdx); it != inputLIDs.end())
 
  160  size_t getSortLID(
size_t w) {
 
  161    if (
auto it = sortToLIDMap.find(w); it != sortToLIDMap.end())
 
  169  size_t setSortLID(
size_t w) {
 
  170    size_t sortlid = lid;
 
  172    sortToLIDMap[w] = lid++;
 
  179  size_t getConstLID(int64_t val, 
size_t w) {
 
  180    if (
auto it = constToLIDMap.find(APInt(w, val)); it != constToLIDMap.end())
 
  188  size_t setConstLID(int64_t val, 
size_t w) {
 
  189    size_t constlid = lid;
 
  191    constToLIDMap[APInt(w, val)] = lid++;
 
  199  void genSort(StringRef type, 
size_t width) {
 
  201    if (getSortLID(width) != noLID) {
 
  205    size_t sortlid = setSortLID(width);
 
  210       << 
" " << type << 
" " << width << 
"\n";
 
  214  void genInput(
size_t inlid, 
size_t width, StringRef name) {
 
  216    size_t sid = sortToLIDMap.at(width);
 
  221       << 
" " << sid << 
" " << name << 
"\n";
 
  225  void genConst(APInt value, 
size_t width, Operation *op) {
 
  228    size_t opLID = getOpLID(op);
 
  231    size_t sid = sortToLIDMap.at(width);
 
  235       << 
" " << sid << 
" " << value << 
"\n";
 
  239  size_t genZero(
size_t width) {
 
  241    size_t zlid = getConstLID(0, width);
 
  246    size_t sid = sortToLIDMap.at(width);
 
  249    size_t constlid = setConstLID(0, width);
 
  252    os << constlid << 
" " 
  254       << 
" " << sid << 
"\n";
 
  260  void genInit(Operation *
reg, Value initVal, int64_t width) {
 
  262    size_t regLID = getOpLID(
reg);
 
  263    size_t sid = sortToLIDMap.at(width);
 
  264    size_t initValLID = getOpLID(initVal);
 
  270       << 
" " << sid << 
" " << regLID << 
" " << initValLID << 
"\n";
 
  275  void genBinOp(StringRef inst, Operation *binop, Value op1, Value op2,
 
  277    if (binop->getNumOperands() != 2) {
 
  279          "only the binary form of this operation is currently supported");
 
  284    size_t opLID = getOpLID(binop);
 
  287    size_t sid = sortToLIDMap.at(width);
 
  291    size_t op1LID = getOpLID(op1);
 
  292    size_t op2LID = getOpLID(op2);
 
  295    os << opLID << 
" " << inst << 
" " << sid << 
" " << op1LID << 
" " << op2LID
 
  300  void genVariadicOp(StringRef inst, Operation *op, 
size_t width) {
 
  301    auto operands = op->getOperands();
 
  302    size_t sid = sortToLIDMap.at(width);
 
  304    if (operands.size() < 2) {
 
  305      op->emitError(
"variadic operations with less than 2 operands are not " 
  306                    "currently supported");
 
  312    if (!op->hasTrait<mlir::OpTrait::SameOperandsAndResultType>()) {
 
  314          "variadic operations with differing operand and result types are " 
  315          "not currently supported");
 
  321    auto prevOperandLID = getOpLID(operands[0]);
 
  323    for (
auto operand : operands.drop_front()) {
 
  325      auto thisLid = lid++;
 
  326      auto thisOperandLID = getOpLID(operand);
 
  327      os << thisLid << 
" " << inst << 
" " << sid << 
" " << prevOperandLID << 
" " 
  328         << thisOperandLID << 
"\n";
 
  329      prevOperandLID = thisLid;
 
  333    opLIDMap[op] = prevOperandLID;
 
  337  void genSlice(Operation *srcop, Value op0, 
size_t lowbit, int64_t width) {
 
  339    size_t opLID = getOpLID(srcop);
 
  342    size_t sid = sortToLIDMap.at(width);
 
  346    size_t op0LID = getOpLID(op0);
 
  351       << 
" " << sid << 
" " << op0LID << 
" " << (lowbit + width - 1) << 
" " 
  356  void genUnaryOp(Operation *srcop, Operation *op0, StringRef inst,
 
  359    size_t opLID = getOpLID(srcop);
 
  362    size_t sid = sortToLIDMap.at(width);
 
  366    size_t op0LID = getOpLID(op0);
 
  368    os << opLID << 
" " << inst << 
" " << sid << 
" " << op0LID << 
"\n";
 
  373  void genUnaryOp(Operation *srcop, Value op0, StringRef inst, 
size_t width) {
 
  374    genUnaryOp(srcop, op0.getDefiningOp(), inst, width);
 
  378  size_t genUnaryOp(
size_t op0LID, StringRef inst, 
size_t width) {
 
  380    size_t curLid = lid++;
 
  383    size_t sid = sortToLIDMap.at(width);
 
  385    os << curLid << 
" " << inst << 
" " << sid << 
" " << op0LID << 
"\n";
 
  390  size_t genUnaryOp(Operation *op0, StringRef inst, 
size_t width) {
 
  391    return genUnaryOp(getOpLID(op0), inst, width);
 
  396  size_t genUnaryOp(Value op0, StringRef inst, 
size_t width) {
 
  397    return genUnaryOp(getOpLID(op0), inst, width);
 
  403  void genBad(Operation *assertop) {
 
  405    size_t assertLID = getOpLID(assertop);
 
  412  void genBad(
size_t assertLID) {
 
  417       << 
" " << assertLID << 
"\n";
 
  422  void genConstraint(Value expr) {
 
  424    size_t exprLID = getOpLID(expr);
 
  426    genConstraint(exprLID);
 
  431  void genConstraint(
size_t exprLID) {
 
  436       << 
" " << exprLID << 
"\n";
 
  441  void genIte(Operation *srcop, Value cond, Value t, Value f, int64_t width) {
 
  443    size_t condLID = getOpLID(cond);
 
  444    size_t tLID = getOpLID(t);
 
  445    size_t fLID = getOpLID(f);
 
  447    genIte(srcop, condLID, tLID, fLID, width);
 
  452  void genIte(Operation *srcop, 
size_t condLID, 
size_t tLID, 
size_t fLID,
 
  455    size_t opLID = getOpLID(srcop);
 
  458    size_t sid = sortToLIDMap.at(width);
 
  463       << 
" " << sid << 
" " << condLID << 
" " << tLID << 
" " << fLID << 
"\n";
 
  467  size_t genImplies(Operation *srcop, Value lhs, Value rhs) {
 
  469    size_t lhsLID = getOpLID(lhs);
 
  470    size_t rhsLID = getOpLID(rhs);
 
  472    return genImplies(srcop, lhsLID, rhsLID);
 
  476  size_t genImplies(Operation *srcop, 
size_t lhsLID, 
size_t rhsLID) {
 
  478    size_t opLID = getOpLID(srcop);
 
  479    return genImplies(opLID, lhsLID, rhsLID);
 
  482  size_t genImplies(
size_t opLID, 
size_t lhsLID, 
size_t rhsLID) {
 
  484    size_t sid = sortToLIDMap.at(1);
 
  488       << 
" " << sid << 
" " << lhsLID << 
" " << rhsLID << 
"\n";
 
  493  void genState(Operation *srcop, int64_t width, StringRef name) {
 
  495    size_t opLID = getOpLID(srcop);
 
  498    size_t sid = sortToLIDMap.at(width);
 
  503       << 
" " << sid << 
" " << name << 
"\n";
 
  508  void genNext(Value next, Operation *
reg, int64_t width) {
 
  510    size_t sid = sortToLIDMap.at(width);
 
  513    size_t regLID = getOpLID(
reg);
 
  514    size_t nextLID = getOpLID(next);
 
  520       << 
" " << sid << 
" " << regLID << 
" " << nextLID << 
"\n";
 
  525  int64_t requireSort(mlir::Type type) {
 
  527    int64_t width = hw::getBitWidth(type);
 
  536    genSort(
"bitvec", width);
 
  542  void finalizeRegVisit(Operation *op) {
 
  544    Value next, reset, resetVal;
 
  547    if (
auto reg = dyn_cast<seq::CompRegOp>(op)) {
 
  548      width = hw::getBitWidth(
reg.getType());
 
  549      next = 
reg.getInput();
 
  550      reset = 
reg.getReset();
 
  551      resetVal = 
reg.getResetValue();
 
  552    } 
else if (
auto reg = dyn_cast<seq::FirRegOp>(op)) {
 
  553      width = hw::getBitWidth(
reg.getType());
 
  554      next = 
reg.getNext();
 
  555      reset = 
reg.getReset();
 
  556      resetVal = 
reg.getResetValue();
 
  558      op->emitError(
"Invalid register operation !");
 
  562    genSort(
"bitvec", width);
 
  567    size_t nextLID = noLID;
 
  571    if (BlockArgument barg = dyn_cast<BlockArgument>(next)) {
 
  573      size_t argIdx = barg.getArgNumber();
 
  576      nextLID = inputLIDs[argIdx];
 
  579      nextLID = getOpLID(next);
 
  584      size_t resetValLID = noLID;
 
  588      size_t resetLID = noLID;
 
  589      if (BlockArgument barg = dyn_cast<BlockArgument>(reset)) {
 
  592        size_t argIdx = barg.getArgNumber();
 
  595        resetLID = inputLIDs[argIdx];
 
  598        resetLID = getOpLID(reset);
 
  603        resetValLID = getOpLID(resetVal.getDefiningOp());
 
  605        resetValLID = genZero(width);
 
  608      setOpLID(next.getDefiningOp());
 
  617      genIte(next.getDefiningOp(), resetLID, resetValLID, nextLID, width);
 
  620      if (nextLID == noLID) {
 
  621        next.getDefiningOp()->emitError(
 
  622            "Register input does not point to a valid op!");
 
  628    genNext(next, op, width);
 
  642    if (port.
isInput() && !isa<seq::ClockType, seq::ImmutableType>(port.
type)) {
 
  644      StringRef iName = port.
getName();
 
  648      int64_t w = requireSort(port.
type);
 
  655      inputLIDs[port.
argNum] = lid;
 
  660      genInput(inlid, w, iName);
 
  669    if (handledOps.contains(op))
 
  673    int64_t w = requireSort(op.getType());
 
  677    genConst(op.getValue(), w, op);
 
  681  void visit(hw::WireOp op) {
 
  682    op->emitError(
"Wires are not supported in btor!");
 
  683    return signalPassFailure();
 
  686  void visitTypeOp(Operation *op) { visitInvalidTypeOp(op); }
 
  689  void visitInvalidTypeOp(Operation *op) {
 
  691    dispatchCombinationalVisitor(op);
 
  696  template <
typename Op>
 
  697  void visitBinOp(Op op, StringRef inst) {
 
  699    int64_t w = requireSort(op.getType());
 
  702    Value op1 = op.getOperand(0);
 
  703    Value op2 = op.getOperand(1);
 
  706    genBinOp(inst, op, op1, op2, w);
 
  709  template <
typename Op>
 
  710  void visitVariadicOp(Op op, StringRef inst) {
 
  712    int64_t w = requireSort(op.getType());
 
  715    genVariadicOp(inst, op, w);
 
  719  void visitComb(
comb::AddOp op) { visitVariadicOp(op, 
"add"); }
 
  720  void visitComb(
comb::SubOp op) { visitBinOp(op, 
"sub"); }
 
  721  void visitComb(
comb::MulOp op) { visitVariadicOp(op, 
"mul"); }
 
  722  void visitComb(
comb::DivSOp op) { visitBinOp(op, 
"sdiv"); }
 
  723  void visitComb(
comb::DivUOp op) { visitBinOp(op, 
"udiv"); }
 
  724  void visitComb(
comb::ModSOp op) { visitBinOp(op, 
"smod"); }
 
  725  void visitComb(
comb::ShlOp op) { visitBinOp(op, 
"sll"); }
 
  726  void visitComb(
comb::ShrUOp op) { visitBinOp(op, 
"srl"); }
 
  727  void visitComb(
comb::ShrSOp op) { visitBinOp(op, 
"sra"); }
 
  728  void visitComb(
comb::AndOp op) { visitVariadicOp(op, 
"and"); }
 
  729  void visitComb(
comb::OrOp op) { visitVariadicOp(op, 
"or"); }
 
  730  void visitComb(
comb::XorOp op) { visitVariadicOp(op, 
"xor"); }
 
  736    int64_t w = requireSort(op.getType());
 
  740    Value op0 = op.getOperand();
 
  741    size_t lb = op.getLowBit();
 
  744    genSlice(op, op0, lb, w);
 
  750  void visitComb(comb::ICmpOp op) {
 
  751    Value lhs = op.getOperand(0);
 
  752    Value rhs = op.getOperand(1);
 
  756    StringRef pred = stringifyICmpPredicate(op.getPredicate());
 
  761    else if (pred == 
"ule")
 
  763    else if (pred == 
"sle")
 
  765    else if (pred == 
"uge")
 
  767    else if (pred == 
"sge")
 
  771    genSort(
"bitvec", 1);
 
  775    genBinOp(pred, op, lhs, rhs, 1);
 
  781    Value pred = op.getCond();
 
  782    Value tval = op.getTrueValue();
 
  783    Value fval = op.getFalseValue();
 
  787    int64_t w = requireSort(op.getType());
 
  790    genIte(op, pred, tval, fval, w);
 
  793  void visitComb(Operation *op) { visitInvalidComb(op); }
 
  796  void visitInvalidComb(Operation *op) { dispatchSVVisitor(op); }
 
  799  void visitSV(sv::AssertOp op) {
 
  801    Value expr = op.getExpression();
 
  804    genSort(
"bitvec", 1);
 
  810    if (
auto ifop = dyn_cast<sv::IfOp>(((Operation *)op)->getParentOp())) {
 
  811      Value 
en = ifop.getOperand();
 
  814      genImplies(ifop, 
en, expr);
 
  817      genUnaryOp(op, ifop, 
"not", 1);
 
  820      genUnaryOp(op, expr, 
"not", 1);
 
  827  void visitSV(sv::AssumeOp op) {
 
  829    Value expr = op.getExpression();
 
  833  void visitSV(Operation *op) { visitInvalidSV(op); }
 
  836  void visitInvalidSV(Operation *op) { dispatchVerifVisitor(op); }
 
  838  template <
typename Op>
 
  839  void visitAssertLike(Op op) {
 
  841    Value prop = op.getProperty();
 
  842    Value 
en = op.getEnable();
 
  845    genSort(
"bitvec", 1);
 
  847    size_t assertLID = noLID;
 
  851      genImplies(op, 
en, prop);
 
  854      assertLID = genUnaryOp(op, 
"not", 1);
 
  857      assertLID = genUnaryOp(prop.getDefiningOp(), 
"not", 1);
 
  864  template <
typename Op>
 
  865  void visitAssumeLike(Op op) {
 
  867    Value prop = op.getProperty();
 
  868    Value 
en = op.getEnable();
 
  870    size_t assumeLID = getOpLID(prop);
 
  874      genSort(
"bitvec", 1);
 
  876      assumeLID = genImplies(op, 
en, prop);
 
  880    genConstraint(assumeLID);
 
  885  void visitVerif(verif::AssertOp op) { visitAssertLike(op); }
 
  886  void visitVerif(verif::ClockedAssertOp op) { visitAssertLike(op); }
 
  890  void visitVerif(verif::AssumeOp op) { visitAssumeLike(op); }
 
  891  void visitVerif(verif::ClockedAssumeOp op) { visitAssumeLike(op); }
 
  893  void visitUnhandledVerif(Operation *op) {
 
  894    op->emitError(
"not supported in btor2!");
 
  895    return signalPassFailure();
 
  898  void visitInvalidVerif(Operation *op) { visit(op); }
 
  902  void visit(Operation *op) {
 
  905    TypeSwitch<Operation *, void>(op)
 
  906        .Case<seq::FirRegOp, 
seq::CompRegOp>([&](
auto expr) { visit(expr); })
 
  907        .Default([&](
auto expr) { visitUnsupportedOp(op); });
 
  913  void visit(seq::FirRegOp 
reg) {
 
  915    StringRef regName = 
reg.getName();
 
  916    int64_t w = requireSort(
reg.getType());
 
  919    genState(
reg, w, regName);
 
  924    regOps.push_back(
reg);
 
  930    StringRef regName = 
reg.getName().value();
 
  931    int64_t w = requireSort(
reg.getType());
 
  935    auto init = 
reg.getInitialValue();
 
  941      if (!init.getDefiningOp<seq::InitialOp>()) {
 
  943            "Initial value must be emitted directly by a seq.initial op");
 
  949      if (!initialConstant)
 
  950        reg->emitError(
"initial value must be constant");
 
  953      dispatchTypeOpVisitor(initialConstant);
 
  956      handledOps.insert(initialConstant);
 
  959      genState(
reg, w, regName);
 
  962      genInit(
reg, initialConstant, w);
 
  965      genState(
reg, w, regName);
 
  971    regOps.push_back(
reg);
 
  976  void ignore(Operation *op) {}
 
  980  void visitUnsupportedOp(Operation *op) {
 
  983    TypeSwitch<Operation *, void>(op)
 
  985        .Case<sv::MacroDefOp, sv::MacroDeclOp, sv::VerbatimOp,
 
  986              sv::VerbatimExprOp, sv::VerbatimExprSEOp, sv::IfOp, 
sv::IfDefOp,
 
  987              sv::IfDefProceduralOp, sv::AlwaysOp, sv::AlwaysCombOp,
 
  988              seq::InitialOp, sv::AlwaysFFOp, seq::FromClockOp, seq::InitialOp,
 
  990            [&](
auto expr) { ignore(op); })
 
  993        .Case<seq::FromClockOp>([&](
auto expr) {
 
  994          if (++nclocks > 1UL) {
 
  995            op->emitOpError(
"Mutli-clock designs are not supported!");
 
  996            return signalPassFailure();
 
 1002        .Default([&](
auto expr) {
 
 1003          op->emitOpError(
"is an unsupported operation");
 
 1004          return signalPassFailure();
 
 1010void ConvertHWToBTOR2Pass::runOnOperation() {
 
 1021    module.walk([&](Operation *op) {
 
 1022      TypeSwitch<Operation *, void>(op)
 
 1023          .Case<seq::FirRegOp, seq::CompRegOp>([&](auto reg) {
 
 1025            handledOps.insert(op);
 
 1027          .Default([&](
auto expr) {});
 
 1031    module.walk([&](Operation *op) {
 
 1033      if (isa<hw::InstanceOp>(op)) {
 
 1034        op->emitOpError("not supported in BTOR2 conversion");
 
 1039      if (handledOps.contains(op))
 
 1043      worklist.insert({op, op->operand_begin()});
 
 1046      while (!worklist.empty()) {
 
 1047        auto &[op, operandIt] = worklist.back();
 
 1048        if (operandIt == op->operand_end()) {
 
 1050          dispatchTypeOpVisitor(op);
 
 1053          handledOps.insert(op);
 
 1054          worklist.pop_back();
 
 1060        Value operand = *(operandIt++);
 
 1061        auto *defOp = operand.getDefiningOp();
 
 1064        if (!defOp || handledOps.contains(defOp))
 
 1069        if (!worklist.insert({defOp, defOp->operand_begin()}).second) {
 
 1070          defOp->emitError(
"dependency cycle");
 
 1077    for (
size_t i = 0; i < regOps.size(); ++i) {
 
 1078      finalizeRegVisit(regOps[i]);
 
 1082  sortToLIDMap.clear();
 
 1083  constToLIDMap.clear();
 
 1092std::unique_ptr<mlir::Pass>
 
 1094  return std::make_unique<ConvertHWToBTOR2Pass>(os);
 
 
 1099  return std::make_unique<ConvertHWToBTOR2Pass>(llvm::outs());
 
 
assert(baseType &&"element must be base type")
 
static SmallVector< PortInfo > getPortList(ModuleTy &mod)
 
This helps visit Combinational nodes.
 
This helps visit TypeOp nodes.
 
Value unwrapImmutableValue(mlir::TypedValue< seq::ImmutableType > immutableVal)
 
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
 
std::unique_ptr< mlir::Pass > createConvertHWToBTOR2Pass()
 
reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
 
This holds the name, type, direction of a module's ports.
 
StringRef getName() const
 
size_t argNum
This is the argument index or the result index depending on the direction.