Register allocator now gets all the way through all of my test file without

crashing (albeit with register moves and swaps stubbed out). Correct code? Who
knows.
This commit is contained in:
David Given 2016-10-10 23:19:46 +02:00
parent a4d06d1795
commit 92bd1ac5f4
4 changed files with 227 additions and 18 deletions

View file

@ -28,6 +28,13 @@ void hop_add_string_insel(struct hop* hop, const char* string)
array_append(&hop->insels, insel); array_append(&hop->insels, insel);
} }
void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg)
{
struct insel* insel = new_insel(INSEL_HREG);
insel->u.hreg = hreg;
array_append(&hop->insels, insel);
}
void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg) void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg)
{ {
struct insel* insel = new_insel(INSEL_VREG); struct insel* insel = new_insel(INSEL_VREG);
@ -48,10 +55,30 @@ void hop_add_eoi_insel(struct hop* hop)
array_append(&hop->insels, insel); array_append(&hop->insels, insel);
} }
static void print_header(char k, struct hop* hop)
{
int i;
tracef(k, "%c: %d", k, hop->id);
if (hop->ir)
tracef(k, " from $%d", hop->ir->id);
tracef(k, ":");
for (i=0; i<hop->ins.count; i++)
tracef(k, " r%%%d", hop->ins.item[i]->id);
for (i=0; i<hop->throughs.count; i++)
tracef(k, " =%%%d", hop->throughs.item[i]->id);
for (i=0; i<hop->outs.count; i++)
tracef(k, " w%%%d", hop->outs.item[i]->id);
tracef(k, " ");
}
void hop_print(char k, struct hop* hop) void hop_print(char k, struct hop* hop)
{ {
int i, j; int i;
bool soi = true; bool soi = false;
print_header(k, hop);
i = 0; i = 0;
for (i=0; i<hop->insels.count; i++) for (i=0; i<hop->insels.count; i++)
@ -60,16 +87,7 @@ void hop_print(char k, struct hop* hop)
if (soi) if (soi)
{ {
tracef(k, "%c: %d from $%d:", k, hop->id, hop->ir->id); print_header(k, hop);
for (j=0; j<hop->ins.count; j++)
tracef(k, " r%%%d", hop->ins.item[j]->id);
for (j=0; j<hop->throughs.count; j++)
tracef(k, " =%%%d", hop->throughs.item[j]->id);
for (j=0; j<hop->outs.count; j++)
tracef(k, " w%%%d", hop->outs.item[j]->id);
tracef(k, " ");
soi = false; soi = false;
} }
@ -80,6 +98,13 @@ void hop_print(char k, struct hop* hop)
soi = true; soi = true;
break; break;
case INSEL_HREG:
{
struct hreg* hreg = insel->u.hreg;
tracef(k, "%s", hreg->name);
break;
}
case INSEL_VREG: case INSEL_VREG:
{ {
struct vreg* vreg = insel->u.vreg; struct vreg* vreg = insel->u.vreg;

View file

@ -4,6 +4,7 @@
enum insel_type enum insel_type
{ {
INSEL_STRING, INSEL_STRING,
INSEL_HREG,
INSEL_VREG, INSEL_VREG,
INSEL_VALUE, INSEL_VALUE,
INSEL_EOI INSEL_EOI
@ -15,6 +16,7 @@ struct insel
union union
{ {
const char* string; const char* string;
struct hreg* hreg;
struct vreg* vreg; struct vreg* vreg;
struct ir* value; struct ir* value;
} }
@ -46,6 +48,7 @@ struct hop
extern struct hop* new_hop(struct basicblock* bb, struct ir* ir); extern struct hop* new_hop(struct basicblock* bb, struct ir* ir);
extern void hop_add_string_insel(struct hop* hop, const char* string); extern void hop_add_string_insel(struct hop* hop, const char* string);
extern void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg);
extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg); extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg);
extern void hop_add_value_insel(struct hop* hop, struct ir* ir); extern void hop_add_value_insel(struct hop* hop, struct ir* ir);
extern void hop_add_eoi_insel(struct hop* hop); extern void hop_add_eoi_insel(struct hop* hop);

View file

@ -106,6 +106,7 @@ extern void pass_convert_stack_ops(struct procedure* proc);
extern void pass_eliminate_trivial_blocks(struct procedure* proc); extern void pass_eliminate_trivial_blocks(struct procedure* proc);
extern void pass_find_phi_congruence_groups(void); extern void pass_find_phi_congruence_groups(void);
extern void pass_group_irs(struct procedure* proc); extern void pass_group_irs(struct procedure* proc);
extern void pass_insert_moves(void);
extern void pass_instruction_selector(void); extern void pass_instruction_selector(void);
extern void pass_live_vreg_analysis(void); extern void pass_live_vreg_analysis(void);
extern void pass_promote_float_ops(struct procedure* proc); extern void pass_promote_float_ops(struct procedure* proc);

View file

@ -3,6 +3,9 @@
static ARRAYOF(struct hreg) hregs; static ARRAYOF(struct hreg) hregs;
static int stacksize; static int stacksize;
static int insert_moves(struct basicblock* bb, int index,
register_assignment_t* srcregs, register_assignment_t* destregs);
static void populate_hregs(void) static void populate_hregs(void)
{ {
const struct burm_register_data* brd = burm_register_data; const struct burm_register_data* brd = burm_register_data;
@ -89,13 +92,10 @@ static void select_registers(struct hop* hop,
} }
} }
void pass_register_allocator(void) static void assign_hregs_to_vregs(void)
{ {
int i, j, k; int i, j, k;
populate_hregs();
wire_up_blocks_ins_outs();
for (i=0; i<dominance.preorder.count; i++) for (i=0; i<dominance.preorder.count; i++)
{ {
struct basicblock* bb = dominance.preorder.item[i]; struct basicblock* bb = dominance.preorder.item[i];
@ -181,6 +181,8 @@ void pass_register_allocator(void)
register_assignment_t* in = &hop->regsin; register_assignment_t* in = &hop->regsin;
register_assignment_t* out = &hop->regsout;; register_assignment_t* out = &hop->regsout;;
select_registers(hop, old, in, out);
tracef('R', "R: %d from $%d:", hop->id, hop->ir->id); tracef('R', "R: %d from $%d:", hop->id, hop->ir->id);
for (k=0; k<hop->ins.count; k++) for (k=0; k<hop->ins.count; k++)
tracef('R', " r%%%d", hop->ins.item[k]->id); tracef('R', " r%%%d", hop->ins.item[k]->id);
@ -188,14 +190,192 @@ void pass_register_allocator(void)
tracef('R', " =%%%d", hop->throughs.item[k]->id); tracef('R', " =%%%d", hop->throughs.item[k]->id);
for (k=0; k<hop->outs.count; k++) for (k=0; k<hop->outs.count; k++)
tracef('R', " w%%%d", hop->outs.item[k]->id); tracef('R', " w%%%d", hop->outs.item[k]->id);
tracef('R', "\n"); tracef('R', " [");
for (k=0; k<hop->regsin.count; k++)
{
struct hreg* hreg = hop->regsin.item[k].left;
struct vreg* vreg = hop->regsin.item[k].right;
if (k != 0)
tracef('R', " ");
tracef('R', "%%%d=>%s", vreg->id, hreg->name);
}
tracef('R', "] [");
for (k=0; k<hop->regsout.count; k++)
{
struct hreg* hreg = hop->regsout.item[k].left;
struct vreg* vreg = hop->regsout.item[k].right;
if (k != 0)
tracef('R', " ");
tracef('R', "%%%d=>%s", vreg->id, hreg->name);
}
tracef('R', "]\n");
select_registers(hop, old, in, out); if (j > 0)
j += insert_moves(bb, j, old, in);
old = out; old = out;
} }
} }
} }
static struct hop* create_move(struct basicblock* bb, struct hreg* src, struct hreg* dest)
{
struct hop* hop = new_hop(bb, NULL);
hop_add_string_insel(hop, "! move ");
hop_add_hreg_insel(hop, src);
hop_add_string_insel(hop, " -> ");
hop_add_hreg_insel(hop, dest);
hop_add_eoi_insel(hop);
return hop;
}
static struct hop* create_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest)
{
struct hop* hop = new_hop(bb, NULL);
hop_add_string_insel(hop, "! swap ");
hop_add_hreg_insel(hop, src);
hop_add_string_insel(hop, " <-> ");
hop_add_hreg_insel(hop, dest);
hop_add_eoi_insel(hop);
return hop;
}
/* returns the number of instructions inserted */
static int insert_moves(struct basicblock* bb, int index,
register_assignment_t* srcregs, register_assignment_t* destregs)
{
int i;
int inserted = 0;
static PMAPOF(struct hreg, struct hreg) copies;
copies.count = 0;
for (i=0; i<destregs->count; i++)
{
struct hreg* dest = destregs->item[i].left;
struct vreg* vreg = destregs->item[i].right;
struct hreg* src = pmap_findright(srcregs, vreg);
assert(src != NULL);
if (src != dest)
pmap_add(&copies, src, dest);
}
while (copies.count > 0)
{
struct hreg* src;
struct hreg* dest;
struct hreg* temp;
struct hop* hop;
/* Try and find a destination which isn't a source. */
src = NULL;
for (i=0; i<copies.count; i++)
{
dest = copies.item[i].right;
if (!pmap_findleft(&copies, dest))
{
src = copies.item[i].left;
break;
}
}
if (src)
{
/* Copy. */
hop = create_move(bb, src, dest);
pmap_remove(&copies, src, dest);
}
else
{
/* Swap. */
src = copies.item[0].left;
dest = pmap_findleft(&copies, src);
hop = create_move(bb, src, dest);
pmap_remove(&copies, src, dest);
pmap_remove(&copies, dest, src);
}
array_insert(&bb->hops, hop, index + inserted);
inserted++;
}
return inserted;
}
static void insert_phi_copies(void)
{
int i, j, k;
/* If we're importing an hreg from a parent block via a phi, insert a move
* at the end of the parent block to put the result into the right
* register. */
for (i=0; i<cfg.preorder.count; i++)
{
struct basicblock* bb = cfg.preorder.item[i];
/* Group together copies from each predecessor, so we can generate the
* appropriate parallel move. */
for (j=0; j<bb->prevs.count; j++)
{
struct basicblock* prevbb = bb->prevs.item[j];
static register_assignment_t destregs;
tracef('R', "R: inserting phis for %s -> %s\n",
prevbb->name, bb->name);
destregs.count = 0;
for (k=0; k<bb->phis.count; k++)
{
struct vreg* vreg = bb->phis.item[k].left;
struct phi* phi = bb->phis.item[k].right;
struct hreg* dest = pmap_findright(bb->regsin, vreg);
if ((phi->prev == prevbb) && dest)
{
/* We inserted critical edges to guarantee this. */
assert(prevbb->nexts.count == 1);
tracef('R', "R: map %%%d -> %%%d (%s)\n",
phi->ir->result->id,
vreg->id, dest->name);
pmap_put(&destregs, dest, phi->ir->result);
}
}
/* Add any non-phi inputs. */
for (k=0; k<bb->regsin->count; k++)
{
struct hreg* hreg = bb->regsin->item[k].left;
struct vreg* vreg = bb->regsin->item[k].right;
if (!pmap_findleft(&bb->phis, vreg))
pmap_add(&destregs, hreg, vreg);
}
/* The last instruction of a block should be the jump that sends us
* to the next block. Insert the moves before then. */
insert_moves(prevbb, prevbb->hops.count-1, prevbb->regsout, &destregs);
}
}
}
void pass_register_allocator(void)
{
populate_hregs();
wire_up_blocks_ins_outs();
assign_hregs_to_vregs();
insert_phi_copies();
}
/* vim: set sw=4 ts=4 expandtab : */ /* vim: set sw=4 ts=4 expandtab : */