From 169b8cc398b8082af5464fb725f56d0cabbdd034 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Jan 2022 23:18:15 +0900 Subject: [PATCH] [qfcc] Rewrite qfo_to_progs offset/size calculation This gets all the sections of the progs file nicely aligned and the code easier to read with the offset and size calculations not being spread through the function. ivar-struct-return now works when compiled for Ruamoko. --- tools/qfcc/include/obj_file.h | 20 +-- tools/qfcc/source/obj_file.c | 228 +++++++++++++++++++++------------- 2 files changed, 153 insertions(+), 95 deletions(-) diff --git a/tools/qfcc/include/obj_file.h b/tools/qfcc/include/obj_file.h index a4861d29a..b827d58a1 100644 --- a/tools/qfcc/include/obj_file.h +++ b/tools/qfcc/include/obj_file.h @@ -249,14 +249,14 @@ typedef struct qfo_reloc_s { typedef struct qfo_mspace_s { qfos_type_t type; qfo_def_t *defs; - unsigned num_defs; + pr_uint_t num_defs; union { dstatement_t *code; pr_type_t *data; char *strings; }; - unsigned data_size; - unsigned id; + pr_uint_t data_size; + pr_uint_t id; } qfo_mspace_t; /** In-memory representation of a QFO object file. @@ -265,16 +265,16 @@ typedef struct qfo_s { pr_uint_t progs_version; ///< version of compatible VM void *data; ///< data buffer holding qfo file when read qfo_mspace_t *spaces; - unsigned num_spaces; + pr_uint_t num_spaces; qfo_reloc_t *relocs; - unsigned num_relocs; // includes num_loose_relocs + pr_uint_t num_relocs; // includes num_loose_relocs qfo_def_t *defs; - unsigned num_defs; + pr_uint_t num_defs; qfo_func_t *funcs; - unsigned num_funcs; + pr_uint_t num_funcs; pr_lineno_t *lines; - unsigned num_lines; - unsigned num_loose_relocs; // included in num_relocs + pr_uint_t num_lines; + pr_uint_t num_loose_relocs; // included in num_relocs } qfo_t; enum { @@ -500,7 +500,7 @@ qfo_t *qfo_new (void); */ void qfo_delete (qfo_t *qfo); -__attribute__((const)) int qfo_log2 (unsigned x); +__attribute__((const)) int qfo_log2 (pr_uint_t x); ///@} diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index fa650a822..a672a41fa 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -918,7 +918,7 @@ align_globals_size (unsigned size) } static int -qfo_def_compare (const void *i1, const void *i2, void *d) +qfo_def_offset_compare (const void *i1, const void *i2, void *d) { __auto_type defs = (const qfo_def_t *) d; unsigned ind1 = *(unsigned *) i1; @@ -928,10 +928,79 @@ qfo_def_compare (const void *i1, const void *i2, void *d) return def1->offset - def2->offset; } +static pr_uint_t +qfo_count_locals (const qfo_t *qfo, pr_uint_t *big_locals) +{ + if (options.code.progsversion == PROG_VERSION) { + // Ruamoko progs keep their locals on the stack rather than a + // "protected" area in the globals + *big_locals = 0; + return 0; + } + + pr_uint_t locals_size = 0; + for (pr_uint_t i = qfo_num_spaces; i < qfo->num_spaces; i++) { + if (options.code.local_merging) { + if (locals_size < qfo->spaces[i].data_size) { + locals_size = qfo->spaces[i].data_size; + *big_locals = i; + } + } else { + locals_size += align_globals_size (qfo->spaces[i].data_size); + } + } + return locals_size; +} + +typedef struct globals_info_s { + pr_uint_t locals_start; + pr_uint_t locals_size; + pr_uint_t big_locals; + pr_uint_t near_data_size; + pr_uint_t type_encodings_start; + pr_uint_t xdefs_start; + pr_uint_t xdefs_size; + pr_uint_t globals_size; +} globals_info_t; + + +static globals_info_t +qfo_count_globals (qfo_t *qfo, dprograms_t *progs, int word_align) +{ + globals_info_t info = {}; + info.globals_size = qfo->spaces[qfo_near_data_space].data_size; + info.globals_size = RUP (info.globals_size, word_align); + + info.locals_start = info.globals_size; + info.locals_size = qfo_count_locals (qfo, &info.big_locals); + info.globals_size += info.locals_size; + info.near_data_size = info.globals_size; + + info.globals_size = RUP (info.globals_size, word_align); + info.globals_size += qfo->spaces[qfo_far_data_space].data_size; + + info.type_encodings_start = info.globals_size; + info.globals_size += qfo->spaces[qfo_type_space].data_size; + info.globals_size = RUP (info.globals_size, type_xdef.alignment); + + info.xdefs_start = info.globals_size; + info.xdefs_size = progs->globaldefs.count + progs->fielddefs.count; + info.xdefs_size *= type_size (&type_xdef); + info.globals_size += info.xdefs_size; + + return info; +} + +static pr_uint_t +qfo_next_offset (pr_chunk_t chunk, pr_uint_t size, pr_uint_t align) +{ + size *= chunk.count; + return RUP (chunk.offset + size, align); +} + dprograms_t * qfo_to_progs (qfo_t *in_qfo, int *size) { - byte *data; char *strings; dstatement_t *statements; dfunction_t *functions; @@ -946,12 +1015,6 @@ qfo_to_progs (qfo_t *in_qfo, int *size) qfo_def_t *types_def = 0; qfo_def_t *xdefs_def = 0; unsigned i, j; - unsigned near_data_size = 0; - unsigned locals_size = 0; - int locals_start; - int type_encodings_start; - int xdefs_start; - unsigned big_locals = 0; int big_func = 0; pr_xdefs_t *xdefs = 0; xdef_t *xdef; @@ -959,6 +1022,16 @@ qfo_to_progs (qfo_t *in_qfo, int *size) unsigned *far_def_indices; unsigned *field_def_indices; + // id progs were aligned to only 4 bytes, but 8 is much more reasonable + pr_uint_t byte_align = 8; + if (options.code.progsversion == PROG_VERSION) { + byte_align = __alignof__ (pr_lvec4_t); + } else if (options.code.progsversion == PROG_V6P_VERSION) { + byte_align = 16; + } + pr_uint_t word_align = byte_align / sizeof (pr_int_t); + + qfo_t *qfo = alloca (sizeof (qfo_t) + in_qfo->num_spaces * sizeof (qfo_mspace_t)); *qfo = *in_qfo; @@ -970,53 +1043,52 @@ qfo_to_progs (qfo_t *in_qfo, int *size) *size = RUP (sizeof (dprograms_t), 16); progs = calloc (1, *size); progs->version = options.code.progsversion; + // crc is set in qfcc.c if enabled + + // these are in order in which they usually appear in the file rather + // than the order they appear in the struct, though with the offsets + // it doesn't matter too much. However, as people expect a certain + // layout, ti does matter enough to preserve the traditional file order. + progs->strings.offset = *size; + progs->strings.count = qfo->spaces[qfo_strings_space].data_size; + + progs->statements.offset = qfo_next_offset (progs->strings, + sizeof (char), + byte_align); progs->statements.count = qfo->spaces[qfo_code_space].data_size; + + progs->functions.offset = qfo_next_offset (progs->statements, + sizeof (dstatement_t), + byte_align); + progs->functions.count = qfo->num_funcs + 1; + + progs->globaldefs.offset = qfo_next_offset (progs->functions, + sizeof (dfunction_t), + byte_align); progs->globaldefs.count = qfo->spaces[qfo_near_data_space].num_defs; //ddef offsets are 16 bits so the ddef ofs will likely be invalid //thus it will be forced invalid and the true offset written to the //.xdefs array in the progs file progs->globaldefs.count += qfo->spaces[qfo_far_data_space].num_defs; + + progs->fielddefs.offset = qfo_next_offset (progs->globaldefs, + sizeof (ddef_t), + byte_align); progs->fielddefs.count = qfo->spaces[qfo_entity_space].num_defs; - progs->functions.count = qfo->num_funcs + 1; - progs->strings.count = qfo->spaces[qfo_strings_space].data_size; - progs->globals.count = qfo->spaces[qfo_near_data_space].data_size; - progs->globals.count = align_globals_size (progs->globals.count); - locals_start = progs->globals.count; - if (options.code.progsversion < PROG_VERSION) { - for (i = qfo_num_spaces; i < qfo->num_spaces; i++) { - if (options.code.local_merging) { - if (locals_size < qfo->spaces[i].data_size) { - locals_size = qfo->spaces[i].data_size; - big_locals = i; - } - } else { - locals_size += align_globals_size (qfo->spaces[i].data_size); - } - } - } - progs->globals.count += locals_size; - near_data_size = progs->globals.count; - progs->globals.count = RUP (progs->globals.count, 16 / sizeof (pr_type_t)); - progs->globals.count += qfo->spaces[qfo_far_data_space].data_size; - type_encodings_start = progs->globals.count; - progs->globals.count += qfo->spaces[qfo_type_space].data_size; - progs->globals.count = RUP (progs->globals.count, type_xdef.alignment); - xdefs_start = progs->globals.count; - progs->globals.count += progs->globaldefs.count * type_size (&type_xdef); - progs->globals.count += progs->fielddefs.count * type_size (&type_xdef); + + progs->globals.offset = qfo_next_offset (progs->fielddefs, + sizeof (ddef_t), + byte_align); + globals_info_t globals_info = qfo_count_globals (qfo, progs, word_align); + progs->globals.count = globals_info.globals_size; + progs->entityfields = qfo->spaces[qfo_entity_space].data_size; // qfo_debug_space does not go in the progs file - *size += progs->statements.count * sizeof (dstatement_t); - *size += progs->globaldefs.count * sizeof (ddef_t); - *size += progs->fielddefs.count * sizeof (ddef_t); - *size += progs->functions.count * sizeof (dfunction_t); - *size += RUP (progs->strings.count * sizeof (char), 16); - *size += progs->globals.count * sizeof (pr_type_t); + + *size = qfo_next_offset (progs->globals, sizeof (pr_type_t), 1); progs = realloc (progs, *size); - data = (byte *) progs; memset (progs + 1, 0, *size - sizeof (dprograms_t)); - data += RUP (sizeof (dprograms_t), 16); def_indices = alloca ((progs->globaldefs.count + progs->fielddefs.count) * sizeof (*def_indices)); @@ -1032,42 +1104,27 @@ qfo_to_progs (qfo_t *in_qfo, int *size) field_def_indices[i] = i; } qsort_r (def_indices, qfo->spaces[qfo_near_data_space].num_defs, - sizeof (unsigned), qfo_def_compare, + sizeof (unsigned), qfo_def_offset_compare, qfo->spaces[qfo_near_data_space].defs); qsort_r (far_def_indices, qfo->spaces[qfo_far_data_space].num_defs, - sizeof (unsigned), qfo_def_compare, + sizeof (unsigned), qfo_def_offset_compare, qfo->spaces[qfo_far_data_space].defs); qsort_r (field_def_indices, qfo->spaces[qfo_entity_space].num_defs, - sizeof (unsigned), qfo_def_compare, + sizeof (unsigned), qfo_def_offset_compare, qfo->spaces[qfo_entity_space].defs); - progs->strings.offset = data - (byte *) progs; - strings = (char *) data; - data += RUP (progs->strings.count * sizeof (char), 16); - - progs->statements.offset = data - (byte *) progs; - statements = (dstatement_t *) data; - data += progs->statements.count * sizeof (dstatement_t); - - progs->functions.offset = data - (byte *) progs; - functions = (dfunction_t *) data; +#define qfo_block(t,b) (t *) ((byte *) progs + progs->b.offset) + strings = qfo_block (char, strings); + statements = qfo_block (dstatement_t, statements); + functions = qfo_block (dfunction_t, functions); functions++; // skip over null function - data += progs->functions.count * sizeof (dfunction_t); - - progs->globaldefs.offset = data - (byte *) progs; - globaldefs = (ddef_t *) data; - data += progs->globaldefs.count * sizeof (ddef_t); - - progs->fielddefs.offset = data - (byte *) progs; - fielddefs = (ddef_t *) (globaldefs + progs->globaldefs.count); - data += progs->fielddefs.count * sizeof (ddef_t); - - progs->globals.offset = data - (byte *) progs; - globals = (pr_type_t*) data; - locals = globals + locals_start; - far_data = globals + near_data_size; - type_data = globals + type_encodings_start; - xdef_data = globals + xdefs_start; + globaldefs = qfo_block (ddef_t, globaldefs); + fielddefs = qfo_block (ddef_t, fielddefs); + globals = qfo_block (pr_type_t, globals); + locals = globals + globals_info.locals_start; + far_data = globals + globals_info.near_data_size; + type_data = globals + globals_info.type_encodings_start; + xdef_data = globals + globals_info.xdefs_start; memcpy (strings, qfo->spaces[qfo_strings_space].strings, qfo->spaces[qfo_strings_space].data_size * sizeof (char)); @@ -1084,13 +1141,13 @@ qfo_to_progs (qfo_t *in_qfo, int *size) df->first_statement = qf->code; if (options.code.progsversion < PROG_VERSION) { - df->parm_start = locals_start; + df->parm_start = globals_info.locals_start; df->locals = space->data_size; // finalize the offsets of the local defs for (j = 0; j < space->num_defs; j++) - space->defs[j].offset += locals_start; + space->defs[j].offset += globals_info.locals_start; if (!options.code.local_merging) - locals_start += align_globals_size (df->locals); + globals_info.locals_start += align_globals_size (df->locals); } df->profile = 0; df->name = qf->name; @@ -1120,7 +1177,7 @@ qfo_to_progs (qfo_t *in_qfo, int *size) } for (i = 0; i < qfo->spaces[qfo_type_space].num_defs; i++) { - qfo->spaces[qfo_type_space].defs[i].offset += type_encodings_start; + qfo->spaces[qfo_type_space].defs[i].offset += globals_info.type_encodings_start; } for (i = 0; i < qfo->spaces[qfo_entity_space].num_defs; i++) { @@ -1134,7 +1191,7 @@ qfo_to_progs (qfo_t *in_qfo, int *size) qfo->spaces[qfo_near_data_space].data_size * sizeof (pr_type_t)); qfo->spaces[qfo_near_data_space].data = globals; // clear locals data - memset (locals, 0, locals_size * sizeof (pr_type_t)); + memset (locals, 0, globals_info.locals_size * sizeof (pr_type_t)); // copy far data memcpy (far_data, qfo->spaces[qfo_far_data_space].data, qfo->spaces[qfo_far_data_space].data_size * sizeof (pr_type_t)); @@ -1148,30 +1205,30 @@ qfo_to_progs (qfo_t *in_qfo, int *size) if (types_def) { qfot_type_encodings_t *encodings; encodings = (qfot_type_encodings_t *) &globals[types_def->offset]; - encodings->types = type_encodings_start; + encodings->types = globals_info.type_encodings_start; encodings->size = qfo->spaces[qfo_type_space].data_size; } if (xdefs_def) { xdefs = (pr_xdefs_t *) &globals[xdefs_def->offset]; xdef = (xdef_t *) xdef_data; - xdefs->xdefs = xdefs_start; + xdefs->xdefs = globals_info.xdefs_start; xdefs->num_xdefs = progs->globaldefs.count + progs->fielddefs.count; for (i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; i++, xdef++) { qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + i; - xdef->type = def->type + type_encodings_start; + xdef->type = def->type + globals_info.type_encodings_start; xdef->ofs = def->offset; } for (i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; i++, xdef++) { qfo_def_t *def = qfo->spaces[qfo_far_data_space].defs + i; - xdef->type = def->type + type_encodings_start; + xdef->type = def->type + globals_info.type_encodings_start; xdef->ofs = def->offset; } for (i = 0; i < qfo->spaces[qfo_entity_space].num_defs; i++, xdef++) { qfo_def_t *def = qfo->spaces[qfo_entity_space].defs + i; - xdef->type = def->type + type_encodings_start; + xdef->type = def->type + globals_info.type_encodings_start; xdef->ofs = def->offset; } } @@ -1183,7 +1240,7 @@ qfo_to_progs (qfo_t *in_qfo, int *size) qfo_func_t *qf = qfo->funcs + i; qfo_mspace_t *space = qfo->spaces + qf->locals_space; - if (qf->locals_space == big_locals) + if (qf->locals_space == globals_info.big_locals) big_func = i; for (j = 0; j < space->num_defs; j++) space->defs[j].offset -= df->parm_start; @@ -1199,8 +1256,9 @@ qfo_to_progs (qfo_t *in_qfo, int *size) printf ("%6i global defs\n", progs->globaldefs.count); printf ("%6i field defs\n", progs->fielddefs.count); printf ("%6i globals\n", progs->globals.count); - printf (" %6i near globals\n", near_data_size); - printf (" %6i locals size%s\n", locals_size, big_function); + printf (" %6i near globals\n", globals_info.near_data_size); + printf (" %6i locals size%s\n", + globals_info.locals_size, big_function); printf (" %6i far globals\n", qfo->spaces[qfo_far_data_space].data_size); printf (" %6i type globals\n",