Implement fork-join_none in vvp.
This commit is contained in:
parent
47ddf5220c
commit
3b7619b46c
|
|
@ -1314,55 +1314,85 @@ static int show_stmt_fork(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
{
|
{
|
||||||
unsigned idx;
|
unsigned idx;
|
||||||
int rc = 0;
|
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);
|
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 out = transient_id++;
|
||||||
unsigned id_base = 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
|
/* 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
|
name, then we can put one of the sub-threads in the current
|
||||||
thread, so decrement the count by one and use the current
|
thread, so decrement the count by one and use the current
|
||||||
scope for all the threads. */
|
scope for all the threads. */
|
||||||
if (! is_named) {
|
if (is_embeddable)
|
||||||
cnt -= 1;
|
join_count -= 1;
|
||||||
|
if (scope==0)
|
||||||
scope = sscope;
|
scope = sscope;
|
||||||
}
|
|
||||||
|
|
||||||
transient_id += cnt;
|
transient_id += join_count;
|
||||||
|
|
||||||
/* Draw a fork statement for all but one of the threads of the
|
/* 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
|
fork/join. Send the threads off to a bit of code where they
|
||||||
are implemented. */
|
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",
|
fprintf(vvp_out, " %%fork t_%u, S_%p;\n",
|
||||||
id_base+idx, scope);
|
id_base+idx, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we are putting one sub-thread into the current thread,
|
/* If we are putting one sub-thread into the current thread,
|
||||||
then draw its code here. */
|
then draw its code here. */
|
||||||
if (! is_named)
|
if (is_embeddable)
|
||||||
rc += show_statement(ivl_stmt_block_stmt(net, cnt), scope);
|
rc += show_statement(ivl_stmt_block_stmt(net, join_count), scope);
|
||||||
|
|
||||||
|
|
||||||
/* Generate enough joins to collect all the sub-threads. */
|
/* 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");
|
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);
|
fprintf(vvp_out, " %%jmp t_%u;\n", out);
|
||||||
|
|
||||||
/* Change the compiling scope to be the named forks scope. */
|
/* Change the compiling scope to be the named forks scope. */
|
||||||
if (is_named) fprintf(vvp_out, " .scope S_%p;\n", scope);
|
if (is_named) fprintf(vvp_out, " .scope S_%p;\n", scope);
|
||||||
/* Generate the sub-threads themselves. */
|
/* 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);
|
fprintf(vvp_out, "t_%u ;\n", id_base+idx);
|
||||||
clear_expression_lookaside();
|
clear_expression_lookaside();
|
||||||
rc += show_statement(ivl_stmt_block_stmt(net, idx), scope);
|
rc += show_statement(ivl_stmt_block_stmt(net, idx), scope);
|
||||||
fprintf(vvp_out, " %%end;\n");
|
fprintf(vvp_out, " %%end;\n");
|
||||||
}
|
}
|
||||||
/* Return to the previous scope. */
|
/* 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
|
/* This is the label for the out. Use this to branch around
|
||||||
the implementations of all the child threads. */
|
the implementations of all the child threads. */
|
||||||
|
|
@ -2073,6 +2103,8 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IVL_ST_FORK:
|
case IVL_ST_FORK:
|
||||||
|
case IVL_ST_FORK_JOIN_ANY:
|
||||||
|
case IVL_ST_FORK_JOIN_NONE:
|
||||||
rc += show_stmt_fork(net, sscope);
|
rc += show_stmt_fork(net, sscope);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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_JMP0XZ(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_JMP1(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(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_AR(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_LOAD_AV(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);
|
extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code);
|
||||||
|
|
|
||||||
|
|
@ -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/0xz",of_JMP0XZ, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
|
||||||
{ "%jmp/1", of_JMP1, 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", 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/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/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} },
|
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
|
||||||
|
|
|
||||||
|
|
@ -2892,6 +2892,44 @@ bool of_JOIN(vthread_t thr, vvp_code_t)
|
||||||
return false;
|
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>;
|
* %load/ar <bit>, <array-label>, <index>;
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue