[qfcc] Split the function defspace into three spaces

Since Ruamoko now uses the stack for parameters and locals, parameters
need to come after locals in the address space (instead of before, as in
v6 progs). Thus use separate spaces for parameters and locals regardless
of the target, then stitch them together appropriately for the target.
The third space is used for allocating stack space for arguments to
called functions. It us not used for v6 progs, and comes before locals
in Ruamoko progs.

Other than the return value, and optimization (ice, not implemented)
calls in Ruamoko look like they'll work.
This commit is contained in:
Bill Currie 2022-01-21 10:20:02 +09:00
parent a19349b242
commit 7bc1396358
8 changed files with 157 additions and 38 deletions

View file

@ -73,13 +73,32 @@ typedef struct function_s {
struct def_s *temp_defs[4]; ///< freed temp vars (by size)
struct def_s *def; ///< output def holding function number
struct symbol_s *sym; ///< internal symbol for this function
/** Root scope symbol table of the function.
/** \name Local data space
Sub-scope symbol tables are not directly accessible, but all defs
created in the function's local data space are recorded in the root
scope symbol table's defspace.
The function parameters form the root scope for the function. Its
defspace is separate from the locals defspace so that it can be moved
to the beginning of locals space for v6 progs, and too the end (just
above the stack pointer on entry to the function) for Ruamoko progs.
The locals scope is a direct child of the parameters scope, and any
sub-scope symbol tables are not directly accessible, but all defs
other than function call arugments created in the function's local
data space are recorded in the root local scope symbol table's
defspace.
The arguments defspace is not used for v6 progs. It is used as a
highwater allocator for the arguments to all calls made by the
funciton, with the arguments to separate functions overlapping each
other.
Afther the function has been emitted, locals, arguments and possibly
parameters will be merged into the one defspace.
*/
struct symtab_s *symtab;
///@{
struct symtab_s *parameters; ///< Root scope symbol table
struct symtab_s *locals; ///< Actual local variables
struct defspace_s *arguments; ///< Space for called function arguments
///@}
struct symtab_s *label_scope;
struct reloc_s *refs; ///< relocation targets for this function
struct expr_s *var_init;

View file

@ -204,7 +204,7 @@ def_t *
temp_def (type_t *type)
{
def_t *temp;
defspace_t *space = current_func->symtab->space;
defspace_t *space = current_func->locals->space;
int size = type_size (type);
int alignment = type->alignment;

View file

@ -609,7 +609,7 @@ flow_build_vars (function_t *func)
// set up pseudo address space for temp vars so accessing tmp vars
// though aliases analyses correctly
func->pseudo_addr = func->num_statements + func->symtab->space->size;
func->pseudo_addr = func->num_statements + func->locals->space->size;
func->num_vars = 0; // incremented by add_operand
// first, add .return and .param_[0-7] as they are always needed

View file

@ -488,16 +488,23 @@ build_scope (symbol_t *fsym, symtab_t *parent)
param_t *p;
symbol_t *args = 0;
symbol_t *param;
symtab_t *symtab;
symtab_t *cs = current_symtab;
symtab_t *parameters;
symtab_t *locals;
symtab_t *cs = current_symtab;//FIXME
check_function (fsym);
symtab = new_symtab (parent, stab_local);
fsym->s.func->symtab = symtab;
fsym->s.func->label_scope = new_symtab (0, stab_local);
symtab->space = defspace_new (ds_virtual);
current_symtab = symtab;
parameters = new_symtab (parent, stab_local);
parameters->space = defspace_new (ds_virtual);
fsym->s.func->parameters = parameters;
locals = new_symtab (parameters, stab_local);
locals->space = defspace_new (ds_virtual);
fsym->s.func->locals = locals;
current_symtab = locals;//FIXME
if (!fsym->s.func) {
internal_error (0, "function %s not defined", fsym->name);
@ -507,7 +514,7 @@ build_scope (symbol_t *fsym, symtab_t *parent)
}
if (fsym->s.func->type->t.func.num_params < 0) {
args = new_symbol_type (".args", &type_va_list);
initialize_def (args, 0, symtab->space, sc_param);
initialize_def (args, 0, parameters->space, sc_param);
}
for (p = fsym->params, i = 0; p; p = p->next) {
@ -520,14 +527,14 @@ build_scope (symbol_t *fsym, symtab_t *parent)
p->name = save_string ("");
}
param = new_symbol_type (p->name, p->type);
initialize_def (param, 0, symtab->space, sc_param);
initialize_def (param, 0, parameters->space, sc_param);
i++;
}
if (args) {
while (i < MAX_PARMS) {
param = new_symbol_type (va (0, ".par%d", i), &type_param);
initialize_def (param, 0, symtab->space, sc_param);
initialize_def (param, 0, parameters->space, sc_param);
i++;
}
}
@ -628,11 +635,32 @@ build_function (symbol_t *fsym)
if (func_type->t.func.num_params > MAX_PARMS) {
error (0, "too many params");
}
// FIXME
// f->def->constant = 1;
// f->def->nosave = 1;
// f->def->initialized = 1;
// G_FUNCTION (f->def->ofs) = f->function_num;
}
static void
merge_spaces (defspace_t *dst, defspace_t *src, int alignment)
{
int offset;
for (def_t *def = src->defs; def; def = def->next) {
if (def->type->alignment > alignment) {
alignment = def->type->alignment;
}
}
offset = defspace_alloc_aligned_highwater (dst, src->size, alignment);
for (def_t *def = src->defs; def; def = def->next) {
def->offset += offset;
def->space = dst;
}
if (src->defs) {
*dst->def_tail = src->defs;
dst->def_tail = src->def_tail;
src->def_tail = &src->defs;
*src->def_tail = 0;
}
defspace_delete (src);
}
function_t *
@ -645,7 +673,35 @@ build_code_function (symbol_t *fsym, expr_t *state_expr, expr_t *statements)
state_expr->next = statements;
statements = state_expr;
}
emit_function (fsym->s.func, statements);
if (options.code.progsversion == PROG_VERSION) {
}
function_t *func = fsym->s.func;
emit_function (func, statements);
if (options.code.progsversion < PROG_VERSION) {
// stitch parameter and locals data together with parameters coming
// first
defspace_t *space = defspace_new (ds_virtual);
merge_spaces (space, func->parameters->space, 1);
func->parameters->space = space;
merge_spaces (space, func->locals->space, 1);
func->locals->space = space;
} else {
defspace_t *space = defspace_new (ds_virtual);
if (func->arguments) {
func->arguments->size = func->arguments->max_size;
merge_spaces (space, func->arguments, 4);
func->arguments = 0;
}
merge_spaces (space, func->locals->space, 4);
func->locals->space = space;
merge_spaces (space, func->parameters->space, 4);
func->parameters->space = space;
}
return fsym->s.func;
}
@ -694,7 +750,8 @@ build_builtin_function (symbol_t *sym, expr_t *bi_val, int far,
// for debug info
build_scope (sym, current_symtab);
sym->s.func->symtab->space->size = 0;
sym->s.func->parameters->space->size = 0;
sym->s.func->locals->space = sym->s.func->parameters->space;
return sym->s.func;
}

View file

@ -171,9 +171,9 @@ qfo_count_function_stuff (qfo_t *qfo, function_t *functions)
for (func = functions; func; func = func->next) {
qfo->num_funcs++;
qfo->num_relocs += count_relocs (func->refs);
if (func->symtab && func->symtab->space) {
if (func->locals && func->locals->space) {
qfo->num_spaces++;
qfo_count_space_stuff (qfo, func->symtab->space);
qfo_count_space_stuff (qfo, func->locals->space);
}
}
}
@ -306,10 +306,10 @@ qfo_encode_functions (qfo_t *qfo, qfo_def_t **defs, qfo_reloc_t **relocs,
if (f->builtin) // FIXME redundant
q->code = -f->builtin;
q->def = f->def->qfo_def;
if (f->symtab && f->symtab->space) {
space->id = f->symtab->space->qfo_space;
qfo_init_data_space (qfo, defs, relocs, space++, f->symtab->space);
q->locals_space = f->symtab->space->qfo_space;
if (f->locals && f->locals->space) {
space->id = f->locals->space->qfo_space;
qfo_init_data_space (qfo, defs, relocs, space++, f->locals->space);
q->locals_space = f->locals->space->qfo_space;
}
q->line_info = f->line_info;
q->relocs = *relocs - qfo->relocs;

View file

@ -517,7 +517,7 @@ function_body
$<symtab>$ = current_symtab;
current_func = begin_function ($<symbol>2, 0, current_symtab, 0,
$<spec>-1.storage);
current_symtab = current_func->symtab;
current_symtab = current_func->locals;
current_storage = sc_local;
}
compound_statement
@ -1249,7 +1249,7 @@ code_func
$<symtab>$ = current_symtab;
current_func = begin_function ($<symbol>0, 0, current_symtab, 0,
$<spec>-1.storage);
current_symtab = current_func->symtab;
current_symtab = current_func->locals;
current_storage = sc_local;
}
compound_statement
@ -2066,10 +2066,10 @@ methoddef
current_func = begin_function (sym, nicename, ivar_scope, 1,
sc_static);
class_finish_ivar_scope (current_class, ivar_scope,
current_func->symtab);
current_func->locals);
method->func = sym->s.func;
method->def = sym->s.func->def;
current_symtab = current_func->symtab;
current_symtab = current_func->locals;
current_storage = sc_local;
}
compound_statement

View file

@ -156,7 +156,7 @@ build_dotmain (symbol_t *program)
current_func = begin_function (dotmain, 0, current_symtab, 0,
current_storage);
current_symtab = current_func->symtab;
current_symtab = current_func->locals;
code = new_block_expr ();
append_expr (code, function_expr (new_symbol_expr (program), 0));
append_expr (code, return_expr (current_func, exitcode));
@ -180,7 +180,7 @@ program
current_func = begin_function ($1, 0, current_symtab, 0,
current_storage);
current_symtab = current_func->symtab;
current_symtab = current_func->locals;
build_code_function ($1, 0, $4);
current_symtab = st;
@ -265,14 +265,14 @@ subprogram_declaration
$<storage>$ = current_storage;
current_func = begin_function ($1, 0, current_symtab, 0,
current_storage);
current_symtab = current_func->symtab;
current_symtab = current_func->locals;
current_storage = sc_local;
}
declarations compound_statement ';'
{
append_expr ($5, new_return_expr (0));
build_code_function ($1, 0, $5);
current_symtab = current_symtab->parent;
current_symtab = current_func->parameters->parent;
current_storage = $<storage>3;
}
| subprogram_head ASSIGNOP '#' VALUE ';'

View file

@ -48,6 +48,7 @@
#include "tools/qfcc/include/class.h"
#include "tools/qfcc/include/dags.h"
#include "tools/qfcc/include/defspace.h"
#include "tools/qfcc/include/diagnostic.h"
#include "tools/qfcc/include/dot.h"
#include "tools/qfcc/include/expr.h"
@ -1011,7 +1012,7 @@ vector_call (sblock_t *sblock, expr_t *earg, expr_t *param, int ind,
}
static sblock_t *
expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
expr_call_v6p (sblock_t *sblock, expr_t *call, operand_t **op)
{
expr_t *func = call->e.branch.target;
expr_t *args = call->e.branch.args;
@ -1075,6 +1076,48 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
return sblock->next;
}
static sblock_t *
expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
{
if (options.code.progsversion < PROG_VERSION) {
return expr_call_v6p (sblock, call, op);
}
if (!current_func->arguments) {
current_func->arguments = defspace_new (ds_virtual);
}
defspace_t *arg_space = current_func->arguments;
expr_t *func = call->e.branch.target;
expr_t *args = call->e.branch.args;
defspace_reset (arg_space);
args = reverse_expr_list (args);
int arg_num = 0;
for (expr_t *a = args; a; a = a->next) {
const char *arg_name = va (0, ".arg%d", arg_num++);
def_t *def = new_def (arg_name, 0, current_func->arguments,
sc_local);
type_t *arg_type = get_type (a);
int size = type_size (arg_type);
int alignment = arg_type->alignment;
if (alignment < 4) {
alignment = 4;
}
def->offset = defspace_alloc_aligned_highwater (arg_space, size,
alignment);
def->type = arg_type;
expr_t *assign = assign_expr (new_def_expr (def), a);
expr_file_line (assign, call);
sblock = statement_slist (sblock, assign);
}
statement_t *s = new_statement (st_func, "call", call);
sblock = statement_subexpr (sblock, func, &s->opa);
s->opc = short_operand (0, call);
sblock_add_statement (sblock, s);
sblock->next = new_sblock ();
return sblock->next;
}
static sblock_t *
statement_branch (sblock_t *sblock, expr_t *e)
{