#include #include #include #include "reggroups.h" #include "stack-man.h" #include "simplex86.h" static int reg_to_index (reg_alloc_t *ra, reg_t reg) { const reg_pool_t *pool = ra->reg_pool; int i; for (i = 0; i < pool->n_registers; ++i) { if (pool->registers[i] == reg) return i; } return -1; } void reg_alloc_init (reg_alloc_t *ra, stack_man_t *stack, const reg_pool_t *reg_pool) { ra->reg_pool = reg_pool; memset (ra->groups, 0, sizeof (ra->groups)); ra->active = NULL; } static reg_group_t * find_group (reg_alloc_t *ra, const char *name) { int i; for (i = 0; i < MAX_GROUPS; ++i) { if (strcmp (ra->groups[i].name, name) == 0) return &(ra->groups[i]); } return NULL; } static reg_group_t * find_owner (reg_alloc_t *ra, reg_t reg) { int idx = reg_to_index (ra, reg); int i; for (i = 0; i < MAX_GROUPS; ++i) { reg_group_t *group = &ra->groups[i]; if (group->name == NULL) continue; if (group->allocated[idx] && group->spill_offset[idx] == -1) return group; } return NULL; } void reg_alloc_switch_group (reg_alloc_t *ra, const char *name) { ra->active = find_group (ra, name); } void reg_alloc_free_group (reg_alloc_t *ra, const char *name) { reg_group_t *group = find_group (ra, name); memset (group, 0, sizeof (reg_group_t)); } static void take_ownership (reg_alloc_t *ra, reg_t reg) { reg_group_t *old_owner = find_owner (ra, reg); int idx = reg_to_index (ra, reg); if (old_owner) { /* FIXME: spill the old owner */ } ra->active->allocated[idx] = 1; ra->active->spill_offset[idx] = -1; } static void relinguish_ownership (reg_alloc_t *ra, reg_t reg) { int idx = reg_to_index (ra, reg); ra->active->allocated[idx] = 0; ra->active->spill_offset[idx] = -1; } static reg_t reload_one_reg (reg_alloc_t *ra, reg_t reg) { reg_group_t *owner = find_owner (ra, reg); reg_t new_location; int idx; int i; if (owner == ra->active) return reg; idx = reg_to_index (ra, reg); if (!ra->active->allocated[idx]) { fprintf (stderr, "Attempting to reload a register that " "isn't allocated in the current group"); return (reg_t)0; } new_location = reg; for (i = 0; i < ra->reg_pool->n_registers; ++i) { reg_t r = ra->reg_pool->registers[i]; if (!find_owner (ra, r)) { new_location = r; break; } } if (new_location != reg) relinguish_ownership (ra, reg); take_ownership (ra, new_location); /* FIXME: Insert unspill code into new_location */ return new_location; } /* After switching back to a group, this should be called for * all registers that will be used again before switching away. * * FIXME: these should be pointers, so that the registers can * be reallocated in more convenient registers if necessary. */ void reg_alloc_reload (reg_alloc_t *ra, reg_t *reg, ...) { va_list list; va_start (list, reg); while (reg) { *reg = reload_one_reg (ra, *reg); reg = va_arg (list, reg_t *); } va_end (list); } /* allocate some register within the current group */ reg_t reg_alloc_alloc (reg_alloc_t *ra) { int i; /* Is there a register that doesn't have an owner? */ for (i = 0; i < ra->reg_pool->n_registers; ++i) { reg_t reg = ra->reg_pool->registers[i]; reg_group_t *owner = find_owner (ra, reg); if (!owner) { take_ownership (ra, reg); return reg; } } /* Is there a register that is owned by someone else? */ for (i = 0; i < ra->reg_pool->n_registers; ++i) { reg_t reg = ra->reg_pool->registers[i]; reg_group_t *owner = find_owner (ra, reg); if (owner && owner != ra->active) { take_ownership (ra, reg); return reg; } } /* No. If we get here, something is seriously wrong. Either: * - an internal error in the register allocator has * produced a situation where a register is in use * but no group claims to own it. * - all registers in the current group have been allocated */ for (i = 0; i < MAX_REGISTERS; ++i) { if (!ra->active->allocated[i]) { fprintf ( stderr, "BUG in register allocator: slot available, " "but no register can be spilled\n"); return (reg_t)0; } } fprintf (stderr, "group %s is out of registers\n", ra->active->name); return (reg_t)0; } /* @reg becomes allocated in the current group, though it * may be moved to another register */ reg_t reg_alloc_preserve (reg_alloc_t *ra, reg_t reg) { reg_group_t *owner; int i; owner = find_owner (ra, reg); if (owner == ra->active) { fprintf (stderr, "Can't preserve value of allocated register\n"); return (reg_t)0; } /* If the register is not in use by another group, then * just take ownership. */ if (!owner) { take_ownership (ra, reg); return reg; } /* Otherwise, is there some other unowned register in * the current group? */ for (i = 0; i < ra->reg_pool->n_registers; ++i) { reg_t r = ra->reg_pool->registers[i]; if (!find_owner (ra, r)) { take_ownership (ra, r); /* FIXME: Issue "mov r, reg" */ return r; } } /* Otherwise, just spill reg in its current owner */ take_ownership (ra, reg); return reg; } void reg_alloc_free (reg_alloc_t *ra, reg_t reg) { relinguish_ownership (ra, reg); } typedef struct reg_info_t reg_info_t; typedef struct reg_alloc_t reg_alloc_t; typedef struct reg_context_t reg_context_t; typedef enum { UNUSED, /* not in use by us, and not in use by parent */ IN_USE, /* in use by us, but not parent */ SPILLABLE, /* in use by parent, but not by us */ SPILLED, /* parent value spilled on stack, and in use by us */ CLOBBERED, /* parent value spilled on stack, but not used by us anymore */ } reg_state_t; struct reg_info_t { reg_state_t state; int spill_offset; }; struct reg_context_t { reg_alloc_t * allocator; reg_context_t * parent; reg_info_t info[MAX_REGISTERS]; }; /* The registers */