CIRCT  19.0.0git
ExportSMTLIB.cpp
Go to the documentation of this file.
1 //===- ExportSMTLIB.cpp - SMT-LIB Emitter -----=---------------------------===//
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 //
9 // This is the main SMT-LIB emitter implementation.
10 //
11 //===----------------------------------------------------------------------===//
12 
18 #include "mlir/Dialect/Func/IR/FuncOps.h"
19 #include "mlir/IR/BuiltinOps.h"
20 #include "mlir/Support/IndentedOstream.h"
21 #include "mlir/Tools/mlir-translate/Translation.h"
22 #include "llvm/ADT/ScopedHashTable.h"
23 #include "llvm/Support/Format.h"
24 
25 using namespace circt;
26 using namespace smt;
27 using namespace ExportSMTLIB;
28 
29 using ValueMap = llvm::ScopedHashTable<mlir::Value, std::string>;
30 
31 #define DEBUG_TYPE "export-smtlib"
32 
33 namespace {
34 
35 /// A visitor to print the SMT dialect types as SMT-LIB formatted sorts.
36 /// Printing nested types use recursive calls since nestings of a depth that
37 /// could lead to problems should not occur in practice.
38 struct TypeVisitor : public smt::SMTTypeVisitor<TypeVisitor, void,
39  mlir::raw_indented_ostream &> {
40  TypeVisitor(const SMTEmissionOptions &options) : options(options) {}
41 
42  void visitSMTType(BoolType type, mlir::raw_indented_ostream &stream) {
43  stream << "Bool";
44  }
45 
46  void visitSMTType(IntType type, mlir::raw_indented_ostream &stream) {
47  stream << "Int";
48  }
49 
50  void visitSMTType(BitVectorType type, mlir::raw_indented_ostream &stream) {
51  stream << "(_ BitVec " << type.getWidth() << ")";
52  }
53 
54  void visitSMTType(ArrayType type, mlir::raw_indented_ostream &stream) {
55  stream << "(Array ";
56  dispatchSMTTypeVisitor(type.getDomainType(), stream);
57  stream << " ";
58  dispatchSMTTypeVisitor(type.getRangeType(), stream);
59  stream << ")";
60  }
61 
62  void visitSMTType(SMTFuncType type, mlir::raw_indented_ostream &stream) {
63  stream << "(";
64  StringLiteral nextToken = "";
65 
66  for (Type domainTy : type.getDomainTypes()) {
67  stream << nextToken;
68  dispatchSMTTypeVisitor(domainTy, stream);
69  nextToken = " ";
70  }
71 
72  stream << ") ";
73  dispatchSMTTypeVisitor(type.getRangeType(), stream);
74  }
75 
76  void visitSMTType(SortType type, mlir::raw_indented_ostream &stream) {
77  if (!type.getSortParams().empty())
78  stream << "(";
79 
80  stream << type.getIdentifier().getValue();
81  for (Type paramTy : type.getSortParams()) {
82  stream << " ";
83  dispatchSMTTypeVisitor(paramTy, stream);
84  }
85 
86  if (!type.getSortParams().empty())
87  stream << ")";
88  }
89 
90 private:
91  // A reference to the emission options for easy use in the visitor methods.
92  [[maybe_unused]] const SMTEmissionOptions &options;
93 };
94 
95 /// Contains the informations passed to the ExpressionVisitor methods. Makes it
96 /// easier to add more information.
97 struct VisitorInfo {
98  VisitorInfo(mlir::raw_indented_ostream &stream, ValueMap &valueMap)
99  : stream(stream), valueMap(valueMap) {}
100  VisitorInfo(mlir::raw_indented_ostream &stream, ValueMap &valueMap,
101  unsigned indentLevel, unsigned openParens)
102  : stream(stream), valueMap(valueMap), indentLevel(indentLevel),
103  openParens(openParens) {}
104 
105  // Stream to print to.
106  mlir::raw_indented_ostream &stream;
107  // Mapping from SSA values to SMT-LIB expressions.
108  ValueMap &valueMap;
109  // Total number of spaces currently indented.
110  unsigned indentLevel = 0;
111  // Number of parentheses that have been opened but not closed yet.
112  unsigned openParens = 0;
113 };
114 
115 /// A visitor to print SMT dialect operations with exactly one result value as
116 /// the equivalent operator in SMT-LIB.
117 struct ExpressionVisitor
118  : public smt::SMTOpVisitor<ExpressionVisitor, LogicalResult,
119  VisitorInfo &> {
120  using Base =
122  using Base::visitSMTOp;
123 
124  ExpressionVisitor(const SMTEmissionOptions &options, Namespace &names)
125  : options(options), typeVisitor(options), names(names) {}
126 
127  LogicalResult dispatchSMTOpVisitor(Operation *op, VisitorInfo &info) {
128  assert(op->getNumResults() == 1 &&
129  "expression op must have exactly one result value");
130 
131  // Print the expression inlined if it is only used once and the
132  // corresponding emission option is enabled. This can lead to bad
133  // performance for big inputs since the inlined expression is stored as a
134  // string in the value mapping where otherwise only the symbol names of free
135  // and bound variables are stored, and due to a lot of string concatenation
136  // (thus it's off by default and just intended to print small examples in a
137  // more human-readable format).
138  Value res = op->getResult(0);
139  if (res.hasOneUse() && options.inlineSingleUseValues) {
140  std::string str;
141  llvm::raw_string_ostream sstream(str);
142  mlir::raw_indented_ostream indentedStream(sstream);
143 
144  VisitorInfo newInfo(indentedStream, info.valueMap, info.indentLevel,
145  info.openParens);
146  if (failed(Base::dispatchSMTOpVisitor(op, newInfo)))
147  return failure();
148 
149  info.valueMap.insert(res, str);
150  return success();
151  }
152 
153  // Generate a let binding for the current expression being processed and
154  // store the sybmol in the value map. Indent the expressions for easier
155  // readability.
156  auto name = names.newName("tmp");
157  info.valueMap.insert(res, name.str());
158  info.stream << "(let ((" << name << " ";
159 
160  VisitorInfo newInfo(info.stream, info.valueMap,
161  info.indentLevel + 8 + name.size(), 0);
162  if (failed(Base::dispatchSMTOpVisitor(op, newInfo)))
163  return failure();
164 
165  info.stream << "))\n";
166 
167  if (options.indentLetBody) {
168  // Five spaces to align with the opening parenthesis
169  info.indentLevel += 5;
170  }
171  ++info.openParens;
172  info.stream.indent(info.indentLevel);
173 
174  return success();
175  }
176 
177  //===--------------------------------------------------------------------===//
178  // Bit-vector theory operation visitors
179  //===--------------------------------------------------------------------===//
180 
181  template <typename Op>
182  LogicalResult printBinaryOp(Op op, StringRef name, VisitorInfo &info) {
183  info.stream << "(" << name << " " << info.valueMap.lookup(op.getLhs())
184  << " " << info.valueMap.lookup(op.getRhs()) << ")";
185  return success();
186  }
187 
188  template <typename Op>
189  LogicalResult printVariadicOp(Op op, StringRef name, VisitorInfo &info) {
190  info.stream << "(" << name;
191  for (Value val : op.getOperands())
192  info.stream << " " << info.valueMap.lookup(val);
193  info.stream << ")";
194  return success();
195  }
196 
197  LogicalResult visitSMTOp(BVNegOp op, VisitorInfo &info) {
198  info.stream << "(bvneg " << info.valueMap.lookup(op.getInput()) << ")";
199  return success();
200  }
201 
202  LogicalResult visitSMTOp(BVNotOp op, VisitorInfo &info) {
203  info.stream << "(bvnot " << info.valueMap.lookup(op.getInput()) << ")";
204  return success();
205  }
206 
207 #define HANDLE_OP(OPTYPE, NAME, KIND) \
208  LogicalResult visitSMTOp(OPTYPE op, VisitorInfo &info) { \
209  return print##KIND##Op(op, NAME, info); \
210  }
211 
212  HANDLE_OP(BVAddOp, "bvadd", Binary);
213  HANDLE_OP(BVMulOp, "bvmul", Binary);
214  HANDLE_OP(BVURemOp, "bvurem", Binary);
215  HANDLE_OP(BVSRemOp, "bvsrem", Binary);
216  HANDLE_OP(BVSModOp, "bvsmod", Binary);
217  HANDLE_OP(BVShlOp, "bvshl", Binary);
218  HANDLE_OP(BVLShrOp, "bvlshr", Binary);
219  HANDLE_OP(BVAShrOp, "bvashr", Binary);
220  HANDLE_OP(BVUDivOp, "bvudiv", Binary);
221  HANDLE_OP(BVSDivOp, "bvsdiv", Binary);
222  HANDLE_OP(BVAndOp, "bvand", Binary);
223  HANDLE_OP(BVOrOp, "bvor", Binary);
224  HANDLE_OP(BVXOrOp, "bvxor", Binary);
225  HANDLE_OP(ConcatOp, "concat", Binary);
226 
227  LogicalResult visitSMTOp(ExtractOp op, VisitorInfo &info) {
228  info.stream << "((_ extract "
229  << (op.getLowBit() + op.getType().getWidth() - 1) << " "
230  << op.getLowBit() << ") " << info.valueMap.lookup(op.getInput())
231  << ")";
232  return success();
233  }
234 
235  LogicalResult visitSMTOp(RepeatOp op, VisitorInfo &info) {
236  info.stream << "((_ repeat " << op.getCount() << ") "
237  << info.valueMap.lookup(op.getInput()) << ")";
238  return success();
239  }
240 
241  LogicalResult visitSMTOp(BVCmpOp op, VisitorInfo &info) {
242  return printBinaryOp(op, "bv" + stringifyBVCmpPredicate(op.getPred()).str(),
243  info);
244  }
245 
246  //===--------------------------------------------------------------------===//
247  // Int theory operation visitors
248  //===--------------------------------------------------------------------===//
249 
250  HANDLE_OP(IntAddOp, "+", Variadic);
251  HANDLE_OP(IntMulOp, "*", Variadic);
252  HANDLE_OP(IntSubOp, "-", Binary);
253  HANDLE_OP(IntDivOp, "div", Binary);
254  HANDLE_OP(IntModOp, "mod", Binary);
255 
256  LogicalResult visitSMTOp(IntCmpOp op, VisitorInfo &info) {
257  switch (op.getPred()) {
258  case IntPredicate::ge:
259  return printBinaryOp(op, ">=", info);
260  case IntPredicate::le:
261  return printBinaryOp(op, "<=", info);
262  case IntPredicate::gt:
263  return printBinaryOp(op, ">", info);
264  case IntPredicate::lt:
265  return printBinaryOp(op, "<", info);
266  }
267  return failure();
268  }
269 
270  //===--------------------------------------------------------------------===//
271  // Core theory operation visitors
272  //===--------------------------------------------------------------------===//
273 
274  HANDLE_OP(EqOp, "=", Variadic);
275  HANDLE_OP(DistinctOp, "distinct", Variadic);
276 
277  LogicalResult visitSMTOp(IteOp op, VisitorInfo &info) {
278  info.stream << "(ite " << info.valueMap.lookup(op.getCond()) << " "
279  << info.valueMap.lookup(op.getThenValue()) << " "
280  << info.valueMap.lookup(op.getElseValue()) << ")";
281  return success();
282  }
283 
284  LogicalResult visitSMTOp(ApplyFuncOp op, VisitorInfo &info) {
285  info.stream << "(" << info.valueMap.lookup(op.getFunc());
286  for (Value arg : op.getArgs())
287  info.stream << " " << info.valueMap.lookup(arg);
288  info.stream << ")";
289  return success();
290  }
291 
292  template <typename OpTy>
293  LogicalResult quantifierHelper(OpTy op, StringRef operatorString,
294  VisitorInfo &info) {
295  auto weight = op.getWeight();
296  // TODO: add support
297  if (op.getNoPattern())
298  return op.emitError() << "no-pattern attribute not supported yet";
299  if (!op.getPatterns().empty())
300  return op.emitError() << "patterns not supported yet";
301 
302  llvm::ScopedHashTableScope<Value, std::string> scope(info.valueMap);
303  info.stream << "(" << operatorString << " (";
304 
305  StringLiteral delimiter = "";
306  for (auto [i, arg] : llvm::enumerate(op.getBody().getArguments())) {
307  // Generate and register a new unique name.
308  StringRef prefix =
309  op.getBoundVarNames()
310  ? cast<StringAttr>(op.getBoundVarNames()->getValue()[i])
311  .getValue()
312  : "tmp";
313  StringRef name = names.newName(prefix);
314  info.valueMap.insert(arg, name.str());
315 
316  // Print the bound variable declaration.
317  info.stream << delimiter << "(" << name << " ";
318  typeVisitor.dispatchSMTTypeVisitor(arg.getType(), info.stream);
319  info.stream << ")";
320  delimiter = " ";
321  }
322 
323  info.stream << ")\n";
324 
325  if (weight != 0)
326  info.stream << "( ! ";
327 
328  // Print the quantifier body. This assumes that quantifiers are not deeply
329  // nested (at least not enough that recursive calls could become a problem).
330  SmallVector<Value> worklist;
331  Value yieldedValue = op.getBody().front().getTerminator()->getOperand(0);
332  worklist.push_back(yieldedValue);
333  unsigned indentExt = operatorString.size() + 2;
334  VisitorInfo newInfo(info.stream, info.valueMap,
335  info.indentLevel + indentExt, 0);
336  newInfo.stream.indent(newInfo.indentLevel);
337  if (failed(printExpression(worklist, newInfo)))
338  return failure();
339 
340  info.stream << info.valueMap.lookup(yieldedValue);
341 
342  for (unsigned j = 0; j < newInfo.openParens; ++j)
343  info.stream << ")";
344 
345  if (weight != 0)
346  info.stream << " :weight " << weight << ")";
347 
348  info.stream << ")";
349 
350  return success();
351  }
352 
353  LogicalResult visitSMTOp(ForallOp op, VisitorInfo &info) {
354  return quantifierHelper(op, "forall", info);
355  }
356 
357  LogicalResult visitSMTOp(ExistsOp op, VisitorInfo &info) {
358  return quantifierHelper(op, "exists", info);
359  }
360 
361  LogicalResult visitSMTOp(NotOp op, VisitorInfo &info) {
362  info.stream << "(not " << info.valueMap.lookup(op.getInput()) << ")";
363  return success();
364  }
365 
366  HANDLE_OP(AndOp, "and", Variadic);
367  HANDLE_OP(OrOp, "or", Variadic);
368  HANDLE_OP(XOrOp, "xor", Variadic);
369  HANDLE_OP(ImpliesOp, "=>", Binary);
370 
371  //===--------------------------------------------------------------------===//
372  // Array theory operation visitors
373  //===--------------------------------------------------------------------===//
374 
375  LogicalResult visitSMTOp(ArrayStoreOp op, VisitorInfo &info) {
376  info.stream << "(store " << info.valueMap.lookup(op.getArray()) << " "
377  << info.valueMap.lookup(op.getIndex()) << " "
378  << info.valueMap.lookup(op.getValue()) << ")";
379  return success();
380  }
381 
382  LogicalResult visitSMTOp(ArraySelectOp op, VisitorInfo &info) {
383  info.stream << "(select " << info.valueMap.lookup(op.getArray()) << " "
384  << info.valueMap.lookup(op.getIndex()) << ")";
385  return success();
386  }
387 
388  LogicalResult visitSMTOp(ArrayBroadcastOp op, VisitorInfo &info) {
389  info.stream << "((as const ";
390  typeVisitor.dispatchSMTTypeVisitor(op.getType(), info.stream);
391  info.stream << ") " << info.valueMap.lookup(op.getValue()) << ")";
392  return success();
393  }
394 
395  LogicalResult visitUnhandledSMTOp(Operation *op, VisitorInfo &info) {
396  return success();
397  }
398 
399 #undef HANDLE_OP
400 
401  /// Print an expression transitively. The root node should be added to the
402  /// 'worklist' before calling.
403  LogicalResult printExpression(SmallVector<Value> &worklist,
404  VisitorInfo &info) {
405  while (!worklist.empty()) {
406  Value curr = worklist.back();
407 
408  // If we already have a let-binding for the value, just print it.
409  if (info.valueMap.count(curr)) {
410  worklist.pop_back();
411  continue;
412  }
413 
414  // Traverse until we reach a value/operation that has all operands
415  // available and can thus be printed.
416  bool allAvailable = true;
417  Operation *defOp = curr.getDefiningOp();
418  assert(defOp != nullptr &&
419  "block arguments must already be in the valueMap");
420 
421  for (Value val : defOp->getOperands()) {
422  if (!info.valueMap.count(val)) {
423  worklist.push_back(val);
424  allAvailable = false;
425  }
426  }
427 
428  if (!allAvailable)
429  continue;
430 
431  if (failed(dispatchSMTOpVisitor(curr.getDefiningOp(), info)))
432  return failure();
433 
434  worklist.pop_back();
435  }
436 
437  return success();
438  }
439 
440 private:
441  // A reference to the emission options for easy use in the visitor methods.
442  [[maybe_unused]] const SMTEmissionOptions &options;
443  TypeVisitor typeVisitor;
444  Namespace &names;
445 };
446 
447 /// A visitor to print SMT dialect operations with zero result values or
448 /// ones that have to initialize some global state.
449 struct StatementVisitor
450  : public smt::SMTOpVisitor<StatementVisitor, LogicalResult,
451  mlir::raw_indented_ostream &, ValueMap &> {
452  using smt::SMTOpVisitor<StatementVisitor, LogicalResult,
453  mlir::raw_indented_ostream &, ValueMap &>::visitSMTOp;
454 
455  StatementVisitor(const SMTEmissionOptions &options, Namespace &names)
456  : options(options), typeVisitor(options), names(names),
457  exprVisitor(options, names) {}
458 
459  LogicalResult visitSMTOp(BVConstantOp op, mlir::raw_indented_ostream &stream,
460  ValueMap &valueMap) {
461  valueMap.insert(op.getResult(), op.getValue().getValueAsString());
462  return success();
463  }
464 
465  LogicalResult visitSMTOp(BoolConstantOp op,
466  mlir::raw_indented_ostream &stream,
467  ValueMap &valueMap) {
468  valueMap.insert(op.getResult(), op.getValue() ? "true" : "false");
469  return success();
470  }
471 
472  LogicalResult visitSMTOp(IntConstantOp op, mlir::raw_indented_ostream &stream,
473  ValueMap &valueMap) {
474  SmallString<16> str;
475  op.getValue().toStringSigned(str);
476  valueMap.insert(op.getResult(), str.str().str());
477  return success();
478  }
479 
480  LogicalResult visitSMTOp(DeclareFunOp op, mlir::raw_indented_ostream &stream,
481  ValueMap &valueMap) {
482  StringRef name =
483  names.newName(op.getNamePrefix() ? *op.getNamePrefix() : "tmp");
484  valueMap.insert(op.getResult(), name.str());
485  stream << "("
486  << (isa<SMTFuncType>(op.getType()) ? "declare-fun "
487  : "declare-const ")
488  << name << " ";
489  typeVisitor.dispatchSMTTypeVisitor(op.getType(), stream);
490  stream << ")\n";
491  return success();
492  }
493 
494  LogicalResult visitSMTOp(AssertOp op, mlir::raw_indented_ostream &stream,
495  ValueMap &valueMap) {
496  llvm::ScopedHashTableScope<Value, std::string> scope1(valueMap);
497  SmallVector<Value> worklist;
498  worklist.push_back(op.getInput());
499  stream << "(assert ";
500  VisitorInfo info(stream, valueMap, 8, 0);
501  if (failed(exprVisitor.printExpression(worklist, info)))
502  return failure();
503  stream << valueMap.lookup(op.getInput());
504  for (unsigned i = 0; i < info.openParens + 1; ++i)
505  stream << ")";
506  stream << "\n";
507  stream.indent(0);
508  return success();
509  }
510 
511  LogicalResult visitSMTOp(CheckOp op, mlir::raw_indented_ostream &stream,
512  ValueMap &valueMap) {
513  if (op->getNumResults() != 0)
514  return op.emitError() << "must not have any result values";
515 
516  if (op.getSatRegion().front().getOperations().size() != 1)
517  return op->emitError() << "'sat' region must be empty";
518  if (op.getUnknownRegion().front().getOperations().size() != 1)
519  return op->emitError() << "'unknown' region must be empty";
520  if (op.getUnsatRegion().front().getOperations().size() != 1)
521  return op->emitError() << "'unsat' region must be empty";
522 
523  stream << "(check-sat)\n";
524  return success();
525  }
526 
527  LogicalResult visitUnhandledSMTOp(Operation *op,
528  mlir::raw_indented_ostream &stream,
529  ValueMap &valueMap) {
530  // Ignore operations which are handled in the Expression Visitor.
531  return success();
532  }
533 
534 private:
535  // A reference to the emission options for easy use in the visitor methods.
536  [[maybe_unused]] const SMTEmissionOptions &options;
537  TypeVisitor typeVisitor;
538  Namespace &names;
539  ExpressionVisitor exprVisitor;
540 };
541 
542 } // namespace
543 
544 //===----------------------------------------------------------------------===//
545 // Unified Emitter implementation
546 //===----------------------------------------------------------------------===//
547 
548 /// Emit the SMT operations in the given 'solver' to the 'stream'.
549 static LogicalResult emit(SolverOp solver, const SMTEmissionOptions &options,
550  mlir::raw_indented_ostream &stream) {
551  if (!solver.getInputs().empty() || solver->getNumResults() != 0)
552  return solver->emitError()
553  << "solver scopes with inputs or results are not supported";
554 
555  Block *block = solver.getBody();
556 
557  // Declare uninterpreted sorts.
558  DenseMap<StringAttr, unsigned> declaredSorts;
559  auto result = block->walk([&](Operation *op) -> WalkResult {
560  if (!isa<SMTDialect>(op->getDialect()))
561  return op->emitError()
562  << "solver must not contain any non-SMT operations";
563 
564  for (Type resTy : op->getResultTypes()) {
565  auto sortTy = dyn_cast<SortType>(resTy);
566  if (!sortTy)
567  continue;
568 
569  unsigned arity = sortTy.getSortParams().size();
570  if (declaredSorts.contains(sortTy.getIdentifier())) {
571  if (declaredSorts[sortTy.getIdentifier()] != arity)
572  return op->emitError("uninterpreted sorts with same identifier but "
573  "different arity found");
574 
575  continue;
576  }
577 
578  declaredSorts[sortTy.getIdentifier()] = arity;
579  stream << "(declare-sort " << sortTy.getIdentifier().getValue() << " "
580  << arity << ")\n";
581  }
582  return WalkResult::advance();
583  });
584  if (result.wasInterrupted())
585  return failure();
586 
587  ValueMap valueMap;
588  llvm::ScopedHashTableScope<Value, std::string> scope0(valueMap);
589  Namespace names;
590  StatementVisitor visitor(options, names);
591 
592  // Collect all statement operations (ops with no result value).
593  // Declare constants and then only refer to them by identifier later on.
594  result = block->walk([&](Operation *op) {
595  if (failed(visitor.dispatchSMTOpVisitor(op, stream, valueMap)))
596  return WalkResult::interrupt();
597  return WalkResult::advance();
598  });
599  if (result.wasInterrupted())
600  return failure();
601 
602  stream << "(reset)\n";
603  return success();
604 }
605 
606 LogicalResult ExportSMTLIB::exportSMTLIB(Operation *module,
607  llvm::raw_ostream &os,
608  const SMTEmissionOptions &options) {
609  if (module->getNumRegions() != 1)
610  return module->emitError("must have exactly one region");
611  if (!module->getRegion(0).hasOneBlock())
612  return module->emitError("op region must have exactly one block");
613 
614  mlir::raw_indented_ostream ios(os);
615  unsigned solverIdx = 0;
616  auto result = module->walk([&](SolverOp solver) {
617  ios << "; solver scope " << solverIdx << "\n";
618  if (failed(emit(solver, options, ios)))
619  return WalkResult::interrupt();
620  ++solverIdx;
621  return WalkResult::advance();
622  });
623 
624  return failure(result.wasInterrupted());
625 }
626 
627 //===----------------------------------------------------------------------===//
628 // circt-translate registration
629 //===----------------------------------------------------------------------===//
630 
632  static llvm::cl::opt<bool> inlineSingleUseValues(
633  "smtlibexport-inline-single-use-values",
634  llvm::cl::desc("Inline expressions that are used only once rather than "
635  "generating a let-binding"),
636  llvm::cl::init(false));
637 
638  auto getOptions = [] {
639  SMTEmissionOptions opts;
640  opts.inlineSingleUseValues = inlineSingleUseValues;
641  return opts;
642  };
643 
644  static mlir::TranslateFromMLIRRegistration toSMTLIB(
645  "export-smtlib", "export SMT-LIB",
646  [=](Operation *module, raw_ostream &output) {
647  return ExportSMTLIB::exportSMTLIB(module, output, getOptions());
648  },
649  [](mlir::DialectRegistry &registry) {
650  // Register the 'func' and 'HW' dialects to support printing solver
651  // scopes nested in functions and modules.
652  registry
653  .insert<mlir::func::FuncDialect, hw::HWDialect, smt::SMTDialect>();
654  });
655 }
assert(baseType &&"element must be base type")
static LogicalResult emit(SolverOp solver, const SMTEmissionOptions &options, mlir::raw_indented_ostream &stream)
Emit the SMT operations in the given 'solver' to the 'stream'.
#define HANDLE_OP(OPTYPE, NAME, KIND)
llvm::ScopedHashTable< mlir::Value, std::string > ValueMap
A namespace that is used to store existing names and generate new names in some scope within the IR.
Definition: Namespace.h:29
StringRef newName(const Twine &name)
Return a unique name, derived from the input name, and add the new name to the internal namespace.
Definition: Namespace.h:63
This helps visit SMT nodes.
Definition: SMTVisitors.h:25
This helps visit SMT types.
Definition: SMTVisitors.h:152
LogicalResult exportSMTLIB(Operation *module, llvm::raw_ostream &os, const SMTEmissionOptions &options=SMTEmissionOptions())
Run the ExportSMTLIB pass.
void registerExportSMTLIBTranslation()
Register the ExportSMTLIB pass.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Emission options for the ExportSMTLIB pass.
Definition: ExportSMTLIB.h:23