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 convert_expr(to_reduction_and_expr(expr).lower());
2919 }
2920 else if(expr.id() == ID_reduction_nand)
2921 {
2922 convert_expr(to_reduction_nand_expr(expr).lower());
2923 }
2924 else if(expr.id() == ID_reduction_or)
2925 {
2926 convert_expr(to_reduction_or_expr(expr).lower());
2927 }
2928 else if(expr.id() == ID_reduction_nor)
2929 {
2930 convert_expr(to_reduction_nor_expr(expr).lower());
2931 }
2932 else if(expr.id() == ID_reduction_xor)
2933 {
2934 // This is the parity of the operand. No SMT-LIB 2 equivalent.
2935 // Do bit-wise. SMT-LIB 3.0 could do this with "fold bvxor".
2936 auto &op = to_reduction_xor_expr(expr).op();
2937 auto width = to_bitvector_type(op.type()).get_width();
2938 PRECONDITION(width >= 1);
2939
2940 if(width == 1)
2941 {
2942 out << "(= ";
2943 flatten2bv(op);
2944 out << " #b1)";
2945 }
2946 else
2947 {
2948 out << "(let ((?rop ";
2949 flatten2bv(op);
2950 out << ")) ";
2951
2952 // XOR all bits: extract each bit and use multi-ary bvxor
2953 out << "(= (bvxor";
2954 for(std::size_t i = 0; i < width; i++)
2955 out << " ((_ extract " << i << " " << i << ") ?rop)";
2956 out << ") #b1)";
2957
2958 out << ')'; // let
2959 }
2960 }
2961 else if(expr.id() == ID_reduction_xnor)
2962 {
2963 // This is the negation of "reduction xor"
2964 auto &op = to_reduction_xnor_expr(expr).op();
2966 }
2967 else
2969 false,
2970 "smt2_convt::convert_expr should not be applied to unsupported "
2971 "expression",
2972 expr.id_string());
2973}
2974
2976{
2977 const exprt &src = expr.op();
2978
2979 typet dest_type = expr.type();
2980
2981 if(dest_type == src.type()) // identity
2982 {
2983 convert_expr(src);
2984 return;
2985 }
2986
2987 if(dest_type.id()==ID_c_enum_tag)
2989
2990 typet src_type = src.type();
2991 if(src_type.id()==ID_c_enum_tag)
2993
2994 if(dest_type.id()==ID_bool)
2995 {
2996 // this is comparison with zero
2997 if(
2998 src_type.id() == ID_signedbv || src_type.id() == ID_unsignedbv ||
2999 src_type.id() == ID_c_bool || src_type.id() == ID_fixedbv ||
3000 src_type.id() == ID_pointer || src_type.id() == ID_integer ||
3001 src_type.id() == ID_natural || src_type.id() == ID_rational ||
3002 src_type.id() == ID_real)
3003 {
3004 out << "(not (= ";
3005 convert_expr(src);
3006 out << " ";
3008 out << "))";
3009 }
3010 else if(src_type.id()==ID_floatbv)
3011 {
3012 if(use_FPA_theory)
3013 {
3014 out << "(not (fp.isZero ";
3015 convert_expr(src);
3016 out << "))";
3017 }
3018 else
3019 convert_floatbv(expr);
3020 }
3021 else
3022 {
3023 UNEXPECTEDCASE("TODO typecast1 "+src_type.id_string()+" -> bool");
3024 }
3025 }
3026 else if(dest_type.id()==ID_c_bool)
3027 {
3028 std::size_t to_width=boolbv_width(dest_type);
3029 out << "(ite ";
3030 out << "(not (= ";
3031 convert_expr(src);
3032 out << " ";
3034 out << "))"; // not, =
3035 out << " (_ bv1 " << to_width << ")";
3036 out << " (_ bv0 " << to_width << ")";
3037 out << ")"; // ite
3038 }
3039 else if(dest_type.id()==ID_signedbv ||
3040 dest_type.id()==ID_unsignedbv ||
3041 dest_type.id()==ID_c_enum ||
3042 dest_type.id()==ID_bv)
3043 {
3044 std::size_t to_width=boolbv_width(dest_type);
3045
3046 if(src_type.id()==ID_signedbv || // from signedbv
3047 src_type.id()==ID_unsignedbv || // from unsigedbv
3048 src_type.id()==ID_c_bool ||
3049 src_type.id()==ID_c_enum ||
3050 src_type.id()==ID_bv)
3051 {
3052 std::size_t from_width=boolbv_width(src_type);
3053
3054 if(from_width==to_width)
3055 convert_expr(src); // ignore
3056 else if(from_width<to_width) // extend
3057 {
3058 if(src_type.id()==ID_signedbv)
3059 out << "((_ sign_extend ";
3060 else
3061 out << "((_ zero_extend ";
3062
3064 << ") "; // ind
3065 convert_expr(src);
3066 out << ")";
3067 }
3068 else // chop off extra bits
3069 {
3070 out << "((_ extract " << (to_width-1) << " 0) ";
3071 convert_expr(src);
3072 out << ")";
3073 }
3074 }
3075 else if(src_type.id()==ID_fixedbv) // from fixedbv to int
3076 {
3078
3079 std::size_t from_width=fixedbv_type.get_width();
3080 std::size_t from_integer_bits=fixedbv_type.get_integer_bits();
3081 std::size_t from_fraction_bits=fixedbv_type.get_fraction_bits();
3082
3083 // we might need to round up in case of negative numbers
3084 // e.g., (int)(-1.00001)==1
3085
3086 out << "(let ((?tcop ";
3087 convert_expr(src);
3088 out << ")) ";
3089
3090 out << "(bvadd ";
3091
3093 {
3094 out << "((_ sign_extend "
3095 << (to_width-from_integer_bits) << ") ";
3096 out << "((_ extract " << (from_width-1) << " "
3097 << from_fraction_bits << ") ";
3098 convert_expr(src);
3099 out << "))";
3100 }
3101 else
3102 {
3103 out << "((_ extract " << (from_fraction_bits+to_width-1)
3104 << " " << from_fraction_bits << ") ";
3105 convert_expr(src);
3106 out << ")";
3107 }
3108
3109 out << " (ite (and ";
3110
3111 // some fraction bit is not zero
3112 out << "(not (= ((_ extract " << (from_fraction_bits-1) << " 0) ?tcop) "
3113 "(_ bv0 " << from_fraction_bits << ")))";
3114
3115 // number negative
3116 out << " (= ((_ extract " << (from_width-1) << " " << (from_width-1)
3117 << ") ?tcop) #b1)";
3118
3119 out << ")"; // and
3120
3121 out << " (_ bv1 " << to_width << ") (_ bv0 " << to_width << "))"; // ite
3122 out << ")"; // bvadd
3123 out << ")"; // let
3124 }
3125 else if(src_type.id()==ID_floatbv) // from floatbv to int
3126 {
3127 if(dest_type.id()==ID_bv)
3128 {
3129 // this is _NOT_ a semantic conversion, but bit-wise
3130
3131 if(use_FPA_theory)
3132 {
3133 defined_expressionst::const_iterator it =
3134 defined_expressions.find(expr);
3135 CHECK_RETURN(it != defined_expressions.end());
3136 out << it->second;
3137 }
3138 else
3139 {
3140 // straight-forward if width matches
3141 convert_expr(src);
3142 }
3143 }
3144 else if(dest_type.id()==ID_signedbv)
3145 {
3146 // this should be floatbv_typecast, not typecast
3148 "typecast unexpected "+src_type.id_string()+" -> "+
3149 dest_type.id_string());
3150 }
3151 else if(dest_type.id()==ID_unsignedbv)
3152 {
3153 // this should be floatbv_typecast, not typecast
3155 "typecast unexpected "+src_type.id_string()+" -> "+
3156 dest_type.id_string());
3157 }
3158 }
3159 else if(src_type.id()==ID_bool) // from boolean to int
3160 {
3161 out << "(ite ";
3162 convert_expr(src);
3163
3164 if(dest_type.id()==ID_fixedbv)
3165 {
3167 out << " (concat (_ bv1 "
3168 << spec.integer_bits << ") " <<
3169 "(_ bv0 " << spec.get_fraction_bits() << ")) " <<
3170 "(_ bv0 " << spec.width << ")";
3171 }
3172 else
3173 {
3174 out << " (_ bv1 " << to_width << ")";
3175 out << " (_ bv0 " << to_width << ")";
3176 }
3177
3178 out << ")";
3179 }
3180 else if(src_type.id()==ID_pointer) // from pointer to int
3181 {
3182 std::size_t from_width=boolbv_width(src_type);
3183
3184 if(from_width<to_width) // extend
3185 {
3186 out << "((_ sign_extend ";
3188 << ") ";
3189 convert_expr(src);
3190 out << ")";
3191 }
3192 else // chop off extra bits
3193 {
3194 out << "((_ extract " << (to_width-1) << " 0) ";
3195 convert_expr(src);
3196 out << ")";
3197 }
3198 }
3199 else if(src_type.id() == ID_integer || src_type.id() == ID_natural)
3200 {
3201 // from integer to bit-vector, must be constant
3202 if(src.is_constant())
3203 {
3205 out << "(_ bv" << i << " " << to_width << ")";
3206 }
3207 else
3208 SMT2_TODO("can't convert non-constant integer to bitvector");
3209 }
3210 else if(
3211 src_type.id() == ID_struct ||
3212 src_type.id() == ID_struct_tag) // flatten a struct to a bit-vector
3213 {
3214 if(use_datatypes)
3215 {
3216 INVARIANT(
3218 "bit vector with of source and destination type shall be equal");
3219 flatten2bv(src);
3220 }
3221 else
3222 {
3223 INVARIANT(
3225 "bit vector with of source and destination type shall be equal");
3226 convert_expr(src); // nothing else to do!
3227 }
3228 }
3229 else if(
3230 src_type.id() == ID_union ||
3231 src_type.id() == ID_union_tag) // flatten a union
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 else if(src_type.id()==ID_c_bit_field)
3239 {
3240 std::size_t from_width=boolbv_width(src_type);
3241
3242 if(from_width==to_width)
3243 convert_expr(src); // ignore
3244 else
3245 {
3249 }
3250 }
3251 else
3252 {
3253 std::ostringstream e_str;
3254 e_str << src_type.id() << " -> " << dest_type.id()
3255 << " src == " << format(src);
3256 UNEXPECTEDCASE("TODO typecast2 " + e_str.str());
3257 }
3258 }
3259 else if(dest_type.id()==ID_fixedbv) // to fixedbv
3260 {
3262 std::size_t to_fraction_bits=fixedbv_type.get_fraction_bits();
3263 std::size_t to_integer_bits=fixedbv_type.get_integer_bits();
3264
3265 if(src_type.id()==ID_unsignedbv ||
3266 src_type.id()==ID_signedbv ||
3267 src_type.id()==ID_c_enum)
3268 {
3269 // integer to fixedbv
3270
3271 std::size_t from_width=to_bitvector_type(src_type).get_width();
3272 out << "(concat ";
3273
3275 convert_expr(src);
3277 {
3278 // too many integer bits
3279 out << "((_ extract " << (to_integer_bits-1) << " 0) ";
3280 convert_expr(src);
3281 out << ")";
3282 }
3283 else
3284 {
3285 // too few integer bits
3286 INVARIANT(
3288 "from_width should be smaller than to_integer_bits as other case "
3289 "have been handled above");
3290 if(dest_type.id()==ID_unsignedbv)
3291 {
3292 out << "(_ zero_extend "
3293 << (to_integer_bits-from_width) << ") ";
3294 convert_expr(src);
3295 out << ")";
3296 }
3297 else
3298 {
3299 out << "((_ sign_extend "
3300 << (to_integer_bits-from_width) << ") ";
3301 convert_expr(src);
3302 out << ")";
3303 }
3304 }
3305
3306 out << "(_ bv0 " << to_fraction_bits << ")";
3307 out << ")"; // concat
3308 }
3309 else if(src_type.id()==ID_bool) // bool to fixedbv
3310 {
3311 out << "(concat (concat"
3312 << " (_ bv0 " << (to_integer_bits-1) << ") ";
3313 flatten2bv(src); // produces #b0 or #b1
3314 out << ") (_ bv0 "
3316 << "))";
3317 }
3318 else if(src_type.id()==ID_fixedbv) // fixedbv to fixedbv
3319 {
3321 std::size_t from_fraction_bits=from_fixedbv_type.get_fraction_bits();
3322 std::size_t from_integer_bits=from_fixedbv_type.get_integer_bits();
3323 std::size_t from_width=from_fixedbv_type.get_width();
3324
3325 out << "(let ((?tcop ";
3326 convert_expr(src);
3327 out << ")) ";
3328
3329 out << "(concat ";
3330
3332 {
3333 out << "((_ extract "
3336 << ") ?tcop)";
3337 }
3338 else
3339 {
3340 INVARIANT(
3342 "to_integer_bits should be greater than from_integer_bits as the"
3343 "other case has been handled above");
3344 out << "((_ sign_extend "
3346 << ") ((_ extract "
3347 << (from_width-1) << " "
3349 << ") ?tcop))";
3350 }
3351
3352 out << " ";
3353
3355 {
3356 out << "((_ extract "
3357 << (from_fraction_bits-1) << " "
3359 << ") ?tcop)";
3360 }
3361 else
3362 {
3363 INVARIANT(
3365 "to_fraction_bits should be greater than from_fraction_bits as the"
3366 "other case has been handled above");
3367 out << "(concat ((_ extract "
3368 << (from_fraction_bits-1) << " 0) ";
3369 convert_expr(src);
3370 out << ")"
3371 << " (_ bv0 " << to_fraction_bits-from_fraction_bits
3372 << "))";
3373 }
3374
3375 out << "))"; // concat, let
3376 }
3377 else
3378 UNEXPECTEDCASE("unexpected typecast to fixedbv");
3379 }
3380 else if(dest_type.id()==ID_pointer)
3381 {
3382 std::size_t to_width=boolbv_width(dest_type);
3383
3384 if(src_type.id()==ID_pointer) // pointer to pointer
3385 {
3386 // this just passes through
3387 convert_expr(src);
3388 }
3389 else if(
3390 src_type.id() == ID_unsignedbv || src_type.id() == ID_signedbv ||
3391 src_type.id() == ID_bv)
3392 {
3393 // integer to pointer
3394
3395 std::size_t from_width=boolbv_width(src_type);
3396
3397 if(from_width==to_width)
3398 convert_expr(src);
3399 else if(from_width<to_width)
3400 {
3401 out << "((_ sign_extend "
3402 << (to_width-from_width)
3403 << ") ";
3404 convert_expr(src);
3405 out << ")"; // sign_extend
3406 }
3407 else // from_width>to_width
3408 {
3409 out << "((_ extract " << to_width << " 0) ";
3410 convert_expr(src);
3411 out << ")"; // extract
3412 }
3413 }
3414 else
3415 UNEXPECTEDCASE("TODO typecast3 "+src_type.id_string()+" -> pointer");
3416 }
3417 else if(dest_type.id()==ID_range)
3418 {
3420 const auto dest_width = address_bits(dest_range_type.size());
3421 if(src_type.id() == ID_range)
3422 {
3424 const auto src_width = address_bits(src_range_type.size());
3425 if(src_width < dest_width)
3426 {
3427 out << "((_ zero_extend " << dest_width - src_width << ") ";
3428 convert_expr(src);
3429 out << ')'; // zero_extend
3430 }
3431 else if(src_width > dest_width)
3432 {
3433 out << "((_ extract " << dest_width - 1 << " 0) ";
3434 convert_expr(src);
3435 out << ')'; // extract
3436 }
3437 else // src_width == dest_width
3438 {
3439 convert_expr(src);
3440 }
3441 }
3442 else
3443 SMT2_TODO("typecast from " + src_type.id_string() + " to range");
3444 }
3445 else if(dest_type.id()==ID_floatbv)
3446 {
3447 // Typecast from integer to floating-point should have be been
3448 // converted to ID_floatbv_typecast during symbolic execution,
3449 // adding the rounding mode. See
3450 // smt2_convt::convert_floatbv_typecast.
3451 // The exception is bool and c_bool to float.
3453
3454 if(src_type.id()==ID_bool)
3455 {
3456 out << "(ite ";
3457 convert_expr(src);
3458 out << ' ';
3460 out << ' ';
3462 out << ')';
3463 }
3464 else if(src_type.id()==ID_c_bool)
3465 {
3466 // turn into proper bool
3467 const typecast_exprt tmp(src, bool_typet());
3469 }
3470 else if(src_type.id() == ID_bv)
3471 {
3472 if(to_bv_type(src_type).get_width() != dest_floatbv_type.get_width())
3473 {
3474 UNEXPECTEDCASE("Typecast bv -> float with wrong width");
3475 }
3476
3477 if(use_FPA_theory)
3478 {
3479 out << "((_ to_fp " << dest_floatbv_type.get_e() << " "
3480 << dest_floatbv_type.get_f() + 1 << ") ";
3481 convert_expr(src);
3482 out << ')';
3483 }
3484 else
3485 convert_expr(src);
3486 }
3487 else
3488 UNEXPECTEDCASE("Unknown typecast "+src_type.id_string()+" -> float");
3489 }
3490 else if(dest_type.id() == ID_integer || dest_type.id() == ID_natural)
3491 {
3492 if(src_type.id()==ID_bool)
3493 {
3494 out << "(ite ";
3495 convert_expr(src);
3496 out <<" 1 0)";
3497 }
3498 else
3499 UNEXPECTEDCASE("Unknown typecast "+src_type.id_string()+" -> integer");
3500 }
3501 else if(dest_type.id()==ID_c_bit_field)
3502 {
3503 std::size_t from_width=boolbv_width(src_type);
3504 std::size_t to_width=boolbv_width(dest_type);
3505
3506 if(from_width==to_width)
3507 convert_expr(src); // ignore
3508 else
3509 {
3513 }
3514 }
3515 else if(dest_type.id() == ID_rational)
3516 {
3517 if(src_type.id() == ID_signedbv)
3518 {
3519 // TODO: negative numbers
3520 out << "(/ ";
3521 convert_expr(src);
3522 out << " 1)";
3523 }
3524 else
3526 "Unknown typecast " + src_type.id_string() + " -> rational");
3527 }
3528 else
3530 "TODO typecast8 "+src_type.id_string()+" -> "+dest_type.id_string());
3531}
3532
3534{
3535 const exprt &src=expr.op();
3536 // const exprt &rounding_mode=expr.rounding_mode();
3537 const typet &src_type=src.type();
3538 const typet &dest_type=expr.type();
3539
3540 if(dest_type.id()==ID_floatbv)
3541 {
3542 if(src_type.id()==ID_floatbv)
3543 {
3544 // float to float
3545
3546 /* ISO 9899:1999
3547 * 6.3.1.5 Real floating types
3548 * 1 When a float is promoted to double or long double, or a
3549 * double is promoted to long double, its value is unchanged.
3550 *
3551 * 2 When a double is demoted to float, a long double is
3552 * demoted to double or float, or a value being represented in
3553 * greater precision and range than required by its semantic
3554 * type (see 6.3.1.8) is explicitly converted to its semantic
3555 * type, if the value being converted can be represented
3556 * exactly in the new type, it is unchanged. If the value
3557 * being converted is in the range of values that can be
3558 * represented but cannot be represented exactly, the result
3559 * is either the nearest higher or nearest lower representable
3560 * value, chosen in an implementation-defined manner. If the
3561 * value being converted is outside the range of values that
3562 * can be represented, the behavior is undefined.
3563 */
3564
3566
3567 if(use_FPA_theory)
3568 {
3569 out << "((_ to_fp " << dst.get_e() << " "
3570 << dst.get_f() + 1 << ") ";
3572 out << " ";
3573 convert_expr(src);
3574 out << ")";
3575 }
3576 else
3577 convert_floatbv(expr);
3578 }
3579 else if(src_type.id()==ID_unsignedbv)
3580 {
3581 // unsigned to float
3582
3583 /* ISO 9899:1999
3584 * 6.3.1.4 Real floating and integer
3585 * 2 When a value of integer type is converted to a real
3586 * floating type, if the value being converted can be
3587 * represented exactly in the new type, it is unchanged. If the
3588 * value being converted is in the range of values that can be
3589 * represented but cannot be represented exactly, the result is
3590 * either the nearest higher or nearest lower representable
3591 * value, chosen in an implementation-defined manner. If the
3592 * value being converted is outside the range of values that can
3593 * be represented, the behavior is undefined.
3594 */
3595
3597
3598 if(use_FPA_theory)
3599 {
3600 out << "((_ to_fp_unsigned " << dst.get_e() << " "
3601 << dst.get_f() + 1 << ") ";
3603 out << " ";
3604 convert_expr(src);
3605 out << ")";
3606 }
3607 else
3608 convert_floatbv(expr);
3609 }
3610 else if(src_type.id()==ID_signedbv)
3611 {
3612 // signed to float
3613
3615
3616 if(use_FPA_theory)
3617 {
3618 out << "((_ to_fp " << dst.get_e() << " "
3619 << dst.get_f() + 1 << ") ";
3621 out << " ";
3622 convert_expr(src);
3623 out << ")";
3624 }
3625 else
3626 convert_floatbv(expr);
3627 }
3628 else if(src_type.id()==ID_c_enum_tag)
3629 {
3630 // enum to float
3631
3632 // We first convert to 'underlying type'
3634 tmp.op() = typecast_exprt(
3635 src, ns.follow_tag(to_c_enum_tag_type(src_type)).underlying_type());
3637 }
3638 else
3640 "TODO typecast11 "+src_type.id_string()+" -> "+dest_type.id_string());
3641 }
3642 else if(dest_type.id()==ID_signedbv)
3643 {
3644 if(use_FPA_theory)
3645 {
3646 std::size_t dest_width=to_signedbv_type(dest_type).get_width();
3647 out << "((_ fp.to_sbv " << dest_width << ") ";
3649 out << " ";
3650 convert_expr(src);
3651 out << ")";
3652 }
3653 else
3654 convert_floatbv(expr);
3655 }
3656 else if(dest_type.id()==ID_unsignedbv)
3657 {
3658 if(use_FPA_theory)
3659 {
3660 std::size_t dest_width=to_unsignedbv_type(dest_type).get_width();
3661 out << "((_ fp.to_ubv " << dest_width << ") ";
3663 out << " ";
3664 convert_expr(src);
3665 out << ")";
3666 }
3667 else
3668 convert_floatbv(expr);
3669 }
3670 else
3671 {
3673 "TODO typecast12 "+src_type.id_string()+" -> "+dest_type.id_string());
3674 }
3675}
3676
3679{
3680 PRECONDITION(expr.type().id() == ID_floatbv);
3681
3682 if(use_FPA_theory)
3683 {
3684 out << "(fp.roundToIntegral ";
3686 out << ' ';
3687 convert_expr(expr.op());
3688 out << ")";
3689 }
3690 else
3691 UNEXPECTEDCASE("TODO floatbv_round_to_integral without FPA");
3692}
3693
3695{
3696 const struct_typet &struct_type =
3697 expr.type().id() == ID_struct_tag
3698 ? ns.follow_tag(to_struct_tag_type(expr.type()))
3699 : to_struct_type(expr.type());
3700
3701 const struct_typet::componentst &components=
3702 struct_type.components();
3703
3705 components.size() == expr.operands().size(),
3706 "number of struct components as indicated by the struct type shall be equal"
3707 "to the number of operands of the struct expression");
3708
3709 DATA_INVARIANT(!components.empty(), "struct shall have struct components");
3710
3711 if(use_datatypes)
3712 {
3713 const std::string &smt_typename = datatype_map.at(struct_type);
3714
3715 // use the constructor for the Z3 datatype
3716 out << "(mk-" << smt_typename;
3717
3718 std::size_t i=0;
3719 for(struct_typet::componentst::const_iterator
3720 it=components.begin();
3721 it!=components.end();
3722 it++, i++)
3723 {
3724 if(is_zero_width(it->type(), ns))
3725 continue;
3726 out << " ";
3727 convert_expr(expr.operands()[i]);
3728 }
3729
3730 out << ")";
3731 }
3732 else
3733 {
3734 auto convert_operand = [this](const exprt &op) {
3735 // may need to flatten array-theory arrays in there
3736 if(op.type().id() == ID_array && use_array_theory(op))
3737 flatten_array(op);
3738 else if(op.type().id() == ID_bool)
3739 flatten2bv(op);
3740 else
3741 convert_expr(op);
3742 };
3743
3744 // SMT-LIB 2 concat is binary only
3745 std::size_t n_concat = 0;
3746 for(std::size_t i = components.size(); i > 1; i--)
3747 {
3748 if(is_zero_width(components[i - 1].type(), ns))
3749 continue;
3750 else if(i > 2 || !is_zero_width(components[0].type(), ns))
3751 {
3752 ++n_concat;
3753 out << "(concat ";
3754 }
3755
3756 convert_operand(expr.operands()[i - 1]);
3757
3758 out << " ";
3759 }
3760
3761 if(!is_zero_width(components[0].type(), ns))
3762 convert_operand(expr.op0());
3763
3764 out << std::string(n_concat, ')');
3765 }
3766}
3767
3770{
3771 const array_typet &array_type = to_array_type(expr.type());
3772 const auto &size_expr = array_type.size();
3773 // Flattening an array to a bit-vector requires a concrete size. Arrays of
3774 // unknown or non-constant size (e.g. those indexed by a mathematical
3775 // integer) can only be encoded with the SMT-LIB array theory, not
3776 // bit-blasted; report that clearly rather than aborting an invariant.
3777 if(!size_expr.is_constant())
3778 {
3780 "cannot flatten an array of non-constant size to a bit-vector; such an "
3781 "array can only be encoded with the SMT-LIB array theory");
3782 }
3783
3785 CHECK_RETURN_WITH_DIAGNOSTICS(size != 0, "can't convert zero-sized array");
3786
3787 out << "(let ((?far ";
3788 convert_expr(expr);
3789 out << ")) ";
3790
3791 for(mp_integer i=size; i!=0; --i)
3792 {
3793 if(i!=1)
3794 out << "(concat ";
3795 out << "(select ?far ";
3796 convert_expr(from_integer(i - 1, array_type.index_type()));
3797 out << ")";
3798 if(i!=1)
3799 out << " ";
3800 }
3801
3802 // close the many parentheses
3803 for(mp_integer i=size; i>1; --i)
3804 out << ")";
3805
3806 out << ")"; // let
3807}
3808
3810{
3811 const exprt &op=expr.op();
3812
3813 std::size_t total_width = boolbv_width(expr.type());
3814
3815 std::size_t member_width=boolbv_width(op.type());
3816
3817 if(total_width==member_width)
3818 {
3819 flatten2bv(op);
3820 }
3821 else
3822 {
3823 // we will pad with zeros, but non-det would be better
3824 INVARIANT(
3825 total_width > member_width,
3826 "total_width should be greater than member_width as member_width can be"
3827 "at most as large as total_width and the other case has been handled "
3828 "above");
3829 out << "(concat ";
3830 out << "(_ bv0 "
3831 << (total_width-member_width) << ") ";
3832 flatten2bv(op);
3833 out << ")";
3834 }
3835}
3836
3838{
3839 const typet &expr_type=expr.type();
3840
3841 if(expr_type.id()==ID_unsignedbv ||
3842 expr_type.id()==ID_signedbv ||
3843 expr_type.id()==ID_bv ||
3844 expr_type.id()==ID_c_enum ||
3845 expr_type.id()==ID_c_enum_tag ||
3846 expr_type.id()==ID_c_bool ||
3848 {
3849 const std::size_t width = boolbv_width(expr_type);
3850
3851 const mp_integer value = bvrep2integer(expr.get_value(), width, false);
3852
3853 out << "(_ bv" << value
3854 << " " << width << ")";
3855 }
3856 else if(expr_type.id()==ID_fixedbv)
3857 {
3859
3860 const mp_integer v = bvrep2integer(expr.get_value(), spec.width, false);
3861
3862 out << "(_ bv" << v << " " << spec.width << ")";
3863 }
3864 else if(expr_type.id()==ID_floatbv)
3865 {
3868
3869 if(use_FPA_theory)
3870 {
3871 /* CBMC stores floating point literals in the most
3872 computationally useful form; biased exponents and
3873 significands including the hidden bit. Thus some encoding
3874 is needed to get to IEEE-754 style representations. */
3875
3877 size_t e=floatbv_type.get_e();
3878 size_t f=floatbv_type.get_f()+1;
3879
3880 /* Should be sufficient, but not currently supported by mathsat */
3881 #if 0
3882 mp_integer binary = v.pack();
3883
3884 out << "((_ to_fp " << e << " " << f << ")"
3885 << " #b" << integer2binary(v.pack(), v.spec.width()) << ")";
3886 #endif
3887
3888 if(v.is_NaN())
3889 {
3890 out << "(_ NaN " << e << " " << f << ")";
3891 }
3892 else if(v.is_infinity())
3893 {
3894 if(v.get_sign())
3895 out << "(_ -oo " << e << " " << f << ")";
3896 else
3897 out << "(_ +oo " << e << " " << f << ")";
3898 }
3899 else
3900 {
3901 // Zero, normal or subnormal
3902
3903 mp_integer binary = v.pack();
3904 std::string binaryString(integer2binary(v.pack(), v.spec.width()));
3905
3906 out << "(fp "
3907 << "#b" << binaryString.substr(0, 1) << " "
3908 << "#b" << binaryString.substr(1, e) << " "
3909 << "#b" << binaryString.substr(1+e, f-1) << ")";
3910 }
3911 }
3912 else
3913 {
3914 // produce corresponding bit-vector
3915 const ieee_float_spect spec(floatbv_type);
3916 const mp_integer v = bvrep2integer(expr.get_value(), spec.width(), false);
3917 out << "(_ bv" << v << " " << spec.width() << ")";
3918 }
3919 }
3920 else if(expr_type.id()==ID_pointer)
3921 {
3922 if(expr.is_null_pointer())
3923 {
3924 out << "(_ bv0 " << boolbv_width(expr_type)
3925 << ")";
3926 }
3927 else
3928 {
3929 // just treat the pointer as a bit vector
3930 const std::size_t width = boolbv_width(expr_type);
3931
3932 const mp_integer value = bvrep2integer(expr.get_value(), width, false);
3933
3934 out << "(_ bv" << value << " " << width << ")";
3935 }
3936 }
3937 else if(expr_type.id()==ID_bool)
3938 {
3939 if(expr == true)
3940 out << "true";
3941 else if(expr == false)
3942 out << "false";
3943 else
3944 UNEXPECTEDCASE("unknown Boolean constant");
3945 }
3946 else if(expr_type.id()==ID_array)
3947 {
3948 defined_expressionst::const_iterator it=defined_expressions.find(expr);
3949 CHECK_RETURN(it != defined_expressions.end());
3950 out << it->second;
3951 }
3952 else if(expr_type.id()==ID_rational)
3953 {
3954 std::string value=id2string(expr.get_value());
3955 const bool negative = has_prefix(value, "-");
3956
3957 if(negative)
3958 {
3959 out << "(- ";
3960 value = value.substr(1);
3961 }
3962
3963 size_t pos=value.find("/");
3964
3965 if(pos==std::string::npos)
3966 out << value << ".0";
3967 else
3968 {
3969 out << "(/ " << value.substr(0, pos) << ".0 "
3970 << value.substr(pos+1) << ".0)";
3971 }
3972
3973 if(negative)
3974 out << ')';
3975 }
3976 else if(expr_type.id() == ID_real)
3977 {
3978 const std::string &value = id2string(expr.get_value());
3979 out << value;
3980 if(value.find('.') == std::string::npos)
3981 out << ".0";
3982 }
3983 else if(expr_type.id()==ID_integer)
3984 {
3985 const auto value = id2string(expr.get_value());
3986
3987 // SMT2 has no negative integer literals
3988 if(has_prefix(value, "-"))
3989 out << "(- " << value.substr(1, std::string::npos) << ')';
3990 else
3991 out << value;
3992 }
3993 else if(expr_type.id() == ID_natural)
3994 {
3995 out << expr.get_value();
3996 }
3997 else if(expr_type.id() == ID_range)
3998 {
4000 const auto width = address_bits(range_type.size());
4001 const auto value_int = numeric_cast_v<mp_integer>(expr);
4002 out << "(_ bv" << (value_int - range_type.from()) << " " << width << ")";
4003 }
4004 else if(expr_type.id() == ID_string)
4005 {
4006 // SMT-LIB 2.6 string literal. The only in-string escape is "" for a double
4007 // quote (backslash is literal). Only printable ASCII may appear verbatim;
4008 // control and non-ASCII bytes are encoded with the \u{...} hex escape.
4009 const std::string &value = id2string(expr.get_value());
4010 out << '"';
4011 for(char ch : value)
4012 {
4013 const auto c = static_cast<unsigned char>(ch);
4014 if(c == '"')
4015 out << "\"\"";
4016 else if(c >= 0x20 && c <= 0x7e)
4017 out << ch;
4018 else
4019 out << "\\u{" << std::hex << static_cast<unsigned>(c) << std::dec
4020 << '}';
4021 }
4022 out << '"';
4023 }
4024 else
4025 UNEXPECTEDCASE("unknown constant: "+expr_type.id_string());
4026}
4027
4029{
4030 if(expr.type().id() == ID_integer)
4031 {
4032 out << "(mod ";
4033 convert_expr(expr.op0());
4034 out << ' ';
4035 convert_expr(expr.op1());
4036 out << ')';
4037 }
4038 else
4040 "unsupported type for euclidean_mod: " + expr.type().id_string());
4041}
4042
4044{
4045 if(expr.type().id()==ID_unsignedbv ||
4046 expr.type().id()==ID_signedbv)
4047 {
4048 if(expr.type().id()==ID_unsignedbv)
4049 out << "(bvurem ";
4050 else
4051 out << "(bvsrem ";
4052
4053 convert_expr(expr.op0());
4054 out << " ";
4055 convert_expr(expr.op1());
4056 out << ")";
4057 }
4058 else if(expr.type().id() == ID_integer)
4059 {
4060 // Mathematical integers (mp_integer) truncate toward zero, so the
4061 // remainder takes the sign of the dividend; SMT-LIB mod is always
4062 // non-negative. Take the remainder of the magnitudes and re-apply the
4063 // dividend's sign.
4064 out << "(let ((?ma ";
4065 convert_expr(expr.op0());
4066 out << ") (?mb ";
4067 convert_expr(expr.op1());
4068 out << ")) (let ((?mr (mod (ite (< ?ma 0) (- ?ma) ?ma)";
4069 out << " (ite (< ?mb 0) (- ?mb) ?mb)))) (ite (< ?ma 0) (- ?mr) ?mr)))";
4070 }
4071 else if(expr.type().id() == ID_natural)
4072 {
4073 // Naturals are non-negative, so SMT-LIB mod already matches mp_integer.
4074 out << "(mod ";
4075 convert_expr(expr.op0());
4076 out << " ";
4077 convert_expr(expr.op1());
4078 out << ")";
4079 }
4080 else
4081 UNEXPECTEDCASE("unsupported type for mod: "+expr.type().id_string());
4082}
4083
4085{
4086 std::vector<mp_integer> dynamic_objects;
4088
4089 if(dynamic_objects.empty())
4090 out << "false";
4091 else
4092 {
4093 std::size_t pointer_width = boolbv_width(expr.op().type());
4094
4095 out << "(let ((?obj ((_ extract "
4096 << pointer_width-1 << " "
4097 << pointer_width-config.bv_encoding.object_bits << ") ";
4098 convert_expr(expr.op());
4099 out << "))) ";
4100
4101 if(dynamic_objects.size()==1)
4102 {
4103 out << "(= (_ bv" << dynamic_objects.front()
4104 << " " << config.bv_encoding.object_bits << ") ?obj)";
4105 }
4106 else
4107 {
4108 out << "(or";
4109
4110 for(const auto &object : dynamic_objects)
4111 out << " (= (_ bv" << object
4112 << " " << config.bv_encoding.object_bits << ") ?obj)";
4113
4114 out << ")"; // or
4115 }
4116
4117 out << ")"; // let
4118 }
4119}
4120
4122{
4123 const typet &op_type=expr.op0().type();
4124
4125 if(
4126 op_type.id() == ID_unsignedbv || op_type.id() == ID_bv ||
4127 op_type.id() == ID_range)
4128 {
4129 // The range type is encoded in binary
4130 out << "(";
4131 if(expr.id()==ID_le)
4132 out << "bvule";
4133 else if(expr.id()==ID_lt)
4134 out << "bvult";
4135 else if(expr.id()==ID_ge)
4136 out << "bvuge";
4137 else if(expr.id()==ID_gt)
4138 out << "bvugt";
4139
4140 out << " ";
4141 convert_expr(expr.op0());
4142 out << " ";
4143 convert_expr(expr.op1());
4144 out << ")";
4145 }
4146 else if(op_type.id()==ID_signedbv ||
4147 op_type.id()==ID_fixedbv)
4148 {
4149 out << "(";
4150 if(expr.id()==ID_le)
4151 out << "bvsle";
4152 else if(expr.id()==ID_lt)
4153 out << "bvslt";
4154 else if(expr.id()==ID_ge)
4155 out << "bvsge";
4156 else if(expr.id()==ID_gt)
4157 out << "bvsgt";
4158
4159 out << " ";
4160 convert_expr(expr.op0());
4161 out << " ";
4162 convert_expr(expr.op1());
4163 out << ")";
4164 }
4165 else if(op_type.id()==ID_floatbv)
4166 {
4167 if(use_FPA_theory)
4168 {
4169 out << "(";
4170 if(expr.id()==ID_le)
4171 out << "fp.leq";
4172 else if(expr.id()==ID_lt)
4173 out << "fp.lt";
4174 else if(expr.id()==ID_ge)
4175 out << "fp.geq";
4176 else if(expr.id()==ID_gt)
4177 out << "fp.gt";
4178
4179 out << " ";
4180 convert_expr(expr.op0());
4181 out << " ";
4182 convert_expr(expr.op1());
4183 out << ")";
4184 }
4185 else
4186 convert_floatbv(expr);
4187 }
4188 else if(
4189 op_type.id() == ID_rational || op_type.id() == ID_integer ||
4190 op_type.id() == ID_natural || op_type.id() == ID_real)
4191 {
4192 out << "(";
4193 out << expr.id();
4194
4195 out << " ";
4196 convert_expr(expr.op0());
4197 out << " ";
4198 convert_expr(expr.op1());
4199 out << ")";
4200 }
4201 else if(op_type.id() == ID_pointer)
4202 {
4203 const exprt same_object = ::same_object(expr.op0(), expr.op1());
4204
4205 out << "(and ";
4207
4208 out << " (";
4209 if(expr.id() == ID_le)
4210 out << "bvsle";
4211 else if(expr.id() == ID_lt)
4212 out << "bvslt";
4213 else if(expr.id() == ID_ge)
4214 out << "bvsge";
4215 else if(expr.id() == ID_gt)
4216 out << "bvsgt";
4217
4218 out << ' ';
4220 out << ' ';
4222 out << ')';
4223
4224 out << ')';
4225 }
4226 else
4228 "unsupported type for "+expr.id_string()+": "+op_type.id_string());
4229}
4230
4232{
4233 if(
4234 expr.type().id() == ID_rational || expr.type().id() == ID_integer ||
4235 expr.type().id() == ID_natural || expr.type().id() == ID_real)
4236 {
4237 // these are multi-ary in SMT-LIB2
4238 out << "(+";
4239
4240 for(const auto &op : expr.operands())
4241 {
4242 out << ' ';
4243 convert_expr(op);
4244 }
4245
4246 out << ')';
4247 }
4248 else if(
4249 expr.type().id() == ID_unsignedbv || expr.type().id() == ID_signedbv ||
4250 expr.type().id() == ID_fixedbv)
4251 {
4252 // These could be chained, i.e., need not be binary,
4253 // but at least MathSat doesn't like that.
4254 if(expr.operands().size() == 2)
4255 {
4256 out << "(bvadd ";
4257 convert_expr(expr.op0());
4258 out << " ";
4259 convert_expr(expr.op1());
4260 out << ")";
4261 }
4262 else
4263 {
4265 }
4266 }
4267 else if(expr.type().id() == ID_range)
4268 {
4269 auto &range_type = to_integer_range_type(expr.type());
4270
4271 // These could be chained, i.e., need not be binary,
4272 // but at least MathSat doesn't like that.
4273 if(expr.operands().size() == 2)
4274 {
4275 // add: lhs + from + rhs + from - from = lhs + rhs + from
4276 const auto width = address_bits(range_type.size());
4277
4278 out << "(bvadd ";
4279 convert_expr(expr.op0());
4280 out << " (bvadd ";
4281 convert_expr(expr.op1());
4282 out << " (_ bv" << range_type.from() << ' ' << width
4283 << ")))"; // bv, bvadd, bvadd
4284 }
4285 else
4286 {
4288 }
4289 }
4290 else if(expr.type().id() == ID_floatbv)
4291 {
4292 // Floating-point additions should have be been converted
4293 // to ID_floatbv_plus during symbolic execution, adding
4294 // the rounding mode. See smt2_convt::convert_floatbv_plus.
4296 }
4297 else if(expr.type().id() == ID_pointer)
4298 {
4299 if(expr.operands().size() == 2)
4300 {
4301 exprt p = expr.op0(), i = expr.op1();
4302
4303 if(p.type().id() != ID_pointer)
4304 p.swap(i);
4305
4307 p.type().id() == ID_pointer,
4308 "one of the operands should have pointer type");
4309
4310 const auto &base_type = to_pointer_type(expr.type()).base_type();
4312 base_type.id() != ID_empty, "no pointer arithmetic over void pointers");
4313
4314 auto element_size_opt = pointer_offset_size(base_type, ns);
4315 CHECK_RETURN(element_size_opt.has_value() && *element_size_opt >= 0);
4317
4318 // First convert the pointer operand
4319 out << "(let ((?pointerop ";
4320 convert_expr(p);
4321 out << ")) ";
4322
4323 // The addition is done on the offset part only.
4324 const std::size_t pointer_width = boolbv_width(p.type());
4325 const std::size_t offset_bits =
4326 pointer_width - config.bv_encoding.object_bits;
4327
4328 out << "(concat ";
4329 out << "((_ extract " << pointer_width - 1 << ' ' << offset_bits
4330 << ") ?pointerop) ";
4331 out << "(bvadd ((_ extract " << offset_bits - 1 << " 0) ?pointerop) ";
4332
4333 if(element_size >= 2)
4334 {
4335 out << "(bvmul ((_ extract " << offset_bits - 1 << " 0) ";
4336 convert_expr(i);
4337 out << ") (_ bv" << element_size << " " << offset_bits << "))";
4338 }
4339 else
4340 {
4341 out << "((_ extract " << offset_bits - 1 << " 0) ";
4342 convert_expr(i);
4343 out << ')'; // extract
4344 }
4345
4346 out << ")))"; // bvadd, concat, let
4347 }
4348 else
4349 {
4351 }
4352 }
4353 else
4354 UNEXPECTEDCASE("unsupported type for +: " + expr.type().id_string());
4355}
4356
4361{
4363
4364 /* CProver uses the x86 numbering of the rounding-mode
4365 * 0 == FE_TONEAREST
4366 * 1 == FE_DOWNWARD
4367 * 2 == FE_UPWARD
4368 * 3 == FE_TOWARDZERO
4369 * These literal values must be used rather than the macros
4370 * the macros from fenv.h to avoid portability problems.
4371 */
4372
4373 if(expr.is_constant())
4374 {
4376
4378
4379 if(value==0)
4380 out << "roundNearestTiesToEven";
4381 else if(value==1)
4382 out << "roundTowardNegative";
4383 else if(value==2)
4384 out << "roundTowardPositive";
4385 else if(value==3)
4386 out << "roundTowardZero";
4387 else if(value == 4)
4388 out << "roundNearestTiesToAway";
4389 else
4391 false,
4392 "Rounding mode should have value 0, 1, 2, 3, or 4",
4393 id2string(cexpr.get_value()));
4394 }
4395 else
4396 {
4397 std::size_t width=to_bitvector_type(expr.type()).get_width();
4398
4399 // Need to make the choice above part of the model
4400 out << "(ite (= (_ bv0 " << width << ") ";
4401 convert_expr(expr);
4402 out << ") roundNearestTiesToEven ";
4403
4404 out << "(ite (= (_ bv1 " << width << ") ";
4405 convert_expr(expr);
4406 out << ") roundTowardNegative ";
4407
4408 out << "(ite (= (_ bv2 " << width << ") ";
4409 convert_expr(expr);
4410 out << ") roundTowardPositive ";
4411
4412 out << "(ite (= (_ bv3 " << width << ") ";
4413 convert_expr(expr);
4414 out << ") roundTowardZero ";
4415
4416 // TODO: add some kind of error checking here
4417 out << "roundNearestTiesToAway";
4418
4419 out << "))))";
4420 }
4421}
4422
4424{
4425 const typet &type=expr.type();
4426
4428 type.id() == ID_floatbv ||
4429 (type.id() == ID_complex &&
4430 to_complex_type(type).subtype().id() == ID_floatbv));
4431
4432 if(use_FPA_theory)
4433 {
4434 if(type.id()==ID_floatbv)
4435 {
4436 out << "(fp.add ";
4438 out << " ";
4439 convert_expr(expr.lhs());
4440 out << " ";
4441 convert_expr(expr.rhs());
4442 out << ")";
4443 }
4444 else if(type.id()==ID_complex)
4445 {
4446 SMT2_TODO("+ for floatbv complex");
4447 }
4448 else
4450 false,
4451 "type should not be one of the unsupported types",
4452 type.id_string());
4453 }
4454 else
4455 convert_floatbv(expr);
4456}
4457
4459{
4460 if(
4461 expr.type().id() == ID_integer || expr.type().id() == ID_natural ||
4462 expr.type().id() == ID_rational || expr.type().id() == ID_real)
4463 {
4464 out << "(- ";
4465 convert_expr(expr.op0());
4466 out << " ";
4467 convert_expr(expr.op1());
4468 out << ")";
4469 }
4470 else if(expr.type().id()==ID_unsignedbv ||
4471 expr.type().id()==ID_signedbv ||
4472 expr.type().id()==ID_fixedbv)
4473 {
4474 if(expr.op0().type().id()==ID_pointer &&
4475 expr.op1().type().id()==ID_pointer)
4476 {
4477 // Pointer difference
4478 const auto &base_type = to_pointer_type(expr.op0().type()).base_type();
4480 base_type.id() != ID_empty, "no pointer arithmetic over void pointers");
4481 auto element_size_opt = pointer_offset_size(base_type, ns);
4482 CHECK_RETURN(element_size_opt.has_value() && *element_size_opt >= 1);
4484
4485 if(element_size >= 2)
4486 out << "(bvsdiv ";
4487
4488 INVARIANT(
4489 boolbv_width(expr.op0().type()) == boolbv_width(expr.type()),
4490 "bitvector width of operand shall be equal to the bitvector width of "
4491 "the expression");
4492
4493 out << "(bvsub ";
4494 convert_expr(expr.op0());
4495 out << " ";
4496 convert_expr(expr.op1());
4497 out << ")";
4498
4499 if(element_size >= 2)
4500 out << " (_ bv" << element_size << " " << boolbv_width(expr.type())
4501 << "))";
4502 }
4503 else
4504 {
4505 out << "(bvsub ";
4506 convert_expr(expr.op0());
4507 out << " ";
4508 convert_expr(expr.op1());
4509 out << ")";
4510 }
4511 }
4512 else if(expr.type().id()==ID_floatbv)
4513 {
4514 // Floating-point subtraction should have be been converted
4515 // to ID_floatbv_minus during symbolic execution, adding
4516 // the rounding mode. See smt2_convt::convert_floatbv_minus.
4518 }
4519 else if(expr.type().id()==ID_pointer)
4520 {
4521 if(
4522 expr.op0().type().id() == ID_pointer &&
4523 (expr.op1().type().id() == ID_unsignedbv ||
4524 expr.op1().type().id() == ID_signedbv))
4525 {
4526 // rewrite p-o to p+(-o)
4527 return convert_plus(
4528 plus_exprt(expr.op0(), unary_minus_exprt(expr.op1())));
4529 }
4530 else
4532 "unsupported operand types for -: " + expr.op0().type().id_string() +
4533 " and " + expr.op1().type().id_string());
4534 }
4535 else if(expr.type().id() == ID_range)
4536 {
4537 auto &range_type = to_integer_range_type(expr.type());
4538
4539 // sub: lhs + from - (rhs + from) - from = lhs - rhs - from
4540 const auto width = address_bits(range_type.size());
4541
4542 out << "(bvsub (bvsub ";
4543 convert_expr(expr.op0());
4544 out << ' ';
4545 convert_expr(expr.op1());
4546 out << ") (_ bv" << range_type.from() << ' ' << width << "))"; // bv, bvsub
4547 }
4548 else
4549 UNEXPECTEDCASE("unsupported type for -: "+expr.type().id_string());
4550}
4551
4553{
4555 expr.type().id() == ID_floatbv,
4556 "type of ieee floating point expression shall be floatbv");
4557
4558 if(use_FPA_theory)
4559 {
4560 out << "(fp.sub ";
4562 out << " ";
4563 convert_expr(expr.lhs());
4564 out << " ";
4565 convert_expr(expr.rhs());
4566 out << ")";
4567 }
4568 else
4569 convert_floatbv(expr);
4570}
4571
4573{
4574 if(expr.type().id()==ID_unsignedbv ||
4575 expr.type().id()==ID_signedbv)
4576 {
4577 if(expr.type().id()==ID_unsignedbv)
4578 out << "(bvudiv ";
4579 else
4580 out << "(bvsdiv ";
4581
4582 convert_expr(expr.op0());
4583 out << " ";
4584 convert_expr(expr.op1());
4585 out << ")";
4586 }
4587 else if(expr.type().id()==ID_fixedbv)
4588 {
4589 fixedbv_spect spec(to_fixedbv_type(expr.type()));
4590 std::size_t fraction_bits=spec.get_fraction_bits();
4591
4592 out << "((_ extract " << spec.width-1 << " 0) ";
4593 out << "(bvsdiv ";
4594
4595 out << "(concat ";
4596 convert_expr(expr.op0());
4597 out << " (_ bv0 " << fraction_bits << ")) ";
4598
4599 out << "((_ sign_extend " << fraction_bits << ") ";
4600 convert_expr(expr.op1());
4601 out << ")";
4602
4603 out << "))";
4604 }
4605 else if(expr.type().id()==ID_floatbv)
4606 {
4607 // Floating-point division should have be been converted
4608 // to ID_floatbv_div during symbolic execution, adding
4609 // the rounding mode. See smt2_convt::convert_floatbv_div.
4611 }
4612 else if(
4613 expr.type().id() == ID_rational || expr.type().id() == ID_integer ||
4614 expr.type().id() == ID_natural || expr.type().id() == ID_real)
4615 {
4616 if(expr.type().id() == ID_integer)
4617 {
4618 // Mathematical integers (mp_integer) truncate division toward zero,
4619 // whereas SMT-LIB div floors. Encode truncation: divide the magnitudes
4620 // and make the quotient negative iff the operands have opposite signs.
4621 out << "(let ((?da ";
4622 convert_expr(expr.op0());
4623 out << ") (?db ";
4624 convert_expr(expr.op1());
4625 out << ")) (let ((?dq (div (ite (< ?da 0) (- ?da) ?da)";
4626 out << " (ite (< ?db 0) (- ?db) ?db))))";
4627 out << " (ite (= (< ?da 0) (< ?db 0)) ?dq (- ?dq))))";
4628 }
4629 else
4630 {
4631 // Naturals are non-negative (SMT-LIB div already truncates); rationals
4632 // and reals use real division.
4633 if(expr.type().id() == ID_natural)
4634 out << "(div ";
4635 else
4636 out << "(/ ";
4637 convert_expr(expr.op0());
4638 out << " ";
4639 convert_expr(expr.op1());
4640 out << ")";
4641 }
4642 }
4643 else
4644 UNEXPECTEDCASE("unsupported type for /: "+expr.type().id_string());
4645}
4646
4648{
4650 expr.type().id() == ID_floatbv,
4651 "type of ieee floating point expression shall be floatbv");
4652
4653 if(use_FPA_theory)
4654 {
4655 out << "(fp.div ";
4657 out << " ";
4658 convert_expr(expr.lhs());
4659 out << " ";
4660 convert_expr(expr.rhs());
4661 out << ")";
4662 }
4663 else
4664 convert_floatbv(expr);
4665}
4666
4668{
4669 // re-write to binary if needed
4670 if(expr.operands().size()>2)
4671 {
4672 // strip last operand
4673 exprt tmp=expr;
4674 tmp.operands().pop_back();
4675
4676 // recursive call
4677 return convert_mult(mult_exprt(tmp, expr.operands().back()));
4678 }
4679
4680 INVARIANT(
4681 expr.operands().size() == 2,
4682 "expression should have been converted to a variant with two operands");
4683
4684 if(expr.type().id()==ID_unsignedbv ||
4685 expr.type().id()==ID_signedbv)
4686 {
4687 // Note that bvmul is really unsigned,
4688 // but this is irrelevant as we chop-off any extra result
4689 // bits.
4690 out << "(bvmul ";
4691 convert_expr(expr.op0());
4692 out << " ";
4693 convert_expr(expr.op1());
4694 out << ")";
4695 }
4696 else if(expr.type().id()==ID_floatbv)
4697 {
4698 // Floating-point multiplication should have be been converted
4699 // to ID_floatbv_mult during symbolic execution, adding
4700 // the rounding mode. See smt2_convt::convert_floatbv_mult.
4702 }
4703 else if(expr.type().id()==ID_fixedbv)
4704 {
4705 fixedbv_spect spec(to_fixedbv_type(expr.type()));
4706 std::size_t fraction_bits=spec.get_fraction_bits();
4707
4708 out << "((_ extract "
4709 << spec.width+fraction_bits-1 << " "
4710 << fraction_bits << ") ";
4711
4712 out << "(bvmul ";
4713
4714 out << "((_ sign_extend " << fraction_bits << ") ";
4715 convert_expr(expr.op0());
4716 out << ") ";
4717
4718 out << "((_ sign_extend " << fraction_bits << ") ";
4719 convert_expr(expr.op1());
4720 out << ")";
4721
4722 out << "))"; // bvmul, extract
4723 }
4724 else if(
4725 expr.type().id() == ID_rational || expr.type().id() == ID_integer ||
4726 expr.type().id() == ID_natural || expr.type().id() == ID_real)
4727 {
4728 out << "(*";
4729
4730 for(const auto &op : expr.operands())
4731 {
4732 out << " ";
4733 convert_expr(op);
4734 }
4735
4736 out << ")";
4737 }
4738 else
4739 UNEXPECTEDCASE("unsupported type for *: "+expr.type().id_string());
4740}
4741
4743{
4745 expr.type().id() == ID_floatbv,
4746 "type of ieee floating point expression shall be floatbv");
4747
4748 if(use_FPA_theory)
4749 {
4750 out << "(fp.mul ";
4752 out << " ";
4753 convert_expr(expr.lhs());
4754 out << " ";
4755 convert_expr(expr.rhs());
4756 out << ")";
4757 }
4758 else
4759 convert_floatbv(expr);
4760}
4761
4763{
4765 expr.type().id() == ID_floatbv,
4766 "type of ieee floating point expression shall be floatbv");
4767
4768 if(use_FPA_theory)
4769 {
4770 // Note that these do not have a rounding mode
4771 out << "(fp.rem ";
4772 convert_expr(expr.lhs());
4773 out << " ";
4774 convert_expr(expr.rhs());
4775 out << ")";
4776 }
4777 else
4778 {
4779 SMT2_TODO(
4780 "smt2_convt::convert_floatbv_rem to be implemented when not using "
4781 "FPA_theory");
4782 }
4783}
4784
4786{
4788 expr.type().id() == ID_floatbv,
4789 "type of ieee floating point expression shall be floatbv");
4790
4791 if(use_FPA_theory)
4792 {
4793 out << "(fp.fma ";
4795 out << " ";
4797 out << " ";
4799 out << " ";
4800 convert_expr(expr.op_add());
4801 out << ")";
4802 }
4803 else
4804 convert_floatbv(expr);
4805}
4806
4808{
4809 INVARIANT(
4810 expr.operands().size() == 3,
4811 "with expression should have exactly three operands");
4812
4813 const typet &expr_type = expr.type();
4814
4815 if(expr_type.id()==ID_array)
4816 {
4818
4819 if(use_array_theory(expr))
4820 {
4821 out << "(store ";
4822 convert_expr(expr.old());
4823 out << " ";
4824 convert_expr(typecast_exprt(expr.where(), array_type.index_type()));
4825 out << " ";
4826 convert_expr(expr.new_value());
4827 out << ")";
4828 }
4829 else
4830 {
4831 // fixed-width
4832 std::size_t array_width=boolbv_width(array_type);
4833 std::size_t sub_width = boolbv_width(array_type.element_type());
4834 std::size_t index_width=boolbv_width(expr.where().type());
4835
4836 // We mask out the updated bits with AND,
4837 // and then OR-in the shifted new value.
4838
4839 out << "(let ((distance? ";
4840 out << "(bvmul (_ bv" << sub_width << " " << array_width << ") ";
4841
4842 // SMT2 says that the shift distance needs to be as wide
4843 // as the stuff we are shifting.
4845 {
4846 out << "((_ zero_extend " << array_width-index_width << ") ";
4847 convert_expr(expr.where());
4848 out << ")";
4849 }
4850 else
4851 {
4852 out << "((_ extract " << array_width-1 << " 0) ";
4853 convert_expr(expr.where());
4854 out << ")";
4855 }
4856
4857 out << "))) "; // bvmul, distance?
4858
4859 out << "(bvor ";
4860 out << "(bvand ";
4861 out << "(bvnot ";
4862 out << "(bvshl (_ bv" << power(2, sub_width) - 1 << " " << array_width
4863 << ") ";
4864 out << "distance?)) "; // bvnot, bvlshl
4865 convert_expr(expr.old());
4866 out << ") "; // bvand
4867 out << "(bvshl ";
4868 out << "((_ zero_extend " << array_width-sub_width << ") ";
4869 convert_expr(expr.new_value());
4870 out << ") distance?)))"; // zero_extend, bvshl, bvor, let
4871 }
4872 }
4873 else if(expr_type.id() == ID_struct || expr_type.id() == ID_struct_tag)
4874 {
4875 const struct_typet &struct_type =
4876 expr_type.id() == ID_struct_tag
4877 ? ns.follow_tag(to_struct_tag_type(expr_type))
4879
4880 const exprt &index = expr.where();
4881 const exprt &value = expr.new_value();
4882
4883 const irep_idt &component_name=index.get(ID_component_name);
4884
4885 INVARIANT(
4886 struct_type.has_component(component_name),
4887 "struct should have accessed component");
4888
4889 if(use_datatypes)
4890 {
4891 const std::string &smt_typename = datatype_map.at(expr_type);
4892
4893 out << "(update-" << smt_typename << "." << component_name << " ";
4894 convert_expr(expr.old());
4895 out << " ";
4896 convert_expr(value);
4897 out << ")";
4898 }
4899 else
4900 {
4901 auto convert_operand = [this](const exprt &op)
4902 {
4903 // may need to flatten array-theory arrays in there
4904 if(op.type().id() == ID_array && use_array_theory(op))
4905 flatten_array(op);
4906 else if(op.type().id() == ID_bool)
4907 flatten2bv(op);
4908 else
4909 convert_expr(op);
4910 };
4911
4913
4914 // figure out the offset and width of the member
4915 const boolbv_widtht::membert &m =
4916 boolbv_width.get_member(struct_type, component_name);
4917
4918 if(m.width==struct_width)
4919 {
4920 // the struct is the same as the member, no concat needed
4921 convert_operand(value);
4922 }
4923 else
4924 {
4925 out << "(let ((?withop ";
4926 convert_operand(expr.old());
4927 out << ")) ";
4928
4929 if(m.offset == 0)
4930 {
4931 // the member is at the beginning
4932 out << "(concat "
4933 << "((_ extract " << (struct_width - 1) << " " << m.width
4934 << ") ?withop) ";
4935 convert_operand(value);
4936 out << ")"; // concat
4937 }
4938 else if(m.offset + m.width == struct_width)
4939 {
4940 // the member is at the end
4941 out << "(concat ";
4942 convert_operand(value);
4943 out << " ((_ extract " << (m.offset - 1) << " 0) ?withop))";
4944 }
4945 else
4946 {
4947 // most general case, need two concat-s
4948 out << "(concat (concat "
4949 << "((_ extract " << (struct_width - 1) << " "
4950 << (m.offset + m.width) << ") ?withop) ";
4951 convert_operand(value);
4952 out << ") ((_ extract " << (m.offset - 1) << " 0) ?withop)";
4953 out << ")"; // concat
4954 }
4955
4956 out << ")"; // let ?withop
4957 }
4958 }
4959 }
4960 else if(expr_type.id() == ID_union || expr_type.id() == ID_union_tag)
4961 {
4962 const exprt &value = expr.new_value();
4963
4964 std::size_t total_width = boolbv_width(expr_type);
4965
4966 std::size_t member_width=boolbv_width(value.type());
4967
4968 if(total_width==member_width)
4969 {
4970 flatten2bv(value);
4971 }
4972 else
4973 {
4974 INVARIANT(
4975 total_width > member_width,
4976 "total width should be greater than member_width as member_width is at "
4977 "most as large as total_width and the other case has been handled "
4978 "above");
4979 out << "(concat ";
4980 out << "((_ extract "
4981 << (total_width-1)
4982 << " " << member_width << ") ";
4983 convert_expr(expr.old());
4984 out << ") ";
4985 flatten2bv(value);
4986 out << ")";
4987 }
4988 }
4989 else if(expr_type.id()==ID_bv ||
4990 expr_type.id()==ID_unsignedbv ||
4991 expr_type.id()==ID_signedbv)
4992 {
4993 if(expr.new_value().type().id() == ID_bool)
4994 {
4996 update_bit_exprt(expr.old(), expr.where(), expr.new_value()));
4997 }
4998 else
4999 {
5001 update_bits_exprt(expr.old(), expr.where(), expr.new_value()));
5002 }
5003 }
5004 else
5006 "with expects struct, union, or array type, but got "+
5007 expr.type().id_string());
5008}
5009
5011{
5012 PRECONDITION(expr.operands().size() == 3);
5013
5014 SMT2_TODO("smt2_convt::convert_update to be implemented");
5015}
5016
5018{
5019 return convert_expr(expr.lower());
5020}
5021
5023{
5024 return convert_expr(expr.lower());
5025}
5026
5028{
5029 const typet &array_op_type = expr.array().type();
5030
5031 if(array_op_type.id()==ID_array)
5032 {
5034
5035 if(use_array_theory(expr.array()))
5036 {
5037 if(expr.is_boolean() && !use_array_of_bool)
5038 {
5039 out << "(= ";
5040 out << "(select ";
5041 convert_expr(expr.array());
5042 out << " ";
5043 convert_expr(typecast_exprt(expr.index(), array_type.index_type()));
5044 out << ")";
5045 out << " #b1)";
5046 }
5047 else
5048 {
5049 out << "(select ";
5050 convert_expr(expr.array());
5051 out << " ";
5052 convert_expr(typecast_exprt(expr.index(), array_type.index_type()));
5053 out << ")";
5054 }
5055 }
5056 else
5057 {
5058 // fixed size
5059 std::size_t array_width=boolbv_width(array_type);
5060
5061 unflatten(wheret::BEGIN, array_type.element_type());
5062
5063 std::size_t sub_width = boolbv_width(array_type.element_type());
5064 std::size_t index_width=boolbv_width(expr.index().type());
5065
5066 out << "((_ extract " << sub_width-1 << " 0) ";
5067 out << "(bvlshr ";
5068 convert_expr(expr.array());
5069 out << " ";
5070 out << "(bvmul (_ bv" << sub_width << " " << array_width << ") ";
5071
5072 // SMT2 says that the shift distance must be the same as
5073 // the width of what we shift.
5075 {
5076 out << "((_ zero_extend " << array_width-index_width << ") ";
5077 convert_expr(expr.index());
5078 out << ")"; // zero_extend
5079 }
5080 else
5081 {
5082 out << "((_ extract " << array_width-1 << " 0) ";
5083 convert_expr(expr.index());
5084 out << ")"; // extract
5085 }
5086
5087 out << ")))"; // mult, bvlshr, extract
5088
5089 unflatten(wheret::END, array_type.element_type());
5090 }
5091 }
5092 else
5093 INVARIANT(
5094 false, "index with unsupported array type: " + array_op_type.id_string());
5095}
5096
5098{
5100 const exprt &struct_op=member_expr.struct_op();
5101 const typet &struct_op_type = struct_op.type();
5102 const irep_idt &name=member_expr.get_component_name();
5103
5105 {
5106 const struct_typet &struct_type =
5108 ? ns.follow_tag(to_struct_tag_type(struct_op_type))
5110
5111 INVARIANT(
5112 struct_type.has_component(name), "struct should have accessed component");
5113
5114 if(use_datatypes)
5115 {
5116 const std::string &smt_typename = datatype_map.at(struct_type);
5117
5118 out << "(" << smt_typename << "."
5119 << struct_type.get_component(name).get_name()
5120 << " ";
5121 convert_expr(struct_op);
5122 out << ")";
5123 }
5124 else
5125 {
5126 // we extract
5127 const auto &member_offset = boolbv_width.get_member(struct_type, name);
5128
5129 if(expr.type().id() == ID_bool)
5130 out << "(= ";
5131 out << "((_ extract " << (member_offset.offset + member_offset.width - 1)
5132 << " " << member_offset.offset << ") ";
5133 convert_expr(struct_op);
5134 out << ")";
5135 if(expr.type().id() == ID_bool)
5136 out << " #b1)";
5137 }
5138 }
5139 else if(
5141 {
5142 std::size_t width=boolbv_width(expr.type());
5144 width != 0, "failed to get union member width");
5145
5146 if(use_datatypes)
5147 {
5148 unflatten(wheret::BEGIN, expr.type());
5149
5150 out << "((_ extract " << (width - 1) << " 0) ";
5151 convert_expr(struct_op);
5152 out << ")";
5153
5154 unflatten(wheret::END, expr.type());
5155 }
5156 else
5157 {
5158 out << "((_ extract " << (width - 1) << " 0) ";
5159 convert_expr(struct_op);
5160 out << ")";
5161 }
5162 }
5163 else
5165 "convert_member on an unexpected type "+struct_op_type.id_string());
5166}
5167
5169{
5170 const typet &type = expr.type();
5171
5172 if(type.id()==ID_bool)
5173 {
5174 out << "(ite ";
5175 convert_expr(expr); // this returns a Bool
5176 out << " #b1 #b0)"; // this is a one-bit bit-vector
5177 }
5178 else if(type.id()==ID_array)
5179 {
5180 if(use_array_theory(expr))
5181 {
5182 // concatenate elements
5183 const array_typet &array_type = to_array_type(type);
5184
5185 mp_integer size =
5187
5188 // SMT-LIB 2 concat is binary only
5189 std::size_t n_concat = 0;
5190 for(mp_integer i = size; i > 1; --i)
5191 {
5192 ++n_concat;
5193 out << "(concat ";
5194
5195 flatten2bv(
5196 index_exprt{expr, from_integer(i - 1, array_type.index_type())});
5197
5198 out << " ";
5199 }
5200
5201 flatten2bv(index_exprt{expr, from_integer(0, array_type.index_type())});
5202
5203 out << std::string(n_concat, ')'); // concat
5204 }
5205 else
5206 convert_expr(expr);
5207 }
5208 else if(type.id() == ID_struct || type.id() == ID_struct_tag)
5209 {
5210 if(use_datatypes)
5211 {
5212 // concatenate elements
5213 const struct_typet &struct_type =
5214 type.id() == ID_struct_tag ? ns.follow_tag(to_struct_tag_type(type))
5215 : to_struct_type(type);
5216
5217 const struct_typet::componentst &components=
5218 struct_type.components();
5219
5220 // SMT-LIB 2 concat is binary only
5221 std::size_t n_concat = 0;
5222 for(std::size_t i=components.size(); i>1; i--)
5223 {
5224 if(is_zero_width(components[i - 1].type(), ns))
5225 continue;
5226 else if(i > 2 || !is_zero_width(components[0].type(), ns))
5227 {
5228 ++n_concat;
5229 out << "(concat ";
5230 }
5231
5232 flatten2bv(member_exprt{expr, components[i - 1]});
5233
5234 out << " ";
5235 }
5236
5237 if(!is_zero_width(components[0].type(), ns))
5238 {
5239 flatten2bv(member_exprt{expr, components[0]});
5240 }
5241
5242 out << std::string(n_concat, ')'); // concat
5243 }
5244 else
5245 convert_expr(expr);
5246 }
5247 else if(type.id()==ID_floatbv)
5248 {
5249 if(use_FPA_theory)
5250 {
5251 // A floatbv constant's IEEE-754 interchange bit pattern is exactly its
5252 // bit-vector representation, so it is emitted as a literal bit-vector.
5253 // This is the only shape that reaches flatten2bv under FPA: a
5254 // non-constant float whose bits are read is lowered by
5255 // lower_byte_operators into a float typecast, which is handled by the
5256 // bvfromfloat round-trip in find_symbols and never reaches here.
5257 if(expr.is_constant())
5258 {
5259 const ieee_float_spect spec(to_floatbv_type(type));
5260 const mp_integer value = bvrep2integer(
5261 to_constant_expr(expr).get_value(), spec.width(), false);
5262 out << "(_ bv" << value << " " << spec.width() << ")";
5263 }
5264 else
5265 {
5267 "flatten2bv of a non-constant FPA-encoded float is unsupported");
5268 }
5269 }
5270 else
5271 convert_expr(expr);
5272 }
5273 else
5274 convert_expr(expr);
5275}
5276
5278 wheret where,
5279 const typet &type,
5280 unsigned nesting)
5281{
5282 if(type.id()==ID_bool)
5283 {
5284 if(where==wheret::BEGIN)
5285 out << "(= "; // produces a bool
5286 else
5287 out << " #b1)";
5288 }
5289 else if(type.id() == ID_array)
5290 {
5292
5293 if(where == wheret::BEGIN)
5294 out << "(let ((?ufop" << nesting << " ";
5295 else
5296 {
5297 out << ")) ";
5298
5299 const array_typet &array_type = to_array_type(type);
5300
5301 std::size_t subtype_width = boolbv_width(array_type.element_type());
5302
5304 array_type.size().is_constant(),
5305 "cannot unflatten arrays of non-constant size");
5306 mp_integer size =
5308
5309 for(mp_integer i = 1; i < size; ++i)
5310 out << "(store ";
5311
5312 // Build a constant array filled with element 0 as the base, then
5313 // overwrite indices 1..N-1 via (store ...).
5314 if(use_as_const)
5315 {
5316 out << "((as const ";
5318 out << ") ";
5319 }
5320 else
5321 {
5322 INVARIANT(
5324 "unflatten relies on `(lambda ...)` for constant arrays "
5325 "when `(as const ...)` is unavailable");
5326 // Note: lambda is a Z3/Bitwuzla extension; not part of the
5327 // SMT-LIB 2.6 standard. The bound variable `?ufidx<n>` is
5328 // intentionally unused -- the body returns the element-0 value
5329 // regardless of its argument, making this semantically
5330 // equivalent to `(as const ...)`.
5331 out << "(lambda ((?ufidx" << nesting << " ";
5332 convert_type(array_type.index_type());
5333 out << ")) ";
5334 }
5335 // use element at index 0 as default value
5336 unflatten(wheret::BEGIN, array_type.element_type(), nesting + 1);
5337 out << "((_ extract " << subtype_width - 1 << " "
5338 << "0) ?ufop" << nesting << ")";
5339 unflatten(wheret::END, array_type.element_type(), nesting + 1);
5340 out << ") ";
5341
5342 std::size_t offset = subtype_width;
5343 for(mp_integer i = 1; i < size; ++i, offset += subtype_width)
5344 {
5345 convert_expr(from_integer(i, array_type.index_type()));
5346 out << ' ';
5347 unflatten(wheret::BEGIN, array_type.element_type(), nesting + 1);
5348 out << "((_ extract " << offset + subtype_width - 1 << " " << offset
5349 << ") ?ufop" << nesting << ")";
5350 unflatten(wheret::END, array_type.element_type(), nesting + 1);
5351 out << ")"; // store
5352 }
5353
5354 out << ")"; // let
5355 }
5356 }
5357 else if(type.id() == ID_struct || type.id() == ID_struct_tag)
5358 {
5359 if(use_datatypes)
5360 {
5361 // extract members
5362 if(where==wheret::BEGIN)
5363 out << "(let ((?ufop" << nesting << " ";
5364 else
5365 {
5366 out << ")) ";
5367
5368 const std::string &smt_typename = datatype_map.at(type);
5369
5370 out << "(mk-" << smt_typename;
5371
5372 const struct_typet &struct_type =
5373 type.id() == ID_struct_tag ? ns.follow_tag(to_struct_tag_type(type))
5374 : to_struct_type(type);
5375
5376 const struct_typet::componentst &components=
5377 struct_type.components();
5378
5379 std::size_t offset=0;
5380
5381 for(struct_typet::componentst::const_iterator it = components.begin();
5382 it != components.end();
5383 it++)
5384 {
5385 if(is_zero_width(it->type(), ns))
5386 continue;
5387
5388 std::size_t member_width=boolbv_width(it->type());
5389
5390 out << " ";
5391 unflatten(wheret::BEGIN, it->type(), nesting+1);
5392 out << "((_ extract " << offset+member_width-1 << " "
5393 << offset << ") ?ufop" << nesting << ")";
5394 unflatten(wheret::END, it->type(), nesting+1);
5395 offset+=member_width;
5396 }
5397
5398 out << "))"; // mk-, let
5399 }
5400 }
5401 else
5402 {
5403 // nop, already a bv
5404 }
5405 }
5406 else
5407 {
5408 // nop
5409 }
5410}
5411
5412void smt2_convt::set_to(const exprt &expr, bool value)
5413{
5414 PRECONDITION(expr.is_boolean());
5415
5416 if(expr.id()==ID_and && value)
5417 {
5418 for(const auto &op : expr.operands())
5419 set_to(op, true);
5420 return;
5421 }
5422
5423 if(expr.id()==ID_or && !value)
5424 {
5425 for(const auto &op : expr.operands())
5426 set_to(op, false);
5427 return;
5428 }
5429
5430 if(expr.id()==ID_not)
5431 {
5432 return set_to(to_not_expr(expr).op(), !value);
5433 }
5434
5435 out << "\n";
5436
5437 // special treatment for "set_to(a=b, true)" where
5438 // a is a new symbol
5439
5440 if(expr.id() == ID_equal && value)
5441 {
5443 if(is_zero_width(equal_expr.lhs().type(), ns))
5444 {
5445 // ignore equality checking over expressions with empty (void) type
5446 return;
5447 }
5448
5449 if(equal_expr.lhs().id()==ID_symbol)
5450 {
5451 const irep_idt &identifier =
5452 to_symbol_expr(equal_expr.lhs()).identifier();
5453
5454 if(
5455 identifier_map.find(identifier) == identifier_map.end() &&
5456 equal_expr.lhs() != equal_expr.rhs())
5457 {
5458 auto id_entry = identifier_map.insert(
5459 {identifier, identifiert{equal_expr.lhs().type(), false}});
5460 CHECK_RETURN(id_entry.second);
5461
5462 find_symbols(id_entry.first->second.type);
5464
5465 std::string smt2_identifier=convert_identifier(identifier);
5467
5468 out << "; set_to true (equal)\n";
5469
5470 // Helper: emit the body of a definition for `smt2_identifier`
5471 // -- either a direct `convert_expr(prepared_rhs)` for non-array
5472 // or array-theory cases, or a `unflatten ... convert_expr ...
5473 // unflatten` reconstruction for array RHSes. Used twice below
5474 // to keep the `declare-fun + assert` and `define-fun` paths in
5475 // sync.
5476 auto emit_definition_body = [&]()
5477 {
5478 if(
5479 equal_expr.lhs().type().id() != ID_array ||
5481 {
5483 }
5484 else
5485 {
5486 unflatten(wheret::BEGIN, equal_expr.lhs().type());
5488 unflatten(wheret::END, equal_expr.lhs().type());
5489 }
5490 };
5491
5492 if(equal_expr.lhs().type().id() == ID_mathematical_function)
5493 {
5494 // We avoid define-fun, since it has been reported to cause
5495 // trouble with Z3's parser.
5496 out << "(declare-fun " << smt2_identifier;
5497
5500
5501 out << " (";
5502 bool first = true;
5503
5504 for(auto &t : mathematical_function_type.domain())
5505 {
5506 if(first)
5507 first = false;
5508 else
5509 out << ' ';
5510
5511 convert_type(t);
5512 }
5513
5514 out << ") ";
5516 out << ")\n";
5517
5518 out << "(assert (= " << smt2_identifier << ' ';
5520 out << ')' << ')' << '\n';
5521 }
5522 else if(use_lambda_for_array)
5523 {
5524 // The body emitted below may contain a `(lambda ...)` from
5525 // `unflatten` (used as a stand-in for `(as const ...)` for
5526 // back-ends with `use_as_const = false`). Z3 rejects
5527 // `get-value` on symbols whose `define-fun` body contains
5528 // a lambda, so we use `declare-fun` + `assert (= ...)` here.
5529 // Back-ends with `use_lambda_for_array = false` (the
5530 // default, currently every back-end other than Z3) keep
5531 // using the `define-fun` form below, so their SMT2 output
5532 // is unaffected.
5533 out << "(declare-fun " << smt2_identifier;
5534 out << " () ";
5535 convert_type(equal_expr.lhs().type());
5536 out << ")\n";
5537 out << "(assert (= " << smt2_identifier << ' ';
5539 out << "))\n";
5540 }
5541 else
5542 {
5543 out << "(define-fun " << smt2_identifier;
5544 out << " () ";
5545 convert_type(equal_expr.lhs().type());
5546 out << ' ';
5548 out << ')' << '\n';
5549 }
5550
5551 return; // done
5552 }
5553 }
5554 }
5555
5557
5558#if 0
5559 out << "; CONV: "
5560 << format(expr) << "\n";
5561#endif
5562
5563 out << "; set_to " << (value?"true":"false") << "\n"
5564 << "(assert ";
5565 if(!value)
5566 {
5567 out << "(not ";
5568 }
5569 const auto found_literal = defined_expressions.find(expr);
5570 if(!(found_literal == defined_expressions.end()))
5571 {
5572 // This is a converted expression, we can just assert the literal name
5573 // since the expression is already defined
5574 out << found_literal->second;
5575 set_values[found_literal->second] = value;
5576 }
5577 else
5578 {
5580 }
5581 if(!value)
5582 {
5583 out << ")";
5584 }
5585 out << ")\n";
5586 return;
5587}
5588
5596{
5597 exprt lowered_expr = expr;
5598
5599 for(auto it = lowered_expr.depth_begin(), itend = lowered_expr.depth_end();
5600 it != itend;
5601 ++it)
5602 {
5603 if(
5604 it->id() == ID_byte_extract_little_endian ||
5605 it->id() == ID_byte_extract_big_endian)
5606 {
5607 it.mutate() = lower_byte_extract(to_byte_extract_expr(*it), ns);
5608 }
5609 else if(
5610 it->id() == ID_byte_update_little_endian ||
5611 it->id() == ID_byte_update_big_endian)
5612 {
5613 it.mutate() = lower_byte_update(to_byte_update_expr(*it), ns);
5614 }
5615 }
5616
5617 return lowered_expr;
5618}
5619
5628{
5629 // First, replace byte operators, because they may introduce new array
5630 // expressions that must be seen by find_symbols:
5632 INVARIANT(
5634 "lower_byte_operators should remove all byte operators");
5635
5636 // Perform rewrites that may introduce new symbols
5637 for(auto it = lowered_expr.depth_begin(), itend = lowered_expr.depth_end();
5638 it != itend;) // no ++it
5639 {
5640 if(
5641 auto prophecy_r_or_w_ok =
5643 {
5645 it.mutate() = lowered;
5646 it.next_sibling_or_parent();
5647 }
5648 else if(
5651 {
5653 it.mutate() = lowered;
5654 it.next_sibling_or_parent();
5655 }
5656 else
5657 ++it;
5658 }
5659
5660 // Now create symbols for all composite expressions present in lowered_expr:
5662
5663 return lowered_expr;
5664}
5665
5676{
5677 if(is_zero_width(expr.type(), ns))
5678 return;
5679
5680 // recursive call on type
5681 find_symbols(expr.type());
5682
5683 if(expr.id() == ID_exists || expr.id() == ID_forall)
5684 {
5685 std::unordered_map<irep_idt, std::optional<identifiert>> shadowed_syms;
5686
5687 // do not declare the quantified symbol, but record
5688 // as 'bound symbol'
5689 const auto &q_expr = to_quantifier_expr(expr);
5690 for(const auto &symbol : q_expr.variables())
5691 {
5692 const auto identifier = symbol.identifier();
5693 auto id_entry =
5694 identifier_map.insert({identifier, identifiert{symbol.type(), true}});
5695 shadowed_syms.insert(
5696 {identifier,
5697 id_entry.second ? std::nullopt
5698 : std::optional{id_entry.first->second}});
5699 }
5700 find_symbols(q_expr.where());
5701 for(const auto &[id, shadowed_val] : shadowed_syms)
5702 {
5703 auto previous_entry = identifier_map.find(id);
5704 if(!shadowed_val.has_value())
5706 else
5707 previous_entry->second = std::move(*shadowed_val);
5708 }
5709 return;
5710 }
5711
5712 // recursive call on operands
5713 for(const auto &op : expr.operands())
5714 find_symbols(op);
5715
5716 if(expr.id()==ID_symbol ||
5717 expr.id()==ID_nondet_symbol)
5718 {
5719 // we don't track function-typed symbols
5720 if(expr.type().id()==ID_code)
5721 return;
5722
5723 irep_idt identifier;
5724
5725 if(expr.id()==ID_symbol)
5726 identifier = to_symbol_expr(expr).identifier();
5727 else
5728 identifier="nondet_"+
5729 id2string(to_nondet_symbol_expr(expr).get_identifier());
5730
5731 auto id_entry =
5732 identifier_map.insert({identifier, identifiert{expr.type(), false}});
5733
5734 if(id_entry.second)
5735 {
5736 std::string smt2_identifier=convert_identifier(identifier);
5738
5739 out << "; find_symbols\n";
5740 out << "(declare-fun " << smt2_identifier;
5741
5742 if(expr.type().id() == ID_mathematical_function)
5743 {
5746 out << " (";
5747 bool first = true;
5748
5749 for(auto &type : mathematical_function_type.domain())
5750 {
5751 if(first)
5752 first = false;
5753 else
5754 out << ' ';
5755 convert_type(type);
5756 }
5757
5758 out << ") ";
5760 }
5761 else
5762 {
5763 out << " () ";
5764 convert_type(expr.type());
5765 }
5766
5767 out << ')' << '\n';
5768
5769 // We need an additional constraint for range-typed symbols,
5770 // or otherwise we get satisfying assignments with values
5771 // outside of the range when the size of the range isn't
5772 // a power of two.
5773 if(expr.type().id() == ID_range)
5774 {
5775 auto &range_type = to_integer_range_type(expr.type());
5776 if(!is_power_of_two(range_type.size()))
5777 {
5778 out << "(assert (bvule " << smt2_identifier << ' ';
5780 out << "))\n"; // bvule, assert
5781 }
5782 }
5783 }
5784 }
5785 else if(expr.id() == ID_array_of)
5786 {
5787 if(!use_as_const)
5788 {
5789 if(defined_expressions.find(expr) == defined_expressions.end())
5790 {
5791 const auto &array_of = to_array_of_expr(expr);
5792 const auto &array_type = array_of.type();
5793
5794 const irep_idt id =
5795 "array_of." + std::to_string(defined_expressions.size());
5796 out << "; the following is a substitute for lambda i. x\n";
5797 out << "(declare-fun " << id << " () ";
5799 out << ")\n";
5800
5801 if(!is_zero_width(array_type.element_type(), ns))
5802 {
5803 // use a quantifier-based initialization instead of lambda
5804 out << "(assert (forall ((i ";
5805 convert_type(array_type.index_type());
5806 out << ")) (= (select " << id << " i) ";
5807 if(array_type.element_type().id() == ID_bool && !use_array_of_bool)
5808 {
5809 out << "(ite ";
5810 convert_expr(array_of.what());
5811 out << " #b1 #b0)";
5812 }
5813 else
5814 {
5815 convert_expr(array_of.what());
5816 }
5817 out << ")))\n";
5818 }
5819
5820 defined_expressions[expr] = id;
5821 }
5822 }
5823 }
5824 else if(expr.id() == ID_array_comprehension)
5825 {
5827 {
5828 if(defined_expressions.find(expr) == defined_expressions.end())
5829 {
5831 const auto &array_type = array_comprehension.type();
5832 const auto &array_size = array_type.size();
5833
5834 const irep_idt id =
5835 "array_comprehension." + std::to_string(defined_expressions.size());
5836 out << "(declare-fun " << id << " () ";
5838 out << ")\n";
5839
5840 out << "; the following is a substitute for lambda i . x(i)\n";
5841 out << "; universally quantified initialization of the array\n";
5842 out << "(assert (forall ((";
5844 out << " ";
5845 convert_type(array_size.type());
5846 out << ")) (=> (and (bvule (_ bv0 " << boolbv_width(array_size.type())
5847 << ") ";
5849 out << ") (bvult ";
5851 out << " ";
5853 out << ")) (= (select " << id << " ";
5855 out << ") ";
5856 if(array_type.element_type().id() == ID_bool && !use_array_of_bool)
5857 {
5858 out << "(ite ";
5860 out << " #b1 #b0)";
5861 }
5862 else
5863 {
5865 }
5866 out << "))))\n";
5867
5868 defined_expressions[expr] = id;
5869 }
5870 }
5871 }
5872 else if(expr.id()==ID_array)
5873 {
5874 if(defined_expressions.find(expr)==defined_expressions.end())
5875 {
5877
5878 const irep_idt id = "array." + std::to_string(defined_expressions.size());
5879 out << "; the following is a substitute for an array constructor" << "\n";
5880 out << "(declare-fun " << id << " () ";
5882 out << ")" << "\n";
5883
5884 if(!is_zero_width(array_type.element_type(), ns))
5885 {
5886 for(std::size_t i = 0; i < expr.operands().size(); i++)
5887 {
5888 out << "(assert (= (select " << id << " ";
5889 convert_expr(from_integer(i, array_type.index_type()));
5890 out << ") "; // select
5891 if(array_type.element_type().id() == ID_bool && !use_array_of_bool)
5892 {
5893 out << "(ite ";
5894 convert_expr(expr.operands()[i]);
5895 out << " #b1 #b0)";
5896 }
5897 else
5898 {
5899 convert_expr(expr.operands()[i]);
5900 }
5901 out << "))"
5902 << "\n"; // =, assert
5903 }
5904 }
5905
5906 defined_expressions[expr]=id;
5907 }
5908 }
5909 else if(expr.id()==ID_string_constant)
5910 {
5911 if(defined_expressions.find(expr)==defined_expressions.end())
5912 {
5913 // introduce a temporary array.
5914 exprt tmp=to_string_constant(expr).to_array_expr();
5915 const array_typet &array_type=to_array_type(tmp.type());
5916
5917 const irep_idt id =
5918 "string." + std::to_string(defined_expressions.size());
5919 out << "; the following is a substitute for a string" << "\n";
5920 out << "(declare-fun " << id << " () ";
5922 out << ")" << "\n";
5923
5924 for(std::size_t i=0; i<tmp.operands().size(); i++)
5925 {
5926 out << "(assert (= (select " << id << ' ';
5927 convert_expr(from_integer(i, array_type.index_type()));
5928 out << ") "; // select
5929 convert_expr(tmp.operands()[i]);
5930 out << "))" << "\n";
5931 }
5932
5933 defined_expressions[expr]=id;
5934 }
5935 }
5936 else if(
5938 {
5939 if(object_sizes.find(*object_size) == object_sizes.end())
5940 {
5941 const irep_idt id = convert_identifier(
5942 "object_size." + std::to_string(object_sizes.size()));
5943 out << "(declare-fun " << id << " () ";
5945 out << ")"
5946 << "\n";
5947
5949 }
5950 }
5951 // clang-format off
5952 else if(!use_FPA_theory &&
5953 expr.operands().size() >= 1 &&
5954 (expr.id() == ID_floatbv_plus ||
5955 expr.id() == ID_floatbv_minus ||
5956 expr.id() == ID_floatbv_mult ||
5957 expr.id() == ID_floatbv_div ||
5958 expr.id() == ID_floatbv_fma ||
5959 expr.id() == ID_floatbv_typecast ||
5960 expr.id() == ID_ieee_float_equal ||
5961 expr.id() == ID_ieee_float_notequal ||
5962 ((expr.id() == ID_lt ||
5963 expr.id() == ID_gt ||
5964 expr.id() == ID_le ||
5965 expr.id() == ID_ge ||
5966 expr.id() == ID_isnan ||
5967 expr.id() == ID_isnormal ||
5968 expr.id() == ID_isfinite ||
5969 expr.id() == ID_isinf ||
5970 expr.id() == ID_sign ||
5971 expr.id() == ID_unary_minus ||
5972 expr.id() == ID_typecast ||
5973 expr.id() == ID_abs) &&
5974 to_multi_ary_expr(expr).op0().type().id() == ID_floatbv)))
5975 // clang-format on
5976 {
5977 irep_idt function =
5978 convert_identifier("float_bv." + expr.id_string() + floatbv_suffix(expr));
5979
5980 if(bvfp_set.insert(function).second)
5981 {
5982 out << "; this is a model for " << expr.id() << " : "
5983 << type2id(to_multi_ary_expr(expr).op0().type()) << " -> "
5984 << type2id(expr.type()) << "\n"
5985 << "(define-fun " << function << " (";
5986
5987 for(std::size_t i = 0; i < expr.operands().size(); i++)
5988 {
5989 if(i!=0)
5990 out << " ";
5991 out << "(op" << i << ' ';
5992 convert_type(expr.operands()[i].type());
5993 out << ')';
5994 }
5995
5996 out << ") ";
5997 convert_type(expr.type()); // return type
5998 out << ' ';
5999
6000 exprt tmp1=expr;
6001 for(std::size_t i = 0; i < tmp1.operands().size(); i++)
6002 tmp1.operands()[i]=
6003 smt2_symbolt("op"+std::to_string(i), tmp1.operands()[i].type());
6004
6006 tmp2=letify(tmp2);
6007 CHECK_RETURN(!tmp2.is_nil());
6008
6010
6011 out << ")\n"; // define-fun
6012 }
6013 }
6014 else if(
6015 use_FPA_theory && expr.id() == ID_typecast &&
6016 to_typecast_expr(expr).op().type().id() == ID_floatbv &&
6017 expr.type().id() == ID_bv)
6018 {
6019 // This is _NOT_ a semantic conversion, but bit-wise.
6020 if(defined_expressions.find(expr) == defined_expressions.end())
6021 {
6022 // This conversion is non-trivial as it requires creating a
6023 // new bit-vector variable and then asserting that it converts
6024 // to the required floating-point number.
6025 const irep_idt id =
6026 "bvfromfloat." + std::to_string(defined_expressions.size());
6027 out << "(declare-fun " << id << " () ";
6028 convert_type(expr.type());
6029 out << ')' << '\n';
6030
6031 const typecast_exprt &tc = to_typecast_expr(expr);
6032 const auto &floatbv_type = to_floatbv_type(tc.op().type());
6033 out << "(assert (= ";
6034 out << "((_ to_fp " << floatbv_type.get_e() << " "
6035 << floatbv_type.get_f() + 1 << ") " << id << ')';
6036 convert_expr(tc.op());
6037 out << ')'; // =
6038 out << ')' << '\n';
6039
6040 defined_expressions[expr] = id;
6041 }
6042 }
6043 else if(expr.id() == ID_initial_state)
6044 {
6045 irep_idt function = "initial-state";
6046
6047 if(state_fkt_declared.insert(function).second)
6048 {
6049 out << "(declare-fun " << function << " (";
6050 convert_type(to_unary_expr(expr).op().type());
6051 out << ") ";
6052 convert_type(expr.type()); // return type
6053 out << ")\n"; // declare-fun
6054 }
6055 }
6056 else if(expr.id() == ID_evaluate)
6057 {
6058 irep_idt function = "evaluate-" + type2id(expr.type());
6059
6060 if(state_fkt_declared.insert(function).second)
6061 {
6062 out << "(declare-fun " << function << " (";
6063 convert_type(to_binary_expr(expr).op0().type());
6064 out << ' ';
6065 convert_type(to_binary_expr(expr).op1().type());
6066 out << ") ";
6067 convert_type(expr.type()); // return type
6068 out << ")\n"; // declare-fun
6069 }
6070 }
6071 else if(
6072 expr.id() == ID_state_is_cstring ||
6073 expr.id() == ID_state_is_dynamic_object ||
6074 expr.id() == ID_state_live_object || expr.id() == ID_state_writeable_object)
6075 {
6076 irep_idt function =
6077 expr.id() == ID_state_is_cstring ? "state-is-cstring"
6078 : expr.id() == ID_state_is_dynamic_object ? "state-is-dynamic-object"
6079 : expr.id() == ID_state_live_object ? "state-live-object"
6080 : "state-writeable-object";
6081
6082 if(state_fkt_declared.insert(function).second)
6083 {
6084 out << "(declare-fun " << function << " (";
6085 convert_type(to_binary_expr(expr).op0().type());
6086 out << ' ';
6087 convert_type(to_binary_expr(expr).op1().type());
6088 out << ") ";
6089 convert_type(expr.type()); // return type
6090 out << ")\n"; // declare-fun
6091 }
6092 }
6093 else if(
6094 expr.id() == ID_state_r_ok || expr.id() == ID_state_w_ok ||
6095 expr.id() == ID_state_rw_ok)
6096 {
6097 irep_idt function = expr.id() == ID_state_r_ok ? "state-r-ok"
6098 : expr.id() == ID_state_w_ok ? "state-w-ok"
6099 : "state-rw-ok";
6100
6101 if(state_fkt_declared.insert(function).second)
6102 {
6103 out << "(declare-fun " << function << " (";
6104 convert_type(to_ternary_expr(expr).op0().type());
6105 out << ' ';
6106 convert_type(to_ternary_expr(expr).op1().type());
6107 out << ' ';
6108 convert_type(to_ternary_expr(expr).op2().type());
6109 out << ") ";
6110 convert_type(expr.type()); // return type
6111 out << ")\n"; // declare-fun
6112 }
6113 }
6114 else if(expr.id() == ID_update_state)
6115 {
6116 irep_idt function =
6117 "update-state-" + type2id(to_multi_ary_expr(expr).op2().type());
6118
6119 if(state_fkt_declared.insert(function).second)
6120 {
6121 out << "(declare-fun " << function << " (";
6122 convert_type(to_multi_ary_expr(expr).op0().type());
6123 out << ' ';
6124 convert_type(to_multi_ary_expr(expr).op1().type());
6125 out << ' ';
6126 convert_type(to_multi_ary_expr(expr).op2().type());
6127 out << ") ";
6128 convert_type(expr.type()); // return type
6129 out << ")\n"; // declare-fun
6130 }
6131 }
6132 else if(expr.id() == ID_enter_scope_state)
6133 {
6134 irep_idt function =
6135 "enter-scope-state-" + type2id(to_binary_expr(expr).op1().type());
6136
6137 if(state_fkt_declared.insert(function).second)
6138 {
6139 out << "(declare-fun " << function << " (";
6140 convert_type(to_binary_expr(expr).op0().type());
6141 out << ' ';
6142 convert_type(to_binary_expr(expr).op1().type());
6143 out << ' ';
6145 out << ") ";
6146 convert_type(expr.type()); // return type
6147 out << ")\n"; // declare-fun
6148 }
6149 }
6150 else if(expr.id() == ID_exit_scope_state)
6151 {
6152 irep_idt function =
6153 "exit-scope-state-" + type2id(to_binary_expr(expr).op1().type());
6154
6155 if(state_fkt_declared.insert(function).second)
6156 {
6157 out << "(declare-fun " << function << " (";
6158 convert_type(to_binary_expr(expr).op0().type());
6159 out << ' ';
6160 convert_type(to_binary_expr(expr).op1().type());
6161 out << ") ";
6162 convert_type(expr.type()); // return type
6163 out << ")\n"; // declare-fun
6164 }
6165 }
6166 else if(expr.id() == ID_allocate)
6167 {
6168 irep_idt function = "allocate";
6169
6170 if(state_fkt_declared.insert(function).second)
6171 {
6172 out << "(declare-fun " << function << " (";
6173 convert_type(to_binary_expr(expr).op0().type());
6174 out << ' ';
6175 convert_type(to_binary_expr(expr).op1().type());
6176 out << ") ";
6177 convert_type(expr.type()); // return type
6178 out << ")\n"; // declare-fun
6179 }
6180 }
6181 else if(expr.id() == ID_reallocate)
6182 {
6183 irep_idt function = "reallocate";
6184
6185 if(state_fkt_declared.insert(function).second)
6186 {
6187 out << "(declare-fun " << function << " (";
6188 convert_type(to_ternary_expr(expr).op0().type());
6189 out << ' ';
6190 convert_type(to_ternary_expr(expr).op1().type());
6191 out << ' ';
6192 convert_type(to_ternary_expr(expr).op2().type());
6193 out << ") ";
6194 convert_type(expr.type()); // return type
6195 out << ")\n"; // declare-fun
6196 }
6197 }
6198 else if(expr.id() == ID_deallocate_state)
6199 {
6200 irep_idt function = "deallocate";
6201
6202 if(state_fkt_declared.insert(function).second)
6203 {
6204 out << "(declare-fun " << function << " (";
6205 convert_type(to_binary_expr(expr).op0().type());
6206 out << ' ';
6207 convert_type(to_binary_expr(expr).op1().type());
6208 out << ") ";
6209 convert_type(expr.type()); // return type
6210 out << ")\n"; // declare-fun
6211 }
6212 }
6213 else if(expr.id() == ID_object_address)
6214 {
6215 irep_idt function = "object-address";
6216
6217 if(state_fkt_declared.insert(function).second)
6218 {
6219 out << "(declare-fun " << function << " (String) ";
6220 convert_type(expr.type()); // return type
6221 out << ")\n"; // declare-fun
6222 }
6223 }
6224 else if(expr.id() == ID_field_address)
6225 {
6226 irep_idt function = "field-address-" + type2id(expr.type());
6227
6228 if(state_fkt_declared.insert(function).second)
6229 {
6230 out << "(declare-fun " << function << " (";
6231 convert_type(to_field_address_expr(expr).op().type());
6232 out << ' ';
6233 out << "String";
6234 out << ") ";
6235 convert_type(expr.type()); // return type
6236 out << ")\n"; // declare-fun
6237 }
6238 }
6239 else if(expr.id() == ID_element_address)
6240 {
6241 irep_idt function = "element-address-" + type2id(expr.type());
6242
6243 if(state_fkt_declared.insert(function).second)
6244 {
6245 out << "(declare-fun " << function << " (";
6246 convert_type(to_element_address_expr(expr).base().type());
6247 out << ' ';
6248 convert_type(to_element_address_expr(expr).index().type());
6249 out << ' '; // repeat, for the element size
6250 convert_type(to_element_address_expr(expr).index().type());
6251 out << ") ";
6252 convert_type(expr.type()); // return type
6253 out << ")\n"; // declare-fun
6254 }
6255 }
6256}
6257
6259{
6260 const typet &type = expr.type();
6261 PRECONDITION(type.id()==ID_array);
6262
6263 // arrays inside structs get flattened, unless we have datatypes
6264 if(expr.id() == ID_with)
6265 return use_array_theory(to_with_expr(expr).old());
6266 else if(expr.id() == ID_if)
6267 {
6268 // For an array-typed if-then-else, the SMT sort produced by
6269 // convert_expr (see the ID_if branch above) is determined by the
6270 // sorts chosen for its two operands:
6271 // - if both branches are bit-vector-encoded, i.e. neither uses array
6272 // theory (typically because both are array-typed members of a
6273 // struct that has been flattened to a bit-vector), the resulting
6274 // ite is a bit-vector;
6275 // - if both branches use array theory, the ite is an SMT array;
6276 // - if exactly one branch uses array theory, the ID_if handler in
6277 // convert_expr unflattens the bit-vector branch back to an SMT
6278 // array (see the wheret::BEGIN/wheret::END unflatten calls), so
6279 // the ite is again an SMT array.
6280 // The ite therefore "uses array theory" iff at least one branch
6281 // does. Without this clause, the fall-through below would
6282 // unconditionally return true for ID_if (since ID_if != ID_member),
6283 // which is wrong in the symmetric bit-vector case: callers like
6284 // convert_index, convert_with, flatten2bv, and the array-typed
6285 // define-fun path would then emit array-theory operators -- e.g.
6286 // (select <ite> ...) or (store <ite> ...) -- on a bit-vector
6287 // operand, producing ill-typed SMT-LIB 2 that is rejected by
6288 // conforming solvers (cf. issue #9008). The asymmetric case was
6289 // already handled, for ID_with branches, in the ID_if conversion
6290 // logic of convert_expr; the present clause makes use_array_theory
6291 // consistent with that conversion in all four combinations.
6292 const if_exprt &if_expr = to_if_expr(expr);
6293 return use_array_theory(if_expr.true_case()) ||
6294 use_array_theory(if_expr.false_case());
6295 }
6296 else
6297 return use_datatypes || expr.id() != ID_member;
6298}
6299
6301{
6302 if(type.id()==ID_array)
6303 {
6304 const array_typet &array_type = to_array_type(type);
6305
6306 // we always use array theory for top-level arrays
6307 const typet &subtype = array_type.element_type();
6308
6309 // Arrays map the index type to the element type.
6310 out << "(Array ";
6311 convert_type(array_type.index_type());
6312 out << " ";
6313
6314 if(subtype.id()==ID_bool && !use_array_of_bool)
6315 out << "(_ BitVec 1)";
6316 else
6317 convert_type(array_type.element_type());
6318
6319 out << ")";
6320 }
6321 else if(type.id()==ID_bool)
6322 {
6323 out << "Bool";
6324 }
6325 else if(type.id() == ID_struct || type.id() == ID_struct_tag)
6326 {
6327 if(use_datatypes)
6328 {
6329 out << datatype_map.at(type);
6330 }
6331 else
6332 {
6333 std::size_t width=boolbv_width(type);
6334
6335 out << "(_ BitVec " << width << ")";
6336 }
6337 }
6338 else if(type.id()==ID_code)
6339 {
6340 // These may appear in structs.
6341 // We replace this by "Bool" in order to keep the same
6342 // member count.
6343 out << "Bool";
6344 }
6345 else if(type.id() == ID_union || type.id() == ID_union_tag)
6346 {
6347 std::size_t width=boolbv_width(type);
6348 const union_typet &union_type = type.id() == ID_union_tag
6349 ? ns.follow_tag(to_union_tag_type(type))
6350 : to_union_type(type);
6352 union_type.components().empty() || width != 0,
6353 "failed to get width of union");
6354
6355 out << "(_ BitVec " << width << ")";
6356 }
6357 else if(type.id()==ID_pointer)
6358 {
6359 out << "(_ BitVec "
6360 << boolbv_width(type) << ")";
6361 }
6362 else if(type.id()==ID_bv ||
6363 type.id()==ID_fixedbv ||
6364 type.id()==ID_unsignedbv ||
6365 type.id()==ID_signedbv ||
6366 type.id()==ID_c_bool)
6367 {
6368 out << "(_ BitVec "
6369 << to_bitvector_type(type).get_width() << ")";
6370 }
6371 else if(type.id()==ID_c_enum)
6372 {
6373 // these have an underlying type
6374 out << "(_ BitVec "
6375 << to_bitvector_type(to_c_enum_type(type).underlying_type()).get_width()
6376 << ")";
6377 }
6378 else if(type.id()==ID_c_enum_tag)
6379 {
6380 convert_type(ns.follow_tag(to_c_enum_tag_type(type)));
6381 }
6382 else if(type.id()==ID_floatbv)
6383 {
6385
6386 if(use_FPA_theory)
6387 out << "(_ FloatingPoint "
6388 << floatbv_type.get_e() << " "
6389 << floatbv_type.get_f() + 1 << ")";
6390 else
6391 out << "(_ BitVec "
6392 << floatbv_type.get_width() << ")";
6393 }
6394 else if(type.id()==ID_rational ||
6395 type.id()==ID_real)
6396 out << "Real";
6397 else if(type.id()==ID_integer)
6398 out << "Int";
6399 else if(type.id() == ID_natural)
6400 out << "Nat";
6401 else if(type.id()==ID_complex)
6402 {
6403 if(use_datatypes)
6404 {
6405 out << datatype_map.at(type);
6406 }
6407 else
6408 {
6409 std::size_t width=boolbv_width(type);
6410
6411 out << "(_ BitVec " << width << ")";
6412 }
6413 }
6414 else if(type.id()==ID_c_bit_field)
6415 {
6417 }
6418 else if(type.id() == ID_state)
6419 {
6420 out << "state";
6421 }
6422 else if(type.id() == ID_range)
6423 {
6424 auto &range_type = to_integer_range_type(type);
6425 if(range_type.empty())
6426 UNEXPECTEDCASE("unsupported range type");
6427 out << "(_ BitVec " << address_bits(range_type.size()) << ")";
6428 }
6429 else if(type.id() == ID_string)
6430 out << "String";
6431 else if(type.id() == ID_regex)
6432 out << "RegLan";
6433 else
6434 {
6435 UNEXPECTEDCASE("unsupported type: "+type.id_string());
6436 }
6437}
6438
6440{
6441 std::set<irep_idt> recstack;
6443}
6444
6446 const typet &type,
6447 std::set<irep_idt> &recstack)
6448{
6449 if(type.id()==ID_array)
6450 {
6452 find_symbols(array_type.size());
6453 find_symbols_rec(array_type.element_type(), recstack);
6454 }
6455 else if(type.id()==ID_complex)
6456 {
6457 find_symbols_rec(to_complex_type(type).subtype(), recstack);
6458
6459 if(use_datatypes &&
6460 datatype_map.find(type)==datatype_map.end())
6461 {
6462 const std::string smt_typename =
6463 "complex." + std::to_string(datatype_map.size());
6464 datatype_map[type] = smt_typename;
6465
6466 out << "(declare-datatypes ((" << smt_typename << " 0)) "
6467 << "(((mk-" << smt_typename;
6468
6469 out << " (" << smt_typename << ".imag ";
6470 convert_type(to_complex_type(type).subtype());
6471 out << ")";
6472
6473 out << " (" << smt_typename << ".real ";
6474 convert_type(to_complex_type(type).subtype());
6475 out << ")";
6476
6477 out << "))))\n";
6478 }
6479 }
6480 else if(type.id() == ID_struct)
6481 {
6482 // Cater for mutually recursive struct types
6483 bool need_decl=false;
6484 if(use_datatypes &&
6485 datatype_map.find(type)==datatype_map.end())
6486 {
6487 const std::string smt_typename =
6488 "struct." + std::to_string(datatype_map.size());
6489 datatype_map[type] = smt_typename;
6490 need_decl=true;
6491 }
6492
6493 const struct_typet::componentst &components =
6494 to_struct_type(type).components();
6495
6496 for(const auto &component : components)
6498
6499 // Declare the corresponding SMT type if we haven't already.
6500 if(need_decl)
6501 {
6502 const std::string &smt_typename = datatype_map.at(type);
6503
6504 // We're going to create a datatype named something like `struct.0'.
6505 // It's going to have a single constructor named `mk-struct.0' with an
6506 // argument for each member of the struct. The declaration that
6507 // creates this type looks like:
6508 //
6509 // (declare-datatypes ((struct.0 0)) (((mk-struct.0
6510 // (struct.0.component1 type1)
6511 // ...
6512 // (struct.0.componentN typeN)))))
6513 out << "(declare-datatypes ((" << smt_typename << " 0)) "
6514 << "(((mk-" << smt_typename << " ";
6515
6516 for(const auto &component : components)
6517 {
6518 if(is_zero_width(component.type(), ns))
6519 continue;
6520
6521 out << "(" << smt_typename << "." << component.get_name()
6522 << " ";
6523 convert_type(component.type());
6524 out << ") ";
6525 }
6526
6527 out << "))))" << "\n";
6528
6529 // Let's also declare convenience functions to update individual
6530 // members of the struct whil we're at it. The functions are
6531 // named like `update-struct.0.component1'. Their declarations
6532 // look like:
6533 //
6534 // (declare-fun update-struct.0.component1
6535 // ((s struct.0) ; first arg -- the struct to update
6536 // (v type1)) ; second arg -- the value to update
6537 // struct.0 ; the output type
6538 // (mk-struct.0 ; build the new struct...
6539 // v ; the updated value
6540 // (struct.0.component2 s) ; retain the other members
6541 // ...
6542 // (struct.0.componentN s)))
6543
6544 for(struct_union_typet::componentst::const_iterator
6545 it=components.begin();
6546 it!=components.end();
6547 ++it)
6548 {
6549 if(is_zero_width(it->type(), ns))
6550 continue;
6551
6553 out << "(define-fun update-" << smt_typename << "."
6554 << component.get_name() << " "
6555 << "((s " << smt_typename << ") "
6556 << "(v ";
6557 convert_type(component.type());
6558 out << ")) " << smt_typename << " "
6559 << "(mk-" << smt_typename
6560 << " ";
6561
6562 for(struct_union_typet::componentst::const_iterator
6563 it2=components.begin();
6564 it2!=components.end();
6565 ++it2)
6566 {
6567 if(it==it2)
6568 out << "v ";
6569 else if(!is_zero_width(it2->type(), ns))
6570 {
6571 out << "(" << smt_typename << "."
6572 << it2->get_name() << " s) ";
6573 }
6574 }
6575
6576 out << "))" << "\n";
6577 }
6578
6579 out << "\n";
6580 }
6581 }
6582 else if(type.id() == ID_union)
6583 {
6584 const union_typet::componentst &components =
6585 to_union_type(type).components();
6586
6587 for(const auto &component : components)
6589 }
6590 else if(type.id()==ID_code)
6591 {
6592 const code_typet::parameterst &parameters=
6593 to_code_type(type).parameters();
6594 for(const auto &param : parameters)
6596
6597 find_symbols_rec(to_code_type(type).return_type(), recstack);
6598 }
6599 else if(type.id()==ID_pointer)
6600 {
6601 find_symbols_rec(to_pointer_type(type).base_type(), recstack);
6602 }
6603 else if(type.id() == ID_struct_tag)
6604 {
6605 const auto &struct_tag = to_struct_tag_type(type);
6606 const irep_idt &id = struct_tag.get_identifier();
6607
6608 if(recstack.find(id) == recstack.end())
6609 {
6610 const auto &base_struct = ns.follow_tag(struct_tag);
6611 recstack.insert(id);
6614 }
6615 }
6616 else if(type.id() == ID_union_tag)
6617 {
6618 const auto &union_tag = to_union_tag_type(type);
6619 const irep_idt &id = union_tag.get_identifier();
6620
6621 if(recstack.find(id) == recstack.end())
6622 {
6623 recstack.insert(id);
6624 find_symbols_rec(ns.follow_tag(union_tag), recstack);
6625 }
6626 }
6627 else if(type.id() == ID_state)
6628 {
6629 if(datatype_map.find(type) == datatype_map.end())
6630 {
6631 datatype_map[type] = "state";
6632 out << "(declare-sort state 0)\n";
6633 }
6634 }
6635 else if(type.id() == ID_mathematical_function)
6636 {
6637 const auto &mathematical_function_type =
6639 for(auto &d_type : mathematical_function_type.domain())
6641
6643 }
6644}
6645
6647{
6649}
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: 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