@@ -551,69 +551,121 @@ static exprt unpack_array_vector(
551551 // refine the number of elements to extract in case the element width is known
552552 // and a multiple of bytes; otherwise we will expand the entire array/vector
553553 optionalt<mp_integer> num_elements = src_size;
554- if (element_bits > 0 && element_bits % bits_per_byte == 0 )
554+ if (element_bits > 0 )
555555 {
556556 if (!num_elements.has_value ())
557557 {
558558 // turn bytes into elements, rounding up
559- num_elements = (*max_bytes + el_bytes - 1 ) / el_bytes;
559+ num_elements =
560+ (*max_bytes * bits_per_byte + element_bits - 1 ) / element_bits;
560561 }
561562
562563 if (offset_bytes.has_value ())
563564 {
564565 // compute offset as number of elements
565- first_element = *offset_bytes / el_bytes ;
566- // insert offset_bytes-many nil bytes into the output array
566+ first_element = *offset_bytes * bits_per_byte / element_bits ;
567+ // insert offset_bytes-many zero bytes into the output array
567568 byte_operands.resize (
568- numeric_cast_v<std::size_t >(*offset_bytes - (*offset_bytes % el_bytes)),
569+ numeric_cast_v<std::size_t >(
570+ (*offset_bytes * bits_per_byte -
571+ ((*offset_bytes * bits_per_byte) % element_bits)) /
572+ bits_per_byte),
569573 from_integer (0 , bv_typet{bits_per_byte}));
570574 }
571575 }
572576
573577 // the maximum number of bytes is an upper bound in case the size of the
574- // array/vector is unknown; if element_bits was usable above this will
578+ // array/vector is unknown; if element_bits was non-zero above this will
575579 // have been turned into a number of elements already
576580 if (!num_elements)
577581 num_elements = *max_bytes;
578582
579583 const exprt src_simp = simplify_expr (src, ns);
580584
581- for (mp_integer i = first_element; i < *num_elements; ++i )
585+ if (element_bits % bits_per_byte == 0 )
582586 {
583- exprt element;
584-
585- if (
586- (src_simp.id () == ID_array || src_simp.id () == ID_vector) &&
587- i < src_simp.operands ().size ())
587+ for (mp_integer i = first_element; i < *num_elements; ++i)
588588 {
589- const std::size_t index_int = numeric_cast_v<std::size_t >(i);
590- element = src_simp.operands ()[index_int];
589+ exprt element;
590+
591+ if (
592+ (src_simp.id () == ID_array || src_simp.id () == ID_vector) &&
593+ i < src_simp.operands ().size ())
594+ {
595+ const std::size_t index_int = numeric_cast_v<std::size_t >(i);
596+ element = src_simp.operands ()[index_int];
597+ }
598+ else
599+ {
600+ element = index_exprt (src_simp, from_integer (i, index_type ()));
601+ }
602+
603+ // recursively unpack each element so that we eventually just have an
604+ // array of bytes left
605+
606+ const optionalt<mp_integer> element_max_bytes =
607+ max_bytes
608+ ? std::min (mp_integer{el_bytes}, *max_bytes - byte_operands.size ())
609+ : optionalt<mp_integer>{};
610+ const std::size_t element_max_bytes_int =
611+ element_max_bytes ? numeric_cast_v<std::size_t >(*element_max_bytes)
612+ : el_bytes;
613+
614+ exprt sub = unpack_rec (
615+ element, little_endian, {}, element_max_bytes, bits_per_byte, ns, true );
616+ exprt::operandst sub_operands = instantiate_byte_array (
617+ sub, 0 , element_max_bytes_int, bits_per_byte, ns);
618+ byte_operands.insert (
619+ byte_operands.end (), sub_operands.begin (), sub_operands.end ());
620+
621+ if (max_bytes && byte_operands.size () >= *max_bytes)
622+ break ;
591623 }
592- else
624+ }
625+ else
626+ {
627+ const std::size_t element_bits_int =
628+ numeric_cast_v<std::size_t >(element_bits);
629+
630+ exprt::operandst elements;
631+ for (mp_integer i = *num_elements - 1 ; i >= first_element; --i)
593632 {
594- element = index_exprt (src_simp, from_integer (i, c_index_type ()));
633+ if (
634+ (src_simp.id () == ID_array || src_simp.id () == ID_vector) &&
635+ i < src_simp.operands ().size ())
636+ {
637+ const std::size_t index_int = numeric_cast_v<std::size_t >(i);
638+ elements.push_back (typecast_exprt::conditional_cast (
639+ src_simp.operands ()[index_int], bv_typet{element_bits_int}));
640+ }
641+ else
642+ {
643+ elements.push_back (typecast_exprt::conditional_cast (
644+ index_exprt (src_simp, from_integer (i, c_index_type ())),
645+ bv_typet{element_bits_int}));
646+ }
595647 }
596648
597- // recursively unpack each element so that we eventually just have an array
598- // of bytes left
649+ const std::size_t merged_bit_width = numeric_cast_v<std::size_t >(
650+ (*num_elements - first_element) * element_bits);
651+ if (!little_endian)
652+ std::reverse (elements.begin (), elements.end ());
653+ concatenation_exprt merged{std::move (elements), bv_typet{merged_bit_width}};
599654
600- const optionalt<mp_integer> element_max_bytes =
601- max_bytes
602- ? std::min (mp_integer{el_bytes}, *max_bytes - byte_operands.size ())
603- : optionalt<mp_integer>{};
604- const std::size_t element_max_bytes_int =
605- element_max_bytes ? numeric_cast_v<std::size_t >(*element_max_bytes)
606- : el_bytes;
655+ exprt merged_as_bytes =
656+ unpack_rec (merged, little_endian, {}, max_bytes, bits_per_byte, ns, true );
607657
608- exprt sub = unpack_rec (
609- element, little_endian, {}, element_max_bytes, bits_per_byte, ns, true );
610- exprt::operandst sub_operands =
611- instantiate_byte_array (sub, 0 , element_max_bytes_int, bits_per_byte, ns);
658+ const std::size_t merged_byte_width =
659+ (merged_bit_width + bits_per_byte - 1 ) / bits_per_byte;
660+ const std::size_t max_bytes_int =
661+ max_bytes.has_value ()
662+ ? std::min (numeric_cast_v<std::size_t >(*max_bytes), merged_byte_width)
663+ : merged_byte_width;
664+
665+ exprt::operandst sub_operands = instantiate_byte_array (
666+ merged_as_bytes, 0 , max_bytes_int, bits_per_byte, ns);
612667 byte_operands.insert (
613668 byte_operands.end (), sub_operands.begin (), sub_operands.end ());
614-
615- if (max_bytes && byte_operands.size () >= *max_bytes)
616- break ;
617669 }
618670
619671 const std::size_t size = byte_operands.size ();
@@ -1060,17 +1112,55 @@ static exprt lower_byte_extract_array_vector(
10601112 operands.reserve (*num_elements);
10611113 for (std::size_t i = 0 ; i < *num_elements; ++i)
10621114 {
1063- plus_exprt new_offset (
1064- unpacked.offset (),
1065- from_integer (
1066- i * element_bits / src.get_bits_per_byte (),
1067- unpacked.offset ().type ()));
1115+ if (element_bits % src.get_bits_per_byte () == 0 )
1116+ {
1117+ plus_exprt new_offset (
1118+ unpacked.offset (),
1119+ from_integer (
1120+ i * element_bits / src.get_bits_per_byte (),
1121+ unpacked.offset ().type ()));
10681122
1069- byte_extract_exprt tmp (unpacked);
1070- tmp.type () = subtype;
1071- tmp.offset () = new_offset;
1123+ byte_extract_exprt tmp (unpacked);
1124+ tmp.type () = subtype;
1125+ tmp.offset () = new_offset;
10721126
1073- operands.push_back (lower_byte_extract (tmp, ns));
1127+ operands.push_back (lower_byte_extract (tmp, ns));
1128+ }
1129+ else
1130+ {
1131+ const mp_integer first_index =
1132+ i * element_bits / src.get_bits_per_byte ();
1133+ const mp_integer last_index =
1134+ ((i + 1 ) * element_bits + src.get_bits_per_byte () - 1 ) /
1135+ src.get_bits_per_byte ();
1136+
1137+ exprt::operandst to_concat;
1138+ to_concat.reserve (
1139+ numeric_cast_v<std::size_t >(last_index - first_index));
1140+ for (mp_integer j = first_index; j < last_index; ++j)
1141+ {
1142+ to_concat.push_back (index_exprt{
1143+ unpacked.op (),
1144+ plus_exprt{
1145+ unpacked.offset (), from_integer (j, unpacked.offset ().type ())}});
1146+ }
1147+
1148+ const std::size_t base = numeric_cast_v<std::size_t >(
1149+ (i * element_bits) % src.get_bits_per_byte ());
1150+ const std::size_t last =
1151+ numeric_cast_v<std::size_t >(base + element_bits - 1 );
1152+ bv_typet concat_type{src.get_bits_per_byte () * to_concat.size ()};
1153+ endianness_mapt endianness_map (
1154+ concat_type, src.id () == ID_byte_extract_little_endian, ns);
1155+ const auto bounds = map_bounds (endianness_map, base, last);
1156+ extractbits_exprt element{
1157+ concatenation_exprt{to_concat, std::move (concat_type)},
1158+ from_integer (bounds.ub , size_type ()),
1159+ from_integer (bounds.lb , size_type ()),
1160+ subtype};
1161+
1162+ operands.push_back (element);
1163+ }
10741164 }
10751165
10761166 exprt result;
@@ -1094,6 +1184,10 @@ static exprt lower_byte_extract_array_vector(
10941184 std::to_string (array_comprehension_index_counter),
10951185 c_index_type ()};
10961186
1187+ PRECONDITION_WITH_DIAGNOSTICS (
1188+ element_bits % src.get_bits_per_byte () == 0 ,
1189+ " byte extracting non-byte-aligned arrays requires constant size" );
1190+
10971191 plus_exprt new_offset{
10981192 unpacked.offset (),
10991193 typecast_exprt::conditional_cast (
@@ -1239,17 +1333,13 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
12391333 {
12401334 const typet &subtype = to_type_with_subtype (src.type ()).subtype ();
12411335
1242- // consider ways of dealing with arrays of unknown subtype size or with a
1243- // subtype size that does not fit byte boundaries; currently we fall back to
1244- // stitching together consecutive elements down below
12451336 auto element_bits = pointer_offset_bits (subtype, ns);
1246- if (
1247- element_bits.has_value () && *element_bits >= 1 &&
1248- *element_bits % src.get_bits_per_byte () == 0 )
1249- {
1250- return lower_byte_extract_array_vector (
1251- src, unpacked, subtype, *element_bits, ns);
1252- }
1337+ PRECONDITION_WITH_DIAGNOSTICS (
1338+ element_bits.has_value () && *element_bits >= 1 ,
1339+ " byte extracting arrays of unknown/zero subtype is not yet implemented" );
1340+
1341+ return lower_byte_extract_array_vector (
1342+ src, unpacked, subtype, *element_bits, ns);
12531343 }
12541344 else if (src.type ().id () == ID_complex)
12551345 {
0 commit comments