From: David Given Date: Sun, 2 Sep 2018 16:57:25 +0000 (+0200) Subject: The MIPS backend is still full of holes, and cut-and-pasted PowerPC code, but X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=1d6ecddcf48991949a064e7cdfad8175f42fca71;p=ack.git The MIPS backend is still full of holes, and cut-and-pasted PowerPC code, but is beginning to look like an actual code generator. --- diff --git a/mach/mips/as/instructions.dat b/mach/mips/as/instructions.dat index af5209e5b..1f7aae7f8 100644 --- a/mach/mips/as/instructions.dat +++ b/mach/mips/as/instructions.dat @@ -7,6 +7,12 @@ # only. It's based on the MIPS32 Instruction Set v5.04 manual (available from # https://www.mips.com/products/architectures/mips32-2/). +# Useful pseudoops. + +0000000000000000100000 "move" RD=gpr ',' RS=gpr + +# Core ALU instructions. + 00000000000100000 "add" RD=gpr ',' RS=gpr ',' RT=gpr 001000 "addi" RT=gpr ',' RT=gpr ',' IMM=e16 001001 "addiu" RT=gpr ',' RT=gpr ',' IMM=e16 diff --git a/mach/mips/as/mach3.c b/mach/mips/as/mach3.c index d6da5e016..0de4b37be 100644 --- a/mach/mips/as/mach3.c +++ b/mach/mips/as/mach3.c @@ -1,83 +1,78 @@ -/* - * $Source$ - * $State$ - */ - /* Integer registers */ -0, GPR, 0, "$0", -0, GPR, 0, "$zero", -0, GPR, 1, "$1", -0, GPR, 1, "$at", -0, GPR, 2, "$2", -0, GPR, 3, "$3", -0, GPR, 4, "$4", -0, GPR, 5, "$5", -0, GPR, 6, "$6", -0, GPR, 7, "$7", -0, GPR, 8, "$8", -0, GPR, 9, "$9", -0, GPR, 10, "$10", -0, GPR, 11, "$11", -0, GPR, 12, "$12", -0, GPR, 13, "$13", -0, GPR, 14, "$14", -0, GPR, 15, "$15", -0, GPR, 16, "$16", -0, GPR, 17, "$17", -0, GPR, 18, "$18", -0, GPR, 19, "$19", -0, GPR, 20, "$20", -0, GPR, 21, "$21", -0, GPR, 22, "$22", -0, GPR, 23, "$23", -0, GPR, 24, "$24", -0, GPR, 25, "$25", -0, GPR, 26, "$26", -0, GPR, 27, "$27", -0, GPR, 28, "$28", -0, GPR, 28, "$gp", -0, GPR, 29, "$29", -0, GPR, 29, "$sp", -0, GPR, 30, "$30", -0, GPR, 30, "$fp", -0, GPR, 31, "$31", -0, GPR, 31, "$a", +0, GPR, 0, "r0", +0, GPR, 0, "zero", +0, GPR, 1, "r1", +0, GPR, 1, "at", +0, GPR, 2, "r2", +0, GPR, 3, "r3", +0, GPR, 4, "r4", +0, GPR, 5, "r5", +0, GPR, 6, "r6", +0, GPR, 7, "r7", +0, GPR, 8, "r8", +0, GPR, 9, "r9", +0, GPR, 10, "r10", +0, GPR, 11, "r11", +0, GPR, 12, "r12", +0, GPR, 13, "r13", +0, GPR, 14, "r14", +0, GPR, 15, "r15", +0, GPR, 16, "r16", +0, GPR, 17, "r17", +0, GPR, 18, "r18", +0, GPR, 19, "r19", +0, GPR, 20, "r20", +0, GPR, 21, "r21", +0, GPR, 22, "r22", +0, GPR, 23, "r23", +0, GPR, 24, "r24", +0, GPR, 25, "r25", +0, GPR, 26, "r26", +0, GPR, 27, "r27", +0, GPR, 28, "r28", +0, GPR, 28, "gp", +0, GPR, 29, "r29", +0, GPR, 29, "sp", +0, GPR, 30, "r30", +0, GPR, 30, "fp", +0, GPR, 31, "r31", +0, GPR, 31, "ra", /* Floating-point registers */ -0, FPR, 0, "$f0", -0, FPR, 1, "$f1", -0, FPR, 2, "$f2", -0, FPR, 3, "$f3", -0, FPR, 4, "$f4", -0, FPR, 5, "$f5", -0, FPR, 6, "$f6", -0, FPR, 7, "$f7", -0, FPR, 8, "$f8", -0, FPR, 9, "$f9", -0, FPR, 10, "$f10", -0, FPR, 11, "$f11", -0, FPR, 12, "$f12", -0, FPR, 13, "$f13", -0, FPR, 14, "$f14", -0, FPR, 15, "$f15", -0, FPR, 16, "$f16", -0, FPR, 17, "$f17", -0, FPR, 18, "$f18", -0, FPR, 19, "$f19", -0, FPR, 20, "$f20", -0, FPR, 21, "$f21", -0, FPR, 22, "$f22", -0, FPR, 23, "$f23", -0, FPR, 24, "$f24", -0, FPR, 25, "$f25", -0, FPR, 26, "$f26", -0, FPR, 27, "$f27", -0, FPR, 28, "$f28", -0, FPR, 29, "$f29", -0, FPR, 30, "$f30", -0, FPR, 31, "$f31", +0, FPR, 0, "f0", +0, FPR, 1, "f1", +0, FPR, 2, "f2", +0, FPR, 3, "f3", +0, FPR, 4, "f4", +0, FPR, 5, "f5", +0, FPR, 6, "f6", +0, FPR, 7, "f7", +0, FPR, 8, "f8", +0, FPR, 9, "f9", +0, FPR, 10, "f10", +0, FPR, 11, "f11", +0, FPR, 12, "f12", +0, FPR, 13, "f13", +0, FPR, 14, "f14", +0, FPR, 15, "f15", +0, FPR, 16, "f16", +0, FPR, 17, "f17", +0, FPR, 18, "f18", +0, FPR, 19, "f19", +0, FPR, 20, "f20", +0, FPR, 21, "f21", +0, FPR, 22, "f22", +0, FPR, 23, "f23", +0, FPR, 24, "f24", +0, FPR, 25, "f25", +0, FPR, 26, "f26", +0, FPR, 27, "f27", +0, FPR, 28, "f28", +0, FPR, 29, "f29", +0, FPR, 30, "f30", +0, FPR, 31, "f31", #include "tokens.y" diff --git a/mach/mips/mcg/platform.c b/mach/mips/mcg/platform.c new file mode 100644 index 000000000..23b01f13e --- /dev/null +++ b/mach/mips/mcg/platform.c @@ -0,0 +1,331 @@ +#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_float_ATTR) + hop_add_insel(hop, "swc1 %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; 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_float_ATTR) + hop_add_insel(hop, "lwc1 %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + } + + 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, "move fp, at"); + hop_add_insel(hop, "jr ra"); + + 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, "move %H, %H", dest, src); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "move %0H, %0H", dest, src); + hop_add_insel(hop, "move %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 : */ + diff --git a/mach/mips/mcg/table b/mach/mips/mcg/table new file mode 100644 index 000000000..e2553729b --- /dev/null +++ b/mach/mips/mcg/table @@ -0,0 +1,566 @@ +REGISTERS + + /* Registers are allocated top down. The odd order below is to make sure + * that cheap registers get allocated first. + * + * Attributes may have at most one of: int, float, long, double. These + * indicate that the register is used to store a value of that type. If + * your register can store more than one type, create an alias. Registers + * with none of these cannot be copied by the code generator (and so cannot + * be moved from register to register or spilt). + */ + + r4 named("r4") int volatile; + r5 named("r5") int volatile; + r6 named("r6") int volatile; + r7 named("r7") int volatile; + r8 named("r8") int volatile; + r9 named("r9") int volatile; + r10 named("r10") int volatile; + r11 named("r11") int volatile; + r12 named("r12") int volatile; + r13 named("r13") int volatile; + r14 named("r14") int volatile; + r15 named("r15") int volatile; + r24 named("r24") int volatile; + r25 named("r25") int volatile; + r2 named("r2") int volatile iret; + r3 named("r3") int volatile; + + r17 named("r16") int; + r18 named("r18") int; + r19 named("r19") int; + r20 named("r20") int; + r21 named("r21") int; + r22 named("r22") int; + r23 named("r23") int; + + r4r5 named("r4", "r5") aliases(r4, r5) long volatile; + r6r7 named("r6", "r7") aliases(r6, r7) long volatile; + r8r9 named("r8", "r9") aliases(r8, r9) long volatile; + r10r11 named("r10", "r11") aliases(r10, r11) long volatile; + r12r13 named("r12", "r13") aliases(r12, r13) long volatile; + r14r15 named("r14", "r15") aliases(r14, r15) long volatile; + r24r25 named("r24", "r25") aliases(r24, r25) long volatile; + r2r3 named("r2", "r3") aliases(r2, r3) long volatile lret; + + zero named("zero") zero int volatile; + + f0 float; + d0 double; + +DECLARATIONS + + ubyteX; /* bottom 8 bits valid, the rest undefined */ + ubyte0; /* bottom 8 bits valid, the rest 0 */ + ushortX; /* bottom 16 bits valid, the rest undefined */ + ushort0; /* bottom 16 bits valid, the rest 0 */ + + address fragment; + + + +PATTERNS + +/* Special */ + + PAIR(BLOCK.I, BLOCK.I); + + + +/* Miscellaneous special things */ + + PUSH.I(in:(int)reg) + emit "addiu sp, sp, -4" + emit "sw %in, 0(sp)" + cost 8; + + PUSH.L(in:(long)reg) + emit "addiu sp, sp, -8" + emit "sw %in.0, 0(sp)" + emit "sw %in.1, 4(sp)" + cost 12; + + out:(int)reg = POP.I + emit "lw %out, 0(sp)" + emit "addiu sp, sp, 4" + cost 8; + + out:(long)reg = POP.L + emit "lw %out.0, 4(sp)" + emit "lw %out.1, 0(sp)" + emit "addiu sp, sp, 8" + cost 12; + + SETRET.I(in:(iret)reg) + emit "! setret4" + cost 1; + + SETRET.L(in:(lret)reg) + emit "! setret8" + cost 1; + + STACKADJUST.I(delta:CONST.I) + when signed_constant(%delta, 16) + emit "addiu sp, sp, $delta" + cost 4; + + STACKADJUST.I(in:(int)reg) + emit "addu sp, sp, %in" + cost 4; + + STACKADJUST.I(NEG.I(in:(int)reg)) + emit "subu sp, sp, %in" + cost 4; + + out:(int)reg = GETFP.I + emit "move %out, fp" + cost 4; + + SETFP.I(in:(int)reg) + emit "move fp, %in" + cost 4; + + out:(int)reg = CHAINFP.I(in:(int)reg) + emit "lw %out, 0(%in)" + cost 4; + + out:(int)reg = FPTOAB.I(GETFP.I) + emit "addiu %out, fp, 8" + cost 4; + + out:(int)reg = FPTOAB.I(in:(int)reg) + emit "addiu %out, %in, 8" + cost 4; + + out:(int)reg = FPTOLB.I(in:(int)reg) + with %out == %in + cost 1; + + out:(int)reg = GETSP.I + emit "move %out, sp" + cost 4; + + SETSP.I(in:(int)reg) + emit "move sp, %in" + cost 4; + + out:(int)reg = ANY.I + cost 1; + + out:(long)reg = ANY.L + cost 1; + + + +/* Memory operations */ + + /* Stores */ + + STORE.L(addr:address, value:(long)reg) + emit "sw %value.0, 4+%addr" + emit "sw %value.1, 0+%addr" + cost 8; + + STORE.I(addr:address, value:(int)reg) + emit "sw %value, %addr" + cost 4; + + STOREH.I(addr:address, value:(int)ushortX) + emit "sh %value, %addr" + cost 4; + + STOREB.I(addr:address, value:(int)ubyteX) + emit "sb %value, %addr" + cost 4; + + /* Loads */ + + out:(int)reg = LOAD.I(addr:address) + emit "lw %out, %addr" + cost 4; + + /* We can't just load directly because %out.0 and %addr might share + * a register, resulting in %addr being corrupted before %out.1 is + * loaded. */ + out:(long)reg = LOAD.L(addr:address) + emit "lw at, 4+%addr" + emit "lw %out.1, 0+%addr" + emit "move %out.0, at" + cost 12; + + out:(int)ushort0 = LOADH.I(addr:address) + emit "lh %out, %addr" + cost 4; + + out:(int)ubyte0 = LOADB.I(addr:address) + emit "lb %out, %addr" + cost 4; + + /* ubyte intrinsics */ + + out:(int)ubyteX = in:(int)ubyte0 + with %out == %in + emit "! ubyte0 -> ubyteX" + cost 1; + + out:(int)ubyte0 = in:(int)ubyteX + emit "andiu %out, %in, 0xff ! ubyteX -> ubyte0" + cost 4; + + out:(int)reg = in:(int)ubyte0 + with %out == %in + emit "! ubyte0 -> reg" + cost 4; + + out:(int)ubyteX = in:(int)reg + with %out == %in + emit "! reg -> ubyteX" + cost 1; + + /* ushort intrinsics */ + + out:(int)ushortX = in:(int)ushort0 + with %out == %in + emit "! ushort0 -> ushortX" + cost 1; + + out:(int)ushort0 = in:(int)ushortX + emit "andiu %out, %in, 0xffff ! ushortX -> ushort0" + cost 4; + + out:(int)reg = in:(int)ushort0 + with %out == %in + emit "! ushort0 -> reg" + cost 4; + + out:(int)ushortX = in:(int)reg + with %out == %in + emit "! reg -> ushortX" + cost 1; + + + +/* Extensions and conversions */ + + out:(int)reg = EXTENDB.I(in:(int)reg) + emit "seb %out, %in" + cost 4; + + out:(int)reg = EXTENDH.I(in:(int)reg) + emit "seh %out, %in" + cost 4; + + out:(int)reg = FROMSI.I(in:(int)reg) + with %out == %in + emit "! FROMSI.I(int) -> int" + cost 1; + + out:(int)reg = FROMUI.I(in:(int)reg) + with %out == %in + emit "! FROMUI.I(int) -> int" + cost 1; + + out:(long)reg = FROMSI.L(in:(int)reg) + emit "move %out.0, %in" + emit "sra %out.1, %in, 31" + cost 8; + + out:(long)reg = FROMUI.L(in:(int)reg) + emit "mr %out.0, %in" + emit "li %out.1, 0" + cost 8; + + out:(lret)reg = FROMIPAIR.L(in1:(int)reg, in2:(int)reg) + emit "move %out.0, %in1" + emit "move %out.1, %in2" + cost 8; + + out:(int)reg = FROML0.I(in:(long)reg) + emit "move %out, %in.0" + cost 4; + + out:(int)reg = FROML1.I(in:(long)reg) + emit "move %out, %in.1" + cost 4; + + + +/* Locals */ + + out:(int)reg = in:LOCAL.I + emit "addiu %out, fp, $in" + cost 4; + + address = in:LOCAL.I + emit "$in(fp)"; + + + +/* Memory addressing modes */ + + address = ADD.I(addr:(int)reg, offset:CONST.I) + when signed_constant(%offset, 16) + emit "$offset(%addr)"; + + address = addr:(int)reg + emit "0(%addr)"; + + + +/* Branches */ + + JUMP(addr:BLOCK.I) + emit "b $addr" + emit "nop" + cost 8; + + FARJUMP(addr:LABEL.I) + with corrupted(volatile) + emit "b $addr" + emit "nop" + cost 8; + + JUMP(dest:(int)reg) + emit "jr %dest" + emit "nop" + cost 8; + + CJUMPEQ(COMPARESI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "beq %left, %right, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLT(COMPARESI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "slt at, %left, %right" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLT(COMPAREUI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "sltu at, %left, %right" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLT(COMPARESI.I(left:(int)reg, right:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%right, 0) + emit "bltz %left, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLE(COMPARESI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "sle at, %left, %right" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLE(COMPAREUI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "sleu at, %left, %right" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLE(COMPARESI.I(left:(int)reg, right:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%right, 0) + emit "blez %left, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + COMPAREUI.I(left:(int)reg, right:(int)reg); + + #define CALLLABEL(insn) \ + insn (dest:LABEL.I) \ + with corrupted(volatile) \ + emit "bal $dest" \ + emit "nop" \ + cost 8; + + CALLLABEL(CALL) + out:(iret)reg = CALLLABEL(CALL.I) + out:(lret)reg = CALLLABEL(CALL.L) + + #define CALLINDIRECT(insn) \ + insn (dest:(int)reg) \ + with corrupted(volatile) \ + emit "jalr %dest" \ + emit "nop" \ + cost 8; + + CALLINDIRECT(CALL) + out:(iret)reg = CALLINDIRECT(CALL.I) + out:(lret)reg = CALLINDIRECT(CALL.L) + + JUMP(dest:LABEL.I) + emit "b $dest" + emit "nop" + cost 8; + + + +/* Comparisons */ + + /* The COMPARE nodes return tristate integer values; -1, 0 or 1. */ + + out:(int)reg = COMPARESI.I(left:(int)reg, right:(int)reg) + emit "slt at, %left, %right" + emit "bne at, zero, 1f" + emit "li %out, -1" + emit "slt %out, %right, %left" + emit "1:" + cost 20; + + out:(int)reg = COMPAREUI.I(left:(int)reg, right:(int)reg) + emit "sltu at, %left, %right" + emit "bne at, zero, 1f" + emit "li %out, -1" + emit "sltu %out, %right, %left" + emit "1:" + cost 20; + +/* Booleans */ + + /* If 0 then 1, else 0 */ + out:(int)reg = IFEQ.I(in:(int)reg) + emit "sleu %out, %in, zero" + cost 4;; + + /* If -1 then 1, else 0 */ + out:(int)reg = IFLT.I(in:(int)reg) + emit "slt %out, %in, zero" + cost 4; + + /* If 1 or 0 then 1, else 0 */ + out:(int)reg = IFLE.I(in:(int)reg) + emit "sle %out, %in, zero" + cost 4; + + + +/* Conversions */ + +#if 0 + out:(int)reg = CIU44(in:(int)reg) + with %out == %in + emit "! ciu44" + cost 4; + + out:(int)reg = CUI44(in:(int)reg) + with %out == %in + emit "! cui44" + cost 4; +#endif + +/* ALU operations */ + + /* reg + reg */ + #define ALUR(name, instr) \ + out:(int)reg = name(left:(int)reg, right:(int)reg) \ + emit instr " %out, %left, %right" \ + cost 4; \ + + /* reg + const */ + #define ALUC(name, instr) \ + out:(int)reg = name(left:(int)reg, right:CONST.I) \ + when signed_constant(%right, 16) \ + emit instr " %out, %left, $right" \ + cost 4; \ + + /* const + reg */ + #define ALUC_reversed(name, instr) \ + out:(int)reg = name(left:CONST.I, right:(int)reg) \ + when signed_constant(%left, 16) \ + emit instr " %out, %right, $left" \ + cost 4; \ + + /* reg + const AND const + reg */ + #define ALUCC(name, instr) \ + ALUC(name, instr) \ + ALUC_reversed(name, instr) + + ALUR(ADD.I, "addu") + ALUCC(ADD.I, "addiu") + + out:(int)reg = SUB.I(left:(int)reg, right:(int)reg) + emit "subu %out, %right, %left" + cost 4; + + out:(int)reg = SUB.I(left:(int)reg, right:CONST.I) + emit "addiu %out, %left, -[$right]" + cost 4; + + out:(int)reg = MOD.I(left:(int)reg, right:(int)reg) + emit "div %left, %right" + emit "mfhi %out" + cost 8; + + out:(int)reg = MODU.I(left:(int)reg, right:(int)reg) + emit "divu %left, %right" + emit "mfhi %out" + cost 8; + + ALUR(MUL.I, "mul") + + ALUR(DIV.I, "divw") + ALUR(DIVU.I, "divwu") + + ALUR(ASL.I, "sll") + ALUC(ASL.I, "sllv") + ALUR(ASR.I, "sra") + ALUC(ASR.I, "srav") + + ALUR(LSL.I, "sll") + ALUC(LSL.I, "sllv") + ALUR(LSR.I, "srl") + ALUC(LSR.I, "srlv") + + out:(int)reg = NEG.I(left:(int)reg) + emit "neg %out, %left" + cost 4; + + out:(int)reg = NOT.I(in:(int)reg) + emit "nor %out, %in, %in" + cost 4; + + ALUR(AND.I, "and") + ALUCC(AND.I, "andi.") + + ALUR(OR.I, "or") + ALUCC(OR.I, "ori") + + ALUR(EOR.I, "xor") + ALUCC(EOR.I, "xori") + + out:(int)reg = value:LABEL.I + emit "li32 %out, $value" + cost 4; + + out:(int)reg = value:BLOCK.I + emit "li32 %out, $value" + cost 4; + + out:(int)reg = value:CONST.I + emit "li %out, $value" + cost 4; + + out:(zero)reg = value:CONST.I + when specific_constant(%value, 0) + cost 1; + + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/mips/top/table b/mach/mips/top/table new file mode 100644 index 000000000..8f6a5d6d7 --- /dev/null +++ b/mach/mips/top/table @@ -0,0 +1,20 @@ + +/* MIPS table for ACK target optimizer */ + +MAXOP 5; +LABEL_STARTER '.'; + +%%; + +X, Y, Z { TRUE }; + +%%; + +/* Whitespace is significant here! */ + +addiu RNZ, RNZ, 0 -> ; + +b X : nop : labdef X -> labdef X ; + +%%; + diff --git a/plat/linuxmips/build-tools.lua b/plat/linuxmips/build-tools.lua index 04a385d47..92167ba63 100644 --- a/plat/linuxmips/build-tools.lua +++ b/plat/linuxmips/build-tools.lua @@ -6,23 +6,22 @@ build_as { deps = { "mach/mips/as+astables" } } ---build_mcg { --- name = "mcg", --- arch = "powerpc", ---} --- ---build_top { --- name = "top", --- arch = "powerpc", ---} +build_mcg { + name = "mcg", + arch = "mips", +} + +build_top { + name = "top", + arch = "mips", +} return installable { name = "tools", map = { ["$(PLATDEP)/linuxmips/as"] = "+as", - --["$(PLATDEP)/linuxppc/ncg"] = "+ncg", - --["$(PLATDEP)/linuxppc/mcg"] = "+mcg", - --["$(PLATDEP)/linuxppc/top"] = "+top", + ["$(PLATDEP)/linuxmips/mcg"] = "+mcg", + ["$(PLATDEP)/linuxmips/top"] = "+top", ["$(PLATIND)/descr/linuxmips"] = "./descr", "util/amisc+aelflod-pkg", "util/opt+pkg", diff --git a/plat/linuxmips/descr b/plat/linuxmips/descr index 7ddaf941b..ad7f5180f 100644 --- a/plat/linuxmips/descr +++ b/plat/linuxmips/descr @@ -20,7 +20,7 @@ var PLATFORMDIR={EM}/share/ack/{PLATFORM} var CPP_F=-D__unix var ALIGN=-a0:4 -a1:4 -a2:4 -a3:4 -b0:0x00400054 var MACHOPT_F=-m2 -var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr +#var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr # Override the setting in fe so that files compiled for linuxppc can see # the platform-specific headers. @@ -30,7 +30,7 @@ var C_INCLUDES=-I{EM}/share/ack/linux/include -I{EM}/share/ack/include/ansi name be from .m.g to .s - program {EM}/lib/ack/{PLATFORM}/ncg + program {EM}/lib/ack/{PLATFORM}/mcg mapflag -gdb GF=-gdb args {GF?} < stdout @@ -83,5 +83,5 @@ name cv to .exe program {EM}/bin/aelflod args -m20 -b < > - outfile linuxppc.exe + outfile linuxmips.exe end