ack/mach/proto/mcg/pass_registerallocator.c
David Given fac12aae32 Calculate phi congruency groups; use them to solve the
importing-hreg-from-the-future problem (probably poorly).
2016-10-09 22:04:20 +02:00

201 lines
6 KiB
C

#include "mcg.h"
static ARRAYOF(struct hreg) hregs;
static int stacksize;
static void populate_hregs(void)
{
const struct burm_register_data* brd = burm_register_data;
stacksize = 0;
while (brd->name)
{
array_append(&hregs, new_hreg(brd));
brd++;
}
}
static void wire_up_blocks_ins_outs(void)
{
int i, j;
for (i=0; i<dominance.preorder.count; i++)
{
struct basicblock* bb = dominance.preorder.item[i];
assert(bb->hops.count >= 1);
bb->regsin = &bb->hops.item[0]->regsin;
bb->regsout = &bb->hops.item[bb->hops.count-1]->regsout;
}
}
static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg, uint32_t attr)
{
int i;
for (i=0; i<hregs.count; i++)
{
struct hreg* hreg = hregs.item[i];
if (!pmap_findleft(regs, hreg))
{
if (hreg->attrs & attr)
{
pmap_put(regs, hreg, vreg);
return hreg;
}
}
}
fatal("ran out of registers");
}
static void select_registers(struct hop* hop,
register_assignment_t* old, register_assignment_t* in, register_assignment_t* out)
{
int i;
/* First, any vregs passing through the instruction stay in the same
* registers they are currently in. */
for (i=0; i<hop->throughs.count; i++)
{
struct vreg* vreg = hop->throughs.item[i];
struct hreg* hreg = pmap_findright(old, vreg);
assert(hreg != NULL);
pmap_put(in, hreg, vreg);
pmap_put(out, hreg, vreg);
}
/* Any registers being *read* by the instruction should also stay where
* they are. (This is likely to duplicate some throughs.) */
for (i=0; i<hop->ins.count; i++)
{
struct vreg* vreg = hop->ins.item[i];
struct hreg* hreg = pmap_findright(old, vreg);
assert(hreg != NULL);
pmap_put(in, hreg, vreg);
}
/* Any output registers will be *new* vregs (because SSA). So, allocate
* new hregs for them. */
for (i=0; i<hop->outs.count; i++)
{
struct vreg* vreg = hop->outs.item[i];
struct constraint* c = pmap_findleft(&hop->constraints, vreg);
allocate_hreg(out, vreg, c->attrs);
}
}
void pass_register_allocator(void)
{
int i, j, k;
populate_hregs();
wire_up_blocks_ins_outs();
for (i=0; i<dominance.preorder.count; i++)
{
struct basicblock* bb = dominance.preorder.item[i];
register_assignment_t* old = bb->regsin;
tracef('R', "R: considering block %s\n", bb->name);
/* Attempt to import any block input registers from a predecessor. At
* least one predecessor should export it; our graph traversal order
* guarantees it. */
for (j=0; j<bb->liveins.count; j++)
{
struct vreg* vreg = bb->liveins.item[j];
for (k=0; k<bb->prevs.count; k++)
{
struct basicblock* prevbb = bb->prevs.item[k];
struct hreg* hreg = pmap_findright(prevbb->regsout, vreg);
if (hreg)
{
tracef('R', "R: import hreg %s for input %%%d from %s\n",
hreg->name, vreg->id, prevbb->name);
assert(!pmap_findleft(old, hreg));
pmap_put(old, hreg, vreg);
goto nextvreg;
}
}
fatal("couldn't find a register assignment for $%d", vreg->id);
nextvreg:;
}
/* And now do the same for the phis. Unlike input vregs, a phi can
* import a vreg from multiple locations. However, we don't care which
* one we find, as this is just a hint. Picking the same register as a
* predecessor helps reduce the number of copies the SSA deconstruction
* pass will need to insert. */
for (j=0; j<bb->phis.count; j++)
{
struct vreg* vreg = bb->phis.item[j].left;
struct phi* phi = bb->phis.item[j].right;
if (!pmap_findright(old, vreg))
{
/* This variable isn't allocated yet. */
struct hreg* hreg = pmap_findright(
phi->prev->regsout, phi->ir->result);
if (hreg && !pmap_findleft(old, hreg))
{
tracef('R', "R: import hreg %s for phi input %%%d from %s\n",
hreg->name, vreg->id, phi->prev->name);
pmap_put(old, hreg, vreg);
}
}
}
/* It's possible for the previous stage to fail because in in has
* clobbered the physical register we were wanting. So we need to
* allocate a new register for that phi value.
*
* We don't bother allocating anything if the vreg is never used.
* */
for (j=0; j<bb->phis.count; j++)
{
struct vreg* vreg = bb->phis.item[j].left;
struct phi* phi = bb->phis.item[j].right;
if (!pmap_findright(old, vreg))
{
struct phicongruence* c = vreg->congruence;
struct hreg* hreg = allocate_hreg(old, vreg, c->attrs);
tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n",
hreg->name, vreg->id, phi->prev->name);
}
}
for (j=0; j<bb->hops.count; j++)
{
int k;
struct hop* hop = bb->hops.item[j];
register_assignment_t* in = &hop->regsin;
register_assignment_t* out = &hop->regsout;;
tracef('R', "R: %d from $%d:", hop->id, hop->ir->id);
for (k=0; k<hop->ins.count; k++)
tracef('R', " r%%%d", hop->ins.item[k]->id);
for (k=0; k<hop->throughs.count; k++)
tracef('R', " =%%%d", hop->throughs.item[k]->id);
for (k=0; k<hop->outs.count; k++)
tracef('R', " w%%%d", hop->outs.item[k]->id);
tracef('R', "\n");
select_registers(hop, old, in, out);
old = out;
}
}
}
/* vim: set sw=4 ts=4 expandtab : */