-
Notifications
You must be signed in to change notification settings - Fork 284
Add conversion for rol and ror operators to c output #6253
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
Codecov Report
@@ Coverage Diff @@
## develop #6253 +/- ##
===========================================
+ Coverage 76.16% 76.18% +0.01%
===========================================
Files 1484 1485 +1
Lines 162164 162217 +53
===========================================
+ Hits 123516 123579 +63
+ Misses 38648 38638 -10
Continue to review full report at Codecov.
|
src/ansi-c/expr2c.cpp
Outdated
|
|
||
| else if(src.id() == ID_rol) | ||
| { | ||
| // AAAA rol n == (AAAA << n) | (AAAA >> (width(AAAA) - 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.
What if n is greater than bit 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.
Also note the cases when shift can give undefined behaviour.
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 is done with modulo now.
51f1e45 to
8d70761
Compare
thomasspriggs
left a comment
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 is good that we have a fix for the issue and that we have both regression and unit tests. However I think there are some issues which should be addressed for the sake of maintainability. The issues which I think really need to be addressed before we merge are marked with 🚫 Hopefully having the tests should make it easy to check the refactorings are sound as you address the issues.
src/ansi-c/expr2c.cpp
Outdated
| } | ||
| else if(src.id() == ID_ror) | ||
| { | ||
| // AAAA rol n == (AAAA >> n % width(AAAA)) |
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 duplicated code will make maintenance more difficult. I suggest deduplicating it by parameterising the new function I suggested in my previous comment.
💡 I suggest creating a single use left_or_rightt enum class with left and right values to use as the type of the left_or_right parameter of the new function. This could alternatively be done without using a new enum with something like bool is_right, with true = right and false = left. But I think the enum would make for more self explanatory 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.
I now consider this to be sorted.
src/ansi-c/expr2c.cpp
Outdated
| { | ||
| // Shifts in C are arithmetic and care about sign, by forcing | ||
| // a cast to unsigned we force the shifts to perform rol/r | ||
| size_t ws = op0.type().get_size_t("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.
⛏️ This and all other variables in this new code which are not mutated should be declared const.
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 bitvector_typet::get_width() instead of get_size_t("width"). By using get_size_t you are directly accessing the underlying data structure of the type. Fixing the accessibility to underlying irept would be a non-trivial refactor, but we should still use the well defined external interface where possible.
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 is ws supposed to be short for? Reminder - the coding standards state that we should "Avoid abbreviations".
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 looks to be sorted, with the exception of the unreachable code.
src/ansi-c/expr2c.cpp
Outdated
| { | ||
| // AAAA rol n == (AAAA << n % width(AAAA)) | ||
| // | (AAAA >> (width(AAAA) - n % width(AAAA))) | ||
| auto bin_expr = to_binary_expr(src); |
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 suggest renaming bin_expr to rotate_expr, because at this point bin_expr can only be a rotate expression, even if the type only specifies that it is a binary_exprt.
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 suggest swapping out to_binary_expr(src) with expr_checked_cast<shift_exprt>(src). That way we are using a more specific type of expression and we are using the checks which are defined alongside that expression.
src/ansi-c/expr2c.cpp
Outdated
| } | ||
| // Get n because we need its type to construct the "width(AAAA)" | ||
| // value to use in operations below. | ||
| exprt &op1 = bin_expr.op1(); |
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 suggest renaming op1 to distance.
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 .distance() of shift_exprt instead of .op1(), because this is the specifically named getter for this data member.
src/ansi-c/expr2c.cpp
Outdated
| auto bin_expr = to_binary_expr(src); | ||
| // Get AAAA and if it's signed wrap it in a cast to remove | ||
| // the sign since this messes with C shifts | ||
| exprt &op0 = bin_expr.op0(); |
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 .op() of shift_exprt rather than op0(), because this is the specifically named getter for this data member.
src/ansi-c/expr2c.cpp
Outdated
| // value to use in operations below. | ||
| exprt &op1 = bin_expr.op1(); | ||
| // Construct the "width(AAAA)" constant | ||
| irep_idt width_val = op0.type().get("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.
⛏️ Duplicated extraction of getting the width from op0. It should be possible to move the previous getting of the width out of the if statement and reuse it. We can expect the type to be a bitvector_typet whether or not it is signed. So extracting the width can be - const size_t width = type_checked_cast<bitvector_typet>(op0.type()).get_width();
src/ansi-c/expr2c.cpp
Outdated
| auto width = constant_exprt(width_val, op1.type()); | ||
| // Apply modulo to n since shifting will overflow | ||
| // That is: 0001 << 4 == 0, but 0001 rol 4 == 0001 | ||
| op1 = mod_exprt(op1, 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.
⛏️ I suggest creating a new variable named distance_modulo_width instead, in order to better specify what this is and in order to avoid mutating.
This adds conversion for the rol and ror operators from CBMC internals into C code. This is done by bit-twiddling the values to achieve the outcome. Fixes diffblue#6241
This adds regression tests for rol/ror using symtba2gb and goto-instrument.
Adds unit test for expr2c of rol and ror operators, testing both signed and unisgned conversions.
Tidies up the style and addresses reviewer comments: - use to_shift_exprt before call to convert_rox - remove "kind" path to try and guess bit width
chrisr-diffblue
left a comment
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.
Mostly looks OK, though I think @thomasspriggs has some blocking review comments that it would be good to resolve. Also, how cross-platform/cross-architecture/cross endian is this work? In particular, are we confident this works on, say ARM architecture where its switchable big/little endian? I think cbmc has --little-endian and --big-endian options.
src/ansi-c/expr2c.cpp
Outdated
| mod_exprt(rotate_expr.distance(), width_expr); | ||
| // Now put the pieces together | ||
| // width(AAAA) - (n % width(AAAA)) | ||
| const auto complement_expr = minus_exprt(width_expr, distance_modulo_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.
I don't think this is actually the complement expression, is the complement width expression ?
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
|
|
||
| TEST_CASE("rol_2_c_conversion_unsigned", "[core][ansi-c][expr2c]") | ||
| { | ||
| auto lhs = from_integer(31, unsignedbv_typet(32)); |
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.
Personal preference here :-) But for tests used for bit-twiddling operations, I'd be rather tempted to use hex representations of the various immediate constants in tests like this. Might just be my background, but I find that easier to mentally model, rather than also adding a decimal->hex->binary mental translation :-)
| "[core][ansi-c][expr2c][convert_with_precedence]") | ||
| { | ||
| config.ansi_c.mode = configt::ansi_ct::flavourt::GCC; | ||
| config.ansi_c.set_arch_spec_i386(); |
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 be worth a comment explaining why this is necessary?
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
21ef742 to
2e1b6ac
Compare
227e044 to
cca8198
Compare
src/ansi-c/expr2c.cpp
Outdated
| // | (AAAA rhs_op (width(AAAA) - n % width(AAAA))) | ||
| // Where lhs_op and rhs_op depend on whether it is rol or ror | ||
| // auto rotate_expr = to_binary_expr(src); | ||
| auto rotate_expr = expr_checked_cast<shift_exprt>(src); |
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 keeping with other functions I'd prefer for convert_rox to take a shift_exprt as first argument and to_shift_expr being used at the call site.
src/ansi-c/expr2c.cpp
Outdated
| // Type that can't be represented as bitvector | ||
| // get some kind of width in a potentially unsafe way | ||
| type_width = op0.type().get_size_t("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.
I think you should just give up in that else case. You might well get back a nil irep, which will make the from_integer fail. You're trying to be very kind, but I don't think you're doing the user any favour.
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.
Agreed. I'd just put an UNREACHABLE here. I think the comments from codecov suggest that it is in fact unreachable with the way it is currently used.
thomasspriggs
left a comment
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.
My blocking comments have been addressed. Therefore I am going to approve this PR.
| // AAAA << complement_expr | ||
| rhs_expr = shl_exprt(op0, complement_expr); | ||
| // AAAA << complement_width_expr | ||
| rhs_expr = shl_exprt(op0, complement_width_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.
⛏️ These changes appear to have been squashed into the wrong commit.
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.
This adds conversion for the rol and ror operators from CBMC
internals into C code. This is done by bit-twiddling the values
to achieve the outcome.
Fixes #6241