diff --git a/mach/powerpc/mcg/platform.c b/mach/powerpc/mcg/platform.c index a049de3b6..7d8499e0b 100644 --- a/mach/powerpc/mcg/platform.c +++ b/mach/powerpc/mcg/platform.c @@ -4,15 +4,19 @@ * * | ...params... * | --------------- <- ab - * | saved regs + * | spills * | --------------- - * | spills + * | saved regs + * | LR + * | FP * | --------------- <- st, fp (a.k.a. lb) * | locals * | --------------- <- sp * V ...user area... * * st indexes up; lb indexes down. + * + * We ensure that dereferencing fp always produces the caller's fp. */ static ARRAYOF(struct hreg) saved_regs; @@ -51,11 +55,12 @@ struct hop* platform_prologue(void) hop_add_insel(hop, "addi sp, sp, %d", -(current_proc->fp_to_ab + current_proc->locals_size)); hop_add_insel(hop, "mfspr r0, lr"); - hop_add_insel(hop, "stw r0, %d(sp)", current_proc->locals_size + current_proc->spills_size); - hop_add_insel(hop, "stw fp, %d(sp)", current_proc->locals_size + current_proc->spills_size + 4); + hop_add_insel(hop, "stw fp, %d(sp)", current_proc->locals_size + 0); + hop_add_insel(hop, "stw r0, %d(sp)", current_proc->locals_size + 4); hop_add_insel(hop, "addi fp, sp, %d", current_proc->locals_size); - saved_offset = current_proc->spills_size + 8; + /* Saved reg offsets are negative. */ + saved_offset = current_proc->saved_size + 8; for (i=0; ispills_size + 8; + /* Saved reg offsets are negative. */ + saved_offset = current_proc->saved_size + 8; for (i=0; ispills_size); + hop_add_insel(hop, "lwz r0, 4(fp)"); hop_add_insel(hop, "mtspr lr, r0"); - hop_add_insel(hop, "lwz r0, %d(fp)", current_proc->spills_size + 4); + hop_add_insel(hop, "lwz r0, 0(fp)"); /* load old fp */ hop_add_insel(hop, "addi sp, fp, %d", current_proc->fp_to_ab); hop_add_insel(hop, "mr fp, r0"); hop_add_insel(hop, "bclr 20, 0, 0"); @@ -247,5 +253,42 @@ nomove: fatal("cannot move %s to %s", src->id, dest->id); } +struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest) +{ + struct hop* hop = new_hop(bb, NULL); + + assert(!src->is_stacked); + assert(!dest->is_stacked); + assert((src->attrs & TYPE_ATTRS) == (dest->attrs & TYPE_ATTRS)); + + switch (src->attrs & TYPE_ATTRS) + { + case burm_int_ATTR: + hop_add_insel(hop, "mr r0, %H", src); + hop_add_insel(hop, "mr %H, %H", src, dest); + hop_add_insel(hop, "mr %H, r0", dest); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "mr r0, %0H", src); + hop_add_insel(hop, "mr %0H, %0H", src, dest); + hop_add_insel(hop, "mr %0H, r0", dest); + + hop_add_insel(hop, "mr r0, %1H", src); + hop_add_insel(hop, "mr %1H, %1H", src, dest); + hop_add_insel(hop, "mr %1H, r0", dest); + break; + + case burm_float_ATTR: + case burm_double_ATTR: + hop_add_insel(hop, "fmr f0, %H", src); + hop_add_insel(hop, "fmr %H, %H", src, dest); + hop_add_insel(hop, "fmr %H, f0", dest); + break; + } + + return hop; +} + /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/powerpc/mcg/table b/mach/powerpc/mcg/table index 0ffbc40f0..5b97ae4d9 100644 --- a/mach/powerpc/mcg/table +++ b/mach/powerpc/mcg/table @@ -210,6 +210,10 @@ PATTERNS emit "mr %out, fp" cost 4; + out:(int)reg = CHAINFP.I(in:(int)reg) + emit "lwz %out, 0(%in)" + cost 4; + out:(int)reg = FPTOARGS.I(GETFP.I) emit "addi %out, fp, 8" cost 4; @@ -641,8 +645,10 @@ PATTERNS ALUR(DIVU.I, "divwu") ALUR(ASL.I, "slw") + ALUR(ASR.I, "sraw") ALUR(LSL.I, "slw") + ALUR(LSR.I, "srw") out:(int)reg = NEG.I(left:(int)reg) emit "neg %out, %left" @@ -694,10 +700,6 @@ PATTERNS out:(double)reg = LOAD.D(addr:address) emit "lfd %out, %addr" cost 4; - - out:(float)reg = value:CONST.F - emit "lfs %out, address-containing-$value" - cost 8; FPU4R(ADDF.F, "fadds") FPU8R(ADDF.D, "fadd") diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index c60dee9ce..13a3d236e 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -123,6 +123,7 @@ extern void platform_calculate_offsets(void); extern struct hop* platform_prologue(void); extern struct hop* platform_epilogue(void); extern struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest); +extern struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest); extern FILE* outputfile; extern FILE* dominance_dot_file; diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index fd10b22a0..0a6eba638 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -578,19 +578,6 @@ static void assign_hregs_to_vregs(void) } } -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, 0); - hop_add_string_insel(hop, " <-> "); - hop_add_hreg_insel(hop, dest, 0); - 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) @@ -640,12 +627,12 @@ static int insert_moves(struct basicblock* bb, int index, } else { - /* Swap. */ + /* There's nowhere to copy to --- the copies that are left form a cycle. + * So we need to swap instead. */ - assert(false); src = copies.item[0].left; dest = pmap_findleft(&copies, src); - hop = create_swap(bb, src, dest); + hop = platform_swap(bb, src, dest); pmap_remove(&copies, src, dest); pmap_remove(&copies, dest, src); }