#include "stack-man.h" #include "simplex86.h" typedef struct reg_info_t reg_info_t; typedef struct reg_alloc_t reg_alloc_t; typedef struct reg_context_t reg_context_t; #define MAX_REGISTERS 64 typedef struct reg_pool_t reg_pool_t; struct reg_pool_t { int n_registers; int register_size; op_t registers[MAX_REGISTERS]; }; struct reg_alloc_t { const reg_pool_t * registers; stack_man_t * stack_man; }; 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]; }; void reg_alloc_init (reg_alloc_t * reg_alloc, const reg_pool_t *registers, stack_man_t * stack_man, reg_context_t * initial_context, int n_initial, /* op_t reg, */ ...); /* The registers */ /* Initializes a context. All registers in the * parent context become available for allocations * except those listed as preserved. * * When the context finishes, all registers allocated * in the parent are restored to their original value. * * "preserved" means that that register will be * allocated in the new context and that its value * is preserved. * * Even a register that is not allocated in the parent * may be listed as preserved if its value is known and * it is known that no other registers have been allocated * since the register was freed. */ void reg_context_init (reg_context_t *ctx, reg_context_t *parent, int n_preserved, /* op_t var, */ ...); /* All registers allocated in @ctx, except those listed as * preserved, are deallocated, and those registers that were * in use by the parent context are restored. * * An attempt will be made to allocate all the preserved * registers in the parent context. If a register is * also in use by the parent the value will be moved to another * register. * * If it isn't possible to preserve all the * listed registers, this function returns FALSE. */ bool_t reg_context_fini (reg_context_t *ctx, fragment_t *frag, int n_preserved, /* op_t *var, */...); /* Allocate a register. * Returns (op_t)0 on failure */ op_t reg_context_alloc (reg_context_t *ctx, fragment_t *frag); /* When a register is freed, it doesn't become invalid * until next time a register is allocated. If a register * is known to be free-but-still-valid, it can be resurrected * by listing it in a call to reg_context_init(). */ void reg_context_free (reg_context_t *ctx, op_t op);