Implement parameter alignment in the engine

The engine now requires non-v6 progs to store the log2 alignment for the
param struct in .param_alignment.

PR_EnterFunction is clearer and possibly more efficient.
This commit is contained in:
Bill Currie 2020-02-16 17:13:45 +09:00
parent 7a399c956b
commit f5741a979e
3 changed files with 64 additions and 50 deletions

View file

@ -1079,7 +1079,7 @@ typedef struct {
pr_int_t locals; pr_int_t locals;
pr_int_t profile; pr_int_t profile;
pr_int_t numparms; pr_int_t numparms;
uint8_t parm_size[MAX_PARMS]; dparmsize_t parm_size[MAX_PARMS];
dfunction_t *descriptor; dfunction_t *descriptor;
builtin_proc func; builtin_proc func;
} bfunction_t; } bfunction_t;
@ -1632,6 +1632,7 @@ struct progs_s {
pr_type_t *pr_saved_params; pr_type_t *pr_saved_params;
int pr_saved_argc; int pr_saved_argc;
int pr_param_size; ///< covers both params and return int pr_param_size; ///< covers both params and return
int pr_param_alignment; ///< covers both params and return
///@} ///@}
/// \name edicts /// \name edicts

View file

@ -142,6 +142,21 @@ PR_PopFrame (progs_t *pr)
pr->pr_xtstr = frame->tstr; pr->pr_xtstr = frame->tstr;
} }
static __attribute__((pure)) long
align_offset (long offset, dparmsize_t parmsize)
{
int mask = (1 << parmsize.alignment) - 1;
return (offset + mask) & ~mask;
}
static void
copy_param (pr_type_t *dst, pr_type_t *src, size_t size)
{
while (size--) {
memcpy (dst++, src++, sizeof (pr_type_t));
}
}
/** Setup the stackframe prior to calling a progs function. Saves all local /** Setup the stackframe prior to calling a progs function. Saves all local
data the called function will trample on and copies the parameters used data the called function will trample on and copies the parameters used
by the function into the function's local data space. by the function into the function's local data space.
@ -153,39 +168,44 @@ PR_PopFrame (progs_t *pr)
static void static void
PR_EnterFunction (progs_t *pr, bfunction_t *f) PR_EnterFunction (progs_t *pr, bfunction_t *f)
{ {
pr_int_t i, j, c, o; pr_int_t i;
pr_int_t k; pr_type_t *dstParams[MAX_PARMS];
pr_int_t count = 0;
int size[2] = {0, 0};
long paramofs = 0; long paramofs = 0;
long offs;
PR_PushFrame (pr); PR_PushFrame (pr);
if (f->numparms > 0) { if (f->numparms > 0) {
for (i = 0; i < 2 && i < f->numparms; i++) { paramofs = f->parm_start;
paramofs += f->parm_size[i]; for (i = 0; i < f->numparms; i++) {
size[i] = f->parm_size[i]; paramofs = align_offset (paramofs, f->parm_size[i]);
dstParams[i] = pr->pr_globals + paramofs;
paramofs += f->parm_size[i].size;
if (pr->pr_params[i] != pr->pr_real_params[i]) {
copy_param (pr->pr_real_params[i], pr->pr_params[i],
f->parm_size[i].size);
}
} }
count = i;
} else if (f->numparms < 0) { } else if (f->numparms < 0) {
for (i = 0; i < 2 && i < -f->numparms - 1; i++) { paramofs = f->parm_start + 2; // argc and argv
paramofs += f->parm_size[i]; for (i = 0; i < -f->numparms - 1; i++) {
size[i] = f->parm_size[i]; paramofs = align_offset (paramofs, f->parm_size[i]);
dstParams[i] = pr->pr_globals + paramofs;
paramofs += f->parm_size[i].size;
if (pr->pr_params[i] != pr->pr_real_params[i]) {
copy_param (pr->pr_real_params[i], pr->pr_params[i],
f->parm_size[i].size);
}
} }
for (; i < 2; i++) { dparmsize_t parmsize = { pr->pr_param_size, pr->pr_param_alignment };
paramofs += pr->pr_param_size; paramofs = align_offset (paramofs, parmsize );
size[i] = pr->pr_param_size; if (i < MAX_PARMS) {
dstParams[i] = pr->pr_globals + paramofs;
} }
count = i; for (; i < MAX_PARMS; i++) {
} if (pr->pr_params[i] != pr->pr_real_params[i]) {
copy_param (pr->pr_real_params[i], pr->pr_params[i],
for (i = 0; i < count && i < pr->pr_argc; i++) { f->parm_size[i].size);
offs = (pr->pr_params[i] - pr->pr_globals) - f->parm_start; }
if (offs >= 0 && offs < paramofs) {
memcpy (pr->pr_real_params[i], pr->pr_params[i],
size[i] * sizeof (pr_type_t));
pr->pr_params[i] = pr->pr_real_params[i];
} }
} }
@ -194,43 +214,33 @@ PR_EnterFunction (progs_t *pr, bfunction_t *f)
pr->pr_xstatement = f->first_statement - 1; // offset the st++ pr->pr_xstatement = f->first_statement - 1; // offset the st++
// save off any locals that the new function steps on // save off any locals that the new function steps on
c = f->locals; if (pr->localstack_used + f->locals > LOCALSTACK_SIZE)
if (pr->localstack_used + c > LOCALSTACK_SIZE)
PR_RunError (pr, "PR_EnterFunction: locals stack overflow"); PR_RunError (pr, "PR_EnterFunction: locals stack overflow");
memcpy (&pr->localstack[pr->localstack_used], memcpy (&pr->localstack[pr->localstack_used],
&pr->pr_globals[f->parm_start], &pr->pr_globals[f->parm_start],
sizeof (pr_type_t) * c); sizeof (pr_type_t) * f->locals);
pr->localstack_used += c; pr->localstack_used += f->locals;
if (pr_deadbeef_locals->int_val) if (pr_deadbeef_locals->int_val)
for (k = f->parm_start; k < f->parm_start + c; k++) for (i = f->parm_start; i < f->parm_start + f->locals; i++)
pr->pr_globals[k].integer_var = 0xdeadbeef; pr->pr_globals[i].integer_var = 0xdeadbeef;
// copy parameters // copy parameters
o = f->parm_start;
if (f->numparms >= 0) { if (f->numparms >= 0) {
for (i = 0; i < f->numparms; i++) { for (i = 0; i < f->numparms; i++) {
for (j = 0; j < f->parm_size[i]; j++) { copy_param (dstParams[i], pr->pr_params[i], f->parm_size[i].size);
memcpy (&pr->pr_globals[o], &P_INT (pr, i) + j,
sizeof (pr_type_t));
o++;
}
} }
} else { } else {
pr_type_t *argc = &pr->pr_globals[o++]; pr_type_t *argc = &pr->pr_globals[f->parm_start + 0];
pr_type_t *argv = &pr->pr_globals[o++]; pr_type_t *argv = &pr->pr_globals[f->parm_start + 1];
for (i = 0; i < -f->numparms - 1; i++) { for (i = 0; i < -f->numparms - 1; i++) {
for (j = 0; j < f->parm_size[i]; j++) { copy_param (dstParams[i], pr->pr_params[i], f->parm_size[i].size);
memcpy (&pr->pr_globals[o], &P_INT (pr, i) + j,
sizeof (pr_type_t));
o++;
}
} }
argc->integer_var = pr->pr_argc - i; argc->integer_var = pr->pr_argc - i;
argv->integer_var = o; argv->integer_var = dstParams[i] - pr->pr_globals;
if (i < MAX_PARMS) { if (i < MAX_PARMS) {
memcpy (&pr->pr_globals[o], &P_INT (pr, i), memcpy (dstParams[i], &P_INT (pr, i),
(MAX_PARMS - i) * pr->pr_param_size * sizeof (pr_type_t)); (MAX_PARMS - i) * pr->pr_param_size * sizeof (pr_type_t));
} }
} }
@ -239,19 +249,18 @@ PR_EnterFunction (progs_t *pr, bfunction_t *f)
static void static void
PR_LeaveFunction (progs_t *pr) PR_LeaveFunction (progs_t *pr)
{ {
int c;
bfunction_t *f = pr->pr_xfunction; bfunction_t *f = pr->pr_xfunction;
PR_PopFrame (pr); PR_PopFrame (pr);
// restore locals from the stack // restore locals from the stack
c = f->locals; pr->localstack_used -= f->locals;
pr->localstack_used -= c;
if (pr->localstack_used < 0) if (pr->localstack_used < 0)
PR_RunError (pr, "PR_LeaveFunction: locals stack underflow"); PR_RunError (pr, "PR_LeaveFunction: locals stack underflow");
memcpy (&pr->pr_globals[f->parm_start], memcpy (&pr->pr_globals[f->parm_start],
&pr->localstack[pr->localstack_used], sizeof (pr_type_t) * c); &pr->localstack[pr->localstack_used],
sizeof (pr_type_t) * f->locals);
} }
VISIBLE void VISIBLE void

View file

@ -122,6 +122,7 @@ PR_ResolveGlobals (progs_t *pr)
pr->pr_params[6] = &pr->pr_globals[OFS_PARM6]; pr->pr_params[6] = &pr->pr_globals[OFS_PARM6];
pr->pr_params[7] = &pr->pr_globals[OFS_PARM7]; pr->pr_params[7] = &pr->pr_globals[OFS_PARM7];
pr->pr_param_size = OFS_PARM1 - OFS_PARM0; pr->pr_param_size = OFS_PARM1 - OFS_PARM0;
pr->pr_param_alignment = 0; // log2
} else { } else {
if (!(def = PR_FindGlobal (pr, sym = ".return"))) if (!(def = PR_FindGlobal (pr, sym = ".return")))
goto error; goto error;
@ -134,6 +135,9 @@ PR_ResolveGlobals (progs_t *pr)
if (!(def = PR_FindGlobal (pr, sym = ".param_size"))) if (!(def = PR_FindGlobal (pr, sym = ".param_size")))
goto error; goto error;
pr->pr_param_size = G_INT (pr, def->ofs); pr->pr_param_size = G_INT (pr, def->ofs);
if (!(def = PR_FindGlobal (pr, sym = ".param_alignment")))
goto error;
pr->pr_param_alignment = G_INT (pr, def->ofs);
} }
if (pr->pr_saved_params) if (pr->pr_saved_params)
free (pr->pr_saved_params); free (pr->pr_saved_params);