Permalink
Browse files

Internalize RegisterAllocator structure

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 34da4f632463018159cfdada3e77968634eaaa04
Showing with 81 additions and 87 deletions.
  1. +0 −2 src/jit/internal.h
  2. +81 −67 src/jit/register.c
  3. +0 −17 src/jit/register.h
  4. +0 −1 src/types.h
View
@@ -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 */
View
@@ -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 {
@@ -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);
}
}
@@ -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);
}
}
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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];
}
@@ -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;
@@ -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
@@ -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);
}
View
@@ -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);
View
@@ -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;

0 comments on commit 34da4f6

Please sign in to comment.