Permalink
Browse files

Reduce register allocator surface area

We will now need way to specify per-tile register requirements,
as tiles can no longer try and 'fix' their registers at runtime.
We don't actually seem to hit the NYI paths, though.
  • Loading branch information...
bdw committed Jun 4, 2016
1 parent 6a6fcc0 commit 9a6ca8108108595442063772fa266753903d7e26
Showing with 194 additions and 235 deletions.
  1. +2 −184 src/jit/compile.c
  2. +186 −1 src/jit/register.c
  3. +1 −27 src/jit/register.h
  4. +5 −23 src/jit/x64/tiles.dasc
View
@@ -7,7 +7,6 @@ void MVM_jit_compiler_init(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJi
void MVM_jit_compiler_deinit(MVMThreadContext *tc, MVMJitCompiler *compiler);
MVMJitCode * MVM_jit_compiler_assemble(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg);
void MVM_jit_compile_expr_tree(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *graph, MVMJitExprTree *tree);
void MVM_jit_allocate_registers(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitExprTree *tree, MVMJitTileList *list);
#define COPY_ARRAY(a, n) memcpy(MVM_malloc(n * sizeof(a[0])), a, n * sizeof(a[0]))
@@ -167,184 +166,6 @@ void MVM_jit_compile_breakpoint(void) {
fprintf(stderr, "Pause here please\n");
}
static MVMJitExprValue* node_value(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMint32 node) {
MVMJitExprValue **v = compiler->allocator->values_by_node + node;
if (*v == NULL) {
*v = MVM_spesh_alloc(tc, compiler->graph->sg, sizeof(MVMJitExprValue));
}
return *v;
}
static void arglist_get_nodes(MVMThreadContext *tc, MVMJitExprTree *tree,
MVMint32 arglist, MVMJitExprNode *nodes) {
MVMint32 i, nchild = tree->nodes[arglist+1];
for (i = 0; i < nchild; i++) {
MVMint32 carg = tree->nodes[arglist+2+i];
*nodes++ = tree->nodes[carg+1];
}
}
static void MVM_jit_get_values(MVMThreadContext *tc, MVMJitCompiler *compiler,
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]->size = tree->info[node].size;
tile->values[0]->type = template->vtype;
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->num_values = 2;
break;
}
case MVM_JIT_ARGLIST:
{
/* NB, arglist can conceivably use more than 7 values, although it can
* safely overflow into args, we may want to find a better solution */
MVMint32 i;
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]);
}
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->num_values = 1;
break;
}
default:
{
MVMint32 i, j, k, num_nodes, value_bitmap;
num_nodes = MVM_jit_expr_tree_get_nodes(tc, tree, node, tile->template->path, buffer);
value_bitmap = tile->template->value_bitmap;
tile->num_values = template->num_values;
j = 1;
k = 0;
for (i = 0; i < num_nodes; i++) {
if (value_bitmap & 1) {
tile->values[j++] = node_value(tc, compiler, buffer[i]);
} else {
tile->args[k++] = buffer[i];
}
value_bitmap >>= 1;
}
break;
}
}
}
void MVM_jit_allocate_registers(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitExprTree *tree, MVMJitTileList *list) {
MVMJitTile *tile;
MVMJitExprValue *value;
MVMint32 i, j;
MVMint8 reg;
/* allocate a table to look up values by node number */
compiler->allocator->values_by_node = MVM_calloc(tree->nodes_num, sizeof(void*));
/* 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);
tile->values[0]->first_created = i;
for (j = 0; j < tile->num_values; j++) {
tile->values[j+1]->last_use = i;
tile->values[j+1]->num_use++;
}
}
/* Assign registers */
for (i = 0; i < list->items_num; i++) {
tile = list->items[i];
if (tile->template == NULL)
continue;
/* ensure that register values are live */
for (j = 0; j < tile->num_values; j++) {
value = tile->values[j+1];
if (value->type != MVM_JIT_REG)
continue;
if (value->state == MVM_JIT_VALUE_SPILLED) {
/* TODO insert load in place */
NYI(load_spilled);
} else if (value->state == MVM_JIT_VALUE_EMPTY ||
value->state == MVM_JIT_VALUE_DEAD) {
MVM_oops(tc, "Required value is not live");
}
}
/* allocate input register if necessary */
value = tile->values[0];
switch(tree->nodes[tile->node]) {
case MVM_JIT_COPY:
/* use same register as input */
value->type = MVM_JIT_REG;
MVM_jit_register_assign(tc, compiler, value, tile->values[1]->reg_cls, tile->values[1]->reg_num);
break;
case MVM_JIT_TC:
/* TODO, this isn't really portable, we should have register
* attributes assigned to the tile itself */
value->type = MVM_JIT_REG;
value->state = MVM_JIT_VALUE_IMMORTAL;
value->reg_cls = MVM_JIT_REGCLS_GPR;
value->reg_num = MVM_JIT_REG_TC;
break;
case MVM_JIT_CU:
value->type = MVM_JIT_REG;
value->state = MVM_JIT_VALUE_IMMORTAL;
value->reg_cls = MVM_JIT_REGCLS_GPR;
value->reg_num = MVM_JIT_REG_CU;
break;
case MVM_JIT_LOCAL:
value->type = MVM_JIT_REG;
value->state = MVM_JIT_VALUE_IMMORTAL;
value->reg_cls = MVM_JIT_REGCLS_GPR;
value->reg_num = MVM_JIT_REG_LOCAL;
break;
case MVM_JIT_STACK:
value->type = MVM_JIT_REG;
value->state = MVM_JIT_VALUE_IMMORTAL;
value->reg_cls = MVM_JIT_REGCLS_GPR;
value->reg_num = MVM_JIT_REG_STACK;
break;
default:
if (value != NULL && value->type == MVM_JIT_REG) {
/* allocate a register for the result */
if (tile->num_values > 0 &&
tile->values[1]->type == MVM_JIT_REG &&
tile->values[1]->state == MVM_JIT_VALUE_ALLOCATED &&
tile->values[1]->last_use == j) {
/* First register expires immediately, therefore we can safely cross-assign */
MVM_jit_register_assign(tc, compiler, value, tile->values[1]->reg_cls, tile->values[1]->reg_num);
} else {
reg = MVM_jit_register_alloc(tc, compiler, MVM_JIT_REGCLS_GPR);
MVM_jit_register_assign(tc, compiler, value, MVM_JIT_REGCLS_GPR, reg);
}
}
break;
}
/* Expire dead values */
MVM_jit_expire_values(tc, compiler, i);
}
MVM_free(compiler->allocator->values_by_node);
}
@@ -368,20 +189,17 @@ void MVM_jit_compile_label(MVMThreadContext *tc, MVMJitCompiler *compiler,
void MVM_jit_compile_expr_tree(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitExprTree *tree) {
MVMJitRegisterAllocator allocator;
MVMJitTileList *list;
MVMJitTile *tile;
MVMint32 i;
/* First stage, tile the tree */
list = MVM_jit_tile_expr_tree(tc, tree);
/* log it, replacing logigng-during-compilation */
/* Log the tile list for debugging purposes */
MVM_jit_log_tile_list(tc, list);
/* Second stage, allocate registers */
MVM_jit_register_allocator_init(tc, compiler, &allocator, list);
MVM_jit_allocate_registers(tc, compiler, tree, list);
MVM_jit_register_allocator_deinit(tc, compiler, &allocator);
MVM_jit_register_allocate(tc, compiler, list);
/* Allocate sufficient space for the internal labels */
dasm_growpc(compiler, compiler->label_offset + tree->num_labels);
Oops, something went wrong.

0 comments on commit 9a6ca81

Please sign in to comment.