CBMC
lower_byte_operators.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: 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 
23 static 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 
29 struct 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 
59 bitvector_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.ub, 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,
165  bv_to_expr(
166  extractbits_exprt{bitvector_expr, bounds.ub, 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(
213  bitvector_expr, bounds.ub, bounds.lb, std::move(type)},
214  array_type.element_type(),
215  endianness_map,
216  ns));
217  }
218  else
219  {
220  operands.push_back(bv_to_expr(
221  bitvector_expr, array_type.element_type(), endianness_map, ns));
222  }
223  }
224 
225  return array_exprt{std::move(operands), array_type};
226 }
227 
231  const exprt &bitvector_expr,
232  const vector_typet &vector_type,
233  const endianness_mapt &endianness_map,
234  const namespacet &ns)
235 {
236  const std::size_t num_elements =
237  numeric_cast_v<std::size_t>(vector_type.size());
238  auto subtype_bits = pointer_offset_bits(vector_type.element_type(), ns);
240  !subtype_bits.has_value() ||
241  *subtype_bits * num_elements ==
242  to_bitvector_type(bitvector_expr.type()).get_width(),
243  "subtype width times vector size should be total bitvector width");
244 
245  exprt::operandst operands;
246  operands.reserve(num_elements);
247  for(std::size_t i = 0; i < num_elements; ++i)
248  {
249  if(subtype_bits.has_value())
250  {
251  const std::size_t subtype_bits_int =
252  numeric_cast_v<std::size_t>(*subtype_bits);
253  const auto bounds = map_bounds(
254  endianness_map, i * subtype_bits_int, ((i + 1) * subtype_bits_int) - 1);
255  bitvector_typet type =
256  adjust_width(bitvector_expr.type(), subtype_bits_int);
257  PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
258  operands.push_back(bv_to_expr(
260  bitvector_expr, bounds.ub, bounds.lb, std::move(type)},
261  vector_type.element_type(),
262  endianness_map,
263  ns));
264  }
265  else
266  {
267  operands.push_back(bv_to_expr(
268  bitvector_expr, vector_type.element_type(), endianness_map, ns));
269  }
270  }
271 
272  return vector_exprt{std::move(operands), vector_type};
273 }
274 
278  const exprt &bitvector_expr,
279  const complex_typet &complex_type,
280  const endianness_mapt &endianness_map,
281  const namespacet &ns)
282 {
283  const std::size_t total_bits =
284  to_bitvector_type(bitvector_expr.type()).get_width();
285  const auto subtype_bits_opt = pointer_offset_bits(complex_type.subtype(), ns);
286  std::size_t subtype_bits;
287  if(subtype_bits_opt.has_value())
288  {
289  subtype_bits = numeric_cast_v<std::size_t>(*subtype_bits_opt);
291  subtype_bits * 2 == total_bits,
292  "subtype width should be half of the total bitvector width");
293  }
294  else
295  subtype_bits = total_bits / 2;
296 
297  const auto bounds_real = map_bounds(endianness_map, 0, subtype_bits - 1);
298  const auto bounds_imag =
299  map_bounds(endianness_map, subtype_bits, subtype_bits * 2 - 1);
300 
301  const bitvector_typet type =
302  adjust_width(bitvector_expr.type(), subtype_bits);
303 
304  PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
305  return complex_exprt{
306  bv_to_expr(
307  extractbits_exprt{bitvector_expr, bounds_real.ub, bounds_real.lb, type},
308  complex_type.subtype(),
309  endianness_map,
310  ns),
311  bv_to_expr(
312  extractbits_exprt{bitvector_expr, bounds_imag.ub, bounds_imag.lb, type},
313  complex_type.subtype(),
314  endianness_map,
315  ns),
316  complex_type};
317 }
318 
333  const exprt &bitvector_expr,
334  const typet &target_type,
335  const endianness_mapt &endianness_map,
336  const namespacet &ns)
337 {
339 
340  if(target_type.id() == ID_floatbv)
341  {
342  std::size_t width = to_bitvector_type(bitvector_expr.type()).get_width();
343  exprt bv_expr =
344  typecast_exprt::conditional_cast(bitvector_expr, bv_typet{width});
345  return simplify_expr(
346  typecast_exprt::conditional_cast(bv_expr, target_type), ns);
347  }
348  else if(
349  can_cast_type<bitvector_typet>(target_type) ||
350  target_type.id() == ID_c_enum || target_type.id() == ID_c_enum_tag ||
351  target_type.id() == ID_string)
352  {
353  return simplify_expr(
354  typecast_exprt::conditional_cast(bitvector_expr, target_type), ns);
355  }
356 
357  if(target_type.id() == ID_struct)
358  {
359  return bv_to_struct_expr(
360  bitvector_expr, to_struct_type(target_type), endianness_map, ns);
361  }
362  else if(target_type.id() == ID_struct_tag)
363  {
365  bitvector_expr,
366  ns.follow_tag(to_struct_tag_type(target_type)),
367  endianness_map,
368  ns);
369  result.type() = target_type;
370  return std::move(result);
371  }
372  else if(target_type.id() == ID_union)
373  {
374  return bv_to_union_expr(
375  bitvector_expr, to_union_type(target_type), endianness_map, ns);
376  }
377  else if(target_type.id() == ID_union_tag)
378  {
379  exprt result = bv_to_union_expr(
380  bitvector_expr,
381  ns.follow_tag(to_union_tag_type(target_type)),
382  endianness_map,
383  ns);
384  result.type() = target_type;
385  return result;
386  }
387  else if(target_type.id() == ID_array)
388  {
389  return bv_to_array_expr(
390  bitvector_expr, to_array_type(target_type), endianness_map, ns);
391  }
392  else if(target_type.id() == ID_vector)
393  {
394  return bv_to_vector_expr(
395  bitvector_expr, to_vector_type(target_type), endianness_map, ns);
396  }
397  else if(target_type.id() == ID_complex)
398  {
399  return bv_to_complex_expr(
400  bitvector_expr, to_complex_type(target_type), endianness_map, ns);
401  }
402  else
403  {
405  false, "bv_to_expr does not yet support ", target_type.id_string());
406  }
407 }
408 
409 static exprt unpack_rec(
410  const exprt &src,
411  bool little_endian,
412  const std::optional<mp_integer> &offset_bytes,
413  const std::optional<mp_integer> &max_bytes,
414  const std::size_t bits_per_byte,
415  const namespacet &ns,
416  bool unpack_byte_array = false);
417 
426  const exprt &src,
427  std::size_t lower_bound,
428  std::size_t upper_bound,
429  const std::size_t bits_per_byte,
430  const namespacet &ns)
431 {
432  PRECONDITION(lower_bound <= upper_bound);
433 
434  if(src.id() == ID_array)
435  {
436  PRECONDITION(upper_bound <= src.operands().size());
437  return exprt::operandst{
438  src.operands().begin() + narrow_cast<std::ptrdiff_t>(lower_bound),
439  src.operands().begin() + narrow_cast<std::ptrdiff_t>(upper_bound)};
440  }
441 
442  const typet &element_type = src.type().id() == ID_array
443  ? to_array_type(src.type()).element_type()
444  : to_vector_type(src.type()).element_type();
445  const typet index_type = src.type().id() == ID_array
446  ? to_array_type(src.type()).index_type()
447  : to_vector_type(src.type()).index_type();
448  PRECONDITION(
449  can_cast_type<bitvector_typet>(element_type) &&
450  to_bitvector_type(element_type).get_width() == bits_per_byte);
451  exprt::operandst bytes;
452  bytes.reserve(upper_bound - lower_bound);
453  for(std::size_t i = lower_bound; i < upper_bound; ++i)
454  {
455  const index_exprt idx{src, from_integer(i, index_type)};
456  bytes.push_back(simplify_expr(idx, ns));
457  }
458  return bytes;
459 }
460 
470  const exprt &src,
471  std::size_t el_bytes,
472  bool little_endian,
473  const std::size_t bits_per_byte,
474  const namespacet &ns)
475 {
476  const typet index_type = src.type().id() == ID_array
477  ? to_array_type(src.type()).index_type()
478  : to_vector_type(src.type()).index_type();
479 
480  // TODO we either need a symbol table here or make array comprehensions
481  // introduce a scope
482  static std::size_t array_comprehension_index_counter = 0;
483  ++array_comprehension_index_counter;
484  symbol_exprt array_comprehension_index{
485  "$array_comprehension_index_a_v" +
486  std::to_string(array_comprehension_index_counter),
487  index_type};
488 
489  index_exprt element{
490  src,
491  div_exprt{array_comprehension_index, from_integer(el_bytes, index_type)}};
492 
493  exprt sub =
494  unpack_rec(element, little_endian, {}, {}, bits_per_byte, ns, false);
495  exprt::operandst sub_operands =
496  instantiate_byte_array(sub, 0, el_bytes, bits_per_byte, ns);
497 
498  exprt body = sub_operands.front();
499  const mod_exprt offset{
500  array_comprehension_index,
501  from_integer(el_bytes, array_comprehension_index.type())};
502  for(std::size_t i = 1; i < el_bytes; ++i)
503  {
504  body = if_exprt{
505  equal_exprt{offset, from_integer(i, array_comprehension_index.type())},
506  sub_operands[i],
507  body};
508  }
509 
510  const exprt array_vector_size = src.type().id() == ID_vector
511  ? to_vector_type(src.type()).size()
512  : to_array_type(src.type()).size();
513 
515  std::move(array_comprehension_index),
516  std::move(body),
517  array_typet{
518  bv_typet{bits_per_byte},
519  mult_exprt{
520  array_vector_size, from_integer(el_bytes, array_vector_size.type())}}};
521 }
522 
539  const exprt &src,
540  const std::optional<mp_integer> &src_size,
541  const mp_integer &element_bits,
542  bool little_endian,
543  const std::optional<mp_integer> &offset_bytes,
544  const std::optional<mp_integer> &max_bytes,
545  const std::size_t bits_per_byte,
546  const namespacet &ns)
547 {
548  const std::size_t el_bytes = numeric_cast_v<std::size_t>(
549  (element_bits + bits_per_byte - 1) / bits_per_byte);
550 
551  if(!src_size.has_value() && !max_bytes.has_value())
552  {
554  el_bytes > 0 && element_bits % bits_per_byte == 0,
555  "unpacking of arrays with non-byte-aligned elements is not supported");
557  src, el_bytes, little_endian, bits_per_byte, ns);
558  }
559 
560  exprt::operandst byte_operands;
561  mp_integer first_element = 0;
562 
563  // refine the number of elements to extract in case the element width is known
564  // and a multiple of bytes; otherwise we will expand the entire array/vector
565  std::optional<mp_integer> num_elements = src_size;
566  if(element_bits > 0 && element_bits % bits_per_byte == 0)
567  {
568  if(!num_elements.has_value())
569  {
570  // turn bytes into elements, rounding up
571  num_elements = (*max_bytes + el_bytes - 1) / el_bytes;
572  }
573 
574  if(offset_bytes.has_value())
575  {
576  // compute offset as number of elements
577  first_element = *offset_bytes / el_bytes;
578  // insert offset_bytes-many nil bytes into the output array
579  byte_operands.resize(
580  numeric_cast_v<std::size_t>(std::min(
581  *offset_bytes - (*offset_bytes % el_bytes),
582  *num_elements * el_bytes)),
583  from_integer(0, bv_typet{bits_per_byte}));
584  }
585  }
586 
587  // the maximum number of bytes is an upper bound in case the size of the
588  // array/vector is unknown; if element_bits was usable above this will
589  // have been turned into a number of elements already
590  if(!num_elements)
591  num_elements = *max_bytes;
592 
593  const exprt src_simp = simplify_expr(src, ns);
594  const typet index_type = src_simp.type().id() == ID_array
595  ? to_array_type(src_simp.type()).index_type()
596  : to_vector_type(src_simp.type()).index_type();
597 
598  for(mp_integer i = first_element; i < *num_elements; ++i)
599  {
600  exprt element;
601 
602  if(
603  (src_simp.id() == ID_array || src_simp.id() == ID_vector) &&
604  i < src_simp.operands().size())
605  {
606  const std::size_t index_int = numeric_cast_v<std::size_t>(i);
607  element = src_simp.operands()[index_int];
608  }
609  else
610  {
611  element = index_exprt(src_simp, from_integer(i, index_type));
612  }
613 
614  // recursively unpack each element so that we eventually just have an array
615  // of bytes left
616 
617  const std::optional<mp_integer> element_max_bytes =
618  max_bytes
619  ? std::min(mp_integer{el_bytes}, *max_bytes - byte_operands.size())
620  : std::optional<mp_integer>{};
621  const std::size_t element_max_bytes_int =
622  element_max_bytes ? numeric_cast_v<std::size_t>(*element_max_bytes)
623  : el_bytes;
624 
625  exprt sub = unpack_rec(
626  element, little_endian, {}, element_max_bytes, bits_per_byte, ns, true);
627  exprt::operandst sub_operands =
628  instantiate_byte_array(sub, 0, element_max_bytes_int, bits_per_byte, ns);
629  byte_operands.insert(
630  byte_operands.end(), sub_operands.begin(), sub_operands.end());
631 
632  if(max_bytes && byte_operands.size() >= *max_bytes)
633  break;
634  }
635 
636  const std::size_t size = byte_operands.size();
637  return array_exprt(
638  std::move(byte_operands),
639  array_typet{bv_typet{bits_per_byte}, from_integer(size, size_type())});
640 }
641 
653 static void process_bit_fields(
654  exprt::operandst &&bit_fields,
655  std::size_t total_bits,
656  exprt::operandst &dest,
657  bool little_endian,
658  const std::optional<mp_integer> &offset_bytes,
659  const std::optional<mp_integer> &max_bytes,
660  const std::size_t bits_per_byte,
661  const namespacet &ns)
662 {
663  const concatenation_exprt concatenation{
664  std::move(bit_fields), bv_typet{total_bits}};
665 
666  exprt sub = unpack_rec(
667  concatenation,
668  little_endian,
669  offset_bytes,
670  max_bytes,
671  bits_per_byte,
672  ns,
673  true);
674 
675  dest.insert(
676  dest.end(),
677  std::make_move_iterator(sub.operands().begin()),
678  std::make_move_iterator(sub.operands().end()));
679 }
680 
692  const exprt &src,
693  bool little_endian,
694  const std::optional<mp_integer> &offset_bytes,
695  const std::optional<mp_integer> &max_bytes,
696  const std::size_t bits_per_byte,
697  const namespacet &ns)
698 {
699  const struct_typet &struct_type =
700  src.type().id() == ID_struct_tag
701  ? ns.follow_tag(to_struct_tag_type(src.type()))
702  : to_struct_type(src.type());
703  const struct_typet::componentst &components = struct_type.components();
704 
705  std::optional<mp_integer> offset_in_member;
706  std::optional<mp_integer> max_bytes_left;
707  std::optional<std::pair<exprt::operandst, std::size_t>> bit_fields;
708 
710  exprt::operandst byte_operands;
711  for(auto it = components.begin(); it != components.end(); ++it)
712  {
713  const auto &comp = *it;
714  auto component_bits = pointer_offset_bits(comp.type(), ns);
715 
716  // We can only handle a member of unknown width when it is the last member
717  // and is byte-aligned. Members of unknown width in the middle would leave
718  // us with unknown alignment of subsequent members, and queuing them up as
719  // bit fields is not possible either as the total width of the concatenation
720  // could not be determined.
722  component_bits.has_value() ||
723  (std::next(it) == components.end() && !bit_fields.has_value()),
724  "members of non-constant width should come last in a struct");
725 
726  member_exprt member(src, comp.get_name(), comp.type());
727  if(src.id() == ID_struct)
728  simplify(member, ns);
729 
730  // Is it a byte-aligned member?
731  if(member_offset_bits % bits_per_byte == 0)
732  {
733  if(bit_fields.has_value())
734  {
736  std::move(bit_fields->first),
737  bit_fields->second,
738  byte_operands,
739  little_endian,
740  offset_in_member,
741  max_bytes_left,
742  bits_per_byte,
743  ns);
744  bit_fields.reset();
745  }
746 
747  if(offset_bytes.has_value())
748  {
749  offset_in_member = *offset_bytes - member_offset_bits / bits_per_byte;
750  // if the offset is negative, offset_in_member remains unset, which has
751  // the same effect as setting it to zero
752  if(*offset_in_member < 0)
753  offset_in_member.reset();
754  }
755 
756  if(max_bytes.has_value())
757  {
758  max_bytes_left = *max_bytes - member_offset_bits / bits_per_byte;
759  if(*max_bytes_left < 0)
760  break;
761  }
762  }
763 
764  if(
765  member_offset_bits % bits_per_byte != 0 ||
766  (component_bits.has_value() && *component_bits % bits_per_byte != 0))
767  {
768  if(!bit_fields.has_value())
769  bit_fields = std::make_pair(exprt::operandst{}, std::size_t{0});
770 
771  const std::size_t bits_int = numeric_cast_v<std::size_t>(*component_bits);
772  bit_fields->first.insert(
773  little_endian ? bit_fields->first.begin() : bit_fields->first.end(),
774  typecast_exprt::conditional_cast(member, bv_typet{bits_int}));
775  bit_fields->second += bits_int;
776 
777  member_offset_bits += *component_bits;
778 
779  continue;
780  }
781 
782  INVARIANT(
783  !bit_fields.has_value(),
784  "all preceding members should have been processed");
785 
786  if(
787  component_bits.has_value() && offset_in_member.has_value() &&
788  *offset_in_member * bits_per_byte >= *component_bits)
789  {
790  // we won't actually need this component, fill in zeros instead of
791  // computing an unpacking
792  byte_operands.resize(
793  byte_operands.size() +
794  numeric_cast_v<std::size_t>(*component_bits / bits_per_byte),
795  from_integer(0, bv_typet{bits_per_byte}));
796  }
797  else
798  {
799  exprt sub = unpack_rec(
800  member,
801  little_endian,
802  offset_in_member,
803  max_bytes_left,
804  bits_per_byte,
805  ns,
806  true);
807 
808  byte_operands.insert(
809  byte_operands.end(),
810  std::make_move_iterator(sub.operands().begin()),
811  std::make_move_iterator(sub.operands().end()));
812  }
813 
814  if(component_bits.has_value())
815  member_offset_bits += *component_bits;
816  }
817 
818  // any remaining bit fields?
819  if(bit_fields.has_value())
820  {
822  std::move(bit_fields->first),
823  bit_fields->second,
824  byte_operands,
825  little_endian,
826  offset_in_member,
827  max_bytes_left,
828  bits_per_byte,
829  ns);
830  }
831 
832  const std::size_t size = byte_operands.size();
833  return array_exprt{
834  std::move(byte_operands),
835  array_typet{bv_typet{bits_per_byte}, from_integer(size, size_type())}};
836 }
837 
845  const exprt &src,
846  bool little_endian,
847  const std::size_t bits_per_byte,
848  const namespacet &ns)
849 {
850  const complex_typet &complex_type = to_complex_type(src.type());
851  const typet &subtype = complex_type.subtype();
852 
853  auto subtype_bits = pointer_offset_bits(subtype, ns);
854  CHECK_RETURN(subtype_bits.has_value());
855  CHECK_RETURN(*subtype_bits % bits_per_byte == 0);
856 
857  exprt sub_real = unpack_rec(
858  complex_real_exprt{src},
859  little_endian,
860  mp_integer{0},
861  *subtype_bits / bits_per_byte,
862  bits_per_byte,
863  ns,
864  true);
865  exprt::operandst byte_operands = std::move(sub_real.operands());
866 
867  exprt sub_imag = unpack_rec(
868  complex_imag_exprt{src},
869  little_endian,
870  mp_integer{0},
871  *subtype_bits / bits_per_byte,
872  bits_per_byte,
873  ns,
874  true);
875  byte_operands.insert(
876  byte_operands.end(),
877  std::make_move_iterator(sub_imag.operands().begin()),
878  std::make_move_iterator(sub_imag.operands().end()));
879 
880  const std::size_t size = byte_operands.size();
881  return array_exprt{
882  std::move(byte_operands),
883  array_typet{bv_typet{bits_per_byte}, from_integer(size, size_type())}};
884 }
885 
896 // array of bytes
899  const exprt &src,
900  bool little_endian,
901  const std::optional<mp_integer> &offset_bytes,
902  const std::optional<mp_integer> &max_bytes,
903  const std::size_t bits_per_byte,
904  const namespacet &ns,
905  bool unpack_byte_array)
906 {
907  if(src.type().id() == ID_array)
908  {
909  const array_typet &array_type = to_array_type(src.type());
910  const typet &subtype = array_type.element_type();
911 
912  auto element_bits = pointer_offset_bits(subtype, ns);
913  CHECK_RETURN(element_bits.has_value());
914 
915  if(
916  !unpack_byte_array && *element_bits == bits_per_byte &&
918  {
919  return src;
920  }
921 
922  const auto constant_size_opt = numeric_cast<mp_integer>(array_type.size());
923  return unpack_array_vector(
924  src,
925  constant_size_opt,
926  *element_bits,
927  little_endian,
928  offset_bytes,
929  max_bytes,
930  bits_per_byte,
931  ns);
932  }
933  else if(src.type().id() == ID_vector)
934  {
935  const vector_typet &vector_type = to_vector_type(src.type());
936  const typet &subtype = vector_type.element_type();
937 
938  auto element_bits = pointer_offset_bits(subtype, ns);
939  CHECK_RETURN(element_bits.has_value());
940 
941  if(
942  !unpack_byte_array && *element_bits == bits_per_byte &&
944  {
945  return src;
946  }
947 
948  return unpack_array_vector(
949  src,
950  numeric_cast_v<mp_integer>(vector_type.size()),
951  *element_bits,
952  little_endian,
953  offset_bytes,
954  max_bytes,
955  bits_per_byte,
956  ns);
957  }
958  else if(src.type().id() == ID_complex)
959  {
960  return unpack_complex(src, little_endian, bits_per_byte, ns);
961  }
962  else if(src.type().id() == ID_struct || src.type().id() == ID_struct_tag)
963  {
964  return unpack_struct(
965  src, little_endian, offset_bytes, max_bytes, bits_per_byte, ns);
966  }
967  else if(src.type().id() == ID_union || src.type().id() == ID_union_tag)
968  {
969  const union_typet &union_type =
970  src.type().id() == ID_union_tag
971  ? ns.follow_tag(to_union_tag_type(src.type()))
972  : to_union_type(src.type());
973 
974  const auto widest_member = union_type.find_widest_union_component(ns);
975 
976  if(widest_member.has_value())
977  {
978  member_exprt member{
979  src, widest_member->first.get_name(), widest_member->first.type()};
980  return unpack_rec(
981  member,
982  little_endian,
983  offset_bytes,
984  widest_member->second,
985  bits_per_byte,
986  ns,
987  true);
988  }
989  else if(!union_type.components().empty())
990  {
991  member_exprt member{src, union_type.components().front()};
992  return unpack_rec(
993  member,
994  little_endian,
995  offset_bytes,
996  max_bytes,
997  bits_per_byte,
998  ns,
999  true);
1000  }
1001  }
1002  else if(src.type().id() == ID_pointer)
1003  {
1004  return unpack_rec(
1006  little_endian,
1007  offset_bytes,
1008  max_bytes,
1009  bits_per_byte,
1010  ns,
1011  unpack_byte_array);
1012  }
1013  else if(src.id() == ID_string_constant)
1014  {
1015  return unpack_rec(
1017  little_endian,
1018  offset_bytes,
1019  max_bytes,
1020  bits_per_byte,
1021  ns,
1022  unpack_byte_array);
1023  }
1024  else if(src.is_constant() && src.type().id() == ID_string)
1025  {
1026  return unpack_rec(
1027  string_constantt(to_constant_expr(src).get_value()).to_array_expr(),
1028  little_endian,
1029  offset_bytes,
1030  max_bytes,
1031  bits_per_byte,
1032  ns,
1033  unpack_byte_array);
1034  }
1035  else if(src.type().id() != ID_empty)
1036  {
1037  // a basic type; we turn that into extractbits while considering
1038  // endianness
1039  auto bits_opt = pointer_offset_bits(src.type(), ns);
1040  DATA_INVARIANT(bits_opt.has_value(), "basic type should have a fixed size");
1041 
1042  const mp_integer total_bits = *bits_opt;
1043  mp_integer last_bit = total_bits;
1044  mp_integer bit_offset = 0;
1045 
1046  if(max_bytes.has_value())
1047  {
1048  const auto max_bits = *max_bytes * bits_per_byte;
1049  if(little_endian)
1050  {
1051  last_bit = std::min(last_bit, max_bits);
1052  }
1053  else
1054  {
1055  bit_offset = std::max(mp_integer{0}, last_bit - max_bits);
1056  }
1057  }
1058 
1059  auto const src_as_bitvector = typecast_exprt::conditional_cast(
1060  src, bv_typet{numeric_cast_v<std::size_t>(total_bits)});
1061  auto const byte_type = bv_typet{bits_per_byte};
1062  exprt::operandst byte_operands;
1063  array_typet array_type{
1064  bv_typet{bits_per_byte}, from_integer(0, size_type())};
1065 
1066  for(; bit_offset < last_bit; bit_offset += bits_per_byte)
1067  {
1068  PRECONDITION(
1069  pointer_offset_bits(src_as_bitvector.type(), ns).has_value());
1070  extractbits_exprt extractbits(
1071  src_as_bitvector,
1072  from_integer(bit_offset + bits_per_byte - 1, array_type.index_type()),
1073  from_integer(bit_offset, array_type.index_type()),
1074  byte_type);
1075 
1076  // endianness_mapt should be the point of reference for mapping out
1077  // endianness, but we need to work on elements here instead of
1078  // individual bits
1079  if(little_endian)
1080  byte_operands.push_back(extractbits);
1081  else
1082  byte_operands.insert(byte_operands.begin(), extractbits);
1083  }
1084 
1085  const std::size_t size = byte_operands.size();
1086  array_type.size() = from_integer(size, size_type());
1087  return array_exprt{std::move(byte_operands), std::move(array_type)};
1088  }
1089 
1090  return array_exprt(
1091  {}, array_typet{bv_typet{bits_per_byte}, from_integer(0, size_type())});
1092 }
1093 
1105  const byte_extract_exprt &src,
1106  const byte_extract_exprt &unpacked,
1107  const typet &subtype,
1108  const mp_integer &element_bits,
1109  const namespacet &ns)
1110 {
1111  std::optional<std::size_t> num_elements;
1112  if(src.type().id() == ID_array)
1113  num_elements = numeric_cast<std::size_t>(to_array_type(src.type()).size());
1114  else
1115  num_elements = numeric_cast<std::size_t>(to_vector_type(src.type()).size());
1116 
1117  if(num_elements.has_value())
1118  {
1119  exprt::operandst operands;
1120  operands.reserve(*num_elements);
1121  for(std::size_t i = 0; i < *num_elements; ++i)
1122  {
1123  plus_exprt new_offset(
1124  unpacked.offset(),
1125  from_integer(
1126  i * element_bits / src.get_bits_per_byte(),
1127  unpacked.offset().type()));
1128 
1129  byte_extract_exprt tmp(unpacked);
1130  tmp.type() = subtype;
1131  tmp.offset() = new_offset;
1132 
1133  operands.push_back(lower_byte_extract(tmp, ns));
1134  }
1135 
1136  exprt result;
1137  if(src.type().id() == ID_array)
1138  result = array_exprt{std::move(operands), to_array_type(src.type())};
1139  else
1140  result = vector_exprt{std::move(operands), to_vector_type(src.type())};
1141 
1142  return simplify_expr(result, ns);
1143  }
1144 
1145  DATA_INVARIANT(src.type().id() == ID_array, "vectors have constant size");
1146  const array_typet &array_type = to_array_type(src.type());
1147 
1148  // TODO we either need a symbol table here or make array comprehensions
1149  // introduce a scope
1150  static std::size_t array_comprehension_index_counter = 0;
1151  ++array_comprehension_index_counter;
1152  symbol_exprt array_comprehension_index{
1153  "$array_comprehension_index_a" +
1154  std::to_string(array_comprehension_index_counter),
1155  array_type.index_type()};
1156 
1157  plus_exprt new_offset{
1158  unpacked.offset(),
1160  mult_exprt{
1161  array_comprehension_index,
1162  from_integer(
1163  element_bits / src.get_bits_per_byte(),
1164  array_comprehension_index.type())},
1165  unpacked.offset().type())};
1166 
1167  byte_extract_exprt body(unpacked);
1168  body.type() = subtype;
1169  body.offset() = std::move(new_offset);
1170 
1172  std::move(array_comprehension_index),
1173  lower_byte_extract(body, ns),
1174  array_type};
1175 }
1176 
1185 static std::optional<exprt> lower_byte_extract_complex(
1186  const byte_extract_exprt &src,
1187  const byte_extract_exprt &unpacked,
1188  const namespacet &ns)
1189 {
1190  const complex_typet &complex_type = to_complex_type(src.type());
1191  const typet &subtype = complex_type.subtype();
1192 
1193  auto subtype_bits = pointer_offset_bits(subtype, ns);
1194  if(!subtype_bits.has_value() || *subtype_bits % src.get_bits_per_byte() != 0)
1195  return {};
1196 
1197  // offset remains unchanged
1198  byte_extract_exprt real{unpacked};
1199  real.type() = subtype;
1200 
1201  const plus_exprt new_offset{
1202  unpacked.offset(),
1203  from_integer(
1204  *subtype_bits / src.get_bits_per_byte(), unpacked.offset().type())};
1205  byte_extract_exprt imag{unpacked};
1206  imag.type() = subtype;
1207  imag.offset() = simplify_expr(new_offset, ns);
1208 
1209  return simplify_expr(
1210  complex_exprt{
1211  lower_byte_extract(real, ns), lower_byte_extract(imag, ns), complex_type},
1212  ns);
1213 }
1214 
1218 {
1219  // General notes about endianness and the bit-vector conversion:
1220  // A single byte with value 0b10001000 is stored (in irept) as
1221  // exactly this string literal, and its bit-vector encoding will be
1222  // bvt bv={0,0,0,1,0,0,0,1}, i.e., bv[0]==0 and bv[7]==1
1223  //
1224  // A multi-byte value like x=256 would be:
1225  // - little-endian storage: ((char*)&x)[0]==0, ((char*)&x)[1]==1
1226  // - big-endian storage: ((char*)&x)[0]==1, ((char*)&x)[1]==0
1227  // - irept representation: 0000000100000000
1228  // - bvt: {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0}
1229  // <... 8bits ...> <... 8bits ...>
1230  //
1231  // An array {0, 1} will be encoded as bvt bv={0,1}, i.e., bv[1]==1
1232  // concatenation(0, 1) will yield a bvt bv={1,0}, i.e., bv[1]==0
1233  //
1234  // The semantics of byte_extract(endianness, op, offset, T) is:
1235  // interpret ((char*)&op)+offset as the endianness-ordered storage
1236  // of an object of type T at address ((char*)&op)+offset
1237  // For some T x, byte_extract(endianness, x, 0, T) must yield x.
1238  //
1239  // byte_extract for a composite type T or an array will interpret
1240  // the individual subtypes with suitable endianness; the overall
1241  // order of components is not affected by endianness.
1242  //
1243  // Examples:
1244  // unsigned char A[4];
1245  // byte_extract_little_endian(A, 0, unsigned short) requests that
1246  // A[0],A[1] be interpreted as the storage of an unsigned short with
1247  // A[1] being the most-significant byte; byte_extract_big_endian for
1248  // the same operands will select A[0] as the most-significant byte.
1249  //
1250  // int A[2] = {0x01020304,0xDEADBEEF}
1251  // byte_extract_big_endian(A, 0, short) should yield 0x0102
1252  // byte_extract_little_endian(A, 0, short) should yield 0x0304
1253  // To obtain this we first compute byte arrays while taking into
1254  // account endianness:
1255  // big-endian byte representation: {01,02,03,04,DE,AB,BE,EF}
1256  // little-endian byte representation: {04,03,02,01,EF,BE,AB,DE}
1257  // We extract the relevant bytes starting from ((char*)A)+0:
1258  // big-endian: {01,02}; little-endian: {04,03}
1259  // Finally we place them in the appropriate byte order as indicated
1260  // by endianness:
1261  // big-endian: (short)concatenation(01,02)=0x0102
1262  // little-endian: (short)concatenation(03,04)=0x0304
1263 
1264  PRECONDITION(
1265  src.id() == ID_byte_extract_little_endian ||
1266  src.id() == ID_byte_extract_big_endian);
1267  const bool little_endian = src.id() == ID_byte_extract_little_endian;
1268 
1269  // determine an upper bound of the last byte we might need
1270  auto upper_bound_opt = size_of_expr(src.type(), ns);
1271  if(upper_bound_opt.has_value())
1272  {
1273  upper_bound_opt = simplify_expr(
1274  plus_exprt(
1275  upper_bound_opt.value(),
1277  src.offset(), upper_bound_opt.value().type())),
1278  ns);
1279  }
1280  else if(src.type().id() == ID_empty)
1281  upper_bound_opt = from_integer(0, size_type());
1282 
1283  const auto lower_bound_int_opt = numeric_cast<mp_integer>(src.offset());
1284  const auto upper_bound_int_opt =
1285  numeric_cast<mp_integer>(upper_bound_opt.value_or(nil_exprt()));
1286 
1287  byte_extract_exprt unpacked(src);
1288  unpacked.op() = unpack_rec(
1289  src.op(),
1290  little_endian,
1291  lower_bound_int_opt,
1292  upper_bound_int_opt,
1293  src.get_bits_per_byte(),
1294  ns);
1295  CHECK_RETURN(
1297  .get_width() == src.get_bits_per_byte());
1298 
1299  if(src.type().id() == ID_array || src.type().id() == ID_vector)
1300  {
1301  const typet &subtype = to_type_with_subtype(src.type()).subtype();
1302 
1303  // consider ways of dealing with arrays of unknown subtype size or with a
1304  // subtype size that does not fit byte boundaries; currently we fall back to
1305  // stitching together consecutive elements down below
1306  auto element_bits = pointer_offset_bits(subtype, ns);
1307  if(
1308  element_bits.has_value() && *element_bits >= 1 &&
1309  *element_bits % src.get_bits_per_byte() == 0)
1310  {
1312  src, unpacked, subtype, *element_bits, ns);
1313  }
1314  }
1315  else if(src.type().id() == ID_complex)
1316  {
1317  auto result = lower_byte_extract_complex(src, unpacked, ns);
1318  if(result.has_value())
1319  return std::move(*result);
1320 
1321  // else fall back to generic lowering that uses bit masks, below
1322  }
1323  else if(src.type().id() == ID_struct || src.type().id() == ID_struct_tag)
1324  {
1325  const struct_typet &struct_type =
1326  src.type().id() == ID_struct_tag
1327  ? ns.follow_tag(to_struct_tag_type(src.type()))
1328  : to_struct_type(src.type());
1329  const struct_typet::componentst &components = struct_type.components();
1330 
1331  bool failed = false;
1332  struct_exprt s({}, src.type());
1333 
1334  for(const auto &comp : components)
1335  {
1336  auto component_bits = pointer_offset_bits(comp.type(), ns);
1337 
1338  // the next member would be misaligned, abort
1339  if(
1340  !component_bits.has_value() ||
1341  *component_bits % src.get_bits_per_byte() != 0)
1342  {
1343  failed = true;
1344  break;
1345  }
1346 
1347  auto member_offset_opt =
1348  member_offset_expr(struct_type, comp.get_name(), ns);
1349 
1350  if(!member_offset_opt.has_value())
1351  {
1352  failed = true;
1353  break;
1354  }
1355 
1356  plus_exprt new_offset(
1357  unpacked.offset(),
1359  member_offset_opt.value(), unpacked.offset().type()));
1360 
1361  byte_extract_exprt tmp(unpacked);
1362  tmp.type() = comp.type();
1363  tmp.offset() = new_offset;
1364 
1365  s.add_to_operands(lower_byte_extract(tmp, ns));
1366  }
1367 
1368  if(!failed)
1369  return simplify_expr(std::move(s), ns);
1370  }
1371  else if(src.type().id() == ID_union || src.type().id() == ID_union_tag)
1372  {
1373  const union_typet &union_type =
1374  src.type().id() == ID_union_tag
1375  ? ns.follow_tag(to_union_tag_type(src.type()))
1376  : to_union_type(src.type());
1377 
1378  const auto widest_member = union_type.find_widest_union_component(ns);
1379 
1380  if(widest_member.has_value())
1381  {
1382  byte_extract_exprt tmp(unpacked);
1383  tmp.type() = widest_member->first.type();
1384 
1385  return union_exprt(
1386  widest_member->first.get_name(),
1387  lower_byte_extract(tmp, ns),
1388  src.type());
1389  }
1390  }
1391 
1392  const exprt &root = unpacked.op();
1393  const exprt &offset = unpacked.offset();
1394 
1395  std::optional<typet> subtype;
1396  std::optional<typet> index_type;
1397  if(root.type().id() == ID_vector)
1398  {
1399  subtype = to_vector_type(root.type()).element_type();
1400  index_type = to_vector_type(root.type()).index_type();
1401  }
1402  else
1403  {
1404  subtype = to_array_type(root.type()).element_type();
1405  index_type = to_array_type(root.type()).index_type();
1406  }
1407 
1408  auto subtype_bits = pointer_offset_bits(*subtype, ns);
1409 
1411  subtype_bits.has_value() && *subtype_bits == src.get_bits_per_byte(),
1412  "offset bits are byte aligned");
1413 
1414  auto size_bits = pointer_offset_bits(unpacked.type(), ns);
1415  if(!size_bits.has_value())
1416  {
1417  auto op0_bits = pointer_offset_bits(unpacked.op().type(), ns);
1418  // all cases with non-constant width should have been handled above
1420  op0_bits.has_value(),
1421  "the extracted width or the source width must be known");
1422  size_bits = op0_bits;
1423  }
1424 
1425  mp_integer num_bytes =
1426  (*size_bits) / src.get_bits_per_byte() +
1427  (((*size_bits) % src.get_bits_per_byte() == 0) ? 0 : 1);
1428 
1429  // get 'width'-many bytes, and concatenate
1430  const std::size_t width_bytes = numeric_cast_v<std::size_t>(num_bytes);
1431  exprt::operandst op;
1432  op.reserve(width_bytes);
1433 
1434  for(std::size_t i = 0; i < width_bytes; i++)
1435  {
1436  // the most significant byte comes first in the concatenation!
1437  std::size_t offset_int = little_endian ? (width_bytes - i - 1) : i;
1438 
1439  plus_exprt offset_i{
1440  from_integer(offset_int, *index_type),
1441  typecast_exprt::conditional_cast(offset, *index_type)};
1442  simplify(offset_i, ns);
1443 
1444  mp_integer index = 0;
1445  if(
1446  offset_i.is_constant() &&
1447  (root.id() == ID_array || root.id() == ID_vector) &&
1448  !to_integer(to_constant_expr(offset_i), index) &&
1449  index < root.operands().size() && index >= 0)
1450  {
1451  // offset is constant and in range
1452  op.push_back(root.operands()[numeric_cast_v<std::size_t>(index)]);
1453  }
1454  else
1455  {
1456  op.push_back(index_exprt(root, offset_i));
1457  }
1458  }
1459 
1460  if(width_bytes == 1)
1461  {
1462  return simplify_expr(
1463  typecast_exprt::conditional_cast(op.front(), src.type()), ns);
1464  }
1465  else // width_bytes>=2
1466  {
1467  concatenation_exprt concatenation(
1468  std::move(op),
1469  adjust_width(*subtype, width_bytes * src.get_bits_per_byte()));
1470 
1471  endianness_mapt map(concatenation.type(), little_endian, ns);
1472  return bv_to_expr(concatenation, src.type(), map, ns);
1473  }
1474 }
1475 
1476 static exprt lower_byte_update(
1477  const byte_update_exprt &src,
1478  const exprt &value_as_byte_array,
1479  const std::optional<exprt> &non_const_update_bound,
1480  const namespacet &ns);
1481 
1492  const byte_update_exprt &src,
1493  const typet &subtype,
1494  const exprt &value_as_byte_array,
1495  const exprt &non_const_update_bound,
1496  const namespacet &ns)
1497 {
1498  // TODO we either need a symbol table here or make array comprehensions
1499  // introduce a scope
1500  static std::size_t array_comprehension_index_counter = 0;
1501  ++array_comprehension_index_counter;
1502  symbol_exprt array_comprehension_index{
1503  "$array_comprehension_index_u_a_v" +
1504  std::to_string(array_comprehension_index_counter),
1505  to_array_type(src.type()).index_type()};
1506 
1507  binary_predicate_exprt lower_bound{
1509  array_comprehension_index, src.offset().type()),
1510  ID_lt,
1511  src.offset()};
1512  binary_predicate_exprt upper_bound{
1514  array_comprehension_index, non_const_update_bound.type()),
1515  ID_ge,
1516  plus_exprt{
1518  src.offset(), non_const_update_bound.type()),
1519  non_const_update_bound}};
1520 
1521  PRECONDITION(
1522  src.id() == ID_byte_update_little_endian ||
1523  src.id() == ID_byte_update_big_endian);
1524  const bool little_endian = src.id() == ID_byte_update_little_endian;
1525  endianness_mapt map(
1526  to_array_type(value_as_byte_array.type()).element_type(),
1527  little_endian,
1528  ns);
1529  if_exprt array_comprehension_body{
1530  or_exprt{std::move(lower_bound), std::move(upper_bound)},
1531  index_exprt{src.op(), array_comprehension_index},
1532  bv_to_expr(
1533  index_exprt{
1534  value_as_byte_array,
1535  minus_exprt{
1536  array_comprehension_index,
1538  src.offset(), array_comprehension_index.type())}},
1539  subtype,
1540  map,
1541  ns)};
1542 
1543  return simplify_expr(
1545  array_comprehension_index,
1546  std::move(array_comprehension_body),
1547  to_array_type(src.type())},
1548  ns);
1549 }
1550 
1561  const byte_update_exprt &src,
1562  const typet &subtype,
1563  const array_exprt &value_as_byte_array,
1564  const std::optional<exprt> &non_const_update_bound,
1565  const namespacet &ns)
1566 {
1567  PRECONDITION(
1568  src.id() == ID_byte_update_little_endian ||
1569  src.id() == ID_byte_update_big_endian);
1570  const bool little_endian = src.id() == ID_byte_update_little_endian;
1571 
1572  const typet index_type = src.type().id() == ID_array
1573  ? to_array_type(src.type()).index_type()
1574  : to_vector_type(src.type()).index_type();
1575 
1576  // apply 'array-update-with' num_elements times
1577  exprt result = src.op();
1578 
1579  for(std::size_t i = 0; i < value_as_byte_array.operands().size(); ++i)
1580  {
1581  const exprt &element = value_as_byte_array.operands()[i];
1582 
1583  exprt where = simplify_expr(
1584  plus_exprt{
1585  typecast_exprt::conditional_cast(src.offset(), index_type),
1586  from_integer(i, index_type)},
1587  ns);
1588 
1589  // skip elements that wouldn't change (skip over typecasts as we might have
1590  // some signed/unsigned char conversions)
1591  const exprt &e = skip_typecast(element);
1592  if(e.id() == ID_index)
1593  {
1594  const index_exprt &index_expr = to_index_expr(e);
1595  if(index_expr.array() == src.op() && index_expr.index() == where)
1596  continue;
1597  }
1598 
1599  endianness_mapt map(element.type(), little_endian, ns);
1600  exprt update_value = bv_to_expr(element, subtype, map, ns);
1601  if(non_const_update_bound.has_value())
1602  {
1603  update_value = if_exprt{
1605  from_integer(i, non_const_update_bound->type()),
1606  ID_lt,
1607  *non_const_update_bound},
1608  update_value,
1609  index_exprt{src.op(), where}};
1610  }
1611 
1612  if(result.id() != ID_with)
1613  result = with_exprt{result, std::move(where), std::move(update_value)};
1614  else
1615  result.add_to_operands(std::move(where), std::move(update_value));
1616  }
1617 
1618  return simplify_expr(std::move(result), ns);
1619 }
1620 
1637  const byte_update_exprt &src,
1638  const typet &subtype,
1639  const exprt &subtype_size,
1640  const exprt &value_as_byte_array,
1641  const exprt &non_const_update_bound,
1642  const exprt &initial_bytes,
1643  const exprt &first_index,
1644  const exprt &first_update_value,
1645  const namespacet &ns)
1646 {
1647  const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
1648  ? ID_byte_extract_little_endian
1649  : ID_byte_extract_big_endian;
1650 
1651  // TODO we either need a symbol table here or make array comprehensions
1652  // introduce a scope
1653  static std::size_t array_comprehension_index_counter = 0;
1654  ++array_comprehension_index_counter;
1655  symbol_exprt array_comprehension_index{
1656  "$array_comprehension_index_u_a_v_u" +
1657  std::to_string(array_comprehension_index_counter),
1658  to_array_type(src.type()).index_type()};
1659 
1660  // all arithmetic uses offset/index types
1661  PRECONDITION(array_comprehension_index.type() == src.offset().type());
1662  PRECONDITION(subtype_size.type() == src.offset().type());
1663  PRECONDITION(initial_bytes.type() == src.offset().type());
1664  PRECONDITION(first_index.type() == src.offset().type());
1665 
1666  // the bound from where updates start
1667  binary_predicate_exprt lower_bound{
1669  array_comprehension_index, first_index.type()),
1670  ID_lt,
1671  first_index};
1672 
1673  // The actual value of updates other than at the start or end
1674  plus_exprt offset_expr{
1675  initial_bytes,
1676  mult_exprt{
1677  subtype_size,
1678  minus_exprt{
1680  array_comprehension_index, first_index.type()),
1681  plus_exprt{first_index, from_integer(1, first_index.type())}}}};
1682  exprt update_value = lower_byte_extract(
1684  extract_opcode,
1685  value_as_byte_array,
1686  std::move(offset_expr),
1687  src.get_bits_per_byte(),
1688  subtype},
1689  ns);
1690 
1691  // The number of target array/vector elements being replaced, not including
1692  // a possible partial update at the end of the updated range, which is handled
1693  // below: (non_const_update_bound + (subtype_size - 1)) / subtype_size to
1694  // round up to the nearest multiple of subtype_size.
1695  div_exprt updated_elements{
1696  plus_exprt{
1698  non_const_update_bound, subtype_size.type()),
1699  minus_exprt{subtype_size, from_integer(1, subtype_size.type())}},
1700  subtype_size};
1701 
1702  // The last element to be updated: first_index + updated_elements - 1
1703  plus_exprt last_index{
1704  first_index,
1705  minus_exprt{
1706  std::move(updated_elements), from_integer(1, first_index.type())}};
1707 
1708  // The size of a partial update at the end of the updated range, may be zero.
1709  mod_exprt tail_size{
1711  minus_exprt{
1713  non_const_update_bound, initial_bytes.type()),
1714  initial_bytes},
1715  subtype_size.type()),
1716  subtype_size};
1717 
1718  // The bound where updates end, which is conditional on the partial update
1719  // being empty.
1720  binary_predicate_exprt upper_bound{
1722  array_comprehension_index, last_index.type()),
1723  ID_ge,
1724  if_exprt{
1725  equal_exprt{tail_size, from_integer(0, tail_size.type())},
1726  last_index,
1727  plus_exprt{last_index, from_integer(1, last_index.type())}}};
1728 
1729  // The actual value of a partial update at the end.
1730  exprt last_update_value = lower_byte_update(
1732  src.id(),
1733  index_exprt{src.op(), last_index},
1735  typecast_exprt::conditional_cast(last_index, subtype_size.type()),
1736  subtype_size}},
1737  value_as_byte_array,
1738  src.get_bits_per_byte()},
1739  ns);
1740 
1741  if_exprt array_comprehension_body{
1742  or_exprt{std::move(lower_bound), std::move(upper_bound)},
1743  index_exprt{src.op(), array_comprehension_index},
1744  if_exprt{
1745  equal_exprt{
1747  array_comprehension_index, first_index.type()),
1748  first_index},
1749  first_update_value,
1750  if_exprt{
1751  equal_exprt{
1753  array_comprehension_index, last_index.type()),
1754  last_index},
1755  std::move(last_update_value),
1756  std::move(update_value)}}};
1757 
1758  return simplify_expr(
1760  array_comprehension_index,
1761  std::move(array_comprehension_body),
1762  to_array_type(src.type())},
1763  ns);
1764 }
1765 
1777  const byte_update_exprt &src,
1778  const typet &subtype,
1779  const exprt &value_as_byte_array,
1780  const std::optional<exprt> &non_const_update_bound,
1781  const namespacet &ns)
1782 {
1783  // do all arithmetic below using index/offset types - the array theory
1784  // back-end is really picky about indices having the same type
1785  auto subtype_size_opt = size_of_expr(subtype, ns);
1786  CHECK_RETURN(subtype_size_opt.has_value());
1787 
1788  const exprt subtype_size = simplify_expr(
1790  subtype_size_opt.value(), src.offset().type()),
1791  ns);
1792 
1793  // compute the index of the first element of the array/vector that may be
1794  // updated
1795  PRECONDITION(
1796  src.offset().type() == to_array_type(src.op().type()).index_type());
1797  exprt first_index = div_exprt{src.offset(), subtype_size};
1798  simplify(first_index, ns);
1799 
1800  // compute the offset within that first element
1801  const exprt update_offset = mod_exprt{src.offset(), subtype_size};
1802 
1803  // compute the number of bytes (from the update value) that are going to be
1804  // consumed for updating the first element
1805  const exprt update_size =
1806  from_integer(value_as_byte_array.operands().size(), subtype_size.type());
1807  exprt initial_bytes = minus_exprt{subtype_size, update_offset};
1808  exprt update_bound;
1809  if(non_const_update_bound.has_value())
1810  {
1811  update_bound = typecast_exprt::conditional_cast(
1812  *non_const_update_bound, subtype_size.type());
1813  }
1814  else
1815  {
1817  value_as_byte_array.id() == ID_array,
1818  "value should be an array expression if the update bound is constant");
1819  update_bound = update_size;
1820  }
1821  initial_bytes = if_exprt{
1822  binary_predicate_exprt{initial_bytes, ID_lt, update_bound},
1823  initial_bytes,
1824  update_bound};
1825  simplify(initial_bytes, ns);
1826 
1827  // encode the first update: update the original element at first_index (the
1828  // actual update will only be initial_bytes-many bytes from
1829  // value_as_byte_array)
1830  exprt first_update_value = lower_byte_update(
1832  src.id(),
1833  index_exprt{src.op(), first_index},
1834  update_offset,
1835  value_as_byte_array,
1836  src.get_bits_per_byte()},
1837  ns);
1838 
1839  if(value_as_byte_array.id() != ID_array)
1840  {
1842  src,
1843  subtype,
1844  subtype_size,
1845  value_as_byte_array,
1846  *non_const_update_bound,
1847  initial_bytes,
1848  first_index,
1849  first_update_value,
1850  ns);
1851  }
1852 
1853  // We will update one array/vector element at a time - compute the number of
1854  // update values that will be consumed in each step. If we cannot determine a
1855  // constant value at this time we assume it's at least one byte. The
1856  // byte_extract_exprt within the loop uses the symbolic value (subtype_size),
1857  // we just need to make sure we make progress for the loop to terminate.
1858  std::size_t step_size = 1;
1859  if(subtype_size.is_constant())
1860  step_size = numeric_cast_v<std::size_t>(to_constant_expr(subtype_size));
1861  // Given the first update already encoded, keep track of the offset into the
1862  // update value. Again, the expressions within the loop use the symbolic
1863  // value, this is just an optimization in case we can determine a constant
1864  // offset.
1865  std::size_t offset = 0;
1866  if(initial_bytes.is_constant())
1867  offset = numeric_cast_v<std::size_t>(to_constant_expr(initial_bytes));
1868 
1869  with_exprt result{src.op(), first_index, first_update_value};
1870 
1871  auto lower_byte_update_array_vector_non_const_one_element =
1872  [&src,
1873  &first_index,
1874  &initial_bytes,
1875  &subtype_size,
1876  &value_as_byte_array,
1877  &ns,
1878  &result](std::size_t i) -> void {
1879  exprt where = simplify_expr(
1880  plus_exprt{first_index, from_integer(i, first_index.type())}, ns);
1881 
1882  exprt neg_offset_expr = simplify_expr(
1884  initial_bytes,
1885  mult_exprt{subtype_size, from_integer(i - 1, subtype_size.type())}}},
1886  ns);
1887 
1888  exprt element = lower_byte_update(
1890  src.id(),
1891  index_exprt{src.op(), where},
1892  neg_offset_expr,
1893  value_as_byte_array,
1894  src.get_bits_per_byte()},
1895  ns);
1896 
1897  result.add_to_operands(std::move(where), std::move(element));
1898  };
1899 
1900  std::size_t i = 1;
1901  for(; offset + step_size <= value_as_byte_array.operands().size();
1902  offset += step_size, ++i)
1903  {
1904  lower_byte_update_array_vector_non_const_one_element(i);
1905  }
1906 
1907  // do the tail
1908  if(offset < value_as_byte_array.operands().size())
1909  lower_byte_update_array_vector_non_const_one_element(i);
1910 
1911  return simplify_expr(std::move(result), ns);
1912 }
1913 
1927  const byte_update_exprt &src,
1928  const mp_integer &offset_bits,
1929  const exprt &element_to_update,
1930  const mp_integer &subtype_bits,
1931  const mp_integer &bits_already_set,
1932  const exprt &value_as_byte_array,
1933  const std::optional<exprt> &non_const_update_bound,
1934  const namespacet &ns)
1935 {
1936  // We need to take one or more bytes from value_as_byte_array to modify the
1937  // target element. We need to compute:
1938  // - The position in value_as_byte_array to take bytes from: If subtype_bits
1939  // is less than the size of a byte, then multiple struct/array/vector elements
1940  // will need to be updated using the same byte.
1941  std::size_t first = 0;
1942  // - An upper bound on the number of bytes required from value_as_byte_array.
1943  mp_integer update_elements =
1944  (subtype_bits + src.get_bits_per_byte() - 1) / src.get_bits_per_byte();
1945  // - The offset into the target element: If subtype_bits is greater or equal
1946  // to the size of a byte, then there may be an offset into the target element
1947  // that needs to be taken into account, and multiple bytes will be required.
1948  mp_integer offset_bits_in_target_element = offset_bits - bits_already_set;
1949 
1950  if(offset_bits_in_target_element < 0)
1951  {
1952  INVARIANT(
1953  value_as_byte_array.id() != ID_array ||
1954  value_as_byte_array.operands().size() * src.get_bits_per_byte() >
1955  -offset_bits_in_target_element,
1956  "indices past the update should be handled below");
1957  first += numeric_cast_v<std::size_t>(
1958  -offset_bits_in_target_element / src.get_bits_per_byte());
1959  offset_bits_in_target_element +=
1960  (-offset_bits_in_target_element / src.get_bits_per_byte()) *
1961  src.get_bits_per_byte();
1962  if(offset_bits_in_target_element < 0)
1963  ++update_elements;
1964  }
1965  else
1966  {
1967  update_elements -= offset_bits_in_target_element / src.get_bits_per_byte();
1968  INVARIANT(
1969  update_elements > 0, "indices before the update should be handled above");
1970  }
1971 
1972  std::size_t end = first + numeric_cast_v<std::size_t>(update_elements);
1973  if(value_as_byte_array.id() == ID_array)
1974  end = std::min(end, value_as_byte_array.operands().size());
1975  exprt::operandst update_values = instantiate_byte_array(
1976  value_as_byte_array, first, end, src.get_bits_per_byte(), ns);
1977  const std::size_t update_size = update_values.size();
1978  const exprt update_size_expr = from_integer(update_size, size_type());
1979  const array_typet update_type{
1980  bv_typet{src.get_bits_per_byte()}, update_size_expr};
1981 
1982  // each case below will set "new_value" as appropriate
1983  exprt new_value;
1984 
1985  if(
1986  offset_bits_in_target_element >= 0 &&
1987  offset_bits_in_target_element % src.get_bits_per_byte() == 0)
1988  {
1989  new_value = array_exprt{update_values, update_type};
1990  }
1991  else
1992  {
1993  if(src.id() == ID_byte_update_little_endian)
1994  std::reverse(update_values.begin(), update_values.end());
1995  if(offset_bits_in_target_element < 0)
1996  {
1997  if(src.id() == ID_byte_update_little_endian)
1998  {
1999  new_value = lshr_exprt{
2001  update_values, bv_typet{update_size * src.get_bits_per_byte()}},
2002  numeric_cast_v<std::size_t>(-offset_bits_in_target_element)};
2003  }
2004  else
2005  {
2006  new_value = shl_exprt{
2008  update_values, bv_typet{update_size * src.get_bits_per_byte()}},
2009  numeric_cast_v<std::size_t>(-offset_bits_in_target_element)};
2010  }
2011  }
2012  else
2013  {
2014  const std::size_t offset_bits_int =
2015  numeric_cast_v<std::size_t>(offset_bits_in_target_element);
2016  const std::size_t subtype_bits_int =
2017  numeric_cast_v<std::size_t>(subtype_bits);
2018 
2019  extractbits_exprt bits_to_keep{
2020  element_to_update,
2021  subtype_bits_int - 1,
2022  subtype_bits_int - offset_bits_int,
2023  bv_typet{offset_bits_int}};
2024  new_value = concatenation_exprt{
2025  bits_to_keep,
2028  update_values, bv_typet{update_size * src.get_bits_per_byte()}},
2029  update_size * src.get_bits_per_byte() - 1,
2030  offset_bits_int,
2031  bv_typet{update_size * src.get_bits_per_byte() - offset_bits_int}},
2032  bv_typet{update_size * src.get_bits_per_byte()}};
2033  }
2034 
2035  const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
2036  ? ID_byte_extract_little_endian
2037  : ID_byte_extract_big_endian;
2038 
2039  const byte_extract_exprt byte_extract_expr{
2040  extract_opcode,
2041  new_value,
2042  from_integer(0, src.offset().type()),
2043  src.get_bits_per_byte(),
2044  update_type};
2045 
2046  new_value = lower_byte_extract(byte_extract_expr, ns);
2047 
2048  offset_bits_in_target_element = 0;
2049  }
2050 
2051  // With an upper bound on the size of the update established, construct the
2052  // actual update expression. If the exact size of the update is unknown,
2053  // make the size expression conditional.
2054  const byte_update_exprt bu{
2055  src.id(),
2056  element_to_update,
2057  from_integer(
2058  offset_bits_in_target_element / src.get_bits_per_byte(),
2059  src.offset().type()),
2060  new_value,
2061  src.get_bits_per_byte()};
2062 
2063  std::optional<exprt> update_bound;
2064  if(non_const_update_bound.has_value())
2065  {
2066  // The size of the update is not constant, and thus is to be symbolically
2067  // bound; first see how many bytes we have left in the update:
2068  // non_const_update_bound > first ? non_const_update_bound - first: 0
2069  const exprt remaining_update_bytes = typecast_exprt::conditional_cast(
2070  if_exprt{
2072  *non_const_update_bound,
2073  ID_gt,
2074  from_integer(first, non_const_update_bound->type())},
2075  minus_exprt{
2076  *non_const_update_bound,
2077  from_integer(first, non_const_update_bound->type())},
2078  from_integer(0, non_const_update_bound->type())},
2079  size_type());
2080  // Now take the minimum of update-bytes-left and the previously computed
2081  // size of the element to be updated:
2082  update_bound = simplify_expr(
2083  if_exprt{
2084  binary_predicate_exprt{update_size_expr, ID_lt, remaining_update_bytes},
2085  update_size_expr,
2086  remaining_update_bytes},
2087  ns);
2088  }
2089 
2090  return lower_byte_update(bu, new_value, update_bound, ns);
2091 }
2092 
2104  const byte_update_exprt &src,
2105  const typet &subtype,
2106  const std::optional<mp_integer> &subtype_bits,
2107  const exprt &value_as_byte_array,
2108  const std::optional<exprt> &non_const_update_bound,
2109  const namespacet &ns)
2110 {
2111  const bool is_array = src.type().id() == ID_array;
2112  exprt size;
2113  typet index_type;
2114  if(is_array)
2115  {
2116  size = to_array_type(src.type()).size();
2117  index_type = to_array_type(src.type()).index_type();
2118  }
2119  else
2120  {
2121  size = to_vector_type(src.type()).size();
2122  index_type = to_vector_type(src.type()).index_type();
2123  }
2124 
2125  // fall back to bytewise updates in all non-constant or dubious cases
2126  if(
2127  !size.is_constant() || !src.offset().is_constant() ||
2128  !subtype_bits.has_value() || value_as_byte_array.id() != ID_array)
2129  {
2131  src, subtype, value_as_byte_array, non_const_update_bound, ns);
2132  }
2133 
2134  std::size_t num_elements =
2135  numeric_cast_v<std::size_t>(to_constant_expr(size));
2136  mp_integer offset_bits =
2137  numeric_cast_v<mp_integer>(to_constant_expr(src.offset())) *
2138  src.get_bits_per_byte();
2139 
2140  exprt::operandst elements;
2141  elements.reserve(num_elements);
2142 
2143  std::size_t i = 0;
2144  // copy the prefix not affected by the update
2145  for(; i < num_elements && (i + 1) * *subtype_bits <= offset_bits; ++i)
2146  elements.push_back(index_exprt{src.op(), from_integer(i, index_type)});
2147 
2148  // the modified elements
2149  for(;
2150  i < num_elements &&
2151  i * *subtype_bits < offset_bits + value_as_byte_array.operands().size() *
2152  src.get_bits_per_byte();
2153  ++i)
2154  {
2155  elements.push_back(lower_byte_update_single_element(
2156  src,
2157  offset_bits,
2158  index_exprt{src.op(), from_integer(i, index_type)},
2159  *subtype_bits,
2160  i * *subtype_bits,
2161  value_as_byte_array,
2162  non_const_update_bound,
2163  ns));
2164  }
2165 
2166  // copy the tail not affected by the update
2167  for(; i < num_elements; ++i)
2168  elements.push_back(index_exprt{src.op(), from_integer(i, index_type)});
2169 
2170  if(is_array)
2171  return simplify_expr(
2172  array_exprt{std::move(elements), to_array_type(src.type())}, ns);
2173  else
2174  return simplify_expr(
2175  vector_exprt{std::move(elements), to_vector_type(src.type())}, ns);
2176 }
2177 
2188  const byte_update_exprt &src,
2189  const struct_typet &struct_type,
2190  const exprt &value_as_byte_array,
2191  const std::optional<exprt> &non_const_update_bound,
2192  const namespacet &ns)
2193 {
2194  exprt::operandst elements;
2195  elements.reserve(struct_type.components().size());
2196 
2198  for(const auto &comp : struct_type.components())
2199  {
2200  auto element_width = pointer_offset_bits(comp.type(), ns);
2201 
2202  // compute the update offset relative to this struct member - will be
2203  // negative if we are already in the middle of the update or beyond it
2204  exprt offset = simplify_expr(
2205  minus_exprt{
2206  mult_exprt{
2207  src.offset(),
2208  from_integer(src.get_bits_per_byte(), src.offset().type())},
2210  ns);
2211  auto offset_bits = numeric_cast<mp_integer>(offset);
2212  if(!offset_bits.has_value() || !element_width.has_value())
2213  {
2214  // The offset to update is not constant, either because the original
2215  // offset in src never was, or because a struct member has an unknown
2216  // offset. Abort the attempt to update individual struct members and
2217  // instead turn the operand-to-be-updated into a byte array, which we know
2218  // how to update even if the offset is non-constant.
2219  const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
2220  ? ID_byte_extract_little_endian
2221  : ID_byte_extract_big_endian;
2222 
2223  auto src_size_opt = size_of_expr(src.type(), ns);
2224  CHECK_RETURN(src_size_opt.has_value());
2225 
2226  const byte_extract_exprt byte_extract_expr{
2227  extract_opcode,
2228  src.op(),
2229  from_integer(0, src.offset().type()),
2230  src.get_bits_per_byte(),
2231  array_typet{bv_typet{src.get_bits_per_byte()}, src_size_opt.value()}};
2232 
2233  byte_update_exprt bu = src;
2234  bu.set_op(lower_byte_extract(byte_extract_expr, ns));
2235  bu.type() = bu.op().type();
2236 
2237  return lower_byte_extract(
2239  extract_opcode,
2241  bu, value_as_byte_array, non_const_update_bound, ns),
2242  from_integer(0, src.offset().type()),
2243  src.get_bits_per_byte(),
2244  src.type()},
2245  ns);
2246  }
2247 
2248  exprt member = member_exprt{src.op(), comp.get_name(), comp.type()};
2249 
2250  // we don't need to update anything when
2251  // 1) the update offset is greater than the end of this member (thus the
2252  // relative offset is greater than this element) or
2253  // 2) the update offset plus the size of the update is less than the member
2254  // offset
2255  if(
2256  *offset_bits >= *element_width ||
2257  (value_as_byte_array.id() == ID_array && *offset_bits < 0 &&
2258  -*offset_bits >=
2259  value_as_byte_array.operands().size() * src.get_bits_per_byte()))
2260  {
2261  elements.push_back(member);
2262  member_offset_bits += *element_width;
2263  continue;
2264  }
2265 
2266  elements.push_back(lower_byte_update_single_element(
2267  src,
2268  *offset_bits + member_offset_bits,
2269  member,
2270  *element_width,
2272  value_as_byte_array,
2273  non_const_update_bound,
2274  ns));
2275 
2276  member_offset_bits += *element_width;
2277  }
2278 
2279  return simplify_expr(struct_exprt{std::move(elements), struct_type}, ns);
2280 }
2281 
2292  const byte_update_exprt &src,
2293  const union_typet &union_type,
2294  const exprt &value_as_byte_array,
2295  const std::optional<exprt> &non_const_update_bound,
2296  const namespacet &ns)
2297 {
2298  const auto widest_member = union_type.find_widest_union_component(ns);
2299 
2301  widest_member.has_value(),
2302  "lower_byte_update of union of unknown size is not supported");
2303 
2304  byte_update_exprt bu = src;
2305  bu.set_op(member_exprt{
2306  src.op(), widest_member->first.get_name(), widest_member->first.type()});
2307  bu.type() = widest_member->first.type();
2308 
2309  return union_exprt{
2310  widest_member->first.get_name(),
2311  lower_byte_update(bu, value_as_byte_array, non_const_update_bound, ns),
2312  src.type()};
2313 }
2314 
2324  const byte_update_exprt &src,
2325  const exprt &value_as_byte_array,
2326  const std::optional<exprt> &non_const_update_bound,
2327  const namespacet &ns)
2328 {
2329  if(src.type().id() == ID_array || src.type().id() == ID_vector)
2330  {
2331  std::optional<typet> subtype;
2332  if(src.type().id() == ID_vector)
2333  subtype = to_vector_type(src.type()).element_type();
2334  else
2335  subtype = to_array_type(src.type()).element_type();
2336 
2337  auto element_width = pointer_offset_bits(*subtype, ns);
2338 
2339  if(element_width.has_value() && *element_width == src.get_bits_per_byte())
2340  {
2341  if(value_as_byte_array.id() != ID_array)
2342  {
2344  non_const_update_bound.has_value(),
2345  "constant update bound should yield an array expression");
2347  src, *subtype, value_as_byte_array, *non_const_update_bound, ns);
2348  }
2349 
2351  src,
2352  *subtype,
2353  to_array_expr(value_as_byte_array),
2354  non_const_update_bound,
2355  ns);
2356  }
2357  else
2358  {
2360  src,
2361  *subtype,
2362  element_width,
2363  value_as_byte_array,
2364  non_const_update_bound,
2365  ns);
2366  }
2367  }
2368  else if(src.type().id() == ID_struct || src.type().id() == ID_struct_tag)
2369  {
2370  const struct_typet &struct_type =
2371  src.type().id() == ID_struct_tag
2372  ? ns.follow_tag(to_struct_tag_type(src.type()))
2373  : to_struct_type(src.type());
2375  src, struct_type, value_as_byte_array, non_const_update_bound, ns);
2376  result.type() = src.type();
2377  return result;
2378  }
2379  else if(src.type().id() == ID_union || src.type().id() == ID_union_tag)
2380  {
2381  const union_typet &union_type =
2382  src.type().id() == ID_union_tag
2383  ? ns.follow_tag(to_union_tag_type(src.type()))
2384  : to_union_type(src.type());
2385  exprt result = lower_byte_update_union(
2386  src, union_type, value_as_byte_array, non_const_update_bound, ns);
2387  result.type() = src.type();
2388  return result;
2389  }
2390  else if(
2392  src.type().id() == ID_c_enum || src.type().id() == ID_c_enum_tag)
2393  {
2394  // mask out the bits to be updated, shift the value according to the
2395  // offset and bit-or
2396  const auto type_width = pointer_offset_bits(src.type(), ns);
2397  CHECK_RETURN(type_width.has_value() && *type_width > 0);
2398  const std::size_t type_bits = numeric_cast_v<std::size_t>(*type_width);
2399 
2400  exprt::operandst update_bytes;
2401  if(value_as_byte_array.id() == ID_array)
2402  update_bytes = value_as_byte_array.operands();
2403  else
2404  {
2405  update_bytes = instantiate_byte_array(
2406  value_as_byte_array,
2407  0,
2408  (type_bits + src.get_bits_per_byte() - 1) / src.get_bits_per_byte(),
2409  src.get_bits_per_byte(),
2410  ns);
2411  }
2412 
2413  const std::size_t update_size_bits =
2414  update_bytes.size() * src.get_bits_per_byte();
2415  const std::size_t bit_width = std::max(type_bits, update_size_bits);
2416 
2417  const bool is_little_endian = src.id() == ID_byte_update_little_endian;
2418 
2419  exprt val_before =
2420  typecast_exprt::conditional_cast(src.op(), bv_typet{type_bits});
2421  if(bit_width > type_bits)
2422  {
2423  val_before = concatenation_exprt{
2424  from_integer(0, bv_typet{bit_width - type_bits}),
2425  val_before,
2426  bv_typet{bit_width}};
2427 
2428  if(!is_little_endian)
2429  to_concatenation_expr(val_before)
2430  .op0()
2431  .swap(to_concatenation_expr(val_before).op1());
2432  }
2433 
2434  if(non_const_update_bound.has_value())
2435  {
2436  const exprt src_as_bytes = unpack_rec(
2437  val_before,
2438  src.id() == ID_byte_update_little_endian,
2439  mp_integer{0},
2440  mp_integer{update_bytes.size()},
2441  src.get_bits_per_byte(),
2442  ns);
2443  CHECK_RETURN(src_as_bytes.id() == ID_array);
2444  CHECK_RETURN(src_as_bytes.operands().size() == update_bytes.size());
2445  for(std::size_t i = 0; i < update_bytes.size(); ++i)
2446  {
2447  update_bytes[i] = if_exprt{
2449  from_integer(i, non_const_update_bound->type()),
2450  ID_lt,
2451  *non_const_update_bound},
2452  update_bytes[i],
2453  src_as_bytes.operands()[i]};
2454  }
2455  }
2456 
2457  // build mask
2458  exprt mask;
2459  if(is_little_endian)
2460  mask = from_integer(power(2, update_size_bits) - 1, bv_typet{bit_width});
2461  else
2462  {
2463  mask = from_integer(
2464  power(2, bit_width) - power(2, bit_width - update_size_bits),
2465  bv_typet{bit_width});
2466  }
2467 
2468  const typet &offset_type = src.offset().type();
2469  mult_exprt offset_in_bits{
2470  src.offset(), from_integer(src.get_bits_per_byte(), offset_type)};
2471 
2472  const binary_predicate_exprt offset_ge_zero{
2473  offset_in_bits, ID_ge, from_integer(0, offset_type)};
2474 
2475  if_exprt mask_shifted{
2476  offset_ge_zero,
2477  shl_exprt{mask, offset_in_bits},
2478  lshr_exprt{mask, unary_minus_exprt{offset_in_bits}}};
2479  if(!is_little_endian)
2480  {
2481  mask_shifted.true_case().swap(mask_shifted.false_case());
2482  to_shift_expr(mask_shifted.true_case())
2483  .distance()
2484  .swap(to_shift_expr(mask_shifted.false_case()).distance());
2485  }
2486 
2487  // original_bits &= ~mask
2488  bitand_exprt bitand_expr{val_before, bitnot_exprt{mask_shifted}};
2489 
2490  // concatenate and zero-extend the value
2491  concatenation_exprt value{update_bytes, bv_typet{update_size_bits}};
2492  if(is_little_endian)
2493  std::reverse(value.operands().begin(), value.operands().end());
2494 
2495  exprt zero_extended;
2496  if(bit_width > update_size_bits)
2497  {
2498  zero_extended = concatenation_exprt{
2499  from_integer(0, bv_typet{bit_width - update_size_bits}),
2500  value,
2501  bv_typet{bit_width}};
2502 
2503  if(!is_little_endian)
2504  to_concatenation_expr(zero_extended)
2505  .op0()
2506  .swap(to_concatenation_expr(zero_extended).op1());
2507  }
2508  else
2509  zero_extended = value;
2510 
2511  // shift the value
2512  if_exprt value_shifted{
2513  offset_ge_zero,
2514  shl_exprt{zero_extended, offset_in_bits},
2515  lshr_exprt{zero_extended, unary_minus_exprt{offset_in_bits}}};
2516  if(!is_little_endian)
2517  {
2518  value_shifted.true_case().swap(value_shifted.false_case());
2519  to_shift_expr(value_shifted.true_case())
2520  .distance()
2521  .swap(to_shift_expr(value_shifted.false_case()).distance());
2522  }
2523 
2524  // original_bits |= newvalue
2525  bitor_exprt bitor_expr{bitand_expr, value_shifted};
2526 
2527  if(bit_width > type_bits)
2528  {
2529  endianness_mapt endianness_map(
2530  bitor_expr.type(), src.id() == ID_byte_update_little_endian, ns);
2531  const auto bounds = map_bounds(endianness_map, 0, type_bits - 1);
2532 
2533  PRECONDITION(pointer_offset_bits(bitor_expr.type(), ns).has_value());
2534  return simplify_expr(
2537  bitor_expr, bounds.ub, bounds.lb, bv_typet{type_bits}},
2538  src.type()),
2539  ns);
2540  }
2541 
2542  return simplify_expr(
2543  typecast_exprt::conditional_cast(bitor_expr, src.type()), ns);
2544  }
2545  else
2546  {
2548  false, "lower_byte_update does not yet support ", src.type().id_string());
2549  }
2550 }
2551 
2553 {
2555  src.id() == ID_byte_update_little_endian ||
2556  src.id() == ID_byte_update_big_endian,
2557  "byte update expression should either be little or big endian");
2558 
2559  // An update of a void-typed object or update by a void-typed value is the
2560  // source operand (this is questionable, but may arise when dereferencing
2561  // invalid pointers).
2562  if(src.type().id() == ID_empty || src.value().type().id() == ID_empty)
2563  return src.op();
2564 
2565  // byte_update lowering proceeds as follows:
2566  // 1) Determine the size of the update, with the size of the object to be
2567  // updated as an upper bound. We fail if neither can be determined.
2568  // 2) Turn the update value into a byte array of the size determined above.
2569  // 3) If the offset is not constant, turn the object into a byte array, and
2570  // use a "with" expression to encode the update; else update the values in
2571  // place.
2572  // 4) Construct a new object.
2573  std::optional<exprt> non_const_update_bound;
2574  // update value, may require extension to full bytes
2575  exprt update_value = src.value();
2576  auto update_size_expr_opt = size_of_expr(update_value.type(), ns);
2577  CHECK_RETURN(update_size_expr_opt.has_value());
2578  simplify(update_size_expr_opt.value(), ns);
2579 
2580  const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
2581  ? ID_byte_extract_little_endian
2582  : ID_byte_extract_big_endian;
2583  const std::size_t bits_per_byte = src.get_bits_per_byte();
2584 
2585  if(!update_size_expr_opt.value().is_constant())
2586  non_const_update_bound = *update_size_expr_opt;
2587  else
2588  {
2589  auto update_bits = pointer_offset_bits(update_value.type(), ns);
2590  // If the following invariant fails, then the type was only found to be
2591  // constant via simplification. Such instances should be fixed at the place
2592  // introducing these constant-but-not-constant_exprt type sizes.
2594  update_bits.has_value(), "constant size-of should imply fixed bit width");
2595  const size_t update_bits_int = numeric_cast_v<size_t>(*update_bits);
2596 
2597  if(update_bits_int % bits_per_byte != 0)
2598  {
2600  can_cast_type<bitvector_typet>(update_value.type()),
2601  "non-byte aligned type expected to be a bitvector type");
2602  const byte_extract_exprt overlapping_byte_extract{
2603  extract_opcode,
2604  src.op(),
2605  simplify_expr(
2606  plus_exprt{
2607  src.offset(),
2608  from_integer(update_bits_int / bits_per_byte, src.offset().type())},
2609  ns),
2610  src.get_bits_per_byte(),
2611  bv_typet{bits_per_byte}};
2612  const exprt overlapping_byte =
2613  lower_byte_extract(overlapping_byte_extract, ns);
2614 
2615  size_t n_extra_bits = bits_per_byte - update_bits_int % bits_per_byte;
2616  extractbits_exprt extra_bits{
2617  overlapping_byte, n_extra_bits - 1, 0, bv_typet{n_extra_bits}};
2618 
2619  update_value = concatenation_exprt{
2621  update_value, bv_typet{update_bits_int}),
2622  extra_bits,
2623  adjust_width(update_value.type(), update_bits_int + n_extra_bits)};
2624  }
2625  else
2626  {
2627  update_size_expr_opt = from_integer(
2628  update_bits_int / bits_per_byte, update_size_expr_opt->type());
2629  }
2630  }
2631 
2632  const byte_extract_exprt byte_extract_expr{
2633  extract_opcode,
2634  update_value,
2635  from_integer(0, src.offset().type()),
2636  src.get_bits_per_byte(),
2637  array_typet{bv_typet{bits_per_byte}, *update_size_expr_opt}};
2638 
2639  const exprt value_as_byte_array = lower_byte_extract(byte_extract_expr, ns);
2640 
2641  exprt result =
2642  lower_byte_update(src, value_as_byte_array, non_const_update_bound, ns);
2643  return result;
2644 }
2645 
2647 {
2648  exprt tmp = src;
2649 
2650  // destroys any sharing, should use hash table
2651  Forall_operands(it, tmp)
2652  {
2653  *it = lower_byte_operators(*it, ns);
2654  }
2655 
2656  if(
2657  src.id() == ID_byte_update_little_endian ||
2658  src.id() == ID_byte_update_big_endian)
2659  {
2660  return lower_byte_update(to_byte_update_expr(tmp), ns);
2661  }
2662  else if(
2663  src.id() == ID_byte_extract_little_endian ||
2664  src.id() == ID_byte_extract_big_endian)
2665  {
2666  return lower_byte_extract(to_byte_extract_expr(tmp), ns);
2667  }
2668  else
2669  return tmp;
2670 }
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.
Definition: arith_tools.cpp:20
mp_integer power(const mp_integer &base, const mp_integer &exponent)
A multi-precision implementation of the power operator.
API to expression classes for bitvectors.
const 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.
Definition: c_types.h:335
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition: c_types.h:224
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 union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition: c_types.h:184
Expression to define a mapping from an argument (index) to elements.
Definition: std_expr.h:3405
Array constructor from list of elements.
Definition: std_expr.h:1616
Arrays with given size.
Definition: std_types.h:807
typet index_type() const
The type of the index expressions into any instance of this type.
Definition: std_types.cpp:33
const typet & element_type() const
The type of the elements of the array.
Definition: std_types.h:827
const exprt & size() const
Definition: std_types.h:840
A base class for expressions that are predicates, i.e., Boolean-typed, and that take exactly two argu...
Definition: std_expr.h:731
Bit-wise AND.
Bit-wise negation of bit-vectors.
Bit-wise OR.
Base class of fixed-width bit-vector types.
Definition: std_types.h:909
std::size_t get_width() const
Definition: std_types.h:920
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 & value() const
const exprt & op() const
const exprt & offset() const
void set_op(exprt e)
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' (...
Definition: c_types.h:20
Complex constructor from a pair of numbers.
Definition: std_expr.h:1911
Imaginary part of the expression describing a complex number.
Definition: std_expr.h:2022
Real part of the expression describing a complex number.
Definition: std_expr.h:1979
Complex numbers made of pair of given subtype.
Definition: std_types.h:1121
Concatenation of bit-vector operands.
Division.
Definition: std_expr.h:1152
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Union constructor to support unions without any member (a GCC/Clang feature).
Definition: std_expr.h:1829
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:1361
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
typet & type()
Return the type of the expression.
Definition: expr.h:84
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.h:212
operandst & operands()
Definition: expr.h:94
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition: expr.h:170
Extracts a sub-range of a bit-vector operand.
The trinary if-then-else operator.
Definition: std_expr.h:2370
Array index operator.
Definition: std_expr.h:1465
exprt & array()
Definition: std_expr.h:1495
exprt & index()
Definition: std_expr.h:1505
const std::string & id_string() const
Definition: irep.h:387
const irep_idt & id() const
Definition: irep.h:384
void swap(irept &irep)
Definition: irep.h:430
Logical right shift.
Extract member of struct or union.
Definition: std_expr.h:2841
Binary minus.
Definition: std_expr.h:1061
Modulo defined as lhs-(rhs * truncate(lhs/rhs)).
Definition: std_expr.h:1223
Binary multiplication Associativity is not specified.
Definition: std_expr.h:1107
exprt & op0()
Definition: std_expr.h:932
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
The NIL expression.
Definition: std_expr.h:3073
Boolean OR.
Definition: std_expr.h:2228
The plus expression Associativity is not specified.
Definition: std_expr.h:1002
exprt & distance()
Left shift.
Fixed-width bit-vector with two's complement interpretation.
Struct constructor from list of elements.
Definition: std_expr.h:1872
Structure type, corresponds to C style structs.
Definition: std_types.h:231
const componentst & components() const
Definition: std_types.h:147
std::vector< componentt > componentst
Definition: std_types.h:140
Expression to hold a symbol (variable)
Definition: std_expr.h:131
const typet & subtype() const
Definition: type.h:187
Semantic type conversion.
Definition: std_expr.h:2068
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:2076
The type of an expression, extends irept.
Definition: type.h:29
The unary minus expression.
Definition: std_expr.h:484
Union constructor from single element.
Definition: std_expr.h:1765
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:1729
The vector type.
Definition: std_types.h:1052
const constant_exprt & size() const
Definition: std_types.cpp:275
const typet & element_type() const
The type of the elements of the vector.
Definition: std_types.h:1068
typet index_type() const
The type of any index expression into an instance of this type.
Definition: std_types.cpp:263
Operator to update elements in structs and arrays.
Definition: std_expr.h:2471
#define Forall_operands(it, expr)
Definition: expr.h:27
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
Definition: expr_util.cpp:219
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.
Definition: pointer_expr.h:93
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)
Pointer Logic.
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 constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:3037
const array_exprt & to_array_expr(const exprt &expr)
Cast an exprt to an array_exprt.
Definition: std_expr.h:1660
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1533
const vector_typet & to_vector_type(const typet &type)
Cast a typet to a vector_typet.
Definition: std_types.h:1104
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
const complex_typet & to_complex_type(const typet &type)
Cast a typet to a complex_typet.
Definition: std_types.h:1146
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition: std_types.h:518
bool can_cast_type< bitvector_typet >(const typet &type)
Check whether a reference to a typet is a bitvector_typet.
Definition: std_types.h:943
const string_constantt & to_string_constant(const exprt &expr)
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
std::size_t lb
std::size_t ub
static bool failed(bool error_indicator)
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition: type.h:208
#define size_type
Definition: unistd.c:347