Skip to content

Commit

Permalink
Register assignment should also cover synthetics
Browse files Browse the repository at this point in the history
Synthetics ought to follow the convention of values, in that
value 0 is always a definition, and value 1 is always a use.
  • Loading branch information
bdw committed Dec 6, 2016
1 parent a70f9fb commit b205d51
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 13 deletions.
18 changes: 8 additions & 10 deletions docs/jit/register-allocator.org → docs/jit/plan.org
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#+STARTUP: showeverything
* Register allocator plan
* Register allocator

Currently, multiple live ranges can inhabit the same location (due to
copies, IF resolution, etc). This is problematic, and results from the
Expand Down Expand Up @@ -120,7 +120,7 @@ it isn't. What we can do is:
- internalize into list? (why not?)


** TODO Find live ranges
** DONE Find live ranges

I think we can do this in a single pass, or maybe two passes

Expand Down Expand Up @@ -324,13 +324,11 @@ Comes down to:
- output-register must be copied off /or/ spilled



** TODO register assignment

This should not be a problem, it's just a final loop that assigns
registers according to some scheme. The only 'tricky' bit is to make
sure that prefered registers can actually be assigned. And the way to
do that is to maintain a table of register to live range, and to
/swap/ prefered registers which have been accidentally assigned to
other live ranges. This is *always possible* since splitting and
spilling has made sure of it.
Register assignment should be inline with the register allocation
step, because otherwise we simply have to iterate twice in the same
order over the same dataset. While possible, it is redundant.

Register assignment also updates the uses and definitions of tiles
using the value reference.
22 changes: 19 additions & 3 deletions src/jit/linear_scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ typedef struct {
MVMint32 live_range_idx;
} UnionFind;


/* In an interesting way, this is equivalent to a pointer to the 'values' memory
* area, and it is just as large anyway! */
typedef struct {
MVMint32 tile_idx;
MVMint32 value_idx;
Expand All @@ -18,6 +21,11 @@ typedef struct {
MVMint32 num_uses;
ValueRef *uses;

/* We can have at most two synthetic tiles, one attached to the first
* definition and one to the last use... we could also point directly into
* the values array of the tile, but it is not directly necessary */
MVMJitTile *synthetic[2];

MVMJitStorageClass reg_cls;
MVMint32 reg_num;
MVMint32 spilled_to; /* location of value in memory, if any */
Expand Down Expand Up @@ -372,6 +380,15 @@ void assign_register(MVMThreadContext *tc, RegisterAllocator *alc, MVMJitTileLis
MVMJitTile *tile = list->istems[ref->tile_idx];
tile->values[ref->value_idx] = reg_num;
}

/* Not sure if we need to store the position of synthetic tiles for the
* purposes of first_def/last_use */
for (i = 0; i < 2; i++) {
MVMJitTile *tile = range->synthetic[i];
if (tile != NULL) {
tile->values[i] = reg_num;
}
}
}

/* not sure if this is sufficiently general-purpose and unconfusing */
Expand All @@ -388,7 +405,7 @@ static void linear_scan(MVMThreadContext *tc, RegisterAllocator *alc, MVMJitTile
MVMint32 v = live_range_heap_pop(alc->values, alc->worklist, &alc->worklist_top);
MVMint32 pos = first_def(&alc->values[v]);
MVMint8 reg;
/* asign registers in first loop */
/* assign registers in loop */
active_set_expire(tc, alc, pos);
while ((reg = get_register(tc, alc, MVM_JIT_STORAGE_CLASS_GPR)) < 0) {
spill_register(tc, alc, list, pos);
Expand All @@ -397,6 +414,5 @@ static void linear_scan(MVMThreadContext *tc, RegisterAllocator *alc, MVMJitTile
active_set_add(tc, alc, v);
}
/* flush active live ranges */
MVM_VECTOR_APPEND(live_range->retired, alc->active, alc->active_top);
alc->active_top = 0;
active_set_expire(tc, alc, list->items_num + 1);
}

0 comments on commit b205d51

Please sign in to comment.