CBMC
Loading...
Searching...
No Matches
smt2_conv.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: SMT Backend
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
11
12#include "smt2_conv.h"
13
15#include <util/arith_tools.h>
16#include <util/bitvector_expr.h>
17#include <util/byte_operators.h>
18#include <util/c_types.h>
19#include <util/config.h>
21#include <util/expr_iterator.h>
22#include <util/expr_util.h>
23#include <util/fixedbv.h>
24#include <util/floatbv_expr.h>
25#include <util/format_expr.h>
26#include <util/ieee_float.h>
27#include <util/invariant.h>
29#include <util/namespace.h>
32#include <util/prefix.h>
33#include <util/range.h>
34#include <util/rational.h>
35#include <util/rational_tools.h>
36#include <util/simplify_expr.h>
37#include <util/std_expr.h>
38#include <util/string2int.h>
40#include <util/threeval.h>
41
46
47#include "smt2_tokenizer.h"
48
49#include <cstdint>
50#include <map>
51
52// Mark different kinds of error conditions
53
54// Unexpected types and other combinations not implemented and not
55// expected to be needed
56#define UNEXPECTEDCASE(S) PRECONDITION_WITH_DIAGNOSTICS(false, S);
57
58// General todos
59#define SMT2_TODO(S) PRECONDITION_WITH_DIAGNOSTICS(false, "TODO: " S)
60
62 const namespacet &_ns,
63 const std::string &_benchmark,
64 const std::string &_notes,
65 const std::string &_logic,
67 std::ostream &_out)
68 : ns(_ns),
69 out(_out),
70 benchmark(_benchmark),
71 notes(_notes),
72 logic(_logic),
74 boolbv_width(_ns),
75 pointer_logic(_ns),
76 no_boolean_variables(0)
77{
78 // We set some defaults differently
79 // for some solvers.
80
81 switch(solver)
82 {
84 break;
85
87 use_FPA_theory = true;
88 use_array_of_bool = true;
89 use_as_const = true;
92 emit_set_logic = false;
93 break;
94
96 break;
97
99 use_FPA_theory = true;
100 use_array_of_bool = true;
101 use_as_const = true;
103 emit_set_logic = false;
104 break;
105
106 case solvert::CVC5:
107 logic = "ALL";
108 use_FPA_theory = true;
109 use_array_of_bool = true;
110 use_as_const = true;
112 use_datatypes = true;
113 break;
114
115 case solvert::MATHSAT:
116 break;
117
118 case solvert::YICES:
119 break;
120
121 case solvert::Z3:
122 use_array_of_bool = true;
123 // `as const` is disabled because of a soundness issue in Z3,
124 // see https://github.com/Z3Prover/z3/issues/9550. Revisit once
125 // the upstream bug is fixed and we can bump the minimum Z3
126 // version accordingly.
127 use_as_const = false;
130 emit_set_logic = false;
131 use_datatypes = true;
132 break;
133 }
134
135 write_header();
136}
137
139{
140 return "SMT2";
141}
142
143void smt2_convt::print_assignment(std::ostream &os) const
144{
145 // Boolean stuff
146
147 for(std::size_t v=0; v<boolean_assignment.size(); v++)
148 os << "b" << v << "=" << boolean_assignment[v] << "\n";
149
150 // others
151}
152
154{
155 if(l.is_true())
156 return tvt(true);
157 if(l.is_false())
158 return tvt(false);
159
160 INVARIANT(
161 l.var_no() < boolean_assignment.size(),
162 "variable number shall be within bounds");
163 return tvt(boolean_assignment[l.var_no()]^l.sign());
164}
165
167{
168 out << "; SMT 2" << "\n";
169
170 switch(solver)
171 {
172 // clang-format off
173 case solvert::GENERIC: break;
174 case solvert::BITWUZLA: out << "; Generated for Bitwuzla\n"; break;
175 case solvert::BOOLECTOR: out << "; Generated for Boolector\n"; break;
177 out << "; Generated for the CPROVER SMT2 solver\n"; break;
178 case solvert::CVC5: out << "; Generated for CVC 5\n"; break;
179 case solvert::MATHSAT: out << "; Generated for MathSAT\n"; break;
180 case solvert::YICES: out << "; Generated for Yices\n"; break;
181 case solvert::Z3: out << "; Generated for Z3\n"; break;
182 // clang-format on
183 }
184
185 out << "(set-info :source \"" << notes << "\")" << "\n";
186
187 out << "(set-option :produce-models true)" << "\n";
188
189 // We use a broad mixture of logics, so on some solvers
190 // its better not to declare here.
191 // set-logic should come after setting options
192 if(emit_set_logic && !logic.empty())
193 out << "(set-logic " << logic << ")" << "\n";
194}
195
197{
198 out << "\n";
199
200 // Output object size definitions
201 // Note: object_sizes is std::map, so iteration is deterministic (sorted by
202 // key)
203 for(const auto &object : object_sizes)
204 define_object_size(object.second, object.first);
205
206 if(use_check_sat_assuming && !assumptions.empty())
207 {
208 out << "(check-sat-assuming (";
209 for(const auto &assumption : assumptions)
210 convert_literal(assumption);
211 out << "))\n";
212 }
213 else
214 {
215 // add the assumptions, if any
216 if(!assumptions.empty())
217 {
218 out << "; assumptions\n";
219
220 for(const auto &assumption : assumptions)
221 {
222 out << "(assert ";
223 convert_literal(assumption);
224 out << ")"
225 << "\n";
226 }
227 }
228
229 out << "(check-sat)\n";
230 }
231
232 out << "\n";
233
235 {
236 // Output get-value commands for all identifiers
237 // Note: smt2_identifiers is std::set, so iteration is deterministic
238 // (sorted)
239 for(const auto &id : smt2_identifiers)
240 out << "(get-value (" << id << "))"
241 << "\n";
242 }
243
244 out << "\n";
245
246 out << "(exit)\n";
247
248 out << "; end of SMT2 file"
249 << "\n";
250}
251
253 const irep_idt &id,
254 const object_size_exprt &expr)
255{
256 const exprt &ptr = expr.pointer();
257 std::size_t pointer_width = boolbv_width(ptr.type());
258 std::size_t number = 0;
259 std::size_t h=pointer_width-1;
260 std::size_t l=pointer_width-config.bv_encoding.object_bits;
261
262 for(const auto &o : pointer_logic.objects)
263 {
264 const typet &type = o.type();
265 auto size_expr = size_of_expr(type, ns);
266
267 if(
268 (o.id() != ID_symbol && o.id() != ID_string_constant) ||
269 !size_expr.has_value())
270 {
271 ++number;
272 continue;
273 }
274
276 out << "(assert (=> (= "
277 << "((_ extract " << h << " " << l << ") ";
278 convert_expr(ptr);
279 out << ") (_ bv" << number << " " << config.bv_encoding.object_bits << "))"
280 << "(= " << id << " ";
282 out << ")))\n";
283
284 ++number;
285 }
286}
287
289{
290 if(assumption.is_nil())
291 write_footer();
292 else
293 {
294 assumptions.push_back(convert(assumption));
295 write_footer();
296 assumptions.pop_back();
297 }
298
299 out.flush();
301}
302
303exprt smt2_convt::get(const exprt &expr) const
304{
305 if(expr.id()==ID_symbol)
306 {
307 const irep_idt &id = to_symbol_expr(expr).identifier();
308
309 identifier_mapt::const_iterator it=identifier_map.find(id);
310
311 if(it!=identifier_map.end())
312 return it->second.value;
313 return expr;
314 }
315 else if(expr.id()==ID_nondet_symbol)
316 {
317 const irep_idt &id=to_nondet_symbol_expr(expr).get_identifier();
318
319 identifier_mapt::const_iterator it=identifier_map.find(id);
320
321 if(it!=identifier_map.end())
322 return it->second.value;
323 }
324 else if(expr.id() == ID_literal)
325 {
326 auto l = to_literal_expr(expr).get_literal();
327 if(l_get(l).is_true())
328 return true_exprt();
329 else
330 return false_exprt();
331 }
332 else if(expr.id() == ID_not)
333 {
334 auto op = get(to_not_expr(expr).op());
335 if(op == true)
336 return false_exprt();
337 else if(op == false)
338 return true_exprt();
339 }
340 else if(
341 expr.is_constant() || expr.id() == ID_empty_union ||
342 (!expr.has_operands() && (expr.id() == ID_struct || expr.id() == ID_array)))
343 {
344 return expr;
345 }
346 else if(expr.has_operands())
347 {
348 exprt copy = expr;
349 for(auto &op : copy.operands())
350 {
351 exprt eval_op = get(op);
352 if(eval_op.is_nil())
353 return nil_exprt{};
354 op = std::move(eval_op);
355 }
356 return copy;
357 }
358
359 return nil_exprt();
360}
361
363 const irept &src,
364 const typet &type)
365{
366 // See http://www.grammatech.com/resources/smt/SMTLIBTutorial.pdf for the
367 // syntax of SMTlib2 literals.
368 //
369 // A literal expression is one of the following forms:
370 //
371 // * Numeral -- this is a natural number in decimal and is of the form:
372 // 0|([1-9][0-9]*)
373 // * Decimal -- this is a decimal expansion of a real number of the form:
374 // (0|[1-9][0-9]*)[.]([0-9]+)
375 // * Binary -- this is a natural number in binary and is of the form:
376 // #b[01]+
377 // * Hex -- this is a natural number in hexadecimal and is of the form:
378 // #x[0-9a-fA-F]+
379 //
380 // Right now I'm not parsing decimals. It'd be nice if we had a real YACC
381 // parser here, but whatever.
382
383 mp_integer value;
384
385 if(!src.id().empty())
386 {
387 const std::string &s=src.id_string();
388
389 if(s.size()>=2 && s[0]=='#' && s[1]=='b')
390 {
391 // Binary #b010101
392 value=string2integer(s.substr(2), 2);
393 }
394 else if(s.size()>=2 && s[0]=='#' && s[1]=='x')
395 {
396 // Hex #x012345
397 value=string2integer(s.substr(2), 16);
398 }
399 else
400 {
401 std::size_t pos = s.find(".");
402 if(pos != std::string::npos)
403 {
404 // Decimal, return as rational or real
405 if(type.id() == ID_rational)
406 {
408 bool failed = to_rational(
412 }
413 else if(type.id() == ID_real)
414 {
416 bool failed = to_rational(
419 return algebraic_numbert{rational_value}.as_expr();
420 }
421 else
422 {
424 "smt2_convt::parse_literal parsed a number with a decimal point "
425 "as type " +
426 type.id_string());
427 }
428 }
429 // Numeral
430 value=string2integer(s);
431 }
432 }
433 else if(src.get_sub().size()==2 &&
434 src.get_sub()[0].id()=="-") // (- 100)
435 {
436 value=-string2integer(src.get_sub()[1].id_string());
437 }
438 else if(src.get_sub().size()==3 &&
439 src.get_sub()[0].id()=="_" &&
440 // (_ bvDECIMAL_VALUE SIZE)
441 src.get_sub()[1].id_string().substr(0, 2)=="bv")
442 {
443 value=string2integer(src.get_sub()[1].id_string().substr(2));
444 }
445 else if(
446 type.id() == ID_rational && src.get_sub().size() == 3 &&
447 src.get_sub()[0].id() == "/")
448 {
449 rationalt numerator;
450 rationalt denominator;
451 bool failed =
452 to_rational(parse_literal(src.get_sub()[1], type), numerator) ||
453 to_rational(parse_literal(src.get_sub()[2], type), denominator);
455 return from_rational(numerator / denominator);
456 }
457 else if(src.get_sub().size()==4 &&
458 src.get_sub()[0].id()=="fp") // (fp signbv exponentbv significandbv)
459 {
460 if(type.id()==ID_floatbv)
461 {
468
472
473 // stitch the bits together
474 value = bitwise_or(
475 s1_int << (floatbv_type.get_e() + floatbv_type.get_f()),
476 bitwise_or((s2_int << floatbv_type.get_f()), s3_int));
477 }
478 else
479 value=0;
480 }
481 else if(src.get_sub().size()==4 &&
482 src.get_sub()[0].id()=="_" &&
483 src.get_sub()[1].id()=="+oo") // (_ +oo e s)
484 {
485 std::size_t e = unsafe_string2size_t(src.get_sub()[2].id_string());
486 std::size_t s = unsafe_string2size_t(src.get_sub()[3].id_string());
488 .to_expr();
489 }
490 else if(src.get_sub().size()==4 &&
491 src.get_sub()[0].id()=="_" &&
492 src.get_sub()[1].id()=="-oo") // (_ -oo e s)
493 {
494 std::size_t e = unsafe_string2size_t(src.get_sub()[2].id_string());
495 std::size_t s = unsafe_string2size_t(src.get_sub()[3].id_string());
497 .to_expr();
498 }
499 else if(src.get_sub().size()==4 &&
500 src.get_sub()[0].id()=="_" &&
501 src.get_sub()[1].id()=="NaN") // (_ NaN e s)
502 {
503 std::size_t e = unsafe_string2size_t(src.get_sub()[2].id_string());
504 std::size_t s = unsafe_string2size_t(src.get_sub()[3].id_string());
505 return ieee_float_valuet::NaN(ieee_float_spect(s - 1, e)).to_expr();
506 }
507 else if(
508 src.get_sub().size() == 3 &&
509 src.get_sub()[0].id() == "root-obj") // (root-obj (+ ...) <index>)
510 {
511 // Z3 emits these while there isn't an agreed-upon standard for representing
512 // algebraic numbers just yet. https://smt-comp.github.io/2023/model.html
513 // gave some proposals, but these don't seem to have been implemented.
514 // For now, we use DATA_INVARIANT as our parsing may be overly restrictive.
515 // Eventually, these should become proper, user-facing exceptions.
516 //
517 // The third element is the 1-based index identifying which real root of
518 // the polynomial Z3 chose for its model. We do not constrain its value
519 // because algebraic_numbert tracks only the polynomial, not the specific
520 // root, so any root of the same polynomial maps to the same expression.
522 src.get_sub()[1].id().empty() && src.get_sub()[1].get_sub().size() == 3 &&
523 src.get_sub()[1].get_sub()[0].id() == "+",
524 "unexpected root-obj expression",
525 src.pretty());
526 irept sum_rhs = src.get_sub()[1].get_sub()[2];
528 bool failed =
531 !failed, "failed to parse rational constant coefficient", src.pretty());
532 irept sum_lhs = src.get_sub()[1].get_sub()[1];
534 sum_lhs.id().empty() && sum_lhs.get_sub().size() == 3 &&
535 sum_lhs.get_sub()[0].id() == "^" && sum_lhs.get_sub()[1].id() == "x",
536 "unexpected first operand to root-obj",
537 src.pretty());
538 std::size_t degree = unsafe_string2size_t(sum_lhs.get_sub()[2].id_string());
540 degree > 0, "polynomial degree must be positive", src.pretty());
541 std::vector<rationalt> coefficients{degree + 1, rationalt{}};
542 coefficients.front() = constant_coeff;
543 coefficients.back() = rationalt{1};
544 algebraic_numbert a{coefficients};
545 return a.as_expr();
546 }
547
548 if(type.id()==ID_signedbv ||
549 type.id()==ID_unsignedbv ||
550 type.id()==ID_c_enum ||
551 type.id()==ID_c_bool)
552 {
553 return from_integer(value, type);
554 }
555 else if(type.id()==ID_c_enum_tag)
556 {
557 constant_exprt result =
558 from_integer(value, ns.follow_tag(to_c_enum_tag_type(type)));
559
560 // restore the c_enum_tag type
561 result.type() = type;
562 return result;
563 }
564 else if(type.id()==ID_fixedbv ||
565 type.id()==ID_floatbv)
566 {
567 std::size_t width=boolbv_width(type);
568 return constant_exprt(integer2bvrep(value, width), type);
569 }
570 else if(
571 type.id() == ID_integer || type.id() == ID_natural ||
572 type.id() == ID_rational || type.id() == ID_real)
573 {
574 return from_integer(value, type);
575 }
576 else if(type.id() == ID_range)
577 {
578 return from_integer(value + to_integer_range_type(type).from(), type);
579 }
580 else
582 "smt2_convt::parse_literal should not be of unsupported type " +
583 type.id_string());
584}
585
587 const irept &src,
588 const array_typet &type)
589{
590 std::unordered_map<int64_t, exprt> operands_map;
591 walk_array_tree(&operands_map, src, type);
592 exprt::operandst operands;
593 // Try to find the default value, if there is none then set it
594 auto maybe_default_op = operands_map.find(-1);
596 if(maybe_default_op == operands_map.end())
598 else
600 int64_t i = 0;
602 if(maybe_size.has_value())
603 {
604 while(i < maybe_size.value())
605 {
606 auto found_op = operands_map.find(i);
607 if(found_op != operands_map.end())
608 operands.emplace_back(found_op->second);
609 else
610 operands.emplace_back(default_op);
611 i++;
612 }
613 }
614 else
615 {
616 // Array size is unknown, keep adding with known indexes in order
617 // until we fail to find one.
618 auto found_op = operands_map.find(i);
619 while(found_op != operands_map.end())
620 {
621 operands.emplace_back(found_op->second);
622 i++;
623 found_op = operands_map.find(i);
624 }
625 operands.emplace_back(default_op);
626 }
627 return array_exprt(operands, type);
628}
629
631 std::unordered_map<int64_t, exprt> *operands_map,
632 const irept &src,
633 const array_typet &type)
634{
635 if(src.get_sub().size()==4 && src.get_sub()[0].id()=="store")
636 {
637 // This is the SMT syntax being parsed here
638 // (store array index value)
639 // Recurse
640 walk_array_tree(operands_map, src.get_sub()[1], type);
641 const auto index_expr = parse_rec(src.get_sub()[2], type.size().type());
642 if(!index_expr.is_constant())
643 // The index in a (store array index value) term is not necessarily a
644 // constant: models for unbounded or non-integer-keyed arrays can carry
645 // a symbolic/non-constant index. Such an entry cannot be placed in the
646 // index-keyed operands map, so skip it during model reconstruction.
647 return;
650 bool failure = to_integer(index_constant, tempint);
651 if(failure)
652 return;
653 long index = tempint.to_long();
654 exprt value = parse_rec(src.get_sub()[3], type.element_type());
655 operands_map->emplace(index, value);
656 }
657 else if(src.get_sub().size()==2 &&
658 src.get_sub()[0].get_sub().size()==3 &&
659 src.get_sub()[0].get_sub()[0].id()=="as" &&
660 src.get_sub()[0].get_sub()[1].id()=="const")
661 {
662 // (as const type_info default_value)
663 exprt default_value = parse_rec(src.get_sub()[1], type.element_type());
664 operands_map->emplace(-1, default_value);
665 }
666 else
667 {
668 auto bindings_it = current_bindings.find(src.id());
669 if(bindings_it != current_bindings.end())
671 }
672}
673
675 const irept &src,
676 const union_typet &type)
677{
678 // these are always flat
679 PRECONDITION(!type.components().empty());
680 const union_typet::componentt &first=type.components().front();
681 std::size_t width=boolbv_width(type);
682 exprt value = parse_rec(src, unsignedbv_typet(width));
683 if(value.is_nil())
684 return nil_exprt();
685 const typecast_exprt converted(value, first.type());
686 return union_exprt(first.get_name(), converted, type);
687}
688
691{
692 const struct_typet::componentst &components =
693 type.components();
694
695 struct_exprt result(exprt::operandst(components.size(), nil_exprt()), type);
696
697 if(components.empty())
698 return result;
699
700 if(use_datatypes)
701 {
702 // Structs look like:
703 // (mk-struct.1 <component0> <component1> ... <componentN>)
704 std::size_t j = 1;
705 for(std::size_t i=0; i<components.size(); i++)
706 {
707 const struct_typet::componentt &c=components[i];
708 if(is_zero_width(components[i].type(), ns))
709 {
710 result.operands()[i] = nil_exprt{};
711 }
712 else
713 {
715 src.get_sub().size() > j, "insufficient number of component values");
716 result.operands()[i] = parse_rec(src.get_sub()[j], c.type());
717 ++j;
718 }
719 }
720 }
721 else
722 {
723 // These are just flattened, i.e., we expect to see a monster bit vector.
724 std::size_t total_width=boolbv_width(type);
725 const auto l = parse_literal(src, unsignedbv_typet(total_width));
726
727 const irep_idt binary =
729
730 CHECK_RETURN(binary.size() == total_width);
731
732 std::size_t offset=0;
733
734 for(std::size_t i=0; i<components.size(); i++)
735 {
736 if(is_zero_width(components[i].type(), ns))
737 continue;
738
739 std::size_t component_width=boolbv_width(components[i].type());
740
741 INVARIANT(
742 offset + component_width <= total_width,
743 "struct component bits shall be within struct bit vector");
744
745 std::string component_binary=
746 "#b"+id2string(binary).substr(
747 total_width-offset-component_width, component_width);
748
749 result.operands()[i]=
750 parse_rec(irept(component_binary), components[i].type());
751
752 offset+=component_width;
753 }
754 }
755
756 return result;
757}
758
759exprt smt2_convt::parse_rec(const irept &src, const typet &type)
760{
761 if(src.get_sub().size() == 3 && src.get_sub()[0].id() == ID_let)
762 {
763 // This is produced by Z3
764 // (let (....) (....))
766 for(const auto &binding : src.get_sub()[1].get_sub())
767 {
768 const irep_idt &name = binding.get_sub()[0].id();
769 current_bindings.emplace(name, binding.get_sub()[1]);
770 }
771 exprt result = parse_rec(src.get_sub()[2], type);
773 return result;
774 }
775
776 auto bindings_it = current_bindings.find(src.id());
777 if(bindings_it != current_bindings.end())
778 {
779 return parse_rec(bindings_it->second, type);
780 }
781
782 if(
783 type.id() == ID_signedbv || type.id() == ID_unsignedbv ||
784 type.id() == ID_integer || type.id() == ID_rational ||
785 type.id() == ID_natural || type.id() == ID_real || type.id() == ID_c_enum ||
786 type.id() == ID_c_enum_tag || type.id() == ID_fixedbv ||
787 type.id() == ID_floatbv || type.id() == ID_c_bool || type.id() == ID_range)
788 {
789 return parse_literal(src, type);
790 }
791 else if(type.id()==ID_bool)
792 {
793 if(src.id()==ID_1 || src.id()==ID_true)
794 return true_exprt();
795 else if(src.id()==ID_0 || src.id()==ID_false)
796 return false_exprt();
797 }
798 else if(type.id()==ID_pointer)
799 {
800 // these come in as bit-vector literals
801 std::size_t width=boolbv_width(type);
803
805
806 // split into object and offset
807 mp_integer pow=power(2, width-config.bv_encoding.object_bits);
810 bv_expr.get_value(),
812 }
813 else if(type.id()==ID_struct)
814 {
815 return parse_struct(src, to_struct_type(type));
816 }
817 else if(type.id() == ID_struct_tag)
818 {
819 auto struct_expr =
820 parse_struct(src, ns.follow_tag(to_struct_tag_type(type)));
821 // restore the tag type
822 struct_expr.type() = type;
823 return std::move(struct_expr);
824 }
825 else if(type.id()==ID_union)
826 {
827 return parse_union(src, to_union_type(type));
828 }
829 else if(type.id() == ID_union_tag)
830 {
831 auto union_expr = parse_union(src, ns.follow_tag(to_union_tag_type(type)));
832 // restore the tag type
833 union_expr.type() = type;
834 return union_expr;
835 }
836 else if(type.id()==ID_array)
837 {
838 return parse_array(src, to_array_type(type));
839 }
840
841 return nil_exprt();
842}
843
845 const exprt &expr,
846 const pointer_typet &result_type)
847{
848 if(
849 expr.id() == ID_symbol || expr.is_constant() ||
850 expr.id() == ID_string_constant || expr.id() == ID_label)
851 {
852 const std::size_t object_bits = config.bv_encoding.object_bits;
853 const std::size_t max_objects = std::size_t(1) << object_bits;
855
857 {
859 "too many addressed objects: maximum number of objects is set to 2^n=" +
860 std::to_string(max_objects) +
861 " (with n=" + std::to_string(object_bits) + "); " +
862 "use the `--object-bits n` option to increase the maximum number"};
863 }
864
865 out << "(concat (_ bv" << object_id << " " << object_bits << ")"
866 << " (_ bv0 " << boolbv_width(result_type) - object_bits << "))";
867 }
868 else if(expr.id()==ID_index)
869 {
870 const index_exprt &index_expr = to_index_expr(expr);
871
872 const exprt &array = index_expr.array();
873 const exprt &index = index_expr.index();
874
875 if(index == 0)
876 {
877 if(array.type().id()==ID_pointer)
878 convert_expr(array);
879 else if(array.type().id()==ID_array)
880 convert_address_of_rec(array, result_type);
881 else
883 }
884 else
885 {
886 // this is really pointer arithmetic
888 new_index_expr.index() = from_integer(0, index.type());
889
892 pointer_type(to_array_type(array.type()).element_type()));
893
895
897 }
898 }
899 else if(expr.id()==ID_member)
900 {
902
903 const exprt &struct_op=member_expr.struct_op();
904 const typet &struct_op_type = struct_op.type();
905
908 "member expression operand shall have struct type");
909
914
915 const irep_idt &component_name = member_expr.get_component_name();
916
917 const auto offset = member_offset(struct_type, component_name, ns);
918 CHECK_RETURN(offset.has_value() && *offset >= 0);
919
920 unsignedbv_typet index_type(boolbv_width(result_type));
921
922 // pointer arithmetic
923 out << "(bvadd ";
924 convert_address_of_rec(struct_op, result_type);
925 convert_expr(from_integer(*offset, index_type));
926 out << ")"; // bvadd
927 }
928 else if(expr.id()==ID_if)
929 {
930 const if_exprt &if_expr = to_if_expr(expr);
931
932 out << "(ite ";
933 convert_expr(if_expr.cond());
934 out << " ";
935 convert_address_of_rec(if_expr.true_case(), result_type);
936 out << " ";
937 convert_address_of_rec(if_expr.false_case(), result_type);
938 out << ")";
939 }
940 else
941 INVARIANT(
942 false,
943 "operand of address of expression should not be of kind " +
944 expr.id_string());
945}
946
947static bool has_quantifier(const exprt &expr)
948{
949 bool result = false;
950 expr.visit_post([&result](const exprt &node) {
951 if(node.id() == ID_exists || node.id() == ID_forall)
952 result = true;
953 });
954 return result;
955}
956
958{
959 PRECONDITION(expr.is_boolean());
960
961 // Three cases where no new handle is needed.
962
963 if(expr == true)
964 return const_literal(true);
965 else if(expr == false)
966 return const_literal(false);
967 else if(expr.id()==ID_literal)
968 return to_literal_expr(expr).get_literal();
969
970 // Need a new handle
971
972 out << "\n";
973
975
978
979 out << "; convert\n";
980 out << "; Converting var_no " << l.var_no() << " with expr ID of "
981 << expr.id_string() << "\n";
982 // We're converting the expression, so store it in the defined_expressions
983 // store and in future we use the literal instead of the whole expression
984 // Note that here we are always converting, so we do not need to consider
985 // other literal kinds, only "|B###|"
986
987 // Z3 refuses get-value when a defined symbol contains a quantifier.
989 {
990 out << "(declare-fun ";
992 out << " () Bool)\n";
993 out << "(assert (= ";
995 out << ' ';
997 out << "))\n";
998 }
999 else
1000 {
1001 auto identifier =
1002 convert_identifier(std::string{"B"} + std::to_string(l.var_no()));
1003 defined_expressions[expr] = identifier;
1004 smt2_identifiers.insert(identifier);
1005 out << "(define-fun " << identifier << " () Bool ";
1007 out << ")\n";
1008 }
1009
1010 return l;
1011}
1012
1014{
1015 // We can only improve Booleans.
1016 if(!expr.is_boolean())
1017 return expr;
1018
1019 return literal_exprt(convert(expr));
1020}
1021
1023{
1024 if(l==const_literal(false))
1025 out << "false";
1026 else if(l==const_literal(true))
1027 out << "true";
1028 else
1029 {
1030 if(l.sign())
1031 out << "(not ";
1032
1033 const auto identifier =
1034 convert_identifier("B" + std::to_string(l.var_no()));
1035
1036 out << identifier;
1037
1038 if(l.sign())
1039 out << ")";
1040
1041 smt2_identifiers.insert(identifier);
1042 }
1043}
1044
1046{
1048}
1049
1050void smt2_convt::push(const std::vector<exprt> &_assumptions)
1051{
1052 INVARIANT(assumptions.empty(), "nested contexts are not supported");
1053
1054 assumptions.reserve(_assumptions.size());
1055 for(auto &assumption : _assumptions)
1056 assumptions.push_back(convert(assumption));
1057}
1058
1060{
1062}
1063
1064static bool is_smt2_simple_identifier(const std::string &identifier)
1065{
1066 if(identifier.empty())
1067 return false;
1068
1069 if(isdigit(identifier[0]))
1070 return false;
1071
1072 for(auto ch : id2string(identifier))
1073 {
1075 return false;
1076 }
1077
1078 return true;
1079}
1080
1081std::string smt2_convt::convert_identifier(const irep_idt &identifier)
1082{
1083 // Is this a "simple identifier"?
1084 if(is_smt2_simple_identifier(id2string(identifier)))
1085 return id2string(identifier);
1086
1087 // Backslashes are disallowed in quoted symbols just for simplicity.
1088 // Otherwise, for Common Lisp compatibility they would have to be treated
1089 // as escaping symbols.
1090
1091 std::string result = "|";
1092
1093 for(auto ch : identifier)
1094 {
1095 switch(ch)
1096 {
1097 case '|':
1098 case '\\':
1099 case '&': // we use the & for escaping
1100 result+='&';
1101 result+=std::to_string(ch);
1102 result+=';';
1103 break;
1104
1105 case '$': // $ _is_ allowed
1106 default:
1107 result+=ch;
1108 }
1109 }
1110
1111 result += '|';
1112
1113 return result;
1114}
1115
1116std::string smt2_convt::type2id(const typet &type) const
1117{
1118 if(type.id()==ID_floatbv)
1119 {
1121 return "f"+std::to_string(spec.width())+"_"+std::to_string(spec.f);
1122 }
1123 else if(type.id() == ID_bv)
1124 {
1125 return "B" + std::to_string(to_bitvector_type(type).get_width());
1126 }
1127 else if(type.id()==ID_unsignedbv)
1128 {
1129 return "u"+std::to_string(to_unsignedbv_type(type).get_width());
1130 }
1131 else if(type.id()==ID_c_bool)
1132 {
1133 return "u"+std::to_string(to_c_bool_type(type).get_width());
1134 }
1135 else if(type.id()==ID_signedbv)
1136 {
1137 return "s"+std::to_string(to_signedbv_type(type).get_width());
1138 }
1139 else if(type.id()==ID_bool)
1140 {
1141 return "b";
1142 }
1143 else if(type.id()==ID_c_enum_tag)
1144 {
1145 return type2id(ns.follow_tag(to_c_enum_tag_type(type)).underlying_type());
1146 }
1147 else if(type.id() == ID_pointer)
1148 {
1149 return "p" + std::to_string(to_pointer_type(type).get_width());
1150 }
1151 else if(type.id() == ID_struct_tag)
1152 {
1153 if(use_datatypes)
1154 return datatype_map.at(type);
1155 else
1156 return "S" + std::to_string(boolbv_width(type));
1157 }
1158 else if(type.id() == ID_union_tag)
1159 {
1160 return "U" + std::to_string(boolbv_width(type));
1161 }
1162 else if(type.id() == ID_array)
1163 {
1164 return "A" + type2id(to_array_type(type).element_type());
1165 }
1166 else if(type.id() == ID_integer)
1167 {
1168 return "Int";
1169 }
1170 else if(type.id() == ID_real)
1171 {
1172 return "Real";
1173 }
1174 else if(type.id() == ID_string)
1175 {
1176 return "String";
1177 }
1178 else if(type.id() == ID_regex)
1179 {
1180 return "RegLan";
1181 }
1182 else if(type.id() == ID_mathematical_function)
1183 {
1184 std::string result = "MF";
1185 const auto &mf = to_mathematical_function_type(type);
1186 for(const auto &d : mf.domain())
1187 result += "_" + type2id(d);
1188 result += "_" + type2id(mf.codomain());
1189 return result;
1190 }
1191 else
1192 {
1194 }
1195}
1196
1197std::string smt2_convt::floatbv_suffix(const exprt &expr) const
1198{
1199 PRECONDITION(!expr.operands().empty());
1200 return "_" + type2id(to_multi_ary_expr(expr).op0().type()) + "->" +
1201 type2id(expr.type());
1202}
1203
1205{
1207
1208 if(expr.id()==ID_symbol)
1209 {
1210 const irep_idt &id = to_symbol_expr(expr).identifier();
1211 out << convert_identifier(id);
1212 return;
1213 }
1214
1215 if(expr.id()==ID_smt2_symbol)
1216 {
1217 const irep_idt &id = to_smt2_symbol(expr).get_identifier();
1218 out << id;
1219 return;
1220 }
1221
1222 INVARIANT(
1223 !expr.operands().empty(), "non-symbol expressions shall have operands");
1224
1225 out << '('
1227 "float_bv." + expr.id_string() + floatbv_suffix(expr));
1228
1229 for(const auto &op : expr.operands())
1230 {
1231 out << ' ';
1232 convert_expr(op);
1233 }
1234
1235 out << ')';
1236}
1237
1238void smt2_convt::convert_string_literal(const std::string &s)
1239{
1240 out << '"';
1241 for(auto ch : s)
1242 {
1243 // " is escaped by double-quoting
1244 if(ch == '"')
1245 out << '"';
1246 out << ch;
1247 }
1248 out << '"';
1249}
1250
1252{
1253 // try hash table first
1254 auto converter_result = converters.find(expr.id());
1255 if(converter_result != converters.end())
1256 {
1257 converter_result->second(expr);
1258 return; // done
1259 }
1260
1261 // huge monster case split over expression id
1262 if(expr.id()==ID_symbol)
1263 {
1264 const irep_idt &id = to_symbol_expr(expr).identifier();
1265 DATA_INVARIANT(!id.empty(), "symbol must have identifier");
1266 out << convert_identifier(id);
1267 }
1268 else if(expr.id()==ID_nondet_symbol)
1269 {
1270 const irep_idt &id = to_nondet_symbol_expr(expr).get_identifier();
1271 DATA_INVARIANT(!id.empty(), "nondet symbol must have identifier");
1272 out << convert_identifier("nondet_" + id2string(id));
1273 }
1274 else if(expr.id()==ID_smt2_symbol)
1275 {
1276 const irep_idt &id = to_smt2_symbol(expr).get_identifier();
1277 DATA_INVARIANT(!id.empty(), "smt2 symbol must have identifier");
1278 out << id;
1279 }
1280 else if(expr.id()==ID_typecast)
1281 {
1283 }
1284 else if(expr.id()==ID_floatbv_typecast)
1285 {
1287 }
1288 else if(expr.id() == ID_floatbv_round_to_integral)
1289 {
1291 }
1292 else if(expr.id()==ID_struct)
1293 {
1295 }
1296 else if(expr.id()==ID_union)
1297 {
1299 }
1300 else if(expr.is_constant())
1301 {
1303 }
1304 else if(expr.id() == ID_concatenation)
1305 {
1307 !expr.operands().empty(),
1308 "concatenation expression should have at least one operand",
1309 expr.id_string());
1310
1311 // collect non-zero-width operands (zero-width not allowed by SMT-LIB)
1313 for(const auto &op : expr.operands())
1314 {
1315 if(!is_zero_width(op.type(), ns))
1316 non_zero_width_ops.push_back(op);
1317 }
1318
1320 !non_zero_width_ops.empty(),
1321 "concatenation must have at least one non-zero-width operand");
1322
1323 if(non_zero_width_ops.size() == 1)
1324 {
1325 // unary concat is not valid SMT-LIB; emit the operand directly
1327 }
1328 else
1329 {
1330 out << "(concat";
1331
1332 for(const auto &op : non_zero_width_ops)
1333 {
1334 out << ' ';
1335 flatten2bv(op);
1336 }
1337
1338 out << ')';
1339 }
1340 }
1341 else if(
1342 expr.id() == ID_bitand || expr.id() == ID_bitor || expr.id() == ID_bitxor)
1343 {
1345 !expr.operands().empty(),
1346 "given expression should have at least one operand",
1347 expr.id_string());
1348
1349 if(expr.operands().size() == 1)
1350 {
1351 flatten2bv(expr.operands().front());
1352 }
1353 else // >= 2
1354 {
1355 out << '(';
1356
1357 if(expr.id() == ID_concatenation)
1358 out << "concat";
1359 else if(expr.id() == ID_bitand)
1360 out << "bvand";
1361 else if(expr.id() == ID_bitor)
1362 out << "bvor";
1363 else if(expr.id() == ID_bitxor)
1364 out << "bvxor";
1365
1366 for(const auto &op : expr.operands())
1367 {
1368 out << ' ';
1369 flatten2bv(op);
1370 }
1371
1372 out << ')';
1373 }
1374 }
1375 else if(
1376 expr.id() == ID_bitxnor || expr.id() == ID_bitnand ||
1377 expr.id() == ID_bitnor)
1378 {
1379 // SMT-LIB only has these as a binary expression,
1380 // owing to their ambiguity.
1381 if(expr.operands().size() == 2)
1382 {
1383 const auto &binary_expr = to_binary_expr(expr);
1384
1385 out << '(';
1386 if(binary_expr.id() == ID_bitxnor)
1387 out << "bvxnor";
1388 else if(binary_expr.id() == ID_bitnand)
1389 out << "bvnand";
1390 else if(binary_expr.id() == ID_bitnor)
1391 out << "bvnor";
1392 out << ' ';
1393 flatten2bv(binary_expr.op0());
1394 out << ' ';
1395 flatten2bv(binary_expr.op1());
1396 out << ')';
1397 }
1398 else if(expr.operands().size() == 1)
1399 {
1400 out << "(bvnot ";
1401 flatten2bv(to_unary_expr(expr).op());
1402 out << ')';
1403 }
1404 else if(expr.operands().size() >= 3)
1405 {
1406 out << "(bvnot (";
1407 if(expr.id() == ID_bitxnor)
1408 out << "bvxor";
1409 else if(expr.id() == ID_bitnand)
1410 out << "bvand";
1411 else if(expr.id() == ID_bitnor)
1412 out << "bvor";
1413
1414 for(const auto &op : expr.operands())
1415 {
1416 out << ' ';
1417 flatten2bv(op);
1418 }
1419
1420 out << "))"; // bvX, bvnot
1421 }
1422 else
1423 {
1425 expr.operands().size() >= 1,
1426 expr.id_string() + " should have at least one operand");
1427 }
1428 }
1429 else if(expr.id()==ID_bitnot)
1430 {
1432
1433 out << "(bvnot ";
1435 out << ")";
1436 }
1437 else if(expr.id()==ID_unary_minus)
1438 {
1440 const auto &type = expr.type();
1441
1442 if(
1443 type.id() == ID_rational || type.id() == ID_integer ||
1444 type.id() == ID_real)
1445 {
1446 out << "(- ";
1448 out << ")";
1449 }
1450 else if(type.id() == ID_range)
1451 {
1452 auto &range_type = to_integer_range_type(type);
1453 PRECONDITION(type == unary_minus_expr.op().type());
1454 // turn -x into 0-x
1455 auto minus_expr =
1456 minus_exprt{range_type.zero_expr(), unary_minus_expr.op()};
1458 }
1459 else if(type.id() == ID_floatbv)
1460 {
1461 // this has no rounding mode
1462 if(use_FPA_theory)
1463 {
1464 out << "(fp.neg ";
1466 out << ")";
1467 }
1468 else
1470 }
1471 else
1472 {
1473 PRECONDITION(type.id() != ID_natural);
1474 out << "(bvneg ";
1476 out << ")";
1477 }
1478 }
1479 else if(expr.id()==ID_unary_plus)
1480 {
1481 // A no-op (apart from type promotion)
1482 convert_expr(to_unary_plus_expr(expr).op());
1483 }
1484 else if(expr.id()==ID_sign)
1485 {
1486 const sign_exprt &sign_expr = to_sign_expr(expr);
1487
1488 const typet &op_type = sign_expr.op().type();
1489
1490 if(op_type.id()==ID_floatbv)
1491 {
1492 if(use_FPA_theory)
1493 {
1494 out << "(fp.isNegative ";
1495 convert_expr(sign_expr.op());
1496 out << ")";
1497 }
1498 else
1500 }
1501 else if(op_type.id()==ID_signedbv)
1502 {
1503 std::size_t op_width=to_signedbv_type(op_type).get_width();
1504
1505 out << "(bvslt ";
1506 convert_expr(sign_expr.op());
1507 out << " (_ bv0 " << op_width << "))";
1508 }
1509 else
1511 false,
1512 "sign should not be applied to unsupported type",
1513 sign_expr.type().id_string());
1514 }
1515 else if(expr.id()==ID_if)
1516 {
1517 const if_exprt &if_expr = to_if_expr(expr);
1518
1519 out << "(ite ";
1520 convert_expr(if_expr.cond());
1521 out << " ";
1522 if(
1523 expr.type().id() == ID_array && !use_array_theory(if_expr.true_case()) &&
1524 use_array_theory(if_expr.false_case()))
1525 {
1526 unflatten(wheret::BEGIN, expr.type());
1527
1528 convert_expr(if_expr.true_case());
1529
1530 unflatten(wheret::END, expr.type());
1531 }
1532 else
1533 {
1534 convert_expr(if_expr.true_case());
1535 }
1536 out << " ";
1537 if(
1538 expr.type().id() == ID_array && use_array_theory(if_expr.true_case()) &&
1539 !use_array_theory(if_expr.false_case()))
1540 {
1541 unflatten(wheret::BEGIN, expr.type());
1542
1543 convert_expr(if_expr.false_case());
1544
1545 unflatten(wheret::END, expr.type());
1546 }
1547 else
1548 {
1549 convert_expr(if_expr.false_case());
1550 }
1551 out << ")";
1552 }
1553 else if(expr.id()==ID_and ||
1554 expr.id()==ID_or ||
1555 expr.id()==ID_xor)
1556 {
1558 expr.is_boolean(),
1559 "logical and, or, and xor expressions should have Boolean type");
1561 expr.operands().size() >= 2,
1562 "logical and, or, and xor expressions should have at least two operands");
1563
1564 out << "(" << expr.id();
1565 for(const auto &op : expr.operands())
1566 {
1567 out << " ";
1568 convert_expr(op);
1569 }
1570 out << ")";
1571 }
1572 else if(expr.id() == ID_nand || expr.id() == ID_nor || expr.id() == ID_xnor)
1573 {
1575 expr.is_boolean(),
1576 "logical nand, nor, xnor expressions should have Boolean type");
1578 expr.operands().size() >= 1,
1579 "logical nand, nor, xnor expressions should have at least one operand");
1580
1581 // SMT-LIB doesn't have nand, nor, xnor
1582 out << "(not ";
1583 if(expr.operands().size() == 1)
1584 convert_expr(to_multi_ary_expr(expr).op0());
1585 else
1586 {
1587 if(expr.id() == ID_nand)
1588 out << "(and";
1589 else if(expr.id() == ID_nor)
1590 out << "(or";
1591 else if(expr.id() == ID_xnor)
1592 out << "(xor";
1593 else
1594 DATA_INVARIANT(false, "unexpected expression");
1595 for(const auto &op : expr.operands())
1596 {
1597 out << ' ';
1598 convert_expr(op);
1599 }
1600 out << ')'; // or, and, xor
1601 }
1602 out << ')'; // not
1603 }
1604 else if(expr.id()==ID_implies)
1605 {
1607
1609 implies_expr.is_boolean(), "implies expression should have Boolean type");
1610
1611 out << "(=> ";
1613 out << " ";
1615 out << ")";
1616 }
1617 else if(expr.id()==ID_not)
1618 {
1619 const not_exprt &not_expr = to_not_expr(expr);
1620
1622 not_expr.is_boolean(), "not expression should have Boolean type");
1623
1624 out << "(not ";
1625 convert_expr(not_expr.op());
1626 out << ")";
1627 }
1628 else if(expr.id() == ID_equal)
1629 {
1630 const equal_exprt &equal_expr = to_equal_expr(expr);
1631
1633 equal_expr.op0().type() == equal_expr.op1().type(),
1634 "operands of equal expression shall have same type");
1635
1636 if(is_zero_width(equal_expr.lhs().type(), ns))
1637 {
1639 }
1640 else
1641 {
1642 out << "(= ";
1643 convert_expr(equal_expr.op0());
1644 out << " ";
1645 convert_expr(equal_expr.op1());
1646 out << ")";
1647 }
1648 }
1649 else if(expr.id() == ID_notequal)
1650 {
1652
1654 notequal_expr.op0().type() == notequal_expr.op1().type(),
1655 "operands of not equal expression shall have same type");
1656
1657 out << "(not (= ";
1659 out << " ";
1661 out << "))";
1662 }
1663 else if(expr.id()==ID_ieee_float_equal ||
1664 expr.id()==ID_ieee_float_notequal)
1665 {
1666 // These are not the same as (= A B)
1667 // because of NaN and negative zero.
1668 const auto &rel_expr = to_binary_relation_expr(expr);
1669
1671 rel_expr.lhs().type() == rel_expr.rhs().type(),
1672 "operands of float equal and not equal expressions shall have same type");
1673
1674 // The FPA theory properly treats NaN and negative zero.
1675 if(use_FPA_theory)
1676 {
1678 out << "(not ";
1679
1680 out << "(fp.eq ";
1681 convert_expr(rel_expr.lhs());
1682 out << " ";
1683 convert_expr(rel_expr.rhs());
1684 out << ")";
1685
1687 out << ")";
1688 }
1689 else
1690 convert_floatbv(expr);
1691 }
1692 else if(expr.id()==ID_le ||
1693 expr.id()==ID_lt ||
1694 expr.id()==ID_ge ||
1695 expr.id()==ID_gt)
1696 {
1698 }
1699 else if(expr.id()==ID_plus)
1700 {
1702 }
1703 else if(expr.id()==ID_floatbv_plus)
1704 {
1706 }
1707 else if(expr.id()==ID_minus)
1708 {
1710 }
1711 else if(expr.id()==ID_floatbv_minus)
1712 {
1714 }
1715 else if(expr.id()==ID_div)
1716 {
1717 convert_div(to_div_expr(expr));
1718 }
1719 else if(expr.id()==ID_floatbv_div)
1720 {
1722 }
1723 else if(expr.id()==ID_mod)
1724 {
1725 convert_mod(to_mod_expr(expr));
1726 }
1727 else if(expr.id() == ID_euclidean_mod)
1728 {
1730 }
1731 else if(expr.id()==ID_mult)
1732 {
1734 }
1735 else if(expr.id()==ID_floatbv_mult)
1736 {
1738 }
1739 else if(expr.id() == ID_floatbv_rem)
1740 {
1742 }
1743 else if(expr.id() == ID_floatbv_fma)
1744 {
1746 }
1747 else if(expr.id()==ID_address_of)
1748 {
1752 }
1753 else if(expr.id() == ID_array_of)
1754 {
1755 const auto &array_of_expr = to_array_of_expr(expr);
1756
1758 array_of_expr.type().id() == ID_array,
1759 "array of expression shall have array type");
1760
1761 if(use_as_const)
1762 {
1763 out << "((as const ";
1765 out << ") ";
1767 out << ")";
1768 }
1769 else
1770 {
1771 defined_expressionst::const_iterator it =
1773 CHECK_RETURN(it != defined_expressions.end());
1774 out << it->second;
1775 }
1776 }
1777 else if(expr.id() == ID_array_comprehension)
1778 {
1780
1782 array_comprehension.type().id() == ID_array,
1783 "array_comprehension expression shall have array type");
1784
1786 {
1787 out << "(lambda ((";
1789 out << " ";
1790 convert_type(array_comprehension.type().size().type());
1791 out << ")) ";
1793 out << ")";
1794 }
1795 else
1796 {
1797 const auto &it = defined_expressions.find(array_comprehension);
1798 CHECK_RETURN(it != defined_expressions.end());
1799 out << it->second;
1800 }
1801 }
1802 else if(expr.id()==ID_index)
1803 {
1805 }
1806 else if(expr.id()==ID_ashr ||
1807 expr.id()==ID_lshr ||
1808 expr.id()==ID_shl)
1809 {
1810 const shift_exprt &shift_expr = to_shift_expr(expr);
1811 const typet &type = shift_expr.type();
1812
1813 if(type.id()==ID_unsignedbv ||
1814 type.id()==ID_signedbv ||
1815 type.id()==ID_bv)
1816 {
1817 if(shift_expr.id() == ID_ashr)
1818 out << "(bvashr ";
1819 else if(shift_expr.id() == ID_lshr)
1820 out << "(bvlshr ";
1821 else if(shift_expr.id() == ID_shl)
1822 out << "(bvshl ";
1823 else
1825
1827 out << " ";
1828
1829 // SMT2 requires the shift distance to have the same width as
1830 // the value that is shifted -- odd!
1831
1832 const auto &distance_type = shift_expr.distance().type();
1833 if(distance_type.id() == ID_integer || distance_type.id() == ID_natural)
1834 {
1835 const mp_integer i =
1837
1838 // shift distance must be bit vector
1839 std::size_t width_op0 = boolbv_width(shift_expr.op().type());
1842 }
1843 else if(
1844 distance_type.id() == ID_signedbv ||
1845 distance_type.id() == ID_unsignedbv ||
1847 {
1848 std::size_t width_op0 = boolbv_width(shift_expr.op().type());
1849 std::size_t width_op1 = boolbv_width(distance_type);
1850
1851 if(width_op0==width_op1)
1852 convert_expr(shift_expr.distance());
1853 else if(width_op0>width_op1)
1854 {
1855 out << "((_ zero_extend " << width_op0-width_op1 << ") ";
1856 convert_expr(shift_expr.distance());
1857 out << ")"; // zero_extend
1858 }
1859 else // width_op0<width_op1
1860 {
1861 out << "((_ extract " << width_op0-1 << " 0) ";
1862 convert_expr(shift_expr.distance());
1863 out << ")"; // extract
1864 }
1865 }
1866 else
1867 {
1869 "unsupported distance type for " + shift_expr.id_string() + ": " +
1870 distance_type.id_string());
1871 }
1872
1873 out << ")"; // bv*sh
1874 }
1875 else
1877 "unsupported type for " + shift_expr.id_string() + ": " +
1878 type.id_string());
1879 }
1880 else if(expr.id() == ID_rol || expr.id() == ID_ror)
1881 {
1882 const shift_exprt &shift_expr = to_shift_expr(expr);
1883 const typet &type = shift_expr.type();
1884
1885 if(
1886 type.id() == ID_unsignedbv || type.id() == ID_signedbv ||
1887 type.id() == ID_bv)
1888 {
1889 // SMT-LIB offers rotate_left and rotate_right, but these require a
1890 // constant distance.
1891 if(shift_expr.id() == ID_rol)
1892 out << "((_ rotate_left";
1893 else if(shift_expr.id() == ID_ror)
1894 out << "((_ rotate_right";
1895 else
1897
1898 out << ' ';
1899
1901
1902 if(distance_int_op.has_value())
1903 {
1904 out << distance_int_op.value();
1905 }
1906 else
1908 "distance type for " + shift_expr.id_string() + "must be constant");
1909
1910 out << ") ";
1912
1913 out << ")"; // rotate_*
1914 }
1915 else
1917 "unsupported type for " + shift_expr.id_string() + ": " +
1918 type.id_string());
1919 }
1920 else if(expr.id() == ID_named_term)
1921 {
1922 const auto &named_term_expr = to_named_term_expr(expr);
1923 out << "(! ";
1924 convert(named_term_expr.value());
1925 out << " :named "
1926 << convert_identifier(named_term_expr.symbol().identifier()) << ')';
1927 }
1928 else if(expr.id()==ID_with)
1929 {
1931 }
1932 else if(expr.id()==ID_update)
1933 {
1935 }
1936 else if(expr.id() == ID_update_bit)
1937 {
1939 }
1940 else if(expr.id() == ID_update_bits)
1941 {
1943 }
1944 else if(expr.id() == ID_object_address)
1945 {
1946 out << "(object-address ";
1948 id2string(to_object_address_expr(expr).object_identifier()));
1949 out << ')';
1950 }
1951 else if(expr.id() == ID_element_address)
1952 {
1953 // We turn this binary expression into a ternary expression
1954 // by adding the size of the array elements as third argument.
1956
1958 ::size_of_expr(element_address_expr.element_type(), ns);
1960
1961 out << "(element-address-" << type2id(expr.type()) << ' ';
1963 out << ' ';
1965 out << ' ';
1968 out << ')';
1969 }
1970 else if(expr.id() == ID_field_address)
1971 {
1972 const auto &field_address_expr = to_field_address_expr(expr);
1973 out << "(field-address-" << type2id(expr.type()) << ' ';
1975 out << ' ';
1977 out << ')';
1978 }
1979 else if(expr.id()==ID_member)
1980 {
1982 }
1983 else if(expr.id()==ID_pointer_offset)
1984 {
1985 const auto &op = to_pointer_offset_expr(expr).pointer();
1986
1988 op.type().id() == ID_pointer,
1989 "operand of pointer offset expression shall be of pointer type");
1990
1991 std::size_t offset_bits =
1992 boolbv_width(op.type()) - config.bv_encoding.object_bits;
1993 std::size_t result_width=boolbv_width(expr.type());
1994
1995 // max extract width
1998
1999 // too few bits?
2001 out << "((_ zero_extend " << result_width-offset_bits << ") ";
2002
2003 out << "((_ extract " << offset_bits-1 << " 0) ";
2004 convert_expr(op);
2005 out << ")";
2006
2008 out << ")"; // zero_extend
2009 }
2010 else if(expr.id()==ID_pointer_object)
2011 {
2012 const auto &op = to_pointer_object_expr(expr).pointer();
2013
2015 op.type().id() == ID_pointer,
2016 "pointer object expressions should be of pointer type");
2017
2018 std::size_t ext=boolbv_width(expr.type())-config.bv_encoding.object_bits;
2019 std::size_t pointer_width = boolbv_width(op.type());
2020
2021 if(ext>0)
2022 out << "((_ zero_extend " << ext << ") ";
2023
2024 out << "((_ extract "
2025 << pointer_width-1 << " "
2026 << pointer_width-config.bv_encoding.object_bits << ") ";
2027 convert_expr(op);
2028 out << ")";
2029
2030 if(ext>0)
2031 out << ")"; // zero_extend
2032 }
2033 else if(expr.id() == ID_is_dynamic_object)
2034 {
2036 }
2037 else if(expr.id() == ID_is_invalid_pointer)
2038 {
2039 const auto &op = to_unary_expr(expr).op();
2040 std::size_t pointer_width = boolbv_width(op.type());
2041 out << "(= ((_ extract "
2042 << pointer_width-1 << " "
2043 << pointer_width-config.bv_encoding.object_bits << ") ";
2044 convert_expr(op);
2045 out << ") (_ bv" << pointer_logic.get_invalid_object()
2046 << " " << config.bv_encoding.object_bits << "))";
2047 }
2048 else if(expr.id()==ID_string_constant)
2049 {
2050 defined_expressionst::const_iterator it=defined_expressions.find(expr);
2051 CHECK_RETURN(it != defined_expressions.end());
2052 out << it->second;
2053 }
2054 else if(expr.id()==ID_extractbit)
2055 {
2057
2058 if(extractbit_expr.index().is_constant())
2059 {
2060 const mp_integer i =
2062
2063 out << "(= ((_ extract " << i << " " << i << ") ";
2065 out << ") #b1)";
2066 }
2067 else
2068 {
2069 out << "(= ((_ extract 0 0) ";
2070 // the arguments of the shift need to have the same width
2071 out << "(bvlshr ";
2073 out << ' ';
2074 typecast_exprt tmp(extractbit_expr.index(), extractbit_expr.src().type());
2076 out << ")) #b1)"; // bvlshr, extract, =
2077 }
2078 }
2079 else if(expr.id() == ID_onehot)
2080 {
2081 convert_expr(to_onehot_expr(expr).lower());
2082 }
2083 else if(expr.id() == ID_onehot0)
2084 {
2085 convert_expr(to_onehot0_expr(expr).lower());
2086 }
2087 else if(expr.id()==ID_extractbits)
2088 {
2090 auto width = boolbv_width(expr.type());
2091
2092 if(extractbits_expr.index().is_constant())
2093 {
2096
2097 out << "((_ extract " << (width + index_i - 1) << " " << index_i << ") ";
2099 out << ")";
2100 }
2101 else
2102 {
2103 #if 0
2104 out << "(= ((_ extract 0 0) ";
2105 // the arguments of the shift need to have the same width
2106 out << "(bvlshr ";
2107 convert_expr(expr.op0());
2108 typecast_exprt tmp(expr.op0().type());
2109 tmp.op0()=expr.op1();
2111 out << ")) bin1)"; // bvlshr, extract, =
2112 #endif
2113 SMT2_TODO("smt2: extractbits with non-constant index");
2114 }
2115 }
2116 else if(expr.id()==ID_replication)
2117 {
2119
2121
2122 // SMT-LIB requires that repeat is given a number of repetitions that is at
2123 // least 1.
2124 PRECONDITION(times >= 1);
2125
2126 out << "((_ repeat " << times << ") ";
2128 out << ")";
2129 }
2130 else if(expr.id()==ID_byte_extract_little_endian ||
2132 {
2133 INVARIANT(
2134 false, "byte_extract ops should be lowered in prepare_for_convert_expr");
2135 }
2136 else if(expr.id()==ID_byte_update_little_endian ||
2138 {
2139 INVARIANT(
2140 false, "byte_update ops should be lowered in prepare_for_convert_expr");
2141 }
2142 else if(expr.id()==ID_abs)
2143 {
2144 const abs_exprt &abs_expr = to_abs_expr(expr);
2145
2146 const typet &type = abs_expr.type();
2147
2148 if(type.id()==ID_signedbv)
2149 {
2150 std::size_t result_width = to_signedbv_type(type).get_width();
2151
2152 out << "(ite (bvslt ";
2153 convert_expr(abs_expr.op());
2154 out << " (_ bv0 " << result_width << ")) ";
2155 out << "(bvneg ";
2156 convert_expr(abs_expr.op());
2157 out << ") ";
2158 convert_expr(abs_expr.op());
2159 out << ")";
2160 }
2161 else if(type.id()==ID_fixedbv)
2162 {
2163 std::size_t result_width=to_fixedbv_type(type).get_width();
2164
2165 out << "(ite (bvslt ";
2166 convert_expr(abs_expr.op());
2167 out << " (_ bv0 " << result_width << ")) ";
2168 out << "(bvneg ";
2169 convert_expr(abs_expr.op());
2170 out << ") ";
2171 convert_expr(abs_expr.op());
2172 out << ")";
2173 }
2174 else if(type.id()==ID_floatbv)
2175 {
2176 if(use_FPA_theory)
2177 {
2178 out << "(fp.abs ";
2179 convert_expr(abs_expr.op());
2180 out << ")";
2181 }
2182 else
2184 }
2185 else
2187 }
2188 else if(expr.id()==ID_isnan)
2189 {
2190 const isnan_exprt &isnan_expr = to_isnan_expr(expr);
2191
2192 const typet &op_type = isnan_expr.op().type();
2193
2194 if(op_type.id()==ID_fixedbv)
2195 out << "false";
2196 else if(op_type.id()==ID_floatbv)
2197 {
2198 if(use_FPA_theory)
2199 {
2200 out << "(fp.isNaN ";
2202 out << ")";
2203 }
2204 else
2206 }
2207 else
2209 }
2210 else if(expr.id()==ID_isfinite)
2211 {
2213
2214 const typet &op_type = isfinite_expr.op().type();
2215
2216 if(op_type.id()==ID_fixedbv)
2217 out << "true";
2218 else if(op_type.id()==ID_floatbv)
2219 {
2220 if(use_FPA_theory)
2221 {
2222 out << "(and ";
2223
2224 out << "(not (fp.isNaN ";
2226 out << "))";
2227
2228 out << "(not (fp.isInfinite ";
2230 out << "))";
2231
2232 out << ")";
2233 }
2234 else
2236 }
2237 else
2239 }
2240 else if(expr.id()==ID_isinf)
2241 {
2242 const isinf_exprt &isinf_expr = to_isinf_expr(expr);
2243
2244 const typet &op_type = isinf_expr.op().type();
2245
2246 if(op_type.id()==ID_fixedbv)
2247 out << "false";
2248 else if(op_type.id()==ID_floatbv)
2249 {
2250 if(use_FPA_theory)
2251 {
2252 out << "(fp.isInfinite ";
2254 out << ")";
2255 }
2256 else
2258 }
2259 else
2261 }
2262 else if(expr.id()==ID_isnormal)
2263 {
2265
2266 const typet &op_type = isnormal_expr.op().type();
2267
2268 if(op_type.id()==ID_fixedbv)
2269 out << "true";
2270 else if(op_type.id()==ID_floatbv)
2271 {
2272 if(use_FPA_theory)
2273 {
2274 out << "(fp.isNormal ";
2276 out << ")";
2277 }
2278 else
2280 }
2281 else
2283 }
2284 else if(
2287 expr.id() == ID_overflow_result_plus ||
2288 expr.id() == ID_overflow_result_minus)
2289 {
2291
2292 const auto &op0 = to_binary_expr(expr).op0();
2293 const auto &op1 = to_binary_expr(expr).op1();
2294
2296 keep_result || expr.is_boolean(),
2297 "overflow plus and overflow minus expressions shall be of Boolean type");
2298
2299 bool subtract = can_cast_expr<minus_overflow_exprt>(expr) ||
2300 expr.id() == ID_overflow_result_minus;
2301 const typet &op_type = op0.type();
2302 std::size_t width=boolbv_width(op_type);
2303
2304 if(op_type.id()==ID_signedbv)
2305 {
2306 // an overflow occurs if the top two bits of the extended sum differ
2307 out << "(let ((?sum (";
2308 out << (subtract?"bvsub":"bvadd");
2309 out << " ((_ sign_extend 1) ";
2310 convert_expr(op0);
2311 out << ")";
2312 out << " ((_ sign_extend 1) ";
2313 convert_expr(op1);
2314 out << ")))) "; // sign_extend, bvadd/sub
2315 if(keep_result)
2316 {
2317 if(use_datatypes)
2318 {
2319 const std::string &smt_typename = datatype_map.at(expr.type());
2320
2321 // use the constructor for the Z3 datatype
2322 out << "(mk-" << smt_typename;
2323 }
2324 else
2325 out << "(concat";
2326
2327 out << " ((_ extract " << width - 1 << " 0) ?sum) ";
2328 if(!use_datatypes)
2329 out << "(ite ";
2330 }
2331 out << "(not (= "
2332 "((_ extract " << width << " " << width << ") ?sum) "
2333 "((_ extract " << (width-1) << " " << (width-1) << ") ?sum)";
2334 out << "))"; // =, not
2335 if(keep_result)
2336 {
2337 if(!use_datatypes)
2338 out << " #b1 #b0)";
2339 out << ")"; // concat
2340 }
2341 out << ")"; // let
2342 }
2343 else if(op_type.id()==ID_unsignedbv ||
2344 op_type.id()==ID_pointer)
2345 {
2346 // overflow is simply carry-out
2347 out << "(let ((?sum (" << (subtract ? "bvsub" : "bvadd");
2348 out << " ((_ zero_extend 1) ";
2349 convert_expr(op0);
2350 out << ")";
2351 out << " ((_ zero_extend 1) ";
2352 convert_expr(op1);
2353 out << "))))"; // zero_extend, bvsub/bvadd
2355 out << " ?sum";
2356 else
2357 {
2359 {
2360 const std::string &smt_typename = datatype_map.at(expr.type());
2361
2362 // use the constructor for the Z3 datatype
2363 out << "(mk-" << smt_typename;
2364 out << " ((_ extract " << width - 1 << " 0) ?sum) ";
2365 }
2366
2367 out << "(= ";
2368 out << "((_ extract " << width << " " << width << ") ?sum)";
2369 out << "#b1)"; // =
2370
2372 out << ")"; // mk
2373 }
2374 out << ")"; // let
2375 }
2376 else
2378 false,
2379 "overflow check should not be performed on unsupported type",
2380 op_type.id_string());
2381 }
2382 else if(
2384 expr.id() == ID_overflow_result_mult)
2385 {
2387
2388 const auto &op0 = to_binary_expr(expr).op0();
2389 const auto &op1 = to_binary_expr(expr).op1();
2390
2392 keep_result || expr.is_boolean(),
2393 "overflow mult expression shall be of Boolean type");
2394
2395 // No better idea than to multiply with double the bits and then compare
2396 // with max value.
2397
2398 const typet &op_type = op0.type();
2399 std::size_t width=boolbv_width(op_type);
2400
2401 if(op_type.id()==ID_signedbv)
2402 {
2403 out << "(let ( (prod (bvmul ((_ sign_extend " << width << ") ";
2404 convert_expr(op0);
2405 out << ") ((_ sign_extend " << width << ") ";
2406 convert_expr(op1);
2407 out << ")) )) ";
2408 if(keep_result)
2409 {
2410 if(use_datatypes)
2411 {
2412 const std::string &smt_typename = datatype_map.at(expr.type());
2413
2414 // use the constructor for the Z3 datatype
2415 out << "(mk-" << smt_typename;
2416 }
2417 else
2418 out << "(concat";
2419
2420 out << " ((_ extract " << width - 1 << " 0) prod) ";
2421 if(!use_datatypes)
2422 out << "(ite ";
2423 }
2424 out << "(or (bvsge prod (_ bv" << power(2, width-1) << " "
2425 << width*2 << "))";
2426 out << " (bvslt prod (bvneg (_ bv" << power(2, width - 1) << " "
2427 << width * 2 << "))))";
2428 if(keep_result)
2429 {
2430 if(!use_datatypes)
2431 out << " #b1 #b0)";
2432 out << ")"; // concat
2433 }
2434 out << ")";
2435 }
2436 else if(op_type.id()==ID_unsignedbv)
2437 {
2438 out << "(let ((prod (bvmul ((_ zero_extend " << width << ") ";
2439 convert_expr(op0);
2440 out << ") ((_ zero_extend " << width << ") ";
2441 convert_expr(op1);
2442 out << ")))) ";
2443 if(keep_result)
2444 {
2445 if(use_datatypes)
2446 {
2447 const std::string &smt_typename = datatype_map.at(expr.type());
2448
2449 // use the constructor for the Z3 datatype
2450 out << "(mk-" << smt_typename;
2451 }
2452 else
2453 out << "(concat";
2454
2455 out << " ((_ extract " << width - 1 << " 0) prod) ";
2456 if(!use_datatypes)
2457 out << "(ite ";
2458 }
2459 out << "(bvuge prod (_ bv" << power(2, width) << " " << width * 2 << "))";
2460 if(keep_result)
2461 {
2462 if(!use_datatypes)
2463 out << " #b1 #b0)";
2464 out << ")"; // concat
2465 }
2466 out << ")";
2467 }
2468 else
2470 false,
2471 "overflow check should not be performed on unsupported type",
2472 op_type.id_string());
2473 }
2474 else if(expr.id() == ID_saturating_plus || expr.id() == ID_saturating_minus)
2475 {
2476 const bool subtract = expr.id() == ID_saturating_minus;
2477 const auto &op_type = expr.type();
2478 const auto &op0 = to_binary_expr(expr).op0();
2479 const auto &op1 = to_binary_expr(expr).op1();
2480
2481 if(op_type.id() == ID_signedbv)
2482 {
2483 auto width = to_signedbv_type(op_type).get_width();
2484
2485 // compute sum with one extra bit
2486 out << "(let ((?sum (";
2487 out << (subtract ? "bvsub" : "bvadd");
2488 out << " ((_ sign_extend 1) ";
2489 convert_expr(op0);
2490 out << ")";
2491 out << " ((_ sign_extend 1) ";
2492 convert_expr(op1);
2493 out << ")))) "; // sign_extend, bvadd/sub
2494
2495 // pick one of MAX, MIN, or the sum
2496 out << "(ite (= "
2497 "((_ extract "
2498 << width << " " << width
2499 << ") ?sum) "
2500 "((_ extract "
2501 << (width - 1) << " " << (width - 1) << ") ?sum)";
2502 out << ") "; // =
2503
2504 // no overflow and no underflow case, return the sum
2505 out << "((_ extract " << width - 1 << " 0) ?sum) ";
2506
2507 // MAX
2508 out << "(ite (= ((_ extract " << width << " " << width << ") ?sum) #b0) ";
2509 convert_expr(to_signedbv_type(op_type).largest_expr());
2510
2511 // MIN
2512 convert_expr(to_signedbv_type(op_type).smallest_expr());
2513 out << ")))"; // ite, ite, let
2514 }
2515 else if(op_type.id() == ID_unsignedbv)
2516 {
2517 auto width = to_unsignedbv_type(op_type).get_width();
2518
2519 // compute sum with one extra bit
2520 out << "(let ((?sum (" << (subtract ? "bvsub" : "bvadd");
2521 out << " ((_ zero_extend 1) ";
2522 convert_expr(op0);
2523 out << ")";
2524 out << " ((_ zero_extend 1) ";
2525 convert_expr(op1);
2526 out << "))))"; // zero_extend, bvsub/bvadd
2527
2528 // pick one of MAX, MIN, or the sum
2529 out << "(ite (= ((_ extract " << width << " " << width << ") ?sum) #b0) ";
2530
2531 // no overflow and no underflow case, return the sum
2532 out << " ((_ extract " << width - 1 << " 0) ?sum) ";
2533
2534 // overflow when adding, underflow when subtracting
2535 if(subtract)
2536 convert_expr(to_unsignedbv_type(op_type).smallest_expr());
2537 else
2538 convert_expr(to_unsignedbv_type(op_type).largest_expr());
2539
2540 // MIN
2541 out << "))"; // ite, let
2542 }
2543 else
2545 false,
2546 "saturating_plus/minus on unsupported type",
2547 op_type.id_string());
2548 }
2549 else if(expr.id()==ID_array)
2550 {
2551 defined_expressionst::const_iterator it=defined_expressions.find(expr);
2552 CHECK_RETURN(it != defined_expressions.end());
2553 out << it->second;
2554 }
2555 else if(expr.id()==ID_literal)
2556 {
2557 convert_literal(to_literal_expr(expr).get_literal());
2558 }
2559 else if(expr.id()==ID_forall ||
2560 expr.id()==ID_exists)
2561 {
2563
2565 // NOLINTNEXTLINE(readability/throw)
2566 throw "MathSAT does not support quantifiers";
2567
2568 if(quantifier_expr.id() == ID_forall)
2569 out << "(forall ";
2570 else if(quantifier_expr.id() == ID_exists)
2571 out << "(exists ";
2572
2573 out << '(';
2574 bool first = true;
2575 for(const auto &bound : quantifier_expr.variables())
2576 {
2577 if(first)
2578 first = false;
2579 else
2580 out << ' ';
2581 out << '(';
2583 out << ' ';
2584 convert_type(bound.type());
2585 out << ')';
2586 }
2587 out << ") ";
2588
2590
2591 out << ')';
2592 }
2593 else if(
2595 {
2597 }
2598 else if(expr.id()==ID_let)
2599 {
2600 const let_exprt &let_expr=to_let_expr(expr);
2601 const auto &variables = let_expr.variables();
2602 const auto &values = let_expr.values();
2603
2604 out << "(let (";
2605 bool first = true;
2606
2607 for(auto &binding : make_range(variables).zip(values))
2608 {
2609 if(first)
2610 first = false;
2611 else
2612 out << ' ';
2613
2614 out << '(';
2615 convert_expr(binding.first);
2616 out << ' ';
2617 convert_expr(binding.second);
2618 out << ')';
2619 }
2620
2621 out << ") "; // bindings
2622
2623 convert_expr(let_expr.where());
2624 out << ')'; // let
2625 }
2626 else if(expr.id()==ID_constraint_select_one)
2627 {
2629 "smt2_convt::convert_expr: '" + expr.id_string() +
2630 "' is not yet supported");
2631 }
2632 else if(expr.id() == ID_bswap)
2633 {
2634 const bswap_exprt &bswap_expr = to_bswap_expr(expr);
2635
2637 bswap_expr.op().type() == bswap_expr.type(),
2638 "operand of byte swap expression shall have same type as the expression");
2639
2640 // first 'let' the operand
2641 out << "(let ((bswap_op ";
2643 out << ")) ";
2644
2645 if(
2646 bswap_expr.type().id() == ID_signedbv ||
2647 bswap_expr.type().id() == ID_unsignedbv)
2648 {
2649 const std::size_t width =
2650 to_bitvector_type(bswap_expr.type()).get_width();
2651
2652 const std::size_t bits_per_byte = bswap_expr.get_bits_per_byte();
2653
2654 // width must be multiple of bytes
2656 width % bits_per_byte == 0,
2657 "bit width indicated by type of bswap expression should be a multiple "
2658 "of the number of bits per byte");
2659
2660 const std::size_t bytes = width / bits_per_byte;
2661
2662 if(bytes <= 1)
2663 out << "bswap_op";
2664 else
2665 {
2666 // do a parallel 'let' for each byte
2667 out << "(let (";
2668
2669 for(std::size_t byte = 0; byte < bytes; byte++)
2670 {
2671 if(byte != 0)
2672 out << ' ';
2673 out << "(bswap_byte_" << byte << ' ';
2674 out << "((_ extract " << (byte * bits_per_byte + (bits_per_byte - 1))
2675 << " " << (byte * bits_per_byte) << ") bswap_op)";
2676 out << ')';
2677 }
2678
2679 out << ") ";
2680
2681 // now stitch back together with 'concat'
2682 out << "(concat";
2683
2684 for(std::size_t byte = 0; byte < bytes; byte++)
2685 out << " bswap_byte_" << byte;
2686
2687 out << ')'; // concat
2688 out << ')'; // let bswap_byte_*
2689 }
2690 }
2691 else
2692 UNEXPECTEDCASE("bswap must get bitvector operand");
2693
2694 out << ')'; // let bswap_op
2695 }
2696 else if(expr.id() == ID_popcount)
2697 {
2699 }
2700 else if(expr.id() == ID_count_leading_zeros)
2701 {
2703 }
2704 else if(expr.id() == ID_count_trailing_zeros)
2705 {
2707 }
2708 else if(expr.id() == ID_find_first_set)
2709 {
2711 }
2712 else if(expr.id() == ID_bitreverse)
2713 {
2715 }
2716 else if(expr.id() == ID_zero_extend)
2717 {
2718 convert_expr(to_zero_extend_expr(expr).lower());
2719 }
2720 else if(expr.id() == ID_function_application)
2721 {
2723
2724 // Front-ends such as Strata represent string and regex operations as
2725 // applications of the CPROVER string built-in functions
2726 // (ID_cprover_string_*_func / ID_cprover_regex_*_func). In the SMT-LIB
2727 // back-end these carry SMT-LIB-native operands (String / RegLan, and
2728 // scalar Int/bit-vector index arguments) -- as opposed to the
2729 // refined-string (length, char-array) representation that the SAT string
2730 // solver in src/solvers/strings consumes -- and we lower them directly to
2731 // the SMT-LIB theory-of-strings operators here.
2732 //
2733 // Operand contract (what a front-end must emit): arguments are SMT-LIB
2734 // native and in SMT-LIB operand order, so most built-ins lower to a flat
2735 // application (op arg0 arg1 ...). Specifically:
2736 // concat(s, t, ...) -> (str.++ s t ...)
2737 // length(s) -> (str.len s) : Int result
2738 // char_at(s, i) -> (str.at s i) : 1-char String
2739 // substring(s, off, len) -> (str.substr s off len) : offset+length
2740 // contains(haystack, needle) -> (str.contains haystack needle)
2741 // is_prefix(prefix, s) -> (str.prefixof prefix s)
2742 // is_suffix(suffix, s) -> (str.suffixof suffix s)
2743 // replace(s, old, new) -> (str.replace s old new) : first match
2744 // equal(s, t) -> (= s t)
2745 // index_of(s, sub[, off]) -> (str.indexof s sub off) : off defaults 0
2746 // startswith(s, prefix) -> (str.prefixof prefix s)
2747 // endswith(s, suffix) -> (str.suffixof suffix s)
2748 // is_empty(s) -> (= s "")
2749 // and the regex operators map to str.to_re / str.in_re and the re.* family
2750 // (re.range, re.++, re.*, re.+, re.opt, re.loop, re.union, re.inter,
2751 // re.comp, re.diff, re.all, re.allchar, re.none). Built-ins without an
2752 // exact SMT-LIB theory-of-strings counterpart (e.g. compare_to, of_int,
2753 // parse_int, format, case folding, trim) are intentionally not lowered and
2754 // fall through to the generic function-application handling below.
2755 //
2756 // Note: this lowering is specific to the (non-incremental) smt2_convt
2757 // back-end. The incremental SMT back-end uses a separate converter
2758 // (src/solvers/smt2_incremental) and does not support these built-ins.
2760 if(function_application_expr.function().id() == ID_symbol)
2761 fn_id =
2762 to_symbol_expr(function_application_expr.function()).get_identifier();
2763
2764 const auto &args = function_application_expr.arguments();
2765
2766 // Flat-application operators: lowered to (op arg0 arg1 ...) with operands
2767 // in the order given. The operands are interpreted in SMT-LIB order, which
2768 // can DIVERGE from the canonical SAT string solver's built-ins -- notably
2769 // substring is (string, offset, length) per SMT-LIB str.substr, NOT the
2770 // SAT solver's (string, start, end), and index_of's optional third operand
2771 // is a start offset. A front-end must emit these built-ins with SMT-LIB
2772 // operand semantics; the soundness guard below only catches refined-string
2773 // (array/pointer) operands, not a mismatched integer operand pair.
2774 static const std::map<irep_idt, std::string> flat_string_ops = {
2775 // string operators
2777 {ID_cprover_string_length_func, "str.len"},
2778 {ID_cprover_string_substring_func, "str.substr"},
2780 {ID_cprover_string_contains_func, "str.contains"},
2781 {ID_cprover_string_is_prefix_func, "str.prefixof"},
2782 {ID_cprover_string_is_suffix_func, "str.suffixof"},
2783 {ID_cprover_string_replace_func, "str.replace"},
2785 // regex operators
2786 {ID_cprover_string_to_regex_func, "str.to_re"},
2787 {ID_cprover_string_in_regex_func, "str.in_re"},
2788 {ID_cprover_regex_range_func, "re.range"},
2792 {ID_cprover_regex_opt_func, "re.opt"},
2793 {ID_cprover_regex_union_func, "re.union"},
2794 {ID_cprover_regex_inter_func, "re.inter"},
2795 {ID_cprover_regex_comp_func, "re.comp"},
2796 {ID_cprover_regex_diff_func, "re.diff"},
2797 {ID_cprover_regex_all_func, "re.all"},
2798 {ID_cprover_regex_allchar_func, "re.allchar"},
2799 {ID_cprover_regex_none_func, "re.none"}};
2800
2801 std::string smt_name;
2802 if(auto it = flat_string_ops.find(fn_id); it != flat_string_ops.end())
2803 smt_name = it->second;
2804
2805 // Operators needing a fixed operand rearrangement or wrapper.
2811
2812 if(
2813 !smt_name.empty() || is_index_of || is_startswith || is_endswith ||
2815 {
2816 // Soundness guard: this native lowering expects SMT-LIB-native operands.
2817 // The same cprover_string_*_func ids are also used with the
2818 // refined-string (length, char-array) representation consumed by the SAT
2819 // string solver; such an application carries array- or pointer-typed
2820 // operands and must NOT be lowered here, as doing so would be silently
2821 // unsound. Reject it with a clear message instead.
2822 for(const auto &arg : args)
2823 {
2824 if(arg.type().id() == ID_array || arg.type().id() == ID_pointer)
2825 {
2827 "string/regex built-in '" + id2string(fn_id) +
2828 "' reached the SMT-LIB string lowering with a refined-string "
2829 "(array/pointer) operand; the refined-string representation "
2830 "requires the SAT string solver (--refine-strings)");
2831 }
2832 }
2833
2834 if(is_index_of)
2835 {
2836 // str.indexof requires three operands; default the start offset to the
2837 // SMT-LIB Int 0 when the front-end omits it.
2838 PRECONDITION(args.size() == 2 || args.size() == 3);
2839 out << "(str.indexof ";
2840 convert_expr(args[0]);
2841 out << ' ';
2842 convert_expr(args[1]);
2843 out << ' ';
2844 if(args.size() == 3)
2845 convert_expr(args[2]);
2846 else
2847 out << '0';
2848 out << ')';
2849 }
2850 else if(is_startswith || is_endswith)
2851 {
2852 // startswith(s, prefix) / endswith(s, suffix): the affix is the second
2853 // argument, but SMT-LIB str.prefixof/str.suffixof take the affix first.
2854 PRECONDITION(args.size() == 2);
2855 out << (is_startswith ? "(str.prefixof " : "(str.suffixof ");
2856 convert_expr(args[1]);
2857 out << ' ';
2858 convert_expr(args[0]);
2859 out << ')';
2860 }
2861 else if(is_is_empty)
2862 {
2863 // is_empty(s) -> (= s "")
2864 PRECONDITION(args.size() == 1);
2865 out << "(= ";
2866 convert_expr(args[0]);
2867 out << " \"\")";
2868 }
2869 else if(is_regex_loop)
2870 {
2871 // re.loop is an indexed SMT-LIB operator: ((_ re.loop lo hi) r), where
2872 // lo and hi are numerals. Contract: loop(regex, lo, hi) with lo/hi
2873 // constant naturals.
2874 PRECONDITION(args.size() == 3);
2875 const auto lo = numeric_cast_v<mp_integer>(to_constant_expr(args[1]));
2876 const auto hi = numeric_cast_v<mp_integer>(to_constant_expr(args[2]));
2877 out << "((_ re.loop " << lo << ' ' << hi << ") ";
2878 convert_expr(args[0]);
2879 out << ')';
2880 }
2881 else if(args.empty())
2882 out << smt_name;
2883 else
2884 {
2885 out << '(' << smt_name;
2886 for(const auto &arg : args)
2887 {
2888 out << ' ';
2889 convert_expr(arg);
2890 }
2891 out << ')';
2892 }
2893 }
2894 // do not use parentheses if there function is a constant
2895 else if(function_application_expr.arguments().empty())
2896 {
2898 }
2899 else
2900 {
2901 out << '(';
2903 for(auto &op : function_application_expr.arguments())
2904 {
2905 out << ' ';
2906 convert_expr(op);
2907 }
2908 out << ')';
2909 }
2910 }
2911 else if(expr.id() == ID_cond)
2912 {
2913 // use the lowering
2914 convert_expr(to_cond_expr(expr).lower());
2915 }
2916 else if(expr.id() == ID_reduction_and)
2917 {
2918 // This is true iff all bits in the operand are true
2919 auto &op = to_reduction_and_expr(expr).op();
2920 auto all_ones = to_bitvector_type(op.type()).all_ones_expr();
2922 }
2923 else if(expr.id() == ID_reduction_nand)
2924 {
2925 // This is the negation of "reduction and"
2926 auto &op = to_reduction_nand_expr(expr).op();
2928 }
2929 else if(expr.id() == ID_reduction_or)
2930 {
2931 // This is true iff the operand is not zero
2932 auto &op = to_reduction_or_expr(expr).op();
2933 auto all_zeros = to_bitvector_type(op.type()).all_zeros_expr();
2935 }
2936 else if(expr.id() == ID_reduction_nor)
2937 {
2938 // This is the negation of "reduction or"
2939 auto &op = to_reduction_nor_expr(expr).op();
2941 }
2942 else if(expr.id() == ID_reduction_xor)
2943 {
2944 // This is the parity of the operand. No SMT-LIB 2 equivalent.
2945 // Do bit-wise. SMT-LIB 3.0 could do this with "fold bvxor".
2946 auto &op = to_reduction_xor_expr(expr).op();
2947 auto width = to_bitvector_type(op.type()).get_width();
2948 PRECONDITION(width >= 1);
2949
2950 if(width == 1)
2951 {
2952 out << "(= ";
2953 flatten2bv(op);
2954 out << " #b1)";
2955 }
2956 else
2957 {
2958 out << "(let ((?rop ";
2959 flatten2bv(op);
2960 out << ")) ";
2961
2962 // XOR all bits: extract each bit and use multi-ary bvxor
2963 out << "(= (bvxor";
2964 for(std::size_t i = 0; i < width; i++)
2965 out << " ((_ extract " << i << " " << i << ") ?rop)";
2966 out << ") #b1)";
2967
2968 out << ')'; // let
2969 }
2970 }
2971 else if(expr.id() == ID_reduction_xnor)
2972 {
2973 // This is the negation of "reduction xor"
2974 auto &op = to_reduction_xnor_expr(expr).op();
2976 }
2977 else
2979 false,
2980 "smt2_convt::convert_expr should not be applied to unsupported "
2981 "expression",
2982 expr.id_string());
2983}
2984
2986{
2987 const exprt &src = expr.op();
2988
2989 typet dest_type = expr.type();
2990
2991 if(dest_type == src.type()) // identity
2992 {
2993 convert_expr(src);
2994 return;
2995 }
2996
2997 if(dest_type.id()==ID_c_enum_tag)
2999
3000 typet src_type = src.type();
3001 if(src_type.id()==ID_c_enum_tag)
3003
3004 if(dest_type.id()==ID_bool)
3005 {
3006 // this is comparison with zero
3007 if(
3008 src_type.id() == ID_signedbv || src_type.id() == ID_unsignedbv ||
3009 src_type.id() == ID_c_bool || src_type.id() == ID_fixedbv ||
3010 src_type.id() == ID_pointer || src_type.id() == ID_integer ||
3011 src_type.id() == ID_natural || src_type.id() == ID_rational ||
3012 src_type.id() == ID_real)
3013 {
3014 out << "(not (= ";
3015 convert_expr(src);
3016 out << " ";
3018 out << "))";
3019 }
3020 else if(src_type.id()==ID_floatbv)
3021 {
3022 if(use_FPA_theory)
3023 {
3024 out << "(not (fp.isZero ";
3025 convert_expr(src);
3026 out << "))";
3027 }
3028 else
3029 convert_floatbv(expr);
3030 }
3031 else
3032 {
3033 UNEXPECTEDCASE("TODO typecast1 "+src_type.id_string()+" -> bool");
3034 }
3035 }
3036 else if(dest_type.id()==ID_c_bool)
3037 {
3038 std::size_t to_width=boolbv_width(dest_type);
3039 out << "(ite ";
3040 out << "(not (= ";
3041 convert_expr(src);
3042 out << " ";
3044 out << "))"; // not, =
3045 out << " (_ bv1 " << to_width << ")";
3046 out << " (_ bv0 " << to_width << ")";
3047 out << ")"; // ite
3048 }
3049 else if(dest_type.id()==ID_signedbv ||
3050 dest_type.id()==ID_unsignedbv ||
3051 dest_type.id()==ID_c_enum ||
3052 dest_type.id()==ID_bv)
3053 {
3054 std::size_t to_width=boolbv_width(dest_type);
3055
3056 if(src_type.id()==ID_signedbv || // from signedbv
3057 src_type.id()==ID_unsignedbv || // from unsigedbv
3058 src_type.id()==ID_c_bool ||
3059 src_type.id()==ID_c_enum ||
3060 src_type.id()==ID_bv)
3061 {
3062 std::size_t from_width=boolbv_width(src_type);
3063
3064 if(from_width==to_width)
3065 convert_expr(src); // ignore
3066 else if(from_width<to_width) // extend
3067 {
3068 if(src_type.id()==ID_signedbv)
3069 out << "((_ sign_extend ";
3070 else
3071 out << "((_ zero_extend ";
3072
3074 << ") "; // ind
3075 convert_expr(src);
3076 out << ")";
3077 }
3078 else // chop off extra bits
3079 {
3080 out << "((_ extract " << (to_width-1) << " 0) ";
3081 convert_expr(src);
3082 out << ")";
3083 }
3084 }
3085 else if(src_type.id()==ID_fixedbv) // from fixedbv to int
3086 {
3088
3089 std::size_t from_width=fixedbv_type.get_width();
3090 std::size_t from_integer_bits=fixedbv_type.get_integer_bits();
3091 std::size_t from_fraction_bits=fixedbv_type.get_fraction_bits();
3092
3093 // we might need to round up in case of negative numbers
3094 // e.g., (int)(-1.00001)==1
3095
3096 out << "(let ((?tcop ";
3097 convert_expr(src);
3098 out << ")) ";
3099
3100 out << "(bvadd ";
3101
3103 {
3104 out << "((_ sign_extend "
3105 << (to_width-from_integer_bits) << ") ";
3106 out << "((_ extract " << (from_width-1) << " "
3107 << from_fraction_bits << ") ";
3108 convert_expr(src);
3109 out << "))";
3110 }
3111 else
3112 {
3113 out << "((_ extract " << (from_fraction_bits+to_width-1)
3114 << " " << from_fraction_bits << ") ";
3115 convert_expr(src);
3116 out << ")";
3117 }
3118
3119 out << " (ite (and ";
3120
3121 // some fraction bit is not zero
3122 out << "(not (= ((_ extract " << (from_fraction_bits-1) << " 0) ?tcop) "
3123 "(_ bv0 " << from_fraction_bits << ")))";
3124
3125 // number negative
3126 out << " (= ((_ extract " << (from_width-1) << " " << (from_width-1)
3127 << ") ?tcop) #b1)";
3128
3129 out << ")"; // and
3130
3131 out << " (_ bv1 " << to_width << ") (_ bv0 " << to_width << "))"; // ite
3132 out << ")"; // bvadd
3133 out << ")"; // let
3134 }
3135 else if(src_type.id()==ID_floatbv) // from floatbv to int
3136 {
3137 if(dest_type.id()==ID_bv)
3138 {
3139 // this is _NOT_ a semantic conversion, but bit-wise
3140
3141 if(use_FPA_theory)
3142 {
3143 defined_expressionst::const_iterator it =
3144 defined_expressions.find(expr);
3145 CHECK_RETURN(it != defined_expressions.end());
3146 out << it->second;
3147 }
3148 else
3149 {
3150 // straight-forward if width matches
3151 convert_expr(src);
3152 }
3153 }
3154 else if(dest_type.id()==ID_signedbv)
3155 {
3156 // this should be floatbv_typecast, not typecast
3158 "typecast unexpected "+src_type.id_string()+" -> "+
3159 dest_type.id_string());
3160 }
3161 else if(dest_type.id()==ID_unsignedbv)
3162 {
3163 // this should be floatbv_typecast, not typecast
3165 "typecast unexpected "+src_type.id_string()+" -> "+
3166 dest_type.id_string());
3167 }
3168 }
3169 else if(src_type.id()==ID_bool) // from boolean to int
3170 {
3171 out << "(ite ";
3172 convert_expr(src);
3173
3174 if(dest_type.id()==ID_fixedbv)
3175 {
3177 out << " (concat (_ bv1 "
3178 << spec.integer_bits << ") " <<
3179 "(_ bv0 " << spec.get_fraction_bits() << ")) " <<
3180 "(_ bv0 " << spec.width << ")";
3181 }
3182 else
3183 {
3184 out << " (_ bv1 " << to_width << ")";
3185 out << " (_ bv0 " << to_width << ")";
3186 }
3187
3188 out << ")";
3189 }
3190 else if(src_type.id()==ID_pointer) // from pointer to int
3191 {
3192 std::size_t from_width=boolbv_width(src_type);
3193
3194 if(from_width<to_width) // extend
3195 {
3196 out << "((_ sign_extend ";
3198 << ") ";
3199 convert_expr(src);
3200 out << ")";
3201 }
3202 else // chop off extra bits
3203 {
3204 out << "((_ extract " << (to_width-1) << " 0) ";
3205 convert_expr(src);
3206 out << ")";
3207 }
3208 }
3209 else if(src_type.id() == ID_integer || src_type.id() == ID_natural)
3210 {
3211 // from integer to bit-vector, must be constant
3212 if(src.is_constant())
3213 {
3215 out << "(_ bv" << i << " " << to_width << ")";
3216 }
3217 else
3218 SMT2_TODO("can't convert non-constant integer to bitvector");
3219 }
3220 else if(
3221 src_type.id() == ID_struct ||
3222 src_type.id() == ID_struct_tag) // flatten a struct to a bit-vector
3223 {
3224 if(use_datatypes)
3225 {
3226 INVARIANT(
3228 "bit vector with of source and destination type shall be equal");
3229 flatten2bv(src);
3230 }
3231 else
3232 {
3233 INVARIANT(
3235 "bit vector with of source and destination type shall be equal");
3236 convert_expr(src); // nothing else to do!
3237 }
3238 }
3239 else if(
3240 src_type.id() == ID_union ||
3241 src_type.id() == ID_union_tag) // flatten a union
3242 {
3243 INVARIANT(
3245 "bit vector with of source and destination type shall be equal");
3246 convert_expr(src); // nothing else to do!
3247 }
3248 else if(src_type.id()==ID_c_bit_field)
3249 {
3250 std::size_t from_width=boolbv_width(src_type);
3251
3252 if(from_width==to_width)
3253 convert_expr(src); // ignore
3254 else
3255 {
3259 }
3260 }
3261 else
3262 {
3263 std::ostringstream e_str;
3264 e_str << src_type.id() << " -> " << dest_type.id()
3265 << " src == " << format(src);
3266 UNEXPECTEDCASE("TODO typecast2 " + e_str.str());
3267 }
3268 }
3269 else if(dest_type.id()==ID_fixedbv) // to fixedbv
3270 {
3272 std::size_t to_fraction_bits=fixedbv_type.get_fraction_bits();
3273 std::size_t to_integer_bits=fixedbv_type.get_integer_bits();
3274
3275 if(src_type.id()==ID_unsignedbv ||
3276 src_type.id()==ID_signedbv ||
3277 src_type.id()==ID_c_enum)
3278 {
3279 // integer to fixedbv
3280
3281 std::size_t from_width=to_bitvector_type(src_type).get_width();
3282 out << "(concat ";
3283
3285 convert_expr(src);
3287 {
3288 // too many integer bits
3289 out << "((_ extract " << (to_integer_bits-1) << " 0) ";
3290 convert_expr(src);
3291 out << ")";
3292 }
3293 else
3294 {
3295 // too few integer bits
3296 INVARIANT(
3298 "from_width should be smaller than to_integer_bits as other case "
3299 "have been handled above");
3300 if(dest_type.id()==ID_unsignedbv)
3301 {
3302 out << "(_ zero_extend "
3303 << (to_integer_bits-from_width) << ") ";
3304 convert_expr(src);
3305 out << ")";
3306 }
3307 else
3308 {
3309 out << "((_ sign_extend "
3310 << (to_integer_bits-from_width) << ") ";
3311 convert_expr(src);
3312 out << ")";
3313 }
3314 }
3315
3316 out << "(_ bv0 " << to_fraction_bits << ")";
3317 out << ")"; // concat
3318 }
3319 else if(src_type.id()==ID_bool) // bool to fixedbv
3320 {
3321 out << "(concat (concat"
3322 << " (_ bv0 " << (to_integer_bits-1) << ") ";
3323 flatten2bv(src); // produces #b0 or #b1
3324 out << ") (_ bv0 "
3326 << "))";
3327 }
3328 else if(src_type.id()==ID_fixedbv) // fixedbv to fixedbv
3329 {
3331 std::size_t from_fraction_bits=from_fixedbv_type.get_fraction_bits();
3332 std::size_t from_integer_bits=from_fixedbv_type.get_integer_bits();
3333 std::size_t from_width=from_fixedbv_type.get_width();
3334
3335 out << "(let ((?tcop ";
3336 convert_expr(src);
3337 out << ")) ";
3338
3339 out << "(concat ";
3340
3342 {
3343 out << "((_ extract "
3346 << ") ?tcop)";
3347 }
3348 else
3349 {
3350 INVARIANT(
3352 "to_integer_bits should be greater than from_integer_bits as the"
3353 "other case has been handled above");
3354 out << "((_ sign_extend "
3356 << ") ((_ extract "
3357 << (from_width-1) << " "
3359 << ") ?tcop))";
3360 }
3361
3362 out << " ";
3363
3365 {
3366 out << "((_ extract "
3367 << (from_fraction_bits-1) << " "
3369 << ") ?tcop)";
3370 }
3371 else
3372 {
3373 INVARIANT(
3375 "to_fraction_bits should be greater than from_fraction_bits as the"
3376 "other case has been handled above");
3377 out << "(concat ((_ extract "
3378 << (from_fraction_bits-1) << " 0) ";
3379 convert_expr(src);
3380 out << ")"
3381 << " (_ bv0 " << to_fraction_bits-from_fraction_bits
3382 << "))";
3383 }
3384
3385 out << "))"; // concat, let
3386 }
3387 else
3388 UNEXPECTEDCASE("unexpected typecast to fixedbv");
3389 }
3390 else if(dest_type.id()==ID_pointer)
3391 {
3392 std::size_t to_width=boolbv_width(dest_type);
3393
3394 if(src_type.id()==ID_pointer) // pointer to pointer
3395 {
3396 // this just passes through
3397 convert_expr(src);
3398 }
3399 else if(
3400 src_type.id() == ID_unsignedbv || src_type.id() == ID_signedbv ||
3401 src_type.id() == ID_bv)
3402 {
3403 // integer to pointer
3404
3405 std::size_t from_width=boolbv_width(src_type);
3406
3407 if(from_width==to_width)
3408 convert_expr(src);
3409 else if(from_width<to_width)
3410 {
3411 out << "((_ sign_extend "
3412 << (to_width-from_width)
3413 << ") ";
3414 convert_expr(src);
3415 out << ")"; // sign_extend
3416 }
3417 else // from_width>to_width
3418 {
3419 out << "((_ extract " << to_width << " 0) ";
3420 convert_expr(src);
3421 out << ")"; // extract
3422 }
3423 }
3424 else
3425 UNEXPECTEDCASE("TODO typecast3 "+src_type.id_string()+" -> pointer");
3426 }
3427 else if(dest_type.id()==ID_range)
3428 {
3430 const auto dest_width = address_bits(dest_range_type.size());
3431 if(src_type.id() == ID_range)
3432 {
3434 const auto src_width = address_bits(src_range_type.size());
3435 if(src_width < dest_width)
3436 {
3437 out << "((_ zero_extend " << dest_width - src_width << ") ";
3438 convert_expr(src);
3439 out << ')'; // zero_extend
3440 }
3441 else if(src_width > dest_width)
3442 {
3443 out << "((_ extract " << dest_width - 1 << " 0) ";
3444 convert_expr(src);
3445 out << ')'; // extract
3446 }
3447 else // src_width == dest_width
3448 {
3449 convert_expr(src);
3450 }
3451 }
3452 else
3453 SMT2_TODO("typecast from " + src_type.id_string() + " to range");
3454 }
3455 else if(dest_type.id()==ID_floatbv)
3456 {
3457 // Typecast from integer to floating-point should have be been
3458 // converted to ID_floatbv_typecast during symbolic execution,
3459 // adding the rounding mode. See
3460 // smt2_convt::convert_floatbv_typecast.
3461 // The exception is bool and c_bool to float.
3463
3464 if(src_type.id()==ID_bool)
3465 {
3466 out << "(ite ";
3467 convert_expr(src);
3468 out << ' ';
3470 out << ' ';
3472 out << ')';
3473 }
3474 else if(src_type.id()==ID_c_bool)
3475 {
3476 // turn into proper bool
3477 const typecast_exprt tmp(src, bool_typet());
3479 }
3480 else if(src_type.id() == ID_bv)
3481 {
3482 if(to_bv_type(src_type).get_width() != dest_floatbv_type.get_width())
3483 {
3484 UNEXPECTEDCASE("Typecast bv -> float with wrong width");
3485 }
3486
3487 if(use_FPA_theory)
3488 {
3489 out << "((_ to_fp " << dest_floatbv_type.get_e() << " "
3490 << dest_floatbv_type.get_f() + 1 << ") ";
3491 convert_expr(src);
3492 out << ')';
3493 }
3494 else
3495 convert_expr(src);
3496 }
3497 else
3498 UNEXPECTEDCASE("Unknown typecast "+src_type.id_string()+" -> float");
3499 }
3500 else if(dest_type.id() == ID_integer || dest_type.id() == ID_natural)
3501 {
3502 if(src_type.id()==ID_bool)
3503 {
3504 out << "(ite ";
3505 convert_expr(src);
3506 out <<" 1 0)";
3507 }
3508 else
3509 UNEXPECTEDCASE("Unknown typecast "+src_type.id_string()+" -> integer");
3510 }
3511 else if(dest_type.id()==ID_c_bit_field)
3512 {
3513 std::size_t from_width=boolbv_width(src_type);
3514 std::size_t to_width=boolbv_width(dest_type);
3515
3516 if(from_width==to_width)
3517 convert_expr(src); // ignore
3518 else
3519 {
3523 }
3524 }
3525 else if(dest_type.id() == ID_rational)
3526 {
3527 if(src_type.id() == ID_signedbv)
3528 {
3529 // TODO: negative numbers
3530 out << "(/ ";
3531 convert_expr(src);
3532 out << " 1)";
3533 }
3534 else
3536 "Unknown typecast " + src_type.id_string() + " -> rational");
3537 }
3538 else
3540 "TODO typecast8 "+src_type.id_string()+" -> "+dest_type.id_string());
3541}
3542
3544{
3545 const exprt &src=expr.op();
3546 // const exprt &rounding_mode=expr.rounding_mode();
3547 const typet &src_type=src.type();
3548 const typet &dest_type=expr.type();
3549
3550 if(dest_type.id()==ID_floatbv)
3551 {
3552 if(src_type.id()==ID_floatbv)
3553 {
3554 // float to float
3555
3556 /* ISO 9899:1999
3557 * 6.3.1.5 Real floating types
3558 * 1 When a float is promoted to double or long double, or a
3559 * double is promoted to long double, its value is unchanged.
3560 *
3561 * 2 When a double is demoted to float, a long double is
3562 * demoted to double or float, or a value being represented in
3563 * greater precision and range than required by its semantic
3564 * type (see 6.3.1.8) is explicitly converted to its semantic
3565 * type, if the value being converted can be represented
3566 * exactly in the new type, it is unchanged. If the value
3567 * being converted is in the range of values that can be
3568 * represented but cannot be represented exactly, the result
3569 * is either the nearest higher or nearest lower representable
3570 * value, chosen in an implementation-defined manner. If the
3571 * value being converted is outside the range of values that
3572 * can be represented, the behavior is undefined.
3573 */
3574
3576
3577 if(use_FPA_theory)
3578 {
3579 out << "((_ to_fp " << dst.get_e() << " "
3580 << dst.get_f() + 1 << ") ";
3582 out << " ";
3583 convert_expr(src);
3584 out << ")";
3585 }
3586 else
3587 convert_floatbv(expr);
3588 }
3589 else if(src_type.id()==ID_unsignedbv)
3590 {
3591 // unsigned to float
3592
3593 /* ISO 9899:1999
3594 * 6.3.1.4 Real floating and integer
3595 * 2 When a value of integer type is converted to a real
3596 * floating type, if the value being converted can be
3597 * represented exactly in the new type, it is unchanged. If the
3598 * value being converted is in the range of values that can be
3599 * represented but cannot be represented exactly, the result is
3600 * either the nearest higher or nearest lower representable
3601 * value, chosen in an implementation-defined manner. If the
3602 * value being converted is outside the range of values that can
3603 * be represented, the behavior is undefined.
3604 */
3605
3607
3608 if(use_FPA_theory)
3609 {
3610 out << "((_ to_fp_unsigned " << dst.get_e() << " "
3611 << dst.get_f() + 1 << ") ";
3613 out << " ";
3614 convert_expr(src);
3615 out << ")";
3616 }
3617 else
3618 convert_floatbv(expr);
3619 }
3620 else if(src_type.id()==ID_signedbv)
3621 {
3622 // signed to float
3623
3625
3626 if(use_FPA_theory)
3627 {
3628 out << "((_ to_fp " << dst.get_e() << " "
3629 << dst.get_f() + 1 << ") ";
3631 out << " ";
3632 convert_expr(src);
3633 out << ")";
3634 }
3635 else
3636 convert_floatbv(expr);
3637 }
3638 else if(src_type.id()==ID_c_enum_tag)
3639 {
3640 // enum to float
3641
3642 // We first convert to 'underlying type'
3644 tmp.op() = typecast_exprt(
3645 src, ns.follow_tag(to_c_enum_tag_type(src_type)).underlying_type());
3647 }
3648 else
3650 "TODO typecast11 "+src_type.id_string()+" -> "+dest_type.id_string());
3651 }
3652 else if(dest_type.id()==ID_signedbv)
3653 {
3654 if(use_FPA_theory)
3655 {
3656 std::size_t dest_width=to_signedbv_type(dest_type).get_width();
3657 out << "((_ fp.to_sbv " << dest_width << ") ";
3659 out << " ";
3660 convert_expr(src);
3661 out << ")";
3662 }
3663 else
3664 convert_floatbv(expr);
3665 }
3666 else if(dest_type.id()==ID_unsignedbv)
3667 {
3668 if(use_FPA_theory)
3669 {
3670 std::size_t dest_width=to_unsignedbv_type(dest_type).get_width();
3671 out << "((_ fp.to_ubv " << dest_width << ") ";
3673 out << " ";
3674 convert_expr(src);
3675 out << ")";
3676 }
3677 else
3678 convert_floatbv(expr);
3679 }
3680 else
3681 {
3683 "TODO typecast12 "+src_type.id_string()+" -> "+dest_type.id_string());
3684 }
3685}
3686
3689{
3690 PRECONDITION(expr.type().id() == ID_floatbv);
3691
3692 if(use_FPA_theory)
3693 {
3694 out << "(fp.roundToIntegral ";
3696 out << ' ';
3697 convert_expr(expr.op());
3698 out << ")";
3699 }
3700 else
3701 UNEXPECTEDCASE("TODO floatbv_round_to_integral without FPA");
3702}
3703
3705{
3706 const struct_typet &struct_type =
3707 expr.type().id() == ID_struct_tag
3708 ? ns.follow_tag(to_struct_tag_type(expr.type()))
3709 : to_struct_type(expr.type());
3710
3711 const struct_typet::componentst &components=
3712 struct_type.components();
3713
3715 components.size() == expr.operands().size(),
3716 "number of struct components as indicated by the struct type shall be equal"
3717 "to the number of operands of the struct expression");
3718
3719 DATA_INVARIANT(!components.empty(), "struct shall have struct components");
3720
3721 if(use_datatypes)
3722 {
3723 const std::string &smt_typename = datatype_map.at(struct_type);
3724
3725 // use the constructor for the Z3 datatype
3726 out << "(mk-" << smt_typename;
3727
3728 std::size_t i=0;
3729 for(struct_typet::componentst::const_iterator
3730 it=components.begin();
3731 it!=components.end();
3732 it++, i++)
3733 {
3734 if(is_zero_width(it->type(), ns))
3735 continue;
3736 out << " ";
3737 convert_expr(expr.operands()[i]);
3738 }
3739
3740 out << ")";
3741 }
3742 else
3743 {
3744 auto convert_operand = [this](const exprt &op) {
3745 // may need to flatten array-theory arrays in there
3746 if(op.type().id() == ID_array && use_array_theory(op))
3747 flatten_array(op);
3748 else if(op.type().id() == ID_bool)
3749 flatten2bv(op);
3750 else
3751 convert_expr(op);
3752 };
3753
3754 // SMT-LIB 2 concat is binary only
3755 std::size_t n_concat = 0;
3756 for(std::size_t i = components.size(); i > 1; i--)
3757 {
3758 if(is_zero_width(components[i - 1].type(), ns))
3759 continue;
3760 else if(i > 2 || !is_zero_width(components[0].type(), ns))
3761 {
3762 ++n_concat;
3763 out << "(concat ";
3764 }
3765
3766 convert_operand(expr.operands()[i - 1]);
3767
3768 out << " ";
3769 }
3770
3771 if(!is_zero_width(components[0].type(), ns))
3772 convert_operand(expr.op0());
3773
3774 out << std::string(n_concat, ')');
3775 }
3776}
3777
3780{
3781 const array_typet &array_type = to_array_type(expr.type());
3782 const auto &size_expr = array_type.size();
3783 // Flattening an array to a bit-vector requires a concrete size. Arrays of
3784 // unknown or non-constant size (e.g. those indexed by a mathematical
3785 // integer) can only be encoded with the SMT-LIB array theory, not
3786 // bit-blasted; report that clearly rather than aborting an invariant.
3787 if(!size_expr.is_constant())
3788 {
3790 "cannot flatten an array of non-constant size to a bit-vector; such an "
3791 "array can only be encoded with the SMT-LIB array theory");
3792 }
3793
3795 CHECK_RETURN_WITH_DIAGNOSTICS(size != 0, "can't convert zero-sized array");
3796
3797 out << "(let ((?far ";
3798 convert_expr(expr);
3799 out << ")) ";
3800
3801 for(mp_integer i=size; i!=0; --i)
3802 {
3803 if(i!=1)
3804 out << "(concat ";
3805 out << "(select ?far ";
3806 convert_expr(from_integer(i - 1, array_type.index_type()));
3807 out << ")";
3808 if(i!=1)
3809 out << " ";
3810 }
3811
3812 // close the many parentheses
3813 for(mp_integer i=size; i>1; --i)
3814 out << ")";
3815
3816 out << ")"; // let
3817}
3818
3820{
3821 const exprt &op=expr.op();
3822
3823 std::size_t total_width = boolbv_width(expr.type());
3824
3825 std::size_t member_width=boolbv_width(op.type());
3826
3827 if(total_width==member_width)
3828 {
3829 flatten2bv(op);
3830 }
3831 else
3832 {
3833 // we will pad with zeros, but non-det would be better
3834 INVARIANT(
3835 total_width > member_width,
3836 "total_width should be greater than member_width as member_width can be"
3837 "at most as large as total_width and the other case has been handled "
3838 "above");
3839 out << "(concat ";
3840 out << "(_ bv0 "
3841 << (total_width-member_width) << ") ";
3842 flatten2bv(op);
3843 out << ")";
3844 }
3845}
3846
3848{
3849 const typet &expr_type=expr.type();
3850
3851 if(expr_type.id()==ID_unsignedbv ||
3852 expr_type.id()==ID_signedbv ||
3853 expr_type.id()==ID_bv ||
3854 expr_type.id()==ID_c_enum ||
3855 expr_type.id()==ID_c_enum_tag ||
3856 expr_type.id()==ID_c_bool ||
3858 {
3859 const std::size_t width = boolbv_width(expr_type);
3860
3861 const mp_integer value = bvrep2integer(expr.get_value(), width, false);
3862
3863 out << "(_ bv" << value
3864 << " " << width << ")";
3865 }
3866 else if(expr_type.id()==ID_fixedbv)
3867 {
3869
3870 const mp_integer v = bvrep2integer(expr.get_value(), spec.width, false);
3871
3872 out << "(_ bv" << v << " " << spec.width << ")";
3873 }
3874 else if(expr_type.id()==ID_floatbv)
3875 {
3878
3879 if(use_FPA_theory)
3880 {
3881 /* CBMC stores floating point literals in the most
3882 computationally useful form; biased exponents and
3883 significands including the hidden bit. Thus some encoding
3884 is needed to get to IEEE-754 style representations. */
3885
3887 size_t e=floatbv_type.get_e();
3888 size_t f=floatbv_type.get_f()+1;
3889
3890 /* Should be sufficient, but not currently supported by mathsat */
3891 #if 0
3892 mp_integer binary = v.pack();
3893
3894 out << "((_ to_fp " << e << " " << f << ")"
3895 << " #b" << integer2binary(v.pack(), v.spec.width()) << ")";
3896 #endif
3897
3898 if(v.is_NaN())
3899 {
3900 out << "(_ NaN " << e << " " << f << ")";
3901 }
3902 else if(v.is_infinity())
3903 {
3904 if(v.get_sign())
3905 out << "(_ -oo " << e << " " << f << ")";
3906 else
3907 out << "(_ +oo " << e << " " << f << ")";
3908 }
3909 else
3910 {
3911 // Zero, normal or subnormal
3912
3913 mp_integer binary = v.pack();
3914 std::string binaryString(integer2binary(v.pack(), v.spec.width()));
3915
3916 out << "(fp "
3917 << "#b" << binaryString.substr(0, 1) << " "
3918 << "#b" << binaryString.substr(1, e) << " "
3919 << "#b" << binaryString.substr(1+e, f-1) << ")";
3920 }
3921 }
3922 else
3923 {
3924 // produce corresponding bit-vector
3925 const ieee_float_spect spec(floatbv_type);
3926 const mp_integer v = bvrep2integer(expr.get_value(), spec.width(), false);
3927 out << "(_ bv" << v << " " << spec.width() << ")";
3928 }
3929 }
3930 else if(expr_type.id()==ID_pointer)
3931 {
3932 if(expr.is_null_pointer())
3933 {
3934 out << "(_ bv0 " << boolbv_width(expr_type)
3935 << ")";
3936 }
3937 else
3938 {
3939 // just treat the pointer as a bit vector
3940 const std::size_t width = boolbv_width(expr_type);
3941
3942 const mp_integer value = bvrep2integer(expr.get_value(), width, false);
3943
3944 out << "(_ bv" << value << " " << width << ")";
3945 }
3946 }
3947 else if(expr_type.id()==ID_bool)
3948 {
3949 if(expr == true)
3950 out << "true";
3951 else if(expr == false)
3952 out << "false";
3953 else
3954 UNEXPECTEDCASE("unknown Boolean constant");
3955 }
3956 else if(expr_type.id()==ID_array)
3957 {
3958 defined_expressionst::const_iterator it=defined_expressions.find(expr);
3959 CHECK_RETURN(it != defined_expressions.end());
3960 out << it->second;
3961 }
3962 else if(expr_type.id()==ID_rational)
3963 {
3964 std::string value=id2string(expr.get_value());
3965 const bool negative = has_prefix(value, "-");
3966
3967 if(negative)
3968 {
3969 out << "(- ";
3970 value = value.substr(1);
3971 }
3972
3973 size_t pos=value.find("/");
3974
3975 if(pos==std::string::npos)
3976 out << value << ".0";
3977 else
3978 {
3979 out << "(/ " << value.substr(0, pos) << ".0 "
3980 << value.substr(pos+1) << ".0)";
3981 }
3982
3983 if(negative)
3984 out << ')';
3985 }
3986 else if(expr_type.id() == ID_real)
3987 {
3988 const std::string &value = id2string(expr.get_value());
3989 out << value;
3990 if(value.find('.') == std::string::npos)
3991 out << ".0";
3992 }
3993 else if(expr_type.id()==ID_integer)
3994 {
3995 const auto value = id2string(expr.get_value());
3996
3997 // SMT2 has no negative integer literals
3998 if(has_prefix(value, "-"))
3999 out << "(- " << value.substr(1, std::string::npos) << ')';
4000 else
4001 out << value;
4002 }
4003 else if(expr_type.id() == ID_natural)
4004 {
4005 out << expr.get_value();
4006 }
4007 else if(expr_type.id() == ID_range)
4008 {
4010 const auto width = address_bits(range_type.size());
4011 const auto value_int = numeric_cast_v<mp_integer>(expr);
4012 out << "(_ bv" << (value_int - range_type.from()) << " " << width << ")";
4013 }
4014 else if(expr_type.id() == ID_string)
4015 {
4016 // SMT-LIB 2.6 string literal. The only in-string escape is "" for a double
4017 // quote (backslash is literal). Only printable ASCII may appear verbatim;
4018 // control and non-ASCII bytes are encoded with the \u{...} hex escape.
4019 const std::string &value = id2string(expr.get_value());
4020 out << '"';
4021 for(char ch : value)
4022 {
4023 const auto c = static_cast<unsigned char>(ch);
4024 if(c == '"')
4025 out << "\"\"";
4026 else if(c >= 0x20 && c <= 0x7e)
4027 out << ch;
4028 else
4029 out << "\\u{" << std::hex << static_cast<unsigned>(c) << std::dec
4030 << '}';
4031 }
4032 out << '"';
4033 }
4034 else
4035 UNEXPECTEDCASE("unknown constant: "+expr_type.id_string());
4036}
4037
4039{
4040 if(expr.type().id() == ID_integer)
4041 {
4042 out << "(mod ";
4043 convert_expr(expr.op0());
4044 out << ' ';
4045 convert_expr(expr.op1());
4046 out << ')';
4047 }
4048 else
4050 "unsupported type for euclidean_mod: " + expr.type().id_string());
4051}
4052
4054{
4055 if(expr.type().id()==ID_unsignedbv ||
4056 expr.type().id()==ID_signedbv)
4057 {
4058 if(expr.type().id()==ID_unsignedbv)
4059 out << "(bvurem ";
4060 else
4061 out << "(bvsrem ";
4062
4063 convert_expr(expr.op0());
4064 out << " ";
4065 convert_expr(expr.op1());
4066 out << ")";
4067 }
4068 else if(expr.type().id() == ID_integer)
4069 {
4070 // Mathematical integers (mp_integer) truncate toward zero, so the
4071 // remainder takes the sign of the dividend; SMT-LIB mod is always
4072 // non-negative. Take the remainder of the magnitudes and re-apply the
4073 // dividend's sign.
4074 out << "(let ((?ma ";
4075 convert_expr(expr.op0());
4076 out << ") (?mb ";
4077 convert_expr(expr.op1());
4078 out << ")) (let ((?mr (mod (ite (< ?ma 0) (- ?ma) ?ma)";
4079 out << " (ite (< ?mb 0) (- ?mb) ?mb)))) (ite (< ?ma 0) (- ?mr) ?mr)))";
4080 }
4081 else if(expr.type().id() == ID_natural)
4082 {
4083 // Naturals are non-negative, so SMT-LIB mod already matches mp_integer.
4084 out << "(mod ";
4085 convert_expr(expr.op0());
4086 out << " ";
4087 convert_expr(expr.op1());
4088 out << ")";
4089 }
4090 else
4091 UNEXPECTEDCASE("unsupported type for mod: "+expr.type().id_string());
4092}
4093
4095{
4096 std::vector<mp_integer> dynamic_objects;
4098
4099 if(dynamic_objects.empty())
4100 out << "false";
4101 else
4102 {
4103 std::size_t pointer_width = boolbv_width(expr.op().type());
4104
4105 out << "(let ((?obj ((_ extract "
4106 << pointer_width-1 << " "
4107 << pointer_width-config.bv_encoding.object_bits << ") ";
4108 convert_expr(expr.op());
4109 out << "))) ";
4110
4111 if(dynamic_objects.size()==1)
4112 {
4113 out << "(= (_ bv" << dynamic_objects.front()
4114 << " " << config.bv_encoding.object_bits << ") ?obj)";
4115 }
4116 else
4117 {
4118 out << "(or";
4119
4120 for(const auto &object : dynamic_objects)
4121 out << " (= (_ bv" << object
4122 << " " << config.bv_encoding.object_bits << ") ?obj)";
4123
4124 out << ")"; // or
4125 }
4126
4127 out << ")"; // let
4128 }
4129}
4130
4132{
4133 const typet &op_type=expr.op0().type();
4134
4135 if(
4136 op_type.id() == ID_unsignedbv || op_type.id() == ID_bv ||
4137 op_type.id() == ID_range)
4138 {
4139 // The range type is encoded in binary
4140 out << "(";
4141 if(expr.id()==ID_le)
4142 out << "bvule";
4143 else if(expr.id()==ID_lt)
4144 out << "bvult";
4145 else if(expr.id()==ID_ge)
4146 out << "bvuge";
4147 else if(expr.id()==ID_gt)
4148 out << "bvugt";
4149
4150 out << " ";
4151 convert_expr(expr.op0());
4152 out << " ";
4153 convert_expr(expr.op1());
4154 out << ")";
4155 }
4156 else if(op_type.id()==ID_signedbv ||
4157 op_type.id()==ID_fixedbv)
4158 {
4159 out << "(";
4160 if(expr.id()==ID_le)
4161 out << "bvsle";
4162 else if(expr.id()==ID_lt)
4163 out << "bvslt";
4164 else if(expr.id()==ID_ge)
4165 out << "bvsge";
4166 else if(expr.id()==ID_gt)
4167 out << "bvsgt";
4168
4169 out << " ";
4170 convert_expr(expr.op0());
4171 out << " ";
4172 convert_expr(expr.op1());
4173 out << ")";
4174 }
4175 else if(op_type.id()==ID_floatbv)
4176 {
4177 if(use_FPA_theory)
4178 {
4179 out << "(";
4180 if(expr.id()==ID_le)
4181 out << "fp.leq";
4182 else if(expr.id()==ID_lt)
4183 out << "fp.lt";
4184 else if(expr.id()==ID_ge)
4185 out << "fp.geq";
4186 else if(expr.id()==ID_gt)
4187 out << "fp.gt";
4188
4189 out << " ";
4190 convert_expr(expr.op0());
4191 out << " ";
4192 convert_expr(expr.op1());
4193 out << ")";
4194 }
4195 else
4196 convert_floatbv(expr);
4197 }
4198 else if(
4199 op_type.id() == ID_rational || op_type.id() == ID_integer ||
4200 op_type.id() == ID_natural || op_type.id() == ID_real)
4201 {
4202 out << "(";
4203 out << expr.id();
4204
4205 out << " ";
4206 convert_expr(expr.op0());
4207 out << " ";
4208 convert_expr(expr.op1());
4209 out << ")";
4210 }
4211 else if(op_type.id() == ID_pointer)
4212 {
4213 const exprt same_object = ::same_object(expr.op0(), expr.op1());
4214
4215 out << "(and ";
4217
4218 out << " (";
4219 if(expr.id() == ID_le)
4220 out << "bvsle";
4221 else if(expr.id() == ID_lt)
4222 out << "bvslt";
4223 else if(expr.id() == ID_ge)
4224 out << "bvsge";
4225 else if(expr.id() == ID_gt)
4226 out << "bvsgt";
4227
4228 out << ' ';
4230 out << ' ';
4232 out << ')';
4233
4234 out << ')';
4235 }
4236 else
4238 "unsupported type for "+expr.id_string()+": "+op_type.id_string());
4239}
4240
4242{
4243 if(
4244 expr.type().id() == ID_rational || expr.type().id() == ID_integer ||
4245 expr.type().id() == ID_natural || expr.type().id() == ID_real)
4246 {
4247 // these are multi-ary in SMT-LIB2
4248 out << "(+";
4249
4250 for(const auto &op : expr.operands())
4251 {
4252 out << ' ';
4253 convert_expr(op);
4254 }
4255
4256 out << ')';
4257 }
4258 else if(
4259 expr.type().id() == ID_unsignedbv || expr.type().id() == ID_signedbv ||
4260 expr.type().id() == ID_fixedbv)
4261 {
4262 // These could be chained, i.e., need not be binary,
4263 // but at least MathSat doesn't like that.
4264 if(expr.operands().size() == 2)
4265 {
4266 out << "(bvadd ";
4267 convert_expr(expr.op0());
4268 out << " ";
4269 convert_expr(expr.op1());
4270 out << ")";
4271 }
4272 else
4273 {
4275 }
4276 }
4277 else if(expr.type().id() == ID_range)
4278 {
4279 auto &range_type = to_integer_range_type(expr.type());
4280
4281 // These could be chained, i.e., need not be binary,
4282 // but at least MathSat doesn't like that.
4283 if(expr.operands().size() == 2)
4284 {
4285 // add: lhs + from + rhs + from - from = lhs + rhs + from
4286 const auto width = address_bits(range_type.size());
4287
4288 out << "(bvadd ";
4289 convert_expr(expr.op0());
4290 out << " (bvadd ";
4291 convert_expr(expr.op1());
4292 out << " (_ bv" << range_type.from() << ' ' << width
4293 << ")))"; // bv, bvadd, bvadd
4294 }
4295 else
4296 {
4298 }
4299 }
4300 else if(expr.type().id() == ID_floatbv)
4301 {
4302 // Floating-point additions should have be been converted
4303 // to ID_floatbv_plus during symbolic execution, adding
4304 // the rounding mode. See smt2_convt::convert_floatbv_plus.
4306 }
4307 else if(expr.type().id() == ID_pointer)
4308 {
4309 if(expr.operands().size() == 2)
4310 {
4311 exprt p = expr.op0(), i = expr.op1();
4312
4313 if(p.type().id() != ID_pointer)
4314 p.swap(i);
4315
4317 p.type().id() == ID_pointer,
4318 "one of the operands should have pointer type");
4319
4320 const auto &base_type = to_pointer_type(expr.type()).base_type();
4322 base_type.id() != ID_empty, "no pointer arithmetic over void pointers");
4323
4324 auto element_size_opt = pointer_offset_size(base_type, ns);
4325 CHECK_RETURN(element_size_opt.has_value() && *element_size_opt >= 0);
4327
4328 // First convert the pointer operand
4329 out << "(let ((?pointerop ";
4330 convert_expr(p);
4331 out << ")) ";
4332
4333 // The addition is done on the offset part only.
4334 const std::size_t pointer_width = boolbv_width(p.type());
4335 const std::size_t offset_bits =
4336 pointer_width - config.bv_encoding.object_bits;
4337
4338 out << "(concat ";
4339 out << "((_ extract " << pointer_width - 1 << ' ' << offset_bits
4340 << ") ?pointerop) ";
4341 out << "(bvadd ((_ extract " << offset_bits - 1 << " 0) ?pointerop) ";
4342
4343 if(element_size >= 2)
4344 {
4345 out << "(bvmul ((_ extract " << offset_bits - 1 << " 0) ";
4346 convert_expr(i);
4347 out << ") (_ bv" << element_size << " " << offset_bits << "))";
4348 }
4349 else
4350 {
4351 out << "((_ extract " << offset_bits - 1 << " 0) ";
4352 convert_expr(i);
4353 out << ')'; // extract
4354 }
4355
4356 out << ")))"; // bvadd, concat, let
4357 }
4358 else
4359 {
4361 }
4362 }
4363 else
4364 UNEXPECTEDCASE("unsupported type for +: " + expr.type().id_string());
4365}
4366
4371{
4373
4374 /* CProver uses the x86 numbering of the rounding-mode
4375 * 0 == FE_TONEAREST
4376 * 1 == FE_DOWNWARD
4377 * 2 == FE_UPWARD
4378 * 3 == FE_TOWARDZERO
4379 * These literal values must be used rather than the macros
4380 * the macros from fenv.h to avoid portability problems.
4381 */
4382
4383 if(expr.is_constant())
4384 {
4386
4388
4389 if(value==0)
4390 out << "roundNearestTiesToEven";
4391 else if(value==1)
4392 out << "roundTowardNegative";
4393 else if(value==2)
4394 out << "roundTowardPositive";
4395 else if(value==3)
4396 out << "roundTowardZero";
4397 else if(value == 4)
4398 out << "roundNearestTiesToAway";
4399 else
4401 false,
4402 "Rounding mode should have value 0, 1, 2, 3, or 4",
4403 id2string(cexpr.get_value()));
4404 }
4405 else
4406 {
4407 std::size_t width=to_bitvector_type(expr.type()).get_width();
4408
4409 // Need to make the choice above part of the model
4410 out << "(ite (= (_ bv0 " << width << ") ";
4411 convert_expr(expr);
4412 out << ") roundNearestTiesToEven ";
4413
4414 out << "(ite (= (_ bv1 " << width << ") ";
4415 convert_expr(expr);
4416 out << ") roundTowardNegative ";
4417
4418 out << "(ite (= (_ bv2 " << width << ") ";
4419 convert_expr(expr);
4420 out << ") roundTowardPositive ";
4421
4422 out << "(ite (= (_ bv3 " << width << ") ";
4423 convert_expr(expr);
4424 out << ") roundTowardZero ";
4425
4426 // TODO: add some kind of error checking here
4427 out << "roundNearestTiesToAway";
4428
4429 out << "))))";
4430 }
4431}
4432
4434{
4435 const typet &type=expr.type();
4436
4438 type.id() == ID_floatbv ||
4439 (type.id() == ID_complex &&
4440 to_complex_type(type).subtype().id() == ID_floatbv));
4441
4442 if(use_FPA_theory)
4443 {
4444 if(type.id()==ID_floatbv)
4445 {
4446 out << "(fp.add ";
4448 out << " ";
4449 convert_expr(expr.lhs());
4450 out << " ";
4451 convert_expr(expr.rhs());
4452 out << ")";
4453 }
4454 else if(type.id()==ID_complex)
4455 {
4456 SMT2_TODO("+ for floatbv complex");
4457 }
4458 else
4460 false,
4461 "type should not be one of the unsupported types",
4462 type.id_string());
4463 }
4464 else
4465 convert_floatbv(expr);
4466}
4467
4469{
4470 if(
4471 expr.type().id() == ID_integer || expr.type().id() == ID_natural ||
4472 expr.type().id() == ID_rational || expr.type().id() == ID_real)
4473 {
4474 out << "(- ";
4475 convert_expr(expr.op0());
4476 out << " ";
4477 convert_expr(expr.op1());
4478 out << ")";
4479 }
4480 else if(expr.type().id()==ID_unsignedbv ||
4481 expr.type().id()==ID_signedbv ||
4482 expr.type().id()==ID_fixedbv)
4483 {
4484 if(expr.op0().type().id()==ID_pointer &&
4485 expr.op1().type().id()==ID_pointer)
4486 {
4487 // Pointer difference
4488 const auto &base_type = to_pointer_type(expr.op0().type()).base_type();
4490 base_type.id() != ID_empty, "no pointer arithmetic over void pointers");
4491 auto element_size_opt = pointer_offset_size(base_type, ns);
4492 CHECK_RETURN(element_size_opt.has_value() && *element_size_opt >= 1);
4494
4495 if(element_size >= 2)
4496 out << "(bvsdiv ";
4497
4498 INVARIANT(
4499 boolbv_width(expr.op0().type()) == boolbv_width(expr.type()),
4500 "bitvector width of operand shall be equal to the bitvector width of "
4501 "the expression");
4502
4503 out << "(bvsub ";
4504 convert_expr(expr.op0());
4505 out << " ";
4506 convert_expr(expr.op1());
4507 out << ")";
4508
4509 if(element_size >= 2)
4510 out << " (_ bv" << element_size << " " << boolbv_width(expr.type())
4511 << "))";
4512 }
4513 else
4514 {
4515 out << "(bvsub ";
4516 convert_expr(expr.op0());
4517 out << " ";
4518 convert_expr(expr.op1());
4519 out << ")";
4520 }
4521 }
4522 else if(expr.type().id()==ID_floatbv)
4523 {
4524 // Floating-point subtraction should have be been converted
4525 // to ID_floatbv_minus during symbolic execution, adding
4526 // the rounding mode. See smt2_convt::convert_floatbv_minus.
4528 }
4529 else if(expr.type().id()==ID_pointer)
4530 {
4531 if(
4532 expr.op0().type().id() == ID_pointer &&
4533 (expr.op1().type().id() == ID_unsignedbv ||
4534 expr.op1().type().id() == ID_signedbv))
4535 {
4536 // rewrite p-o to p+(-o)
4537 return convert_plus(
4538 plus_exprt(expr.op0(), unary_minus_exprt(expr.op1())));
4539 }
4540 else
4542 "unsupported operand types for -: " + expr.op0().type().id_string() +
4543 " and " + expr.op1().type().id_string());
4544 }
4545 else if(expr.type().id() == ID_range)
4546 {
4547 auto &range_type = to_integer_range_type(expr.type());
4548
4549 // sub: lhs + from - (rhs + from) - from = lhs - rhs - from
4550 const auto width = address_bits(range_type.size());
4551
4552 out << "(bvsub (bvsub ";
4553 convert_expr(expr.op0());
4554 out << ' ';
4555 convert_expr(expr.op1());
4556 out << ") (_ bv" << range_type.from() << ' ' << width << "))"; // bv, bvsub
4557 }
4558 else
4559 UNEXPECTEDCASE("unsupported type for -: "+expr.type().id_string());
4560}
4561
4563{
4565 expr.type().id() == ID_floatbv,
4566 "type of ieee floating point expression shall be floatbv");
4567
4568 if(use_FPA_theory)
4569 {
4570 out << "(fp.sub ";
4572 out << " ";
4573 convert_expr(expr.lhs());
4574 out << " ";
4575 convert_expr(expr.rhs());
4576 out << ")";
4577 }
4578 else
4579 convert_floatbv(expr);
4580}
4581
4583{
4584 if(expr.type().id()==ID_unsignedbv ||
4585 expr.type().id()==ID_signedbv)
4586 {
4587 if(expr.type().id()==ID_unsignedbv)
4588 out << "(bvudiv ";
4589 else
4590 out << "(bvsdiv ";
4591
4592 convert_expr(expr.op0());
4593 out << " ";
4594 convert_expr(expr.op1());
4595 out << ")";
4596 }
4597 else if(expr.type().id()==ID_fixedbv)
4598 {
4599 fixedbv_spect spec(to_fixedbv_type(expr.type()));
4600 std::size_t fraction_bits=spec.get_fraction_bits();
4601
4602 out << "((_ extract " << spec.width-1 << " 0) ";
4603 out << "(bvsdiv ";
4604
4605 out << "(concat ";
4606 convert_expr(expr.op0());
4607 out << " (_ bv0 " << fraction_bits << ")) ";
4608
4609 out << "((_ sign_extend " << fraction_bits << ") ";
4610 convert_expr(expr.op1());
4611 out << ")";
4612
4613 out << "))";
4614 }
4615 else if(expr.type().id()==ID_floatbv)
4616 {
4617 // Floating-point division should have be been converted
4618 // to ID_floatbv_div during symbolic execution, adding
4619 // the rounding mode. See smt2_convt::convert_floatbv_div.
4621 }
4622 else if(
4623 expr.type().id() == ID_rational || expr.type().id() == ID_integer ||
4624 expr.type().id() == ID_natural || expr.type().id() == ID_real)
4625 {
4626 if(expr.type().id() == ID_integer)
4627 {
4628 // Mathematical integers (mp_integer) truncate division toward zero,
4629 // whereas SMT-LIB div floors. Encode truncation: divide the magnitudes
4630 // and make the quotient negative iff the operands have opposite signs.
4631 out << "(let ((?da ";
4632 convert_expr(expr.op0());
4633 out << ") (?db ";
4634 convert_expr(expr.op1());
4635 out << ")) (let ((?dq (div (ite (< ?da 0) (- ?da) ?da)";
4636 out << " (ite (< ?db 0) (- ?db) ?db))))";
4637 out << " (ite (= (< ?da 0) (< ?db 0)) ?dq (- ?dq))))";
4638 }
4639 else
4640 {
4641 // Naturals are non-negative (SMT-LIB div already truncates); rationals
4642 // and reals use real division.
4643 if(expr.type().id() == ID_natural)
4644 out << "(div ";
4645 else
4646 out << "(/ ";
4647 convert_expr(expr.op0());
4648 out << " ";
4649 convert_expr(expr.op1());
4650 out << ")";
4651 }
4652 }
4653 else
4654 UNEXPECTEDCASE("unsupported type for /: "+expr.type().id_string());
4655}
4656
4658{
4660 expr.type().id() == ID_floatbv,
4661 "type of ieee floating point expression shall be floatbv");
4662
4663 if(use_FPA_theory)
4664 {
4665 out << "(fp.div ";
4667 out << " ";
4668 convert_expr(expr.lhs());
4669 out << " ";
4670 convert_expr(expr.rhs());
4671 out << ")";
4672 }
4673 else
4674 convert_floatbv(expr);
4675}
4676
4678{
4679 // re-write to binary if needed
4680 if(expr.operands().size()>2)
4681 {
4682 // strip last operand
4683 exprt tmp=expr;
4684 tmp.operands().pop_back();
4685
4686 // recursive call
4687 return convert_mult(mult_exprt(tmp, expr.operands().back()));
4688 }
4689
4690 INVARIANT(
4691 expr.operands().size() == 2,
4692 "expression should have been converted to a variant with two operands");
4693
4694 if(expr.type().id()==ID_unsignedbv ||
4695 expr.type().id()==ID_signedbv)
4696 {
4697 // Note that bvmul is really unsigned,
4698 // but this is irrelevant as we chop-off any extra result
4699 // bits.
4700 out << "(bvmul ";
4701 convert_expr(expr.op0());
4702 out << " ";
4703 convert_expr(expr.op1());
4704 out << ")";
4705 }
4706 else if(expr.type().id()==ID_floatbv)
4707 {
4708 // Floating-point multiplication should have be been converted
4709 // to ID_floatbv_mult during symbolic execution, adding
4710 // the rounding mode. See smt2_convt::convert_floatbv_mult.
4712 }
4713 else if(expr.type().id()==ID_fixedbv)
4714 {
4715 fixedbv_spect spec(to_fixedbv_type(expr.type()));
4716 std::size_t fraction_bits=spec.get_fraction_bits();
4717
4718 out << "((_ extract "
4719 << spec.width+fraction_bits-1 << " "
4720 << fraction_bits << ") ";
4721
4722 out << "(bvmul ";
4723
4724 out << "((_ sign_extend " << fraction_bits << ") ";
4725 convert_expr(expr.op0());
4726 out << ") ";
4727
4728 out << "((_ sign_extend " << fraction_bits << ") ";
4729 convert_expr(expr.op1());
4730 out << ")";
4731
4732 out << "))"; // bvmul, extract
4733 }
4734 else if(
4735 expr.type().id() == ID_rational || expr.type().id() == ID_integer ||
4736 expr.type().id() == ID_natural || expr.type().id() == ID_real)
4737 {
4738 out << "(*";
4739
4740 for(const auto &op : expr.operands())
4741 {
4742 out << " ";
4743 convert_expr(op);
4744 }
4745
4746 out << ")";
4747 }
4748 else
4749 UNEXPECTEDCASE("unsupported type for *: "+expr.type().id_string());
4750}
4751
4753{
4755 expr.type().id() == ID_floatbv,
4756 "type of ieee floating point expression shall be floatbv");
4757
4758 if(use_FPA_theory)
4759 {
4760 out << "(fp.mul ";
4762 out << " ";
4763 convert_expr(expr.lhs());
4764 out << " ";
4765 convert_expr(expr.rhs());
4766 out << ")";
4767 }
4768 else
4769 convert_floatbv(expr);
4770}
4771
4773{
4775 expr.type().id() == ID_floatbv,
4776 "type of ieee floating point expression shall be floatbv");
4777
4778 if(use_FPA_theory)
4779 {
4780 // Note that these do not have a rounding mode
4781 out << "(fp.rem ";
4782 convert_expr(expr.lhs());
4783 out << " ";
4784 convert_expr(expr.rhs());
4785 out << ")";
4786 }
4787 else
4788 {
4789 SMT2_TODO(
4790 "smt2_convt::convert_floatbv_rem to be implemented when not using "
4791 "FPA_theory");
4792 }
4793}
4794
4796{
4798 expr.type().id() == ID_floatbv,
4799 "type of ieee floating point expression shall be floatbv");
4800
4801 if(use_FPA_theory)
4802 {
4803 out << "(fp.fma ";
4805 out << " ";
4807 out << " ";
4809 out << " ";
4810 convert_expr(expr.op_add());
4811 out << ")";
4812 }
4813 else
4814 convert_floatbv(expr);
4815}
4816
4818{
4819 INVARIANT(
4820 expr.operands().size() == 3,
4821 "with expression should have exactly three operands");
4822
4823 const typet &expr_type = expr.type();
4824
4825 if(expr_type.id()==ID_array)
4826 {
4828
4829 if(use_array_theory(expr))
4830 {
4831 out << "(store ";
4832 convert_expr(expr.old());
4833 out << " ";
4834 convert_expr(typecast_exprt(expr.where(), array_type.index_type()));
4835 out << " ";
4836 convert_expr(expr.new_value());
4837 out << ")";
4838 }
4839 else
4840 {
4841 // fixed-width
4842 std::size_t array_width=boolbv_width(array_type);
4843 std::size_t sub_width = boolbv_width(array_type.element_type());
4844 std::size_t index_width=boolbv_width(expr.where().type());
4845
4846 // We mask out the updated bits with AND,
4847 // and then OR-in the shifted new value.
4848
4849 out << "(let ((distance? ";
4850 out << "(bvmul (_ bv" << sub_width << " " << array_width << ") ";
4851
4852 // SMT2 says that the shift distance needs to be as wide
4853 // as the stuff we are shifting.
4855 {
4856 out << "((_ zero_extend " << array_width-index_width << ") ";
4857 convert_expr(expr.where());
4858 out << ")";
4859 }
4860 else
4861 {
4862 out << "((_ extract " << array_width-1 << " 0) ";
4863 convert_expr(expr.where());
4864 out << ")";
4865 }
4866
4867 out << "))) "; // bvmul, distance?
4868
4869 out << "(bvor ";
4870 out << "(bvand ";
4871 out << "(bvnot ";
4872 out << "(bvshl (_ bv" << power(2, sub_width) - 1 << " " << array_width
4873 << ") ";
4874 out << "distance?)) "; // bvnot, bvlshl
4875 convert_expr(expr.old());
4876 out << ") "; // bvand
4877 out << "(bvshl ";
4878 out << "((_ zero_extend " << array_width-sub_width << ") ";
4879 convert_expr(expr.new_value());
4880 out << ") distance?)))"; // zero_extend, bvshl, bvor, let
4881 }
4882 }
4883 else if(expr_type.id() == ID_struct || expr_type.id() == ID_struct_tag)
4884 {
4885 const struct_typet &struct_type =
4886 expr_type.id() == ID_struct_tag
4887 ? ns.follow_tag(to_struct_tag_type(expr_type))
4889
4890 const exprt &index = expr.where();
4891 const exprt &value = expr.new_value();
4892
4893 const irep_idt &component_name=index.get(ID_component_name);
4894
4895 INVARIANT(
4896 struct_type.has_component(component_name),
4897 "struct should have accessed component");
4898
4899 if(use_datatypes)
4900 {
4901 const std::string &smt_typename = datatype_map.at(expr_type);
4902
4903 out << "(update-" << smt_typename << "." << component_name << " ";
4904 convert_expr(expr.old());
4905 out << " ";
4906 convert_expr(value);
4907 out << ")";
4908 }
4909 else
4910 {
4911 auto convert_operand = [this](const exprt &op)
4912 {
4913 // may need to flatten array-theory arrays in there
4914 if(op.type().id() == ID_array && use_array_theory(op))
4915 flatten_array(op);
4916 else if(op.type().id() == ID_bool)
4917 flatten2bv(op);
4918 else
4919 convert_expr(op);
4920 };
4921
4923
4924 // figure out the offset and width of the member
4925 const boolbv_widtht::membert &m =
4926 boolbv_width.get_member(struct_type, component_name);
4927
4928 if(m.width==struct_width)
4929 {
4930 // the struct is the same as the member, no concat needed
4931 convert_operand(value);
4932 }
4933 else
4934 {
4935 out << "(let ((?withop ";
4936 convert_operand(expr.old());
4937 out << ")) ";
4938
4939 if(m.offset == 0)
4940 {
4941 // the member is at the beginning
4942 out << "(concat "
4943 << "((_ extract " << (struct_width - 1) << " " << m.width
4944 << ") ?withop) ";
4945 convert_operand(value);
4946 out << ")"; // concat
4947 }
4948 else if(m.offset + m.width == struct_width)
4949 {
4950 // the member is at the end
4951 out << "(concat ";
4952 convert_operand(value);
4953 out << " ((_ extract " << (m.offset - 1) << " 0) ?withop))";
4954 }
4955 else
4956 {
4957 // most general case, need two concat-s
4958 out << "(concat (concat "
4959 << "((_ extract " << (struct_width - 1) << " "
4960 << (m.offset + m.width) << ") ?withop) ";
4961 convert_operand(value);
4962 out << ") ((_ extract " << (m.offset - 1) << " 0) ?withop)";
4963 out << ")"; // concat
4964 }
4965
4966 out << ")"; // let ?withop
4967 }
4968 }
4969 }
4970 else if(expr_type.id() == ID_union || expr_type.id() == ID_union_tag)
4971 {
4972 const exprt &value = expr.new_value();
4973
4974 std::size_t total_width = boolbv_width(expr_type);
4975
4976 std::size_t member_width=boolbv_width(value.type());
4977
4978 if(total_width==member_width)
4979 {
4980 flatten2bv(value);
4981 }
4982 else
4983 {
4984 INVARIANT(
4985 total_width > member_width,
4986 "total width should be greater than member_width as member_width is at "
4987 "most as large as total_width and the other case has been handled "
4988 "above");
4989 out << "(concat ";
4990 out << "((_ extract "
4991 << (total_width-1)
4992 << " " << member_width << ") ";
4993 convert_expr(expr.old());
4994 out << ") ";
4995 flatten2bv(value);
4996 out << ")";
4997 }
4998 }
4999 else if(expr_type.id()==ID_bv ||
5000 expr_type.id()==ID_unsignedbv ||
5001 expr_type.id()==ID_signedbv)
5002 {
5003 if(expr.new_value().type().id() == ID_bool)
5004 {
5006 update_bit_exprt(expr.old(), expr.where(), expr.new_value()));
5007 }
5008 else
5009 {
5011 update_bits_exprt(expr.old(), expr.where(), expr.new_value()));
5012 }
5013 }
5014 else
5016 "with expects struct, union, or array type, but got "+
5017 expr.type().id_string());
5018}
5019
5021{
5022 PRECONDITION(expr.operands().size() == 3);
5023
5024 SMT2_TODO("smt2_convt::convert_update to be implemented");
5025}
5026
5028{
5029 return convert_expr(expr.lower());
5030}
5031
5033{
5034 return convert_expr(expr.lower());
5035}
5036
5038{
5039 const typet &array_op_type = expr.array().type();
5040
5041 if(array_op_type.id()==ID_array)
5042 {
5044
5045 if(use_array_theory(expr.array()))
5046 {
5047 if(expr.is_boolean() && !use_array_of_bool)
5048 {
5049 out << "(= ";
5050 out << "(select ";
5051 convert_expr(expr.array());
5052 out << " ";
5053 convert_expr(typecast_exprt(expr.index(), array_type.index_type()));
5054 out << ")";
5055 out << " #b1)";
5056 }
5057 else
5058 {
5059 out << "(select ";
5060 convert_expr(expr.array());
5061 out << " ";
5062 convert_expr(typecast_exprt(expr.index(), array_type.index_type()));
5063 out << ")";
5064 }
5065 }
5066 else
5067 {
5068 // fixed size
5069 std::size_t array_width=boolbv_width(array_type);
5070
5071 unflatten(wheret::BEGIN, array_type.element_type());
5072
5073 std::size_t sub_width = boolbv_width(array_type.element_type());
5074 std::size_t index_width=boolbv_width(expr.index().type());
5075
5076 out << "((_ extract " << sub_width-1 << " 0) ";
5077 out << "(bvlshr ";
5078 convert_expr(expr.array());
5079 out << " ";
5080 out << "(bvmul (_ bv" << sub_width << " " << array_width << ") ";
5081
5082 // SMT2 says that the shift distance must be the same as
5083 // the width of what we shift.
5085 {
5086 out << "((_ zero_extend " << array_width-index_width << ") ";
5087 convert_expr(expr.index());
5088 out << ")"; // zero_extend
5089 }
5090 else
5091 {
5092 out << "((_ extract " << array_width-1 << " 0) ";
5093 convert_expr(expr.index());
5094 out << ")"; // extract
5095 }
5096
5097 out << ")))"; // mult, bvlshr, extract
5098
5099 unflatten(wheret::END, array_type.element_type());
5100 }
5101 }
5102 else
5103 INVARIANT(
5104 false, "index with unsupported array type: " + array_op_type.id_string());
5105}
5106
5108{
5110 const exprt &struct_op=member_expr.struct_op();
5111 const typet &struct_op_type = struct_op.type();
5112 const irep_idt &name=member_expr.get_component_name();
5113
5115 {
5116 const struct_typet &struct_type =
5118 ? ns.follow_tag(to_struct_tag_type(struct_op_type))
5120
5121 INVARIANT(
5122 struct_type.has_component(name), "struct should have accessed component");
5123
5124 if(use_datatypes)
5125 {
5126 const std::string &smt_typename = datatype_map.at(struct_type);
5127
5128 out << "(" << smt_typename << "."
5129 << struct_type.get_component(name).get_name()
5130 << " ";
5131 convert_expr(struct_op);
5132 out << ")";
5133 }
5134 else
5135 {
5136 // we extract
5137 const auto &member_offset = boolbv_width.get_member(struct_type, name);
5138
5139 if(expr.type().id() == ID_bool)
5140 out << "(= ";
5141 out << "((_ extract " << (member_offset.offset + member_offset.width - 1)
5142 << " " << member_offset.offset << ") ";
5143 convert_expr(struct_op);
5144 out << ")";
5145 if(expr.type().id() == ID_bool)
5146 out << " #b1)";
5147 }
5148 }
5149 else if(
5151 {
5152 std::size_t width=boolbv_width(expr.type());
5154 width != 0, "failed to get union member width");
5155
5156 if(use_datatypes)
5157 {
5158 unflatten(wheret::BEGIN, expr.type());
5159
5160 out << "((_ extract " << (width - 1) << " 0) ";
5161 convert_expr(struct_op);
5162 out << ")";
5163
5164 unflatten(wheret::END, expr.type());
5165 }
5166 else
5167 {
5168 out << "((_ extract " << (width - 1) << " 0) ";
5169 convert_expr(struct_op);
5170 out << ")";
5171 }
5172 }
5173 else
5175 "convert_member on an unexpected type "+struct_op_type.id_string());
5176}
5177
5179{
5180 const typet &type = expr.type();
5181
5182 if(type.id()==ID_bool)
5183 {
5184 out << "(ite ";
5185 convert_expr(expr); // this returns a Bool
5186 out << " #b1 #b0)"; // this is a one-bit bit-vector
5187 }
5188 else if(type.id()==ID_array)
5189 {
5190 if(use_array_theory(expr))
5191 {
5192 // concatenate elements
5193 const array_typet &array_type = to_array_type(type);
5194
5195 mp_integer size =
5197
5198 // SMT-LIB 2 concat is binary only
5199 std::size_t n_concat = 0;
5200 for(mp_integer i = size; i > 1; --i)
5201 {
5202 ++n_concat;
5203 out << "(concat ";
5204
5205 flatten2bv(
5206 index_exprt{expr, from_integer(i - 1, array_type.index_type())});
5207
5208 out << " ";
5209 }
5210
5211 flatten2bv(index_exprt{expr, from_integer(0, array_type.index_type())});
5212
5213 out << std::string(n_concat, ')'); // concat
5214 }
5215 else
5216 convert_expr(expr);
5217 }
5218 else if(type.id() == ID_struct || type.id() == ID_struct_tag)
5219 {
5220 if(use_datatypes)
5221 {
5222 // concatenate elements
5223 const struct_typet &struct_type =
5224 type.id() == ID_struct_tag ? ns.follow_tag(to_struct_tag_type(type))
5225 : to_struct_type(type);
5226
5227 const struct_typet::componentst &components=
5228 struct_type.components();
5229
5230 // SMT-LIB 2 concat is binary only
5231 std::size_t n_concat = 0;
5232 for(std::size_t i=components.size(); i>1; i--)
5233 {
5234 if(is_zero_width(components[i - 1].type(), ns))
5235 continue;
5236 else if(i > 2 || !is_zero_width(components[0].type(), ns))
5237 {
5238 ++n_concat;
5239 out << "(concat ";
5240 }
5241
5242 flatten2bv(member_exprt{expr, components[i - 1]});
5243
5244 out << " ";
5245 }
5246
5247 if(!is_zero_width(components[0].type(), ns))
5248 {
5249 flatten2bv(member_exprt{expr, components[0]});
5250 }
5251
5252 out << std::string(n_concat, ')'); // concat
5253 }
5254 else
5255 convert_expr(expr);
5256 }
5257 else if(type.id()==ID_floatbv)
5258 {
5259 if(use_FPA_theory)
5260 {
5261 // A floatbv constant's IEEE-754 interchange bit pattern is exactly its
5262 // bit-vector representation, so it is emitted as a literal bit-vector.
5263 // This is the only shape that reaches flatten2bv under FPA: a
5264 // non-constant float whose bits are read is lowered by
5265 // lower_byte_operators into a float typecast, which is handled by the
5266 // bvfromfloat round-trip in find_symbols and never reaches here.
5267 if(expr.is_constant())
5268 {
5269 const ieee_float_spect spec(to_floatbv_type(type));
5270 const mp_integer value = bvrep2integer(
5271 to_constant_expr(expr).get_value(), spec.width(), false);
5272 out << "(_ bv" << value << " " << spec.width() << ")";
5273 }
5274 else
5275 {
5277 "flatten2bv of a non-constant FPA-encoded float is unsupported");
5278 }
5279 }
5280 else
5281 convert_expr(expr);
5282 }
5283 else
5284 convert_expr(expr);
5285}
5286
5288 wheret where,
5289 const typet &type,
5290 unsigned nesting)
5291{
5292 if(type.id()==ID_bool)
5293 {
5294 if(where==wheret::BEGIN)
5295 out << "(= "; // produces a bool
5296 else
5297 out << " #b1)";
5298 }
5299 else if(type.id() == ID_array)
5300 {
5302
5303 if(where == wheret::BEGIN)
5304 out << "(let ((?ufop" << nesting << " ";
5305 else
5306 {
5307 out << ")) ";
5308
5309 const array_typet &array_type = to_array_type(type);
5310
5311 std::size_t subtype_width = boolbv_width(array_type.element_type());
5312
5314 array_type.size().is_constant(),
5315 "cannot unflatten arrays of non-constant size");
5316 mp_integer size =
5318
5319 for(mp_integer i = 1; i < size; ++i)
5320 out << "(store ";
5321
5322 // Build a constant array filled with element 0 as the base, then
5323 // overwrite indices 1..N-1 via (store ...).
5324 if(use_as_const)
5325 {
5326 out << "((as const ";
5328 out << ") ";
5329 }
5330 else
5331 {
5332 INVARIANT(
5334 "unflatten relies on `(lambda ...)` for constant arrays "
5335 "when `(as const ...)` is unavailable");
5336 // Note: lambda is a Z3/Bitwuzla extension; not part of the
5337 // SMT-LIB 2.6 standard. The bound variable `?ufidx<n>` is
5338 // intentionally unused -- the body returns the element-0 value
5339 // regardless of its argument, making this semantically
5340 // equivalent to `(as const ...)`.
5341 out << "(lambda ((?ufidx" << nesting << " ";
5342 convert_type(array_type.index_type());
5343 out << ")) ";
5344 }
5345 // use element at index 0 as default value
5346 unflatten(wheret::BEGIN, array_type.element_type(), nesting + 1);
5347 out << "((_ extract " << subtype_width - 1 << " "
5348 << "0) ?ufop" << nesting << ")";
5349 unflatten(wheret::END, array_type.element_type(), nesting + 1);
5350 out << ") ";
5351
5352 std::size_t offset = subtype_width;
5353 for(mp_integer i = 1; i < size; ++i, offset += subtype_width)
5354 {
5355 convert_expr(from_integer(i, array_type.index_type()));
5356 out << ' ';
5357 unflatten(wheret::BEGIN, array_type.element_type(), nesting + 1);
5358 out << "((_ extract " << offset + subtype_width - 1 << " " << offset
5359 << ") ?ufop" << nesting << ")";
5360 unflatten(wheret::END, array_type.element_type(), nesting + 1);
5361 out << ")"; // store
5362 }
5363
5364 out << ")"; // let
5365 }
5366 }
5367 else if(type.id() == ID_struct || type.id() == ID_struct_tag)
5368 {
5369 if(use_datatypes)
5370 {
5371 // extract members
5372 if(where==wheret::BEGIN)
5373 out << "(let ((?ufop" << nesting << " ";
5374 else
5375 {
5376 out << ")) ";
5377
5378 const std::string &smt_typename = datatype_map.at(type);
5379
5380 out << "(mk-" << smt_typename;
5381
5382 const struct_typet &struct_type =
5383 type.id() == ID_struct_tag ? ns.follow_tag(to_struct_tag_type(type))
5384 : to_struct_type(type);
5385
5386 const struct_typet::componentst &components=
5387 struct_type.components();
5388
5389 std::size_t offset=0;
5390
5391 std::size_t i=0;
5392 for(struct_typet::componentst::const_iterator
5393 it=components.begin();
5394 it!=components.end();
5395 it++, i++)
5396 {
5397 if(is_zero_width(it->type(), ns))
5398 continue;
5399
5400 std::size_t member_width=boolbv_width(it->type());
5401
5402 out << " ";
5403 unflatten(wheret::BEGIN, it->type(), nesting+1);
5404 out << "((_ extract " << offset+member_width-1 << " "
5405 << offset << ") ?ufop" << nesting << ")";
5406 unflatten(wheret::END, it->type(), nesting+1);
5407 offset+=member_width;
5408 }
5409
5410 out << "))"; // mk-, let
5411 }
5412 }
5413 else
5414 {
5415 // nop, already a bv
5416 }
5417 }
5418 else
5419 {
5420 // nop
5421 }
5422}
5423
5424void smt2_convt::set_to(const exprt &expr, bool value)
5425{
5426 PRECONDITION(expr.is_boolean());
5427
5428 if(expr.id()==ID_and && value)
5429 {
5430 for(const auto &op : expr.operands())
5431 set_to(op, true);
5432 return;
5433 }
5434
5435 if(expr.id()==ID_or && !value)
5436 {
5437 for(const auto &op : expr.operands())
5438 set_to(op, false);
5439 return;
5440 }
5441
5442 if(expr.id()==ID_not)
5443 {
5444 return set_to(to_not_expr(expr).op(), !value);
5445 }
5446
5447 out << "\n";
5448
5449 // special treatment for "set_to(a=b, true)" where
5450 // a is a new symbol
5451
5452 if(expr.id() == ID_equal && value)
5453 {
5455 if(is_zero_width(equal_expr.lhs().type(), ns))
5456 {
5457 // ignore equality checking over expressions with empty (void) type
5458 return;
5459 }
5460
5461 if(equal_expr.lhs().id()==ID_symbol)
5462 {
5463 const irep_idt &identifier =
5464 to_symbol_expr(equal_expr.lhs()).identifier();
5465
5466 if(
5467 identifier_map.find(identifier) == identifier_map.end() &&
5468 equal_expr.lhs() != equal_expr.rhs())
5469 {
5470 auto id_entry = identifier_map.insert(
5471 {identifier, identifiert{equal_expr.lhs().type(), false}});
5472 CHECK_RETURN(id_entry.second);
5473
5474 find_symbols(id_entry.first->second.type);
5476
5477 std::string smt2_identifier=convert_identifier(identifier);
5479
5480 out << "; set_to true (equal)\n";
5481
5482 // Helper: emit the body of a definition for `smt2_identifier`
5483 // -- either a direct `convert_expr(prepared_rhs)` for non-array
5484 // or array-theory cases, or a `unflatten ... convert_expr ...
5485 // unflatten` reconstruction for array RHSes. Used twice below
5486 // to keep the `declare-fun + assert` and `define-fun` paths in
5487 // sync.
5488 auto emit_definition_body = [&]()
5489 {
5490 if(
5491 equal_expr.lhs().type().id() != ID_array ||
5493 {
5495 }
5496 else
5497 {
5498 unflatten(wheret::BEGIN, equal_expr.lhs().type());
5500 unflatten(wheret::END, equal_expr.lhs().type());
5501 }
5502 };
5503
5504 if(equal_expr.lhs().type().id() == ID_mathematical_function)
5505 {
5506 // We avoid define-fun, since it has been reported to cause
5507 // trouble with Z3's parser.
5508 out << "(declare-fun " << smt2_identifier;
5509
5512
5513 out << " (";
5514 bool first = true;
5515
5516 for(auto &t : mathematical_function_type.domain())
5517 {
5518 if(first)
5519 first = false;
5520 else
5521 out << ' ';
5522
5523 convert_type(t);
5524 }
5525
5526 out << ") ";
5528 out << ")\n";
5529
5530 out << "(assert (= " << smt2_identifier << ' ';
5532 out << ')' << ')' << '\n';
5533 }
5534 else if(use_lambda_for_array)
5535 {
5536 // The body emitted below may contain a `(lambda ...)` from
5537 // `unflatten` (used as a stand-in for `(as const ...)` for
5538 // back-ends with `use_as_const = false`). Z3 rejects
5539 // `get-value` on symbols whose `define-fun` body contains
5540 // a lambda, so we use `declare-fun` + `assert (= ...)` here.
5541 // Back-ends with `use_lambda_for_array = false` (the
5542 // default, currently every back-end other than Z3) keep
5543 // using the `define-fun` form below, so their SMT2 output
5544 // is unaffected.
5545 out << "(declare-fun " << smt2_identifier;
5546 out << " () ";
5547 convert_type(equal_expr.lhs().type());
5548 out << ")\n";
5549 out << "(assert (= " << smt2_identifier << ' ';
5551 out << "))\n";
5552 }
5553 else
5554 {
5555 out << "(define-fun " << smt2_identifier;
5556 out << " () ";
5557 convert_type(equal_expr.lhs().type());
5558 out << ' ';
5560 out << ')' << '\n';
5561 }
5562
5563 return; // done
5564 }
5565 }
5566 }
5567
5569
5570#if 0
5571 out << "; CONV: "
5572 << format(expr) << "\n";
5573#endif
5574
5575 out << "; set_to " << (value?"true":"false") << "\n"
5576 << "(assert ";
5577 if(!value)
5578 {
5579 out << "(not ";
5580 }
5581 const auto found_literal = defined_expressions.find(expr);
5582 if(!(found_literal == defined_expressions.end()))
5583 {
5584 // This is a converted expression, we can just assert the literal name
5585 // since the expression is already defined
5586 out << found_literal->second;
5587 set_values[found_literal->second] = value;
5588 }
5589 else
5590 {
5592 }
5593 if(!value)
5594 {
5595 out << ")";
5596 }
5597 out << ")\n";
5598 return;
5599}
5600
5608{
5609 exprt lowered_expr = expr;
5610
5611 for(auto it = lowered_expr.depth_begin(), itend = lowered_expr.depth_end();
5612 it != itend;
5613 ++it)
5614 {
5615 if(
5616 it->id() == ID_byte_extract_little_endian ||
5617 it->id() == ID_byte_extract_big_endian)
5618 {
5619 it.mutate() = lower_byte_extract(to_byte_extract_expr(*it), ns);
5620 }
5621 else if(
5622 it->id() == ID_byte_update_little_endian ||
5623 it->id() == ID_byte_update_big_endian)
5624 {
5625 it.mutate() = lower_byte_update(to_byte_update_expr(*it), ns);
5626 }
5627 }
5628
5629 return lowered_expr;
5630}
5631
5640{
5641 // First, replace byte operators, because they may introduce new array
5642 // expressions that must be seen by find_symbols:
5644 INVARIANT(
5646 "lower_byte_operators should remove all byte operators");
5647
5648 // Perform rewrites that may introduce new symbols
5649 for(auto it = lowered_expr.depth_begin(), itend = lowered_expr.depth_end();
5650 it != itend;) // no ++it
5651 {
5652 if(
5653 auto prophecy_r_or_w_ok =
5655 {
5657 it.mutate() = lowered;
5658 it.next_sibling_or_parent();
5659 }
5660 else if(
5663 {
5665 it.mutate() = lowered;
5666 it.next_sibling_or_parent();
5667 }
5668 else
5669 ++it;
5670 }
5671
5672 // Now create symbols for all composite expressions present in lowered_expr:
5674
5675 return lowered_expr;
5676}
5677
5688{
5689 if(is_zero_width(expr.type(), ns))
5690 return;
5691
5692 // recursive call on type
5693 find_symbols(expr.type());
5694
5695 if(expr.id() == ID_exists || expr.id() == ID_forall)
5696 {
5697 std::unordered_map<irep_idt, std::optional<identifiert>> shadowed_syms;
5698
5699 // do not declare the quantified symbol, but record
5700 // as 'bound symbol'
5701 const auto &q_expr = to_quantifier_expr(expr);
5702 for(const auto &symbol : q_expr.variables())
5703 {
5704 const auto identifier = symbol.identifier();
5705 auto id_entry =
5706 identifier_map.insert({identifier, identifiert{symbol.type(), true}});
5707 shadowed_syms.insert(
5708 {identifier,
5709 id_entry.second ? std::nullopt
5710 : std::optional{id_entry.first->second}});
5711 }
5712 find_symbols(q_expr.where());
5713 for(const auto &[id, shadowed_val] : shadowed_syms)
5714 {
5715 auto previous_entry = identifier_map.find(id);
5716 if(!shadowed_val.has_value())
5718 else
5719 previous_entry->second = std::move(*shadowed_val);
5720 }
5721 return;
5722 }
5723
5724 // recursive call on operands
5725 for(const auto &op : expr.operands())
5726 find_symbols(op);
5727
5728 if(expr.id()==ID_symbol ||
5729 expr.id()==ID_nondet_symbol)
5730 {
5731 // we don't track function-typed symbols
5732 if(expr.type().id()==ID_code)
5733 return;
5734
5735 irep_idt identifier;
5736
5737 if(expr.id()==ID_symbol)
5738 identifier = to_symbol_expr(expr).identifier();
5739 else
5740 identifier="nondet_"+
5741 id2string(to_nondet_symbol_expr(expr).get_identifier());
5742
5743 auto id_entry =
5744 identifier_map.insert({identifier, identifiert{expr.type(), false}});
5745
5746 if(id_entry.second)
5747 {
5748 std::string smt2_identifier=convert_identifier(identifier);
5750
5751 out << "; find_symbols\n";
5752 out << "(declare-fun " << smt2_identifier;
5753
5754 if(expr.type().id() == ID_mathematical_function)
5755 {
5758 out << " (";
5759 bool first = true;
5760
5761 for(auto &type : mathematical_function_type.domain())
5762 {
5763 if(first)
5764 first = false;
5765 else
5766 out << ' ';
5767 convert_type(type);
5768 }
5769
5770 out << ") ";
5772 }
5773 else
5774 {
5775 out << " () ";
5776 convert_type(expr.type());
5777 }
5778
5779 out << ')' << '\n';
5780
5781 // We need an additional constraint for range-typed symbols,
5782 // or otherwise we get satisfying assignments with values
5783 // outside of the range when the size of the range isn't
5784 // a power of two.
5785 if(expr.type().id() == ID_range)
5786 {
5787 auto &range_type = to_integer_range_type(expr.type());
5788 if(!is_power_of_two(range_type.size()))
5789 {
5790 out << "(assert (bvule " << smt2_identifier << ' ';
5792 out << "))\n"; // bvule, assert
5793 }
5794 }
5795 }
5796 }
5797 else if(expr.id() == ID_array_of)
5798 {
5799 if(!use_as_const)
5800 {
5801 if(defined_expressions.find(expr) == defined_expressions.end())
5802 {
5803 const auto &array_of = to_array_of_expr(expr);
5804 const auto &array_type = array_of.type();
5805
5806 const irep_idt id =
5807 "array_of." + std::to_string(defined_expressions.size());
5808 out << "; the following is a substitute for lambda i. x\n";
5809 out << "(declare-fun " << id << " () ";
5811 out << ")\n";
5812
5813 if(!is_zero_width(array_type.element_type(), ns))
5814 {
5815 // use a quantifier-based initialization instead of lambda
5816 out << "(assert (forall ((i ";
5817 convert_type(array_type.index_type());
5818 out << ")) (= (select " << id << " i) ";
5819 if(array_type.element_type().id() == ID_bool && !use_array_of_bool)
5820 {
5821 out << "(ite ";
5822 convert_expr(array_of.what());
5823 out << " #b1 #b0)";
5824 }
5825 else
5826 {
5827 convert_expr(array_of.what());
5828 }
5829 out << ")))\n";
5830 }
5831
5832 defined_expressions[expr] = id;
5833 }
5834 }
5835 }
5836 else if(expr.id() == ID_array_comprehension)
5837 {
5839 {
5840 if(defined_expressions.find(expr) == defined_expressions.end())
5841 {
5843 const auto &array_type = array_comprehension.type();
5844 const auto &array_size = array_type.size();
5845
5846 const irep_idt id =
5847 "array_comprehension." + std::to_string(defined_expressions.size());
5848 out << "(declare-fun " << id << " () ";
5850 out << ")\n";
5851
5852 out << "; the following is a substitute for lambda i . x(i)\n";
5853 out << "; universally quantified initialization of the array\n";
5854 out << "(assert (forall ((";
5856 out << " ";
5857 convert_type(array_size.type());
5858 out << ")) (=> (and (bvule (_ bv0 " << boolbv_width(array_size.type())
5859 << ") ";
5861 out << ") (bvult ";
5863 out << " ";
5865 out << ")) (= (select " << id << " ";
5867 out << ") ";
5868 if(array_type.element_type().id() == ID_bool && !use_array_of_bool)
5869 {
5870 out << "(ite ";
5872 out << " #b1 #b0)";
5873 }
5874 else
5875 {
5877 }
5878 out << "))))\n";
5879
5880 defined_expressions[expr] = id;
5881 }
5882 }
5883 }
5884 else if(expr.id()==ID_array)
5885 {
5886 if(defined_expressions.find(expr)==defined_expressions.end())
5887 {
5889
5890 const irep_idt id = "array." + std::to_string(defined_expressions.size());
5891 out << "; the following is a substitute for an array constructor" << "\n";
5892 out << "(declare-fun " << id << " () ";
5894 out << ")" << "\n";
5895
5896 if(!is_zero_width(array_type.element_type(), ns))
5897 {
5898 for(std::size_t i = 0; i < expr.operands().size(); i++)
5899 {
5900 out << "(assert (= (select " << id << " ";
5901 convert_expr(from_integer(i, array_type.index_type()));
5902 out << ") "; // select
5903 if(array_type.element_type().id() == ID_bool && !use_array_of_bool)
5904 {
5905 out << "(ite ";
5906 convert_expr(expr.operands()[i]);
5907 out << " #b1 #b0)";
5908 }
5909 else
5910 {
5911 convert_expr(expr.operands()[i]);
5912 }
5913 out << "))"
5914 << "\n"; // =, assert
5915 }
5916 }
5917
5918 defined_expressions[expr]=id;
5919 }
5920 }
5921 else if(expr.id()==ID_string_constant)
5922 {
5923 if(defined_expressions.find(expr)==defined_expressions.end())
5924 {
5925 // introduce a temporary array.
5926 exprt tmp=to_string_constant(expr).to_array_expr();
5927 const array_typet &array_type=to_array_type(tmp.type());
5928
5929 const irep_idt id =
5930 "string." + std::to_string(defined_expressions.size());
5931 out << "; the following is a substitute for a string" << "\n";
5932 out << "(declare-fun " << id << " () ";
5934 out << ")" << "\n";
5935
5936 for(std::size_t i=0; i<tmp.operands().size(); i++)
5937 {
5938 out << "(assert (= (select " << id << ' ';
5939 convert_expr(from_integer(i, array_type.index_type()));
5940 out << ") "; // select
5941 convert_expr(tmp.operands()[i]);
5942 out << "))" << "\n";
5943 }
5944
5945 defined_expressions[expr]=id;
5946 }
5947 }
5948 else if(
5950 {
5951 if(object_sizes.find(*object_size) == object_sizes.end())
5952 {
5953 const irep_idt id = convert_identifier(
5954 "object_size." + std::to_string(object_sizes.size()));
5955 out << "(declare-fun " << id << " () ";
5957 out << ")"
5958 << "\n";
5959
5961 }
5962 }
5963 // clang-format off
5964 else if(!use_FPA_theory &&
5965 expr.operands().size() >= 1 &&
5966 (expr.id() == ID_floatbv_plus ||
5967 expr.id() == ID_floatbv_minus ||
5968 expr.id() == ID_floatbv_mult ||
5969 expr.id() == ID_floatbv_div ||
5970 expr.id() == ID_floatbv_fma ||
5971 expr.id() == ID_floatbv_typecast ||
5972 expr.id() == ID_ieee_float_equal ||
5973 expr.id() == ID_ieee_float_notequal ||
5974 ((expr.id() == ID_lt ||
5975 expr.id() == ID_gt ||
5976 expr.id() == ID_le ||
5977 expr.id() == ID_ge ||
5978 expr.id() == ID_isnan ||
5979 expr.id() == ID_isnormal ||
5980 expr.id() == ID_isfinite ||
5981 expr.id() == ID_isinf ||
5982 expr.id() == ID_sign ||
5983 expr.id() == ID_unary_minus ||
5984 expr.id() == ID_typecast ||
5985 expr.id() == ID_abs) &&
5986 to_multi_ary_expr(expr).op0().type().id() == ID_floatbv)))
5987 // clang-format on
5988 {
5989 irep_idt function =
5990 convert_identifier("float_bv." + expr.id_string() + floatbv_suffix(expr));
5991
5992 if(bvfp_set.insert(function).second)
5993 {
5994 out << "; this is a model for " << expr.id() << " : "
5995 << type2id(to_multi_ary_expr(expr).op0().type()) << " -> "
5996 << type2id(expr.type()) << "\n"
5997 << "(define-fun " << function << " (";
5998
5999 for(std::size_t i = 0; i < expr.operands().size(); i++)
6000 {
6001 if(i!=0)
6002 out << " ";
6003 out << "(op" << i << ' ';
6004 convert_type(expr.operands()[i].type());
6005 out << ')';
6006 }
6007
6008 out << ") ";
6009 convert_type(expr.type()); // return type
6010 out << ' ';
6011
6012 exprt tmp1=expr;
6013 for(std::size_t i = 0; i < tmp1.operands().size(); i++)
6014 tmp1.operands()[i]=
6015 smt2_symbolt("op"+std::to_string(i), tmp1.operands()[i].type());
6016
6018 tmp2=letify(tmp2);
6019 CHECK_RETURN(!tmp2.is_nil());
6020
6022
6023 out << ")\n"; // define-fun
6024 }
6025 }
6026 else if(
6027 use_FPA_theory && expr.id() == ID_typecast &&
6028 to_typecast_expr(expr).op().type().id() == ID_floatbv &&
6029 expr.type().id() == ID_bv)
6030 {
6031 // This is _NOT_ a semantic conversion, but bit-wise.
6032 if(defined_expressions.find(expr) == defined_expressions.end())
6033 {
6034 // This conversion is non-trivial as it requires creating a
6035 // new bit-vector variable and then asserting that it converts
6036 // to the required floating-point number.
6037 const irep_idt id =
6038 "bvfromfloat." + std::to_string(defined_expressions.size());
6039 out << "(declare-fun " << id << " () ";
6040 convert_type(expr.type());
6041 out << ')' << '\n';
6042
6043 const typecast_exprt &tc = to_typecast_expr(expr);
6044 const auto &floatbv_type = to_floatbv_type(tc.op().type());
6045 out << "(assert (= ";
6046 out << "((_ to_fp " << floatbv_type.get_e() << " "
6047 << floatbv_type.get_f() + 1 << ") " << id << ')';
6048 convert_expr(tc.op());
6049 out << ')'; // =
6050 out << ')' << '\n';
6051
6052 defined_expressions[expr] = id;
6053 }
6054 }
6055 else if(expr.id() == ID_initial_state)
6056 {
6057 irep_idt function = "initial-state";
6058
6059 if(state_fkt_declared.insert(function).second)
6060 {
6061 out << "(declare-fun " << function << " (";
6062 convert_type(to_unary_expr(expr).op().type());
6063 out << ") ";
6064 convert_type(expr.type()); // return type
6065 out << ")\n"; // declare-fun
6066 }
6067 }
6068 else if(expr.id() == ID_evaluate)
6069 {
6070 irep_idt function = "evaluate-" + type2id(expr.type());
6071
6072 if(state_fkt_declared.insert(function).second)
6073 {
6074 out << "(declare-fun " << function << " (";
6075 convert_type(to_binary_expr(expr).op0().type());
6076 out << ' ';
6077 convert_type(to_binary_expr(expr).op1().type());
6078 out << ") ";
6079 convert_type(expr.type()); // return type
6080 out << ")\n"; // declare-fun
6081 }
6082 }
6083 else if(
6084 expr.id() == ID_state_is_cstring ||
6085 expr.id() == ID_state_is_dynamic_object ||
6086 expr.id() == ID_state_live_object || expr.id() == ID_state_writeable_object)
6087 {
6088 irep_idt function =
6089 expr.id() == ID_state_is_cstring ? "state-is-cstring"
6090 : expr.id() == ID_state_is_dynamic_object ? "state-is-dynamic-object"
6091 : expr.id() == ID_state_live_object ? "state-live-object"
6092 : "state-writeable-object";
6093
6094 if(state_fkt_declared.insert(function).second)
6095 {
6096 out << "(declare-fun " << function << " (";
6097 convert_type(to_binary_expr(expr).op0().type());
6098 out << ' ';
6099 convert_type(to_binary_expr(expr).op1().type());
6100 out << ") ";
6101 convert_type(expr.type()); // return type
6102 out << ")\n"; // declare-fun
6103 }
6104 }
6105 else if(
6106 expr.id() == ID_state_r_ok || expr.id() == ID_state_w_ok ||
6107 expr.id() == ID_state_rw_ok)
6108 {
6109 irep_idt function = expr.id() == ID_state_r_ok ? "state-r-ok"
6110 : expr.id() == ID_state_w_ok ? "state-w-ok"
6111 : "state-rw-ok";
6112
6113 if(state_fkt_declared.insert(function).second)
6114 {
6115 out << "(declare-fun " << function << " (";
6116 convert_type(to_ternary_expr(expr).op0().type());
6117 out << ' ';
6118 convert_type(to_ternary_expr(expr).op1().type());
6119 out << ' ';
6120 convert_type(to_ternary_expr(expr).op2().type());
6121 out << ") ";
6122 convert_type(expr.type()); // return type
6123 out << ")\n"; // declare-fun
6124 }
6125 }
6126 else if(expr.id() == ID_update_state)
6127 {
6128 irep_idt function =
6129 "update-state-" + type2id(to_multi_ary_expr(expr).op2().type());
6130
6131 if(state_fkt_declared.insert(function).second)
6132 {
6133 out << "(declare-fun " << function << " (";
6134 convert_type(to_multi_ary_expr(expr).op0().type());
6135 out << ' ';
6136 convert_type(to_multi_ary_expr(expr).op1().type());
6137 out << ' ';
6138 convert_type(to_multi_ary_expr(expr).op2().type());
6139 out << ") ";
6140 convert_type(expr.type()); // return type
6141 out << ")\n"; // declare-fun
6142 }
6143 }
6144 else if(expr.id() == ID_enter_scope_state)
6145 {
6146 irep_idt function =
6147 "enter-scope-state-" + type2id(to_binary_expr(expr).op1().type());
6148
6149 if(state_fkt_declared.insert(function).second)
6150 {
6151 out << "(declare-fun " << function << " (";
6152 convert_type(to_binary_expr(expr).op0().type());
6153 out << ' ';
6154 convert_type(to_binary_expr(expr).op1().type());
6155 out << ' ';
6157 out << ") ";
6158 convert_type(expr.type()); // return type
6159 out << ")\n"; // declare-fun
6160 }
6161 }
6162 else if(expr.id() == ID_exit_scope_state)
6163 {
6164 irep_idt function =
6165 "exit-scope-state-" + type2id(to_binary_expr(expr).op1().type());
6166
6167 if(state_fkt_declared.insert(function).second)
6168 {
6169 out << "(declare-fun " << function << " (";
6170 convert_type(to_binary_expr(expr).op0().type());
6171 out << ' ';
6172 convert_type(to_binary_expr(expr).op1().type());
6173 out << ") ";
6174 convert_type(expr.type()); // return type
6175 out << ")\n"; // declare-fun
6176 }
6177 }
6178 else if(expr.id() == ID_allocate)
6179 {
6180 irep_idt function = "allocate";
6181
6182 if(state_fkt_declared.insert(function).second)
6183 {
6184 out << "(declare-fun " << function << " (";
6185 convert_type(to_binary_expr(expr).op0().type());
6186 out << ' ';
6187 convert_type(to_binary_expr(expr).op1().type());
6188 out << ") ";
6189 convert_type(expr.type()); // return type
6190 out << ")\n"; // declare-fun
6191 }
6192 }
6193 else if(expr.id() == ID_reallocate)
6194 {
6195 irep_idt function = "reallocate";
6196
6197 if(state_fkt_declared.insert(function).second)
6198 {
6199 out << "(declare-fun " << function << " (";
6200 convert_type(to_ternary_expr(expr).op0().type());
6201 out << ' ';
6202 convert_type(to_ternary_expr(expr).op1().type());
6203 out << ' ';
6204 convert_type(to_ternary_expr(expr).op2().type());
6205 out << ") ";
6206 convert_type(expr.type()); // return type
6207 out << ")\n"; // declare-fun
6208 }
6209 }
6210 else if(expr.id() == ID_deallocate_state)
6211 {
6212 irep_idt function = "deallocate";
6213
6214 if(state_fkt_declared.insert(function).second)
6215 {
6216 out << "(declare-fun " << function << " (";
6217 convert_type(to_binary_expr(expr).op0().type());
6218 out << ' ';
6219 convert_type(to_binary_expr(expr).op1().type());
6220 out << ") ";
6221 convert_type(expr.type()); // return type
6222 out << ")\n"; // declare-fun
6223 }
6224 }
6225 else if(expr.id() == ID_object_address)
6226 {
6227 irep_idt function = "object-address";
6228
6229 if(state_fkt_declared.insert(function).second)
6230 {
6231 out << "(declare-fun " << function << " (String) ";
6232 convert_type(expr.type()); // return type
6233 out << ")\n"; // declare-fun
6234 }
6235 }
6236 else if(expr.id() == ID_field_address)
6237 {
6238 irep_idt function = "field-address-" + type2id(expr.type());
6239
6240 if(state_fkt_declared.insert(function).second)
6241 {
6242 out << "(declare-fun " << function << " (";
6243 convert_type(to_field_address_expr(expr).op().type());
6244 out << ' ';
6245 out << "String";
6246 out << ") ";
6247 convert_type(expr.type()); // return type
6248 out << ")\n"; // declare-fun
6249 }
6250 }
6251 else if(expr.id() == ID_element_address)
6252 {
6253 irep_idt function = "element-address-" + type2id(expr.type());
6254
6255 if(state_fkt_declared.insert(function).second)
6256 {
6257 out << "(declare-fun " << function << " (";
6258 convert_type(to_element_address_expr(expr).base().type());
6259 out << ' ';
6260 convert_type(to_element_address_expr(expr).index().type());
6261 out << ' '; // repeat, for the element size
6262 convert_type(to_element_address_expr(expr).index().type());
6263 out << ") ";
6264 convert_type(expr.type()); // return type
6265 out << ")\n"; // declare-fun
6266 }
6267 }
6268}
6269
6271{
6272 const typet &type = expr.type();
6273 PRECONDITION(type.id()==ID_array);
6274
6275 // arrays inside structs get flattened, unless we have datatypes
6276 if(expr.id() == ID_with)
6277 return use_array_theory(to_with_expr(expr).old());
6278 else if(expr.id() == ID_if)
6279 {
6280 // For an array-typed if-then-else, the SMT sort produced by
6281 // convert_expr (see the ID_if branch above) is determined by the
6282 // sorts chosen for its two operands:
6283 // - if both branches are bit-vector-encoded, i.e. neither uses array
6284 // theory (typically because both are array-typed members of a
6285 // struct that has been flattened to a bit-vector), the resulting
6286 // ite is a bit-vector;
6287 // - if both branches use array theory, the ite is an SMT array;
6288 // - if exactly one branch uses array theory, the ID_if handler in
6289 // convert_expr unflattens the bit-vector branch back to an SMT
6290 // array (see the wheret::BEGIN/wheret::END unflatten calls), so
6291 // the ite is again an SMT array.
6292 // The ite therefore "uses array theory" iff at least one branch
6293 // does. Without this clause, the fall-through below would
6294 // unconditionally return true for ID_if (since ID_if != ID_member),
6295 // which is wrong in the symmetric bit-vector case: callers like
6296 // convert_index, convert_with, flatten2bv, and the array-typed
6297 // define-fun path would then emit array-theory operators -- e.g.
6298 // (select <ite> ...) or (store <ite> ...) -- on a bit-vector
6299 // operand, producing ill-typed SMT-LIB 2 that is rejected by
6300 // conforming solvers (cf. issue #9008). The asymmetric case was
6301 // already handled, for ID_with branches, in the ID_if conversion
6302 // logic of convert_expr; the present clause makes use_array_theory
6303 // consistent with that conversion in all four combinations.
6304 const if_exprt &if_expr = to_if_expr(expr);
6305 return use_array_theory(if_expr.true_case()) ||
6306 use_array_theory(if_expr.false_case());
6307 }
6308 else
6309 return use_datatypes || expr.id() != ID_member;
6310}
6311
6313{
6314 if(type.id()==ID_array)
6315 {
6316 const array_typet &array_type = to_array_type(type);
6317
6318 // we always use array theory for top-level arrays
6319 const typet &subtype = array_type.element_type();
6320
6321 // Arrays map the index type to the element type.
6322 out << "(Array ";
6323 convert_type(array_type.index_type());
6324 out << " ";
6325
6326 if(subtype.id()==ID_bool && !use_array_of_bool)
6327 out << "(_ BitVec 1)";
6328 else
6329 convert_type(array_type.element_type());
6330
6331 out << ")";
6332 }
6333 else if(type.id()==ID_bool)
6334 {
6335 out << "Bool";
6336 }
6337 else if(type.id() == ID_struct || type.id() == ID_struct_tag)
6338 {
6339 if(use_datatypes)
6340 {
6341 out << datatype_map.at(type);
6342 }
6343 else
6344 {
6345 std::size_t width=boolbv_width(type);
6346
6347 out << "(_ BitVec " << width << ")";
6348 }
6349 }
6350 else if(type.id()==ID_code)
6351 {
6352 // These may appear in structs.
6353 // We replace this by "Bool" in order to keep the same
6354 // member count.
6355 out << "Bool";
6356 }
6357 else if(type.id() == ID_union || type.id() == ID_union_tag)
6358 {
6359 std::size_t width=boolbv_width(type);
6360 const union_typet &union_type = type.id() == ID_union_tag
6361 ? ns.follow_tag(to_union_tag_type(type))
6362 : to_union_type(type);
6364 union_type.components().empty() || width != 0,
6365 "failed to get width of union");
6366
6367 out << "(_ BitVec " << width << ")";
6368 }
6369 else if(type.id()==ID_pointer)
6370 {
6371 out << "(_ BitVec "
6372 << boolbv_width(type) << ")";
6373 }
6374 else if(type.id()==ID_bv ||
6375 type.id()==ID_fixedbv ||
6376 type.id()==ID_unsignedbv ||
6377 type.id()==ID_signedbv ||
6378 type.id()==ID_c_bool)
6379 {
6380 out << "(_ BitVec "
6381 << to_bitvector_type(type).get_width() << ")";
6382 }
6383 else if(type.id()==ID_c_enum)
6384 {
6385 // these have an underlying type
6386 out << "(_ BitVec "
6387 << to_bitvector_type(to_c_enum_type(type).underlying_type()).get_width()
6388 << ")";
6389 }
6390 else if(type.id()==ID_c_enum_tag)
6391 {
6392 convert_type(ns.follow_tag(to_c_enum_tag_type(type)));
6393 }
6394 else if(type.id()==ID_floatbv)
6395 {
6397
6398 if(use_FPA_theory)
6399 out << "(_ FloatingPoint "
6400 << floatbv_type.get_e() << " "
6401 << floatbv_type.get_f() + 1 << ")";
6402 else
6403 out << "(_ BitVec "
6404 << floatbv_type.get_width() << ")";
6405 }
6406 else if(type.id()==ID_rational ||
6407 type.id()==ID_real)
6408 out << "Real";
6409 else if(type.id()==ID_integer)
6410 out << "Int";
6411 else if(type.id() == ID_natural)
6412 out << "Nat";
6413 else if(type.id()==ID_complex)
6414 {
6415 if(use_datatypes)
6416 {
6417 out << datatype_map.at(type);
6418 }
6419 else
6420 {
6421 std::size_t width=boolbv_width(type);
6422
6423 out << "(_ BitVec " << width << ")";
6424 }
6425 }
6426 else if(type.id()==ID_c_bit_field)
6427 {
6429 }
6430 else if(type.id() == ID_state)
6431 {
6432 out << "state";
6433 }
6434 else if(type.id() == ID_range)
6435 {
6436 auto &range_type = to_integer_range_type(type);
6437 if(range_type.empty())
6438 UNEXPECTEDCASE("unsupported range type");
6439 out << "(_ BitVec " << address_bits(range_type.size()) << ")";
6440 }
6441 else if(type.id() == ID_string)
6442 out << "String";
6443 else if(type.id() == ID_regex)
6444 out << "RegLan";
6445 else
6446 {
6447 UNEXPECTEDCASE("unsupported type: "+type.id_string());
6448 }
6449}
6450
6452{
6453 std::set<irep_idt> recstack;
6455}
6456
6458 const typet &type,
6459 std::set<irep_idt> &recstack)
6460{
6461 if(type.id()==ID_array)
6462 {
6464 find_symbols(array_type.size());
6465 find_symbols_rec(array_type.element_type(), recstack);
6466 }
6467 else if(type.id()==ID_complex)
6468 {
6469 find_symbols_rec(to_complex_type(type).subtype(), recstack);
6470
6471 if(use_datatypes &&
6472 datatype_map.find(type)==datatype_map.end())
6473 {
6474 const std::string smt_typename =
6475 "complex." + std::to_string(datatype_map.size());
6476 datatype_map[type] = smt_typename;
6477
6478 out << "(declare-datatypes ((" << smt_typename << " 0)) "
6479 << "(((mk-" << smt_typename;
6480
6481 out << " (" << smt_typename << ".imag ";
6482 convert_type(to_complex_type(type).subtype());
6483 out << ")";
6484
6485 out << " (" << smt_typename << ".real ";
6486 convert_type(to_complex_type(type).subtype());
6487 out << ")";
6488
6489 out << "))))\n";
6490 }
6491 }
6492 else if(type.id() == ID_struct)
6493 {
6494 // Cater for mutually recursive struct types
6495 bool need_decl=false;
6496 if(use_datatypes &&
6497 datatype_map.find(type)==datatype_map.end())
6498 {
6499 const std::string smt_typename =
6500 "struct." + std::to_string(datatype_map.size());
6501 datatype_map[type] = smt_typename;
6502 need_decl=true;
6503 }
6504
6505 const struct_typet::componentst &components =
6506 to_struct_type(type).components();
6507
6508 for(const auto &component : components)
6510
6511 // Declare the corresponding SMT type if we haven't already.
6512 if(need_decl)
6513 {
6514 const std::string &smt_typename = datatype_map.at(type);
6515
6516 // We're going to create a datatype named something like `struct.0'.
6517 // It's going to have a single constructor named `mk-struct.0' with an
6518 // argument for each member of the struct. The declaration that
6519 // creates this type looks like:
6520 //
6521 // (declare-datatypes ((struct.0 0)) (((mk-struct.0
6522 // (struct.0.component1 type1)
6523 // ...
6524 // (struct.0.componentN typeN)))))
6525 out << "(declare-datatypes ((" << smt_typename << " 0)) "
6526 << "(((mk-" << smt_typename << " ";
6527
6528 for(const auto &component : components)
6529 {
6530 if(is_zero_width(component.type(), ns))
6531 continue;
6532
6533 out << "(" << smt_typename << "." << component.get_name()
6534 << " ";
6535 convert_type(component.type());
6536 out << ") ";
6537 }
6538
6539 out << "))))" << "\n";
6540
6541 // Let's also declare convenience functions to update individual
6542 // members of the struct whil we're at it. The functions are
6543 // named like `update-struct.0.component1'. Their declarations
6544 // look like:
6545 //
6546 // (declare-fun update-struct.0.component1
6547 // ((s struct.0) ; first arg -- the struct to update
6548 // (v type1)) ; second arg -- the value to update
6549 // struct.0 ; the output type
6550 // (mk-struct.0 ; build the new struct...
6551 // v ; the updated value
6552 // (struct.0.component2 s) ; retain the other members
6553 // ...
6554 // (struct.0.componentN s)))
6555
6556 for(struct_union_typet::componentst::const_iterator
6557 it=components.begin();
6558 it!=components.end();
6559 ++it)
6560 {
6561 if(is_zero_width(it->type(), ns))
6562 continue;
6563
6565 out << "(define-fun update-" << smt_typename << "."
6566 << component.get_name() << " "
6567 << "((s " << smt_typename << ") "
6568 << "(v ";
6569 convert_type(component.type());
6570 out << ")) " << smt_typename << " "
6571 << "(mk-" << smt_typename
6572 << " ";
6573
6574 for(struct_union_typet::componentst::const_iterator
6575 it2=components.begin();
6576 it2!=components.end();
6577 ++it2)
6578 {
6579 if(it==it2)
6580 out << "v ";
6581 else if(!is_zero_width(it2->type(), ns))
6582 {
6583 out << "(" << smt_typename << "."
6584 << it2->get_name() << " s) ";
6585 }
6586 }
6587
6588 out << "))" << "\n";
6589 }
6590
6591 out << "\n";
6592 }
6593 }
6594 else if(type.id() == ID_union)
6595 {
6596 const union_typet::componentst &components =
6597 to_union_type(type).components();
6598
6599 for(const auto &component : components)
6601 }
6602 else if(type.id()==ID_code)
6603 {
6604 const code_typet::parameterst &parameters=
6605 to_code_type(type).parameters();
6606 for(const auto &param : parameters)
6608
6609 find_symbols_rec(to_code_type(type).return_type(), recstack);
6610 }
6611 else if(type.id()==ID_pointer)
6612 {
6613 find_symbols_rec(to_pointer_type(type).base_type(), recstack);
6614 }
6615 else if(type.id() == ID_struct_tag)
6616 {
6617 const auto &struct_tag = to_struct_tag_type(type);
6618 const irep_idt &id = struct_tag.get_identifier();
6619
6620 if(recstack.find(id) == recstack.end())
6621 {
6622 const auto &base_struct = ns.follow_tag(struct_tag);
6623 recstack.insert(id);
6626 }
6627 }
6628 else if(type.id() == ID_union_tag)
6629 {
6630 const auto &union_tag = to_union_tag_type(type);
6631 const irep_idt &id = union_tag.get_identifier();
6632
6633 if(recstack.find(id) == recstack.end())
6634 {
6635 recstack.insert(id);
6636 find_symbols_rec(ns.follow_tag(union_tag), recstack);
6637 }
6638 }
6639 else if(type.id() == ID_state)
6640 {
6641 if(datatype_map.find(type) == datatype_map.end())
6642 {
6643 datatype_map[type] = "state";
6644 out << "(declare-sort state 0)\n";
6645 }
6646 }
6647 else if(type.id() == ID_mathematical_function)
6648 {
6649 const auto &mathematical_function_type =
6651 for(auto &d_type : mathematical_function_type.domain())
6653
6655 }
6656}
6657
6659{
6661}
configt config
Definition config.cpp:25
mp_integer bvrep2integer(const irep_idt &src, std::size_t width, bool is_signed)
convert a bit-vector representation (possibly signed) to integer
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
std::size_t address_bits(const mp_integer &size)
ceil(log2(size))
bool to_integer(const constant_exprt &expr, mp_integer &int_value)
Convert a constant expression expr to an arbitrary-precision integer.
bool is_power_of_two(const mp_integer &n)
irep_idt integer2bvrep(const mp_integer &src, std::size_t width)
convert an integer to bit-vector representation with given width This uses two's complement for negat...
mp_integer power(const mp_integer &base, const mp_integer &exponent)
A multi-precision implementation of the power operator.
API to expression classes for bitvectors.
const onehot0_exprt & to_onehot0_expr(const exprt &expr)
Cast an exprt to a onehot0_exprt.
const replication_exprt & to_replication_expr(const exprt &expr)
Cast an exprt to a replication_exprt.
const reduction_xnor_exprt & to_reduction_xnor_expr(const exprt &expr)
Cast an exprt to a reduction_xnor_exprt.
const reduction_nand_exprt & to_reduction_nand_expr(const exprt &expr)
Cast an exprt to a reduction_nand_exprt.
const shift_exprt & to_shift_expr(const exprt &expr)
Cast an exprt to a shift_exprt.
const reduction_and_exprt & to_reduction_and_expr(const exprt &expr)
Cast an exprt to a reduction_and_exprt.
const reduction_or_exprt & to_reduction_or_expr(const exprt &expr)
Cast an exprt to a reduction_or_exprt.
const popcount_exprt & to_popcount_expr(const exprt &expr)
Cast an exprt to a popcount_exprt.
const update_bits_exprt & to_update_bits_expr(const exprt &expr)
Cast an exprt to an update_bits_exprt.
const extractbits_exprt & to_extractbits_expr(const exprt &expr)
Cast an exprt to an extractbits_exprt.
const onehot_exprt & to_onehot_expr(const exprt &expr)
Cast an exprt to a onehot_exprt.
bool can_cast_expr< minus_overflow_exprt >(const exprt &base)
const find_first_set_exprt & to_find_first_set_expr(const exprt &expr)
Cast an exprt to a find_first_set_exprt.
bool can_cast_expr< overflow_result_exprt >(const exprt &base)
const update_bit_exprt & to_update_bit_expr(const exprt &expr)
Cast an exprt to an update_bit_exprt.
const bitnot_exprt & to_bitnot_expr(const exprt &expr)
Cast an exprt to a bitnot_exprt.
const bswap_exprt & to_bswap_expr(const exprt &expr)
Cast an exprt to a bswap_exprt.
const count_leading_zeros_exprt & to_count_leading_zeros_expr(const exprt &expr)
Cast an exprt to a count_leading_zeros_exprt.
const reduction_xor_exprt & to_reduction_xor_expr(const exprt &expr)
Cast an exprt to a reduction_xor_exprt.
const bitreverse_exprt & to_bitreverse_expr(const exprt &expr)
Cast an exprt to a bitreverse_exprt.
const extractbit_exprt & to_extractbit_expr(const exprt &expr)
Cast an exprt to an extractbit_exprt.
const reduction_nor_exprt & to_reduction_nor_expr(const exprt &expr)
Cast an exprt to a reduction_nor_exprt.
const zero_extend_exprt & to_zero_extend_expr(const exprt &expr)
Cast an exprt to a zero_extend_exprt.
const count_trailing_zeros_exprt & to_count_trailing_zeros_expr(const exprt &expr)
Cast an exprt to a count_trailing_zeros_exprt.
const bv_typet & to_bv_type(const typet &type)
Cast a typet to a bv_typet.
const fixedbv_typet & to_fixedbv_type(const typet &type)
Cast a typet to a fixedbv_typet.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
const floatbv_typet & to_floatbv_type(const typet &type)
Cast a typet to a floatbv_typet.
const unsignedbv_typet & to_unsignedbv_type(const typet &type)
Cast a typet to an unsignedbv_typet.
const signedbv_typet & to_signedbv_type(const typet &type)
Cast a typet to a signedbv_typet.
bool has_byte_operator(const exprt &src)
Return true iff src or one of its operands contain a byte extract or byte update expression.
Expression classes for byte-level operators.
const byte_update_exprt & to_byte_update_expr(const exprt &expr)
exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
Rewrite a byte extract expression to more fundamental operations.
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
exprt lower_byte_update(const byte_update_exprt &src, const namespacet &ns)
Rewrite a byte update expression to more fundamental operations.
typet c_bit_field_replacement_type(const c_bit_field_typet &src, const namespacet &ns)
pointer_typet pointer_type(const typet &subtype)
Definition c_types.cpp:235
const c_bit_field_typet & to_c_bit_field_type(const typet &type)
Cast a typet to a c_bit_field_typet.
Definition c_types.h:80
const c_enum_typet & to_c_enum_type(const typet &type)
Cast a typet to a c_enum_typet.
Definition c_types.h:335
const c_enum_tag_typet & to_c_enum_tag_type(const typet &type)
Cast a typet to a c_enum_tag_typet.
Definition c_types.h:377
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition c_types.h:184
const c_bool_typet & to_c_bool_type(const typet &type)
Cast a typet to a c_bool_typet.
Definition c_types.h:128
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition c_types.h:224
Absolute value.
Definition std_expr.h:440
Operator to return the address of an object.
virtual void clear()
Reset the abstract state.
Definition ai.h:269
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:566
Represents real numbers as roots (zeros) of a polynomial with rational coefficients.
Thrown when an unexpected error occurs during the analysis (e.g., when the SAT solver returns an erro...
Pointer-typed bitvector constant annotated with the pointer expression that the bitvector is the nume...
Array constructor from list of elements.
Definition std_expr.h:1570
Arrays with given size.
Definition std_types.h:806
const exprt & size() const
Definition std_types.h:839
const typet & element_type() const
The type of the elements of the array.
Definition std_types.h:826
A base class for binary expressions.
Definition std_expr.h:649
exprt & lhs()
Definition std_expr.h:679
exprt & rhs()
Definition std_expr.h:689
exprt & op0()
Definition expr.h:134
exprt & op1()
Definition expr.h:137
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition std_expr.h:784
Bit-wise negation of bit-vectors.
The Boolean type.
Definition std_types.h:35
const membert & get_member(const struct_typet &type, const irep_idt &member) const
The byte swap expression.
std::vector< parametert > parameterst
Definition std_types.h:585
struct configt::bv_encodingt bv_encoding
A constant literal expression.
Definition std_expr.h:3007
const irep_idt & get_value() const
Definition std_expr.h:3015
bool is_null_pointer() const
Returns true if expr has a pointer type and a value NULL; it also returns true when expr has value ze...
Definition std_expr.cpp:170
resultt
Result of running the decision procedure.
Division.
Definition std_expr.h:1152
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Equality.
Definition std_expr.h:1339
Boute's Euclidean definition of Modulo – to match SMT-LIB2.
Definition std_expr.h:1277
Base class for all expressions.
Definition expr.h:57
std::vector< exprt > operandst
Definition expr.h:59
bool has_operands() const
Return true if there is at least one operand.
Definition expr.h:92
bool is_boolean() const
Return whether the expression represents a Boolean.
Definition expr.h:229
exprt & op0()
Definition expr.h:134
exprt & op1()
Definition expr.h:137
bool is_constant() const
Return whether the expression is a constant.
Definition expr.h:213
typet & type()
Return the type of the expression.
Definition expr.h:85
void visit_post(std::function< void(exprt &)>)
These are post-order traversal visitors, i.e., the visitor is executed on a node after its children h...
Definition expr.cpp:119
operandst & operands()
Definition expr.h:95
Extracts a single bit of a bit-vector operand.
Extracts a sub-range of a bit-vector operand.
The Boolean constant false.
Definition std_expr.h:3135
std::size_t integer_bits
Definition fixedbv.h:22
std::size_t width
Definition fixedbv.h:22
std::size_t get_fraction_bits() const
Definition fixedbv.h:35
Fixed-width bit-vector with signed fixed-point interpretation.
Fused multiply-add expression: round(op0 * op1 + op2) with a single rounding.
exprt & op_multiply_lhs()
exprt & op_multiply_rhs()
exprt & rounding_mode()
Round a floating-point number to an integral value considering the given rounding mode.
Semantic type conversion from/to floating-point formats.
Fixed-width bit-vector with IEEE floating-point interpretation.
IEEE floating-point operations These have two data operands (op0 and op1) and one rounding mode (op2)...
std::size_t f
Definition ieee_float.h:26
std::size_t width() const
Definition ieee_float.h:50
An IEEE 754 floating-point value, including specificiation.
Definition ieee_float.h:117
static ieee_float_valuet minus_infinity(const ieee_float_spect &_spec)
Definition ieee_float.h:209
bool is_NaN() const
Definition ieee_float.h:259
static ieee_float_valuet one(const floatbv_typet &)
ieee_float_spect spec
Definition ieee_float.h:119
mp_integer pack() const
bool get_sign() const
Definition ieee_float.h:254
static ieee_float_valuet zero(const floatbv_typet &type)
Definition ieee_float.h:172
static ieee_float_valuet NaN(const ieee_float_spect &_spec)
Definition ieee_float.h:195
static ieee_float_valuet plus_infinity(const ieee_float_spect &_spec)
Definition ieee_float.h:202
bool is_infinity() const
Definition ieee_float.h:260
The trinary if-then-else operator.
Definition std_expr.h:2426
Boolean implication.
Definition std_expr.h:2154
Array index operator.
Definition std_expr.h:1431
exprt & index()
Definition std_expr.h:1471
exprt & array()
Definition std_expr.h:1461
There are a large number of kinds of tree structured or tree-like data in CPROVER.
Definition irep.h:364
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition irep.cpp:482
const irep_idt & get(const irep_idt &name) const
Definition irep.cpp:44
const std::string & id_string() const
Definition irep.h:391
subt & get_sub()
Definition irep.h:448
void swap(irept &irep)
Definition irep.h:434
const irep_idt & id() const
Definition irep.h:388
bool is_nil() const
Definition irep.h:368
Evaluates to true if the operand is finite.
Evaluates to true if the operand is infinite.
Evaluates to true if the operand is NaN.
Evaluates to true if the operand is a normal number.
A let expression.
Definition std_expr.h:3259
bool is_true() const
Definition literal.h:156
bool sign() const
Definition literal.h:88
var_not var_no() const
Definition literal.h:83
bool is_false() const
Definition literal.h:161
Extract member of struct or union.
Definition std_expr.h:2866
Binary minus.
Definition std_expr.h:1065
Modulo defined as lhs-(rhs * truncate(lhs/rhs)).
Definition std_expr.h:1216
Binary multiplication Associativity is not specified.
Definition std_expr.h:1104
exprt & op1()
Definition std_expr.h:942
exprt & op0()
Definition std_expr.h:936
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
The NIL expression.
Definition std_expr.h:3144
Boolean negation.
Definition std_expr.h:2388
Disequality.
Definition std_expr.h:1393
Expression for finding the size (in bytes) of the object a pointer points to.
The plus expression Associativity is not specified.
Definition std_expr.h:1006
const mp_integer & get_invalid_object() const
numberingt< exprt, irep_hash > objects
exprt pointer_expr(const pointert &pointer, const pointer_typet &type) const
Convert an (object,offset) pair to an expression.
void get_dynamic_objects(std::vector< mp_integer > &objects) const
mp_integer add_object(const exprt &expr)
The pointer type These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (they ...
A base class for quantifier expressions.
Unbounded, signed rational numbers.
Boolean reduction: true iff every bit of the operand is 1.
Boolean reduction: true iff any bit of the operand is 1.
Boolean reduction: XOR (parity) of all bits in the operand.
Bit-vector replication.
A base class for shift and rotate operators.
Sign of an expression Predicate is true if _op is negative, false otherwise.
Definition std_expr.h:612
void convert_relation(const binary_relation_exprt &)
bool use_lambda_for_array
Definition smt2_conv.h:71
void convert_type(const typet &)
void unflatten(wheret, const typet &, unsigned nesting=0)
bool use_array_theory(const exprt &)
void find_symbols(const exprt &expr)
Find and declare symbols used in an expression This function traverses the expression tree and create...
std::size_t number_of_solver_calls
Definition smt2_conv.h:110
void convert_typecast(const typecast_exprt &expr)
void write_footer()
Writes the end of the SMT file to the smt_convt::out stream.
tvt l_get(literalt l) const
void convert_floatbv_rem(const binary_exprt &expr)
std::unordered_map< irep_idt, irept > current_bindings
Definition smt2_conv.h:200
bool use_FPA_theory
Definition smt2_conv.h:66
resultt dec_solve(const exprt &) override
Implementation of the decision procedure.
std::set< irep_idt > bvfp_set
Definition smt2_conv.h:206
void convert_address_of_rec(const exprt &expr, const pointer_typet &result_type)
void push() override
Unimplemented.
void convert_is_dynamic_object(const unary_exprt &)
void convert_literal(const literalt)
void convert_floatbv_div(const ieee_float_op_exprt &expr)
void convert_string_literal(const std::string &)
std::size_t get_number_of_solver_calls() const override
Return the number of incremental solver calls.
const namespacet & ns
Definition smt2_conv.h:99
void convert_floatbv_mult(const ieee_float_op_exprt &expr)
boolbv_widtht boolbv_width
Definition smt2_conv.h:108
void convert_constant(const constant_exprt &expr)
std::string floatbv_suffix(const exprt &) const
void flatten2bv(const exprt &)
std::string notes
Definition smt2_conv.h:101
void convert_floatbv_fma(const floatbv_fma_exprt &expr)
void convert_div(const div_exprt &expr)
std::ostream & out
Definition smt2_conv.h:100
exprt lower_byte_operators(const exprt &expr)
Lower byte_update and byte_extract operations within expr.
std::string type2id(const typet &) const
bool emit_set_logic
Definition smt2_conv.h:72
void convert_rounding_mode_FPA(const exprt &expr)
Converting a constant or symbolic rounding mode to SMT-LIB.
void convert_floatbv_typecast(const floatbv_typecast_exprt &expr)
struct_exprt parse_struct(const irept &s, const struct_typet &type)
std::string logic
Definition smt2_conv.h:101
void convert_mult(const mult_exprt &expr)
void convert_update_bit(const update_bit_exprt &)
exprt prepare_for_convert_expr(const exprt &expr)
Perform steps necessary before an expression is passed to convert_expr.
exprt get(const exprt &expr) const override
Return expr with variables replaced by values from satisfying assignment if available.
std::string decision_procedure_text() const override
Return a textual description of the decision procedure.
void convert_floatbv_minus(const ieee_float_op_exprt &expr)
bool use_check_sat_assuming
Definition smt2_conv.h:69
std::map< object_size_exprt, irep_idt > object_sizes
Definition smt2_conv.h:287
void define_object_size(const irep_idt &id, const object_size_exprt &expr)
bool use_datatypes
Definition smt2_conv.h:70
datatype_mapt datatype_map
Definition smt2_conv.h:272
void convert_mod(const mod_exprt &expr)
static std::string convert_identifier(const irep_idt &identifier)
void convert_floatbv_plus(const ieee_float_op_exprt &expr)
void convert_struct(const struct_exprt &expr)
std::unordered_map< irep_idt, bool > set_values
The values which boolean identifiers have been smt2_convt::set_to or in other words those which are a...
Definition smt2_conv.h:285
smt2_convt(const namespacet &_ns, const std::string &_benchmark, const std::string &_notes, const std::string &_logic, solvert _solver, std::ostream &_out)
Definition smt2_conv.cpp:61
void convert_member(const member_exprt &expr)
void convert_euclidean_mod(const euclidean_mod_exprt &expr)
void convert_index(const index_exprt &expr)
converterst converters
Definition smt2_conv.h:105
pointer_logict pointer_logic
Definition smt2_conv.h:240
exprt handle(const exprt &expr) override
Generate a handle, which is an expression that has the same value as the argument in any model that i...
void print_assignment(std::ostream &out) const override
Print satisfying assignment to out.
void walk_array_tree(std::unordered_map< int64_t, exprt > *operands_map, const irept &src, const array_typet &type)
This function walks the SMT output and populates a map with index/value pairs for the array.
void convert_floatbv_round_to_integral(const floatbv_round_to_integral_exprt &)
void set_to(const exprt &expr, bool value) override
For a Boolean expression expr, add the constraint 'expr' if value is true, otherwise add 'not expr'.
bool use_as_const
Definition smt2_conv.h:68
exprt parse_rec(const irept &s, const typet &type)
void convert_union(const union_exprt &expr)
exprt parse_union(const irept &s, const union_typet &type)
exprt parse_array(const irept &s, const array_typet &type)
This function is for parsing array output from SMT solvers when "(get-value |???|)" returns an array ...
std::vector< bool > boolean_assignment
Definition smt2_conv.h:294
void flatten_array(const exprt &)
produce a flat bit-vector for a given array of fixed size
void convert_with(const with_exprt &expr)
letifyt letify
Definition smt2_conv.h:177
bool use_array_of_bool
Definition smt2_conv.h:67
std::vector< literalt > assumptions
Definition smt2_conv.h:107
void convert_plus(const plus_exprt &expr)
defined_expressionst defined_expressions
Definition smt2_conv.h:281
void pop() override
Currently, only implements a single stack element (no nested contexts)
void convert_update_bits(const update_bits_exprt &)
void find_symbols_rec(const typet &type, std::set< irep_idt > &recstack)
void convert_update(const update_exprt &)
void write_header()
std::set< irep_idt > state_fkt_declared
Definition smt2_conv.h:210
solvert solver
Definition smt2_conv.h:102
identifier_mapt identifier_map
Definition smt2_conv.h:265
void convert_minus(const minus_exprt &expr)
void convert_expr(const exprt &)
constant_exprt parse_literal(const irept &, const typet &type)
const smt2_symbolt & to_smt2_symbol(const exprt &expr)
Definition smt2_conv.h:225
std::size_t no_boolean_variables
Definition smt2_conv.h:293
smt2_identifierst smt2_identifiers
Definition smt2_conv.h:290
void convert_floatbv(const exprt &expr)
literalt convert(const exprt &expr)
Struct constructor from list of elements.
Definition std_expr.h:1820
Structure type, corresponds to C style structs.
Definition std_types.h:230
const irep_idt & get_name() const
Definition std_types.h:78
const componentst & components() const
Definition std_types.h:146
std::vector< componentt > componentst
Definition std_types.h:139
The Boolean constant true.
Definition std_expr.h:3126
Definition threeval.h:20
Semantic type conversion.
Definition std_expr.h:1995
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition std_expr.h:2003
The type of an expression, extends irept.
Definition type.h:29
Generic base class for unary expressions.
Definition std_expr.h:364
const exprt & op() const
Definition std_expr.h:394
The unary minus expression.
Definition std_expr.h:477
Union constructor from single element.
Definition std_expr.h:1724
The union type.
Definition c_types.h:147
Fixed-width bit-vector with unsigned binary interpretation.
Thrown when we encounter an instruction, parameters to an instruction etc.
Replaces a sub-range of a bit-vector operand.
exprt lower() const
A lowering to masking, shifting, or.
Replaces a sub-range of a bit-vector operand.
exprt lower() const
A lowering to masking, shifting, or.
Operator to update elements in structs and arrays.
Definition std_expr.h:2679
Operator to update elements in structs and arrays.
Definition std_expr.h:2520
exprt & new_value()
Definition std_expr.h:2550
exprt & where()
Definition std_expr.h:2540
exprt & old()
Definition std_expr.h:2530
bool has_prefix(const std::string &s, const std::string &prefix)
Definition converter.cpp:13
int isdigit(int c)
Definition ctype.c:24
Forward depth-first search iterators These iterators' copy operations are expensive,...
exprt make_binary(const exprt &expr)
splits an expression with >=3 operands into nested binary expressions
Definition expr_util.cpp:38
Deprecated expression utility functions.
exprt float_bv(const exprt &src)
Definition float_bv.h:202
API to expression classes for floating-point arithmetic.
const ieee_float_op_exprt & to_ieee_float_op_expr(const exprt &expr)
Cast an exprt to an ieee_float_op_exprt.
const floatbv_fma_exprt & to_floatbv_fma_expr(const exprt &expr)
const floatbv_round_to_integral_exprt & to_floatbv_round_to_integral_expr(const exprt &expr)
Cast an exprt to a floatbv_round_to_integral_exprt.
const isnormal_exprt & to_isnormal_expr(const exprt &expr)
Cast an exprt to a isnormal_exprt.
const isinf_exprt & to_isinf_expr(const exprt &expr)
Cast an exprt to a isinf_exprt.
const isfinite_exprt & to_isfinite_expr(const exprt &expr)
Cast an exprt to a isfinite_exprt.
const isnan_exprt & to_isnan_expr(const exprt &expr)
Cast an exprt to a isnan_exprt.
const floatbv_typecast_exprt & to_floatbv_typecast_expr(const exprt &expr)
Cast an exprt to a floatbv_typecast_exprt.
static format_containert< T > format(const T &o)
Definition format.h:37
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
static std::string binary(const constant_exprt &src)
exprt to_expr(const namespacet &ns, const irep_idt &identifier, const std::string &src)
bool is_true(const literalt &l)
Definition literal.h:198
literalt const_literal(bool value)
Definition literal.h:188
literalt pos(literalt a)
Definition literal.h:194
const literal_exprt & to_literal_expr(const exprt &expr)
Cast a generic exprt to a literal_exprt.
double pow(double x, double y)
Definition math.c:3049
API to expression classes for 'mathematical' expressions.
const quantifier_exprt & to_quantifier_expr(const exprt &expr)
Cast an exprt to a quantifier_exprt.
const function_application_exprt & to_function_application_expr(const exprt &expr)
Cast an exprt to a function_application_exprt.
const integer_range_typet & to_integer_range_type(const typet &type)
Cast a typet to a integer_range_typet.
const mathematical_function_typet & to_mathematical_function_type(const typet &type)
Cast a typet to a mathematical_function_typet.
const mp_integer string2integer(const std::string &n, unsigned base)
Definition mp_arith.cpp:54
mp_integer bitwise_or(const mp_integer &a, const mp_integer &b)
bitwise 'or' of two nonnegative integers
Definition mp_arith.cpp:215
const std::string integer2binary(const mp_integer &n, std::size_t width)
Definition mp_arith.cpp:64
const element_address_exprt & to_element_address_expr(const exprt &expr)
Cast an exprt to an element_address_exprt.
const object_address_exprt & to_object_address_expr(const exprt &expr)
Cast an exprt to an object_address_exprt.
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
const pointer_offset_exprt & to_pointer_offset_expr(const exprt &expr)
Cast an exprt to a pointer_offset_exprt.
const pointer_object_exprt & to_pointer_object_expr(const exprt &expr)
Cast an exprt to a pointer_object_exprt.
const field_address_exprt & to_field_address_expr(const exprt &expr)
Cast an exprt to an field_address_exprt.
std::optional< mp_integer > pointer_offset_size(const typet &type, const namespacet &ns)
Compute the size of a type in bytes, rounding up to full bytes.
bool is_zero_width(const typet &type, const namespacet &ns)
Returns true iff type has effective width of zero bits.
std::optional< exprt > size_of_expr(const typet &type, const namespacet &ns)
std::optional< mp_integer > member_offset(const struct_typet &type, const irep_idt &member, const namespacet &ns)
Pointer Logic.
exprt pointer_offset(const exprt &pointer)
exprt object_size(const exprt &pointer)
exprt same_object(const exprt &p1, const exprt &p2)
Various predicates over pointers in programs.
Ranges: pair of begin and end iterators, which can be initialized from containers,...
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition range.h:522
bool to_rational(const exprt &expr, rationalt &rational_value)
constant_exprt from_rational(const rationalt &a)
exprt simplify_expr(exprt src, const namespacet &ns)
static bool has_quantifier(const exprt &expr)
#define SMT2_TODO(S)
Definition smt2_conv.cpp:59
static bool is_smt2_simple_identifier(const std::string &identifier)
#define UNEXPECTEDCASE(S)
Definition smt2_conv.cpp:56
bool is_smt2_simple_symbol_character(char ch)
Tokenizer for the SMT-LIB v2.6 syntax.
void solver(std::vector< framet > &frames, const std::unordered_set< symbol_exprt, irep_hash > &address_taken, const solver_optionst &solver_options, const namespacet &ns, std::vector< propertyt > &properties, std::size_t property_index)
Definition solver.cpp:44
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition invariant.h:525
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition invariant.h:534
#define PRECONDITION(CONDITION)
Definition invariant.h:463
#define UNIMPLEMENTED
Definition invariant.h:558
#define INVARIANT_WITH_DIAGNOSTICS(CONDITION, REASON,...)
Same as invariant, with one or more diagnostics attached Diagnostics can be of any type that has a sp...
Definition invariant.h:437
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
#define CHECK_RETURN_WITH_DIAGNOSTICS(CONDITION,...)
Definition invariant.h:496
#define DATA_INVARIANT_WITH_DIAGNOSTICS(CONDITION, REASON,...)
Definition invariant.h:535
#define UNREACHABLE_BECAUSE(REASON)
Definition invariant.h:526
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition std_expr.cpp:291
API to expression classes.
const struct_exprt & to_struct_expr(const exprt &expr)
Cast an exprt to a struct_exprt.
Definition std_expr.h:1843
const array_of_exprt & to_array_of_expr(const exprt &expr)
Cast an exprt to an array_of_exprt.
Definition std_expr.h:1552
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
Definition std_expr.h:828
const unary_plus_exprt & to_unary_plus_expr(const exprt &expr)
Cast an exprt to a unary_plus_exprt.
Definition std_expr.h:539
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1494
const mod_exprt & to_mod_expr(const exprt &expr)
Cast an exprt to a mod_exprt.
Definition std_expr.h:1260
const mult_exprt & to_mult_expr(const exprt &expr)
Cast an exprt to a mult_exprt.
Definition std_expr.h:1134
const array_comprehension_exprt & to_array_comprehension_expr(const exprt &expr)
Cast an exprt to a array_comprehension_exprt.
Definition std_expr.h:3529
const ternary_exprt & to_ternary_expr(const exprt &expr)
Cast an exprt to a ternary_exprt.
Definition std_expr.h:117
const named_term_exprt & to_named_term_expr(const exprt &expr)
Cast an exprt to a named_term_exprt.
Definition std_expr.h:3702
const cond_exprt & to_cond_expr(const exprt &expr)
Cast an exprt to a cond_exprt.
Definition std_expr.h:3443
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition std_expr.h:2024
const div_exprt & to_div_expr(const exprt &expr)
Cast an exprt to a div_exprt.
Definition std_expr.h:1196
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition std_expr.h:721
const plus_exprt & to_plus_expr(const exprt &expr)
Cast an exprt to a plus_exprt.
Definition std_expr.h:1045
const notequal_exprt & to_notequal_expr(const exprt &expr)
Cast an exprt to an notequal_exprt.
Definition std_expr.h:1413
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition std_expr.h:424
const multi_ary_exprt & to_multi_ary_expr(const exprt &expr)
Cast an exprt to a multi_ary_exprt.
Definition std_expr.h:991
const let_exprt & to_let_expr(const exprt &expr)
Cast an exprt to a let_exprt.
Definition std_expr.h:3383
const abs_exprt & to_abs_expr(const exprt &expr)
Cast an exprt to a abs_exprt.
Definition std_expr.h:459
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition std_expr.h:2501
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition std_expr.h:2953
const minus_exprt & to_minus_expr(const exprt &expr)
Cast an exprt to a minus_exprt.
Definition std_expr.h:1085
const union_exprt & to_union_expr(const exprt &expr)
Cast an exprt to a union_exprt.
Definition std_expr.h:1765
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3078
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition std_expr.h:2408
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:221
const with_exprt & to_with_expr(const exprt &expr)
Cast an exprt to a with_exprt.
Definition std_expr.h:2573
const implies_exprt & to_implies_expr(const exprt &expr)
Cast an exprt to a implies_exprt.
Definition std_expr.h:2174
const update_exprt & to_update_expr(const exprt &expr)
Cast an exprt to an update_exprt.
Definition std_expr.h:2762
const unary_minus_exprt & to_unary_minus_expr(const exprt &expr)
Cast an exprt to a unary_minus_exprt.
Definition std_expr.h:502
const equal_exprt & to_equal_expr(const exprt &expr)
Cast an exprt to an equal_exprt.
Definition std_expr.h:1375
const nondet_symbol_exprt & to_nondet_symbol_expr(const exprt &expr)
Cast an exprt to a nondet_symbol_exprt.
Definition std_expr.h:346
const sign_exprt & to_sign_expr(const exprt &expr)
Cast an exprt to a sign_exprt.
Definition std_expr.h:632
const euclidean_mod_exprt & to_euclidean_mod_expr(const exprt &expr)
Cast an exprt to a euclidean_mod_exprt.
Definition std_expr.h:1321
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:787
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition std_types.h:307
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition std_types.h:517
const complex_typet & to_complex_type(const typet &type)
Cast a typet to a complex_typet.
Definition std_types.h:1048
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:887
std::size_t unsafe_string2size_t(const std::string &str, int base)
const string_constantt & to_string_constant(const exprt &expr)
static bool failed(bool error_indicator)
#define size_type
Definition unistd.c:186