@@ -436,11 +436,12 @@ void arrayst::add_array_constraints(
436
436
return add_array_constraints_if (index_set, to_if_expr (expr));
437
437
else if (expr.id ()==ID_array_of)
438
438
return add_array_constraints_array_of (index_set, to_array_of_expr (expr));
439
+ else if (expr.id () == ID_array)
440
+ return add_array_constraints_array_constant (index_set, to_array_expr (expr));
439
441
else if (expr.id ()==ID_symbol ||
440
442
expr.id ()==ID_nondet_symbol ||
441
443
expr.id ()==ID_constant ||
442
444
expr.id ()==" zero_string" ||
443
- expr.id ()==ID_array ||
444
445
expr.id ()==ID_string_constant)
445
446
{
446
447
}
@@ -647,6 +648,85 @@ void arrayst::add_array_constraints_array_of(
647
648
}
648
649
}
649
650
651
+ void arrayst::add_array_constraints_array_constant (
652
+ const index_sett &index_set,
653
+ const array_exprt &expr)
654
+ {
655
+ // we got x = { v, ... } - add constraint x[i] = v
656
+ const exprt::operandst &operands = expr.operands ();
657
+
658
+ for (const auto &index : index_set)
659
+ {
660
+ const typet &subtype = expr.type ().subtype ();
661
+ const index_exprt index_expr{expr, index, subtype};
662
+
663
+ if (index.is_constant ())
664
+ {
665
+ // We have a constant index - just pick the element at that index from the
666
+ // array constant.
667
+
668
+ const std::size_t i =
669
+ numeric_cast_v<std::size_t >(to_constant_expr (index));
670
+ // if the access is out of bounds, we leave it unconstrained
671
+ if (i >= operands.size ())
672
+ continue ;
673
+
674
+ const exprt v = operands[i];
675
+ DATA_INVARIANT (
676
+ index_expr.type () == v.type (),
677
+ " array operand type should match array element type" );
678
+
679
+ // add constraint
680
+ lazy_constraintt lazy{lazy_typet::ARRAY_CONSTANT,
681
+ equal_exprt{index_expr, v}};
682
+ add_array_constraint (lazy, false ); // added immediately
683
+ }
684
+ else
685
+ {
686
+ // We have a non-constant index into an array constant. We need to build a
687
+ // case statement testing the index against all possible values. Whenever
688
+ // neighbouring array elements are the same, we can test the index against
689
+ // the range rather than individual elements. This should be particularly
690
+ // helpful when we have arrays of zeros, as is the case for initializers.
691
+
692
+ std::vector<std::pair<std::size_t , std::size_t >> ranges;
693
+
694
+ for (std::size_t i = 0 ; i < operands.size (); ++i)
695
+ {
696
+ if (ranges.empty () || operands[i] != operands[ranges.back ().first ])
697
+ ranges.emplace_back (i, i);
698
+ else
699
+ ranges.back ().second = i;
700
+ }
701
+
702
+ for (const auto &range : ranges)
703
+ {
704
+ exprt index_constraint;
705
+
706
+ if (range.first == range.second )
707
+ {
708
+ index_constraint =
709
+ equal_exprt{index, from_integer (range.first , index.type ())};
710
+ }
711
+ else
712
+ {
713
+ index_constraint = and_exprt{
714
+ binary_predicate_exprt{
715
+ from_integer (range.first , index.type ()), ID_le, index},
716
+ binary_predicate_exprt{
717
+ index, ID_le, from_integer (range.second , index.type ())}};
718
+ }
719
+
720
+ lazy_constraintt lazy{
721
+ lazy_typet::ARRAY_CONSTANT,
722
+ implies_exprt{index_constraint,
723
+ equal_exprt{index_expr, operands[range.first ]}}};
724
+ add_array_constraint (lazy, true ); // added lazily
725
+ }
726
+ }
727
+ }
728
+ }
729
+
650
730
void arrayst::add_array_constraints_if (
651
731
const index_sett &index_set,
652
732
const if_exprt &expr)
0 commit comments