Skip to content

Commit

Permalink
Extract MVMJitExprValue out of MVMJitExprNodeInfo
Browse files Browse the repository at this point in the history
A particular nodes' value may be stored in a multitude of
registers and stack locations (and vice versa). Hence we want
multiple value (descriptor0 structures per node. I first
extract the MVMJitExprValue structure out of the NodeInfo
structure. The NodeInfo structure is relevant in an earlier
phase, not really during register allocation. Value structures
are now spesh-allocated.
  • Loading branch information
bdw committed May 29, 2016
1 parent c9bf2fc commit 37211ac
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 113 deletions.
81 changes: 56 additions & 25 deletions src/jit/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,55 +167,81 @@ 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_values(MVMThreadContext *tc, MVMJitExprTree *tree, MVMint32 node, MVMJitExprValue **values) {
MVMint32 i, nchild = tree->nodes[node+1];
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[node+2+i];
MVMint32 val = tree->nodes[carg+1];
*values++ = &tree->info[val].value;
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) {
MVMint32 node = tile->node;

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] = &tree->info[node].value;
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] = &tree->info[left].value;
tile->values[2] = &tree->info[right].value;
tile->num_vals = 2;
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 */
arglist_get_values(tc, tree, node, tile->values + 1);
tile->num_vals = tree->nodes[node+1];
/* 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] = &tree->info[last_child].value;
tile->num_vals = 1;
tile->values[1] = node_value(tc, compiler, last_child);
tile->num_values = 1;
break;
}
default:
{
MVM_jit_tile_get_values(tc, tree, node,
template->path, template->regs,
tile->values + 1, tile->args);
tile->num_vals = template->num_vals;
MVMint32 i, j, k, num_nodes, value_bitmap;
num_nodes = MVM_jit_tile_get_nodes(tc, tree, tile, 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;
}
}
Expand All @@ -228,13 +254,17 @@ void MVM_jit_allocate_registers(MVMThreadContext *tc, MVMJitCompiler *compiler,
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 (tile = list->first; tile != NULL; tile = tile->next) {
if (tile->template == NULL) /* pseudotiles */
continue;
MVM_jit_get_values(tc, compiler, list->tree, tile);
MVM_jit_get_values(tc, compiler, tree, tile);
tile->values[0]->first_created = tile->order_nr;
for (i = 0; i < tile->num_vals; i++) {
for (i = 0; i < tile->num_values; i++) {
tile->values[i+1]->last_use = tile->order_nr;
tile->values[i+1]->num_use++;
}
Expand All @@ -247,7 +277,7 @@ void MVM_jit_allocate_registers(MVMThreadContext *tc, MVMJitCompiler *compiler,
continue;
i++;
/* ensure that register values are live */
for (j = 1; j < tile->num_vals; j++) {
for (j = 1; j < tile->num_values; j++) {
value = tile->values[j];
if (value->type != MVM_JIT_REG)
continue;
Expand Down Expand Up @@ -297,7 +327,7 @@ void MVM_jit_allocate_registers(MVMThreadContext *tc, MVMJitCompiler *compiler,
default:
if (value != NULL && value->type == MVM_JIT_REG) {
/* allocate a register for the result */
if (tile->num_vals > 0 &&
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 == i) {
Expand All @@ -313,6 +343,7 @@ void MVM_jit_allocate_registers(MVMThreadContext *tc, MVMJitCompiler *compiler,
/* Expire dead values */
MVM_jit_expire_values(tc, compiler, i);
}
MVM_free(compiler->allocator->values_by_node);
}


Expand Down
36 changes: 18 additions & 18 deletions src/jit/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,16 +273,16 @@ static void analyze_node(MVMThreadContext *tc, MVMJitTreeTraverser *traverser,
switch (tree->nodes[node]) {
case MVM_JIT_CONST:
/* node size is given */
node_info->value.size = args[1];
node_info->size = args[1];
break;
case MVM_JIT_COPY:
node_info->value.size = tree->info[tree->nodes[first_child]].value.size;
node_info->size = tree->info[tree->nodes[first_child]].size;
break;
case MVM_JIT_LOAD:
node_info->value.size = args[0];
node_info->size = args[0];
break;
case MVM_JIT_CAST:
node_info->value.size = args[0];
node_info->size = args[0];
break;
case MVM_JIT_ADDR:
case MVM_JIT_IDX:
Expand All @@ -294,7 +294,7 @@ static void analyze_node(MVMThreadContext *tc, MVMJitTreeTraverser *traverser,
case MVM_JIT_STACK:
case MVM_JIT_VMNULL:
/* addresses result in pointers */
node_info->value.size = MVM_JIT_PTR_SZ;
node_info->size = MVM_JIT_PTR_SZ;
break;
case MVM_JIT_ADD:
case MVM_JIT_SUB:
Expand All @@ -306,39 +306,39 @@ static void analyze_node(MVMThreadContext *tc, MVMJitTreeTraverser *traverser,
/* arithmetic nodes use their largest operand */
MVMint32 left = tree->nodes[first_child];
MVMint32 right = tree->nodes[first_child+1];
node_info->value.size = MAX(tree->info[left].value.size,
tree->info[right].value.size);
node_info->size = MAX(tree->info[left].size,
tree->info[right].size);
break;
}
case MVM_JIT_DO:
/* node size of last child */
{
MVMint32 last_child = tree->nodes[first_child + nchild - 1];
node_info->value.size = tree->info[last_child].value.size;
node_info->size = tree->info[last_child].size;
break;
}
case MVM_JIT_IF:
{
MVMint32 left = tree->nodes[first_child+1];
MVMint32 right = tree->nodes[first_child+2];
node_info->value.size = MAX(tree->info[left].value.size,
tree->info[right].value.size);
node_info->size = MAX(tree->info[left].size,
tree->info[right].size);
break;
}
case MVM_JIT_CALL:
if (args[0] == MVM_JIT_VOID)
node_info->value.size = 0;
node_info->size = 0;
else if (args[0] == MVM_JIT_INT)
node_info->value.size = MVM_JIT_INT_SZ;
node_info->size = MVM_JIT_INT_SZ;
else if (args[0] == MVM_JIT_PTR)
node_info->value.size = MVM_JIT_PTR_SZ;
node_info->size = MVM_JIT_PTR_SZ;
else
node_info->value.size = MVM_JIT_NUM_SZ;
node_info->size = MVM_JIT_NUM_SZ;
break;
default:
/* all other things, branches, labels, when, arglist, carg,
* comparisons, etc, have no value size */
node_info->value.size = 0;
node_info->size = 0;
break;
}
/* Insert casts as necessary */
Expand All @@ -347,10 +347,10 @@ static void analyze_node(MVMThreadContext *tc, MVMJitTreeTraverser *traverser,
MVMint32 child = tree->nodes[first_child+i];
if (tree->nodes[child] == MVM_JIT_CONST) {
/* CONST nodes can always take over their target size, so they never need to be cast */
tree->info[child].value.size = tree->info[node].value.size;
} else if (tree->info[child].value.size < node_info->value.size) {
tree->info[child].size = tree->info[node].size;
} else if (tree->info[child].size < node_info->size) {
/* Widening casts need to be handled explicitly, shrinking casts do not */
MVMint32 cast = MVM_jit_expr_add_cast(tc, tree, child, node_info->value.size, op_info->cast);
MVMint32 cast = MVM_jit_expr_add_cast(tc, tree, child, node_info->size, op_info->cast);
/* Because the cast may have grown the backing nodes array, the info array needs to grow as well */
MVM_DYNAR_ENSURE_SIZE(tree->info, cast);
/* And because analyze_node is called in postorder,
Expand Down
10 changes: 3 additions & 7 deletions src/jit/expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,10 @@ struct MVMJitExprNodeInfo {
const MVMJitExprOpInfo *op_info;
/* VM instruction represented by this node */
MVMSpeshIns *spesh_ins;
/* VM Local value of this node */
MVMint16 local_addr;

/* Size of computed value */
MVMint8 size;
/* internal label for IF/WHEN/ALL/ANY etc, relative to the tree label offset */
MVMint32 label;

/* Result value information (register/memory location, size etc) */
MVMJitExprValue value;
MVMint32 label;
};

struct MVMJitExprTree {
Expand Down
2 changes: 1 addition & 1 deletion src/jit/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ static void dump_tree(MVMThreadContext *tc, MVMJitTreeTraverser *traverser,
}
nargs[j] = 0;
MVM_jit_log(tc, "%04d%s%s (%s; sz=%d)\n", node, indent, op->name,
nargs, info->value.size);
nargs, info->size);
}

static void ascend_tree(MVMThreadContext *tc, MVMJitTreeTraverser *traverser,
Expand Down
33 changes: 1 addition & 32 deletions src/jit/register.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ static MVMint8 free_num[] = { -1 };
#define UNLOCK_REGISTER(a,n) ((a)->reg_lock &= ~(1 << (n)))


/* NB only implement GPR register allocation now */

void MVM_jit_register_allocator_init(MVMThreadContext *tc, MVMJitCompiler *compiler,
MVMJitRegisterAllocator *alc) {
/* Store live ranges */
Expand Down Expand Up @@ -321,37 +321,6 @@ void MVM_jit_register_put(MVMThreadContext *tc, MVMJitCompiler *cl, MVMJitExprVa
}


/* Spill values prior to emitting a call */
void MVM_jit_spill_before_call(MVMThreadContext *tc, MVMJitCompiler *cl) {
MVMJitRegisterAllocator *alc = cl->allocator;
MVMint32 order_nr = cl->order_nr;
MVMint32 i;
for (i = 0; i < alc->active_num; i++) {
MVMJitExprValue *v = alc->active[i];
if (v->last_use > order_nr && v->state == MVM_JIT_VALUE_ALLOCATED) {
MVM_jit_register_spill(tc, cl, v->reg_cls, v->reg_num);
}
}
}

void MVM_jit_spill_before_conditional(MVMThreadContext *tc, MVMJitCompiler *cl, MVMJitExprTree *tree, MVMint32 node) {
MVMJitRegisterAllocator *alc = cl->allocator;
MVMint32 exit_order_nr = tree->info[node].value.first_created;
MVMint32 i;
for (i = 0; i < alc->active_num; i++) {
MVMJitExprValue *value = alc->active[i];
if (value->last_use > exit_order_nr) {
/* Emit a spill - this inadvertently frees the register */
MVM_jit_register_spill(tc, cl, value->reg_cls, value->reg_num);
/* So we have to take it again */
MVM_jit_register_take(tc, cl, value->reg_cls, value->reg_num);
/* Because the value has been assigned before, we should
* not reassign it, but update it's state directly */
value->state = MVM_JIT_VALUE_ALLOCATED;
alc->reg_use[value->reg_num]++;
}
}
}

/* Expire values that are no longer useful */
void MVM_jit_expire_values(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMint32 order_nr) {
Expand Down
17 changes: 5 additions & 12 deletions src/jit/register.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
/* Register allocator based on linear-scan allocation. For this
* algorithm, we need the live ranges of values, sorted ascending and
* descending by end point. I want to use this algorithm online, so it
* seems logical to use a heap */

struct MVMJitRegisterAllocator {
/* List of active 'live' ranges */
MVM_DYNAR_DECL(MVMJitExprValue*, active);

/* stacks of free registers */
/* Values by node */
MVMJitExprValue **values_by_node;

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

Expand Down Expand Up @@ -45,11 +44,5 @@ void MVM_jit_register_expire(MVMThreadContext *tc, MVMJitCompiler *compiler,
void MVM_jit_register_put(MVMThreadContext *tc, MVMJitCompiler *compiler,
MVMJitExprValue *value, MVMint32 reg_cls, MVMint8 reg_num);

void MVM_jit_spill_before_call(MVMThreadContext *tc, MVMJitCompiler *compiler);
void MVM_jit_spill_before_conditional(MVMThreadContext *tc, MVMJitCompiler *compiler,
MVMJitExprTree *tree, MVMint32 node);
void MVM_jit_expire_values(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMint32 order_nr);

void MVM_jit_enter_branch(MVMThreadContext *tc, MVMJitCompiler *compiler);
void MVM_jit_leave_branch(MVMThreadContext *tc, MVMJitCompiler *compiler);

22 changes: 10 additions & 12 deletions src/jit/tile.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ static void add_pseudotile(MVMThreadContext *tc, struct TileTree *tiles,
tile = MVM_spesh_alloc(tc, tiles->sg, sizeof(MVMJitTile));
tile->emit = emit;
tile->node = node;
tile->num_vals = 0;
tile->num_values = 0;
for (i = 0; i < nargs; i++) {
tile->args[i] = va_arg(arglist, MVMJitExprNode);
}
Expand Down Expand Up @@ -436,26 +436,24 @@ MVMJitTileList * MVM_jit_tile_expr_tree(MVMThreadContext *tc, MVMJitExprTree *tr
}

#define FIRST_CHILD(t,x) (t->info[x].op_info->nchild < 0 ? x + 2 : x + 1)
/* Get input for a tile rule, write into values and args */
void MVM_jit_tile_get_values(MVMThreadContext *tc, MVMJitExprTree *tree, MVMint32 node,
const MVMint8 *path, MVMint32 regs,
MVMJitExprValue **values, MVMJitExprNode *args) {

/* Get the nodes that a tile refers to */
MVMint32 MVM_jit_tile_get_nodes(MVMThreadContext *tc, MVMJitExprTree *tree,
MVMJitTile *tile, MVMJitExprNode *nodes) {
const char *path = tile->template->path;
MVMJitExprNode *start = nodes;
while (*path) {
MVMJitExprNode cur_node = node;
MVMJitExprNode cur_node = tile->node;
do {
MVMint32 first_child = FIRST_CHILD(tree, cur_node) - 1;
MVMint32 child_nr = *path++ - '0';
cur_node = tree->nodes[first_child+child_nr];
} while (*path != '.');
/* regs nodes go to values, others to args */
if (regs & 1) {
*values++ = &tree->info[cur_node].value;
} else {
*args++ = cur_node;
}
regs >>= 1;
*nodes++ = cur_node;
path++;
}
return nodes - start;
}

#undef FIRST_CHILD
Loading

0 comments on commit 37211ac

Please sign in to comment.