CBMC
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 <util/arith_tools.h>
10 #include <util/bitvector_expr.h>
11 #include <util/byte_operators.h>
12 #include <util/c_types.h>
13 #include <util/endianness_map.h>
14 #include <util/expr_util.h>
15 #include <util/namespace.h>
16 #include <util/narrow.h>
18 #include <util/simplify_expr.h>
19 #include <util/string_constant.h>
20 
21 #include "expr_lowering.h"
22 
23 #include <algorithm>
24 
25 static exprt bv_to_expr(
26  const exprt &bitvector_expr,
27  const typet &target_type,
28  const endianness_mapt &endianness_map,
29  const namespacet &ns);
30 
31 struct boundst
32 {
33  std::size_t lb;
34  std::size_t ub;
35 };
36 
39  const endianness_mapt &endianness_map,
40  std::size_t lower_bound,
41  std::size_t upper_bound)
42 {
43  boundst result;
44  result.lb = lower_bound;
45  result.ub = upper_bound;
46 
47  if(result.ub < endianness_map.number_of_bits())
48  {
49  result.lb = endianness_map.map_bit(result.lb);
50  result.ub = endianness_map.map_bit(result.ub);
51 
52  // big-endian bounds need swapping
53  if(result.ub < result.lb)
54  std::swap(result.lb, result.ub);
55  }
56 
57  return result;
58 }
59 
61 bitvector_typet adjust_width(const typet &src, std::size_t new_width)
62 {
63  if(src.id() == ID_unsignedbv)
64  return unsignedbv_typet(new_width);
65  else if(src.id() == ID_signedbv)
66  return signedbv_typet(new_width);
67  else if(src.id() == ID_bv)
68  return bv_typet(new_width);
69  else if(src.id() == ID_c_enum) // we use the underlying type
70  return adjust_width(to_c_enum_type(src).underlying_type(), new_width);
71  else if(src.id() == ID_c_bit_field)
72  return c_bit_field_typet(
73  to_c_bit_field_type(src).underlying_type(), new_width);
74  else
75  PRECONDITION(false);
76 }
77 
81  const exprt &bitvector_expr,
82  const struct_typet &struct_type,
83  const endianness_mapt &endianness_map,
84  const namespacet &ns)
85 {
86  const struct_typet::componentst &components = struct_type.components();
87 
88  exprt::operandst operands;
89  operands.reserve(components.size());
90  std::size_t member_offset_bits = 0;
91  for(const auto &comp : components)
92  {
93  const auto component_bits_opt = pointer_offset_bits(comp.type(), ns);
94  std::size_t component_bits;
95  if(component_bits_opt.has_value())
96  component_bits = numeric_cast_v<std::size_t>(*component_bits_opt);
97  else
98  component_bits = to_bitvector_type(bitvector_expr.type()).get_width() -
100 
101  if(component_bits == 0)
102  {
103  operands.push_back(constant_exprt{irep_idt{}, comp.type()});
104  continue;
105  }
106 
107  const auto bounds = map_bounds(
108  endianness_map,
110  member_offset_bits + component_bits - 1);
111  bitvector_typet type = adjust_width(bitvector_expr.type(), component_bits);
112  PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
113  operands.push_back(bv_to_expr(
114  extractbits_exprt{bitvector_expr, bounds.ub, bounds.lb, std::move(type)},
115  comp.type(),
116  endianness_map,
117  ns));
118 
119  if(component_bits_opt.has_value())
120  member_offset_bits += component_bits;
121  }
122 
123  return struct_exprt{std::move(operands), struct_type};
124 }
125 
129  const exprt &bitvector_expr,
130  const union_typet &union_type,
131  const endianness_mapt &endianness_map,
132  const namespacet &ns)
133 {
134  const union_typet::componentst &components = union_type.components();
135 
136  // empty union, handled the same way as done in expr_initializert
137  if(components.empty())
138  return union_exprt{irep_idt{}, nil_exprt{}, union_type};
139 
140  const auto widest_member = union_type.find_widest_union_component(ns);
141 
142  std::size_t component_bits;
143  if(widest_member.has_value())
144  component_bits = numeric_cast_v<std::size_t>(widest_member->second);
145  else
146  component_bits = to_bitvector_type(bitvector_expr.type()).get_width();
147 
148  if(component_bits == 0)
149  {
150  return union_exprt{components.front().get_name(),
151  constant_exprt{irep_idt{}, components.front().type()},
152  union_type};
153  }
154 
155  const auto bounds = map_bounds(endianness_map, 0, component_bits - 1);
156  bitvector_typet type = adjust_width(bitvector_expr.type(), component_bits);
157  const irep_idt &component_name = widest_member.has_value()
158  ? widest_member->first.get_name()
159  : components.front().get_name();
160  const typet &component_type = widest_member.has_value()
161  ? widest_member->first.type()
162  : components.front().type();
163  PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
164  return union_exprt{
165  component_name,
166  bv_to_expr(
167  extractbits_exprt{bitvector_expr, bounds.ub, bounds.lb, std::move(type)},
168  component_type,
169  endianness_map,
170  ns),
171  union_type};
172 }
173 
177  const exprt &bitvector_expr,
178  const array_typet &array_type,
179  const endianness_mapt &endianness_map,
180  const namespacet &ns)
181 {
182  auto num_elements = numeric_cast<std::size_t>(array_type.size());
183  auto subtype_bits = pointer_offset_bits(array_type.element_type(), ns);
184 
185  const std::size_t total_bits =
186  to_bitvector_type(bitvector_expr.type()).get_width();
187  if(!num_elements.has_value())
188  {
189  if(!subtype_bits.has_value() || *subtype_bits == 0)
190  num_elements = total_bits;
191  else
192  num_elements = total_bits / numeric_cast_v<std::size_t>(*subtype_bits);
193  }
195  !num_elements.has_value() || !subtype_bits.has_value() ||
196  *subtype_bits * *num_elements == total_bits,
197  "subtype width times array size should be total bitvector width");
198 
199  exprt::operandst operands;
200  operands.reserve(*num_elements);
201  for(std::size_t i = 0; i < *num_elements; ++i)
202  {
203  if(subtype_bits.has_value())
204  {
205  const std::size_t subtype_bits_int =
206  numeric_cast_v<std::size_t>(*subtype_bits);
207  const auto bounds = map_bounds(
208  endianness_map, i * subtype_bits_int, ((i + 1) * subtype_bits_int) - 1);
209  bitvector_typet type =
210  adjust_width(bitvector_expr.type(), subtype_bits_int);
211  PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
212  operands.push_back(bv_to_expr(
214  bitvector_expr, bounds.ub, bounds.lb, std::move(type)},
215  array_type.element_type(),
216  endianness_map,
217  ns));
218  }
219  else
220  {
221  operands.push_back(bv_to_expr(
222  bitvector_expr, array_type.element_type(), endianness_map, ns));
223  }
224  }
225 
226  return array_exprt{std::move(operands), array_type};
227 }
228 
232  const exprt &bitvector_expr,
233  const vector_typet &vector_type,
234  const endianness_mapt &endianness_map,
235  const namespacet &ns)
236 {
237  const std::size_t num_elements =
238  numeric_cast_v<std::size_t>(vector_type.size());
239  auto subtype_bits = pointer_offset_bits(vector_type.element_type(), ns);
241  !subtype_bits.has_value() ||
242  *subtype_bits * num_elements ==
243  to_bitvector_type(bitvector_expr.type()).get_width(),
244  "subtype width times vector size should be total bitvector width");
245 
246  exprt::operandst operands;
247  operands.reserve(num_elements);
248  for(std::size_t i = 0; i < num_elements; ++i)
249  {
250  if(subtype_bits.has_value())
251  {
252  const std::size_t subtype_bits_int =
253  numeric_cast_v<std::size_t>(*subtype_bits);
254  const auto bounds = map_bounds(
255  endianness_map, i * subtype_bits_int, ((i + 1) * subtype_bits_int) - 1);
256  bitvector_typet type =
257  adjust_width(bitvector_expr.type(), subtype_bits_int);
258  PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
259  operands.push_back(bv_to_expr(
261  bitvector_expr, bounds.ub, bounds.lb, std::move(type)},
262  vector_type.element_type(),
263  endianness_map,
264  ns));
265  }
266  else
267  {
268  operands.push_back(bv_to_expr(
269  bitvector_expr, vector_type.element_type(), endianness_map, ns));
270  }
271  }
272 
273  return vector_exprt{std::move(operands), vector_type};
274 }
275 
279  const exprt &bitvector_expr,
280  const complex_typet &complex_type,
281  const endianness_mapt &endianness_map,
282  const namespacet &ns)
283 {
284  const std::size_t total_bits =
285  to_bitvector_type(bitvector_expr.type()).get_width();
286  const auto subtype_bits_opt = pointer_offset_bits(complex_type.subtype(), ns);
287  std::size_t subtype_bits;
288  if(subtype_bits_opt.has_value())
289  {
290  subtype_bits = numeric_cast_v<std::size_t>(*subtype_bits_opt);
292  subtype_bits * 2 == total_bits,
293  "subtype width should be half of the total bitvector width");
294  }
295  else
296  subtype_bits = total_bits / 2;
297 
298  const auto bounds_real = map_bounds(endianness_map, 0, subtype_bits - 1);
299  const auto bounds_imag =
300  map_bounds(endianness_map, subtype_bits, subtype_bits * 2 - 1);
301 
302  const bitvector_typet type =
303  adjust_width(bitvector_expr.type(), subtype_bits);
304 
305  PRECONDITION(pointer_offset_bits(bitvector_expr.type(), ns).has_value());
306  return complex_exprt{
307  bv_to_expr(
308  extractbits_exprt{bitvector_expr, bounds_real.ub, bounds_real.lb, type},
309  complex_type.subtype(),
310  endianness_map,
311  ns),
312  bv_to_expr(
313  extractbits_exprt{bitvector_expr, bounds_imag.ub, bounds_imag.lb, type},
314  complex_type.subtype(),
315  endianness_map,
316  ns),
317  complex_type};
318 }
319 
334  const exprt &bitvector_expr,
335  const typet &target_type,
336  const endianness_mapt &endianness_map,
337  const namespacet &ns)
338 {
340 
341  if(
342  can_cast_type<bitvector_typet>(target_type) ||
343  target_type.id() == ID_c_enum || target_type.id() == ID_c_enum_tag ||
344  target_type.id() == ID_string)
345  {
346  std::size_t width = to_bitvector_type(bitvector_expr.type()).get_width();
347  exprt bv_expr =
348  typecast_exprt::conditional_cast(bitvector_expr, bv_typet{width});
349  return simplify_expr(
350  typecast_exprt::conditional_cast(bv_expr, target_type), ns);
351  }
352 
353  if(target_type.id() == ID_struct)
354  {
355  return bv_to_struct_expr(
356  bitvector_expr, to_struct_type(target_type), endianness_map, ns);
357  }
358  else if(target_type.id() == ID_struct_tag)
359  {
361  bitvector_expr,
362  ns.follow_tag(to_struct_tag_type(target_type)),
363  endianness_map,
364  ns);
365  result.type() = target_type;
366  return std::move(result);
367  }
368  else if(target_type.id() == ID_union)
369  {
370  return bv_to_union_expr(
371  bitvector_expr, to_union_type(target_type), endianness_map, ns);
372  }
373  else if(target_type.id() == ID_union_tag)
374  {
375  union_exprt result = bv_to_union_expr(
376  bitvector_expr,
377  ns.follow_tag(to_union_tag_type(target_type)),
378  endianness_map,
379  ns);
380  result.type() = target_type;
381  return std::move(result);
382  }
383  else if(target_type.id() == ID_array)
384  {
385  return bv_to_array_expr(
386  bitvector_expr, to_array_type(target_type), endianness_map, ns);
387  }
388  else if(target_type.id() == ID_vector)
389  {
390  return bv_to_vector_expr(
391  bitvector_expr, to_vector_type(target_type), endianness_map, ns);
392  }
393  else if(target_type.id() == ID_complex)
394  {
395  return bv_to_complex_expr(
396  bitvector_expr, to_complex_type(target_type), endianness_map, ns);
397  }
398  else
399  {
401  false, "bv_to_expr does not yet support ", target_type.id_string());
402  }
403 }
404 
405 static exprt unpack_rec(
406  const exprt &src,
407  bool little_endian,
408  const optionalt<mp_integer> &offset_bytes,
409  const optionalt<mp_integer> &max_bytes,
410  const namespacet &ns,
411  bool unpack_byte_array = false);
412 
420  const exprt &src,
421  std::size_t lower_bound,
422  std::size_t upper_bound,
423  const namespacet &ns)
424 {
425  PRECONDITION(lower_bound <= upper_bound);
426 
427  if(src.id() == ID_array)
428  {
429  PRECONDITION(upper_bound <= src.operands().size());
430  return exprt::operandst{
431  src.operands().begin() + narrow_cast<std::ptrdiff_t>(lower_bound),
432  src.operands().begin() + narrow_cast<std::ptrdiff_t>(upper_bound)};
433  }
434 
435  PRECONDITION(src.type().id() == ID_array || src.type().id() == ID_vector);
436  PRECONDITION(
438  to_type_with_subtype(src.type()).subtype()) &&
440  8);
441  exprt::operandst bytes;
442  bytes.reserve(upper_bound - lower_bound);
443  for(std::size_t i = lower_bound; i < upper_bound; ++i)
444  {
445  const index_exprt idx{src, from_integer(i, c_index_type())};
446  bytes.push_back(simplify_expr(idx, ns));
447  }
448  return bytes;
449 }
450 
459  const exprt &src,
460  std::size_t el_bytes,
461  bool little_endian,
462  const namespacet &ns)
463 {
464  // TODO we either need a symbol table here or make array comprehensions
465  // introduce a scope
466  static std::size_t array_comprehension_index_counter = 0;
467  ++array_comprehension_index_counter;
468  symbol_exprt array_comprehension_index{
469  "$array_comprehension_index_a_v" +
470  std::to_string(array_comprehension_index_counter),
471  c_index_type()};
472 
473  index_exprt element{src,
474  div_exprt{array_comprehension_index,
475  from_integer(el_bytes, c_index_type())}};
476 
477  exprt sub = unpack_rec(element, little_endian, {}, {}, ns, false);
478  exprt::operandst sub_operands = instantiate_byte_array(sub, 0, el_bytes, ns);
479 
480  exprt body = sub_operands.front();
481  const mod_exprt offset{
482  array_comprehension_index,
483  from_integer(el_bytes, array_comprehension_index.type())};
484  for(std::size_t i = 1; i < el_bytes; ++i)
485  {
486  body = if_exprt{
487  equal_exprt{offset, from_integer(i, array_comprehension_index.type())},
488  sub_operands[i],
489  body};
490  }
491 
492  const exprt array_vector_size = src.type().id() == ID_vector
493  ? to_vector_type(src.type()).size()
494  : to_array_type(src.type()).size();
495 
497  std::move(array_comprehension_index),
498  std::move(body),
500  mult_exprt{array_vector_size,
501  from_integer(el_bytes, array_vector_size.type())}}};
502 }
503 
518  const exprt &src,
519  const optionalt<mp_integer> &src_size,
520  const mp_integer &element_bits,
521  bool little_endian,
522  const optionalt<mp_integer> &offset_bytes,
523  const optionalt<mp_integer> &max_bytes,
524  const namespacet &ns)
525 {
526  const std::size_t el_bytes =
527  numeric_cast_v<std::size_t>((element_bits + 7) / 8);
528 
529  if(!src_size.has_value() && !max_bytes.has_value())
530  {
532  el_bytes > 0 && element_bits % 8 == 0,
533  "unpacking of arrays with non-byte-aligned elements is not supported");
535  src, el_bytes, little_endian, ns);
536  }
537 
538  exprt::operandst byte_operands;
539  mp_integer first_element = 0;
540 
541  // refine the number of elements to extract in case the element width is known
542  // and a multiple of bytes; otherwise we will expand the entire array/vector
543  optionalt<mp_integer> num_elements = src_size;
544  if(element_bits > 0 && element_bits % 8 == 0)
545  {
546  if(!num_elements.has_value())
547  {
548  // turn bytes into elements, rounding up
549  num_elements = (*max_bytes + el_bytes - 1) / el_bytes;
550  }
551 
552  if(offset_bytes.has_value())
553  {
554  // compute offset as number of elements
555  first_element = *offset_bytes / el_bytes;
556  // insert offset_bytes-many nil bytes into the output array
557  byte_operands.resize(
558  numeric_cast_v<std::size_t>(*offset_bytes - (*offset_bytes % el_bytes)),
559  from_integer(0, bv_typet{8}));
560  }
561  }
562 
563  // the maximum number of bytes is an upper bound in case the size of the
564  // array/vector is unknown; if element_bits was usable above this will
565  // have been turned into a number of elements already
566  if(!num_elements)
567  num_elements = *max_bytes;
568 
569  const exprt src_simp = simplify_expr(src, ns);
570 
571  for(mp_integer i = first_element; i < *num_elements; ++i)
572  {
573  exprt element;
574 
575  if(
576  (src_simp.id() == ID_array || src_simp.id() == ID_vector) &&
577  i < src_simp.operands().size())
578  {
579  const std::size_t index_int = numeric_cast_v<std::size_t>(i);
580  element = src_simp.operands()[index_int];
581  }
582  else
583  {
584  element = index_exprt(src_simp, from_integer(i, c_index_type()));
585  }
586 
587  // recursively unpack each element so that we eventually just have an array
588  // of bytes left
589 
590  const optionalt<mp_integer> element_max_bytes =
591  max_bytes
592  ? std::min(mp_integer{el_bytes}, *max_bytes - byte_operands.size())
594  const std::size_t element_max_bytes_int =
595  element_max_bytes ? numeric_cast_v<std::size_t>(*element_max_bytes)
596  : el_bytes;
597 
598  exprt sub =
599  unpack_rec(element, little_endian, {}, element_max_bytes, ns, true);
600  exprt::operandst sub_operands =
601  instantiate_byte_array(sub, 0, element_max_bytes_int, ns);
602  byte_operands.insert(
603  byte_operands.end(), sub_operands.begin(), sub_operands.end());
604 
605  if(max_bytes && byte_operands.size() >= *max_bytes)
606  break;
607  }
608 
609  const std::size_t size = byte_operands.size();
610  return array_exprt(
611  std::move(byte_operands),
613 }
614 
625 static void process_bit_fields(
626  exprt::operandst &&bit_fields,
627  std::size_t total_bits,
628  exprt::operandst &dest,
629  bool little_endian,
630  const optionalt<mp_integer> &offset_bytes,
631  const optionalt<mp_integer> &max_bytes,
632  const namespacet &ns)
633 {
634  const concatenation_exprt concatenation{std::move(bit_fields),
635  bv_typet{total_bits}};
636 
637  exprt sub =
638  unpack_rec(concatenation, little_endian, offset_bytes, max_bytes, ns, true);
639 
640  dest.insert(
641  dest.end(),
642  std::make_move_iterator(sub.operands().begin()),
643  std::make_move_iterator(sub.operands().end()));
644 }
645 
656  const exprt &src,
657  bool little_endian,
658  const optionalt<mp_integer> &offset_bytes,
659  const optionalt<mp_integer> &max_bytes,
660  const namespacet &ns)
661 {
662  const struct_typet &struct_type = to_struct_type(ns.follow(src.type()));
663  const struct_typet::componentst &components = struct_type.components();
664 
665  optionalt<mp_integer> offset_in_member;
666  optionalt<mp_integer> max_bytes_left;
668 
670  exprt::operandst byte_operands;
671  for(auto it = components.begin(); it != components.end(); ++it)
672  {
673  const auto &comp = *it;
674  auto component_bits = pointer_offset_bits(comp.type(), ns);
675 
676  // We can only handle a member of unknown width when it is the last member
677  // and is byte-aligned. Members of unknown width in the middle would leave
678  // us with unknown alignment of subsequent members, and queuing them up as
679  // bit fields is not possible either as the total width of the concatenation
680  // could not be determined.
682  component_bits.has_value() ||
683  (std::next(it) == components.end() && !bit_fields.has_value()),
684  "members of non-constant width should come last in a struct");
685 
686  member_exprt member(src, comp.get_name(), comp.type());
687  if(src.id() == ID_struct)
688  simplify(member, ns);
689 
690  // Is it a byte-aligned member?
691  if(member_offset_bits % 8 == 0)
692  {
693  if(bit_fields.has_value())
694  {
696  std::move(bit_fields->first),
697  bit_fields->second,
698  byte_operands,
699  little_endian,
700  offset_in_member,
701  max_bytes_left,
702  ns);
703  bit_fields.reset();
704  }
705 
706  if(offset_bytes.has_value())
707  {
708  offset_in_member = *offset_bytes - member_offset_bits / 8;
709  // if the offset is negative, offset_in_member remains unset, which has
710  // the same effect as setting it to zero
711  if(*offset_in_member < 0)
712  offset_in_member.reset();
713  }
714 
715  if(max_bytes.has_value())
716  {
717  max_bytes_left = *max_bytes - member_offset_bits / 8;
718  if(*max_bytes_left < 0)
719  break;
720  }
721  }
722 
723  if(
724  member_offset_bits % 8 != 0 ||
725  (component_bits.has_value() && *component_bits % 8 != 0))
726  {
727  if(!bit_fields.has_value())
728  bit_fields = std::make_pair(exprt::operandst{}, std::size_t{0});
729 
730  const std::size_t bits_int = numeric_cast_v<std::size_t>(*component_bits);
731  bit_fields->first.insert(
732  little_endian ? bit_fields->first.begin() : bit_fields->first.end(),
733  typecast_exprt::conditional_cast(member, bv_typet{bits_int}));
734  bit_fields->second += bits_int;
735 
736  member_offset_bits += *component_bits;
737 
738  continue;
739  }
740 
741  INVARIANT(
742  !bit_fields.has_value(),
743  "all preceding members should have been processed");
744 
745  exprt sub = unpack_rec(
746  member, little_endian, offset_in_member, max_bytes_left, ns, true);
747 
748  byte_operands.insert(
749  byte_operands.end(),
750  std::make_move_iterator(sub.operands().begin()),
751  std::make_move_iterator(sub.operands().end()));
752 
753  if(component_bits.has_value())
754  member_offset_bits += *component_bits;
755  }
756 
757  if(bit_fields.has_value())
759  std::move(bit_fields->first),
760  bit_fields->second,
761  byte_operands,
762  little_endian,
763  offset_in_member,
764  max_bytes_left,
765  ns);
766 
767  const std::size_t size = byte_operands.size();
768  return array_exprt{std::move(byte_operands),
770 }
771 
777 static array_exprt
778 unpack_complex(const exprt &src, bool little_endian, const namespacet &ns)
779 {
780  const complex_typet &complex_type = to_complex_type(src.type());
781  const typet &subtype = complex_type.subtype();
782 
783  auto subtype_bits = pointer_offset_bits(subtype, ns);
784  CHECK_RETURN(subtype_bits.has_value());
785  CHECK_RETURN(*subtype_bits % 8 == 0);
786 
787  exprt sub_real = unpack_rec(
788  complex_real_exprt{src},
789  little_endian,
790  mp_integer{0},
791  *subtype_bits / 8,
792  ns,
793  true);
794  exprt::operandst byte_operands = std::move(sub_real.operands());
795 
796  exprt sub_imag = unpack_rec(
797  complex_imag_exprt{src},
798  little_endian,
799  mp_integer{0},
800  *subtype_bits / 8,
801  ns,
802  true);
803  byte_operands.insert(
804  byte_operands.end(),
805  std::make_move_iterator(sub_imag.operands().begin()),
806  std::make_move_iterator(sub_imag.operands().end()));
807 
808  const std::size_t size = byte_operands.size();
809  return array_exprt{std::move(byte_operands),
811 }
812 
822 // array of bytes
825  const exprt &src,
826  bool little_endian,
827  const optionalt<mp_integer> &offset_bytes,
828  const optionalt<mp_integer> &max_bytes,
829  const namespacet &ns,
830  bool unpack_byte_array)
831 {
832  if(src.type().id()==ID_array)
833  {
834  const array_typet &array_type=to_array_type(src.type());
835  const typet &subtype = array_type.element_type();
836 
837  auto element_bits = pointer_offset_bits(subtype, ns);
838  CHECK_RETURN(element_bits.has_value());
839 
840  if(!unpack_byte_array && *element_bits == 8)
841  return src;
842 
843  const auto constant_size_opt = numeric_cast<mp_integer>(array_type.size());
844  return unpack_array_vector(
845  src,
846  constant_size_opt,
847  *element_bits,
848  little_endian,
849  offset_bytes,
850  max_bytes,
851  ns);
852  }
853  else if(src.type().id() == ID_vector)
854  {
855  const vector_typet &vector_type = to_vector_type(src.type());
856  const typet &subtype = vector_type.element_type();
857 
858  auto element_bits = pointer_offset_bits(subtype, ns);
859  CHECK_RETURN(element_bits.has_value());
860 
861  if(!unpack_byte_array && *element_bits == 8)
862  return src;
863 
864  return unpack_array_vector(
865  src,
866  numeric_cast_v<mp_integer>(vector_type.size()),
867  *element_bits,
868  little_endian,
869  offset_bytes,
870  max_bytes,
871  ns);
872  }
873  else if(src.type().id() == ID_complex)
874  {
875  return unpack_complex(src, little_endian, ns);
876  }
877  else if(src.type().id() == ID_struct || src.type().id() == ID_struct_tag)
878  {
879  return unpack_struct(src, little_endian, offset_bytes, max_bytes, ns);
880  }
881  else if(src.type().id() == ID_union || src.type().id() == ID_union_tag)
882  {
883  const union_typet &union_type = to_union_type(ns.follow(src.type()));
884 
885  const auto widest_member = union_type.find_widest_union_component(ns);
886 
887  if(widest_member.has_value())
888  {
889  member_exprt member{
890  src, widest_member->first.get_name(), widest_member->first.type()};
891  return unpack_rec(
892  member, little_endian, offset_bytes, widest_member->second, ns, true);
893  }
894  }
895  else if(src.type().id() == ID_pointer)
896  {
897  return unpack_rec(
899  little_endian,
900  offset_bytes,
901  max_bytes,
902  ns,
903  unpack_byte_array);
904  }
905  else if(src.id() == ID_string_constant)
906  {
907  return unpack_rec(
909  little_endian,
910  offset_bytes,
911  max_bytes,
912  ns,
913  unpack_byte_array);
914  }
915  else if(src.id() == ID_constant && src.type().id() == ID_string)
916  {
917  return unpack_rec(
918  string_constantt(to_constant_expr(src).get_value()).to_array_expr(),
919  little_endian,
920  offset_bytes,
921  max_bytes,
922  ns,
923  unpack_byte_array);
924  }
925  else if(src.type().id()!=ID_empty)
926  {
927  // a basic type; we turn that into extractbits while considering
928  // endianness
929  auto bits_opt = pointer_offset_bits(src.type(), ns);
930  DATA_INVARIANT(bits_opt.has_value(), "basic type should have a fixed size");
931 
932  const mp_integer total_bits = *bits_opt;
933  mp_integer last_bit = total_bits;
934  mp_integer bit_offset = 0;
935 
936  if(max_bytes.has_value())
937  {
938  const auto max_bits = *max_bytes * 8;
939  if(little_endian)
940  {
941  last_bit = std::min(last_bit, max_bits);
942  }
943  else
944  {
945  bit_offset = std::max(mp_integer{0}, last_bit - max_bits);
946  }
947  }
948 
949  auto const src_as_bitvector = typecast_exprt::conditional_cast(
950  src, bv_typet{numeric_cast_v<std::size_t>(total_bits)});
951  auto const byte_type = bv_typet{8};
952  exprt::operandst byte_operands;
953  for(; bit_offset < last_bit; bit_offset += 8)
954  {
955  PRECONDITION(
956  pointer_offset_bits(src_as_bitvector.type(), ns).has_value());
957  extractbits_exprt extractbits(
958  src_as_bitvector,
959  from_integer(bit_offset + 7, c_index_type()),
960  from_integer(bit_offset, c_index_type()),
961  byte_type);
962 
963  // endianness_mapt should be the point of reference for mapping out
964  // endianness, but we need to work on elements here instead of
965  // individual bits
966  if(little_endian)
967  byte_operands.push_back(extractbits);
968  else
969  byte_operands.insert(byte_operands.begin(), extractbits);
970  }
971 
972  const std::size_t size = byte_operands.size();
973  return array_exprt(
974  std::move(byte_operands),
976  }
977 
978  return array_exprt(
979  {}, array_typet{bv_typet{8}, from_integer(0, size_type())});
980 }
981 
993  const byte_extract_exprt &src,
994  const byte_extract_exprt &unpacked,
995  const typet &subtype,
996  const mp_integer &element_bits,
997  const namespacet &ns)
998 {
999  optionalt<std::size_t> num_elements;
1000  if(src.type().id() == ID_array)
1001  num_elements = numeric_cast<std::size_t>(to_array_type(src.type()).size());
1002  else
1003  num_elements = numeric_cast<std::size_t>(to_vector_type(src.type()).size());
1004 
1005  if(num_elements.has_value())
1006  {
1007  exprt::operandst operands;
1008  operands.reserve(*num_elements);
1009  for(std::size_t i = 0; i < *num_elements; ++i)
1010  {
1011  plus_exprt new_offset(
1012  unpacked.offset(),
1013  from_integer(i * element_bits / 8, unpacked.offset().type()));
1014 
1015  byte_extract_exprt tmp(unpacked);
1016  tmp.type() = subtype;
1017  tmp.offset() = new_offset;
1018 
1019  operands.push_back(lower_byte_extract(tmp, ns));
1020  }
1021 
1022  exprt result;
1023  if(src.type().id() == ID_array)
1024  result = array_exprt{std::move(operands), to_array_type(src.type())};
1025  else
1026  result = vector_exprt{std::move(operands), to_vector_type(src.type())};
1027 
1028  return simplify_expr(result, ns);
1029  }
1030 
1031  DATA_INVARIANT(src.type().id() == ID_array, "vectors have constant size");
1032  const array_typet &array_type = to_array_type(src.type());
1033 
1034  // TODO we either need a symbol table here or make array comprehensions
1035  // introduce a scope
1036  static std::size_t array_comprehension_index_counter = 0;
1037  ++array_comprehension_index_counter;
1038  symbol_exprt array_comprehension_index{
1039  "$array_comprehension_index_a" +
1040  std::to_string(array_comprehension_index_counter),
1041  c_index_type()};
1042 
1043  plus_exprt new_offset{
1044  unpacked.offset(),
1046  mult_exprt{
1047  array_comprehension_index,
1048  from_integer(element_bits / 8, array_comprehension_index.type())},
1049  unpacked.offset().type())};
1050 
1051  byte_extract_exprt body(unpacked);
1052  body.type() = subtype;
1053  body.offset() = std::move(new_offset);
1054 
1055  return array_comprehension_exprt{std::move(array_comprehension_index),
1056  lower_byte_extract(body, ns),
1057  array_type};
1058 }
1059 
1069  const byte_extract_exprt &src,
1070  const byte_extract_exprt &unpacked,
1071  const namespacet &ns)
1072 {
1073  const complex_typet &complex_type = to_complex_type(src.type());
1074  const typet &subtype = complex_type.subtype();
1075 
1076  auto subtype_bits = pointer_offset_bits(subtype, ns);
1077  if(!subtype_bits.has_value() || *subtype_bits % 8 != 0)
1078  return {};
1079 
1080  // offset remains unchanged
1081  byte_extract_exprt real{unpacked};
1082  real.type() = subtype;
1083 
1084  const plus_exprt new_offset{
1085  unpacked.offset(),
1086  from_integer(*subtype_bits / 8, unpacked.offset().type())};
1087  byte_extract_exprt imag{unpacked};
1088  imag.type() = subtype;
1089  imag.offset() = simplify_expr(new_offset, ns);
1090 
1091  return simplify_expr(
1092  complex_exprt{
1093  lower_byte_extract(real, ns), lower_byte_extract(imag, ns), complex_type},
1094  ns);
1095 }
1096 
1100 {
1101  // General notes about endianness and the bit-vector conversion:
1102  // A single byte with value 0b10001000 is stored (in irept) as
1103  // exactly this string literal, and its bit-vector encoding will be
1104  // bvt bv={0,0,0,1,0,0,0,1}, i.e., bv[0]==0 and bv[7]==1
1105  //
1106  // A multi-byte value like x=256 would be:
1107  // - little-endian storage: ((char*)&x)[0]==0, ((char*)&x)[1]==1
1108  // - big-endian storage: ((char*)&x)[0]==1, ((char*)&x)[1]==0
1109  // - irept representation: 0000000100000000
1110  // - bvt: {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0}
1111  // <... 8bits ...> <... 8bits ...>
1112  //
1113  // An array {0, 1} will be encoded as bvt bv={0,1}, i.e., bv[1]==1
1114  // concatenation(0, 1) will yield a bvt bv={1,0}, i.e., bv[1]==0
1115  //
1116  // The semantics of byte_extract(endianness, op, offset, T) is:
1117  // interpret ((char*)&op)+offset as the endianness-ordered storage
1118  // of an object of type T at address ((char*)&op)+offset
1119  // For some T x, byte_extract(endianness, x, 0, T) must yield x.
1120  //
1121  // byte_extract for a composite type T or an array will interpret
1122  // the individual subtypes with suitable endianness; the overall
1123  // order of components is not affected by endianness.
1124  //
1125  // Examples:
1126  // unsigned char A[4];
1127  // byte_extract_little_endian(A, 0, unsigned short) requests that
1128  // A[0],A[1] be interpreted as the storage of an unsigned short with
1129  // A[1] being the most-significant byte; byte_extract_big_endian for
1130  // the same operands will select A[0] as the most-significant byte.
1131  //
1132  // int A[2] = {0x01020304,0xDEADBEEF}
1133  // byte_extract_big_endian(A, 0, short) should yield 0x0102
1134  // byte_extract_little_endian(A, 0, short) should yield 0x0304
1135  // To obtain this we first compute byte arrays while taking into
1136  // account endianness:
1137  // big-endian byte representation: {01,02,03,04,DE,AB,BE,EF}
1138  // little-endian byte representation: {04,03,02,01,EF,BE,AB,DE}
1139  // We extract the relevant bytes starting from ((char*)A)+0:
1140  // big-endian: {01,02}; little-endian: {04,03}
1141  // Finally we place them in the appropriate byte order as indicated
1142  // by endianness:
1143  // big-endian: (short)concatenation(01,02)=0x0102
1144  // little-endian: (short)concatenation(03,04)=0x0304
1145 
1146  PRECONDITION(
1147  src.id() == ID_byte_extract_little_endian ||
1148  src.id() == ID_byte_extract_big_endian);
1149  const bool little_endian = src.id() == ID_byte_extract_little_endian;
1150 
1151  // determine an upper bound of the last byte we might need
1152  auto upper_bound_opt = size_of_expr(src.type(), ns);
1153  if(upper_bound_opt.has_value())
1154  {
1155  upper_bound_opt = simplify_expr(
1156  plus_exprt(
1157  upper_bound_opt.value(),
1159  src.offset(), upper_bound_opt.value().type())),
1160  ns);
1161  }
1162  else if(src.type().id() == ID_empty)
1163  upper_bound_opt = from_integer(0, size_type());
1164 
1165  const auto lower_bound_int_opt = numeric_cast<mp_integer>(src.offset());
1166  const auto upper_bound_int_opt =
1167  numeric_cast<mp_integer>(upper_bound_opt.value_or(nil_exprt()));
1168 
1169  byte_extract_exprt unpacked(src);
1170  unpacked.op() = unpack_rec(
1171  src.op(), little_endian, lower_bound_int_opt, upper_bound_int_opt, ns);
1172  CHECK_RETURN(
1174  .get_width() == 8);
1175 
1176  if(src.type().id() == ID_array || src.type().id() == ID_vector)
1177  {
1178  const typet &subtype = to_type_with_subtype(src.type()).subtype();
1179 
1180  // consider ways of dealing with arrays of unknown subtype size or with a
1181  // subtype size that does not fit byte boundaries; currently we fall back to
1182  // stitching together consecutive elements down below
1183  auto element_bits = pointer_offset_bits(subtype, ns);
1184  if(element_bits.has_value() && *element_bits >= 1 && *element_bits % 8 == 0)
1185  {
1187  src, unpacked, subtype, *element_bits, ns);
1188  }
1189  }
1190  else if(src.type().id() == ID_complex)
1191  {
1192  auto result = lower_byte_extract_complex(src, unpacked, ns);
1193  if(result.has_value())
1194  return std::move(*result);
1195 
1196  // else fall back to generic lowering that uses bit masks, below
1197  }
1198  else if(src.type().id() == ID_struct || src.type().id() == ID_struct_tag)
1199  {
1200  const struct_typet &struct_type=to_struct_type(ns.follow(src.type()));
1201  const struct_typet::componentst &components=struct_type.components();
1202 
1203  bool failed=false;
1204  struct_exprt s({}, src.type());
1205 
1206  for(const auto &comp : components)
1207  {
1208  auto component_bits = pointer_offset_bits(comp.type(), ns);
1209 
1210  // the next member would be misaligned, abort
1211  if(
1212  !component_bits.has_value() || *component_bits == 0 ||
1213  *component_bits % 8 != 0)
1214  {
1215  failed=true;
1216  break;
1217  }
1218 
1219  auto member_offset_opt =
1220  member_offset_expr(struct_type, comp.get_name(), ns);
1221 
1222  if(!member_offset_opt.has_value())
1223  {
1224  failed = true;
1225  break;
1226  }
1227 
1228  plus_exprt new_offset(
1229  unpacked.offset(),
1231  member_offset_opt.value(), unpacked.offset().type()));
1232 
1233  byte_extract_exprt tmp(unpacked);
1234  tmp.type()=comp.type();
1235  tmp.offset()=new_offset;
1236 
1237  s.add_to_operands(lower_byte_extract(tmp, ns));
1238  }
1239 
1240  if(!failed)
1241  return simplify_expr(std::move(s), ns);
1242  }
1243  else if(src.type().id() == ID_union || src.type().id() == ID_union_tag)
1244  {
1245  const union_typet &union_type = to_union_type(ns.follow(src.type()));
1246 
1247  const auto widest_member = union_type.find_widest_union_component(ns);
1248 
1249  if(widest_member.has_value())
1250  {
1251  byte_extract_exprt tmp(unpacked);
1252  tmp.type() = widest_member->first.type();
1253 
1254  return union_exprt(
1255  widest_member->first.get_name(),
1256  lower_byte_extract(tmp, ns),
1257  src.type());
1258  }
1259  }
1260 
1261  const exprt &root=unpacked.op();
1262  const exprt &offset=unpacked.offset();
1263 
1264  optionalt<typet> subtype;
1265  if(root.type().id() == ID_vector)
1266  subtype = to_vector_type(root.type()).element_type();
1267  else
1268  subtype = to_array_type(root.type()).element_type();
1269 
1270  auto subtype_bits = pointer_offset_bits(*subtype, ns);
1271 
1273  subtype_bits.has_value() && *subtype_bits == 8,
1274  "offset bits are byte aligned");
1275 
1276  auto size_bits = pointer_offset_bits(unpacked.type(), ns);
1277  if(!size_bits.has_value())
1278  {
1279  auto op0_bits = pointer_offset_bits(unpacked.op().type(), ns);
1280  // all cases with non-constant width should have been handled above
1282  op0_bits.has_value(),
1283  "the extracted width or the source width must be known");
1284  size_bits = op0_bits;
1285  }
1286 
1287  mp_integer num_bytes = (*size_bits) / 8 + (((*size_bits) % 8 == 0) ? 0 : 1);
1288 
1289  // get 'width'-many bytes, and concatenate
1290  const std::size_t width_bytes = numeric_cast_v<std::size_t>(num_bytes);
1291  exprt::operandst op;
1292  op.reserve(width_bytes);
1293 
1294  for(std::size_t i=0; i<width_bytes; i++)
1295  {
1296  // the most significant byte comes first in the concatenation!
1297  std::size_t offset_int=
1298  little_endian?(width_bytes-i-1):i;
1299 
1300  plus_exprt offset_i(from_integer(offset_int, offset.type()), offset);
1301  simplify(offset_i, ns);
1302 
1303  mp_integer index = 0;
1304  if(
1305  offset_i.is_constant() &&
1306  (root.id() == ID_array || root.id() == ID_vector) &&
1307  !to_integer(to_constant_expr(offset_i), index) &&
1308  index < root.operands().size() && index >= 0)
1309  {
1310  // offset is constant and in range
1311  op.push_back(root.operands()[numeric_cast_v<std::size_t>(index)]);
1312  }
1313  else
1314  {
1315  op.push_back(index_exprt(root, offset_i));
1316  }
1317  }
1318 
1319  if(width_bytes==1)
1320  {
1321  return simplify_expr(
1322  typecast_exprt::conditional_cast(op.front(), src.type()), ns);
1323  }
1324  else // width_bytes>=2
1325  {
1326  concatenation_exprt concatenation(
1327  std::move(op), adjust_width(*subtype, width_bytes * 8));
1328 
1329  endianness_mapt map(concatenation.type(), little_endian, ns);
1330  return bv_to_expr(concatenation, src.type(), map, ns);
1331  }
1332 }
1333 
1334 static exprt lower_byte_update(
1335  const byte_update_exprt &src,
1336  const exprt &value_as_byte_array,
1337  const optionalt<exprt> &non_const_update_bound,
1338  const namespacet &ns);
1339 
1350  const byte_update_exprt &src,
1351  const typet &subtype,
1352  const exprt &value_as_byte_array,
1353  const exprt &non_const_update_bound,
1354  const namespacet &ns)
1355 {
1356  // TODO we either need a symbol table here or make array comprehensions
1357  // introduce a scope
1358  static std::size_t array_comprehension_index_counter = 0;
1359  ++array_comprehension_index_counter;
1360  symbol_exprt array_comprehension_index{
1361  "$array_comprehension_index_u_a_v" +
1362  std::to_string(array_comprehension_index_counter),
1363  c_index_type()};
1364 
1365  binary_predicate_exprt lower_bound{
1367  array_comprehension_index, src.offset().type()),
1368  ID_lt,
1369  src.offset()};
1370  binary_predicate_exprt upper_bound{
1372  array_comprehension_index, non_const_update_bound.type()),
1373  ID_ge,
1375  src.offset(), non_const_update_bound.type()),
1376  non_const_update_bound}};
1377 
1378  if_exprt array_comprehension_body{
1379  or_exprt{std::move(lower_bound), std::move(upper_bound)},
1380  index_exprt{src.op(), array_comprehension_index},
1382  index_exprt{
1383  value_as_byte_array,
1384  minus_exprt{array_comprehension_index,
1386  src.offset(), array_comprehension_index.type())}},
1387  subtype)};
1388 
1389  return simplify_expr(
1390  array_comprehension_exprt{array_comprehension_index,
1391  std::move(array_comprehension_body),
1392  to_array_type(src.type())},
1393  ns);
1394 }
1395 
1406  const byte_update_exprt &src,
1407  const typet &subtype,
1408  const array_exprt &value_as_byte_array,
1409  const optionalt<exprt> &non_const_update_bound,
1410  const namespacet &ns)
1411 {
1412  // apply 'array-update-with' num_elements times
1413  exprt result = src.op();
1414 
1415  for(std::size_t i = 0; i < value_as_byte_array.operands().size(); ++i)
1416  {
1417  const exprt &element = value_as_byte_array.operands()[i];
1418 
1419  exprt where = simplify_expr(
1420  plus_exprt{src.offset(), from_integer(i, src.offset().type())}, ns);
1421 
1422  // skip elements that wouldn't change (skip over typecasts as we might have
1423  // some signed/unsigned char conversions)
1424  const exprt &e = skip_typecast(element);
1425  if(e.id() == ID_index)
1426  {
1427  const index_exprt &index_expr = to_index_expr(e);
1428  if(index_expr.array() == src.op() && index_expr.index() == where)
1429  continue;
1430  }
1431 
1432  exprt update_value;
1433  if(non_const_update_bound.has_value())
1434  {
1435  update_value = typecast_exprt::conditional_cast(
1437  from_integer(i, non_const_update_bound->type()),
1438  ID_lt,
1439  *non_const_update_bound},
1440  element,
1441  index_exprt{src.op(), where}},
1442  subtype);
1443  }
1444  else
1445  update_value = typecast_exprt::conditional_cast(element, subtype);
1446 
1447  if(result.id() != ID_with)
1448  result = with_exprt{result, std::move(where), std::move(update_value)};
1449  else
1450  result.add_to_operands(std::move(where), std::move(update_value));
1451  }
1452 
1453  return simplify_expr(std::move(result), ns);
1454 }
1455 
1472  const byte_update_exprt &src,
1473  const typet &subtype,
1474  const exprt &subtype_size,
1475  const exprt &value_as_byte_array,
1476  const exprt &non_const_update_bound,
1477  const exprt &initial_bytes,
1478  const exprt &first_index,
1479  const exprt &first_update_value,
1480  const namespacet &ns)
1481 {
1482  const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
1483  ? ID_byte_extract_little_endian
1484  : ID_byte_extract_big_endian;
1485 
1486  // TODO we either need a symbol table here or make array comprehensions
1487  // introduce a scope
1488  static std::size_t array_comprehension_index_counter = 0;
1489  ++array_comprehension_index_counter;
1490  symbol_exprt array_comprehension_index{
1491  "$array_comprehension_index_u_a_v_u" +
1492  std::to_string(array_comprehension_index_counter),
1493  c_index_type()};
1494 
1495  // all arithmetic uses offset/index types
1496  PRECONDITION(subtype_size.type() == src.offset().type());
1497  PRECONDITION(initial_bytes.type() == src.offset().type());
1498  PRECONDITION(first_index.type() == src.offset().type());
1499 
1500  // the bound from where updates start
1501  binary_predicate_exprt lower_bound{
1503  array_comprehension_index, first_index.type()),
1504  ID_lt,
1505  first_index};
1506 
1507  // The actual value of updates other than at the start or end
1508  plus_exprt offset_expr{
1509  initial_bytes,
1510  mult_exprt{subtype_size,
1512  array_comprehension_index, first_index.type()),
1513  plus_exprt{first_index,
1514  from_integer(1, first_index.type())}}}};
1515  exprt update_value = lower_byte_extract(
1517  extract_opcode, value_as_byte_array, std::move(offset_expr), subtype},
1518  ns);
1519 
1520  // The number of target array/vector elements being replaced, not including
1521  // a possible partial update at the end of the updated range, which is handled
1522  // below: (non_const_update_bound + (subtype_size - 1)) / subtype_size to
1523  // round up to the nearest multiple of subtype_size.
1524  div_exprt updated_elements{
1526  non_const_update_bound, subtype_size.type()),
1527  minus_exprt{subtype_size, from_integer(1, subtype_size.type())}},
1528  subtype_size};
1529 
1530  // The last element to be updated: first_index + updated_elements - 1
1531  plus_exprt last_index{first_index,
1532  minus_exprt{std::move(updated_elements),
1533  from_integer(1, first_index.type())}};
1534 
1535  // The size of a partial update at the end of the updated range, may be zero.
1536  mod_exprt tail_size{
1538  non_const_update_bound, initial_bytes.type()),
1539  initial_bytes},
1540  subtype_size};
1541 
1542  // The bound where updates end, which is conditional on the partial update
1543  // being empty.
1544  binary_predicate_exprt upper_bound{
1546  array_comprehension_index, last_index.type()),
1547  ID_ge,
1548  if_exprt{equal_exprt{tail_size, from_integer(0, tail_size.type())},
1549  last_index,
1550  plus_exprt{last_index, from_integer(1, last_index.type())}}};
1551 
1552  // The actual value of a partial update at the end.
1553  exprt last_update_value = lower_byte_operators(
1555  src.id(),
1556  index_exprt{src.op(), last_index},
1557  from_integer(0, src.offset().type()),
1558  byte_extract_exprt{extract_opcode,
1559  value_as_byte_array,
1561  last_index, subtype_size.type()),
1562  subtype_size},
1563  array_typet{bv_typet{8}, tail_size}}},
1564  ns);
1565 
1566  if_exprt array_comprehension_body{
1567  or_exprt{std::move(lower_bound), std::move(upper_bound)},
1568  index_exprt{src.op(), array_comprehension_index},
1569  if_exprt{
1571  array_comprehension_index, first_index.type()),
1572  first_index},
1573  first_update_value,
1575  array_comprehension_index, last_index.type()),
1576  last_index},
1577  std::move(last_update_value),
1578  std::move(update_value)}}};
1579 
1580  return simplify_expr(
1581  array_comprehension_exprt{array_comprehension_index,
1582  std::move(array_comprehension_body),
1583  to_array_type(src.type())},
1584  ns);
1585 }
1586 
1598  const byte_update_exprt &src,
1599  const typet &subtype,
1600  const exprt &value_as_byte_array,
1601  const optionalt<exprt> &non_const_update_bound,
1602  const namespacet &ns)
1603 {
1604  const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
1605  ? ID_byte_extract_little_endian
1606  : ID_byte_extract_big_endian;
1607 
1608  // do all arithmetic below using index/offset types - the array theory
1609  // back-end is really picky about indices having the same type
1610  auto subtype_size_opt = size_of_expr(subtype, ns);
1611  CHECK_RETURN(subtype_size_opt.has_value());
1612 
1613  const exprt subtype_size = simplify_expr(
1615  subtype_size_opt.value(), src.offset().type()),
1616  ns);
1617 
1618  // compute the index of the first element of the array/vector that may be
1619  // updated
1620  exprt first_index = div_exprt{src.offset(), subtype_size};
1621  simplify(first_index, ns);
1622 
1623  // compute the offset within that first element
1624  const exprt update_offset = mod_exprt{src.offset(), subtype_size};
1625 
1626  // compute the number of bytes (from the update value) that are going to be
1627  // consumed for updating the first element
1628  exprt initial_bytes = minus_exprt{subtype_size, update_offset};
1629  exprt update_bound;
1630  if(non_const_update_bound.has_value())
1631  {
1632  update_bound = typecast_exprt::conditional_cast(
1633  *non_const_update_bound, subtype_size.type());
1634  }
1635  else
1636  {
1638  value_as_byte_array.id() == ID_array,
1639  "value should be an array expression if the update bound is constant");
1640  update_bound =
1641  from_integer(value_as_byte_array.operands().size(), initial_bytes.type());
1642  }
1643  initial_bytes =
1644  if_exprt{binary_predicate_exprt{initial_bytes, ID_lt, update_bound},
1645  initial_bytes,
1646  update_bound};
1647  simplify(initial_bytes, ns);
1648 
1649  // encode the first update: update the original element at first_index with
1650  // initial_bytes-many bytes extracted from value_as_byte_array
1651  exprt first_update_value = lower_byte_operators(
1653  src.id(),
1654  index_exprt{src.op(), first_index},
1655  update_offset,
1656  byte_extract_exprt{extract_opcode,
1657  value_as_byte_array,
1658  from_integer(0, src.offset().type()),
1659  array_typet{bv_typet{8}, initial_bytes}}},
1660  ns);
1661 
1662  if(value_as_byte_array.id() != ID_array)
1663  {
1665  src,
1666  subtype,
1667  subtype_size,
1668  value_as_byte_array,
1669  *non_const_update_bound,
1670  initial_bytes,
1671  first_index,
1672  first_update_value,
1673  ns);
1674  }
1675 
1676  // We will update one array/vector element at a time - compute the number of
1677  // update values that will be consumed in each step. If we cannot determine a
1678  // constant value at this time we assume it's at least one byte. The
1679  // byte_extract_exprt within the loop uses the symbolic value (subtype_size),
1680  // we just need to make sure we make progress for the loop to terminate.
1681  std::size_t step_size = 1;
1682  if(subtype_size.is_constant())
1683  step_size = numeric_cast_v<std::size_t>(to_constant_expr(subtype_size));
1684  // Given the first update already encoded, keep track of the offset into the
1685  // update value. Again, the expressions within the loop use the symbolic
1686  // value, this is just an optimization in case we can determine a constant
1687  // offset.
1688  std::size_t offset = 0;
1689  if(initial_bytes.is_constant())
1690  offset = numeric_cast_v<std::size_t>(to_constant_expr(initial_bytes));
1691 
1692  with_exprt result{src.op(), first_index, first_update_value};
1693 
1694  std::size_t i = 1;
1695  for(; offset + step_size <= value_as_byte_array.operands().size();
1696  offset += step_size, ++i)
1697  {
1698  exprt where = simplify_expr(
1699  plus_exprt{first_index, from_integer(i, first_index.type())}, ns);
1700 
1701  exprt offset_expr = simplify_expr(
1702  plus_exprt{
1703  initial_bytes,
1704  mult_exprt{subtype_size, from_integer(i - 1, subtype_size.type())}},
1705  ns);
1706 
1707  exprt element = lower_byte_operators(
1709  src.id(),
1710  index_exprt{src.op(), where},
1711  from_integer(0, src.offset().type()),
1712  byte_extract_exprt{extract_opcode,
1713  value_as_byte_array,
1714  std::move(offset_expr),
1715  array_typet{bv_typet{8}, subtype_size}}},
1716  ns);
1717 
1718  result.add_to_operands(std::move(where), std::move(element));
1719  }
1720 
1721  // do the tail
1722  if(offset < value_as_byte_array.operands().size())
1723  {
1724  const std::size_t tail_size =
1725  value_as_byte_array.operands().size() - offset;
1726 
1727  exprt where = simplify_expr(
1728  plus_exprt{first_index, from_integer(i, first_index.type())}, ns);
1729 
1730  exprt element = lower_byte_operators(
1732  src.id(),
1733  index_exprt{src.op(), where},
1734  from_integer(0, src.offset().type()),
1736  extract_opcode,
1737  value_as_byte_array,
1738  from_integer(offset, src.offset().type()),
1739  array_typet{bv_typet{8}, from_integer(tail_size, size_type())}}},
1740  ns);
1741 
1742  result.add_to_operands(std::move(where), std::move(element));
1743  }
1744 
1745  return simplify_expr(std::move(result), ns);
1746 }
1747 
1758  const byte_update_exprt &src,
1759  const typet &subtype,
1760  const exprt &value_as_byte_array,
1761  const optionalt<exprt> &non_const_update_bound,
1762  const namespacet &ns)
1763 {
1764  const bool is_array = src.type().id() == ID_array;
1765  exprt size;
1766  if(is_array)
1767  size = to_array_type(src.type()).size();
1768  else
1769  size = to_vector_type(src.type()).size();
1770 
1771  auto subtype_bits = pointer_offset_bits(subtype, ns);
1772 
1773  // fall back to bytewise updates in all non-constant or dubious cases
1774  if(
1775  !size.is_constant() || !src.offset().is_constant() ||
1776  !subtype_bits.has_value() || *subtype_bits == 0 || *subtype_bits % 8 != 0 ||
1777  non_const_update_bound.has_value() || value_as_byte_array.id() != ID_array)
1778  {
1780  src, subtype, value_as_byte_array, non_const_update_bound, ns);
1781  }
1782 
1783  std::size_t num_elements =
1784  numeric_cast_v<std::size_t>(to_constant_expr(size));
1785  mp_integer offset_bytes =
1786  numeric_cast_v<mp_integer>(to_constant_expr(src.offset()));
1787 
1788  exprt::operandst elements;
1789  elements.reserve(num_elements);
1790 
1791  std::size_t i = 0;
1792  // copy the prefix not affected by the update
1793  for(; i < num_elements && (i + 1) * *subtype_bits <= offset_bytes * 8; ++i)
1794  elements.push_back(index_exprt{src.op(), from_integer(i, c_index_type())});
1795 
1796  // the modified elements
1797  for(; i < num_elements &&
1798  i * *subtype_bits <
1799  (offset_bytes + value_as_byte_array.operands().size()) * 8;
1800  ++i)
1801  {
1802  mp_integer update_offset = offset_bytes - i * (*subtype_bits / 8);
1803  mp_integer update_elements = *subtype_bits / 8;
1804  exprt::operandst::const_iterator first =
1805  value_as_byte_array.operands().begin();
1806  exprt::operandst::const_iterator end = value_as_byte_array.operands().end();
1807  if(update_offset < 0)
1808  {
1809  INVARIANT(
1810  value_as_byte_array.operands().size() > -update_offset,
1811  "indices past the update should be handled above");
1812  first += numeric_cast_v<std::ptrdiff_t>(-update_offset);
1813  }
1814  else
1815  {
1816  update_elements -= update_offset;
1817  INVARIANT(
1818  update_elements > 0,
1819  "indices before the update should be handled above");
1820  }
1821 
1822  if(std::distance(first, end) > update_elements)
1823  end = first + numeric_cast_v<std::ptrdiff_t>(update_elements);
1824  exprt::operandst update_values{first, end};
1825  const std::size_t update_size = update_values.size();
1826 
1827  const byte_update_exprt bu{
1828  src.id(),
1829  index_exprt{src.op(), from_integer(i, c_index_type())},
1830  from_integer(update_offset < 0 ? 0 : update_offset, src.offset().type()),
1831  array_exprt{
1832  std::move(update_values),
1833  array_typet{bv_typet{8}, from_integer(update_size, size_type())}}};
1834  elements.push_back(lower_byte_operators(bu, ns));
1835  }
1836 
1837  // copy the tail not affected by the update
1838  for(; i < num_elements; ++i)
1839  elements.push_back(index_exprt{src.op(), from_integer(i, c_index_type())});
1840 
1841  if(is_array)
1842  return simplify_expr(
1843  array_exprt{std::move(elements), to_array_type(src.type())}, ns);
1844  else
1845  return simplify_expr(
1846  vector_exprt{std::move(elements), to_vector_type(src.type())}, ns);
1847 }
1848 
1859  const byte_update_exprt &src,
1860  const struct_typet &struct_type,
1861  const exprt &value_as_byte_array,
1862  const optionalt<exprt> &non_const_update_bound,
1863  const namespacet &ns)
1864 {
1865  const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
1866  ? ID_byte_extract_little_endian
1867  : ID_byte_extract_big_endian;
1868 
1869  exprt::operandst elements;
1870  elements.reserve(struct_type.components().size());
1871 
1873  for(const auto &comp : struct_type.components())
1874  {
1875  auto element_width = pointer_offset_bits(comp.type(), ns);
1876 
1877  exprt member = member_exprt{src.op(), comp.get_name(), comp.type()};
1878 
1879  // compute the update offset relative to this struct member - will be
1880  // negative if we are already in the middle of the update or beyond it
1881  exprt offset = simplify_expr(
1882  minus_exprt{src.offset(),
1883  from_integer(member_offset_bits / 8, src.offset().type())},
1884  ns);
1885  auto offset_bytes = numeric_cast<mp_integer>(offset);
1886  // we don't need to update anything when
1887  // 1) the update offset is greater than the end of this member (thus the
1888  // relative offset is greater than this element) or
1889  // 2) the update offset plus the size of the update is less than the member
1890  // offset
1891  if(
1892  offset_bytes.has_value() &&
1893  (*offset_bytes * 8 >= *element_width ||
1894  (value_as_byte_array.id() == ID_array && *offset_bytes < 0 &&
1895  -*offset_bytes >= value_as_byte_array.operands().size())))
1896  {
1897  elements.push_back(std::move(member));
1898  member_offset_bits += *element_width;
1899  continue;
1900  }
1901  else if(!offset_bytes.has_value())
1902  {
1903  // The offset to update is not constant; abort the attempt to update
1904  // indiviual struct members and instead turn the operand-to-be-updated
1905  // into a byte array, which we know how to update even if the offset is
1906  // non-constant.
1907  auto src_size_opt = size_of_expr(src.type(), ns);
1908  CHECK_RETURN(src_size_opt.has_value());
1909 
1910  const byte_extract_exprt byte_extract_expr{
1911  extract_opcode,
1912  src.op(),
1913  from_integer(0, src.offset().type()),
1914  array_typet{bv_typet{8}, src_size_opt.value()}};
1915 
1916  byte_update_exprt bu = src;
1917  bu.set_op(lower_byte_extract(byte_extract_expr, ns));
1918  bu.type() = bu.op().type();
1919 
1920  return lower_byte_extract(
1922  extract_opcode,
1924  bu, value_as_byte_array, non_const_update_bound, ns),
1925  from_integer(0, src.offset().type()),
1926  src.type()},
1927  ns);
1928  }
1929 
1930  // We now need to figure out how many bytes to consume from the update
1931  // value. If the size of the update is unknown, then we need to leave some
1932  // of this work to a back-end solver via the non_const_update_bound branch
1933  // below.
1934  mp_integer update_elements = (*element_width + 7) / 8;
1935  std::size_t first = 0;
1936  if(*offset_bytes < 0)
1937  {
1938  offset = from_integer(0, src.offset().type());
1939  INVARIANT(
1940  value_as_byte_array.id() != ID_array ||
1941  value_as_byte_array.operands().size() > -*offset_bytes,
1942  "members past the update should be handled above");
1943  first = numeric_cast_v<std::size_t>(-*offset_bytes);
1944  }
1945  else
1946  {
1947  update_elements -= *offset_bytes;
1948  INVARIANT(
1949  update_elements > 0,
1950  "members before the update should be handled above");
1951  }
1952 
1953  // Now that we have an idea on how many bytes we need from the update value,
1954  // determine the exact range [first, end) in the update value, and create
1955  // that sequence of bytes (via instantiate_byte_array).
1956  std::size_t end = first + numeric_cast_v<std::size_t>(update_elements);
1957  if(value_as_byte_array.id() == ID_array)
1958  end = std::min(end, value_as_byte_array.operands().size());
1959  exprt::operandst update_values =
1960  instantiate_byte_array(value_as_byte_array, first, end, ns);
1961  const std::size_t update_size = update_values.size();
1962 
1963  // With an upper bound on the size of the update established, construct the
1964  // actual update expression. If the exact size of the update is unknown,
1965  // make the size expression conditional.
1966  exprt update_size_expr = from_integer(update_size, size_type());
1967  array_exprt update_expr{std::move(update_values),
1968  array_typet{bv_typet{8}, update_size_expr}};
1969  optionalt<exprt> member_update_bound;
1970  if(non_const_update_bound.has_value())
1971  {
1972  // The size of the update is not constant, and thus is to be symbolically
1973  // bound; first see how many bytes we have left in the update:
1974  // non_const_update_bound > first ? non_const_update_bound - first: 0
1975  const exprt remaining_update_bytes = typecast_exprt::conditional_cast(
1976  if_exprt{
1978  *non_const_update_bound,
1979  ID_gt,
1980  from_integer(first, non_const_update_bound->type())},
1981  minus_exprt{*non_const_update_bound,
1982  from_integer(first, non_const_update_bound->type())},
1983  from_integer(0, non_const_update_bound->type())},
1984  size_type());
1985  // Now take the minimum of update-bytes-left and the previously computed
1986  // size of the member to be updated:
1987  update_size_expr = if_exprt{
1988  binary_predicate_exprt{update_size_expr, ID_lt, remaining_update_bytes},
1989  update_size_expr,
1990  remaining_update_bytes};
1991  simplify(update_size_expr, ns);
1992  member_update_bound = std::move(update_size_expr);
1993  }
1994 
1995  // We have established the bytes to use for the update, but now need to
1996  // account for sub-byte members.
1997  const std::size_t shift =
1998  numeric_cast_v<std::size_t>(member_offset_bits % 8);
1999  const std::size_t element_bits_int =
2000  numeric_cast_v<std::size_t>(*element_width);
2001 
2002  const bool little_endian = src.id() == ID_byte_update_little_endian;
2003  if(shift != 0)
2004  {
2005  member = concatenation_exprt{
2006  typecast_exprt::conditional_cast(member, bv_typet{element_bits_int}),
2007  from_integer(0, bv_typet{shift}),
2008  bv_typet{shift + element_bits_int}};
2009 
2010  if(!little_endian)
2011  to_concatenation_expr(member).op0().swap(
2012  to_concatenation_expr(member).op1());
2013  }
2014 
2015  // Finally construct the updated member.
2016  byte_update_exprt bu{src.id(), std::move(member), offset, update_expr};
2017  exprt updated_element =
2018  lower_byte_update(bu, update_expr, member_update_bound, ns);
2019 
2020  if(shift == 0)
2021  elements.push_back(updated_element);
2022  else
2023  {
2024  PRECONDITION(pointer_offset_bits(updated_element.type(), ns).has_value());
2025  elements.push_back(typecast_exprt::conditional_cast(
2026  extractbits_exprt{updated_element,
2027  element_bits_int - 1 + (little_endian ? shift : 0),
2028  (little_endian ? shift : 0),
2029  bv_typet{element_bits_int}},
2030  comp.type()));
2031  }
2032 
2033  member_offset_bits += *element_width;
2034  }
2035 
2036  return simplify_expr(struct_exprt{std::move(elements), struct_type}, ns);
2037 }
2038 
2049  const byte_update_exprt &src,
2050  const union_typet &union_type,
2051  const exprt &value_as_byte_array,
2052  const optionalt<exprt> &non_const_update_bound,
2053  const namespacet &ns)
2054 {
2055  const auto widest_member = union_type.find_widest_union_component(ns);
2056 
2058  widest_member.has_value(),
2059  "lower_byte_update of union of unknown size is not supported");
2060 
2061  byte_update_exprt bu = src;
2062  bu.set_op(member_exprt{
2063  src.op(), widest_member->first.get_name(), widest_member->first.type()});
2064  bu.type() = widest_member->first.type();
2065 
2066  return union_exprt{
2067  widest_member->first.get_name(),
2068  lower_byte_update(bu, value_as_byte_array, non_const_update_bound, ns),
2069  src.type()};
2070 }
2071 
2081  const byte_update_exprt &src,
2082  const exprt &value_as_byte_array,
2083  const optionalt<exprt> &non_const_update_bound,
2084  const namespacet &ns)
2085 {
2086  if(src.type().id() == ID_array || src.type().id() == ID_vector)
2087  {
2088  optionalt<typet> subtype;
2089  if(src.type().id() == ID_vector)
2090  subtype = to_vector_type(src.type()).element_type();
2091  else
2092  subtype = to_array_type(src.type()).element_type();
2093 
2094  auto element_width = pointer_offset_bits(*subtype, ns);
2095  CHECK_RETURN(element_width.has_value());
2096  CHECK_RETURN(*element_width > 0);
2097  CHECK_RETURN(*element_width % 8 == 0);
2098 
2099  if(*element_width == 8)
2100  {
2101  if(value_as_byte_array.id() != ID_array)
2102  {
2104  non_const_update_bound.has_value(),
2105  "constant update bound should yield an array expression");
2107  src, *subtype, value_as_byte_array, *non_const_update_bound, ns);
2108  }
2109 
2111  src,
2112  *subtype,
2113  to_array_expr(value_as_byte_array),
2114  non_const_update_bound,
2115  ns);
2116  }
2117  else
2119  src, *subtype, value_as_byte_array, non_const_update_bound, ns);
2120  }
2121  else if(src.type().id() == ID_struct || src.type().id() == ID_struct_tag)
2122  {
2124  src,
2125  to_struct_type(ns.follow(src.type())),
2126  value_as_byte_array,
2127  non_const_update_bound,
2128  ns);
2129  result.type() = src.type();
2130  return result;
2131  }
2132  else if(src.type().id() == ID_union || src.type().id() == ID_union_tag)
2133  {
2134  exprt result = lower_byte_update_union(
2135  src,
2136  to_union_type(ns.follow(src.type())),
2137  value_as_byte_array,
2138  non_const_update_bound,
2139  ns);
2140  result.type() = src.type();
2141  return result;
2142  }
2143  else if(
2145  src.type().id() == ID_c_enum || src.type().id() == ID_c_enum_tag)
2146  {
2147  // mask out the bits to be updated, shift the value according to the
2148  // offset and bit-or
2149  const auto type_width = pointer_offset_bits(src.type(), ns);
2150  CHECK_RETURN(type_width.has_value() && *type_width > 0);
2151  const std::size_t type_bits = numeric_cast_v<std::size_t>(*type_width);
2152 
2153  exprt::operandst update_bytes;
2154  if(value_as_byte_array.id() == ID_array)
2155  update_bytes = value_as_byte_array.operands();
2156  else
2157  {
2158  update_bytes =
2159  instantiate_byte_array(value_as_byte_array, 0, (type_bits + 7) / 8, ns);
2160  }
2161 
2162  const std::size_t update_size_bits = update_bytes.size() * 8;
2163  const std::size_t bit_width = std::max(type_bits, update_size_bits);
2164 
2165  const bool is_little_endian = src.id() == ID_byte_update_little_endian;
2166 
2167  exprt val_before =
2168  typecast_exprt::conditional_cast(src.op(), bv_typet{type_bits});
2169  if(bit_width > type_bits)
2170  {
2171  val_before =
2172  concatenation_exprt{from_integer(0, bv_typet{bit_width - type_bits}),
2173  val_before,
2174  bv_typet{bit_width}};
2175 
2176  if(!is_little_endian)
2177  to_concatenation_expr(val_before)
2178  .op0()
2179  .swap(to_concatenation_expr(val_before).op1());
2180  }
2181 
2182  if(non_const_update_bound.has_value())
2183  {
2184  const exprt src_as_bytes = unpack_rec(
2185  val_before,
2186  src.id() == ID_byte_update_little_endian,
2187  mp_integer{0},
2188  mp_integer{update_bytes.size()},
2189  ns);
2190  CHECK_RETURN(src_as_bytes.id() == ID_array);
2191  CHECK_RETURN(src_as_bytes.operands().size() == update_bytes.size());
2192  for(std::size_t i = 0; i < update_bytes.size(); ++i)
2193  {
2194  update_bytes[i] =
2196  from_integer(i, non_const_update_bound->type()),
2197  ID_lt,
2198  *non_const_update_bound},
2199  update_bytes[i],
2200  src_as_bytes.operands()[i]};
2201  }
2202  }
2203 
2204  // build mask
2205  exprt mask;
2206  if(is_little_endian)
2207  mask = from_integer(power(2, update_size_bits) - 1, bv_typet{bit_width});
2208  else
2209  {
2210  mask = from_integer(
2211  power(2, bit_width) - power(2, bit_width - update_size_bits),
2212  bv_typet{bit_width});
2213  }
2214 
2215  const typet &offset_type = src.offset().type();
2216  mult_exprt offset_times_eight{src.offset(), from_integer(8, offset_type)};
2217 
2218  const binary_predicate_exprt offset_ge_zero{
2219  offset_times_eight, ID_ge, from_integer(0, offset_type)};
2220 
2221  if_exprt mask_shifted{offset_ge_zero,
2222  shl_exprt{mask, offset_times_eight},
2223  lshr_exprt{mask, offset_times_eight}};
2224  if(!is_little_endian)
2225  mask_shifted.true_case().swap(mask_shifted.false_case());
2226 
2227  // original_bits &= ~mask
2228  bitand_exprt bitand_expr{val_before, bitnot_exprt{mask_shifted}};
2229 
2230  // concatenate and zero-extend the value
2231  concatenation_exprt value{update_bytes, bv_typet{update_size_bits}};
2232  if(is_little_endian)
2233  std::reverse(value.operands().begin(), value.operands().end());
2234 
2235  exprt zero_extended;
2236  if(bit_width > update_size_bits)
2237  {
2238  zero_extended = concatenation_exprt{
2239  from_integer(0, bv_typet{bit_width - update_size_bits}),
2240  value,
2241  bv_typet{bit_width}};
2242 
2243  if(!is_little_endian)
2244  to_concatenation_expr(zero_extended)
2245  .op0()
2246  .swap(to_concatenation_expr(zero_extended).op1());
2247  }
2248  else
2249  zero_extended = value;
2250 
2251  // shift the value
2252  if_exprt value_shifted{offset_ge_zero,
2253  shl_exprt{zero_extended, offset_times_eight},
2254  lshr_exprt{zero_extended, offset_times_eight}};
2255  if(!is_little_endian)
2256  value_shifted.true_case().swap(value_shifted.false_case());
2257 
2258  // original_bits |= newvalue
2259  bitor_exprt bitor_expr{bitand_expr, value_shifted};
2260 
2261  if(bit_width > type_bits)
2262  {
2263  endianness_mapt endianness_map(
2264  bitor_expr.type(), src.id() == ID_byte_update_little_endian, ns);
2265  const auto bounds = map_bounds(endianness_map, 0, type_bits - 1);
2266 
2267  PRECONDITION(pointer_offset_bits(bitor_expr.type(), ns).has_value());
2268  return simplify_expr(
2271  bitor_expr, bounds.ub, bounds.lb, bv_typet{type_bits}},
2272  src.type()),
2273  ns);
2274  }
2275 
2276  return simplify_expr(
2277  typecast_exprt::conditional_cast(bitor_expr, src.type()), ns);
2278  }
2279  else
2280  {
2282  false, "lower_byte_update does not yet support ", src.type().id_string());
2283  }
2284 }
2285 
2287 {
2289  src.id() == ID_byte_update_little_endian ||
2290  src.id() == ID_byte_update_big_endian,
2291  "byte update expression should either be little or big endian");
2292 
2293  // An update of a void-typed object or update by a void-typed value is the
2294  // source operand (this is questionable, but may arise when dereferencing
2295  // invalid pointers).
2296  if(src.type().id() == ID_empty || src.value().type().id() == ID_empty)
2297  return src.op();
2298 
2299  // byte_update lowering proceeds as follows:
2300  // 1) Determine the size of the update, with the size of the object to be
2301  // updated as an upper bound. We fail if neither can be determined.
2302  // 2) Turn the update value into a byte array of the size determined above.
2303  // 3) If the offset is not constant, turn the object into a byte array, and
2304  // use a "with" expression to encode the update; else update the values in
2305  // place.
2306  // 4) Construct a new object.
2307  optionalt<exprt> non_const_update_bound;
2308  // update value, may require extension to full bytes
2309  exprt update_value = src.value();
2310  auto update_size_expr_opt = size_of_expr(update_value.type(), ns);
2311  CHECK_RETURN(update_size_expr_opt.has_value());
2312  simplify(update_size_expr_opt.value(), ns);
2313 
2314  const irep_idt extract_opcode = src.id() == ID_byte_update_little_endian
2315  ? ID_byte_extract_little_endian
2316  : ID_byte_extract_big_endian;
2317 
2318  if(!update_size_expr_opt.value().is_constant())
2319  non_const_update_bound = *update_size_expr_opt;
2320  else
2321  {
2322  auto update_bits = pointer_offset_bits(update_value.type(), ns);
2323  // If the following invariant fails, then the type was only found to be
2324  // constant via simplification. Such instances should be fixed at the place
2325  // introducing these constant-but-not-constant_exprt type sizes.
2327  update_bits.has_value(), "constant size-of should imply fixed bit width");
2328  const size_t update_bits_int = numeric_cast_v<size_t>(*update_bits);
2329 
2330  if(update_bits_int % 8 != 0)
2331  {
2333  can_cast_type<bitvector_typet>(update_value.type()),
2334  "non-byte aligned type expected to be a bitvector type");
2335  const byte_extract_exprt overlapping_byte_extract{
2336  extract_opcode,
2337  src.op(),
2338  simplify_expr(
2339  plus_exprt{
2340  src.offset(),
2341  from_integer(update_bits_int / 8, src.offset().type())},
2342  ns),
2343  bv_typet{8}};
2344  const exprt overlapping_byte =
2345  lower_byte_extract(overlapping_byte_extract, ns);
2346 
2347  size_t n_extra_bits = 8 - update_bits_int % 8;
2348  extractbits_exprt extra_bits{
2349  overlapping_byte, n_extra_bits - 1, 0, bv_typet{n_extra_bits}};
2350 
2351  update_value = concatenation_exprt{
2353  update_value, bv_typet{update_bits_int}),
2354  extra_bits,
2355  adjust_width(update_value.type(), update_bits_int + n_extra_bits)};
2356  }
2357  else
2358  {
2359  update_size_expr_opt =
2360  from_integer(update_bits_int / 8, update_size_expr_opt->type());
2361  }
2362  }
2363 
2364  const byte_extract_exprt byte_extract_expr{
2365  extract_opcode,
2366  update_value,
2367  from_integer(0, src.offset().type()),
2368  array_typet{bv_typet{8}, *update_size_expr_opt}};
2369 
2370  const exprt value_as_byte_array = lower_byte_extract(byte_extract_expr, ns);
2371 
2372  exprt result =
2373  lower_byte_update(src, value_as_byte_array, non_const_update_bound, ns);
2374  return result;
2375 }
2376 
2377 bool has_byte_operator(const exprt &src)
2378 {
2379  if(src.id()==ID_byte_update_little_endian ||
2380  src.id()==ID_byte_update_big_endian ||
2381  src.id()==ID_byte_extract_little_endian ||
2382  src.id()==ID_byte_extract_big_endian)
2383  return true;
2384 
2385  forall_operands(it, src)
2386  if(has_byte_operator(*it))
2387  return true;
2388 
2389  return false;
2390 }
2391 
2393 {
2394  exprt tmp=src;
2395 
2396  // destroys any sharing, should use hash table
2397  Forall_operands(it, tmp)
2398  {
2399  *it = lower_byte_operators(*it, ns);
2400  }
2401 
2402  if(src.id()==ID_byte_update_little_endian ||
2403  src.id()==ID_byte_update_big_endian)
2404  return lower_byte_update(to_byte_update_expr(tmp), ns);
2405  else if(src.id()==ID_byte_extract_little_endian ||
2406  src.id()==ID_byte_extract_big_endian)
2407  return lower_byte_extract(to_byte_extract_expr(tmp), ns);
2408  else
2409  return tmp;
2410 }
with_exprt
Operator to update elements in structs and arrays.
Definition: std_expr.h:2423
to_union_tag_type
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition: c_types.h:202
bv_to_vector_expr
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.
Definition: byte_operators.cpp:231
struct_union_typet::components
const componentst & components() const
Definition: std_types.h:147
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
pointer_offset_size.h
to_union_type
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition: c_types.h:162
unpack_complex
static array_exprt unpack_complex(const exprt &src, bool little_endian, const namespacet &ns)
Rewrite a complex_exprt into its individual bytes.
Definition: byte_operators.cpp:778
typecast_exprt::conditional_cast
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:2025
skip_typecast
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
Definition: expr_util.cpp:217
mp_integer
BigInt mp_integer
Definition: smt_terms.h:17
byte_update_exprt
Expression corresponding to op() where the bytes starting at position offset (given in number of byte...
Definition: byte_operators.h:77
Forall_operands
#define Forall_operands(it, expr)
Definition: expr.h:27
arith_tools.h
to_array_expr
const array_exprt & to_array_expr(const exprt &expr)
Cast an exprt to an array_exprt.
Definition: std_expr.h:1603
to_struct_type
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
CHECK_RETURN
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
member_offset_bits
optionalt< mp_integer > member_offset_bits(const struct_typet &type, const irep_idt &member, const namespacet &ns)
Definition: pointer_offset_size.cpp:65
typet
The type of an expression, extends irept.
Definition: type.h:28
to_byte_extract_expr
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
Definition: byte_operators.h:57
union_typet::find_widest_union_component
optionalt< 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:318
to_index_expr
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1478
vector_typet::size
const constant_exprt & size() const
Definition: std_types.cpp:269
if_exprt
The trinary if-then-else operator.
Definition: std_expr.h:2322
byte_update_exprt::offset
const exprt & offset() const
Definition: byte_operators.h:106
has_byte_operator
bool has_byte_operator(const exprt &src)
Definition: byte_operators.cpp:2377
unpack_array_vector
static exprt unpack_array_vector(const exprt &src, const optionalt< mp_integer > &src_size, const mp_integer &element_bits, bool little_endian, const optionalt< mp_integer > &offset_bytes, const optionalt< mp_integer > &max_bytes, const namespacet &ns)
Rewrite an array or vector into its individual bytes.
Definition: byte_operators.cpp:517
to_c_enum_type
const c_enum_typet & to_c_enum_type(const typet &type)
Cast a typet to a c_enum_typet.
Definition: c_types.h:302
lower_byte_update
static exprt lower_byte_update(const byte_update_exprt &src, const exprt &value_as_byte_array, const optionalt< exprt > &non_const_update_bound, const namespacet &ns)
Apply a byte update src using the byte array value_as_byte_array as update value.
Definition: byte_operators.cpp:2080
complex_real_exprt
Real part of the expression describing a complex number.
Definition: std_expr.h:1925
union_exprt
Union constructor from single element.
Definition: std_expr.h:1707
to_string_constant
const string_constantt & to_string_constant(const exprt &expr)
Definition: string_constant.h:40
bv_to_expr
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.
Definition: byte_operators.cpp:333
to_type_with_subtype
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition: type.h:193
plus_exprt
The plus expression Associativity is not specified.
Definition: std_expr.h:946
lower_byte_extract
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...
Definition: byte_operators.cpp:1099
string_constant.h
lower_byte_update_array_vector
static exprt lower_byte_update_array_vector(const byte_update_exprt &src, const typet &subtype, const exprt &value_as_byte_array, const optionalt< 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 ...
Definition: byte_operators.cpp:1757
exprt
Base class for all expressions.
Definition: expr.h:55
struct_union_typet::componentst
std::vector< componentt > componentst
Definition: std_types.h:140
namespace_baset::follow_tag
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
byte_update_exprt::set_op
void set_op(exprt e)
Definition: byte_operators.h:92
complex_typet
Complex numbers made of pair of given subtype.
Definition: std_types.h:1076
vector_typet
The vector type.
Definition: std_types.h:1007
to_integer
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
concatenation_exprt
Concatenation of bit-vector operands.
Definition: bitvector_expr.h:607
to_string
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
Definition: string_constraint.cpp:58
vector_exprt
Vector constructor from list of elements.
Definition: std_expr.h:1671
lshr_exprt
Logical right shift.
Definition: bitvector_expr.h:359
to_bitvector_type
const bitvector_typet & to_bitvector_type(const typet &type)
Cast a typet to a bitvector_typet.
Definition: bitvector_types.h:32
to_complex_type
const complex_typet & to_complex_type(const typet &type)
Cast a typet to a complex_typet.
Definition: std_types.h:1102
div_exprt
Division.
Definition: std_expr.h:1096
symbol_exprt
Expression to hold a symbol (variable)
Definition: std_expr.h:112
namespace.h
string_constantt
Definition: string_constant.h:14
equal_exprt
Equality.
Definition: std_expr.h:1305
unsignedbv_typet
Fixed-width bit-vector with unsigned binary interpretation.
Definition: bitvector_types.h:158
expr_lowering.h
narrow.h
lower_byte_update_byte_array_vector
static exprt lower_byte_update_byte_array_vector(const byte_update_exprt &src, const typet &subtype, const array_exprt &value_as_byte_array, const optionalt< 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...
Definition: byte_operators.cpp:1405
struct_exprt
Struct constructor from list of elements.
Definition: std_expr.h:1818
array_typet::size
const exprt & size() const
Definition: std_types.h:800
namespacet
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:90
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
bv_to_struct_expr
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.
Definition: byte_operators.cpp:80
byte_operators.h
Expression classes for byte-level operators.
vector_typet::element_type
const typet & element_type() const
The type of the elements of the vector.
Definition: std_types.h:1026
bitor_exprt
Bit-wise OR.
Definition: bitvector_expr.h:124
endianness_mapt::number_of_bits
size_t number_of_bits() const
Definition: endianness_map.h:55
or_exprt
Boolean OR.
Definition: std_expr.h:2178
lower_byte_update_array_vector_non_const
static exprt lower_byte_update_array_vector_non_const(const byte_update_exprt &src, const typet &subtype, const exprt &value_as_byte_array, const optionalt< 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...
Definition: byte_operators.cpp:1597
DATA_INVARIANT
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:510
c_bit_field_typet
Type for C bit fields These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (...
Definition: c_types.h:19
lower_byte_update_struct
static exprt lower_byte_update_struct(const byte_update_exprt &src, const struct_typet &struct_type, const exprt &value_as_byte_array, const optionalt< 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 ...
Definition: byte_operators.cpp:1858
byte_extract_exprt::op
exprt & op()
Definition: byte_operators.h:43
failed
static bool failed(bool error_indicator)
Definition: symtab2gb_parse_options.cpp:39
forall_operands
#define forall_operands(it, expr)
Definition: expr.h:20
to_byte_update_expr
const byte_update_exprt & to_byte_update_expr(const exprt &expr)
Definition: byte_operators.h:117
boundst
Definition: byte_operators.cpp:31
lower_byte_update_array_vector_unbounded
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...
Definition: byte_operators.cpp:1471
binary_predicate_exprt
A base class for expressions that are predicates, i.e., Boolean-typed, and that take exactly two argu...
Definition: std_expr.h:675
PRECONDITION
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
nil_exprt
The NIL expression.
Definition: std_expr.h:3025
pointer_offset_bits
optionalt< mp_integer > pointer_offset_bits(const typet &type, const namespacet &ns)
Definition: pointer_offset_size.cpp:101
signedbv_typet
Fixed-width bit-vector with two's complement interpretation.
Definition: bitvector_types.h:207
endianness_mapt::map_bit
size_t map_bit(size_t bit) const
Definition: endianness_map.h:47
lower_byte_operators
exprt lower_byte_operators(const exprt &src, const namespacet &ns)
Rewrite an expression possibly containing byte-extract or -update expressions to more fundamental ope...
Definition: byte_operators.cpp:2392
irept::id_string
const std::string & id_string() const
Definition: irep.h:399
simplify
bool simplify(exprt &expr, const namespacet &ns)
Definition: simplify_expr.cpp:2926
bv_to_union_expr
static union_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.
Definition: byte_operators.cpp:128
mult_exprt
Binary multiplication Associativity is not specified.
Definition: std_expr.h:1051
bv_to_complex_expr
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.
Definition: byte_operators.cpp:278
to_pointer_type
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:79
simplify_expr
exprt simplify_expr(exprt src, const namespacet &ns)
Definition: simplify_expr.cpp:2931
index_exprt::index
exprt & index()
Definition: std_expr.h:1450
index_exprt::array
exprt & array()
Definition: std_expr.h:1440
irept::swap
void swap(irept &irep)
Definition: irep.h:442
irept::id
const irep_idt & id() const
Definition: irep.h:396
to_struct_tag_type
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition: std_types.h:474
exprt::operandst
std::vector< exprt > operandst
Definition: expr.h:58
instantiate_byte_array
static exprt::operandst instantiate_byte_array(const exprt &src, std::size_t lower_bound, std::size_t upper_bound, const namespacet &ns)
Build the individual bytes to be used in an update.
Definition: byte_operators.cpp:419
complex_exprt
Complex constructor from a pair of numbers.
Definition: std_expr.h:1857
union_typet
The union type.
Definition: c_types.h:124
bitand_exprt
Bit-wise AND.
Definition: bitvector_expr.h:194
lower_byte_update_union
static exprt lower_byte_update_union(const byte_update_exprt &src, const union_typet &union_type, const exprt &value_as_byte_array, const optionalt< 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...
Definition: byte_operators.cpp:2048
optionalt
nonstd::optional< T > optionalt
Definition: optional.h:35
minus_exprt
Binary minus.
Definition: std_expr.h:1005
lower_byte_extract_complex
static optionalt< 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...
Definition: byte_operators.cpp:1068
map_bounds
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.
Definition: byte_operators.cpp:38
endianness_map.h
simplify_expr.h
bitvector_typet::get_width
std::size_t get_width() const
Definition: std_types.h:876
bitnot_exprt
Bit-wise negation of bit-vectors.
Definition: bitvector_expr.h:81
byte_extract_exprt::offset
exprt & offset()
Definition: byte_operators.h:44
to_concatenation_expr
const concatenation_exprt & to_concatenation_expr(const exprt &expr)
Cast an exprt to a concatenation_exprt.
Definition: bitvector_expr.h:636
member_exprt
Extract member of struct or union.
Definition: std_expr.h:2793
to_c_bit_field_type
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:58
expr_util.h
Deprecated expression utility functions.
struct_typet
Structure type, corresponds to C style structs.
Definition: std_types.h:230
byte_update_exprt::value
const exprt & value() const
Definition: byte_operators.h:107
array_typet
Arrays with given size.
Definition: std_types.h:762
adjust_width
bitvector_typet adjust_width(const typet &src, std::size_t new_width)
changes the width of the given bitvector type
Definition: byte_operators.cpp:61
bitvector_typet
Base class of fixed-width bit-vector types.
Definition: std_types.h:864
namespace_baset::follow
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
bv_to_array_expr
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.
Definition: byte_operators.cpp:176
from_integer
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:100
PRECONDITION_WITH_DIAGNOSTICS
#define PRECONDITION_WITH_DIAGNOSTICS(CONDITION,...)
Definition: invariant.h:464
unpack_rec
static exprt unpack_rec(const exprt &src, bool little_endian, const optionalt< mp_integer > &offset_bytes, const optionalt< mp_integer > &max_bytes, const namespacet &ns, bool unpack_byte_array=false)
Rewrite an object into its individual bytes.
Definition: byte_operators.cpp:824
exprt::is_constant
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.cpp:27
complex_imag_exprt
Imaginary part of the expression describing a complex number.
Definition: std_expr.h:1970
byte_extract_exprt
Expression of type type extracted from some object op starting at position offset (given in number of...
Definition: byte_operators.h:28
to_array_type
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:844
power
mp_integer power(const mp_integer &base, const mp_integer &exponent)
A multi-precision implementation of the power operator.
Definition: arith_tools.cpp:195
exprt::add_to_operands
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition: expr.h:162
endianness_mapt
Maps a big-endian offset to a little-endian offset.
Definition: endianness_map.h:30
type_with_subtypet::subtype
const typet & subtype() const
Definition: type.h:172
unpack_struct
static array_exprt unpack_struct(const exprt &src, bool little_endian, const optionalt< mp_integer > &offset_bytes, const optionalt< mp_integer > &max_bytes, const namespacet &ns)
Rewrite a struct-typed expression into its individual bytes.
Definition: byte_operators.cpp:655
to_vector_type
const vector_typet & to_vector_type(const typet &type)
Cast a typet to a vector_typet.
Definition: std_types.h:1060
size_of_expr
optionalt< exprt > size_of_expr(const typet &type, const namespacet &ns)
Definition: pointer_offset_size.cpp:280
boundst::ub
std::size_t ub
Definition: byte_operators.cpp:34
boundst::lb
std::size_t lb
Definition: byte_operators.cpp:33
extractbits_exprt
Extracts a sub-range of a bit-vector operand.
Definition: bitvector_expr.h:447
exprt::operands
operandst & operands()
Definition: expr.h:94
index_exprt
Array index operator.
Definition: std_expr.h:1409
INVARIANT
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition: invariant.h:423
typecast_exprt
Semantic type conversion.
Definition: std_expr.h:2016
size_type
unsignedbv_typet size_type()
Definition: c_types.cpp:68
array_comprehension_exprt
Expression to define a mapping from an argument (index) to elements.
Definition: std_expr.h:3350
constant_exprt
A constant literal expression.
Definition: std_expr.h:2941
multi_ary_exprt::op0
exprt & op0()
Definition: std_expr.h:877
member_offset_expr
optionalt< exprt > member_offset_expr(const member_exprt &member_expr, const namespacet &ns)
Definition: pointer_offset_size.cpp:221
c_index_type
bitvector_typet c_index_type()
Definition: c_types.cpp:16
byte_update_exprt::op
const exprt & op() const
Definition: byte_operators.h:105
lower_byte_update_byte_array_vector_non_const
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...
Definition: byte_operators.cpp:1349
array_exprt
Array constructor from list of elements.
Definition: std_expr.h:1562
c_types.h
lower_byte_extract_array_vector
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...
Definition: byte_operators.cpp:992
process_bit_fields
static void process_bit_fields(exprt::operandst &&bit_fields, std::size_t total_bits, exprt::operandst &dest, bool little_endian, const optionalt< mp_integer > &offset_bytes, const optionalt< mp_integer > &max_bytes, const namespacet &ns)
Extract bytes from a sequence of bitvector-typed elements.
Definition: byte_operators.cpp:625
can_cast_type< bitvector_typet >
bool can_cast_type< bitvector_typet >(const typet &type)
Check whether a reference to a typet is a bitvector_typet.
Definition: std_types.h:899
bitvector_expr.h
bv_typet
Fixed-width bit-vector without numerical interpretation.
Definition: bitvector_types.h:48
mod_exprt
Modulo defined as lhs-(rhs * truncate(lhs/rhs)).
Definition: std_expr.h:1167
array_typet::element_type
const typet & element_type() const
The type of the elements of the array.
Definition: std_types.h:785
shl_exprt
Left shift.
Definition: bitvector_expr.h:294
unpack_array_vector_no_known_bounds
static exprt unpack_array_vector_no_known_bounds(const exprt &src, std::size_t el_bytes, bool little_endian, const namespacet &ns)
Rewrite an array or vector into its individual bytes when no maximum number of bytes is known.
Definition: byte_operators.cpp:458
to_constant_expr
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:2992