Skip to content

Commit c750f5e

Browse files
committed
Add conversion for rol and ror operators to c output
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
1 parent 932d41d commit c750f5e

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

src/ansi-c/expr2c.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2290,6 +2290,72 @@ std::string expr2ct::convert_initializer_list(const exprt &src)
22902290
return dest;
22912291
}
22922292

2293+
std::string expr2ct::convert_rox(const exprt &src, unsigned precedence)
2294+
{
2295+
// AAAA rox n == (AAAA lhs_op n % width(AAAA))
2296+
// | (AAAA rhs_op (width(AAAA) - n % width(AAAA)))
2297+
// Where lhs_op and rhs_op depend on whether it is rol or ror
2298+
// auto rotate_expr = to_binary_expr(src);
2299+
auto rotate_expr = expr_checked_cast<shift_exprt>(src);
2300+
// Get AAAA and if it's signed wrap it in a cast to remove
2301+
// the sign since this messes with C shifts
2302+
exprt &op0 = rotate_expr.op();
2303+
size_t type_width;
2304+
if(can_cast_type<signedbv_typet>(op0.type()))
2305+
{
2306+
// Set the type width
2307+
type_width = to_signedbv_type(op0.type()).get_width();
2308+
// Shifts in C are arithmetic and care about sign, by forcing
2309+
// a cast to unsigned we force the shifts to perform rol/r
2310+
op0 = typecast_exprt(op0, unsignedbv_typet(type_width));
2311+
}
2312+
else if(can_cast_type<unsignedbv_typet>(op0.type()))
2313+
{
2314+
// Set the type width
2315+
type_width = to_unsignedbv_type(op0.type()).get_width();
2316+
}
2317+
else
2318+
{
2319+
// Type that can't be represented as bitvector
2320+
// get some kind of width in a potentially unsafe way
2321+
type_width = op0.type().get_size_t("width");
2322+
}
2323+
// Construct the "width(AAAA)" constant
2324+
const exprt width_expr =
2325+
from_integer(type_width, rotate_expr.distance().type());
2326+
// Apply modulo to n since shifting will overflow
2327+
// That is: 0001 << 4 == 0, but 0001 rol 4 == 0001
2328+
const exprt distance_modulo_width =
2329+
mod_exprt(rotate_expr.distance(), width_expr);
2330+
// Now put the pieces together
2331+
// width(AAAA) - (n % width(AAAA))
2332+
const auto complement_width_expr =
2333+
minus_exprt(width_expr, distance_modulo_width);
2334+
// lhs and rhs components defined according to rol/ror
2335+
exprt lhs_expr;
2336+
exprt rhs_expr;
2337+
if(src.id() == ID_rol)
2338+
{
2339+
// AAAA << (n % width(AAAA))
2340+
lhs_expr = shl_exprt(op0, distance_modulo_width);
2341+
// AAAA >> complement_width_expr
2342+
rhs_expr = ashr_exprt(op0, complement_width_expr);
2343+
}
2344+
else if(src.id() == ID_ror)
2345+
{
2346+
// AAAA >> (n % width(AAAA))
2347+
lhs_expr = ashr_exprt(op0, distance_modulo_width);
2348+
// AAAA << complement_width_expr
2349+
rhs_expr = shl_exprt(op0, complement_width_expr);
2350+
}
2351+
else
2352+
{
2353+
// Someone called this function when they shouldn't have.
2354+
UNREACHABLE;
2355+
}
2356+
return convert_with_precedence(bitor_exprt(lhs_expr, rhs_expr), precedence);
2357+
}
2358+
22932359
std::string expr2ct::convert_designated_initializer(const exprt &src)
22942360
{
22952361
if(src.operands().size()!=1)
@@ -3794,6 +3860,9 @@ std::string expr2ct::convert_with_precedence(
37943860
else if(src.id()==ID_type)
37953861
return convert(src.type());
37963862

3863+
else if(src.id() == ID_rol || src.id() == ID_ror)
3864+
return convert_rox(src, precedence);
3865+
37973866
auto function_string_opt = convert_function(src);
37983867
if(function_string_opt.has_value())
37993868
return *function_string_opt;

src/ansi-c/expr2c_class.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,15 @@ class expr2ct
126126
const std::string &symbol2,
127127
unsigned precedence);
128128

129+
/// Conversion function from rol/ror expressions to C code strings
130+
/// Note that this constructs a complex expression to do bit
131+
/// twiddling since rol/ror operations are not native to ANSI-C.
132+
/// The complex expression is then recursively converted.
133+
/// \param src: is an exprt that must be either an rol or ror
134+
/// \param precedence: precedence for bracketing
135+
/// \returns string for performing rol/ror as bit twiddling with C
136+
std::string convert_rox(const exprt &src, unsigned precedence);
137+
129138
std::string convert_overflow(
130139
const exprt &src, unsigned &precedence);
131140

0 commit comments

Comments
 (0)