Skip to content

Commit 65293be

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 65293be

File tree

2 files changed

+65
-14
lines changed

2 files changed

+65
-14
lines changed

src/goto-symex/goto_state.cpp

Lines changed: 61 additions & 1 deletion
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,16 +47,56 @@ 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+
if(to_not_expr(condition).op().id() == ID_notequal)
59+
{
60+
// !(A != B)
61+
// -->
62+
// A == B
63+
const auto &notequal_expr = to_notequal_expr(to_not_expr(condition).op());
64+
apply_condition(
65+
equal_exprt(notequal_expr.lhs(), notequal_expr.rhs()),
66+
previous_state,
67+
ns);
68+
}
69+
else if(to_not_expr(condition).op().id() == ID_equal)
70+
{
71+
// !(A == B)
72+
// -->
73+
// A != B
74+
const auto &equal_expr = to_equal_expr(to_not_expr(condition).op());
75+
apply_condition(
76+
notequal_exprt(equal_expr.lhs(), equal_expr.rhs()), previous_state, ns);
77+
}
78+
else
79+
{
80+
// !A
81+
// -->
82+
// A == false
83+
apply_condition(
84+
equal_exprt(to_not_expr(condition).op(), false_exprt()),
85+
previous_state,
86+
ns);
87+
}
88+
}
5289
else if(condition.id() == ID_equal)
5390
{
91+
// Base case: try to apply a single equality constraint
5492
exprt lhs = to_equal_expr(condition).lhs();
5593
exprt rhs = to_equal_expr(condition).rhs();
56-
if(is_ssa_expr(rhs))
94+
if(is_ssa_expr(skip_typecast(rhs)))
5795
std::swap(lhs, rhs);
5896

97+
lhs = skip_typecast(lhs);
98+
rhs = typecast_exprt::conditional_cast(rhs, lhs.type());
99+
59100
if(is_ssa_expr(lhs) && goto_symex_is_constantt()(rhs))
60101
{
61102
const ssa_exprt &ssa_lhs = to_ssa_expr(lhs);
@@ -84,4 +125,23 @@ void goto_statet::apply_condition(
84125
}
85126
}
86127
}
128+
else if(
129+
condition.id() == ID_notequal &&
130+
skip_typecast(to_notequal_expr(condition).lhs()).type().id() == ID_c_bool)
131+
{
132+
// A != (true|false)
133+
// -->
134+
// A == (false|true)
135+
exprt lhs = to_notequal_expr(condition).lhs();
136+
exprt rhs = to_notequal_expr(condition).rhs();
137+
if(is_ssa_expr(rhs))
138+
std::swap(lhs, rhs);
139+
140+
if(rhs.is_zero())
141+
apply_condition(equal_exprt(lhs, from_integer(1, rhs.type())), previous_state, ns);
142+
else if(rhs.is_one())
143+
apply_condition(equal_exprt(lhs, from_integer(0, rhs.type())), previous_state, ns);
144+
else
145+
UNREACHABLE;
146+
}
87147
}

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)