Permalink
Browse files

Extract MVMJitExprValue out of MVMJitExprNodeInfo

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 37211ac4dd7083e4e5e103ac8ac19b9b7878a095
Showing with 99 additions and 113 deletions.
  1. +56 −25 src/jit/compile.c
  2. +18 −18 src/jit/expr.c
  3. +3 −7 src/jit/expr.h
  4. +1 −1 src/jit/log.c
  5. +1 −32 src/jit/register.c
  6. +5 −12 src/jit/register.h
  7. +10 −12 src/jit/tile.c
  8. +5 −6 src/jit/tile.h
View
@@ -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;
}
}
@@ -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++;
}
@@ -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;
@@ -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) {
@@ -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);
}
View
@@ -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:
@@ -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:
@@ -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 */
@@ -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,
View
@@ -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 {
View
@@ -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,
View
@@ -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 */
@@ -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) {
View
@@ -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;
@@ -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);
View
@@ -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);
}
@@ -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
Oops, something went wrong.

0 comments on commit 37211ac

Please sign in to comment.