Implement fork-join_none in vvp.

This commit is contained in:
Stephen Williams 2012-05-20 11:39:52 -07:00
parent 47ddf5220c
commit 3b7619b46c
4 changed files with 85 additions and 13 deletions

View File

@ -1314,55 +1314,85 @@ static int show_stmt_fork(ivl_statement_t net, ivl_scope_t sscope)
{
unsigned idx;
int rc = 0;
unsigned cnt = ivl_stmt_block_count(net);
unsigned join_count = ivl_stmt_block_count(net);
unsigned join_detach_count = 0;
ivl_scope_t scope = ivl_stmt_block_scope(net);
unsigned is_named = (scope != 0);
int is_named = (scope != 0);
/* This is TRUE if it is allowed to embed one of the threads
into this thread. */
int is_embeddable = 1;
unsigned out = transient_id++;
unsigned id_base = transient_id;
/* Children are certainly not embeddable if they are going
into a new scope. */
if (is_named)
is_embeddable = 0;
switch (ivl_statement_type(net)) {
case IVL_ST_FORK:
break;
case IVL_ST_FORK_JOIN_ANY:
if (join_count < 2)
break;
is_embeddable = 0;
join_detach_count = join_count - 1;
join_count = 1;
break;
case IVL_ST_FORK_JOIN_NONE:
is_embeddable = 0;
join_detach_count = join_count;
join_count = 0;
break;
default:
assert(0);
}
/* cnt is the number of sub-threads. If the fork-join has no
name, then we can put one of the sub-threads in the current
thread, so decrement the count by one and use the current
scope for all the threads. */
if (! is_named) {
cnt -= 1;
if (is_embeddable)
join_count -= 1;
if (scope==0)
scope = sscope;
}
transient_id += cnt;
transient_id += join_count;
/* Draw a fork statement for all but one of the threads of the
fork/join. Send the threads off to a bit of code where they
are implemented. */
for (idx = 0 ; idx < cnt ; idx += 1) {
for (idx = 0 ; idx < (join_count+join_detach_count) ; idx += 1) {
fprintf(vvp_out, " %%fork t_%u, S_%p;\n",
id_base+idx, scope);
}
/* If we are putting one sub-thread into the current thread,
then draw its code here. */
if (! is_named)
rc += show_statement(ivl_stmt_block_stmt(net, cnt), scope);
if (is_embeddable)
rc += show_statement(ivl_stmt_block_stmt(net, join_count), scope);
/* Generate enough joins to collect all the sub-threads. */
for (idx = 0 ; idx < cnt ; idx += 1) {
for (idx = 0 ; idx < join_count ; idx += 1)
fprintf(vvp_out, " %%join;\n");
}
if (join_detach_count > 0)
fprintf(vvp_out, " %%join/detach %u;\n", join_detach_count);
/* Jump around all the threads that I'm creating. */
fprintf(vvp_out, " %%jmp t_%u;\n", out);
/* Change the compiling scope to be the named forks scope. */
if (is_named) fprintf(vvp_out, " .scope S_%p;\n", scope);
/* Generate the sub-threads themselves. */
for (idx = 0 ; idx < cnt ; idx += 1) {
for (idx = 0 ; idx < (join_count + join_detach_count) ; idx += 1) {
fprintf(vvp_out, "t_%u ;\n", id_base+idx);
clear_expression_lookaside();
rc += show_statement(ivl_stmt_block_stmt(net, idx), scope);
fprintf(vvp_out, " %%end;\n");
}
/* Return to the previous scope. */
if (is_named) fprintf(vvp_out, " .scope S_%p;\n", sscope);
if (sscope) fprintf(vvp_out, " .scope S_%p;\n", sscope);
/* This is the label for the out. Use this to branch around
the implementations of all the child threads. */
@ -2073,6 +2103,8 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
break;
case IVL_ST_FORK:
case IVL_ST_FORK_JOIN_ANY:
case IVL_ST_FORK_JOIN_NONE:
rc += show_stmt_fork(net, sscope);
break;

View File

@ -115,6 +115,7 @@ extern bool of_JMP0(vthread_t thr, vvp_code_t code);
extern bool of_JMP0XZ(vthread_t thr, vvp_code_t code);
extern bool of_JMP1(vthread_t thr, vvp_code_t code);
extern bool of_JOIN(vthread_t thr, vvp_code_t code);
extern bool of_JOIN_DETACH(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AR(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code);

View File

@ -157,6 +157,7 @@ static const struct opcode_table_s opcode_table[] = {
{ "%jmp/0xz",of_JMP0XZ, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
{ "%jmp/1", of_JMP1, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
{ "%join", of_JOIN, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%join/detach",of_JOIN_DETACH,1,{OA_NUMBER,OA_NONE, OA_NONE} },
{ "%load/ar",of_LOAD_AR,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },

View File

@ -2892,6 +2892,44 @@ bool of_JOIN(vthread_t thr, vvp_code_t)
return false;
}
/*
* This %join/detach <n> instruction causes the thread to detach
* threads that were created by an earlier %fork.
*/
bool of_JOIN_DETACH(vthread_t thr, vvp_code_t cp)
{
unsigned long count = cp->number;
while (count > 0) {
assert(thr->child);
assert(thr->child->parent == thr);
assert(thr->fork_count > 0);
assert(thr->child->wt_context == 0);
thr->fork_count -= 1;
if (thr->child->i_have_ended) {
/* If the child has already ended, then reap it
instead of pulling it from the list. */
vthread_reap(thr->child);
} else {
/* Pull the child from the parent->child list. */
struct vthread_s*tmp = thr->child;
assert(tmp->fork_count == 0);
thr->child = tmp->child;
if (thr->child)
thr->child->parent = thr;
/* set up detach. */
tmp->parent = 0;
tmp->child = 0;
}
count -= 1;
}
return true;
}
/*
* %load/ar <bit>, <array-label>, <index>;
*/