Constant propagator: improve GOTO condition propagation#2522
Conversation
allredj
left a comment
There was a problem hiding this comment.
Passed Diffblue compatibility checks (cbmc commit: d61ce78).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/78115950
hannes-steffenhagen-diffblue
left a comment
There was a problem hiding this comment.
I don't completely understand the two way propagation, but this looks reasonable to me.
src/analyses/constant_propagator.h
Outdated
|
|
||
| dirtyt dirty; | ||
|
|
||
| std::function<bool(const exprt &, const namespacet &)> should_track_value; |
There was a problem hiding this comment.
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.
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.
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.
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.
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.
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
allredj
left a comment
There was a problem hiding this comment.
Passed Diffblue compatibility checks (cbmc commit: bf3d12c).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/78301619
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.
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 :-) |
tautschnig
left a comment
There was a problem hiding this comment.
Could do with a bunch of cleanup as indicated in comments, but otherwise ok.
src/analyses/constant_propagator.cpp
Outdated
| // 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.
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
| #endif | ||
|
|
||
| bool change=false; | ||
| bool change = false; |
| { | ||
| code_ifthenelset new_cond; | ||
| new_cond.cond() = test; | ||
| new_cond.then_case() = to_wrap; |
There was a problem hiding this comment.
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.
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.
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.
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.
move_to_operands is deprecated
| for(const exprt &test : c_bool_tests) | ||
| wrap_with_test(program, test); | ||
|
|
||
| null_message_handlert null_out; |
f988768 to
06e6573
Compare
|
@tautschnig @chrisr-diffblue @peterschrammel this is updated and ready for re-review. |
allredj
left a comment
There was a problem hiding this comment.
✔️
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.
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.
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().
| 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.
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. |
allredj
left a comment
There was a problem hiding this comment.
✔️
Passed Diffblue compatibility checks (cbmc commit: 897ffda).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/96195386
This improves two-way propagation to also account for many other common patterns that imply an equality (e.g.
x != y->x == !ywhen 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_reccan both enlarge and shrink its value-set -- for example, the conditionx == 5 && **unknown == (void*)also_unknownwould result in repeatedly addingx -> 5and 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.