Implement aligned allocations

This commit is contained in:
Bill Currie 2020-02-15 02:21:21 +09:00
parent 293f10211a
commit a4a57b6ffd
8 changed files with 161 additions and 59 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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