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) liveins;
|
||||||
ARRAYOF(struct vreg) liveouts;
|
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_fake : 1;
|
||||||
bool is_root : 1;
|
bool is_root : 1;
|
||||||
bool is_terminated : 1;
|
bool is_terminated : 1;
|
||||||
|
|
|
@ -87,10 +87,10 @@ static struct basicblock* intersect(struct basicblock* p1, struct basicblock* p2
|
||||||
while (p1 != p2)
|
while (p1 != p2)
|
||||||
{
|
{
|
||||||
while (p1->order < p2->order)
|
while (p1->order < p2->order)
|
||||||
p1 = pmap_get(&dominance.graph, p1);
|
p1 = pmap_findleft(&dominance.graph, p1);
|
||||||
|
|
||||||
while (p2->order < p1->order)
|
while (p2->order < p1->order)
|
||||||
p2 = pmap_get(&dominance.graph, p2);
|
p2 = pmap_findleft(&dominance.graph, p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return p1;
|
return p1;
|
||||||
|
@ -129,16 +129,16 @@ static void calculate_dominance_graph(void)
|
||||||
struct basicblock* p = b->prevs.item[j];
|
struct basicblock* p = b->prevs.item[j];
|
||||||
|
|
||||||
/* Skip unprocessed blocks. */
|
/* Skip unprocessed blocks. */
|
||||||
if (!pmap_get(&dominance.graph, p))
|
if (!pmap_findleft(&dominance.graph, p))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!new_idom)
|
if (!new_idom)
|
||||||
new_idom = p;
|
new_idom = p;
|
||||||
else if (pmap_get(&dominance.graph, p))
|
else if (pmap_findleft(&dominance.graph, p))
|
||||||
new_idom = intersect(p, new_idom);
|
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);
|
pmap_put(&dominance.graph, b, new_idom);
|
||||||
changed = true;
|
changed = true;
|
||||||
|
|
|
@ -81,8 +81,17 @@ void hop_print(char k, struct hop* hop)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INSEL_VREG:
|
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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case INSEL_STRING:
|
case INSEL_STRING:
|
||||||
tracef(k, "%s", insel->u.string);
|
tracef(k, "%s", insel->u.string);
|
||||||
|
|
|
@ -32,7 +32,8 @@ struct hop
|
||||||
ARRAYOF(struct vreg) ins;
|
ARRAYOF(struct vreg) ins;
|
||||||
ARRAYOF(struct vreg) outs;
|
ARRAYOF(struct vreg) outs;
|
||||||
ARRAYOF(struct vreg) throughs;
|
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);
|
extern struct hop* new_hop(struct basicblock* bb, struct ir* ir);
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
#include "astring.h"
|
#include "astring.h"
|
||||||
#include "ir.h"
|
#include "ir.h"
|
||||||
#include "mcgg.h"
|
#include "mcgg.h"
|
||||||
#include "hop.h"
|
|
||||||
#include "reg.h"
|
#include "reg.h"
|
||||||
|
#include "hop.h"
|
||||||
#include "basicblock.h"
|
#include "basicblock.h"
|
||||||
#include "procedure.h"
|
#include "procedure.h"
|
||||||
#include "graph.h"
|
#include "graph.h"
|
||||||
|
|
|
@ -1,7 +1,176 @@
|
||||||
#include "mcg.h"
|
#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)
|
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 : */
|
/* 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++)
|
for (i=0; i<cfg.postorder.count; i++)
|
||||||
{
|
{
|
||||||
struct basicblock* b = cfg.postorder.item[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)
|
if (b->prevs.count >= 2)
|
||||||
{
|
{
|
||||||
for (j=0; j<b->prevs.count; j++)
|
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",
|
tracef('S', "S: %s is in %s's dominance frontier\n",
|
||||||
b->name, runner->name);
|
b->name, runner->name);
|
||||||
pmap_add(&dominancefrontiers, runner, b);
|
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++)
|
for (i=0; i<defining.count; i++)
|
||||||
{
|
{
|
||||||
struct basicblock* bb = defining.item[i];
|
struct basicblock* bb = defining.item[i];
|
||||||
struct basicblock* dominates = pmap_get(&dominancefrontiers, bb);
|
struct basicblock* dominates = pmap_findleft(&dominancefrontiers, bb);
|
||||||
if (dominates)
|
if (dominates)
|
||||||
{
|
{
|
||||||
array_appendu(&needsphis, dominates);
|
array_appendu(&needsphis, dominates);
|
||||||
|
|
|
@ -167,9 +167,11 @@ void procedure_compile(struct procedure* proc)
|
||||||
print_blocks('6', proc);
|
print_blocks('6', proc);
|
||||||
|
|
||||||
pass_instruction_selector();
|
pass_instruction_selector();
|
||||||
pass_live_vreg_analysis();
|
|
||||||
print_hops('7', proc);
|
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)
|
if (cfg_dot_file)
|
||||||
write_cfg_graph(proc->name);
|
write_cfg_graph(proc->name);
|
||||||
|
|
|
@ -9,7 +9,7 @@ struct vreg* new_vreg(void)
|
||||||
return vreg;
|
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);
|
struct hreg* hreg = calloc(1, sizeof *hreg);
|
||||||
hreg->name = brd->name;
|
hreg->name = brd->name;
|
||||||
|
|
|
@ -18,9 +18,11 @@ struct vreg
|
||||||
ARRAYOF(struct hop) used;
|
ARRAYOF(struct hop) used;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef PMAPOF(struct hreg, struct vreg) register_assignment_t;
|
||||||
|
|
||||||
extern struct vreg* new_vreg(void);
|
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);
|
extern struct hreg* new_stacked_hreg(int offset, uint32_t attrs);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -104,7 +104,7 @@ PATTERNS
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
SETRET4(in:(ret)reg)
|
SETRET4(in:(ret)reg)
|
||||||
emit "mov r0, %in"
|
emit "mr r3, %in"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
(ret)reg = GETRET4
|
(ret)reg = GETRET4
|
||||||
|
|
Loading…
Reference in a new issue