#include "mcg.h" /* mcg stack frames are laid out as: * * | ...params... * | --------------- <- ab * | old FR * | old FP * | --------------- <- fp (a.k.a. lb) * | locals * | --------------- * | spills * | --------------- <- sb * | saved regs * | --------------- <- sp, rb * V ...user area... * * st indexes up; lb indexes down. * * Note that [fp] == old_fp and ab == fp + 8. */ static ARRAYOF(struct hreg) saved_regs; void platform_calculate_offsets(void) { int i; saved_regs.count = 0; for (i=0; iusedregs.count; i++) { struct hreg* hreg = current_proc->usedregs.item[i]; if (!(hreg->attrs & burm_volatile_ATTR) && ((hreg->attrs & burm_long_ATTR) || (hreg->attrs & burm_double_ATTR))) { hreg->offset = current_proc->saved_size; current_proc->saved_size += 8; array_append(&saved_regs, hreg); } } for (i=0; iusedregs.count; i++) { struct hreg* hreg = current_proc->usedregs.item[i]; if (!(hreg->attrs & burm_volatile_ATTR) && ((hreg->attrs & burm_int_ATTR) || (hreg->attrs & burm_float_ATTR))) { hreg->offset = current_proc->saved_size; current_proc->saved_size += 4; array_append(&saved_regs, hreg); } } current_proc->fp_to_ab = 8; current_proc->fp_to_lb = 0; current_proc->fp_to_sb = -(current_proc->locals_size + current_proc->spills_size); current_proc->fp_to_rb = current_proc->fp_to_sb - current_proc->saved_size; } struct hop* platform_prologue(void) { int i; int spoffset = current_proc->saved_size + current_proc->spills_size + current_proc->locals_size; struct hop* hop = new_hop(current_proc->entry, NULL); hop_add_insel(hop, "! locals_size = %d", current_proc->locals_size); hop_add_insel(hop, "! spills_size = %d", current_proc->spills_size); hop_add_insel(hop, "! saved_size = %d", current_proc->saved_size); hop_add_insel(hop, "! params @ fp+%d", current_proc->fp_to_ab); hop_add_insel(hop, "! lr @ fp+4"); hop_add_insel(hop, "! fp @ fp+0"); hop_add_insel(hop, "! locals @ fp-%d to fp+0", current_proc->locals_size); hop_add_insel(hop, "! spills @ fp-%d to fp-%d", -current_proc->fp_to_sb, current_proc->locals_size); for (i=saved_regs.count-1; i>=0; i--) { struct hreg* hreg = saved_regs.item[i]; hop_add_insel(hop, "! %s @ fp-%d", hreg->id, -(current_proc->fp_to_rb + hreg->offset)); } hop_add_insel(hop, "addiu sp, sp, %d", -(spoffset + 8)); hop_add_insel(hop, "sw fp, %d(sp)", spoffset + 0); hop_add_insel(hop, "sw ra, %d(sp)", spoffset + 4); hop_add_insel(hop, "addiu fp, sp, %d", spoffset); /* Saved reg offsets are negative. */ for (i=0; iattrs & burm_int_ATTR) hop_add_insel(hop, "sw %H, %d(fp)", hreg, current_proc->fp_to_rb + hreg->offset); else if (hreg->attrs & burm_long_ATTR) { hop_add_insel(hop, "sw %0H, %d(fp)", hreg, current_proc->fp_to_rb + hreg->offset + 0); hop_add_insel(hop, "sw %1H, %d(fp)", hreg, current_proc->fp_to_rb + hreg->offset + 4); } else if (hreg->attrs & burm_float_ATTR) hop_add_insel(hop, "swc1 %H, %d(fp)", hreg, current_proc->fp_to_rb + hreg->offset); else if (hreg->attrs & burm_double_ATTR) hop_add_insel(hop, "sdc1 %H, %d(fp)", hreg, current_proc->fp_to_rb + hreg->offset); else fatal("unsavable non-volatile register %s", hreg->id); } return hop; } struct hop* platform_epilogue(void) { struct hop* hop = new_hop(current_proc->exit, NULL); int i; for (i=0; iattrs & burm_int_ATTR) hop_add_insel(hop, "lw %H, %d(fp)", hreg, current_proc->fp_to_rb + hreg->offset); else if (hreg->attrs & burm_long_ATTR) { hop_add_insel(hop, "lw %0H, %d(fp)", hreg, current_proc->fp_to_rb + hreg->offset + 0); hop_add_insel(hop, "lw %1H, %d(fp)", hreg, current_proc->fp_to_rb + hreg->offset + 4); } else if (hreg->attrs & burm_float_ATTR) hop_add_insel(hop, "lwc1 %H, %d(fp)", hreg, current_proc->fp_to_rb + hreg->offset); else if (hreg->attrs & burm_double_ATTR) hop_add_insel(hop, "ldc1 %H, %d(fp)", hreg, current_proc->fp_to_rb + hreg->offset); else fatal("unloadable non-volatile register %s", hreg->id); } hop_add_insel(hop, "lw ra, 4(fp)"); hop_add_insel(hop, "lw at, 0(fp)"); /* load old fp */ hop_add_insel(hop, "addiu sp, fp, %d", current_proc->fp_to_ab); hop_add_insel(hop, "jr ra"); hop_add_insel(hop, "mov fp, at"); /* delay slot */ return hop; } struct hop* platform_move(struct basicblock* bb, struct vreg* vreg, struct hreg* src, struct hreg* dest) { struct hop* hop = new_hop(bb, NULL); if ((src->attrs & TYPE_ATTRS) != (dest->attrs & TYPE_ATTRS)) fatal("hreg move of %%%d from %s to %s with mismatched types", vreg->id, src->id, dest->id); else { uint32_t type = src->attrs & TYPE_ATTRS; tracef('R', "R: non-converting move from %s to %s of type 0x%x\n", src->id, dest->id, type); if (!src->is_stacked && dest->is_stacked) { switch (type) { case burm_int_ATTR: hop_add_insel(hop, "sw %H, %S(fp) ! %H", src, dest, dest); break; case burm_long_ATTR: hop_add_insel(hop, "sw %0H, 0+%S(fp) ! %H", src, dest, dest); hop_add_insel(hop, "sw %1H, 4+%S(fp) ! %H", src, dest, dest); break; case burm_float_ATTR: hop_add_insel(hop, "swc1 %H, %S(fp) ! %H", src, dest, dest); break; case burm_double_ATTR: hop_add_insel(hop, "sdc1 %H, %S(fp) ! %H", src, dest, dest); break; default: goto nomove; } } else if (src->is_stacked && !dest->is_stacked) { switch (type) { case burm_int_ATTR: hop_add_insel(hop, "lw %H, %S(fp) ! %H", dest, src, src); break; case burm_long_ATTR: /* Can't load straight into dest because it might overlap with src. */ hop_add_insel(hop, "lw at, 0+%S(fp) ! %H", dest, src, src); hop_add_insel(hop, "lw %1H, 4+%S(fp) ! %H", dest, src, src); hop_add_insel(hop, "mov %0H, at", dest); break; case burm_float_ATTR: hop_add_insel(hop, "lwc1 %H, %S(fp) ! %H", dest, src, src); break; case burm_double_ATTR: hop_add_insel(hop, "ldc1 %H, %S(fp) ! %H", dest, src, src); break; default: goto nomove; } } else if (!src->is_stacked && !dest->is_stacked) { switch (type) { case burm_int_ATTR: hop_add_insel(hop, "mov %H, %H", dest, src); break; case burm_long_ATTR: hop_add_insel(hop, "mov %0H, %0H", dest, src); hop_add_insel(hop, "mov %1H, %1H", dest, src); break; case burm_float_ATTR: hop_add_insel(hop, "mov.s %H, %H", dest, src); break; case burm_double_ATTR: hop_add_insel(hop, "mov.d %H, %H", dest, src); break; default: goto nomove; } } else if (src->is_stacked && dest->is_stacked) fatal("tried to move stacked object %%%d of type 0x%x from %s to %s", vreg->id, type, src->id, dest->id); else goto nomove; } return hop; 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); tracef('R', "R: swap of %s to %s\n", src->id, dest->id); 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, "mov at, %H", src); hop_add_insel(hop, "mov %H, %H", src, dest); hop_add_insel(hop, "mov %H, at", dest); break; case burm_long_ATTR: hop_add_insel(hop, "mov at, %0H", src); hop_add_insel(hop, "mov %0H, %0H", src, dest); hop_add_insel(hop, "mov %0H, at", dest); hop_add_insel(hop, "mov at, %1H", src); hop_add_insel(hop, "mov %1H, %1H", src, dest); hop_add_insel(hop, "mov %1H, at", dest); break; case burm_float_ATTR: hop_add_insel(hop, "mov.s f30, %H", src); hop_add_insel(hop, "mov.s %H, %H", src, dest); hop_add_insel(hop, "mov.s %H, f30", dest); break; case burm_double_ATTR: hop_add_insel(hop, "mov.d f30, %H", src); hop_add_insel(hop, "mov.d %H, %H", src, dest); hop_add_insel(hop, "mov.d %H, f30", dest); break; } return hop; } const char* platform_label(const char* label) { /* Labels starting with . are internal, not exported, and don't need mangling. */ if (label[0] == '.') return label; /* Otherwise, mangle. */ return aprintf("_%s", label); } /* vim: set sw=4 ts=4 expandtab : */