mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-25 19:50:46 +00:00
[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:
parent
a19349b242
commit
7bc1396358
8 changed files with 157 additions and 38 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ';'
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue