SMT-LIB2: shifts with wider shift distances#8834
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #8834 +/- ##
========================================
Coverage 80.00% 80.01%
========================================
Files 1700 1700
Lines 188252 188312 +60
Branches 73 73
========================================
+ Hits 150613 150675 +62
+ Misses 37639 37637 -2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
7fed5fd to
365bd7b
Compare
This fixes the case of converting shifts where the shift distance is wider than the shift operand to SMT-LIB2. SMT-LIB2 requires that the width of the shift operand and the shift distance is the same. To not lose leading bits of the shift distance, use the wider one of the two as the width of the shift, and truncate the result when needed.
| out << ')'; // bv*sh | ||
| } | ||
| else // width_op0<width_op1 | ||
| else // width_op<width_distance -- distance is wider | ||
| { | ||
| out << "((_ extract " << width_op0-1 << " 0) "; | ||
| // enlarge the shift to match the distance operand, | ||
| // then extract again | ||
| out << "((_ extract " << width_op - 1 << " 0) "; | ||
| emit_operator(shift_expr); | ||
|
|
||
| // use sign extension when needed | ||
| if(shift_expr.op().type().id() == ID_signedbv) | ||
| { | ||
| out << "((_ sign_extend " << width_distance - width_op << ") "; | ||
| convert_expr(shift_expr.op()); |
There was a problem hiding this comment.
I believe sign-extending the operand is incorrect for lshr (logical right shift). Sign extension should only be used for ashr. For lshr and shl, zero extension is always correct:
| out << ')'; // bv*sh | |
| } | |
| else // width_op0<width_op1 | |
| else // width_op<width_distance -- distance is wider | |
| { | |
| out << "((_ extract " << width_op0-1 << " 0) "; | |
| // enlarge the shift to match the distance operand, | |
| // then extract again | |
| out << "((_ extract " << width_op - 1 << " 0) "; | |
| emit_operator(shift_expr); | |
| // use sign extension when needed | |
| if(shift_expr.op().type().id() == ID_signedbv) | |
| { | |
| out << "((_ sign_extend " << width_distance - width_op << ") "; | |
| convert_expr(shift_expr.op()); | |
| // use sign extension for arithmetic right shift | |
| if( | |
| shift_expr.id() == ID_ashr && | |
| shift_expr.op().type().id() == ID_signedbv) | |
| { | |
| out << "((_ sign_extend " << width_distance - width_op << ") "; | |
| convert_expr(shift_expr.op()); | |
| out << ')'; // sign_extend | |
| } | |
| else | |
| { | |
| out << "((_ zero_extend " << width_distance - width_op << ") "; | |
| convert_expr(shift_expr.op()); | |
| out << ')'; // zero_extend | |
| } |
| REQUIRE( | ||
| smt2(shift) == "((_ extract 7 0) (bvashr ((_ sign_extend 2) op) dist))"); | ||
| } | ||
|
|
There was a problem hiding this comment.
This test covers ashr with a signed operand and wider distance, which exercises the sign-extension path. Please also add a test for lshr with a signed operand and wider distance to catch the bug described in my other comment. Expected output should use zero_extend, not sign_extend:
GIVEN("A logical right shift with a signed operand and wider distance")
{
auto op = symbol_exprt{"op", signedbv_typet{8}};
auto distance = symbol_exprt{"dist", unsignedbv_typet{10}};
auto shift = lshr_exprt{op, distance};
REQUIRE(
smt2(shift) == "((_ extract 7 0) (bvlshr ((_ zero_extend 2) op) dist))");
}|
|
||
| TEST_CASE("smt2_convt conversion for shifts", "[core][solvers][smt2]") | ||
| { | ||
| GIVEN("A shift expression with equal-with operands") |
There was a problem hiding this comment.
| GIVEN("A shift expression with equal-with operands") | |
| GIVEN("A shift expression with equal-width operands") |
This fixes the case of converting shifts where the shift distance is wider than the shift operand to SMT-LIB2.
SMT-LIB2 requires that the width of the shift operand and the shift distance is the same. To not lose leading bits of the shift distance, use the wider one of the two as the width of the shift, and truncate the result when needed.