Skip to content

Commit f52e3b7

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 f52e3b7

File tree

2 files changed

+69
-13
lines changed

2 files changed

+69
-13
lines changed

src/goto-symex/goto_state.cpp

Lines changed: 65 additions & 0 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.
@@ -46,11 +47,46 @@ void goto_statet::apply_condition(
4647
{
4748
if(condition.id() == ID_and)
4849
{
50+
// A == B && C == D && E == F ...
51+
// -->
52+
// Apply each condition individually
4953
for(const auto &op : condition.operands())
5054
apply_condition(op, previous_state, ns);
5155
}
56+
else if(condition.id() == ID_not)
57+
{
58+
const exprt &operand = to_not_expr(condition).op();
59+
if(operand.id() == ID_notequal)
60+
{
61+
// !(A != B)
62+
// -->
63+
// A == B
64+
const auto &notequal_expr = to_notequal_expr(operand);
65+
apply_condition(
66+
equal_exprt{notequal_expr.lhs(), notequal_expr.rhs()},
67+
previous_state,
68+
ns);
69+
}
70+
else if(operand.id() == ID_equal)
71+
{
72+
// !(A == B)
73+
// -->
74+
// A != B
75+
const auto &equal_expr = to_equal_expr(operand);
76+
apply_condition(
77+
notequal_exprt{equal_expr.lhs(), equal_expr.rhs()}, previous_state, ns);
78+
}
79+
else
80+
{
81+
// !A
82+
// -->
83+
// A == false
84+
apply_condition(equal_exprt{operand, false_exprt{}}, previous_state, ns);
85+
}
86+
}
5287
else if(condition.id() == ID_equal)
5388
{
89+
// Base case: try to apply a single equality constraint
5490
exprt lhs = to_equal_expr(condition).lhs();
5591
exprt rhs = to_equal_expr(condition).rhs();
5692
if(is_ssa_expr(rhs))
@@ -84,4 +120,33 @@ void goto_statet::apply_condition(
84120
}
85121
}
86122
}
123+
else if(condition.id() == ID_symbol)
124+
{
125+
if(condition.type() == bool_typet())
126+
{
127+
// A
128+
// -->
129+
// A == true
130+
apply_condition(equal_exprt{condition, true_exprt()}, previous_state, ns);
131+
}
132+
}
133+
else if(
134+
condition.id() == ID_notequal &&
135+
to_notequal_expr(condition).lhs().type() == bool_typet{})
136+
{
137+
// A != (true|false)
138+
// -->
139+
// A == (false|true)
140+
exprt lhs = to_notequal_expr(condition).lhs();
141+
exprt rhs = to_notequal_expr(condition).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: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,21 +55,12 @@ 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+
exprt negated_new_guard = new_guard.id() == ID_not
61+
? to_not_expr(new_guard).op()
62+
: not_exprt(new_guard);
63+
jump_not_taken_state.apply_condition(negated_new_guard, current_state, ns);
7364
}
7465

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

0 commit comments

Comments
 (0)