32 #include "mlir/Pass/Pass.h"
33 #include "llvm/ADT/MapVector.h"
34 #include "llvm/ADT/TypeSwitch.h"
35 #include "llvm/Support/raw_ostream.h"
38 #define GEN_PASS_DEF_CONVERTHWTOBTOR2
39 #include "circt/Conversion/Passes.h.inc"
42 using namespace circt;
48 struct ConvertHWToBTOR2Pass
49 :
public circt::impl::ConvertHWToBTOR2Base<ConvertHWToBTOR2Pass>,
50 public comb::CombinationalVisitor<ConvertHWToBTOR2Pass>,
51 public sv::Visitor<ConvertHWToBTOR2Pass>,
52 public hw::TypeOpVisitor<ConvertHWToBTOR2Pass>,
53 public verif::Visitor<ConvertHWToBTOR2Pass> {
55 ConvertHWToBTOR2Pass(raw_ostream &os) : os(os) {}
57 void runOnOperation()
override;
73 DenseMap<size_t, size_t> sortToLIDMap;
78 DenseMap<APInt, size_t> constToLIDMap;
83 DenseMap<Operation *, size_t> opLIDMap;
87 DenseMap<size_t, size_t> inputLIDs;
93 SmallVector<Operation *> regOps;
97 llvm::SmallMapVector<Operation *, OperandRange::iterator, 16> worklist;
100 DenseSet<Operation *> handledOps;
103 static constexpr
size_t noLID = -1UL;
104 [[maybe_unused]]
static constexpr int64_t noWidth = -1L;
111 size_t getOpLID(Operation *op) {
114 Operation *defOp = op;
115 auto &f = opLIDMap[defOp];
125 size_t setOpLID(Operation *op) {
126 size_t oplid = lid++;
127 opLIDMap[op] = oplid;
134 size_t getOpLID(Value value) {
135 Operation *defOp = value.getDefiningOp();
137 if (
auto it = opLIDMap.find(defOp); it != opLIDMap.end())
142 if (BlockArgument barg = dyn_cast<BlockArgument>(value)) {
144 size_t argIdx = barg.getArgNumber();
147 if (
auto it = inputLIDs.find(argIdx); it != inputLIDs.end())
159 size_t getSortLID(
size_t w) {
160 if (
auto it = sortToLIDMap.find(w); it != sortToLIDMap.end())
168 size_t setSortLID(
size_t w) {
169 size_t sortlid = lid;
171 sortToLIDMap[w] = lid++;
178 size_t getConstLID(int64_t val,
size_t w) {
179 if (
auto it = constToLIDMap.find(APInt(w, val)); it != constToLIDMap.end())
187 size_t setConstLID(int64_t val,
size_t w) {
188 size_t constlid = lid;
190 constToLIDMap[APInt(w, val)] = lid++;
198 void genSort(StringRef type,
size_t width) {
200 if (getSortLID(width) != noLID) {
204 size_t sortlid = setSortLID(width);
209 <<
" " << type <<
" " << width <<
"\n";
213 void genInput(
size_t inlid,
size_t width, StringRef name) {
215 size_t sid = sortToLIDMap.at(width);
220 <<
" " << sid <<
" " << name <<
"\n";
224 void genConst(APInt value,
size_t width, Operation *op) {
227 size_t opLID = getOpLID(op);
230 size_t sid = sortToLIDMap.at(width);
234 <<
" " << sid <<
" " << value <<
"\n";
238 size_t genZero(
size_t width) {
240 size_t zlid = getConstLID(0, width);
245 size_t sid = sortToLIDMap.at(width);
248 size_t constlid = setConstLID(0, width);
251 os << constlid <<
" "
253 <<
" " << sid <<
"\n";
259 void genInit(Operation *
reg, Value initVal, int64_t width) {
261 size_t regLID = getOpLID(
reg);
262 size_t sid = sortToLIDMap.at(width);
263 size_t initValLID = getOpLID(initVal);
269 <<
" " << sid <<
" " << regLID <<
" " << initValLID <<
"\n";
274 void genBinOp(StringRef inst, Operation *binop, Value op1, Value op2,
277 if (binop->getNumOperands() != 2) {
278 binop->emitError(
"variadic operations not are not currently supported");
283 size_t opLID = getOpLID(binop);
286 size_t sid = sortToLIDMap.at(width);
290 size_t op1LID = getOpLID(op1);
291 size_t op2LID = getOpLID(op2);
294 os << opLID <<
" " << inst <<
" " << sid <<
" " << op1LID <<
" " << op2LID
299 void genSlice(Operation *srcop, Value op0,
size_t lowbit, int64_t width) {
301 size_t opLID = getOpLID(srcop);
304 size_t sid = sortToLIDMap.at(width);
308 size_t op0LID = getOpLID(op0);
313 <<
" " << sid <<
" " << op0LID <<
" " << (lowbit + width - 1) <<
" "
318 void genUnaryOp(Operation *srcop, Operation *op0, StringRef inst,
321 size_t opLID = getOpLID(srcop);
324 size_t sid = sortToLIDMap.at(width);
328 size_t op0LID = getOpLID(op0);
330 os << opLID <<
" " << inst <<
" " << sid <<
" " << op0LID <<
"\n";
335 void genUnaryOp(Operation *srcop, Value op0, StringRef inst,
size_t width) {
336 genUnaryOp(srcop, op0.getDefiningOp(), inst, width);
340 size_t genUnaryOp(
size_t op0LID, StringRef inst,
size_t width) {
342 size_t curLid = lid++;
345 size_t sid = sortToLIDMap.at(width);
347 os << curLid <<
" " << inst <<
" " << sid <<
" " << op0LID <<
"\n";
352 size_t genUnaryOp(Operation *op0, StringRef inst,
size_t width) {
353 return genUnaryOp(getOpLID(op0), inst, width);
358 size_t genUnaryOp(Value op0, StringRef inst,
size_t width) {
359 return genUnaryOp(getOpLID(op0), inst, width);
365 void genBad(Operation *assertop) {
367 size_t assertLID = getOpLID(assertop);
374 void genBad(
size_t assertLID) {
379 <<
" " << assertLID <<
"\n";
384 void genConstraint(Value expr) {
386 size_t exprLID = getOpLID(expr);
388 genConstraint(exprLID);
393 void genConstraint(
size_t exprLID) {
398 <<
" " << exprLID <<
"\n";
403 void genIte(Operation *srcop, Value cond, Value t, Value f, int64_t width) {
405 size_t condLID = getOpLID(cond);
406 size_t tLID = getOpLID(t);
407 size_t fLID = getOpLID(f);
409 genIte(srcop, condLID, tLID, fLID, width);
414 void genIte(Operation *srcop,
size_t condLID,
size_t tLID,
size_t fLID,
417 size_t opLID = getOpLID(srcop);
420 size_t sid = sortToLIDMap.at(width);
425 <<
" " << sid <<
" " << condLID <<
" " << tLID <<
" " << fLID <<
"\n";
429 size_t genImplies(Operation *srcop, Value lhs, Value rhs) {
431 size_t lhsLID = getOpLID(lhs);
432 size_t rhsLID = getOpLID(rhs);
434 return genImplies(srcop, lhsLID, rhsLID);
438 size_t genImplies(Operation *srcop,
size_t lhsLID,
size_t rhsLID) {
440 size_t opLID = getOpLID(srcop);
441 return genImplies(opLID, lhsLID, rhsLID);
444 size_t genImplies(
size_t opLID,
size_t lhsLID,
size_t rhsLID) {
446 size_t sid = sortToLIDMap.at(1);
450 <<
" " << sid <<
" " << lhsLID <<
" " << rhsLID <<
"\n";
455 void genState(Operation *srcop, int64_t width, StringRef name) {
457 size_t opLID = getOpLID(srcop);
460 size_t sid = sortToLIDMap.at(width);
465 <<
" " << sid <<
" " << name <<
"\n";
470 void genNext(Value next, Operation *
reg, int64_t width) {
472 size_t sid = sortToLIDMap.at(width);
475 size_t regLID = getOpLID(
reg);
476 size_t nextLID = getOpLID(next);
482 <<
" " << sid <<
" " << regLID <<
" " << nextLID <<
"\n";
487 int64_t requireSort(mlir::Type type) {
498 genSort(
"bitvec", width);
504 void finalizeRegVisit(Operation *op) {
506 Value next, reset, resetVal;
509 if (
auto reg = dyn_cast<seq::CompRegOp>(op)) {
511 next =
reg.getInput();
512 reset =
reg.getReset();
513 resetVal =
reg.getResetValue();
514 }
else if (
auto reg = dyn_cast<seq::FirRegOp>(op)) {
516 next =
reg.getNext();
517 reset =
reg.getReset();
518 resetVal =
reg.getResetValue();
520 op->emitError(
"Invalid register operation !");
524 genSort(
"bitvec", width);
529 size_t nextLID = noLID;
533 if (BlockArgument barg = dyn_cast<BlockArgument>(next)) {
535 size_t argIdx = barg.getArgNumber();
538 nextLID = inputLIDs[argIdx];
541 nextLID = getOpLID(next);
546 size_t resetValLID = noLID;
550 size_t resetLID = noLID;
551 if (BlockArgument barg = dyn_cast<BlockArgument>(reset)) {
554 size_t argIdx = barg.getArgNumber();
557 resetLID = inputLIDs[argIdx];
560 resetLID = getOpLID(reset);
565 resetValLID = getOpLID(resetVal.getDefiningOp());
567 resetValLID = genZero(width);
570 setOpLID(next.getDefiningOp());
579 genIte(next.getDefiningOp(), resetLID, resetValLID, nextLID, width);
582 if (nextLID == noLID) {
583 next.getDefiningOp()->emitError(
584 "Register input does not point to a valid op!");
590 genNext(next, op, width);
600 void visit(hw::PortInfo &port) {
604 if (port.isInput() && !isa<seq::ClockType, seq::ImmutableType>(port.type)) {
606 StringRef iName = port.getName();
610 int64_t w = requireSort(port.type);
617 inputLIDs[port.argNum] = lid;
622 genInput(inlid, w, iName);
631 if (handledOps.contains(op))
635 int64_t w = requireSort(op.getType());
639 genConst(op.getValue(), w, op);
643 void visit(hw::WireOp op) {
644 op->emitError(
"Wires are not supported in btor!");
645 return signalPassFailure();
648 void visitTypeOp(Operation *op) { visitInvalidTypeOp(op); }
651 void visitInvalidTypeOp(Operation *op) {
653 dispatchCombinationalVisitor(op);
658 template <
typename Op>
659 void visitBinOp(Op op, StringRef inst) {
661 int64_t w = requireSort(op.getType());
664 Value op1 = op.getOperand(0);
665 Value op2 = op.getOperand(1);
668 genBinOp(inst, op, op1, op2, w);
672 void visitComb(
comb::AddOp op) { visitBinOp(op,
"add"); }
673 void visitComb(
comb::SubOp op) { visitBinOp(op,
"sub"); }
674 void visitComb(
comb::MulOp op) { visitBinOp(op,
"mul"); }
675 void visitComb(
comb::DivSOp op) { visitBinOp(op,
"sdiv"); }
676 void visitComb(
comb::DivUOp op) { visitBinOp(op,
"udiv"); }
677 void visitComb(
comb::ModSOp op) { visitBinOp(op,
"smod"); }
678 void visitComb(
comb::ShlOp op) { visitBinOp(op,
"sll"); }
679 void visitComb(
comb::ShrUOp op) { visitBinOp(op,
"srl"); }
680 void visitComb(
comb::ShrSOp op) { visitBinOp(op,
"sra"); }
681 void visitComb(
comb::AndOp op) { visitBinOp(op,
"and"); }
682 void visitComb(
comb::OrOp op) { visitBinOp(op,
"or"); }
683 void visitComb(
comb::XorOp op) { visitBinOp(op,
"xor"); }
689 int64_t w = requireSort(op.getType());
693 Value op0 = op.getOperand();
694 size_t lb = op.getLowBit();
697 genSlice(op, op0, lb, w);
703 void visitComb(comb::ICmpOp op) {
704 Value lhs = op.getOperand(0);
705 Value rhs = op.getOperand(1);
709 StringRef pred = stringifyICmpPredicate(op.getPredicate());
716 genSort(
"bitvec", 1);
720 genBinOp(pred, op, lhs, rhs, 1);
726 Value pred = op.getCond();
727 Value tval = op.getTrueValue();
728 Value fval = op.getFalseValue();
732 int64_t w = requireSort(op.getType());
735 genIte(op, pred, tval, fval, w);
738 void visitComb(Operation *op) { visitInvalidComb(op); }
741 void visitInvalidComb(Operation *op) { dispatchSVVisitor(op); }
744 void visitSV(sv::AssertOp op) {
746 Value expr = op.getExpression();
749 genSort(
"bitvec", 1);
755 if (
auto ifop = dyn_cast<sv::IfOp>(((Operation *)op)->getParentOp())) {
756 Value
en = ifop.getOperand();
759 genImplies(ifop,
en, expr);
762 genUnaryOp(op, ifop,
"not", 1);
765 genUnaryOp(op, expr,
"not", 1);
772 void visitSV(sv::AssumeOp op) {
774 Value expr = op.getExpression();
778 void visitSV(Operation *op) { visitInvalidSV(op); }
781 void visitInvalidSV(Operation *op) { dispatchVerifVisitor(op); }
783 template <
typename Op>
784 void visitAssertLike(Op op) {
786 Value prop = op.getProperty();
787 Value
en = op.getEnable();
790 genSort(
"bitvec", 1);
792 size_t assertLID = noLID;
796 genImplies(op,
en, prop);
799 assertLID = genUnaryOp(op,
"not", 1);
802 assertLID = genUnaryOp(prop.getDefiningOp(),
"not", 1);
809 template <
typename Op>
810 void visitAssumeLike(Op op) {
812 Value prop = op.getProperty();
813 Value
en = op.getEnable();
815 size_t assumeLID = getOpLID(prop);
819 genSort(
"bitvec", 1);
821 assumeLID = genImplies(op,
en, prop);
825 genConstraint(assumeLID);
830 void visitVerif(verif::AssertOp op) { visitAssertLike(op); }
831 void visitVerif(verif::ClockedAssertOp op) { visitAssertLike(op); }
835 void visitVerif(verif::AssumeOp op) { visitAssumeLike(op); }
836 void visitVerif(verif::ClockedAssumeOp op) { visitAssumeLike(op); }
839 void visitVerif(verif::CoverOp op) {
840 op->emitError(
"Cover is not supported in btor2!");
841 return signalPassFailure();
844 void visitVerif(verif::ClockedCoverOp op) {
845 op->emitError(
"Cover is not supported in btor2!");
846 return signalPassFailure();
849 void visitInvalidVerif(Operation *op) { visit(op); }
853 void visit(Operation *op) {
856 TypeSwitch<Operation *, void>(op)
857 .Case<seq::FirRegOp,
seq::CompRegOp>([&](
auto expr) { visit(expr); })
858 .Default([&](
auto expr) { visitUnsupportedOp(op); });
864 void visit(seq::FirRegOp
reg) {
866 StringRef regName =
reg.getName();
867 int64_t w = requireSort(
reg.getType());
870 genState(
reg, w, regName);
875 regOps.push_back(
reg);
881 StringRef regName =
reg.getName().value();
882 int64_t w = requireSort(
reg.getType());
886 auto init =
reg.getInitialValue();
892 if (!init.getDefiningOp<seq::InitialOp>()) {
894 "Initial value must be emitted directly by a seq.initial op");
900 if (!initialConstant)
901 reg->emitError(
"initial value must be constant");
904 dispatchTypeOpVisitor(initialConstant);
907 handledOps.insert(initialConstant);
910 genState(
reg, w, regName);
913 genInit(
reg, initialConstant, w);
916 genState(
reg, w, regName);
922 regOps.push_back(
reg);
927 void ignore(Operation *op) {}
931 void visitUnsupportedOp(Operation *op) {
934 TypeSwitch<Operation *, void>(op)
936 .Case<sv::MacroDefOp, sv::MacroDeclOp, sv::VerbatimOp,
937 sv::VerbatimExprOp, sv::VerbatimExprSEOp, sv::IfOp,
sv::IfDefOp,
938 sv::IfDefProceduralOp, sv::AlwaysOp, sv::AlwaysCombOp,
939 seq::InitialOp, sv::AlwaysFFOp, seq::FromClockOp, seq::InitialOp,
941 [&](
auto expr) { ignore(op); })
944 .Case<seq::FromClockOp>([&](
auto expr) {
945 if (++nclocks > 1UL) {
946 op->emitOpError(
"Mutli-clock designs are not supported!");
947 return signalPassFailure();
953 .Default([&](
auto expr) {
954 op->emitOpError(
"is an unsupported operation");
955 return signalPassFailure();
961 void ConvertHWToBTOR2Pass::runOnOperation() {
967 for (
auto &port : module.getPortList()) {
972 module.walk([&](Operation *op) {
973 TypeSwitch<Operation *, void>(op)
974 .Case<seq::FirRegOp, seq::CompRegOp>([&](auto reg) {
976 handledOps.insert(op);
978 .Default([&](
auto expr) {});
982 module.walk([&](Operation *op) {
984 if (isa<hw::InstanceOp>(op)) {
985 op->emitOpError(
"not supported in BTOR2 conversion");
990 if (handledOps.contains(op))
994 worklist.insert({op, op->operand_begin()});
997 while (!worklist.empty()) {
998 auto &[op, operandIt] = worklist.back();
999 if (operandIt == op->operand_end()) {
1001 dispatchTypeOpVisitor(op);
1004 handledOps.insert(op);
1005 worklist.pop_back();
1011 Value operand = *(operandIt++);
1012 auto *defOp = operand.getDefiningOp();
1015 if (!defOp || handledOps.contains(defOp))
1020 if (!worklist.insert({defOp, defOp->operand_begin()}).second) {
1021 defOp->emitError(
"dependency cycle");
1028 for (
size_t i = 0; i < regOps.size(); ++i) {
1029 finalizeRegVisit(regOps[i]);
1033 sortToLIDMap.clear();
1034 constToLIDMap.clear();
1043 std::unique_ptr<mlir::Pass>
1045 return std::make_unique<ConvertHWToBTOR2Pass>(os);
1050 return std::make_unique<ConvertHWToBTOR2Pass>(llvm::outs());
assert(baseType &&"element must be base type")
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
Value unwrapImmutableValue(mlir::TypedValue< seq::ImmutableType > immutableVal)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::Pass > createConvertHWToBTOR2Pass(llvm::raw_ostream &os)
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)