diff --git a/tools/qfcc/include/function.h b/tools/qfcc/include/function.h index 667cfb5ba..3b04bb9e5 100644 --- a/tools/qfcc/include/function.h +++ b/tools/qfcc/include/function.h @@ -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; diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 449db7320..5f6947c37 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -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; diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 1cbf057d8..8bcd4bbeb 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -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 diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 4840fb41f..bfc1da059 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -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; } diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index a9f562984..17ba70080 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -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; diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index a9c2ea102..c0d7d93c0 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -517,7 +517,7 @@ function_body $$ = current_symtab; current_func = begin_function ($2, 0, current_symtab, 0, $-1.storage); - current_symtab = current_func->symtab; + current_symtab = current_func->locals; current_storage = sc_local; } compound_statement @@ -1249,7 +1249,7 @@ code_func $$ = current_symtab; current_func = begin_function ($0, 0, current_symtab, 0, $-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 diff --git a/tools/qfcc/source/qp-parse.y b/tools/qfcc/source/qp-parse.y index e7bb66647..a36f27910 100644 --- a/tools/qfcc/source/qp-parse.y +++ b/tools/qfcc/source/qp-parse.y @@ -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 $$ = 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 = $3; } | subprogram_head ASSIGNOP '#' VALUE ';' diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index bc4cb396b..51a7a4ac9 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -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) {