#include #include #include #include "regscope.h" void reg_alloc_init (reg_alloc_t *ra, fragment_t *frag, stack_man_t *stack, const reg_pool_t *reg_pool) { int i; ra->pool = reg_pool; ra->stack = stack; ra->fragment = frag; for (i = 0; i < ra->pool->n_registers; ++i) { int j; ra->status[i].allocated = FALSE; ra->status[i].spillable = FALSE; ra->status[i].n_spills = 0; for (j = 0; j < MAX_SPILLS; ++j) ra->status[i].spill_offsets[j] = -1; } } /* Allocates a register. The allocation is non-local, so it * is allowed to survive the current begin/end_spill group. */ reg_t reg_alloc_alloc (reg_alloc_t *ra) { int i; for (i = 0; i < ra->pool->n_registers; ++i) { reg_status_t *status = &ra->status[i]; if (!status->allocated) { status->allocated = 1; return ra->pool->registers[i]; } } return (reg_t)0; } static void one_register_begin_spill (reg_alloc_t *ra, reg_status_t *status, reg_t reg) { if (!status->allocated) fprintf (stderr, "Attempting to spill a register that isn't allocated\n"); if (status->spillable) fprintf (stderr, "Attempting to spill a register that is already spillable\n"); status->spillable = TRUE; } static void one_register_end_spill (reg_alloc_t *ra, reg_status_t *status, reg_t reg) { if (!status->allocated) fprintf (stderr, "Attempting to unspill an unallocated register\n"); if (!status->spillable) { int offset; if (status->n_spills < 0) { fprintf (stderr, "No spill offset available for reloading\n"); return; } offset = status->spill_offsets[--status->n_spills]; BEGIN_ASM (ra->fragment) ra->pool->move_instruction, reg, BASE(rsp, offset), END_ASM (); } status->spillable = FALSE; } static int find_index (reg_alloc_t *ra, reg_t reg) { int i; for (i = 0; i < ra->pool->n_registers; ++i) { if (ra->pool->registers[i] == reg) return i; } return -1; } /* Calling this indicates that the registers given will not be * needed until the corresponding reg_alloc_end_spill(). */ void reg_alloc_begin_spill (reg_alloc_t *ra, reg_t reg, ...) { va_list list; va_start (list, reg); while (reg != (reg_t)0) { int idx = find_index (ra, reg); one_register_begin_spill (ra, &ra->status[idx], reg); reg = va_arg (list, reg_t); } va_end (list); } void reg_alloc_end_spill (reg_alloc_t *ra, reg_t reg, ...) { va_list list; va_start (list, reg); while (reg != (reg_t)0) { int idx = find_index (ra, reg); one_register_end_spill (ra, &ra->status[idx], reg); reg = va_arg (list, reg_t); } va_end (list); } /* This allocates a register. Calliing this function indicates that * the register in question will be freed before the current * begin/end_spill group ends. */ reg_t reg_alloc_alloc_local (reg_alloc_t *ra) { reg_t reg; int i; reg = reg_alloc_alloc (ra); if (reg) return reg; /* All registers are in use, so find a spillable one */ for (i = 0; i < ra->pool->n_registers; ++i) { reg_status_t *status = &ra->status[i]; int offset; if (status->spillable) { reg_t reg = ra->pool->registers[i]; if (!stack_manager_alloc ( ra->stack, ra->pool->bytes_per_reg, &offset)) { fprintf (stderr, "OOM\n"); } BEGIN_ASM (ra->fragment) ra->pool->move_instruction, BASE(rsp, offset), reg, END_ASM (); if (status->n_spills >= MAX_SPILLS) { fprintf (stderr, "Out of spill levels\n"); } status->spill_offsets[status->n_spills++] = offset; status->allocated = TRUE; status->spillable = 0; return reg; } } return (reg_t)0; } /* This resurrects a register that has been freed, but is known * to still contain a useful value. The allocation is non-local, * so it is allowed to survive the current begin/end_spill group. * * The returned register may or may not be the same as the * input register. */ reg_t reg_alloc_alloc_preserve (reg_alloc_t *ra, reg_t reg) { int idx = find_index (ra, reg); reg_t new_loc; if (!ra->status[idx].allocated) { ra->status[idx].allocated = TRUE; return reg; } new_loc = reg_alloc_alloc (ra); if (new_loc) { BEGIN_ASM (ra->fragment) ra->pool->move_instruction, new_loc, reg, END_ASM (); } return new_loc; } void reg_alloc_free (reg_alloc_t *ra, reg_t reg) { int idx = find_index (ra, reg); reg_status_t *status = &ra->status[idx]; if (status->spillable) { fprintf (stderr, "Attempting to free a spillable register\n"); return; } if (status->n_spills == 0) status->allocated = FALSE; } int main () { return 0; }