cprover
Loading...
Searching...
No Matches
lower_byte_operators.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
9#include "arith_tools.h"
10#include "bitvector_expr.h"
11#include "byte_operators.h"
12#include "c_types.h"
13#include "endianness_map.h"
14#include "expr_util.h"
15#include "namespace.h"
16#include "narrow.h"
17#include "pointer_offset_size.h"
18#include "simplify_expr.h"
19#include "string_constant.h"
20
21#include <algorithm>
22
23static exprt bv_to_expr(
24 const exprt &bitvector_expr,
25 const typet &target_type,
26 const endianness_mapt &endianness_map,
27 const namespacet &ns);
28
29struct boundst
30{
31 std::size_t lb;
32 std::size_t ub;
33};
34
37 const endianness_mapt &endianness_map,
38 std::size_t lower_bound,
39 std::size_t upper_bound)
40{
41 boundst result;
42 result.lb = lower_bound;
43 result.ub = upper_bound;
44
45 if(result.ub < endianness_map.number_of_bits())
46 {
47 result.lb = endianness_map.map_bit(result.lb);
48 result.ub = endianness_map.map_bit(result.ub);
49
50 // big-endian bounds need swapping
51 if(result.ub < result.lb)
52 std::swap(result.lb, result.ub);
53 }
54
55 return result;
56}
57
59bitvector_typet adjust_width(const typet &src, std::size_t new_width)
60{
61 if(src.id() == ID_unsignedbv)
62 return unsignedbv_typet(new_width);
63 else if(src.id() == ID_signedbv)
64 return signedbv_typet(new_width);
65 else if(src.id() == ID_bv)
66 return bv_typet(new_width);
67 else if(src.id() == ID_c_enum) // we use the underlying type
68 return adjust_width(to_c_enum_type(src).underlying_type(), new_width);
69 else if(src.id() == ID_c_bit_field)
70 return c_bit_field_typet(
71 to_c_bit_field_type(src).underlying_type(), new_width);
72 else
73 PRECONDITION(false);
74}
75
79 const exprt &bitvector_expr,
80 const struct_typet &struct_type,
81 const endianness_mapt &endianness_map,
82 const namespacet &ns)
83{
84 const struct_typet::componentst &components = struct_type.components();
85
86 exprt::operandst operands;
87 operands.reserve(components.size());
88 std::size_t member_offset_bits = 0;
89 for(const auto &comp : components)
90 {
91 const auto component_bits_opt = pointer_offset_bits(comp.type(), ns);
92 std::size_t component_bits;
93 if(component_bits_opt.has_value())
94 component_bits = numeric_cast_v<std::size_t>(*component_bits_opt);
95 else
96 component_bits = to_bitvector_type(bitvector_expr.type()).get_width() -
98
99 if(component_bits == 0)
100 {
101 operands.push_back(
102 bv_to_expr(bitvector_expr, comp.type(), endianness_map, ns));
103 continue;
104 }
105
106 const auto bounds = map_bounds(
107 endianness_map,
109 member_offset_bits + component_bits - 1);
110 bitvector_typet type = adjust_width(bitvector_expr.type(), component_bits);
111 PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
112 operands.push_back(bv_to_expr(
113 extractbits_exprt{bitvector_expr, bounds.lb, std::move(type)},
114 comp.type(),
115 endianness_map,
116 ns));
117
118 if(component_bits_opt.has_value())
119 member_offset_bits += component_bits;
120 }
121
122 return struct_exprt{std::move(operands), struct_type};
123}
124
128 const exprt &bitvector_expr,
129 const union_typet &union_type,
130 const endianness_mapt &endianness_map,
131 const namespacet &ns)
132{
133 const union_typet::componentst &components = union_type.components();
134
135 if(components.empty())
136 return empty_union_exprt{union_type};
137
138 const auto widest_member = union_type.find_widest_union_component(ns);
139
140 std::size_t component_bits;
141 if(widest_member.has_value())
142 component_bits = numeric_cast_v<std::size_t>(widest_member->second);
143 else
144 component_bits = to_bitvector_type(bitvector_expr.type()).get_width();
145
146 if(component_bits == 0)
147 {
148 return union_exprt{
149 components.front().get_name(),
150 bv_to_expr(bitvector_expr, components.front().type(), endianness_map, ns),
151 union_type};
152 }
153
154 const auto bounds = map_bounds(endianness_map, 0, component_bits - 1);
155 bitvector_typet type = adjust_width(bitvector_expr.type(), component_bits);
156 const irep_idt &component_name = widest_member.has_value()
157 ? widest_member->first.get_name()
158 : components.front().get_name();
159 const typet &component_type = widest_member.has_value()
160 ? widest_member->first.type()
161 : components.front().type();
162 PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
163 return union_exprt{
164 component_name,
166 extractbits_exprt{bitvector_expr, bounds.lb, std::move(type)},
167 component_type,
168 endianness_map,
169 ns),
170 union_type};
171}
172
176 const exprt &bitvector_expr,
177 const array_typet &array_type,
178 const endianness_mapt &endianness_map,
179 const namespacet &ns)
180{
181 auto num_elements = numeric_cast<std::size_t>(array_type.size());
182 auto subtype_bits = pointer_offset_bits(array_type.element_type(), ns);
183
184 const std::size_t total_bits =
185 to_bitvector_type(bitvector_expr.type()).get_width();
186 if(!num_elements.has_value())
187 {
188 if(!subtype_bits.has_value() || *subtype_bits == 0)
189 num_elements = total_bits;
190 else
191 num_elements = total_bits / numeric_cast_v<std::size_t>(*subtype_bits);
192 }
194 !num_elements.has_value() || !subtype_bits.has_value() ||
195 *subtype_bits * *num_elements == total_bits,
196 "subtype width times array size should be total bitvector width");
197
198 exprt::operandst operands;
199 operands.reserve(*num_elements);
200 for(std::size_t i = 0; i < *num_elements; ++i)
201 {
202 if(subtype_bits.has_value())
203 {
204 const std::size_t subtype_bits_int =
205 numeric_cast_v<std::size_t>(*subtype_bits);
206 const auto bounds = map_bounds(
207 endianness_map, i * subtype_bits_int, ((i + 1) * subtype_bits_int) - 1);
208 bitvector_typet type =
209 adjust_width(bitvector_expr.type(), subtype_bits_int);
210 PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
211 operands.push_back(bv_to_expr(
212 extractbits_exprt{bitvector_expr, bounds.lb, std::move(type)},
213 array_type.element_type(),
214 endianness_map,
215 ns));
216 }
217 else
218 {
219 operands.push_back(bv_to_expr(
220 bitvector_expr, array_type.element_type(), endianness_map, ns));
221 }
222 }
223
224 return array_exprt{std::move(operands), array_type};
225}
226
230 const exprt &bitvector_expr,
231 const vector_typet &vector_type,
232 const endianness_mapt &endianness_map,
233 const namespacet &ns)
234{
235 const std::size_t num_elements =
236 numeric_cast_v<std::size_t>(vector_type.size());
237 auto subtype_bits = pointer_offset_bits(vector_type.element_type(), ns);
239 !subtype_bits.has_value() ||
240 *subtype_bits * num_elements ==
241 to_bitvector_type(bitvector_expr.type()).get_width(),
242 "subtype width times vector size should be total bitvector width");
243
244 exprt::operandst operands;
245 operands.reserve(num_elements);
246 for(std::size_t i = 0; i < num_elements; ++i)
247 {
248 if(subtype_bits.has_value())
249 {
250 const std::size_t subtype_bits_int =
251 numeric_cast_v<std::size_t>(*subtype_bits);
252 const auto bounds = map_bounds(
253 endianness_map, i * subtype_bits_int, ((i + 1) * subtype_bits_int) - 1);
254 bitvector_typet type =
255 adjust_width(bitvector_expr.type(), subtype_bits_int);
256 PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
257 operands.push_back(bv_to_expr(
258 extractbits_exprt{bitvector_expr, bounds.lb, std::move(type)},
259 vector_type.element_type(),
260 endianness_map,
261 ns));
262 }
263 else
264 {
265 operands.push_back(bv_to_expr(
266 bitvector_expr, vector_type.element_type(), endianness_map, ns));
267 }
268 }
269
270 return vector_exprt{std::move(operands), vector_type};
271}
272
276 const exprt &bitvector_expr,
277 const complex_typet &complex_type,
278 const endianness_mapt &endianness_map,
279 const namespacet &ns)
280{
281 const std::size_t total_bits =
282 to_bitvector_type(bitvector_expr.type()).get_width();
283 const auto subtype_bits_opt = pointer_offset_bits(complex_type.subtype(), ns);
284 std::size_t subtype_bits;
285 if(subtype_bits_opt.has_value())
286 {
287 subtype_bits = numeric_cast_v<std::size_t>(*subtype_bits_opt);
289 subtype_bits * 2 == total_bits,
290 "subtype width should be half of the total bitvector width");
291 }
292 else
293 subtype_bits = total_bits / 2;
294
295 const auto bounds_real = map_bounds(endianness_map, 0, subtype_bits - 1);
296 const auto bounds_imag =
297 map_bounds(endianness_map, subtype_bits, subtype_bits * 2 - 1);
298
299 const bitvector_typet type =
300 adjust_width(bitvector_expr.type(), subtype_bits);
301
302 PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
303 return complex_exprt{
305 extractbits_exprt{bitvector_expr, bounds_real.lb, type},
306 complex_type.subtype(),
307 endianness_map,
308 ns),
310 extractbits_exprt{bitvector_expr, bounds_imag.lb, type},
311 complex_type.subtype(),
312 endianness_map,
313 ns),
314 complex_type};
315}
316
331 const exprt &bitvector_expr,
332 const typet &target_type,
333 const endianness_mapt &endianness_map,
334 const namespacet &ns)
335{
337
338 if(target_type.id() == ID_floatbv)
339 {
340 std::size_t width = to_bitvector_type(bitvector_expr.type()).get_width();
341 exprt bv_expr =
342 typecast_exprt::conditional_cast(bitvector_expr, bv_typet{width});
343 return simplify_expr(
344 typecast_exprt::conditional_cast(bv_expr, target_type), ns);
345 }
346 else if(
347 can_cast_type<bitvector_typet>(target_type) ||
348 target_type.id() == ID_c_enum || target_type.id() == ID_c_enum_tag ||
349 target_type.id() == ID_string ||
350 (target_type.id() == ID_bool &&
351 to_bitvector_type(bitvector_expr.type()).get_width() == 1))
352 {
353 return simplify_expr(
354 typecast_exprt::conditional_cast(bitvector_expr, target_type), ns);
355 }
356 else if(target_type.id() == ID_struct)
357 {
358 return bv_to_struct_expr(
359 bitvector_expr, to_struct_type(target_type), endianness_map, ns);
360 }
361 else if(target_type.id() == ID_struct_tag)
362 {
364 bitvector_expr,
365 ns.follow_tag(to_struct_tag_type(target_type)),
366 endianness_map,
367 ns);
368 result.type() = target_type;
369 return std::move(result);
370 }
371 else if(target_type.id() == ID_union)
372 {
373 return bv_to_union_expr(
374 bitvector_expr, to_union_type(target_type), endianness_map, ns);
375 }
376 else if(target_type.id() == ID_union_tag)
377 {
378 exprt result = bv_to_union_expr(
379 bitvector_expr,
380 ns.follow_tag(to_union_tag_type(target_type)),
381 endianness_map,
382 ns);
383 result.type() = target_type;
384 return result;
385 }
386 else if(target_type.id() == ID_array)
387 {
388 return bv_to_array_expr(
389 bitvector_expr, to_array_type(target_type), endianness_map, ns);
390 }
391 else if(target_type.id() == ID_vector)
392 {
393 return bv_to_vector_expr(
394 bitvector_expr, to_vector_type(target_type), endianness_map, ns);
395 }
396 else if(target_type.id() == ID_complex)
397 {
398 return bv_to_complex_expr(
399 bitvector_expr, to_complex_type(target_type), endianness_map, ns);
400 }
401 else
402 {
404 false, "bv_to_expr does not yet support ", target_type.id_string());
405 }
406}
407
408static exprt unpack_rec(
409 const exprt &src,
410 bool little_endian,
411 const std::optional<mp_integer> &offset_bytes,
412 const std::optional<mp_integer> &max_bytes,
413 const std::size_t bits_per_byte,
414 const namespacet &ns,
415 bool unpack_byte_array = false);
416
425 const exprt &src,
426 std::size_t lower_bound,
427 std::size_t upper_bound,
428 const std::size_t bits_per_byte,
429 const namespacet &ns)
430{
431 PRECONDITION(lower_bound <= upper_bound);
432
433 if(src.id() == ID_array)
434 {
435 PRECONDITION(upper_bound <= src.operands().size());
436 return exprt::operandst{
437 src.operands().begin() + narrow_cast<std::ptrdiff_t>(lower_bound),
438 src.operands().begin() + narrow_cast<std::ptrdiff_t>(upper_bound)};
439 }
440
441 const typet &element_type = src.type().id() == ID_array
444 const typet index_type = src.type().id() == ID_array
445 ? to_array_type(src.type()).index_type()
446 : to_vector_type(src.type()).index_type();
448 can_cast_type<bitvector_typet>(element_type) &&
449 to_bitvector_type(element_type).get_width() == bits_per_byte);
450 exprt::operandst bytes;
451 bytes.reserve(upper_bound - lower_bound);
452 for(std::size_t i = lower_bound; i < upper_bound; ++i)
453 {
454 const index_exprt idx{src, from_integer(i, index_type)};
455 bytes.push_back(simplify_expr(idx, ns));
456 }
457 return bytes;
458}
459
469 const exprt &src,
470 std::size_t el_bytes,
471 bool little_endian,
472 const std::size_t bits_per_byte,
473 const namespacet &ns)
474{
475 const typet index_type = src.type().id() == ID_array
476 ? to_array_type(src.type()).index_type()
477 : to_vector_type(src.type()).index_type();
478
479 // TODO we either need a symbol table here or make array comprehensions
480 // introduce a scope
481 static std::size_t array_comprehension_index_counter = 0;
482 ++array_comprehension_index_counter;
483 symbol_exprt array_comprehension_index{
484 "$array_comprehension_index_a_v" +
485 std::to_string(array_comprehension_index_counter),
486 index_type};
487
488 index_exprt element{
489 src,
490 div_exprt{array_comprehension_index, from_integer(el_bytes, index_type)}};
491
492 exprt sub =
493 unpack_rec(element, little_endian, {}, {}, bits_per_byte, ns, false);
494 exprt::operandst sub_operands =
495 instantiate_byte_array(sub, 0, el_bytes, bits_per_byte, ns);
496
497 exprt body = sub_operands.front();
498 const mod_exprt offset{
499 array_comprehension_index,
500 from_integer(el_bytes, array_comprehension_index.type())};
501 for(std::size_t i = 1; i < el_bytes; ++i)
502 {
503 body = if_exprt{
504 equal_exprt{offset, from_integer(i, array_comprehension_index.type())},
505 sub_operands[i],
506 body};
507 }
508
509 const exprt array_vector_size = src.type().id() == ID_vector
510 ? to_vector_type(src.type()).size()
511 : to_array_type(src.type()).size();
512
513 if(array_vector_size.is_nil())
514 {
515 // The source array/vector has no statically known size (an incomplete
516 // type whose extent is genuinely unknown here, e.g. an extern array
517 // declared without a bound). Represent it as a zero-length comprehension;
518 // any byte access into it is then out of bounds and becomes nondet/fails,
519 // which is the behaviour the extern6 regression exercises.
521 std::move(array_comprehension_index),
522 std::move(body),
523 array_typet{bv_typet{bits_per_byte}, from_integer(0, size_type())}};
524 }
525
527 std::move(array_comprehension_index),
528 std::move(body),
530 bv_typet{bits_per_byte},
532 array_vector_size, from_integer(el_bytes, array_vector_size.type())}}};
533}
534
551 const exprt &src,
552 const std::optional<mp_integer> &src_size,
553 const mp_integer &element_bits,
554 bool little_endian,
555 const std::optional<mp_integer> &offset_bytes,
556 const std::optional<mp_integer> &max_bytes,
557 const std::size_t bits_per_byte,
558 const namespacet &ns)
559{
560 const std::size_t el_bytes = numeric_cast_v<std::size_t>(
561 (element_bits + bits_per_byte - 1) / bits_per_byte);
562
563 if(!src_size.has_value() && !max_bytes.has_value())
564 {
566 el_bytes > 0 && element_bits % bits_per_byte == 0,
567 "unpacking of arrays with non-byte-aligned elements is not supported");
569 src, el_bytes, little_endian, bits_per_byte, ns);
570 }
571
572 exprt::operandst byte_operands;
573 mp_integer first_element = 0;
574
575 // refine the number of elements to extract in case the element width is known
576 // and a multiple of bytes; otherwise we will expand the entire array/vector
577 std::optional<mp_integer> num_elements = src_size;
578 if(element_bits > 0 && element_bits % bits_per_byte == 0)
579 {
580 if(!num_elements.has_value())
581 {
582 // turn bytes into elements, rounding up
583 num_elements = (*max_bytes + el_bytes - 1) / el_bytes;
584 }
585
586 if(offset_bytes.has_value())
587 {
588 // compute offset as number of elements
589 first_element = *offset_bytes / el_bytes;
590 // insert offset_bytes-many nil bytes into the output array
591 byte_operands.resize(
593 *offset_bytes - (*offset_bytes % el_bytes),
594 *num_elements * el_bytes)),
595 bv_typet{bits_per_byte}.all_zeros_expr());
596 }
597 }
598
599 // the maximum number of bytes is an upper bound in case the size of the
600 // array/vector is unknown; if element_bits was usable above this will
601 // have been turned into a number of elements already
602 if(!num_elements)
603 num_elements = *max_bytes;
604
605 const exprt src_simp = simplify_expr(src, ns);
606 const typet index_type = src_simp.type().id() == ID_array
607 ? to_array_type(src_simp.type()).index_type()
608 : to_vector_type(src_simp.type()).index_type();
609
610 for(mp_integer i = first_element; i < *num_elements; ++i)
611 {
612 exprt element;
613
614 if(
615 (src_simp.id() == ID_array || src_simp.id() == ID_vector) &&
616 i < src_simp.operands().size())
617 {
618 const std::size_t index_int = numeric_cast_v<std::size_t>(i);
619 element = src_simp.operands()[index_int];
620 }
621 else
622 {
623 element = index_exprt(src_simp, from_integer(i, index_type));
624 }
625
626 // recursively unpack each element so that we eventually just have an array
627 // of bytes left
628
629 const std::optional<mp_integer> element_max_bytes =
630 max_bytes
631 ? std::min(mp_integer{el_bytes}, *max_bytes - byte_operands.size())
632 : std::optional<mp_integer>{};
633 const std::size_t element_max_bytes_int =
634 element_max_bytes ? numeric_cast_v<std::size_t>(*element_max_bytes)
635 : el_bytes;
636
637 exprt sub = unpack_rec(
638 element, little_endian, {}, element_max_bytes, bits_per_byte, ns, true);
639 exprt::operandst sub_operands =
640 instantiate_byte_array(sub, 0, element_max_bytes_int, bits_per_byte, ns);
641 byte_operands.insert(
642 byte_operands.end(), sub_operands.begin(), sub_operands.end());
643
644 if(max_bytes && byte_operands.size() >= *max_bytes)
645 break;
646 }
647
648 const std::size_t size = byte_operands.size();
649 return array_exprt(
650 std::move(byte_operands),
651 array_typet{bv_typet{bits_per_byte}, from_integer(size, size_type())});
652}
653
666 exprt::operandst &&bit_fields,
667 std::size_t total_bits,
668 exprt::operandst &dest,
669 bool little_endian,
670 const std::optional<mp_integer> &offset_bytes,
671 const std::optional<mp_integer> &max_bytes,
672 const std::size_t bits_per_byte,
673 const namespacet &ns)
674{
675 const concatenation_exprt concatenation{
676 std::move(bit_fields), bv_typet{total_bits}};
677
678 exprt sub = unpack_rec(
679 concatenation,
680 little_endian,
681 offset_bytes,
682 max_bytes,
683 bits_per_byte,
684 ns,
685 true);
686
687 dest.insert(
688 dest.end(),
689 std::make_move_iterator(sub.operands().begin()),
690 std::make_move_iterator(sub.operands().end()));
691}
692
704 const exprt &src,
705 bool little_endian,
706 const std::optional<mp_integer> &offset_bytes,
707 const std::optional<mp_integer> &max_bytes,
708 const std::size_t bits_per_byte,
709 const namespacet &ns)
710{
711 const struct_typet &struct_type =
712 src.type().id() == ID_struct_tag
714 : to_struct_type(src.type());
715 const struct_typet::componentst &components = struct_type.components();
716
717 std::optional<mp_integer> offset_in_member;
718 std::optional<mp_integer> max_bytes_left;
719 std::optional<std::pair<exprt::operandst, std::size_t>> bit_fields;
720
722 exprt::operandst byte_operands;
723 for(auto it = components.begin(); it != components.end(); ++it)
724 {
725 const auto &comp = *it;
726 auto component_bits = pointer_offset_bits(comp.type(), ns);
727
728 // We can only handle a member of unknown width when it is the last member
729 // and is byte-aligned. Members of unknown width in the middle would leave
730 // us with unknown alignment of subsequent members, and queuing them up as
731 // bit fields is not possible either as the total width of the concatenation
732 // could not be determined.
734 component_bits.has_value() ||
735 (std::next(it) == components.end() && !bit_fields.has_value()),
736 "members of non-constant width should come last in a struct");
737
738 member_exprt member(src, comp.get_name(), comp.type());
739 if(src.id() == ID_struct)
740 simplify(member, ns);
741
742 // Is it a byte-aligned member?
743 if(member_offset_bits % bits_per_byte == 0)
744 {
745 if(bit_fields.has_value())
746 {
748 std::move(bit_fields->first),
749 bit_fields->second,
750 byte_operands,
751 little_endian,
752 offset_in_member,
753 max_bytes_left,
754 bits_per_byte,
755 ns);
756 bit_fields.reset();
757 }
758
759 if(offset_bytes.has_value())
760 {
761 offset_in_member = *offset_bytes - member_offset_bits / bits_per_byte;
762 // if the offset is negative, offset_in_member remains unset, which has
763 // the same effect as setting it to zero
764 if(*offset_in_member < 0)
765 offset_in_member.reset();
766 }
767
768 if(max_bytes.has_value())
769 {
770 max_bytes_left = *max_bytes - member_offset_bits / bits_per_byte;
771 if(*max_bytes_left < 0)
772 break;
773 }
774 }
775
776 if(
777 member_offset_bits % bits_per_byte != 0 ||
778 (component_bits.has_value() && *component_bits % bits_per_byte != 0))
779 {
780 if(!bit_fields.has_value())
781 bit_fields = std::make_pair(exprt::operandst{}, std::size_t{0});
782
783 const std::size_t bits_int = numeric_cast_v<std::size_t>(*component_bits);
784 bit_fields->first.insert(
785 little_endian ? bit_fields->first.begin() : bit_fields->first.end(),
786 typecast_exprt::conditional_cast(member, bv_typet{bits_int}));
787 bit_fields->second += bits_int;
788
789 member_offset_bits += *component_bits;
790
791 continue;
792 }
793
794 INVARIANT(
795 !bit_fields.has_value(),
796 "all preceding members should have been processed");
797
798 if(
799 component_bits.has_value() && offset_in_member.has_value() &&
800 *offset_in_member * bits_per_byte >= *component_bits)
801 {
802 // we won't actually need this component, fill in zeros instead of
803 // computing an unpacking
804 byte_operands.resize(
805 byte_operands.size() +
806 numeric_cast_v<std::size_t>(*component_bits / bits_per_byte),
807 bv_typet{bits_per_byte}.all_zeros_expr());
808 }
809 else
810 {
811 exprt sub = unpack_rec(
812 member,
813 little_endian,
814 offset_in_member,
815 max_bytes_left,
816 bits_per_byte,
817 ns,
818 true);
819
820 byte_operands.insert(
821 byte_operands.end(),
822 std::make_move_iterator(sub.operands().begin()),
823 std::make_move_iterator(sub.operands().end()));
824 }
825
826 if(component_bits.has_value())
827 member_offset_bits += *component_bits;
828 }
829
830 // any remaining bit fields?
831 if(bit_fields.has_value())
832 {
834 std::move(bit_fields->first),
835 bit_fields->second,
836 byte_operands,
837 little_endian,
838 offset_in_member,
839 max_bytes_left,
840 bits_per_byte,
841 ns);
842 }
843
844 const std::size_t size = byte_operands.size();
845 return array_exprt{
846 std::move(byte_operands),
847 array_typet{bv_typet{bits_per_byte}, from_integer(size, size_type())}};
848}
849
857 const exprt &src,
858 bool little_endian,
859 const std::size_t bits_per_byte,
860 const namespacet &ns)
861{
862 const complex_typet &complex_type = to_complex_type(src.type());
863 const typet &subtype = complex_type.subtype();
864
865 auto subtype_bits = pointer_offset_bits(subtype, ns);
866 CHECK_RETURN(subtype_bits.has_value());
867 CHECK_RETURN(*subtype_bits % bits_per_byte == 0);
868
869 exprt sub_real = unpack_rec(
871 little_endian,
872 mp_integer{0},
873 *subtype_bits / bits_per_byte,
874 bits_per_byte,
875 ns,
876 true);
877 exprt::operandst byte_operands = std::move(sub_real.operands());
878
879 exprt sub_imag = unpack_rec(
881 little_endian,
882 mp_integer{0},
883 *subtype_bits / bits_per_byte,
884 bits_per_byte,
885 ns,
886 true);
887 byte_operands.insert(
888 byte_operands.end(),
889 std::make_move_iterator(sub_imag.operands().begin()),
890 std::make_move_iterator(sub_imag.operands().end()));
891
892 const std::size_t size = byte_operands.size();
893 return array_exprt{
894 std::move(byte_operands),
895 array_typet{bv_typet{bits_per_byte}, from_integer(size, size_type())}};
896}
897
908// array of bytes
911 const exprt &src,
912 bool little_endian,
913 const std::optional<mp_integer> &offset_bytes,
914 const std::optional<mp_integer> &max_bytes,
915 const std::size_t bits_per_byte,
916 const namespacet &ns,
917 bool unpack_byte_array)
918{
919 if(src.type().id() == ID_array)
920 {
921 const array_typet &array_type = to_array_type(src.type());
922 const typet &subtype = array_type.element_type();
923
924 auto element_bits = pointer_offset_bits(subtype, ns);
925 CHECK_RETURN(element_bits.has_value());
926
927 if(
928 !unpack_byte_array && *element_bits == bits_per_byte &&
930 {
931 return src;
932 }
933
934 const auto constant_size_opt = numeric_cast<mp_integer>(array_type.size());
935 return unpack_array_vector(
936 src,
937 constant_size_opt,
938 *element_bits,
939 little_endian,
940 offset_bytes,
941 max_bytes,
942 bits_per_byte,
943 ns);
944 }
945 else if(src.type().id() == ID_vector)
946 {
947 const vector_typet &vector_type = to_vector_type(src.type());
948 const typet &subtype = vector_type.element_type();
949
950 auto element_bits = pointer_offset_bits(subtype, ns);
951 CHECK_RETURN(element_bits.has_value());
952
953 if(
954 !unpack_byte_array && *element_bits == bits_per_byte &&
956 {
957 return src;
958 }
959
960 return unpack_array_vector(
961 src,
962 numeric_cast_v<mp_integer>(vector_type.size()),
963 *element_bits,
964 little_endian,
965 offset_bytes,
966 max_bytes,
967 bits_per_byte,
968 ns);
969 }
970 else if(src.type().id() == ID_complex)
971 {
972 return unpack_complex(src, little_endian, bits_per_byte, ns);
973 }
974 else if(src.type().id() == ID_struct || src.type().id() == ID_struct_tag)
975 {
976 return unpack_struct(
977 src, little_endian, offset_bytes, max_bytes, bits_per_byte, ns);
978 }
979 else if(src.type().id() == ID_union || src.type().id() == ID_union_tag)
980 {
981 const union_typet &union_type =
982 src.type().id() == ID_union_tag
984 : to_union_type(src.type());
985
986 const auto widest_member = union_type.find_widest_union_component(ns);
987
988 if(widest_member.has_value())
989 {
990 member_exprt member{
991 src, widest_member->first.get_name(), widest_member->first.type()};
992 return unpack_rec(
993 member,
994 little_endian,
995 offset_bytes,
996 widest_member->second,
997 bits_per_byte,
998 ns,
999 true);
1000 }
1001 else if(!union_type.components().empty())
1002 {
1003 member_exprt member{src, union_type.components().front()};
1004 return unpack_rec(
1005 member,
1006 little_endian,
1007 offset_bytes,
1008 max_bytes,
1009 bits_per_byte,
1010 ns,
1011 true);
1012 }
1013 }
1014 else if(src.type().id() == ID_pointer)
1015 {
1016 return unpack_rec(
1018 little_endian,
1019 offset_bytes,
1020 max_bytes,
1021 bits_per_byte,
1022 ns,
1023 unpack_byte_array);
1024 }
1025 else if(src.id() == ID_string_constant)
1026 {
1027 return unpack_rec(
1029 little_endian,
1030 offset_bytes,
1031 max_bytes,
1032 bits_per_byte,
1033 ns,
1034 unpack_byte_array);
1035 }
1036 else if(src.is_constant() && src.type().id() == ID_string)
1037 {
1038 return unpack_rec(
1040 little_endian,
1041 offset_bytes,
1042 max_bytes,
1043 bits_per_byte,
1044 ns,
1045 unpack_byte_array);
1046 }
1047 else if(src.type().id() != ID_empty)
1048 {
1049 // a basic type; we turn that into extractbits while considering
1050 // endianness
1051 auto bits_opt = pointer_offset_bits(src.type(), ns);
1052 DATA_INVARIANT(bits_opt.has_value(), "basic type should have a fixed size");
1053
1054 const mp_integer total_bits = *bits_opt;
1055 mp_integer last_bit = total_bits;
1056 mp_integer bit_offset = 0;
1057
1058 if(max_bytes.has_value())
1059 {
1060 const auto max_bits = *max_bytes * bits_per_byte;
1061 if(little_endian)
1062 {
1063 last_bit = std::min(last_bit, max_bits);
1064 }
1065 else
1066 {
1067 bit_offset = std::max(mp_integer{0}, last_bit - max_bits);
1068 }
1069 }
1070
1071 auto const src_as_bitvector = typecast_exprt::conditional_cast(
1072 src, bv_typet{numeric_cast_v<std::size_t>(total_bits)});
1073 auto const byte_type = bv_typet{bits_per_byte};
1074 exprt::operandst byte_operands;
1075 array_typet array_type{
1076 bv_typet{bits_per_byte}, from_integer(0, size_type())};
1077
1078 for(; bit_offset < last_bit; bit_offset += bits_per_byte)
1079 {
1081 pointer_offset_bits(src_as_bitvector.type(), ns).has_value());
1082 extractbits_exprt extractbits(
1083 src_as_bitvector,
1084 from_integer(bit_offset, array_type.index_type()),
1085 byte_type);
1086
1087 // endianness_mapt should be the point of reference for mapping out
1088 // endianness, but we need to work on elements here instead of
1089 // individual bits
1090 if(little_endian)
1091 byte_operands.push_back(extractbits);
1092 else
1093 byte_operands.insert(byte_operands.begin(), extractbits);
1094 }
1095
1096 const std::size_t size = byte_operands.size();
1097 array_type.size() = from_integer(size, size_type());
1098 return array_exprt{std::move(byte_operands), std::move(array_type)};
1099 }
1100
1101 return array_exprt(
1102 {}, array_typet{bv_typet{bits_per_byte}, from_integer(0, size_type())});
1103}
1104
1116 const byte_extract_exprt &src,
1117 const byte_extract_exprt &unpacked,
1118 const typet &subtype,
1119 const mp_integer &element_bits,
1120 const namespacet &ns)
1121{
1122 std::optional<std::size_t> num_elements;
1123 if(src.type().id() == ID_array)
1124 num_elements = numeric_cast<std::size_t>(to_array_type(src.type()).size());
1125 else
1126 num_elements = numeric_cast<std::size_t>(to_vector_type(src.type()).size());
1127
1128 if(num_elements.has_value())
1129 {
1130 exprt::operandst operands;
1131 operands.reserve(*num_elements);
1132 for(std::size_t i = 0; i < *num_elements; ++i)
1133 {
1134 plus_exprt new_offset(
1135 unpacked.offset(),
1137 i * element_bits / src.get_bits_per_byte(),
1138 unpacked.offset().type()));
1139
1140 byte_extract_exprt tmp(unpacked);
1141 tmp.type() = subtype;
1142 tmp.offset() = new_offset;
1143
1144 operands.push_back(lower_byte_extract(tmp, ns));
1145 }
1146
1147 exprt result;
1148 if(src.type().id() == ID_array)
1149 result = array_exprt{std::move(operands), to_array_type(src.type())};
1150 else
1151 result = vector_exprt{std::move(operands), to_vector_type(src.type())};
1152
1153 return simplify_expr(result, ns);
1154 }
1155
1156 DATA_INVARIANT(src.type().id() == ID_array, "vectors have constant size");
1157 const array_typet &array_type = to_array_type(src.type());
1158
1159 // TODO we either need a symbol table here or make array comprehensions
1160 // introduce a scope
1161 static std::size_t array_comprehension_index_counter = 0;
1162 ++array_comprehension_index_counter;
1163 symbol_exprt array_comprehension_index{
1164 "$array_comprehension_index_a" +
1165 std::to_string(array_comprehension_index_counter),
1166 array_type.index_type()};
1167
1168 plus_exprt new_offset{
1169 unpacked.offset(),
1171 mult_exprt{
1172 array_comprehension_index,
1174 element_bits / src.get_bits_per_byte(),
1175 array_comprehension_index.type())},
1176 unpacked.offset().type())};
1177
1178 byte_extract_exprt body(unpacked);
1179 body.type() = subtype;
1180 body.offset() = std::move(new_offset);
1181
1183 std::move(array_comprehension_index),
1184 lower_byte_extract(body, ns),
1185 array_type};
1186}
1187
1196static std::optional<exprt> lower_byte_extract_complex(
1197 const byte_extract_exprt &src,
1198 const byte_extract_exprt &unpacked,
1199 const namespacet &ns)
1200{
1201 const complex_typet &complex_type = to_complex_type(src.type());
1202 const typet &subtype = complex_type.subtype();
1203
1204 auto subtype_bits = pointer_offset_bits(subtype, ns);
1205 if(!subtype_bits.has_value() || *subtype_bits % src.get_bits_per_byte() != 0)
1206 return {};
1207
1208 // offset remains unchanged
1209 byte_extract_exprt real{unpacked};
1210 real.type() = subtype;
1211
1212 const plus_exprt new_offset{
1213 unpacked.offset(),
1215 *subtype_bits / src.get_bits_per_byte(), unpacked.offset().type())};
1216 byte_extract_exprt imag{unpacked};
1217 imag.type() = subtype;
1218 imag.offset() = simplify_expr(new_offset, ns);
1219
1220 return simplify_expr(
1222 lower_byte_extract(real, ns), lower_byte_extract(imag, ns), complex_type},
1223 ns);
1224}
1225
1229{
1230 // General notes about endianness and the bit-vector conversion:
1231 // A single byte with value 0b10001000 is stored (in irept) as
1232 // exactly this string literal, and its bit-vector encoding will be
1233 // bvt bv={0,0,0,1,0,0,0,1}, i.e., bv[0]==0 and bv[7]==1
1234 //
1235 // A multi-byte value like x=256 would be:
1236 // - little-endian storage: ((char*)&x)[0]==0, ((char*)&x)[1]==1
1237 // - big-endian storage: ((char*)&x)[0]==1, ((char*)&x)[1]==0
1238 // - irept representation: 0000000100000000
1239 // - bvt: {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0}
1240 // <... 8bits ...> <... 8bits ...>
1241 //
1242 // An array {0, 1} will be encoded as bvt bv={0,1}, i.e., bv[1]==1
1243 // concatenation(0, 1) will yield a bvt bv={1,0}, i.e., bv[1]==0
1244 //
1245 // The semantics of byte_extract(endianness, op, offset, T) is:
1246 // interpret ((char*)&op)+offset as the endianness-ordered storage
1247 // of an object of type T at address ((char*)&op)+offset
1248 // For some T x, byte_extract(endianness, x, 0, T) must yield x.
1249 //
1250 // byte_extract for a composite type T or an array will interpret
1251 // the individual subtypes with suitable endianness; the overall
1252 // order of components is not affected by endianness.
1253 //
1254 // Examples:
1255 // unsigned char A[4];
1256 // byte_extract_little_endian(A, 0, unsigned short) requests that
1257 // A[0],A[1] be interpreted as the storage of an unsigned short with
1258 // A[1] being the most-significant byte; byte_extract_big_endian for
1259 // the same operands will select A[0] as the most-significant byte.
1260 //
1261 // int A[2] = {0x01020304,0xDEADBEEF}
1262 // byte_extract_big_endian(A, 0, short) should yield 0x0102
1263 // byte_extract_little_endian(A, 0, short) should yield 0x0304
1264 // To obtain this we first compute byte arrays while taking into
1265 // account endianness:
1266 // big-endian byte representation: {01,02,03,04,DE,AB,BE,EF}
1267 // little-endian byte representation: {04,03,02,01,EF,BE,AB,DE}
1268 // We extract the relevant bytes starting from ((char*)A)+0:
1269 // big-endian: {01,02}; little-endian: {04,03}
1270 // Finally we place them in the appropriate byte order as indicated
1271 // by endianness:
1272 // big-endian: (short)concatenation(01,02)=0x0102
1273 // little-endian: (short)concatenation(03,04)=0x0304
1274
1276 src.id() == ID_byte_extract_little_endian ||
1277 src.id() == ID_byte_extract_big_endian);
1278 const bool little_endian = src.id() == ID_byte_extract_little_endian;
1279
1280 // determine an upper bound of the last byte we might need
1281 auto upper_bound_opt = size_of_expr(src.type(), ns);
1282 if(upper_bound_opt.has_value())
1283 {
1284 upper_bound_opt = simplify_expr(
1285 plus_exprt(
1286 upper_bound_opt.value(),
1288 src.offset(), upper_bound_opt.value().type())),
1289 ns);
1290 }
1291 else if(src.type().id() == ID_empty)
1292 upper_bound_opt = from_integer(0, size_type());
1293
1294 const auto lower_bound_int_opt = numeric_cast<mp_integer>(src.offset());
1295 const auto upper_bound_int_opt =
1296 numeric_cast<mp_integer>(upper_bound_opt.value_or(nil_exprt()));
1297
1298 byte_extract_exprt unpacked(src);
1299 unpacked.op() = unpack_rec(
1300 src.op(),
1301 little_endian,
1302 lower_bound_int_opt,
1303 upper_bound_int_opt,
1304 src.get_bits_per_byte(),
1305 ns);
1308 .get_width() == src.get_bits_per_byte());
1309
1310 if(src.type().id() == ID_array || src.type().id() == ID_vector)
1311 {
1312 const typet &subtype = to_type_with_subtype(src.type()).subtype();
1313
1314 // consider ways of dealing with arrays of unknown subtype size or with a
1315 // subtype size that does not fit byte boundaries; currently we fall back to
1316 // stitching together consecutive elements down below
1317 auto element_bits = pointer_offset_bits(subtype, ns);
1318 if(
1319 element_bits.has_value() && *element_bits >= 1 &&
1320 *element_bits % src.get_bits_per_byte() == 0)
1321 {
1323 src, unpacked, subtype, *element_bits, ns);
1324 }
1325 }
1326 else if(src.type().id() == ID_complex)
1327 {
1328 auto result = lower_byte_extract_complex(src, unpacked, ns);
1329 if(result.has_value())
1330 return std::move(*result);
1331
1332 // else fall back to generic lowering that uses bit masks, below
1333 }
1334 else if(src.type().id() == ID_struct || src.type().id() == ID_struct_tag)
1335 {
1336 const struct_typet &struct_type =
1337 src.type().id() == ID_struct_tag
1339 : to_struct_type(src.type());
1340 const struct_typet::componentst &components = struct_type.components();
1341
1342 bool failed = false;
1343 struct_exprt s({}, src.type());
1344
1345 for(const auto &comp : components)
1346 {
1347 auto component_bits = pointer_offset_bits(comp.type(), ns);
1348
1349 // the next member would be misaligned, abort
1350 if(
1351 !component_bits.has_value() ||
1352 *component_bits % src.get_bits_per_byte() != 0)
1353 {
1354 failed = true;
1355 break;
1356 }
1357
1358 auto member_offset_opt =
1359 member_offset_expr(struct_type, comp.get_name(), ns);
1360
1361 if(!member_offset_opt.has_value())
1362 {
1363 failed = true;
1364 break;
1365 }
1366
1367 plus_exprt new_offset(
1368 unpacked.offset(),
1370 member_offset_opt.value(), unpacked.offset().type()));
1371
1372 byte_extract_exprt tmp(unpacked);
1373 tmp.type() = comp.type();
1374 tmp.offset() = new_offset;
1375
1377 }
1378
1379 if(!failed)
1380 return simplify_expr(std::move(s), ns);
1381 }
1382 else if(src.type().id() == ID_union || src.type().id() == ID_union_tag)
1383 {
1384 const union_typet &union_type =
1385 src.type().id() == ID_union_tag
1386 ? ns.follow_tag(to_union_tag_type(src.type()))
1387 : to_union_type(src.type());
1388
1389 const auto widest_member = union_type.find_widest_union_component(ns);
1390
1391 if(widest_member.has_value())
1392 {
1393 byte_extract_exprt tmp(unpacked);
1394 tmp.type() = widest_member->first.type();
1395
1396 return union_exprt(
1397 widest_member->first.get_name(),
1398 lower_byte_extract(tmp, ns),
1399 src.type());
1400 }
1401 }
1402
1403 const exprt &root = unpacked.op();
1404 const exprt &offset = unpacked.offset();
1405
1406 std::optional<typet> subtype;
1407 std::optional<typet> index_type;
1408 if(root.type().id() == ID_vector)
1409 {
1410 subtype = to_vector_type(root.type()).element_type();
1411 index_type = to_vector_type(root.type()).index_type();
1412 }
1413 else
1414 {
1415 subtype = to_array_type(root.type()).element_type();
1416 index_type = to_array_type(root.type()).index_type();
1417 }
1418
1419 auto subtype_bits = pointer_offset_bits(*subtype, ns);
1420
1422 subtype_bits.has_value() && *subtype_bits == src.get_bits_per_byte(),
1423 "offset bits are byte aligned");
1424
1425 auto size_bits = pointer_offset_bits(unpacked.type(), ns);
1426 if(!size_bits.has_value())
1427 {
1428 auto op0_bits = pointer_offset_bits(unpacked.op().type(), ns);
1429 // all cases with non-constant width should have been handled above
1431 op0_bits.has_value(),
1432 "the extracted width or the source width must be known");
1433 size_bits = op0_bits;
1434 }
1435
1436 mp_integer num_bytes =
1437 (*size_bits) / src.get_bits_per_byte() +
1438 (((*size_bits) % src.get_bits_per_byte() == 0) ? 0 : 1);
1439
1440 // get 'width'-many bytes, and concatenate
1441 const std::size_t width_bytes = numeric_cast_v<std::size_t>(num_bytes);
1443 op.reserve(width_bytes);
1444
1445 for(std::size_t i = 0; i < width_bytes; i++)
1446 {
1447 // the most significant byte comes first in the concatenation!
1448 std::size_t offset_int = little_endian ? (width_bytes - i - 1) : i;
1449
1450 plus_exprt offset_i{
1451 from_integer(offset_int, *index_type),
1452 typecast_exprt::conditional_cast(offset, *index_type)};
1453 simplify(offset_i, ns);
1454
1455 mp_integer index = 0;
1456 if(
1457 offset_i.is_constant() &&
1458 (root.id() == ID_array || root.id() == ID_vector) &&
1459 !to_integer(to_constant_expr(offset_i), index) &&
1460 index < root.operands().size() && index >= 0)
1461 {
1462 // offset is constant and in range
1463 op.push_back(root.operands()[numeric_cast_v<std::size_t>(index)]);
1464 }
1465 else
1466 {
1467 op.push_back(index_exprt(root, offset_i));
1468 }
1469 }
1470
1471 if(width_bytes == 1)
1472 {
1473 return simplify_expr(
1474 typecast_exprt::conditional_cast(op.front(), src.type()), ns);
1475 }
1476 else // width_bytes>=2
1477 {
1478 concatenation_exprt concatenation(
1479 std::move(op),
1480 adjust_width(*subtype, width_bytes * src.get_bits_per_byte()));
1481
1482 endianness_mapt map(concatenation.type(), little_endian, ns);
1483 return bv_to_expr(concatenation, src.type(), map, ns);
1484 }
1485}
1486
1488 const byte_update_exprt &src,
1489 const exprt &value_as_byte_array,
1490 const std::optional<exprt> &non_const_update_bound,
1491 const namespacet &ns);
1492
1503 const byte_update_exprt &src,
1504 const typet &subtype,
1505 const exprt &value_as_byte_array,
1506 const exprt &non_const_update_bound,
1507 const namespacet &ns)
1508{
1509 // TODO we either need a symbol table here or make array comprehensions
1510 // introduce a scope
1511 static std::size_t array_comprehension_index_counter = 0;
1512 ++array_comprehension_index_counter;
1513 symbol_exprt array_comprehension_index{
1514 "$array_comprehension_index_u_a_v" +
1515 std::to_string(array_comprehension_index_counter),
1516 to_array_type(src.type()).index_type()};
1517
1518 binary_predicate_exprt lower_bound{
1520 array_comprehension_index, src.offset().type()),
1521 ID_lt,
1522 src.offset()};
1523 binary_predicate_exprt upper_bound{
1525 array_comprehension_index, non_const_update_bound.type()),
1526 ID_ge,
1527 plus_exprt{
1529 src.offset(), non_const_update_bound.type()),
1530 non_const_update_bound}};
1531
1533 src.id() == ID_byte_update_little_endian ||
1534 src.id() == ID_byte_update_big_endian);
1535 const bool little_endian = src.id() == ID_byte_update_little_endian;
1536 endianness_mapt map(
1537 to_array_type(value_as_byte_array.type()).element_type(),
1538 little_endian,
1539 ns);
1540 if_exprt array_comprehension_body{
1541 or_exprt{std::move(lower_bound), std::move(upper_bound)},
1542 index_exprt{src.op(), array_comprehension_index},
1543 bv_to_expr(
1545 value_as_byte_array,
1547 array_comprehension_index,
1549 src.offset(), array_comprehension_index.type())}},
1550 subtype,
1551 map,
1552 ns)};
1553
1554 return simplify_expr(
1556 array_comprehension_index,
1557 std::move(array_comprehension_body),
1558 to_array_type(src.type())},
1559 ns);
1560}
1561
1572 const byte_update_exprt &src,
1573 const typet &subtype,
1574 const array_exprt &value_as_byte_array,
1575 const std::optional<exprt> &non_const_update_bound,
1576 const namespacet &ns)
1577{
1579 src.id() == ID_byte_update_little_endian ||
1580 src.id() == ID_byte_update_big_endian);
1581 const bool little_endian = src.id() == ID_byte_update_little_endian;
1582
1583 const typet index_type = src.type().id() == ID_array
1584 ? to_array_type(src.type()).index_type()
1585 : to_vector_type(src.type()).index_type();
1586
1587 // apply 'array-update-with' num_elements times
1588 exprt result = src.op();
1589
1590 for(std::size_t i = 0; i < value_as_byte_array.operands().size(); ++i)
1591 {
1592 const exprt &element = value_as_byte_array.operands()[i];
1593
1594 exprt where = simplify_expr(
1595 plus_exprt{
1596 typecast_exprt::conditional_cast(src.offset(), index_type),
1597 from_integer(i, index_type)},
1598 ns);
1599
1600 // skip elements that wouldn't change (skip over typecasts as we might have
1601 // some signed/unsigned char conversions)
1602 const exprt &e = skip_typecast(element);
1603 if(e.id() == ID_index)
1604 {
1605 const index_exprt &index_expr = to_index_expr(e);
1606 if(index_expr.array() == src.op() && index_expr.index() == where)
1607 continue;
1608 }
1609
1610 endianness_mapt map(element.type(), little_endian, ns);
1611 exprt update_value = bv_to_expr(element, subtype, map, ns);
1612 if(non_const_update_bound.has_value())
1613 {
1614 update_value = if_exprt{
1616 from_integer(i, non_const_update_bound->type()),
1617 ID_lt,
1618 *non_const_update_bound},
1619 update_value,
1620 index_exprt{src.op(), where}};
1621 }
1622
1623 result = with_exprt{result, std::move(where), std::move(update_value)};
1624 }
1625
1626 return simplify_expr(std::move(result), ns);
1627}
1628
1645 const byte_update_exprt &src,
1646 const typet &subtype,
1647 const exprt &subtype_size,
1648 const exprt &value_as_byte_array,
1649 const exprt &non_const_update_bound,
1650 const exprt &initial_bytes,
1651 const exprt &first_index,
1652 const exprt &first_update_value,
1653 const namespacet &ns)
1654{
1655 const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
1656 ? ID_byte_extract_little_endian
1657 : ID_byte_extract_big_endian;
1658
1659 // TODO we either need a symbol table here or make array comprehensions
1660 // introduce a scope
1661 static std::size_t array_comprehension_index_counter = 0;
1662 ++array_comprehension_index_counter;
1663 symbol_exprt array_comprehension_index{
1664 "$array_comprehension_index_u_a_v_u" +
1665 std::to_string(array_comprehension_index_counter),
1666 to_array_type(src.type()).index_type()};
1667
1668 // all arithmetic uses offset/index types
1669 PRECONDITION(array_comprehension_index.type() == src.offset().type());
1670 PRECONDITION(subtype_size.type() == src.offset().type());
1671 PRECONDITION(initial_bytes.type() == src.offset().type());
1672 PRECONDITION(first_index.type() == src.offset().type());
1673
1674 // the bound from where updates start
1675 binary_predicate_exprt lower_bound{
1677 array_comprehension_index, first_index.type()),
1678 ID_lt,
1679 first_index};
1680
1681 // The actual value of updates other than at the start or end
1682 plus_exprt offset_expr{
1683 initial_bytes,
1684 mult_exprt{
1685 subtype_size,
1688 array_comprehension_index, first_index.type()),
1689 plus_exprt{first_index, from_integer(1, first_index.type())}}}};
1690 exprt update_value = lower_byte_extract(
1692 extract_opcode,
1693 value_as_byte_array,
1694 std::move(offset_expr),
1695 src.get_bits_per_byte(),
1696 subtype},
1697 ns);
1698
1699 // The number of target array/vector elements being replaced, not including
1700 // a possible partial update at the end of the updated range, which is handled
1701 // below: (non_const_update_bound + (subtype_size - 1)) / subtype_size to
1702 // round up to the nearest multiple of subtype_size.
1703 div_exprt updated_elements{
1704 plus_exprt{
1706 non_const_update_bound, subtype_size.type()),
1707 minus_exprt{subtype_size, from_integer(1, subtype_size.type())}},
1708 subtype_size};
1709
1710 // The last element to be updated: first_index + updated_elements - 1
1711 plus_exprt last_index{
1712 first_index,
1714 std::move(updated_elements), from_integer(1, first_index.type())}};
1715
1716 // The size of a partial update at the end of the updated range, may be zero.
1717 mod_exprt tail_size{
1721 non_const_update_bound, initial_bytes.type()),
1722 initial_bytes},
1723 subtype_size.type()),
1724 subtype_size};
1725
1726 // The bound where updates end, which is conditional on the partial update
1727 // being empty.
1728 binary_predicate_exprt upper_bound{
1730 array_comprehension_index, last_index.type()),
1731 ID_ge,
1732 if_exprt{
1733 equal_exprt{tail_size, from_integer(0, tail_size.type())},
1734 last_index,
1735 plus_exprt{last_index, from_integer(1, last_index.type())}}};
1736
1737 // The actual value of a partial update at the end.
1738 exprt last_update_value = lower_byte_update(
1740 src.id(),
1741 index_exprt{src.op(), last_index},
1743 typecast_exprt::conditional_cast(last_index, subtype_size.type()),
1744 subtype_size}},
1745 value_as_byte_array,
1746 src.get_bits_per_byte()},
1747 ns);
1748
1749 if_exprt array_comprehension_body{
1750 or_exprt{std::move(lower_bound), std::move(upper_bound)},
1751 index_exprt{src.op(), array_comprehension_index},
1752 if_exprt{
1755 array_comprehension_index, first_index.type()),
1756 first_index},
1757 first_update_value,
1758 if_exprt{
1761 array_comprehension_index, last_index.type()),
1762 last_index},
1763 std::move(last_update_value),
1764 std::move(update_value)}}};
1765
1766 return simplify_expr(
1768 array_comprehension_index,
1769 std::move(array_comprehension_body),
1770 to_array_type(src.type())},
1771 ns);
1772}
1773
1785 const byte_update_exprt &src,
1786 const typet &subtype,
1787 const exprt &value_as_byte_array,
1788 const std::optional<exprt> &non_const_update_bound,
1789 const namespacet &ns)
1790{
1791 // do all arithmetic below using index/offset types - the array theory
1792 // back-end is really picky about indices having the same type
1793 auto subtype_size_opt = size_of_expr(subtype, ns);
1794 CHECK_RETURN(subtype_size_opt.has_value());
1795
1796 const exprt subtype_size = simplify_expr(
1798 subtype_size_opt.value(), src.offset().type()),
1799 ns);
1800
1801 // compute the index of the first element of the array/vector that may be
1802 // updated
1804 src.offset().type() == to_array_type(src.op().type()).index_type());
1805 exprt first_index = div_exprt{src.offset(), subtype_size};
1806 simplify(first_index, ns);
1807
1808 // compute the offset within that first element
1809 const exprt update_offset = mod_exprt{src.offset(), subtype_size};
1810
1811 // compute the number of bytes (from the update value) that are going to be
1812 // consumed for updating the first element
1813 const exprt update_size =
1814 from_integer(value_as_byte_array.operands().size(), subtype_size.type());
1815 exprt initial_bytes = minus_exprt{subtype_size, update_offset};
1816 exprt update_bound;
1817 if(non_const_update_bound.has_value())
1818 {
1819 update_bound = typecast_exprt::conditional_cast(
1820 *non_const_update_bound, subtype_size.type());
1821 }
1822 else
1823 {
1825 value_as_byte_array.id() == ID_array,
1826 "value should be an array expression if the update bound is constant");
1827 update_bound = update_size;
1828 }
1829 initial_bytes = if_exprt{
1830 binary_predicate_exprt{initial_bytes, ID_lt, update_bound},
1831 initial_bytes,
1832 update_bound};
1833 simplify(initial_bytes, ns);
1834
1835 // encode the first update: update the original element at first_index (the
1836 // actual update will only be initial_bytes-many bytes from
1837 // value_as_byte_array)
1838 exprt first_update_value = lower_byte_update(
1840 src.id(),
1841 index_exprt{src.op(), first_index},
1842 update_offset,
1843 value_as_byte_array,
1844 src.get_bits_per_byte()},
1845 ns);
1846
1847 if(value_as_byte_array.id() != ID_array)
1848 {
1850 src,
1851 subtype,
1852 subtype_size,
1853 value_as_byte_array,
1854 *non_const_update_bound,
1855 initial_bytes,
1856 first_index,
1857 first_update_value,
1858 ns);
1859 }
1860
1861 // We will update one array/vector element at a time - compute the number of
1862 // update values that will be consumed in each step. If we cannot determine a
1863 // constant value at this time we assume it's at least one byte. The
1864 // byte_extract_exprt within the loop uses the symbolic value (subtype_size),
1865 // we just need to make sure we make progress for the loop to terminate.
1866 std::size_t step_size = 1;
1867 if(subtype_size.is_constant())
1868 step_size = numeric_cast_v<std::size_t>(to_constant_expr(subtype_size));
1869 // Given the first update already encoded, keep track of the offset into the
1870 // update value. Again, the expressions within the loop use the symbolic
1871 // value, this is just an optimization in case we can determine a constant
1872 // offset.
1873 std::size_t offset = 0;
1874 if(initial_bytes.is_constant())
1875 offset = numeric_cast_v<std::size_t>(to_constant_expr(initial_bytes));
1876
1877 with_exprt result{src.op(), first_index, first_update_value};
1878
1879 auto lower_byte_update_array_vector_non_const_one_element =
1880 [&src,
1881 &first_index,
1882 &initial_bytes,
1883 &subtype_size,
1884 &value_as_byte_array,
1885 &ns,
1886 &result](std::size_t i) -> void {
1887 exprt where = simplify_expr(
1888 plus_exprt{first_index, from_integer(i, first_index.type())}, ns);
1889
1890 exprt neg_offset_expr = simplify_expr(
1892 initial_bytes,
1893 mult_exprt{subtype_size, from_integer(i - 1, subtype_size.type())}}},
1894 ns);
1895
1896 exprt element = lower_byte_update(
1898 src.id(),
1899 index_exprt{src.op(), where},
1900 neg_offset_expr,
1901 value_as_byte_array,
1902 src.get_bits_per_byte()},
1903 ns);
1904
1905 result = with_exprt{result, std::move(where), std::move(element)};
1906 };
1907
1908 std::size_t i = 1;
1909 for(; offset + step_size <= value_as_byte_array.operands().size();
1910 offset += step_size, ++i)
1911 {
1912 lower_byte_update_array_vector_non_const_one_element(i);
1913 }
1914
1915 // do the tail
1916 if(offset < value_as_byte_array.operands().size())
1917 lower_byte_update_array_vector_non_const_one_element(i);
1918
1919 return simplify_expr(std::move(result), ns);
1920}
1921
1935 const byte_update_exprt &src,
1936 const mp_integer &offset_bits,
1937 const exprt &element_to_update,
1938 const mp_integer &subtype_bits,
1939 const mp_integer &bits_already_set,
1940 const exprt &value_as_byte_array,
1941 const std::optional<exprt> &non_const_update_bound,
1942 const namespacet &ns)
1943{
1944 // We need to take one or more bytes from value_as_byte_array to modify the
1945 // target element. We need to compute:
1946 // - The position in value_as_byte_array to take bytes from: If subtype_bits
1947 // is less than the size of a byte, then multiple struct/array/vector elements
1948 // will need to be updated using the same byte.
1949 std::size_t first = 0;
1950 // - An upper bound on the number of bytes required from value_as_byte_array.
1951 mp_integer update_elements =
1952 (subtype_bits + src.get_bits_per_byte() - 1) / src.get_bits_per_byte();
1953 // - The offset into the target element: If subtype_bits is greater or equal
1954 // to the size of a byte, then there may be an offset into the target element
1955 // that needs to be taken into account, and multiple bytes will be required.
1956 mp_integer offset_bits_in_target_element = offset_bits - bits_already_set;
1957
1958 if(offset_bits_in_target_element < 0)
1959 {
1960 INVARIANT(
1961 value_as_byte_array.id() != ID_array ||
1962 value_as_byte_array.operands().size() * src.get_bits_per_byte() >
1963 -offset_bits_in_target_element,
1964 "indices past the update should be handled below");
1966 -offset_bits_in_target_element / src.get_bits_per_byte());
1967 offset_bits_in_target_element +=
1968 (-offset_bits_in_target_element / src.get_bits_per_byte()) *
1969 src.get_bits_per_byte();
1970 if(offset_bits_in_target_element < 0)
1971 ++update_elements;
1972 }
1973 else
1974 {
1975 update_elements -= offset_bits_in_target_element / src.get_bits_per_byte();
1976 INVARIANT(
1977 update_elements > 0, "indices before the update should be handled above");
1978 }
1979
1980 std::size_t end = first + numeric_cast_v<std::size_t>(update_elements);
1981 if(value_as_byte_array.id() == ID_array)
1982 end = std::min(end, value_as_byte_array.operands().size());
1984 value_as_byte_array, first, end, src.get_bits_per_byte(), ns);
1985 const std::size_t update_size = update_values.size();
1986 const exprt update_size_expr = from_integer(update_size, size_type());
1987 const array_typet update_type{
1988 bv_typet{src.get_bits_per_byte()}, update_size_expr};
1989
1990 // each case below will set "new_value" as appropriate
1991 exprt new_value;
1992
1993 if(
1994 offset_bits_in_target_element >= 0 &&
1995 offset_bits_in_target_element % src.get_bits_per_byte() == 0)
1996 {
1997 new_value = array_exprt{update_values, update_type};
1998 }
1999 else
2000 {
2001 if(src.id() == ID_byte_update_little_endian)
2002 std::reverse(update_values.begin(), update_values.end());
2003 if(offset_bits_in_target_element < 0)
2004 {
2005 if(src.id() == ID_byte_update_little_endian)
2006 {
2007 new_value = lshr_exprt{
2009 update_values, bv_typet{update_size * src.get_bits_per_byte()}},
2010 numeric_cast_v<std::size_t>(-offset_bits_in_target_element)};
2011 }
2012 else
2013 {
2014 new_value = shl_exprt{
2016 update_values, bv_typet{update_size * src.get_bits_per_byte()}},
2017 numeric_cast_v<std::size_t>(-offset_bits_in_target_element)};
2018 }
2019 }
2020 else
2021 {
2022 const std::size_t offset_bits_int =
2023 numeric_cast_v<std::size_t>(offset_bits_in_target_element);
2024 const std::size_t subtype_bits_int =
2025 numeric_cast_v<std::size_t>(subtype_bits);
2026
2027 extractbits_exprt bits_to_keep{
2028 element_to_update,
2029 subtype_bits_int - offset_bits_int,
2030 bv_typet{offset_bits_int}};
2031 new_value = concatenation_exprt{
2032 bits_to_keep,
2035 update_values, bv_typet{update_size * src.get_bits_per_byte()}},
2036 offset_bits_int,
2037 bv_typet{update_size * src.get_bits_per_byte() - offset_bits_int}},
2038 bv_typet{update_size * src.get_bits_per_byte()}};
2039 }
2040
2041 const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
2042 ? ID_byte_extract_little_endian
2043 : ID_byte_extract_big_endian;
2044
2045 const byte_extract_exprt byte_extract_expr{
2046 extract_opcode,
2047 new_value,
2048 from_integer(0, src.offset().type()),
2049 src.get_bits_per_byte(),
2050 update_type};
2051
2052 new_value = lower_byte_extract(byte_extract_expr, ns);
2053
2054 offset_bits_in_target_element = 0;
2055 }
2056
2057 // With an upper bound on the size of the update established, construct the
2058 // actual update expression. If the exact size of the update is unknown,
2059 // make the size expression conditional.
2060 const byte_update_exprt bu{
2061 src.id(),
2062 element_to_update,
2064 offset_bits_in_target_element / src.get_bits_per_byte(),
2065 src.offset().type()),
2066 new_value,
2067 src.get_bits_per_byte()};
2068
2069 std::optional<exprt> update_bound;
2070 if(non_const_update_bound.has_value())
2071 {
2072 // The size of the update is not constant, and thus is to be symbolically
2073 // bound; first see how many bytes we have left in the update:
2074 // non_const_update_bound > first ? non_const_update_bound - first: 0
2075 const exprt remaining_update_bytes = typecast_exprt::conditional_cast(
2076 if_exprt{
2078 *non_const_update_bound,
2079 ID_gt,
2080 from_integer(first, non_const_update_bound->type())},
2082 *non_const_update_bound,
2083 from_integer(first, non_const_update_bound->type())},
2084 from_integer(0, non_const_update_bound->type())},
2085 size_type());
2086 // Now take the minimum of update-bytes-left and the previously computed
2087 // size of the element to be updated:
2088 update_bound = simplify_expr(
2089 if_exprt{
2090 binary_predicate_exprt{update_size_expr, ID_lt, remaining_update_bytes},
2091 update_size_expr,
2092 remaining_update_bytes},
2093 ns);
2094 }
2095
2096 return lower_byte_update(bu, new_value, update_bound, ns);
2097}
2098
2110 const byte_update_exprt &src,
2111 const typet &subtype,
2112 const std::optional<mp_integer> &subtype_bits,
2113 const exprt &value_as_byte_array,
2114 const std::optional<exprt> &non_const_update_bound,
2115 const namespacet &ns)
2116{
2117 const bool is_array = src.type().id() == ID_array;
2118 exprt size;
2119 typet index_type;
2120 if(is_array)
2121 {
2122 size = to_array_type(src.type()).size();
2123 index_type = to_array_type(src.type()).index_type();
2124 }
2125 else
2126 {
2127 size = to_vector_type(src.type()).size();
2128 index_type = to_vector_type(src.type()).index_type();
2129 }
2130
2131 // fall back to bytewise updates in all non-constant or dubious cases
2132 if(
2133 !size.is_constant() || !src.offset().is_constant() ||
2134 !subtype_bits.has_value() || value_as_byte_array.id() != ID_array)
2135 {
2137 src, subtype, value_as_byte_array, non_const_update_bound, ns);
2138 }
2139
2140 std::size_t num_elements =
2142 mp_integer offset_bits =
2144 src.get_bits_per_byte();
2145
2146 exprt::operandst elements;
2147 elements.reserve(num_elements);
2148
2149 std::size_t i = 0;
2150 // copy the prefix not affected by the update
2151 for(; i < num_elements && (i + 1) * *subtype_bits <= offset_bits; ++i)
2152 elements.push_back(index_exprt{src.op(), from_integer(i, index_type)});
2153
2154 // the modified elements
2155 for(;
2156 i < num_elements &&
2157 i * *subtype_bits < offset_bits + value_as_byte_array.operands().size() *
2158 src.get_bits_per_byte();
2159 ++i)
2160 {
2161 elements.push_back(lower_byte_update_single_element(
2162 src,
2163 offset_bits,
2164 index_exprt{src.op(), from_integer(i, index_type)},
2165 *subtype_bits,
2166 i * *subtype_bits,
2167 value_as_byte_array,
2168 non_const_update_bound,
2169 ns));
2170 }
2171
2172 // copy the tail not affected by the update
2173 for(; i < num_elements; ++i)
2174 elements.push_back(index_exprt{src.op(), from_integer(i, index_type)});
2175
2176 if(is_array)
2177 return simplify_expr(
2178 array_exprt{std::move(elements), to_array_type(src.type())}, ns);
2179 else
2180 return simplify_expr(
2181 vector_exprt{std::move(elements), to_vector_type(src.type())}, ns);
2182}
2183
2194 const byte_update_exprt &src,
2195 const struct_typet &struct_type,
2196 const exprt &value_as_byte_array,
2197 const std::optional<exprt> &non_const_update_bound,
2198 const namespacet &ns)
2199{
2200 exprt::operandst elements;
2201 elements.reserve(struct_type.components().size());
2202
2204 for(const auto &comp : struct_type.components())
2205 {
2206 auto element_width = pointer_offset_bits(comp.type(), ns);
2207
2208 // compute the update offset relative to this struct member - will be
2209 // negative if we are already in the middle of the update or beyond it
2210 exprt offset = simplify_expr(
2212 mult_exprt{
2213 src.offset(),
2214 from_integer(src.get_bits_per_byte(), src.offset().type())},
2216 ns);
2217 auto offset_bits = numeric_cast<mp_integer>(offset);
2218 if(!offset_bits.has_value() || !element_width.has_value())
2219 {
2220 // The offset to update is not constant, either because the original
2221 // offset in src never was, or because a struct member has an unknown
2222 // offset. Abort the attempt to update individual struct members and
2223 // instead turn the operand-to-be-updated into a byte array, which we know
2224 // how to update even if the offset is non-constant.
2225 const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
2226 ? ID_byte_extract_little_endian
2227 : ID_byte_extract_big_endian;
2228
2229 auto src_size_opt = size_of_expr(src.type(), ns);
2230 CHECK_RETURN(src_size_opt.has_value());
2231
2232 const byte_extract_exprt byte_extract_expr{
2233 extract_opcode,
2234 src.op(),
2235 from_integer(0, src.offset().type()),
2236 src.get_bits_per_byte(),
2237 array_typet{bv_typet{src.get_bits_per_byte()}, src_size_opt.value()}};
2238
2239 byte_update_exprt bu = src;
2240 bu.set_op(lower_byte_extract(byte_extract_expr, ns));
2241 bu.type() = bu.op().type();
2242
2243 return lower_byte_extract(
2245 extract_opcode,
2247 bu, value_as_byte_array, non_const_update_bound, ns),
2248 from_integer(0, src.offset().type()),
2249 src.get_bits_per_byte(),
2250 src.type()},
2251 ns);
2252 }
2253
2254 exprt member = member_exprt{src.op(), comp.get_name(), comp.type()};
2255
2256 // we don't need to update anything when
2257 // 1) the update offset is greater than the end of this member (thus the
2258 // relative offset is greater than this element) or
2259 // 2) the update offset plus the size of the update is less than the member
2260 // offset
2261 if(
2262 *offset_bits >= *element_width ||
2263 (value_as_byte_array.id() == ID_array && *offset_bits < 0 &&
2264 -*offset_bits >=
2265 value_as_byte_array.operands().size() * src.get_bits_per_byte()))
2266 {
2267 elements.push_back(member);
2268 member_offset_bits += *element_width;
2269 continue;
2270 }
2271
2272 elements.push_back(lower_byte_update_single_element(
2273 src,
2274 *offset_bits + member_offset_bits,
2275 member,
2276 *element_width,
2278 value_as_byte_array,
2279 non_const_update_bound,
2280 ns));
2281
2282 member_offset_bits += *element_width;
2283 }
2284
2285 return simplify_expr(struct_exprt{std::move(elements), struct_type}, ns);
2286}
2287
2298 const byte_update_exprt &src,
2299 const union_typet &union_type,
2300 const exprt &value_as_byte_array,
2301 const std::optional<exprt> &non_const_update_bound,
2302 const namespacet &ns)
2303{
2304 const auto widest_member = union_type.find_widest_union_component(ns);
2305
2307 widest_member.has_value(),
2308 "lower_byte_update of union of unknown size is not supported");
2309
2310 byte_update_exprt bu = src;
2312 src.op(), widest_member->first.get_name(), widest_member->first.type()});
2313 bu.type() = widest_member->first.type();
2314
2315 return union_exprt{
2316 widest_member->first.get_name(),
2317 lower_byte_update(bu, value_as_byte_array, non_const_update_bound, ns),
2318 src.type()};
2319}
2320
2330 const byte_update_exprt &src,
2331 const exprt &value_as_byte_array,
2332 const std::optional<exprt> &non_const_update_bound,
2333 const namespacet &ns)
2334{
2335 if(src.type().id() == ID_array || src.type().id() == ID_vector)
2336 {
2337 std::optional<typet> subtype;
2338 if(src.type().id() == ID_vector)
2339 subtype = to_vector_type(src.type()).element_type();
2340 else
2341 subtype = to_array_type(src.type()).element_type();
2342
2343 auto element_width = pointer_offset_bits(*subtype, ns);
2344
2345 if(element_width.has_value() && *element_width == src.get_bits_per_byte())
2346 {
2347 if(value_as_byte_array.id() != ID_array)
2348 {
2350 non_const_update_bound.has_value(),
2351 "constant update bound should yield an array expression");
2353 src, *subtype, value_as_byte_array, *non_const_update_bound, ns);
2354 }
2355
2357 src,
2358 *subtype,
2359 to_array_expr(value_as_byte_array),
2360 non_const_update_bound,
2361 ns);
2362 }
2363 else
2364 {
2366 src,
2367 *subtype,
2368 element_width,
2369 value_as_byte_array,
2370 non_const_update_bound,
2371 ns);
2372 }
2373 }
2374 else if(src.type().id() == ID_struct || src.type().id() == ID_struct_tag)
2375 {
2376 const struct_typet &struct_type =
2377 src.type().id() == ID_struct_tag
2379 : to_struct_type(src.type());
2381 src, struct_type, value_as_byte_array, non_const_update_bound, ns);
2382 result.type() = src.type();
2383 return result;
2384 }
2385 else if(src.type().id() == ID_union || src.type().id() == ID_union_tag)
2386 {
2387 const union_typet &union_type =
2388 src.type().id() == ID_union_tag
2389 ? ns.follow_tag(to_union_tag_type(src.type()))
2390 : to_union_type(src.type());
2392 src, union_type, value_as_byte_array, non_const_update_bound, ns);
2393 result.type() = src.type();
2394 return result;
2395 }
2396 else if(
2398 src.type().id() == ID_c_enum || src.type().id() == ID_c_enum_tag)
2399 {
2400 // mask out the bits to be updated, shift the value according to the
2401 // offset and bit-or
2402 const auto type_width = pointer_offset_bits(src.type(), ns);
2403 CHECK_RETURN(type_width.has_value() && *type_width > 0);
2404 const std::size_t type_bits = numeric_cast_v<std::size_t>(*type_width);
2405
2406 exprt::operandst update_bytes;
2407 if(value_as_byte_array.id() == ID_array)
2408 update_bytes = value_as_byte_array.operands();
2409 else
2410 {
2411 update_bytes = instantiate_byte_array(
2412 value_as_byte_array,
2413 0,
2414 (type_bits + src.get_bits_per_byte() - 1) / src.get_bits_per_byte(),
2415 src.get_bits_per_byte(),
2416 ns);
2417 }
2418
2419 const std::size_t update_size_bits =
2420 update_bytes.size() * src.get_bits_per_byte();
2421 const std::size_t bit_width = std::max(type_bits, update_size_bits);
2422
2423 const bool is_little_endian = src.id() == ID_byte_update_little_endian;
2424
2425 exprt val_before =
2426 typecast_exprt::conditional_cast(src.op(), bv_typet{type_bits});
2427 if(bit_width > type_bits)
2428 {
2429 val_before = concatenation_exprt{
2430 bv_typet{bit_width - type_bits}.all_zeros_expr(),
2431 val_before,
2432 bv_typet{bit_width}};
2433
2434 if(!is_little_endian)
2435 to_concatenation_expr(val_before)
2436 .op0()
2437 .swap(to_concatenation_expr(val_before).op1());
2438 }
2439
2440 if(non_const_update_bound.has_value())
2441 {
2442 const exprt src_as_bytes = unpack_rec(
2443 val_before,
2444 src.id() == ID_byte_update_little_endian,
2445 mp_integer{0},
2446 mp_integer{update_bytes.size()},
2447 src.get_bits_per_byte(),
2448 ns);
2449 CHECK_RETURN(src_as_bytes.id() == ID_array);
2450 CHECK_RETURN(src_as_bytes.operands().size() == update_bytes.size());
2451 for(std::size_t i = 0; i < update_bytes.size(); ++i)
2452 {
2453 update_bytes[i] = if_exprt{
2455 from_integer(i, non_const_update_bound->type()),
2456 ID_lt,
2457 *non_const_update_bound},
2458 update_bytes[i],
2459 src_as_bytes.operands()[i]};
2460 }
2461 }
2462
2463 // build mask
2464 exprt mask;
2465 if(is_little_endian)
2466 mask = from_integer(power(2, update_size_bits) - 1, bv_typet{bit_width});
2467 else
2468 {
2470 power(2, bit_width) - power(2, bit_width - update_size_bits),
2471 bv_typet{bit_width});
2472 }
2473
2474 const typet &offset_type = src.offset().type();
2475 mult_exprt offset_in_bits{
2476 src.offset(), from_integer(src.get_bits_per_byte(), offset_type)};
2477
2478 const binary_predicate_exprt offset_ge_zero{
2479 offset_in_bits, ID_ge, from_integer(0, offset_type)};
2480
2481 if_exprt mask_shifted{
2482 offset_ge_zero,
2483 shl_exprt{mask, offset_in_bits},
2484 lshr_exprt{mask, unary_minus_exprt{offset_in_bits}}};
2485 if(!is_little_endian)
2486 {
2487 mask_shifted.true_case().swap(mask_shifted.false_case());
2488 to_shift_expr(mask_shifted.true_case())
2489 .distance()
2490 .swap(to_shift_expr(mask_shifted.false_case()).distance());
2491 }
2492
2493 // original_bits &= ~mask
2494 bitand_exprt bitand_expr{val_before, bitnot_exprt{mask_shifted}};
2495
2496 // concatenate and zero-extend the value
2497 concatenation_exprt value{update_bytes, bv_typet{update_size_bits}};
2498 if(is_little_endian)
2499 std::reverse(value.operands().begin(), value.operands().end());
2500
2501 exprt zero_extended;
2502 if(bit_width > update_size_bits)
2503 {
2504 if(is_little_endian)
2505 zero_extended = zero_extend_exprt{value, bv_typet{bit_width}};
2506 else
2507 {
2508 // Big endian -- the zero is added as LSB.
2509 zero_extended = concatenation_exprt{
2510 value,
2511 bv_typet{bit_width - update_size_bits}.all_zeros_expr(),
2512 bv_typet{bit_width}};
2513 }
2514 }
2515 else
2516 zero_extended = value;
2517
2518 // shift the value
2519 if_exprt value_shifted{
2520 offset_ge_zero,
2521 shl_exprt{zero_extended, offset_in_bits},
2522 lshr_exprt{zero_extended, unary_minus_exprt{offset_in_bits}}};
2523 if(!is_little_endian)
2524 {
2525 value_shifted.true_case().swap(value_shifted.false_case());
2526 to_shift_expr(value_shifted.true_case())
2527 .distance()
2528 .swap(to_shift_expr(value_shifted.false_case()).distance());
2529 }
2530
2531 // original_bits |= newvalue
2532 bitor_exprt bitor_expr{bitand_expr, value_shifted};
2533
2534 if(bit_width > type_bits)
2535 {
2536 endianness_mapt endianness_map(
2537 bitor_expr.type(), src.id() == ID_byte_update_little_endian, ns);
2538 const auto bounds = map_bounds(endianness_map, 0, type_bits - 1);
2539
2540 PRECONDITION(pointer_offset_bits(bitor_expr.type(), ns).has_value());
2541 return simplify_expr(
2543 extractbits_exprt{bitor_expr, bounds.lb, bv_typet{type_bits}},
2544 src.type()),
2545 ns);
2546 }
2547
2548 return simplify_expr(
2549 typecast_exprt::conditional_cast(bitor_expr, src.type()), ns);
2550 }
2551 else
2552 {
2554 false, "lower_byte_update does not yet support ", src.type().id_string());
2555 }
2556}
2557
2559{
2561 src.id() == ID_byte_update_little_endian ||
2562 src.id() == ID_byte_update_big_endian,
2563 "byte update expression should either be little or big endian");
2564
2565 // An update of a void-typed object or update by a void-typed value is the
2566 // source operand (this is questionable, but may arise when dereferencing
2567 // invalid pointers).
2568 if(src.type().id() == ID_empty || src.value().type().id() == ID_empty)
2569 return src.op();
2570
2571 // byte_update lowering proceeds as follows:
2572 // 1) Determine the size of the update, with the size of the object to be
2573 // updated as an upper bound. We fail if neither can be determined.
2574 // 2) Turn the update value into a byte array of the size determined above.
2575 // 3) If the offset is not constant, turn the object into a byte array, and
2576 // use a "with" expression to encode the update; else update the values in
2577 // place.
2578 // 4) Construct a new object.
2579 std::optional<exprt> non_const_update_bound;
2580 // update value, may require extension to full bytes
2581 exprt update_value = src.value();
2582 auto update_size_expr_opt = size_of_expr(update_value.type(), ns);
2583 CHECK_RETURN(update_size_expr_opt.has_value());
2584 simplify(update_size_expr_opt.value(), ns);
2585
2586 const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
2587 ? ID_byte_extract_little_endian
2588 : ID_byte_extract_big_endian;
2589 const std::size_t bits_per_byte = src.get_bits_per_byte();
2590
2591 if(!update_size_expr_opt.value().is_constant())
2592 non_const_update_bound = *update_size_expr_opt;
2593 else
2594 {
2595 auto update_bits = pointer_offset_bits(update_value.type(), ns);
2596 // If the following invariant fails, then the type was only found to be
2597 // constant via simplification. Such instances should be fixed at the place
2598 // introducing these constant-but-not-constant_exprt type sizes.
2600 update_bits.has_value(), "constant size-of should imply fixed bit width");
2601 const size_t update_bits_int = numeric_cast_v<size_t>(*update_bits);
2602
2603 if(update_bits_int % bits_per_byte != 0)
2604 {
2606 can_cast_type<bitvector_typet>(update_value.type()),
2607 "non-byte aligned type expected to be a bitvector type");
2608 const byte_extract_exprt overlapping_byte_extract{
2609 extract_opcode,
2610 src.op(),
2612 plus_exprt{
2613 src.offset(),
2614 from_integer(update_bits_int / bits_per_byte, src.offset().type())},
2615 ns),
2616 src.get_bits_per_byte(),
2617 bv_typet{bits_per_byte}};
2618 const exprt overlapping_byte =
2619 lower_byte_extract(overlapping_byte_extract, ns);
2620
2621 size_t n_extra_bits = bits_per_byte - update_bits_int % bits_per_byte;
2622 extractbits_exprt extra_bits{overlapping_byte, 0, bv_typet{n_extra_bits}};
2623
2624 update_value = concatenation_exprt{
2626 update_value, bv_typet{update_bits_int}),
2627 extra_bits,
2628 adjust_width(update_value.type(), update_bits_int + n_extra_bits)};
2629 }
2630 else
2631 {
2632 update_size_expr_opt = from_integer(
2633 update_bits_int / bits_per_byte, update_size_expr_opt->type());
2634 }
2635 }
2636
2637 const byte_extract_exprt byte_extract_expr{
2638 extract_opcode,
2639 update_value,
2640 from_integer(0, src.offset().type()),
2641 src.get_bits_per_byte(),
2642 array_typet{bv_typet{bits_per_byte}, *update_size_expr_opt}};
2643
2644 const exprt value_as_byte_array = lower_byte_extract(byte_extract_expr, ns);
2645
2646 exprt result =
2647 lower_byte_update(src, value_as_byte_array, non_const_update_bound, ns);
2648 return result;
2649}
2650
2652{
2653 exprt tmp = src;
2654
2655 // destroys any sharing, should use hash table
2656 Forall_operands(it, tmp)
2657 {
2658 *it = lower_byte_operators(*it, ns);
2659 }
2660
2661 if(
2662 src.id() == ID_byte_update_little_endian ||
2663 src.id() == ID_byte_update_big_endian)
2664 {
2665 return lower_byte_update(to_byte_update_expr(tmp), ns);
2666 }
2667 else if(
2668 src.id() == ID_byte_extract_little_endian ||
2669 src.id() == ID_byte_extract_big_endian)
2670 {
2672 }
2673 else
2674 return tmp;
2675}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
bool to_integer(const constant_exprt &expr, mp_integer &int_value)
Convert a constant expression expr to an arbitrary-precision integer.
mp_integer power(const mp_integer &base, const mp_integer &exponent)
A multi-precision implementation of the power operator.
Target numeric_cast_v(const mp_integer &arg)
Convert an mp_integer to integral type Target An invariant will fail if the conversion is not possibl...
std::optional< Target > numeric_cast(const exprt &arg)
Converts an expression to any integral type.
API to expression classes for bitvectors.
const shift_exprt & to_shift_expr(const exprt &expr)
Cast an exprt to a shift_exprt.
const concatenation_exprt & to_concatenation_expr(const exprt &expr)
Cast an exprt to a concatenation_exprt.
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
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)
unsignedbv_typet size_type()
Definition c_types.cpp:50
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 union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition c_types.h:184
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition c_types.h:224
Expression to define a mapping from an argument (index) to elements.
Definition std_expr.h:3586
Array constructor from list of elements.
Definition std_expr.h:1570
Arrays with given size.
Definition std_types.h:806
typet index_type() const
The type of the index expressions into any instance of this type.
Definition std_types.cpp:34
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 expressions that are predicates, i.e., Boolean-typed, and that take exactly two argu...
Definition std_expr.h:737
Bit-wise AND Any number of operands that is greater or equal one.
Bit-wise negation of bit-vectors.
Bit-wise OR Any number of operands that is greater or equal one.
Base class of fixed-width bit-vector types.
constant_exprt all_zeros_expr() const
std::size_t get_width() const
Fixed-width bit-vector without numerical interpretation.
Expression of type type extracted from some object op starting at position offset (given in number of...
std::size_t get_bits_per_byte() const
Expression corresponding to op() where the bytes starting at position offset (given in number of byte...
const exprt & offset() const
const exprt & op() const
void set_op(exprt e)
std::size_t get_bits_per_byte() const
const exprt & value() const
Type for C bit fields These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (...
Definition c_types.h:20
Complex constructor from a pair of numbers.
Definition std_expr.h:1859
Imaginary part of the expression describing a complex number.
Definition std_expr.h:1957
Real part of the expression describing a complex number.
Definition std_expr.h:1920
Complex numbers made of pair of given subtype.
Definition std_types.h:1023
Concatenation of bit-vector operands.
Division.
Definition std_expr.h:1152
Union constructor to support unions without any member (a GCC/Clang feature).
Definition std_expr.h:1783
Maps a big-endian offset to a little-endian offset.
size_t number_of_bits() const
size_t map_bit(size_t bit) const
Equality.
Definition std_expr.h:1339
Base class for all expressions.
Definition expr.h:57
std::vector< exprt > operandst
Definition expr.h:59
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
operandst & operands()
Definition expr.h:95
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition expr.h:171
Extracts a sub-range of a bit-vector operand.
The trinary if-then-else operator.
Definition std_expr.h:2426
exprt & false_case()
Definition std_expr.h:2463
exprt & true_case()
Definition std_expr.h:2453
Array index operator.
Definition std_expr.h:1431
exprt & index()
Definition std_expr.h:1471
exprt & array()
Definition std_expr.h:1461
const std::string & id_string() const
Definition irep.h:391
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
Logical right shift.
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 & op0()
Definition std_expr.h:936
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition namespace.cpp:49
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 OR All operands must be boolean, and the result is always boolean.
Definition std_expr.h:2193
The plus expression Associativity is not specified.
Definition std_expr.h:1006
exprt & distance()
Left shift.
Fixed-width bit-vector with two's complement interpretation.
Struct constructor from list of elements.
Definition std_expr.h:1820
Structure type, corresponds to C style structs.
Definition std_types.h:230
const componentst & components() const
Definition std_types.h:146
std::vector< componentt > componentst
Definition std_types.h:139
Expression to hold a symbol (variable).
Definition std_expr.h:132
const typet & subtype() const
Definition type.h:187
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
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
std::optional< std::pair< struct_union_typet::componentt, mp_integer > > find_widest_union_component(const namespacet &ns) const
Determine the member of maximum bit width in a union type.
Definition c_types.cpp:300
Fixed-width bit-vector with unsigned binary interpretation.
Vector constructor from list of elements.
Definition std_expr.h:1686
The vector type.
Definition std_types.h:954
const constant_exprt & size() const
typet index_type() const
The type of any index expression into an instance of this type.
const typet & element_type() const
The type of the elements of the vector.
Definition std_types.h:970
Operator to update elements in structs and arrays.
Definition std_expr.h:2520
zero extension The operand is converted to the given type by either a) truncating if the new type is ...
#define Forall_operands(it, expr)
Definition expr.h:28
bool can_cast_type(const typet &base)
Check whether a reference to a generic typet is of a specific derived class.
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
Deprecated expression utility functions.
static exprt lower_byte_update_union(const byte_update_exprt &src, const union_typet &union_type, const exprt &value_as_byte_array, const std::optional< exprt > &non_const_update_bound, const namespacet &ns)
Apply a byte update src to a union typed operand using the byte array value_as_byte_array as update v...
static exprt lower_byte_update_byte_array_vector(const byte_update_exprt &src, const typet &subtype, const array_exprt &value_as_byte_array, const std::optional< exprt > &non_const_update_bound, const namespacet &ns)
Apply a byte update src to an array/vector of bytes using the byte array value_as_byte_array as updat...
static exprt bv_to_expr(const exprt &bitvector_expr, const typet &target_type, const endianness_mapt &endianness_map, const namespacet &ns)
Convert a bitvector-typed expression bitvector_expr to an expression of type target_type.
static exprt bv_to_union_expr(const exprt &bitvector_expr, const union_typet &union_type, const endianness_mapt &endianness_map, const namespacet &ns)
Convert a bitvector-typed expression bitvector_expr to a union-typed expression.
static complex_exprt bv_to_complex_expr(const exprt &bitvector_expr, const complex_typet &complex_type, const endianness_mapt &endianness_map, const namespacet &ns)
Convert a bitvector-typed expression bitvector_expr to a complex-typed expression.
static array_exprt unpack_struct(const exprt &src, bool little_endian, const std::optional< mp_integer > &offset_bytes, const std::optional< mp_integer > &max_bytes, const std::size_t bits_per_byte, const namespacet &ns)
Rewrite a struct-typed expression into its individual bytes.
static exprt::operandst instantiate_byte_array(const exprt &src, std::size_t lower_bound, std::size_t upper_bound, const std::size_t bits_per_byte, const namespacet &ns)
Build the individual bytes to be used in an update.
exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
rewrite byte extraction from an array to byte extraction from a concatenation of array index expressi...
bitvector_typet adjust_width(const typet &src, std::size_t new_width)
changes the width of the given bitvector type
static vector_exprt bv_to_vector_expr(const exprt &bitvector_expr, const vector_typet &vector_type, const endianness_mapt &endianness_map, const namespacet &ns)
Convert a bitvector-typed expression bitvector_expr to a vector-typed expression.
static void process_bit_fields(exprt::operandst &&bit_fields, std::size_t total_bits, exprt::operandst &dest, bool little_endian, const std::optional< mp_integer > &offset_bytes, const std::optional< mp_integer > &max_bytes, const std::size_t bits_per_byte, const namespacet &ns)
Extract bytes from a sequence of bitvector-typed elements.
static struct_exprt bv_to_struct_expr(const exprt &bitvector_expr, const struct_typet &struct_type, const endianness_mapt &endianness_map, const namespacet &ns)
Convert a bitvector-typed expression bitvector_expr to a struct-typed expression.
static array_exprt unpack_complex(const exprt &src, bool little_endian, const std::size_t bits_per_byte, const namespacet &ns)
Rewrite a complex_exprt into its individual bytes.
static exprt unpack_array_vector_no_known_bounds(const exprt &src, std::size_t el_bytes, bool little_endian, const std::size_t bits_per_byte, const namespacet &ns)
Rewrite an array or vector into its individual bytes when no maximum number of bytes is known.
static exprt lower_byte_update_array_vector(const byte_update_exprt &src, const typet &subtype, const std::optional< mp_integer > &subtype_bits, const exprt &value_as_byte_array, const std::optional< exprt > &non_const_update_bound, const namespacet &ns)
Apply a byte update src to an array/vector typed operand using the byte array value_as_byte_array as ...
static exprt lower_byte_update_array_vector_non_const(const byte_update_exprt &src, const typet &subtype, const exprt &value_as_byte_array, const std::optional< exprt > &non_const_update_bound, const namespacet &ns)
Apply a byte update src to an array/vector typed operand, using the byte array value_as_byte_array as...
static array_exprt bv_to_array_expr(const exprt &bitvector_expr, const array_typet &array_type, const endianness_mapt &endianness_map, const namespacet &ns)
Convert a bitvector-typed expression bitvector_expr to an array-typed expression.
static boundst map_bounds(const endianness_mapt &endianness_map, std::size_t lower_bound, std::size_t upper_bound)
Map bit boundaries according to endianness.
exprt lower_byte_operators(const exprt &src, const namespacet &ns)
Rewrite an expression possibly containing byte-extract or -update expressions to more fundamental ope...
static exprt lower_byte_extract_array_vector(const byte_extract_exprt &src, const byte_extract_exprt &unpacked, const typet &subtype, const mp_integer &element_bits, const namespacet &ns)
Rewrite a byte extraction of an array/vector-typed result to byte extraction of the individual compon...
static exprt lower_byte_update(const byte_update_exprt &src, const exprt &value_as_byte_array, const std::optional< exprt > &non_const_update_bound, const namespacet &ns)
Apply a byte update src using the byte array value_as_byte_array as update value.
static exprt unpack_array_vector(const exprt &src, const std::optional< mp_integer > &src_size, const mp_integer &element_bits, bool little_endian, const std::optional< mp_integer > &offset_bytes, const std::optional< mp_integer > &max_bytes, const std::size_t bits_per_byte, const namespacet &ns)
Rewrite an array or vector into its individual bytes.
static exprt unpack_rec(const exprt &src, bool little_endian, const std::optional< mp_integer > &offset_bytes, const std::optional< mp_integer > &max_bytes, const std::size_t bits_per_byte, const namespacet &ns, bool unpack_byte_array=false)
Rewrite an object into its individual bytes.
static exprt lower_byte_update_struct(const byte_update_exprt &src, const struct_typet &struct_type, const exprt &value_as_byte_array, const std::optional< exprt > &non_const_update_bound, const namespacet &ns)
Apply a byte update src to a struct typed operand using the byte array value_as_byte_array as update ...
static std::optional< exprt > lower_byte_extract_complex(const byte_extract_exprt &src, const byte_extract_exprt &unpacked, const namespacet &ns)
Rewrite a byte extraction of a complex-typed result to byte extraction of the individual components t...
static exprt lower_byte_update_byte_array_vector_non_const(const byte_update_exprt &src, const typet &subtype, const exprt &value_as_byte_array, const exprt &non_const_update_bound, const namespacet &ns)
Apply a byte update src to an array/vector of bytes using the byte-array typed expression value_as_by...
static exprt lower_byte_update_single_element(const byte_update_exprt &src, const mp_integer &offset_bits, const exprt &element_to_update, const mp_integer &subtype_bits, const mp_integer &bits_already_set, const exprt &value_as_byte_array, const std::optional< exprt > &non_const_update_bound, const namespacet &ns)
Byte update a struct/array/vector element.
static exprt lower_byte_update_array_vector_unbounded(const byte_update_exprt &src, const typet &subtype, const exprt &subtype_size, const exprt &value_as_byte_array, const exprt &non_const_update_bound, const exprt &initial_bytes, const exprt &first_index, const exprt &first_update_value, const namespacet &ns)
Apply a byte update src to an array/vector typed operand, using the byte array value_as_byte_array as...
output_type narrow_cast(input_type value)
Alias for static_cast intended to be used for numeric casting Rationale: Easier to grep than static_c...
Definition narrow.h:19
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
std::optional< mp_integer > pointer_offset_bits(const typet &type, const namespacet &ns)
std::optional< mp_integer > member_offset_bits(const struct_typet &type, const irep_idt &member, const namespacet &ns)
std::optional< exprt > size_of_expr(const typet &type, const namespacet &ns)
std::optional< exprt > member_offset_expr(const member_exprt &member_expr, const namespacet &ns)
Pointer Logic.
const std::size_t sharing_mapt< keyT, valueT, fail_if_equal, hashT, equalT >::mask
bool simplify(exprt &expr, const namespacet &ns)
exprt simplify_expr(exprt src, const namespacet &ns)
BigInt mp_integer
Definition smt_terms.h:17
#define PRECONDITION_WITH_DIAGNOSTICS(CONDITION,...)
Definition invariant.h:464
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#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 INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition std_expr.h:1494
const array_exprt & to_array_expr(const exprt &expr)
Cast an exprt to an array_exprt.
Definition std_expr.h:1614
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3078
const vector_typet & to_vector_type(const typet &type)
Cast a typet to a vector_typet.
Definition std_types.h:1006
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
const string_constantt & to_string_constant(const exprt &expr)
static bool failed(bool error_indicator)
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition type.h:208
dstringt irep_idt