Basic register allocation works!
This commit is contained in:
parent
4261744537
commit
d75cc0a663
|
@ -24,6 +24,12 @@ struct basicblock
|
|||
ARRAYOF(struct vreg) liveins;
|
||||
ARRAYOF(struct vreg) liveouts;
|
||||
|
||||
/* Register assignments on entry and exit. These are *pointers* (because
|
||||
* they just point to the regsin/regsout of the first and last hop
|
||||
* respectively). */
|
||||
register_assignment_t* regsin;
|
||||
register_assignment_t* regsout;
|
||||
|
||||
bool is_fake : 1;
|
||||
bool is_root : 1;
|
||||
bool is_terminated : 1;
|
||||
|
|
|
@ -87,10 +87,10 @@ static struct basicblock* intersect(struct basicblock* p1, struct basicblock* p2
|
|||
while (p1 != p2)
|
||||
{
|
||||
while (p1->order < p2->order)
|
||||
p1 = pmap_get(&dominance.graph, p1);
|
||||
p1 = pmap_findleft(&dominance.graph, p1);
|
||||
|
||||
while (p2->order < p1->order)
|
||||
p2 = pmap_get(&dominance.graph, p2);
|
||||
p2 = pmap_findleft(&dominance.graph, p2);
|
||||
}
|
||||
|
||||
return p1;
|
||||
|
@ -129,16 +129,16 @@ static void calculate_dominance_graph(void)
|
|||
struct basicblock* p = b->prevs.item[j];
|
||||
|
||||
/* Skip unprocessed blocks. */
|
||||
if (!pmap_get(&dominance.graph, p))
|
||||
if (!pmap_findleft(&dominance.graph, p))
|
||||
continue;
|
||||
|
||||
if (!new_idom)
|
||||
new_idom = p;
|
||||
else if (pmap_get(&dominance.graph, p))
|
||||
else if (pmap_findleft(&dominance.graph, p))
|
||||
new_idom = intersect(p, new_idom);
|
||||
}
|
||||
|
||||
if (pmap_get(&dominance.graph, b) != new_idom)
|
||||
if (pmap_findleft(&dominance.graph, b) != new_idom)
|
||||
{
|
||||
pmap_put(&dominance.graph, b, new_idom);
|
||||
changed = true;
|
||||
|
|
|
@ -81,8 +81,17 @@ void hop_print(char k, struct hop* hop)
|
|||
break;
|
||||
|
||||
case INSEL_VREG:
|
||||
tracef(k, "%%%d", insel->u.vreg->id);
|
||||
{
|
||||
struct vreg* vreg = insel->u.vreg;
|
||||
struct hreg* hreg = pmap_findright(&hop->regsin, vreg);
|
||||
if (!hreg)
|
||||
hreg = pmap_findright(&hop->regsout, vreg);
|
||||
if (hreg)
|
||||
tracef(k, "%s", hreg->name);
|
||||
else
|
||||
tracef(k, "%%%d", vreg->id);
|
||||
break;
|
||||
}
|
||||
|
||||
case INSEL_STRING:
|
||||
tracef(k, "%s", insel->u.string);
|
||||
|
|
|
@ -32,7 +32,8 @@ struct hop
|
|||
ARRAYOF(struct vreg) ins;
|
||||
ARRAYOF(struct vreg) outs;
|
||||
ARRAYOF(struct vreg) throughs;
|
||||
PMAPOF(struct vreg, struct hreg) registers;
|
||||
register_assignment_t regsin;
|
||||
register_assignment_t regsout;
|
||||
};
|
||||
|
||||
extern struct hop* new_hop(struct basicblock* bb, struct ir* ir);
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#include "astring.h"
|
||||
#include "ir.h"
|
||||
#include "mcgg.h"
|
||||
#include "hop.h"
|
||||
#include "reg.h"
|
||||
#include "hop.h"
|
||||
#include "basicblock.h"
|
||||
#include "procedure.h"
|
||||
#include "graph.h"
|
||||
|
|
|
@ -1,7 +1,176 @@
|
|||
#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)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<hregs.count; i++)
|
||||
{
|
||||
struct hreg* hreg = hregs.item[i];
|
||||
if (!pmap_findleft(regs, hreg))
|
||||
{
|
||||
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];
|
||||
allocate_hreg(out, vreg);
|
||||
}
|
||||
}
|
||||
|
||||
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: allocating 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. */
|
||||
|
||||
for (j=0; j<bb->phis.count; j++)
|
||||
{
|
||||
struct vreg* vreg = bb->phis.item[j].left;
|
||||
if (!pmap_findright(old, vreg))
|
||||
allocate_hreg(old, vreg);
|
||||
}
|
||||
|
||||
for (j=0; j<bb->hops.count; j++)
|
||||
{
|
||||
struct hop* hop = bb->hops.item[j];
|
||||
register_assignment_t* in = &hop->regsin;
|
||||
register_assignment_t* out = &hop->regsout;;
|
||||
|
||||
select_registers(hop, old, in, out);
|
||||
|
||||
old = out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* vim: set sw=4 ts=4 expandtab : */
|
||||
|
|
|
@ -26,7 +26,7 @@ static void calculate_dominance_frontier_graph(void)
|
|||
for (i=0; i<cfg.postorder.count; i++)
|
||||
{
|
||||
struct basicblock* b = cfg.postorder.item[i];
|
||||
struct basicblock* dominator = pmap_get(&dominance.graph, b);
|
||||
struct basicblock* dominator = pmap_findleft(&dominance.graph, b);
|
||||
if (b->prevs.count >= 2)
|
||||
{
|
||||
for (j=0; j<b->prevs.count; j++)
|
||||
|
@ -37,7 +37,7 @@ static void calculate_dominance_frontier_graph(void)
|
|||
tracef('S', "S: %s is in %s's dominance frontier\n",
|
||||
b->name, runner->name);
|
||||
pmap_add(&dominancefrontiers, runner, b);
|
||||
runner = pmap_get(&dominance.graph, runner);
|
||||
runner = pmap_findleft(&dominance.graph, runner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ static void ssa_convert(void)
|
|||
for (i=0; i<defining.count; i++)
|
||||
{
|
||||
struct basicblock* bb = defining.item[i];
|
||||
struct basicblock* dominates = pmap_get(&dominancefrontiers, bb);
|
||||
struct basicblock* dominates = pmap_findleft(&dominancefrontiers, bb);
|
||||
if (dominates)
|
||||
{
|
||||
array_appendu(&needsphis, dominates);
|
||||
|
|
|
@ -167,9 +167,11 @@ void procedure_compile(struct procedure* proc)
|
|||
print_blocks('6', proc);
|
||||
|
||||
pass_instruction_selector();
|
||||
pass_live_vreg_analysis();
|
||||
print_hops('7', proc);
|
||||
//pass_register_allocator();
|
||||
pass_live_vreg_analysis();
|
||||
print_hops('8', proc);
|
||||
pass_register_allocator();
|
||||
print_hops('9', proc);
|
||||
|
||||
if (cfg_dot_file)
|
||||
write_cfg_graph(proc->name);
|
||||
|
|
|
@ -9,7 +9,7 @@ struct vreg* new_vreg(void)
|
|||
return vreg;
|
||||
}
|
||||
|
||||
struct hreg* new_hreg(struct burm_register_data* brd)
|
||||
struct hreg* new_hreg(const struct burm_register_data* brd)
|
||||
{
|
||||
struct hreg* hreg = calloc(1, sizeof *hreg);
|
||||
hreg->name = brd->name;
|
||||
|
|
|
@ -18,9 +18,11 @@ struct vreg
|
|||
ARRAYOF(struct hop) used;
|
||||
};
|
||||
|
||||
typedef PMAPOF(struct hreg, struct vreg) register_assignment_t;
|
||||
|
||||
extern struct vreg* new_vreg(void);
|
||||
|
||||
extern struct hreg* new_hreg(struct burm_register_data* brd);
|
||||
extern struct hreg* new_hreg(const struct burm_register_data* brd);
|
||||
extern struct hreg* new_stacked_hreg(int offset, uint32_t attrs);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -104,7 +104,7 @@ PATTERNS
|
|||
cost 4;
|
||||
|
||||
SETRET4(in:(ret)reg)
|
||||
emit "mov r0, %in"
|
||||
emit "mr r3, %in"
|
||||
cost 4;
|
||||
|
||||
(ret)reg = GETRET4
|
||||
|
|
Loading…
Reference in a new issue