-
Notifications
You must be signed in to change notification settings - Fork 273
Improve performance and fix limitations of flatten_byte_operators [blocks: #3725] #2068
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
Conversation
04bc573
to
a1a41af
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.
Reviewed up to byte_operators.cpp:578
, to continue tomorrow
#endif | ||
|
||
error().source_location = expr.find_source_location(); | ||
error() << "member: component type does not match: " << subtype.pretty() |
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.
Recommend newlines before pretty
for readability
error().source_location = expr.find_source_location(); | ||
error() << "member: component type does not match: " << subtype.pretty() | ||
<< " vs. " << expr.type().pretty() << eom; | ||
throw 0; |
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 this is an invariant, as it's our responsibility to make sure this is true, not a user error
|
||
return bv; | ||
#if 0 | ||
std::cout << "DEBUG " << expr.pretty() << "\n"; |
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.
If we're going to commit this, replace DEBUG with a more useful key?
mp_integer num_elements; | ||
if(to_integer(max_bytes, num_elements) && to_integer(src_size, num_elements)) | ||
{ | ||
throw "cannot unpack array/vector of non-const size:\n" + |
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.
Again, invariant?
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.
It's something that may be fixable in some way, and really a limitation of the implementation rather than a bug. So I'm inclined to leave it in place.
|
||
mp_integer offset_int = 0; | ||
|
||
if(element_width > 0 && element_width % 8 == 0) |
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.
What would element_width == 0
mean?
if(!to_integer(offset, offset_int)) | ||
{ | ||
// compute offset as number of elements | ||
offset_int /= el_bytes; |
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.
offset_elements
?
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.
Fixed.
|
||
exprt src_simp = simplify_expr(src, ns); | ||
|
||
for(mp_integer i = offset_int; i < num_elements; ++i) |
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.
Given the above units trouble, i
-> element_idx
?
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 I've made a right mess here. Thanks for looking carefully, I'm working on cleanup.
|
||
if(src_simp.id() != ID_array || i >= src_simp.operands().size()) | ||
{ | ||
index = index_exprt(src_simp, from_integer(i, index_type())); |
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.
index
-> element
?
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.
Done.
new_offset = from_integer(new_offset_int, offset.type()); | ||
} | ||
|
||
if(!to_integer(max_bytes, new_max_bytes_int)) |
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.
Comment before these what the intended adjustment is? At the moment it looks like you would reduce both lower and upper bounds if the access is not byte-aligned, whereas I might expect you to round the lower bound down and the upper bound up to ensure you include the desired range?
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.
No, byte-alignedness is tested above, there shouldn't be a need for rounding I believe.
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.
In that case member_offset_bits % 8
is always zero, as it starts at zero and is the incremental sum of several element_width
s, each of which is itself a multiple of eight.
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.
Your comment really highlighted that there was a problem: member_offset_bits
wasn't actually being used properly, this should have been a division, not modulo!
UNREACHABLE; | ||
|
||
// TODO: consider ways of dealing with vectors of unknown subtype | ||
// size or with a subtype size that does not fit byte boundaries |
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.
What currently happens?
179f937
to
5b8938e
Compare
has_subtype(expr.op0().type(), ID_pointer, ns)) | ||
{ | ||
exprt tmp = lower_byte_update(expr, ns); | ||
return convert_bv(tmp); |
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.
const exprt tmp
or just one line return
@@ -30,7 +30,7 @@ literalt boolbvt::convert_equality(const equal_exprt &expr) | |||
|
|||
if(has_byte_operator(expr)) | |||
{ | |||
exprt tmp=flatten_byte_operators(expr, ns); | |||
exprt tmp = lower_byte_operators(expr, ns); |
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.
const
it++) | ||
for(struct_union_typet::componentst::const_iterator it = components.begin(); | ||
it != components.end(); | ||
++it) |
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 ranged for if it
is not used as an iterator inside the loop
offset+=sub_width; | ||
DATA_INVARIANT( | ||
base_type_eq(subtype, expr.type(), ns), | ||
"component type expected to match expression type:\n" + expr.pretty()); |
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's better to avoid calling pretty
in places where it will be called even if there is no error.
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 sure I understand the "called even if there is no error" part - this would only be printed in case of a violated invariant?!
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.
oh yes sorry, you can ignore my comment, the macro is so that the second part does not need to be called.
offset + sub_width <= struct_bv.size(), "member access outside struct"); | ||
|
||
for(std::size_t i = 0; i < sub_width; i++) | ||
bv[i] = struct_bv[offset + i]; |
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 you could use bv.insert(bv.begin(), struct_bv + offset, struct_bv + offset + sub_width)
instead
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.
Good call! This actually enables a further simplification of just doing return bvt(struct_bv.begin() + ...)
.
83a50d6
to
95f06fb
Compare
|
||
mp_integer index = 0; | ||
if( | ||
!offset_i.is_constant() || root.id() != ID_array || |
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.
Readability: suggest break after each disjunct
@@ -371,41 +657,40 @@ exprt flatten_byte_update( | |||
// byte array? | |||
if(sub_size==1) | |||
{ | |||
byte_extract_exprt byte_extract_expr( | |||
src.id()==ID_byte_update_little_endian? |
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 as well use conventional operator spacing here
src.op2(), t); | ||
else | ||
value_extended=src.op2(); | ||
value_extended, unsignedbv_typet(width)); |
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.
Style: params all on one line, or one per line
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.
Thanks for fixing the comments above; done reviewing with only nitpicks regarding the second half.
2af5790
to
afc73ba
Compare
a746e0c
to
442b268
Compare
Fix array constraints for with_exprt with >3 operands [blocks: #2068]
442b268
to
6c4ebdb
Compare
Restarted spurious CI failure -- is this good to go with @kroening or @peterschrammel's review? |
Yes, reviews would be much appreciated. |
if( | ||
is_unbounded_array(expr.op().type()) || | ||
has_subtype(expr.type(), ID_pointer, ns) || | ||
has_subtype(expr.op().type(), ID_pointer, ns)) | ||
{ |
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.
What's the rationale for that, actually?
Is the alternative to always use the flattening code?
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.
The rationale for lowering byte-operators when pointers are involved? Given that there is another commit that does lowering when encountering a pointer I can check whether that's still necessary (without the latter it would certainly lead to an exception), it's a matter of whether the SMT back-end now needs this or not(edit: this code is not for SMT).
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.
Very good call, this is now unnecessary. Commit (for both byte extract and byte update) and commit message amended.
… types byte_update lowering now proceeds as follows: 1) Determine the size of the update, with the size of the object to be updated as an upper bound. We fail if neither can be determined. 2) Turn the update value into a byte array of the size determined above. 3) If the offset is not constant, turn the object into a byte array, and use a "with" expression to encode the update; else update the values in place. 4) Construct a new object.
A prior lowering pass may have removed them (for example, if they occur within unbounded arrays).
6c4ebdb
to
34a4de9
Compare
The array theory does not handle byte_{extract,update} operators. For pointers, make sure the flattening back-end also uses lowering rather than failing with an exception.
The locally implemented lowering was very incomplete.
These may be generated when dereferencing invalid pointers, and are just no-ops. Make sure we don't fail as size_of_expr would return nil_exprt() for those.
This removes the constraint on aligned member accesses. Includes factoring out of unpack_struct to avoid growing the size of unpack_rec even further.
34a4de9
to
4ada4bf
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: 4ada4bf).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/102380441
Let's merge this now -- in the long run, it may be the case that the bit-vector flattener in SMT2 possibly outperforms the lowerer for byte_update. |
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 PR failed Diffblue compatibility checks (cbmc commit: 34a4de9).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/102381986
Status will be re-evaluated on next push.
Common spurious failures:
-
the cbmc commit has disappeared in the mean time (e.g. in a force-push)
-
the author is not in the list of contributors (e.g. first-time contributors).
-
the compatibility was already broken by an earlier merge.
Depends on #2061 and #2063 and thus should not be merged just yet.