Register spilling to the stack frame works, more or less.
This commit is contained in:
parent
0eb32e7553
commit
7aa60a6451
|
@ -52,6 +52,27 @@ void hop_add_value_insel(struct hop* hop, struct ir* ir)
|
||||||
array_append(&hop->insels, insel);
|
array_append(&hop->insels, insel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hop_add_st_offset_insel(struct hop* hop, struct hreg* hreg)
|
||||||
|
{
|
||||||
|
struct insel* insel = new_insel(INSEL_ST_OFFSET);
|
||||||
|
insel->u.hreg = hreg;
|
||||||
|
array_append(&hop->insels, insel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hop_add_ab_offset_insel(struct hop* hop, int offset)
|
||||||
|
{
|
||||||
|
struct insel* insel = new_insel(INSEL_AB_OFFSET);
|
||||||
|
insel->u.offset = offset;
|
||||||
|
array_append(&hop->insels, insel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hop_add_lb_offset_insel(struct hop* hop, int offset)
|
||||||
|
{
|
||||||
|
struct insel* insel = new_insel(INSEL_LB_OFFSET);
|
||||||
|
insel->u.offset = offset;
|
||||||
|
array_append(&hop->insels, insel);
|
||||||
|
}
|
||||||
|
|
||||||
void hop_add_eoi_insel(struct hop* hop)
|
void hop_add_eoi_insel(struct hop* hop)
|
||||||
{
|
{
|
||||||
struct insel* insel = new_insel(INSEL_EOI);
|
struct insel* insel = new_insel(INSEL_EOI);
|
||||||
|
@ -74,6 +95,18 @@ void hop_add_insel(struct hop* hop, const char* fmt, ...)
|
||||||
hop_add_string_insel(hop, aprintf("%d", va_arg(ap, int)));
|
hop_add_string_insel(hop, aprintf("%d", va_arg(ap, int)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'S':
|
||||||
|
hop_add_st_offset_insel(hop, va_arg(ap, struct hreg*));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'A':
|
||||||
|
hop_add_ab_offset_insel(hop, va_arg(ap, int));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'L':
|
||||||
|
hop_add_lb_offset_insel(hop, va_arg(ap, int));
|
||||||
|
break;
|
||||||
|
|
||||||
case 'H':
|
case 'H':
|
||||||
hop_add_hreg_insel(hop, va_arg(ap, struct hreg*));
|
hop_add_hreg_insel(hop, va_arg(ap, struct hreg*));
|
||||||
break;
|
break;
|
||||||
|
@ -193,6 +226,18 @@ char* hop_render(struct hop* hop)
|
||||||
appendf("%s", insel->u.string);
|
appendf("%s", insel->u.string);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case INSEL_ST_OFFSET:
|
||||||
|
appendf("(st+%d)", insel->u.hreg->offset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INSEL_AB_OFFSET:
|
||||||
|
appendf("(ab+%d)", insel->u.offset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INSEL_LB_OFFSET:
|
||||||
|
appendf("(lb+%d)", insel->u.offset);
|
||||||
|
break;
|
||||||
|
|
||||||
case INSEL_VALUE:
|
case INSEL_VALUE:
|
||||||
{
|
{
|
||||||
struct ir* ir = insel->u.value;
|
struct ir* ir = insel->u.value;
|
||||||
|
|
|
@ -7,6 +7,9 @@ enum insel_type
|
||||||
INSEL_HREG,
|
INSEL_HREG,
|
||||||
INSEL_VREG,
|
INSEL_VREG,
|
||||||
INSEL_VALUE,
|
INSEL_VALUE,
|
||||||
|
INSEL_ST_OFFSET,
|
||||||
|
INSEL_AB_OFFSET,
|
||||||
|
INSEL_LB_OFFSET,
|
||||||
INSEL_EOI
|
INSEL_EOI
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,6 +22,7 @@ struct insel
|
||||||
struct hreg* hreg;
|
struct hreg* hreg;
|
||||||
struct vreg* vreg;
|
struct vreg* vreg;
|
||||||
struct ir* value;
|
struct ir* value;
|
||||||
|
int offset;
|
||||||
}
|
}
|
||||||
u;
|
u;
|
||||||
};
|
};
|
||||||
|
@ -53,6 +57,9 @@ 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_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_st_offset_insel(struct hop* hop, struct hreg* hreg);
|
||||||
|
extern void hop_add_ab_offset_insel(struct hop* hop, int offset);
|
||||||
|
extern void hop_add_lb_offset_insel(struct hop* hop, int offset);
|
||||||
extern void hop_add_eoi_insel(struct hop* hop);
|
extern void hop_add_eoi_insel(struct hop* hop);
|
||||||
|
|
||||||
extern void hop_add_insel(struct hop* hop, const char* fmt, ...);
|
extern void hop_add_insel(struct hop* hop, const char* fmt, ...);
|
||||||
|
|
|
@ -112,7 +112,7 @@ extern void pass_instruction_selector(void);
|
||||||
extern void pass_live_vreg_analysis(void);
|
extern void pass_live_vreg_analysis(void);
|
||||||
extern void pass_add_prologue_epilogue(struct procedure* proc);
|
extern void pass_add_prologue_epilogue(struct procedure* proc);
|
||||||
extern void pass_promote_float_ops(struct procedure* proc);
|
extern void pass_promote_float_ops(struct procedure* proc);
|
||||||
extern void pass_register_allocator(void);
|
extern void pass_register_allocator(struct procedure* proc);
|
||||||
extern void pass_remove_dead_blocks(struct procedure* proc);
|
extern void pass_remove_dead_blocks(struct procedure* proc);
|
||||||
extern void pass_remove_dead_phis(void);
|
extern void pass_remove_dead_phis(void);
|
||||||
extern void pass_split_critical_edges(struct procedure* proc);
|
extern void pass_split_critical_edges(struct procedure* proc);
|
||||||
|
@ -120,6 +120,7 @@ extern void pass_split_critical_edges(struct procedure* proc);
|
||||||
extern struct hop* platform_prologue(struct procedure* proc);
|
extern struct hop* platform_prologue(struct procedure* proc);
|
||||||
extern struct hop* platform_epilogue(struct procedure* proc);
|
extern struct hop* platform_epilogue(struct procedure* proc);
|
||||||
extern struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest);
|
extern struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest);
|
||||||
|
extern void platform_calculate_offsets(struct procedure* proc);
|
||||||
|
|
||||||
extern FILE* outputfile;
|
extern FILE* outputfile;
|
||||||
extern FILE* dominance_dot_file;
|
extern FILE* dominance_dot_file;
|
||||||
|
|
|
@ -308,7 +308,7 @@ static void parse_pseu(void)
|
||||||
current_proc = calloc(sizeof(struct procedure), 1);
|
current_proc = calloc(sizeof(struct procedure), 1);
|
||||||
current_proc->name = strdup(em.em_pnam);
|
current_proc->name = strdup(em.em_pnam);
|
||||||
current_proc->entry = bb_get(current_proc->name);
|
current_proc->entry = bb_get(current_proc->name);
|
||||||
current_proc->nlocals = em.em_nlocals;
|
current_proc->locals_size = em.em_nlocals;
|
||||||
code_bb = current_proc->entry;
|
code_bb = current_proc->entry;
|
||||||
code_bb->is_root = true;
|
code_bb->is_root = true;
|
||||||
array_append(¤t_proc->blocks, code_bb);
|
array_append(¤t_proc->blocks, code_bb);
|
||||||
|
|
|
@ -100,6 +100,26 @@ static void constrain_input_reg(int child, uint32_t attr)
|
||||||
get_constraint(vreg)->attrs = attr;
|
get_constraint(vreg)->attrs = attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t find_type_from_constraint(uint32_t attr)
|
||||||
|
{
|
||||||
|
/* Looks through the registers and finds a concrete register implementing
|
||||||
|
* that attribute, and returns the type. We assume that all registers
|
||||||
|
* implementing an attribute (which anyone is going to ask for, 'volatile'
|
||||||
|
* doesn't count) will have the same type. TODO: mcgg should check for
|
||||||
|
* this. */
|
||||||
|
|
||||||
|
const struct burm_register_data* brd = burm_register_data;
|
||||||
|
while (brd->name)
|
||||||
|
{
|
||||||
|
if (brd->attrs & attr)
|
||||||
|
return brd->type;
|
||||||
|
brd++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fatal("unable to find a register matching attribute 0x%x", attr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void constrain_output_reg(uint32_t attr)
|
static void constrain_output_reg(uint32_t attr)
|
||||||
{
|
{
|
||||||
struct vreg* vreg = current_hop->output;
|
struct vreg* vreg = current_hop->output;
|
||||||
|
@ -109,6 +129,7 @@ static void constrain_output_reg(uint32_t attr)
|
||||||
|
|
||||||
array_appendu(¤t_hop->outs, vreg);
|
array_appendu(¤t_hop->outs, vreg);
|
||||||
vreg->defined = current_hop;
|
vreg->defined = current_hop;
|
||||||
|
vreg->type = find_type_from_constraint(attr);
|
||||||
|
|
||||||
get_constraint(vreg)->attrs = attr;
|
get_constraint(vreg)->attrs = attr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,9 @@ static void recursively_associate_group(struct phicongruence* c, struct vreg* vr
|
||||||
if (vreg->defined)
|
if (vreg->defined)
|
||||||
{
|
{
|
||||||
struct constraint* constraint = pmap_findleft(&vreg->defined->constraints, vreg);
|
struct constraint* constraint = pmap_findleft(&vreg->defined->constraints, vreg);
|
||||||
if ((c->attrs == 0) || (constraint->attrs < c->attrs))
|
if (c->type == 0)
|
||||||
c->attrs = constraint->attrs;
|
c->type = vreg->type;
|
||||||
|
assert(c->type == vreg->type);
|
||||||
|
|
||||||
array_appendu(&c->definitions, vreg->defined);
|
array_appendu(&c->definitions, vreg->defined);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ struct assignment
|
||||||
struct vreg* out;
|
struct vreg* out;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct procedure* current_proc;
|
||||||
|
|
||||||
static ARRAYOF(struct hreg) hregs;
|
static ARRAYOF(struct hreg) hregs;
|
||||||
|
|
||||||
static PMAPOF(struct vreg, struct hreg) evicted;
|
static PMAPOF(struct vreg, struct hreg) evicted;
|
||||||
|
@ -42,7 +44,7 @@ static void wire_up_blocks_ins_outs(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hreg* allocate_phi_hreg(register_assignment_t* regs,
|
static struct hreg* allocate_phi_hreg(register_assignment_t* regs,
|
||||||
struct vreg* vreg, uint32_t attrs)
|
struct vreg* vreg, uint32_t type)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -52,7 +54,7 @@ static struct hreg* allocate_phi_hreg(register_assignment_t* regs,
|
||||||
for (i=0; i<hregs.count; i++)
|
for (i=0; i<hregs.count; i++)
|
||||||
{
|
{
|
||||||
struct hreg* hreg = hregs.item[i];
|
struct hreg* hreg = hregs.item[i];
|
||||||
if (!pmap_findleft(regs, hreg) && (hreg->attrs & attrs))
|
if (!pmap_findleft(regs, hreg) && (hreg->type == type))
|
||||||
{
|
{
|
||||||
/* This one is unused. Use it. */
|
/* This one is unused. Use it. */
|
||||||
return hreg;
|
return hreg;
|
||||||
|
@ -99,19 +101,39 @@ static struct hreg* evict(struct vreg* vreg)
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool allocatable_input(struct hreg* hreg, struct vreg* vreg)
|
static bool type_match(struct hreg* hreg, struct vreg* vreg)
|
||||||
{
|
{
|
||||||
struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg);
|
struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg);
|
||||||
|
if (c)
|
||||||
|
return (hreg->attrs & c->attrs);
|
||||||
|
if (vreg->congruence)
|
||||||
|
return (hreg->type == vreg->congruence->type);
|
||||||
|
return (hreg->type == vreg->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool allocatable_stackable_input(struct hreg* hreg, struct vreg* vreg)
|
||||||
|
{
|
||||||
return !pmap_findleft(current_ins, hreg) &&
|
return !pmap_findleft(current_ins, hreg) &&
|
||||||
(!c || (hreg->attrs & c->attrs));
|
type_match(hreg, vreg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool allocatable_stackable_output(struct hreg* hreg, struct vreg* vreg)
|
||||||
|
{
|
||||||
|
return !pmap_findleft(current_outs, hreg) &&
|
||||||
|
type_match(hreg, vreg) &&
|
||||||
|
!(hreg->attrs & current_hop->insndata->corrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool allocatable_input(struct hreg* hreg, struct vreg* vreg)
|
||||||
|
{
|
||||||
|
return allocatable_stackable_input(hreg, vreg) &&
|
||||||
|
!hreg->is_stacked;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool allocatable_output(struct hreg* hreg, struct vreg* vreg)
|
static bool allocatable_output(struct hreg* hreg, struct vreg* vreg)
|
||||||
{
|
{
|
||||||
struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg);
|
return allocatable_stackable_output(hreg, vreg) &&
|
||||||
return !pmap_findleft(current_outs, hreg) &&
|
!hreg->is_stacked;
|
||||||
(!c || (hreg->attrs & c->attrs)) &&
|
|
||||||
!(hreg->attrs & current_hop->insndata->corrupts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hreg* find_input_reg(struct vreg* vreg)
|
static struct hreg* find_input_reg(struct vreg* vreg)
|
||||||
|
@ -174,7 +196,32 @@ static void add_input_register(struct vreg* vreg, struct hreg* hreg)
|
||||||
|
|
||||||
if (hreg)
|
if (hreg)
|
||||||
{
|
{
|
||||||
if (pmap_findleft(current_ins, hreg) == vreg)
|
if (hreg->is_stacked)
|
||||||
|
{
|
||||||
|
/* This vreg is stacked; we need to put it in a register. That's
|
||||||
|
* slightly exciting because the vreg might be a through, which
|
||||||
|
* means we need an output register too... which we might not be
|
||||||
|
* able to allocate. */
|
||||||
|
|
||||||
|
if (array_contains(¤t_hop->throughs, vreg))
|
||||||
|
{
|
||||||
|
struct hreg* src = hreg;
|
||||||
|
hreg = find_through_reg(vreg);
|
||||||
|
assert(hreg);
|
||||||
|
pmap_remove(current_ins, src, vreg);
|
||||||
|
pmap_remove(current_outs, src, vreg);
|
||||||
|
pmap_add(current_ins, hreg, vreg);
|
||||||
|
pmap_add(current_outs, hreg, vreg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Not a through. */
|
||||||
|
pmap_remove(current_ins, hreg, vreg);
|
||||||
|
hreg = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pmap_findleft(current_ins, hreg) == vreg)
|
||||||
{
|
{
|
||||||
/* Yup, already there. */
|
/* Yup, already there. */
|
||||||
}
|
}
|
||||||
|
@ -213,7 +260,7 @@ static void add_output_register(struct vreg* vreg)
|
||||||
c = pmap_findleft(¤t_hop->constraints, vreg);
|
c = pmap_findleft(¤t_hop->constraints, vreg);
|
||||||
if (c->equals_to)
|
if (c->equals_to)
|
||||||
{
|
{
|
||||||
tracef('R', "R: outputput equality constraint of %%%d to %%%d\n",
|
tracef('R', "R: output equality constraint of %%%d to %%%d\n",
|
||||||
vreg->id, c->equals_to->id);
|
vreg->id, c->equals_to->id);
|
||||||
|
|
||||||
/* This output register is constrained to be in the same hreg as an
|
/* This output register is constrained to be in the same hreg as an
|
||||||
|
@ -262,28 +309,31 @@ static void add_through_register(struct vreg* vreg, struct hreg* hreg)
|
||||||
|
|
||||||
if (hreg)
|
if (hreg)
|
||||||
{
|
{
|
||||||
bool infree = allocatable_input(hreg, vreg);
|
bool infree = allocatable_stackable_input(hreg, vreg);
|
||||||
bool outfree = allocatable_output(hreg, vreg);
|
bool outfree = allocatable_stackable_output(hreg, vreg);
|
||||||
|
struct vreg* inuse = pmap_findleft(current_ins, hreg);
|
||||||
|
struct vreg* outuse = pmap_findleft(current_outs, hreg);
|
||||||
|
|
||||||
if (infree && outfree)
|
if ((infree || (inuse == vreg)) &&
|
||||||
|
(outfree || (outuse == vreg)))
|
||||||
{
|
{
|
||||||
/* Register unused --- use it. */
|
/* Input and output are either free or already assigned to this
|
||||||
}
|
* vreg. */
|
||||||
if ((infree || pmap_findleft(current_ins, hreg) == vreg) &&
|
|
||||||
(outfree || pmap_findleft(current_outs, hreg) == vreg))
|
|
||||||
{
|
|
||||||
/* Input and output are either free or already assigned. */
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Nope, can't honour the hint. */
|
/* Nope, can't honour the hint. Mark the register as evicted; we'll
|
||||||
hreg = NULL;
|
* put it in something later (probably a stack slot). */
|
||||||
|
|
||||||
|
tracef('R', "R: cannot place %%%d in %s, evicting\n", vreg->id, hreg->name);
|
||||||
|
pmap_put(&evicted, vreg, hreg);
|
||||||
|
pmap_remove(current_ins, hreg, vreg);
|
||||||
|
pmap_remove(current_outs, hreg, vreg);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hreg)
|
assert(hreg);
|
||||||
hreg = find_through_reg(vreg);
|
|
||||||
|
|
||||||
pmap_put(current_ins, hreg, vreg);
|
pmap_put(current_ins, hreg, vreg);
|
||||||
pmap_put(current_outs, hreg, vreg);
|
pmap_put(current_outs, hreg, vreg);
|
||||||
}
|
}
|
||||||
|
@ -302,8 +352,8 @@ static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* s
|
||||||
{
|
{
|
||||||
hreg = hregs.item[i];
|
hreg = hregs.item[i];
|
||||||
if ((hreg->type == src->type) &&
|
if ((hreg->type == src->type) &&
|
||||||
allocatable_input(hreg, vreg) &&
|
allocatable_stackable_input(hreg, vreg) &&
|
||||||
allocatable_output(hreg, vreg))
|
allocatable_stackable_output(hreg, vreg))
|
||||||
{
|
{
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
|
@ -311,7 +361,8 @@ static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* s
|
||||||
|
|
||||||
/* No more registers --- allocate a stack slot. */
|
/* No more registers --- allocate a stack slot. */
|
||||||
|
|
||||||
assert(false);
|
hreg = new_stacked_hreg(src->type);
|
||||||
|
array_append(&hregs, hreg);
|
||||||
|
|
||||||
found:
|
found:
|
||||||
tracef('R', "R: evicted %%%d moving to %s\n", vreg->id, hreg->name);
|
tracef('R', "R: evicted %%%d moving to %s\n", vreg->id, hreg->name);
|
||||||
|
@ -442,7 +493,7 @@ static void assign_hregs_to_vregs(void)
|
||||||
if (!pmap_findright(old, vreg))
|
if (!pmap_findright(old, vreg))
|
||||||
{
|
{
|
||||||
struct phicongruence* c = vreg->congruence;
|
struct phicongruence* c = vreg->congruence;
|
||||||
struct hreg* hreg = allocate_phi_hreg(old, vreg, c->attrs);
|
struct hreg* hreg = allocate_phi_hreg(old, vreg, c->type);
|
||||||
|
|
||||||
tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n",
|
tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n",
|
||||||
hreg->name, vreg->id, phi->prev->name);
|
hreg->name, vreg->id, phi->prev->name);
|
||||||
|
@ -551,7 +602,8 @@ static int insert_moves(struct basicblock* bb, int index,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Swap. */
|
/* Swap. */
|
||||||
|
|
||||||
|
assert(false);
|
||||||
src = copies.item[0].left;
|
src = copies.item[0].left;
|
||||||
dest = pmap_findleft(&copies, src);
|
dest = pmap_findleft(&copies, src);
|
||||||
hop = create_swap(bb, src, dest);
|
hop = create_swap(bb, src, dest);
|
||||||
|
@ -626,13 +678,43 @@ static void insert_phi_copies(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pass_register_allocator(void)
|
static int pack_stackframe(int stacksize, int size, uint32_t attr)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<hregs.count; i++)
|
||||||
|
{
|
||||||
|
struct hreg* hreg = hregs.item[i];
|
||||||
|
if (hreg->is_stacked && (hreg->type & attr))
|
||||||
|
{
|
||||||
|
hreg->offset = stacksize;
|
||||||
|
stacksize += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stacksize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void layout_stack_frame(void)
|
||||||
|
{
|
||||||
|
int stacksize = 0;
|
||||||
|
stacksize = pack_stackframe(stacksize, 8, burm_bytes8_ATTR);
|
||||||
|
stacksize = pack_stackframe(stacksize, 4, burm_bytes4_ATTR);
|
||||||
|
stacksize = pack_stackframe(stacksize, 2, burm_bytes2_ATTR);
|
||||||
|
stacksize = pack_stackframe(stacksize, 1, burm_bytes1_ATTR);
|
||||||
|
current_proc->spills_size = stacksize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pass_register_allocator(struct procedure* proc)
|
||||||
|
{
|
||||||
|
current_proc = proc;
|
||||||
|
|
||||||
populate_hregs();
|
populate_hregs();
|
||||||
wire_up_blocks_ins_outs();
|
wire_up_blocks_ins_outs();
|
||||||
|
|
||||||
assign_hregs_to_vregs();
|
assign_hregs_to_vregs();
|
||||||
insert_phi_copies();
|
insert_phi_copies();
|
||||||
|
layout_stack_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vim: set sw=4 ts=4 expandtab : */
|
/* vim: set sw=4 ts=4 expandtab : */
|
||||||
|
|
|
@ -1,17 +1,35 @@
|
||||||
#include "mcg.h"
|
#include "mcg.h"
|
||||||
|
|
||||||
|
/* mcg stack frames are laid out as:
|
||||||
|
*
|
||||||
|
* | ...params...
|
||||||
|
* | --------------- <- ap
|
||||||
|
* | saved regs
|
||||||
|
* | --------------- <- st
|
||||||
|
* | spills
|
||||||
|
* | --------------- <- fp (a.k.a. lb)
|
||||||
|
* | locals
|
||||||
|
* | --------------- <- sp
|
||||||
|
* V ...user area...
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void platform_calculate_offsets(struct procedure* proc)
|
||||||
|
{
|
||||||
|
proc->fp_to_st = proc->spills_size;
|
||||||
|
proc->fp_to_ap = proc->fp_to_st + proc->saved_size + 8;
|
||||||
|
proc->fp_to_lb = 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct hop* platform_prologue(struct procedure* proc)
|
struct hop* platform_prologue(struct procedure* proc)
|
||||||
{
|
{
|
||||||
int framesize = proc->nlocals + 8;
|
|
||||||
int retbase = proc->nlocals;
|
|
||||||
|
|
||||||
struct hop* hop = new_hop(proc->entry, NULL);
|
struct hop* hop = new_hop(proc->entry, NULL);
|
||||||
|
|
||||||
hop_add_insel(hop, "addi sp, fp, %d", -framesize);
|
hop_add_insel(hop, "addi sp, sp, %d", proc->fp_to_ap + proc->locals_size);
|
||||||
hop_add_insel(hop, "mfspr 0, lr");
|
hop_add_insel(hop, "mfspr 0, lr");
|
||||||
hop_add_insel(hop, "stw fp, %d(sp)", retbase);
|
hop_add_insel(hop, "stw fp, %d(sp)", proc->fp_to_st + proc->locals_size);
|
||||||
hop_add_insel(hop, "stw 0, %d(sp)", retbase+4);
|
hop_add_insel(hop, "stw 0, %d(sp)", proc->fp_to_st + proc->locals_size + 4);
|
||||||
hop_add_insel(hop, "addi fp, sp, retbase");
|
hop_add_insel(hop, "addi fp, sp, %d", proc->locals_size);
|
||||||
|
|
||||||
return hop;
|
return hop;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +48,14 @@ struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg*
|
||||||
struct hop* hop = new_hop(bb, NULL);
|
struct hop* hop = new_hop(bb, NULL);
|
||||||
|
|
||||||
if ((src->type & burm_int_ATTR) && (dest->type & burm_int_ATTR))
|
if ((src->type & burm_int_ATTR) && (dest->type & burm_int_ATTR))
|
||||||
hop_add_insel(hop, "mr %H, %H", dest, src);
|
{
|
||||||
|
if (src->is_stacked)
|
||||||
|
hop_add_insel(hop, "lwz %H, %S(fp) ! %H", dest, src, src);
|
||||||
|
else if (dest->is_stacked)
|
||||||
|
hop_add_insel(hop, "stw %H, %S(fp) ! %H", src, dest, dest);
|
||||||
|
else
|
||||||
|
hop_add_insel(hop, "mr %H, %H", dest, src);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
fatal("cannot generate move from %s to %s", src->name, dest->name);
|
fatal("cannot generate move from %s to %s", src->name, dest->name);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "mcg.h"
|
#include "mcg.h"
|
||||||
|
|
||||||
|
extern struct procedure* current_proc;
|
||||||
|
|
||||||
static void print_blocks(char k, struct procedure* proc)
|
static void print_blocks(char k, struct procedure* proc)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -157,8 +159,6 @@ static void write_dominance_graph(const char* name)
|
||||||
|
|
||||||
void procedure_compile(struct procedure* proc)
|
void procedure_compile(struct procedure* proc)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
pass_group_irs(proc);
|
pass_group_irs(proc);
|
||||||
print_blocks('1', proc);
|
print_blocks('1', proc);
|
||||||
|
|
||||||
|
@ -189,10 +189,11 @@ void procedure_compile(struct procedure* proc)
|
||||||
pass_find_phi_congruence_groups();
|
pass_find_phi_congruence_groups();
|
||||||
pass_live_vreg_analysis();
|
pass_live_vreg_analysis();
|
||||||
print_hops('8', proc);
|
print_hops('8', proc);
|
||||||
pass_register_allocator();
|
pass_register_allocator(proc);
|
||||||
pass_add_prologue_epilogue(proc);
|
pass_add_prologue_epilogue(proc);
|
||||||
print_hops('9', proc);
|
print_hops('9', proc);
|
||||||
|
|
||||||
|
platform_calculate_offsets(proc);
|
||||||
emit_procedure(proc);
|
emit_procedure(proc);
|
||||||
|
|
||||||
if (cfg_dot_file)
|
if (cfg_dot_file)
|
||||||
|
|
|
@ -13,7 +13,12 @@ struct procedure
|
||||||
const char* name;
|
const char* name;
|
||||||
struct basicblock* entry;
|
struct basicblock* entry;
|
||||||
struct basicblock* exit;
|
struct basicblock* exit;
|
||||||
size_t nlocals;
|
int locals_size;
|
||||||
|
int spills_size;
|
||||||
|
int saved_size;
|
||||||
|
int fp_to_st;
|
||||||
|
int fp_to_ap;
|
||||||
|
int fp_to_lb;
|
||||||
ARRAYOF(struct basicblock) blocks;
|
ARRAYOF(struct basicblock) blocks;
|
||||||
IMAPOF(struct local) locals;
|
IMAPOF(struct local) locals;
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,15 +20,16 @@ struct hreg* new_hreg(const struct burm_register_data* brd)
|
||||||
return hreg;
|
return hreg;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hreg* new_stacked_hreg(int offset, uint32_t type)
|
struct hreg* new_stacked_hreg(uint32_t type)
|
||||||
{
|
{
|
||||||
|
static int hreg_count = 1;
|
||||||
struct hreg* hreg = calloc(1, sizeof *hreg);
|
struct hreg* hreg = calloc(1, sizeof *hreg);
|
||||||
hreg->name = aprintf("stacked_%d", offset);
|
hreg->name = aprintf("stacked_%d_id_%d", type, hreg_count++);
|
||||||
hreg->realname = hreg->name;
|
hreg->realname = hreg->name;
|
||||||
hreg->type = type;
|
hreg->type = type;
|
||||||
hreg->attrs = type;
|
hreg->attrs = type;
|
||||||
hreg->is_stacked = true;
|
hreg->is_stacked = true;
|
||||||
hreg->offset = offset;
|
hreg->offset = -1;
|
||||||
return hreg;
|
return hreg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ struct phicongruence
|
||||||
int id;
|
int id;
|
||||||
ARRAYOF(struct vreg) vregs;
|
ARRAYOF(struct vreg) vregs;
|
||||||
ARRAYOF(struct hop) definitions;
|
ARRAYOF(struct hop) definitions;
|
||||||
uint32_t attrs;
|
uint32_t type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hreg
|
struct hreg
|
||||||
|
@ -24,6 +24,7 @@ struct hreg
|
||||||
struct vreg
|
struct vreg
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
|
uint32_t type;
|
||||||
struct phicongruence* congruence;
|
struct phicongruence* congruence;
|
||||||
struct hop* defined;
|
struct hop* defined;
|
||||||
ARRAYOF(struct hop) used;
|
ARRAYOF(struct hop) used;
|
||||||
|
@ -34,7 +35,7 @@ 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(const 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 type);
|
extern struct hreg* new_stacked_hreg(uint32_t type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -721,6 +721,7 @@ static void insn_ivalue(int opcode, arith value)
|
||||||
/* This is actually ignored --- the entire block gets special
|
/* This is actually ignored --- the entire block gets special
|
||||||
* treatment. But a lot of the rest of the code assumes that
|
* treatment. But a lot of the rest of the code assumes that
|
||||||
* all basic blocks have one instruction, so we insert one. */
|
* all basic blocks have one instruction, so we insert one. */
|
||||||
|
|
||||||
array_append(¤t_proc->exit->irs,
|
array_append(¤t_proc->exit->irs,
|
||||||
new_ir0(
|
new_ir0(
|
||||||
IR_RET, 0
|
IR_RET, 0
|
||||||
|
|
Loading…
Reference in a new issue