Skip to content

Commit

Permalink
Internalize RegisterAllocator structure
Browse files Browse the repository at this point in the history
The register allocator only contains temporary structures, and as
such does not need to be 'public'.
  • Loading branch information
bdw committed Jun 4, 2016
1 parent fcc270b commit 34da4f6
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 87 deletions.
2 changes: 0 additions & 2 deletions src/jit/internal.h
Expand Up @@ -25,8 +25,6 @@ struct MVMJitCompiler {
/* For spilling values that don't fit into the register allocator */
MVMint32 spill_offset;
MVMint32 max_spill;

MVMJitRegisterAllocator *allocator;
};

/* Declarations for architecture-specific codegen stuff */
Expand Down
148 changes: 81 additions & 67 deletions src/jit/register.c
Expand Up @@ -23,63 +23,79 @@ static MVMint8 free_num[] = { -1 };
#define UNLOCK_REGISTER(a,n) ((a)->reg_lock &= ~(1 << (n)))


struct RegisterAllocator {
MVM_DYNAR_DECL(MVMJitValueDescriptor*, active);

void MVM_jit_register_allocator_init(MVMThreadContext *tc, MVMJitCompiler *compiler,
MVMJitRegisterAllocator *alc, MVMJitTileList *list) {
/* Values by node */
MVMJitValueDescriptor **values_by_node;

MVMJitCompiler *compiler;

/* Register giveout ring */
MVMint8 *free_reg;
MVMuint8 *reg_use;

MVMint32 reg_give, reg_take;

/* topmost spill location used */
MVMint32 spill_top;
/* Bitmap of used registers */
MVMint32 reg_lock;
};


void MVM_jit_register_allocator_init(MVMThreadContext *tc, struct RegisterAllocator *allocator,
MVMJitCompiler *compiler, MVMJitTileList *list) {
/* Store live ranges */
MVM_DYNAR_INIT(alc->active, NUM_GPR);
MVM_DYNAR_INIT(allocator->active, NUM_GPR);
/* Initialize free register buffer */
alc->free_reg = MVM_malloc(sizeof(free_gpr));
memcpy(alc->free_reg, free_gpr, NUM_GPR);
allocator->free_reg = MVM_malloc(sizeof(free_gpr));
memcpy(allocator->free_reg, free_gpr, NUM_GPR);

alc->reg_use = MVM_calloc(16, sizeof(MVMint8));
allocator->reg_use = MVM_calloc(16, sizeof(MVMint8));

alc->reg_give = 0;
alc->reg_take = 0;
allocator->reg_give = 0;
allocator->reg_take = 0;

alc->spill_top = 1;
alc->reg_lock = 0;
allocator->spill_top = 1;
allocator->reg_lock = 0;

alc->values_by_node = MVM_calloc(list->tree->nodes_num, sizeof(void*));
allocator->values_by_node = MVM_calloc(list->tree->nodes_num, sizeof(void*));

compiler->allocator = alc;
allocator->compiler = compiler;
}

void MVM_jit_register_allocator_deinit(MVMThreadContext *tc, MVMJitCompiler *compiler,
MVMJitRegisterAllocator *alc) {
MVM_free(alc->active);
MVM_free(alc->free_reg);
MVM_free(alc->reg_use);
MVM_free(alc->values_by_node);
compiler->allocator = NULL;
void MVM_jit_register_allocator_deinit(MVMThreadContext *tc, struct RegisterAllocator *allocator) {
MVM_free(allocator->active);
MVM_free(allocator->free_reg);
MVM_free(allocator->reg_use);
MVM_free(allocator->values_by_node);
}

#define NYI(x) MVM_oops(tc, #x " NYI");


MVMint8 MVM_jit_register_alloc(MVMThreadContext *tc, MVMJitCompiler *cl, MVMint32 reg_cls) {
MVMJitRegisterAllocator *alc = cl->allocator;
MVMint8 MVM_jit_register_alloc(MVMThreadContext *tc, struct RegisterAllocator *allocator, MVMint32 reg_cls) {
MVMint8 reg_num;
if (reg_cls == MVM_JIT_STORAGE_FPR) {
NYI(numeric_regs);
} else {
if (NEXT_REG(alc->reg_take) == alc->reg_give) {
if (NEXT_REG(allocator->reg_take) == allocator->reg_give) {
/* Out of registers, spill something */
NYI(spill_something);
}
/* Use a circular handout scheme for the 'fair use' of registers */
reg_num = alc->free_reg[alc->reg_take];
alc->free_reg[alc->reg_take] = 0xff; /* mark it for debugging purposes */
alc->reg_take = NEXT_REG(alc->reg_take);
reg_num = allocator->free_reg[allocator->reg_take];
allocator->free_reg[allocator->reg_take] = 0xff; /* mark it for debugging purposes */
allocator->reg_take = NEXT_REG(allocator->reg_take);
}
/* MVM_jit_log(tc, "Allocated register %d at order nr %d\n", reg_num, cl->order_nr); */
return reg_num;
}


/* Freeing a register makes it available again */
void MVM_jit_register_free(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMint32 reg_cls, MVMint8 reg_num) {
MVMJitRegisterAllocator *alc = compiler->allocator;
void MVM_jit_register_free(MVMThreadContext *tc, struct RegisterAllocator *allocator, MVMint32 reg_cls, MVMint8 reg_num) {
if (reg_cls == MVM_JIT_STORAGE_FPR) {
NYI(numeric_regs);
} else {
Expand All @@ -92,11 +108,11 @@ void MVM_jit_register_free(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMin
}
MVM_oops(tc, "This is not a free register!");
ok:
if (alc->reg_give == alc->reg_take) {
if (allocator->reg_give == allocator->reg_take) {
MVM_oops(tc, "Trying to free too many registers");
}
alc->free_reg[alc->reg_give] = reg_num;
alc->reg_give = NEXT_REG(alc->reg_give);
allocator->free_reg[allocator->reg_give] = reg_num;
allocator->reg_give = NEXT_REG(allocator->reg_give);
}
}

Expand All @@ -105,41 +121,40 @@ void MVM_jit_register_free(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMin


/* Assign a register to a value */
void MVM_jit_register_assign(MVMThreadContext *tc, MVMJitCompiler *cl, MVMJitValueDescriptor *value, MVMJitStorageClass st_cls, MVMint8 reg_num) {
MVMJitRegisterAllocator *alc = cl->allocator;
void MVM_jit_register_assign(MVMThreadContext *tc, struct RegisterAllocator *allocator, MVMJitValueDescriptor *value, MVMJitStorageClass st_cls, MVMint8 reg_num) {
value->st_cls = st_cls;
value->st_pos = reg_num;

MVM_DYNAR_PUSH(alc->active, value);
alc->reg_use[reg_num]++;
MVM_DYNAR_PUSH(allocator->active, value);
allocator->reg_use[reg_num]++;
}


/* Expiring a value marks it dead and possibly releases its register */
void MVM_jit_register_expire(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitValueDescriptor *value) {
MVMJitRegisterAllocator *alc = compiler->allocator;
void MVM_jit_register_expire(MVMThreadContext *tc, struct RegisterAllocator *allocator, MVMJitValueDescriptor *value) {

MVMint8 reg_num = value->st_pos;
MVMint32 i;
if (value->st_cls == MVM_JIT_STORAGE_FPR) {
NYI(numeric_regs);
}
/* Remove value from active */
i = 0;
while (i < alc->active_num) {
if (alc->active[i] == value) {
while (i < allocator->active_num) {
if (allocator->active[i] == value) {
/* splice it out */
alc->active_num--;
alc->active[i] = alc->active[alc->active_num];
allocator->active_num--;
allocator->active[i] = allocator->active[allocator->active_num];
} else {
i++;
}
}

if (value->st_cls == MVM_JIT_STORAGE_GPR) {
/* Decrease register number count and free if possible */
alc->reg_use[reg_num]--;
if (alc->reg_use[reg_num] == 0) {
MVM_jit_register_free(tc, compiler, value->st_cls, reg_num);
allocator->reg_use[reg_num]--;
if (allocator->reg_use[reg_num] == 0) {
MVM_jit_register_free(tc, allocator, value->st_cls, reg_num);
}
}
}
Expand All @@ -148,24 +163,23 @@ void MVM_jit_register_expire(MVMThreadContext *tc, MVMJitCompiler *compiler, MVM


/* Expire values that are no longer useful */
void MVM_jit_expire_values(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMint32 order_nr) {
MVMJitRegisterAllocator *alc = compiler->allocator;
void MVM_jit_expire_values(MVMThreadContext *tc, struct RegisterAllocator *allocator, MVMint32 order_nr) {
MVMint32 i = 0;
while (i < alc->active_num) {
MVMJitValueDescriptor *value = alc->active[i];
while (i < allocator->active_num) {
MVMJitValueDescriptor *value = allocator->active[i];
if (value->range_end <= order_nr) {
MVM_jit_register_expire(tc, compiler, value);
MVM_jit_register_expire(tc, allocator, value);
} else {
i++;
}
}
}


static MVMJitValueDescriptor* node_value(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMint32 node) {
MVMJitValueDescriptor **v = compiler->allocator->values_by_node + node;
static MVMJitValueDescriptor* node_value(MVMThreadContext *tc, struct RegisterAllocator *allocator, MVMint32 node) {
MVMJitValueDescriptor **v = allocator->values_by_node + node;
if (*v == NULL) {
*v = MVM_spesh_alloc(tc, compiler->graph->sg, sizeof(MVMJitValueDescriptor));
*v = MVM_spesh_alloc(tc, allocator->compiler->graph->sg, sizeof(MVMJitValueDescriptor));
}
return *v;
}
Expand All @@ -181,22 +195,22 @@ static void arglist_get_nodes(MVMThreadContext *tc, MVMJitExprTree *tree,



static void MVM_jit_get_values(MVMThreadContext *tc, MVMJitCompiler *compiler,
static void MVM_jit_get_values(MVMThreadContext *tc, struct RegisterAllocator *allocator,
MVMJitExprTree *tree, MVMJitTile *tile) {
MVMJitExprNode node = tile->node;
MVMJitExprNode buffer[16];
const MVMJitTileTemplate *template = tile->template;

tile->values[0] = node_value(tc, compiler, node);
tile->values[0] = node_value(tc, allocator, node);
tile->values[0]->size = tree->info[node].size;

switch (tree->nodes[node]) {
case MVM_JIT_IF:
{
MVMint32 left = tree->nodes[node+2], right = tree->nodes[node+3];
/* assign results of IF to values array */
tile->values[1] = node_value(tc, compiler, left);
tile->values[2] = node_value(tc, compiler, right);
tile->values[1] = node_value(tc, allocator, left);
tile->values[2] = node_value(tc, allocator, right);
tile->num_values = 2;
break;
}
Expand All @@ -208,15 +222,15 @@ static void MVM_jit_get_values(MVMThreadContext *tc, MVMJitCompiler *compiler,
tile->num_values = tree->nodes[node+1];
arglist_get_nodes(tc, tree, node, buffer);
for (i = 0; i < tile->num_values; i++) {
tile->values[i+1] = node_value(tc, compiler, buffer[i]);
tile->values[i+1] = node_value(tc, allocator, buffer[i]);
}
break;
}
case MVM_JIT_DO:
{
MVMint32 nchild = tree->nodes[node+1];
MVMint32 last_child = tree->nodes[node+1+nchild];
tile->values[1] = node_value(tc, compiler, last_child);
tile->values[1] = node_value(tc, allocator, last_child);
tile->num_values = 1;
break;
}
Expand All @@ -230,7 +244,7 @@ static void MVM_jit_get_values(MVMThreadContext *tc, MVMJitCompiler *compiler,
k = 0;
for (i = 0; i < num_nodes; i++) {
if (value_bitmap & 1) {
tile->values[j++] = node_value(tc, compiler, buffer[i]);
tile->values[j++] = node_value(tc, allocator, buffer[i]);
} else {
tile->args[k++] = buffer[i];
}
Expand All @@ -244,22 +258,22 @@ static void MVM_jit_get_values(MVMThreadContext *tc, MVMJitCompiler *compiler,


void MVM_jit_register_allocate(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitTileList *list) {
MVMJitRegisterAllocator allocator;
struct RegisterAllocator allocator;
MVMJitExprTree *tree = list->tree;
MVMJitTile *tile;
MVMJitValueDescriptor *value;
MVMint32 i, j;
MVMint8 reg;

/* Allocate tables used in register */
MVM_jit_register_allocator_init(tc, compiler, &allocator, list);
MVM_jit_register_allocator_init(tc, &allocator, compiler, list);

/* Get value descriptors and calculate live ranges */
for (i = 0; i < list->items_num; i++) {
tile = list->items[i];
if (tile->template == NULL) /* pseudotiles */
continue;
MVM_jit_get_values(tc, compiler, tree, tile);
MVM_jit_get_values(tc, &allocator, tree, tile);
tile->values[0]->range_start = i;
for (j = 0; j < tile->num_values; j++) {
tile->values[j+1]->range_end = i;
Expand All @@ -278,7 +292,7 @@ void MVM_jit_register_allocate(MVMThreadContext *tc, MVMJitCompiler *compiler, M
switch(tree->nodes[tile->node]) {
case MVM_JIT_COPY:
/* use same register as input */
MVM_jit_register_assign(tc, compiler, value, tile->values[1]->st_cls, tile->values[1]->st_pos);
MVM_jit_register_assign(tc, &allocator, value, tile->values[1]->st_cls, tile->values[1]->st_pos);
break;
case MVM_JIT_TC:
/* TODO, this isn't really portable, we should have register
Expand All @@ -305,16 +319,16 @@ void MVM_jit_register_allocate(MVMThreadContext *tc, MVMJitCompiler *compiler, M
tile->values[1]->st_cls == MVM_JIT_STORAGE_GPR &&
tile->values[1]->range_end == j) {
/* First register expires immediately, therefore we can safely cross-assign */
MVM_jit_register_assign(tc, compiler, value, tile->values[1]->st_cls, tile->values[1]->st_pos);
MVM_jit_register_assign(tc, &allocator, value, tile->values[1]->st_cls, tile->values[1]->st_pos);
} else {
reg = MVM_jit_register_alloc(tc, compiler, MVM_JIT_STORAGE_GPR);
MVM_jit_register_assign(tc, compiler, value, MVM_JIT_STORAGE_GPR, reg);
reg = MVM_jit_register_alloc(tc, &allocator, MVM_JIT_STORAGE_GPR);
MVM_jit_register_assign(tc, &allocator, value, MVM_JIT_STORAGE_GPR, reg);
}
}
break;
}
/* Expire dead values */
MVM_jit_expire_values(tc, compiler, i);
MVM_jit_expire_values(tc, &allocator, i);
}
MVM_jit_register_allocator_deinit(tc, compiler, &allocator);
MVM_jit_register_allocator_deinit(tc, &allocator);
}
17 changes: 0 additions & 17 deletions src/jit/register.h
Expand Up @@ -20,22 +20,5 @@ struct MVMJitValueDescriptor {
MVMJitValueDescriptor *next_by_position;
};

struct MVMJitRegisterAllocator {
MVM_DYNAR_DECL(MVMJitValueDescriptor*, active);

/* Values by node */
MVMJitValueDescriptor **values_by_node;

/* Register giveout ring */
MVMint8 *free_reg;
MVMuint8 *reg_use;

MVMint32 reg_give, reg_take;

/* topmost spill location used */
MVMint32 spill_top;
/* Bitmap of used registers */
MVMint32 reg_lock;
};

void MVM_jit_register_allocate(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitTileList *list);
1 change: 0 additions & 1 deletion src/types.h
Expand Up @@ -234,7 +234,6 @@ typedef struct MVMJitTileTemplate MVMJitTileTemplate;
typedef struct MVMJitTile MVMJitTile;
typedef struct MVMJitTileList MVMJitTileList;
typedef struct MVMJitValueDescriptor MVMJitValueDescriptor;
typedef struct MVMJitRegisterAllocator MVMJitRegisterAllocator;
typedef struct MVMProfileThreadData MVMProfileThreadData;
typedef struct MVMProfileGC MVMProfileGC;
typedef struct MVMProfileCallNode MVMProfileCallNode;
Expand Down

0 comments on commit 34da4f6

Please sign in to comment.