summaryrefslogtreecommitdiff
path: root/usr.bin/pcc/mips
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2007-10-07 17:58:53 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2007-10-07 17:58:53 +0000
commit14b353bdf99a61b29314822d06fff3f7250019ac (patch)
treecfb9b82ab66c64756933986a1d66b0b133819ab4 /usr.bin/pcc/mips
parent71267fa7f73e6e874cf9cb489551cb44ead37aba (diff)
reorg pcc tree; requested by and ok deraadt@; ok ragge@
Diffstat (limited to 'usr.bin/pcc/mips')
-rw-r--r--usr.bin/pcc/mips/TODO9
-rw-r--r--usr.bin/pcc/mips/code.c239
-rw-r--r--usr.bin/pcc/mips/local.c533
-rw-r--r--usr.bin/pcc/mips/local2.c774
-rw-r--r--usr.bin/pcc/mips/macdefs.h227
-rw-r--r--usr.bin/pcc/mips/order.c350
-rw-r--r--usr.bin/pcc/mips/table.c776
7 files changed, 2908 insertions, 0 deletions
diff --git a/usr.bin/pcc/mips/TODO b/usr.bin/pcc/mips/TODO
new file mode 100644
index 00000000000..4b104cf8ee2
--- /dev/null
+++ b/usr.bin/pcc/mips/TODO
@@ -0,0 +1,9 @@
+$OpenBSD: TODO,v 1.1 2007/10/07 17:58:51 otto Exp $
+
+* Look at long long support for the new register allocator.
+
+* Add floating point support.
+
+* Add support for struct/union arguments and return values.
+
+* See if the workaround for the function arguments can be removed/rewritten.
diff --git a/usr.bin/pcc/mips/code.c b/usr.bin/pcc/mips/code.c
new file mode 100644
index 00000000000..1ada0196529
--- /dev/null
+++ b/usr.bin/pcc/mips/code.c
@@ -0,0 +1,239 @@
+/* $OpenBSD: code.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+# include "pass1.h"
+# include "manifest.h"
+
+/* Offset to arguments passed to a function. */
+int passedargoff;
+
+/*
+ * cause the alignment to become a multiple of n
+ * never called for text segment.
+ */
+void
+defalign(int n)
+{
+ n /= SZCHAR;
+ if (n == 1)
+ return;
+ printf(" .align %d\n", n);
+}
+
+/*
+ * define the current location as the name p->sname
+ * never called for text segment.
+ */
+void
+defnam(struct symtab *p)
+{
+ char *c = p->sname;
+
+#ifdef GCC_COMPAT
+ c = gcc_findname(p);
+#endif
+ if (p->sclass == EXTDEF)
+ printf(" .globl %s\n", c);
+ printf("%s:\n", c);
+}
+
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode()
+{
+ NODE *p, *q;
+ int sz;
+
+ if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+ return;
+}
+
+/*
+ * helper for bfcode() to put register arguments on stack.
+ */
+static void
+argmove(struct symtab *s, int regno)
+{
+ NODE *p, *r;
+
+ s->sclass = PARAM;
+ s->soffset = NOOFFSET;
+
+ oalloc(s, &passedargoff);
+
+ spname = s;
+ p = buildtree(NAME, NIL, NIL);
+ r = bcon(0);
+ r->n_op = REG;
+ r->n_rval = regno;
+ r->n_type = p->n_type;
+ r->n_sue = p->n_sue;
+ r->n_df = p->n_df;
+ ecode(buildtree(ASSIGN, p, r));
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **a, int n)
+{
+ int i, m;
+
+ /* Passed arguments start 64 bits above the framepointer. */
+ passedargoff = 64;
+
+ if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+ /* Function returns struct, adjust arg offset */
+ for (i = 0; i < n; i++)
+ a[i]->soffset += SZPOINT(INT);
+ }
+
+ m = n <= 4 ? n : 4;
+
+ for(i = 0; i < m; i++) {
+ /*
+ if(a[i]->stype == LONGLONG || a[i]->stype == ULONGLONG) {
+ printf("longlong\n");
+ argmove(a[i], A0+i);
+
+ if(i+1 < 4) {
+ argmove(a[i], A0+i+1);
+ }
+
+ i++;
+ } else*/
+ argmove(a[i], A0+i);
+
+ }
+}
+
+
+/*
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+ SETOFF(autooff, SZINT);
+}
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag )
+{
+}
+
+void
+bjobcode()
+{
+}
+
+/*
+ * Print character t at position i in one string, until t == -1.
+ * Locctr & label is already defined.
+ */
+void
+bycode(int t, int i)
+{
+ static int lastoctal = 0;
+
+ /* put byte i+1 in a string */
+
+ if (t < 0) {
+ if (i != 0)
+ puts("\"");
+ } else {
+ if (i == 0)
+ printf("\t.ascii \"");
+ if (t == '\\' || t == '"') {
+ lastoctal = 0;
+ putchar('\\');
+ putchar(t);
+ } else if (t < 040 || t >= 0177) {
+ lastoctal++;
+ printf("\\%o",t);
+ } else if (lastoctal && '0' <= t && t <= '9') {
+ lastoctal = 0;
+ printf("\"\n\t.ascii \"%c", t);
+ } else {
+ lastoctal = 0;
+ putchar(t);
+ }
+ }
+}
+
+/*
+ * n integer words of zeros
+ */
+void
+zecode(int n)
+{
+ printf(" .zero %d\n", n * (SZINT/SZCHAR));
+ inoff += n * SZINT;
+}
+
+/*
+ * return the alignment of field of type t
+ */
+int
+fldal(unsigned int t)
+{
+ uerror("illegal field type");
+ return(ALINT);
+}
+
+/* fix up type of field p */
+void
+fldty(struct symtab *p)
+{
+}
+
+/* p points to an array of structures, each consisting
+ * of a constant value and a label.
+ * The first is >=0 if there is a default label;
+ * its value is the label number
+ * The entries p[1] to p[n] are the nontrivial cases
+ * XXX - fix genswitch.
+ */
+void
+genswitch(struct swents **p, int n)
+{
+}
diff --git a/usr.bin/pcc/mips/local.c b/usr.bin/pcc/mips/local.c
new file mode 100644
index 00000000000..554b53190f3
--- /dev/null
+++ b/usr.bin/pcc/mips/local.c
@@ -0,0 +1,533 @@
+/* $OpenBSD: local.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+# include "pass1.h"
+
+/* this file contains code which is dependent on the target machine */
+
+NODE *
+clocal(NODE *p)
+{
+ /* this is called to do local transformations on
+ an expression tree preparitory to its being
+ written out in intermediate code.
+ */
+
+ /* the major essential job is rewriting the
+ automatic variables and arguments in terms of
+ REG and OREG nodes */
+ /* conversion ops which are not necessary are also clobbered here */
+ /* in addition, any special features (such as rewriting
+ exclusive or) are easily handled here as well */
+
+ register struct symtab *q;
+ register NODE *r, *l;
+ register int o;
+ register int m, ml;
+ TWORD t;
+
+//printf("in:\n");
+//fwalk(p, eprint, 0);
+ switch( o = p->n_op ){
+
+ case NAME:
+ if ((q = p->n_sp) == NULL)
+ return p; /* Nothing to care about */
+
+ switch (q->sclass) {
+
+ case PARAM:
+ case AUTO:
+ /* fake up a structure reference */
+ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+ r->n_lval = 0;
+ r->n_rval = FPREG;
+ p = stref(block(STREF, r, p, 0, 0, 0));
+ break;
+
+ case STATIC:
+ if (q->slevel == 0)
+ break;
+ p->n_lval = 0;
+ p->n_sp = q;
+ break;
+
+ case REGISTER:
+ p->n_op = REG;
+ p->n_lval = 0;
+ p->n_rval = q->soffset;
+ break;
+
+ }
+ break;
+
+ case FUNARG:
+ /* Args smaller than int are given as int */
+ if (p->n_type != CHAR && p->n_type != UCHAR &&
+ p->n_type != SHORT && p->n_type != USHORT)
+ break;
+ p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKSUE(INT));
+ p->n_type = INT;
+ p->n_sue = MKSUE(INT);
+ p->n_rval = SZINT;
+ break;
+
+ case CBRANCH:
+ l = p->n_left;
+
+ /*
+ * Remove unneccessary conversion ops.
+ */
+ if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
+ if (coptype(l->n_op) != BITYPE)
+ break;
+ if (l->n_right->n_op == ICON) {
+ r = l->n_left->n_left;
+ if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
+ break;
+ /* Type must be correct */
+ t = r->n_type;
+ nfree(l->n_left);
+ l->n_left = r;
+ l->n_type = t;
+ l->n_right->n_type = t;
+ }
+#if 0
+ else if (l->n_right->n_op == SCONV &&
+ l->n_left->n_type == l->n_right->n_type) {
+ r = l->n_left->n_left;
+ nfree(l->n_left);
+ l->n_left = r;
+ r = l->n_right->n_left;
+ nfree(l->n_right);
+ l->n_right = r;
+ }
+#endif
+ }
+ break;
+
+ case PCONV:
+ ml = p->n_left->n_type;
+ l = p->n_left;
+ if ((ml == CHAR || ml == UCHAR || ml == SHORT || ml == USHORT)
+ && l->n_op != ICON)
+ break;
+ l->n_type = p->n_type;
+ l->n_qual = p->n_qual;
+ l->n_df = p->n_df;
+ l->n_sue = p->n_sue;
+ nfree(p);
+ p = l;
+ break;
+
+ case SCONV:
+ l = p->n_left;
+
+ if (p->n_type == l->n_type) {
+ nfree(p);
+ return l;
+ }
+
+ if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+ btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
+ if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+ l->n_type != FLOAT && l->n_type != DOUBLE &&
+ l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+ if (l->n_op == NAME || l->n_op == UMUL) {
+ l->n_type = p->n_type;
+ nfree(p);
+ return l;
+ }
+ }
+ }
+
+#if 0
+ if ((p->n_type == INT || p->n_type == UNSIGNED) &&
+ ISPTR(l->n_type)) {
+ nfree(p);
+ return l;
+ }
+#endif
+
+ o = l->n_op;
+ m = p->n_type;
+
+ if (o == ICON) {
+ CONSZ val = l->n_lval;
+
+ if (!ISPTR(m)) /* Pointers don't need to be conv'd */
+ switch (m) {
+ case CHAR:
+ l->n_lval = (char)val;
+ break;
+ case UCHAR:
+ l->n_lval = val & 0377;
+ break;
+ case SHORT:
+ l->n_lval = (short)val;
+ break;
+ case USHORT:
+ l->n_lval = val & 0177777;
+ break;
+ case ULONG:
+ case UNSIGNED:
+ l->n_lval = val & 0xffffffff;
+ break;
+ case ENUMTY:
+ case MOETY:
+ case LONG:
+ case INT:
+ l->n_lval = (int)val;
+ break;
+ case LONGLONG:
+ l->n_lval = (long long)val;
+ break;
+ case ULONGLONG:
+ l->n_lval = val;
+ break;
+ case VOID:
+ break;
+ case LDOUBLE:
+ case DOUBLE:
+ case FLOAT:
+ l->n_op = FCON;
+ l->n_dcon = val;
+ break;
+ default:
+ cerror("unknown type %d", m);
+ }
+ l->n_type = m;
+ nfree(p);
+ return l;
+ }
+ if (DEUNSIGN(p->n_type) == SHORT &&
+ DEUNSIGN(l->n_type) == SHORT) {
+ nfree(p);
+ p = l;
+ }
+ break;
+
+ case MOD:
+ case DIV:
+ if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
+ break;
+ if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
+ break;
+ /* make it an int division by inserting conversions */
+ p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKSUE(INT));
+ p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKSUE(INT));
+ p = block(SCONV, p, NIL, p->n_type, 0, MKSUE(p->n_type));
+ p->n_left->n_type = INT;
+ break;
+
+ case PMCONV:
+ case PVCONV:
+ if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
+ nfree(p);
+ return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
+
+ case FORCE:
+ /* put return value in return reg */
+ p->n_op = ASSIGN;
+ p->n_right = p->n_left;
+ p->n_left = block(REG, NIL, NIL, p->n_type, 0,
+ MKSUE(INT));
+ p->n_left->n_rval = RETREG;
+ break;
+ }
+//printf("ut:\n");
+//fwalk(p, eprint, 0);
+
+
+ return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+ return(1); /* all names can have & taken on them */
+}
+
+/*
+ * at the end of the arguments of a ftn, set the automatic offset
+ */
+void
+cendarg()
+{
+ autooff = AUTOINIT;
+}
+
+/*
+ * is an automatic variable of type t OK for a register variable
+ */
+int
+cisreg(TWORD t)
+{
+ if (t == INT || t == UNSIGNED || t == LONG || t == ULONG)
+ return(1);
+ return 0; /* XXX - fix reg assignment in pftn.c */
+}
+
+/*
+ * return a node, for structure references, which is suitable for
+ * being added to a pointer of type t, in order to be off bits offset
+ * into a structure
+ * t, d, and s are the type, dimension offset, and sizeoffset
+ * For pdp10, return the type-specific index number which calculation
+ * is based on its size. For example, short a[3] would return 3.
+ * Be careful about only handling first-level pointers, the following
+ * indirections must be fullword.
+ */
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
+{
+ register NODE *p;
+
+ if (xdebug)
+ printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
+ off, t, d, sue->suesize);
+
+ p = bcon(0);
+ p->n_lval = off/SZCHAR; /* Default */
+ return(p);
+}
+
+/*
+ * Allocate off bits on the stack. p is a tree that when evaluated
+ * is the multiply count for off, t is a NAME node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+ NODE *sp;
+
+ if ((off % SZINT) == 0)
+ p = buildtree(MUL, p, bcon(off/SZINT));
+ else if ((off % SZSHORT) == 0) {
+ p = buildtree(MUL, p, bcon(off/SZSHORT));
+ p = buildtree(PLUS, p, bcon(1));
+ p = buildtree(RS, p, bcon(1));
+ } else if ((off % SZCHAR) == 0) {
+ p = buildtree(MUL, p, bcon(off/SZCHAR));
+ p = buildtree(PLUS, p, bcon(3));
+ p = buildtree(RS, p, bcon(2));
+ } else
+ cerror("roundsp");
+
+ /* save the address of sp */
+ sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
+ sp->n_lval = 0;
+ sp->n_rval = STKREG;
+ t->n_type = sp->n_type;
+ ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+ /* add the size to sp */
+ sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+ sp->n_lval = 0;
+ sp->n_rval = STKREG;
+ ecomp(buildtree(PLUSEQ, sp, p));
+}
+
+/*
+ * print out a constant node
+ * mat be associated with a label
+ */
+void
+ninval(NODE *p)
+{
+ struct symtab *q;
+ TWORD t;
+
+ p = p->n_left;
+ t = p->n_type;
+ if (t > BTMASK)
+ t = INT; /* pointer */
+
+ switch (t) {
+ case LONGLONG:
+ case ULONGLONG:
+ inval(p->n_lval & 0xffffffff);
+ inval(p->n_lval >> 32);
+ break;
+ case INT:
+ case UNSIGNED:
+ printf("\t.long 0x%x", (int)p->n_lval);
+ if ((q = p->n_sp) != NULL) {
+ if ((q->sclass == STATIC && q->slevel > 0) ||
+ q->sclass == ILABEL) {
+ printf("+" LABFMT, q->soffset);
+ } else
+ printf("+%s", exname(q->sname));
+ }
+ printf("\n");
+ break;
+ default:
+ cerror("ninval");
+ }
+}
+
+/*
+ * print out an integer.
+ */
+void
+inval(CONSZ word)
+{
+ word &= 0xffffffff;
+ printf(" .long 0x%llx\n", word);
+}
+
+/* output code to initialize a floating point value */
+/* the proper alignment has been obtained */
+void
+finval(NODE *p)
+{
+ switch (p->n_type) {
+ case LDOUBLE:
+ printf("\t.tfloat\t0t%.20Le\n", p->n_dcon);
+ break;
+ case DOUBLE:
+ printf("\t.dfloat\t0d%.20e\n", (double)p->n_dcon);
+ break;
+ case FLOAT:
+ printf("\t.ffloat\t0f%.20e\n", (float)p->n_dcon);
+ break;
+ }
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+ if (p == NULL)
+ return "";
+ return p;
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+ switch (BTYPE(type)) {
+ case LONG:
+ MODTYPE(type,INT);
+ break;
+
+ case ULONG:
+ MODTYPE(type,UNSIGNED);
+
+ }
+ return (type);
+}
+
+/* curid is a variable which is defined but
+ * is not initialized (and not a function );
+ * This routine returns the storage class for an uninitialized declaration
+ */
+int
+noinit()
+{
+ return(EXTERN);
+}
+
+void
+calldec(NODE *p, NODE *q)
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+commdec(struct symtab *q)
+{
+ int off;
+
+ off = tsize(q->stype, q->sdf, q->ssue);
+ off = (off+(SZCHAR-1))/SZCHAR;
+
+#ifdef GCC_COMPAT
+ printf(" .comm %s,0%o\n", gcc_findname(q), off);
+#else
+ printf(" .comm %s,0%o\n", exname(q->sname), off);
+#endif
+}
+
+/* make a local common declaration for id, if reasonable */
+void
+lcommdec(struct symtab *q)
+{
+ int off;
+
+ off = tsize(q->stype, q->sdf, q->ssue);
+ off = (off+(SZCHAR-1))/SZCHAR;
+ if (q->slevel == 0)
+#ifdef GCC_COMPAT
+ printf(" .lcomm %s,0%o\n", gcc_findname(q), off);
+#else
+ printf(" .lcomm %s,0%o\n", exname(q->sname), off);
+#endif
+ else
+ printf(" .lcomm " LABFMT ",0%o\n", q->soffset, off);
+}
+
+/*
+ * print a (non-prog) label.
+ */
+void
+deflab1(int label)
+{
+ printf(LABFMT ":\n", label);
+}
+
+static char *loctbl[] = { "text", "data", "section .rodata", "section .rodata" };
+
+void
+setloc1(int locc)
+{
+ if (locc == lastloc)
+ return;
+ lastloc = locc;
+ printf(" .%s\n", loctbl[locc]);
+}
diff --git a/usr.bin/pcc/mips/local2.c b/usr.bin/pcc/mips/local2.c
new file mode 100644
index 00000000000..11d151a7f05
--- /dev/null
+++ b/usr.bin/pcc/mips/local2.c
@@ -0,0 +1,774 @@
+/* $OpenBSD: local2.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+# include "pass2.h"
+# include <ctype.h>
+
+void acon(NODE *p);
+int argsize(NODE *p);
+void genargs(NODE *p);
+static void sconv(NODE *p);
+void branchfunc(NODE *p);
+void offchg(NODE *p);
+
+void
+lineid(int l, char *fn)
+{
+ /* identify line l and file fn */
+ printf("# line %d, file %s\n", l, fn);
+}
+
+void
+deflab(int label)
+{
+ printf(LABFMT ":\n", label);
+}
+
+static int regoff[32];
+static TWORD ftype;
+
+/*
+ * Print out the prolog assembler.
+ * addto and regoff are already calculated.
+ */
+static void
+prtprolog(struct interpass_prolog *ipp, int addto)
+{
+ int i, j;
+
+ printf(" addi $sp, $sp, -%d\n", addto + 8);
+ printf(" sw $ra, %d($sp)\n", addto + 4);
+ printf(" sw $fp, %d($sp)\n", addto);
+ printf(" addi $fp, $sp, %d\n", addto);
+
+ for (i = ipp->ipp_regs, j = 0; i; i >>= 1, j++)
+ if (i & 1)
+ fprintf(stdout, " sw %s, -%d(%s)\n",
+ rnames[j], regoff[j], rnames[FPREG]);
+}
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog *ipp)
+{
+ int i, j, addto;
+
+ addto = p2maxautooff;
+ if (addto >= AUTOINIT)
+ addto -= AUTOINIT;
+ addto /= SZCHAR;
+
+ for (i = ipp->ipp_regs, j = 0; i ; i >>= 1, j++) {
+ if (i & 1) {
+ addto += SZINT/SZCHAR;
+ regoff[j] = addto;
+ }
+ }
+
+ return addto;
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+ int addto;
+
+ ftype = ipp->ipp_type;
+ if (ipp->ipp_vis)
+ printf(" .globl %s\n", ipp->ipp_name);
+ printf(" .align 4\n");
+ printf("%s:\n", ipp->ipp_name);
+ /*
+ * We here know what register to save and how much to
+ * add to the stack.
+ */
+ addto = offcalc(ipp);
+ prtprolog(ipp, addto);
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+ int i, j;
+ int addto;
+
+ addto = offcalc(ipp);
+
+ if (ipp->ipp_ip.ip_lbl == 0)
+ return; /* no code needs to be generated */
+
+ /* return from function code */
+ for (i = ipp->ipp_regs, j = 0; i ; i >>= 1, j++) {
+ if (i & 1)
+ fprintf(stdout, " lw %s, -%d(%s)\n",
+ rnames[j], regoff[j], rnames[FPREG]);
+ }
+
+ printf(" lw $ra, %d($sp)\n", addto + 4);
+ printf(" lw $fp, %d($sp)\n", addto);
+ printf(" addi $sp, $sp, %d\n", addto + 8);
+
+ /* struct return needs special treatment */
+ if (ftype == STRTY || ftype == UNIONTY) {
+ /* XXX - implement struct return support. */
+ } else {
+ printf(" jr $ra\n nop\n");
+ }
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+ char *str;
+
+ switch (o) {
+ case PLUS:
+ str = "addu";
+ break;
+ case MINUS:
+ str = "subu";
+ break;
+ case AND:
+ str = "and";
+ break;
+ case OR:
+ str = "or";
+ break;
+ case ER:
+ str = "xor";
+ break;
+ default:
+ comperr("hopcode2: %d", o);
+ str = 0; /* XXX gcc */
+ }
+
+ printf("%s%c", str, f);
+}
+
+char *
+rnames[] = { /* keyed to register number tokens */
+ "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8",
+ "$t9", "$v0", "$v1", "$zero", "$at", "$a0", "$a1", "$a2", "$a3",
+ "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", "$k0",
+ "$k1", "$gp", "$sp", "$fp", "$ra",
+};
+
+int
+tlen(p) NODE *p;
+{
+ switch(p->n_type) {
+ case CHAR:
+ case UCHAR:
+ return(1);
+
+ case SHORT:
+ case USHORT:
+ return(SZSHORT/SZCHAR);
+
+ case DOUBLE:
+ return(SZDOUBLE/SZCHAR);
+
+ case INT:
+ case UNSIGNED:
+ case LONG:
+ case ULONG:
+ return(SZINT/SZCHAR);
+
+ case LONGLONG:
+ case ULONGLONG:
+ return SZLONGLONG/SZCHAR;
+
+ default:
+ if (!ISPTR(p->n_type))
+ comperr("tlen type %d not pointer");
+ return SZPOINT(p->n_type)/SZCHAR;
+ }
+}
+
+
+/*
+ * Push a structure on stack as argument.
+ * the scratch registers are already free here
+ */
+static void
+starg(NODE *p)
+{
+ FILE *fp = stdout;
+
+ if (p->n_left->n_op == REG && p->n_left->n_type == PTR+STRTY)
+ return; /* already on stack */
+
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+ NODE *r;
+
+ switch (c) {
+ case 'A': /* Set the right offset for SCON OREG to REG */
+ offchg(p);
+ break;
+
+ case 'B':
+ /*
+ * Function arguments
+ */
+
+ break;
+
+ case 'C': /* remove arguments from stack after subroutine call */
+ printf(" addi %s, %s, %d\n",
+ rnames[STKREG], rnames[STKREG], (p->n_rval + 4) * 4);
+ break;
+
+ case 'H': /* Fix correct order of sub from stack */
+ /* Check which leg was evaluated first */
+ if ((p->n_su & DORIGHT) == 0)
+ putchar('r');
+ break;
+
+ case 'I': /* high part of init constant */
+ if (p->n_name[0] != '\0')
+ comperr("named highword");
+ fprintf(stdout, CONFMT, (p->n_lval >> 32) & 0xffffffff);
+ break;
+
+ case 'Q': /* Branch instructions */
+ branchfunc(p);
+ break;
+
+ default:
+ comperr("zzzcode %c", c);
+ }
+}
+
+/* set up temporary registers */
+void
+setregs()
+{
+ /* 12 free regs on the mips (0-9, temporary and 10-11 is v0 and v1). */
+ fregs = 12;
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+ return(1);
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+ int o = p->n_op;
+
+ if (o==NAME || o==REG || o==ICON || o==OREG ||
+ (o==UMUL && shumul(p->n_left)))
+ return(1);
+ return(0);
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+ int o = p->n_op;
+
+ if (o == OREG || o == REG || o == NAME)
+ return SRDIR; /* Direct match */
+ if (o == UMUL && shumul(p->n_left))
+ return SROREG; /* Convert into oreg */
+ return SRREG; /* put it into a register */
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE *p)
+{
+ return 0;
+#if 0
+ int r;
+
+ if (p->n_op == STARG )
+ p = p->n_left;
+
+ switch (p->n_op) {
+ case REG:
+ return (!istreg(p->n_rval));
+
+ case OREG:
+ r = p->n_rval;
+ if (R2TEST(r)) {
+ if (istreg(R2UPK1(r)))
+ return(0);
+ r = R2UPK2(r);
+ }
+ return (!istreg(r));
+
+ case UMUL:
+ p = p->n_left;
+ return (p->n_op != UMUL && shtemp(p));
+ }
+
+ if (optype(p->n_op) != LTYPE)
+ return(0);
+ return(1);
+#endif
+}
+
+void
+adrcon(CONSZ val)
+{
+ printf(CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+ int val = p->n_lval;
+
+ switch (p->n_op) {
+ case ICON:
+ if (p->n_name[0] != '\0') {
+ fprintf(fp, "%s", p->n_name);
+ if (val)
+ fprintf(fp, "+%d", val);
+ } else
+ fprintf(fp, "%d", val);
+ return;
+
+ default:
+ comperr("illegal conput");
+ }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+ comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+ size /= SZCHAR;
+ switch (p->n_op) {
+ case REG:
+ fputs(rnames[p->n_rval + 1], stdout);
+ break;
+
+ case NAME:
+ case OREG:
+ p->n_lval += size;
+ adrput(stdout, p);
+ p->n_lval -= size;
+ break;
+ case ICON:
+ fprintf(stdout, CONFMT, p->n_lval >> 32);
+ break;
+ default:
+ comperr("upput bad op %d size %d", p->n_op, size);
+ }
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+ int r;
+ /* output an address, with offsets, from p */
+
+ if (p->n_op == FLD)
+ p = p->n_left;
+
+ switch (p->n_op) {
+
+ case NAME:
+ if (p->n_name[0] != '\0')
+ fputs(p->n_name, io);
+ if (p->n_lval != 0)
+ fprintf(io, "+" CONFMT, p->n_lval);
+ return;
+
+ case OREG:
+ r = p->n_rval;
+
+ if (p->n_lval)
+ fprintf(io, "%d", (int)p->n_lval);
+
+ fprintf(io, "(%s)", rnames[p->n_rval]);
+ return;
+ case ICON:
+ /* addressable value of the constant */
+ //fputc('$', io);
+ conput(io, p);
+ return;
+
+ case MOVE:
+ case REG:
+ fprintf(io, "%s", rnames[p->n_rval]);
+ return;
+
+ default:
+ comperr("illegal address, op %d, node %p", p->n_op, p);
+ return;
+
+ }
+}
+
+/* This function changes the offset of a OREG when doing a type cast. */
+void
+offchg(NODE *p)
+{
+
+ if (p->n_op != SCONV) {
+ comperr("illegal offchg");
+ }
+
+#ifndef RTOLBYTES
+ /* change the offset depending on source and target types */
+ switch(p->n_left->n_type) {
+ case SHORT:
+ case USHORT:
+ if (p->n_type == CHAR || p->n_type == UCHAR) {
+ p->n_left->n_lval += 1;
+ }
+ break;
+
+ case UNSIGNED:
+ case ULONG:
+ case INT:
+ case LONG:
+ if (p->n_type == CHAR || p->n_type == UCHAR) {
+ p->n_left->n_lval += 3;
+ } else if (p->n_type == SHORT || p->n_type == USHORT) {
+ p->n_left->n_lval += 2;
+ }
+ break;
+
+ /* This code is not tested!
+ case LONGLONG:
+ case ULONGLONG:
+ if (p->n_type == CHAR || p->n_type == UCHAR) {
+ p->n_lval += 7;
+ } else if (p->n_type == SHORT || p->n_type == USHORT) {
+ p->n_lval += 6;
+ } else if (p->n_type == UNSIGNED || p->n_type == ULONG ||
+ p->n_type == INT || p->n_type == LONG) {
+
+ p->n_lval += 4;
+ }
+ break;
+ */
+ }
+#endif
+
+ /* print the code for the OREG */
+ if (p->n_left->n_lval) {
+ printf("%d", (int)p->n_left->n_lval);
+ }
+
+ printf("(%s)", rnames[p->n_left->n_rval]);
+
+}
+
+
+/* printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+}
+
+void branchfunc(NODE *p)
+{
+ int o = p->n_op;
+
+ if (o < EQ || o > GT)
+ cerror("bad binary conditional branch: %s", opst[o]);
+
+ switch(o) {
+ case EQ:
+ printf("beq ");
+ adrput(stdout, getlr(p, 'L'));
+ printf(", ");
+ adrput(stdout, getlr(p, 'R'));
+ printf(", ");
+ break;
+ case NE:
+ printf("bne ");
+ adrput(stdout, getlr(p, 'L'));
+ printf(", ");
+ adrput(stdout, getlr(p, 'R'));
+ printf(", ");
+ break;
+ case LE:
+ expand(p, 0, "blez A1, ");
+ break;
+ case LT:
+ expand(p, 0, "bltz A1, ");
+ break;
+ case GE:
+ expand(p, 0, "bgez A1, ");
+ break;
+ case GT:
+ expand(p, 0, "bgez A1, ");
+ break;
+ }
+ printf(".L%d\n", p->n_label);
+ printf(" nop\n");
+}
+
+#if 0
+/*
+ * Do some local optimizations that must be done after optim is called.
+ */
+static void
+optim2(NODE *p)
+{
+ int op = p->n_op;
+ int m, ml;
+ NODE *l;
+
+ /* Remove redundant PCONV's */
+ if (op == PCONV) {
+ l = p->n_left;
+ m = BTYPE(p->n_type);
+ ml = BTYPE(l->n_type);
+ if ((m == INT || m == LONG || m == LONGLONG || m == FLOAT ||
+ m == DOUBLE || m == STRTY || m == UNIONTY || m == ENUMTY ||
+ m == UNSIGNED || m == ULONG || m == ULONGLONG) &&
+ (ml == INT || ml == LONG || ml == LONGLONG || ml == FLOAT ||
+ ml == DOUBLE || ml == STRTY || ml == UNIONTY ||
+ ml == ENUMTY || ml == UNSIGNED || ml == ULONG ||
+ ml == ULONGLONG) && ISPTR(l->n_type)) {
+ *p = *l;
+ nfree(l);
+ op = p->n_op;
+ } else
+ if (ISPTR(DECREF(p->n_type)) &&
+ (l->n_type == INCREF(STRTY))) {
+ *p = *l;
+ nfree(l);
+ op = p->n_op;
+ } else
+ if (ISPTR(DECREF(l->n_type)) &&
+ (p->n_type == INCREF(INT) ||
+ p->n_type == INCREF(STRTY) ||
+ p->n_type == INCREF(UNSIGNED))) {
+ *p = *l;
+ nfree(l);
+ op = p->n_op;
+ }
+
+ }
+ /* Add constands, similar to the one in optim() */
+ if (op == PLUS && p->n_right->n_op == ICON) {
+ l = p->n_left;
+ if (l->n_op == PLUS && l->n_right->n_op == ICON &&
+ (p->n_right->n_name[0] == '\0' ||
+ l->n_right->n_name[0] == '\0')) {
+ l->n_right->n_lval += p->n_right->n_lval;
+ if (l->n_right->n_name[0] == '\0')
+ l->n_right->n_name = p->n_right->n_name;
+ nfree(p->n_right);
+ *p = *l;
+ nfree(l);
+ }
+ }
+
+ /* Convert "PTR undef" (void *) to "PTR uchar" */
+ /* XXX - should be done in MI code */
+ if (BTYPE(p->n_type) == VOID)
+ p->n_type = (p->n_type & ~BTMASK) | UCHAR;
+}
+#endif
+
+static void
+myhardops(NODE *p)
+{
+ int ty = optype(p->n_op);
+ NODE *l, *r, *q;
+
+ if (ty == UTYPE)
+ return myhardops(p->n_left);
+ if (ty != BITYPE)
+ return;
+ myhardops(p->n_right);
+ if (p->n_op != STASG)
+ return;
+
+ /*
+ * If the structure size to copy is less than 32 byte, let it
+ * be and generate move instructions later. Otherwise convert it
+ * to memcpy() calls, unless it has a STCALL function as its
+ * right node, in which case it is untouched.
+ * STCALL returns are handled special.
+ */
+ if (p->n_right->n_op == STCALL || p->n_right->n_op == USTCALL)
+ return;
+ l = p->n_left;
+ if (l->n_op == UMUL)
+ l = nfree(l);
+ else if (l->n_op == NAME) {
+ l->n_op = ICON; /* Constant reference */
+ l->n_type = INCREF(l->n_type);
+ } else
+ comperr("myhardops");
+ r = p->n_right;
+ q = mkbinode(CM, l, r, 0);
+ q = mkbinode(CM, q, mklnode(ICON, p->n_stsize, 0, INT), 0);
+ p->n_op = CALL;
+ p->n_right = q;
+ p->n_left = mklnode(ICON, 0, 0, 0);
+ p->n_left->n_name = "memcpy";
+}
+
+void
+myreader(NODE *p)
+{
+ int e2print(NODE *p, int down, int *a, int *b);
+ // walkf(p, optim2);
+ myhardops(p);
+ if (x2debug) {
+ printf("myreader final tree:\n");
+ fwalk(p, e2print, 0);
+ }
+}
+
+/*
+ * Remove some PCONVs after OREGs are created.
+ */
+static void
+pconv2(NODE *p)
+{
+ NODE *q;
+
+ if (p->n_op == PLUS) {
+ if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
+ if (p->n_right->n_op != ICON)
+ return;
+ if (p->n_left->n_op != PCONV)
+ return;
+ if (p->n_left->n_left->n_op != OREG)
+ return;
+ q = p->n_left->n_left;
+ nfree(p->n_left);
+ p->n_left = q;
+ /*
+ * This will be converted to another OREG later.
+ */
+ }
+ }
+}
+
+void
+mycanon(NODE *p)
+{
+ walkf(p, pconv2);
+}
+
+void
+mygenregs(NODE *p)
+{
+ if (p->n_op == MINUS && p->n_type == DOUBLE &&
+ (p->n_su & (LMASK|RMASK)) == (LREG|RREG)) {
+ p->n_su |= DORIGHT;
+ }
+ /* Must walk down correct node first for logops to work */
+ if (p->n_op != CBRANCH)
+ return;
+ p = p->n_left;
+ if ((p->n_su & (LMASK|RMASK)) != (LREG|RREG))
+ return;
+ p->n_su &= ~DORIGHT;
+}
+
+/*
+ * Remove last goto.
+ */
+void
+myoptim(struct interpass *ip)
+{
+#if 0
+ while (ip->sqelem.sqe_next->type != IP_EPILOG)
+ ip = ip->sqelem.sqe_next;
+ if (ip->type != IP_NODE || ip->ip_node->n_op != GOTO)
+ comperr("myoptim");
+ tfree(ip->ip_node);
+ *ip = *ip->sqelem.sqe_next;
+#endif
+}
+
+struct hardops hardops[] = {
+ { MUL, LONGLONG, "__muldi3" },
+ { MUL, ULONGLONG, "__muldi3" },
+ { DIV, LONGLONG, "__divdi3" },
+ { DIV, ULONGLONG, "__udivdi3" },
+ { MOD, LONGLONG, "__moddi3" },
+ { MOD, ULONGLONG, "__umoddi3" },
+ { RS, LONGLONG, "__ashrdi3" },
+ { RS, ULONGLONG, "__lshrdi3" },
+ { LS, LONGLONG, "__ashldi3" },
+ { LS, ULONGLONG, "__ashldi3" },
+#if 0
+ { STASG, PTR+STRTY, "memcpy" },
+ { STASG, PTR+UNIONTY, "memcpy" },
+#endif
+ { 0 },
+};
+
+void
+rmove(int s, int d, TWORD t)
+{
+ printf(" move %s, %s\n", rnames[d], rnames[s]);
+}
+
+
+
diff --git a/usr.bin/pcc/mips/macdefs.h b/usr.bin/pcc/mips/macdefs.h
new file mode 100644
index 00000000000..71e5b17f955
--- /dev/null
+++ b/usr.bin/pcc/mips/macdefs.h
@@ -0,0 +1,227 @@
+/* $OpenBSD: macdefs.h,v 1.1 2007/10/07 17:58:51 otto Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ * Assume: If only one value; store at left side (char size), otherwise
+ * treat it as an integer.
+ */
+#define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24);
+
+#define ARGINIT 64 /* # bits above fp where arguments start */
+#define AUTOINIT 0 /* # bits below fp where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR 8
+#define SZINT 32
+#define SZFLOAT 32
+#define SZDOUBLE 64
+#define SZLDOUBLE 96
+#define SZLONG 32
+#define SZSHORT 16
+#define SZLONGLONG 64
+#define SZPOINT(t) 32
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR 8
+#define ALINT 32
+#define ALFLOAT 32
+#define ALDOUBLE 32
+#define ALLDOUBLE 32
+#define ALLONG 32
+#define ALLONGLONG 32
+#define ALSHORT 16
+#define ALPOINT 32
+#define ALSTRUCT 32
+#define ALSTACK 32
+
+/*
+ * Min/max values.
+ */
+#define MIN_CHAR -128
+#define MAX_CHAR 127
+#define MAX_UCHAR 255
+#define MIN_SHORT -32768
+#define MAX_SHORT 32767
+#define MAX_USHORT 65535
+#define MIN_INT -1
+#define MAX_INT 0x7fffffff
+#define MAX_UNSIGNED 0xffffffff
+#define MIN_LONG MIN_INT
+#define MAX_LONG MAX_INT
+#define MAX_ULONG MAX_UNSIGNED
+#define MIN_LONGLONG 0x8000000000000000LL
+#define MAX_LONGLONG 0x7fffffffffffffffLL
+#define MAX_ULONGLONG 0xffffffffffffffffULL
+
+/* Default char is unsigned */
+#undef CHAR_UNSIGNED
+
+/*
+ * Use large-enough types.
+ */
+typedef long long CONSZ;
+typedef unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT "%lld" /* format for printing constants */
+#define LABFMT ".L%d" /* format for printing labels */
+#define STABLBL ".LL%d" /* format for stab (debugging) labels */
+#ifdef FORTRAN
+#define XL 8
+#define FLABELFMT "%s:\n"
+#define USETEXT ".text"
+#define USECONST ".data\t0" /* XXX - fix */
+#define USEBSS ".data\t1" /* XXX - fix */
+#define USEINIT ".data\t2" /* XXX - fix */
+#define MAXREGVAR 3 /* XXX - fix */
+#define BLANKCOMMON "_BLNK_"
+#define MSKIREG (M(TYSHORT)|M(TYLONG))
+#define TYIREG TYLONG
+#define FSZLENG FSZLONG
+#define FUDGEOFFSET 1
+#define AUTOREG EBP
+#define ARGREG EBP
+#define ARGOFFSET 4
+#endif
+
+#define BACKAUTO /* stack grows negatively for automatics */
+#define BACKTEMP /* stack grows negatively for temporaries */
+
+#define MYP2TREE(p) myp2tree(p);
+
+#undef FIELDOPS /* no bit-field instructions */
+#define RTOLBYTES /* bytes are numbered right to left */
+
+#define ENUMSIZE(high,low) INT /* enums are always stored in full int */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x) ((x)&03)
+#define wdal(k) (BYTEOFF(k)==0)
+#define BITOOR(x) ((x)/SZCHAR) /* bit offset to oreg offset */
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+#define genfcall(a,b) gencall(a,b)
+
+#define szty(t) (((t) == DOUBLE || (t) == FLOAT || \
+ (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1)
+
+/*
+ * Register names. These must match rnames[] and rstatus[] in local2.c.
+ * The crazy order of the registers are due to the current register
+ * allocations strategy and should be fixed.
+ */
+#define T0 0
+#define T1 1
+#define T2 2
+#define T3 3
+#define T4 4
+#define T5 5
+#define T6 6
+#define T7 7
+#define T8 8
+#define T9 9
+
+#define V0 10
+#define V1 11
+
+#define ZERO 12
+#define AT 13
+
+#define A0 14
+#define A1 15
+#define A2 16
+#define A3 17
+
+#define S0 18
+#define S1 19
+#define S2 20
+#define S3 21
+#define S4 22
+#define S5 23
+#define S6 24
+#define S7 25
+
+#define K0 26
+#define K1 27
+
+#define GP 28
+#define SP 29
+#define FP 30
+#define RA 31
+
+#define RETREG V0 /* Return register */
+#define REGSZ 32 /* number of registers */
+#define FPREG FP /* frame pointer */
+#define STKREG SP /* stack pointer */
+#define MINRVAR S0 /* first register variable */
+#define MAXRVAR S7 /* last register variable */
+
+#define NREGREG (MAXRVAR-MINRVAR+1)
+
+/*
+ * Register types are described by bitmasks.
+ */
+#define AREGS (REGBIT(T0)|REGBIT(T1)|REGBIT(T2)|REGBIT(T3)| \
+ REGBIT(T4)|REGBIT(T5)|REGBIT(T6)|REGBIT(T7)|REGBIT(T8)|REGBIT(T9)|\
+ REGBIT(V0)|REGBIT(V1)|REGBIT(A0)|REGBIT(A1)|REGBIT(A2)|REGBIT(A3)|\
+ REGBIT(S0)|REGBIT(S1)|REGBIT(S2)|REGBIT(S3)|REGBIT(S4)|REGBIT(S5)|\
+ REGBIT(S6)|REGBIT(S7))
+#define TAREGS (REGBIT(T0)|REGBIT(T1)|REGBIT(T2)|REGBIT(T3)|REGBIT(T4)|\
+ REGBIT(T5)|REGBIT(T6)|REGBIT(T7)|REGBIT(T8)|REGBIT(T9)|\
+ REGBIT(V0)|REGBIT(V1))
+
+/* For floating point? */
+#define BREGS 0xff00
+#define TBREGS BREGS
+
+//#define MYADDEDGE(x, t) if (t < INT) { AddEdge(x, ESI); AddEdge(x, EDI); }
+#define MYADDEDGE(x, t)
+#define PCLASS(p) SAREG
+
+#define MYREADER(p) myreader(p)
+#define MYCANON(p) mycanon(p)
+#define MYOPTIM
+
+#define special(a, b) SRNOPE
diff --git a/usr.bin/pcc/mips/order.c b/usr.bin/pcc/mips/order.c
new file mode 100644
index 00000000000..9a028f6092c
--- /dev/null
+++ b/usr.bin/pcc/mips/order.c
@@ -0,0 +1,350 @@
+/* $OpenBSD: order.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+# include "pass2.h"
+
+int canaddr(NODE *);
+
+/* should we delay the INCR or DECR operation p */
+int
+deltest(NODE *p)
+{
+ return 0;
+}
+
+/*
+ * Check if p can be autoincremented.
+ * XXX - nothing can be autoincremented for now.
+ */
+int
+autoincr(NODE *p)
+{
+ return 0;
+}
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+ return(0); /* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ */
+int
+offstar(NODE *p)
+{
+ if (x2debug)
+ printf("offstar(%p)\n", p);
+
+ if( p->n_op == PLUS || p->n_op == MINUS ){
+ if( p->n_right->n_op == ICON ){
+ geninsn(p->n_left, INTAREG|INAREG);
+ p->n_su = -1;
+ return 1;
+ }
+ }
+ geninsn(p, INTAREG|INAREG);
+ return 0;
+}
+
+/*
+ * Shape matches for UMUL. Cooperates with offstar().
+ */
+int
+shumul(NODE *p)
+{
+
+ if (x2debug)
+ printf("shumul(%p)\n", p);
+
+ /* Always turn it into OREG on x86 */
+ return SOREG;
+}
+
+/*
+ * Rewrite increment/decrement operation.
+ */
+int
+setincr(NODE *p)
+{
+ if (x2debug)
+ printf("setincr(%p)\n", p);
+
+ return(0);
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE *p)
+{
+
+ if (x2debug)
+ printf("setbin(%p)\n", p);
+ return 0;
+
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+ if (x2debug)
+ printf("setasg(%p)\n", p);
+ return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+ return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ * - left is the register that left node wants.
+ * - right is the register that right node wants.
+ * - res is in which register the result will end up.
+ * - mask is registers that will be clobbered.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+ static int v0[] = { V0, -1 };
+ static int v0v1[] = { V0, V1, -1 };
+
+ static struct rspecial ucall = { v0, 0, v0v1, v0 };
+
+ switch (q->op) {
+
+ default:
+ comperr("nspecial entry %d", q - table);
+ }
+ return 0; /* XXX gcc */
+}
+
+/*
+ * Splitup a function call and give away its arguments first.
+ */
+void
+gencall(NODE *p, NODE *prev)
+{
+ NODE *n = 0; /* XXX gcc */
+ static int storearg(NODE *);
+ int o = p->n_op;
+ int ty = optype(o);
+
+ if (ty == LTYPE)
+ return;
+
+ switch (o) {
+ case CALL:
+ /* Normal call, just push args and be done with it */
+ p->n_op = UCALL;
+
+ gencall(p->n_left, p);
+ p->n_rval = storearg(p->n_right);
+
+ break;
+
+ case UFORTCALL:
+ case FORTCALL:
+ comperr("FORTCALL");
+
+ case USTCALL:
+ case STCALL:
+ /*
+ * Structure return. Look at the node above
+ * to decide about buffer address:
+ * - FUNARG, allocate space on stack, don't remove.
+ * - nothing, allocate space on stack and remove.
+ * - STASG, get the address of the left side as arg.
+ * - FORCE, this ends up in a return, get supplied addr.
+ * (this is not pretty, but what to do?)
+ */
+ if (prev == NULL || prev->n_op == FUNARG) {
+ /* Create nodes to generate stack space */
+ n = mkbinode(ASSIGN, mklnode(REG, 0, STKREG, INT),
+ mkbinode(MINUS, mklnode(REG, 0, STKREG, INT),
+ mklnode(ICON, p->n_stsize, 0, INT), INT), INT);
+ //printf("stsize %d\n", p->n_stsize);
+ pass2_compile(ipnode(n));
+ } else if (prev->n_op == STASG) {
+ n = prev->n_left;
+ if (n->n_op == UMUL)
+ n = nfree(n);
+ else if (n->n_op == NAME) {
+ n->n_op = ICON; /* Constant reference */
+ n->n_type = INCREF(n->n_type);
+ } else
+ comperr("gencall stasg");
+ } else if (prev->n_op == FORCE) {
+ ; /* do nothing here */
+ } else {
+ comperr("gencall bad op %d", prev->n_op);
+ }
+
+ /* Deal with standard arguments */
+ gencall(p->n_left, p);
+ if (o == STCALL) {
+ p->n_op = USTCALL;
+ p->n_rval = storearg(p->n_right);
+ } else
+ p->n_rval = 0;
+ /* push return struct address */
+ if (prev == NULL || prev->n_op == FUNARG) {
+ n = mklnode(REG, 0, STKREG, INT);
+ if (p->n_rval)
+ n = mkbinode(PLUS, n,
+ mklnode(ICON, p->n_rval, 0, INT), INT);
+ pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
+ if (prev == NULL)
+ p->n_rval += p->n_stsize/4;
+ } else if (prev->n_op == FORCE) {
+ /* return value for this function */
+ n = mklnode(OREG, 8, FPREG, INT);
+ pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
+ p->n_rval++;
+ } else {
+ pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
+ n = p;
+ *prev = *p;
+ nfree(n);
+ }
+ //printf("end stcall\n");
+ break;
+
+ default:
+ if (ty != UTYPE)
+ gencall(p->n_right, p);
+ gencall(p->n_left, p);
+ break;
+ }
+}
+
+/*
+ * Create separate node trees for function arguments.
+ * Returns the number of registers needed to hold the argument.
+ */
+static int
+storearg(NODE *p)
+{
+ static void storecall(NODE *);
+ struct interpass *ip;
+ NODE *np;
+ int tsz, recval;
+ TWORD t;
+ extern int thisline;
+ static int counter = 0; /* Count number of register arguments */
+
+ ip = tmpalloc(sizeof(struct interpass));
+ ip->type = IP_NODE;
+ ip->lineno = thisline;
+
+ if (p->n_op == CM) {
+ np = p->n_left;
+
+ if (p->n_right->n_op == STARG) {
+ NODE *op = p;
+ p = p->n_right;
+ nfree(op);
+ tsz = (p->n_stsize + 3) / 4;
+ } else {
+ p->n_type = p->n_right->n_type;
+ p->n_left = p->n_right;
+
+
+ /* Process left subtree first, to get arguments in the correct
+ order on the stack as well as in the registers. */
+ recval = storearg(np);
+
+ /* Not a register argument */
+ if (!(counter < 4)) {
+ p->n_op = FUNARG;
+ ip->ip_node = p;
+ pass2_compile(ip);
+ tsz = szty(p->n_type);
+
+ } else { /* Else fetch value from stack to register */
+ t = p->n_type;
+
+ pass2_compile(ipnode(mkbinode(ASSIGN,
+ mklnode(REG, 0, A0+counter, t),
+ p->n_right, t)));
+ tsz = 0;
+ counter++;
+
+ /* Free the comma node */
+ nfree(p);
+
+ }
+ }
+
+ return recval + tsz;
+ } else {
+ if (p->n_op != STARG) {
+ /* Register argument */
+ if (counter < 4) {
+ t = p->n_type;
+
+ pass2_compile(ipnode(mkbinode(ASSIGN,
+ mklnode(REG, 0, A0+counter, t),
+ p, t)));
+ counter++;
+
+ return 0;
+ } else {
+ np = talloc();
+
+ np->n_type = p->n_type;
+ np->n_op = FUNARG;
+ np->n_left = p;
+ p = np;
+ tsz = szty(p->n_type);
+ }
+ } else {
+ p->n_op = FUNARG;
+ tsz = (p->n_stsize + 3) / 4;
+ }
+ ip->ip_node = p;
+ pass2_compile(ip);
+ return tsz;
+ }
+}
diff --git a/usr.bin/pcc/mips/table.c b/usr.bin/pcc/mips/table.c
new file mode 100644
index 00000000000..78d0555c28a
--- /dev/null
+++ b/usr.bin/pcc/mips/table.c
@@ -0,0 +1,776 @@
+/* $OpenBSD: table.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+
+
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+# include "pass2.h"
+
+# define TLL TLONGLONG|TULONGLONG
+# define ANYSIGNED TINT|TLONG|TSHORT|TCHAR
+# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TUWORD TUNSIGNED|TULONG
+# define TSWORD TINT|TLONG
+# define TWORD TUWORD|TSWORD
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+
+/*
+ * A bunch conversions of integral<->integral types
+ */
+
+
+
+
+
+
+/* convert char to (u)short */
+{ SCONV, INTAREG,
+ SOREG, TCHAR,
+ SAREG, TSHORT|TUSHORT,
+ NAREG, RESC1,
+ " lb A1, ZA\n nop\n", },
+
+/* convert uchar to (u)short */
+{ SCONV, INTAREG,
+ SOREG, TUCHAR,
+ SAREG, TSHORT|TUSHORT,
+ NAREG, RESC1,
+ " lbu A1, ZA\n nop\n", },
+
+/* convert char to (u)long */
+{ SCONV, INTAREG,
+ SOREG, TCHAR,
+ SAREG, TWORD,
+ NAREG, RESC1,
+ " lb A1, ZA\n nop\n", },
+
+/* convert uchar to (u)long */
+{ SCONV, INTAREG,
+ SOREG, TUCHAR,
+ SAREG, TWORD,
+ NAREG, RESC1,
+ " lbu A1, ZA\n nop\n", },
+
+/* convert char to (u)long long */
+{ SCONV, INTAREG,
+ SOREG, TCHAR,
+ SAREG, TLL,
+ NAREG, RESC1,
+ " lb U1, ZA\n"
+ " nop\n"
+ " sra A1, U1, 31\n"
+ " sub A1, $zero, A1\n", },
+
+/* convert uchar to (u)long long */
+{ SCONV, INTAREG,
+ SOREG, TUCHAR,
+ SAREG, TLL,
+ NAREG, RESC1,
+ " lbu U1, ZA\n"
+ " move A1, $zero\n", },
+
+
+
+
+
+/* convert (u)short to char */
+{ SCONV, INTAREG,
+ SOREG, TSHORT|TUSHORT,
+ SAREG, TCHAR,
+ NAREG, RESC1,
+ " lb A1, ZA\n nop\n", },
+
+/* convert (u)short to uchar */
+{ SCONV, INTAREG,
+ SOREG, TSHORT|TUSHORT,
+ SAREG, TUCHAR,
+ NAREG, RESC1,
+ " lbu A1, ZA\n nop\n", },
+
+
+/* convert short to (u)long */
+{ SCONV, INTAREG,
+ SOREG, TSHORT,
+ SAREG, TWORD,
+ NAREG, RESC1,
+ " lh A1, ZA\n nop\n", },
+
+/* convert ushort to (u)long */
+{ SCONV, INTAREG,
+ SOREG, TUSHORT,
+ SAREG, TWORD,
+ NAREG, RESC1,
+ " lhu A1, ZA\n nop\n", },
+
+/* convert short to (u)long long */
+{ SCONV, INTAREG,
+ SOREG, TSHORT,
+ SAREG, TLL,
+ NAREG, RESC1,
+ " lh U1, ZA\n"
+ " nop\n"
+ " sra A1, U1, 31\n"
+ " sub A1, $zero, A1\n", },
+
+/* convert ushort to (u)long long */
+{ SCONV, INTAREG,
+ SOREG, TUSHORT,
+ SAREG, TLL,
+ NAREG, RESC1,
+ " lhu U1, ZA\n"
+ " move A1, $zero\n", },
+
+
+
+
+
+/* convert (u)long to char */
+{ SCONV, INTAREG,
+ SOREG, TWORD,
+ SAREG, TCHAR,
+ NAREG, RESC1,
+ " lb A1, ZA\n nop\n", },
+
+/* convert (u)long to uchar */
+{ SCONV, INTAREG,
+ SOREG, TWORD,
+ SAREG, TUCHAR,
+ NAREG, RESC1,
+ " lbu A1, ZA\n nop\n", },
+
+/* convert (u)long to short */
+{ SCONV, INTAREG,
+ SOREG, TWORD,
+ SAREG, TSHORT,
+ NAREG, RESC1,
+ " lh A1, ZA\n nop\n", },
+
+/* convert (u)long to ushort */
+{ SCONV, INTAREG,
+ SOREG, TWORD,
+ SAREG, TUSHORT,
+ NAREG, RESC1,
+ " lhu A1, ZA\n nop\n", },
+
+/* convert long to (u)long long */
+{ SCONV, INTAREG,
+ SOREG, TSWORD,
+ SAREG, TLL,
+ NAREG, RESC1,
+ " lw U1, ZA\n"
+ " nop\n"
+ " sra A1, U1, 31\n"
+ " sub A1, $zero, A1\n", },
+
+/* convert ulong to (u)long long */
+{ SCONV, INTAREG,
+ SOREG, TUWORD,
+ SAREG, TLL,
+ NAREG, RESC1,
+ " lw U1, ZA\n"
+ " move A1, $zero\n", },
+
+
+
+
+
+/* convert (u)long long to char */
+{ SCONV, INTAREG,
+ SOREG, TLL,
+ SAREG, TCHAR,
+ NAREG, RESC1,
+ " lb A1, ZA\n nop\n", },
+
+/* convert (u)long long to uchar */
+{ SCONV, INTAREG,
+ SOREG, TLL,
+ SAREG, TUCHAR,
+ NAREG, RESC1,
+ " lbu A1, ZA\n nop\n", },
+
+/* convert (u)long long to short */
+{ SCONV, INTAREG,
+ SOREG, TLL,
+ SAREG, TSHORT,
+ NAREG, RESC1,
+ " lh A1, ZA\n nop\n", },
+
+/* convert (u)long long to ushort */
+{ SCONV, INTAREG,
+ SOREG, TLL,
+ SAREG, TUSHORT,
+ NAREG, RESC1,
+ " lhu A1, ZA\n nop\n", },
+
+/* convert (u)long long to long */
+{ SCONV, INTAREG,
+ SOREG, TLL,
+ SAREG, TSWORD,
+ NAREG, RESC1,
+ " lw U1, ZA\n nop\n", },
+
+/* convert (u)long long to (u)long long */
+{ SCONV, INTAREG,
+ SOREG, TLL,
+ SAREG, TUWORD,
+ NAREG, RESC1,
+ " lwu U1, ZA\n nop\n", },
+
+
+
+
+
+
+
+/* Register to register conversion with long long */
+
+{ SCONV, INTAREG,
+ SAREG, TLL,
+ SAREG, TLL,
+ 0, 0,
+ "", },
+
+{ SCONV, INTAREG,
+ SAREG, TPOINT|TWORD|SHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TLL,
+ NAREG, 0,
+ "move A1, AR\n"
+ "move U1, $zero\n", },
+
+{ SCONV, INTAREG,
+ SAREG, TLL,
+ SAREG, TPOINT|TWORD|SHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG, 0,
+ "move A1, AL\n", },
+
+
+
+
+/* For register to register conversion with bit length <= 32, do nothing */
+
+{ SCONV, INTAREG,
+ SAREG, TPOINT|TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TPOINT|TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ 0, 0,
+ "", },
+
+
+
+
+
+
+/*
+ * Multiplication and division
+ */
+
+{ MUL, INAREG|FOREFF,
+ SAREG, TSWORD|TSHORT|TCHAR,
+ SAREG, TSWORD|TSHORT|TCHAR,
+ NAREG|NASR|NASL, RESC1,
+ " mult AL, AR\n mflo A1\n nop\n nop\n", },
+
+{ MUL, INAREG|FOREFF,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
+ NAREG|NASR|NASL, RESC1,
+ " multu AL, AR\n mflo A1\n nop\n nop\n", },
+
+{ DIV, INAREG|FOREFF,
+ SAREG, TSWORD|TSHORT|TCHAR,
+ SAREG, TSWORD|TSHORT|TCHAR,
+ NAREG|NASR|NASL, RESC1,
+ " div AL, AR\n mflo A1\n nop\n nop\n", },
+
+{ DIV, INAREG|FOREFF,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
+ NAREG|NASR|NASL, RESC1,
+ " divu AL, AR\n mflo A1\n nop\n nop\n", },
+
+/*
+ * Templates for unsigned values needs to come before OPSIMP
+ */
+
+{ PLUS, INAREG|FOREFF,
+ SAREG, TLL,
+ SAREG, TLL,
+ 3*NAREG, RESC3,
+ " addu A1, AL, AR\n"
+ " sltu A2, A1, AR\n"
+ " addu A3, UL, UR\n"
+ " addu A3, A3, A2\n", },
+
+{ PLUS, INAREG|FOREFF,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SCON, TUSHORT|TSHORT|TCHAR|TUCHAR,
+ NAREG|NASR|NASL, RESC1,
+ " addiu A1, AL, AR\n", },
+
+ /*
+{ PLUS, INAREG|FOREFF,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
+ NAREG|NASR|NASL, RESC1,
+ " addu A1, AL, AR\n", },
+
+{ MINUS, INAREG|FOREFF,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
+ NAREG|NASR|NASL, RESC1,
+ " subu A1, AL, AR\n", },
+ */
+
+{ MINUS, INAREG|FOREFF,
+ SAREG, TLL,
+ SAREG, TLL,
+ NAREG|NASR|NASL, RESC1,
+ " sltu A1, AL, AR\n"
+ " subu AR, AL, AR\n"
+ " subu UR, UL, UR\n"
+ " subu UR, UR, A1\n", },
+
+{ MINUS, INAREG|FOREFF,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SCON, TUSHORT|TSHORT|TCHAR|TUCHAR,
+ NAREG|NASR|NASL, RESC1,
+ " subiu A1, AL, AR\n", },
+
+
+{ UMINUS, INAREG|FOREFF|INTAREG,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SANY, TANY,
+ NAREG|NASL, RESC1,
+ " neg A1, AL\n", },
+
+
+/* Simple 'op rd, rs, rt' or 'op rt, rs, imm' operations */
+
+{ OPSIMP, INAREG|FOREFF,
+ SAREG, TLL,
+ SAREG, TLL,
+ NAREG|NASR|NASL, RESC1,
+ " O A1, AL, AR\n"
+ " O U1, UL, UR\n", },
+
+{ OPSIMP, INAREG|FOREFF,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR,
+ NAREG|NASR|NASL, RESC1,
+ " O A1, AL, AR\n", },
+
+{ OPSIMP, INAREG|FOREFF,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR,
+ SCON, TSHORT|TUSHORT|TUCHAR|TCHAR,
+ NAREG|NASR|NASL, RESC1,
+ " Oi A1, AL, AR\n", },
+
+/*
+ * Shift instructions
+ */
+
+ /* order.c SPECIAL
+{ RS, INAREG|INTAREG|FOREFF,
+ SAREG, TWORD|TUSHORT|TSHORT|TCHAR|TUCHAR,
+ SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " srl A1, AL, AR\n", },
+
+{ LS, INAREG|INTAREG|FOREFF,
+ SAREG, TWORD|TUSHORT|TSHORT|TCHAR|TUCHAR,
+ SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " sll A1, AL, AR\n", },
+ */
+
+{ RS, INAREG|INTAREG|FOREFF,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " srlv A1, AL, AR\n", },
+
+{ LS, INAREG|INTAREG|FOREFF,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " sllv A1, AL, AR\n", },
+
+/*
+ * Rule for unary one's complement
+ */
+
+{ COMPL, INTAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SANY, TANY,
+ NAREG|NASL, RESC1,
+ " not A1, AL\n", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+
+{ ASSIGN, INTAREG,
+ SOREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RRIGHT,
+ " sw AR, AL\n", },
+
+{ ASSIGN, INTAREG,
+ SOREG, TSHORT|TUSHORT,
+ SAREG, TSHORT|TUSHORT,
+ 0, RRIGHT,
+ " sh AR, AL\n", },
+
+{ ASSIGN, INTAREG,
+ SOREG, TCHAR|TUCHAR,
+ SAREG, TCHAR|TUCHAR,
+ 0, RRIGHT,
+ " sb AR, AL\n", },
+
+{ ASSIGN, INTAREG,
+ SOREG, TLL,
+ SAREG, TLL,
+ 0, RRIGHT,
+ " sw UR, UL\n"
+ " sw AR, AL\n", },
+
+{ ASSIGN, INTAREG, // XXX: Funkar ej A1 == AR
+ SNAME, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ NAREG, RRIGHT,
+ " la A1, AL\n sw AR, 0(A1)\n", },
+
+{ ASSIGN, INTAREG,
+ SNAME, TSHORT|TUSHORT,
+ SAREG, TSHORT|TUSHORT,
+ NAREG, RRIGHT,
+ " la A1, AL\n sh AR, 0(A1)\n", },
+
+{ ASSIGN, INTAREG,
+ SNAME, TCHAR|TUCHAR,
+ SAREG, TCHAR|TUCHAR,
+ NAREG, RRIGHT,
+ " la A1, AL\n sb AR, 0(A1)\n", },
+
+{ ASSIGN, INTAREG,
+ SNAME, TLL,
+ SAREG, TLL,
+ 0, RRIGHT,
+ " sw UR, UL\n"
+ " sw AR, AL\n", },
+
+{ ASSIGN, INTAREG,
+ SAREG, TLL,
+ SAREG, TLL,
+ 0, RRIGHT,
+ " move UR, UL\n"
+ " move AR, AL\n", },
+
+{ ASSIGN, INTAREG|FOREFF,
+ SAREG, TANY,
+ SAREG, TANY,
+ 0, RLEFT,
+ " move AL, AR\n", },
+
+#if 0
+/* XXX - Stupid rule, shouldn't exist */
+{ ASSIGN, INTAREG,
+ SANY, TANY,
+ SAREG, TANY,
+ 0, RLEFT,
+ " move AL, AR\n", },
+#endif
+
+/*
+ * Compare instructions
+ */
+
+{ EQ, FORCC,
+ SAREG, TANY,
+ SAREG, TANY,
+ 0, RESCC,
+ " ZQ\n", },
+
+{ NE, FORCC,
+ SAREG, TANY,
+ SAREG, TANY,
+ 0, RESCC,
+ " ZQ\n", },
+
+{ LE, FORCC,
+ SAREG, TANY,
+ SAREG, TANY,
+ NAREG|NASL, RESCC,
+ " sub A1, AL, AR\n ZQ\n", },
+
+{ LT, FORCC,
+ SAREG, TANY,
+ SAREG, TANY,
+ NAREG|NASL, RESCC,
+ " sub A1, AL, AR\n ZQ\n", },
+
+{ GE, FORCC,
+ SAREG, TANY,
+ SAREG, TANY,
+ NAREG|NASL, RESCC,
+ " sub A1, AL, AR\n ZQ\n", },
+
+{ GT, FORCC,
+ SAREG, TANY,
+ SAREG, TANY,
+ NAREG|NASL, RESCC,
+ " sub A1, AL, AR\n ZQ\n", },
+
+
+/*
+ * Convert LTYPE to reg.
+ */
+
+
+/* from OREG to REG */
+
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SOREG, TCHAR,
+ NAREG, RESC1,
+ " lb A1,AR\n nop\n", },
+
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SOREG, TUCHAR,
+ NAREG, RESC1,
+ " lbu A1,AR\n nop\n", },
+
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SOREG, TSHORT,
+ NAREG, RESC1,
+ " lh A1,AR\n nop\n", },
+
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SOREG, TUSHORT,
+ NAREG, RESC1,
+ " lhu A1,AR\n nop\n", },
+
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SOREG, TWORD|TPOINT,
+ NAREG, RESC1,
+ " lw A1, AR\n nop\n", },
+
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SOREG, TLL,
+ NAREG, RESC1,
+ " lw U1, UR\n"
+ " lw A1, AR\n"
+ " nop\n", },
+
+/* from NAME to REG */
+
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SNAME, TCHAR,
+ 2*NAREG, RESC1,
+ " la A2, AR\n lb A1, 0(A2)\n nop\n", },
+
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SNAME, TUCHAR,
+ 2*NAREG, RESC1,
+ " la A2, AR\n lbu A1, 0(A2)\n nop\n", },
+
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SNAME, TSHORT,
+ 2*NAREG, RESC1,
+ " la A2, AR\n lh A1, 0(A2)\n nop\n", },
+
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SNAME, TUSHORT,
+ 2*NAREG, RESC1,
+ " la A2, AR\n lhu A1, 0(A2)\n nop\n", },
+
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SNAME, TWORD|TPOINT,
+ 2*NAREG, RESC1,
+ " la A2, AR\n lw A1, 0(A2)\n nop\n", },
+
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SNAME, TLL,
+ 2*NAREG, RESC1,
+ " la A2, UR\n"
+ " lw U1, 0(A2)\n"
+ " la A2, AR\n"
+ " lw A1, 0(A2)\n"
+ " nop\n", },
+
+/* from CON to REG */
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SCON, TPOINT,
+ NAREG, RESC1,
+ " la A1, AR\n", },
+
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SCON, TANY,
+ NAREG, RESC1,
+ " li A1, AR\n", },
+
+#if 0
+/* Matches REG nodes. XXX - shouldn't be necessary? */
+{ OPLTYPE, INTAREG,
+ SANY, TANY,
+ SANY, TANY,
+ NAREG, RESC1,
+ " move A1, AR\n", },
+#endif
+
+/*
+ * Jumps.
+ */
+{ GOTO, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ 0, RNOP,
+ " j LL\n nop\n", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ UCALL, INTAREG|FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG, RESC1,
+ " addi $sp, $sp, -16\n jal AL\n nop\nZC\n", },
+
+/* struct return */
+{ USTCALL, INTAREG|FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " call CL\nZC", },
+
+/*
+ * Function arguments
+ */
+
+
+{ FUNARG, FOREFF,
+ SAREG, TWORD|TPOINT,
+ SANY, TWORD|TPOINT,
+ 0, RNULL,
+ " addi $sp, $sp, -4\n sw AL, 0($sp)\n", },
+
+{ FUNARG, FOREFF,
+ SAREG, TSHORT|TUSHORT,
+ SANY, TSHORT|TUSHORT,
+ 0, RNULL,
+ " addi $sp, $sp, -4\n sh AL, 0($sp)\n", },
+{ FUNARG, FOREFF,
+ SAREG, TCHAR|TUCHAR,
+ SANY, TCHAR|TUCHAR,
+ 0, RNULL,
+ " addi $sp, $sp, -4\n sb AL, 0($sp)\n", },
+
+
+/*
+ * Indirection operators.
+ */
+{ UMUL, INTAREG,
+ SOREG, TPOINT|TWORD|TPTRTO,
+ SANY, TPOINT|TWORD,
+ NAREG|NASL, RESC1,
+ " lw A1, AL\n nop\n", },
+
+{ UMUL, INTAREG,
+ SOREG, TSHORT|TUSHORT|TPTRTO,
+ SANY, TSHORT|TUSHORT,
+ NAREG|NASL, RESC1,
+ " lh A1, AL\n nop\n", },
+
+{ UMUL, INTAREG,
+ SOREG, TCHAR|TUCHAR|TPTRTO,
+ SANY, TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " lb A1, AL\n nop\n", },
+
+{ UMUL, INTAREG,
+ SNAME, TPOINT|TWORD|TPTRTO,
+ SANY, TPOINT|TWORD,
+ NAREG|NASL, RESC1,
+ " la A1, AL\n lw A1, 0(A1)\n nop\n", },
+
+{ UMUL, INTAREG,
+ SNAME, TSHORT|TUSHORT|TPTRTO,
+ SANY, TSHORT|TUSHORT,
+ NAREG|NASL, RESC1,
+ " la A1, AL\n lh A1, 0(A1)\n nop\n", },
+
+{ UMUL, INTAREG,
+ SNAME, TCHAR|TUCHAR|TPTRTO,
+ SANY, TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " la A1, AL\n lb A1, 0(A1)\n nop\n", },
+
+{ UMUL, INTAREG,
+ SAREG, TPOINT|TWORD|TPTRTO,
+ SANY, TPOINT|TWORD,
+ NAREG|NASL, RESC1,
+ " lw A1, 0(AL)\n nop\n", },
+
+{ UMUL, INTAREG,
+ SAREG, TSHORT|TUSHORT|TPTRTO,
+ SANY, TSHORT|TUSHORT,
+ NAREG|NASL, RESC1,
+ " lh A1, 0(AL)\n nop\n", },
+
+{ UMUL, INTAREG,
+ SAREG, TCHAR|TUCHAR|TPTRTO,
+ SANY, TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " lb A1, 0(AL)\n nop\n", },
+
+{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);