11#include <mlir/IR/Builders.h>
12#include <mlir/IR/OpImplementation.h>
14#include <llvm/ADT/APSInt.h>
15#include <llvm/ADT/StringExtras.h>
16#include <llvm/ADT/TypeSwitch.h>
21static bool isValidSetInfoValue(Attribute attr) {
22 return TypeSwitch<Attribute, bool>(attr)
23 .Case<BoolAttr, IntegerAttr, StringAttr, KeywordAttr, SymbolAttr>([](
auto) {
return true; })
24 .Case<ArrayAttr>([](ArrayAttr arrayAttr) {
25 return llvm::all_of(arrayAttr, [](Attribute element) {
return isValidSetInfoValue(element); });
26 }).Default([](Attribute) {
return false; });
29static void printSetInfoValue(AsmPrinter &printer, Attribute value) {
30 TypeSwitch<Attribute>(value)
31 .Case<KeywordAttr>([&printer](
auto keywordAttr) { printer << keywordAttr.getValue(); })
32 .Case<SymbolAttr>([&printer](
auto symbolAttr) { printer << symbolAttr.getValue(); })
33 .Case<StringAttr, BoolAttr>([&printer](
auto attr) { printer.printAttribute(attr); })
34 .Case<IntegerAttr>([&printer](
auto intAttr) {
35 SmallString<32> valueText;
36 intAttr.getValue().toStringSigned(valueText);
38 }).Case<ArrayAttr>([&printer](ArrayAttr arrayAttr) {
40 llvm::interleave(arrayAttr, [&printer](Attribute element) {
41 printSetInfoValue(printer, element);
42 }, [&printer] { printer <<
' '; });
47static ParseResult parseSetInfoValue(OpAsmParser &parser, Attribute &value) {
48 Builder builder(parser.getContext());
50 if (succeeded(parser.parseOptionalLParen())) {
51 SmallVector<Attribute> elements;
52 while (failed(parser.parseOptionalRParen())) {
54 if (parseSetInfoValue(parser, element)) {
57 elements.push_back(element);
59 value = builder.getArrayAttr(elements);
63 if (succeeded(parser.parseOptionalColon())) {
65 if (parser.parseKeyword(&keyword)) {
68 value = KeywordAttr::get(parser.getContext(), (
":" + keyword).str());
74 OptionalParseResult parseResult = parser.parseOptionalInteger(numeral);
75 if (!parseResult.has_value()) {
78 if (failed(*parseResult)) {
81 auto intType = IntegerType::get(parser.getContext(), numeral.getBitWidth());
82 value = IntegerAttr::get(intType, numeral);
89 OptionalParseResult parseResult = parser.parseOptionalAttribute(strAttr, Type());
90 if (!parseResult.has_value()) {
93 if (failed(*parseResult)) {
101 StringRef symbolOrBool;
102 if (succeeded(parser.parseOptionalKeyword(&symbolOrBool))) {
103 if (symbolOrBool ==
"true" || symbolOrBool ==
"false") {
104 value = builder.getBoolAttr(symbolOrBool ==
"true");
106 value = SymbolAttr::get(parser.getContext(), symbolOrBool);
111 parser.emitError(parser.getCurrentLocation()) <<
"expected SMT-LIB set-info value";
120 MLIRContext * , std::optional<Location> , ValueRange ,
121 DictionaryAttr , OpaqueProperties properties, RegionRange ,
122 SmallVectorImpl<Type> &inferredReturnTypes
124 inferredReturnTypes.push_back(properties.as<
Properties *>()->getValue().getType());
129 SmallVector<char, 128> specialNameBuffer;
130 llvm::raw_svector_ostream specialName(specialNameBuffer);
131 specialName <<
"c" <<
getValue().getValue() <<
"_bv" <<
getValue().getValue().getBitWidth();
132 setNameFn(
getResult(), specialName.str());
136 assert(adaptor.
getOperands().empty() &&
"constant has no operands");
153 if (getBody()->getTerminator()->getOperands().getTypes() != getResultTypes()) {
154 return emitOpError() <<
"types of yielded values must match return values";
156 if (getBody()->getArgumentTypes() !=
getInputs().getTypes()) {
157 return emitOpError() <<
"block argument types must match the types of the 'inputs'";
168 SMLoc loc = parser.getCurrentLocation();
172 if (parser.parseAttribute(keyText) || parseSetInfoValue(parser, value) ||
173 parser.parseOptionalAttrDict(result.attributes)) {
177 auto keyAttr = KeywordAttr::getChecked([&parser, loc]() {
178 return parser.emitError(loc);
179 }, parser.getContext(), keyText.getValue());
184 result.addAttribute(
"key", keyAttr);
185 result.addAttribute(
"value", value);
186 result.location = parser.getEncodedSourceLoc(loc);
192 printer.printAttribute(StringAttr::get(getContext(),
getKey().
getValue()));
195 printer.printOptionalAttrDict(getOperation()->getAttrs(), {
"key",
"value"});
201 "requires an SMT-LIB set-info value built from strings, booleans, "
202 "integers, SMT keywords, SMT symbols, or nested lists"
213 if (
getSatRegion().front().getTerminator()->getOperands().getTypes() != getResultTypes()) {
214 return emitOpError() <<
"types of yielded values in 'sat' region must "
215 "match return values";
217 if (
getUnknownRegion().front().getTerminator()->getOperands().getTypes() != getResultTypes()) {
218 return emitOpError() <<
"types of yielded values in 'unknown' region must "
219 "match return values";
221 if (
getUnsatRegion().front().getTerminator()->getOperands().getTypes() != getResultTypes()) {
222 return emitOpError() <<
"types of yielded values in 'unsat' region must "
223 "match return values";
234parseSameOperandTypeVariadicToBoolOp(OpAsmParser &parser, OperationState &result) {
235 SmallVector<OpAsmParser::UnresolvedOperand, 4> inputs;
236 SMLoc loc = parser.getCurrentLocation();
239 if (parser.parseOperandList(inputs) || parser.parseOptionalAttrDict(result.attributes) ||
240 parser.parseColon() || parser.parseType(type)) {
244 result.addTypes(BoolType::get(parser.getContext()));
245 if (parser.resolveOperands(
246 inputs, SmallVector<Type>(inputs.size(), type), loc, result.operands
254ParseResult
EqOp::parse(OpAsmParser &parser, OperationState &result) {
255 return parseSameOperandTypeVariadicToBoolOp(parser, result);
260 printer.printOptionalAttrDict(getOperation()->getAttrs());
261 printer <<
" : " <<
getInputs().front().getType();
266 return emitOpError() <<
"'inputs' must have at least size 2, but got " <<
getInputs().size();
277 return parseSameOperandTypeVariadicToBoolOp(parser, result);
282 printer.printOptionalAttrDict(getOperation()->getAttrs());
283 printer <<
" : " <<
getInputs().front().getType();
288 return emitOpError() <<
"'inputs' must have at least size 2, but got " <<
getInputs().size();
299 unsigned rangeWidth = getType().getWidth();
301 if (
getLowBit() + rangeWidth > inputWidth) {
303 "range to be extracted is too big, expected range "
306 <<
getLowBit() <<
" of length " << rangeWidth <<
" requires input width of at least "
307 << (
getLowBit() + rangeWidth) <<
", but the input width is only " << inputWidth;
317 MLIRContext *context, std::optional<Location> , ValueRange operands,
318 DictionaryAttr , OpaqueProperties , RegionRange ,
319 SmallVectorImpl<Type> &inferredReturnTypes
321 inferredReturnTypes.push_back(
336 unsigned resultWidth = getType().getWidth();
337 if (resultWidth % inputWidth != 0) {
338 return emitOpError() <<
"result bit-vector width must be a multiple of the "
339 "input bit-vector width";
347 unsigned resultWidth = getType().getWidth();
348 return resultWidth / inputWidth;
351void RepeatOp::build(OpBuilder &builder, OperationState &state,
unsigned count, Value input) {
354 build(builder, state, resultTy, input);
358 OpAsmParser::UnresolvedOperand input;
360 llvm::SMLoc countLoc = parser.getCurrentLocation();
363 if (parser.parseInteger(count) || parser.parseKeyword(
"times")) {
367 if (count.isNonPositive()) {
368 return parser.emitError(countLoc) <<
"integer must be positive";
371 llvm::SMLoc inputLoc = parser.getCurrentLocation();
372 if (parser.parseOperand(input) || parser.parseOptionalAttrDict(result.attributes) ||
373 parser.parseColon() || parser.parseType(inputType)) {
377 if (parser.resolveOperand(input, inputType, result.operands)) {
381 auto bvInputTy = dyn_cast<BitVectorType>(inputType);
383 return parser.emitError(inputLoc) <<
"input must have bit-vector type";
388 const unsigned maxBw = 63;
389 if (count.getActiveBits() > maxBw) {
390 return parser.emitError(countLoc) <<
"integer must fit into " << maxBw <<
" bits";
396 APInt resultBw = bvInputTy.getWidth() * count.zext(2 * maxBw);
397 if (resultBw.getActiveBits() > maxBw) {
398 return parser.emitError(countLoc)
399 <<
"result bit-width (provided integer times bit-width of the input "
400 "type) must fit into "
404 uint64_t val = resultBw.getZExtValue();
405 assert(val <= std::numeric_limits<int64_t>::max() &&
"value too large");
407 result.addTypes(resultTy);
413 printer.printOptionalAttrDict((*this)->getAttrs());
414 printer <<
" : " <<
getInput().getType();
426 assert(adaptor.
getOperands().empty() &&
"constant has no operands");
435 SmallVector<char, 32> specialNameBuffer;
436 llvm::raw_svector_ostream specialName(specialNameBuffer);
438 setNameFn(
getResult(), specialName.str());
442 assert(adaptor.
getOperands().empty() &&
"constant has no operands");
448 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
453 if (parser.parseInteger(value)) {
457 result.getOrAddProperties<
Properties>().setValue(
458 IntegerAttr::get(parser.getContext(), APSInt(value))
461 if (parser.parseOptionalAttrDict(result.attributes)) {
465 result.addTypes(smt::IntType::get(parser.getContext()));
473template <
typename QuantifierOp>
static LogicalResult verifyQuantifierRegions(QuantifierOp op) {
474 if (op.getBoundVarNames() && op.getBody().getNumArguments() != op.getBoundVarNames()->size()) {
475 return op.emitOpError(
"number of bound variable names must match number of block arguments");
478 return op.emitOpError() <<
"bound variables must by any non-function SMT value";
481 if (op.getBody().front().getTerminator()->getNumOperands() != 1) {
482 return op.emitOpError(
"must have exactly one yielded value");
484 if (!isa<BoolType>(op.getBody().front().getTerminator()->getOperand(0).getType())) {
485 return op.emitOpError(
"yielded value must be of '!smt.bool' type");
488 for (
auto regionWithIndex : llvm::enumerate(op.getPatterns())) {
489 unsigned i = regionWithIndex.index();
490 Region ®ion = regionWithIndex.value();
492 if (op.getBody().getArgumentTypes() != region.getArgumentTypes()) {
493 return op.emitOpError() <<
"block argument number and types of the 'body' "
494 "and 'patterns' region #"
495 << i <<
" must match";
497 if (region.front().getTerminator()->getNumOperands() < 1) {
498 return op.emitOpError() <<
"'patterns' region #" << i
499 <<
" must have at least one yielded value";
503 auto result = region.walk([&](Operation *childOp) {
504 if (!isa<SMTDialect>(childOp->getDialect())) {
505 auto diag = op.emitOpError()
506 <<
"the 'patterns' region #" << i <<
" may only contain SMT dialect operations";
507 diag.attachNote(childOp->getLoc()) <<
"first non-SMT operation here";
508 return WalkResult::interrupt();
513 if (isa<ForallOp, ExistsOp>(childOp)) {
514 auto diag = op.emitOpError() <<
"the 'patterns' region #" << i
515 <<
" must not contain "
516 "any variable binding operations";
517 diag.attachNote(childOp->getLoc()) <<
"first violating operation here";
518 return WalkResult::interrupt();
521 return WalkResult::advance();
523 if (result.wasInterrupted()) {
531template <
typename Properties>
532static void buildQuantifier(
533 OpBuilder &odsBuilder, OperationState &odsState, TypeRange boundVarTypes,
534 function_ref<Value(OpBuilder &, Location, ValueRange)> bodyBuilder,
535 std::optional<ArrayRef<StringRef>> boundVarNames,
536 function_ref<ValueRange(OpBuilder &, Location, ValueRange)> patternBuilder, uint32_t weight,
539 odsState.addTypes(BoolType::get(odsBuilder.getContext()));
541 odsState.getOrAddProperties<Properties>().weight =
542 odsBuilder.getIntegerAttr(odsBuilder.getIntegerType(32), weight);
545 odsState.getOrAddProperties<Properties>().noPattern = odsBuilder.getUnitAttr();
547 if (boundVarNames.has_value()) {
548 SmallVector<Attribute> boundVarNamesList;
549 for (StringRef str : *boundVarNames) {
550 boundVarNamesList.emplace_back(odsBuilder.getStringAttr(str));
552 odsState.getOrAddProperties<Properties>().boundVarNames =
553 odsBuilder.getArrayAttr(boundVarNamesList);
556 OpBuilder::InsertionGuard guard(odsBuilder);
557 Region *region = odsState.addRegion();
558 Block *block = odsBuilder.createBlock(region);
560 boundVarTypes, SmallVector<Location>(boundVarTypes.size(), odsState.location)
562 Value returnVal = bodyBuilder(odsBuilder, odsState.location, block->getArguments());
563 odsBuilder.create<llzk::smt::YieldOp>(odsState.location, returnVal);
565 if (patternBuilder) {
566 Region *region = odsState.addRegion();
567 OpBuilder::InsertionGuard guard(odsBuilder);
568 Block *block = odsBuilder.createBlock(region);
570 boundVarTypes, SmallVector<Location>(boundVarTypes.size(), odsState.location)
572 ValueRange returnVals = patternBuilder(odsBuilder, odsState.location, block->getArguments());
573 odsBuilder.create<llzk::smt::YieldOp>(odsState.location, returnVals);
579 return emitOpError() <<
"patterns and the no_pattern attribute must not be "
580 "specified at the same time";
589 OpBuilder &odsBuilder, OperationState &odsState, TypeRange boundVarTypes,
590 function_ref<Value(OpBuilder &, Location, ValueRange)> bodyBuilder,
591 std::optional<ArrayRef<StringRef>> boundVarNames,
592 function_ref<ValueRange(OpBuilder &, Location, ValueRange)> patternBuilder, uint32_t weight,
595 buildQuantifier<Properties>(
596 odsBuilder, odsState, boundVarTypes, bodyBuilder, boundVarNames, patternBuilder, weight,
607 return emitOpError() <<
"patterns and the no_pattern attribute must not be "
608 "specified at the same time";
617 OpBuilder &odsBuilder, OperationState &odsState, TypeRange boundVarTypes,
618 function_ref<Value(OpBuilder &, Location, ValueRange)> bodyBuilder,
619 std::optional<ArrayRef<StringRef>> boundVarNames,
620 function_ref<ValueRange(OpBuilder &, Location, ValueRange)> patternBuilder, uint32_t weight,
623 buildQuantifier<Properties>(
624 odsBuilder, odsState, boundVarTypes, bodyBuilder, boundVarNames, patternBuilder, weight,
629#define GET_OP_CLASSES
void getAsmResultNames(::mlir::OpAsmSetValueNameFn setNameFn)
::llzk::smt::BitVectorAttr getValue()
::llzk::smt::BitVectorAttr getValueAttr()
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
::llvm::LogicalResult inferReturnTypes(::mlir::MLIRContext *context, ::std::optional<::mlir::Location > location, ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes, ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions, ::llvm::SmallVectorImpl<::mlir::Type > &inferredReturnTypes)
FoldAdaptor::Properties Properties
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::TypedValue<::llzk::smt::BitVectorType > getResult()
static BitVectorType get(::mlir::MLIRContext *context, int64_t width)
::mlir::TypedValue<::llzk::smt::BoolType > getResult()
void getAsmResultNames(::mlir::OpAsmSetValueNameFn setNameFn)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::BoolAttr getValueAttr()
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
::mlir::Region & getUnsatRegion()
::mlir::Region & getUnknownRegion()
::mlir::Region & getSatRegion()
::llvm::LogicalResult verifyRegions()
::llvm::LogicalResult inferReturnTypes(::mlir::MLIRContext *context, ::std::optional<::mlir::Location > location, ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes, ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions, ::llvm::SmallVectorImpl<::mlir::Type > &inferredReturnTypes)
::mlir::TypedValue<::mlir::Type > getResult()
void getAsmResultNames(::mlir::OpAsmSetValueNameFn setNameFn)
::std::optional< ::llvm::StringRef > getNamePrefix()
::mlir::Operation::operand_range getInputs()
void print(::mlir::OpAsmPrinter &p)
::llvm::LogicalResult verify()
::mlir::ParseResult parse(::mlir::OpAsmParser &parser, ::mlir::OperationState &result)
::mlir::Operation::operand_range getInputs()
void print(::mlir::OpAsmPrinter &p)
::mlir::ParseResult parse(::mlir::OpAsmParser &parser, ::mlir::OperationState &result)
::llvm::LogicalResult verify()
::llvm::LogicalResult verify()
::llvm::LogicalResult verifyRegions()
::mlir::MutableArrayRef<::mlir::Region > getPatterns()
static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, mlir::TypeRange boundVarTypes, llvm::function_ref< mlir::Value(mlir::OpBuilder &, mlir::Location, mlir::ValueRange)> bodyBuilder, std::optional< llvm::ArrayRef< mlir::StringRef > > boundVarNames=std::nullopt, llvm::function_ref< mlir::ValueRange(mlir::OpBuilder &, mlir::Location, mlir::ValueRange)> patternBuilder={}, uint32_t weight=0, bool noPattern=false)
::llvm::LogicalResult verifyRegions()
::llvm::LogicalResult verify()
static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, mlir::TypeRange boundVarTypes, llvm::function_ref< mlir::Value(mlir::OpBuilder &, mlir::Location, mlir::ValueRange)> bodyBuilder, std::optional< llvm::ArrayRef< mlir::StringRef > > boundVarNames=std::nullopt, llvm::function_ref< mlir::ValueRange(mlir::OpBuilder &, mlir::Location, mlir::ValueRange)> patternBuilder={}, uint32_t weight=0, bool noPattern=false)
::mlir::MutableArrayRef<::mlir::Region > getPatterns()
void print(::mlir::OpAsmPrinter &p)
GenericAdaptor<::llvm::ArrayRef<::mlir::Attribute > > FoldAdaptor
::mlir::OpFoldResult fold(FoldAdaptor adaptor)
::mlir::TypedValue<::llzk::smt::IntType > getResult()
void getAsmResultNames(::mlir::OpAsmSetValueNameFn setNameFn)
::mlir::ParseResult parse(::mlir::OpAsmParser &parser, ::mlir::OperationState &result)
FoldAdaptor::Properties Properties
::mlir::IntegerAttr getValueAttr()
::mlir::TypedValue<::llzk::smt::BitVectorType > getInput()
::llvm::LogicalResult verify()
static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, unsigned count, mlir::Value input)
void print(::mlir::OpAsmPrinter &p)
unsigned getCount()
Get the number of times the input operand is repeated.
::mlir::ParseResult parse(::mlir::OpAsmParser &parser, ::mlir::OperationState &result)
::mlir::Attribute getValue()
::llzk::smt::KeywordAttr getKey()
void print(::mlir::OpAsmPrinter &p)
::mlir::ParseResult parse(::mlir::OpAsmParser &parser, ::mlir::OperationState &result)
::mlir::Attribute getValueAttr()
::llvm::LogicalResult verify()
::llvm::LogicalResult verifyRegions()
::mlir::Operation::operand_range getInputs()
bool isAnyNonFuncSMTValueType(mlir::Type type)
Returns whether the given type is an SMT value type (excluding functions).