Skip to content

Commit d7f72d5

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 #6241
1 parent d5c9ef8 commit d7f72d5

File tree

9 files changed

+166
-43
lines changed

9 files changed

+166
-43
lines changed

src/analyses/invariant_set_domain.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ void invariant_set_domaint::transform(
5050
}
5151
break;
5252

53-
case RETURN:
54-
// ignore
55-
break;
53+
case RETURN:
54+
// ignore
55+
break;
5656

57-
case ASSIGN:
57+
case ASSIGN:
5858
{
5959
const code_assignt &assignment = from_l->get_assign();
6060
invariant_set.assignment(assignment.lhs(), assignment.rhs());

src/ansi-c/expr2c.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2290,6 +2290,71 @@ 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_expr = minus_exprt(width_expr, distance_modulo_width);
2333+
// lhs and rhs components defined according to rol/ror
2334+
exprt lhs_expr;
2335+
exprt rhs_expr;
2336+
if(src.id() == ID_rol)
2337+
{
2338+
// AAAA << (n % width(AAAA))
2339+
lhs_expr = shl_exprt(op0, distance_modulo_width);
2340+
// AAAA >> complement_expr
2341+
rhs_expr = ashr_exprt(op0, complement_expr);
2342+
}
2343+
else if(src.id() == ID_ror)
2344+
{
2345+
// AAAA >> (n % width(AAAA))
2346+
lhs_expr = ashr_exprt(op0, distance_modulo_width);
2347+
// AAAA << complement_expr
2348+
rhs_expr = shl_exprt(op0, complement_expr);
2349+
}
2350+
else
2351+
{
2352+
// Someone called this function when they shouldn't have.
2353+
UNREACHABLE;
2354+
}
2355+
return convert_with_precedence(bitor_exprt(lhs_expr, rhs_expr), precedence);
2356+
}
2357+
22932358
std::string expr2ct::convert_designated_initializer(const exprt &src)
22942359
{
22952360
if(src.operands().size()!=1)
@@ -3794,6 +3859,9 @@ std::string expr2ct::convert_with_precedence(
37943859
else if(src.id()==ID_type)
37953860
return convert(src.type());
37963861

3862+
else if(src.id() == ID_rol || src.id() == ID_ror)
3863+
return convert_rox(src, precedence);
3864+
37973865
auto function_string_opt = convert_function(src);
37983866
if(function_string_opt.has_value())
37993867
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

src/goto-instrument/dot.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,8 @@ void dott::write_dot_subgraph(
155155
function_calls.push_back(
156156
std::pair<std::string, exprt>(ss.str(), function_call.function()));
157157
}
158-
else if(it->is_assign() ||
159-
it->is_decl() ||
160-
it->is_return() ||
161-
it->is_other())
158+
else if(
159+
it->is_assign() || it->is_decl() || it->is_return() || it->is_other())
162160
{
163161
std::string t = from_expr(ns, function_id, it->get_code());
164162
while(t[ t.size()-1 ]=='\n')

src/goto-instrument/function.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,14 @@ void function_exit(
142142
assert(last->is_end_function());
143143

144144
// is there already a return?
145-
bool has_return=false;
145+
bool has_return = false;
146146

147147
if(last!=body.instructions.begin())
148148
{
149149
goto_programt::targett before_last=last;
150150
--before_last;
151151
if(before_last->is_return())
152-
has_return=true;
152+
has_return = true;
153153
}
154154

155155
if(!has_return)

src/goto-instrument/wmm/goto2graph.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,13 +1227,9 @@ void inline instrumentert::add_instr_to_interleaving(
12271227
goto_programt::instructionst::iterator it,
12281228
goto_programt &interleaving)
12291229
{
1230-
if(it->is_return() ||
1231-
it->is_throw() ||
1232-
it->is_catch() ||
1233-
it->is_skip() ||
1234-
it->is_dead() ||
1235-
it->is_start_thread() ||
1236-
it->is_end_thread())
1230+
if(
1231+
it->is_return() || it->is_throw() || it->is_catch() || it->is_skip() ||
1232+
it->is_dead() || it->is_start_thread() || it->is_end_thread())
12371233
return;
12381234

12391235
if(it->is_atomic_begin() ||

src/goto-programs/goto_program.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,8 @@ std::ostream &goto_programt::output_instruction(
174174
{
175175
const auto &landingpad = to_code_landingpad(instruction.get_code());
176176
out << "EXCEPTION LANDING PAD ("
177-
<< from_type(ns, identifier, landingpad.catch_expr().type())
178-
<< ' '
179-
<< from_expr(ns, identifier, landingpad.catch_expr())
180-
<< ")";
177+
<< from_type(ns, identifier, landingpad.catch_expr().type()) << ' '
178+
<< from_expr(ns, identifier, landingpad.catch_expr()) << ")";
181179
}
182180
else if(instruction.get_code().get_statement() == ID_push_catch)
183181
{

src/goto-programs/goto_program.h

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -467,24 +467,78 @@ class goto_programt
467467
type = GOTO;
468468
}
469469

470-
bool is_goto () const { return type==GOTO; }
471-
bool is_return () const { return type==RETURN; }
472-
bool is_assign () const { return type==ASSIGN; }
473-
bool is_function_call() const { return type==FUNCTION_CALL; }
474-
bool is_throw () const { return type==THROW; }
475-
bool is_catch () const { return type==CATCH; }
476-
bool is_skip () const { return type==SKIP; }
477-
bool is_location () const { return type==LOCATION; }
478-
bool is_other () const { return type==OTHER; }
479-
bool is_decl () const { return type==DECL; }
480-
bool is_dead () const { return type==DEAD; }
481-
bool is_assume () const { return type==ASSUME; }
482-
bool is_assert () const { return type==ASSERT; }
483-
bool is_atomic_begin () const { return type==ATOMIC_BEGIN; }
484-
bool is_atomic_end () const { return type==ATOMIC_END; }
485-
bool is_start_thread () const { return type==START_THREAD; }
486-
bool is_end_thread () const { return type==END_THREAD; }
487-
bool is_end_function () const { return type==END_FUNCTION; }
470+
bool is_goto() const
471+
{
472+
return type == GOTO;
473+
}
474+
bool is_return() const
475+
{
476+
return type == RETURN;
477+
}
478+
bool is_assign() const
479+
{
480+
return type == ASSIGN;
481+
}
482+
bool is_function_call() const
483+
{
484+
return type == FUNCTION_CALL;
485+
}
486+
bool is_throw() const
487+
{
488+
return type == THROW;
489+
}
490+
bool is_catch() const
491+
{
492+
return type == CATCH;
493+
}
494+
bool is_skip() const
495+
{
496+
return type == SKIP;
497+
}
498+
bool is_location() const
499+
{
500+
return type == LOCATION;
501+
}
502+
bool is_other() const
503+
{
504+
return type == OTHER;
505+
}
506+
bool is_decl() const
507+
{
508+
return type == DECL;
509+
}
510+
bool is_dead() const
511+
{
512+
return type == DEAD;
513+
}
514+
bool is_assume() const
515+
{
516+
return type == ASSUME;
517+
}
518+
bool is_assert() const
519+
{
520+
return type == ASSERT;
521+
}
522+
bool is_atomic_begin() const
523+
{
524+
return type == ATOMIC_BEGIN;
525+
}
526+
bool is_atomic_end() const
527+
{
528+
return type == ATOMIC_END;
529+
}
530+
bool is_start_thread() const
531+
{
532+
return type == START_THREAD;
533+
}
534+
bool is_end_thread() const
535+
{
536+
return type == END_THREAD;
537+
}
538+
bool is_end_function() const
539+
{
540+
return type == END_FUNCTION;
541+
}
488542
bool is_incomplete_goto() const
489543
{
490544
return type == INCOMPLETE_GOTO;

src/goto-programs/goto_trace.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -570,10 +570,10 @@ void show_full_goto_trace(
570570
break;
571571

572572
case goto_trace_stept::typet::ASSIGNMENT:
573-
if(step.pc->is_assign() ||
574-
step.pc->is_return() || // returns have a lhs!
575-
step.pc->is_function_call() ||
576-
(step.pc->is_other() && step.full_lhs.is_not_nil()))
573+
if(
574+
step.pc->is_assign() || step.pc->is_return() || // returns have a lhs!
575+
step.pc->is_function_call() ||
576+
(step.pc->is_other() && step.full_lhs.is_not_nil()))
577577
{
578578
if(prev_step_nr!=step.step_nr || first_step)
579579
{

0 commit comments

Comments
 (0)