mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-04-07 18:01:30 +00:00
[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:
parent
bff709e71d
commit
c8fbb93424
8 changed files with 149 additions and 149 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue