Skip to content

Commit 2ae229b

Browse files
smowtonowen-mc-diffblue
authored andcommitted
GOTO-symex: propagate notequal conditions for boolean types
Conditional branches on "x != false", as well as "x" and "!x", can and should lead to constant propagation just as "x == true" does now. This is particularly beneficial for the "clinit_already_run" variables that are maintained to determine if a static initialiser should be run or not -- the current "if(already_run != true) clinit(); already_run = true;" condition now leaves symex certain that it has been run at the bottom of the function regardless of the already_run flag's initial value, whereas before it could remain uncertain and so explore the static initialiser more than is necessary.
1 parent fc0a0cd commit 2ae229b

File tree

2 files changed

+71
-18
lines changed

2 files changed

+71
-18
lines changed

src/goto-symex/goto_state.cpp

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,50 @@ void goto_statet::apply_condition(
4444
const goto_symex_statet &previous_state,
4545
const namespacet &ns)
4646
{
47-
if(condition.id() == ID_and)
47+
if(auto and_expr = expr_try_dynamic_cast<and_exprt>(condition))
4848
{
49-
for(const auto &op : condition.operands())
49+
// A == B && C == D && E == F ...
50+
// -->
51+
// Apply each condition individually
52+
for(const auto &op : and_expr->operands())
5053
apply_condition(op, previous_state, ns);
5154
}
52-
else if(condition.id() == ID_equal)
55+
else if(auto not_expr = expr_try_dynamic_cast<not_exprt>(condition))
5356
{
54-
exprt lhs = to_equal_expr(condition).lhs();
55-
exprt rhs = to_equal_expr(condition).rhs();
57+
const exprt &operand = not_expr->op();
58+
if(auto notequal_expr = expr_try_dynamic_cast<notequal_exprt>(operand))
59+
{
60+
// !(A != B)
61+
// -->
62+
// A == B
63+
apply_condition(
64+
equal_exprt{notequal_expr->lhs(), notequal_expr->rhs()},
65+
previous_state,
66+
ns);
67+
}
68+
else if(auto equal_expr = expr_try_dynamic_cast<equal_exprt>(operand))
69+
{
70+
// !(A == B)
71+
// -->
72+
// A != B
73+
apply_condition(
74+
notequal_exprt{equal_expr->lhs(), equal_expr->rhs()},
75+
previous_state,
76+
ns);
77+
}
78+
else
79+
{
80+
// !A
81+
// -->
82+
// A == false
83+
apply_condition(equal_exprt{operand, false_exprt{}}, previous_state, ns);
84+
}
85+
}
86+
else if(auto equal_expr = expr_try_dynamic_cast<equal_exprt>(condition))
87+
{
88+
// Base case: try to apply a single equality constraint
89+
exprt lhs = equal_expr->lhs();
90+
exprt rhs = equal_expr->rhs();
5691
if(is_ssa_expr(rhs))
5792
std::swap(lhs, rhs);
5893

@@ -84,4 +119,33 @@ void goto_statet::apply_condition(
84119
}
85120
}
86121
}
122+
else if(
123+
can_cast_expr<symbol_exprt>(condition) && condition.type() == bool_typet())
124+
{
125+
// A
126+
// -->
127+
// A == true
128+
apply_condition(equal_exprt{condition, true_exprt()}, previous_state, ns);
129+
}
130+
else if(
131+
can_cast_expr<notequal_exprt>(condition) &&
132+
expr_checked_cast<notequal_exprt>(condition).lhs().type() == bool_typet{})
133+
{
134+
// A != (true|false)
135+
// -->
136+
// A == (false|true)
137+
const notequal_exprt &notequal_expr =
138+
expr_dynamic_cast<notequal_exprt>(condition);
139+
exprt lhs = notequal_expr.lhs();
140+
exprt rhs = notequal_expr.rhs();
141+
if(is_ssa_expr(rhs))
142+
std::swap(lhs, rhs);
143+
144+
if(rhs.is_true())
145+
apply_condition(equal_exprt{lhs, false_exprt{}}, previous_state, ns);
146+
else if(rhs.is_false())
147+
apply_condition(equal_exprt{lhs, true_exprt{}}, previous_state, ns);
148+
else
149+
UNREACHABLE;
150+
}
87151
}

src/goto-symex/symex_goto.cpp

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,21 +55,10 @@ void goto_symext::apply_goto_condition(
5555

5656
jump_taken_state.apply_condition(new_guard, current_state, ns);
5757

58-
// Try to find a negative condition that implies an equality constraint on
59-
// the branch-not-taken path.
6058
// Could use not_exprt + simplify, but let's avoid paying that cost on quite
6159
// a hot path:
62-
if(new_guard.id() == ID_not)
63-
jump_not_taken_state.apply_condition(
64-
to_not_expr(new_guard).op(), current_state, ns);
65-
else if(new_guard.id() == ID_notequal)
66-
{
67-
auto &not_equal_expr = to_notequal_expr(new_guard);
68-
jump_not_taken_state.apply_condition(
69-
equal_exprt(not_equal_expr.lhs(), not_equal_expr.rhs()),
70-
current_state,
71-
ns);
72-
}
60+
const exprt negated_new_guard = boolean_negate(new_guard);
61+
jump_not_taken_state.apply_condition(negated_new_guard, current_state, ns);
7362
}
7463

7564
/// Try to evaluate a simple pointer comparison.

0 commit comments

Comments
 (0)