Skip to content

Commit 71feb01

Browse files
committed
goto-symex: apply_condition should not change L2 index
Updating the L2 index would result in additional phi assignments, which can result in more costly verification. One such example is that the use of `i != size` instead of `i < size` in loop conditions resulted increased verification time when we would expect not-equal to be cheaper than less-than.
1 parent fa1d719 commit 71feb01

File tree

11 files changed

+99
-36
lines changed

11 files changed

+99
-36
lines changed

regression/cbmc-cover/pointer-function-parameters/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ main.c
55
^Test suite:$
66
^(tmp(\$\d+)?=[^,]*, a=\(\(signed int \*\)NULL\))|(a=\(\(signed int \*\)NULL\), tmp(\$\d+)?=[^,]*)$
77
^(a=&tmp(\$\d+)?!0@1, tmp(\$\d+)?=4)|(tmp(\$\d+)?=4, a=&tmp(\$\d+)?!0@1)$
8-
^(a=&tmp(\$\d+)?!0@1, tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+))|(tmp(\$\d+)?=([012356789][0-9]*|4[0-9]+), a=&tmp(\$\d+)?!0@1)$
8+
^(a=&tmp(\$\d+)?!0@1, tmp(\$\d+)?=(-?[012356789][0-9]*|4[0-9]+))|(tmp(\$\d+)?=(-?[012356789][0-9]*|4[0-9]+), a=&tmp(\$\d+)?!0@1)$
99
^EXIT=0$
1010
^SIGNAL=0$
1111
--
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
int main()
2+
{
3+
int s;
4+
5+
int i = 0;
6+
if(i != s)
7+
++i;
8+
else
9+
__CPROVER_assert(s == 0, "constant propagate");
10+
11+
int s2 = s;
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE paths-lifo-expected-failure
2+
main.c
3+
--program-only
4+
s2!0@1#2 == s!0@1#1
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
ASSERT
9+
s2!0@1#[3-9]
10+
--
11+
The branch condition should yield constant propagation on s without introducing
12+
fresh assignments to s.

regression/validate-trace-xml-schema/check.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
['Quantifiers-simplify', 'simplify_not_forall.desc'],
3939
['array-cell-sensitivity15', 'test.desc'],
4040
['saturating_arithmetric', 'output-formula.desc'],
41+
['apply_condition2', 'test.desc'],
4142
# these test for invalid command line handling
4243
['bad_option', 'test_multiple.desc'],
4344
['bad_option', 'test.desc'],

src/goto-symex/goto_state.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,11 @@ void goto_statet::apply_condition(
107107
const ssa_exprt l1_lhs = remove_level_2(ssa_lhs);
108108
const irep_idt &l1_identifier = l1_lhs.get_identifier();
109109

110-
level2.increase_generation(
111-
l1_identifier, l1_lhs, previous_state.get_l2_name_provider());
112-
113-
const auto propagation_entry = propagation.find(l1_identifier);
110+
const auto propagation_entry = branch_propagation.find(l1_identifier);
114111
if(!propagation_entry.has_value())
115-
propagation.insert(l1_identifier, rhs);
112+
branch_propagation.insert(l1_identifier, rhs);
116113
else if(propagation_entry->get() != rhs)
117-
propagation.replace(l1_identifier, rhs);
114+
branch_propagation.replace(l1_identifier, rhs);
118115

119116
value_set.assign(l1_lhs, rhs, ns, true, false);
120117
}

src/goto-symex/goto_state.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ class goto_statet
6868
// "constants" can include symbols, but only in the context of an address-of
6969
// op (i.e. &x can be propagated), and an address-taken thing should only be
7070
// L1.
71-
sharing_mapt<irep_idt, exprt> propagation;
71+
//
72+
// Entries in branch_propagation are local to the current branch and will
73+
// never be merged back in phi nodes.
74+
sharing_mapt<irep_idt, exprt> propagation, branch_propagation;
7275

7376
void output_propagation_map(std::ostream &);
7477

src/goto-symex/goto_symex.cpp

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -372,15 +372,19 @@ goto_symext::try_evaluate_constant_string(
372372
return {};
373373
}
374374

375-
const auto s_pointer_opt =
376-
state.propagation.find(to_symbol_expr(content).get_identifier());
375+
const irep_idt &content_id = to_symbol_expr(content).get_identifier();
377376

378-
if(!s_pointer_opt)
379-
{
380-
return {};
381-
}
377+
const auto s_pointer_opt = state.propagation.find(content_id);
378+
379+
if(s_pointer_opt)
380+
return try_get_string_data_array(s_pointer_opt->get(), ns);
381+
382+
const auto b_entry = state.branch_propagation.find(content_id);
383+
384+
if(b_entry)
385+
return try_get_string_data_array(b_entry->get(), ns);
382386

383-
return try_get_string_data_array(s_pointer_opt->get(), ns);
387+
return {};
384388
}
385389

386390
optionalt<std::reference_wrapper<const constant_exprt>>
@@ -391,16 +395,25 @@ goto_symext::try_evaluate_constant(const statet &state, const exprt &expr)
391395
return {};
392396
}
393397

394-
const auto constant_expr_opt =
395-
state.propagation.find(to_symbol_expr(expr).get_identifier());
398+
const irep_idt &expr_id = to_symbol_expr(expr).get_identifier();
396399

397-
if(!constant_expr_opt || !constant_expr_opt->get().is_constant())
400+
const auto constant_expr_opt = state.propagation.find(expr_id);
401+
402+
if(constant_expr_opt && constant_expr_opt->get().is_constant())
398403
{
399-
return {};
404+
return optionalt<std::reference_wrapper<const constant_exprt>>(
405+
to_constant_expr(constant_expr_opt->get()));
406+
}
407+
408+
const auto b_entry = state.branch_propagation.find(expr_id);
409+
410+
if(b_entry && b_entry->get().id() == ID_constant)
411+
{
412+
return optionalt<std::reference_wrapper<const constant_exprt>>(
413+
to_constant_expr(b_entry->get()));
400414
}
401415

402-
return optionalt<std::reference_wrapper<const constant_exprt>>(
403-
to_constant_expr(constant_expr_opt->get()));
416+
return {};
404417
}
405418

406419
void goto_symext::constant_propagate_empty_string(

src/goto-symex/goto_symex_state.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ renamedt<ssa_exprt, L2> goto_symex_statet::assignment(
112112
"pointer handling for concurrency is unsound");
113113

114114
// Update constant propagation map -- the RHS is L2
115+
branch_propagation.erase_if_exists(l1_identifier);
115116
if(!is_shared && record_value && goto_symex_can_forward_propagatet(ns)(rhs))
116117
{
117118
const auto propagation_entry = propagation.find(l1_identifier);
@@ -214,14 +215,19 @@ goto_symex_statet::rename(exprt expr, const namespacet &ns)
214215
{
215216
// We also consider propagation if we go up to L2.
216217
// L1 identifiers are used for propagation!
217-
auto p_it = propagation.find(ssa.get_identifier());
218+
const auto &l1_identifier = ssa.get_identifier();
219+
auto p_it = propagation.find(l1_identifier);
218220

219221
if(p_it.has_value())
220222
{
221223
return renamedt<exprt, level>(*p_it); // already L2
222224
}
223225
else
224226
{
227+
auto b_entry = branch_propagation.find(l1_identifier);
228+
if(b_entry.has_value())
229+
return renamedt<exprt, level>(*b_entry);
230+
225231
if(level == L2)
226232
ssa = set_indices<L2>(std::move(ssa), ns).get();
227233
return renamedt<exprt, level>(std::move(ssa));
@@ -432,7 +438,7 @@ bool goto_symex_statet::l2_thread_read_encoding(
432438
// written this object within the atomic section. We must actually do this,
433439
// because goto_state::apply_condition may have placed the latest value in
434440
// the propagation map without recording an assignment.
435-
auto p_it = propagation.find(ssa_l1.get_identifier());
441+
auto p_it = branch_propagation.find(ssa_l1.get_identifier());
436442
const exprt l2_true_case =
437443
p_it.has_value() ? *p_it : set_indices<L2>(ssa_l1, ns).get();
438444

src/goto-symex/symex_dead.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ static void remove_l1_object_rec(
4141
state.value_set.values.erase_if_exists(l1_identifier);
4242
}
4343
state.propagation.erase_if_exists(l1_identifier);
44+
state.branch_propagation.erase_if_exists(l1_identifier);
4445
// Remove from the local L2 renaming map; this means any reads from the dead
4546
// identifier will use generation 0 (e.g. x!N@M#0, where N and M are
4647
// positive integers), which is never defined by any write, and will be

src/goto-symex/symex_goto.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,13 @@ static void merge_names(
799799
if(p_it.has_value())
800800
goto_state_rhs = *p_it;
801801
else
802-
to_ssa_expr(goto_state_rhs).set_level_2(goto_count);
802+
{
803+
auto b_entry = goto_state.branch_propagation.find(l1_identifier);
804+
if(b_entry.has_value())
805+
goto_state_rhs = *b_entry;
806+
else
807+
to_ssa_expr(goto_state_rhs).set_level_2(goto_count);
808+
}
803809
}
804810

805811
{
@@ -808,7 +814,13 @@ static void merge_names(
808814
if(p_it.has_value())
809815
dest_state_rhs = *p_it;
810816
else
811-
to_ssa_expr(dest_state_rhs).set_level_2(dest_count);
817+
{
818+
auto b_entry = dest_state.branch_propagation.find(l1_identifier);
819+
if(b_entry.has_value())
820+
dest_state_rhs = *b_entry;
821+
else
822+
to_ssa_expr(dest_state_rhs).set_level_2(dest_count);
823+
}
812824
}
813825

814826
exprt rhs;
@@ -921,6 +933,12 @@ void goto_symext::phi_function(
921933
goto_count,
922934
dest_count);
923935
}
936+
937+
sharing_mapt<irep_idt, exprt>::delta_viewt bp_delta_view =
938+
dest_state.branch_propagation.get_delta_view(
939+
goto_state.branch_propagation, false);
940+
for(const auto &delta_item : bp_delta_view)
941+
dest_state.branch_propagation.erase(delta_item.k);
924942
}
925943

926944
void goto_symext::loop_bound_exceeded(

unit/goto-symex/apply_condition.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ SCENARIO(
6060

6161
THEN("b should be in the constant propagator with value 'true'")
6262
{
63-
auto it = goto_state.propagation.find(
63+
auto it = goto_state.branch_propagation.find(
6464
to_ssa_expr(renamed_b).get_l1_object_identifier());
6565
REQUIRE(it);
6666
REQUIRE(it->get() == true_exprt{});
@@ -74,7 +74,7 @@ SCENARIO(
7474

7575
THEN("b should be in the constant propagator with value 'false'")
7676
{
77-
auto it = goto_state.propagation.find(
77+
auto it = goto_state.branch_propagation.find(
7878
to_ssa_expr(renamed_b).get_l1_object_identifier());
7979
REQUIRE(it);
8080
REQUIRE(it->get() == false_exprt{});
@@ -88,7 +88,7 @@ SCENARIO(
8888

8989
THEN("b should be in the constant propagator with value 'true'")
9090
{
91-
auto it = goto_state.propagation.find(
91+
auto it = goto_state.branch_propagation.find(
9292
to_ssa_expr(renamed_b).get_l1_object_identifier());
9393
REQUIRE(it);
9494
REQUIRE(it->get() == true_exprt{});
@@ -102,7 +102,7 @@ SCENARIO(
102102

103103
THEN("b should be in the constant propagator with value 'false'")
104104
{
105-
auto it = goto_state.propagation.find(
105+
auto it = goto_state.branch_propagation.find(
106106
to_ssa_expr(renamed_b).get_l1_object_identifier());
107107
REQUIRE(it);
108108
REQUIRE(it->get() == false_exprt{});
@@ -116,7 +116,7 @@ SCENARIO(
116116

117117
THEN("b should be in the constant propagator with value 'false'")
118118
{
119-
auto it = goto_state.propagation.find(
119+
auto it = goto_state.branch_propagation.find(
120120
to_ssa_expr(renamed_b).get_l1_object_identifier());
121121
REQUIRE(it);
122122
REQUIRE(it->get() == false_exprt{});
@@ -130,7 +130,7 @@ SCENARIO(
130130

131131
THEN("b should be in the constant propagator with value 'true'")
132132
{
133-
auto it = goto_state.propagation.find(
133+
auto it = goto_state.branch_propagation.find(
134134
to_ssa_expr(renamed_b).get_l1_object_identifier());
135135
REQUIRE(it);
136136
REQUIRE(it->get() == true_exprt{});
@@ -144,7 +144,7 @@ SCENARIO(
144144

145145
THEN("b should be in the constant propagator with value 'false'")
146146
{
147-
auto it = goto_state.propagation.find(
147+
auto it = goto_state.branch_propagation.find(
148148
to_ssa_expr(renamed_b).get_l1_object_identifier());
149149
REQUIRE(it);
150150
REQUIRE(it->get() == false_exprt{});
@@ -158,7 +158,7 @@ SCENARIO(
158158

159159
THEN("b should be in the constant propagator with value 'true'")
160160
{
161-
auto it = goto_state.propagation.find(
161+
auto it = goto_state.branch_propagation.find(
162162
to_ssa_expr(renamed_b).get_l1_object_identifier());
163163
REQUIRE(it);
164164
REQUIRE(it->get() == true_exprt{});
@@ -172,7 +172,7 @@ SCENARIO(
172172

173173
THEN("b should be in the constant propagator with value 'true'")
174174
{
175-
auto it = goto_state.propagation.find(
175+
auto it = goto_state.branch_propagation.find(
176176
to_ssa_expr(renamed_b).get_l1_object_identifier());
177177
REQUIRE(it);
178178
REQUIRE(it->get() == true_exprt{});
@@ -186,7 +186,7 @@ SCENARIO(
186186

187187
THEN("b should be in the constant propagator with value 'false'")
188188
{
189-
auto it = goto_state.propagation.find(
189+
auto it = goto_state.branch_propagation.find(
190190
to_ssa_expr(renamed_b).get_l1_object_identifier());
191191
REQUIRE(it);
192192
REQUIRE(it->get() == false_exprt{});
@@ -200,7 +200,7 @@ SCENARIO(
200200

201201
THEN("b should be in the constant propagator with value 'true'")
202202
{
203-
auto it = goto_state.propagation.find(
203+
auto it = goto_state.branch_propagation.find(
204204
to_ssa_expr(renamed_b).get_l1_object_identifier());
205205
REQUIRE(it);
206206
REQUIRE(it->get() == true_exprt{});

0 commit comments

Comments
 (0)