-
Notifications
You must be signed in to change notification settings - Fork 274
Constant propagator: improve GOTO condition propagation #2522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Constant propagator: improve GOTO condition propagation #2522
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passed Diffblue compatibility checks (cbmc commit: d61ce78).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/78115950
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't completely understand the two way propagation, but this looks reasonable to me.
src/analyses/constant_propagator.h
Outdated
{ | ||
operator()(goto_function, ns); | ||
replace(goto_function, ns); | ||
} | ||
|
||
dirtyt dirty; | ||
|
||
std::function<bool(const exprt &, const namespacet &)> should_track_value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a fan of this being a public member. IMHO would be better to have this private. If this needs to be called from the outside, we could just call it should_track_value_handler
and have a method should_track_value
call this. It being public just invites shenanigans with people manually overwriting it.
src/analyses/constant_propagator.cpp
Outdated
if(lhs.is_constant() && !rhs.is_constant()) | ||
std::swap(lhs, rhs); | ||
|
||
if(!(rhs.is_constant() && !lhs.is_constant())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd be clearer to expand the not here: lhs.is_constant() || !rhs.is_constant()
.
src/analyses/constant_propagator.cpp
Outdated
// (int)var xx 0 ==> var xx (_Bool)0 or similar | ||
// Note this is restricted to bools because in general turning a widening | ||
// into a narrowing typecast is not correct. | ||
if(lhs.id() == ID_typecast && rhs.id() == ID_constant && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rhs.id() == ID_constant
should always be true at this point.
// Create a program like: | ||
// bool b0, b1, b2, ...; | ||
// int marker; | ||
// if(b0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible / reasonable to break this up into multiple smaller examples? Something this big is a bit difficult to follow.
Marking do not merge as it's based on another commit that should go in first |
|
||
symbolt main_function_symbol; | ||
main_function_symbol.name = "main"; | ||
main_function_symbol.type = code_typet(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This constructor is deprecated.
|
||
symbolt main_function_symbol; | ||
main_function_symbol.name = "main"; | ||
main_function_symbol.type = code_typet(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This constructor is deprecated.
d61ce78
to
4705ed7
Compare
1af51c0
to
3eec1a7
Compare
Comments mostly applied-- but this is parked for now pending #2132 landing. |
931c74d
to
bf3d12c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passed Diffblue compatibility checks (cbmc commit: bf3d12c).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/78301619
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me
src/analyses/constant_propagator.cpp
Outdated
else | ||
rhs = from_integer(0, rhs.type()); | ||
|
||
two_way_propagate_rec(equal_exprt(lhs, rhs), ns, cp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we use assign_rec()
here?
Noting this is still blocked on 2132 as noted above, I believe action @tautschnig |
... which in turn is blocked by #2221 - @kroening @peterschrammel @smowton ;-) |
In light of #2132 let me dare and go for high-level comments first:
|
Improvements to goto-analyzer's constant propagator and simplifier [blocks: #2522]
bf3d12c
to
f988768
Compare
@tautschnig rebased and improved somewhat, and described the new state of affairs in the PR description -- please re-review |
@smowton clang-format demands more work :-) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could do with a bunch of cleanup as indicated in comments, but otherwise ok.
src/analyses/constant_propagator.cpp
Outdated
} | ||
else | ||
{ | ||
// it's an assignment, but we don't really know what object is being written | ||
// to on the left-hand side - bail and set all values to top to be on the | ||
// safe side in terms of soundness | ||
dest_values.set_to_top(); | ||
if(is_assignment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about changing the above else
to else if(is_assignment)
and then even simplifying the comment a bit?
src/analyses/constant_propagator.cpp
Outdated
@@ -275,31 +312,87 @@ bool constant_propagator_domaint::two_way_propagate_rec( | |||
std::cout << "two_way_propagate_rec: " << format(expr) << '\n'; | |||
#endif | |||
|
|||
bool change=false; | |||
bool change = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated change?
{ | ||
code_ifthenelset new_cond; | ||
new_cond.cond() = test; | ||
new_cond.then_case() = to_wrap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the new code_ifthenelset
constructor.
// b = true; | ||
// Repeat this using bool_typet and c_bool_typet for "bool". | ||
|
||
null_message_handlert null_out; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a global one defined for the unit tests.
|
||
code_blockt code; | ||
code.copy_to_operands(code_declt(bool_local.symbol_expr())); | ||
code.copy_to_operands(code_declt(c_bool_local.symbol_expr())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might use the initializer-list constructor
const exprt c_bool_true = from_integer(1, c_bool_typet(8)); | ||
c_bool_cond_block.cond() = | ||
notequal_exprt(c_bool_local.symbol_expr(), c_bool_true); | ||
c_bool_cond_block.then_case() = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use recently added constructor
code_assignt(c_bool_local.symbol_expr(), c_bool_true); | ||
|
||
code.move_to_operands(bool_cond_block); | ||
code.move_to_operands(c_bool_cond_block); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move_to_operands
is deprecated
for(const exprt &test : c_bool_tests) | ||
wrap_with_test(program, test); | ||
|
||
null_message_handlert null_out; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use global one
f988768
to
06e6573
Compare
@tautschnig @chrisr-diffblue @peterschrammel this is updated and ready for re-review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✔️
Passed Diffblue compatibility checks (cbmc commit: 06e6573).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/96099635
else if(expr.id()==ID_equal) | ||
else if(expr.id() == ID_symbol) | ||
{ | ||
if(expr.type() == bool_typet()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd use expr.type().id() == ID_bool
to be consistent with what you're using above.
src/analyses/constant_propagator.cpp
Outdated
// into a narrowing typecast is not correct. | ||
if( | ||
lhs.id() == ID_typecast && | ||
(lhs.op0().type().id() == ID_bool || lhs.op0().type().id() == ID_c_bool)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rewrite this code a bit to do an early if(lhs.id() != ID_typecast) return;
and then use to_typecast_expr
instead of using the generic .op0()
.
static bool starts_with_x(const exprt &e, const namespacet &) | ||
{ | ||
if(e.id() != ID_symbol) | ||
return false; | ||
return has_prefix(id2string(to_symbol_expr(e).get_identifier()), "x"); | ||
} | ||
|
||
static void wrap_with_test(codet &to_wrap, const exprt &test) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this function actually still add value? Doing this one-liner inline might aid clarity.
06e6573
to
dc31f10
Compare
Updated as requested (except comparison with |
I'm not disputing that, but I'm unhappy about mixing both approaches in a single commit. But this is a very minor issue indeed. |
This supports propagation of booleans in more situations, including propagating "x != false" and "IF x" like "IF x == TRUE".
dc31f10
to
897ffda
Compare
Ah sure, switched to use full type comparison everywhere. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✔️
Passed Diffblue compatibility checks (cbmc commit: 897ffda).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/96195386
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This improves two-way propagation to also account for many other common patterns that imply an equality (e.g.
x != y
->x == !y
when the operands are of boolean types, or!x
-->x == TRUE
). I also fix a case where the fixpoint loop around the&&
case would loop forever becauseassign_rec
can both enlarge and shrink its value-set -- for example, the conditionx == 5 && **unknown == (void*)also_unknown
would result in repeatedly addingx -> 5
and the clobbering the entire value set. I fix that by noting that in the context of two-way propagation, since there's no write operation taking place we should never shrink the value set.