Skip to content

Commit 7a07e82

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 d7099ae commit 7a07e82

File tree

11 files changed

+99
-36
lines changed

11 files changed

+99
-36
lines changed

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

+1-1
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
--
+12
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+
}
+12
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

+1
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

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

109-
level2.increase_generation(
110-
l1_identifier, l1_lhs, previous_state.get_l2_name_provider());
111-
112-
const auto propagation_entry = propagation.find(l1_identifier);
109+
const auto propagation_entry = branch_propagation.find(l1_identifier);
113110
if(!propagation_entry.has_value())
114-
propagation.insert(l1_identifier, rhs);
111+
branch_propagation.insert(l1_identifier, rhs);
115112
else if(propagation_entry->get() != rhs)
116-
propagation.replace(l1_identifier, rhs);
113+
branch_propagation.replace(l1_identifier, rhs);
117114

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

src/goto-symex/goto_state.h

+4-1
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

+26-13
Original file line numberDiff line numberDiff line change
@@ -354,15 +354,19 @@ goto_symext::try_evaluate_constant_string(
354354
return {};
355355
}
356356

357-
const auto s_pointer_opt =
358-
state.propagation.find(to_symbol_expr(content).get_identifier());
357+
const irep_idt &content_id = to_symbol_expr(content).get_identifier();
359358

360-
if(!s_pointer_opt)
361-
{
362-
return {};
363-
}
359+
const auto s_pointer_opt = state.propagation.find(content_id);
360+
361+
if(s_pointer_opt)
362+
return try_get_string_data_array(s_pointer_opt->get(), ns);
363+
364+
const auto b_entry = state.branch_propagation.find(content_id);
365+
366+
if(b_entry)
367+
return try_get_string_data_array(b_entry->get(), ns);
364368

365-
return try_get_string_data_array(s_pointer_opt->get(), ns);
369+
return {};
366370
}
367371

368372
optionalt<std::reference_wrapper<const constant_exprt>>
@@ -373,16 +377,25 @@ goto_symext::try_evaluate_constant(const statet &state, const exprt &expr)
373377
return {};
374378
}
375379

376-
const auto constant_expr_opt =
377-
state.propagation.find(to_symbol_expr(expr).get_identifier());
380+
const irep_idt &expr_id = to_symbol_expr(expr).get_identifier();
378381

379-
if(!constant_expr_opt || !constant_expr_opt->get().is_constant())
382+
const auto constant_expr_opt = state.propagation.find(expr_id);
383+
384+
if(constant_expr_opt && constant_expr_opt->get().is_constant())
380385
{
381-
return {};
386+
return optionalt<std::reference_wrapper<const constant_exprt>>(
387+
to_constant_expr(constant_expr_opt->get()));
388+
}
389+
390+
const auto b_entry = state.branch_propagation.find(expr_id);
391+
392+
if(b_entry && b_entry->get().id() == ID_constant)
393+
{
394+
return optionalt<std::reference_wrapper<const constant_exprt>>(
395+
to_constant_expr(b_entry->get()));
382396
}
383397

384-
return optionalt<std::reference_wrapper<const constant_exprt>>(
385-
to_constant_expr(constant_expr_opt->get()));
398+
return {};
386399
}
387400

388401
void goto_symext::constant_propagate_empty_string(

src/goto-symex/goto_symex_state.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ renamedt<ssa_exprt, L2> goto_symex_statet::assignment(
110110
"pointer handling for concurrency is unsound");
111111

112112
// Update constant propagation map -- the RHS is L2
113+
branch_propagation.erase_if_exists(l1_identifier);
113114
if(!is_shared && record_value && goto_symex_is_constantt(ns)(rhs))
114115
{
115116
const auto propagation_entry = propagation.find(l1_identifier);
@@ -212,14 +213,19 @@ goto_symex_statet::rename(exprt expr, const namespacet &ns)
212213
{
213214
// We also consider propagation if we go up to L2.
214215
// L1 identifiers are used for propagation!
215-
auto p_it = propagation.find(ssa.get_identifier());
216+
const auto &l1_identifier = ssa.get_identifier();
217+
auto p_it = propagation.find(l1_identifier);
216218

217219
if(p_it.has_value())
218220
{
219221
return renamedt<exprt, level>(*p_it); // already L2
220222
}
221223
else
222224
{
225+
auto b_entry = branch_propagation.find(l1_identifier);
226+
if(b_entry.has_value())
227+
return renamedt<exprt, level>(*b_entry);
228+
223229
if(level == L2)
224230
ssa = set_indices<L2>(std::move(ssa), ns).get();
225231
return renamedt<exprt, level>(std::move(ssa));
@@ -430,7 +436,7 @@ bool goto_symex_statet::l2_thread_read_encoding(
430436
// written this object within the atomic section. We must actually do this,
431437
// because goto_state::apply_condition may have placed the latest value in
432438
// the propagation map without recording an assignment.
433-
auto p_it = propagation.find(ssa_l1.get_identifier());
439+
auto p_it = branch_propagation.find(ssa_l1.get_identifier());
434440
const exprt l2_true_case =
435441
p_it.has_value() ? *p_it : set_indices<L2>(ssa_l1, ns).get();
436442

src/goto-symex/symex_dead.cpp

+1
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

+20-2
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

+11-11
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)