The MIPS backend is still full of holes, and cut-and-pasted PowerPC code, but

is beginning to look like an actual code generator.
This commit is contained in:
David Given 2018-09-02 18:57:25 +02:00
parent a023fd8591
commit 1d6ecddcf4
7 changed files with 1007 additions and 90 deletions

View file

@ -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.
000000<RS->00000<RD->00000100000 "move" RD=gpr ',' RS=gpr
# Core ALU instructions.
000000<RS-><RT-><RD->00000100000 "add" RD=gpr ',' RS=gpr ',' RT=gpr
001000<RS-><RT-><IMM-----------> "addi" RT=gpr ',' RT=gpr ',' IMM=e16
001001<RS-><RT-><IMM-----------> "addiu" RT=gpr ',' RT=gpr ',' IMM=e16

View file

@ -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"

331
mach/mips/mcg/platform.c Normal file
View file

@ -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; 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, "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; i<saved_regs.count; i++)
{
struct hreg* hreg = saved_regs.item[i];
if (hreg->attrs & 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; i<saved_regs.count; i++)
{
struct hreg* hreg = saved_regs.item[i];
if (hreg->attrs & 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 : */

566
mach/mips/mcg/table Normal file
View file

@ -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 : */

20
mach/mips/top/table Normal file
View file

@ -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 ;
%%;

View file

@ -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",

View file

@ -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