Skip to content

Commit 4092dff

Browse files
Refactoring in boolbvt::convert_index
Factor out is_uniform function to reduce size of big function and make it clearer. Add const keyword where possible. Change assertions in INVARIANTS. Remove blank lines that are not helping clarity (for example between comments and instructions to which they apply). Use numeric_cast instead of to_integer.
1 parent 9d386d3 commit 4092dff

File tree

1 file changed

+64
-132
lines changed

1 file changed

+64
-132
lines changed

src/solvers/flattening/boolbv_index.cpp

+64-132
Original file line numberDiff line numberDiff line change
@@ -13,117 +13,98 @@ Author: Daniel Kroening, [email protected]
1313
#include <util/arith_tools.h>
1414
#include <util/std_expr.h>
1515
#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+
}
1635

1736
bvt boolbvt::convert_index(const index_exprt &expr)
1837
{
1938
DATA_INVARIANT(expr.operands().size() == 2, "index takes two operands");
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,28 +247,22 @@ 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++)
329262
bv[i]=tmp[integer2size_t(offset+i)];
330263
}
331264
else
332265
{
333-
// out of bounds
334266
for(std::size_t i=0; i<width; i++)
335267
bv[i]=prop.new_variable();
336268
}

0 commit comments

Comments
 (0)