Make real functions in processes use parent stack for return value.
This commit is contained in:
parent
e44010c2a3
commit
bfc9cd8715
|
|
@ -205,11 +205,8 @@ void draw_ufunc_real(ivl_expr_t expr)
|
||||||
/* Take in arguments to function and call the function code. */
|
/* Take in arguments to function and call the function code. */
|
||||||
draw_ufunc_preamble(expr);
|
draw_ufunc_preamble(expr);
|
||||||
|
|
||||||
/* Return value signal cannot be an array. */
|
/* The %callf/real function emitted by the preamble leaves
|
||||||
assert(ivl_signal_dimensions(retval) == 0);
|
the result in the stack for us. */
|
||||||
|
|
||||||
/* Load the result into a word. */
|
|
||||||
fprintf(vvp_out, " %%load/real v%p_0;\n", retval);
|
|
||||||
|
|
||||||
draw_ufunc_epilogue(expr);
|
draw_ufunc_epilogue(expr);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -574,6 +574,18 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
|
||||||
var = ivl_lval_sig(lval);
|
var = ivl_lval_sig(lval);
|
||||||
assert(var != 0);
|
assert(var != 0);
|
||||||
|
|
||||||
|
/* Special Case: If the l-value signal is named after its scope,
|
||||||
|
and the scope is a function, then this is an assign to a return
|
||||||
|
value and should be handled differently. */
|
||||||
|
ivl_scope_t sig_scope = ivl_signal_scope(var);
|
||||||
|
if ((ivl_scope_type(sig_scope) == IVL_SCT_FUNCTION)
|
||||||
|
&& (strcmp(ivl_signal_basename(var), ivl_scope_basename(sig_scope)) == 0)) {
|
||||||
|
assert(ivl_signal_dimensions(var) == 0);
|
||||||
|
fprintf(vvp_out, " %%ret/real 0; Assign to %s\n",
|
||||||
|
ivl_signal_basename(var));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (ivl_signal_dimensions(var) == 0) {
|
if (ivl_signal_dimensions(var) == 0) {
|
||||||
fprintf(vvp_out, " %%store/real v%p_0;\n", var);
|
fprintf(vvp_out, " %%store/real v%p_0;\n", var);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -449,6 +449,16 @@ static void draw_reg_in_scope(ivl_signal_t sig)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Special Case: If this variable is the return value of a function,
|
||||||
|
then it need to exist as an actual variable. */
|
||||||
|
if ((ivl_signal_data_type(sig)==IVL_VT_REAL)
|
||||||
|
&& (ivl_scope_type(ivl_signal_scope(sig))==IVL_SCT_FUNCTION)
|
||||||
|
&& (strcmp(ivl_signal_basename(sig),ivl_scope_basename(ivl_signal_scope(sig))) == 0)) {
|
||||||
|
fprintf(vvp_out, "; Variable %s is REAL return value of scope S_%p\n",
|
||||||
|
ivl_signal_basename(sig), ivl_signal_scope(sig));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const char *datatype_flag = ivl_signal_integer(sig) ? "/i" :
|
const char *datatype_flag = ivl_signal_integer(sig) ? "/i" :
|
||||||
ivl_signal_signed(sig)? "/s" : "";
|
ivl_signal_signed(sig)? "/s" : "";
|
||||||
const char *local_flag = local_flag_str(sig);
|
const char *local_flag = local_flag_str(sig);
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,7 @@ extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
|
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
|
extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_REPLICATE(vthread_t thr, vvp_code_t code);
|
extern bool of_REPLICATE(vthread_t thr, vvp_code_t code);
|
||||||
|
extern bool of_RET_REAL(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_SCOPY(vthread_t thr, vvp_code_t code);
|
extern bool of_SCOPY(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_SET_DAR_OBJ_REAL(vthread_t thr, vvp_code_t code);
|
extern bool of_SET_DAR_OBJ_REAL(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_SET_DAR_OBJ_STR(vthread_t thr, vvp_code_t code);
|
extern bool of_SET_DAR_OBJ_STR(vthread_t thr, vvp_code_t code);
|
||||||
|
|
|
||||||
|
|
@ -249,6 +249,7 @@ static const struct opcode_table_s opcode_table[] = {
|
||||||
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||||
{ "%release/wr", of_RELEASE_WR, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
{ "%release/wr", of_RELEASE_WR, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||||
{ "%replicate", of_REPLICATE, 1,{OA_NUMBER, OA_NONE,OA_NONE} },
|
{ "%replicate", of_REPLICATE, 1,{OA_NUMBER, OA_NONE,OA_NONE} },
|
||||||
|
{ "%ret/real", of_RET_REAL, 1,{OA_NUMBER, OA_NONE,OA_NONE} },
|
||||||
{ "%scopy", of_SCOPY, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
{ "%scopy", of_SCOPY, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||||
{ "%set/dar/obj/real",of_SET_DAR_OBJ_REAL,1,{OA_NUMBER,OA_NONE,OA_NONE} },
|
{ "%set/dar/obj/real",of_SET_DAR_OBJ_REAL,1,{OA_NUMBER,OA_NONE,OA_NONE} },
|
||||||
{ "%set/dar/obj/str", of_SET_DAR_OBJ_STR, 1,{OA_NUMBER,OA_NONE,OA_NONE} },
|
{ "%set/dar/obj/str", of_SET_DAR_OBJ_STR, 1,{OA_NUMBER,OA_NONE,OA_NONE} },
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ out, then this function is a no-op.
|
||||||
* %callf/void <code-label>, <scope-label>
|
* %callf/void <code-label>, <scope-label>
|
||||||
|
|
||||||
More directly implement function calling. This subsumes the %fork and
|
More directly implement function calling. This subsumes the %fork and
|
||||||
%join of the mroe general task and block calling, but is optimized for
|
%join of the more general task and block calling, but is optimized for
|
||||||
functions, which are threads of a special, constrained sort.
|
functions, which are threads of a special, constrained sort.
|
||||||
|
|
||||||
The different variants reflect the different return types for the
|
The different variants reflect the different return types for the
|
||||||
|
|
@ -1004,6 +1004,18 @@ Pop the vec4 value, replicate it <count> times, then push the
|
||||||
result. In other words, push the concatenation of <count> copies.
|
result. In other words, push the concatenation of <count> copies.
|
||||||
See also the %concat instruction.
|
See also the %concat instruction.
|
||||||
|
|
||||||
|
* %ret/obj <index>
|
||||||
|
* %ret/real <index>
|
||||||
|
* %ret/str <index>
|
||||||
|
* %ret/vec4 <index>
|
||||||
|
|
||||||
|
Write a value to the indexed function argument. The value is popped
|
||||||
|
from the appropriate stack and written into the argument. The return
|
||||||
|
value of a function is the first argument of the appropriate type, so
|
||||||
|
for example to store the return value for a real function, use
|
||||||
|
"%ret/real 0;". It is up to the function caller to set up the argument
|
||||||
|
references.
|
||||||
|
|
||||||
* %set/dar/obj/real <index>
|
* %set/dar/obj/real <index>
|
||||||
* %set/dar/obj/str <index>
|
* %set/dar/obj/str <index>
|
||||||
* %set/dar/obj/vec4 <index>
|
* %set/dar/obj/vec4 <index>
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,11 @@ struct vthread_s {
|
||||||
uint64_t w_uint;
|
uint64_t w_uint;
|
||||||
} words[WORDS_COUNT];
|
} words[WORDS_COUNT];
|
||||||
|
|
||||||
|
// These vectors are depths within the parent thread's
|
||||||
|
// corresponding stack. This is how the %ret/* instructions
|
||||||
|
// get at parent thread arguments.
|
||||||
|
vector<unsigned> args_real;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vector<vvp_vector4_t>stack_vec4_;
|
vector<vvp_vector4_t>stack_vec4_;
|
||||||
public:
|
public:
|
||||||
|
|
@ -167,6 +172,12 @@ struct vthread_s {
|
||||||
unsigned use_index = stack_real_.size()-1-depth;
|
unsigned use_index = stack_real_.size()-1-depth;
|
||||||
return stack_real_[use_index];
|
return stack_real_[use_index];
|
||||||
}
|
}
|
||||||
|
inline void poke_real(unsigned depth, double val)
|
||||||
|
{
|
||||||
|
assert(depth < stack_real_.size());
|
||||||
|
unsigned use_index = stack_real_.size()-1-depth;
|
||||||
|
stack_real_[use_index] = val;
|
||||||
|
}
|
||||||
inline void pop_real(unsigned cnt)
|
inline void pop_real(unsigned cnt)
|
||||||
{
|
{
|
||||||
while (cnt > 0) {
|
while (cnt > 0) {
|
||||||
|
|
@ -1270,11 +1281,10 @@ bool of_BREAKPOINT(vthread_t, vvp_code_t)
|
||||||
* %callf/void <code-label>, <scope-label>
|
* %callf/void <code-label>, <scope-label>
|
||||||
* Combine the %fork and %join steps for invoking a function.
|
* Combine the %fork and %join steps for invoking a function.
|
||||||
*/
|
*/
|
||||||
static bool do_callf_void(vthread_t thr, vvp_code_t cp)
|
static bool do_callf_void(vthread_t thr, vthread_t child)
|
||||||
{
|
{
|
||||||
vthread_t child = vthread_new(cp->cptr2, cp->scope);
|
|
||||||
|
|
||||||
if (cp->scope->is_automatic()) {
|
if (child->parent_scope->is_automatic()) {
|
||||||
/* The context allocated for this child is the top entry
|
/* The context allocated for this child is the top entry
|
||||||
on the write context stack */
|
on the write context stack */
|
||||||
child->wt_context = thr->wt_context;
|
child->wt_context = thr->wt_context;
|
||||||
|
|
@ -1289,7 +1299,7 @@ static bool do_callf_void(vthread_t thr, vvp_code_t cp)
|
||||||
|
|
||||||
// Execute the function. This SHOULD run the function to completion,
|
// Execute the function. This SHOULD run the function to completion,
|
||||||
// but there are some exceptional situations where it won't.
|
// but there are some exceptional situations where it won't.
|
||||||
assert(cp->scope->get_type_code() == vpiFunction);
|
assert(child->parent_scope->get_type_code() == vpiFunction);
|
||||||
thr->task_func_children.insert(child);
|
thr->task_func_children.insert(child);
|
||||||
child->is_scheduled = 1;
|
child->is_scheduled = 1;
|
||||||
child->i_am_in_function = 1;
|
child->i_am_in_function = 1;
|
||||||
|
|
@ -1309,36 +1319,44 @@ static bool do_callf_void(vthread_t thr, vvp_code_t cp)
|
||||||
|
|
||||||
bool of_CALLF_OBJ(vthread_t thr, vvp_code_t cp)
|
bool of_CALLF_OBJ(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
return do_callf_void(thr, cp);
|
vthread_t child = vthread_new(cp->cptr2, cp->scope);
|
||||||
|
return do_callf_void(thr, child);
|
||||||
|
|
||||||
// XXXX NOT IMPLEMENTED
|
// XXXX NOT IMPLEMENTED
|
||||||
}
|
}
|
||||||
|
|
||||||
bool of_CALLF_REAL(vthread_t thr, vvp_code_t cp)
|
bool of_CALLF_REAL(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
// XXXX Here, I should arrange for a reference to the destination variable
|
vthread_t child = vthread_new(cp->cptr2, cp->scope);
|
||||||
// XXXX as a place in my stack. The function will write to that place in
|
|
||||||
// XXXX my stack for me.
|
// This is the return value. Push a place-holder value. The function
|
||||||
return do_callf_void(thr, cp);
|
// will replace this with the actual value using a %ret/real instruction.
|
||||||
|
thr->push_real(0.0);
|
||||||
|
child->args_real.push_back(0);
|
||||||
|
|
||||||
|
return do_callf_void(thr, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool of_CALLF_STR(vthread_t thr, vvp_code_t cp)
|
bool of_CALLF_STR(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
return do_callf_void(thr, cp);
|
vthread_t child = vthread_new(cp->cptr2, cp->scope);
|
||||||
|
return do_callf_void(thr, child);
|
||||||
|
|
||||||
// XXXX NOT IMPLEMENTED
|
// XXXX NOT IMPLEMENTED
|
||||||
}
|
}
|
||||||
|
|
||||||
bool of_CALLF_VEC4(vthread_t thr, vvp_code_t cp)
|
bool of_CALLF_VEC4(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
return do_callf_void(thr, cp);
|
vthread_t child = vthread_new(cp->cptr2, cp->scope);
|
||||||
|
return do_callf_void(thr, child);
|
||||||
|
|
||||||
// XXXX NOT IMPLEMENTED
|
// XXXX NOT IMPLEMENTED
|
||||||
}
|
}
|
||||||
|
|
||||||
bool of_CALLF_VOID(vthread_t thr, vvp_code_t cp)
|
bool of_CALLF_VOID(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
return do_callf_void(thr, cp);
|
vthread_t child = vthread_new(cp->cptr2, cp->scope);
|
||||||
|
return do_callf_void(thr, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -4930,6 +4948,22 @@ bool of_REPLICATE(vthread_t thr, vvp_code_t cp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* %ret/real <index>
|
||||||
|
*/
|
||||||
|
bool of_RET_REAL(vthread_t thr, vvp_code_t cp)
|
||||||
|
{
|
||||||
|
size_t index = cp->number;
|
||||||
|
double val = thr->pop_real();
|
||||||
|
|
||||||
|
assert(index >= 0 && index < thr->args_real.size());
|
||||||
|
unsigned depth = thr->args_real[index];
|
||||||
|
// Use the depth to put the value into the stack of
|
||||||
|
// the parent thread.
|
||||||
|
thr->parent->poke_real(depth, val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool of_SCOPY(vthread_t thr, vvp_code_t)
|
bool of_SCOPY(vthread_t thr, vvp_code_t)
|
||||||
{
|
{
|
||||||
vvp_object_t tmp;
|
vvp_object_t tmp;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue