Skip to content

Commit 0d56ddd

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 0d56ddd

File tree

2 files changed

+72
-18
lines changed

2 files changed

+72
-18
lines changed

src/goto-symex/goto_state.cpp

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Author: Romain Brenguier, [email protected]
1010
#include "goto_symex_is_constant.h"
1111
#include "goto_symex_state.h"
1212

13+
#include <util/arith_tools.h>
1314
#include <util/format_expr.h>
1415

1516
/// Print the constant propagation map in a human-friendly format.
@@ -44,15 +45,50 @@ void goto_statet::apply_condition(
4445
const goto_symex_statet &previous_state,
4546
const namespacet &ns)
4647
{
47-
if(condition.id() == ID_and)
48+
if(auto and_expr = expr_try_dynamic_cast<and_exprt>(condition))
4849
{
49-
for(const auto &op : condition.operands())
50+
// A == B && C == D && E == F ...
51+
// -->
52+
// Apply each condition individually
53+
for(const auto &op : and_expr->operands())
5054
apply_condition(op, previous_state, ns);
5155
}
52-
else if(condition.id() == ID_equal)
56+
else if(auto not_expr = expr_try_dynamic_cast<not_exprt>(condition))
5357
{
54-
exprt lhs = to_equal_expr(condition).lhs();
55-
exprt rhs = to_equal_expr(condition).rhs();
58+
const exprt &operand = not_expr->op();
59+
if(auto notequal_expr = expr_try_dynamic_cast<notequal_exprt>(operand))
60+
{
61+
// !(A != B)
62+
// -->
63+
// A == B
64+
apply_condition(
65+
equal_exprt{notequal_expr->lhs(), notequal_expr->rhs()},
66+
previous_state,
67+
ns);
68+
}
69+
else if(auto equal_expr = expr_try_dynamic_cast<equal_exprt>(operand))
70+
{
71+
// !(A == B)
72+
// -->
73+
// A != B
74+
apply_condition(
75+
notequal_exprt{equal_expr->lhs(), equal_expr->rhs()},
76+
previous_state,
77+
ns);
78+
}
79+
else
80+
{
81+
// !A
82+
// -->
83+
// A == false
84+
apply_condition(equal_exprt{operand, false_exprt{}}, previous_state, ns);
85+
}
86+
}
87+
else if(auto equal_expr = expr_try_dynamic_cast<equal_exprt>(condition))
88+
{
89+
// Base case: try to apply a single equality constraint
90+
exprt lhs = equal_expr->lhs();
91+
exprt rhs = equal_expr->rhs();
5692
if(is_ssa_expr(rhs))
5793
std::swap(lhs, rhs);
5894

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

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)