From c8fbb934248699e35d8eaf1195240c8a7ec07a14 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 27 Oct 2024 20:58:23 +0900 Subject: [PATCH] [qfcc] Separate out backend function building It turns out that emit_function should have been (something like) build_code and had the stack/locals related code taken along with it. --- tools/qfcc/include/defspace.h | 2 + tools/qfcc/include/target.h | 2 +- tools/qfcc/source/defspace.c | 27 +++++++ tools/qfcc/source/function.c | 124 +------------------------------ tools/qfcc/source/pragma.c | 9 ++- tools/qfcc/source/target_rua.c | 96 +++++++++++++++++++++--- tools/qfcc/source/target_spirv.c | 4 +- tools/qfcc/source/target_v6.c | 34 ++++++--- 8 files changed, 149 insertions(+), 149 deletions(-) diff --git a/tools/qfcc/include/defspace.h b/tools/qfcc/include/defspace.h index 33d58f1a8..bbbb58ef3 100644 --- a/tools/qfcc/include/defspace.h +++ b/tools/qfcc/include/defspace.h @@ -237,6 +237,8 @@ void defspace_reset (defspace_t *space); void defspace_sort_defs (defspace_t *space); +void merge_spaces (defspace_t *dst, defspace_t *src, int alignment); + ///@} #endif//__defspace_h diff --git a/tools/qfcc/include/target.h b/tools/qfcc/include/target.h index a8bf20dfe..3bd0a8c9a 100644 --- a/tools/qfcc/include/target.h +++ b/tools/qfcc/include/target.h @@ -36,7 +36,7 @@ typedef struct expr_s expr_t; typedef struct { bool (*value_too_large) (const type_t *val_type); void (*build_scope) (symbol_t *fsym); - void (*emit_function) (function_t *f, const expr_t *e); + void (*build_code) (function_t *func, const expr_t *statements); } target_t; extern target_t current_target; diff --git a/tools/qfcc/source/defspace.c b/tools/qfcc/source/defspace.c index fc9f22421..688278284 100644 --- a/tools/qfcc/source/defspace.c +++ b/tools/qfcc/source/defspace.c @@ -47,6 +47,7 @@ #include "tools/qfcc/include/def.h" #include "tools/qfcc/include/defspace.h" #include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/type.h" typedef struct locref_s { struct locref_s *next; @@ -350,3 +351,29 @@ defspace_sort_defs (defspace_t *space) } *space->def_tail = 0; } + +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); +} diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index d6db815a9..2a7f04c27 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -76,13 +76,6 @@ static hashtab_t *generic_functions; static hashtab_t *metafuncs; static hashtab_t *function_map; -// standardized base register to use for all locals (arguments, local defs, -// params) -#define LOCALS_REG 1 -// keep the stack aligned to 8 words (32 bytes) so lvec etc can be used without -// having to do shenanigans with mixed-alignment stack frames -#define STACK_ALIGN 8 - static const char * gen_func_get_key (const void *_f, void *unused) { @@ -1143,32 +1136,6 @@ build_function (symbol_t *fsym) } } -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 * build_code_function (symbol_t *fsym, const expr_t *state_expr, expr_t *statements) @@ -1180,89 +1147,8 @@ build_code_function (symbol_t *fsym, const expr_t *state_expr, prepend_expr (statements, state_expr); } function_t *func = fsym->metafunc->func; - if (options.code.progsversion == PROG_VERSION) { - /* Create a function entry block to set up the stack frame and add the - * actual function code to that block. This ensure that the adjstk and - * with statements always come first, regardless of what ideas the - * optimizer gets. - */ - expr_t *e; - expr_t *entry = new_block_expr (0); - entry->loc = func->def->loc; + current_target.build_code (func, statements); - e = new_adjstk_expr (0, 0); - e->loc = entry->loc; - append_expr (entry, e); - - e = new_with_expr (2, LOCALS_REG, new_short_expr (0)); - e->loc = entry->loc; - append_expr (entry, e); - - append_expr (entry, statements); - statements = entry; - - /* Mark all local defs as using the base register used for stack - * references. - */ - func->temp_reg = LOCALS_REG; - for (def_t *def = func->locals->space->defs; def; def = def->next) { - if (def->local || def->param) { - def->reg = LOCALS_REG; - } - } - for (def_t *def = func->parameters->space->defs; def; def = def->next) { - if (def->local || def->param) { - def->reg = LOCALS_REG; - } - } - } - emit_function (func, statements); - defspace_sort_defs (func->parameters->space); - defspace_sort_defs (func->locals->space); - if (options.code.progsversion < PROG_VERSION) { - // stitch parameter and locals data together with parameters coming - // first - defspace_t *space = defspace_new (ds_virtual); - - func->params_start = 0; - - 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, STACK_ALIGN); - func->arguments = 0; - } - - merge_spaces (space, func->locals->space, STACK_ALIGN); - func->locals->space = space; - - // allocate 0 words to force alignment and get the address - func->params_start = defspace_alloc_aligned_highwater (space, 0, - STACK_ALIGN); - - dstatement_t *st = &pr.code->code[func->code]; - if (pr.code->size > func->code && st->op == OP_ADJSTK) { - if (func->params_start) { - st->b = -func->params_start; - } else { - // skip over adjstk so a zero adjustment doesn't get executed - func->code += 1; - } - } - merge_spaces (space, func->parameters->space, STACK_ALIGN); - func->parameters->space = space; - - // force the alignment again so the full stack slot is counted when - // the final parameter is smaller than STACK_ALIGN words - defspace_alloc_aligned_highwater (space, 0, STACK_ALIGN); - } return fsym->metafunc->func; } @@ -1325,14 +1211,6 @@ build_builtin_function (symbol_t *sym, const expr_t *bi_val, int far, return func; } -void -emit_function (function_t *f, expr_t *e) -{ - if (pr.error_count) - return; - current_target.emit_function (f, e); -} - void clear_functions (void) { diff --git a/tools/qfcc/source/pragma.c b/tools/qfcc/source/pragma.c index 5e5f035fb..f57c7804c 100644 --- a/tools/qfcc/source/pragma.c +++ b/tools/qfcc/source/pragma.c @@ -49,6 +49,7 @@ #include "tools/qfcc/include/pragma.h" #include "tools/qfcc/include/rua-lang.h" #include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/target.h" #include "tools/qfcc/include/type.h" typedef struct pragma_arg_s { @@ -67,7 +68,7 @@ set_traditional (int traditional) case -1: options.traditional = 0; options.advanced = 2; - options.code.progsversion = PROG_VERSION; + target_set_backend ("ruamoko"); type_default = &type_int; type_long_int = &type_long; type_ulong_uint = &type_ulong; @@ -75,7 +76,7 @@ set_traditional (int traditional) case 0: options.traditional = 0; options.advanced = 1; - options.code.progsversion = PROG_V6P_VERSION; + target_set_backend ("v6p"); type_default = &type_int; type_long_int = &type_int; type_ulong_uint = &type_uint; @@ -83,13 +84,13 @@ set_traditional (int traditional) case 1: options.traditional = 1; options.advanced = 0; - options.code.progsversion = PROG_ID_VERSION; + target_set_backend ("v6"); type_default = &type_float; break; case 2: options.traditional = 2; options.advanced = 0; - options.code.progsversion = PROG_ID_VERSION; + target_set_backend ("v6"); type_default = &type_float; break; } diff --git a/tools/qfcc/source/target_rua.c b/tools/qfcc/source/target_rua.c index 526b9349a..295ac8747 100644 --- a/tools/qfcc/source/target_rua.c +++ b/tools/qfcc/source/target_rua.c @@ -46,6 +46,13 @@ #include "tools/qfcc/include/target.h" #include "tools/qfcc/include/type.h" +// standardized base register to use for all locals (arguments, local defs, +// params) +#define LOCALS_REG 1 +// keep the stack aligned to 8 words (32 bytes) so lvec etc can be used without +// having to do shenanigans with mixed-alignment stack frames +#define STACK_ALIGN 8 + static bool ruamoko_value_too_large (const type_t *val_type) { @@ -116,21 +123,90 @@ ruamoko_build_scope (symbol_t *fsym) } static void -ruamoko_emit_function (function_t *f, const expr_t *e) +ruamoko_build_code (function_t *func, const expr_t *statements) { - f->code = pr.code->size; - lineno_base = f->def->loc.line; - f->sblock = make_statements (e); - if (options.code.optimize) { - flow_data_flow (f); - } else { - statements_count_temps (f->sblock); + /* Create a function entry block to set up the stack frame and add the + * actual function code to that block. This ensure that the adjstk and + * with statements always come first, regardless of what ideas the + * optimizer gets. + */ + expr_t *e; + expr_t *entry = new_block_expr (0); + entry->loc = func->def->loc; + + e = new_adjstk_expr (0, 0); + e->loc = entry->loc; + append_expr (entry, e); + + e = new_with_expr (2, LOCALS_REG, new_short_expr (0)); + e->loc = entry->loc; + append_expr (entry, e); + + append_expr (entry, statements); + statements = entry; + + /* Mark all local defs as using the base register used for stack + * references. + */ + func->temp_reg = LOCALS_REG; + for (def_t *def = func->locals->space->defs; def; def = def->next) { + if (def->local || def->param) { + def->reg = LOCALS_REG; + } } - emit_statements (f->sblock); + for (def_t *def = func->parameters->space->defs; def; def = def->next) { + if (def->local || def->param) { + def->reg = LOCALS_REG; + } + } + + func->code = pr.code->size; + lineno_base = func->def->loc.line; + func->sblock = make_statements (statements); + if (options.code.optimize) { + flow_data_flow (func); + } else { + statements_count_temps (func->sblock); + } + emit_statements (func->sblock); + + defspace_sort_defs (func->parameters->space); + defspace_sort_defs (func->locals->space); + + defspace_t *space = defspace_new (ds_virtual); + + if (func->arguments) { + func->arguments->size = func->arguments->max_size; + merge_spaces (space, func->arguments, STACK_ALIGN); + func->arguments = 0; + } + + merge_spaces (space, func->locals->space, STACK_ALIGN); + func->locals->space = space; + + // allocate 0 words to force alignment and get the address + func->params_start = defspace_alloc_aligned_highwater (space, 0, + STACK_ALIGN); + + dstatement_t *st = &pr.code->code[func->code]; + if (pr.code->size > func->code && st->op == OP_ADJSTK) { + if (func->params_start) { + st->b = -func->params_start; + } else { + // skip over adjstk so a zero adjustment doesn't get executed + func->code += 1; + } + } + merge_spaces (space, func->parameters->space, STACK_ALIGN); + func->parameters->space = space; + + // force the alignment again so the full stack slot is counted when + // the final parameter is smaller than STACK_ALIGN words + defspace_alloc_aligned_highwater (space, 0, STACK_ALIGN); } target_t ruamoko_target = { .value_too_large = ruamoko_value_too_large, .build_scope = ruamoko_build_scope, - .emit_function = ruamoko_emit_function, + .build_code = ruamoko_build_code, }; diff --git a/tools/qfcc/source/target_spirv.c b/tools/qfcc/source/target_spirv.c index 64b12ced8..26ff2baac 100644 --- a/tools/qfcc/source/target_spirv.c +++ b/tools/qfcc/source/target_spirv.c @@ -914,12 +914,12 @@ spirv_build_scope (symbol_t *fsym) } static void -spirv_emit_function (function_t *f, const expr_t *e) +spirv_build_code (function_t *func, const expr_t *statements) { } target_t spirv_target = { .value_too_large = spirv_value_too_large, .build_scope = spirv_build_scope, - .emit_function = spirv_emit_function, + .build_code = spirv_build_code, }; diff --git a/tools/qfcc/source/target_v6.c b/tools/qfcc/source/target_v6.c index 4f0cc9ec1..bf003c064 100644 --- a/tools/qfcc/source/target_v6.c +++ b/tools/qfcc/source/target_v6.c @@ -33,6 +33,7 @@ #include "tools/qfcc/include/codespace.h" #include "tools/qfcc/include/debug.h" +#include "tools/qfcc/include/defspace.h" #include "tools/qfcc/include/diagnostic.h" #include "tools/qfcc/include/emit.h" #include "tools/qfcc/include/flow.h" @@ -99,27 +100,42 @@ v6_value_too_large (const type_t *val_type) } static void -v6p_emit_function (function_t *f, const expr_t *e) +v6p_build_code (function_t *func, const expr_t *statements) { - f->code = pr.code->size; - lineno_base = f->def->loc.line; - f->sblock = make_statements (e); + func->code = pr.code->size; + lineno_base = func->def->loc.line; + func->sblock = make_statements (statements); if (options.code.optimize) { - flow_data_flow (f); + flow_data_flow (func); } else { - statements_count_temps (f->sblock); + statements_count_temps (func->sblock); } - emit_statements (f->sblock); + emit_statements (func->sblock); + + defspace_sort_defs (func->parameters->space); + defspace_sort_defs (func->locals->space); + + // stitch parameter and locals data together with parameters coming + // first + defspace_t *space = defspace_new (ds_virtual); + + func->params_start = 0; + + merge_spaces (space, func->parameters->space, 1); + func->parameters->space = space; + + merge_spaces (space, func->locals->space, 1); + func->locals->space = space; } target_t v6_target = { .value_too_large = v6_value_too_large, .build_scope = v6p_build_scope, - .emit_function = v6p_emit_function, + .build_code = v6p_build_code, }; target_t v6p_target = { .value_too_large = v6_value_too_large, .build_scope = v6p_build_scope, - .emit_function = v6p_emit_function, + .build_code = v6p_build_code, };