Merge pull request #131 from davidgiven/dtrg-mips

Add an mcg-based MIPS code generator.
This commit is contained in:
David Given 2018-09-20 23:05:55 +01:00 committed by GitHub
commit 8fd3e1f5ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
101 changed files with 5450 additions and 781 deletions

3
README
View file

@ -33,6 +33,7 @@ pc86 produces bootable floppy disk images for 8086 PCs
linux386 produces ELF executables for PC Linux systems
linux68k produces ELF executables for m68020 Linux systems
linuxppc produces ELF executables for PowerPC Linux systems
linuxmips produces ELF executables for little-endian MIPS32r2 Linux systems
cpm produces i80 CP/M .COM files
rpi produces Raspberry Pi GPU binaries
pdpv7 produces PDP/11 V7 Unix binaries
@ -194,4 +195,4 @@ Please enjoy.
David Given (davidgiven on Github)
dg@cowlark.com
2016-11-26
2018-09-18

View file

@ -10,9 +10,9 @@ vars.plats = {
"linux386",
"linux68k",
"linuxppc",
"linuxmips",
"osx386",
"osxppc",
-- --"qemuppc",
"pc86",
"rpi",
"pdpv7",
@ -22,7 +22,7 @@ vars.plats_with_tests = {
"linux68k",
"linux386",
"linuxppc",
-- --"qemuppc",
"linuxmips",
"pc86",
}

View file

@ -5,7 +5,7 @@
/* $Id$ */
/*
/*
#define CODE_GENERATOR for code generator
#define CODE_EXPANDER for code expander
@ -20,9 +20,9 @@
Unfortunately, the IEEE standard does not define the byte-order.
depends on the #defines
FL_MSL_AT_LOW_ADDRESS 1 if most significant long is at low address
FL_MSW_AT_LOW_ADDRESS 1 if most significant word is at low address
FL_MSB_AT_LOW_ADDRESS 1 if most significant byte is at low address
FL_MSL_AT_LOW_ADDRESS 1 if most significant long is at low address
FL_MSW_AT_LOW_ADDRESS 1 if most significant word is at low address
FL_MSB_AT_LOW_ADDRESS 1 if most significant byte is at low address
*/
#ifdef IEEEFLOAT
#define USE_FLT
@ -37,47 +37,57 @@
#define FL_MSB_AT_LOW_ADDRESS 0
#endif
#define I0 ((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
#define I1 ((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
#define I2 ((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
#define I3 ((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
#define I4 ((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
#define I5 ((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
#define I6 ((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
#define I7 ((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
#define I0 \
((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
#define I1 \
((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
#define I2 \
((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
#define I3 \
((FL_MSL_AT_LOW_ADDRESS ? 0 : 4) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
#define I4 \
((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
#define I5 \
((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 0 : 2) \
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
#define I6 \
((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
+ (FL_MSB_AT_LOW_ADDRESS ? 0 : 1))
#define I7 \
((FL_MSL_AT_LOW_ADDRESS ? 4 : 0) + (FL_MSW_AT_LOW_ADDRESS ? 2 : 0) \
+ (FL_MSB_AT_LOW_ADDRESS ? 1 : 0))
#ifndef USE_FLT
static int
float_cst(str, sz, buf)
char *str, *buf;
int sz;
static int float_cst(str, sz, buf) char *str, *buf;
int sz;
{
int i;
char *p;
char* p;
float fl;
double f;
double atof();
if (sz!= 4 && sz!= 8) {
if (sz != 4 && sz != 8)
{
return 1;
}
f = atof(str);
if (sz == 4) {
if (sz == 4)
{
fl = f;
p = (char *) &fl;
p = (char*)&fl;
}
else {
p = (char *) &f;
else
{
p = (char*)&f;
}
for (i = sz; i; i--) {
for (i = sz; i; i--)
{
*buf++ = *p++;
}
return 0;
@ -87,89 +97,105 @@ float_cst(str, sz, buf)
#include <ctype.h>
#include <flt_arith.h>
int
float_cst(str, sz, buf)
char *str, *buf;
int sz;
int float_cst(str, sz, buf) char *str, *buf;
int sz;
{
int overflow = 0;
flt_arith e;
if (sz!= 4 && sz!= 8) {
if (sz != 4 && sz != 8)
{
return 1;
}
flt_str2flt(str, &e);
#ifdef IEEEFLOAT
if (sz == 4) {
if (sz == 4)
{
#endif
#ifdef PDPFLOAT
e.flt_exp += 129;
#else
e.flt_exp += 127;
e.flt_exp += 127;
#endif
if (e.flt_mantissa.flt_h_32 == 0) e.flt_exp = 0;
if (e.flt_mantissa.flt_h_32 == 0)
e.flt_exp = 0;
#ifdef IEEEFLOAT
if (e.flt_mantissa.flt_h_32 & 0x80) {
if (e.flt_mantissa.flt_h_32 & 0x80)
{
/* rounding */
if ((e.flt_mantissa.flt_h_32 & 0xffffff00) == 0xffffff00) {
if ((e.flt_mantissa.flt_h_32 & 0xffffff00) == 0xffffff00)
{
e.flt_exp++;
e.flt_mantissa.flt_h_32 = 0x80000000;
}
else {
else
{
e.flt_mantissa.flt_h_32 += 0x80;
}
}
if (e.flt_exp >= 255) {
if (e.flt_exp >= 255)
{
overflow = 1;
e.flt_exp = 255;
e.flt_mantissa.flt_h_32 = e.flt_mantissa.flt_l_32 = 0;
}
if (e.flt_exp <= 0) {
if (e.flt_exp <= 0)
{
flt_b64_sft(&(e.flt_mantissa), 1);
if (e.flt_exp < 0) {
if (e.flt_exp < 0)
{
flt_b64_sft(&(e.flt_mantissa), -e.flt_exp);
e.flt_exp = 0;
}
}
#endif
#ifndef IEEEFLOAT
if (sz == 4 && (e.flt_mantissa.flt_h_32 & 0x80)) {
if (sz == 4 && (e.flt_mantissa.flt_h_32 & 0x80))
{
/* rounding */
if ((e.flt_mantissa.flt_h_32 & 0xffffff00) == 0xffffff00) {
if ((e.flt_mantissa.flt_h_32 & 0xffffff00) == 0xffffff00)
{
e.flt_exp++;
e.flt_mantissa.flt_h_32 = 0x80000000;
}
else {
else
{
e.flt_mantissa.flt_h_32 += 0x80;
}
}
if (sz == 8 && (e.flt_mantissa.flt_l_32 & 0x80)) {
if (sz == 8 && (e.flt_mantissa.flt_l_32 & 0x80))
{
/* rounding */
if ((e.flt_mantissa.flt_l_32 & 0xffffff00) == 0xffffff00) {
if ((e.flt_mantissa.flt_l_32 & 0xffffff00) == 0xffffff00)
{
e.flt_mantissa.flt_l_32 = 0;
if (e.flt_mantissa.flt_h_32 == 0xffffffff) {
if (e.flt_mantissa.flt_h_32 == 0xffffffff)
{
e.flt_exp++;
e.flt_mantissa.flt_h_32 = 0x80000000;
}
else e.flt_mantissa.flt_h_32++;
else
e.flt_mantissa.flt_h_32++;
}
else {
else
{
e.flt_mantissa.flt_l_32 += 0x80;
}
}
if (e.flt_exp > 255) {
if (e.flt_exp > 255)
{
overflow = 1;
e.flt_exp = 255;
e.flt_mantissa.flt_h_32 = e.flt_mantissa.flt_l_32 = 0xffffffff;
}
#endif
buf[I0] = (e.flt_sign << 7) | (e.flt_exp >> 1);
buf[I1] = ((e.flt_exp&1) << 7) |
((e.flt_mantissa.flt_h_32 & 0x7fffffff) >> 24);
buf[I1] = ((e.flt_exp & 1) << 7) | ((e.flt_mantissa.flt_h_32 & 0x7fffffff) >> 24);
buf[I2] = e.flt_mantissa.flt_h_32 >> 16;
buf[I3] = e.flt_mantissa.flt_h_32 >> 8;
#ifndef IEEEFLOAT
if (sz == 8) {
if (sz == 8)
{
buf[I4] = e.flt_mantissa.flt_h_32;
buf[I5] = e.flt_mantissa.flt_l_32 >> 24;
buf[I6] = e.flt_mantissa.flt_l_32 >> 16;
@ -181,37 +207,47 @@ float_cst(str, sz, buf)
flt_b64_sft(&(e.flt_mantissa), -24);
#ifdef IEEEFLOAT
}
else {
else
{
e.flt_exp += 1023;
if (e.flt_mantissa.flt_h_32 == 0) e.flt_exp = 0;
if (e.flt_mantissa.flt_l_32 & 0x400) {
if (e.flt_mantissa.flt_h_32 == 0)
e.flt_exp = 0;
if (e.flt_mantissa.flt_l_32 & 0x400)
{
/* rounding */
if ((e.flt_mantissa.flt_l_32 & 0xfffff800) == 0xfffff800) {
if ((e.flt_mantissa.flt_l_32 & 0xfffff800) == 0xfffff800)
{
e.flt_mantissa.flt_l_32 = 0;
if (e.flt_mantissa.flt_h_32 == 0xffffffff) {
if (e.flt_mantissa.flt_h_32 == 0xffffffff)
{
e.flt_exp++;
e.flt_mantissa.flt_h_32 = 0x80000000;
}
else e.flt_mantissa.flt_h_32++;
else
e.flt_mantissa.flt_h_32++;
}
else {
else
{
e.flt_mantissa.flt_l_32 += 0x400;
}
}
if (e.flt_exp >= 2047) {
if (e.flt_exp >= 2047)
{
overflow = 1;
e.flt_exp = 2047;
e.flt_mantissa.flt_h_32 = e.flt_mantissa.flt_l_32 = 0;
}
if (e.flt_exp <= 0) {
if (e.flt_exp <= 0)
{
flt_b64_sft(&(e.flt_mantissa), 1);
if (e.flt_exp < 0) {
if (e.flt_exp < 0)
{
flt_b64_sft(&(e.flt_mantissa), -e.flt_exp);
e.flt_exp = 0;
}
}
buf[I0] = (e.flt_sign << 7) | (e.flt_exp >> 4);
buf[I1] = ((e.flt_exp & 017)<< 4) | ((e.flt_mantissa.flt_h_32 >> 27) & 017);
buf[I1] = ((e.flt_exp & 017) << 4) | ((e.flt_mantissa.flt_h_32 >> 27) & 017);
buf[I2] = e.flt_mantissa.flt_h_32 >> 19;
buf[I3] = e.flt_mantissa.flt_h_32 >> 11;
buf[I4] = e.flt_mantissa.flt_h_32 >> 3;
@ -221,15 +257,17 @@ float_cst(str, sz, buf)
flt_b64_sft(&(e.flt_mantissa), -53);
}
#endif
#if ! FL_MSL_AT_LOW_ADDRESS
if (sz == 4) {
#if !FL_MSL_AT_LOW_ADDRESS
if (sz == 4)
{
buf[I4] = buf[I0];
buf[I5] = buf[I1];
buf[I6] = buf[I2];
buf[I7] = buf[I3];
}
#endif
if (overflow) {
if (overflow)
{
return 2;
}
return 0;
@ -237,22 +275,25 @@ float_cst(str, sz, buf)
#endif /* USE_FLT */
#ifdef CODE_GENERATOR
con_float()
void con_float(void)
{
char buf[8];
int rval = float_cst(str, (int)argval, buf);
int i;
if (rval == 1) {
fprintf(stderr,"float constant size = %d\n",(int)argval);
if (rval == 1)
{
fprintf(stderr, "float constant size = %d\n", (int)argval);
fatal("bad fcon size");
}
fprintf(codefile,"!float %s sz %d\n", str, (int)argval);
if (rval == 2) {
fprintf(codefile, "!float %s sz %d\n", str, (int)argval);
if (rval == 2)
{
fprintf(stderr, "Warning: overflow in floating point constant %s\n", str);
}
fprintf(codefile, ".data1 0%o", buf[0] & 0377);
for (i = 1; i < (int)argval; i++) {
for (i = 1; i < (int)argval; i++)
{
fprintf(codefile, ",0%o", buf[i] & 0377);
}
putc('\n', codefile);
@ -260,19 +301,19 @@ con_float()
#endif /* CODE_GENERATOR */
#ifdef CODE_EXPANDER
con_float(str, argval)
char *str;
arith argval;
void con_float(const char* str, arith argval)
{
char buf[8];
int rval = float_cst(str, (int)argval, buf);
int i;
if (rval == 1) {
if (rval == 1)
{
argval = 8;
rval = float_cst(str, 8, buf);
}
for (i = 0; i < (int)argval; i++) {
for (i = 0; i < (int)argval; i++)
{
gen1(buf[i]);
}
}

View file

@ -67,7 +67,10 @@ struct outname {
#define RELO4 3 /* 4 bytes */
#define RELOPPC 4 /* PowerPC 26-bit address */
#define RELOPPC_LIS 5 /* PowerPC lis */
#define RELOVC4 6 /* VideoCore IV address in 32-bit instruction */
#define RELOVC4 6 /* VideoCore IV address in 32-bit instruction */
#define RELOMIPS 7 /* MIPS */
#define RELO2HI 8 /* high 2 bytes of word */
#define RELO2HISAD 9 /* high 2 bytes of word, sign adjusted */
#define RELPC 0x2000 /* pc relative */
#define RELBR 0x4000 /* High order byte lowest address. */

View file

@ -199,19 +199,26 @@ int lab;
genreturns()
{
int count;
int nr;
nr= genlabel();
C_df_dnam("returns");
C_rom_ilb((label) nr);
C_rom_cst((arith)1);
C_rom_cst((arith) (gosubcnt-1));
C_rom_cst((arith) (gosubcnt-2));
count = 0;
while ( gosubhead)
{
C_rom_ilb((label) gosubhead->emlabel);
gosubhead= gosubhead->nextlist;
count++;
}
if (count != (gosubcnt-1))
error("gosub count table mismatch");
C_df_ilb((label) nr);
C_loc((arith) 1);
C_cal("error");

6
mach/mips/as/build.lua Normal file
View file

@ -0,0 +1,6 @@
normalrule {
name = "astables",
outleaves = {"definitions.y", "tokens.y", "rules.y"},
ins = {"./mktables.lua", "./instructions.dat"},
commands = {"$(LUA) %{ins[1]} %{outs} < %{ins[2]}"}
}

View file

@ -0,0 +1,275 @@
# Syntax:
# <thing---->: a field occupying so many bits.
# T: a field occupying one bit.
# Undefined bits end up as 0.
#
# This is intended to be compatible with MIPS release 5, integer instructions
# only. It's based on the MIPS32 Instruction Set v5.04 manual (available from
# https://www.mips.com/products/architectures/mips32-2/).
# Useful pseudoops.
# or RD, RS, zero
000000<RS->00000<RD->00000100101 "mov" RD=gpr ',' RS=gpr
# Condition code tokens; these have to be defined here because .f overlaps with
# a format code.
%token .f
%token .un
%token .eq
%token .ueq
%token .olt
%token .ult
%token .ole
%token .ule
%token .sf
%token .ngle
%token .seq
%token .ngl
%token .lt
%token .nge
%token .le
%token .ngt
# Core ALU instructions.
000000<RS-><RT-><RD->00000100000 "add" RD=gpr ',' RS=gpr ',' RT=gpr
001000<RS-><RT-><IMM-----------> "addi" RT=gpr ',' RS=gpr ',' IMM=e16
001001<RS-><RT-><IMM-----------> "addiu" RT=gpr ',' RS=gpr ',' IMM=e16
000000<RS-><RT-><RD->00000100001 "addu" RD=gpr ',' RS=gpr ',' RT=gpr
000000<RS-><RT-><RD->00000100100 "and" RD=gpr ',' RS=gpr ',' RT=gpr
001100<RS-><RT-><IMM-----------> "andi" RT=gpr ',' RS=gpr ',' IMM=e16
0001000000000000<OFF-----------> "b" OFF=offset16
0000010000010001<OFF-----------> "bal" OFF=offset16
000100<RS-><RT-><OFF-----------> "beq" RS=gpr ',' RT=gpr ',' OFF=offset16
010100<RS-><RT-><OFF-----------> "beql" RS=gpr ',' RT=gpr ',' OFF=offset16
000001<RS->00001<OFF-----------> "bgez" RS=gpr ',' OFF=offset16
000001<RS->10001<OFF-----------> "bgezal" RS=gpr ',' OFF=offset16
000001<RS->10011<OFF-----------> "bgezall" RS=gpr ',' OFF=offset16
000001<RS->00011<OFF-----------> "bgezl" RS=gpr ',' OFF=offset16
000111<RS->00000<OFF-----------> "bgtz" RS=gpr ',' OFF=offset16
010111<RS->00000<OFF-----------> "bgtzl" RS=gpr ',' OFF=offset16
000110<RS->00000<OFF-----------> "blez" RS=gpr ',' OFF=offset16
010110<RS->00000<OFF-----------> "blezl" RS=gpr ',' OFF=offset16
000001<RS->00000<OFF-----------> "bltz" RS=gpr ',' OFF=offset16
000001<RS->10000<OFF-----------> "bltzal" RS=gpr ',' OFF=offset16
000001<RS->10010<OFF-----------> "bltzall" RS=gpr ',' OFF=offset16
000001<RS->00010<OFF-----------> "bltzl" RS=gpr ',' OFF=offset16
000101<RS-><RT-><OFF-----------> "bne" RS=gpr ',' RT=gpr ',' OFF=offset16
010101<RS-><RT-><OFF-----------> "bnel" RS=gpr ',' RT=gpr ',' OFF=offset16
101111<RS-><OP-><OFF-----------> "cache" OP=u5 ',' OFF=e16 '(' RS=gpr ')'
011111<RS-><OP-><OFF---->0011011 "cachee" OP=u5 ',' OFF=e9 '(' RS=gpr ')'
011100<RS-><RT-><RD->00000100001 "clo" RD=RT=gpr ',' RS=gpr
011100<RS-><RT-><RD->00000100000 "clz" RD=RT=gpr ',' RS=gpr
01000010000000000000000000011111 "deret"
01000001011<RT->0110000000000000 "di" RT=gpr
01000001011000000110000000000000 "di"
000000<RS-><RT->0000000000011010 "div" RS=gpr ',' RT=gpr
000000<RS-><RT->0000000000011011 "divu" RS=gpr ',' RT=gpr
00000000000000000000000011000000 "ehb"
01000001011<RT->0110000000100000 "ei" RT=gpr
01000001011000000110000000100000 "ei"
011111<RS-><RT-><MSBLSB-->000000 "ext" RT=gpr ',' RS=gpr ',' extmsblsb
011111<RS-><RT-><MSBLSB-->000100 "ins" RT=gpr ',' RS=gpr ',' insmsblsb
000010<ABS---------------------> "j" ABS=abs26
000011<ABS---------------------> "jal" ABS=abs26
000000<RS->00000<RD->00000001001 "jalr" RD=gpr ',' RS=gpr
000000<RS->000001111100000001001 "jalr" RS=gpr
000000<RS->00000<RD->10000001001 "jalr.hb" RD=gpr ',' RS=gpr
000000<RS->000001111110000001001 "jalr.hb" RS=gpr
011101<ABS---------------------> "jalx" ABS=abs26
000000<RS->000000000000000001000 "jr" RS=gpr
000000<RS->000000000010000001000 "jr.hb" RS=gpr
100000<RS-><RT-><IMM-----------> "lb" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0101100 "lbe" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
100100<RS-><RT-><IMM-----------> "lbu" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0101000 "lbue" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
100001<RS-><RT-><IMM-----------> "lh" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0101101 "lhe" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
100101<RS-><RT-><IMM-----------> "lhu" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0101001 "lhue" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
110000<RS-><RT-><IMM-----------> "ll" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0101110 "lle" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
00111100000<RT-><IMM-----------> "lui" RT=gpr ',' IMM=e16
100011<RS-><RT-><IMM-----------> "lw" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0101111 "lwe" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
100010<RS-><RT-><IMM-----------> "lwl" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0011001 "lwle" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
100110<RS-><RT-><IMM-----------> "lwr" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0011010 "lwre" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
011100<RS-><RT->0000000000000000 "madd" RS=gpr ',' RT=gpr
011100<RS-><RT->0000000000000001 "maddu" RS=gpr ',' RT=gpr
0000000000000000<RD->00000010000 "mfhi" RD=gpr
0000000000000000<RD->00000010010 "mflo" RD=gpr
000000<RS-><RT-><RD->00000001011 "movn" RD=gpr ',' RS=gpr ',' RT=gpr
000000<RS-><RT-><RD->00000001010 "movz" RD=gpr ',' RS=gpr ',' RT=gpr
011100<RS-><RT->0000000000000100 "msub" RS=gpr ',' RT=gpr
011100<RS-><RT->0000000000000101 "msubu" RS=gpr ',' RT=gpr
000000<RS->000000000000000010001 "mthi" RS=gpr
000000<RS->000000000000000010011 "mtlo" RS=gpr
011100<RS-><RT-><RD->00000000010 "mul" RD=gpr ',' RS=gpr ',' RT=gpr
000000<RS-><RT->0000000000011000 "mult" RS=gpr ',' RT=gpr
000000<RS-><RT->0000000000000001 "multu" RS=gpr ',' RT=gpr
00000000000000000000000000000000 "nop"
000000<RS-><RT-><RD->00000100111 "nor" RD=gpr ',' RS=gpr ',' RT=gpr
000000<RS-><RT-><RD->00000100101 "or" RD=gpr ',' RS=gpr ',' RT=gpr
001101<RS-><RT-><IMM-----------> "ori" RT=gpr ',' RS=gpr ',' IMM=e16
00000000000000000000000101000000 "pause"
110011<RS-><H--><IMM-----------> "pref" H=u5 ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><H--><IMM---->0100011 "prefe" H=u5 ',' IMM=e9 '(' RS=gpr ')'
010011<RS-><RT-><H-->00000001111 "prefx" H=u5 ',' RT=gpr '(' RS=gpr ')'
01111100000<RT-><RD->00000111011 "rdhwr" RT=gpr ',' RD=gpr
01000001010<RT-><RD->00000000000 "rdpgpr" RD=gpr ',' RT=gpr
00000000001<RT-><RD-><SA->000010 "rotr" RD=gpr ',' RT=gpr ',' SA=u5
000000<RS-><RT-><RD->00001000110 "rotrv" RD=gpr ',' RT=gpr ',' RS=gpr
101000<RS-><RT-><IMM-----------> "sb" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0011100 "sbe" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
111000<RS-><RT-><IMM-----------> "sc" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0011110 "sce" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
011100<CODE-------------->111111 "sdbbp" CODE=u20
01111100000<RT-><RD->10000100000 "seb" RD=gpr ',' RT=gpr
01111100000<RT-><RD->11000100000 "seh" RD=gpr ',' RT=gpr
101001<RS-><RT-><IMM-----------> "sh" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0011101 "she" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
00000000000<RT-><RD-><SA->000000 "sll" RD=gpr ',' RT=gpr ',' SA=u5
000000<RS-><RT-><RD->00000000100 "sllv" RD=gpr ',' RT=gpr ',' RS=gpr
000000<RS-><RT-><RD->00000101010 "slt" RD=gpr ',' RS=gpr ',' RT=gpr
001010<RS-><RT-><IMM-----------> "slti" RT=gpr ',' RS=gpr ',' IMM=e16
001011<RS-><RT-><IMM-----------> "sltiu" RT=gpr ',' RS=gpr ',' IMM=e16
000000<RS-><RT-><RD->00000101011 "sltu" RD=gpr ',' RS=gpr ',' RT=gpr
00000000000<RT-><RD-><SA->000011 "sra" RD=gpr ',' RT=gpr ',' SA=u5
000000<RS-><RT-><RD->00000000111 "srav" RD=gpr ',' RT=gpr ',' RS=gpr
00000000000<RT-><RD-><SA->000010 "srl" RD=gpr ',' RT=gpr ',' SA=u5
000000<RS-><RT-><RD->00000000110 "srlv" RD=gpr ',' RT=gpr ',' RS=gpr
00000000000000000000000001000000 "ssnop"
000000<RS-><RT-><RD->00000100010 "sub" RD=gpr ',' RS=gpr ',' RT=gpr
000000<RS-><RT-><RD->00000100011 "subu" RD=gpr ',' RS=gpr ',' RT=gpr
101011<RS-><RT-><IMM-----------> "sw" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0011111 "swe" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
101010<RS-><RT-><IMM-----------> "swl" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0010001 "swle" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
101110<RS-><RT-><IMM-----------> "swr" RT=gpr ',' IMM=e16 '(' RS=gpr ')'
011111<RS-><RT-><IMM---->0100010 "swre" RT=gpr ',' IMM=e9 '(' RS=gpr ')'
000001<RS->11111<IMM-----------> "synci" IMM=e16 '(' RS=gpr ')'
000000<CODE-------------->001100 "syscall" CODE=u20
000000<RS-><RT->0000000000110100 "teq" RS=gpr ',' RT=gpr
000001<RS->01100<IMM-----------> "teqi" RS=gpr ',' IMM=e16
000000<RS-><RT->0000000000110000 "tge" RS=gpr ',' RT=gpr
000001<RS->01000<IMM-----------> "tgei" RS=gpr ',' IMM=e16
000001<RS->01001<IMM-----------> "tgeiu" RS=gpr ',' IMM=e16
000000<RS-><RT->0000000000110001 "tgeu" RS=gpr ',' RT=gpr
01000010000000000000000000000011 "tlbinv"
01000010000000000000000000000100 "tlbinvf"
01000010000000000000000000001000 "tlbp"
01000010000000000000000000000001 "tlbr"
01000010000000000000000000000010 "tlbwi"
01000010000000000000000000000110 "tlbwr"
000000<RS-><RT->0000000000110010 "tlt" RS=gpr ',' RT=gpr
000001<RS->01010<IMM-----------> "tlti" RS=gpr ',' IMM=e16
000001<RS->01011<IMM-----------> "tltiu" RS=gpr ',' IMM=e16
000000<RS-><RT->0000000000110011 "tltu" RS=gpr ',' RT=gpr
000000<RS-><RT->0000000000110110 "tne" RS=gpr ',' RT=gpr
000001<RS->01110<IMM-----------> "tnei" RS=gpr ',' IMM=e16
01000010000000000000000000100000 "wait"
01000001110<RT-><RD->00000000000 "wrpgpr" RD=gpr ',' RT=gpr
01111100000<RT-><RD->00010100000 "wsbh" RD=gpr ',' RT=gpr
000000<RS-><RT-><RD->00000100110 "xor" RD=gpr ',' RS=gpr ',' RT=gpr
001110<RS-><RT-><IMM-----------> "xori" RT=gpr ',' RS=gpr ',' IMM=e16
# FPU instructions.
010001<F-->00000<FS-><FD->000101 "abs" F=fmt FD=fpr ',' FS=fpr
010001<F--><FT-><FS-><FD->000000 "add" F=fmt FD=fpr ',' FS=fpr ',' FT=fpr
010011<RS-><FT-><FS-><FD->011110 "alnv" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr ',' RS=gpr
010001<F--><FT-><FS-><C>0011<CO> "c" CO=fcond F=fmt C=u3 ',' FS=fpr ',' FT=fpr
010001<F-->00000<FS-><FD->001010 "ceil" ".l" F=fmt FD=fpr ',' FS=fpr
010001<F-->00000<FS-><FD->001110 "ceil" ".w" F=fmt FD=fpr ',' FS=fpr
01000100010<RT-><FS->00000000000 "cfc1" RT=gpr ',' FS=fpr
01000100110<RT-><FS->00000000000 "ctc1" RT=gpr ',' FS=fpr
010001<F-->00000<FS-><FD->100001 "cvt" ".d" F=fmt FD=fpr ',' FS=fpr
010001<F-->00000<FS-><FD->100101 "cvt" ".l" F=fmt FD=fpr ',' FS=fpr
01000110000<FT-><FS-><FD->100110 "cvt" ".ps" ".s" FD=fpr ',' FS=fpr ',' FT=fpr
010001<F-->00000<FS-><FD->100000 "cvt" ".s" F=fmt FD=fpr ',' FS=fpr
0100011011000000<FS-><FD->101000 "cvt" ".s" ".pl" FS=fpr ',' FD=fpr
0100011011000000<FS-><FD->100000 "cvt" ".s" ".pu" FS=fpr ',' FD=fpr
010001<F-->00000<FS-><FD->100100 "cvt" ".w" F=fmt FD=fpr ',' FS=fpr
010001<F--><FT-><FS-><FD->000011 "div" F=fmt FD=fpr ',' FS=fpr ',' FT=fpr
010001<F-->00000<FS-><FD->001011 "floor" ".l" F=fmt FD=fpr ',' FS=fpr
010001<F-->00000<FS-><FD->001111 "floor" ".w" F=fmt FD=fpr ',' FS=fpr
110101<RS-><FT-><IMM-----------> "ldc1" FT=fpr ',' IMM=e16 '(' RS=gpr ')'
010011<RS-><RT->00000<FD->000001 "ldxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')'
010011<RS-><RT->00000<FD->000101 "luxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')'
110001<RS-><FT-><IMM-----------> "lwc1" FT=fpr ',' IMM=e16 '(' RS=gpr ')'
010011<RS-><RT->00000<FD->000000 "lwxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')'
010011<FR-><FT-><FS-><FD->100<F> "madd" F=fmt3 FD=fpr ',' FR=fpr ',' FS=fpr ',' FT=fpr
01000100000<RT-><FS->00000000000 "mfc1" RT=gpr ',' FS=fpr
01000100011<RT-><FS->00000000000 "mfhc1" RT=gpr ',' FS=fpr
010001<F-->00000<FS-><FD->000110 "mov" F=fmt FD=fpr ',' FS=fpr
000000<RS-><C>00<RD->00000000001 "movf" RD=gpr ',' RS=gpr ',' C=u3
010001<F--><C>00<FS-><FD->010001 "movf" F=fmt FD=fpr ',' FS=fpr ',' C=u3
010001<F--><RT-><FS-><FD->010011 "movn" F=fmt FD=fpr ',' FS=fpr ',' RT=gpr
000000<RS-><C>01<RD->00000000001 "movt" RD=gpr ',' RS=gpr ',' C=u3
010001<F--><C>01<FS-><FD->010001 "movt" F=fmt FD=fpr ',' FS=fpr ',' C=u3
010001<F--><RT-><FS-><FD->010010 "movz" F=fmt FD=fpr ',' FS=fpr ',' RT=gpr
010011<FR-><FT-><FS-><FD->101<F> "msub" F=fmt3 FD=fpr ',' FR=fpr ',' FS=fpr ',' FT=fpr
01000100100<RT-><FS->00000000000 "mtc1" RT=gpr ',' FS=fpr
01000100111<RT-><FS->00000000000 "mthc1" RT=gpr ',' FS=fpr
010001<F--><FT-><FS-><FD->000010 "mul" F=fmt FD=fpr ',' FS=fpr ',' FT=fpr
010001<F-->00000<FS-><FD->000111 "neg" F=fmt FD=fpr ',' FS=fpr
010011<FR-><FT-><FS-><FD->110<F> "nmadd" F=fmt3 FD=fpr ',' FR=fpr ',' FS=fpr ',' FT=fpr
010011<FR-><FT-><FS-><FD->111<F> "nmsub" F=fmt3 FD=fpr ',' FR=fpr ',' FS=fpr ',' FT=fpr
01000110110<FT-><FS-><FD->101100 "pll" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr
01000110110<FT-><FS-><FD->101101 "plu" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr
01000110110<FT-><FS-><FD->101110 "pul" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr
01000110110<FT-><FS-><FD->101111 "puu" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr
010001<F-->00000<FS-><FD->010101 "recip." F=fmt FD=fpr ',' FS=fpr
010001<F-->00000<FS-><FD->001000 "round" ".l" F=fmt FD=fpr ',' FS=fpr
010001<F-->00000<FS-><FD->001100 "round" ".w" F=fmt FD=fpr ',' FS=fpr
010001<F-->00000<FS-><FD->010110 "rsqrt" F=fmt FD=fpr ',' FS=fpr
111101<RS-><FT-><IMM-----------> "sdc1" FT=fpr ',' IMM=e16 '(' RS=gpr ')'
010011<RS-><RT->00000<FD->001001 "sdxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')'
010001<F-->00000<FS-><FD->000100 "sqrt" F=fmt FD=fpr ',' FS=fpr
010001<F--><FT-><FS-><FD->000001 "sub" F=fmt FD=fpr ',' FS=fpr ',' FT=fpr
010011<RS-><RT->00000<FD->001101 "suxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')'
111001<RS-><FT-><IMM-----------> "swc1" FT=fpr ',' IMM=e16 '(' RS=gpr ')'
010011<RS-><RT->00000<FD->001000 "swxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')'
010001<F-->00000<FS-><FD->001001 "trunc" ".l" F=fmt FD=fpr ',' FS=fpr
010001<F-->00000<FS-><FD->001101 "trunc" ".w" F=fmt FD=fpr ',' FS=fpr
# Generic coprocessor instructions.
01000101000<C>00<OFF-----------> "bc1f" C=u3 ',' OFF=offset16
0100010100000000<OFF-----------> "bc1f" OFF=offset16
01000101000<C>10<OFF-----------> "bc1fl" C=u3 ',' OFF=offset16
0100010100000010<OFF-----------> "bc1fl" OFF=offset16
01000101000<C>01<OFF-----------> "bc1t" C=u3 ',' OFF=offset16
0100010100000001<OFF-----------> "bc1t" OFF=offset16
01000101000<C>11<OFF-----------> "bc1tl" C=u3 ',' OFF=offset16
0100010100000011<OFF-----------> "bc1tl" OFF=offset16
01001001000<C>00<OFF-----------> "bc2f" C=u3 ',' OFF=offset16
0100100100000000<OFF-----------> "bc2f" OFF=offset16
01001001000<C>10<OFF-----------> "bc2fl" C=u3 ',' OFF=offset16
0100100100000010<OFF-----------> "bc2fl" OFF=offset16
01001001000<C>01<OFF-----------> "bc2t" C=u3 ',' OFF=offset16
0100100100000001<OFF-----------> "bc2t" OFF=offset16
01001001000<C>11<OFF-----------> "bc2tl" C=u3 ',' OFF=offset16
0100100100000011<OFF-----------> "bc2tl" OFF=offset16
01001000010<RT-><IMM-----------> "cfc2" RT=gpr ',' IMM=u16
01001000110<RT-><IMM-----------> "ctc2" RT=gpr ',' IMM=u16
0100101<FUN--------------------> "cop2" FUN=u25
110110<RS-><RT-><IMM-----------> "ldc2" RT=u5 ',' IMM=e16 '(' RS=gpr ')'
110010<RS-><RT-><IMM-----------> "lwc2" RT=u5 ',' IMM=e16 '(' RS=gpr ')'
01000000000<RT-><RD->00000000<S> "mfc0" RT=gpr ',' RD=u5 ',' S=u3
01001000000<RT-><IMM-----------> "mfc2" RT=gpr ',' IMM=u16
01000000010<RT-><RD->00000000<S> "mfhc0" RT=gpr ',' RD=u5 ',' S=u3
01001000011<RT-><IMM-----------> "mfhc2" RT=gpr ',' IMM=u16
01000000100<RT-><RD->00000000<S> "mtc0" RT=gpr ',' RD=u5 ',' S=u3
01001000100<RT-><IMM-----------> "mtc2" RT=gpr ',' IMM=u16
01000000110<RT-><RD->00000000<S> "mthc0" RT=gpr ',' RD=u5 ',' S=u3
01001000111<RT-><IMM-----------> "mthc2" RT=gpr ',' IMM=u16
111110<RS-><RT-><IMM-----------> "sdc2" RT=u5 ',' IMM=e16 '(' RS=gpr ')'
111010<RS-><RT-><IMM-----------> "swc2" RT=u5 ',' IMM=e16 '(' RS=gpr ')'

29
mach/mips/as/mach0.c Normal file
View file

@ -0,0 +1,29 @@
/*
* $Source$
* $State$
*/
#define THREE_PASS /* branch and offset optimization */
#define LISTING /* enable listing facilities */
#define RELOCATION /* generate relocatable code */
#define DEBUG 0
#undef valu_t
#define valu_t int32_t
#undef ADDR_T
#define ADDR_T uint32_t
#undef word_t
#define word_t uint32_t
#undef ALIGNWORD
#define ALIGNWORD 4
#undef ALIGNSECT
#define ALIGNSECT 4
#undef VALWIDTH
#define VALWIDTH 8
#define FIXUPFLAGS 0

3
mach/mips/as/mach1.c Normal file
View file

@ -0,0 +1,3 @@
/*
* Do not #include anything here. Do it in mach/proto/as/comm0.h
*/

23
mach/mips/as/mach2.c Normal file
View file

@ -0,0 +1,23 @@
%token <y_word> GPR
%token <y_word> FPR
%token <y_word> FCOND
%token <y_word> OP_LI
%token <y_word> HI16
%token <y_word> HA16
%token <y_word> LO16
%type <y_word> gpr fpr
%type <y_word> e16 e9
%type <y_word> u25 u20 u16 u5 u3
%type <y_word> abs26 offset16
%type <y_word> fmt fmt3
%type <y_word> fcond
%type <y_word> extmsblsb insmsblsb
%type <y_valu> extabsexp
#include "definitions.y"

83
mach/mips/as/mach3.c Normal file
View file

@ -0,0 +1,83 @@
/* Integer registers */
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, OP_LI, 0, "li",
0, HI16, 0, "hi16",
0, HA16, 0, "ha16",
0, LO16, 0, "lo16",
#include "tokens.y"

184
mach/mips/as/mach4.c Normal file
View file

@ -0,0 +1,184 @@
#include "rules.y"
| OP_LI GPR ',' extabsexp
{
word_t reg = $2;
uint32_t val = $4;
if (((int32_t)val >= -0x8000) && ((int32_t)val <= 0x7fff))
emit4(0x24000000 | (reg<<16) | (val & 0xffff)); /* addiu reg, zero, value */
else if (val <= 0xffff)
emit4(0x34000000 | (reg<<16) | val); /* ori reg, zero, value */
else
{
emit4(0x3c000000 | (reg<<16) | (val>>16)); /* lui reg, value */
emit4(0x34000000 | (reg<<16) | (reg<<21) | (val & 0xffff)); /* ori reg, reg, value */
}
}
extabsexp
: absexp
| LO16 ASC_LPAR expr ASC_RPAR
{
newrelo($3.typ, RELO2 | FIXUPFLAGS);
$$ = $3.val;
}
| HI16 ASC_LPAR expr ASC_RPAR
{
newrelo($3.typ, RELO2HI | FIXUPFLAGS);
if ($3.val & 0xffff0000)
fatal("relocation offset in hi16[] too big");
$$ = $3.val;
}
| HA16 ASC_LPAR expr ASC_RPAR
{
newrelo($3.typ, RELO2HISAD | FIXUPFLAGS);
if ($3.val & 0xffff0000)
fatal("relocation offset in ha16[] too big");
$$ = $3.val;
}
;
gpr: GPR
fpr: FPR
fmt3
: OP__DOT_S { $$ = 0; }
| OP__DOT_D { $$ = 1; }
| OP__DOT_W { $$ = 4; }
| OP__DOT_L { $$ = 5; }
| OP__DOT_PS { $$ = 6; }
;
fmt
: fmt3 { $$ = $1 + 16; }
;
fcond
: OP__DOT_F { $$ = 0; }
| OP__DOT_UN { $$ = 1; }
| OP__DOT_EQ { $$ = 2; }
| OP__DOT_UEQ { $$ = 3; }
| OP__DOT_OLT { $$ = 4; }
| OP__DOT_ULT { $$ = 5; }
| OP__DOT_OLE { $$ = 6; }
| OP__DOT_ULE { $$ = 7; }
| OP__DOT_SF { $$ = 8; }
| OP__DOT_NGLE { $$ = 9; }
| OP__DOT_SEQ { $$ = 10; }
| OP__DOT_NGL { $$ = 11; }
| OP__DOT_LT { $$ = 12; }
| OP__DOT_NGE { $$ = 13; }
| OP__DOT_LE { $$ = 14; }
| OP__DOT_NGT { $$ = 15; }
;
e16
: extabsexp
{
/* Allow signed or unsigned 16-bit values. */
if (($1 < -0x8000) || ($1 > 0xffff))
serror("16-bit signed value out of range");
$$ = (uint16_t) $1;
}
;
e9
: absexp
{
/* Allow signed or unsigned 9-bit values. */
if (($1 < -0x100) || ($1 > 0x1ff))
serror("9-bit signed value out of range");
$$ = (uint16_t) $1;
}
;
u25
: absexp
{
if (($1 < 0) || ($1 > 0x1ffffff))
serror("25-bit unsigned value out of range");
$$ = $1;
}
;
u20
: absexp
{
if (($1 < 0) || ($1 > 0xfffff))
serror("20-bit unsigned value out of range");
$$ = $1;
}
;
u16
: extabsexp
{
if (($1 < 0) || ($1 > 0xffff))
serror("16-bit unsigned value out of range");
$$ = $1;
}
;
u5
: absexp
{
if (($1 < 0) || ($1 > 0x1f))
serror("5-bit unsigned value out of range");
$$ = $1;
}
;
u3
: absexp
{
if (($1 < 0) || ($1 > 0x7))
serror("3-bit unsigned value out of range");
$$ = $1;
}
;
offset16
: expr
{
int dist = $1.val - DOTVAL - 4;
fit(fitx(dist, 18));
if (dist & 0x3)
serror("jump targets must be 4-aligned");
newrelo($1.typ, RELOMIPS | RELPC | FIXUPFLAGS);
$$ = (dist >> 2) & 0x0000ffff;
}
;
abs26
: expr
{
int target = $1.val;
fit(fitx(target, 28));
if (target & 0x3)
serror("jump targets must be 4-aligned");
newrelo($1.typ, RELOMIPS | FIXUPFLAGS);
$$ = (target >> 2) & 0x03ffffff;
}
;
extmsblsb
: u5 ',' u5
{
int pos = $1;
int size = $3;
$$ = ((size-1) << 5) | pos;
}
;
insmsblsb
: u5 ',' u5
{
int pos = $1;
int size = $3;
$$ = ((pos+size-1) << 5) | pos;
}
;

0
mach/mips/as/mach5.c Normal file
View file

192
mach/mips/as/mktables.lua Executable file
View file

@ -0,0 +1,192 @@
local args = {...}
local words = {}
local insns = {}
local function addword(word)
local w = words[word]
if not w then
w = word:upper()
w = w:gsub("%.", "_DOT_")
if not w:match("^[A-Z0-9_]*$") then
error(word.." is not a valid token")
end
words[word] = w
end
return w
end
local function parsesyntax(line)
local syntax = {}
for word in line:gmatch("%S+") do
local _, _, s = word:find('^"(.*)"$')
if s then
syntax[#syntax+1] = {word=addword(s) }
else
_, _, s = word:find("^('.*')$")
if s then
syntax[#syntax+1] = {punct=s }
else
local token = {}
for equate in word:gmatch("([^=]+)=") do
token[#token+1] = equate
end
_, _, token.token = word:find("([^=]*)$")
syntax[#syntax+1] = token
if not token.token then
error("can't parse "..word)
end
end
end
end
return syntax
end
local function parsefields(line)
local _, _, bits = line:find("^([^ ]+) ")
if #bits ~= 32 then
error("'"..bits.."' isn't 32 bits long")
end
local fields = {}
local i = 1
while i ~= 33 do
local c = line:sub(i, i)
if c ~= "." then
local f = { pos=i }
if c:find("%w") then
f.size = 1
f.value = c
elseif c == "<" then
local _, newi, name = line:find("^<%-*(%w+)%-*>", i)
f.size = 1 + newi - i
f.value = name
i = newi
else
error("bad field char '"..c.."' in '"..line.."'")
end
if f.value:find("[0-9]+") then
f.literal = true
f.variable = false
else
f.literal = false
f.variable = true
end
-- Convert from PowerPC numbering to sane numbering
f.pos = 33-(f.pos + f.size)
fields[#fields+1] = f
if f.value then
fields[f.value] = f
end
end
i = i + 1
end
local value = 0
for _, f in ipairs(fields) do
if f.literal then
local s = math.pow(2, f.pos)
value = value + f.value*s
end
end
fields.value = value
return fields
end
local function emit(fields, code)
local mask = 0
local value = 0
for _, f in ipairs(fields) do
if f.literal then
local s = math.pow(2, f.pos)
local m = math.pow(2, f.size) - 1
mask = mask + m*s
value = value + f.value*s
end
end
print(string.format("if ((value & 0x%x) == 0x%x) {", mask, value))
for _, f in ipairs(fields) do
if f.variable then
local m = math.pow(2, f.size) - 1
print(string.format("uint32_t %s = (value >> %d) & 0x%x;", f.value, f.pos, m))
end
end
print(code)
print("return;")
print("}")
end
while true do
local line = io.stdin:read("*l")
if not line then
break
end
line = line:gsub("#.*$", "")
line = line:gsub(" *$", "")
if line:find("^%%token ") then
addword(line:sub(8))
elseif line ~= "" then
local fields = parsefields(line)
local syntax = parsesyntax(line:sub(34, #line))
insns[#insns+1] = {
fields=parsefields(line),
syntax=parsesyntax(line:sub(34, #line))
}
end
end
local definitionsfp = io.open(args[1], "w")
for word, value in pairs(words) do
definitionsfp:write("%token <y_word> OP_", tostring(value), " /* ", word, " */\n")
end
definitionsfp:close()
local tokensfp = io.open(args[2], "w")
for word, value in pairs(words) do
tokensfp:write("0, OP_", value, ", 0, \"", word, "\",\n")
end
tokensfp:close()
local rulesfp = io.open(args[3], "w")
rulesfp:write("operation\n")
for index, insn in ipairs(insns) do
if index == 1 then
rulesfp:write("\t:")
else
rulesfp:write("\t|")
end
for _, word in ipairs(insn.syntax) do
if word.word then
rulesfp:write(" OP_", word.word)
end
if word.punct then
rulesfp:write(" ", word.punct)
end
if word.token then
rulesfp:write(" ", word.token)
end
end
rulesfp:write("\n")
rulesfp:write("\t{ emit4(", string.format("0x%08x", insn.fields.value))
for wordindex, word in ipairs(insn.syntax) do
if word.token then
for _, alias in ipairs(word) do
local f = insn.fields[alias]
if not f then
error("reference to field "..alias.." which doesn't exist")
end
local mask = math.pow(2, f.size) - 1
rulesfp:write(" | (($", wordindex,
" & ", string.format("0x%x", mask), ") << ", f.pos, ")")
end
end
end
rulesfp:write("); }\n")
end
rulesfp:close()

47
mach/mips/libem/aar4.s Normal file
View file

@ -0,0 +1,47 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* Get address of element of bounds-checked array.
*
* Stack: ( array-adr index descriptor-adr -- element-adr )
* Sets r2 = size of element for .los4, .sts4
* Preserves r25 (the last volatile register)
*
* An array descriptor is:
*
* +0 lower bound
* +4 range (upper bound - lower bound); *inclusive*
* +8 element size
*/
.sect .text
.define .aar4
.aar4:
lw r4, 0(sp) ! r4 = address of descriptor
lw r5, 4(sp) ! r5 = index
lw r6, 8(sp) ! r6 = address of array
lw r7, 0(r4) ! r7 = lower bound
slt at, r5, r7 ! at = index < lower bound
bne at, zero, .trap_earray
nop
subu r5, r5, r7 ! adjust index for non-zero lower bound
lw at, 4(r4) ! at = range
slt at, at, r5 ! at = range < adjusted index
bne at, zero, .trap_earray
nop
lw r2, 8(r4) ! r2 = size of element
mul r5, r5, r2 ! scale index by size
addu r5, r5, r6 ! calculate address of element
sw r5, 8(sp) ! push address of element
addiu sp, sp, 8
jr ra
nop
.define .trap_earray
.trap_earray:
li r4, 0 ! EARRAY = 0 in h/em_abs.h
b .trp

30
mach/mips/libem/and.s Normal file
View file

@ -0,0 +1,30 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/*
* Set intersection.
* Stack: ( a b size -- a&b )
*/
.sect .text
.define .and
.and:
lw r4, 0(sp) ! r4 = size
addiu sp, sp, 4 ! sp points at b
addu r5, sp, r4 ! r5 points at a
srl r4, r4, 2 ! r4 = count of words
1:
lw at, 0(r5) ! load a
lw r6, 0(sp) ! load b
and at, at, r6 ! combine
sw at, 0(r5) ! write back to a
addiu r5, r5, 4
addiu sp, sp, 4
addiu r4, r4, -1
bne r4, zero, 1b
nop
jr ra
nop

31
mach/mips/libem/bls4.s Normal file
View file

@ -0,0 +1,31 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* Does a block move of words between non-overlapping buffers.
* Stack: ( src dst len -- )
*/
.sect .text
.define .bls4
.bls4:
lw r4, 0(sp) ! r4=len
lw r5, 4(sp) ! r5=dst
lw r6, 8(sp) ! r6=src
addiu sp, sp, 12
srl r4, r4, 2 ! convert len to words
1:
beq r4, zero, 2f
nop
lw at, 0(r6)
sw at, 0(r5)
addiu r6, r6, 4
addiu r5, r5, 4
addiu r4, r4, -1
b 1b
nop
2:
jr ra
nop

17
mach/mips/libem/build.lua Normal file
View file

@ -0,0 +1,17 @@
for _, plat in ipairs(vars.plats) do
acklibrary {
name = "headers_"..plat,
}
acklibrary {
name = "lib_"..plat,
srcs = {
"./*.s", -- dus4.s
},
vars = { plat = plat },
deps = {
"h+emheaders",
"+headers_"..plat,
}
}
end

36
mach/mips/libem/c_ud_i.s Normal file
View file

@ -0,0 +1,36 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
.sect .text
.define .c_ud_i
.c_ud_i:
/* Input: f0
* Output: r2
* Only at and f30/f31 may be used.
*/
lui at, ha16[.fd_80000000]
ldc1 f30, lo16[.fd_80000000] (at)
c.le.d 0, f30, f0
bc1t toobig
nop
trunc.w.d f0, f0
mfc1 r2, f0
jr ra
nop
toobig:
sub.d f0, f0, f30
trunc.w.d f0, f0
mfc1 r2, f0
lui at, 0x8000 ! load 0x80000000
addu r2, r2, at
jr ra
nop
.sect .rom
.define .fd_80000000
.fd_80000000:
.dataf8 2147483648.0

38
mach/mips/libem/c_uf_i.s Normal file
View file

@ -0,0 +1,38 @@
#
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
.define .c_uf_i
.c_uf_i:
/* Input: f0
* Output: r2
* Only at and f30/f31 may be used.
*/
lui at, ha16[.ff_80000000]
lwc1 f30, lo16[.ff_80000000] (at)
c.le.s 0, f30, f0
bc1t toobig
nop
trunc.w.s f0, f0
mfc1 r2, f0
jr ra
nop
toobig:
sub.s f0, f0, f30
trunc.w.s f0, f0
mfc1 r2, f0
lui at, 0x8000 ! load 0x80000000
addu r2, r2, at
jr ra
nop
.sect .rom
.ff_80000000:
.dataf4 2147483648.0

25
mach/mips/libem/c_ui_d.s Normal file
View file

@ -0,0 +1,25 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
.sect .text
.define .c_ui_d
.c_ui_d:
/* Input: r2
* Output: f0
* Only at and f30/f31 may be used.
*/
mtc1 r2, f0
cvt.d.w f0, f0
bgez r2, nonnegative
nop
lui at, ha16[.fd_100000000]
ldc1 f30, lo16[.fd_100000000] (at)
add.d f0, f0, f30
nonnegative:
jr ra
nop
.sect .rom
.fd_100000000:
.dataf8 4294967296.0

26
mach/mips/libem/c_ui_f.s Normal file
View file

@ -0,0 +1,26 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
.sect .text
.define .c_ui_f
.c_ui_f:
/* Input: r2
* Output: f0
* Only at and f30/f31 may be used.
*/
mtc1 r2, f0
cvt.s.w f0, f0
bgez r2, nonnegative
nop
lui at, ha16[.fs_100000000]
ldc1 f30, lo16[.fs_100000000] (at)
add.d f0, f0, f30
nonnegative:
jr ra
nop
/* 4294967296 as a float. */
.sect .rom
.fs_100000000:
.dataf4 4294967296.0

35
mach/mips/libem/cms.s Normal file
View file

@ -0,0 +1,35 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/*
* Set comparison Returns 0 if the sets were equal.
* Stack: ( a b size -- a!=b )
*/
.sect .text
.define .cms
.cms:
lw r4, 0(sp) ! r4 = size; sp points at b-word
addu r5, sp, r4 ! r5 points at a-word
addu r6, r5, r4 ! r6 is final sp-word
srl r4, r4, 2 ! r4 = count of words
li r8, 1 ! result
1:
lw at, 4(r5) ! load a
lw r7, 4(sp) ! load b
bne at, r7, exit ! branch if not equal
nop
addiu r5, r5, 4
addiu sp, sp, 4
addiu r4, r4, -1
bne r4, zero, 1b
nop
li r8, 0 ! Update result.
exit:
mov sp, r6
sw r8, 0(sp)
jr ra
nop

28
mach/mips/libem/com.s Normal file
View file

@ -0,0 +1,28 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/*
* Set complement.
* Stack: ( a size -- ~a )
*/
.sect .text
.define .com
.com:
lw r4, 0(sp) ! r4 = size
addiu sp, sp, 4
mov r5, sp ! r5 points to set
srl r4, r4, 2 ! r4 = word count
1:
lw at, 0(r5)
nor at, zero, at
sw at, 0(r5)
addiu r5, r5, 4
addiu r4, r4, -1
bne r4, zero, 1b
nop
jr ra
nop

View file

@ -0,0 +1,39 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/*
* 64-big unsigned tristate comparison.
* Inputs:
* r2r3: left
* r4r5: right
* Outputs;
* r2: result
*/
.sect .text
.define .compareul
.compareul:
/* Compare high words. */
sltu at, r3, r5 ! if r3<r5, then 1
subu at, zero, at ! if r3<r5, then -1
bne at, zero, exit
nop
sltu at, r5, r3 ! if r3>r5, then 1
bne at, zero, exit
nop
/* High words are equal --- compare low words. */
sltu at, r2, r4 ! if r2<r4, then 1
subu at, zero, at ! if r2<r4, then -1
bne at, zero, exit
nop
sltu at, r4, r2 ! if r2>r4, then 1
exit:
mov r2, at
jr ra
nop

42
mach/mips/libem/csa.s Normal file
View file

@ -0,0 +1,42 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* This is not a subroutine, but just a
* piece of code that computes the jump-
* address and jumps to it.
* traps if resulting address is zero
*
* Stack: ( value tableaddr -- )
*/
.sect .text
.define .csa
.csa:
lw r4, 0(sp) /* r4 = table */
lw r5, 4(sp) /* r5 = value */
addiu sp, sp, 8
lw r6, 0(r4) /* r6 = default target */
lw r7, 4(r4) /* r7 = lower bound */
subu r5, r5, r7 /* adjust value */
bltz r5, 1f /* jump to default if out of range */
nop
lw r7, 8(r4) /* fetch range */
subu r7, r7, r5 /* compute difference within range */
bltz r7, 1f /* jump to default if out of range */
nop
addiu r4, r4, 12 /* skip header */
sll r5, r5, 2 /* value = value<<2 */
addu r4, r4, r5 /* find address of target */
lw r6, 0(r4) /* r6 = new target */
1:
beq r6, zero, 2f /* trap if null */
nop
jr r6 /* otherwise jump */
nop
2:
j .trap_ecase
nop

47
mach/mips/libem/csb.s Normal file
View file

@ -0,0 +1,47 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* this is not a subroutine, but just a
* piece of code that computes the jump-
* address and jumps to it.
* traps if resulting address is zero
*
* Stack: ( value tableaddr -- )
*/
.sect .text
.define .csb
.csb:
lw r4, 0(sp) ! r4 = address of table
lw r5, 4(sp) ! r5 = value
addiu sp, sp, 8
lw r6, 0(r4) ! r6 = default target
lw r7, 4(r4) ! r7 = table count
2:
addiu r7, r7, -1 ! decrement count
bltz r7, 1f ! exit loop if out
nop
lw r8, 8(r4) ! candidate value
beq r8, r5, 3f ! branch if equal
nop
addiu r4, r4, 8 ! next entry
b 2b
nop
3:
/* We found an item in the table. */
lw r6, 12(r4) ! load jump target
/* fall through */
1:
beq r6, zero, 4f /* trap if null */
nop
jr r6 /* otherwise jump */
nop
4:
j .trap_ecase
nop

28
mach/mips/libem/dus4.s Normal file
View file

@ -0,0 +1,28 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* Duplicates some words on top of stack.
* Stack: ( a size -- a a )
*/
.sect .text
.define .dus4
.dus4:
lw r4, 0(sp) ! r4 = size
addiu sp, sp, 4 ! sp = pointer to a
mov r5, sp ! r5 = pointer to a
subu sp, sp, r4 ! sp = pointer to newa
mov r6, sp ! r6 = pointer to b
srl r4, r4, 2 ! r4 = number of words
1:
lw at, 0(r5)
sw at, 0(r6)
addiu r5, r5, 4
addiu r6, r6, 4
addiu r4, r4, -1
bne r4, zero, 1b
nop
jr ra
nop

31
mach/mips/libem/exg.s Normal file
View file

@ -0,0 +1,31 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* Exchange top two values on stack.
* Stack: ( a b size -- b a )
*/
.sect .text
.define .exg
.exg:
lw r4, 0(sp) ! r4 = size
srl r5, r4, 2 ! r5 = number of words
addiu sp, sp, 4 ! adjust stack for input/output parameter size
mov r6, sp ! r6 = pointer to b
addu r7, r6, r4 ! r7 = pointer to a
! Loop to swap each pair of words.
1:
lw r8, 0(r6)
lw r9, 0(r7)
sw r9, 0(r6)
sw r8, 0(r7)
addiu r6, r6, 4
addiu r7, r7, 4
addiu r5, r5, -1
bne r5, zero, 1b
nop
jr ra
nop

56
mach/mips/libem/fef8.s Normal file
View file

@ -0,0 +1,56 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* Split a double-precision float into fraction and exponent, like
* frexp(3) in C, http://en.cppreference.com/w/c/numeric/math/frexp
*
* Stack: ( double -- fraction exponent )
*/
#define DBL_EXPBITS 11
#define DBL_FRACHBITS 20
#define DBL_FRACLBITS 32
#define DBL_FRACBITS 52
#define DBL_EXP_INFNAN 2047
#define DBL_EXP_BIAS 1023
.sect .text
.define .fef8
.fef8:
lw r4, 0(sp) ! r4 = low word (bits 0..31)
lw r5, 4(sp) ! r5 = high word (bits 32..63)
! IEEE double = sign * 1.fraction * 2**(exponent - 1023)
! sign exponent fraction
! 31 30..19 18..0, 31..0
!
! IEEE exponent = 1022 in [0.5, 1) or (-1, -0.5].
ext r7, r5, DBL_FRACHBITS, DBL_EXPBITS ! r7 = IEEE exponent
beq r7, zero, zeroexp ! this number is zero or denormalised, treat specially
nop
li at, DBL_EXP_INFNAN
beq r7, at, return ! just return if infinity or NaN
nop
addiu r7, r7, -[DBL_EXP_BIAS-1] ! undo exponent bias
li at, DBL_EXP_BIAS-1
ins r5, at, DBL_FRACHBITS, DBL_EXPBITS ! replace exponent
return:
addiu sp, sp, -4 ! returning one more quad than we got
sw r5, 8(sp)
sw r6, 4(sp)
sw r7, 0(sp)
jr ra
nop
/* We received a denormalised number or zero. */
zeroexp:
/* TODO: we just assume that the number is zero here. */
mov r5, zero
mov r6, zero
mov r7, zero
b return
nop

69
mach/mips/libem/fif8.s Normal file
View file

@ -0,0 +1,69 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* Multiplies two double-precision floats, then splits the product into
* fraction and integer, both as floats, like modf(3) in C,
* http://en.cppreference.com/w/c/numeric/math/modf
*
* Stack: ( a b -- fraction integer )
*/
.sect .text
.define .fif8
.fif8:
ldc1 f0, 8(sp) ! f0 = a
ldc1 f2, 0(sp) ! f2 = b
mul.d f0, f0, f2 ! f0 = a * b
abs.d f2, f0 ! f2 = abs(f0)
lui at, ha16[max_power_of_two]
ldc1 f4, lo16[max_power_of_two] (at) ! f4 = max power of two
mov.d f6, f2 ! we're going to assemble the integer part in f6
c.lt.d 0, f4, f2 ! if absolute value too big, it must be integral
bc1t 0, return
nop
! Crudely strip off the fractional part.
add.d f6, f2, f4 ! f6 = absolute value + max power of two
sub.d f6, f6, f4 ! f6 -= max_power_of_two
! The above might round, so correct that.
lui at, ha16[one]
ldc1 f8, lo16[one] (at) ! f8 = 1.0
1:
c.le.d 0, f6, f2 ! if result <= absolute value, stop
bc1t 0, 2f
nop
sub.d f6, f6, f8 ! result -= 1.0
b 1b
nop
2:
! Correct the sign of the result.
mtc1 zero, f8
mthc1 zero, f8 ! f8 = 0.0
c.lt.d 0, f0, f8 ! if original value was negative
bc1f 0, 1f
nop
neg.d f6, f6 ! negate the result
1:
return:
sdc1 f6, 0(sp) ! store integer part
sub.d f6, f0, f6 ! calculate fractional part
sdc1 f6, 8(sp) ! store fractional part
jr ra
nop
! doubles >= MAXPOWTWO are already integers
.sect .rom
max_power_of_two:
.dataf8 4.503599627370496000E+15
one:
.dataf8 1.0

32
mach/mips/libem/inn.s Normal file
View file

@ -0,0 +1,32 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* Tests a bit in a bitset on the stack.
*
* Stack: ( bitset bitnum setsize -- bool )
*
* Some back ends push false if bitnum is too large. We don't because
* the compilers tend to pass a small enough bitnum.
*/
.sect .text
.define .inn
.inn:
lw r4, 0(sp) ! r4 = size of set (bytes)
lw r5, 4(sp) ! r5 = bit number
addiu sp, sp, 4 ! sp now points to word below bitset
andi r6, r5, ~31 ! r6 = bit offset of base of word in set
srl r6, r6, 3 ! r6 = byte offset of base of word in set
addu r6, sp, r6 ! r6 = address of word in set
lw r6, 4(r6) ! r6 = word (remember stack offset)
andi r7, r5, 31 ! r7 = bit number within word
srlv r6, r6, r7 ! r7 = candidate bit now at bit 0
andi r6, r6, 1 ! r7 = bool
addu sp, sp, r4 ! retract over bitfield (remember stack offset)
sw r6, 0(sp) ! store result
jr ra
nop

30
mach/mips/libem/ior.s Normal file
View file

@ -0,0 +1,30 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/*
* Set union.
* Stack: ( a b size -- a|b )
*/
.sect .text
.define .ior
.ior:
lw r4, 0(sp) ! r4 = size
addiu sp, sp, 4 ! sp points at b
addu r5, sp, r4 ! r5 points at a
srl r4, r4, 2 ! r4 = count of words
1:
lw at, 0(r5) ! load a
lw r6, 0(sp) ! load b
or at, at, r6 ! combine
sw at, 0(r5) ! write back to a
addiu r5, r5, 4
addiu sp, sp, 4
addiu r4, r4, -1
bne r4, zero, 1b
nop
jr ra
nop

23
mach/mips/libem/lar4.s Normal file
View file

@ -0,0 +1,23 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* Load from bounds-checked array.
*
* Stack: ( array-adr index descriptor-adr -- element )
*/
.sect .text
.define .lar4
.lar4:
mov r25, ra
jal .aar4
nop
/* pass r2 = size from .aar4 to .los4 */
jal .los4
nop
jr r25
nop

55
mach/mips/libem/los4.s Normal file
View file

@ -0,0 +1,55 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* Loads a variable-sized block onto the stack.
*
* On entry: r2 = size
* Stack: ( address -- block )
* Preserves r25 for .lar4 and .sar4
*/
.sect .text
.define .los4
.los4:
lw r4, 0(sp) ! r4 = address of source block
! Sizes 1 and 2 are handled specially.
li at, 1
beq r2, at, byte_sized
nop
li at, 2
beq r2, at, word_sized
nop
! Else the size must be a multiple of 4.
srl r5, r2, 2 ! r5 = number of words
addiu sp, sp, 4 ! retract over address
subu sp, sp, r2 ! allocate space for destination block
mov r6, sp ! r6 = start of destination block
1:
lw at, 0(r4)
sw at, 0(r6)
addiu r4, r4, 4
addiu r6, r6, 4
addiu r5, r5, -1
bne r5, zero, 1b
nop
jr ra
nop
byte_sized:
lbu at, 0(r4)
sw at, 0(sp)
jr ra
nop
word_sized:
lhu at, 0(r4)
sw at, 0(sp)
jr ra
nop

35
mach/mips/libem/rck.s Normal file
View file

@ -0,0 +1,35 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* Bounds check. Traps if the value is out of range.
* Stack: ( value descriptor -- value )
*
* This ".rck" only works with 4-byte integers. The name is ".rck" and
* not ".rck4" because many back ends only do rck with the word size.
*/
.sect .text
.define .rck
.rck:
lw r4, 0(sp) ! r4 = pointer to descriptor
addiu sp, sp, 4 ! leave value on stack
lw r5, 0(sp) ! r5 = value
lw at, 0(r4) ! at = lower bound
slt at, r5, at ! at = r5 < at
bne at, zero, .trap_erange
nop
lw at, 4(r4) ! at = upper bound
slt at, at, r5 ! at = at < r5
bne at, zero, .trap_erange
nop
jr ra
nop
.define .trap_erange
.trap_erange:
li r4, 1
j .trp
nop

24
mach/mips/libem/sar4.s Normal file
View file

@ -0,0 +1,24 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* Store to bounds-checked array.
*
* Stack: ( element array-adr index descriptor-adr -- )
*/
.sect .text
.define .sar4
.sar4:
mov r25, ra
jal .aar4
nop
/* pass r2 = size from .aar4 to .sts4 */
jal .sts4
nop
jr r25
nop

39
mach/mips/libem/set.s Normal file
View file

@ -0,0 +1,39 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/*
* Create singleton set.
* Stack: ( bitnumber size -- set )
*/
.sect .text
.define .set
.set:
lw r4, 0(sp) ! r4 = size
lw r5, 4(sp) ! r5 = bit number
addiu sp, sp, 8
srl r4, r4, 2 ! r4 = word count
! Create an empty set by pushing zeros.
1:
addiu sp, sp, -4
sw zero, 0(sp)
addiu r4, r4, -1
bne r4, zero, 1b
nop
! sp now points at the set.
andi r6, r5, ~31 ! r6 = bit offset of base of word in set
srl r6,r6, 3 ! r6 = byte offset of word in set
addu r6, sp, r6 ! r6 = address of word in set
andi r7, r5, 31 ! r7 = bit number within word
li r8, 1
sllv r8, r8, r7 ! r8 = word with 1 set
sw r8, 0(r6) ! write to set
jr ra
nop

57
mach/mips/libem/sts4.s Normal file
View file

@ -0,0 +1,57 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/* Stores a variable-sized block from the stack.
*
* On entry: r2 = size
* Stack: ( block address -- )
* Preserves r25 for .lar4 and .sar4
*/
.sect .text
.define .sts4
.sts4:
lw r4, 0(sp) ! r4 = address
addiu sp, sp, 4 ! sp = pointer to block
! Sizes 1 and 2 are handled specially.
li at, 1
beq r2, at, byte_sized
nop
li at, 2
beq r2, at, word_sized
nop
! Else the size must be a multiple of 4.
srl r5, r2, 2 ! r5 = number of words
! Copy.
1:
lw at, 0(sp)
sw at, 0(r4)
addiu sp, sp, 4
addiu r4, r4, 4
addiu r5, r5, -1
bne r5, zero, 1b
nop
jr ra
nop
byte_sized:
lw at, 0(sp)
sb at, 0(r4)
addiu sp, sp, 4
jr ra
nop
word_sized:
lw at, 0(sp)
sh at, 0(r4)
addiu sp, sp, 4
jr ra
nop

65
mach/mips/libem/trp.s Normal file
View file

@ -0,0 +1,65 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
.sect .text
.define .trap_ecase
.trap_ecase:
li r4, 20 ! ECASE = 20 in h/em_abs.h
! FALLTHROUGH to .trp
! Raises an EM trap.
! Expects r4 = trap number.
.define .trp
.trp:
andi at, r4, 0xfff0
bne at, zero, 1f ! traps > 15 can't be ignored
nop
lui at, ha16[.ignmask]
lw r5, lo16[.ignmask] (at) ! load ignore mask
srlv r5, r5, r4
andi r5, r5, 1
bne r5, zero, return ! return if ignoring trap
nop
1:
lui at, ha16[.trppc]
lw r5, lo16[.trppc] (at) ! r5 = user trap routine
sw zero, lo16[.trppc] (at) ! reset the trap routine for next time
beq r5, zero, abend ! abort if no user trap routine
nop
addiu sp, sp, -8
sw r4, 0(sp) ! push trap number
sw ra, 4(sp) ! and link register
jalr r5 ! call trap routine
nop
lw ra, 4(sp) ! ...and return
addiu sp, sp, 8
return:
jr ra
nop
! No trap handler; write error message and exit.
abend:
addiu sp, sp, -12
li at, 2
sw at, 0(sp)
lui at, hi16[message]
ori at, at, lo16[message]
sw at, 4(sp)
li at, 6
sw at, 8(sp)
jal _write ! write(2, message, 6)
nop
li at, 1
sw at, 0(sp)
j __exit ! _exit(1)
.sect .rom
message:
.ascii "TRAP!\n"

30
mach/mips/libem/xor.s Normal file
View file

@ -0,0 +1,30 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/*
* Set xor..
* Stack: ( a b size -- a^b )
*/
.sect .text
.define .xor
.xor:
lw r4, 0(sp) ! r4 = size
addiu sp, sp, 4 ! sp points at b
addu r5, sp, r4 ! r5 points at a
srl r4, r4, 2 ! r4 = count of words
1:
lw at, 0(r5) ! load a
lw r6, 0(sp) ! load b
xor at, at, r6 ! combine
sw at, 0(r5) ! write back to a
addiu r5, r5, 4
addiu sp, sp, 4
addiu r4, r4, -1
bne r4, zero, 1b
nop
jr ra
nop

25
mach/mips/libem/zer.s Normal file
View file

@ -0,0 +1,25 @@
#
.sect .text; .sect .rom; .sect .data; .sect .bss
/*
* Create empty set.
* Stack: ( size -- set )
*/
.sect .text
.define .zer
.zer:
lw r4, 0(sp) ! r4 = size
addiu sp, sp, 4
srl r4, r4, 2 ! r4 = word count
1:
addiu sp, sp, -4
sw zero, 0(sp)
addiu r4, r4, -1
bne r4, zero, 1b
nop
jr ra
nop

View file

@ -0,0 +1,8 @@
for _, plat in ipairs(vars.plats) do
acklibrary {
name = "lib_"..plat,
srcs = { "./*.s" },
vars = { plat = plat },
}
end

9
mach/mips/libend/edata.s Normal file
View file

@ -0,0 +1,9 @@
.sect .text
.sect .rom
.sect .data
.sect .bss
.define _edata
.sect .data
.align 4
.sect .data
_edata:

24
mach/mips/libend/em_end.s Normal file
View file

@ -0,0 +1,24 @@
! $Source$
! $State$
! $Revision$
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .end ! only for declaration of _end, __end and endbss.
.define endtext, endrom, enddata, endbss, __end
.sect .text
.align 4
endtext:
.sect .rom
.align 4
endrom:
.sect .data
.align 4
enddata:
.sect .end
.align 4
__end:
endbss:

7
mach/mips/libend/end.s Normal file
View file

@ -0,0 +1,7 @@
.sect .text
.sect .rom
.sect .data
.sect .bss
.define _end
.sect .end ! only for declaration of _end, __end and endbss.
_end:

9
mach/mips/libend/etext.s Normal file
View file

@ -0,0 +1,9 @@
.sect .text
.sect .rom
.sect .data
.sect .bss
.define _etext
.sect .text
.align 4
.sect .text
_etext:

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

@ -0,0 +1,310 @@
#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_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; 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_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, "mov fp, at");
hop_add_insel(hop, "jr ra");
hop_add_insel(hop, "nop");
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 : */

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

@ -0,0 +1,992 @@
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 int volatile;
r5 int volatile;
r6 int volatile;
r7 int volatile;
r8 int volatile;
r9 int volatile;
r10 int volatile;
r11 int volatile;
r12 int volatile;
r13 int volatile;
r14 int volatile;
r15 int volatile;
r24 int volatile;
r25 int volatile;
r2 int volatile iret;
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 volatilei lret1;
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;
r17r18 named("r17", "r18") aliases(r17, r18) long;
r19r20 named("r19", "r20") aliases(r19, r20) long;
r21r22 named("r21", "r22") aliases(r21, r22) long;
f0 float volatile fret;
f1 float volatile;
f2 float volatile;
f3 float volatile;
f4 float volatile;
f5 float volatile;
f6 float volatile;
f7 float volatile;
f8 float volatile;
f9 float volatile;
f10 float volatile;
f11 float volatile;
f12 float volatile;
f13 float volatile;
f14 float volatile;
f15 float volatile;
f16 float volatile;
f17 float volatile;
f18 float volatile;
f19 float volatile;
f20 float;
f21 float;
f22 float;
f23 float;
f24 float;
f25 float;
f26 float;
f27 float;
f28 float;
f29 float;
/* f30 and f31 is used by the compiler as a temporary. */
d0 named("f0") aliases(f0, f1) double volatile dret;
d2 named("f2") aliases(f2, f3) double volatile;
d4 named("f4") aliases(f4, f5) double volatile;
d6 named("f6") aliases(f6, f7) double volatile;
d8 named("f8") aliases(f8, f9) double volatile;
d10 named("f10") aliases(f10, f11) double volatile;
d12 named("f12") aliases(f12, f13) double volatile;
d14 named("f14") aliases(f14, f15) double volatile;
d16 named("f16") aliases(f16, f17) double volatile;
d18 named("f18") aliases(f18, f19) double volatile;
d20 named("f20") aliases(f20, f21) double;
d22 named("f22") aliases(f22, f23) double;
d24 named("f24") aliases(f24, f25) double;
d26 named("f26") aliases(f26, f27) double;
d28 named("f28") aliases(f28, f29) 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;
PUSH.F(in:(float)reg)
emit "addiu sp, sp, -4"
emit "swc1 %in, 0(sp)"
cost 8;
PUSH.D(in:(double)reg)
emit "addiu sp, sp, -8"
emit "sdc1 %in, 0(sp)"
cost 8;
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;
out:(float)reg = POP.F
emit "lwc1 %out, 0(sp)"
emit "addiu sp, sp, 4"
cost 8;
out:(double)reg = POP.D
emit "ldc1 %out, 0(sp)"
emit "addiu sp, sp, 8"
cost 8;
SETRET.I(in:(iret)reg)
emit "! setret.i"
cost 1;
SETRET.L(in:(lret)reg)
emit "! setret.l"
cost 1;
SETRET.F(in:(fret)reg)
emit "! setret.f"
cost 1;
SETRET.D(in:(dret)reg)
emit "! setret.d"
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 "mov %out, fp"
cost 4;
SETFP.I(in:(int)reg)
emit "mov 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 "mov %out, sp"
cost 4;
SETSP.I(in:(int)reg)
emit "mov 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, 0+%addr"
emit "sw %value.1, 4+%addr"
cost 8;
STORE.I(addr:address, value:(int)reg)
emit "sw %value, %addr"
cost 4;
STORE.I(label:LABEL.I, value:(int)reg)
emit "lui at, ha16[$label]"
emit "sw %value, lo16[$label] (at)"
cost 8;
STOREH.I(addr:address, value:(int)ushortX)
emit "sh %value, %addr"
cost 4;
STOREH.I(label:LABEL.I, value:(int)reg)
emit "lui at, ha16[$label]"
emit "sh %value, lo16[$label] (at)"
cost 8;
STOREB.I(addr:address, value:(int)ubyteX)
emit "sb %value, %addr"
cost 4;
STOREB.I(label:LABEL.I, value:(int)reg)
emit "lui at, ha16[$label]"
emit "sb %value, lo16[$label] (at)"
cost 8;
STORE.F(addr:address, value:(float)reg)
emit "swc1 %value, %addr"
cost 4;
STORE.F(label:LABEL.I, value:(int)reg)
emit "lui at, ha16[$label]"
emit "swc1 %value, lo16[$label] (at)"
cost 8;
STORE.D(addr:address, value:(double)reg)
emit "sdc1 %value, %addr"
cost 4;
STORE.D(label:LABEL.I, value:(int)reg)
emit "lui at, ha16[$label]"
emit "sdc1 %value, lo16[$label] (at)"
cost 8;
/* Loads */
out:(int)reg = LOAD.I(addr:address)
emit "lw %out, %addr"
cost 4;
out:(int)reg = LOAD.I(label:LABEL.I)
emit "lui at, ha16[$label]"
emit "lw %out, lo16[$label] (at)"
cost 8;
/* 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, 0+%addr"
emit "lw %out.1, 4+%addr"
emit "mov %out.0, at"
cost 12;
out:(int)ushort0 = LOADH.I(addr:address)
emit "lhu %out, %addr"
cost 4;
out:(int)reg = EXTENDH.I(LOADH.I(addr:address))
emit "lh %out, %addr"
cost 4;
out:(int)ushort0 = LOADH.I(label:LABEL.I)
emit "lui at, ha16[$label]"
emit "lhu %out, lo16[$label] (at)"
cost 8;
out:(int)reg = EXTENDH.I(LOADH.I(label:LABEL.I))
emit "lui at, ha16[$label]"
emit "lh %out, lo16[$label] (at)"
cost 8;
out:(int)ubyte0 = LOADB.I(addr:address)
emit "lbu %out, %addr"
cost 4;
out:(int)reg = EXTENDB.I(LOADB.I(addr:address))
emit "lb %out, %addr"
cost 4;
out:(int)ubyte0 = LOADB.I(label:LABEL.I)
emit "lui at, ha16[$label]"
emit "lbu %out, lo16[$label] (at)"
cost 8;
out:(int)reg = EXTENDB.I(LOADB.I(label:LABEL.I))
emit "lui at, ha16[$label]"
emit "lb %out, lo16[$label] (at)"
cost 8;
out:(float)reg = LOAD.F(addr:address)
emit "lwc1 %out, %addr"
cost 4;
out:(float)reg = LOAD.F(label:LABEL.I)
emit "lui at, ha16[$label]"
emit "lwc1 %out, lo16[$label] (at)"
cost 8;
out:(double)reg = LOAD.D(addr:address)
emit "ldc1 %out, %addr"
cost 4;
out:(double)reg = LOAD.D(label:LABEL.I)
emit "lui at, ha16[$label]"
emit "ldc1 %out, lo16[$label] (at)"
cost 8;
/* 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 "mov %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)
with preserved(%in1), preserved(%in2)
emit "mov %out.0, %in1"
emit "mov %out.1, %in2"
cost 8;
out:(int)reg = FROML0.I(in:(long)reg)
emit "mov %out, %in.0"
cost 4;
out:(int)reg = FROML1.I(in:(long)reg)
emit "mov %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 "j $addr"
emit "nop"
cost 8;
JUMP(dest:(int)reg)
emit "jr %dest"
emit "nop"
cost 8;
CJUMPEQ(left:(int)reg, PAIR(true:BLOCK.I, false:BLOCK.I))
emit "beq %left, zero, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 16;
CJUMPLT(left:(int)reg, PAIR(true:BLOCK.I, false:BLOCK.I))
emit "bltz %left, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 20;
CJUMPLE(left:(int)reg, PAIR(true:BLOCK.I, false:BLOCK.I))
emit "blez %left, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 20;
#define CALLLABEL(insn) \
insn (dest:LABEL.I) \
with corrupted(volatile) \
emit "jal $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;
/* Conditional branches */
/* Normally COMPARE returns a condition code (in a flags register) which the CJUMP
* instructions can then operate on. But MIPS doesn't have a flags register, and
* requires you to know what condition you're testing for when you do the comparison.
* mcg doesn't like this much and we have to list every combination individually.
*/
/* Signed integer comparisons against zero */
CJUMPEQ(COMPARESI.I(left:(int)reg, zero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
when specific_constant(%zero, 0)
emit "beq %left, zero, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 16;
CJUMPLT(COMPARESI.I(left:(int)reg, zero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
when specific_constant(%zero, 0)
emit "bltz %left, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 16;
CJUMPLE(COMPARESI.I(left:(int)reg, zero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
when specific_constant(%zero, 0)
emit "blez %left, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 16;
/* Signed integer comparisons against a constant */
CJUMPEQ(COMPARESI.I(left:(int)reg, value:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
emit "li at, $value"
emit "beq %left, at, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 20;
CJUMPLT(COMPARESI.I(left:(int)reg, value:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
when signed_constant(%value, 16)
emit "slti at, %left, $value"
emit "bne at, zero, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 20;
CJUMPLE(COMPARESI.I(left:(int)reg, value:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
when constant_within_inclusive_range(%value, -0x8000, 0x7ffe)
emit "slti at, %left, 1+$value"
emit "bne at, zero, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 20;
/* Signed integer comparisons against a register */
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 20;
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;
CJUMPLE(COMPARESI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I))
emit "slt at, %right, %left"
emit "beq at, zero, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 20;
/* Unsigned integer comparisons against a constant */
CJUMPLT(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:CONST.I), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
when signed_constant(%right, 16)
when specific_constant(%alwayszero, 0)
emit "sltiu at, %left, $right"
emit "bne at, zero, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 16;
CJUMPLE(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:CONST.I), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
when constant_within_inclusive_range(%right, -0x8000, 0x7ffe)
when specific_constant(%alwayszero, 0)
emit "sltiu at, %left, 1+$right"
emit "bne at, zero, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 20;
/* Unsigned integer comparisons against registers */
CJUMPEQ(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:(int)reg), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
when specific_constant(%alwayszero, 0)
emit "beq %left, %right, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 16;
CJUMPLT(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:(int)reg), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
when specific_constant(%alwayszero, 0)
emit "sltu at, %left, %right"
emit "bne at, zero, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 16;
CJUMPLE(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:(int)reg), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I))
when specific_constant(%alwayszero, 0)
emit "sltu at, %right, %left"
emit "beq at, zero, $true"
emit "nop"
emit "b $false"
emit "nop"
cost 16;
/* Comparisons */
/* The COMPARE nodes return tristate integer values; -1, 0 or 1. */
out:(int)reg = COMPARESI.I(left:(int)reg, right:(int)reg)
with preserved(%left), preserved(%right)
emit "slt at, %left, %right"
emit "bne at, zero, 1f"
emit "li %out, -1" /* delay slot */
emit "slt %out, %right, %left"
emit "1:"
cost 20;
out:(int)reg = COMPAREUI.I(left:(int)reg, right:(int)reg)
with preserved(%left), preserved(%right)
emit "sltu at, %left, %right"
emit "bne at, zero, 1f"
emit "li %out, -1" /* delay slot */
emit "sltu %out, %right, %left"
emit "1:"
cost 20;
out:(iret)reg = COMPAREUL.I(left:(lret)reg, right:(lret1)reg)
emit "jal .compareul"
emit "nop"
cost 30;
out:(int)reg = COMPAREF.I(left:(float)reg, right:(float)reg)
with preserved(%left), preserved(%right)
emit "c.lt.s 0, %left, %right"
emit "li %out, -1"
emit "bc1t 0, 1f"
emit "nop"
emit "c.lt.s 0, %right, %left"
emit "li %out, 1"
emit "movf %out, zero, 0"
emit "1:"
cost 28;
out:(int)reg = COMPARED.I(left:(double)reg, right:(double)reg)
with preserved(%left), preserved(%right)
emit "c.lt.d 0, %left, %right"
emit "li %out, -1"
emit "bc1t 0, 1f"
emit "nop"
emit "c.lt.d 0, %right, %left"
emit "li %out, 1"
emit "movf %out, zero, 0"
emit "1:"
cost 28;
/* Booleans */
/* If 0 then 1, else 0 */
out:(int)reg = IFEQ.I(in:(int)reg)
emit "sltiu %out, %in, 1"
cost 4;
/* If -1 then 1, else 0 */
out:(int)reg = IFLT.I(in:(int)reg)
emit "srl %out, %in, 31"
cost 4;
/* If 1 or 0 then 1, else 0 */
out:(int)reg = IFLE.I(in:(int)reg)
emit "slti %out, %in, 1"
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, %left, %right"
cost 4;
out:(int)reg = SUB.I(left:(int)reg, right:CONST.I)
emit "addiu %out, %left, -[$right]"
cost 4;
out:(int)reg = DIV.I(left:(int)reg, right:(int)reg)
emit "div %left, %right"
emit "mflo %out"
cost 8;
out:(int)reg = DIVU.I(left:(int)reg, right:(int)reg)
emit "divu %left, %right"
emit "mflo %out"
cost 8;
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(ASL.I, "sllv")
ALUC(ASL.I, "sll")
ALUR(ASR.I, "srav")
ALUC(ASR.I, "sra")
ALUR(LSL.I, "sllv")
ALUC(LSL.I, "sll")
ALUR(LSR.I, "srlv")
ALUC(LSR.I, "srl")
out:(int)reg = NEG.I(left:(int)reg)
emit "subu %out, zero, %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 "lui %out, hi16[$value]"
emit "ori %out, %out, lo16[$value]"
cost 4;
out:(int)reg = value:BLOCK.I
emit "lui %out, hi16[$value]"
emit "ori %out, %out, lo16[$value]"
cost 4;
out:(int)reg = value:CONST.I
emit "li %out, $value"
cost 4;
/* FPU operations */
/* Doubles */
out:(double)reg = ADDF.D(left:(double)reg, right:(double)reg)
emit "add.d %out, %left, %right"
cost 4;
out:(double)reg = SUBF.D(left:(double)reg, right:(double)reg)
emit "sub.d %out, %left, %right"
cost 4;
out:(double)reg = MULF.D(left:(double)reg, right:(double)reg)
emit "mul.d %out, %left, %right"
cost 4;
out:(double)reg = DIVF.D(left:(double)reg, right:(double)reg)
emit "div.d %out, %left, %right"
cost 4;
out:(double)reg = NEGF.D(left:(double)reg)
emit "neg.d %out, %left"
cost 4;
out:(double)reg = FROMSI.D(in:(int)reg)
emit "mtc1 %in, %out" /* mtc1 has reversed parameters */
emit "cvt.d.w %out, %out"
cost 4;
out:(dret)reg = FROMUI.D(in:(iret)reg)
emit "jal .c_ui_d"
emit "nop"
cost 30;
out:(int)reg = FROMSD.I(in:(double)reg)
emit "trunc.w.d f30, %in"
emit "mfc1 %out, f30"
cost 8;
out:(lret)reg = FROMSD.L(in:(dret)reg)
emit "jal .c_sd_l"
emit "nop"
cost 30;
out:(iret)reg = FROMUD.I(in:(dret)reg)
with corrupted(dret)
emit "jal .c_ud_i"
emit "nop"
cost 30;
out:(double)reg = COPYL.D(in:(long)reg)
emit "mtc1 %in.0, %out" /* mtc1 has reversed parameters */
emit "mthc1 %in.1, %out" /* mtc1 has reversed parameters */
cost 8;
out:(long)reg = COPYD.L(in:(double)reg)
emit "mfc1 %out.0, %in"
emit "mfhc1 %out.1, %in"
cost 8;
/* Floats */
out:(float)reg = ADDF.F(left:(float)reg, right:(float)reg)
emit "add.d %out, %left, %right"
cost 4;
out:(float)reg = SUBF.F(left:(float)reg, right:(float)reg)
emit "sub.d %out, %left, %right"
cost 4;
out:(float)reg = MULF.F(left:(float)reg, right:(float)reg)
emit "mul.d %out, %left, %right"
cost 4;
out:(float)reg = DIVF.F(left:(float)reg, right:(float)reg)
emit "div.d %out, %left, %right"
cost 4;
out:(float)reg = NEGF.F(left:(float)reg)
emit "neg.s %out, %left"
cost 4;
out:(float)reg = FROMSI.F(in:(int)reg)
emit "mtc1 %in, %out" /* mtc1 has reversed parameters */
emit "cvt.s.w %out, %out"
cost 4;
out:(int)reg = FROMSF.I(in:(float)reg)
emit "trunc.w.s f30, %in"
emit "mfc1 %out, f30"
cost 8;
out:(lret)reg = FROMSF.L(in:(fret)reg)
emit "jal .c_sf_l"
emit "nop"
cost 30;
out:(fret)reg = FROMUI.F(in:(iret)reg)
emit "jal .c_ui_f"
emit "nop"
cost 30;
out:(iret)reg = FROMUF.I(in:(fret)reg)
with corrupted(fret)
emit "jal .c_uf_i"
emit "nop"
cost 30;
out:(float)reg = COPYI.F(in:(int)reg)
emit "mtc1 %in, %out" /* mtc1 has reversed parameters */
cost 4;
out:(int)reg = COPYF.I(in:(float)reg)
emit "mfc1 %out, %in"
cost 4;
out:(float)reg = value:CONST.F
when specific_constant(%value, 0)
emit "mtc1 zero, %out" /* mtc1 has reversed parameters */
cost 4;
/* vim: set sw=4 ts=4 expandtab : */

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

@ -0,0 +1,47 @@
/* MIPS table for ACK target optimizer */
MAXOP 5;
LABEL_STARTER '.';
%%;
X, Y, Z { TRUE };
R { TRUE };
%%;
/* Whitespace is significant here! */
addiu R, R, X : addiu R, R, Y { plus(X, Y, Z) } -> addiu R, R, Z ;
addiu X, X, 0 -> ;
b X : nop : labdef X -> labdef X ;
%%;
/* Does it fit a signed 16-bit integer? */
static int fits16(long l) {
return l >= -32768 && l <= 32767;
}
/* Tries sum = a + b with signed 16-bit integers. */
int plus(const char *a, const char *b, const char *sum)
{
long la, lb, lsum;
char *end;
la = strtol(a, &end, 10);
if (*a == '\0' || *end != '\0' || !fits16(la))
return 0;
lb = strtol(b, &end, 10);
if (*b == '\0' || *end != '\0' || !fits16(lb))
return 0;
lsum = la + lb;
if (!fits16(lsum))
return 0;
snprintf(sum, 7, "%ld", lsum);
return 1;
}

View file

@ -12,6 +12,7 @@
#define WORDS_REVERSED
#define LISTING
#define RELOCATION
#define PDPFLOAT
#undef ISALPHA
#define ISALPHA(c) (isalpha(c) || c == '_' || c == '.' || c == '~')
#undef ISALNUM

View file

@ -128,7 +128,7 @@ struct hop* platform_epilogue(void)
return hop;
}
struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest)
struct hop* platform_move(struct basicblock* bb, struct vreg* vreg, struct hreg* src, struct hreg* dest)
{
struct hop* hop = new_hop(bb, NULL);

View file

@ -2,7 +2,8 @@ include("first/yacc.lua")
definerule("build_as",
{
arch = { type="string" }
arch = { type="string" },
deps = { type="targets", default={} },
},
function(e)
-- Remember this is executed from the caller's directory; local
@ -25,6 +26,7 @@ definerule("build_as",
"mach/proto/as/comm1.h",
"h+emheaders",
archlib,
e.deps,
},
}
@ -42,8 +44,10 @@ definerule("build_as",
deps = {
"h+emheaders",
"modules/src/object+lib",
"modules/src/flt_arith+lib",
archlib,
yaccfiles
yaccfiles,
e.deps
}
}
end

View file

@ -22,6 +22,7 @@ _include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#endif
/* ========== ON/OFF options (use #define in mach0.c) ========== */

View file

@ -153,6 +153,7 @@ void emit1(int);
void emit2(int);
void emit4(long);
void emitx(valu_t, int);
void emitf(int size, int negative);
void emitstr(int);
void ffreopen(char *, FILE *);
FILE *ffcreat(char *);

View file

@ -43,9 +43,11 @@ static item_t *last_it, *o_it;
%token NUMBER2
%token NUMBER3
%token <y_valu> NUMBER
%token NUMBERF
%token DOT
%token EXTERN
%token <y_word> DATA
%token <y_word> DATAF
%token <y_word> ASCII
%token SECTION
%token COMMON
@ -58,14 +60,6 @@ static item_t *last_it, *o_it;
%token <y_word> LINE
%token FILe
%token <y_word> LIST
%token OP_EQ
%token OP_NE
%token OP_LE
%token OP_GE
%token OP_LL
%token OP_RR
%token OP_OO
%token OP_AA
%left OP_OO
%left OP_AA
@ -257,6 +251,7 @@ operation
DOTSCT->s_zero += $2;
}
| DATA datalist
| DATAF dataflist
| ASCII STRING
{ emitstr($1);}
;
@ -284,6 +279,23 @@ datalist
emitx($3.val, (int)$<y_word>0);
}
;
numberf
: NUMBERF
{
emitf((int)$<y_word>-1, 0);
}
| '-' NUMBERF
{
emitf((int)$<y_word>-1, 1);
}
;
dataflist
: numberf
| dataflist ',' numberf
;
expr : error
{ serror("expr syntax err");
$$.val = 0; $$.typ = S_UND;

View file

@ -29,6 +29,8 @@ item_t keytab[] = {
0, DATA, RELO1, ".data1",
0, DATA, RELO2, ".data2",
0, DATA, RELO4, ".data4",
0, DATAF, 4, ".dataf4",
0, DATAF, 8, ".dataf8",
0, ASCII, 0, ".ascii",
0, ASCII, 1, ".asciz",
0, ALIGN, 0, ".align",

View file

@ -5,26 +5,28 @@
*/
/* @(#)comm5.c 1.1 */
#include "comm0.h"
#include "comm1.h"
#include "y.tab.h"
#include "comm0.h"
#include "comm1.h"
#include "y.tab.h"
extern YYSTYPE yylval;
extern YYSTYPE yylval;
static void readcode(int);
static int induo(int);
static int inident(int);
static int innumber(int);
static int instring(int);
static int inescape(void);
static int infbsym(const char *);
static void readcode(int);
static int induo(int);
static int inident(int);
static int innumber(int);
static int instring(int);
static int inescape(void);
static int infbsym(const char*);
int
yylex(void)
static int maxstring = 0;
int yylex(void)
{
int c, c0, c1;
if (pass == PASS_1) {
if (pass == PASS_1)
{
/* scan the input file */
do
c = nextchar();
@ -33,126 +35,150 @@ yylex(void)
c = inident(c);
else if (isdigit(c))
c = innumber(c);
else switch (c) {
case '=':
case '<':
case '>':
case '|':
case '&':
c = induo(c); break;
case ASC_SQUO:
case ASC_DQUO:
c = instring(c); break;
case ASC_COMM:
do
c = nextchar();
while (c != '\n' && c != '\0');
break;
case CTRL('A'):
c = CODE1; readcode(1); break;
case CTRL('B'):
c = CODE2; readcode(2); break;
case CTRL('C'):
c = CODE4; readcode(4); break;
}
else
switch (c)
{
case '=':
case '<':
case '>':
case '|':
case '&':
c = induo(c);
break;
case ASC_SQUO:
case ASC_DQUO:
c = instring(c);
break;
case ASC_COMM:
do
c = nextchar();
while (c != '\n' && c != '\0');
break;
case CTRL('A'):
c = CODE1;
readcode(1);
break;
case CTRL('B'):
c = CODE2;
readcode(2);
break;
case CTRL('C'):
c = CODE4;
readcode(4);
break;
}
/* produce the intermediate token file */
if (c <= 0)
return(0);
if (c < 256) {
return (0);
if (c < 256)
{
putc(c, tempfile);
putc(0, tempfile);
} else {
}
else
{
putval(c);
}
} else {
}
else
{
/* read from intermediate token file */
c0 = getc(tempfile);
if (c0 == EOF)
return(0);
return (0);
c1 = getc(tempfile);
if (c1 == EOF)
return(0);
return (0);
c = c0 + (c1 << 8);
if (c >= 256)
c = getval(c);
}
curr_token = c;
return(c);
return (c);
}
void
putval(int c)
void putval(int c)
{
valu_t v;
int n = 0;
char *p = 0;
char* p = 0;
assert(c == (c & 0xffff));
switch (c) {
case CODE1:
n = 1; goto putnum;
case CODE2:
n = 2; goto putnum;
case CODE4:
n = 4; goto putnum;
case NUMBER:
v = yylval.y_valu;
for (n = 0; n < sizeof(v); n++) {
if (v == 0)
break;
v >>= 8;
}
assert(n <= 4);
c = NUMBER0 + n;
putnum:
putc(c, tempfile);
putc(c >> 8, tempfile);
v = yylval.y_valu;
while (--n >= 0)
putc((int) (v >> (n*8)), tempfile);
return;
case IDENT:
case FBSYM:
n = sizeof(item_t *);
p = (char *) &yylval.y_item; break;
switch (c)
{
case CODE1:
n = 1;
goto putnum;
case CODE2:
n = 2;
goto putnum;
case CODE4:
n = 4;
goto putnum;
case NUMBER:
v = yylval.y_valu;
for (n = 0; n < sizeof(v); n++)
{
if (v == 0)
break;
v >>= 8;
}
assert(n <= 4);
c = NUMBER0 + n;
putnum:
putc(c, tempfile);
putc(c >> 8, tempfile);
v = yylval.y_valu;
while (--n >= 0)
putc((int)(v >> (n * 8)), tempfile);
return;
case IDENT:
case FBSYM:
n = sizeof(item_t*);
p = (char*)&yylval.y_item;
break;
#ifdef ASLD
case MODULE:
n = sizeof(char *);
p = (char *) &yylval.y_strp; break;
case MODULE:
n = sizeof(char*);
p = (char*)&yylval.y_strp;
break;
#endif
case STRING:
v = stringlen;
putc(c, tempfile);
putc(c >> 8, tempfile);
for (n = 0; n < sizeof(v); n++) {
if (v == 0)
break;
v >>= 8;
}
assert(n <= 4);
putc(n, tempfile);
v = stringlen;
while (--n >= 0)
putc((int) (v >> (n*8)), tempfile);
p = stringbuf;
n = stringlen;
while (--n >= 0)
putc(*p++, tempfile);
return;
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_GE:
case OP_LL:
case OP_RR:
case OP_OO:
case OP_AA:
break;
default:
n = sizeof(word_t);
p = (char *) &yylval.y_word; break;
case STRING:
case NUMBERF:
v = stringlen;
putc(c, tempfile);
putc(c >> 8, tempfile);
for (n = 0; n < sizeof(v); n++)
{
if (v == 0)
break;
v >>= 8;
}
assert(n <= 4);
putc(n, tempfile);
v = stringlen;
while (--n >= 0)
putc((int)(v >> (n * 8)), tempfile);
p = stringbuf;
n = stringlen;
while (--n >= 0)
putc(*p++, tempfile);
return;
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_GE:
case OP_LL:
case OP_RR:
case OP_OO:
case OP_AA:
break;
default:
n = sizeof(word_t);
p = (char*)&yylval.y_word;
break;
}
putc(c, tempfile);
putc(c >> 8, tempfile);
@ -160,151 +186,172 @@ putval(int c)
putc(*p++, tempfile);
}
int
getval(int c)
int getval(int c)
{
int n = 0;
valu_t v;
char *p = 0;
char* p = 0;
switch (c) {
case CODE1:
n = 1; goto getnum;
case CODE2:
n = 2; goto getnum;
case CODE4:
n = 4; goto getnum;
case NUMBER0:
c = NUMBER; goto getnum;
case NUMBER1:
n = 1; c = NUMBER; goto getnum;
case NUMBER2:
n = 2; c = NUMBER; goto getnum;
case NUMBER3:
n = 3; c = NUMBER; goto getnum;
case NUMBER:
n = 4;
getnum:
v = 0;
while (--n >= 0) {
v <<= 8;
v |= getc(tempfile);
}
yylval.y_valu = v;
return(c);
case IDENT:
case FBSYM:
n = sizeof(item_t *);
p = (char *) &yylval.y_item; break;
switch (c)
{
case CODE1:
n = 1;
goto getnum;
case CODE2:
n = 2;
goto getnum;
case CODE4:
n = 4;
goto getnum;
case NUMBER0:
c = NUMBER;
goto getnum;
case NUMBER1:
n = 1;
c = NUMBER;
goto getnum;
case NUMBER2:
n = 2;
c = NUMBER;
goto getnum;
case NUMBER3:
n = 3;
c = NUMBER;
goto getnum;
case NUMBER:
n = 4;
getnum:
v = 0;
while (--n >= 0)
{
v <<= 8;
v |= getc(tempfile);
}
yylval.y_valu = v;
return (c);
case IDENT:
case FBSYM:
n = sizeof(item_t*);
p = (char*)&yylval.y_item;
break;
#ifdef ASLD
case MODULE:
n = sizeof(char *);
p = (char *) &yylval.y_strp; break;
case MODULE:
n = sizeof(char*);
p = (char*)&yylval.y_strp;
break;
#endif
case STRING:
getval(getc(tempfile)+NUMBER0);
stringlen = n = yylval.y_valu;
p = stringbuf;
p[n] = '\0'; break;
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_GE:
case OP_LL:
case OP_RR:
case OP_OO:
case OP_AA:
break;
default:
n = sizeof(word_t);
p = (char *) &yylval.y_word; break;
case STRING:
case NUMBERF:
getval(getc(tempfile) + NUMBER0);
stringlen = n = yylval.y_valu;
p = stringbuf;
p[n] = '\0';
break;
case OP_EQ:
case OP_NE:
case OP_LE:
case OP_GE:
case OP_LL:
case OP_RR:
case OP_OO:
case OP_AA:
break;
default:
n = sizeof(word_t);
p = (char*)&yylval.y_word;
break;
}
while (--n >= 0)
*p++ = getc(tempfile);
return(c);
return (c);
}
/* ---------- lexical scan in pass 1 ---------- */
int
nextchar(void)
int nextchar(void)
{
int c;
if (peekc != -1) {
if (peekc != -1)
{
c = peekc;
peekc = -1;
return(c);
return (c);
}
#ifdef ASLD
if (archmode && --archsize < 0)
return(0);
return (0);
#endif
if ((c = getc(input)) == EOF)
return(0);
return (0);
if (isascii(c) == 0)
fatal("non-ascii character");
#ifdef LISTING
if (listflag & 0440)
putc(c, listfile);
#endif
return(c);
return (c);
}
static void
readcode(int n)
static void readcode(int n)
{
int c;
yylval.y_valu = 0;
do {
do
{
if (
#ifdef ASLD
(archmode && --archsize < 0)
||
(archmode && --archsize < 0) ||
#endif
(c = getc(input)) == EOF
)
(c = getc(input)) == EOF)
fatal("unexpected EOF in compact input");
yylval.y_valu <<= 8;
yylval.y_valu |= c;
} while (--n);
}
static int
induo(int c)
static int induo(int c)
{
static short duo[] = {
('='<<8) | '=', OP_EQ,
('<'<<8) | '>', OP_NE,
('<'<<8) | '=', OP_LE,
('>'<<8) | '=', OP_GE,
('<'<<8) | '<', OP_LL,
('>'<<8) | '>', OP_RR,
('|'<<8) | '|', OP_OO,
('&'<<8) | '&', OP_AA,
0 /* terminates array */
('=' << 8) | '=',
OP_EQ,
('<' << 8) | '>',
OP_NE,
('<' << 8) | '=',
OP_LE,
('>' << 8) | '=',
OP_GE,
('<' << 8) | '<',
OP_LL,
('>' << 8) | '>',
OP_RR,
('|' << 8) | '|',
OP_OO,
('&' << 8) | '&',
OP_AA,
0 /* terminates array */
};
short *p;
short* p;
c = (c<<8) | nextchar();
c = (c << 8) | nextchar();
for (p = duo; *p; p++)
if (*p++ == c)
return(*p++);
return (*p++);
peekc = c & 0377;
return(c>>8);
return (c >> 8);
}
static char name[NAMEMAX+1];
static char name[NAMEMAX + 1];
static int
inident(int c)
static int inident(int c)
{
char *p = name;
item_t *ip;
char* p = name;
item_t* ip;
int n = NAMEMAX;
do {
do
{
if (--n >= 0)
*p++ = c;
c = nextchar();
@ -312,76 +359,88 @@ inident(int c)
*p = '\0';
peekc = c;
ip = item_search(name);
if (ip == 0) {
if (ip == 0)
{
ip = item_alloc(S_UND);
ip->i_name = remember(name);
/* printf("ident %s %o\n", ip->i_name, ip); */
unresolved++;
item_insert(ip, H_LOCAL + (hashindex%H_SIZE));
} else if (hashindex < H_SIZE) {
item_insert(ip, H_LOCAL + (hashindex % H_SIZE));
}
else if (hashindex < H_SIZE)
{
assert(H_KEY == 0);
yylval.y_word = (word_t) ip->i_valu;
return(ip->i_type);
yylval.y_word = (word_t)ip->i_valu;
return (ip->i_type);
}
yylval.y_item = ip;
return(IDENT);
return (IDENT);
}
#ifdef ASLD
char *
readident(int c)
char* readident(int c)
{
int n = NAMEMAX;
char *p = name;
char* p = name;
do {
do
{
if (--n >= 0)
*p++ = c;
c = nextchar();
} while (ISALNUM(c));
*p++ = '\0';
peekc = c;
return(name);
return (name);
}
#endif
static int
innumber(int c)
static int innumber(int c)
{
char *p;
char* p;
int radix;
static char num[20+1];
static char num[40 + 1];
p = num;
radix = 20;
do {
radix = 40;
if (c == '.')
goto floatconstant;
do
{
if (--radix < 0)
fatal("number too long");
if (isupper(c))
c += ('a' - 'A');
*p++ = c;
c = nextchar();
if (c == '.')
goto floatconstant;
} while (isalnum(c));
peekc = c;
*p = '\0';
c = *--p;
p = num;
radix = 10;
if (*p == '0') {
if (*p == '0')
{
radix = 8;
p++;
if (*p == 'x') {
if (*p == 'x')
{
radix = 16;
p++;
} else if (*p == 'b') {
}
else if (*p == 'b')
{
radix = 2;
p++;
}
}
if (radix != 16 && (c == 'f' || c == 'b'))
return(infbsym(num));
return (infbsym(num));
yylval.y_valu = 0;
while (c = *p++) {
while (c = *p++)
{
if (c > '9')
c -= ('a' - '9' - 1);
c -= '0';
@ -389,26 +448,50 @@ innumber(int c)
serror("digit exceeds radix");
yylval.y_valu = yylval.y_valu * radix + c;
}
return(NUMBER);
return (NUMBER);
floatconstant:
do
{
if (--radix < 0)
fatal("number too long");
*p++ = c;
c = nextchar();
if (isupper(c))
c = tolower(c);
} while (isdigit(c) || (c == '.') || (c == 'e') || (c == '+') || (c == '-'));
peekc = c;
*p = '\0';
stringlen = p - num;
if (stringlen > maxstring)
{
maxstring = stringlen;
stringbuf = realloc(stringbuf, maxstring);
}
strcpy(stringbuf, num);
return NUMBERF;
}
static int
instring(int termc)
static int instring(int termc)
{
char *p;
char* p;
int c;
static int maxstring = 0;
if (! maxstring) {
if (!maxstring)
{
maxstring = STRINGMAX;
if ((stringbuf = malloc(maxstring)) == 0) {
if ((stringbuf = malloc(maxstring)) == 0)
{
fatal("out of memory");
}
}
p = stringbuf;
for (;;) {
for (;;)
{
c = nextchar();
if (c == '\n' || c == '\0') {
if (c == '\n' || c == '\0')
{
peekc = c;
serror("non-terminated string");
break;
@ -417,10 +500,12 @@ instring(int termc)
break;
if (c == '\\')
c = inescape();
if (p >= &stringbuf[maxstring - 1]) {
if (p >= &stringbuf[maxstring - 1])
{
int cnt = p - stringbuf;
if ((stringbuf = realloc(stringbuf, maxstring += 256)) == 0) {
if ((stringbuf = realloc(stringbuf, maxstring += 256)) == 0)
{
fatal("out of memory");
}
p = stringbuf + cnt;
@ -429,57 +514,69 @@ instring(int termc)
}
stringlen = p - stringbuf;
*p = '\0';
return(STRING);
return (STRING);
}
static int
inescape(void)
static int inescape(void)
{
int c, j, r;
c = nextchar();
if (c >= '0' && c <= '7') {
if (c >= '0' && c <= '7')
{
r = c - '0';
for (j = 0; j < 2; j++) {
for (j = 0; j < 2; j++)
{
c = nextchar();
if (c < '0' || c > '7') {
if (c < '0' || c > '7')
{
peekc = c;
return(r);
return (r);
}
r <<= 3;
r += (c - '0');
}
return(r);
return (r);
}
switch (c) {
case 'b': return('\b');
case 'f': return('\f');
case 'n': return('\n');
case 'r': return('\r');
case 't': return('\t');
case '\'': return('\'');
case '"': return('"');
switch (c)
{
case 'b':
return ('\b');
case 'f':
return ('\f');
case 'n':
return ('\n');
case 'r':
return ('\r');
case 't':
return ('\t');
case '\'':
return ('\'');
case '"':
return ('"');
}
return(c);
return (c);
}
static int
infbsym(const char *p)
static int infbsym(const char* p)
{
int lab;
item_t *ip;
item_t* ip;
lab = *p++ - '0';
if ((unsigned)lab < 10) {
if (*p++ == 'f') {
ip = fb_ptr[FB_FORW+lab];
if (ip == 0) {
if ((unsigned)lab < 10)
{
if (*p++ == 'f')
{
ip = fb_ptr[FB_FORW + lab];
if (ip == 0)
{
ip = fb_alloc(lab);
fb_ptr[FB_FORW+lab] = ip;
fb_ptr[FB_FORW + lab] = ip;
}
goto ok;
}
ip = fb_ptr[FB_BACK+lab];
ip = fb_ptr[FB_BACK + lab];
if (ip != 0 && *p == 0)
goto ok;
}
@ -487,32 +584,33 @@ infbsym(const char *p)
ip = fb_alloc(0);
ok:
yylval.y_item = ip;
return(FBSYM);
return (FBSYM);
}
int
hash(const char *p)
int hash(const char* p)
{
unsigned short h;
int c;
h = 0;
while (c = *p++) {
while (c = *p++)
{
h <<= 2;
h += c;
}
return(h % H_SIZE);
return (h % H_SIZE);
}
item_t *
item_search(const char *p)
item_t* item_search(const char* p)
{
int h;
item_t *ip;
item_t* ip;
for (h = hash(p); h < H_TOTAL; h += H_SIZE) {
for (h = hash(p); h < H_TOTAL; h += H_SIZE)
{
ip = hashtab[h];
while (ip != 0) {
while (ip != 0)
{
if (strcmp(p, ip->i_name) == 0)
goto done;
ip = ip->i_next;
@ -520,25 +618,24 @@ item_search(const char *p)
}
done:
hashindex = h;
return(ip);
return (ip);
}
void
item_insert(item_t *ip, int h)
void item_insert(item_t* ip, int h)
{
ip->i_next = hashtab[h];
hashtab[h] = ip;
}
item_t *
item_alloc(int typ)
item_t* item_alloc(int typ)
{
item_t *ip;
item_t* ip;
static int nleft = 0;
static item_t *next;
static item_t* next;
if (--nleft < 0) {
next = (item_t *) malloc(MEMINCR);
if (--nleft < 0)
{
next = (item_t*)malloc(MEMINCR);
if (next == 0)
fatal("out of memory");
nleft += (MEMINCR / sizeof(item_t));
@ -548,36 +645,34 @@ item_alloc(int typ)
ip->i_type = typ;
ip->i_name = 0;
ip->i_valu = 0;
return(ip);
return (ip);
}
item_t *
fb_alloc(int lab)
item_t* fb_alloc(int lab)
{
item_t *ip, *p;
ip = item_alloc(S_UND);
p = fb_ptr[FB_TAIL+lab];
p = fb_ptr[FB_TAIL + lab];
if (p == 0)
fb_ptr[FB_HEAD+lab] = ip;
fb_ptr[FB_HEAD + lab] = ip;
else
p->i_next = ip;
fb_ptr[FB_TAIL+lab] = ip;
return(ip);
fb_ptr[FB_TAIL + lab] = ip;
return (ip);
}
item_t *
fb_shift(int lab)
item_t* fb_shift(int lab)
{
item_t *ip;
item_t* ip;
ip = fb_ptr[FB_FORW+lab];
ip = fb_ptr[FB_FORW + lab];
if (ip == 0)
if (pass == PASS_1)
ip = fb_alloc(lab);
else
ip = fb_ptr[FB_HEAD+lab];
fb_ptr[FB_BACK+lab] = ip;
fb_ptr[FB_FORW+lab] = ip->i_next;
return(ip);
ip = fb_ptr[FB_HEAD + lab];
fb_ptr[FB_BACK + lab] = ip;
fb_ptr[FB_FORW + lab] = ip->i_next;
return (ip);
}

View file

@ -8,37 +8,37 @@
* miscellaneous
*/
#include "comm0.h"
#include "comm1.h"
#include "y.tab.h"
#include <stdarg.h>
#include <object.h>
#include "comm0.h"
#include "comm1.h"
#include "y.tab.h"
#include <stdarg.h>
#include <object.h>
valu_t
load(const item_t *ip)
valu_t load(const item_t* ip)
{
#ifdef ASLD
int typ;
typ = ip->i_type & S_TYP;
if ((typ -= S_MIN) < 0) /* S_UND or S_ABS */
return(ip->i_valu);
return(ip->i_valu + sect[typ].s_base);
if ((typ -= S_MIN) < 0) /* S_UND or S_ABS */
return (ip->i_valu);
return (ip->i_valu + sect[typ].s_base);
#else
if ((ip->i_type & S_TYP) == S_UND || (ip->i_type & S_COM)) {
if (pass == PASS_3) {
if ((ip->i_type & S_TYP) == S_UND || (ip->i_type & S_COM))
{
if (pass == PASS_3)
{
if (relonami != 0)
serror("relocation error (relonami=%d, type=%08x)", relonami, ip->i_type);
relonami = ip->i_valu+1;
relonami = ip->i_valu + 1;
}
return(0);
return (0);
}
return(ip->i_valu);
return (ip->i_valu);
#endif
}
int
store(item_t *ip, valu_t val)
int store(item_t* ip, valu_t val)
{
#ifdef ASLD
int typ;
@ -48,27 +48,27 @@ store(item_t *ip, valu_t val)
val -= sect[typ].s_base;
#else
if ((ip->i_type & S_TYP) == S_UND)
return(0);
return (0);
#endif
assert(pass != PASS_3 || (ip->i_type & S_VAR) || ip->i_valu == val);
ip->i_valu = val;
return(1);
return (1);
}
char *
remember(char *s)
char* remember(char* s)
{
char *p;
char* p;
int n;
static int nleft = 0;
static char *next;
static char* next;
p = s;
n = 0;
do
n++;
while (*p++);
if ((nleft -= n) < 0) {
if ((nleft -= n) < 0)
{
next = malloc(MEMINCR);
if (next == 0)
fatal("out of memory");
@ -80,84 +80,86 @@ remember(char *s)
;
s = next;
next = p;
return(s);
return (s);
}
int
combine(int typ1, int typ2, int op)
int combine(int typ1, int typ2, int op)
{
switch (op) {
case '+':
if (typ1 == S_ABS)
return(typ2);
if (typ2 == S_ABS)
return(typ1);
break;
case '-':
if (typ2 == S_ABS)
return(typ1);
if ((typ1 & ~S_DOT) == (typ2 & ~S_DOT) && typ1 != S_UND)
return(S_ABS|S_VAR);
break;
case '>':
if (typ1 == S_ABS && typ2 == S_ABS)
return(S_ABS);
if (
((typ1 & ~S_DOT) == (typ2 & ~S_DOT) && typ1 != S_UND)
|| (typ1 == S_ABS)
|| (typ2 == S_ABS)
)
return(S_ABS|S_VAR);
break;
default:
if (typ1 == S_ABS && typ2 == S_ABS)
return(S_ABS);
break;
switch (op)
{
case '+':
if (typ1 == S_ABS)
return (typ2);
if (typ2 == S_ABS)
return (typ1);
break;
case '-':
if (typ2 == S_ABS)
return (typ1);
if ((typ1 & ~S_DOT) == (typ2 & ~S_DOT) && typ1 != S_UND)
return (S_ABS | S_VAR);
break;
case '>':
if (typ1 == S_ABS && typ2 == S_ABS)
return (S_ABS);
if (((typ1 & ~S_DOT) == (typ2 & ~S_DOT) && typ1 != S_UND) || (typ1 == S_ABS)
|| (typ2 == S_ABS))
return (S_ABS | S_VAR);
break;
default:
if (typ1 == S_ABS && typ2 == S_ABS)
return (S_ABS);
break;
}
if (pass != PASS_1)
serror("illegal operator");
return(S_UND);
return (S_UND);
}
#ifdef LISTING
int
printx(int ndig, valu_t val)
int printx(int ndig, valu_t val)
{
static char buf[8];
char *p;
char* p;
int c, n;
p = buf; n = ndig;
do {
*p++ = (int) val & 017;
p = buf;
n = ndig;
do
{
*p++ = (int)val & 017;
val >>= 4;
} while (--n);
do {
do
{
c = "0123456789ABCDEF"[*--p];
putchar(c);
} while (p > buf);
return(ndig);
return (ndig);
}
void
listline(int textline)
void listline(int textline)
{
int c;
if ((listflag & 4) && (c = getc(listfile)) != '\n' && textline) {
if ((listflag & 4) && (c = getc(listfile)) != '\n' && textline)
{
if (listcolm >= 24)
printf(" \\\n\t\t\t");
else
do {
do
{
putchar('\t');
listcolm += 8;
} while (listcolm < 24);
do {
do
{
assert(c != EOF);
putchar(c);
} while ((c = getc(listfile)) != '\n');
}
if (listflag & 7) {
if (listflag & 7)
{
putchar('\n');
fflush(stdout);
}
@ -170,35 +172,40 @@ listline(int textline)
/* ---------- code optimization ---------- */
#ifdef THREE_PASS
#define PBITTABSZ 128
static char *pbittab[PBITTABSZ];
#define PBITTABSZ 128
static char* pbittab[PBITTABSZ];
int
small(int fitsmall, int gain)
int small(int fitsmall, int gain)
{
int bit;
char *p;
char* p;
if (DOTSCT == NULL)
nosect();
if (bflag)
return(0);
if (nbits == BITCHUNK) {
return (0);
if (nbits == BITCHUNK)
{
bitindex++;
nbits = 0;
if (bitindex == PBITTABSZ) {
if (bitindex == PBITTABSZ)
{
static int w_given;
if (pass == PASS_1 && ! w_given) {
if (pass == PASS_1 && !w_given)
{
w_given = 1;
warning("bit table overflow");
}
return(0);
return (0);
}
if (pbittab[bitindex] == 0 && pass == PASS_1) {
if ((pbittab[bitindex] = calloc(MEMINCR, 1)) == 0) {
if (pbittab[bitindex] == 0 && pass == PASS_1)
{
if ((pbittab[bitindex] = calloc(MEMINCR, 1)) == 0)
{
static int w2_given;
if (!w2_given) {
if (!w2_given)
{
w2_given = 1;
warning("out of space for bit table");
}
@ -207,21 +214,23 @@ small(int fitsmall, int gain)
if (pbittab[bitindex] == 0)
return (0);
}
bit = 1 << (nbits&7);
p = pbittab[bitindex]+(nbits>>3);
bit = 1 << (nbits & 7);
p = pbittab[bitindex] + (nbits >> 3);
nbits++;
switch (pass) {
case PASS_1:
return(0);
case PASS_2:
if (fitsmall) {
DOTGAIN += gain;
*p |= bit;
}
return(fitsmall);
case PASS_3:
assert(fitsmall || (*p & bit) == 0);
return(*p & bit);
switch (pass)
{
case PASS_1:
return (0);
case PASS_2:
if (fitsmall)
{
DOTGAIN += gain;
*p |= bit;
}
return (fitsmall);
case PASS_3:
assert(fitsmall || (*p & bit) == 0);
return (*p & bit);
}
/*NOTREACHED*/
}
@ -229,13 +238,14 @@ small(int fitsmall, int gain)
/* ---------- output ---------- */
void
emit1(int arg)
void emit1(int arg)
{
static int olddottyp = -1;
#ifdef LISTING
if (listeoln) {
if (listflag & 1) {
if (listeoln)
{
if (listflag & 1)
{
listcolm += printx(VALWIDTH, (valu_t)DOTVAL);
listcolm++;
putchar(' ');
@ -243,81 +253,90 @@ emit1(int arg)
listeoln = 0;
}
if (listflag & 2)
listcolm += printx(2, (valu_t) arg);
listcolm += printx(2, (valu_t)arg);
#endif
switch (pass) {
case PASS_1:
if (DOTSCT == NULL)
nosect();
/* no break */
case PASS_2:
DOTSCT->s_zero = 0;
break;
case PASS_3:
if (DOTTYP != olddottyp) {
wr_outsect(DOTTYP-S_MIN);
olddottyp = DOTTYP;
}
while (DOTSCT->s_zero) {
wr_putc(0);
DOTSCT->s_zero--;
}
wr_putc(arg);
break;
switch (pass)
{
case PASS_1:
if (DOTSCT == NULL)
nosect();
/* no break */
case PASS_2:
DOTSCT->s_zero = 0;
break;
case PASS_3:
if (DOTTYP != olddottyp)
{
wr_outsect(DOTTYP - S_MIN);
olddottyp = DOTTYP;
}
while (DOTSCT->s_zero)
{
wr_putc(0);
DOTSCT->s_zero--;
}
wr_putc(arg);
break;
}
DOTVAL++;
}
void
emit2(int arg)
void emit2(int arg)
{
#ifdef BYTES_REVERSED
emit1((arg>>8)); emit1(arg);
emit1((arg >> 8));
emit1(arg);
#else
emit1(arg); emit1((arg>>8));
emit1(arg);
emit1((arg >> 8));
#endif
}
void
emit4(long arg)
void emit4(long arg)
{
#ifdef WORDS_REVERSED
emit2((int)(arg>>16)); emit2((int)(arg));
emit2((int)(arg >> 16));
emit2((int)(arg));
#else
emit2((int)(arg)); emit2((int)(arg>>16));
emit2((int)(arg));
emit2((int)(arg >> 16));
#endif
}
void
emitx(valu_t val, int n)
void emitx(valu_t val, int n)
{
switch (n) {
case RELO1:
emit1((int)val); break;
case RELO2:
switch (n)
{
case RELO1:
emit1((int)val);
break;
case RELO2:
#ifdef BYTES_REVERSED
emit1(((int)val>>8)); emit1((int)val);
emit1(((int)val >> 8));
emit1((int)val);
#else
emit1((int)val); emit1(((int)val>>8));
emit1((int)val);
emit1(((int)val >> 8));
#endif
break;
case RELO4:
break;
case RELO4:
#ifdef WORDS_REVERSED
emit2((int)(val>>16)); emit2((int)(val));
emit2((int)(val >> 16));
emit2((int)(val));
#else
emit2((int)(val)); emit2((int)(val>>16));
emit2((int)(val));
emit2((int)(val >> 16));
#endif
break;
default:
assert(0);
break;
default:
assert(0);
}
}
void
emitstr(int zero)
void emitstr(int zero)
{
int i;
char *p;
char* p;
p = stringbuf;
i = stringlen;
@ -327,57 +346,92 @@ emitstr(int zero)
emit1(0);
}
#define CODE_EXPANDER
#if !defined IEEEFLOAT && !defined PDPFLOAT
#define IEEEFLOAT
#endif
#if defined WORDS_REVERSED
#define FL_MSL_AT_LOW_ADDRESS 1
#define FL_MSW_AT_LOW_ADDRESS 1
#else
#define FL_MSL_AT_LOW_ADDRESS 0
#define FL_MSW_AT_LOW_ADDRESS 0
#endif
#if defined BYTES_REVERSED
#define FL_MSB_AT_LOW_ADDRESS 1
#else
#define FL_MSB_AT_LOW_ADDRESS 0
#endif
#define gen1 emit1
#include <con_float>
void emitf(int size, int negative)
{
char buffer[40];
if (stringlen > sizeof(buffer)-1)
fatal("floating point constant too long");
if (negative)
{
buffer[0] = '-';
strcpy(buffer+1, stringbuf);
con_float(buffer, size);
}
else
con_float(stringbuf, size);
}
/* ---------- Error checked file I/O ---------- */
void
ffreopen(char *s, FILE *f)
void ffreopen(char* s, FILE* f)
{
if (freopen(s, "r", f) == NULL)
fatal("can't reopen %s", s);
}
FILE *
ffcreat(char *s)
FILE* ffcreat(char* s)
{
FILE *f;
FILE* f;
if ((f = fopen(s, "w")) == NULL)
fatal("can't create %s", s);
return(f);
return (f);
}
#ifndef TMPDIR
#define TMPDIR "/tmp"
#endif
char *tmp_dir = TMPDIR;
char* tmp_dir = TMPDIR;
FILE *
fftemp(char *path, char *tail)
FILE* fftemp(char* path, char* tail)
{
char *dir;
char* dir;
if ((dir = getenv("TMPDIR")) == NULL)
dir = tmp_dir;
sprintf(path, "%s/%s", dir, tail);
close(mkstemp(path));
return(ffcreat(path));
return (ffcreat(path));
}
/* ---------- Error handling ---------- */
/* ARGSUSED */
void
yyerror(const char *message)
{} /* we will do our own error printing */
void yyerror(const char* message)
{
} /* we will do our own error printing */
void
nosect(void)
void nosect(void)
{
fatal("no sections");
}
void
wr_fatal(void)
void wr_fatal(void)
{
fatal("write error");
}
@ -432,8 +486,7 @@ void warning(const char* s, ...)
va_end(ap);
}
void
nofit(void)
void nofit(void)
{
if (pass == PASS_3)
warning("too big");

View file

@ -85,6 +85,7 @@ int regallowed=0;
extern char em_flag[];
extern short em_ptyp[];
extern double atof();
extern void con_float(void);
/* Own version of atol that continues computing on overflow.
We don't know that about the ANSI C one.

View file

@ -35,7 +35,6 @@ definerule("build_mcg",
"modules/src/data+lib",
"modules/src/em_code+lib_k",
"modules/src/em_data+lib",
"modules/src/flt_arith+lib",
"modules/src/idf+lib",
"modules/src/object+lib",
"modules/src/read_em+lib_kv",

View file

@ -1,13 +1,6 @@
#include "mcg.h"
#include <ctype.h>
#define IEEEFLOAT
#define FL_MSL_AT_LOW_ADDRESS 1
#define FL_MSW_AT_LOW_ADDRESS 1
#define FL_MSB_AT_LOW_ADDRESS 1
#include "con_float"
static struct symbol* pending;
void data_label(const char* label)
@ -66,7 +59,7 @@ void data_int(arith data, size_t size, bool is_ro)
{
emit_header(is_ro ? SECTION_ROM : SECTION_DATA);
assert((size == 1) || (size == 2) || (size == 4) || (size == 8));
fprintf(outputfile, "\t.data%d ", size);
fprintf(outputfile, "\t.data%ld ", size);
writehex(data, size);
fprintf(outputfile, "\n");
}
@ -80,19 +73,7 @@ void data_float(const char* data, size_t size, bool is_ro)
emit_header(is_ro ? SECTION_ROM : SECTION_DATA);
assert((size == 4) || (size == 8));
i = float_cst(data, size, (char*) buffer);
if ((i != 0) && (i != 2)) /* 2 == overflow */
fatal("cannot parse floating point constant %s sz %d", data, size);
fprintf(outputfile, "\t!float %s sz %d\n", data, size);
fprintf(outputfile, "\t.data1 ");
writehex(buffer[0], 1);
for (i=1; i<size; i++)
{
fprintf(outputfile, ", ");
writehex(buffer[i], 1);
}
fprintf(outputfile, "\n");
fprintf(outputfile, "\t.dataf%ld %s\n", size, data);
}
static bool istext(c)
@ -149,7 +130,7 @@ void data_block(const uint8_t* data, size_t size, bool is_ro)
void data_offset(const char* label, arith offset, bool is_ro)
{
emit_header(is_ro ? SECTION_ROM : SECTION_DATA);
fprintf(outputfile, "\t.data%d %s+%lld\n",
fprintf(outputfile, "\t.data%d %s+%ld\n",
EM_pointersize, platform_label(label), offset);
}
@ -159,7 +140,7 @@ void data_bss(arith size, int init)
fatal("non-zero-initialised bss not supported");
emit_header(SECTION_BSS);
fprintf(outputfile, "\t.space %lld\n", size);
fprintf(outputfile, "\t.space %ld\n", size);
}
/* vim: set sw=4 ts=4 expandtab : */

View file

@ -8,7 +8,6 @@
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include "flt_arith.h"
#include "em_arith.h"
#include "em_label.h"
#include "em.h"
@ -123,7 +122,7 @@ extern void pass_wire_up_return_values(void);
extern void platform_calculate_offsets(void);
extern struct hop* platform_prologue(void);
extern struct hop* platform_epilogue(void);
extern struct hop* platform_move(struct basicblock* bb, struct hreg* src, struct hreg* dest);
extern struct hop* platform_move(struct basicblock* bb, struct vreg* vreg, struct hreg* src, struct hreg* dest);
extern struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest);
extern const char* platform_label(const char* label);

View file

@ -10,6 +10,7 @@ extern void burm_panic_cannot_match(NODEPTR_TYPE node);
extern bool burm_predicate_signed_constant(struct burm_node* node, arith size);
extern bool burm_predicate_unsigned_constant(struct burm_node* node, arith size);
extern bool burm_predicate_specific_constant(struct burm_node* node, arith value);
extern bool burm_predicate_constant_within_inclusive_range(struct burm_node* node, arith min, arith max);
/* vim: set sw=4 ts=4 expandtab : */

View file

@ -181,6 +181,36 @@ static void queue_ilabel(arith label)
change_basicblock(bb_get(ilabel_to_str(label)));
}
/* This is really hacky; to handle basic block flow
* descriptor blocks, we need to be able to identify
* them, read them and parse them. So we create
* can exit to. So we create fake bb objects for each
* block, purely to track this, and copy ints and labels
* into them.
*/
static void data_block_int(arith value)
{
if (data_bb)
{
struct em* em = new_insn(op_loc);
em->paramtype = PARAM_IVALUE;
em->u.ivalue = value;
array_append(&data_bb->ems, em);
}
}
static void data_block_label(const char* label)
{
if (data_bb)
{
struct em* em = new_insn(op_bra);
em->paramtype = PARAM_BVALUE;
em->u.bvalue.left = bb_get(label);
array_append(&data_bb->ems, em);
}
}
static void parse_pseu(void)
{
switch (em.em_opcode)
@ -227,6 +257,7 @@ static void parse_pseu(void)
{
arith val = atol(em.em_string);
data_int(val, em.em_size, ro);
data_block_int(val);
break;
}
@ -237,12 +268,16 @@ static void parse_pseu(void)
}
case str_ptyp:
data_block(strdup(em.em_string), em.em_size, ro);
data_block((const uint8_t*) strdup(em.em_string), em.em_size, ro);
break;
case cst_ptyp:
data_int(em.em_cst, EM_wordsize, ro);
{
arith value = em.em_cst;
data_int(value, EM_wordsize, ro);
data_block_int(value);
break;
}
case nof_ptyp:
data_offset(dlabel_to_str(em.em_dlb), em.em_off, ro);
@ -256,22 +291,8 @@ static void parse_pseu(void)
case ilb_ptyp:
{
const char* label = ilabel_to_str(em.em_ilb);
/* This is really hacky; to handle basic block flow
* descriptor blocks, we need to track which bbs a descriptor
* can exit to. So we create fake bb objects for each
* block, purely to track this.
*/
if (data_bb)
{
struct em* em = new_insn(op_bra);
em->paramtype = PARAM_BVALUE;
em->u.bvalue.left = bb_get(label);
array_append(&data_bb->ems, em);
}
data_offset(label, 0, ro);
data_block_label(label);
break;
}
@ -384,9 +405,12 @@ static void create_data_label(const char* label)
data_label(label);
if (current_proc)
{
/* Create the fake bb used to track values inside this data block
* (as it's a chance it's a jump table which we'll need to process
* later).
*/
data_bb = bb_get(label);
data_bb->is_fake = true;
array_append(&current_proc->blocks, data_bb);
}
}

View file

@ -10,7 +10,8 @@ static void make_phimap(void)
for (i=0; i<cfg.preorder.count; i++)
{
struct basicblock* bb = cfg.preorder.item[i];
/* Registers imported through a phi can come from multiple locations. */
for (j=0; j<bb->phis.count; j++)
{
struct vreg* vreg = bb->phis.item[j].left;
@ -36,8 +37,10 @@ static void recursively_associate_group(struct phicongruence* c, struct vreg* vr
struct constraint* constraint = pmap_findleft(&vreg->defined->constraints, vreg);
if (c->type == 0)
c->type = vreg->type;
assert(c->type == vreg->type);
if (c->type != vreg->type)
fatal("tried to add register %%%d of type 0x%x to a phi congruence group of type 0x%x",
vreg->id, vreg->type, c->type);
array_appendu(&c->definitions, vreg->defined);
}

View file

@ -386,16 +386,28 @@ static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* s
for (i=0; i<hregs.count; i++)
{
hreg = hregs.item[i];
if ((hreg->attrs & srctype) &&
if (!hreg->is_stacked && (hreg->attrs & srctype) &&
allocatable_through(hreg, vreg))
{
goto found;
}
}
/* No more registers --- allocate a stack slot. */
/* No more registers --- allocate a stack slot. Ensure that we use the same stack
* slot for this vreg throughout the function. */
hreg = new_stacked_hreg(srctype);
hreg = vreg->evicted;
if (!hreg)
{
if (vreg->congruence)
hreg = vreg->evicted = vreg->congruence->evicted;
if (!hreg)
{
hreg = vreg->evicted = new_stacked_hreg(srctype);
if (vreg->congruence)
vreg->congruence->evicted = hreg;
}
}
array_append(&hregs, hreg);
found:
@ -480,7 +492,7 @@ static void assign_hregs_to_vregs(void)
{
tracef('R', "R: import hreg %s for input %%%d from %s\n",
hreg->id, vreg->id, prevbb->name);
assert(!pmap_findleft(old, hreg));
assert(!register_used(old, hreg));
pmap_put(old, hreg, vreg);
goto nextvreg;
}
@ -506,7 +518,7 @@ static void assign_hregs_to_vregs(void)
struct hreg* hreg = pmap_findright(
phi->prev->regsout, phi->ir->result);
if (hreg && !pmap_findleft(old, hreg))
if (hreg && !register_used(old, hreg))
{
tracef('R', "R: import hreg %s for %%%d, imported from %s %%%d\n",
hreg->id, vreg->id,
@ -617,7 +629,8 @@ static int insert_moves(struct basicblock* bb, int index,
{
/* Copy. */
hop = platform_move(bb, src, dest);
struct vreg* vreg = pmap_findleft(srcregs, src);
hop = platform_move(bb, vreg, src, dest);
pmap_remove(&copies, src, dest);
}
else
@ -710,13 +723,17 @@ static void insert_phi_copies(void)
for (k=0; k<bb->regsin.count; k++)
{
struct hreg*hreg = bb->regsin.item[k].left;
struct hreg* hreg = bb->regsin.item[k].left;
struct vreg* vreg = bb->regsin.item[k].right;
struct hreg* src = pmap_findright(prevbb->regsout, vreg);
if (!pmap_findleft(&bb->phis, vreg))
{
tracef('R', "R: input map %%%d (%s) -> (%s)\n",
vreg->id, src->id, hreg->id);
if ((src->id != hreg->id) && src->is_stacked && hreg->is_stacked)
fatal("vreg %%%d is stacked in %s on entry to %s, but is passed in in %s from %s",
vreg->id, hreg->id, bb->name,
src->id, prevbb->name);
pmap_add(&destregs, hreg, vreg);
}

View file

@ -27,6 +27,14 @@ bool burm_predicate_specific_constant(struct burm_node* node, arith val)
return ir->u.ivalue == val;
}
bool burm_predicate_constant_within_inclusive_range(struct burm_node* node, arith min, arith max)
{
struct ir* ir = node->ir;
assert(ir->opcode == IR_CONST);
return (ir->u.ivalue >= min) && (ir->u.ivalue <= max);
}
/* vim: set sw=4 ts=4 expandtab : */

View file

@ -38,6 +38,18 @@ static void print_blocks(char k)
}
}
static void print_vreg(char k, register_assignment_t* assignments, struct vreg* vreg)
{
struct hreg* hreg;
tracef(k, "%%%d", vreg->id);
if (assignments)
{
hreg = pmap_findright(assignments, vreg);
if (hreg)
tracef(k, "(%s)", hreg->id);
}
}
static void print_hops(char k)
{
int i;
@ -73,7 +85,10 @@ static void print_hops(char k)
{
tracef(k, "%c: INS:", k);
for (j=0; j<bb->liveins.count; j++)
tracef(k, " %%%d", bb->liveins.item[j]->id);
{
tracef(k, " ");
print_vreg(k, &bb->regsin, bb->liveins.item[j]);
}
tracef(k, "\n");
}
@ -81,7 +96,10 @@ static void print_hops(char k)
{
tracef(k, "%c: OUTS:", k);
for (j=0; j<bb->liveouts.count; j++)
tracef(k, " %%%d", bb->liveouts.item[j]->id);
{
tracef(k, " ");
print_vreg(k, bb->regsout, bb->liveouts.item[j]);
}
tracef(k, "\n");
}
@ -93,10 +111,10 @@ static void print_hops(char k)
struct vreg* vreg = bb->phis.item[j].left;
struct phi* phi = bb->phis.item[j].right;
tracef(k, " %%%d(via %s)=>%%%d",
tracef(k, " %%%d(via %s)=>",
phi->ir->result->id,
phi->prev->name,
vreg->id);
phi->prev->name);
print_vreg(k, &bb->regsin, vreg);
}
tracef(k, "\n");
}

View file

@ -9,6 +9,7 @@ struct phicongruence
ARRAYOF(struct vreg) vregs;
ARRAYOF(struct hop) definitions;
uint32_t type;
struct hreg* evicted; /* stack slot to evict to */
};
struct hreg
@ -28,6 +29,7 @@ struct vreg
struct phicongruence* congruence;
struct hop* defined;
ARRAYOF(struct hop) used;
struct hreg* evicted; /* stack slot to evict to */
};
typedef PMAPOF(struct hreg, struct vreg) register_assignment_t;

View file

@ -5,10 +5,20 @@ static struct basicblock* current_bb;
static int stackptr;
static struct ir* stack[64];
struct jumptable
{
struct basicblock* defaulttarget;
IMAPOF(struct basicblock) targets;
};
static struct ir* convert(struct ir* src, int srcsize, int destsize, int opcode);
static struct ir* appendir(struct ir* ir);
static void insn_ivalue(int opcode, arith value);
static void parse_csa(struct basicblock* data_bb, struct jumptable* table);
static void parse_csb(struct basicblock* data_bb, struct jumptable* table);
static void emit_jumptable(struct ir* targetvalue, struct jumptable* table);
static void reset_stack(void)
{
stackptr = 0;
@ -85,6 +95,8 @@ static struct ir* pop(int size)
}
else if ((size == EM_wordsize) && (ir->size == (EM_wordsize*2)))
{
appendir(ir);
/* Tried to read an int, but we got a long. */
push(
new_ir1(
@ -553,6 +565,7 @@ static void insn_simple(int opcode)
{
struct ir* label = new_labelir(".trppc");
struct ir* value = pop(EM_pointersize);
appendir(label); /* because we need to use label twice */
push(
load(
EM_pointersize,
@ -717,6 +730,10 @@ static void rotate(int opcode, int size, int irop, int irop_reverse)
struct ir* left = pop(size);
struct ir* bits = new_wordir(8 * size);
/* Fix left and right so we can refer to them multiple times. */
appendir(right);
appendir(left);
/* a rol b -> (a << b) | (a >> (32 - b)) */
push(
new_ir2(
@ -732,27 +749,6 @@ static void rotate(int opcode, int size, int irop, int irop_reverse)
}
}
static struct ir* extract_block_refs(struct basicblock* bb)
{
struct ir* outir = NULL;
int i;
for (i=0; i<bb->ems.count; i++)
{
struct em* em = bb->ems.item[i];
assert(em->opcode == op_bra);
assert(em->paramtype == PARAM_BVALUE);
outir = new_ir2(
IR_PAIR, 0,
new_bbir(em->u.bvalue.left),
outir
);
}
return outir;
}
static void change_by(struct ir* address, int amount)
{
appendir(
@ -1332,25 +1328,34 @@ static void insn_ivalue(int opcode, arith value)
}
case op_csa:
case op_csb:
{
const char* helper = aprintf(".%s",
(opcode == op_csa) ? "csa" : "csb");
struct ir* descriptor = pop(EM_pointersize);
struct ir* targetvalue = appendir(pop(EM_pointersize));
struct jumptable jumptable = {};
int i;
if (descriptor->opcode != IR_LABEL)
fatal("csa/csb are only supported if they refer "
fatal("csa is only supported if it refers "
"directly to a descriptor block");
push(descriptor);
materialise_stack();
appendir(
new_ir2(
IR_FARJUMP, 0,
new_labelir(helper),
extract_block_refs(bb_get(descriptor->u.lvalue))
)
);
parse_csa(bb_get(descriptor->u.lvalue), &jumptable);
emit_jumptable(targetvalue, &jumptable);
break;
}
case op_csb:
{
struct ir* descriptor = pop(EM_pointersize);
struct ir* targetvalue = appendir(pop(EM_pointersize));
struct jumptable jumptable = {};
int i;
if (descriptor->opcode != IR_LABEL)
fatal("csb is only supported if it refers "
"directly to a descriptor block");
parse_csb(bb_get(descriptor->u.lvalue), &jumptable);
emit_jumptable(targetvalue, &jumptable);
break;
}
@ -1755,4 +1760,133 @@ void tb_procedure(void)
generate_tree(current_proc->blocks.item[i]);
}
static void parse_csa(struct basicblock* data_bb, struct jumptable* table)
{
struct em* em;
int lowerbound;
int count;
int i;
assert(data_bb->ems.count >= 3);
/* Default target */
em = data_bb->ems.item[0];
assert(em->opcode == op_bra);
assert(em->paramtype == PARAM_BVALUE);
table->defaulttarget = em->u.bvalue.left;
/* Lower bound */
em = data_bb->ems.item[1];
assert(em->opcode == op_loc);
assert(em->paramtype == PARAM_IVALUE);
lowerbound = em->u.ivalue;
/* Count */
em = data_bb->ems.item[2];
assert(em->opcode == op_loc);
assert(em->paramtype == PARAM_IVALUE);
count = em->u.ivalue + 1; /* value in descriptor is inclusive */
assert(data_bb->ems.count >= (count + 3));
/* Now, each target in turn. */
for (i=0; i<count; i++)
{
struct basicblock* target;
em = data_bb->ems.item[3 + i];
assert(em->opcode == op_bra);
assert(em->paramtype == PARAM_BVALUE);
target = em->u.bvalue.left;
imap_put(&table->targets, lowerbound+i, target);
}
}
static void parse_csb(struct basicblock* data_bb, struct jumptable* table)
{
struct em* em;
int count;
int i;
assert(data_bb->ems.count >= 2);
/* Default target */
em = data_bb->ems.item[0];
assert(em->opcode == op_bra);
assert(em->paramtype == PARAM_BVALUE);
table->defaulttarget = em->u.bvalue.left;
/* Number of targets */
em = data_bb->ems.item[1];
assert(em->opcode == op_loc);
assert(em->paramtype == PARAM_IVALUE);
count = em->u.ivalue;
assert(data_bb->ems.count >= (count*2 + 2));
/* Now, each target in turn. */
for (i=0; i<count; i++)
{
int value;
struct basicblock* target;
em = data_bb->ems.item[2 + i*2];
assert(em->opcode == op_loc);
assert(em->paramtype == PARAM_IVALUE);
value = em->u.ivalue;
em = data_bb->ems.item[3 + i*2];
assert(em->opcode == op_bra);
assert(em->paramtype == PARAM_BVALUE);
target = em->u.bvalue.left;
imap_put(&table->targets, value, target);
}
}
static void emit_jumptable(struct ir* targetvalue, struct jumptable* jumptable)
{
int i;
materialise_stack();
for (i=0; i<jumptable->targets.count; i++)
{
int value = jumptable->targets.item[i].left;
struct basicblock* target = jumptable->targets.item[i].right;
struct basicblock* nextblock = bb_get(NULL);
array_append(&current_proc->blocks, nextblock);
appendir(
new_ir2(
IR_CJUMPEQ, 0,
new_ir2(
IR_COMPARESI, EM_wordsize,
targetvalue,
new_wordir(value)
),
new_ir2(
IR_PAIR, 0,
new_bbir(target),
new_bbir(nextblock)
)
)
);
current_bb = nextblock;
}
appendir(
new_ir1(
IR_JUMP, 0,
new_bbir(jumptable->defaulttarget)
)
);
}
/* vim: set sw=4 ts=4 expandtab : */

View file

@ -83,7 +83,7 @@ extern short em_ptyp[];
/* machine dependent */
void con_part(int, word);
void con_mult(word);
int con_float(void); /* actually returns void, but need K&R C compatibility */
void con_float(void); /* actually returns void, but need K&R C compatibility */
void prolog(full nlocals);
void mes(word);

View file

@ -206,6 +206,16 @@ This is not followed by automatic alignment.
.Pu ".data4 \fIexpression [, expression]*\fP"
Initialize a sequence of longs (4-byte values).
This is not followed by automatic alignment.
.Pu ".dataf4 \fIliteralfloat [, literalfloat]*\fP"
Initialize a sequence of floats (4-byte values).
The values must be literal floating point constants containing
a dot character.
This is not followed by automatic alignment.
.Pu ".dataf8 \fIliteralfloat [, literalfloat]*\fP"
Initialize a sequence of doubles (8-byte values).
The values must be literal floating point constants containing
a dot character.
This is not followed by automatic alignment.
.Pu ".ascii \fIstring\fP"
Initialize a sequence of bytes with the value of the bytes in
the string.

37
plat/linuxmips/README Normal file
View file

@ -0,0 +1,37 @@
The linuxmips platform
======================
linuxmips is a little-endian MIPS32r2 BSP that produces Linux MIPS executables.
This port only implements a very limited number of system calls; basically,
just enough to make the demo apps run. Adding more is easy, but there are some
subtleties that require more thought. The port should be considered only in
proof-of-concept stage right now.
Important note: you *can't* link access ELF shared libraries from these
executables. In other words, you have to all your work from inside ACK.
IEEE floating point is available, but requires an FPU.
The executables are generated with aelfslod and are extremely simple; there's
one rwx ELF section which contains all the application's code and data. This
is not optimal, but it does work. Symbols are provided.
Bugs
====
isatty() is a stub and always returns 0.
Example command line
====================
ack -mlinuxmips -O -o linuxmips.exe examples/paranoia.c
The file linuxmips.exe can then be run on a MIPS32r2 Linux machine (or on an
emulation thereof).
David Given
dg@cowlark.com

58
plat/linuxmips/boot.s Normal file
View file

@ -0,0 +1,58 @@
#
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
.define .entry
.entry:
! This code is placed at the beginning of the ELF executable and is the
! first thing that runs.
!
! On entry, the stack looks like this:
!
! sp+... NULL
! sp+8+(4*argc) env (X quads)
! sp+4+(4*argc) NULL
! sp+4 argv (argc quads)
! sp argc
!
! The ACK actually expects:
!
! sp+8 argc
! sp+4 ptr to argv
! sp ptr to env
lw r4, 0(sp) ! r4 = argc
addiu r5, sp, 4 ! r5 = argv
sll r6, r4, 2 ! r6 = argc*4
addu r6, r6, r5 ! r6 = null after last arg
addiu r6, r6, 4 ! r6 = env
addiu sp, sp, -3 * 4
sw r4, 0(sp) ! argc
sw r5, 4(sp) ! argv
sw r6, 8(sp) ! envp
j __m_a_i_n
nop
! Define symbols at the beginning of our various segments, so that we can find
! them. (Except .text, which has already been done.)
.sect .data; begdata:
.sect .rom; begrom:
.sect .bss; begbss:
! Some magic data. All EM systems need these.
.define _errno
.comm _errno, 4 ! Posix errno storage
.define .trppc, .ignmask
.comm .trppc, 4 ! ptr to user trap handler
.comm .ignmask, 4 ! user trap ignore mask

View file

@ -0,0 +1,25 @@
include("plat/build.lua")
ackfile {
name = "boot",
srcs = { "./boot.s" },
vars = { plat = "linuxmips" }
}
build_plat_libs {
name = "libs",
arch = "mips",
plat = "linuxmips",
}
installable {
name = "pkg",
map = {
"+tools",
"+libs",
"./include+pkg",
["$(PLATIND)/linuxmips/boot.o"] = "+boot",
["$(PLATIND)/linuxmips/libsys.a"] = "./libsys+lib",
}
}

View file

@ -0,0 +1,29 @@
include("plat/build.lua")
build_as {
name = "as",
arch = "mips",
deps = { "mach/mips/as+astables" }
}
build_mcg {
name = "mcg",
arch = "mips",
}
build_top {
name = "top",
arch = "mips",
}
return installable {
name = "tools",
map = {
["$(PLATDEP)/linuxmips/as"] = "+as",
["$(PLATDEP)/linuxmips/mcg"] = "+mcg",
["$(PLATDEP)/linuxmips/top"] = "+top",
["$(PLATIND)/descr/linuxmips"] = "./descr",
"util/amisc+aelflod-pkg",
"util/opt+pkg",
}
}

87
plat/linuxmips/descr Normal file
View file

@ -0,0 +1,87 @@
# plat/linuxppc/descr
var w=4
var wa=4
var p={w}
var pa={w}
var s=2
var sa={s}
var l={w}
var la={w}
var f={w}
var fa={w}
var d=8
var da={d}
var x=8
var xa={x}
var ARCH=mips
var PLATFORM=linuxmips
var PLATFORMDIR={EM}/share/ack/{PLATFORM}
var CPP_F=-D__unix
var ALIGN=-a0:8 -a1:8 -a2:8 -a3:8 -b0:0x00400058
var MACHOPT_F=-m2
#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.
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}/mcg
mapflag -gdb GF=-gdb
args {GF?} <
stdout
need .e
end
name asopt
from .s
to .so
program {EM}/lib/ack/{PLATFORM}/top
args
optimizer
stdin
stdout
end
name as
from .s.so
to .o
program {EM}/lib/ack/{PLATFORM}/as
args - -o > <
prep cond
end
name led
from .o.a
to .out
program {EM}/lib/ack/em_led
mapflag -l* LNAME={PLATFORMDIR}/lib*
mapflag -fp FLOATS={EM}/{LIB}fp
args {ALIGN} {SEPID?} \
({RTS}:.b=-u _i_main) \
(.e:{HEAD}={PLATFORMDIR}/boot.o) \
({RTS}:.ocm.bas.b={PLATFORMDIR}/c-ansi.o) \
({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
({RTS}:.mod={PLATFORMDIR}/modula2.o) \
({RTS}:.p={PLATFORMDIR}/pascal.o) \
-o > < \
(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
(.b:{TAIL}={PLATFORMDIR}/libb.a) \
(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
{FLOATS?} \
(.e:{TAIL}={PLATFORMDIR}/libem.a \
{PLATFORMDIR}/libsys.a \
{PLATFORMDIR}/libend.a)
linker
end
name cv
from .out
to .exe
program {EM}/bin/aelflod
args -m8 -l -f0x70001000 < >
outfile linuxmips.exe
end

View file

@ -0,0 +1,4 @@
installable {
name = "pkg",
map = { "plat/linux/include+pkg" }
}

View file

@ -0,0 +1,34 @@
#
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#define EINVAL 22
! Perform a Linux system call.
.define __syscall
__syscall:
lw r2, 0(sp) ! syscall number
addiu r2, r2, 4000 ! MIPS uses non-standard numbers
lw r4, 4(sp)
lw r5, 8(sp)
lw r6, 12(sp)
syscall 0
beq r7, zero, exit ! branch on success
nop
/* The result (in r2) is the errno. */
lui at, ha16[_errno]
sw r2, lo16[_errno] (at)
li r2, -1
exit:
jr ra
nop

View file

@ -0,0 +1,33 @@
acklibrary {
name = "lib",
srcs = {
"./_syscall.s",
"plat/linux/libsys/_exit.c",
"plat/linux/libsys/_hol0.s",
"plat/linux/libsys/close.c",
"plat/linux/libsys/creat.c",
"plat/linux/libsys/execve.c",
"plat/linux/libsys/getpid.c",
"plat/linux/libsys/gettimeofday.c",
"plat/linux/libsys/ioctl.c",
"plat/linux/libsys/isatty.c",
"plat/linux/libsys/kill.c",
"plat/linux/libsys/lseek.c",
"plat/linux/libsys/open.c",
"plat/linux/libsys/read.c",
"plat/linux/libsys/sbrk.c",
"plat/linux/libsys/signal.c",
"plat/linux/libsys/sigprocmask.c",
"plat/linux/libsys/unlink.c",
"plat/linux/libsys/write.c",
},
deps = {
"plat/linux/libsys/*.h",
"lang/cem/libcc.ansi/headers+headers",
"plat/linuxmips/include+pkg",
},
vars = {
plat = "linuxmips"
}
}

View file

@ -0,0 +1,8 @@
include("tests/plat/build.lua")
plat_testsuite {
name = "tests",
plat = "linuxmips",
method = "qemu-mipsel",
-- skipsets = {"m2"},
}

75
tests/plat/core/aar_e.e Normal file
View file

@ -0,0 +1,75 @@
#
mes 2, EM_WSIZE, EM_PSIZE
/*
* Does basic testing of aar. Unfortunately, aar throws ERANGE on
* error, which we can't catch (or at least, the platforms I've looked at
* don't allow it to be caught, those platforms which actually throw it on
* error). So we just test the non-throwing cases, not the negative ones.
*/
array
bss 3*EM_WSIZE, 0, 0
descriptor
con -1 ; lower bound
con 2 ; range, *inclusive*
con EM_WSIZE ; size of element
exp $_m_a_i_n
pro $_m_a_i_n, 0
/* Access element -1 */
lae array
loc -1
lae descriptor
aar EM_WSIZE
lae array
cmu EM_WSIZE
zeq *1
loc __LINE__
cal $fail
ass EM_WSIZE
1
/* Access element 0 */
lae array
loc 0
lae descriptor
aar EM_WSIZE
lae array
adp EM_WSIZE
cmu EM_WSIZE
zeq *2
loc __LINE__
cal $fail
ass EM_WSIZE
2
/* Access element 1 */
lae array
loc 1
lae descriptor
aar EM_WSIZE
lae array
adp EM_WSIZE*2
cmu EM_WSIZE
zeq *3
loc __LINE__
cal $fail
ass EM_WSIZE
3
cal $finished
end

54
tests/plat/core/and_e.e Normal file
View file

@ -0,0 +1,54 @@
#
mes 2, EM_WSIZE, EM_PSIZE
exp $_m_a_i_n
pro $_m_a_i_n, 0
/* And word-sized set */
four
rom EM_WSIZE
loc 32769
loc 1
loe four /* to defeat constant folding */
and
loc 1
cmu EM_WSIZE
zeq *1
loc __LINE__
cal $fail
asp 4
1
/* And triple-word-sized set */
four_by_three
rom EM_WSIZE*3
loc 32769
loc 32770
loc 32772
loc 1
loc 2
loc 4
loe four_by_three
and
loc 4
cmu EM_WSIZE
zne *2
loc 2
cmu EM_WSIZE
zne *2
loc 1
cmu EM_WSIZE
zeq *3
2
loc __LINE__
cal $fail
asp 4
3
cal $finished
end

75
tests/plat/core/cms_e.e Normal file
View file

@ -0,0 +1,75 @@
#
mes 2, EM_WSIZE, EM_PSIZE
exp $_m_a_i_n
pro $_m_a_i_n, 0
/* Compare equal word sets. */
word
rom EM_WSIZE
loc 1
loc 1
loe word /* to defeat constant folding */
cms
zeq *1
loc __LINE__
cal $fail
asp 4
1
/* Compare non-equal word sets. */
loc 1
loc 2
loe word /* to defeat constant folding */
cms
zne *2
loc __LINE__
cal $fail
asp 4
2
/* Compare equal triple-word sets. */
loc 1
loc 2
loc 3
loc 1
loc 2
loc 3
loe word /* to defeat constant folding */
loc 3
mli EM_WSIZE
cms
zeq *3
loc __LINE__
cal $fail
asp 4
3
/* Compare non-equal triple-word sets. */
loc 1
loc 2
loc 3
loc 1
loc 2
loc 4
loe word /* to defeat constant folding */
loc 3
mli EM_WSIZE
cms
zne *4
loc __LINE__
cal $fail
asp 4
4
cal $finished
end

54
tests/plat/core/ior_e.e Normal file
View file

@ -0,0 +1,54 @@
#
mes 2, EM_WSIZE, EM_PSIZE
exp $_m_a_i_n
pro $_m_a_i_n, 0
/* Or word-sized set */
four
rom EM_WSIZE
loc 0
loc 1
loe four /* to defeat constant folding */
ior
loc 1
cmu EM_WSIZE
zeq *1
loc __LINE__
cal $fail
asp 4
1
/* Or triple-word-sized set */
four_by_three
rom EM_WSIZE*3
loc 16
loc 32
loc 64
loc 1
loc 2
loc 3
loe four_by_three
ior
loc 67
cmu EM_WSIZE
zne *2
loc 34
cmu EM_WSIZE
zne *2
loc 17
cmu EM_WSIZE
zeq *3
2
loc __LINE__
cal $fail
asp 4
3
cal $finished
end

73
tests/plat/core/lar_e.e Normal file
View file

@ -0,0 +1,73 @@
#
mes 2, EM_WSIZE, EM_PSIZE
/*
* Does basic testing of lar. Unfortunately, lar throws ERANGE on
* error, which we can't catch (or at least, the platforms I've looked at
* don't allow it to be caught, those platforms which actually throw it on
* error). So we just test the non-throwing cases, not the negative ones.
*/
#define ARRAY_SIZE 3*EM_WSIZE
array
con 1
con 2
con 3
descriptor
con -1 ; lower bound
con 2 ; range, *inclusive*
con EM_WSIZE ; size of element
exp $_m_a_i_n
pro $_m_a_i_n, 0
/* Read element -1 */
lae array
loc -1
lae descriptor
lar EM_WSIZE
loc 1
beq *1
loc __LINE__
cal $fail
ass EM_WSIZE
1
/* Read element 0 */
lae array
loc 0
lae descriptor
lar EM_WSIZE
loc 2
beq *2
loc __LINE__
cal $fail
ass EM_WSIZE
2
/* Read element 1 */
lae array
loc 1
lae descriptor
lar EM_WSIZE
loc 3
beq *3
loc __LINE__
cal $fail
ass EM_WSIZE
3
cal $finished
end

125
tests/plat/core/sar_e.e Normal file
View file

@ -0,0 +1,125 @@
#
mes 2, EM_WSIZE, EM_PSIZE
/*
* Does basic testing of sar. Unfortunately, sar throws ERANGE on
* error, which we can't catch (or at least, the platforms I've looked at
* don't allow it to be caught, those platforms which actually throw it on
* error). So we just test the non-throwing cases, not the negative ones.
*/
#define ARRAY_SIZE 3*EM_WSIZE
array
bss ARRAY_SIZE, 0, 0
descriptor
con -1 ; lower bound
con 2 ; range, *inclusive*
con EM_WSIZE ; size of element
element0
con 1
con 0
con 0
element1
con 0
con 1
con 0
element2
con 0
con 0
con 1
exp $_m_a_i_n
pro $_m_a_i_n, 0
/* Write element -1 */
cal $clear_array
loc 1
lae array
loc -1
lae descriptor
sar EM_WSIZE
lae array
loi ARRAY_SIZE
lae element0
loi ARRAY_SIZE
loc ARRAY_SIZE
cms
zeq *1
loc __LINE__
cal $fail
ass EM_WSIZE
1
/* Write element 0 */
cal $clear_array
loc 1
lae array
loc 0
lae descriptor
sar EM_WSIZE
lae array
loi ARRAY_SIZE
lae element1
loi ARRAY_SIZE
loc ARRAY_SIZE
cms
zeq *2
loc __LINE__
cal $fail
ass EM_WSIZE
2
/* Write element 1 */
cal $clear_array
loc 1
lae array
loc 1
lae descriptor
sar EM_WSIZE
lae array
loi ARRAY_SIZE
lae element2
loi ARRAY_SIZE
loc ARRAY_SIZE
cms
zeq *3
loc __LINE__
cal $fail
ass EM_WSIZE
3
cal $finished
end
exp $clear_array
pro $clear_array, 0
loc 0
lae array + EM_WSIZE*0
sti EM_WSIZE
loc 0
lae array + EM_WSIZE*1
sti EM_WSIZE
loc 0
lae array + EM_WSIZE*2
sti EM_WSIZE
ret 0
end

50
tests/plat/core/set_e.e Normal file
View file

@ -0,0 +1,50 @@
#
mes 2, EM_WSIZE, EM_PSIZE
exp $_m_a_i_n
pro $_m_a_i_n, 0
/* Create word-sized singleton set. */
word
rom EM_WSIZE
loc 1
loe word /* to defeat constant folding */
set
loc 2
cmu EM_WSIZE
zeq *1
loc __LINE__
cal $fail
asp 4
1
/* Create triple-word-sized set with low bit */
loc EM_WSIZE*8 + 1
loe word /* to defeat constant folding */
loc 3
mli EM_WSIZE
set
loc 0
cmu EM_WSIZE
zne *2
loc 2
cmu EM_WSIZE
zne *2
loc 0
cmu EM_WSIZE
zeq *3
2
loc __LINE__
cal $fail
asp 4
3
cal $finished
end

54
tests/plat/core/xor_e.e Normal file
View file

@ -0,0 +1,54 @@
#
mes 2, EM_WSIZE, EM_PSIZE
exp $_m_a_i_n
pro $_m_a_i_n, 0
/* Xor word-sized set */
four
rom EM_WSIZE
loc 32769
loc 1
loe four /* to defeat constant folding */
xor
loc 32768
cmu EM_WSIZE
zeq *1
loc __LINE__
cal $fail
asp 4
1
/* Xor triple-word-sized set */
four_by_three
rom EM_WSIZE*3
loc 32769
loc 32770
loc 32772
loc 1
loc 2
loc 4
loe four_by_three
xor
loc 32768
cmu EM_WSIZE
zne *2
loc 32768
cmu EM_WSIZE
zne *2
loc 32768
cmu EM_WSIZE
zeq *3
2
loc __LINE__
cal $fail
asp 4
3
cal $finished
end

View file

@ -6,7 +6,9 @@ double one = 1.0;
double zero = 0.0;
double minusone = -1.0;
double big = (double)INT_MAX;
double minusbig = (double)INT_MIN;
/* We don't test INT_MIN because some platforms *cough*mips*cough* don't handle
* it correctly, and we don't want to fail them. */
double minusbig = (double)(INT_MIN+1);
/* Bypasses the CRT, so there's no stdio. */
void _m_a_i_n(void)
@ -15,7 +17,7 @@ void _m_a_i_n(void)
ASSERT((int)one == 1);
ASSERT((int)minusone == -1);
ASSERT((int)big == INT_MAX);
ASSERT((int)minusbig == INT_MIN);
ASSERT((int)minusbig == (INT_MIN+1));
finished();
}

View file

@ -9,7 +9,7 @@ void finished(void)
_exit(0);
}
void writehex(uint32_t code)
void writehex(unsigned int code)
{
char buf[8];
char* p = &buf[sizeof(buf)];
@ -24,7 +24,7 @@ void writehex(uint32_t code)
write(1, p, buf + sizeof(buf) - p);
}
void fail(uint32_t code)
void fail(unsigned int code)
{
static const char fail_msg[] = "@@FAIL 0x";
static const char nl_msg[] = "\n";

View file

@ -5,8 +5,8 @@
#include <stdint.h>
extern void finished(void);
extern void writehex(uint32_t code);
extern void fail(uint32_t code);
extern void writehex(unsigned int code);
extern void fail(unsigned int code);
#define ASSERT(condition) \
do { if (!(condition)) fail(__LINE__); } while(0)

View file

@ -35,6 +35,10 @@ The default value is \fI3\fP for Intel 386 (i386).
Other values are \fI4\fP for Motorola 68000 (m68k)
and \fI20\fP for PowerPC.
.TP
.BI \-f number
Set the processor flags in the ELF header to \fInumber\fP.
The default value is 0.
.TP
.B \-v
Be verbose.
.PP

View file

@ -33,6 +33,7 @@
int bigendian = 0;
int elfabi = 3; /* abi = Linux */
int elfmachine = 3; /* machine = EM_386 */
uint32_t elfflags = 0; /* elf processor flags */
/* Header and section table of an ack object file. */
@ -643,7 +644,7 @@ int main(int argc, char* argv[])
switch (argv[1][1])
{
case 'a':
elfabi = atoi(&argv[1][2]);
elfabi = strtoul(&argv[1][2], NULL, 0);
break;
case 'b':
@ -660,7 +661,11 @@ int main(int argc, char* argv[])
break;
case 'm':
elfmachine = atoi(&argv[1][2]);
elfmachine = strtoul(&argv[1][2], NULL, 0);
break;
case 'f':
elfflags = strtoul(&argv[1][2], NULL, 0);
break;
case 'v':
@ -808,7 +813,7 @@ int main(int argc, char* argv[])
emit32(outsect[TEXT].os_base); /* entry point */
emit32(ELF_HEADER_SIZE); /* program header offset */
emit32(sh_offset); /* section header offset */
emit32(0); /* flags */
emit32(elfflags); /* flags */
emit16(ELF_HEADER_SIZE); /* elf header size */
emit16(PROGRAM_HEADER_SIZE); /* program header entry size */
emit16(1); /* number of program header entries */

View file

@ -134,6 +134,12 @@ showrelo()
case RELO2:
printf("\t2 bytes\n");
break;
case RELO2HI:
printf("\ttop 2 bytes of result\n");
break;
case RELO2HISAD:
printf("\ttop 2 bytes of result, sign adjusted\n");
break;
case RELO4:
printf("\t4 bytes\n");
break;
@ -146,6 +152,9 @@ showrelo()
case RELOVC4:
printf("\tVideoCore IV address in 32-bit instruction\n");
break;
case RELOMIPS:
printf("\tMIPS b or j instruction\n");
break;
default:
printf("\tunknown relocation type %d\n", relrec.or_type & RELSZ);
break;

View file

@ -579,7 +579,7 @@ addbase(name)
return;
name->on_valu += outsect[sectindex].os_base;
debug( "%s: type 0x%x, value %ld\n",
debug( "%s: type 0x%x, value 0x%lx\n",
address((name->on_type & S_EXT) ? ALLOGCHR : ALLOLCHR,
(ind_t)name->on_foff
),

View file

@ -18,7 +18,7 @@ static char rcsid[] = "$Id$";
#include "orig.h"
#include "sym.h"
#define UBYTE(x) ((x) & BYTEMASK)
#define UBYTE(x) ((x)&BYTEMASK)
static uint16_t read2(char* addr, int type)
{
@ -34,10 +34,13 @@ static uint32_t read4(char* addr, int type)
{
unsigned short word0, word1;
if (type & RELBR) {
if (type & RELBR)
{
word0 = (UBYTE(addr[0]) << WIDTH) + UBYTE(addr[1]);
word1 = (UBYTE(addr[2]) << WIDTH) + UBYTE(addr[3]);
} else {
}
else
{
word0 = (UBYTE(addr[1]) << WIDTH) + UBYTE(addr[0]);
word1 = (UBYTE(addr[3]) << WIDTH) + UBYTE(addr[2]);
}
@ -61,9 +64,9 @@ static uint32_t get_vc4_valu(char* addr)
* st<w> rd, $+o: [1110 0111 ww 1 d:5] [11111 o:27]
*/
int32_t value = read4(addr+2, 0);
int32_t value = read4(addr + 2, 0);
value &= 0x07ffffff;
value = value<<5>>5;
value = value << 5 >> 5;
return value;
}
@ -75,7 +78,7 @@ static uint32_t get_vc4_valu(char* addr)
uint32_t value = read4(addr, RELWR);
value &= 0x007fffff;
value = value<<9>>9;
value = value << 9 >> 9;
value *= 2;
return value;
}
@ -90,18 +93,18 @@ static uint32_t get_vc4_valu(char* addr)
int32_t value = read4(addr, RELWR);
int32_t lov = value & 0x007fffff;
int32_t hiv = value & 0x0f000000;
value = lov | (hiv>>1);
value = value<<5>>5;
value = lov | (hiv >> 1);
value = value << 5 >> 5;
value *= 2;
return value;
}
if ((opcode & 0xffe0) == 0xe500)
{
/* lea: [1110 0101 000 d:5] [o:32] */
/* lea: [1110 0101 000 d:5] [o:32] */
return read4(addr+2, 0);
}
return read4(addr + 2, 0);
}
assert(0 && "unrecognised VC4 instruction");
}
@ -137,22 +140,20 @@ static bool is_powerpc_memory_op(uint32_t opcode)
static uint32_t get_powerpc_valu(char* addr, uint16_t type)
{
uint32_t opcode1 = read4(addr+0, type);
uint32_t opcode2 = read4(addr+4, type);
uint32_t opcode1 = read4(addr + 0, type);
uint32_t opcode2 = read4(addr + 4, type);
if ((opcode1 & 0xfc000000) == 0x48000000)
{
/* branch instruction */
return opcode1 & 0x03fffffd;
}
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
((opcode2 & 0xfc000000) == 0x60000000))
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && ((opcode2 & 0xfc000000) == 0x60000000))
{
/* addis / ori instruction pair */
return ((opcode1 & 0xffff) << 16) | (opcode2 & 0xffff);
}
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
is_powerpc_memory_op(opcode2))
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && is_powerpc_memory_op(opcode2))
{
/* addis / memoryop instruction pair */
uint16_t hi = opcode1 & 0xffff;
@ -166,12 +167,13 @@ static uint32_t get_powerpc_valu(char* addr, uint16_t type)
return ((hi << 16) | lo);
}
fatal("Don't know how to read from PowerPC fixup on instructions 0x%08lx+0x%08lx",
(unsigned long)opcode1, (unsigned long)opcode2);
fatal(
"Don't know how to read from PowerPC fixup on instructions 0x%08lx+0x%08lx",
(unsigned long)opcode1, (unsigned long)opcode2);
}
/* RELOPPC_LIS stores a signed 26-bit offset in the low bits. */
static uint32_t get_lis_valu(char *addr, uint16_t type)
static uint32_t get_lis_valu(char* addr, uint16_t type)
{
uint32_t valu = read4(addr, type) & 0x03ffffff;
if (valu & 0x02000000)
@ -179,39 +181,71 @@ static uint32_t get_lis_valu(char *addr, uint16_t type)
return valu;
}
/* RELOMIPS is used for j and b instructions only. */
static uint32_t get_mips_valu(char* addr)
{
uint32_t value = read4(addr, 0);
switch (value >> 26)
{
case 2: /* j */
case 3: /* jal */
case 29: /* jalx */
/* Unsigned 26-bit payload. */
value = value & ((1 << 26) - 1);
break;
default: /* assume everything else is a b, there are lots */
/* Signed 16-bit payload. */
value = ((int32_t)value << 16) >> 16;
break;
}
/* The value has two implicit zero bits on the bottom. */
value <<= 2;
return value;
}
/*
* The bits in type indicate how many bytes the value occupies and what
* significance should be attributed to each byte.
*/
static uint32_t getvalu(char* addr, uint16_t type)
{
switch (type & RELSZ) {
case RELO1:
return UBYTE(addr[0]);
case RELO2:
return read2(addr, type);
case RELO4:
return read4(addr, type);
case RELOPPC:
return get_powerpc_valu(addr, type);
case RELOPPC_LIS:
return get_lis_valu(addr, type);
case RELOVC4:
return get_vc4_valu(addr);
default:
fatal("bad relocation type %x", type & RELSZ);
switch (type & RELSZ)
{
case RELO1:
return UBYTE(addr[0]);
case RELO2:
case RELO2HI:
case RELO2HISAD:
return read2(addr, type);
case RELO4:
return read4(addr, type);
case RELOPPC:
return get_powerpc_valu(addr, type);
case RELOPPC_LIS:
return get_lis_valu(addr, type);
case RELOVC4:
return get_vc4_valu(addr);
case RELOMIPS:
return get_mips_valu(addr);
default:
fatal("can't read relocation type %x", type & RELSZ);
}
/* NOTREACHED */
}
static void write2(uint16_t valu, char* addr, int type)
{
unsigned short word0, word1;
unsigned short word0, word1;
if (type & RELBR) {
if (type & RELBR)
{
addr[0] = valu >> WIDTH;
addr[1] = valu;
} else {
}
else
{
addr[0] = valu;
addr[1] = valu >> WIDTH;
}
@ -219,21 +253,27 @@ static void write2(uint16_t valu, char* addr, int type)
static void write4(uint32_t valu, char* addr, int type)
{
unsigned short word0, word1;
unsigned short word0, word1;
if (type & RELWR) {
if (type & RELWR)
{
word0 = valu >> (2 * WIDTH);
word1 = valu;
} else {
}
else
{
word0 = valu;
word1 = valu >> (2 * WIDTH);
}
if (type & RELBR) {
if (type & RELBR)
{
addr[0] = word0 >> WIDTH;
addr[1] = word0;
addr[2] = word1 >> WIDTH;
addr[3] = word1;
} else {
}
else
{
addr[0] = word0;
addr[1] = word0 >> WIDTH;
addr[2] = word1;
@ -255,10 +295,10 @@ static void put_vc4_valu(char* addr, uint32_t value)
* st<w> rd, o, (pc): [1110 0111 ww 1 d:5] [11111 o:27]
*/
uint32_t v = read4(addr+2, 0);
uint32_t v = read4(addr + 2, 0);
v &= 0xf8000000;
v |= value & 0x07ffffff;
write4(v, addr+2, 0);
write4(v, addr + 2, 0);
}
else if ((opcode & 0xf080) == 0x9000)
{
@ -268,7 +308,7 @@ static void put_vc4_valu(char* addr, uint32_t value)
uint32_t v = read4(addr, RELWR);
v &= 0xff800000;
v |= (value/2) & 0x007fffff;
v |= (value / 2) & 0x007fffff;
write4(v, addr, RELWR);
}
else if ((opcode & 0xf080) == 0x9080)
@ -279,19 +319,19 @@ static void put_vc4_valu(char* addr, uint32_t value)
*/
uint32_t v = read4(addr, RELWR);
uint32_t lovalue = (value/2) & 0x007fffff;
uint32_t hivalue = (value/2) & 0x07800000;
uint32_t lovalue = (value / 2) & 0x007fffff;
uint32_t hivalue = (value / 2) & 0x07800000;
v &= 0xf0800000;
v |= lovalue | (hivalue<<1);
v |= lovalue | (hivalue << 1);
write4(v, addr, RELWR);
}
else if ((opcode & 0xffe0) == 0xe500)
{
/* lea: [1110 0101 000 d:5] [o:32] */
/* lea: [1110 0101 000 d:5] [o:32] */
write4(value, addr+2, 0);
}
else
write4(value, addr + 2, 0);
}
else
assert(0 && "unrecognised VC4 instruction");
}
@ -302,8 +342,8 @@ static void put_vc4_valu(char* addr, uint32_t value)
static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type)
{
uint32_t opcode1 = read4(addr+0, type);
uint32_t opcode2 = read4(addr+4, type);
uint32_t opcode1 = read4(addr + 0, type);
uint32_t opcode2 = read4(addr + 4, type);
if ((opcode1 & 0xfc000000) == 0x48000000)
{
@ -312,18 +352,16 @@ static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type)
i |= value & 0x03fffffd;
write4(i, addr, type);
}
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
((opcode2 & 0xfc000000) == 0x60000000))
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && ((opcode2 & 0xfc000000) == 0x60000000))
{
/* addis / ori instruction pair */
uint16_t hi = value >> 16;
uint16_t lo = value & 0xffff;
write4((opcode1 & 0xffff0000) | hi, addr+0, type);
write4((opcode2 & 0xffff0000) | lo, addr+4, type);
write4((opcode1 & 0xffff0000) | hi, addr + 0, type);
write4((opcode2 & 0xffff0000) | lo, addr + 4, type);
}
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
is_powerpc_memory_op(opcode2))
else if (((opcode1 & 0xfc1f0000) == 0x3c000000) && is_powerpc_memory_op(opcode2))
{
/* addis / memoryop instruction pair */
uint16_t hi = value >> 16;
@ -334,13 +372,14 @@ static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type)
if (lo > 0x7fff)
hi++;
write4((opcode1 & 0xffff0000) | hi, addr+0, type);
write4((opcode2 & 0xffff0000) | lo, addr+4, type);
write4((opcode1 & 0xffff0000) | hi, addr + 0, type);
write4((opcode2 & 0xffff0000) | lo, addr + 4, type);
}
else
fatal("Don't know how to write a PowerPC fixup to instructions 0x%08lx+0x%08lx",
(unsigned long)opcode1, (unsigned long)opcode2);
fatal(
"Don't know how to write a PowerPC fixup to instructions 0x%08lx+0x%08lx",
(unsigned long)opcode1, (unsigned long)opcode2);
}
/* Writes a PowerPC lis instruction. */
@ -369,6 +408,36 @@ static void put_lis_valu(char* addr, uint32_t value, uint16_t type)
write4(opcode, addr, type);
}
/* RELOMIPS is used for j and b instructions only. */
static void put_mips_valu(char* addr, uint32_t value)
{
uint32_t opcode = read4(addr, 0);
/* The two bottom zero bits are implicit. */
if (value & 3)
fatal("invalid MIPS relocation value 0x%x", value);
value >>= 2;
switch (opcode >> 26)
{
case 2: /* j */
case 3: /* jal */
case 29: /* jalx */
/* Unsigned 26-bit payload. */
value = value & ((1 << 26) - 1);
opcode = opcode & ~((1 << 26) - 1);
break;
default: /* assume everything else is a b, there are lots */
/* Signed 16-bit payload. */
value = value & ((1 << 16) - 1);
opcode = opcode & ~((1 << 16) - 1);
break;
}
write4(opcode | value, addr, 0);
}
/*
* The bits in type indicate how many bytes the value occupies and what
* significance should be attributed to each byte.
@ -377,32 +446,42 @@ static void put_lis_valu(char* addr, uint32_t value, uint16_t type)
static putvalu(uint32_t valu, char* addr, uint16_t type)
{
switch (type & RELSZ) {
case RELO1:
addr[0] = valu;
break;
case RELO2:
write2(valu, addr, type);
break;
case RELO4:
write4(valu, addr, type);
break;
case RELOPPC:
put_powerpc_valu(addr, valu, type);
break;
case RELOPPC_LIS:
put_lis_valu(addr, valu, type);
break;
case RELOVC4:
put_vc4_valu(addr, valu);
break;
default:
fatal("bad relocation type %x", type & RELSZ);
switch (type & RELSZ)
{
case RELO1:
addr[0] = valu;
break;
case RELO2:
write2(valu, addr, type);
break;
case RELO2HI:
write2(valu >> 16, addr, type);
break;
case RELO2HISAD:
write2((valu >> 16) + !!(valu & 0x8000), addr, type);
break;
case RELO4:
write4(valu, addr, type);
break;
case RELOPPC:
put_powerpc_valu(addr, valu, type);
break;
case RELOPPC_LIS:
put_lis_valu(addr, valu, type);
break;
case RELOVC4:
put_vc4_valu(addr, valu);
break;
case RELOMIPS:
put_mips_valu(addr, valu);
break;
default:
fatal("can't write relocation type %x", type & RELSZ);
}
}
extern struct outsect outsect[];
extern struct orig relorig[];
extern struct outsect outsect[];
extern struct orig relorig[];
/*
* There are two cases: `local' is an undefined external or common name,
@ -416,42 +495,47 @@ extern struct orig relorig[];
* Second case: we must update the value by the change
* in position of the section of local.
*/
static unsigned
addrelo(relo, names, valu_out)
struct outrelo *relo;
struct outname *names;
long *valu_out; /* Out variable. */
static unsigned addrelo(relo, names, valu_out) struct outrelo* relo;
struct outname* names;
long* valu_out; /* Out variable. */
{
register struct outname *local = &names[relo->or_nami];
register unsigned short index = NLocals;
register long valu = *valu_out;
register struct outname* local = &names[relo->or_nami];
register unsigned short index = NLocals;
register long valu = *valu_out;
if ((local->on_type & S_SCT)) {
register int sectindex = (local->on_type & S_TYP) - S_MIN;
if ((local->on_type & S_SCT))
{
register int sectindex = (local->on_type & S_TYP) - S_MIN;
valu += relorig[sectindex].org_size;
valu += outsect[sectindex].os_base;
index += NGlobals + sectindex;
} else {
register struct outname *name;
extern int hash();
extern struct outname *searchname();
extern unsigned indexof();
extern struct outhead outhead;
}
else
{
register struct outname* name;
extern int hash();
extern struct outname* searchname();
extern unsigned indexof();
extern struct outhead outhead;
name = searchname(local->on_mptr, hash(local->on_mptr));
if (name == (struct outname *)0)
if (name == (struct outname*)0)
fatal("name %s not found in pass 2", local->on_mptr);
if (ISCOMMON(name) || ISUNDEFINED(name)) {
debug("can't relocate from %s\n",local->on_mptr,0,0,0);
if (ISCOMMON(name) || ISUNDEFINED(name))
{
debug("can't relocate from %s\n", local->on_mptr, 0, 0, 0);
index += indexof(name);
} else {
}
else
{
valu += name->on_valu;
if ((name->on_type & S_TYP) == S_ABS) {
if ((name->on_type & S_TYP) == S_ABS)
{
index += NGlobals + outhead.oh_nsect;
}
else index += NGlobals +
(name->on_type & S_TYP) - S_MIN;
else
index += NGlobals + (name->on_type & S_TYP) - S_MIN;
}
}
*valu_out = valu;
@ -463,21 +547,23 @@ addrelo(relo, names, valu_out)
* which the header is pointed to by `head'. Relocation is relative to the
* names in `names'; `relo' tells how to relocate.
*/
relocate(head, emit, names, relo, off)
struct outhead *head;
char *emit;
struct outname names[];
struct outrelo *relo;
long off;
relocate(head, emit, names, relo, off) struct outhead* head;
char* emit;
struct outname names[];
struct outrelo* relo;
long off;
{
long valu;
int sectindex = relo->or_sect - S_MIN;
extern struct outhead outhead;
long valu;
int sectindex = relo->or_sect - S_MIN;
extern struct outhead outhead;
uint32_t realaddress = outsect[sectindex].os_base + relo->or_addr
+ relorig[sectindex].org_size;
/*
* Pick up previous value at location to be relocated.
*/
valu = getvalu(emit + (relo->or_addr - off), relo->or_type);
debug("read relocation from 0x%08x type 0x%x value 0x%08x symbol %d\n", realaddress, relo->or_type, valu, relo->or_nami);
/*
* Or_nami is an index in the name table of the considered module.
@ -486,10 +572,13 @@ relocate(head, emit, names, relo, off)
* - a section name
* - the first name outside! the name table (argh)
*/
if (relo->or_nami < head->oh_nname) {
if (relo->or_nami < head->oh_nname)
{
/* First two cases. */
relo->or_nami = addrelo(relo, names, &valu);
} else {
}
else
{
/*
* Third case: it is absolute. The relocation of absolute
* names is always 0. We only need to change the index.
@ -504,11 +593,12 @@ relocate(head, emit, names, relo, off)
* now we subtract the origin of the referencING section.
*/
if (relo->or_type & RELPC)
valu -= relorig[sectindex].org_size+outsect[sectindex].os_base;
valu -= relorig[sectindex].org_size + outsect[sectindex].os_base;
/*
* Now put the value back.
*/
debug("written fixed up relocation to 0x%08x type 0x%x value 0x%08x\n", realaddress, relo->or_type, valu, 0);
putvalu(valu, emit + (relo->or_addr - off), relo->or_type);
/*

View file

@ -16,7 +16,10 @@
#include "smap.h"
#include "mcgg.h"
static char rcsid[] = "$Id$";
#define REGATTR_INT 0
#define REGATTR_LONG 1
#define REGATTR_FLOAT 2
#define REGATTR_DOUBLE 3
int maxcost = SHRT_MAX / 2;
@ -162,6 +165,18 @@ int main(int argc, char* argv[])
rule(&reg, tree(&NOPL, tree(&reg, NULL, NULL), NULL))->cost = 1;
rule(&reg, tree(&NOPD, tree(&reg, NULL, NULL), NULL))->cost = 1;
rule(NULL, tree(&RET, NULL, NULL))->cost = 1;
}
{
struct regattr* attr = makeregattr("int");
assert(attr->number == REGATTR_INT);
attr = makeregattr("long");
assert(attr->number == REGATTR_LONG);
attr = makeregattr("float");
assert(attr->number == REGATTR_FLOAT);
attr = makeregattr("double");
assert(attr->number == REGATTR_DOUBLE);
}
yyin = infp;
@ -612,7 +627,8 @@ static void emitregisterattrs(void)
assert(rc->number == i);
print("%1\"%s\",\n", rc->name);
printh("#define %P%s_ATTR (1U<<%d)\n", rc->name, rc->number);
if (rc->number > REGATTR_DOUBLE)
printh("#define %P%s_ATTR (1U<<%d)\n", rc->name, rc->number);
}
print("};\n\n");
printh("\n");
@ -655,7 +671,10 @@ static void emitregisters(void)
for (i=0; i<registers.count; i++)
{
struct reg* r = registers.item[i].right;
uint32_t type = r->attrs & TYPE_ATTRS;
assert(r->number == i);
if (type & (type-1))
yyerror("register %s has more than one type attribute set", r->name);
print("%1{ \"%s\", 0x%x, %Pregister_names_%d_%s, %Pregister_aliases_%d_%s },\n",
r->name, r->attrs, i, r->name, i, r->name);

View file

@ -17,6 +17,11 @@ struct ir_data
extern const struct ir_data ir_data[];
#define burm_int_ATTR (1U<<0)
#define burm_long_ATTR (1U<<1)
#define burm_float_ATTR (1U<<2)
#define burm_double_ATTR (1U<<3)
#define TYPE_ATTRS \
(burm_int_ATTR | burm_long_ATTR | burm_float_ATTR | burm_double_ATTR)

Some files were not shown because too many files have changed in this diff Show more