Skip to content

Commit 96c593f

Browse files
committed
More constant propagation
1) Within goto-symex, propagation of nondet_symbol_exprt is actually safe, as they are instantiations of side_effect_expr_nondett and the value of these instantiations cannot change. 2) This highlights that we also need to consider further expressions as possibly being constant in is_constantt which we would otherwise simplify away when they are constant (but cannot any longer do so when nondet_symbol_exprt are contained in there). 3) Constant propagation now yields different right-hand sides in a test, and makes another test trivial. 4) goto-symex applies filters on what is considered "constant" to keep the size of expressions contained as (repeated) simplification of large expressions is expensive. We may revisit this in future as we improve the simplifier.
1 parent 8c3dac0 commit 96c593f

File tree

6 files changed

+56
-5
lines changed

6 files changed

+56
-5
lines changed

jbmc/regression/jbmc-strings/ClassName/test.desc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,3 @@ test.class
44
^EXIT=0$
55
^SIGNAL=0$
66
^VERIFICATION SUCCESSFUL$
7-
\[java::test\.main:\(\)V\.assertion\.1\] line 5 assertion at file test\.java line 5 function java::test\.main:\(\)V bytecode-index 8: SUCCESS$
8-
\[java::test\.main:\(\)V\.assertion\.2\] line 6 assertion at file test\.java line 6 function java::test\.main:\(\)V bytecode-index 19: SUCCESS$

jbmc/regression/jbmc-strings/long_string/test_abort.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Test.class
33
--function Test.checkAbort --trace
44
^EXIT=10$
55
^SIGNAL=0$
6-
dynamic_object[0-9]*=\(assignment removed\)
6+
dynamic_object[0-9]*=.*\?.*
77
--
88
--
99
This tests that the object does not appear in the trace, because concretizing
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
typedef struct _pair
2+
{
3+
int x;
4+
int y;
5+
} pair;
6+
7+
int __VERIFIER_nondet_int();
8+
9+
int main(void)
10+
{
11+
pair p1 = {.x = 0, .y = __VERIFIER_nondet_int()};
12+
pair p2 = {};
13+
p2.x = __VERIFIER_nondet_int();
14+
15+
__CPROVER_assert(p1.x == p2.y, "true by constant propagation");
16+
17+
return 0;
18+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
^Generated 1 VCC\(s\), 0 remaining after simplification$
8+
--
9+
^warning: ignoring

src/goto-symex/goto_symex_state.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,26 @@ class goto_symex_is_constantt : public is_constantt
157157
*/
158158
return false;
159159
}
160+
else if(expr.id() == ID_if)
161+
{
162+
// don't treat nested if_exprt as constant (even when they are!) as this
163+
// may give rise to large expressions that we repeatedly pass to the
164+
// simplifier; this is observable on regression/cbmc-library/memmove-01
165+
const if_exprt &if_expr = to_if_expr(expr);
166+
if(
167+
if_expr.true_case().id() == ID_if || if_expr.false_case().id() == ID_if)
168+
{
169+
return false;
170+
}
171+
}
172+
else if(expr.id() == ID_nondet_symbol)
173+
return true;
174+
else if(expr.id() == ID_symbol)
175+
{
176+
// we only ever assign to a single guard once, we can treat it as constant
177+
return to_ssa_expr(expr).get_object_name() ==
178+
goto_symex_statet::guard_identifier();
179+
}
160180

161181
return is_constantt::is_constant(expr);
162182
}

src/util/expr_util.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,9 @@ bool is_constantt::is_constant(const exprt &expr) const
241241
expr.id() == ID_with || expr.id() == ID_struct || expr.id() == ID_union ||
242242
// byte_update works, byte_extract may be out-of-bounds
243243
expr.id() == ID_byte_update_big_endian ||
244-
expr.id() == ID_byte_update_little_endian)
244+
expr.id() == ID_byte_update_little_endian ||
245+
// member works, index may be out-of-bounds
246+
expr.id() == ID_member || expr.id() == ID_if)
245247
{
246248
return std::all_of(
247249
expr.operands().begin(), expr.operands().end(), [this](const exprt &e) {
@@ -276,8 +278,12 @@ bool is_constantt::is_constant_address_of(const exprt &expr) const
276278

277279
return is_constant(deref.pointer());
278280
}
279-
else if(expr.id() == ID_string_constant)
281+
else if(
282+
expr.id() == ID_string_constant || expr.id() == ID_array ||
283+
expr.id() == ID_struct || expr.id() == ID_union)
284+
{
280285
return true;
286+
}
281287

282288
return false;
283289
}

0 commit comments

Comments
 (0)