From 17dfd1492f4a124cb57194eba2346e3e41960e20 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 20 Jan 2022 20:54:12 +0900 Subject: [PATCH] [qfcc] Make virtual defspaces useful for highwater allocation This seems to be the most reasonable approach to allocating space for function call parameters without using push and pop (or adding to the stack pointer), though it's probably good even when using push and pop to help keep things aligned. --- tools/qfcc/include/defspace.h | 57 ++++++++++++++++++++++++++++++++-- tools/qfcc/source/defspace.c | 55 +++++++++++++++++++++++++++----- tools/qfcc/source/statements.c | 8 +++++ 3 files changed, 110 insertions(+), 10 deletions(-) diff --git a/tools/qfcc/include/defspace.h b/tools/qfcc/include/defspace.h index 6e839ce67..eea13bf71 100644 --- a/tools/qfcc/include/defspace.h +++ b/tools/qfcc/include/defspace.h @@ -43,7 +43,8 @@ typedef enum { ds_backed, ///< data space is globally addressable (near/far/type) and ///< has backing store ds_virtual, ///< data space has no backing store (local vars, entity - ///< fields) + ///< fields) defspace_t::max_size reflects the highest + ///< address allocated } ds_type_t; /** Represent a block of memory in the progs data space. @@ -56,7 +57,8 @@ typedef struct defspace_s { struct def_s **def_tail; ///< for appending to \a defs pr_type_t *data; ///< backing memory for this space int size; ///< current high-water mark for alloced data - int max_size; ///< size of backing memory + int max_size; ///< size of backing memory, or highwater mark + ///< for ds_virtual /** Grow the backing memory of the defspace. This function is called when more memory is needed for the space. @@ -168,6 +170,57 @@ void defspace_free_loc (defspace_t *space, int ofs, int size); */ int defspace_add_data (defspace_t *space, pr_type_t *data, int size); +/** Allocate a block of data from the end of the defspace. + + If memory cannot be allocated (there is no free space in the currently + available memory and defspace_t::grow is null), then an internal error + will be generated. + + \param space The space from which to allocate data. + \param size The amount of pr_type_t words to allocated. int and float + need 1 word, vector 3 words, and quaternion 4. + \return The offset of the first word of the freshly allocated + space. May be 0 if the allocated space is at the beginning + of the defspace. +*/ +int defspace_alloc_highwater (defspace_t *space, int size); + +/** Allocate an aligned block of data from the end of the defspace. + + Any unallocated holes in the defspace are ignored, even if the hole is + at the end of the defspace. However, any holes created by the padding + required for aligning the block will be available to defspace_alloc_loc() + and defspace_alloc_aligned_loc(). + + If memory cannot be allocated (there is no free space in the currently + available memory and defspace_t::grow is null), then an internal error + will be generated. + + \param space The space from which to allocate data. + \param size The amount of pr_type_t words to allocated. int and float + need 1 word, vector 3 words, and quaternion 4. + \param alignment The alignment of the allocated space. + \return The offset of the first word of the freshly allocated + space. May be 0 if the allocated space is at the beginning + of the defspace. +*/ +int defspace_alloc_aligned_highwater (defspace_t *space, int size, + int alignment); +/** Reset a defspace, freeing all allocated memory. + + defspace_t::max_size is not affected. This allows the defspace to be used + to find the larged block of memory required for a set of operations (eg, + the largest parameter block required in a function for all its calls + allowing the stack to remain constant instead of using many push/pop + operations. Note that this works best with ds_virtual defspaces. + + If the defspace has backing memory (ds_backed), the memory is not freed, + but it is zeroed so any new allocations will contain zeroed memory. + + \param space The space to be reset. +*/ +void defspace_reset (defspace_t *space); + ///@} #endif//__defspace_h diff --git a/tools/qfcc/source/defspace.c b/tools/qfcc/source/defspace.c index 1cfe572c3..5bae41bff 100644 --- a/tools/qfcc/source/defspace.c +++ b/tools/qfcc/source/defspace.c @@ -105,14 +105,9 @@ grow_space_global (defspace_t *space) static int grow_space_virtual (defspace_t *space) { - int size; - - if (space->size <= space->max_size) - return 1; - - size = space->size + GROW; - size -= size % GROW; - space->max_size = size; + if (space->size > space->max_size) { + space->max_size = space->size; + } return 1; } @@ -208,6 +203,7 @@ defspace_alloc_aligned_loc (defspace_t *space, int size, int alignment) internal_error (0, "unable to allocate %d words", size); } if (pad) { + // mark the padding as free *l = new_locref (ofs, pad, 0); } return ofs + pad; @@ -271,3 +267,46 @@ defspace_add_data (defspace_t *space, pr_type_t *data, int size) memcpy (space->data + loc, data, size * sizeof (pr_type_t)); return loc; } + +int +defspace_alloc_highwater (defspace_t *space, int size) +{ + return defspace_alloc_aligned_highwater (space, size, 1); +} + +int +defspace_alloc_aligned_highwater (defspace_t *space, int size, int alignment) +{ + if (size <= 0) + internal_error (0, "invalid number of words requested: %d", size); + if (alignment <= 0) + internal_error (0, "invalid alignment requested: %d", alignment); + + int ofs = space->size; + int pad = alignment * ((ofs + alignment - 1) / alignment) - ofs; + space->size += size + pad; + if (space->size > space->max_size) { + if (!space->grow || !space->grow (space)) + internal_error (0, "unable to allocate %d words", size); + } + locref_t **l = &space->free_locs; + if (pad) { + // mark the padding as free + *l = new_locref (ofs, pad, 0); + } + return ofs + pad; +} + +void +defspace_reset (defspace_t *space) +{ + space->size = 0; + while (space->free_locs) { + locref_t *l = space->free_locs; + space->free_locs = l->next; + del_locref (l); + } + if (space->data) { + memset (space->data, 0, space->max_size * sizeof (pr_type_t)); + } +} diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 354f1d1db..756b38492 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1136,6 +1136,14 @@ statement_return (sblock_t *sblock, expr_t *e) } } else { if (e->e.retrn.ret_val) { + expr_t *ret_val = e->e.retrn.ret_val; + type_t *ret_type = get_type (ret_val); + if (is_indirect (ret_val)) { + } else { + sblock = statement_subexpr (sblock, ret_val, &s->opa); + s->opb = short_operand (0, e); + s->opc = short_operand (type_size (ret_type) - 1, e); + } } else { s->opa = short_operand (0, e); s->opb = short_operand (0, e);