13
13
#include < util/arith_tools.h>
14
14
#include < util/std_expr.h>
15
15
#include < util/simplify_expr.h>
16
+ #include < algorithm>
17
+
18
+ // / \param array: an array expression
19
+ // / \return true if all elements are equal
20
+ static bool is_uniform (const exprt &array)
21
+ {
22
+ if (array.id () == ID_array_of)
23
+ return true ;
24
+ if (array.id () == ID_constant || array.id () == ID_array)
25
+ {
26
+ return std::all_of (
27
+ array.operands ().begin (),
28
+ array.operands ().end (),
29
+ [&](const exprt &expr) { // NOLINT
30
+ return expr == array.op0 ();
31
+ });
32
+ }
33
+ return false ;
34
+ }
16
35
17
36
bvt boolbvt::convert_index (const index_exprt &expr)
18
37
{
19
38
DATA_INVARIANT (expr.operands ().size () == 2 , " index takes two operands" );
20
39
const exprt &array=expr.array ();
21
40
const exprt &index =expr.index ();
22
-
23
41
const typet &array_op_type=ns.follow (array.type ());
24
-
25
42
bvt bv;
26
43
27
44
if (array_op_type.id ()==ID_array)
28
45
{
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 ());
33
48
34
49
if (width==0 )
35
50
return conversion_failed (expr);
36
51
37
52
// see if the array size is constant
38
-
39
53
if (is_unbounded_array (array_type))
40
54
{
41
55
// use array decision procedure
42
56
43
57
// free variables
44
-
45
58
bv.resize (width);
46
59
for (std::size_t i=0 ; i<width; i++)
47
60
bv[i]=prop.new_variable ();
48
61
49
62
record_array_index (expr);
50
63
51
64
// record type if array is a symbol
52
-
53
65
if (array.id ()==ID_symbol)
54
66
map.get_map_entry (
55
67
to_symbol_expr (array).get_identifier (), array_type);
56
68
57
69
// make sure we have the index in the cache
58
70
convert_bv (index );
59
-
60
71
return bv;
61
72
}
62
73
63
74
// 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 ());
67
76
68
77
// see if the index address is constant
69
78
// many of these are compacted by simplify_expr
70
79
// 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);
74
82
75
83
// Special case : arrays of one thing (useful for constants)
76
84
// TODO : merge with ACTUAL_ARRAY_HACK so that ranges of the same
77
85
// value, bit-patterns with the same value, etc. are treated like
78
86
// this rather than as a series of individual options.
79
87
#define UNIFORM_ARRAY_HACK
80
88
#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 ())
104
90
{
105
91
static int uniform_array_counter; // Temporary hack
106
92
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++);
110
95
111
- symbol_exprt result (identifier, expr.type ());
96
+ const symbol_exprt result (identifier, expr.type ());
112
97
bv = convert_bv (result);
113
98
114
- equal_exprt value_equality (result, array.op0 ());
99
+ const equal_exprt value_equality (result, array.op0 ());
115
100
116
- binary_relation_exprt lower_bound (
101
+ const binary_relation_exprt lower_bound (
117
102
from_integer (0 , index .type ()), ID_le, index );
118
- binary_relation_exprt upper_bound (
103
+ const binary_relation_exprt upper_bound (
119
104
index , ID_lt, from_integer (array_size, index .type ()));
120
105
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);
127
108
128
109
// Simplify may remove the lower bound if the type
129
110
// is correct.
@@ -147,77 +128,53 @@ bvt boolbvt::convert_index(const index_exprt &expr)
147
128
// Symbol for output
148
129
static int actual_array_counter; // Temporary hack
149
130
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++);
153
133
154
- symbol_exprt result (identifier, expr.type ());
134
+ const symbol_exprt result (identifier, expr.type ());
155
135
bv = convert_bv (result);
156
136
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" );
164
140
165
141
#ifdef COMPACT_EQUAL_CONST
166
142
bv_utils.equal_const_register (convert_bv (index )); // Definitely
167
143
bv_utils.equal_const_register (convert_bv (result)); // Maybe
168
144
#endif
169
145
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)
173
147
{
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)));
186
152
}
187
153
188
154
return bv;
189
155
}
190
156
191
157
#endif
192
158
193
-
194
159
// TODO : As with constant index, there is a trade-off
195
160
// of when it is best to flatten the whole array and
196
161
// when it is best to use the array theory and then use
197
162
// one or more of the above encoding strategies.
198
163
199
164
// get literals for the whole array
200
-
201
165
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 ());
205
167
206
168
// TODO: maybe a shifter-like construction would be better
207
169
// Would be a lot more compact but propagate worse
208
170
209
171
if (prop.has_set_to ())
210
172
{
211
173
// free variables
212
-
213
174
bv.resize (width);
214
175
for (std::size_t i=0 ; i<width; i++)
215
176
bv[i]=prop.new_variable ();
216
177
217
- // add implications
218
-
219
- equal_exprt index_equality;
220
- index_equality.lhs ()=index ; // index operand
221
178
222
179
#ifdef COMPACT_EQUAL_CONST
223
180
bv_utils.equal_const_register (convert_bv (index )); // Definitely
@@ -228,16 +185,12 @@ bvt boolbvt::convert_index(const index_exprt &expr)
228
185
229
186
for (mp_integer i=0 ; i<array_size; i=i+1 )
230
187
{
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 ()));
236
189
mp_integer offset=i*width;
237
190
238
191
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)]);
241
194
242
195
prop.l_set_to_true (
243
196
prop.limplies (convert (index_equality), prop.land (equal_bv)));
@@ -246,34 +199,23 @@ bvt boolbvt::convert_index(const index_exprt &expr)
246
199
else
247
200
{
248
201
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" );
252
204
253
205
#ifdef COMPACT_EQUAL_CONST
254
206
bv_utils.equal_const_register (convert_bv (index )); // Definitely
255
207
#endif
256
208
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)
262
210
{
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)
270
215
{
271
216
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]);
277
219
}
278
220
}
279
221
}
@@ -289,14 +231,10 @@ bvt boolbvt::convert_index(
289
231
const exprt &array,
290
232
const mp_integer &index)
291
233
{
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 ());
297
236
if (width==0 )
298
237
return conversion_failed (array);
299
-
300
238
bvt bv;
301
239
bv.resize (width);
302
240
@@ -309,28 +247,22 @@ bvt boolbvt::convert_index(
309
247
// the array (constant and variable indexes) and updated
310
248
// versions of it.
311
249
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)
318
255
{
319
- // in bounds
320
-
321
256
// The assertion below is disabled as we want to be able
322
257
// to run CBMC without simplifier.
323
258
// Expression simplification should remove these cases
324
- // assert(array.id()!=ID_array_of &&
325
- // array.id()!=ID_array);
326
259
// If not there are large improvements possible as above
327
260
328
261
for (std::size_t i=0 ; i<width; i++)
329
262
bv[i]=tmp[integer2size_t (offset+i)];
330
263
}
331
264
else
332
265
{
333
- // out of bounds
334
266
for (std::size_t i=0 ; i<width; i++)
335
267
bv[i]=prop.new_variable ();
336
268
}
0 commit comments