Skip to content

Commit 5c3997d

Browse files
committed
Refectors how CBMC interprets a codet thread-block
The current use of labels starting with a specific prefix (__CPROVER_ASYNC_) is a viable way to insert concurrency related goto-instructions in the goto program for C programs. However, in the context of a java program, where labels are removed by the compiler this is not possible. In-order to facilitate the support of both C and Java concurrency, this commit does the following change: In 'goto_convertt::convert_label' instead of inserting a codet(ID_start_thread) we insert the actual goto-instructions that would have previously been generated by 'goto_convertt::convert_start_thread' when 'ID_started_thread' is being parsed.
1 parent 001c1a2 commit 5c3997d

File tree

2 files changed

+69
-39
lines changed

2 files changed

+69
-39
lines changed

src/goto-programs/goto_convert.cpp

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -344,23 +344,33 @@ void goto_convertt::convert_label(
344344

345345
goto_programt tmp;
346346

347-
// magic thread creation label?
347+
// magic thread creation label.
348+
// The "__CPROVER_ASYNC_" signals the start of a sequence of instructions
349+
// that can be executed in parallel, i.e, a new thread.
348350
if(has_prefix(id2string(label), "__CPROVER_ASYNC_"))
349351
{
350-
// this is like a START_THREAD
351-
codet tmp_code(ID_start_thread);
352-
tmp_code.copy_to_operands(code.op0());
353-
tmp_code.add_source_location()=code.source_location();
354-
convert(tmp_code, tmp);
352+
// the body of the thread is expected to be
353+
// in the operand.
354+
INVARIANT(code.op0().is_not_nil(),
355+
"op0 in magic thread creation label is null");
356+
357+
// replace the magic thread creation label with a
358+
// thread block (START_THREAD...END_THREAD).
359+
code_blockt thread_body;
360+
thread_body.add(to_code(code.op0()));
361+
thread_body.add_source_location()=code.source_location();
362+
generate_thread_block(thread_body, dest);
355363
}
356364
else
365+
{
357366
convert(to_code(code.op0()), tmp);
358367

359-
goto_programt::targett target=tmp.instructions.begin();
360-
dest.destructive_append(tmp);
368+
goto_programt::targett target=tmp.instructions.begin();
369+
dest.destructive_append(tmp);
361370

362-
targets.labels.insert({label, {target, targets.destructor_stack}});
363-
target->labels.push_front(label);
371+
targets.labels.insert({label, {target, targets.destructor_stack}});
372+
target->labels.push_front(label);
373+
}
364374
}
365375

366376
void goto_convertt::convert_gcc_local_label(
@@ -1539,39 +1549,14 @@ void goto_convertt::convert_start_thread(
15391549
const codet &code,
15401550
goto_programt &dest)
15411551
{
1542-
if(code.operands().size()!=1)
1543-
{
1544-
error().source_location=code.find_source_location();
1545-
error() << "start_thread expects one operand" << eom;
1546-
throw 0;
1547-
}
1548-
15491552
goto_programt::targett start_thread=
15501553
dest.add_instruction(START_THREAD);
1551-
15521554
start_thread->source_location=code.source_location();
1555+
start_thread->code=code;
15531556

1554-
{
1555-
// start_thread label;
1556-
// goto tmp;
1557-
// label: op0-code
1558-
// end_thread
1559-
// tmp: skip
1560-
1561-
goto_programt::targett goto_instruction=dest.add_instruction(GOTO);
1562-
goto_instruction->guard=true_exprt();
1563-
goto_instruction->source_location=code.source_location();
1564-
1565-
goto_programt tmp;
1566-
convert(to_code(code.op0()), tmp);
1567-
goto_programt::targett end_thread=tmp.add_instruction(END_THREAD);
1568-
end_thread->source_location=code.source_location();
1569-
1570-
start_thread->targets.push_back(tmp.instructions.begin());
1571-
dest.destructive_append(tmp);
1572-
goto_instruction->targets.push_back(dest.add_instruction(SKIP));
1573-
dest.instructions.back().source_location=code.source_location();
1574-
}
1557+
// remember it to do target later
1558+
targets.gotos.push_back(
1559+
std::make_pair(start_thread, targets.destructor_stack));
15751560
}
15761561

15771562
void goto_convertt::convert_end_thread(
@@ -2242,3 +2227,43 @@ void goto_convert(
22422227

22432228
::goto_convert(to_code(symbol.value), symbol_table, dest, message_handler);
22442229
}
2230+
2231+
/// Generates the necessary goto-instructions to represent a thread-block.
2232+
/// Specifically, the following instructions are generated:
2233+
///
2234+
/// A: START_THREAD : C
2235+
/// B: GOTO Z
2236+
/// C: SKIP
2237+
/// D: {THREAD BODY}
2238+
/// E: END_THREAD
2239+
/// Z: SKIP
2240+
///
2241+
/// \param thread_body: sequence of codet's that can be executed
2242+
/// in parallel.
2243+
/// \param [out] dest: resulting goto-instructions.
2244+
void goto_convertt::generate_thread_block(
2245+
const code_blockt &thread_body,
2246+
goto_programt &dest)
2247+
{
2248+
goto_programt preamble, body, postamble;
2249+
2250+
goto_programt::targett c=body.add_instruction();
2251+
c->make_skip();
2252+
convert(thread_body, body);
2253+
2254+
goto_programt::targett e=postamble.add_instruction(END_THREAD);
2255+
e->source_location=thread_body.source_location();
2256+
goto_programt::targett z=postamble.add_instruction();
2257+
z->make_skip();
2258+
2259+
goto_programt::targett a=preamble.add_instruction(START_THREAD);
2260+
a->source_location=thread_body.source_location();
2261+
a->targets.push_back(c);
2262+
goto_programt::targett b=preamble.add_instruction();
2263+
b->source_location=thread_body.source_location();
2264+
b->make_goto(z);
2265+
2266+
dest.destructive_append(preamble);
2267+
dest.destructive_append(body);
2268+
dest.destructive_append(postamble);
2269+
}

src/goto-programs/goto_convert_class.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,11 @@ class goto_convertt:public messaget
502502
const irep_idt &id,
503503
std::list<exprt> &dest);
504504

505+
// START_THREAD; ... END_THREAD;
506+
void generate_thread_block(
507+
const code_blockt &thread_body,
508+
goto_programt &dest);
509+
505510
//
506511
// misc
507512
//

0 commit comments

Comments
 (0)