mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-23 19:01:06 +00:00
Implement aligned allocations
This commit is contained in:
parent
293f10211a
commit
a4a57b6ffd
8 changed files with 161 additions and 59 deletions
|
@ -109,6 +109,27 @@ defspace_t *defspace_new (ds_type_t type);
|
|||
*/
|
||||
int defspace_alloc_loc (defspace_t *space, int size);
|
||||
|
||||
/** Allocate space from the defspace's backing memory.
|
||||
|
||||
If the memory is fragmented, then the first available location at least
|
||||
as large as \a size plus padding for alignment is returned. This means
|
||||
that freeing a location then allocating the same amount of space may
|
||||
return a different location.
|
||||
|
||||
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_loc (defspace_t *space, int size, int alignment);
|
||||
|
||||
/** Free a block of contiguous words, returning them to the defspace.
|
||||
|
||||
The block to be freed is specified by \a ofs indicating the offset of the
|
||||
|
|
|
@ -63,6 +63,7 @@ typedef enum {
|
|||
typedef struct type_s {
|
||||
etype_t type; ///< ev_invalid means structure/array etc
|
||||
const char *name;
|
||||
int alignment; ///< required alignment for instances
|
||||
/// function/pointer/array/struct types are more complex
|
||||
ty_meta_e meta;
|
||||
union {
|
||||
|
|
|
@ -68,28 +68,29 @@ static hashtab_t *category_hash;
|
|||
static hashtab_t *protocol_hash;
|
||||
|
||||
// these will be built up further
|
||||
type_t type_obj_selector = { ev_invalid, 0, ty_struct};
|
||||
type_t type_SEL = { ev_pointer, "SEL", ty_none, {{&type_obj_selector}}};
|
||||
type_t type_IMP = { ev_func, "IMP", ty_none,
|
||||
type_t type_obj_selector = { ev_invalid, 0, 0, ty_struct};
|
||||
type_t type_SEL = { ev_pointer, "SEL", 1, ty_none, {{&type_obj_selector}}};
|
||||
type_t type_IMP = { ev_func, "IMP", 1, ty_none,
|
||||
{{&type_id, -3, {&type_id, &type_SEL}}}};
|
||||
type_t type_obj_super = { ev_invalid, 0 };
|
||||
type_t type_SuperPtr = { ev_pointer, 0, ty_none, {{&type_obj_super}}};
|
||||
type_t type_supermsg = { ev_func, ".supermsg", ty_none,
|
||||
type_t type_obj_super = { ev_invalid, 0, 0 };
|
||||
type_t type_SuperPtr = { ev_pointer, 0, 1, ty_none, {{&type_obj_super}}};
|
||||
type_t type_supermsg = { ev_func, ".supermsg", 1, ty_none,
|
||||
{{&type_id, -3, {&type_SuperPtr, &type_SEL}}}};
|
||||
type_t type_obj_method = { ev_invalid, 0, ty_struct };
|
||||
type_t type_obj_method_description = { ev_invalid, 0, ty_struct };
|
||||
type_t type_obj_category = { ev_invalid, 0, ty_struct};
|
||||
type_t type_obj_ivar = { ev_invalid, 0, ty_struct};
|
||||
type_t type_obj_module = { ev_invalid, 0, ty_struct};
|
||||
type_t type_moduleptr = { ev_pointer, 0, ty_none, {{&type_obj_module}}};
|
||||
type_t type_obj_exec_class = { ev_func, 0, ty_none,
|
||||
type_t type_obj_method = { ev_invalid, 0, 0, ty_struct };
|
||||
type_t type_obj_method_description = { ev_invalid, 0, 0, ty_struct };
|
||||
type_t type_obj_category = { ev_invalid, 0, 0, ty_struct};
|
||||
type_t type_obj_ivar = { ev_invalid, 0, 0, ty_struct};
|
||||
type_t type_obj_module = { ev_invalid, 0, 0, ty_struct};
|
||||
type_t type_moduleptr = { ev_pointer, 0, 1, ty_none,
|
||||
{{&type_obj_module}}};
|
||||
type_t type_obj_exec_class = { ev_func, 0, 1, ty_none,
|
||||
{{&type_void, 1, { &type_moduleptr }}}};
|
||||
|
||||
type_t type_obj_object = {ev_invalid, 0, ty_struct};
|
||||
type_t type_id = { ev_pointer, "id", ty_none, {{&type_obj_object}}};
|
||||
type_t type_obj_class = { ev_invalid, 0, ty_struct};
|
||||
type_t type_Class = { ev_pointer, 0, ty_none, {{&type_obj_class}}};
|
||||
type_t type_obj_protocol = { ev_invalid, 0, ty_struct};
|
||||
type_t type_obj_object = {ev_invalid, 0, 0, ty_struct};
|
||||
type_t type_id = { ev_pointer, "id", 1, ty_none, {{&type_obj_object}}};
|
||||
type_t type_obj_class = { ev_invalid, 0, 0, ty_struct};
|
||||
type_t type_Class = { ev_pointer, 0, 1, ty_none, {{&type_obj_class}}};
|
||||
type_t type_obj_protocol = { ev_invalid, 0, 0, ty_struct};
|
||||
|
||||
int obj_initialized = 0;
|
||||
|
||||
|
|
|
@ -148,11 +148,17 @@ new_def (const char *name, type_t *type, defspace_t *space,
|
|||
|
||||
if (storage != sc_extern) {
|
||||
int size = type_size (type);
|
||||
int alignment = type->alignment;
|
||||
|
||||
if (!size) {
|
||||
error (0, "%s has incomplete type", name);
|
||||
size = 1;
|
||||
}
|
||||
def->offset = defspace_alloc_loc (space, size);
|
||||
if (alignment < 1) {
|
||||
print_type (type);
|
||||
internal_error (0, "temp type has no alignment");
|
||||
}
|
||||
def->offset = defspace_alloc_aligned_loc (space, size, alignment);
|
||||
}
|
||||
|
||||
return def;
|
||||
|
@ -199,16 +205,20 @@ temp_def (type_t *type)
|
|||
def_t *temp;
|
||||
defspace_t *space = current_func->symtab->space;
|
||||
int size = type_size (type);
|
||||
int alignment = type->alignment;
|
||||
|
||||
if (size < 1 || size > 4) {
|
||||
internal_error (0, "%d invalid size for temp def", size);
|
||||
}
|
||||
if (alignment < 1) {
|
||||
internal_error (0, "temp type has no alignment");
|
||||
}
|
||||
if ((temp = current_func->temp_defs[size - 1])) {
|
||||
current_func->temp_defs[size - 1] = temp->temp_next;
|
||||
temp->temp_next = 0;
|
||||
} else {
|
||||
ALLOC (16384, def_t, defs, temp);
|
||||
temp->offset = defspace_alloc_loc (space, size);
|
||||
temp->offset = defspace_alloc_aligned_loc (space, size, alignment);
|
||||
*space->def_tail = temp;
|
||||
space->def_tail = &temp->next;
|
||||
temp->name = save_string (va (".tmp%d", current_func->temp_num++));
|
||||
|
|
|
@ -63,6 +63,33 @@ typedef struct locref_s {
|
|||
static defspace_t *spaces_freelist;
|
||||
static locref_t *locrefs_freelist;
|
||||
|
||||
static locref_t *
|
||||
new_locref (int ofs, int size, locref_t *next)
|
||||
{
|
||||
locref_t *loc;
|
||||
|
||||
ALLOC (1024, locref_t, locrefs, loc);
|
||||
loc->ofs = ofs;
|
||||
loc->size = size;
|
||||
loc->next = next;
|
||||
return loc;
|
||||
}
|
||||
|
||||
static void
|
||||
del_locref (locref_t *loc)
|
||||
{
|
||||
FREE (locrefs, loc);
|
||||
}
|
||||
|
||||
static defspace_t *
|
||||
new_defspace (void)
|
||||
{
|
||||
defspace_t *space;
|
||||
|
||||
ALLOC (1024, defspace_t, spaces, space);
|
||||
return space;
|
||||
}
|
||||
|
||||
#define GROW 1024
|
||||
|
||||
static int
|
||||
|
@ -98,9 +125,8 @@ grow_space_virtual (defspace_t *space)
|
|||
defspace_t *
|
||||
defspace_new (ds_type_t type)
|
||||
{
|
||||
defspace_t *space;
|
||||
defspace_t *space = new_defspace ();
|
||||
|
||||
ALLOC (1024, defspace_t, spaces, space);
|
||||
space->def_tail = &space->defs;
|
||||
space->type = type;
|
||||
if (type == ds_backed) {
|
||||
|
@ -116,33 +142,59 @@ defspace_new (ds_type_t type)
|
|||
int
|
||||
defspace_alloc_loc (defspace_t *space, int size)
|
||||
{
|
||||
int ofs;
|
||||
return defspace_alloc_aligned_loc (space, size, 1);
|
||||
}
|
||||
|
||||
int
|
||||
defspace_alloc_aligned_loc (defspace_t *space, int size, int alignment)
|
||||
{
|
||||
int ofs, pad;
|
||||
locref_t *loc;
|
||||
locref_t **l = &space->free_locs;
|
||||
|
||||
if (size <= 0)
|
||||
internal_error (0, "invalid number of words requested: %d", size);
|
||||
while (*l && (*l)->size < size)
|
||||
l = &(*l)->next;
|
||||
if ((loc = *l)) {
|
||||
ofs = (*l)->ofs;
|
||||
if ((*l)->size == size) {
|
||||
loc = *l;
|
||||
*l = (*l)->next;
|
||||
FREE (locrefs, loc);
|
||||
} else {
|
||||
(*l)->ofs += size;
|
||||
(*l)->size -= size;
|
||||
if (alignment <= 0)
|
||||
internal_error (0, "invalid alignment requested: %d", alignment);
|
||||
while ((loc = *l)) {
|
||||
ofs = loc->ofs;
|
||||
pad = alignment * ((ofs + alignment - 1) / alignment) - ofs;
|
||||
// exact fit, so just shrink the block or remove it if there is no
|
||||
// padding (any padding remains free)
|
||||
if (size + pad == loc->size) {
|
||||
if (!pad) {
|
||||
*l = loc->next;
|
||||
del_locref (loc);
|
||||
}
|
||||
return ofs + pad;
|
||||
}
|
||||
return ofs;
|
||||
// there's excess space in the block. If there's no padding, then
|
||||
// just shrink it, otherwise split it into two, one on either side
|
||||
// of the allocated block, such that the padding remains free
|
||||
if (size + pad < loc->size) {
|
||||
if (!pad) {
|
||||
loc->ofs += size;
|
||||
loc->size -= size;
|
||||
} else {
|
||||
loc->next = new_locref (ofs + pad + size,
|
||||
loc->size - ofs - pad, loc->next);
|
||||
loc->size = pad;
|
||||
}
|
||||
return ofs + pad;
|
||||
}
|
||||
l = &(*l)->next;
|
||||
}
|
||||
ofs = space->size;
|
||||
space->size += size;
|
||||
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);
|
||||
}
|
||||
return ofs;
|
||||
if (pad) {
|
||||
*l = new_locref (ofs, pad, 0);
|
||||
}
|
||||
return ofs + pad;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -184,17 +236,13 @@ defspace_free_loc (defspace_t *space, int ofs, int size)
|
|||
loc->size += loc->next->size;
|
||||
loc = loc->next;
|
||||
*l = loc->next;
|
||||
FREE (locrefs, loc);
|
||||
del_locref (loc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// insert a new free block for the location to be freed
|
||||
ALLOC (1024, locref_t, locrefs, loc);
|
||||
loc->ofs = ofs;
|
||||
loc->size = size;
|
||||
loc->next = *l;
|
||||
*l = loc;
|
||||
*l = new_locref (ofs, size, *l);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -158,6 +158,7 @@ parse_params (type_t *type, param_t *parms)
|
|||
|
||||
new = new_type ();
|
||||
new->type = ev_func;
|
||||
new->alignment = 1;
|
||||
new->t.func.type = type;
|
||||
new->t.func.num_params = 0;
|
||||
|
||||
|
|
|
@ -112,6 +112,7 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type)
|
|||
{
|
||||
symbol_t *sym = find_struct (su, tag, type);
|
||||
symbol_t *s;
|
||||
int alignment = 1;
|
||||
|
||||
symtab->parent = 0; // disconnect struct's symtab from parent scope
|
||||
|
||||
|
@ -130,10 +131,14 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type)
|
|||
if (size > symtab->size)
|
||||
symtab->size = size;
|
||||
}
|
||||
if (s->type->alignment > alignment) {
|
||||
alignment = s->type->alignment;
|
||||
}
|
||||
}
|
||||
if (!type)
|
||||
sym->type = find_type (sym->type); // checks the tag, not the symtab
|
||||
sym->type->t.symtab = symtab;
|
||||
sym->type->alignment = alignment;
|
||||
if (!type && sym->type->type_def->external) //FIXME should not be necessary
|
||||
sym->type->type_def = qfo_encode_type (sym->type);
|
||||
return sym;
|
||||
|
@ -166,6 +171,7 @@ finish_enum (symbol_t *sym)
|
|||
|
||||
enum_type = sym->type = find_type (sym->type);
|
||||
enum_tab = enum_type->t.symtab;
|
||||
enum_type->alignment = 1;
|
||||
|
||||
for (name = enum_tab->symbols; name; name = name->next) {
|
||||
name->type = sym->type;
|
||||
|
|
|
@ -63,20 +63,20 @@
|
|||
// simple types. function types are dynamically allocated
|
||||
type_t type_invalid = { ev_invalid, "invalid" };
|
||||
type_t type_void = { ev_void, "void" };
|
||||
type_t type_string = { ev_string, "string" };
|
||||
type_t type_float = { ev_float, "float" };
|
||||
type_t type_vector = { ev_vector, "vector" };
|
||||
type_t type_entity = { ev_entity, "entity" };
|
||||
type_t type_field = {ev_field, "field", ty_none, {{&type_void}} };
|
||||
type_t type_string = { ev_string, "string", 1 };
|
||||
type_t type_float = { ev_float, "float", 1 };
|
||||
type_t type_vector = { ev_vector, "vector", 1 };
|
||||
type_t type_entity = { ev_entity, "entity", 1 };
|
||||
type_t type_field = {ev_field, "field", 1, ty_none, {{&type_void}} };
|
||||
|
||||
// type_function is a void() function used for state defs
|
||||
type_t type_function = { ev_func, "function", ty_none, {{&type_void}} };
|
||||
type_t type_pointer = { ev_pointer, "pointer", ty_none, {{&type_void}} };
|
||||
type_t type_quaternion = { ev_quat, "quaternion" };
|
||||
type_t type_integer = { ev_integer, "int" };
|
||||
type_t type_uinteger = { ev_uinteger, "uint" };
|
||||
type_t type_short = { ev_short, "short" };
|
||||
type_t type_double = { ev_double, "double" };
|
||||
type_t type_function = { ev_func, "function", 1, ty_none, {{&type_void}} };
|
||||
type_t type_pointer = { ev_pointer, "pointer", 1, ty_none, {{&type_void}} };
|
||||
type_t type_quaternion = { ev_quat, "quaternion", 1 };
|
||||
type_t type_integer = { ev_integer, "int", 1 };
|
||||
type_t type_uinteger = { ev_uinteger, "uint", 1 };
|
||||
type_t type_short = { ev_short, "short", 1 };
|
||||
type_t type_double = { ev_double, "double", 2 };
|
||||
|
||||
type_t *type_nil;
|
||||
type_t *type_default;
|
||||
|
@ -85,9 +85,11 @@ type_t *type_default;
|
|||
type_t type_va_list = { ev_invalid, 0, ty_struct };
|
||||
type_t type_param = { ev_invalid, 0, ty_struct };
|
||||
type_t type_zero = { ev_invalid, 0, ty_struct };
|
||||
type_t type_type_encodings = { ev_invalid, "@type_encodings", ty_struct };
|
||||
type_t type_type_encodings = { ev_invalid, "@type_encodings", 0,
|
||||
ty_struct };
|
||||
|
||||
type_t type_floatfield = { ev_field, ".float", ty_none, {{&type_float}} };
|
||||
type_t type_floatfield = { ev_field, ".float", 1, ty_none,
|
||||
{{&type_float}} };
|
||||
|
||||
type_t *ev_types[ev_type_count] = {
|
||||
&type_void,
|
||||
|
@ -222,15 +224,19 @@ append_type (type_t *type, type_t *new)
|
|||
case ev_field:
|
||||
case ev_pointer:
|
||||
t = &(*t)->t.fldptr.type;
|
||||
type->alignment = 1;
|
||||
break;
|
||||
case ev_func:
|
||||
t = &(*t)->t.func.type;
|
||||
type->alignment = 1;
|
||||
break;
|
||||
case ev_invalid:
|
||||
if ((*t)->meta == ty_array)
|
||||
if ((*t)->meta == ty_array) {
|
||||
t = &(*t)->t.array.type;
|
||||
else
|
||||
type->alignment = new->alignment;
|
||||
} else {
|
||||
internal_error (0, "append to object type");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -364,6 +370,7 @@ field_type (type_t *aux)
|
|||
else
|
||||
new = new_type ();
|
||||
new->type = ev_field;
|
||||
new->alignment = 1;
|
||||
new->t.fldptr.type = aux;
|
||||
if (aux)
|
||||
new = find_type (new);
|
||||
|
@ -381,6 +388,7 @@ pointer_type (type_t *aux)
|
|||
else
|
||||
new = new_type ();
|
||||
new->type = ev_pointer;
|
||||
new->alignment = 1;
|
||||
new->t.fldptr.type = aux;
|
||||
if (aux)
|
||||
new = find_type (new);
|
||||
|
@ -398,6 +406,9 @@ array_type (type_t *aux, int size)
|
|||
else
|
||||
new = new_type ();
|
||||
new->type = ev_invalid;
|
||||
if (aux) {
|
||||
new->alignment = aux->alignment;
|
||||
}
|
||||
new->meta = ty_array;
|
||||
new->t.array.type = aux;
|
||||
new->t.array.size = size;
|
||||
|
@ -417,6 +428,9 @@ based_array_type (type_t *aux, int base, int top)
|
|||
else
|
||||
new = new_type ();
|
||||
new->type = ev_invalid;
|
||||
if (aux) {
|
||||
new->alignment = aux->alignment;
|
||||
}
|
||||
new->meta = ty_array;
|
||||
new->t.array.type = aux;
|
||||
new->t.array.base = base;
|
||||
|
|
Loading…
Reference in a new issue