Skip to content

Commit 0ec5018

Browse files
author
Enrico Steffinlongo
committed
Add simplify_expr step to duplicate_per_byte
The function `duplicate_per_byte` contains a more efficient implementation when `init_expr` is a constant. However this feature is never used as the shadow memory module almost always wraps `init_expr` with a typecast to the type of the shadow memory. This commit applies a simplification step in `duplicate_per_byte`, calling `simplify_expr`, so that the casts may be removed and the more efficient implementation will be used.
1 parent f2fd9c6 commit 0ec5018

File tree

3 files changed

+68
-41
lines changed

3 files changed

+68
-41
lines changed

src/util/expr_initializer.cpp

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Author: Daniel Kroening, [email protected]
1818
#include "config.h"
1919
#include "magic.h"
2020
#include "namespace.h" // IWYU pragma: keep
21+
#include "simplify_expr.h"
2122
#include "std_code.h"
2223
#include "symbol_table.h"
2324

@@ -68,7 +69,7 @@ optionalt<exprt> expr_initializert::expr_initializer_rec(
6869
else if(init_expr.is_zero())
6970
result = from_integer(0, type);
7071
else
71-
result = duplicate_per_byte(init_expr, type);
72+
result = duplicate_per_byte(init_expr, type, ns);
7273

7374
result.add_source_location()=source_location;
7475
return result;
@@ -82,7 +83,7 @@ optionalt<exprt> expr_initializert::expr_initializer_rec(
8283
else if(init_expr.is_zero())
8384
result = constant_exprt(ID_0, type);
8485
else
85-
result = duplicate_per_byte(init_expr, type);
86+
result = duplicate_per_byte(init_expr, type, ns);
8687

8788
result.add_source_location()=source_location;
8889
return result;
@@ -101,7 +102,7 @@ optionalt<exprt> expr_initializert::expr_initializer_rec(
101102
result = constant_exprt(value, type);
102103
}
103104
else
104-
result = duplicate_per_byte(init_expr, type);
105+
result = duplicate_per_byte(init_expr, type, ns);
105106

106107
result.add_source_location()=source_location;
107108
return result;
@@ -121,7 +122,7 @@ optionalt<exprt> expr_initializert::expr_initializer_rec(
121122
result = complex_exprt(*sub_zero, *sub_zero, to_complex_type(type));
122123
}
123124
else
124-
result = duplicate_per_byte(init_expr, type);
125+
result = duplicate_per_byte(init_expr, type, ns);
125126

126127
result.add_source_location()=source_location;
127128
return result;
@@ -289,7 +290,7 @@ optionalt<exprt> expr_initializert::expr_initializer_rec(
289290
else if(init_expr.is_zero())
290291
result = constant_exprt(irep_idt(), type);
291292
else
292-
result = duplicate_per_byte(init_expr, type);
293+
result = duplicate_per_byte(init_expr, type, ns);
293294

294295
result.add_source_location()=source_location;
295296
return result;
@@ -373,10 +374,14 @@ static exprt cast_or_reinterpret(const exprt &expr, const typet &out_type)
373374
/// output type.
374375
/// \param init_byte_expr The initialization expression
375376
/// \param output_type The output type
377+
/// \param ns Namespace to perform type symbol/tag lookups
376378
/// \return The built expression
377379
/// \note `init_byte_expr` must be a boolean or a bitvector and must be of at
378380
/// most `size <= config.ansi_c.char_width`
379-
exprt duplicate_per_byte(const exprt &init_byte_expr, const typet &output_type)
381+
exprt duplicate_per_byte(
382+
const exprt &init_byte_expr,
383+
const typet &output_type,
384+
const namespacet &ns)
380385
{
381386
const auto init_type_as_bitvector =
382387
type_try_dynamic_cast<bitvector_typet>(init_byte_expr.type());
@@ -385,20 +390,25 @@ exprt duplicate_per_byte(const exprt &init_byte_expr, const typet &output_type)
385390
(init_type_as_bitvector &&
386391
init_type_as_bitvector->get_width() <= config.ansi_c.char_width) ||
387392
init_byte_expr.type().id() == ID_bool);
393+
// Simplify init_expr to enable faster duplication when simplifiable to a
394+
// constant expr
395+
const auto simplified_init_expr = simplify_expr(init_byte_expr, ns);
388396
if(const auto output_bv = type_try_dynamic_cast<bitvector_typet>(output_type))
389397
{
390398
const auto out_width = output_bv->get_width();
391-
// Replicate `init_byte_expr` enough times until it completely fills
399+
// Replicate `simplified_init_expr` enough times until it completely fills
392400
// `output_type`.
393401

394402
// We've got a constant. So, precompute the value of the constant.
395-
if(init_byte_expr.is_constant())
403+
if(simplified_init_expr.is_constant())
396404
{
397405
const auto init_size = init_type_as_bitvector->get_width();
398-
const irep_idt init_value = to_constant_expr(init_byte_expr).get_value();
406+
const irep_idt init_value =
407+
to_constant_expr(simplified_init_expr).get_value();
399408

400409
// Create a new BV of `output_type` size with its representation being the
401-
// replication of the init_byte_expr (padded with 0) enough times to fill.
410+
// replication of the simplified_init_expr (padded with 0) enough times to
411+
// fill.
402412
const auto output_value =
403413
make_bvrep(out_width, [&init_size, &init_value](std::size_t index) {
404414
// Index modded by 8 to access the i-th bit of init_value
@@ -427,7 +437,7 @@ exprt duplicate_per_byte(const exprt &init_byte_expr, const typet &output_type)
427437
{
428438
operation_type = unsignedbv_typet{float_type->get_width()};
429439
}
430-
// Let's cast init_byte_expr to output_type.
440+
// Let's cast simplified_init_expr to output_type.
431441
const exprt casted_init_byte_expr =
432442
typecast_exprt::conditional_cast(init_byte_expr, operation_type);
433443
values.push_back(casted_init_byte_expr);

src/util/expr_initializer.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ optionalt<exprt> expr_initializer(
3333
const namespacet &ns,
3434
const exprt &init_byte_expr);
3535

36-
exprt duplicate_per_byte(const exprt &init_byte_expr, const typet &output_type);
36+
exprt duplicate_per_byte(
37+
const exprt &init_byte_expr,
38+
const typet &output_type,
39+
const namespacet &ns);
3740

3841
#endif // CPROVER_UTIL_EXPR_INITIALIZER_H

unit/util/expr_initializer.cpp

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ TEST_CASE(
113113
const cbmc_invariants_should_throwt invariants_throw;
114114

115115
REQUIRE_THROWS_MATCHES(
116-
duplicate_per_byte(array_of_exprt{true_exprt{}, array_type}, input_type),
116+
duplicate_per_byte(
117+
array_of_exprt{true_exprt{}, array_type}, input_type, test.ns),
117118
invariant_failedt,
118119
invariant_failure_containing(
119120
"Condition: (init_type_as_bitvector && "
@@ -128,7 +129,8 @@ TEST_CASE(
128129
const cbmc_invariants_should_throwt invariants_throw;
129130

130131
REQUIRE_THROWS_MATCHES(
131-
duplicate_per_byte(from_integer(0, unsignedbv_typet{10}), input_type),
132+
duplicate_per_byte(
133+
from_integer(0, unsignedbv_typet{10}), input_type, test.ns),
132134
invariant_failedt,
133135
invariant_failure_containing(
134136
"init_type_as_bitvector->get_width() <= config.ansi_c.char_width"));
@@ -170,15 +172,17 @@ TEST_CASE(
170172
typet output_type = unsignedbv_typet{output_size};
171173
const auto result = duplicate_per_byte(
172174
from_integer(init_expr_value, unsignedbv_typet{init_expr_size}),
173-
output_type);
175+
output_type,
176+
test.ns);
174177
const auto expected =
175178
from_integer(output_expected_value, unsignedbv_typet{output_size});
176179
REQUIRE(result == expected);
177180

178181
// Check that signed-bv values are replicated including the sign bit.
179182
const auto result_with_signed_init_type = duplicate_per_byte(
180183
from_integer(init_expr_value, signedbv_typet{init_expr_size}),
181-
output_type);
184+
output_type,
185+
test.ns);
182186
REQUIRE(result_with_signed_init_type == result);
183187
}
184188

@@ -187,15 +191,17 @@ TEST_CASE(
187191
typet output_type = signedbv_typet{output_size};
188192
const auto result = duplicate_per_byte(
189193
from_integer(init_expr_value, unsignedbv_typet{init_expr_size}),
190-
output_type);
194+
output_type,
195+
test.ns);
191196
const auto expected =
192197
from_integer(output_expected_value, signedbv_typet{output_size});
193198
REQUIRE(result == expected);
194199

195200
// Check that signed-bv values are replicated including the sign bit.
196201
const auto result_with_signed_init_type = duplicate_per_byte(
197202
from_integer(init_expr_value, signedbv_typet{init_expr_size}),
198-
output_type);
203+
output_type,
204+
test.ns);
199205
REQUIRE(result_with_signed_init_type == result);
200206
}
201207

@@ -205,7 +211,8 @@ TEST_CASE(
205211
const pointer_typet output_type{bool_typet{}, output_size};
206212
const auto result = duplicate_per_byte(
207213
from_integer(init_expr_value, signedbv_typet{init_expr_size}),
208-
output_type);
214+
output_type,
215+
test.ns);
209216
auto expected =
210217
from_integer(output_expected_value, unsignedbv_typet{output_size});
211218
// Forcing the type to be pointer_typet otherwise from_integer fails when
@@ -219,11 +226,13 @@ TEST_CASE(
219226
// Check that replicating to a float_value is same as unsigned_bv.
220227
const auto result = duplicate_per_byte(
221228
from_integer(init_expr_value, unsignedbv_typet{init_expr_size}),
222-
float_type());
229+
float_type(),
230+
test.ns);
223231
const auto expected_unsigned_value =
224232
expr_try_dynamic_cast<constant_exprt>(duplicate_per_byte(
225233
from_integer(init_expr_value, unsignedbv_typet{init_expr_size}),
226-
unsignedbv_typet{float_type().get_width()}));
234+
unsignedbv_typet{float_type().get_width()},
235+
test.ns));
227236
REQUIRE(expected_unsigned_value);
228237
const auto expected =
229238
constant_exprt{expected_unsigned_value->get_value(), float_type()};
@@ -250,13 +259,13 @@ TEST_CASE(
250259
SECTION("Testing with init size " + std::to_string(init_expr_size))
251260
{
252261
const auto init_expr = plus_exprt{
253-
from_integer(1, unsignedbv_typet{init_expr_size}),
262+
symbol_exprt{"a_symbol", unsignedbv_typet{init_expr_size}},
254263
from_integer(2, unsignedbv_typet{init_expr_size})};
255264
SECTION("filling signedbv of size " + std::to_string(output_size))
256265
{
257266
typet output_type = signedbv_typet{output_size};
258267

259-
const auto result = duplicate_per_byte(init_expr, output_type);
268+
const auto result = duplicate_per_byte(init_expr, output_type, test.ns);
260269

261270
const auto casted_init_expr =
262271
typecast_exprt::conditional_cast(init_expr, output_type);
@@ -269,7 +278,7 @@ TEST_CASE(
269278
SECTION("filling unsignedbv of size " + std::to_string(output_size))
270279
{
271280
typet output_type = unsignedbv_typet{output_size};
272-
const auto result = duplicate_per_byte(init_expr, output_type);
281+
const auto result = duplicate_per_byte(init_expr, output_type, test.ns);
273282

274283
const auto casted_init_expr =
275284
typecast_exprt::conditional_cast(init_expr, output_type);
@@ -284,7 +293,7 @@ TEST_CASE(
284293
// Check that replicating a pointer_value is same as unsigned_bv modulo a
285294
// byte_extract outside.
286295
const pointer_typet output_type{bool_typet{}, output_size};
287-
const auto result = duplicate_per_byte(init_expr, output_type);
296+
const auto result = duplicate_per_byte(init_expr, output_type, test.ns);
288297
const auto unsigned_corr_type = unsignedbv_typet{output_size};
289298
const auto unsigned_init_expr =
290299
typecast_exprt::conditional_cast(init_expr, unsigned_corr_type);
@@ -306,7 +315,7 @@ TEST_CASE(
306315
const std::size_t float_replication_count =
307316
(float_type().get_width() + config.ansi_c.char_width - 1) /
308317
config.ansi_c.char_width;
309-
const auto result = duplicate_per_byte(init_expr, float_type());
318+
const auto result = duplicate_per_byte(init_expr, float_type(), test.ns);
310319
const auto unsigned_corr_type =
311320
unsignedbv_typet{float_type().get_width()};
312321
const auto unsigned_init_expr =
@@ -412,8 +421,8 @@ TEST_CASE(
412421
const auto result =
413422
expr_initializer(input_type, test.loc, test.ns, init_value);
414423
REQUIRE(result.has_value());
415-
const auto expected =
416-
duplicate_per_byte(init_value, unsignedbv_typet{input_type_size});
424+
const auto expected = duplicate_per_byte(
425+
init_value, unsignedbv_typet{input_type_size}, test.ns);
417426
REQUIRE(result.value() == expected);
418427
}
419428
}
@@ -460,7 +469,7 @@ TEST_CASE(
460469
expr_initializer(input_type, test.loc, test.ns, init_value);
461470
REQUIRE(result.has_value());
462471
const auto expected = duplicate_per_byte(
463-
init_value, pointer_typet{bool_typet{}, input_type_size});
472+
init_value, pointer_typet{bool_typet{}, input_type_size}, test.ns);
464473
REQUIRE(result.value() == expected);
465474
}
466475
}
@@ -499,7 +508,8 @@ TEST_CASE("expr_initializer on float type", "[core][util][expr_initializer]")
499508
const auto result =
500509
expr_initializer(input_type, test.loc, test.ns, init_value);
501510
REQUIRE(result.has_value());
502-
const auto expected = duplicate_per_byte(init_value, float_type());
511+
const auto expected =
512+
duplicate_per_byte(init_value, float_type(), test.ns);
503513
REQUIRE(result.value() == expected);
504514
}
505515
}
@@ -562,13 +572,13 @@ TEST_CASE(
562572
from_integer(0xAB, signedbv_typet{config.ansi_c.char_width});
563573
const auto result =
564574
expr_initializer(enum_type, test.loc, test.ns, init_value);
565-
const auto expected = duplicate_per_byte(init_value, enum_type);
575+
const auto expected = duplicate_per_byte(init_value, enum_type, test.ns);
566576
REQUIRE(result.has_value());
567577
REQUIRE(result.value() == expected);
568578

569579
const auto tag_result =
570580
expr_initializer(c_enum_tag_type, test.loc, test.ns, init_value);
571-
auto tag_expected = duplicate_per_byte(init_value, enum_type);
581+
auto tag_expected = duplicate_per_byte(init_value, enum_type, test.ns);
572582
tag_expected.type() = c_enum_tag_type;
573583
REQUIRE(tag_result.has_value());
574584
REQUIRE(tag_result.value() == tag_expected);
@@ -624,7 +634,7 @@ TEST_CASE(
624634
expr_initializer(array_type, test.loc, test.ns, init_value);
625635
REQUIRE(result.has_value());
626636
std::vector<exprt> array_values{
627-
elem_count, duplicate_per_byte(init_value, inner_type)};
637+
elem_count, duplicate_per_byte(init_value, inner_type, test.ns)};
628638
const auto expected = array_exprt{
629639
array_values,
630640
array_typet{
@@ -678,7 +688,7 @@ TEST_CASE(
678688
expr_initializer(array_type, test.loc, test.ns, init_value);
679689
REQUIRE(result.has_value());
680690
const auto expected = array_of_exprt{
681-
duplicate_per_byte(init_value, inner_type),
691+
duplicate_per_byte(init_value, inner_type, test.ns),
682692
array_typet{
683693
inner_type, side_effect_expr_nondett{signedbv_typet{8}, test.loc}}};
684694
REQUIRE(result.value() == expected);
@@ -750,7 +760,7 @@ TEST_CASE(
750760
expr_initializer(array_type, test.loc, test.ns, init_value);
751761
REQUIRE(result.has_value());
752762
std::vector<exprt> inner_array_values{
753-
elem_count, duplicate_per_byte(init_value, inner_type)};
763+
elem_count, duplicate_per_byte(init_value, inner_type, test.ns)};
754764
const auto inner_expected = array_exprt{
755765
inner_array_values,
756766
array_typet{
@@ -847,12 +857,13 @@ TEST_CASE(
847857
expr_initializer(struct_type, test.loc, test.ns, init_value);
848858
REQUIRE(result.has_value());
849859
const exprt::operandst expected_inner_struct_fields{
850-
duplicate_per_byte(init_value, signedbv_typet{32}),
851-
duplicate_per_byte(init_value, unsignedbv_typet{16})};
860+
duplicate_per_byte(init_value, signedbv_typet{32}, test.ns),
861+
duplicate_per_byte(init_value, unsignedbv_typet{16}, test.ns)};
852862
const struct_exprt expected_inner_struct_expr{
853863
expected_inner_struct_fields, inner_struct_type};
854864
const exprt::operandst expected_struct_fields{
855-
duplicate_per_byte(init_value, bool_typet{}), expected_inner_struct_expr};
865+
duplicate_per_byte(init_value, bool_typet{}, test.ns),
866+
expected_inner_struct_expr};
856867
const struct_exprt expected_struct_expr{
857868
expected_struct_fields, struct_type};
858869
REQUIRE(result.value() == expected_struct_expr);
@@ -935,7 +946,9 @@ TEST_CASE("expr_initializer on union type", "[core][util][expr_initializer]")
935946
expr_initializer(union_type, test.loc, test.ns, init_value);
936947
REQUIRE(result.has_value());
937948
const union_exprt expected_union{
938-
"foo", duplicate_per_byte(init_value, signedbv_typet{256}), union_type};
949+
"foo",
950+
duplicate_per_byte(init_value, signedbv_typet{256}, test.ns),
951+
union_type};
939952
REQUIRE(result.value() == expected_union);
940953

941954
const auto union_tag_type =
@@ -945,7 +958,7 @@ TEST_CASE("expr_initializer on union type", "[core][util][expr_initializer]")
945958
REQUIRE(tag_result.has_value());
946959
const union_exprt expected_union_tag{
947960
"foo",
948-
duplicate_per_byte(init_value, signedbv_typet{256}),
961+
duplicate_per_byte(init_value, signedbv_typet{256}, test.ns),
949962
union_tag_type};
950963
REQUIRE(tag_result.value() == expected_union_tag);
951964
}
@@ -1024,7 +1037,8 @@ TEST_CASE("expr_initializer on string type", "[core][util][expr_initializer]")
10241037
const auto result =
10251038
expr_initializer(string_type, test.loc, test.ns, init_value);
10261039
REQUIRE(result.has_value());
1027-
const auto expected_string = duplicate_per_byte(init_value, string_type);
1040+
const auto expected_string =
1041+
duplicate_per_byte(init_value, string_type, test.ns);
10281042
REQUIRE(result.value() == expected_string);
10291043
}
10301044
}

0 commit comments

Comments
 (0)