88
99#include " boolbv.h"
1010
11+ #include < algorithm>
1112#include < cassert>
1213
1314#include < util/arith_tools.h>
1415#include < util/pointer_offset_size.h>
1516#include < util/simplify_expr.h>
1617#include < util/std_expr.h>
1718
19+ // / \param array: an array expression
20+ // / \return true if all elements are equal
21+ static bool is_uniform (const exprt &array)
22+ {
23+ if (array.id () == ID_array_of)
24+ return true ;
25+ if (array.id () == ID_constant || array.id () == ID_array)
26+ {
27+ return std::all_of (
28+ array.operands ().begin (),
29+ array.operands ().end (),
30+ [&](const exprt &expr) { // NOLINT
31+ return expr == array.op0 ();
32+ });
33+ }
34+ return false ;
35+ }
36+
1837bvt boolbvt::convert_index (const index_exprt &expr)
1938{
2039 const exprt &array=expr.array ();
2140 const exprt &index=expr.index ();
22-
2341 const typet &array_op_type=ns.follow (array.type ());
24-
2542 bvt bv;
2643
2744 if (array_op_type.id ()==ID_array)
2845 {
29- const array_typet &array_type=
30- to_array_type (array_op_type);
31-
32- std::size_t width=boolbv_width (expr.type ());
46+ const array_typet &array_type = to_array_type (array_op_type);
47+ const std::size_t width = boolbv_width (expr.type ());
3348
3449 if (width==0 )
3550 return conversion_failed (expr);
3651
3752 // see if the array size is constant
38-
3953 if (is_unbounded_array (array_type))
4054 {
4155 // use array decision procedure
4256
4357 // free variables
44-
4558 bv.resize (width);
4659 for (std::size_t i=0 ; i<width; i++)
4760 bv[i]=prop.new_variable ();
4861
4962 record_array_index (expr);
5063
5164 // record type if array is a symbol
52-
5365 if (array.id ()==ID_symbol)
5466 map.get_map_entry (
5567 to_symbol_expr (array).get_identifier (), array_type);
5668
5769 // make sure we have the index in the cache
5870 convert_bv (index);
59-
6071 return bv;
6172 }
6273
6374 // Must have a finite size
64- mp_integer array_size;
65- if (to_integer (array_type.size (), array_size))
66- throw " failed to convert array size" ;
75+ const auto array_size = numeric_cast_v<mp_integer>(array_type.size ());
6776
6877 // see if the index address is constant
6978 // many of these are compacted by simplify_expr
7079 // but variable location writes will block this
71- mp_integer index_value;
72- if (!to_integer (index, index_value))
73- return convert_index (array, index_value);
80+ if (const auto index_value = numeric_cast<mp_integer>(index))
81+ return convert_index (array, *index_value);
7482
7583 // Special case : arrays of one thing (useful for constants)
7684 // TODO : merge with ACTUAL_ARRAY_HACK so that ranges of the same
7785 // value, bit-patterns with the same value, etc. are treated like
7886 // this rather than as a series of individual options.
7987 #define UNIFORM_ARRAY_HACK
8088 #ifdef UNIFORM_ARRAY_HACK
81- bool is_uniform = false ;
82-
83- if (array.id ()==ID_array_of)
84- {
85- is_uniform = true ;
86- }
87- else if (array.id ()==ID_constant || array.id ()==ID_array)
88- {
89- bool found_exception = false ;
90- forall_expr (it, array.operands ())
91- {
92- if (*it != array.op0 ())
93- {
94- found_exception = true ;
95- break ;
96- }
97- }
98-
99- if (!found_exception)
100- is_uniform = true ;
101- }
102-
103- if (is_uniform && prop.has_set_to ())
89+ if (is_uniform (array) && prop.has_set_to ())
10490 {
10591 static int uniform_array_counter; // Temporary hack
10692
107- std::string identifier=
108- " __CPROVER_internal_uniform_array_" +
109- std::to_string (uniform_array_counter++);
93+ const std::string identifier = " __CPROVER_internal_uniform_array_" +
94+ std::to_string (uniform_array_counter++);
11095
111- symbol_exprt result (identifier, expr.type ());
96+ const symbol_exprt result (identifier, expr.type ());
11297 bv = convert_bv (result);
11398
114- equal_exprt value_equality (result, array.op0 ());
99+ const equal_exprt value_equality (result, array.op0 ());
115100
116- binary_relation_exprt lower_bound (
101+ const binary_relation_exprt lower_bound (
117102 from_integer (0 , index.type ()), ID_le, index);
118- binary_relation_exprt upper_bound (
103+ const binary_relation_exprt upper_bound (
119104 index, ID_lt, from_integer (array_size, index.type ()));
120105
121- if (lower_bound.lhs ().is_nil () ||
122- upper_bound.rhs ().is_nil ())
123- throw " number conversion failed (2)" ;
124-
125- and_exprt range_condition (lower_bound, upper_bound);
126- implies_exprt implication (range_condition, value_equality);
106+ const and_exprt range_condition (lower_bound, upper_bound);
107+ const implies_exprt implication (range_condition, value_equality);
127108
128109 // Simplify may remove the lower bound if the type
129110 // is correct.
@@ -147,77 +128,53 @@ bvt boolbvt::convert_index(const index_exprt &expr)
147128 // Symbol for output
148129 static int actual_array_counter; // Temporary hack
149130
150- std::string identifier=
151- " __CPROVER_internal_actual_array_" +
152- std::to_string (actual_array_counter++);
131+ const std::string identifier = " __CPROVER_internal_actual_array_" +
132+ std::to_string (actual_array_counter++);
153133
154- symbol_exprt result (identifier, expr.type ());
134+ const symbol_exprt result (identifier, expr.type ());
155135 bv = convert_bv (result);
156136
157- // add implications
158-
159- equal_exprt index_equality;
160- index_equality.lhs ()=index; // index operand
161-
162- equal_exprt value_equality;
163- value_equality.lhs ()=result;
137+ INVARIANT (
138+ array_size <= array.operands ().size (),
139+ " size should not exceed number of operands" );
164140
165141#ifdef COMPACT_EQUAL_CONST
166142 bv_utils.equal_const_register (convert_bv (index)); // Definitely
167143 bv_utils.equal_const_register (convert_bv (result)); // Maybe
168144#endif
169145
170- exprt::operandst::const_iterator it = array.operands ().begin ();
171-
172- for (mp_integer i=0 ; i<array_size; i=i+1 )
146+ for (std::size_t i = 0 ; i < array_size; ++i)
173147 {
174- index_equality.rhs ()=from_integer (i, index_equality.lhs ().type ());
175-
176- if (index_equality.rhs ().is_nil ())
177- throw " number conversion failed (1)" ;
178-
179- assert (it != array.operands ().end ());
180-
181- value_equality.rhs ()=*it++;
182-
183- // Cache comparisons and equalities
184- prop.l_set_to_true (convert (implies_exprt (index_equality,
185- value_equality)));
148+ const equal_exprt index_equality (index, from_integer (i, index.type ()));
149+ const equal_exprt value_equality (result, array.operands ()[i]);
150+ prop.l_set_to_true (
151+ convert (implies_exprt (index_equality, value_equality)));
186152 }
187153
188154 return bv;
189155 }
190156
191157#endif
192158
193-
194159 // TODO : As with constant index, there is a trade-off
195160 // of when it is best to flatten the whole array and
196161 // when it is best to use the array theory and then use
197162 // one or more of the above encoding strategies.
198163
199164 // get literals for the whole array
200-
201165 const bvt &array_bv=convert_bv (array);
202-
203- if (array_size*width!=array_bv.size ())
204- throw " unexpected array size" ;
166+ CHECK_RETURN (array_size * width == array_bv.size ());
205167
206168 // TODO: maybe a shifter-like construction would be better
207169 // Would be a lot more compact but propagate worse
208170
209171 if (prop.has_set_to ())
210172 {
211173 // free variables
212-
213174 bv.resize (width);
214175 for (std::size_t i=0 ; i<width; i++)
215176 bv[i]=prop.new_variable ();
216177
217- // add implications
218-
219- equal_exprt index_equality;
220- index_equality.lhs ()=index; // index operand
221178
222179#ifdef COMPACT_EQUAL_CONST
223180 bv_utils.equal_const_register (convert_bv (index)); // Definitely
@@ -228,16 +185,12 @@ bvt boolbvt::convert_index(const index_exprt &expr)
228185
229186 for (mp_integer i=0 ; i<array_size; i=i+1 )
230187 {
231- index_equality.rhs ()=from_integer (i, index_equality.lhs ().type ());
232-
233- if (index_equality.rhs ().is_nil ())
234- throw " number conversion failed (1)" ;
235-
188+ const equal_exprt index_equality (index, from_integer (i, index.type ()));
236189 mp_integer offset=i*width;
237190
238191 for (std::size_t j=0 ; j<width; j++)
239- equal_bv[j]=prop. lequal (bv[j],
240- array_bv[integer2size_t (offset+ j)]);
192+ equal_bv[j] =
193+ prop. lequal (bv[j], array_bv[integer2size_t (offset + j)]);
241194
242195 prop.l_set_to_true (
243196 prop.limplies (convert (index_equality), prop.land (equal_bv)));
@@ -246,34 +199,23 @@ bvt boolbvt::convert_index(const index_exprt &expr)
246199 else
247200 {
248201 bv.resize (width);
249-
250- equal_exprt equality;
251- equality.lhs ()=index; // index operand
202+ const typet index_type = index.type ();
203+ INVARIANT (array_size > 0 , " array size should be positive" );
252204
253205#ifdef COMPACT_EQUAL_CONST
254206 bv_utils.equal_const_register (convert_bv (index)); // Definitely
255207#endif
256208
257- typet constant_type=index.type (); // type of index operand
258-
259- assert (array_size>0 );
260-
261- for (mp_integer i=0 ; i<array_size; i=i+1 )
209+ for (mp_integer i = 0 ; i < array_size; ++i)
262210 {
263- equality.op1 ()=from_integer (i, constant_type);
264-
265- literalt e=convert (equality);
266-
267- mp_integer offset=i*width;
268-
269- for (std::size_t j=0 ; j<width; j++)
211+ const equal_exprt equality (index, from_integer (i, index_type));
212+ const literalt e = convert (equality);
213+ const mp_integer offset = i * width;
214+ for (std::size_t j = 0 ; j < width; ++j)
270215 {
271216 literalt l=array_bv[integer2size_t (offset+j)];
272-
273- if (i==0 ) // this initializes bv
274- bv[j]=l;
275- else
276- bv[j]=prop.lselect (e, l, bv[j]);
217+ // for 0 only initializes bv
218+ bv[j] = i == 0 ? l : prop.lselect (e, l, bv[j]);
277219 }
278220 }
279221 }
@@ -289,14 +231,10 @@ bvt boolbvt::convert_index(
289231 const exprt &array,
290232 const mp_integer &index)
291233{
292- const array_typet &array_type=
293- to_array_type (ns.follow (array.type ()));
294-
295- std::size_t width=boolbv_width (array_type.subtype ());
296-
234+ const array_typet &array_type = to_array_type (ns.follow (array.type ()));
235+ const std::size_t width = boolbv_width (array_type.subtype ());
297236 if (width==0 )
298237 return conversion_failed (array);
299-
300238 bvt bv;
301239 bv.resize (width);
302240
@@ -309,20 +247,15 @@ bvt boolbvt::convert_index(
309247 // the array (constant and variable indexes) and updated
310248 // versions of it.
311249
312- const bvt &tmp=convert_bv (array); // recursive call
313-
314- mp_integer offset=index*width;
315-
316- if (offset>=0 &&
317- offset+width<=mp_integer (tmp.size ()))
250+ const bvt &tmp = convert_bv (array);
251+ const mp_integer offset = index * width;
252+ const bool in_bounds =
253+ offset >= 0 && offset + width <= mp_integer (tmp.size ());
254+ if (in_bounds)
318255 {
319- // in bounds
320-
321256 // The assertion below is disabled as we want to be able
322257 // to run CBMC without simplifier.
323258 // Expression simplification should remove these cases
324- // assert(array.id()!=ID_array_of &&
325- // array.id()!=ID_array);
326259 // If not there are large improvements possible as above
327260
328261 for (std::size_t i=0 ; i<width; i++)
@@ -339,19 +272,18 @@ bvt boolbvt::convert_index(
339272
340273 const mp_integer subtype_bytes =
341274 pointer_offset_size (array_type.subtype (), ns);
342- exprt new_offset = simplify_expr (
275+ const exprt new_offset = simplify_expr (
343276 plus_exprt (
344277 o.offset (), from_integer (index * subtype_bytes, o.offset ().type ())),
345278 ns);
346279
347- byte_extract_exprt be (
280+ const byte_extract_exprt be (
348281 byte_extract_id (), o.root_object (), new_offset, array_type.subtype ());
349282
350283 return convert_bv (be);
351284 }
352285 else
353286 {
354- // out of bounds
355287 for (std::size_t i=0 ; i<width; i++)
356288 bv[i]=prop.new_variable ();
357289 }
0 commit comments