2016-10-15 16:38:46 +00:00
|
|
|
#include "mcg.h"
|
|
|
|
|
2016-10-15 20:53:56 +00:00
|
|
|
/* mcg stack frames are laid out as:
|
|
|
|
*
|
|
|
|
* | ...params...
|
2016-10-15 21:33:30 +00:00
|
|
|
* | --------------- <- ab
|
2016-10-27 19:50:58 +00:00
|
|
|
* | spills
|
2016-10-15 21:33:30 +00:00
|
|
|
* | ---------------
|
2016-10-27 19:50:58 +00:00
|
|
|
* | saved regs
|
|
|
|
* | LR
|
|
|
|
* | FP
|
2016-10-15 21:33:30 +00:00
|
|
|
* | --------------- <- st, fp (a.k.a. lb)
|
2016-10-15 20:53:56 +00:00
|
|
|
* | locals
|
|
|
|
* | --------------- <- sp
|
|
|
|
* V ...user area...
|
|
|
|
*
|
2016-10-15 21:33:30 +00:00
|
|
|
* st indexes up; lb indexes down.
|
2016-10-27 19:50:58 +00:00
|
|
|
*
|
|
|
|
* We ensure that dereferencing fp always produces the caller's fp.
|
2016-10-15 20:53:56 +00:00
|
|
|
*/
|
|
|
|
|
2016-10-16 20:37:42 +00:00
|
|
|
static ARRAYOF(struct hreg) saved_regs;
|
|
|
|
|
2016-10-15 21:19:44 +00:00
|
|
|
void platform_calculate_offsets(void)
|
2016-10-15 16:38:46 +00:00
|
|
|
{
|
2016-10-16 20:37:42 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
saved_regs.count = 0;
|
|
|
|
for (i=0; i<current_proc->usedregs.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)))
|
|
|
|
{
|
|
|
|
current_proc->saved_size += 4;
|
|
|
|
array_append(&saved_regs, hreg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-15 21:33:30 +00:00
|
|
|
current_proc->fp_to_st = 0;
|
|
|
|
current_proc->fp_to_ab = current_proc->spills_size + current_proc->saved_size + 8;
|
2016-10-15 21:19:44 +00:00
|
|
|
current_proc->fp_to_lb = 0;
|
2016-10-15 20:53:56 +00:00
|
|
|
}
|
2016-10-15 16:38:46 +00:00
|
|
|
|
2016-10-15 21:19:44 +00:00
|
|
|
struct hop* platform_prologue(void)
|
2016-10-15 20:53:56 +00:00
|
|
|
{
|
2016-10-16 20:37:42 +00:00
|
|
|
int i;
|
|
|
|
int saved_offset;
|
2016-10-15 21:19:44 +00:00
|
|
|
struct hop* hop = new_hop(current_proc->entry, NULL);
|
2016-10-15 16:38:46 +00:00
|
|
|
|
2016-10-15 21:33:30 +00:00
|
|
|
hop_add_insel(hop, "! saved_size = %d+8 bytes", current_proc->saved_size);
|
|
|
|
hop_add_insel(hop, "! spills_size = %d bytes", current_proc->spills_size);
|
|
|
|
hop_add_insel(hop, "! locals_size = %d bytes", current_proc->locals_size);
|
|
|
|
hop_add_insel(hop, "addi sp, sp, %d", -(current_proc->fp_to_ab + current_proc->locals_size));
|
2016-10-15 21:39:38 +00:00
|
|
|
hop_add_insel(hop, "mfspr r0, lr");
|
2016-10-16 20:37:42 +00:00
|
|
|
|
2016-10-27 19:50:58 +00:00
|
|
|
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);
|
2016-10-15 21:19:44 +00:00
|
|
|
hop_add_insel(hop, "addi fp, sp, %d", current_proc->locals_size);
|
2016-10-15 16:38:46 +00:00
|
|
|
|
2016-10-27 19:50:58 +00:00
|
|
|
/* Saved reg offsets are negative. */
|
|
|
|
saved_offset = current_proc->saved_size + 8;
|
2016-10-16 20:37:42 +00:00
|
|
|
for (i=0; i<saved_regs.count; i++)
|
|
|
|
{
|
|
|
|
struct hreg* hreg = saved_regs.item[i];
|
2016-10-25 21:04:20 +00:00
|
|
|
if (hreg->attrs & burm_int_ATTR)
|
2016-10-16 20:37:42 +00:00
|
|
|
hop_add_insel(hop, "stw %H, %d(fp)", hreg, saved_offset);
|
2016-10-25 21:04:20 +00:00
|
|
|
else if (hreg->attrs & burm_float_ATTR)
|
2016-10-16 20:37:42 +00:00
|
|
|
hop_add_insel(hop, "stfs %H, %d(fp)", hreg, saved_offset);
|
|
|
|
saved_offset += 4;
|
|
|
|
}
|
2016-10-15 16:38:46 +00:00
|
|
|
return hop;
|
|
|
|
}
|
|
|
|
|
2016-10-15 21:19:44 +00:00
|
|
|
struct hop* platform_epilogue(void)
|
2016-10-15 16:38:46 +00:00
|
|
|
{
|
2016-10-15 21:19:44 +00:00
|
|
|
struct hop* hop = new_hop(current_proc->exit, NULL);
|
2016-10-16 20:37:42 +00:00
|
|
|
int i;
|
|
|
|
int saved_offset;
|
|
|
|
|
2016-10-27 19:50:58 +00:00
|
|
|
/* Saved reg offsets are negative. */
|
|
|
|
saved_offset = current_proc->saved_size + 8;
|
2016-10-16 20:37:42 +00:00
|
|
|
for (i=0; i<saved_regs.count; i++)
|
|
|
|
{
|
|
|
|
struct hreg* hreg = saved_regs.item[i];
|
2016-10-25 21:04:20 +00:00
|
|
|
if (hreg->attrs & burm_int_ATTR)
|
2016-10-16 20:37:42 +00:00
|
|
|
hop_add_insel(hop, "lwz %H, %d(fp)", hreg, saved_offset);
|
2016-10-25 21:04:20 +00:00
|
|
|
else if (hreg->attrs & burm_float_ATTR)
|
2016-10-16 20:37:42 +00:00
|
|
|
hop_add_insel(hop, "lfs %H, %d(fp)", hreg, saved_offset);
|
|
|
|
saved_offset += 4;
|
|
|
|
}
|
2016-10-15 16:38:46 +00:00
|
|
|
|
2016-10-27 19:50:58 +00:00
|
|
|
hop_add_insel(hop, "lwz r0, 4(fp)");
|
2016-10-16 20:37:42 +00:00
|
|
|
hop_add_insel(hop, "mtspr lr, r0");
|
2016-10-27 19:50:58 +00:00
|
|
|
hop_add_insel(hop, "lwz r0, 0(fp)"); /* load old fp */
|
2016-10-16 20:37:42 +00:00
|
|
|
hop_add_insel(hop, "addi sp, fp, %d", current_proc->fp_to_ab);
|
|
|
|
hop_add_insel(hop, "mr fp, r0");
|
2016-10-17 22:31:26 +00:00
|
|
|
hop_add_insel(hop, "bclr 20, 0, 0");
|
2016-10-15 16:38:46 +00:00
|
|
|
|
|
|
|
return hop;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest)
|
|
|
|
{
|
|
|
|
struct hop* hop = new_hop(bb, NULL);
|
|
|
|
|
2016-10-25 21:04:20 +00:00
|
|
|
if ((src->attrs & TYPE_ATTRS) != (dest->attrs & TYPE_ATTRS))
|
2016-10-19 21:29:05 +00:00
|
|
|
{
|
2016-10-21 21:31:00 +00:00
|
|
|
assert(!src->is_stacked);
|
|
|
|
assert(!dest->is_stacked);
|
|
|
|
|
2016-10-25 21:04:20 +00:00
|
|
|
switch (src->attrs & TYPE_ATTRS)
|
2016-10-19 21:29:05 +00:00
|
|
|
{
|
2016-10-21 21:31:00 +00:00
|
|
|
case burm_int_ATTR:
|
2016-10-19 21:29:05 +00:00
|
|
|
hop_add_insel(hop, "stwu %H, -4(sp)", src);
|
2016-10-21 21:31:00 +00:00
|
|
|
break;
|
|
|
|
|
2016-10-23 19:54:14 +00:00
|
|
|
case burm_long_ATTR:
|
2016-10-21 22:48:26 +00:00
|
|
|
hop_add_insel(hop, "stwu %0H, -4(sp)", src);
|
|
|
|
hop_add_insel(hop, "stwu %1H, -4(sp)", src);
|
|
|
|
break;
|
|
|
|
|
2016-10-21 21:31:00 +00:00
|
|
|
case burm_float_ATTR:
|
2016-10-19 21:29:05 +00:00
|
|
|
hop_add_insel(hop, "stfsu %H, -4(sp)", src);
|
2016-10-21 21:31:00 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case burm_double_ATTR:
|
|
|
|
hop_add_insel(hop, "stfdu %H, -8(sp)", src);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2016-10-25 21:04:20 +00:00
|
|
|
goto nomove;
|
2016-10-21 21:31:00 +00:00
|
|
|
}
|
2016-10-19 21:29:05 +00:00
|
|
|
|
2016-10-25 21:04:20 +00:00
|
|
|
switch (dest->attrs & TYPE_ATTRS)
|
2016-10-21 21:31:00 +00:00
|
|
|
{
|
|
|
|
case burm_int_ATTR:
|
2016-10-19 21:29:05 +00:00
|
|
|
hop_add_insel(hop, "lwz %H, 0(sp)", dest);
|
2016-10-21 21:31:00 +00:00
|
|
|
break;
|
|
|
|
|
2016-10-23 19:54:14 +00:00
|
|
|
case burm_long_ATTR:
|
2016-10-21 22:48:26 +00:00
|
|
|
hop_add_insel(hop, "lwz %0H, 4(sp)", dest);
|
|
|
|
hop_add_insel(hop, "lwz %1H, 0(sp)", dest);
|
|
|
|
break;
|
|
|
|
|
2016-10-21 21:31:00 +00:00
|
|
|
case burm_float_ATTR:
|
2016-10-19 21:29:05 +00:00
|
|
|
hop_add_insel(hop, "lfs %H, 0(sp)", dest);
|
2016-10-21 21:31:00 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case burm_double_ATTR:
|
|
|
|
hop_add_insel(hop, "lfd %H, 0(sp)", dest);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2016-10-25 21:04:20 +00:00
|
|
|
goto nomove;
|
2016-10-19 21:29:05 +00:00
|
|
|
}
|
2016-10-21 21:31:00 +00:00
|
|
|
|
2016-10-25 21:04:20 +00:00
|
|
|
switch (dest->attrs & TYPE_ATTRS)
|
2016-10-21 21:31:00 +00:00
|
|
|
{
|
|
|
|
case burm_int_ATTR:
|
|
|
|
case burm_float_ATTR:
|
|
|
|
hop_add_insel(hop, "addi sp, sp, 4");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case burm_double_ATTR:
|
2016-10-23 19:54:14 +00:00
|
|
|
case burm_long_ATTR:
|
2016-10-21 21:31:00 +00:00
|
|
|
hop_add_insel(hop, "addi sp, sp, 8");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2016-10-25 21:04:20 +00:00
|
|
|
goto nomove;
|
2016-10-21 21:31:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-10-25 21:04:20 +00:00
|
|
|
uint32_t type = src->attrs & TYPE_ATTRS;
|
2016-10-21 21:31:00 +00:00
|
|
|
|
|
|
|
if (!src->is_stacked && dest->is_stacked)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case burm_int_ATTR:
|
|
|
|
hop_add_insel(hop, "stw %H, %S(fp) ! %H", src, dest, dest);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case burm_float_ATTR:
|
|
|
|
hop_add_insel(hop, "stfs %H, %S(fp) ! %H", src, dest, dest);
|
|
|
|
break;
|
|
|
|
|
2016-10-24 20:14:08 +00:00
|
|
|
case burm_long_ATTR:
|
|
|
|
hop_add_insel(hop, "stw %0H, 4+%S(fp) ! %H", src, dest, dest);
|
|
|
|
hop_add_insel(hop, "stw %1H, 0+%S(fp) ! %H", src, dest, dest);
|
|
|
|
break;
|
|
|
|
|
2016-10-21 22:48:26 +00:00
|
|
|
case burm_double_ATTR:
|
|
|
|
hop_add_insel(hop, "stfd %H, %S(fp) ! %H", src, dest, dest);
|
|
|
|
break;
|
|
|
|
|
2016-10-21 21:31:00 +00:00
|
|
|
default:
|
2016-10-25 21:04:20 +00:00
|
|
|
goto nomove;
|
2016-10-21 21:31:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (src->is_stacked && !dest->is_stacked)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case burm_int_ATTR:
|
|
|
|
hop_add_insel(hop, "lwz %H, %S(fp) ! %H", dest, src, src);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case burm_float_ATTR:
|
|
|
|
hop_add_insel(hop, "lfs %H, %S(fp) ! %H", dest, src, src);
|
|
|
|
break;
|
|
|
|
|
2016-10-21 22:48:26 +00:00
|
|
|
case burm_double_ATTR:
|
|
|
|
hop_add_insel(hop, "lfd %H, %S(fp) ! %H", dest, src, src);
|
|
|
|
break;
|
|
|
|
|
2016-10-21 21:31:00 +00:00
|
|
|
default:
|
2016-10-25 21:04:20 +00:00
|
|
|
goto nomove;
|
2016-10-21 21:31:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!src->is_stacked && !dest->is_stacked)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case burm_int_ATTR:
|
|
|
|
hop_add_insel(hop, "mr %H, %H", dest, src);
|
|
|
|
break;
|
|
|
|
|
2016-10-23 19:54:14 +00:00
|
|
|
case burm_long_ATTR:
|
2016-10-21 22:02:15 +00:00
|
|
|
hop_add_insel(hop, "mr %0H, %0H", dest, src);
|
|
|
|
hop_add_insel(hop, "mr %1H, %1H", dest, src);
|
|
|
|
break;
|
|
|
|
|
2016-10-21 21:31:00 +00:00
|
|
|
case burm_float_ATTR:
|
|
|
|
case burm_double_ATTR:
|
|
|
|
hop_add_insel(hop, "fmr %H, %H", dest, src);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2016-10-25 21:04:20 +00:00
|
|
|
goto nomove;
|
2016-10-21 21:31:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2016-10-25 21:04:20 +00:00
|
|
|
goto nomove;
|
2016-10-21 21:31:00 +00:00
|
|
|
}
|
2016-10-15 16:38:46 +00:00
|
|
|
|
|
|
|
return hop;
|
2016-10-25 21:04:20 +00:00
|
|
|
|
|
|
|
nomove:
|
|
|
|
fatal("cannot move %s to %s", src->id, dest->id);
|
2016-10-15 16:38:46 +00:00
|
|
|
}
|
|
|
|
|
2016-10-27 19:50:58 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-10-27 21:17:16 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-10-15 16:38:46 +00:00
|
|
|
/* vim: set sw=4 ts=4 expandtab : */
|
|
|
|
|