24 const exprt &bitvector_expr,
25 const typet &target_type,
38 std::size_t lower_bound,
39 std::size_t upper_bound)
42 result.
lb = lower_bound;
43 result.
ub = upper_bound;
51 if(result.
ub < result.
lb)
52 std::swap(result.
lb, result.
ub);
61 if(src.
id() == ID_unsignedbv)
63 else if(src.
id() == ID_signedbv)
65 else if(src.
id() == ID_bv)
67 else if(src.
id() == ID_c_enum)
69 else if(src.
id() == ID_c_bit_field)
79 const exprt &bitvector_expr,
87 operands.reserve(components.size());
89 for(
const auto &comp : components)
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);
99 if(component_bits == 0)
118 if(component_bits_opt.has_value())
128 const exprt &bitvector_expr,
135 if(components.empty())
140 std::size_t component_bits;
141 if(widest_member.has_value())
142 component_bits = numeric_cast_v<std::size_t>(widest_member->second);
146 if(component_bits == 0)
149 components.front().get_name(),
150 bv_to_expr(bitvector_expr, components.front().
type(), endianness_map, ns),
154 const auto bounds =
map_bounds(endianness_map, 0, component_bits - 1);
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();
176 const exprt &bitvector_expr,
181 auto num_elements = numeric_cast<std::size_t>(array_type.
size());
184 const std::size_t total_bits =
186 if(!num_elements.has_value())
188 if(!subtype_bits.has_value() || *subtype_bits == 0)
189 num_elements = total_bits;
191 num_elements = total_bits / numeric_cast_v<std::size_t>(*subtype_bits);
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");
199 operands.reserve(*num_elements);
200 for(std::size_t i = 0; i < *num_elements; ++i)
202 if(subtype_bits.has_value())
204 const std::size_t subtype_bits_int =
205 numeric_cast_v<std::size_t>(*subtype_bits);
207 endianness_map, i * subtype_bits_int, ((i + 1) * subtype_bits_int) - 1);
220 bitvector_expr, array_type.
element_type(), endianness_map, ns));
224 return array_exprt{std::move(operands), array_type};
230 const exprt &bitvector_expr,
235 const std::size_t num_elements =
236 numeric_cast_v<std::size_t>(vector_type.
size());
239 !subtype_bits.has_value() ||
240 *subtype_bits * num_elements ==
242 "subtype width times vector size should be total bitvector width");
245 operands.reserve(num_elements);
246 for(std::size_t i = 0; i < num_elements; ++i)
248 if(subtype_bits.has_value())
250 const std::size_t subtype_bits_int =
251 numeric_cast_v<std::size_t>(*subtype_bits);
253 endianness_map, i * subtype_bits_int, ((i + 1) * subtype_bits_int) - 1);
266 bitvector_expr, vector_type.
element_type(), endianness_map, ns));
276 const exprt &bitvector_expr,
281 const std::size_t total_bits =
284 std::size_t subtype_bits;
285 if(subtype_bits_opt.has_value())
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");
293 subtype_bits = total_bits / 2;
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);
331 const exprt &bitvector_expr,
332 const typet &target_type,
338 if(target_type.
id() == ID_floatbv)
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 &&
356 else if(target_type.
id() == ID_struct)
361 else if(target_type.
id() == ID_struct_tag)
368 result.
type() = target_type;
369 return std::move(result);
371 else if(target_type.
id() == ID_union)
374 bitvector_expr,
to_union_type(target_type), endianness_map, ns);
376 else if(target_type.
id() == ID_union_tag)
383 result.
type() = target_type;
386 else if(target_type.
id() == ID_array)
389 bitvector_expr,
to_array_type(target_type), endianness_map, ns);
391 else if(target_type.
id() == ID_vector)
396 else if(target_type.
id() == ID_complex)
404 false,
"bv_to_expr does not yet support ", target_type.
id_string());
411 const std::optional<mp_integer> &offset_bytes,
412 const std::optional<mp_integer> &max_bytes,
413 const std::size_t bits_per_byte,
415 bool unpack_byte_array =
false);
426 std::size_t lower_bound,
427 std::size_t upper_bound,
428 const std::size_t bits_per_byte,
433 if(src.
id() == ID_array)
437 src.
operands().begin() + narrow_cast<std::ptrdiff_t>(lower_bound),
438 src.
operands().begin() + narrow_cast<std::ptrdiff_t>(upper_bound)};
441 const typet &element_type = src.
type().
id() == ID_array
444 const typet index_type = src.
type().
id() == ID_array
451 bytes.reserve(upper_bound - lower_bound);
452 for(std::size_t i = lower_bound; i < upper_bound; ++i)
470 std::size_t el_bytes,
472 const std::size_t bits_per_byte,
475 const typet index_type = src.
type().
id() == ID_array
481 static std::size_t array_comprehension_index_counter = 0;
482 ++array_comprehension_index_counter;
484 "$array_comprehension_index_a_v" +
493 unpack_rec(element, little_endian, {}, {}, bits_per_byte, ns,
false);
497 exprt body = sub_operands.front();
499 array_comprehension_index,
500 from_integer(el_bytes, array_comprehension_index.type())};
501 for(std::size_t i = 1; i < el_bytes; ++i)
509 const exprt array_vector_size = src.
type().
id() == ID_vector
514 std::move(array_comprehension_index),
539 const std::optional<mp_integer> &src_size,
542 const std::optional<mp_integer> &offset_bytes,
543 const std::optional<mp_integer> &max_bytes,
544 const std::size_t bits_per_byte,
547 const std::size_t el_bytes = numeric_cast_v<std::size_t>(
548 (element_bits + bits_per_byte - 1) / bits_per_byte);
550 if(!src_size.has_value() && !max_bytes.has_value())
553 el_bytes > 0 && element_bits % bits_per_byte == 0,
554 "unpacking of arrays with non-byte-aligned elements is not supported");
556 src, el_bytes, little_endian, bits_per_byte, ns);
564 std::optional<mp_integer> num_elements = src_size;
565 if(element_bits > 0 && element_bits % bits_per_byte == 0)
567 if(!num_elements.has_value())
570 num_elements = (*max_bytes + el_bytes - 1) / el_bytes;
573 if(offset_bytes.has_value())
576 first_element = *offset_bytes / el_bytes;
578 byte_operands.resize(
579 numeric_cast_v<std::size_t>(std::min(
580 *offset_bytes - (*offset_bytes % el_bytes),
581 *num_elements * el_bytes)),
590 num_elements = *max_bytes;
593 const typet index_type = src_simp.
type().
id() == ID_array
597 for(
mp_integer i = first_element; i < *num_elements; ++i)
602 (src_simp.
id() == ID_array || src_simp.
id() == ID_vector) &&
605 const std::size_t index_int = numeric_cast_v<std::size_t>(i);
606 element = src_simp.
operands()[index_int];
616 const std::optional<mp_integer> element_max_bytes =
618 ? std::min(
mp_integer{el_bytes}, *max_bytes - byte_operands.size())
619 : std::optional<mp_integer>{};
620 const std::size_t element_max_bytes_int =
621 element_max_bytes ? numeric_cast_v<std::size_t>(*element_max_bytes)
625 element, little_endian, {}, element_max_bytes, bits_per_byte, ns,
true);
628 byte_operands.insert(
629 byte_operands.end(), sub_operands.begin(), sub_operands.end());
631 if(max_bytes && byte_operands.size() >= *max_bytes)
635 const std::size_t size = byte_operands.size();
637 std::move(byte_operands),
654 std::size_t total_bits,
657 const std::optional<mp_integer> &offset_bytes,
658 const std::optional<mp_integer> &max_bytes,
659 const std::size_t bits_per_byte,
663 std::move(bit_fields),
bv_typet{total_bits}};
676 std::make_move_iterator(sub.
operands().begin()),
677 std::make_move_iterator(sub.
operands().end()));
693 const std::optional<mp_integer> &offset_bytes,
694 const std::optional<mp_integer> &max_bytes,
695 const std::size_t bits_per_byte,
699 src.
type().
id() == ID_struct_tag
704 std::optional<mp_integer> offset_in_member;
705 std::optional<mp_integer> max_bytes_left;
706 std::optional<std::pair<exprt::operandst, std::size_t>> bit_fields;
710 for(
auto it = components.begin(); it != components.end(); ++it)
712 const auto &comp = *it;
721 component_bits.has_value() ||
722 (std::next(it) == components.end() && !bit_fields.has_value()),
723 "members of non-constant width should come last in a struct");
726 if(src.
id() == ID_struct)
732 if(bit_fields.has_value())
735 std::move(bit_fields->first),
746 if(offset_bytes.has_value())
751 if(*offset_in_member < 0)
752 offset_in_member.reset();
755 if(max_bytes.has_value())
758 if(*max_bytes_left < 0)
765 (component_bits.has_value() && *component_bits % bits_per_byte != 0))
767 if(!bit_fields.has_value())
770 const std::size_t bits_int = numeric_cast_v<std::size_t>(*component_bits);
771 bit_fields->first.insert(
772 little_endian ? bit_fields->first.begin() : bit_fields->first.end(),
774 bit_fields->second += bits_int;
782 !bit_fields.has_value(),
783 "all preceding members should have been processed");
786 component_bits.has_value() && offset_in_member.has_value() &&
787 *offset_in_member * bits_per_byte >= *component_bits)
791 byte_operands.resize(
792 byte_operands.size() +
793 numeric_cast_v<std::size_t>(*component_bits / bits_per_byte),
807 byte_operands.insert(
809 std::make_move_iterator(sub.
operands().begin()),
810 std::make_move_iterator(sub.
operands().end()));
813 if(component_bits.has_value())
818 if(bit_fields.has_value())
821 std::move(bit_fields->first),
831 const std::size_t size = byte_operands.size();
833 std::move(byte_operands),
846 const std::size_t bits_per_byte,
860 *subtype_bits / bits_per_byte,
870 *subtype_bits / bits_per_byte,
874 byte_operands.insert(
876 std::make_move_iterator(sub_imag.
operands().begin()),
877 std::make_move_iterator(sub_imag.
operands().end()));
879 const std::size_t size = byte_operands.size();
881 std::move(byte_operands),
900 const std::optional<mp_integer> &offset_bytes,
901 const std::optional<mp_integer> &max_bytes,
902 const std::size_t bits_per_byte,
904 bool unpack_byte_array)
906 if(src.
type().
id() == ID_array)
915 !unpack_byte_array && *element_bits == bits_per_byte &&
921 const auto constant_size_opt = numeric_cast<mp_integer>(array_type.
size());
932 else if(src.
type().
id() == ID_vector)
941 !unpack_byte_array && *element_bits == bits_per_byte &&
949 numeric_cast_v<mp_integer>(vector_type.
size()),
957 else if(src.
type().
id() == ID_complex)
961 else if(src.
type().
id() == ID_struct || src.
type().
id() == ID_struct_tag)
964 src, little_endian, offset_bytes, max_bytes, bits_per_byte, ns);
966 else if(src.
type().
id() == ID_union || src.
type().
id() == ID_union_tag)
969 src.
type().
id() == ID_union_tag
975 if(widest_member.has_value())
978 src, widest_member->first.get_name(), widest_member->first.
type()};
983 widest_member->second,
1001 else if(src.
type().
id() == ID_pointer)
1012 else if(src.
id() == ID_string_constant)
1034 else if(src.
type().
id() != ID_empty)
1039 DATA_INVARIANT(bits_opt.has_value(),
"basic type should have a fixed size");
1045 if(max_bytes.has_value())
1047 const auto max_bits = *max_bytes * bits_per_byte;
1050 last_bit = std::min(last_bit, max_bits);
1054 bit_offset = std::max(
mp_integer{0}, last_bit - max_bits);
1059 src,
bv_typet{numeric_cast_v<std::size_t>(total_bits)});
1060 auto const byte_type =
bv_typet{bits_per_byte};
1065 for(; bit_offset < last_bit; bit_offset += bits_per_byte)
1078 byte_operands.push_back(extractbits);
1080 byte_operands.insert(byte_operands.begin(), extractbits);
1083 const std::size_t size = byte_operands.size();
1085 return array_exprt{std::move(byte_operands), std::move(array_type)};
1105 const typet &subtype,
1109 std::optional<std::size_t> num_elements;
1110 if(src.
type().
id() == ID_array)
1115 if(num_elements.has_value())
1118 operands.reserve(*num_elements);
1119 for(std::size_t i = 0; i < *num_elements; ++i)
1128 tmp.
type() = subtype;
1129 tmp.
offset() = new_offset;
1135 if(src.
type().
id() == ID_array)
1148 static std::size_t array_comprehension_index_counter = 0;
1149 ++array_comprehension_index_counter;
1151 "$array_comprehension_index_a" +
1159 array_comprehension_index,
1162 array_comprehension_index.type())},
1166 body.
type() = subtype;
1167 body.
offset() = std::move(new_offset);
1170 std::move(array_comprehension_index),
1197 real.
type() = subtype;
1204 imag.
type() = subtype;
1263 src.
id() == ID_byte_extract_little_endian ||
1264 src.
id() == ID_byte_extract_big_endian);
1265 const bool little_endian = src.
id() == ID_byte_extract_little_endian;
1269 if(upper_bound_opt.has_value())
1273 upper_bound_opt.value(),
1275 src.
offset(), upper_bound_opt.value().
type())),
1278 else if(src.
type().
id() == ID_empty)
1281 const auto lower_bound_int_opt = numeric_cast<mp_integer>(src.
offset());
1282 const auto upper_bound_int_opt =
1283 numeric_cast<mp_integer>(upper_bound_opt.value_or(
nil_exprt()));
1289 lower_bound_int_opt,
1290 upper_bound_int_opt,
1297 if(src.
type().
id() == ID_array || src.
type().
id() == ID_vector)
1306 element_bits.has_value() && *element_bits >= 1 &&
1310 src, unpacked, subtype, *element_bits, ns);
1313 else if(src.
type().
id() == ID_complex)
1316 if(result.has_value())
1317 return std::move(*result);
1321 else if(src.
type().
id() == ID_struct || src.
type().
id() == ID_struct_tag)
1324 src.
type().
id() == ID_struct_tag
1332 for(
const auto &comp : components)
1338 !component_bits.has_value() ||
1345 auto member_offset_opt =
1348 if(!member_offset_opt.has_value())
1357 member_offset_opt.value(), unpacked.
offset().
type()));
1360 tmp.
type() = comp.type();
1361 tmp.
offset() = new_offset;
1369 else if(src.
type().
id() == ID_union || src.
type().
id() == ID_union_tag)
1372 src.
type().
id() == ID_union_tag
1378 if(widest_member.has_value())
1381 tmp.
type() = widest_member->first.type();
1384 widest_member->first.get_name(),
1390 const exprt &root = unpacked.
op();
1393 std::optional<typet> subtype;
1394 std::optional<typet> index_type;
1395 if(root.
type().
id() == ID_vector)
1410 "offset bits are byte aligned");
1413 if(!size_bits.has_value())
1418 op0_bits.has_value(),
1419 "the extracted width or the source width must be known");
1420 size_bits = op0_bits;
1428 const std::size_t width_bytes = numeric_cast_v<std::size_t>(num_bytes);
1430 op.reserve(width_bytes);
1432 for(std::size_t i = 0; i < width_bytes; i++)
1435 std::size_t offset_int = little_endian ? (width_bytes - i - 1) : i;
1444 offset_i.is_constant() &&
1445 (root.
id() == ID_array || root.
id() == ID_vector) &&
1447 index < root.
operands().size() && index >= 0)
1450 op.push_back(root.
operands()[numeric_cast_v<std::size_t>(index)]);
1458 if(width_bytes == 1)
1476 const exprt &value_as_byte_array,
1477 const std::optional<exprt> &non_const_update_bound,
1491 const typet &subtype,
1492 const exprt &value_as_byte_array,
1493 const exprt &non_const_update_bound,
1498 static std::size_t array_comprehension_index_counter = 0;
1499 ++array_comprehension_index_counter;
1501 "$array_comprehension_index_u_a_v" +
1507 array_comprehension_index, src.
offset().
type()),
1512 array_comprehension_index, non_const_update_bound.
type()),
1516 src.
offset(), non_const_update_bound.
type()),
1517 non_const_update_bound}};
1520 src.
id() == ID_byte_update_little_endian ||
1521 src.
id() == ID_byte_update_big_endian);
1522 const bool little_endian = src.
id() == ID_byte_update_little_endian;
1528 or_exprt{std::move(lower_bound), std::move(upper_bound)},
1532 value_as_byte_array,
1534 array_comprehension_index,
1536 src.
offset(), array_comprehension_index.
type())}},
1543 array_comprehension_index,
1544 std::move(array_comprehension_body),
1560 const typet &subtype,
1562 const std::optional<exprt> &non_const_update_bound,
1566 src.
id() == ID_byte_update_little_endian ||
1567 src.
id() == ID_byte_update_big_endian);
1568 const bool little_endian = src.
id() == ID_byte_update_little_endian;
1570 const typet index_type = src.
type().
id() == ID_array
1577 for(std::size_t i = 0; i < value_as_byte_array.
operands().size(); ++i)
1590 if(e.id() == ID_index)
1593 if(index_expr.
array() == src.
op() && index_expr.
index() == where)
1599 if(non_const_update_bound.has_value())
1605 *non_const_update_bound},
1610 if(result.
id() != ID_with)
1611 result =
with_exprt{result, std::move(where), std::move(update_value)};
1636 const typet &subtype,
1637 const exprt &subtype_size,
1638 const exprt &value_as_byte_array,
1639 const exprt &non_const_update_bound,
1640 const exprt &initial_bytes,
1641 const exprt &first_index,
1642 const exprt &first_update_value,
1645 const irep_idt extract_opcode = src.
id() == ID_byte_update_little_endian
1646 ? ID_byte_extract_little_endian
1647 : ID_byte_extract_big_endian;
1651 static std::size_t array_comprehension_index_counter = 0;
1652 ++array_comprehension_index_counter;
1654 "$array_comprehension_index_u_a_v_u" +
1667 array_comprehension_index, first_index.
type()),
1678 array_comprehension_index, first_index.
type()),
1683 value_as_byte_array,
1684 std::move(offset_expr),
1696 non_const_update_bound, subtype_size.
type()),
1711 non_const_update_bound, initial_bytes.
type()),
1713 subtype_size.
type()),
1720 array_comprehension_index, last_index.type()),
1735 value_as_byte_array,
1740 or_exprt{std::move(lower_bound), std::move(upper_bound)},
1745 array_comprehension_index, first_index.
type()),
1751 array_comprehension_index, last_index.type()),
1753 std::move(last_update_value),
1754 std::move(update_value)}}};
1758 array_comprehension_index,
1759 std::move(array_comprehension_body),
1776 const typet &subtype,
1777 const exprt &value_as_byte_array,
1778 const std::optional<exprt> &non_const_update_bound,
1788 subtype_size_opt.value(), src.
offset().
type()),
1803 const exprt update_size =
1807 if(non_const_update_bound.has_value())
1810 *non_const_update_bound, subtype_size.
type());
1815 value_as_byte_array.
id() == ID_array,
1816 "value should be an array expression if the update bound is constant");
1817 update_bound = update_size;
1833 value_as_byte_array,
1837 if(value_as_byte_array.
id() != ID_array)
1843 value_as_byte_array,
1844 *non_const_update_bound,
1856 std::size_t step_size = 1;
1863 std::size_t offset = 0;
1867 with_exprt result{src.
op(), first_index, first_update_value};
1869 auto lower_byte_update_array_vector_non_const_one_element =
1874 &value_as_byte_array,
1876 &result](std::size_t i) ->
void {
1891 value_as_byte_array,
1899 for(; offset + step_size <= value_as_byte_array.
operands().size();
1900 offset += step_size, ++i)
1902 lower_byte_update_array_vector_non_const_one_element(i);
1906 if(offset < value_as_byte_array.
operands().size())
1907 lower_byte_update_array_vector_non_const_one_element(i);
1927 const exprt &element_to_update,
1930 const exprt &value_as_byte_array,
1931 const std::optional<exprt> &non_const_update_bound,
1939 std::size_t first = 0;
1946 mp_integer offset_bits_in_target_element = offset_bits - bits_already_set;
1948 if(offset_bits_in_target_element < 0)
1951 value_as_byte_array.
id() != ID_array ||
1953 -offset_bits_in_target_element,
1954 "indices past the update should be handled below");
1955 first += numeric_cast_v<std::size_t>(
1957 offset_bits_in_target_element +=
1960 if(offset_bits_in_target_element < 0)
1967 update_elements > 0,
"indices before the update should be handled above");
1970 std::size_t end = first + numeric_cast_v<std::size_t>(update_elements);
1971 if(value_as_byte_array.
id() == ID_array)
1972 end = std::min(end, value_as_byte_array.
operands().size());
1975 const std::size_t update_size = update_values.size();
1984 offset_bits_in_target_element >= 0 &&
1987 new_value =
array_exprt{update_values, update_type};
1991 if(src.
id() == ID_byte_update_little_endian)
1992 std::reverse(update_values.begin(), update_values.end());
1993 if(offset_bits_in_target_element < 0)
1995 if(src.
id() == ID_byte_update_little_endian)
2000 numeric_cast_v<std::size_t>(-offset_bits_in_target_element)};
2007 numeric_cast_v<std::size_t>(-offset_bits_in_target_element)};
2012 const std::size_t offset_bits_int =
2013 numeric_cast_v<std::size_t>(offset_bits_in_target_element);
2014 const std::size_t subtype_bits_int =
2015 numeric_cast_v<std::size_t>(subtype_bits);
2019 subtype_bits_int - offset_bits_int,
2031 const irep_idt extract_opcode = src.
id() == ID_byte_update_little_endian
2032 ? ID_byte_extract_little_endian
2033 : ID_byte_extract_big_endian;
2044 offset_bits_in_target_element = 0;
2059 std::optional<exprt> update_bound;
2060 if(non_const_update_bound.has_value())
2068 *non_const_update_bound,
2072 *non_const_update_bound,
2082 remaining_update_bytes},
2101 const typet &subtype,
2102 const std::optional<mp_integer> &subtype_bits,
2103 const exprt &value_as_byte_array,
2104 const std::optional<exprt> &non_const_update_bound,
2107 const bool is_array = src.
type().
id() == ID_array;
2124 !subtype_bits.has_value() || value_as_byte_array.
id() != ID_array)
2127 src, subtype, value_as_byte_array, non_const_update_bound, ns);
2130 std::size_t num_elements =
2137 elements.reserve(num_elements);
2141 for(; i < num_elements && (i + 1) * *subtype_bits <= offset_bits; ++i)
2147 i * *subtype_bits < offset_bits + value_as_byte_array.operands().size() *
2148 src.get_bits_per_byte();
2157 value_as_byte_array,
2158 non_const_update_bound,
2163 for(; i < num_elements; ++i)
2186 const exprt &value_as_byte_array,
2187 const std::optional<exprt> &non_const_update_bound,
2191 elements.reserve(struct_type.
components().size());
2194 for(
const auto &comp : struct_type.
components())
2207 auto offset_bits = numeric_cast<mp_integer>(offset);
2208 if(!offset_bits.has_value() || !element_width.has_value())
2215 const irep_idt extract_opcode = src.
id() == ID_byte_update_little_endian
2216 ? ID_byte_extract_little_endian
2217 : ID_byte_extract_big_endian;
2237 bu, value_as_byte_array, non_const_update_bound, ns),
2252 *offset_bits >= *element_width ||
2253 (value_as_byte_array.
id() == ID_array && *offset_bits < 0 &&
2257 elements.push_back(member);
2268 value_as_byte_array,
2269 non_const_update_bound,
2290 const exprt &value_as_byte_array,
2291 const std::optional<exprt> &non_const_update_bound,
2297 widest_member.has_value(),
2298 "lower_byte_update of union of unknown size is not supported");
2302 src.
op(), widest_member->first.get_name(), widest_member->first.
type()});
2303 bu.
type() = widest_member->first.type();
2306 widest_member->first.get_name(),
2321 const exprt &value_as_byte_array,
2322 const std::optional<exprt> &non_const_update_bound,
2325 if(src.
type().
id() == ID_array || src.
type().
id() == ID_vector)
2327 std::optional<typet> subtype;
2328 if(src.
type().
id() == ID_vector)
2337 if(value_as_byte_array.
id() != ID_array)
2340 non_const_update_bound.has_value(),
2341 "constant update bound should yield an array expression");
2343 src, *subtype, value_as_byte_array, *non_const_update_bound, ns);
2350 non_const_update_bound,
2359 value_as_byte_array,
2360 non_const_update_bound,
2364 else if(src.
type().
id() == ID_struct || src.
type().
id() == ID_struct_tag)
2367 src.
type().
id() == ID_struct_tag
2371 src, struct_type, value_as_byte_array, non_const_update_bound, ns);
2375 else if(src.
type().
id() == ID_union || src.
type().
id() == ID_union_tag)
2378 src.
type().
id() == ID_union_tag
2382 src, union_type, value_as_byte_array, non_const_update_bound, ns);
2388 src.
type().
id() == ID_c_enum || src.
type().
id() == ID_c_enum_tag)
2393 CHECK_RETURN(type_width.has_value() && *type_width > 0);
2394 const std::size_t type_bits = numeric_cast_v<std::size_t>(*type_width);
2397 if(value_as_byte_array.
id() == ID_array)
2398 update_bytes = value_as_byte_array.
operands();
2402 value_as_byte_array,
2409 const std::size_t update_size_bits =
2411 const std::size_t bit_width = std::max(type_bits, update_size_bits);
2413 const bool is_little_endian = src.
id() == ID_byte_update_little_endian;
2417 if(bit_width > type_bits)
2424 if(!is_little_endian)
2430 if(non_const_update_bound.has_value())
2434 src.
id() == ID_byte_update_little_endian,
2441 for(std::size_t i = 0; i < update_bytes.size(); ++i)
2447 *non_const_update_bound},
2455 if(is_little_endian)
2460 power(2, bit_width) -
power(2, bit_width - update_size_bits),
2475 if(!is_little_endian)
2477 mask_shifted.true_case().
swap(mask_shifted.false_case());
2488 if(is_little_endian)
2489 std::reverse(value.operands().begin(), value.operands().end());
2491 exprt zero_extended;
2492 if(bit_width > update_size_bits)
2494 if(is_little_endian)
2506 zero_extended = value;
2511 shl_exprt{zero_extended, offset_in_bits},
2513 if(!is_little_endian)
2515 value_shifted.true_case().
swap(value_shifted.false_case());
2522 bitor_exprt bitor_expr{bitand_expr, value_shifted};
2524 if(bit_width > type_bits)
2527 bitor_expr.type(), src.
id() == ID_byte_update_little_endian, ns);
2528 const auto bounds =
map_bounds(endianness_map, 0, type_bits - 1);
2544 false,
"lower_byte_update does not yet support ", src.
type().
id_string());
2551 src.
id() == ID_byte_update_little_endian ||
2552 src.
id() == ID_byte_update_big_endian,
2553 "byte update expression should either be little or big endian");
2569 std::optional<exprt> non_const_update_bound;
2574 simplify(update_size_expr_opt.value(), ns);
2576 const irep_idt extract_opcode = src.
id() == ID_byte_update_little_endian
2577 ? ID_byte_extract_little_endian
2578 : ID_byte_extract_big_endian;
2581 if(!update_size_expr_opt.value().is_constant())
2582 non_const_update_bound = *update_size_expr_opt;
2590 update_bits.has_value(),
"constant size-of should imply fixed bit width");
2591 const size_t update_bits_int = numeric_cast_v<size_t>(*update_bits);
2593 if(update_bits_int % bits_per_byte != 0)
2597 "non-byte aligned type expected to be a bitvector type");
2608 const exprt overlapping_byte =
2611 size_t n_extra_bits = bits_per_byte - update_bits_int % bits_per_byte;
2616 update_value,
bv_typet{update_bits_int}),
2623 update_bits_int / bits_per_byte, update_size_expr_opt->type());
2652 src.
id() == ID_byte_update_little_endian ||
2653 src.
id() == ID_byte_update_big_endian)
2658 src.
id() == ID_byte_extract_little_endian ||
2659 src.
id() == ID_byte_extract_big_endian)
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)
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
const c_enum_typet & to_c_enum_type(const typet &type)
Cast a typet to a c_enum_typet.
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
const c_bit_field_typet & to_c_bit_field_type(const typet &type)
Cast a typet to a c_bit_field_typet.
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Expression to define a mapping from an argument (index) to elements.
Array constructor from list of elements.
typet index_type() const
The type of the index expressions into any instance of this type.
const typet & element_type() const
The type of the elements of the array.
const exprt & size() const
A base class for expressions that are predicates, i.e., Boolean-typed, and that take exactly two argu...
Bit-wise negation of bit-vectors.
Base class of fixed-width bit-vector types.
std::size_t get_width() const
Fixed-width bit-vector without numerical interpretation.
constant_exprt all_zeros_expr() const
Expression corresponding to op() where the bytes starting at position offset (given in number of byte...
const exprt & value() const
const exprt & offset() const
std::size_t get_bits_per_byte() const
Type for C bit fields These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (...
Complex constructor from a pair of numbers.
Imaginary part of the expression describing a complex number.
Real part of the expression describing a complex number.
Complex numbers made of pair of given subtype.
Concatenation of bit-vector operands.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Union constructor to support unions without any member (a GCC/Clang feature).
Maps a big-endian offset to a little-endian offset.
size_t number_of_bits() const
size_t map_bit(size_t bit) const
Base class for all expressions.
std::vector< exprt > operandst
typet & type()
Return the type of the expression.
bool is_constant() const
Return whether the expression is a constant.
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
The trinary if-then-else operator.
const std::string & id_string() const
const irep_idt & id() const
Extract member of struct or union.
Modulo defined as lhs-(rhs * truncate(lhs/rhs)).
Binary multiplication Associativity is not specified.
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
The plus expression Associativity is not specified.
Fixed-width bit-vector with two's complement interpretation.
Struct constructor from list of elements.
Structure type, corresponds to C style structs.
const componentst & components() const
std::vector< componentt > componentst
Expression to hold a symbol (variable)
const typet & subtype() const
Semantic type conversion.
static exprt conditional_cast(const exprt &expr, const typet &type)
The type of an expression, extends irept.
The unary minus expression.
Union constructor from single element.
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.
Fixed-width bit-vector with unsigned binary interpretation.
Vector constructor from list of elements.
const constant_exprt & size() const
const typet & element_type() const
The type of the elements of the vector.
typet index_type() const
The type of any index expression into an instance of this type.
Operator to update elements in structs and arrays.
zero extension The operand is converted to the given type by either a) truncating if the new type is ...
#define Forall_operands(it, expr)
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 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 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_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...
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< exprt > size_of_expr(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 > member_offset_expr(const member_exprt &member_expr, const namespacet &ns)
bool simplify(exprt &expr, const namespacet &ns)
exprt simplify_expr(exprt src, const namespacet &ns)
#define PRECONDITION_WITH_DIAGNOSTICS(CONDITION,...)
#define CHECK_RETURN(CONDITION)
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
#define PRECONDITION(CONDITION)
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
const array_exprt & to_array_expr(const exprt &expr)
Cast an exprt to an array_exprt.
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
const vector_typet & to_vector_type(const typet &type)
Cast a typet to a vector_typet.
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
const complex_typet & to_complex_type(const typet &type)
Cast a typet to a complex_typet.
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
bool can_cast_type< bitvector_typet >(const typet &type)
Check whether a reference to a typet is a bitvector_typet.
const string_constantt & to_string_constant(const exprt &expr)
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
static bool failed(bool error_indicator)
const type_with_subtypet & to_type_with_subtype(const typet &type)