[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.
This commit is contained in:
Bill Currie 2024-10-27 20:58:23 +09:00
parent bff709e71d
commit c8fbb93424
8 changed files with 149 additions and 149 deletions

View file

@ -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

View file

@ -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;

View file

@ -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);
}

View file

@ -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)
{

View file

@ -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;
}

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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,
};