333 lines
		
	
	
	
		
			9.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			333 lines
		
	
	
	
		
			9.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #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; i<current_proc->usedregs.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; 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)))
 | |
|         {
 | |
|             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, "addi sp, sp, %d", -(spoffset + 8));
 | |
| 	hop_add_insel(hop, "mfspr r0, lr");
 | |
| 	hop_add_insel(hop, "stw fp, %d(sp)", spoffset + 0);
 | |
| 	hop_add_insel(hop, "stw r0, %d(sp)", spoffset + 4);
 | |
| 	hop_add_insel(hop, "addi fp, sp, %d", spoffset);
 | |
| 
 | |
|     /* Saved reg offsets are negative. */
 | |
|     for (i=0; i<saved_regs.count; i++)
 | |
|     {
 | |
|         struct hreg* hreg = saved_regs.item[i];
 | |
|         if (hreg->attrs & burm_int_ATTR)
 | |
|             hop_add_insel(hop, "stw %H, %d(fp)",
 | |
|                 hreg, current_proc->fp_to_rb + hreg->offset);
 | |
|         else if (hreg->attrs & burm_float_ATTR)
 | |
|             hop_add_insel(hop, "stfs %H, %d(fp)",
 | |
|                 hreg, current_proc->fp_to_rb + hreg->offset);
 | |
|     }
 | |
| 	return hop;
 | |
| }
 | |
| 
 | |
| struct hop* platform_epilogue(void)
 | |
| {
 | |
| 	struct hop* hop = new_hop(current_proc->exit, NULL);
 | |
|     int i;
 | |
| 
 | |
|     for (i=0; i<saved_regs.count; i++)
 | |
|     {
 | |
|         struct hreg* hreg = saved_regs.item[i];
 | |
|         if (hreg->attrs & burm_int_ATTR)
 | |
|             hop_add_insel(hop, "lwz %H, %d(fp)",
 | |
|                 hreg, current_proc->fp_to_rb + hreg->offset);
 | |
|         else if (hreg->attrs & burm_float_ATTR)
 | |
|             hop_add_insel(hop, "lfs %H, %d(fp)",
 | |
|                 hreg, current_proc->fp_to_rb + hreg->offset);
 | |
|     }
 | |
| 
 | |
|     hop_add_insel(hop, "lwz r0, 4(fp)");
 | |
|     hop_add_insel(hop, "mtspr lr, r0");
 | |
|     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");
 | |
| 
 | |
| 	return hop;
 | |
| }
 | |
| 
 | |
| struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest)
 | |
| {
 | |
|     struct hop* hop = new_hop(bb, NULL);
 | |
| 
 | |
|     if ((src->attrs & TYPE_ATTRS) != (dest->attrs & TYPE_ATTRS))
 | |
|     {
 | |
|         assert(!src->is_stacked);
 | |
|         assert(!dest->is_stacked);
 | |
| 
 | |
|         switch (src->attrs & TYPE_ATTRS)
 | |
|         {
 | |
|             case burm_int_ATTR:
 | |
|                 hop_add_insel(hop, "stwu %H, -4(sp)", src);
 | |
|                 break;
 | |
| 
 | |
|             case burm_long_ATTR:
 | |
|                 hop_add_insel(hop, "stwu %0H, -4(sp)", src);
 | |
|                 hop_add_insel(hop, "stwu %1H, -4(sp)", src);
 | |
|                 break;
 | |
| 
 | |
|             case burm_float_ATTR:
 | |
|                 hop_add_insel(hop, "stfsu %H, -4(sp)", src);
 | |
|                 break;
 | |
| 
 | |
|             case burm_double_ATTR:
 | |
|                 hop_add_insel(hop, "stfdu %H, -8(sp)", src);
 | |
|                 break;
 | |
| 
 | |
|             default:
 | |
|                 goto nomove;
 | |
|         }
 | |
| 
 | |
|         switch (dest->attrs & TYPE_ATTRS)
 | |
|         {
 | |
|             case burm_int_ATTR:
 | |
|                 hop_add_insel(hop, "lwz %H, 0(sp)", dest);
 | |
|                 break;
 | |
| 
 | |
|             case burm_long_ATTR:
 | |
|                 hop_add_insel(hop, "lwz %0H, 4(sp)", dest);
 | |
|                 hop_add_insel(hop, "lwz %1H, 0(sp)", dest);
 | |
|                 break;
 | |
| 
 | |
|             case burm_float_ATTR:
 | |
|                 hop_add_insel(hop, "lfs %H, 0(sp)", dest);
 | |
|                 break;
 | |
| 
 | |
|             case burm_double_ATTR:
 | |
|                 hop_add_insel(hop, "lfd %H, 0(sp)", dest);
 | |
|                 break;
 | |
| 
 | |
|             default:
 | |
|                 goto nomove;
 | |
|         }
 | |
| 
 | |
|         switch (dest->attrs & TYPE_ATTRS)
 | |
|         {
 | |
|             case burm_int_ATTR:
 | |
|             case burm_float_ATTR:
 | |
|                 hop_add_insel(hop, "addi sp, sp, 4");
 | |
|                 break;
 | |
| 
 | |
|             case burm_double_ATTR:
 | |
|             case burm_long_ATTR:
 | |
|                 hop_add_insel(hop, "addi sp, sp, 8");
 | |
|                 break;
 | |
| 
 | |
|             default:
 | |
|                 goto nomove;
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         uint32_t type = src->attrs & TYPE_ATTRS;
 | |
| 
 | |
|         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;
 | |
| 
 | |
|                 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;
 | |
| 
 | |
|                 case burm_double_ATTR:
 | |
|                     hop_add_insel(hop, "stfd %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, "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;
 | |
| 
 | |
|                 case burm_double_ATTR:
 | |
|                     hop_add_insel(hop, "lfd %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, "mr %H, %H", dest, src);
 | |
|                     break;
 | |
| 
 | |
|                 case burm_long_ATTR:
 | |
|                     hop_add_insel(hop, "mr %0H, %0H", dest, src);
 | |
|                     hop_add_insel(hop, "mr %1H, %1H", dest, src);
 | |
|                     break;
 | |
| 
 | |
|                 case burm_float_ATTR:
 | |
|                 case burm_double_ATTR:
 | |
|                     hop_add_insel(hop, "fmr %H, %H", dest, src);
 | |
|                     break;
 | |
| 
 | |
|                 default:
 | |
|                     goto nomove;
 | |
|             }
 | |
|         }
 | |
|         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);
 | |
| 
 | |
|     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;
 | |
| }
 | |
| 
 | |
| 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 : */
 | |
| 
 |