summaryrefslogtreecommitdiff
path: root/usr.bin/pcc/arch
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/pcc/arch')
-rw-r--r--usr.bin/pcc/arch/m16c/TODO1
-rw-r--r--usr.bin/pcc/arch/m16c/code.c376
-rw-r--r--usr.bin/pcc/arch/m16c/local.c487
-rw-r--r--usr.bin/pcc/arch/m16c/local2.c639
-rw-r--r--usr.bin/pcc/arch/m16c/macdefs.h205
-rw-r--r--usr.bin/pcc/arch/m16c/order.c600
-rw-r--r--usr.bin/pcc/arch/m16c/table.c595
-rw-r--r--usr.bin/pcc/arch/mips/TODO7
-rw-r--r--usr.bin/pcc/arch/mips/code.c239
-rw-r--r--usr.bin/pcc/arch/mips/local.c533
-rw-r--r--usr.bin/pcc/arch/mips/local2.c774
-rw-r--r--usr.bin/pcc/arch/mips/macdefs.h227
-rw-r--r--usr.bin/pcc/arch/mips/order.c350
-rw-r--r--usr.bin/pcc/arch/mips/table.c776
-rw-r--r--usr.bin/pcc/arch/nova/README120
-rw-r--r--usr.bin/pcc/arch/nova/code.c212
-rw-r--r--usr.bin/pcc/arch/nova/local.c618
-rw-r--r--usr.bin/pcc/arch/nova/local2.c563
-rw-r--r--usr.bin/pcc/arch/nova/macdefs.h195
-rw-r--r--usr.bin/pcc/arch/nova/order.c164
-rw-r--r--usr.bin/pcc/arch/nova/table.c1514
-rw-r--r--usr.bin/pcc/arch/pdp10/code.c167
-rw-r--r--usr.bin/pcc/arch/pdp10/local.c782
-rw-r--r--usr.bin/pcc/arch/pdp10/local2.c1237
-rw-r--r--usr.bin/pcc/arch/pdp10/macdefs.h148
-rw-r--r--usr.bin/pcc/arch/pdp10/order.c187
-rw-r--r--usr.bin/pcc/arch/pdp10/table.c1153
-rw-r--r--usr.bin/pcc/arch/vax/code.c452
-rw-r--r--usr.bin/pcc/arch/vax/local.c528
-rw-r--r--usr.bin/pcc/arch/vax/local2.c923
-rw-r--r--usr.bin/pcc/arch/vax/macdefs.h155
-rw-r--r--usr.bin/pcc/arch/vax/order.c533
-rw-r--r--usr.bin/pcc/arch/vax/table.c652
-rw-r--r--usr.bin/pcc/arch/x86/code.c213
-rw-r--r--usr.bin/pcc/arch/x86/local.c743
-rw-r--r--usr.bin/pcc/arch/x86/local2.c1051
-rw-r--r--usr.bin/pcc/arch/x86/macdefs.h301
-rw-r--r--usr.bin/pcc/arch/x86/order.c287
-rw-r--r--usr.bin/pcc/arch/x86/table.c1453
39 files changed, 20160 insertions, 0 deletions
diff --git a/usr.bin/pcc/arch/m16c/TODO b/usr.bin/pcc/arch/m16c/TODO
new file mode 100644
index 00000000000..5ef0ba4b478
--- /dev/null
+++ b/usr.bin/pcc/arch/m16c/TODO
@@ -0,0 +1 @@
+* Mul/Div does not work. \ No newline at end of file
diff --git a/usr.bin/pcc/arch/m16c/code.c b/usr.bin/pcc/arch/m16c/code.c
new file mode 100644
index 00000000000..536a5eb1435
--- /dev/null
+++ b/usr.bin/pcc/arch/m16c/code.c
@@ -0,0 +1,376 @@
+/* $Id: code.c,v 1.1 2007/09/15 18:12:27 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.
+ */
+
+
+# include "pass1.h"
+
+/*
+ * cause the alignment to become a multiple of n
+ */
+void
+defalign(int n)
+{
+#if 0
+ char *s;
+
+ n /= SZCHAR;
+ if (lastloc == PROG || n == 1)
+ return;
+ s = (isinlining ? permalloc(40) : tmpalloc(40));
+ sprintf(s, ".align %d", n);
+ send_passt(IP_ASM, s);
+#endif
+}
+
+/*
+ * define the current location as the name p->sname
+ */
+void
+defnam(struct symtab *p)
+{
+ char *c = p->sname;
+
+#ifdef GCC_COMPAT
+ c = gcc_findname(p);
+#endif
+ if (p->sclass == EXTDEF)
+ printf(" PUBLIC %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;
+ /* address of return struct is in eax */
+ /* create a call to memcpy() */
+ /* will get the result in eax */
+ p = block(REG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+ p->n_rval = R0;
+ q = block(OREG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+ q->n_rval = FB;
+ q->n_lval = 8; /* return buffer offset */
+ p = block(CM, q, p, INT, 0, MKSUE(INT));
+ sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR;
+ p = block(CM, p, bcon(sz), INT, 0, MKSUE(INT));
+ p->n_right->n_name = "";
+ p = block(CALL, bcon(0), p, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+ p->n_left->n_name = "memcpy";
+ send_passt(IP_NODE, p);
+}
+
+/*
+ * helper for bfcode() to put register arguments on stack.
+ */
+static void
+argmove(struct symtab *s, int regno)
+{
+ NODE *p, *r;
+
+ s->sclass = AUTO;
+ s->soffset = NOOFFSET;
+ oalloc(s, &autooff);
+ 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
+ * On m16k, space is allocated on stack for register arguments,
+ * arguments are moved to the stack and symtab is updated accordingly.
+ */
+void
+bfcode(struct symtab **a, int n)
+{
+ struct symtab *s;
+ int i, r0l, r0h, a0, r2, sz, hasch, stk;
+ int argoff = ARGINIT;
+
+ 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);
+ }
+ /* first check if there are 1-byte parameters */
+ for (hasch = i = 0; i < n && i < 6; i++)
+ if (DEUNSIGN(a[i]->stype) == CHAR)
+ hasch = 1;
+
+ stk = r0l = r0h = a0 = r2 = 0;
+ for (i = 0; i < n; i++) {
+ s = a[i];
+ sz = tsize(s->stype, s->sdf, s->ssue);
+ if (ISPTR(s->stype) && ISFTN(DECREF(s->stype)))
+ sz = SZLONG; /* function pointers are always 32 */
+ if (stk == 0)
+ switch (sz) {
+ case SZCHAR:
+ if (r0l) {
+ if (r0h)
+ break;
+ argmove(s, 1);
+ r0h = 1;
+ } else {
+ argmove(s, 0);
+ r0l = 1;
+ }
+ continue;
+
+ case SZINT:
+ if (s->stype > BTMASK) {
+ /* is a pointer */
+ if (a0) {
+ if (r0l || hasch) {
+ if (r2)
+ break;
+ argmove(s, R2);
+ r2 = 1;
+ } else {
+ argmove(s, R0);
+ r0l = r0h = 1;
+ }
+ } else {
+ argmove(s, A0);
+ a0 = 1;
+ }
+ } else if (r0l || hasch) {
+ if (r2) {
+ if (a0)
+ break;
+ argmove(s, A0);
+ a0 = 1;
+ } else {
+ argmove(s, R2);
+ r2 = 1;
+ }
+ } else {
+ argmove(s, R0);
+ r0l = r0h = 1;
+ }
+ continue;
+ case SZLONG:
+ if (r0l||r0h||r2)
+ break;
+ argmove(s, R0);
+ r0l = r0h = r2 = 1;
+ continue;
+
+ default:
+ break;
+ }
+ stk = 1;
+ s->soffset = argoff;
+ argoff += sz;
+ }
+}
+
+/*
+ * Add a symbol to an internal list printed out at the end.
+ */
+void addsym(struct symtab *);
+static struct symlst {
+ struct symlst *next;
+ struct symtab *sp;
+} *sympole;
+
+void
+addsym(struct symtab *q)
+{
+ struct symlst *w = sympole;
+
+ if (q == NULL)
+ return;
+
+ while (w) {
+ if (q == w->sp)
+ return; /* exists */
+ w = w->next;
+ }
+ w = permalloc(sizeof(struct symlst));
+ w->sp = q;
+ w->next = sympole;
+ sympole = w;
+}
+
+/*
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+}
+
+struct caps {
+ char *cap, *stat;
+} caps[] = {
+ { "__64bit_doubles", "Disabled" },
+ { "__calling_convention", "Normal" },
+ { "__constant_data", "near" },
+ { "__data_alignment", "2" },
+ { "__data_model", "near" },
+ { "__processor", "M16C" },
+ { "__rt_version", "1" },
+ { "__variable_data", "near" },
+ { NULL, NULL },
+};
+/*
+ * Called before parsing begins.
+ */
+void
+bjobcode()
+{
+ struct caps *c;
+
+ printf(" NAME gurka.c\n"); /* Don't have the name */
+ for (c = caps; c->cap; c++)
+ printf(" RTMODEL \"%s\", \"%s\"\n", c->cap, c->stat);
+ //printf(" RSEG CODE:CODE:REORDER:NOROOT(0)\n");
+}
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag )
+{
+ struct symlst *w = sympole;
+
+ for (w = sympole; w; w = w->next) {
+ if (w->sp->sclass != EXTERN)
+ continue;
+ printf(" EXTERN %s\n", w->sp->sname);
+ }
+
+ printf(" END\n");
+}
+
+/*
+ * 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)
+{
+ uerror("switch() statements unsopported");
+#if 0
+ int i;
+ char *s;
+
+ /* simple switch code */
+ for (i = 1; i <= n; ++i) {
+ /* already in 1 */
+ s = (isinlining ? permalloc(40) : tmpalloc(40));
+ sprintf(s, " cmpl $%lld,%%eax", p[i]->sval);
+ send_passt(IP_ASM, s);
+ s = (isinlining ? permalloc(40) : tmpalloc(40));
+ sprintf(s, " je " LABFMT, p[i]->slab);
+ send_passt(IP_ASM, s);
+ }
+ if (p[0]->slab > 0)
+ branch(p[0]->slab);
+#endif
+}
diff --git a/usr.bin/pcc/arch/m16c/local.c b/usr.bin/pcc/arch/m16c/local.c
new file mode 100644
index 00000000000..ddc6276d36a
--- /dev/null
+++ b/usr.bin/pcc/arch/m16c/local.c
@@ -0,0 +1,487 @@
+/* $Id: local.c,v 1.1 2007/09/15 18:12:26 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.
+ */
+
+
+# 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 */
+
+ struct symtab *q;
+ NODE *l, *r;
+ int o;
+ TWORD ml;
+
+ 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 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 PCONV:
+ ml = p->n_left->n_type;
+ l = p->n_left;
+ if ((ml == CHAR || ml == UCHAR) && 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 (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT) {
+ nfree(p);
+ return l;
+ }
+ if (l->n_op == ICON) {
+ CONSZ val = l->n_lval;
+ switch (p->n_type) {
+ case CHAR:
+ l->n_lval = (char)val;
+ break;
+ case UCHAR:
+ l->n_lval = val & 0377;
+ break;
+ case SHORT:
+ case INT:
+ l->n_lval = (short)val;
+ break;
+ case USHORT:
+ case UNSIGNED:
+ l->n_lval = val & 0177777;
+ break;
+ case ULONG:
+ case ULONGLONG:
+ l->n_lval = val & 0xffffffff;
+ break;
+ case LONG:
+ case LONGLONG:
+ l->n_lval = (int)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", p->n_type);
+ }
+ l->n_type = p->n_type;
+ nfree(p);
+ return l;
+ }
+ break;
+
+
+ }
+
+ return(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 == CHAR || t == UCHAR ||
+ ISPTR(t))
+ 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 LONG:
+ case ULONG:
+ 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:
+ fwalk(p, eprint, 0);
+ 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 SHORT:
+ MODTYPE(type,INT);
+ break;
+
+ case USHORT:
+ MODTYPE(type,UNSIGNED);
+ break;
+
+ case LONGLONG:
+ MODTYPE(type,LONG);
+ break;
+
+ case ULONGLONG:
+ MODTYPE(type,ULONG);
+ break;
+
+ case LDOUBLE:
+ MODTYPE(type,DOUBLE);
+ break;
+ }
+ 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);
+}
+
+/*
+ * Extern variable not necessary common.
+ */
+void
+extdec(struct symtab *q)
+{
+ extern void addsym(struct symtab *);
+ addsym(q);
+}
+
+/*
+ * Call to a function
+ */
+void
+calldec(NODE *p, NODE *r)
+{
+ struct symtab *q = p->n_sp;
+ extern void addsym(struct symtab *);
+ addsym(q);
+}
+
+/* make a common declaration for id, if reasonable */
+void
+commdec(struct symtab *q)
+{
+ int off;
+ char *c = q->sname;
+
+ off = tsize(q->stype, q->sdf, q->ssue);
+ off = (off+(SZCHAR-1))/SZCHAR;
+
+#ifdef GCC_COMPAT
+ c = gcc_findname(q);
+#endif
+ printf(" PUBLIC %s\n", c);
+ /* XXX - NOROOT??? */
+ printf(" RSEG DATA16_Z:NEARDATA:SORT:NOROOT(1)\n");
+ printf("%s:\n", c);
+ printf(" DS8 %d\n", off);
+ printf(" REQUIRE __data16_zero\n");
+}
+
+/* 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);
+}
+
+void
+setloc1(int locc)
+{
+ if (locc == lastloc)
+ return;
+ lastloc = locc;
+}
+
+/*
+ * special handling before tree is written out.
+ */
+void
+myp2tree(NODE *p)
+{
+ union dimfun *df;
+ union arglist *al;
+ NODE *q;
+ int i;
+
+ switch (p->n_op) {
+ case MOD:
+ case DIV:
+ if (p->n_type == LONG || p->n_type == ULONG) {
+ /* Swap arguments for hardops() later */
+ q = p->n_left;
+ p->n_left = p->n_right;
+ p->n_right = q;
+ }
+ break;
+
+ case CALL:
+ case STCALL:
+ /*
+ * inform pass2 about varargs.
+ * store first variadic argument number in n_stalign
+ * in the CM node.
+ */
+ if (p->n_right->n_op != CM)
+ break; /* nothing to care about */
+ df = p->n_left->n_df;
+ if (df && (al = df->dfun)) {
+ for (i = 0; i < 6; i++, al++) {
+ if (al->type == TELLIPSIS || al->type == TNULL)
+ break;
+ }
+ p->n_right->n_stalign = al->type == TELLIPSIS ? i : 0;
+ } else
+ p->n_right->n_stalign = 0;
+ break;
+ }
+
+}
diff --git a/usr.bin/pcc/arch/m16c/local2.c b/usr.bin/pcc/arch/m16c/local2.c
new file mode 100644
index 00000000000..09f7e6f1204
--- /dev/null
+++ b/usr.bin/pcc/arch/m16c/local2.c
@@ -0,0 +1,639 @@
+/* $Id: local2.c,v 1.1 2007/09/15 18:12:27 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.
+ */
+
+
+# include "pass2.h"
+# include <ctype.h>
+
+void acon(NODE *p);
+int argsize(NODE *p);
+void genargs(NODE *p);
+
+static int ftlab1, ftlab2;
+
+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 TWORD ftype;
+static int addto;
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+ ftype = ipp->ipp_type;
+
+#if 0
+ if (ipp->ipp_regs > 0 && ipp->ipp_regs != MINRVAR)
+ comperr("fix prologue register savings", ipp->ipp_regs);
+#endif
+
+ printf(" RSEG CODE:CODE:REORDER:NOROOT(0)\n");
+ if (ipp->ipp_vis)
+ printf(" PUBLIC %s\n", ipp->ipp_name);
+ printf("%s:\n", ipp->ipp_name);
+
+#if 0
+ if (xsaveip) {
+ /* Optimizer running, save space on stack */
+ addto = (p2maxautooff - AUTOINIT)/SZCHAR;
+ printf(" enter #%d\n", addto);
+ } else {
+#endif
+
+ /* non-optimized code, jump to epilogue for code generation */
+ ftlab1 = getlab();
+ ftlab2 = getlab();
+ printf(" jmp.w " LABFMT "\n", ftlab1);
+ deflab(ftlab2);
+}
+
+/*
+ * End of block.
+ */
+void
+eoftn(struct interpass_prolog *ipp)
+{
+#if 0
+ if (ipp->ipp_regs != MINRVAR)
+ comperr("fix eoftn register savings %x", ipp->ipp_regs);
+#endif
+
+ // if (xsaveip == 0)
+ addto = (p2maxautooff - AUTOINIT)/SZCHAR;
+
+ /* return from function code */
+ //deflab(ipp->ipp_ip.ip_lbl); //XXX - is this necessary?
+
+ /* If retval is a pointer and not a function pointer, put in A0 */
+ if (ISPTR(DECREF(ipp->ipp_type)) &&
+ !ISFTN(DECREF(DECREF(ipp->ipp_type))))
+ printf(" mov.w r0,a0\n");
+
+ /* struct return needs special treatment */
+ if (ftype == STRTY || ftype == UNIONTY) {
+ comperr("fix struct return in eoftn");
+ } else
+ printf(" exitd\n");
+
+ /* Prolog code */
+ // if (xsaveip == 0) {
+ deflab(ftlab1);
+ printf(" enter #%d\n", addto);
+ printf(" jmp.w " LABFMT "\n", ftlab2);
+ //}
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+ char *str;
+
+ switch (o) {
+ case PLUS:
+ str = "add";
+ break;
+ case MINUS:
+ str = "sub";
+ 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 */
+ "r0", "r2", "r1", "r3", "a0", "a1", "fb", "sp", "r0h", "r0l",
+ "r1h", "r1l",
+};
+
+/*
+ * Return the size (in bytes) of some types.
+ */
+int
+tlen(p) NODE *p;
+{
+ switch(p->n_type) {
+ case CHAR:
+ case UCHAR:
+ return(1);
+
+ case INT:
+ case UNSIGNED:
+ case FLOAT:
+ return 2;
+
+ case DOUBLE:
+ case LONG:
+ case ULONG:
+ return 4;
+
+ default:
+ if (!ISPTR(p->n_type))
+ comperr("tlen type %d not pointer");
+ return SZPOINT(p->n_type)/SZCHAR;
+ }
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+ int o = p->n_op;
+ int s = getlab();
+ int e = p->n_label;
+ int cb1, cb2;
+
+ if (o >= ULE)
+ o -= (ULE-LE);
+ switch (o) {
+ case NE:
+ cb1 = 0;
+ cb2 = NE;
+ break;
+ case EQ:
+ cb1 = NE;
+ cb2 = 0;
+ break;
+ case LE:
+ case LT:
+ cb1 = GT;
+ cb2 = LT;
+ break;
+ case GE:
+ case GT:
+ cb1 = LT;
+ cb2 = GT;
+ break;
+
+ default:
+ cb1 = cb2 = 0; /* XXX gcc */
+ }
+ if (p->n_op >= ULE)
+ cb1 += 4, cb2 += 4;
+ expand(p, 0, " cmp.w UR,UL\n");
+ if (cb1) cbgen(cb1, s);
+ if (cb2) cbgen(cb2, e);
+ expand(p, 0, " cmp.w AR,AL\n");
+ cbgen(p->n_op, e);
+ deflab(s);
+}
+
+
+void
+zzzcode(NODE *p, int c)
+{
+ NODE *l;
+
+ switch (c) {
+ case 'A': /* print negative shift constant */
+ p = getlr(p, 'R');
+ if (p->n_op != ICON)
+ comperr("ZA bad use");
+ p->n_lval = -p->n_lval;
+ adrput(stdout, p);
+ p->n_lval = -p->n_lval;
+ break;
+
+ case 'B':
+ if (p->n_rval)
+ printf(" add.b #%d,%s\n",
+ p->n_rval, rnames[STKREG]);
+ break;
+
+ case 'C': /* Print label address */
+ p = p->n_left;
+ if (p->n_lval)
+ printf(LABFMT, (int)p->n_lval);
+ else
+ printf("%s", p->n_name);
+ break;
+
+ case 'D': /* copy function pointers */
+ l = p->n_left;
+ printf("\tmov.w #HWRD(%s),%s\n\tmov.w #LWRD(%s),%s\n",
+ p->n_right->n_name, rnames[l->n_rval+1],
+ p->n_right->n_name, rnames[l->n_rval]);
+ break;
+
+ case 'E': /* double-reg printout */
+ /* XXX - always r0r2 here */
+ printf("%s%s", rnames[R0], rnames[R2]);
+ break;
+
+ case 'F': /* long comparisions */
+ twollcomp(p);
+ break;
+
+ case 'G':
+ printf("R0R2");
+ break;
+
+ case 'H': /* push 32-bit address (for functions) */
+ printf("\tpush.w #HWRD(%s)\n\tpush.w #LWRD(%s)\n",
+ p->n_left->n_name, p->n_left->n_name);
+ break;
+
+ case 'I': /* push 32-bit address (for functions) */
+ l = p->n_left;
+ printf("\tpush.w %d[%s]\n\tpush.w %d[%s]\n",
+ (int)l->n_lval, rnames[l->n_rval],
+ (int)l->n_lval+2, rnames[l->n_rval]);
+ break;
+
+ default:
+ comperr("bad zzzcode %c", c);
+ }
+}
+
+/*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) == SRDIR))
+ 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;
+}
+
+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 /= SZINT;
+ 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 >> 16);
+ break;
+ default:
+ comperr("upput bad op %d size %d", p->n_op, size);
+ }
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+ /* 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:
+ 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:
+ /*if (DEUNSIGN(p->n_type) == CHAR) {
+ fprintf(io, "R%c%c", p->n_rval < 2 ? '0' : '1',
+ (p->n_rval & 1) ? 'H' : 'L');
+ } else*/
+ fprintf(io, "%s", rnames[p->n_rval]);
+ return;
+
+ default:
+ comperr("illegal address, op %d, node %p", p->n_op, p);
+ return;
+
+ }
+}
+
+static char *
+ccbranches[] = {
+ "jeq", /* jumpe */
+ "jne", /* jumpn */
+ "jle", /* jumple */
+ "jlt", /* jumpl */
+ "jge", /* jumpge */
+ "jgt", /* jumpg */
+ "jleu", /* jumple (jlequ) */
+ "jltu", /* jumpl (jlssu) */
+ "jgeu", /* jumpge (jgequ) */
+ "jgtu", /* jumpg (jgtru) */
+};
+
+
+/* printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+ if (o < EQ || o > UGT)
+ comperr("bad conditional branch: %s", opst[o]);
+ printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab);
+}
+
+#if 0
+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;
+
+}
+#endif
+
+struct hardops hardops[] = {
+ { PLUS, FLOAT, "?F_ADD_L04" },
+ { MUL, LONG, "?L_MUL_L03" },
+ { MUL, ULONG, "?L_MUL_L03" },
+ { DIV, LONG, "?SL_DIV_L03" },
+ { DIV, ULONG, "?UL_DIV_L03" },
+ { MOD, LONG, "?SL_MOD_L03" },
+ { MOD, ULONG, "?UL_MOD_L03" },
+ { RS, LONGLONG, "__ashrdi3" },
+ { RS, ULONGLONG, "__lshrdi3" },
+ { LS, LONGLONG, "__ashldi3" },
+ { LS, ULONGLONG, "__ashldi3" },
+ { 0 },
+};
+
+int
+special(NODE *p, int shape)
+{
+ switch (shape) {
+ case SFTN:
+ if (ISPTR(p->n_type) && ISFTN(DECREF(p->n_type))) {
+ if (p->n_op == NAME || p->n_op == OREG)
+ return SRDIR;
+ else
+ return SRREG;
+ }
+ break;
+ }
+ return SRNOPE;
+}
+
+void
+myreader(NODE *p)
+{
+ NODE *q, *r, *s, *right;
+
+ if (optype(p->n_op) == LTYPE)
+ return;
+ if (optype(p->n_op) != UTYPE)
+ myreader(p->n_right);
+ myreader(p->n_left);
+
+ switch (p->n_op) {
+ case PLUS:
+ case MINUS:
+ if (p->n_type != LONG && p->n_type != ULONG)
+ break;
+ if (p->n_right->n_op == NAME || p->n_right->n_op == OREG)
+ break;
+ /* Must convert right into OREG */
+ right = p->n_right;
+ q = mklnode(OREG, BITOOR(freetemp(szty(right->n_type))),
+ FPREG, right->n_type);
+ s = mkbinode(ASSIGN, q, right, right->n_type);
+ r = talloc();
+ *r = *q;
+ p->n_right = r;
+ pass2_compile(ipnode(s));
+ break;
+ }
+}
+
+
+void
+rmove(int s, int d, TWORD t)
+{
+ switch (t) {
+ case CHAR:
+ case UCHAR:
+ printf(" mov.b %s,%s\n", rnames[s], rnames[d]);
+ break;
+ default:
+ printf(" mov.w %s,%s\n", rnames[s], rnames[d]);
+ }
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+ int num;
+
+ switch (c) {
+ case CLASSA:
+ num = r[CLASSA];
+ num += r[CLASSC];
+ return num < 4;
+ case CLASSB:
+ num = r[CLASSB];
+ return num < 2;
+ case CLASSC:
+ num = 2*r[CLASSA];
+ num += r[CLASSC];
+ return num < 4;
+ }
+ return 0; /* XXX gcc */
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+ if (t == CHAR || t == UCHAR)
+ return CLASSC;
+
+ if(ISPTR(t))
+ return CLASSB;
+
+ return CLASSA;
+}
+
+static int sizen;
+
+/* XXX: Fix this. */
+static int
+argsiz(NODE *p)
+{
+ TWORD t = p->n_type;
+
+ if (t < LONGLONG || t > MAXTYPES)
+ return 4;
+ if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
+ return 8;
+ if (t == LDOUBLE)
+ return 12;
+ if (t == STRTY)
+ return p->n_stsize;
+ comperr("argsiz");
+ return 0;
+}
+
+/*
+ * Calculate argument sizes.
+ * XXX: Fix this.
+ */
+void
+lastcall(NODE *p)
+{
+ sizen = 0;
+ for (p = p->n_right; p->n_op == CM; p = p->n_left)
+ sizen += argsiz(p->n_right);
+ sizen += argsiz(p);
+}
diff --git a/usr.bin/pcc/arch/m16c/macdefs.h b/usr.bin/pcc/arch/m16c/macdefs.h
new file mode 100644
index 00000000000..010a2464b55
--- /dev/null
+++ b/usr.bin/pcc/arch/m16c/macdefs.h
@@ -0,0 +1,205 @@
+/* $Id: macdefs.h,v 1.1 2007/09/15 18:12:27 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.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+#define makecc(val,i) lastcon = (lastcon<<8)|((val<<8)>>8);
+
+#define ARGINIT 40 /* # bits above fp where arguments start */
+#define AUTOINIT 0 /* # bits below fp where automatics start */
+
+/*
+ * Convert (multi-)character constant to integer.
+ * Assume: If only one value; store at left side (char size), otherwise
+ * treat it as an integer.
+ */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR 8
+#define SZINT 16
+#define SZFLOAT 16
+#define SZDOUBLE 16
+#define SZLDOUBLE 16
+#define SZLONG 32
+#define SZSHORT 16
+#define SZLONGLONG 32
+/* pointers are of different sizes on m16c */
+#define SZPOINT(t) (ISFTN(DECREF(t)) ? 32 : 16)
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR 8
+#define ALINT 16
+#define ALFLOAT 16
+#define ALDOUBLE 16
+#define ALLDOUBLE 16
+#define ALLONG 16
+#define ALLONGLONG 16
+#define ALSHORT 16
+#define ALPOINT 16
+#define ALSTRUCT 16
+#define ALSTACK 16
+
+/*
+ * 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 -32768
+#define MAX_INT 32767
+#define MAX_UNSIGNED 65535
+#define MIN_LONG -2147483648
+#define MAX_LONG 2147483647
+#define MAX_ULONG 4294967295UL
+#define MIN_LONGLONG -2147483648
+#define MAX_LONGLONG 2147483647
+#define MAX_ULONGLONG 4294967295UL
+
+/* 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 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 */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x) 1
+#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) == LONG || (t) == ULONG || \
+ (ISPTR(t) && ISFTN(DECREF(t)))) ? 2 : 1)
+
+/*
+ * m16c register classes:
+ * A - 16-bit data registers R0-R3
+ * B - 16-bit address registers A0-A1
+ * C - 8-bit data registers R0H, R0L, R1H, R1L
+ */
+
+#define R0 0
+#define R2 1
+#define R1 2
+#define R3 3
+
+#define A0 4
+#define A1 5
+#define FB 6
+#define SP 7
+
+#define R0H 8
+#define R0L 9
+#define R1H 10
+#define R1L 11
+
+#define NUMCLASS 4 /* Number of register classes */
+
+#define RETREG(x) (x == CHAR || x == UCHAR ? R0L : R0)
+
+#define FPREG FB /* frame pointer */
+#define STKREG SP /* stack pointer */
+
+#if 0
+#define REGSZ 8 /* Number of registers */
+#define MINRVAR R1 /* first register variable */
+#define MAXRVAR R2 /* last register variable */
+#endif
+
+#define MAXREGS 12 /* 12 registers */
+
+#define RSTATUS \
+ SAREG|TEMPREG, SAREG|PERMREG, SAREG|TEMPREG, SAREG|PERMREG, \
+ SBREG|TEMPREG, SBREG|PERMREG, 0, 0, SCREG, SCREG, SCREG, SCREG,
+
+#define ROVERLAP \
+ {R0H, R0L, -1},\
+ {-1},\
+ {R1H, R1L, -1},\
+ {-1},\
+\
+ {-1},\
+ {-1},\
+\
+ {-1},\
+ {-1},\
+\
+ {R0, -1},\
+ {R0, -1},\
+ {R1, -1},\
+ {R1, -1},
+
+#define PCLASS(p) (p->n_type <= UCHAR ? SCREG : ISPTR(p->n_type) ? SBREG:SAREG)
+
+int COLORMAP(int c, int *r);
+#define GCLASS(x) (x < 4 ? CLASSA : x < 6 ? CLASSB : x < 12 ? CLASSC : CLASSD)
+#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */
+#define ENCRD(x) (x) /* Encode dest reg in n_reg */
+#define ENCRA1(x) ((x) << 6) /* A1 */
+#define ENCRA2(x) ((x) << 12) /* A2 */
+#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */
+
+#define MYADDEDGE(x, t)
+#define MYREADER(p) myreader(p)
+#define MYP2TREE(p) myp2tree(p)
+
+#if 0
+#define MYCANON(p) mycanon(p)
+#define MYOPTIM
+#endif
+
+#ifndef NEW_READER
+//#define TAILCALL
+#endif
+#define SFTN (SPECIAL|6)
diff --git a/usr.bin/pcc/arch/m16c/order.c b/usr.bin/pcc/arch/m16c/order.c
new file mode 100644
index 00000000000..4c648c01ef0
--- /dev/null
+++ b/usr.bin/pcc/arch/m16c/order.c
@@ -0,0 +1,600 @@
+/* $Id: order.c,v 1.1 2007/09/15 18:12:27 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.
+ */
+
+
+# include "pass2.h"
+# include <strings.h>
+
+int canaddr(NODE *);
+
+/*
+ * should the assignment op p be stored,
+ * given that it lies as the right operand of o
+ * (or the left, if o==UNARY MUL)
+ */
+/*
+void
+stoasg(NODE *p, int o)
+{
+ if (x2debug)
+ printf("stoasg(%p, %o)\n", p, o);
+}
+*/
+/* 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, int shape)
+{
+ 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, INBREG);
+ p->n_su = -1;
+ return 1;
+ }
+ }
+ geninsn(p, INBREG);
+ return 0;
+}
+
+/*
+ * Shape matches for UMUL. Cooperates with offstar().
+ */
+int
+shumul(NODE *p)
+{
+// NODE *l = p->n_left;
+
+#ifdef PCC_DEBUG
+ if (x2debug) {
+ printf("shumul(%p)\n", p);
+ fwalk(p, e2print, 0);
+ }
+#endif
+
+ /* Can only generate OREG of BREGs (or FB) */
+ if (p->n_op == REG && (isbreg(p->n_rval) || p->n_rval == FB))
+ return SOREG;
+#if 0
+ if ((p->n_op == PLUS || p->n_op == MINUS) &&
+ (l->n_op == REG && (isbreg(l->n_rval) || l->n_rval == FB)) &&
+ p->n_right->n_op == ICON)
+ return SOREG;
+ return 0;
+#else
+ return SOREG;
+#endif
+}
+
+/*
+ * 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;
+}
+
+#if 0
+/*
+ * register allocation for instructions with special preferences.
+ */
+regcode
+regalloc(NODE *p, struct optab *q, int wantreg)
+{
+ regcode regc;
+
+ if (q->op == DIV || q->op == MOD) {
+ /*
+ * 16-bit div.
+ */
+ if (regblk[R0] & 1 || regblk[R2] & 1)
+ comperr("regalloc: needed regs inuse, node %p", p);
+ if (p->n_su & DORIGHT) {
+ regc = alloregs(p->n_right, A0);
+ if (REGNUM(regc) != A0) {
+ p->n_right = movenode(p->n_right, A0);
+ if ((p->n_su & RMASK) == ROREG) {
+ p->n_su &= ~RMASK;
+ p->n_su |= RREG;
+ p->n_right->n_su &= ~LMASK;
+ p->n_right->n_su |= LOREG;
+ }
+ freeregs(regc);
+ regblk[A0] |= 1;
+ }
+ }
+ regc = alloregs(p->n_left, R0);
+ if (REGNUM(regc) != R0) {
+ p->n_left = movenode(p->n_left, R0);
+ freeregs(regc);
+ regblk[R0] |= 1;
+ }
+ if ((p->n_su & RMASK) && !(p->n_su & DORIGHT)) {
+ regc = alloregs(p->n_right, A0);
+ if (REGNUM(regc) != A0) {
+ p->n_right = movenode(p->n_right, A0);
+ if ((p->n_su & RMASK) == ROREG) {
+ p->n_su &= ~RMASK;
+ p->n_su |= RREG;
+ p->n_right->n_su &= ~LMASK;
+ p->n_right->n_su |= LOREG;
+ }
+ }
+ }
+ regblk[A0] &= ~1;
+ regblk[R0] &= ~1;
+ regblk[R2] &= ~1;
+ if (q->op == DIV) {
+ MKREGC(regc, R0, 1);
+ regblk[R0] |= 1;
+ } else {
+ MKREGC(regc, R2, 1);
+ regblk[R2] |= 1;
+ }
+ } else
+ comperr("regalloc");
+ p->n_rall = REGNUM(regc);
+ return regc;
+}
+#endif
+
+/*
+ * 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.
+ *
+ * XXX - Fix this function
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+ switch (q->op) {
+
+ case DIV:
+ case MOD:
+ if(q->ltype & (TINT|TSHORT)){
+ static struct rspecial s[] = {
+ { NRES, R0 }, { NRES, R2}, { 0 } };
+ return s;
+ }
+ /*
+ else if(q->ltype & TCHAR) {
+ static struct rspecial s[] = {
+ { NRES, R0L }, { NRES, R0H}, { 0 } };
+ return s;
+ }*/
+ break;
+
+ case MUL:
+ /*
+ if(q->ltype & (TINT|TSHORT)){
+ static struct rspecial s[] = {
+ { NRES, R0 }, { NRES, R2}, { 0 } };
+ return s;
+ }*/
+ comperr("multiplication not implemented");
+ break;
+
+ default:
+ break;
+ }
+ comperr("nspecial entry %d", q - table);
+ return 0; /* XXX gcc */
+}
+
+
+/*
+ * Splitup a function call and give away its arguments first.
+ * Calling convention used ("normal" in IAR syntax) is:
+ * - 1-byte parameters in R0L if possible, otherwise in R0H.
+ * - 2-byte pointers in A0.
+ * - 2-byte non-pointers in R0 if no byte-size arguments are found in
+ * in the first 6 bytes of parameters, otherwise R2 or at last A0.
+ * - 4-byte parameters in R2R0.
+ */
+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:
+ /* swap arguments on some hardop-converted insns */
+ /* Normal call, just push args and be done with it */
+ p->n_op = UCALL;
+//printf("call\n");
+ /* Check if left can be evaluated directly */
+ if (p->n_left->n_op == UMUL) {
+ TWORD t = p->n_left->n_type;
+ int k = BITOOR(freetemp(szty(t)));
+ NODE *n = mklnode(OREG, k, FB, t);
+ NODE *q = tcopy(n);
+ pass2_compile(ipnode(mkbinode(ASSIGN, n, p->n_left,t)));
+ p->n_left = q;
+ }
+ gencall(p->n_left, p);
+ p->n_rval = storearg(p->n_right);
+//printf("end call\n");
+ 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.
+ * This is partly ticky, the strange calling convention
+ * may cause a bunch of code reorganization here.
+ */
+static int
+storearg(NODE *p)
+{
+ NODE *n, *q, **narry;
+ int nch, k, i, nn, rary[4];
+ int r0l, r0h, r2, a0, stk, sz;
+ TWORD t;
+ int maxrargs = 0;
+
+ if (p->n_op == CM)
+ maxrargs = p->n_stalign;
+
+ /* count the arguments */
+ for (i = 1, q = p; q->n_op == CM; q = q->n_left)
+ i++;
+ nn = i;
+
+ /* allocate array to store arguments */
+ narry = tmpalloc(sizeof(NODE *)*nn);
+
+ /* enter nodes into array */
+ for (q = p; q->n_op == CM; q = q->n_left)
+ narry[--i] = q->n_right;
+ narry[--i] = q;
+
+ /* free CM nodes */
+ for (q = p; q->n_op == CM; ) {
+ n = q->n_left;
+ nfree(q);
+ q = n;
+ }
+
+ /* count char args */
+ r0l = r0h = r2 = a0 = 0;
+ for (sz = nch = i = 0; i < nn && i < 6; i++) {
+ TWORD t = narry[i]->n_type;
+ if (sz >= 6)
+ break;
+ if (t == CHAR || t == UCHAR) {
+ nch++;
+ sz++;
+ } else if ((t >= SHORT && t <= UNSIGNED) ||
+ t > BTMASK || t == FLOAT) {
+ sz += 2;
+ } else /* long, double */
+ sz += 4;
+
+ }
+
+ /*
+ * Now the tricky part. The parameters that should be on stack
+ * must be found and pushed first, then the register parameters.
+ * For the latter, be sure that evaluating them do not use any
+ * registers where argument values already are inserted.
+ * XXX - function pointers?
+ * XXX foo(long a, char b) ???
+ */
+ for (stk = 0; stk < 4; stk++) {
+ TWORD t;
+
+ if (stk == nn)
+ break;
+ t = narry[stk]->n_type;
+ if (ISFTN(DECREF(t)))
+ t = LONG;
+ switch (t) {
+ case CHAR: case UCHAR:
+ if (r0l) {
+ if (r0h)
+ break;
+ rary[stk] = R2; /* char talk for 'R0H' */
+ r0h = 1;
+ } else {
+ rary[stk] = R0;
+ r0l = 1;
+ }
+ continue;
+
+ case INT: case UNSIGNED:
+ if (r0l || nch) {
+ if (r2) {
+ if (a0)
+ break;
+ rary[stk] = A0;
+ a0 = 1;
+ } else {
+ rary[stk] = R2;
+ r2 = 1;
+ }
+ } else {
+ rary[stk] = R0;
+ r0l = r0h = 1;
+ }
+ continue;
+
+ case LONG: case ULONG:
+ if (r0l || r2)
+ break;
+ rary[stk] = R0;
+ r0l = r0h = r2 = 1;
+ continue;
+
+ default:
+ if (ISPTR(narry[stk]->n_type) &&
+ !ISFTN(DECREF(narry[stk]->n_type))) {
+ if (a0) {
+ if (r0l || nch) {
+ if (r2)
+ break;
+ rary[stk] = R2;
+ r2 = 1;
+ } else {
+ rary[stk] = R0;
+ r0l = r0h = 1;
+ }
+ } else {
+ rary[stk] = A0;
+ a0 = 1;
+ }
+ continue;
+ }
+ break;
+ }
+ break;
+ }
+
+ /*
+ * The arguments that must be on stack are stk->nn args.
+ * Argument 0->stk-1 should be put in the rary[] register.
+ */
+ for (sz = 0, i = nn-1; i >= stk; i--) { /* first stack args */
+ NODE nod;
+ pass2_compile(ipnode(mkunode(FUNARG,
+ narry[i], 0, narry[i]->n_type)));
+ nod.n_type = narry[i]->n_type;
+ sz += tlen(&nod);
+ }
+ /* if param cannot be addressed directly, evaluate and put on stack */
+ for (i = 0; i < stk; i++) {
+
+ if (canaddr(narry[i]))
+ continue;
+ t = narry[i]->n_type;
+ k = BITOOR(freetemp(szty(t)));
+ n = mklnode(OREG, k, FB, t);
+ q = tcopy(n);
+ pass2_compile(ipnode(mkbinode(ASSIGN, n, narry[i], t)));
+ narry[i] = q;
+ }
+ /* move args to registers */
+ for (i = 0; i < stk; i++) {
+ t = narry[i]->n_type;
+ pass2_compile(ipnode(mkbinode(ASSIGN,
+ mklnode(REG, 0, rary[i], t), narry[i], t)));
+ }
+ return sz;
+}
+
+/*
+ * Tell if a register can hold a specific datatype.
+ */
+#if 0
+int
+mayuse(int reg, TWORD type)
+{
+ return 1; /* Everything is OK */
+}
+#endif
+
+#ifdef TAILCALL
+void
+mktailopt(struct interpass *ip1, struct interpass *ip2)
+{
+ extern int earlylab;
+ extern char *cftname;
+ char *fn;
+ NODE *p;
+
+ p = ip1->ip_node->n_left->n_left;
+ if (p->n_op == ICON) {
+ fn = p->n_name;
+ /* calling ourselves */
+ p = ip1->ip_node->n_left;
+ if (p->n_op == CALL) {
+ if (storearg(p->n_right))
+ comperr("too many args: fix mktailopt");
+ p->n_op = UCALL;
+ }
+ tfree(ip1->ip_node);
+ p = ip2->ip_node->n_left;
+ if (strcmp(fn, cftname)) {
+ /* Not us, must generate fake prologue */
+ ip1->type = IP_ASM;
+ ip1->ip_asm = "mov.w FB,SP\n\tpop.w FB";
+ pass2_compile(ip1);
+ p->n_lval = p->n_rval = 0;
+ p->n_name = fn;
+ } else
+ p->n_lval = earlylab;
+ } else {
+ pass2_compile(ip1);
+ }
+ pass2_compile(ip2);
+}
+#endif
diff --git a/usr.bin/pcc/arch/m16c/table.c b/usr.bin/pcc/arch/m16c/table.c
new file mode 100644
index 00000000000..879a41334c7
--- /dev/null
+++ b/usr.bin/pcc/arch/m16c/table.c
@@ -0,0 +1,595 @@
+#include "pass2.h"
+
+# define ANYSIGNED TINT|TLONG|TCHAR
+# define ANYUSIGNED TUNSIGNED|TULONG|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TL TLONG|TULONG
+# define TWORD TUNSIGNED|TINT
+# define TCH TCHAR|TUCHAR
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* (signed) char -> int/pointer */
+{ SCONV, INAREG,
+ SCREG, TCHAR,
+ SANY, TINT|TPOINT,
+ NAREG, RESC1,
+ " mov.b AL, A1\n\texts.b A1\n", },
+
+/* (unsigned) char -> int/pointer */
+{ SCONV, INAREG,
+ SCREG, TUCHAR,
+ SANY, TINT|TPOINT,
+ NAREG, RESC1,
+ " mov.b AL, A1\n", },
+
+/* unsigned char -> long */
+{ SCONV, INAREG,
+ SCREG, TUCHAR,
+ SANY, TL,
+ NAREG|NASL, RESC1,
+ " mov.b AL, A1\n mov.w #0,U1\n", },
+
+/* int or pointer -> (unsigned) long */
+{ SCONV, INAREG,
+ SAREG|SNAME, TWORD|TPOINT,
+ SANY, TL,
+ NAREG|NASL, RESC1,
+ " mov.w AL,A1\n mov.w #0,U1\n", },
+
+/* char -> (signed) long */
+{ SCONV, INAREG,
+ SAREG|SNAME, TCHAR,
+ SANY, TLONG,
+ NAREG|NASL, RESC1,
+ " exts.b AL\n exts.w AL\n", },
+
+/* long -> ulong */
+{ SCONV, INAREG,
+ SAREG, TL,
+ SANY, TL,
+ 0, RLEFT,
+ "", },
+
+/* long -> int or pointer */
+{ SCONV, INAREG,
+ SAREG|SOREG|SNAME, TL,
+ SANY, TWORD|TPOINT,
+ NAREG|NASL, RESC1,
+ " mov.w AL,A1\n", },
+
+/* int -> char */
+{ SCONV, INCREG,
+ SAREG, TWORD,
+ SANY, TCH,
+ NCREG, RESC1,
+ " mov.b AL, A1\n", },
+
+/* int -> long */
+{ SCONV, INAREG,
+ SAREG, TWORD,
+ SANY, TLONG,
+ NAREG|NASL, RESC1,
+ " exts.w AL", },
+
+/* long -> char */
+{ SCONV, INAREG,
+ SAREG, TL,
+ SANY, TCH,
+ NAREG|NASL, RESC1,
+ "", },
+
+{ SCONV, INAREG,
+ SAREG, TPOINT,
+ SANY, TWORD,
+ 0, RLEFT,
+ "", },
+
+{ PLUS, INAREG|FOREFF,
+ SAREG, TL,
+ SCON|SNAME|SOREG, TL,
+ 0, RLEFT,
+ " add.w AR,AL\n adc.w UR,UL\n", },
+
+{ MINUS, INAREG|FOREFF,
+ SAREG, TL,
+ SCON|SNAME|SOREG, TL,
+ 0, RLEFT,
+ " sub.w AR,AL\n sbb.w UR,UL\n", },
+
+{ AND, INAREG|FOREFF,
+ SAREG, TL,
+ SAREG|SNAME|SOREG, TL,
+ 0, RLEFT,
+ " and.w AR,AL\n and.w UR,UL\n", },
+
+{ ER, INAREG|FOREFF,
+ SAREG, TL,
+ SAREG|SNAME|SOREG, TL,
+ 0, RLEFT,
+ " xor.w AR,AL\n xor.w UR,UL\n", },
+
+{ OR, INAREG|FOREFF,
+ SAREG, TL,
+ SAREG|SNAME|SOREG, TL,
+ 0, RLEFT,
+ " xor.w AR,AL\n xor.w UR,UL\n", },
+
+{ COMPL, INAREG|FOREFF,
+ SAREG, TL,
+ SAREG|SNAME|SOREG, TL,
+ 0, RLEFT,
+ " not.w AR,AL\n not.w UR,UL\n", },
+
+{ OPSIMP, INAREG|FOREFF,
+ SAREG, TWORD|TPOINT,
+ SAREG|SNAME|SOREG|SCON, TWORD|TPOINT,
+ 0, RLEFT,
+ " Ow AR,AL\n", },
+
+/* XXX - Is this rule really correct? Having a SAREG shape seems kind of
+ strange. Doesn't work. Gives a areg as A1. */
+#if 0
+{ OPSIMP, INBREG,
+ SAREG, TWORD|TPOINT,
+ SAREG|SBREG|SNAME|SOREG|SCON, TWORD|TPOINT,
+ NBREG, RESC1,
+ " ++Ow AR,A1\n", },
+#endif
+
+{ OPSIMP, INBREG,
+ SBREG, TWORD|TPOINT,
+ SAREG|SBREG|SNAME|SOREG|SCON, TWORD|TPOINT,
+ 0, RLEFT,
+ " Ow AR,AL\n", },
+
+{ OPSIMP, INCREG|FOREFF,
+ SCREG, TCH,
+ SCREG|SNAME|SOREG|SCON, TCH,
+ 0, RLEFT,
+ " Ob AR,AL\n", },
+
+/* XXX - Do these work? check nspecial in order.c */
+/* signed integer division */
+{ DIV, INAREG,
+ SAREG, TINT,
+ SAREG|SNAME|SOREG, TWORD,
+ /*2*NAREG|NASL|*/NSPECIAL, RLEFT,
+ " div.w AR\n mov.w r0,AL\n", },
+ // " xor.w r2\n div.w AR\n", },
+
+
+/* signed integer/char division - separate entry for FOREFF */
+{ DIV, FOREFF,
+ SAREG, TINT,
+ SAREG|SNAME|SOREG, TWORD,
+ 0, 0,
+ "", },
+
+#if 0
+/* signed char division */
+{ DIV, INCREG,
+ SCREG, TCHAR,
+ SCREG|SNAME|SOREG, TCH,
+ 2*NCREG|NCSL|NSPECIAL, RLEFT,
+ " div.b AR\n\tmov.b r0l,AL\n", },
+ // " xor.w r2\n div.w AR\n", },
+#endif
+
+/* signed integer modulus, equal to above */
+{ MOD, INAREG,
+ SAREG, TINT,
+ SAREG|SNAME|SOREG, TWORD,
+ /*2*NAREG|NASL|*/NSPECIAL, RLEFT,
+ " div.w AR\n\tmov r2,AL\n", },
+
+/* signed integer modulus - separate entry for FOREFF */
+{ MOD, FOREFF,
+ SAREG, TINT,
+ SAREG|SNAME|SOREG, TWORD,
+ 0, 0,
+ "", },
+
+/* signed integer multiplication */
+{ MUL, INAREG,
+ SAREG, TINT,
+ SAREG|SNAME|SOREG, TWORD,
+ 2*NAREG|NASL|NSPECIAL, RESC1,
+ " mul.w AL,AR\n", },
+
+{ MUL, FOREFF,
+ SAREG, TINT,
+ SAREG|SNAME|SOREG, TWORD,
+ 0, 0,
+ "", },
+
+#if 0
+{ LS, INAREG,
+ SAREG, TWORD,
+ SCON, TANY,
+ 0, RLEFT,
+ " shl.w AR,AL\n", },
+#endif
+
+{ LS, INAREG,
+ SAREG, TWORD,
+ SAREG, TWORD,
+ 0, RLEFT,
+ " push.b r1h\n"
+ " mov.b AR,r1h\n"
+ " shl.w r1h,AL\n"
+ " pop.b r1h\n", },
+
+{ LS, INAREG,
+ SAREG, TL,
+ SAREG, TWORD,
+ 0, RLEFT,
+ " push.b r1h\n"
+ " mov.b AR,r1h\n"
+ " shl.l r1h,ZG\n"
+ " pop.b r1h\n", },
+
+{ RS, INAREG,
+ SAREG, TWORD,
+ SAREG, TWORD,
+ 0, RLEFT,
+ " push.b r1h\n"
+ " mov.b AR,r1h\n"
+ " neg.b r1h\n"
+ " shl.w r1h,AL\n"
+ " pop.b r1h\n", },
+
+{ RS, INAREG,
+ SAREG, TL,
+ SAREG, TWORD,
+ 0, RLEFT,
+ " push.b r1h\n"
+ " mov.b AR,r1h\n"
+ " neg.b r1h\n"
+ " shl.l r1h,ZG\n"
+ " pop.b r1h\n", },
+
+#if 0
+{ RS, INAREG,
+ SAREG, TUNSIGNED,
+ SCON, TANY,
+ 0, RLEFT,
+ " shl ZA,AL\n", },
+
+{ RS, INAREG,
+ SAREG, TINT,
+ SCON, TANY,
+ 0, RLEFT,
+ " sha ZA,AL\n", },
+#endif
+
+{ OPLOG, FORCC,
+ SAREG|SBREG|SOREG|SNAME, TL,
+ SAREG|SBREG|SOREG|SNAME, TL,
+ 0, 0,
+ "ZF", },
+
+{ OPLOG, FORCC,
+ SBREG|SOREG, TWORD|TPOINT,
+ SCON, TWORD|TPOINT,
+ 0, RESCC,
+ " cmp.w AR,AL\n", },
+
+{ OPLOG, FORCC,
+ SAREG|SBREG|SOREG|SNAME, TWORD|TPOINT,
+ SAREG|SBREG|SOREG|SNAME, TWORD|TPOINT,
+ 0, RESCC,
+ " cmp.w AR,AL\n", },
+
+{ OPLOG, FORCC,
+ SCREG|SOREG|SNAME, TCH,
+ SCREG|SOREG|SNAME, TCH,
+ 0, RESCC,
+ " cmp.b AR,AL\n", },
+
+{ OPLOG, FORCC,
+ SCREG|SOREG|SNAME, TCH,
+ SCREG|SOREG|SNAME, TCH,
+ 0, RESCC,
+ " cmp.b AR,AL\n", },
+
+{ GOTO, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ 0, RNOP,
+ " jmp.w ZC\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SCON|SNAME|SOREG|SAREG, TL|TFTN,
+ NAREG, RESC1,
+ " mov.w AR,A1\n mov.w UR,U1\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SCON|SNAME|SOREG|SAREG|SBREG, TWORD|TPOINT,
+ NAREG, RESC1,
+ " mov.w AR,A1\n", },
+
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SBREG|SCON|SNAME|SOREG|SAREG, TWORD|TPOINT,
+ NBREG, RESC1,
+ " mov.w AR,A1\n", },
+ /*
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SCON|SNAME|SOREG, TCH,
+ NAREG, RESC1,
+ " mov.b AR, A1\n", },
+
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SCON|SNAME|SOREG, TCHAR|TUCHAR,
+ NBREG, RESC1,
+ " mov.b AR,A1\n", },
+ */
+
+{ OPLTYPE, INCREG,
+ SANY, TANY,
+ SCON|SNAME|SOREG, TCHAR|TUCHAR,
+ NCREG, RESC1,
+ " mov.b AR,A1\n", },
+
+{ COMPL, INAREG,
+ SAREG, TWORD,
+ SANY, TANY,
+ 0, RLEFT,
+ " not.w AL\n", },
+
+{ COMPL, INCREG,
+ SCREG, TCH,
+ SANY, TANY,
+ 0, RLEFT,
+ " not.b AL\n", },
+
+/* Push function address */
+{ FUNARG, FOREFF,
+ SCON, TFTN,
+ SANY, TANY,
+ 0, RNULL,
+ "ZH", },
+
+{ FUNARG, FOREFF,
+ SOREG, TFTN,
+ SANY, TANY,
+ 0, RNULL,
+ "ZI", },
+
+{ FUNARG, FOREFF,
+ SNAME|SAREG, TL|TFTN,
+ SANY, TANY,
+ 0, RNULL,
+ " push.w UL\n push.w AL\n", },
+
+{ FUNARG, FOREFF,
+ SCON|SAREG|SNAME|SOREG, TWORD|TPOINT,
+ SANY, TANY,
+ 0, RNULL,
+ " push.w AL\n", },
+
+{ FUNARG, FOREFF,
+ SAREG|SNAME|SOREG, TCHAR|TUCHAR,
+ SANY, TANY,
+ 0, RNULL,
+ " push.b AL\n", },
+
+/* Match function pointers first */
+#if 0
+{ ASSIGN, FOREFF,
+ SFTN, TWORD|TPOINT,
+ SFTN, TWORD|TPOINT,
+ NAREG, 0,
+ "ZD", },
+#endif
+
+{ ASSIGN, INAREG,
+ SAREG, TFTN,
+ SCON, TFTN,
+ 0, RLEFT,
+ "ZD", },
+
+{ ASSIGN, INBREG,
+ SBREG, TFTN,
+ SCON, TFTN,
+ 0, RLEFT,
+ "ZD", },
+
+{ ASSIGN, INAREG,
+ SAREG, TFTN,
+ SBREG|SAREG|SOREG|SNAME, TFTN,
+ 0, RLEFT,
+ " mov.w AR,AL\n mov.w UR,UL\n", },
+
+{ ASSIGN, INBREG,
+ SBREG, TFTN,
+ SBREG|SAREG|SOREG|SNAME, TFTN,
+ 0, RLEFT,
+ " mov.w AR,AL\n mov.w UR,UL\n", },
+
+{ ASSIGN, INAREG,
+ SBREG|SAREG|SOREG|SNAME, TFTN,
+ SAREG, TFTN,
+ 0, RRIGHT,
+ " mov.w AR,AL\n mov.w UR,UL\n", },
+
+{ ASSIGN, INBREG,
+ SBREG|SAREG|SOREG|SNAME, TFTN,
+ SBREG, TFTN,
+ 0, RRIGHT,
+ " mov.w AR,AL\n mov.w UR,UL\n", },
+
+/* a reg -> a reg */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RLEFT,
+ " mov.w AR,AL\n", },
+
+{ ASSIGN, INAREG,
+ SBREG|SAREG|SOREG|SNAME, TL,
+ SAREG, TL,
+ 0, RRIGHT,
+ " mov.w AR,AL\n mov.w UR,UL\n", },
+
+{ ASSIGN, INBREG,
+ SBREG|SAREG|SOREG|SNAME, TL,
+ SBREG, TL,
+ 0, RRIGHT,
+ " mov.w AR,AL\n mov.w UR,UL\n", },
+
+{ ASSIGN, FOREFF,
+ SBREG|SAREG|SOREG|SNAME, TL,
+ SCON|SBREG|SAREG|SOREG|SNAME, TL,
+ 0, 0,
+ " mov.w AR,AL\n mov.w UR,UL\n", },
+
+{ ASSIGN, INAREG|FOREFF,
+ SAREG, TWORD|TPOINT,
+ SCON, TANY,
+ 0, RLEFT,
+ " mov.w AR,AL\n", },
+
+{ ASSIGN, INBREG|FOREFF,
+ SBREG, TWORD|TPOINT,
+ SCON, TANY,
+ 0, RLEFT,
+ " mov.w AR,AL\n", },
+
+{ ASSIGN, FOREFF,
+ SNAME|SOREG, TWORD|TPOINT,
+ SCON, TANY,
+ 0, 0,
+ " mov.w AR,AL\n", },
+
+/* char, oreg/name -> c reg */
+{ ASSIGN, FOREFF|INCREG,
+ SCREG, TCHAR|TUCHAR,
+ SOREG|SNAME|SCON, TCHAR|TUCHAR,
+ 0, RLEFT,
+ " mov.b AR,AL\n", },
+
+/* int, oreg/name -> a reg */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TWORD|TPOINT,
+ SOREG|SNAME, TWORD|TPOINT,
+ 0, RLEFT,
+ " mov.w AR,AL\n", },
+
+{ ASSIGN, FOREFF|INBREG,
+ SBREG, TWORD|TPOINT,
+ SOREG|SNAME, TWORD|TPOINT,
+ 0, RLEFT,
+ " mov.w AR,AL\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SOREG|SNAME, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RRIGHT,
+ " mov.w AR,AL\n", },
+
+{ ASSIGN, FOREFF|INBREG,
+ SOREG|SNAME, TWORD|TPOINT,
+ SBREG, TWORD|TPOINT,
+ 0, RRIGHT,
+ " mov.w AR,AL\n", },
+
+{ ASSIGN, FOREFF|INCREG,
+ SOREG|SNAME, TCHAR|TUCHAR,
+ SCREG, TCHAR|TUCHAR,
+ 0, RRIGHT,
+ " mov.b AR,AL\n", },
+
+{ ASSIGN, FOREFF|INCREG,
+ SCREG, TCHAR|TUCHAR,
+ SCREG, TCHAR|TUCHAR,
+ 0, RRIGHT,
+ " mov.b AR,AL\n", },
+
+{ ASSIGN, FOREFF|INBREG,
+ SBREG, TWORD|TPOINT,
+ SBREG, TWORD|TPOINT,
+ 0, RRIGHT,
+ " mov.w AR,AL\n", },
+
+ /*
+{ MOVE, FOREFF|INAREG,
+ SAREG|SBREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ NAREG, RESC1,
+ " mov.w AL, AR\n", },
+ */
+
+{ UMUL, INAREG,
+ SBREG, TPOINT|TWORD,
+ SANY, TFTN,
+ NAREG, RESC1,
+ " mov.w [AL],A1\n mov.w 2[AL],U1\n", },
+
+{ UMUL, INAREG,
+ SBREG, TPOINT|TWORD,
+ SANY, TPOINT|TWORD,
+ NAREG, RESC1,
+ " mov.w [AL],A1\n", },
+
+{ UMUL, INBREG,
+ SBREG, TPOINT|TWORD,
+ SANY, TPOINT|TWORD,
+ NBREG|NBSL, RESC1,
+ " mov.w [AL],A1\n", },
+
+{ UMUL, INAREG,
+ SBREG, TCHAR|TUCHAR|TPTRTO,
+ SANY, TCHAR|TUCHAR,
+ NAREG, RESC1,
+ " mov.b [AL], A1\n", },
+
+{ UCALL, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ 0, 0,
+ " jsr.w CL\nZB", },
+
+{ UCALL, INAREG,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG, RESC1,
+ " jsr.w CL\nZB", },
+
+{ UCALL, INAREG,
+ SNAME|SOREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " jsri.a AL\nZB", },
+
+{ UCALL, FOREFF,
+ SNAME|SOREG, TANY,
+ SANY, TANY,
+ 0, 0,
+ " jsri.a AL\nZB", },
+
+{ UCALL, INAREG,
+ SBREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " jsri.a [AL]\nZB", },
+
+{ UCALL, FOREFF,
+ SBREG, TANY,
+ SANY, TANY,
+ 0, 0,
+ " jsri.a [AL]\nZB", },
+
+
+{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
+
diff --git a/usr.bin/pcc/arch/mips/TODO b/usr.bin/pcc/arch/mips/TODO
new file mode 100644
index 00000000000..63b5f67c34a
--- /dev/null
+++ b/usr.bin/pcc/arch/mips/TODO
@@ -0,0 +1,7 @@
+* 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/arch/mips/code.c b/usr.bin/pcc/arch/mips/code.c
new file mode 100644
index 00000000000..397210ece14
--- /dev/null
+++ b/usr.bin/pcc/arch/mips/code.c
@@ -0,0 +1,239 @@
+/* $Id: code.c,v 1.1 2007/09/15 18:12:27 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/arch/mips/local.c b/usr.bin/pcc/arch/mips/local.c
new file mode 100644
index 00000000000..33baa4e8cd2
--- /dev/null
+++ b/usr.bin/pcc/arch/mips/local.c
@@ -0,0 +1,533 @@
+/* $Id: local.c,v 1.1 2007/09/15 18:12:27 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/arch/mips/local2.c b/usr.bin/pcc/arch/mips/local2.c
new file mode 100644
index 00000000000..37fa54f13fb
--- /dev/null
+++ b/usr.bin/pcc/arch/mips/local2.c
@@ -0,0 +1,774 @@
+/* $Id: local2.c,v 1.1 2007/09/15 18:12:27 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/arch/mips/macdefs.h b/usr.bin/pcc/arch/mips/macdefs.h
new file mode 100644
index 00000000000..87534a64660
--- /dev/null
+++ b/usr.bin/pcc/arch/mips/macdefs.h
@@ -0,0 +1,227 @@
+/* $Id: macdefs.h,v 1.1 2007/09/15 18:12:27 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/arch/mips/order.c b/usr.bin/pcc/arch/mips/order.c
new file mode 100644
index 00000000000..2173d8db624
--- /dev/null
+++ b/usr.bin/pcc/arch/mips/order.c
@@ -0,0 +1,350 @@
+/* $Id: order.c,v 1.1 2007/09/15 18:12:27 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/arch/mips/table.c b/usr.bin/pcc/arch/mips/table.c
new file mode 100644
index 00000000000..e7d10ad1fe7
--- /dev/null
+++ b/usr.bin/pcc/arch/mips/table.c
@@ -0,0 +1,776 @@
+/* $Id: table.c,v 1.1 2007/09/15 18:12:28 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]);
diff --git a/usr.bin/pcc/arch/nova/README b/usr.bin/pcc/arch/nova/README
new file mode 100644
index 00000000000..939f8061c2a
--- /dev/null
+++ b/usr.bin/pcc/arch/nova/README
@@ -0,0 +1,120 @@
+Calling conventions, stack frame and zero page:
+
+The variables that normally are placed on the stack or in registers in C
+are instead allocated in the zero page and saved on a (fictive) stack
+when calling functions. Some locations have predefined functions though.
+Arrays allocated as automatics are stored on the stack with a pointer
+in zero page to its destination.
+
+0-7 Unused
+10 Stack pointer
+11 Frame pointer
+12-14 Unused
+15 Used by prolog
+16 Prolog address, written in crt0
+17 Epilog address, written in crt0
+20-27 Auto-increment, scratch
+30-37 Auto-decrement, scratch
+40-47 Unused
+50-57 Scratch/Arguments
+60-77 Permanent, save before use.
+100-377 Addresses for subroutines, written by the assembler
+
+The normal registers (AC0-AC3) are all considered scratch registers.
+
+Register classes are assigned as:
+ AC0-AC3: AREGs.
+ AC2-AC3: BREGs.
+ 50-77: CREGs.
+ ...and eventually register pairs as DREGs.
+
+In byte code the low half of a word is the first byte (little-endian).
+This is bit 8-15 in Nova syntax.
+
+The stack is growing towards lower adresses (as opposed to the Eclipse stack).
+Stack layout:
+
+ ! arg1 !
+ ! arg0 !
+ fp -> ! old pc!
+ ! old fp!
+ pc -> ! saved !
+
+A reference to a struct member in assembler, a = b->c; b is in ZP 50
++ is zeropage-addressing
+* is fp-adressing
+
+# offset 0
++ lda 0,@50 # load value from indirect ZP 50 into ac0
+* lda 2,,3 # load value from (ac3) into ac2
+* lda 0,,2 # load value from (ac2) into ac0
+
+# offset 12
++ lda 2,50 # load value from ZP 50 into ac2
++ lda 0,12,2 # load value from (ac2+12) into ac0
+* lda 2,,3 # load value from (ac3) into ac2
+* lda 0,12,2 # load value from 12(ac2) into ac0
+
+# offset 517
++ lda 2,50 # load value from ZP 50 into ac2
++ lda 0,.L42-.,1 # load offset from .L42 PC-indexed
++ addz 0,2,skp # add offset to ac2 and skip
++.L42: .word 517 # offset value
++ lda 0,,2 # load value from (ac2) into ac0
+
+The prolog/epilog implementation; it is implemented as subroutines.
+
+.L42: .word 13 # number of words to save
+func:
+ sta 3,@40 # save return address on stack
+ lda 2,.L42-.,1 # get save word count
+ jsr @45 # go to prolog
+ ...
+ lda 2,.L42-.,1 # get restore word count
+ jmp @46 # jump to epilog
+
+# words to save in 2, return address in 3
+prolog:
+ sta 2,45 # save # of words to move at scratch
+ lda 0,41 # get old fp
+ lda 1,40 # get sp
+ sta 1,41 # save new fp
+ dsz 40 # decrement stack, will never be 0
+ sta 0,@40 # save old fp
+ dsz 40
+
+ lda 0,off57 # fetch address of regs to save - 1
+ sta 0,20 # store address at autoincr
+1: lda 0,@20 # get word to copy
+ sta 0,@40 # push on stack
+ dsz 40 # manually decrement sp
+ dsz 45 # copied all words?
+ jmp 1b,1 # no, continue
+ jmp 0,3 # return
+
+epilog:
+ sta 2,45 # save # of words to move at scratch
+
+ lda 3,off57 # fetch address of regs to save
+ sta 3,20 # store at autoincr
+ lda 3,41 # fetch fp
+ sta 3,30 # store at autodecr
+ lda 3,@30 # get old fp
+
+1: lda 2,@30 # fetch word from stack
+ sta 2,@20 # store at orig place
+ dsz 45 # enough?
+ jmp 1b,1 # no, continue
+
+ lda 2,41 # get new fp
+ sta 2,40 # restore stack
+ sta 3,41 # restore old fp
+ jmp @40 # Return
+
+Assembler syntax and functions.
+
+The assembler syntax mimics the DG assembler.
+Load and store to addresses is written "lda 0,foo" to load from address foo.
+If foo is not in zero page then the assembler will put the lda in the
+text area close to the instruction and do an indirect pc-relative load.
+
diff --git a/usr.bin/pcc/arch/nova/code.c b/usr.bin/pcc/arch/nova/code.c
new file mode 100644
index 00000000000..78bcdd4d4be
--- /dev/null
+++ b/usr.bin/pcc/arch/nova/code.c
@@ -0,0 +1,212 @@
+/* $Id: code.c,v 1.1 2007/09/15 18:12:28 otto Exp $ */
+/*
+ * Copyright (c) 2006 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.
+ */
+
+
+# include "pass1.h"
+
+/*
+ * cause the alignment to become a multiple of n
+ * never called for text segment.
+ */
+void
+defalign(int n)
+{
+ /* alignment are always correct */
+}
+
+/*
+ * 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;
+cerror("efcode");
+ /* address of return struct is in eax */
+ /* create a call to memcpy() */
+ /* will get the result in eax */
+ p = block(REG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+// p->n_rval = EAX;
+ q = block(OREG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+// q->n_rval = EBP;
+ q->n_lval = 8; /* return buffer offset */
+ p = block(CM, q, p, INT, 0, MKSUE(INT));
+ sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR;
+ p = block(CM, p, bcon(sz), INT, 0, MKSUE(INT));
+ p->n_right->n_name = "";
+ p = block(CALL, bcon(0), p, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+ p->n_left->n_name = "memcpy";
+ p = clocal(p);
+ send_passt(IP_NODE, p);
+}
+
+/*
+ * 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;
+
+ if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+ return;
+cerror("bfcode");
+ /* Function returns struct, adjust arg offset */
+ for (i = 0; i < n; i++)
+ a[i]->soffset += SZPOINT(INT);
+}
+
+
+/*
+ * 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(int num, struct swents **p, int n)
+{
+ NODE *r;
+ int i;
+
+ /* simple switch code */
+ for (i = 1; i <= n; ++i) {
+ /* already in 1 */
+ r = tempnode(num, INT, 0, MKSUE(INT));
+ r = buildtree(NE, r, bcon(p[i]->sval));
+ cbranch(buildtree(NOT, r, NIL), bcon(p[i]->slab));
+ }
+ if (p[0]->slab > 0)
+ branch(p[0]->slab);
+}
diff --git a/usr.bin/pcc/arch/nova/local.c b/usr.bin/pcc/arch/nova/local.c
new file mode 100644
index 00000000000..61ccb9429e9
--- /dev/null
+++ b/usr.bin/pcc/arch/nova/local.c
@@ -0,0 +1,618 @@
+/* $Id: local.c,v 1.1 2007/09/15 18:12:28 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.
+ */
+
+
+# include "pass1.h"
+
+/* this file contains code which is dependent on the target machine */
+
+NODE *
+clocal(NODE *p)
+{
+ struct symtab *q;
+ NODE *r, *l;
+ int o;
+
+ switch( o = p->n_op ){
+ case NAME:
+ /* handle variables */
+ if ((q = p->n_sp) == NULL)
+ return p; /* Nothing to care about */
+ switch (q->sclass) {
+ 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;
+ default:
+ break;
+ }
+ 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 PCONV:
+ l = p->n_left;
+ /* if conversion to another pointer type, just remove */
+ if (p->n_type > BTMASK && l->n_type > BTMASK)
+ goto delp;
+ break;
+
+ delp: 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;
+ }
+
+#if 0
+ register struct symtab *q;
+ register NODE *r, *l;
+ register int o;
+ register int m;
+ 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 STCALL:
+ case CALL:
+ /* Fix function call arguments. On x86, just add funarg */
+ for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+ if (r->n_right->n_op != STARG &&
+ r->n_right->n_op != FUNARG)
+ r->n_right = block(FUNARG, r->n_right, NIL,
+ r->n_right->n_type, r->n_right->n_df,
+ r->n_right->n_sue);
+ }
+ if (r->n_op != STARG && r->n_op != FUNARG) {
+ l = talloc();
+ *l = *r;
+ r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type;
+ }
+ 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;
+ }
+ }
+ break;
+
+ case PCONV:
+ /* Remove redundant PCONV's. Be careful */
+ l = p->n_left;
+ if (l->n_op == ICON) {
+ l->n_lval = (unsigned)l->n_lval;
+ goto delp;
+ }
+ if (l->n_type < INT || l->n_type == LONGLONG ||
+ l->n_type == ULONGLONG) {
+ /* float etc? */
+ p->n_left = block(SCONV, l, NIL,
+ UNSIGNED, 0, MKSUE(UNSIGNED));
+ break;
+ }
+ /* if left is SCONV, cannot remove */
+ if (l->n_op == SCONV)
+ break;
+ /* if conversion to another pointer type, just remove */
+ if (p->n_type > BTMASK && l->n_type > BTMASK)
+ goto delp;
+ break;
+
+ delp: 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_op == TEMP) {
+ l->n_type = p->n_type;
+ nfree(p);
+ return l;
+ }
+ }
+ }
+
+ if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+ coptype(l->n_op) == BITYPE) {
+ l->n_type = p->n_type;
+ nfree(p);
+ return l;
+ }
+
+ 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;
+ l->n_sue = MKSUE(m);
+ nfree(p);
+ return l;
+ }
+ if (DEUNSIGN(p->n_type) == SHORT &&
+ DEUNSIGN(l->n_type) == SHORT) {
+ nfree(p);
+ p = l;
+ }
+ if ((p->n_type == CHAR || p->n_type == UCHAR ||
+ p->n_type == SHORT || p->n_type == USHORT) &&
+ (l->n_type == FLOAT || l->n_type == DOUBLE ||
+ l->n_type == LDOUBLE)) {
+ p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
+ p->n_left->n_type = INT;
+ return p;
+ }
+ 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(p->n_type);
+ break;
+
+ case LS:
+ case RS:
+ /* shift count must be in a char
+ * unless longlong, where it must be int */
+ if (p->n_right->n_op == ICON)
+ break; /* do not do anything */
+ if (p->n_type == LONGLONG || p->n_type == ULONGLONG) {
+ if (p->n_right->n_type != INT)
+ p->n_right = block(SCONV, p->n_right, NIL,
+ INT, 0, MKSUE(INT));
+ break;
+ }
+ if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
+ break;
+ p->n_right = block(SCONV, p->n_right, NIL,
+ CHAR, 0, MKSUE(CHAR));
+ break;
+ }
+//printf("ut:\n");
+//fwalk(p, eprint, 0);
+
+#endif
+
+ 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;
+}
+
+/*
+ * Return 1 if a variable of type type is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+ return 1; /* try to put anything in a register */
+}
+
+/*
+ * 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 nova, return the type-specific index number which calculation
+ * is based on its size. For example, char 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 %ld type %x dim %p siz %d\n",
+ off, t, d, sue->suesize);
+
+ p = bcon(0);
+ p->n_lval = off/SZINT; /* Default */
+ if (ISPTR(DECREF(t)))
+ return p;
+ if (t == VOID || t == CHAR || t == UCHAR)
+ p->n_lval = off/SZCHAR; /* pointer to char */
+ 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;
+
+cerror("spalloc");
+ 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 */
+
+ if (p->n_op != ICON)
+ cerror("ninval: init node not constant");
+
+ switch (t) {
+ case LONG:
+ case ULONG:
+ inval(p->n_lval & 0xffff);
+ inval(p->n_lval >> 16);
+ break;
+ case INT:
+ case UNSIGNED:
+ printf("\t.word 0%o", (short)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 &= 0xffff;
+ printf(" .word 0%o\n", (int)word);
+}
+
+/* output code to initialize a floating point value */
+/* the proper alignment has been obtained */
+void
+finval(NODE *p)
+{
+ union { float f; double d; long double l; int i[3]; } u;
+
+cerror("finval");
+ switch (p->n_type) {
+ case LDOUBLE:
+ u.i[2] = 0;
+ u.l = (long double)p->n_dcon;
+ printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+ break;
+ case DOUBLE:
+ u.d = (double)p->n_dcon;
+ printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+ break;
+ case FLOAT:
+ u.f = (float)p->n_dcon;
+ printf("\t.long\t0x%x\n", u.i[0]);
+ 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 LONGLONG:
+ MODTYPE(type,LONG);
+ break;
+
+ case ULONGLONG:
+ MODTYPE(type,ULONG);
+ break;
+ case SHORT:
+ MODTYPE(type,INT);
+ break;
+ case USHORT:
+ MODTYPE(type,UNSIGNED);
+ break;
+ }
+ 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/arch/nova/local2.c b/usr.bin/pcc/arch/nova/local2.c
new file mode 100644
index 00000000000..93c2f843781
--- /dev/null
+++ b/usr.bin/pcc/arch/nova/local2.c
@@ -0,0 +1,563 @@
+/* $Id: local2.c,v 1.1 2007/09/15 18:12:28 otto Exp $ */
+/*
+ * Copyright (c) 2006 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.
+ */
+
+
+# include "pass2.h"
+# include <ctype.h>
+# include <string.h>
+
+void acon(NODE *p);
+int argsize(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 prolnum;
+static struct ldq {
+ struct ldq *next;
+ int val;
+ int lab;
+ char *name;
+} *ldq;
+
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+ int i, j;
+
+ for (i = ipp->ipp_regs, j = 0; i; i >>= 1)
+ if (i&1)
+ j++;
+ printf(".LP%d: .word 0%o\n", prolnum, j);
+ if (ipp->ipp_vis)
+ printf(" .globl %s\n", ipp->ipp_name);
+ printf("%s:\n", ipp->ipp_name);
+ printf(" sta 3,@40\n"); /* save ret pc on stack */
+ printf(" lda 2,.LP%d-.,1\n", prolnum);
+ printf(" jsr @45\n");
+ prolnum++;
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+ int i, j;
+
+ 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)
+ if (i & 1)
+ j++;
+ printf(" lda 2,.LP%d-.,1\n", prolnum);
+ printf(" jmp @46\n");
+ printf(".LP%d: .word 0%o\n", prolnum, j);
+ prolnum++;
+ while (ldq) {
+ printf(".LP%d: .word 0%o", ldq->lab, ldq->val);
+ if (ldq->name && *ldq->name)
+ printf("+%s", ldq->name);
+ printf("\n");
+ ldq = ldq->next;
+ }
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+ char *str = 0;
+
+ switch (o) {
+ case PLUS:
+ str = "add";
+ break;
+ case MINUS:
+ str = "sub";
+ break;
+ case AND:
+ str = "and";
+ break;
+ case OR:
+ cerror("hopcode OR");
+ break;
+ case ER:
+ cerror("hopcode xor");
+ str = "xor";
+ break;
+ default:
+ comperr("hopcode2: %d", o);
+ str = 0; /* XXX gcc */
+ }
+ printf("%s%c", str, f);
+}
+
+#if 0
+/*
+ * Return type size in bytes. Used by R2REGS, arg 2 to offset().
+ */
+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;
+ }
+}
+#endif
+
+#if 0
+/*
+ * Assign to a bitfield.
+ * Clumsy at least, but what to do?
+ */
+static void
+bfasg(NODE *p)
+{
+ NODE *fn = p->n_left;
+ int shift = UPKFOFF(fn->n_rval);
+ int fsz = UPKFSZ(fn->n_rval);
+ int andval, tch = 0;
+
+ /* get instruction size */
+ switch (p->n_type) {
+ case CHAR: case UCHAR: tch = 'b'; break;
+ case SHORT: case USHORT: tch = 'w'; break;
+ case INT: case UNSIGNED: tch = 'l'; break;
+ default: comperr("bfasg");
+ }
+
+ /* put src into a temporary reg */
+ fprintf(stdout, " mov%c ", tch);
+ adrput(stdout, getlr(p, 'R'));
+ fprintf(stdout, ",");
+ adrput(stdout, getlr(p, '1'));
+ fprintf(stdout, "\n");
+
+ /* AND away the bits from dest */
+ andval = ~(((1 << fsz) - 1) << shift);
+ fprintf(stdout, " and%c $%d,", tch, andval);
+ adrput(stdout, fn->n_left);
+ fprintf(stdout, "\n");
+
+ /* AND away unwanted bits from src */
+ andval = ((1 << fsz) - 1);
+ fprintf(stdout, " and%c $%d,", tch, andval);
+ adrput(stdout, getlr(p, '1'));
+ fprintf(stdout, "\n");
+
+ /* SHIFT left src number of bits */
+ if (shift) {
+ fprintf(stdout, " sal%c $%d,", tch, shift);
+ adrput(stdout, getlr(p, '1'));
+ fprintf(stdout, "\n");
+ }
+
+ /* OR in src to dest */
+ fprintf(stdout, " or%c ", tch);
+ adrput(stdout, getlr(p, '1'));
+ fprintf(stdout, ",");
+ adrput(stdout, fn->n_left);
+ fprintf(stdout, "\n");
+}
+#endif
+
+#if 0
+/*
+ * Push a structure on stack as argument.
+ * the scratch registers are already free here
+ */
+static void
+starg(NODE *p)
+{
+ FILE *fp = stdout;
+
+ fprintf(fp, " subl $%d,%%esp\n", p->n_stsize);
+ fprintf(fp, " pushl $%d\n", p->n_stsize);
+ expand(p, 0, " pushl AL\n");
+ expand(p, 0, " leal 8(%esp),A1\n");
+ expand(p, 0, " pushl A1\n");
+ fprintf(fp, " call memcpy\n");
+ fprintf(fp, " addl $12,%%esp\n");
+}
+#endif
+
+void
+zzzcode(NODE *p, int c)
+{
+ struct ldq *ld;
+
+ switch (c) {
+ case 'A': /* print out a skip ending if any numbers in queue */
+ if (ldq == NULL)
+ return;
+ printf(",skp\n.LP%d: .word 0%o", ldq->lab, ldq->val);
+ if (ldq->name && *ldq->name)
+ printf("+%s", ldq->name);
+ printf("\n");
+ ldq = ldq->next;
+ break;
+
+ case 'B': /* print a label for later load */
+ ld = tmpalloc(sizeof(struct ldq));
+ ld->val = p->n_lval;
+ ld->name = p->n_name;
+ ld->lab = prolnum++;
+ ld->next = ldq;
+ ldq = ld;
+ printf(".LP%d-.", ld->lab);
+ break;
+
+ case 'C': /* fix reference to external variable via indirection */
+ zzzcode(p->n_left, 'B');
+ break;
+
+ case 'D': /* fix reference to external variable via indirection */
+ zzzcode(p, 'B');
+ break;
+
+ default:
+ comperr("zzzcode %c", c);
+ }
+}
+
+/*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;
+
+cerror("flshape");
+ 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);
+}
+
+/*
+ * Conput should only be used by e2print on Nova.
+ */
+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, p %p", p);
+ }
+}
+
+/*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)
+{
+comperr("upput");
+#if 0
+ size /= SZCHAR;
+ switch (p->n_op) {
+ case REG:
+ fprintf(stdout, "%%%s", &rnames[p->n_rval][3]);
+ 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);
+ }
+#endif
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+ /* 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:
+ printf("%d,%s", (int)p->n_lval, rnames[p->n_rval]);
+ return;
+
+ case ICON:
+ /* addressable value of the constant */
+ fputc('$', io);
+ conput(io, p);
+ return;
+
+ case MOVE:
+ case REG:
+ switch (p->n_type) {
+ case LONGLONG:
+ case ULONGLONG:
+ fprintf(io, "%%%c%c%c", rnames[p->n_rval][0],
+ rnames[p->n_rval][1], rnames[p->n_rval][2]);
+ break;
+ case SHORT:
+ case USHORT:
+ fprintf(io, "%%%s", &rnames[p->n_rval][2]);
+ break;
+ default:
+ fprintf(io, "%s", rnames[p->n_rval]);
+ }
+ return;
+
+ default:
+ comperr("illegal address, op %d, node %p", p->n_op, p);
+ return;
+
+ }
+}
+
+/* printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+ comperr("cbgen");
+}
+
+void
+myreader(struct interpass *ipole)
+{
+ if (x2debug)
+ printip(ipole);
+}
+
+void
+mycanon(NODE *p)
+{
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+ comperr("rmove");
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ * Return true if we always can find a color.
+ */
+int
+COLORMAP(int c, int *r)
+{
+ int num;
+
+ switch (c) {
+ case CLASSA:
+ num = r[CLASSB] + r[CLASSA];
+ return num < 4;
+ case CLASSB:
+ num = r[CLASSB] + r[CLASSA];
+ return num < 2;
+ case CLASSC:
+ return r[CLASSC] < CREGCNT;
+ case CLASSD:
+ return r[CLASSD] < DREGCNT;
+ }
+ return 0; /* XXX gcc */
+}
+
+char *rnames[] = {
+ "0", "1", "2", "3",
+ "050", "051", "052", "053", "054", "055", "056", "057",
+ "060", "061", "062", "063", "064", "065", "066", "067",
+ "070", "071", "072", "073", "074", "075", "076", "077",
+ "041", "040"
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+ return CLASSA;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+ return SRNOPE;
+}
diff --git a/usr.bin/pcc/arch/nova/macdefs.h b/usr.bin/pcc/arch/nova/macdefs.h
new file mode 100644
index 00000000000..3104c900ef4
--- /dev/null
+++ b/usr.bin/pcc/arch/nova/macdefs.h
@@ -0,0 +1,195 @@
+/* $Id: macdefs.h,v 1.1 2007/09/15 18:12:28 otto Exp $ */
+/*
+ * Copyright (c) 2006 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.
+ */
+
+/*
+ * Machine-dependent defines for Data General Nova.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ */
+#define makecc(val,i) lastcon = (lastcon<<8)|(val);
+
+#define ARGINIT 16 /* adjusted in MD code */
+#define AUTOINIT 16 /* adjusted in MD code */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR 8
+#define SZINT 16
+#define SZFLOAT 32
+#define SZDOUBLE 64
+#define SZLDOUBLE 64
+#define SZLONG 32
+#define SZSHORT 16
+#define SZLONGLONG 32
+#define SZPOINT(t) 16 /* Actually 15 */
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR 8
+#define ALINT 16
+#define ALFLOAT 16
+#define ALDOUBLE 16
+#define ALLDOUBLE 16
+#define ALLONG 16
+#define ALLONGLONG 16
+#define ALSHORT 16
+#define ALPOINT 16
+#define ALSTRUCT 16
+#define ALSTACK 16
+
+/*
+ * 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 MIN_SHORT
+#define MAX_INT MAX_SHORT
+#define MAX_UNSIGNED MAX_USHORT
+#define MIN_LONG 0x80000000L
+#define MAX_LONG 0x7fffffffL
+#define MAX_ULONG 0xffffffffUL
+#define MIN_LONGLONG MIN_LONG
+#define MAX_LONGLONG MAX_LONG
+#define MAX_ULONGLONG MAX_ULONG
+
+/* Default char is unsigned */
+#define CHAR_UNSIGNED
+
+/*
+ * Use large-enough types.
+ */
+typedef long CONSZ;
+typedef unsigned long U_CONSZ;
+typedef long OFFSZ;
+
+#define CONFMT "%ld" /* 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)&01)
+#define wdal(k) (BYTEOFF(k)==0)
+#define BITOOR(x) (x) /* bit offset to oreg offset XXX die! */
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+#define genfcall(a,b) gencall(a,b)
+
+#define szty(t) (((t) == DOUBLE || (t) == LDOUBLE) ? 4 : \
+ ((t) == LONGLONG || (t) == ULONGLONG || \
+ (t) == LONG || (t) == ULONG) ? 2 : 1)
+
+/*
+ * The Nova has three register classes. Note that the space used in
+ * zero page is considered registers.
+ * Register 28 and 29 are FP and SP.
+ *
+ * The classes used on Nova are:
+ * A - AC0-AC3 (as non-index registers) : reg 0-3
+ * B - AC2-AC3 (as index registers) : reg 2-3
+ * C - address 50-77 in memory : reg 4-27
+ */
+#define MAXREGS 30 /* 0-29 */
+
+#define RSTATUS \
+ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|SBREG|TEMPREG, SAREG|SBREG|TEMPREG,\
+ SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG, \
+ SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG, \
+ SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, \
+ SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, \
+ SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, \
+ SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, \
+ 0, 0
+
+#define ROVERLAP \
+ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 },
+
+
+/* Return a register class based on the type of the node */
+/* all types in all classes */
+#define PCLASS(p) (SAREG|SBREG|SCREG)
+
+#define NUMCLASS 4 /* highest number of reg classes used */
+ /* XXX - must be 4 */
+
+int COLORMAP(int c, int *r);
+#define GCLASS(x) (x < 4 ? CLASSA : CLASSC)
+#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */
+#define ENCRD(x) (x) /* Encode dest reg in n_reg */
+#define ENCRA1(x) ((x) << 6) /* A1 */
+#define ENCRA2(x) ((x) << 12) /* A2 */
+#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */
+#define RETREG(x) (0) /* ? Sanity */
+
+/* XXX - to die */
+#define FPREG 28 /* frame pointer */
+#define STKREG 29 /* stack pointer */
+
+#define MYREADER(p) myreader(p)
+#define MYCANON(p) mycanon(p)
+#define MYOPTIM
diff --git a/usr.bin/pcc/arch/nova/order.c b/usr.bin/pcc/arch/nova/order.c
new file mode 100644
index 00000000000..fc6b2191d2c
--- /dev/null
+++ b/usr.bin/pcc/arch/nova/order.c
@@ -0,0 +1,164 @@
+/* $Id: order.c,v 1.1 2007/09/15 18:12:28 otto Exp $ */
+/*
+ * Copyright (c) 2006 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.
+ */
+
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/* 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)
+{
+ if (r != 2 && r != 3)
+ return 1; /* can only index ac2 and ac3 */
+ if (t == CHAR || t == UCHAR) {
+ if (off < -256 || off > 254)
+ return 1;
+ } else if (off < -128 || off > 127)
+ return 1;
+ return(0); /* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ * Be careful about register classes, this is a place where classes change.
+ */
+void
+offstar(NODE *p, int shape)
+{
+ NODE *r;
+
+ if (x2debug)
+ printf("offstar(%p)\n", p);
+
+ if (isreg(p))
+ return; /* Is already OREG */
+
+ r = p->n_right;
+ if( p->n_op == PLUS || p->n_op == MINUS ){
+ if( r->n_op == ICON ){
+ if (isreg(p->n_left) == 0 ||
+ (p->n_left->n_op == REG &&
+ p->n_left->n_rval != 2 && p->n_left->n_rval != 3))
+ (void)geninsn(p->n_left, INBREG);
+ /* Converted in ormake() */
+ return;
+ }
+ }
+ (void)geninsn(p, INBREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *q)
+{
+ if (x2debug)
+ printf("myormake(%p)\n", q);
+}
+
+/*
+ * Shape matches for UMUL. Cooperates with offstar().
+ */
+int
+shumul(NODE *p)
+{
+
+ if (x2debug)
+ printf("shumul(%p)\n", p);
+
+ /* Turns currently anything 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.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+ comperr("nspecial entry %d", q - table);
+ return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+ return 0;
+}
diff --git a/usr.bin/pcc/arch/nova/table.c b/usr.bin/pcc/arch/nova/table.c
new file mode 100644
index 00000000000..d2d7bdd6513
--- /dev/null
+++ b/usr.bin/pcc/arch/nova/table.c
@@ -0,0 +1,1514 @@
+/* $Id: table.c,v 1.1 2007/09/15 18:12:28 otto Exp $ */
+/*
+ * Copyright (c) 2006 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.
+ */
+
+
+# include "pass2.h"
+
+# 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, "", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RDEST,
+ " mov AR,ALZA\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SNAME, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RDEST,
+ " sta AR,ZC,1\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SOREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RDEST,
+ " sta AR,AL\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SONE, TWORD,
+ NAREG, RESC1,
+ " subzl A1,A1ZA\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SCON, TWORD,
+ NAREG, RESC1,
+ " lda A1,ZB,1\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SZERO, TWORD,
+ NAREG, RESC1,
+ " sub A1,A1ZA\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SNAME, TWORD|TPOINT,
+ NAREG, RESC1,
+ " lda A1,ZD,1\n", },
+
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SNAME, TWORD|TPOINT,
+ NBREG, RESC1,
+ " lda A1,ZD,1\n", },
+
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SCREG, TWORD|TPOINT,
+ NBREG, RESC1,
+ " lda A1,AR\n", },
+
+{ PLUS, INBREG|INAREG,
+ SAREG|SBREG, TWORD|TPOINT,
+ SONE, TANY,
+ 0, RLEFT,
+ " inc AL,AL\n", },
+
+{ OPSIMP, INBREG|INAREG|FOREFF,
+ SAREG|SBREG, TWORD|TPOINT,
+ SAREG|SBREG, TWORD|TPOINT,
+ 0, RLEFT,
+ " O AR,AL\n", },
+
+{ UMUL, INAREG,
+ SANY, TPOINT|TWORD,
+ SOREG, TPOINT|TWORD,
+ NAREG|NASL, RESC1,
+ " lda A1,AL\n", },
+
+#if 0
+
+/* PCONVs are usually not necessary */
+{ PCONV, INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RLEFT,
+ "", },
+
+/*
+ * A bunch conversions of integral<->integral types
+ * There are lots of them, first in table conversions to itself
+ * and then conversions from each type to the others.
+ */
+
+/* itself to itself, including pointers */
+
+/* convert (u)char to (u)char. */
+{ SCONV, INCH,
+ SHCH, TCHAR|TUCHAR,
+ SHCH, TCHAR|TUCHAR,
+ 0, RLEFT,
+ "", },
+
+/* convert pointers to int. */
+{ SCONV, ININT,
+ SHINT, TPOINT|TWORD,
+ SANY, TWORD,
+ 0, RLEFT,
+ "", },
+
+/* convert (u)longlong to (u)longlong. */
+{ SCONV, INLL,
+ SHLL, TLL,
+ SHLL, TLL,
+ 0, RLEFT,
+ "", },
+
+/* convert double <-> float. nothing to do here */
+{ SCONV, INFL,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RLEFT,
+ "", },
+
+/* convert pointers to pointers. */
+{ SCONV, ININT,
+ SHINT, TPOINT,
+ SANY, TPOINT,
+ 0, RLEFT,
+ "", },
+
+/* char to something */
+
+/* convert char to (unsigned) short. */
+{ SCONV, ININT,
+ SBREG|SOREG|SNAME, TCHAR,
+ SAREG, TSHORT|TUSHORT,
+ NASL|NAREG, RESC1,
+ " movsbw AL,A1\n", },
+
+/* convert unsigned char to (u)short. */
+{ SCONV, ININT,
+ SHCH|SOREG|SNAME, TUCHAR,
+ SAREG, TSHORT|TUSHORT,
+ NASL|NAREG, RESC1,
+ " movzbw AL,A1\n", },
+
+/* convert signed char to int (or pointer). */
+{ SCONV, ININT,
+ SHCH|SOREG|SNAME, TCHAR,
+ SAREG, TWORD|TPOINT,
+ NASL|NAREG, RESC1,
+ " movsbl AL,A1\n", },
+
+/* convert unsigned char to (u)int. */
+{ SCONV, ININT,
+ SHCH|SOREG|SNAME, TUCHAR,
+ SAREG, TWORD,
+ NASL|NAREG, RESC1,
+ " movzbl AL,A1\n", },
+
+/* convert char to (u)long long */
+{ SCONV, INLL,
+ SHCH|SOREG|SNAME, TCHAR,
+ SANY, TLL,
+ NSPECIAL|NAREG|NASL, RESC1,
+ " movsbl AL,%eax\n cltd\n", },
+
+/* convert unsigned char to (u)long long */
+{ SCONV, INLL,
+ SHCH|SOREG|SNAME, TUCHAR,
+ SANY, TLL,
+ NCREG|NCSL, RESC1,
+ " movzbl AL,A1\n xorl U1,U1\n", },
+
+/* convert char (in register) to double XXX - use NTEMP */
+{ SCONV, INFL,
+ SHCH|SOREG|SNAME, TCHAR,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NAREG|NASL|NDREG, RESC2,
+ " movsbl AL,A1\n pushl A1\n"
+ " fildl (%esp)\n addl $4,%esp\n", },
+
+/* convert (u)char (in register) to double XXX - use NTEMP */
+{ SCONV, INFL,
+ SHCH|SOREG|SNAME, TUCHAR,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NAREG|NASL|NDREG, RESC2,
+ " movzbl AL,A1\n pushl A1\n"
+ " fildl (%esp)\n addl $4,%esp\n", },
+
+/* short to something */
+
+/* convert short (in memory) to char */
+{ SCONV, INCH,
+ SNAME|SOREG, TSHORT|TUSHORT,
+ SHCH, TCHAR|TUCHAR,
+ NBREG|NBSL, RESC1,
+ " movb AL,A1\n", },
+
+/* convert short (in reg) to char. */
+{ SCONV, INCH,
+ SAREG|SNAME|SOREG, TSHORT|TUSHORT,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL|NBREG|NBSL, RESC1,
+ "ZM", },
+
+/* convert short to (u)int. */
+{ SCONV, ININT,
+ SAREG|SOREG|SNAME, TSHORT,
+ SAREG, TWORD,
+ NASL|NAREG, RESC1,
+ " movswl AL,A1\n", },
+
+/* convert unsigned short to (u)int. */
+{ SCONV, ININT,
+ SAREG|SOREG|SNAME, TUSHORT,
+ SAREG, TWORD,
+ NASL|NAREG, RESC1,
+ " movzwl AL,A1\n", },
+
+/* convert short to (u)long long */
+{ SCONV, INLL,
+ SAREG|SOREG|SNAME, TSHORT,
+ SHLL, TLL,
+ NSPECIAL|NCREG|NCSL, RESC1,
+ " movswl AL,%eax\n cltd\n", },
+
+/* convert unsigned short to (u)long long */
+{ SCONV, INLL,
+ SAREG|SOREG|SNAME, TUSHORT,
+ SHLL, TLL,
+ NCREG|NCSL, RESC1,
+ " movzwl AL,A1\n xorl U1,U1\n", },
+
+/* convert short (in memory) to float/double */
+{ SCONV, INFL,
+ SOREG|SNAME, TSHORT,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ NDREG, RESC1,
+ " fild AL\n", },
+
+/* convert short (in register) to float/double */
+{ SCONV, INFL,
+ SAREG, TSHORT,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ NTEMP|NDREG, RESC1,
+ " pushw AL\n fild (%esp)\n addl $2,%esp\n", },
+
+/* convert unsigned short to double XXX - use NTEMP */
+{ SCONV, INFL,
+ SAREG|SOREG|SNAME, TUSHORT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NAREG|NASL|NDREG|NTEMP, RESC2,
+ " movzwl AL,A1\n pushl A1\n"
+ " fildl (%esp)\n addl $4,%esp\n", },
+
+/* int to something */
+
+/* convert int to char. This is done when register is loaded */
+{ SCONV, INCH,
+ SAREG, TWORD,
+ SANY, TCHAR|TUCHAR,
+ NSPECIAL|NBREG|NBSL, RESC1,
+ "ZM", },
+
+/* convert int to short. Nothing to do */
+{ SCONV, INAREG,
+ SAREG, TWORD,
+ SANY, TSHORT|TUSHORT,
+ 0, RLEFT,
+ "", },
+
+/* convert int to long long */
+{ SCONV, INLL,
+ SAREG, TWORD|TPOINT,
+ SCREG, TLONGLONG,
+ NSPECIAL|NCREG|NCSL, RESC1,
+ " cltd\n", },
+
+/* convert int to unsigned long long */
+{ SCONV, INLL,
+ SAREG|SOREG|SNAME, TWORD|TPOINT,
+ SHLL, TULONGLONG,
+ NCSL|NCREG, RESC1,
+ " movl AL,A1\n xorl U1,U1\n", },
+
+/* convert int (in memory) to double */
+{ SCONV, INFL,
+ SOREG|SNAME, TWORD,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NDREG, RESC1,
+ " fildl AL\n", },
+
+/* convert int (in register) to double */
+{ SCONV, INFL,
+ SAREG, TWORD,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NTEMP|NDREG, RESC1,
+ " pushl AL\n fildl (%esp)\n addl $4,%esp\n", },
+
+/* long long to something */
+
+/* convert (u)long long to (u)char (mem->reg) */
+{ SCONV, INCH,
+ SOREG|SNAME, TLL,
+ SANY, TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " movb AL,A1\n", },
+
+/* convert (u)long long to (u)char (reg->reg, hopefully nothing) */
+{ SCONV, INCH,
+ SHLL, TLL,
+ SANY, TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ "ZS", },
+
+/* convert (u)long long to (u)short (mem->reg) */
+{ SCONV, INAREG,
+ SOREG|SNAME, TLL,
+ SAREG, TSHORT|TUSHORT,
+ NAREG|NASL, RESC1,
+ " movw AL,A1\n", },
+
+/* convert (u)long long to (u)short (reg->reg, hopefully nothing) */
+{ SCONV, INAREG,
+ SHLL|SOREG|SNAME, TLL,
+ SAREG, TSHORT|TUSHORT,
+ NAREG|NASL, RESC1,
+ "ZS", },
+
+/* convert long long to int (mem->reg) */
+{ SCONV, INAREG,
+ SOREG|SNAME, TLL,
+ SAREG, TWORD|TPOINT,
+ NAREG|NASL, RESC1,
+ " movl AL,A1\n", },
+
+/* convert long long to int (reg->reg, hopefully nothing) */
+{ SCONV, INAREG,
+ SHLL|SOREG|SNAME, TLL,
+ SAREG, TWORD|TPOINT,
+ NAREG|NASL, RESC1,
+ "ZS", },
+
+/* convert long long (in memory) to floating */
+{ SCONV, INFL,
+ SOREG|SNAME, TLONGLONG,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NDREG, RESC1,
+ " fildq AL\n", },
+
+/* convert long long (in register) to floating */
+{ SCONV, INFL,
+ SHLL, TLONGLONG,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NTEMP|NDREG, RESC1,
+ " pushl UL\n pushl AL\n"
+ " fildq (%esp)\n addl $8,%esp\n", },
+
+/* convert unsigned long long to floating */
+{ SCONV, INFL,
+ SCREG, TULONGLONG,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ NDREG, RESC1,
+ "ZJ", },
+
+/* float to something */
+
+#if 0 /* go via int by adding an extra sconv in clocal() */
+/* convert float/double to (u) char. XXX should use NTEMP here */
+{ SCONV, INCH,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NBREG, RESC1,
+ " subl $4,%esp\n fistpl (%esp)\n popl A1\n", },
+
+/* convert float/double to (u) int/short/char. XXX should use NTEMP here */
+{ SCONV, INCH,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NCREG, RESC1,
+ " subl $4,%esp\n fistpl (%esp)\n popl A1\n", },
+#endif
+
+/* convert float/double to (u)int. XXX should use NTEMP here */
+{ SCONV, INAREG,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SAREG, TWORD,
+ NAREG, RESC1,
+ " subl $4,%esp\n fistpl (%esp)\n popl A1\n", },
+
+/* convert float/double (in register) to (unsigned) long long */
+/* XXX - unsigned is not handled correct */
+{ SCONV, INLL,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHLL, TLONGLONG|TULONGLONG,
+ NCREG, RESC1,
+ " subl $8,%esp\n fistpq (%esp)\n"
+ " popl A1\n popl U1\n", },
+
+/* slut sconv */
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ 0, 0,
+ " call CL\nZC", },
+
+{ UCALL, FOREFF,
+ SCON, TANY,
+ SAREG, TWORD|TPOINT,
+ 0, 0,
+ " call CL\n", },
+
+{ CALL, INAREG,
+ SCON, TANY,
+ SAREG, TWORD|TPOINT,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " call CL\nZC", },
+
+{ UCALL, INAREG,
+ SCON, TANY,
+ SAREG, TWORD|TPOINT,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " call CL\n", },
+
+{ CALL, INBREG,
+ SCON, TANY,
+ SBREG, TCHAR|TUCHAR,
+ NBREG, RESC1, /* should be 0 */
+ " call CL\nZC", },
+
+{ UCALL, INBREG,
+ SCON, TANY,
+ SBREG, TCHAR|TUCHAR,
+ NBREG, RESC1, /* should be 0 */
+ " call CL\n", },
+
+{ CALL, INCREG,
+ SCON, TANY,
+ SCREG, TANY,
+ NCREG|NCSL, RESC1, /* should be 0 */
+ " call CL\nZC", },
+
+{ UCALL, INCREG,
+ SCON, TANY,
+ SCREG, TANY,
+ NCREG|NCSL, RESC1, /* should be 0 */
+ " call CL\n", },
+
+{ CALL, INDREG,
+ SCON, TANY,
+ SDREG, TANY,
+ NDREG|NDSL, RESC1, /* should be 0 */
+ " call CL\nZC", },
+
+{ UCALL, INDREG,
+ SCON, TANY,
+ SDREG, TANY,
+ NDREG|NDSL, RESC1, /* should be 0 */
+ " call CL\nZC", },
+
+{ CALL, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, 0,
+ " call *AL\nZC", },
+
+{ UCALL, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, 0,
+ " call *AL\nZC", },
+
+{ CALL, INAREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ UCALL, INAREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ CALL, INBREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NBREG|NBSL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ UCALL, INBREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NBREG|NBSL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ CALL, INCREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NCREG|NCSL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ UCALL, INCREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NCREG|NCSL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ CALL, INDREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NDREG|NDSL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ UCALL, INDREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NDREG|NDSL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+/* struct return */
+{ USTCALL, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, 0,
+ "ZP call CL\nZC", },
+
+{ USTCALL, INAREG,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ "ZP call CL\nZC", },
+
+{ USTCALL, INAREG,
+ SNAME|SAREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ "ZP call *AL\nZC", },
+
+{ STCALL, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, 0,
+ "ZP call CL\nZC", },
+
+{ STCALL, INAREG,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ "ZP call CL\nZC", },
+
+{ STCALL, INAREG,
+ SNAME|SAREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ "ZP call *AL\nZC", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+/* Special treatment for long long */
+{ PLUS, INLL|FOREFF,
+ SHLL, TLL,
+ SHLL|SNAME|SOREG, TLL,
+ 0, RLEFT,
+ " addl AR,AL\n adcl UR,UL\n", },
+
+/* Special treatment for long long XXX - fix commutative check */
+{ PLUS, INLL|FOREFF,
+ SHLL|SNAME|SOREG, TLL,
+ SHLL, TLL,
+ 0, RRIGHT,
+ " addl AL,AR\n adcl UL,UR\n", },
+
+{ PLUS, INFL,
+ SHFL, TDOUBLE,
+ SNAME|SOREG, TDOUBLE,
+ 0, RLEFT,
+ " faddl AR\n", },
+
+{ PLUS, INFL|FOREFF,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RLEFT,
+ " faddp\n", },
+
+{ PLUS, INAREG,
+ SAREG|SNAME|SOREG, TWORD|TPOINT,
+ SONE, TANY,
+ 0, RLEFT,
+ " incl AL\n", },
+
+{ PLUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SCON, TANY,
+ NAREG|NASL, RESC1,
+ " leal CR(AL),A1\n", },
+
+{ PLUS, INCH,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ SONE, TANY,
+ 0, RLEFT,
+ " incb AL\n", },
+
+{ PLUS, INAREG,
+ SAREG, TWORD,
+ SAREG, TWORD,
+ NAREG|NASL|NASR, RESC1,
+ " leal (AL,AR),A1\n", },
+
+
+/* address as register offset, negative */
+{ MINUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SPCON, TANY,
+ NAREG|NASL, RESC1,
+ " leal -CR(AL),A1\n", },
+
+{ MINUS, INLL|FOREFF,
+ SHLL, TLL,
+ SHLL|SNAME|SOREG, TLL,
+ 0, RLEFT,
+ " subl AR,AL\n sbbl UR,UL\n", },
+
+{ MINUS, INFL,
+ SHFL, TDOUBLE,
+ SNAME|SOREG, TDOUBLE,
+ 0, RLEFT,
+ " fsubl AR\n", },
+
+{ MINUS, INFL|FOREFF,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RLEFT,
+ " fsubZAp\n", },
+
+/* Simple r/m->reg ops */
+{ OPSIMP, INAREG|FOREFF,
+ SAREG, TWORD|TPOINT,
+ SAREG|SNAME|SOREG, TWORD|TPOINT,
+ 0, RLEFT,
+ " Ol AR,AL\n", },
+
+{ OPSIMP, INAREG|FOREFF,
+ SHINT, TSHORT|TUSHORT,
+ SHINT|SNAME|SOREG, TSHORT|TUSHORT,
+ 0, RLEFT,
+ " Ow AR,AL\n", },
+
+{ OPSIMP, INCH|FOREFF,
+ SHCH, TCHAR|TUCHAR,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ 0, RLEFT,
+ " Ob AR,AL\n", },
+
+{ OPSIMP, INAREG|FOREFF,
+ SAREG, TWORD|TPOINT,
+ SCON, TWORD|TPOINT,
+ 0, RLEFT,
+ " Ol AR,AL\n", },
+
+{ OPSIMP, INAREG|FOREFF,
+ SHINT|SNAME|SOREG, TSHORT|TUSHORT,
+ SCON, TANY,
+ 0, RLEFT,
+ " Ow AR,AL\n", },
+
+{ OPSIMP, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ SCON, TANY,
+ 0, RLEFT,
+ " Ob AR,AL\n", },
+
+{ OPSIMP, INLL|FOREFF,
+ SHLL, TLL,
+ SHLL|SNAME|SOREG, TLL,
+ 0, RLEFT,
+ " Ol AR,AL\n Ol UR,UL\n", },
+
+
+/*
+ * The next rules handle all shift operators.
+ */
+/* (u)longlong left shift is emulated */
+{ LS, INCREG,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ SAREG|SNAME|SOREG|SCON, TINT, /* will be int */
+ NSPECIAL|NCREG|NCSL|NCSR, RESC1,
+ "ZO", },
+
+{ LS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TWORD,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " sall AR,AL\n", },
+
+{ LS, INAREG|FOREFF,
+ SAREG, TWORD,
+ SCON, TANY,
+ 0, RLEFT,
+ " sall AR,AL\n", },
+
+{ LS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TSHORT|TUSHORT,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " shlw AR,AL\n", },
+
+{ LS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TSHORT|TUSHORT,
+ SCON, TANY,
+ 0, RLEFT,
+ " shlw AR,AL\n", },
+
+{ LS, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " salb AR,AL\n", },
+
+{ LS, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ SCON, TANY,
+ 0, RLEFT,
+ " salb AR,AL\n", },
+
+/* (u)longlong right shift is emulated */
+{ RS, INCREG,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ SAREG|SNAME|SOREG|SCON, TINT, /* will be int */
+ NSPECIAL|NCREG|NCSL|NCSR, RESC1,
+ "ZO", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TSWORD,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " sarl AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TSWORD,
+ SCON, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ 0, RLEFT,
+ " sarl AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TUWORD,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " shrl AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TUWORD,
+ SCON, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ 0, RLEFT,
+ " shrl AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TSHORT,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " sarw AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TSHORT,
+ SCON, TANY,
+ 0, RLEFT,
+ " sarw AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TUSHORT,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " shrw AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TUSHORT,
+ SCON, TANY,
+ 0, RLEFT,
+ " shrw AR,AL\n", },
+
+{ RS, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TCHAR,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " sarb AR,AL\n", },
+
+{ RS, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TCHAR,
+ SCON, TANY,
+ 0, RLEFT,
+ " sarb AR,AL\n", },
+
+{ RS, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TUCHAR,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " shrb AR,AL\n", },
+
+{ RS, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TUCHAR,
+ SCON, TANY,
+ 0, RLEFT,
+ " shrb AR,AL\n", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+{ ASSIGN, FOREFF,
+ SHLL|SNAME|SOREG, TLL,
+ SCON, TANY,
+ 0, 0,
+ " movl AR,AL\n movl UR,UL\n", },
+
+{ ASSIGN, FOREFF|INLL,
+ SHLL, TLL,
+ SCON, TANY,
+ 0, RDEST,
+ " movl AR,AL\n movl UR,UL\n", },
+
+{ ASSIGN, FOREFF,
+ SAREG|SNAME|SOREG, TWORD|TPOINT,
+ SCON, TANY,
+ 0, 0,
+ " movl AR,AL\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TWORD|TPOINT,
+ SCON, TANY,
+ 0, RDEST,
+ " movl AR,AL\n", },
+
+{ ASSIGN, FOREFF,
+ SAREG|SNAME|SOREG, TSHORT|TUSHORT,
+ SCON, TANY,
+ 0, 0,
+ " movw AR,AL\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TSHORT|TUSHORT,
+ SCON, TANY,
+ 0, RDEST,
+ " movw AR,AL\n", },
+
+{ ASSIGN, FOREFF,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ SCON, TANY,
+ 0, 0,
+ " movb AR,AL\n", },
+
+{ ASSIGN, FOREFF|INCH,
+ SHCH, TCHAR|TUCHAR,
+ SCON, TANY,
+ 0, RDEST,
+ " movb AR,AL\n", },
+
+{ ASSIGN, FOREFF|INLL,
+ SHLL|SNAME|SOREG, TLL,
+ SHLL, TLL,
+ 0, RDEST,
+ " movl AR,AL\n movl UR,UL\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SAREG|SNAME|SOREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RDEST,
+ " movl AR,AL\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG|SNAME|SOREG, TWORD|TPOINT,
+ 0, RDEST,
+ " movl AR,AL\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SAREG|SNAME|SOREG, TSHORT|TUSHORT,
+ SAREG, TSHORT|TUSHORT,
+ 0, RDEST,
+ " movw AR,AL\n", },
+
+{ ASSIGN, FOREFF|INCH,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ SHCH, TCHAR|TUCHAR|TWORD,
+ 0, RDEST,
+ " movb AR,AL\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SFLD, TANY,
+ SAREG, TANY,
+ NAREG, RDEST,
+ "ZE", },
+
+{ ASSIGN, FOREFF,
+ SFLD, TANY,
+ SAREG|SNAME|SOREG|SCON, TANY,
+ NAREG, 0,
+ "ZE", },
+
+{ ASSIGN, INDREG|FOREFF,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, RDEST,
+ "", }, /* This will always be in the correct register */
+
+/* order of table entries is very important here! */
+{ ASSIGN, INFL,
+ SNAME|SOREG, TLDOUBLE,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, RDEST,
+ " fstt AL\n", },
+
+{ ASSIGN, FOREFF,
+ SNAME|SOREG, TLDOUBLE,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, 0,
+ " fstpt AL\n", },
+
+{ ASSIGN, INFL,
+ SNAME|SOREG, TDOUBLE,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, RDEST,
+ " fstl AL\n", },
+
+{ ASSIGN, FOREFF,
+ SNAME|SOREG, TDOUBLE,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, 0,
+ " fstpl AL\n", },
+
+{ ASSIGN, INFL,
+ SNAME|SOREG, TFLOAT,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, RDEST,
+ " fsts AL\n", },
+
+{ ASSIGN, FOREFF,
+ SNAME|SOREG, TFLOAT,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, 0,
+ " fstps AL\n", },
+/* end very important order */
+
+{ ASSIGN, INFL|FOREFF,
+ SHFL, TLDOUBLE,
+ SHFL|SOREG|SNAME, TLDOUBLE,
+ 0, RDEST,
+ " fldt AR\n", },
+
+{ ASSIGN, INFL|FOREFF,
+ SHFL, TDOUBLE,
+ SHFL|SOREG|SNAME, TDOUBLE,
+ 0, RDEST,
+ " fldl AR\n", },
+
+{ ASSIGN, INFL|FOREFF,
+ SHFL, TFLOAT,
+ SHFL|SOREG|SNAME, TFLOAT,
+ 0, RDEST,
+ " flds AR\n", },
+
+/* Do not generate memcpy if return from funcall */
+#if 0
+{ STASG, INAREG|FOREFF,
+ SOREG|SNAME|SAREG, TPTRTO|TSTRUCT,
+ SFUNCALL, TPTRTO|TSTRUCT,
+ 0, RRIGHT,
+ "", },
+#endif
+
+{ STASG, INAREG|FOREFF,
+ SOREG|SNAME, TANY,
+ SAREG|SOREG|SNAME, TPTRTO|TANY,
+ NSPECIAL, RRIGHT,
+ "ZQ", },
+
+/*
+ * DIV/MOD/MUL
+ */
+/* long long div is emulated */
+{ DIV, INCREG,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ NSPECIAL|NCREG|NCSL|NCSR, RESC1,
+ "ZO", },
+
+{ DIV, INAREG,
+ SAREG, TSWORD,
+ SAREG|SNAME|SOREG, TWORD,
+ NSPECIAL, RDEST,
+ " cltd\n idivl AR\n", },
+
+{ DIV, INAREG,
+ SAREG, TUWORD|TPOINT,
+ SAREG|SNAME|SOREG, TUWORD|TPOINT,
+ NSPECIAL, RDEST,
+ " xorl %edx,%edx\n divl AR\n", },
+
+{ DIV, INAREG,
+ SAREG, TUSHORT,
+ SAREG|SNAME|SOREG, TUSHORT,
+ NSPECIAL, RDEST,
+ " xorl %edx,%edx\n divw AR\n", },
+
+{ DIV, INCH,
+ SHCH, TUCHAR,
+ SHCH|SNAME|SOREG, TUCHAR,
+ NSPECIAL, RDEST,
+ " xorb %ah,%ah\n divb AR\n", },
+
+{ DIV, INFL,
+ SHFL, TDOUBLE,
+ SNAME|SOREG, TDOUBLE,
+ 0, RLEFT,
+ " fdivl AR\n", },
+
+{ DIV, INFL,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RLEFT,
+ " fdivZAp\n", },
+
+/* (u)longlong mod is emulated */
+{ MOD, INCREG,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ NSPECIAL|NCREG|NCSL|NCSR, RESC1,
+ "ZO", },
+
+{ MOD, INAREG,
+ SAREG, TSWORD,
+ SAREG|SNAME|SOREG, TSWORD,
+ NAREG|NSPECIAL, RESC1,
+ " cltd\n idivl AR\n", },
+
+{ MOD, INAREG,
+ SAREG, TUWORD|TPOINT,
+ SAREG|SNAME|SOREG, TUWORD|TPOINT,
+ NAREG|NSPECIAL, RESC1,
+ " xorl %edx,%edx\n divl AR\n", },
+
+{ MOD, INAREG,
+ SAREG, TUSHORT,
+ SAREG|SNAME|SOREG, TUSHORT,
+ NAREG|NSPECIAL, RESC1,
+ " xorl %edx,%edx\n divw AR\n", },
+
+{ MOD, INCH,
+ SHCH, TUCHAR,
+ SHCH|SNAME|SOREG, TUCHAR,
+ NBREG|NSPECIAL, RESC1,
+ " xorb %ah,%ah\n divb AR\n", },
+
+/* (u)longlong mul is emulated */
+{ MUL, INCREG,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ NSPECIAL|NCREG|NCSL|NCSR, RESC1,
+ "ZO", },
+
+{ MUL, INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG|SNAME|SOREG|SCON, TWORD|TPOINT,
+ 0, RLEFT,
+ " imull AR,AL\n", },
+
+{ MUL, INAREG,
+ SAREG, TSHORT|TUSHORT,
+ SAREG|SNAME|SOREG, TSHORT|TUSHORT,
+ 0, RLEFT,
+ " imulw AR,AL\n", },
+
+{ MUL, INCH,
+ SHCH, TCHAR|TUCHAR,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ NSPECIAL, RDEST,
+ " imulb AR\n", },
+
+{ MUL, INFL,
+ SHFL, TDOUBLE,
+ SNAME|SOREG, TDOUBLE,
+ 0, RLEFT,
+ " fmull AR\n", },
+
+{ MUL, INFL,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RLEFT,
+ " fmulp\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL, INLL,
+ SANY, TANY,
+ SOREG, TLL,
+ NCREG|NCSL, RESC1,
+ " movl UL,U1\n movl AL,A1\n", },
+
+{ UMUL, INAREG,
+ SANY, TPOINT|TWORD,
+ SOREG, TPOINT|TWORD,
+ NAREG|NASL, RESC1,
+ " movl AL,A1\n", },
+
+{ UMUL, INCH,
+ SANY, TANY,
+ SOREG, TCHAR|TUCHAR,
+ NBREG|NBSL, RESC1,
+ " movb AL,A1\n", },
+
+{ UMUL, INAREG,
+ SANY, TANY,
+ SOREG, TSHORT|TUSHORT,
+ NAREG|NASL, RESC1,
+ " movw AL,A1\n", },
+
+{ UMUL, INFL,
+ SANY, TANY,
+ SOREG, TLDOUBLE,
+ NDREG|NDSL, RESC1,
+ " fldt AL\n", },
+
+{ UMUL, INFL,
+ SANY, TANY,
+ SOREG, TDOUBLE,
+ NDREG|NDSL, RESC1,
+ " fldl AL\n", },
+
+{ UMUL, INFL,
+ SANY, TANY,
+ SOREG, TFLOAT,
+ NDREG|NDSL, RESC1,
+ " flds AL\n", },
+
+/*
+ * Logical/branching operators
+ */
+
+/* Comparisions, take care of everything */
+{ OPLOG, FORCC,
+ SHLL|SOREG|SNAME, TLL,
+ SHLL, TLL,
+ 0, 0,
+ "ZD", },
+
+{ OPLOG, FORCC,
+ SAREG|SOREG|SNAME, TWORD|TPOINT,
+ SCON|SAREG, TWORD|TPOINT,
+ 0, RESCC,
+ " cmpl AR,AL\n", },
+
+{ OPLOG, FORCC,
+ SCON|SAREG, TWORD|TPOINT,
+ SAREG|SOREG|SNAME, TWORD|TPOINT,
+ 0, RESCC,
+ " cmpl AR,AL\n", },
+
+{ OPLOG, FORCC,
+ SAREG|SOREG|SNAME, TSHORT|TUSHORT,
+ SCON|SAREG, TANY,
+ 0, RESCC,
+ " cmpw AR,AL\n", },
+
+{ OPLOG, FORCC,
+ SBREG|SOREG|SNAME, TCHAR|TUCHAR,
+ SCON|SBREG, TANY,
+ 0, RESCC,
+ " cmpb AR,AL\n", },
+
+{ OPLOG, FORCC,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ NSPECIAL, 0,
+ "ZG", },
+
+{ OPLOG, FORCC,
+ SOREG|SNAME, TDOUBLE|TFLOAT,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ NSPECIAL, 0,
+ "ZG", },
+
+#if 0
+/* Ppro and later only */
+{ OPLOG, FORCC,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RESCC,
+ "ZA fucomip %st,%st(1)\n", },
+#endif
+
+{ OPLOG, FORCC,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, 0,
+ "diediedie!", },
+
+/* AND/OR/ER/NOT */
+{ AND, INAREG|FOREFF,
+ SAREG|SOREG|SNAME, TWORD,
+ SCON|SAREG, TWORD,
+ 0, RLEFT,
+ " andl AR,AL\n", },
+
+{ AND, INCREG|FOREFF,
+ SCREG, TLL,
+ SCREG|SOREG|SNAME, TLL,
+ 0, RLEFT,
+ " andl AR,AL\n andl UR,UL\n", },
+
+{ AND, INAREG|FOREFF,
+ SAREG, TWORD,
+ SAREG|SOREG|SNAME, TWORD,
+ 0, RLEFT,
+ " andl AR,AL\n", },
+
+{ AND, INAREG|FOREFF,
+ SAREG|SOREG|SNAME, TSHORT|TUSHORT,
+ SCON|SAREG, TSHORT|TUSHORT,
+ 0, RLEFT,
+ " andw AR,AL\n", },
+
+{ AND, INAREG|FOREFF,
+ SAREG, TSHORT|TUSHORT,
+ SAREG|SOREG|SNAME, TSHORT|TUSHORT,
+ 0, RLEFT,
+ " andw AR,AL\n", },
+
+{ AND, INBREG|FOREFF,
+ SBREG|SOREG|SNAME, TCHAR|TUCHAR,
+ SCON|SBREG, TCHAR|TUCHAR,
+ 0, RLEFT,
+ " andb AR,AL\n", },
+
+{ AND, INBREG|FOREFF,
+ SBREG, TCHAR|TUCHAR,
+ SBREG|SOREG|SNAME, TCHAR|TUCHAR,
+ 0, RLEFT,
+ " andb AR,AL\n", },
+/* AND/OR/ER/NOT */
+
+/*
+ * Jumps.
+ */
+{ GOTO, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ 0, RNOP,
+ " jmp LL\n", },
+
+#ifdef GCC_COMPAT
+{ GOTO, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, RNOP,
+ " jmp *AL\n", },
+#endif
+
+/*
+ * Convert LTYPE to reg.
+ */
+{ OPLTYPE, INLL,
+ SANY, TANY,
+ SCREG|SCON|SOREG|SNAME, TLL,
+ NCREG, RESC1,
+ " movl UL,U1\n movl AL,A1\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SAREG|SCON|SOREG|SNAME, TWORD|TPOINT,
+ NAREG|NASL, RESC1,
+ " movl AL,A1\n", },
+
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SBREG|SOREG|SNAME|SCON, TCHAR|TUCHAR,
+ NBREG, RESC1,
+ " movb AL,A1\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SAREG|SOREG|SNAME|SCON, TSHORT|TUSHORT,
+ NAREG, RESC1,
+ " movw AL,A1\n", },
+
+{ OPLTYPE, INDREG,
+ SANY, TLDOUBLE,
+ SOREG|SNAME, TLDOUBLE,
+ NDREG, RESC1,
+ " fldt AL\n", },
+
+{ OPLTYPE, INDREG,
+ SANY, TDOUBLE,
+ SOREG|SNAME, TDOUBLE,
+ NDREG, RESC1,
+ " fldl AL\n", },
+
+{ OPLTYPE, INDREG,
+ SANY, TFLOAT,
+ SOREG|SNAME, TFLOAT,
+ NDREG, RESC1,
+ " flds AL\n", },
+
+/* Only used in ?: constructs. The stack already contains correct value */
+{ OPLTYPE, INDREG,
+ SANY, TFLOAT|TDOUBLE|TLDOUBLE,
+ SDREG, TFLOAT|TDOUBLE|TLDOUBLE,
+ NDREG, RESC1,
+ "", },
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS, INCREG|FOREFF,
+ SCREG, TLL,
+ SCREG, TLL,
+ 0, RLEFT,
+ " negl AL\n adcl $0,UL\n negl UL\n", },
+
+{ UMINUS, INAREG|FOREFF,
+ SAREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RLEFT,
+ " negl AL\n", },
+
+{ UMINUS, INAREG|FOREFF,
+ SAREG, TSHORT|TUSHORT,
+ SAREG, TSHORT|TUSHORT,
+ 0, RLEFT,
+ " negw AL\n", },
+
+{ UMINUS, INBREG|FOREFF,
+ SBREG, TCHAR|TUCHAR,
+ SBREG, TCHAR|TUCHAR,
+ 0, RLEFT,
+ " negb AL\n", },
+
+{ UMINUS, INFL|FOREFF,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RLEFT,
+ " fchs\n", },
+
+{ COMPL, INCREG,
+ SCREG, TLL,
+ SANY, TANY,
+ 0, RLEFT,
+ " notl AL\n notl UL\n", },
+
+{ COMPL, INAREG,
+ SAREG, TWORD,
+ SANY, TANY,
+ 0, RLEFT,
+ " notl AL\n", },
+
+{ COMPL, INAREG,
+ SAREG, TSHORT|TUSHORT,
+ SANY, TANY,
+ 0, RLEFT,
+ " notw AL\n", },
+
+{ COMPL, INBREG,
+ SBREG, TCHAR|TUCHAR,
+ SANY, TANY,
+ 0, RLEFT,
+ " notb AL\n", },
+
+/*
+ * Arguments to functions.
+ */
+{ FUNARG, FOREFF,
+ SCON|SCREG|SNAME|SOREG, TLL,
+ SANY, TLL,
+ 0, RNULL,
+ " pushl UL\n pushl AL\n", },
+
+{ FUNARG, FOREFF,
+ SCON|SAREG|SNAME|SOREG, TWORD|TPOINT,
+ SANY, TWORD|TPOINT,
+ 0, RNULL,
+ " pushl AL\n", },
+
+{ FUNARG, FOREFF,
+ SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SANY, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ 0, RNULL,
+ " pushl AL\n", },
+
+{ FUNARG, FOREFF,
+ SAREG|SNAME|SOREG, TSHORT,
+ SANY, TSHORT,
+ NAREG, 0,
+ " movswl AL,ZN\n pushl ZN\n", },
+
+{ FUNARG, FOREFF,
+ SAREG|SNAME|SOREG, TUSHORT,
+ SANY, TUSHORT,
+ NAREG, 0,
+ " movzwl AL,ZN\n pushl ZN\n", },
+
+{ FUNARG, FOREFF,
+ SHCH|SNAME|SOREG, TCHAR,
+ SANY, TCHAR,
+ NAREG, 0,
+ " movsbl AL,A1\n pushl A1\n", },
+
+{ FUNARG, FOREFF,
+ SHCH|SNAME|SOREG, TUCHAR,
+ SANY, TUCHAR,
+ NAREG, 0,
+ " movzbl AL,A1\n pushl A1\n", },
+
+{ FUNARG, FOREFF,
+ SNAME|SOREG, TDOUBLE,
+ SANY, TDOUBLE,
+ 0, 0,
+ " pushl UL\n pushl AL\n", },
+
+{ FUNARG, FOREFF,
+ SDREG, TDOUBLE,
+ SANY, TDOUBLE,
+ 0, 0,
+ " subl $8,%esp\n fstpl (%esp)\n", },
+
+{ FUNARG, FOREFF,
+ SNAME|SOREG, TFLOAT,
+ SANY, TFLOAT,
+ 0, 0,
+ " pushl AL\n", },
+
+{ FUNARG, FOREFF,
+ SDREG, TFLOAT,
+ SANY, TFLOAT,
+ 0, 0,
+ " subl $4,%esp\n fstps (%esp)\n", },
+
+{ FUNARG, FOREFF,
+ SDREG, TLDOUBLE,
+ SANY, TLDOUBLE,
+ 0, 0,
+ " subl $12,%esp\n fstpt (%esp)\n", },
+
+{ STARG, FOREFF,
+ SAREG|SOREG|SNAME|SCON, TANY,
+ SANY, TSTRUCT,
+ NSPECIAL|NAREG, 0,
+ "ZF", },
+
+#endif
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+{ INIT, DF(INIT), },
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/usr.bin/pcc/arch/pdp10/code.c b/usr.bin/pcc/arch/pdp10/code.c
new file mode 100644
index 00000000000..6121bdc6219
--- /dev/null
+++ b/usr.bin/pcc/arch/pdp10/code.c
@@ -0,0 +1,167 @@
+/* $Id: code.c,v 1.1 2007/09/15 18:12:29 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.
+ */
+
+
+# include "pass1.h"
+
+/*
+ * cause the alignment to become a multiple of n
+ * Nothing to do on PDP10.
+ */
+void
+defalign(int n)
+{
+}
+
+/*
+ * code for the end of a function
+ */
+void
+efcode()
+{
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in stab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **a, int n)
+{
+ send_passt(IP_LOCCTR, PROG);
+ defnam(cftnsp);
+}
+
+
+/*
+ * 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 )
+{
+}
+
+/*
+ * 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(" .block %d\n", n);
+ 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)
+{
+ int i;
+ char *s;
+
+ /* simple switch code */
+ for (i = 1; i <= n; ++i) {
+ /* already in 1 */
+ s = (isinlining ? permalloc(40) : tmpalloc(40));
+ if (p[i]->sval >= 0 && p[i]->sval <= 0777777)
+ sprintf(s, " cain 1,0%llo", p[i]->sval);
+ else if (p[i]->sval < 0)
+ sprintf(s, " camn 1,[ .long -0%llo ]", -p[i]->sval);
+ else
+ sprintf(s, " camn 1,[ .long 0%llo ]", p[i]->sval);
+ send_passt(IP_ASM, s);
+ branch(p[i]->slab);
+ }
+ if (p[0]->slab > 0) {
+ send_passt(IP_DEFLAB, getlab()); /* XXX - fool optimizer */
+ branch(p[0]->slab);
+ }
+}
diff --git a/usr.bin/pcc/arch/pdp10/local.c b/usr.bin/pcc/arch/pdp10/local.c
new file mode 100644
index 00000000000..8d18720aa1e
--- /dev/null
+++ b/usr.bin/pcc/arch/pdp10/local.c
@@ -0,0 +1,782 @@
+/* $Id: local.c,v 1.1 2007/09/15 18:12:29 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.
+ */
+
+
+# include "pass1.h"
+
+/* this file contains code which is dependent on the target machine */
+
+static int pointp(TWORD t);
+static struct symtab *newfun(char *name, TWORD type);
+
+#define PTRNORMAL 1
+#define PTRCHAR 2
+#define PTRSHORT 3
+static int ptype(TWORD t);
+
+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, *oop;
+ register int o;
+ register int m, ml;
+ int siz;
+
+ 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 */
+ if (q->stype == CHAR || q->stype == UCHAR ||
+ q->stype == SHORT || q->stype == USHORT)
+ r = block(REG, NIL, NIL, PTR+q->stype, 0, 0);
+ else
+ 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;
+ if ((q->sflags & SLABEL) == 0)
+ cerror("STATIC");
+ break;
+
+ case REGISTER:
+ p->n_op = REG;
+ p->n_lval = 0;
+ p->n_rval = q->soffset;
+ break;
+
+ }
+ break;
+
+ case PCONV:
+ l = p->n_left;
+ /*
+ * Handle frame pointer directly without conversion,
+ * for efficiency.
+ */
+ if (l->n_op == REG && l->n_rval == 0) {
+rmpc: l->n_type = p->n_type;
+ l->n_df = p->n_df;
+ l->n_sue = p->n_sue;
+ nfree(p);
+ return l;
+ }
+ /* Convert ICON with name to new type */
+ if (l->n_op == ICON && l->n_sp != NULL &&
+ l->n_type == INCREF(STRTY) &&
+ (p->n_type == INCREF(CHAR) ||
+ p->n_type == INCREF(UCHAR) ||
+ p->n_type == INCREF(SHORT) ||
+ p->n_type == INCREF(USHORT))) {
+ l->n_lval *= (BTYPE(p->n_type) == CHAR ||
+ BTYPE(p->n_type) == UCHAR ? 4 : 2);
+ goto rmpc;
+ }
+ /* Convert only address constants, never convert other */
+ if (l->n_op == ICON) {
+ if (l->n_sp == NULL)
+ goto rmpc;
+ if (p->n_type == INCREF(CHAR) ||
+ p->n_type == INCREF(UCHAR) ||
+ p->n_type == INCREF(VOID))
+ l->n_lval = (l->n_lval & 07777777777) |
+ 0700000000000LL;
+ else if (p->n_type == INCREF(SHORT) ||
+ p->n_type == INCREF(USHORT))
+ l->n_lval = (l->n_lval & 07777777777) |
+ 0750000000000LL;
+ else
+ l->n_lval = l->n_lval & 07777777777;
+ goto rmpc;
+ }
+
+ /* Remove more conversions of identical pointers */
+ /* Be careful! optim() may do bad things */
+ if (ISPTR(DECREF(p->n_type))) {
+ if (ISPTR(DECREF(l->n_type))) {
+ if ((coptype(l->n_op) == UTYPE ||
+ coptype(l->n_op) == BITYPE) &&
+ (l->n_left->n_op == REG))
+ l->n_left->n_type = p->n_type;
+ goto rmpc;
+ }
+ }
+
+ /* Change PCONV from int to double pointer to right shift */
+ if (ISPTR(p->n_type) && ISPTR(DECREF(p->n_type)) &&
+ (l->n_type == INT || l->n_type == UNSIGNED)) {
+ p->n_op = RS;
+ p->n_right = bcon(2);
+ break;
+ }
+
+ /* Check for cast integral -> pointer */
+ if (BTYPE(l->n_type) == l->n_type)
+ break;
+
+ /* Remove conversions to identical pointers */
+ switch (ptype(p->n_type)) {
+ case PTRNORMAL:
+ if (ptype(l->n_type) == PTRNORMAL)
+ goto rmpc;
+ break;
+
+ case PTRSHORT:
+ if (ptype(l->n_type) == PTRSHORT)
+ goto rmpc;
+ break;
+
+ case PTRCHAR:
+ if (ptype(l->n_type) == PTRCHAR)
+ goto rmpc;
+ break;
+ }
+
+ break;
+
+ case SCONV:
+ l = p->n_left;
+
+ if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+ btdim[p->n_type] == btdim[l->n_type]) {
+ if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+ l->n_type != FLOAT && l->n_type != DOUBLE) {
+ nfree(p);
+ return l;
+ }
+ }
+ /* cast to (void) XXX should be removed in MI code */
+ if (p->n_type == VOID) {
+ nfree(p);
+ return l;
+ }
+ m = p->n_type;
+ ml = l->n_type;
+ if (m == ml) {
+ nfree(p);
+ return l;
+ }
+ o = l->n_op;
+ if (ml == FLOAT || ml == DOUBLE) {
+ if (o != FCON)
+ break;
+ ml = ISUNSIGNED(m) ? UNSIGNED : INT; /* LONG? */
+ r = block(ICON, (NODE *)NULL, (NODE *)NULL, ml, 0, 0);
+ r->n_lval = ml == INT ?
+ (int) p->n_left->n_dcon :
+ (unsigned) p->n_left->n_dcon;
+ r->n_sp = NULL;
+ nfree(p->n_left);
+ p->n_left = r;
+ o = ICON;
+ if (m == ml) {
+ r = p->n_left;
+ nfree(p);
+ return r;
+ }
+ }
+ if (o == ICON) {
+ CONSZ val = l->n_lval;
+
+ switch (m) {
+ case CHAR:
+ l->n_lval = val & 0777;
+ if (val & 0400)
+ l->n_lval |= ~((CONSZ)0777);
+ break;
+ case UCHAR:
+ l->n_lval = val & 0777;
+ break;
+ case USHORT:
+ l->n_lval = val & 0777777;
+ break;
+ case SHORT:
+ l->n_lval = val & 0777777;
+ if (val & 0400000)
+ l->n_lval |= ~((CONSZ)0777777);
+ break;
+ case UNSIGNED:
+ l->n_lval = val & 0777777777777LL;
+ break;
+ case ENUMTY:
+ case MOETY:
+ case INT:
+ l->n_lval = val & 0777777777777LL;
+ if (val & 0400000000000LL)
+ l->n_lval |= ~(0777777777777LL);
+ break;
+ case LONGLONG: /* XXX */
+ case ULONGLONG:
+ l->n_lval = val;
+ break;
+ case VOID:
+ break;
+ case DOUBLE:
+ case FLOAT:
+ l->n_op = FCON;
+ l->n_dcon = 0;
+ break;
+ default:
+ cerror("unknown type %d", m);
+ }
+ l->n_type = m;
+ l->n_sue = MKSUE(m);
+ nfree(p);
+ return l;
+ }
+ 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 RS:
+ case RSEQ:
+ /* convert >> to << with negative shift count */
+ /* Beware! constant shifts will be converted back in optim() */
+
+ if (p->n_right->n_op != UMINUS) {
+ p->n_right = buildtree(UMINUS, p->n_right, NIL);
+ } else {
+ r = p->n_right;
+ p->n_right = p->n_right->n_left;
+ nfree(r);
+ }
+ if (p->n_op == RS)
+ p->n_op = LS;
+ else
+ p->n_op = LSEQ;
+ break;
+
+ case UMUL: /* Convert structure assignment to memcpy() */
+ if (p->n_left->n_op == PLUS &&
+ p->n_left->n_left->n_op == PCONV &&
+ p->n_left->n_right->n_op == ICON &&
+ (p->n_type == CHAR || p->n_type == UCHAR ||
+ p->n_type == SHORT || p->n_type == USHORT)) {
+ /* Can remove the left SCONV */
+ l = p->n_left->n_left;
+ p->n_left->n_left = l->n_left;
+ nfree(l);
+ break;
+
+ }
+ if (p->n_left->n_op != STASG)
+ break;
+ oop = p;
+ p = p->n_left;
+ siz = p->n_sue->suesize/SZCHAR;
+ l = p->n_left;
+ r = p->n_right;
+ if (l->n_type == STRTY || l->n_type == UNIONTY) {
+ if (l->n_op == UMUL) {
+ p->n_left = l->n_left;
+ nfree(l);
+ l = p->n_left;
+ } else {
+ l = block(ADDROF, l, NIL, INCREF(l->n_type),
+ 0, MKSUE(INT));
+ }
+ }
+ if ((l->n_type != (STRTY+PTR) && l->n_type != (UNIONTY+PTR)) ||
+ (r->n_type != (STRTY+PTR) && r->n_type != (UNIONTY+PTR)))
+ cerror("bad stasg, l = %o, r = %o", l->n_type, r->n_type);
+ q = newfun("__structcpy", p->n_type);
+
+ /* structure pointer block */
+ l = block(CM, l, r, INT, 0, MKSUE(INT));
+ /* Size block */
+ r = block(CM, l, bcon(siz), INT, 0, MKSUE(INT));
+
+ l = block(ICON, NIL, NIL, q->stype, 0, MKSUE(INT));
+ l->n_sp = q;
+ p->n_left = l;
+ p->n_right = r;
+ p->n_op = CALL;
+ oop->n_left = p;
+ return oop;
+
+ }
+
+ return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+ NODE *r;
+
+ switch (p->n_op) {
+ case ULT: /* exor sign bit to avoid unsigned comparitions */
+ case ULE:
+ case UGT:
+ case UGE:
+ if (ISLONGLONG(p->n_left->n_type)) {
+ r = block(ICON, NIL, NIL, LONGLONG, 0, MKSUE(LONGLONG));
+ r->n_lval = 0x8000000000000000ULL; /* XXX */
+ } else {
+ r = block(ICON, NIL, NIL, INT, 0, MKSUE(INT));
+ r->n_lval = 0400000000000LL;
+ }
+ r->n_sp = NULL;
+ p->n_left = buildtree(ER, p->n_left, r);
+ if (ISUNSIGNED(p->n_left->n_type))
+ p->n_left->n_type = DEUNSIGN(p->n_left->n_type);
+
+ if (ISLONGLONG(p->n_right->n_type)) {
+ r = block(ICON, NIL, NIL, LONGLONG, 0, MKSUE(LONGLONG));
+ r->n_lval = 0x8000000000000000ULL; /* XXX */
+ } else {
+ r = block(ICON, NIL, NIL, INT, 0, MKSUE(INT));
+ r->n_lval = 0400000000000LL;
+ }
+ r->n_sp = NULL;
+ p->n_right = buildtree(ER, p->n_right, r);
+ if (ISUNSIGNED(p->n_right->n_type))
+ p->n_right->n_type = DEUNSIGN(p->n_right->n_type);
+
+ p->n_op -= (ULT-LT);
+ break;
+ }
+}
+
+
+struct symtab *
+newfun(char *name, TWORD type)
+{
+ struct symtab *sp;
+
+ sp = lookup(name, 0);
+ if (sp->stype == VOID) {
+ sp->stype = INCREF(type | FTN);
+ sp->sclass = EXTERN;
+ sp->soffset = 0;
+ }
+#ifdef notdef
+ else if (!ISFTN(DECREF(sp->stype)))
+ uerror("reserved name '%s' used illegally", name);
+#endif
+ return sp;
+}
+
+/*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
+ * Everything is trusted to be in register here.
+ */
+int
+cisreg(TWORD t)
+{
+ return(1);
+}
+
+int
+ptype(TWORD t)
+{
+ int tt = BTYPE(t);
+ int e, rv;
+
+ if (!ISPTR(t))
+ cerror("not a pointer");
+
+ e = t & ~BTMASK;
+ while (e) {
+ rv = e;
+ if (DECREF(e) == 0)
+ break;
+ e = DECREF(e);
+ }
+ if (ISFTN(rv))
+ return PTRNORMAL;
+
+ switch (tt) {
+ case INT:
+ case LONG:
+ case LONGLONG:
+ case FLOAT:
+ case DOUBLE:
+ case STRTY:
+ case UNIONTY:
+ case ENUMTY:
+ case UNSIGNED:
+ case ULONG:
+ case ULONGLONG:
+ return PTRNORMAL;
+ case VOID:
+ case CHAR:
+ case UCHAR:
+ if (DECREF(t) == tt || ISARY(rv))
+ return PTRCHAR;
+ return PTRNORMAL;
+ case SHORT:
+ case USHORT:
+ if (DECREF(t) == tt || ISARY(rv))
+ return PTRSHORT;
+ return PTRNORMAL;
+ default:
+ break;
+ }
+ cerror("unknown type");
+ return PTRNORMAL; /* XXX */
+}
+
+/*
+ * Help routine to the one below; return true if it's not a word pointer.
+ */
+static int
+pointp(TWORD t)
+{
+ int rv = 0;
+
+ if (ISPTR(t) && ((t & TMASK1) == 0))
+ return 1;
+
+ t &= ~BTMASK;
+ while (t) {
+ rv = ISARY(t);
+ t = DECREF(t);
+ }
+ return rv;
+}
+
+/*
+ * 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/SZINT; /* Default */
+ if (ISPTR(DECREF(t)))
+ return p; /* Pointer/pointer reference */
+ switch (BTMASK & t) {
+ case INT:
+ case UNSIGNED:
+ case LONG:
+ case ULONG:
+ case STRTY:
+ case UNIONTY:
+ case ENUMTY:
+ case LONGLONG:
+ case ULONGLONG:
+ case FLOAT:
+ case DOUBLE:
+ break;
+
+ case SHORT:
+ case USHORT:
+ if (pointp(t))
+ p->n_lval = off/SZSHORT;
+ break;
+
+ case VOID: /* void pointers */
+ case CHAR:
+ case UCHAR:
+ if (pointp(t))
+ p->n_lval = off/SZCHAR;
+ break;
+
+ default:
+ cerror("offcon, off %llo size %d type %x", off, sue->suesize, t);
+ }
+ if (xdebug)
+ printf("offcon return 0%llo\n", p->n_lval);
+ 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.
+ * Be aware that a pointer conversion may be needed when saving
+ * to node t!
+ */
+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;
+ /* Cast sp to destination type (may be redundant) */
+ sp = buildtree(CAST,
+ block(NAME, NIL, NIL, t->n_type, t->n_df, t->n_sue), sp);
+ nfree(sp->n_left);
+ nfree(sp);
+ sp = sp->n_right;
+ 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));
+}
+
+static int inwd; /* current bit offsed in word */
+static CONSZ word; /* word being built from fields */
+
+/*
+ * Generate initialization code for assigning a constant c
+ * to a field of width sz
+ * we assume that the proper alignment has been obtained
+ * inoff is updated to have the proper final value
+ * we also assume sz < SZINT
+ */
+void
+incode(NODE *p, int sz)
+{
+ char *s;
+
+ inoff += sz;
+ if ((sz + inwd) > SZINT)
+ cerror("incode: field > int");
+
+ word |= ((p->n_lval & ((1 << sz) - 1)) << (36 - inwd - sz));
+
+ inwd += sz;
+ if (inoff % SZINT == 0) {
+ s = isinlining ? permalloc(30) : tmpalloc(30);
+ sprintf(s, " .long 0%llo", word);
+ send_passt(IP_ASM, s);
+ word = inwd = 0;
+ }
+ tfree(p);
+}
+
+/* output code to initialize space of size sz to the value d */
+/* the proper alignment has been obtained */
+/* inoff is updated to have the proper final value */
+/* on the target machine, write it out in octal! */
+void
+fincode(NODE *p, int sz)
+{
+ double d = p->n_dcon;
+
+ if(!nerrors)
+ printf(" %s 0%c%.20e\n",
+ sz == SZDOUBLE ? ".double" : ".float",
+ sz == SZDOUBLE ? 'd' : 'f', d);
+ inoff += sz;
+}
+
+void
+cinit(NODE *p, int sz)
+{
+ NODE *l;
+
+ /*
+ * as a favor (?) to people who want to write
+ * int i = 9600/134.5;
+ * we will, under the proper circumstances, do
+ * a coercion here.
+ */
+ switch (p->n_type) {
+ case INT:
+ case UNSIGNED:
+ l = p->n_left;
+ if (l->n_op != SCONV || l->n_left->n_op != FCON)
+ break;
+ nfree(l);
+ l = l->n_left;
+ l->n_lval = (long)(l->n_dcon);
+ l->n_sp = NULL;
+ l->n_op = ICON;
+ l->n_type = INT;
+ p->n_left = l;
+ break;
+ }
+ /* arrange for the initialization of p into a space of size sz */
+ /* the proper alignment has been opbtained */
+ /* inoff is updated to have the proper final value */
+ ecode( p );
+ inoff += sz;
+}
+
+/*
+ * define n bits of zeros in a vfd
+ */
+void
+vfdzero(int n)
+{
+ char *s;
+
+ inoff += n;
+ inwd += n;
+ if (inoff%ALINT ==0) {
+ s = isinlining ? permalloc(30) : tmpalloc(30);
+ sprintf(s, " .long 0%llo", word);
+ send_passt(IP_ASM, s);
+ word = inwd = 0;
+ }
+}
+
+/* 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
+ */
+int
+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 stroage class for an uninitialized declaration
+ */
+int
+noinit()
+{
+ return(EXTERN);
+}
+
+/* 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+(SZINT-1))/SZINT;
+ printf(" .comm %s,0%o\n", exname(q->sname), off);
+}
+
+/* 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+(SZINT-1))/SZINT;
+ if (q->slevel == 0)
+ printf(" .lcomm %s,0%o\n", exname(q->sname), off);
+ else
+ printf(" .lcomm " LABFMT ",0%o\n", q->soffset, off);
+}
+
+/*
+ * Debugger code - ignore.
+ */
+void
+prcstab(int a)
+{
+}
+
+void
+pfstab(char *a)
+{
+}
diff --git a/usr.bin/pcc/arch/pdp10/local2.c b/usr.bin/pcc/arch/pdp10/local2.c
new file mode 100644
index 00000000000..8591a44f4fc
--- /dev/null
+++ b/usr.bin/pcc/arch/pdp10/local2.c
@@ -0,0 +1,1237 @@
+/* $Id: local2.c,v 1.1 2007/09/15 18:12:29 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.
+ */
+
+
+# include "pass2.h"
+# include <ctype.h>
+
+# define putstr(s) fputs((s), stdout)
+
+void acon(FILE *, NODE *p);
+int argsize(NODE *p);
+void genargs(NODE *p);
+
+static int ftlab1, ftlab2;
+static int offlab;
+int offarg;
+
+void
+lineid(int l, char *fn)
+{
+ /* identify line l and file fn */
+ printf("# line %d, file %s\n", l, fn);
+}
+
+void
+defname(char *name, int visib)
+{
+ if (visib)
+ printf(" .globl %s\n", name);
+ printf("%s:\n", name);
+}
+
+void
+deflab(int label)
+{
+ printf(LABFMT ":\n", label);
+}
+
+static int isoptim;
+
+void
+prologue(int regs, int autos)
+{
+ int i, addto;
+
+ offlab = getlab();
+ if (regs < 0 || autos < 0) {
+ /*
+ * non-optimized code, jump to epilogue for code generation.
+ */
+ ftlab1 = getlab();
+ ftlab2 = getlab();
+ printf(" jrst L%d\n", ftlab1);
+ printf("L%d:\n", ftlab2);
+ } else {
+ /*
+ * We here know what register to save and how much to
+ * add to the stack.
+ */
+ autos = autos + (SZINT-1);
+ addto = (autos - AUTOINIT)/SZINT + (MAXRVAR-regs);
+ if (addto || gflag) {
+ printf(" push %s,%s\n",rnames[017], rnames[016]);
+ printf(" move %s,%s\n", rnames[016],rnames[017]);
+ for (i = regs; i < MAXRVAR; i++) {
+ int db = ((i+1) < MAXRVAR);
+ printf(" %smovem %s,0%o(%s)\n",
+ db ? "d" : "",
+ rnames[i+1], i+1-regs, rnames[016]);
+ if (db)
+ i++;
+ }
+ if (addto)
+ printf(" addi %s,0%o\n", rnames[017], addto);
+ } else
+ offarg = 1;
+ isoptim = 1;
+ }
+}
+
+/*
+ * End of block.
+ */
+void
+eoftn(int regs, int autos, int retlab)
+{
+ register OFFSZ spoff; /* offset from stack pointer */
+ int i;
+
+ spoff = autos + (SZINT-1);
+ if (spoff >= AUTOINIT)
+ spoff -= AUTOINIT;
+ spoff /= SZINT;
+ /* return from function code */
+ printf("L%d:\n", retlab);
+ if (gflag || isoptim == 0 || autos != AUTOINIT || regs != MAXRVAR) {
+ for (i = regs; i < MAXRVAR; i++) {
+ int db = ((i+1) < MAXRVAR);
+ printf(" %smove %s,0%o(%s)\n", db ? "d" : "",
+ rnames[i+1], i+1-regs, rnames[016]);
+ if (db)
+ i++;
+ }
+ printf(" move %s,%s\n", rnames[017], rnames[016]);
+ printf(" pop %s,%s\n", rnames[017], rnames[016]);
+ }
+ printf(" popj %s,\n", rnames[017]);
+
+ /* Prolog code */
+ if (isoptim == 0) {
+ printf("L%d:\n", ftlab1);
+ printf(" push %s,%s\n", rnames[017], rnames[016]);
+ printf(" move %s,%s\n", rnames[016], rnames[017]);
+ for (i = regs; i < MAXRVAR; i++) {
+ int db = ((i+1) < MAXRVAR);
+ printf(" %smovem %s,0%o(%s)\n", db ? "d" : "",
+ rnames[i+1], i+1-regs, rnames[016]);
+ spoff++;
+ if (db)
+ i++, spoff++;
+ }
+ if (spoff)
+ printf(" addi %s,0%llo\n", rnames[017], spoff);
+ printf(" jrst L%d\n", ftlab2);
+ }
+ printf(" .set " LABFMT ",0%o\n", offlab, MAXRVAR-regs);
+ offarg = isoptim = 0;
+}
+
+static char *loctbl[] = { "text", "data", "data", "text", "text", "stab" };
+
+void
+setlocc(int locctr)
+{
+ static int lastloc;
+
+ if (locctr == lastloc)
+ return;
+
+ lastloc = locctr;
+ printf(" .%s\n", loctbl[locctr]);
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ * R - Register
+ * M - Memory
+ * C - Constant
+ */
+void
+hopcode(int f, int o)
+{
+ cerror("hopcode: f %d %d", f, o);
+}
+
+char *
+rnames[] = { /* keyed to register number tokens */
+ "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7",
+ "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
+};
+
+int rstatus[] = {
+ 0, STAREG, STAREG, STAREG, STAREG, STAREG, STAREG, STAREG,
+ SAREG, SAREG, SAREG, SAREG, SAREG, SAREG, 0, 0,
+};
+
+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))
+ cerror("tlen type %d not pointer");
+ return SZPOINT/SZCHAR;
+ }
+}
+
+static char *
+binskip[] = {
+ "e", /* jumpe */
+ "n", /* jumpn */
+ "le", /* jumple */
+ "l", /* jumpl */
+ "ge", /* jumpge */
+ "g", /* jumpg */
+};
+
+/*
+ * Extract the higher 36 bits from a longlong.
+ */
+static CONSZ
+gethval(CONSZ lval)
+{
+ CONSZ hval = (lval >> 35) & 03777777777LL;
+
+ if ((hval & 03000000000LL) == 03000000000LL) {
+ hval |= 0777000000000LL;
+ } else if ((hval & 03000000000LL) == 02000000000LL) {
+ hval &= 01777777777LL;
+ hval |= 0400000000000LL;
+ }
+ return hval;
+}
+
+/*
+ * Do a binary comparision, and jump accordingly.
+ */
+static void
+twocomp(NODE *p)
+{
+ int o = p->n_op;
+ extern int negrel[];
+ int isscon = 0, iscon = p->n_right->n_op == ICON;
+
+ if (o < EQ || o > GT)
+ cerror("bad binary conditional branch: %s", opst[o]);
+
+ if (iscon && p->n_right->n_name[0] != 0) {
+ printf(" cam%s ", binskip[negrel[o-EQ]-EQ]);
+ adrput(stdout, getlr(p, 'L'));
+ putchar(',');
+ printf("[ .long ");
+ adrput(stdout, getlr(p, 'R'));
+ putchar(']');
+ printf("\n jrst L%d\n", p->n_label);
+ return;
+ }
+ if (iscon)
+ isscon = p->n_right->n_lval >= 0 &&
+ p->n_right->n_lval < 01000000;
+
+ printf(" ca%c%s ", iscon && isscon ? 'i' : 'm',
+ binskip[negrel[o-EQ]-EQ]);
+ adrput(stdout, getlr(p, 'L'));
+ putchar(',');
+ if (iscon && (isscon == 0)) {
+ printf("[ .long ");
+ adrput(stdout, getlr(p, 'R'));
+ putchar(']');
+ } else
+ adrput(stdout, getlr(p, 'R'));
+ printf("\n jrst L%d\n", p->n_label);
+}
+
+/*
+ * Compare byte/word pointers.
+ * XXX - do not work for highest bit set in address
+ */
+static void
+ptrcomp(NODE *p)
+{
+ printf(" rot "); adrput(stdout, getlr(p, 'L')); printf(",6\n");
+ printf(" rot "); adrput(stdout, getlr(p, 'R')); printf(",6\n");
+ twocomp(p);
+}
+
+/*
+ * Do a binary comparision of two long long, and jump accordingly.
+ * XXX - can optimize for constants.
+ */
+static void
+twollcomp(NODE *p)
+{
+ int o = p->n_op;
+ int iscon = p->n_right->n_op == ICON;
+ int m;
+
+ if (o < EQ || o > GT)
+ cerror("bad long long conditional branch: %s", opst[o]);
+
+ /* Special strategy for equal/not equal */
+ if (o == EQ || o == NE) {
+ if (o == EQ)
+ m = getlab();
+ printf(" came ");
+ upput(getlr(p, 'L'), SZLONG);
+ putchar(',');
+ if (iscon)
+ printf("[ .long ");
+ upput(getlr(p, 'R'), SZLONG);
+ if (iscon)
+ putchar(']');
+ printf("\n jrst L%d\n", o == EQ ? m : p->n_label);
+ printf(" cam%c ", o == EQ ? 'n' : 'e');
+ adrput(stdout, getlr(p, 'L'));
+ putchar(',');
+ if (iscon)
+ printf("[ .long ");
+ adrput(stdout, getlr(p, 'R'));
+ if (iscon)
+ putchar(']');
+ printf("\n jrst L%d\n", p->n_label);
+ if (o == EQ)
+ printf("L%d:\n", m);
+ return;
+ }
+ /* First test highword */
+ printf(" cam%ce ", o == GT || o == GE ? 'l' : 'g');
+ adrput(stdout, getlr(p, 'L'));
+ putchar(',');
+ if (iscon)
+ printf("[ .long ");
+ adrput(stdout, getlr(p, 'R'));
+ if (iscon)
+ putchar(']');
+ printf("\n jrst L%d\n", p->n_label);
+
+ /* Test equality */
+ printf(" came ");
+ adrput(stdout, getlr(p, 'L'));
+ putchar(',');
+ if (iscon)
+ printf("[ .long ");
+ adrput(stdout, getlr(p, 'R'));
+ if (iscon)
+ putchar(']');
+ printf("\n jrst L%d\n", m = getlab());
+
+ /* Test lowword. Only works with pdp10 format for longlongs */
+ printf(" cam%c%c ", o == GT || o == GE ? 'l' : 'g',
+ o == LT || o == GT ? 'e' : ' ');
+ upput(getlr(p, 'L'), SZLONG);
+ putchar(',');
+ if (iscon)
+ printf("[ .long ");
+ upput(getlr(p, 'R'), SZLONG);
+ if (iscon)
+ putchar(']');
+ printf("\n jrst L%d\n", p->n_label);
+ printf("L%d:\n", m);
+}
+
+/*
+ * Print the correct instruction for constants.
+ */
+static void
+constput(NODE *p)
+{
+ CONSZ val = p->n_right->n_lval;
+ int reg = p->n_left->n_rval;
+
+ /* Only numeric constant */
+ if (p->n_right->n_name[0] == '\0') {
+ if (val == 0) {
+ printf("movei %s,0", rnames[reg]);
+ } else if ((val & 0777777000000LL) == 0) {
+ printf("movei %s,0%llo", rnames[reg], val);
+ } else if ((val & 0777777) == 0) {
+ printf("hrlzi %s,0%llo", rnames[reg], val >> 18);
+ } else {
+ printf("move %s,[ .long 0%llo]", rnames[reg],
+ szty(p->n_right->n_type) > 1 ? val :
+ val & 0777777777777LL);
+ }
+ /* Can have more tests here, hrloi etc */
+ return;
+ } else {
+ printf("xmovei %s,%s", rnames[reg], p->n_right->n_name);
+ if (val)
+ printf("+" CONFMT, val);
+ }
+}
+
+/*
+ * Return true if the constant can be bundled in an instruction (immediate).
+ */
+static int
+oneinstr(NODE *p)
+{
+ if (p->n_name[0] != '\0')
+ return 0;
+ if ((p->n_lval & 0777777000000ULL) != 0)
+ return 0;
+ return 1;
+}
+
+/*
+ * Emit a halfword or byte instruction, from OREG to REG.
+ * Sign extension must also be done here.
+ */
+static void
+emitshort(NODE *p)
+{
+ CONSZ off = p->n_lval;
+ TWORD type = p->n_type;
+ int reg = p->n_rval;
+ int issigned = !ISUNSIGNED(type);
+ int ischar = type == CHAR || type == UCHAR;
+ int reg1 = getlr(p, '1')->n_rval;
+
+ if (off < 0) { /* argument, use move instead */
+ printf(" move ");
+ } else if (off == 0 && p->n_name[0] == 0) {
+ printf(" ldb %s,%s\n", rnames[reg1], rnames[reg]);
+ /* XXX must sign extend here even if not necessary */
+ switch (type) {
+ case CHAR:
+ printf(" lsh %s,033\n", rnames[reg1]);
+ printf(" ash %s,-033\n", rnames[reg1]);
+ break;
+ case SHORT:
+ printf(" hrre %s,%s\n",
+ rnames[reg1], rnames[reg1]);
+ break;
+ }
+ return;
+ } else if (ischar) {
+ if (off >= 0700000000000LL && p->n_name[0] != '\0') {
+ cerror("emitsh");
+ /* reg contains index integer */
+ if (!istreg(reg))
+ cerror("emitshort !istreg");
+ printf(" adjbp %s,[ .long 0%llo+%s ]\n",
+ rnames[reg], off, p->n_name);
+ printf(" ldb ");
+ adrput(stdout, getlr(p, '1'));
+ printf(",%s\n", rnames[reg]);
+ goto signe;
+ }
+ printf(" ldb ");
+ adrput(stdout, getlr(p, '1'));
+ if (off)
+ printf(",[ .long 0%02o11%02o%06o ]\n",
+ (int)(27-(9*(off&3))), reg, (int)off/4);
+ else
+ printf(",%s\n", rnames[reg]);
+signe: if (issigned) {
+ printf(" lsh ");
+ adrput(stdout, getlr(p, '1'));
+ printf(",033\n ash ");
+ adrput(stdout, getlr(p, '1'));
+ printf(",-033\n");
+ }
+ return;
+ } else {
+ printf(" h%cr%c ", off & 1 ? 'r' : 'l',
+ issigned ? 'e' : 'z');
+ }
+ p->n_lval /= (ischar ? 4 : 2);
+ adrput(stdout, getlr(p, '1'));
+ putchar(',');
+ adrput(stdout, getlr(p, 'L'));
+ putchar('\n');
+}
+
+/*
+ * Store a short from a register. Destination is a OREG.
+ */
+static void
+storeshort(NODE *p)
+{
+ NODE *l = p->n_left;
+ CONSZ off = l->n_lval;
+ int reg = l->n_rval;
+ int ischar = BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR;
+
+ if (l->n_op == NAME) {
+ if (ischar) {
+ printf(" dpb ");
+ adrput(stdout, getlr(p, 'R'));
+ printf(",[ .long 0%02o%010o+%s ]\n",
+ 070+((int)off&3), (int)(off/4), l->n_name);
+ return;
+ }
+ printf(" hr%cm ", off & 1 ? 'r' : 'l');
+ l->n_lval /= 2;
+ adrput(stdout, getlr(p, 'R'));
+ putchar(',');
+ adrput(stdout, getlr(p, 'L'));
+ putchar('\n');
+ return;
+ }
+
+ if (off || reg == FPREG) { /* Can emit halfword instructions */
+ if (off < 0) { /* argument, use move instead */
+ printf(" movem ");
+ } else if (ischar) {
+ printf(" dpb ");
+ adrput(stdout, getlr(p, '1'));
+ printf(",[ .long 0%02o11%02o%06o ]\n",
+ (int)(27-(9*(off&3))), reg, (int)off/4);
+ return;
+ } else {
+ printf(" hr%cm ", off & 1 ? 'r' : 'l');
+ }
+ l->n_lval /= 2;
+ adrput(stdout, getlr(p, 'R'));
+ putchar(',');
+ adrput(stdout, getlr(p, 'L'));
+ } else {
+ printf(" dpb ");
+ adrput(stdout, getlr(p, 'R'));
+ putchar(',');
+ l = getlr(p, 'L');
+ l->n_op = REG;
+ adrput(stdout, l);
+ l->n_op = OREG;
+ }
+ putchar('\n');
+}
+
+/*
+ * Multiply a register with a constant.
+ */
+static void
+imuli(NODE *p)
+{
+ NODE *r = p->n_right;
+
+ if (r->n_lval >= 0 && r->n_lval <= 0777777) {
+ printf(" imuli ");
+ adrput(stdout, getlr(p, 'L'));
+ printf(",0%llo\n", r->n_lval);
+ } else {
+ printf(" imul ");
+ adrput(stdout, getlr(p, 'L'));
+ printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL);
+ }
+}
+
+/*
+ * Divide a register with a constant.
+ */
+static void
+idivi(NODE *p)
+{
+ NODE *r = p->n_right;
+
+ if (r->n_lval >= 0 && r->n_lval <= 0777777) {
+ printf(" idivi ");
+ adrput(stdout, getlr(p, '1'));
+ printf(",0%llo\n", r->n_lval);
+ } else {
+ printf(" idiv ");
+ adrput(stdout, getlr(p, '1'));
+ printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL);
+ }
+}
+
+/*
+ * move a constant into a register.
+ */
+static void
+xmovei(NODE *p)
+{
+ /*
+ * Trick: If this is an unnamed constant, just move it directly,
+ * otherwise use xmovei to get section number.
+ */
+ if (p->n_name[0] == '\0' || p->n_lval > 0777777) {
+ printf(" ");
+ zzzcode(p, 'D');
+ putchar(' ');
+ adrput(stdout, getlr(p, '1'));
+ putchar(',');
+ zzzcode(p, 'E');
+ } else {
+ printf(" xmovei ");
+ adrput(stdout, getlr(p, '1'));
+ printf(",%s", p->n_name);
+ if (p->n_lval != 0)
+ printf("+0%llo", p->n_lval);
+ }
+ putchar('\n');
+}
+
+static void
+printcon(NODE *p)
+{
+ CONSZ cz;
+
+ p = p->n_left;
+ if (p->n_lval >= 0700000000000LL) {
+ /* converted to pointer in clocal() */
+ conput(p);
+ return;
+ }
+ if (p->n_lval == 0 && p->n_name[0] == '\0') {
+ putchar('0');
+ return;
+ }
+ if (BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR)
+ cz = (p->n_lval/4) | ((p->n_lval & 3) << 30);
+ else
+ cz = (p->n_lval/2) | (((p->n_lval & 1) + 5) << 30);
+ cz |= 0700000000000LL;
+ printf("0%llo", cz);
+ if (p->n_name[0] != '\0')
+ printf("+%s", p->n_name);
+}
+
+static void
+putcond(NODE *p)
+{
+ char *c;
+
+ switch (p->n_op) {
+ case EQ: c = "e"; break;
+ case NE: c = "n"; break;
+ case LE: c = "le"; break;
+ case LT: c = "l"; break;
+ case GT: c = "g"; break;
+ case GE: c = "ge"; break;
+ default:
+ cerror("putcond");
+ }
+ printf("%s", c);
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+ NODE *l;
+ CONSZ hval;
+
+ switch (c) {
+ case 'A': /* ildb right arg */
+ adrput(stdout, p->n_left->n_left);
+ break;
+
+ case 'B': /* remove from stack after subroutine call */
+ if (p->n_rval)
+ printf(" subi %%17,0%o\n", p->n_rval/SZINT);
+ break;
+
+ case 'C':
+ constput(p);
+ break;
+
+ case 'D': /* Find out which type of const load insn to use */
+ if (p->n_op != ICON)
+ cerror("zzzcode not ICON");
+ if (p->n_name[0] == '\0') {
+ if ((p->n_lval <= 0777777) && (p->n_lval > 0))
+ printf("movei");
+ else if ((p->n_lval & 0777777) == 0)
+ printf("hrlzi");
+ else
+ printf("move");
+ } else
+ printf("move");
+ break;
+
+ case 'E': /* Print correct constant expression */
+ if (p->n_name[0] == '\0') {
+ if ((p->n_lval <= 0777777) && (p->n_lval > 0)){
+ printf("0%llo", p->n_lval);
+ } else if ((p->n_lval & 0777777) == 0) {
+ printf("0%llo", p->n_lval >> 18);
+ } else {
+ if (p->n_lval < 0)
+ printf("[ .long -0%llo]", -p->n_lval);
+ else
+ printf("[ .long 0%llo]", p->n_lval);
+ }
+ } else {
+ if (p->n_lval == 0)
+ printf("[ .long %s]", p->n_name);
+ else
+ printf("[ .long %s+0%llo]",
+ p->n_name, p->n_lval);
+ }
+ break;
+
+ case 'P':
+ p = getlr(p, 'R');
+ /* FALLTHROUGH */
+ case 'O':
+ /*
+ * Print long long expression.
+ */
+ hval = gethval(p->n_lval);
+ printf("[ .long 0%llo,0%llo", hval,
+ (p->n_lval & 0377777777777LL) | (hval & 0400000000000LL));
+ if (p->n_name[0] != '\0')
+ printf("+%s", p->n_name);
+ printf(" ]");
+ break;
+
+ case 'F': /* Print an "opsimp" instruction based on its const type */
+ hopcode(oneinstr(p->n_right) ? 'C' : 'R', p->n_op);
+ break;
+
+ case 'H': /* Print a small constant */
+ p = p->n_right;
+ printf("0%llo", p->n_lval & 0777777);
+ break;
+
+ case 'Q': /* two-param long long comparisions */
+ twollcomp(p);
+ break;
+
+ case 'R': /* two-param conditionals */
+ twocomp(p);
+ break;
+
+ case 'U':
+ emitshort(p);
+ break;
+
+ case 'V':
+ storeshort(p);
+ break;
+
+ case 'Z':
+ ptrcomp(p);
+ break;
+
+ case 'a':
+ imuli(p);
+ break;
+
+ case 'b':
+ idivi(p);
+ break;
+
+ case 'c':
+ xmovei(p);
+ break;
+
+ case 'd':
+ printcon(p);
+ break;
+
+ case 'e':
+ putcond(p);
+ break;
+
+ case 'g':
+ if (p->n_right->n_op != OREG || p->n_right->n_lval != 0)
+ comperr("bad Zg oreg");
+ printf("%s", rnames[p->n_right->n_rval]);
+ break;
+
+#if 0
+ case '1': /* double upput */
+ p = getlr(p, '1');
+ p->n_rval += 2;
+ adrput(stdout, p);
+ p->n_rval -= 2;
+ break;
+#endif
+
+ case 'i': /* Write instruction for short load from name */
+ l = getlr(p, 'L');
+ printf(" h%cr%c %s,%s+" CONFMT "\n",
+ l->n_lval & 1 ? 'r' : 'l',
+ ISUNSIGNED(p->n_type) ? 'z' : 'e',
+ rnames[getlr(p, '1')->n_rval],
+ l->n_name, l->n_lval >> 1);
+ break;
+
+ default:
+ cerror("zzzcode %c", c);
+ }
+}
+
+/* set up temporary registers */
+void
+setregs()
+{
+ fregs = 7; /* 7 free regs on PDP10 (1-7) */
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+ return(1);
+}
+
+int
+flshape(NODE *p)
+{
+ register int o = p->n_op;
+
+ return (o == REG || o == NAME || o == ICON ||
+ (o == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1)));
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+int
+shtemp(NODE *p)
+{
+ 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);
+}
+
+int
+shumul(NODE *p)
+{
+ register int o;
+
+ if (x2debug) {
+ int val;
+ printf("shumul(%p)\n", p);
+ eprint(p, 0, &val, &val);
+ }
+
+ o = p->n_op;
+#if 0
+ if (o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON)
+ return(STARNM);
+#endif
+
+ if ((o == INCR) &&
+ (p->n_left->n_op == REG && p->n_right->n_op == ICON) &&
+ p->n_right->n_name[0] == '\0') {
+ switch (p->n_type) {
+ case CHAR|PTR:
+ case UCHAR|PTR:
+ o = 1;
+ break;
+
+ case SHORT|PTR:
+ case USHORT|PTR:
+ o = 2;
+ break;
+
+ case INT|PTR:
+ case UNSIGNED|PTR:
+ case LONG|PTR:
+ case ULONG|PTR:
+ case FLOAT|PTR:
+ o = 4;
+ break;
+
+ case DOUBLE|PTR:
+ case LONGLONG|PTR:
+ case ULONGLONG|PTR:
+ o = 8;
+ break;
+
+ default:
+ if (ISPTR(p->n_type) &&
+ ISPTR(DECREF(p->n_type))) {
+ o = 4;
+ break;
+ } else
+ return(0);
+ }
+ return( 0);
+ }
+
+ return( 0 );
+}
+
+void
+adrcon(CONSZ val)
+{
+ cerror("adrcon: val %llo\n", val);
+}
+
+void
+conput(NODE *p)
+{
+ switch (p->n_op) {
+ case ICON:
+ if (p->n_lval != 0) {
+ acon(stdout, p);
+ if (p->n_name[0] != '\0')
+ putchar('+');
+ }
+ if (p->n_name[0] != '\0')
+ printf("%s", p->n_name);
+ if (p->n_name[0] == '\0' && p->n_lval == 0)
+ putchar('0');
+ return;
+
+ case REG:
+ putstr(rnames[p->n_rval]);
+ return;
+
+ default:
+ cerror("illegal conput");
+ }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+ cerror("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 /= SZLONG;
+ switch (p->n_op) {
+ case REG:
+ putstr(rnames[p->n_rval + size]);
+ break;
+
+ case NAME:
+ case OREG:
+ p->n_lval += size;
+ adrput(stdout, p);
+ p->n_lval -= size;
+ break;
+ case ICON:
+ printf(CONFMT, p->n_lval >> (36 * size));
+ break;
+ default:
+ cerror("upput bad op %d size %d", p->n_op, size);
+ }
+}
+
+void
+adrput(FILE *fp, 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, fp);
+ if (p->n_lval != 0)
+ fprintf(fp, "+" CONFMT, p->n_lval & 0777777777777LL);
+ return;
+
+ case OREG:
+ r = p->n_rval;
+#if 0
+ if (R2TEST(r)) { /* double indexing */
+ register int flags;
+
+ flags = R2UPK3(r);
+ if (flags & 1)
+ putc('*', fp);
+ if (flags & 4)
+ putc('-', fp);
+ if (p->n_lval != 0 || p->n_name[0] != '\0')
+ acon(p);
+ if (R2UPK1(r) != 100)
+ printf("(%s)", rnames[R2UPK1(r)]);
+ if (flags & 2)
+ putchar('+');
+ printf("[%s]", rnames[R2UPK2(r)]);
+ return;
+ }
+#endif
+ if (R2TEST(r))
+ cerror("adrput: unwanted double indexing: r %o", r);
+ if (p->n_rval != FPREG && p->n_lval < 0 && p->n_name[0]) {
+ fprintf(fp, "%s", p->n_name);
+ acon(fp, p);
+ fprintf(fp, "(%s)", rnames[p->n_rval]);
+ return;
+ }
+ if (p->n_lval < 0 && p->n_rval == FPREG && offarg) {
+ p->n_lval -= offarg-2; acon(fp, p); p->n_lval += offarg-2;
+ } else if (p->n_lval != 0)
+ acon(fp, p);
+ if (p->n_name[0] != '\0')
+ fprintf(fp, "%s%s", p->n_lval ? "+" : "", p->n_name);
+ if (p->n_lval > 0 && p->n_rval == FPREG && offlab)
+ fprintf(fp, "+" LABFMT, offlab);
+ if (p->n_lval < 0 && p->n_rval == FPREG && offarg)
+ fprintf(fp, "(017)");
+ else
+ fprintf(fp, "(%s)", rnames[p->n_rval]);
+ return;
+ case ICON:
+ /* addressable value of the constant */
+ if (p->n_lval > 0) {
+ acon(fp, p);
+ if (p->n_name[0] != '\0')
+ putc('+', fp);
+ }
+ if (p->n_name[0] != '\0')
+ fprintf(fp, "%s", p->n_name);
+ if (p->n_lval < 0)
+ acon(fp, p);
+ if (p->n_name[0] == '\0' && p->n_lval == 0)
+ putc('0', fp);
+ return;
+
+ case REG:
+ fputs(rnames[p->n_rval], fp);
+ return;
+
+ case MOVE: /* Specially generated node */
+ fputs(rnames[p->n_rall], fp);
+ return;
+
+ default:
+ cerror("illegal address, op %d", p->n_op);
+ return;
+
+ }
+}
+
+/*
+ * print out a constant
+*/
+void
+acon(FILE *fp, NODE *p)
+{
+ if (p->n_lval < 0 && p->n_lval > -0777777777777ULL)
+ fprintf(fp, "-" CONFMT, -p->n_lval);
+ else
+ fprintf(fp, CONFMT, p->n_lval);
+}
+
+/* printf conditional and unconditional branches */
+void
+cbgen(int o,int lab)
+{
+}
+
+/*
+ * 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;
+ if (op == ICON) {
+ if ((p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR))
+ && p->n_lval == 0 && p->n_name[0] != '\0')
+ p->n_lval = 0700000000000LL;
+ if ((p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT))
+ && p->n_lval == 0 && p->n_name[0] != '\0')
+ p->n_lval = 0750000000000LL;
+ }
+ if (op == MINUS) {
+ if ((p->n_left->n_type == (PTR|CHAR) ||
+ p->n_left->n_type == (PTR|UCHAR)) &&
+ (p->n_right->n_type == (PTR|CHAR) ||
+ p->n_right->n_type == (PTR|UCHAR))) {
+ l = talloc();
+ l->n_op = SCONV;
+ l->n_type = INT;
+ l->n_left = p->n_right;
+ p->n_right = l;
+ l = talloc();
+ l->n_op = SCONV;
+ l->n_type = INT;
+ l->n_left = p->n_left;
+ p->n_left = l;
+ }
+ }
+}
+
+void
+myreader(NODE *p)
+{
+ int e2print(NODE *p, int down, int *a, int *b);
+ walkf(p, optim2);
+ 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);
+}
+
+/*
+ * Remove last goto.
+ */
+void
+myoptim(struct interpass *ip)
+{
+ while (ip->sqelem.sqe_next->type != IP_EPILOG)
+ ip = ip->sqelem.sqe_next;
+ if (ip->type != IP_NODE || ip->ip_node->n_op != GOTO)
+ cerror("myoptim");
+ tfree(ip->ip_node);
+ *ip = *ip->sqelem.sqe_next;
+}
diff --git a/usr.bin/pcc/arch/pdp10/macdefs.h b/usr.bin/pcc/arch/pdp10/macdefs.h
new file mode 100644
index 00000000000..600427e554f
--- /dev/null
+++ b/usr.bin/pcc/arch/pdp10/macdefs.h
@@ -0,0 +1,148 @@
+/* $Id: macdefs.h,v 1.1 2007/09/15 18:12:29 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.
+ */
+
+/*
+ * 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) { \
+ if (i == 0) { lastcon = val; \
+ } else if (i == 1) { lastcon = (lastcon << 9) | val; lastcon <<= 18; \
+ } else { lastcon |= (val << (27 - (i * 9))); } }
+
+#define ARGINIT 36 /* # bits below fp where arguments start */
+#define AUTOINIT 36 /* # bits above fp where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR 9
+#define SZINT 36
+#define SZFLOAT 36
+#define SZDOUBLE 72
+#define SZLONG 36
+#define SZSHORT 18
+#define SZPOINT 36
+#define SZLONGLONG 72
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR 9
+#define ALINT 36
+#define ALFLOAT 36
+#define ALDOUBLE 36
+#define ALLONG 36
+#define ALLONGLONG 36
+#define ALSHORT 18
+#define ALPOINT 36
+#define ALSTRUCT 36
+#define ALSTACK 36
+
+/*
+ * Max values.
+ */
+#define MAX_INT 0377777777777LL
+#define MAX_UNSIGNED 0777777777777ULL
+#define MAX_LONG 0377777777777LL
+#define MAX_ULONG 0777777777777ULL
+#define MAX_LONGLONG 000777777777777777777777LL /* XXX cross */
+#define MAX_ULONGLONG 001777777777777777777777ULL /* XXX cross */
+
+/* Default char is unsigned */
+#define CHAR_UNSIGNED
+
+/*
+ * Use large-enough types.
+ */
+typedef long long CONSZ;
+typedef unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT "0%llo" /* format for printing constants */
+#define LABFMT "L%d" /* format for printing labels */
+
+#define FPREG 016 /* frame pointer */
+#define STKREG 017 /* stack pointer */
+
+/*
+ * Maximum and minimum register variables
+ */
+#define MINRVAR 010 /* use 10 thru ... */
+#define MAXRVAR 015 /* ... 15 */
+
+#define PARAMS_UPWARD /* stack grows upwards for parameters */
+#undef BACKAUTO /* stack grows negatively for automatics */
+#undef BACKTEMP /* stack grows negatively for temporaries */
+
+#define MYP2TREE(p) myp2tree(p);
+
+#undef FIELDOPS /* no bit-field instructions */
+#undef RTOLBYTES /* bytes are numbered left to right */
+
+#define ENUMSIZE(high,low) INT /* enums are always stored in full int */
+
+/* Definitions mostly used in pass2 */
+
+#define REGSZ 020
+#define TMPREG 016
+
+#define BYTEOFF(x) ((x)&03)
+#define wdal(k) (BYTEOFF(k)==0)
+#define BITOOR(x) ((x)/36) /* 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)
+
+#define shltype(o, p) \
+ ((o) == REG || (o) == NAME || (o) == ICON || \
+ (o) == OREG || ((o) == UMUL && shumul((p)->n_left)))
+
+#define MYREADER(p) myreader(p)
+#define MYCANON(p) mycanon(p)
+#define MYOPTIM
+
+#undef SPECIAL_INTEGERS
+
+/*
+ * Special shapes used in code generation.
+ */
+#define SUSHCON (SPECIAL|6) /* unsigned short constant */
+#define SNSHCON (SPECIAL|7) /* negative short constant */
+#define SILDB (SPECIAL|8) /* use ildb here */
+
diff --git a/usr.bin/pcc/arch/pdp10/order.c b/usr.bin/pcc/arch/pdp10/order.c
new file mode 100644
index 00000000000..b548c294b8d
--- /dev/null
+++ b/usr.bin/pcc/arch/pdp10/order.c
@@ -0,0 +1,187 @@
+/* $Id: order.c,v 1.1 2007/09/15 18:12:29 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.
+ */
+
+
+# include "pass2.h"
+
+int canaddr(NODE *);
+
+/*
+ * should the assignment op p be stored,
+ * given that it lies as the right operand of o
+ * (or the left, if o==UMUL)
+ */
+void
+stoasg(NODE *p, int o)
+{
+ if (x2debug)
+ printf("stoasg(%p, %o)\n", p, o);
+}
+
+/* should we delay the INCR or DECR operation p */
+int
+deltest(NODE *p)
+{
+ TWORD ty = p->n_type;
+
+ return ty == PTR+CHAR || ty == PTR+UCHAR ||
+ ty == PTR+SHORT || ty == PTR+USHORT;
+}
+
+/*
+ * Check if p can be autoincremented.
+ * Nothing can be autoincremented on PDP10.
+ */
+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 */
+}
+
+int radebug = 0;
+
+int
+offstar(NODE *p)
+{
+ NODE *q;
+
+ if (x2debug)
+ printf("offstar(%p)\n", p);
+
+ if( p->n_op == PLUS || p->n_op == MINUS ){
+ if( p->n_right->n_op == ICON ){
+ q = p->n_left;
+ if (q->n_op != REG)
+ geninsn(q, INTAREG|INAREG);
+ p->n_su = -1;
+ return 1;
+ }
+ }
+ geninsn(p, INTAREG|INAREG);
+ return 0;
+}
+
+/*
+ * Rewrite increment/decrement operation.
+ */
+int
+setincr(NODE *p)
+{
+ if (x2debug)
+ printf("setincr(%p)\n", p);
+
+ return(0);
+}
+
+/*
+ * findops() failed, see if we can rewrite it to match.
+ */
+int
+setbin(NODE *p)
+{
+ TWORD ty;
+ NODE *r, *s;
+
+ ty = p->n_type;
+ switch (p->n_op) {
+ case MINUS:
+ switch (ty) {
+ case PTR+CHAR:
+ case PTR+UCHAR:
+ case PTR+SHORT:
+ case PTR+USHORT:
+ /*
+ * Must negate the right side and change op to PLUS.
+ */
+ r = p->n_right;
+ if (r->n_op == ICON) {
+ r->n_lval = -r->n_lval;
+ } else {
+ s = talloc();
+ s->n_type = r->n_type;
+ s->n_op = UMINUS;
+ s->n_left = r;
+ p->n_right = s;
+ }
+ p->n_op = PLUS;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+ return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+ return 0;
+}
+
+int
+special(NODE *p, int shape)
+{
+ switch (shape) {
+ case SUSHCON:
+ if (p->n_op == ICON && p->n_name[0] == '\0' &&
+ (p->n_lval > 0 && p->n_lval <= 0777777))
+ return 1;
+ break;
+
+ case SNSHCON:
+ if (p->n_op == ICON && p->n_name[0] == '\0' &&
+ (p->n_lval < 0 && p->n_lval > -01000000))
+ return 1;
+ break;
+ case SILDB:
+ if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
+ p->n_right->n_op == PLUS &&
+ p->n_right->n_left->n_op == REG &&
+ p->n_right->n_right->n_op == ICON &&
+ p->n_right->n_right->n_lval == 1 &&
+ p->n_right->n_left->n_rval == p->n_left->n_rval)
+ return 1;
+ break;
+ }
+ return 0;
+}
diff --git a/usr.bin/pcc/arch/pdp10/table.c b/usr.bin/pcc/arch/pdp10/table.c
new file mode 100644
index 00000000000..321b88cb94e
--- /dev/null
+++ b/usr.bin/pcc/arch/pdp10/table.c
@@ -0,0 +1,1153 @@
+/* $Id: table.c,v 1.1 2007/09/15 18:12:30 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.
+ */
+
+
+# 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[] = {
+{ -1, FORREW,SANY,TANY,SANY,TANY,REWRITE,-1,"", },
+/*
+ * A bunch of pointer conversions.
+ * First pointer to integer.
+ */
+/* Convert char pointer to int */
+{ SCONV, INTAREG,
+ SAREG|STAREG, TPTRTO|TCHAR|TUCHAR,
+ SANY, TWORD,
+ NAREG, RLEFT,
+ " lsh AL,2\n"
+ " move A1,AL\n"
+ " lsh A1,-040\n"
+ " trz A1,074\n"
+ " ior AL,A1\n"
+ " tlz AL,0740000\n", },
+
+/* Convert short pointer to int */
+{ SCONV, INTAREG,
+ SAREG|STAREG, TPTRTO|TSHORT|TUSHORT,
+ SANY, TWORD,
+ NAREG, RLEFT,
+ " lsh AL,2\n"
+ " move A1,AL\n"
+ " lsh A1,-041\n"
+ " trz A1,2\n"
+ " ior AL,A1\n"
+ " tlz AL,0740000\n", },
+
+/* Convert int/unsigned/long/ulong/struct/union/func ptr to int */
+{ SCONV, INTAREG,
+ SAREG|STAREG, TPTRTO|TWORD|TSTRUCT|TPOINT,
+ SANY, TWORD,
+ 0, RLEFT,
+ " lsh AL,2\n", },
+
+/*
+ * Convert int/long to pointers.
+ */
+/* Convert int to char pointer */
+{ PCONV, INTAREG,
+ STAREG, TWORD,
+ SANY, TPTRTO|TCHAR|TUCHAR,
+ NAREG, RLEFT,
+ " move A1,AL\n"
+ " lsh A1,036\n"
+ " tlo A1,0700000\n"
+ " tlz A1,0040000\n"
+ " lsh AL,-2\n"
+ " ior AL,A1\n", },
+
+/* Convert int/long to short pointer */
+{ PCONV, INTAREG,
+ STAREG, TWORD,
+ SANY, TPTRTO|TSHORT|TUSHORT,
+ NAREG, RLEFT,
+ " move A1,AL\n"
+ " lsh AL,-2\n"
+ " tlo AL,0750000\n"
+ " lsh A1,035\n"
+ " tlz A1,0760000\n"
+ " add AL,A1\n", },
+
+/* Convert int/long to int/struct/multiple ptr */
+{ PCONV, INTAREG,
+ STAREG, TWORD,
+ SANY, TPOINT|TWORD|TSTRUCT,
+ 0, RLEFT,
+ " lsh AL,-2\n", },
+
+/*
+ * Pointer to pointer conversions.
+ */
+/* Convert char ptr to short ptr */
+{ PCONV, INTAREG,
+ STAREG, TPTRTO|TCHAR|TUCHAR,
+ SANY, TPTRTO|TSHORT|TUSHORT,
+ 0, RLEFT,
+ " tlo AL,050000\n"
+ " tlne AL,020000\n"
+ " tlz AL,010000\n", },
+
+/* Convert char/short pointer to int/struct/multiple ptr */
+{ PCONV, INTAREG,
+ STAREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SANY, TPOINT|TWORD|TSTRUCT,
+ 0, RLEFT,
+ " tlz AL,0770000\n", },
+
+/* Convert short pointer to char ptr */
+{ PCONV, INTAREG,
+ STAREG, TPTRTO|TSHORT|TUSHORT,
+ SANY, TPTRTO|TCHAR|TUCHAR,
+ 0, RLEFT,
+ " tlz AL,050000\n", },
+
+/* Convert int/struct/foo pointer to char ptr */
+{ PCONV, INTAREG,
+ STAREG, TPOINT|TWORD|TSTRUCT,
+ SANY, TPTRTO|TCHAR|TUCHAR,
+ 0, RLEFT,
+ " tlo AL,0700000\n", },
+
+/* Convert int/struct/foo pointer to short ptr */
+{ PCONV, INTAREG,
+ STAREG, TPTRTO|TWORD|TSTRUCT,
+ SANY, TPTRTO|TSHORT|TUSHORT,
+ 0, RLEFT,
+ " tlo AL,0750000\n", },
+
+/*
+ * A bunch conversions of integral<->integral types
+ */
+
+/* convert short/char to int. This is done when register is loaded */
+{ SCONV, INTAREG,
+ STAREG, TSHORT|TUSHORT|TCHAR|TUCHAR|TWORD,
+ SANY, TWORD,
+ 0, RLEFT,
+ "", },
+
+/* convert int to short/char. This is done when register is loaded */
+{ SCONV, INTAREG,
+ STAREG, TWORD,
+ SANY, TSHORT|TUSHORT|TCHAR|TUCHAR|TWORD,
+ 0, RLEFT,
+ "", },
+
+/* convert int/long to unsigned long long */
+{ SCONV, INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ SANY, TULONGLONG,
+ NAREG|NASL, RESC1,
+ " move U1,AL\n"
+ " setz A1,\n"
+ " tlze U1,0400000\n"
+ " tro A1,01\n" , },
+
+/* convert int/long to long long */
+{ SCONV, INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ SANY, TLONGLONG,
+ NAREG|NASL, RESC1,
+ " move U1,AL\n"
+ " move A1,U1\n"
+ " ash A1,-043\n", },
+
+/* convert uchar/ushort to (unsigned) long long */
+{ SCONV, INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TUCHAR|TUSHORT,
+ SANY, TLL,
+ NAREG|NASL, RESC1,
+ " move U1,AL\n"
+ " setz A1,\n", },
+
+/* convert long long to int/long */
+{ SCONV, INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ SANY, TWORD,
+ NAREG|NASL, RESC1,
+ " move A1,UL\n", },
+
+/* convert long long to unsigned char - XXX - signed char */
+{ SCONV, INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ SANY, TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " move A1,UL\n"
+ " andi A1,0777\n", },
+
+/* convert long long to short - XXX - signed short */
+{ SCONV, INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ SANY, TSHORT|TUSHORT,
+ NAREG|NASL, RESC1,
+ " move A1,UL\n"
+ " hrrz A1,A1\n", },
+
+/* floating point conversions */
+{ SCONV, INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TDOUBLE|TFLOAT,
+ SANY, TWORD,
+ NAREG|NASL, RESC1,
+ " fix A1,AL\n", },
+
+{ SCONV, INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ SANY, TFLOAT,
+ NAREG|NASL, RESC1,
+ " fltr A1,AL\n", },
+
+{ SCONV, INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ SANY, TDOUBLE,
+ NAREG|NASL, RESC1,
+ " fltr A1,AL\n setz U1,\n", },
+
+{ SCONV, INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TDOUBLE,
+ SANY, TFLOAT,
+ NAREG|NASL, RESC1,
+ " move A1,AL\n", },
+
+{ SCONV, INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TFLOAT,
+ SANY, TDOUBLE,
+ NAREG|NASL, RESC1,
+ " move A1,AL\n setz U1,\n", },
+
+/*
+ * Store constant initializers.
+ */
+{ INIT, FOREFF,
+ SCON, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SANY, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ 0, RNOP,
+ " .long Zd\n", },
+{ INIT, FOREFF,
+ SCON, TANY,
+ SANY, TWORD|TPOINT,
+ 0, RNOP,
+ " .long CL\n", },
+
+{ INIT, FOREFF,
+ SCON, TANY,
+ SANY, TLL,
+ 0, RNOP,
+ " .long UL\n .long CL\n", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ UCALL, INTAREG,
+ SCON, TANY,
+ SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT,
+ NAREG, RESC1, /* should be 0 */
+ " pushj 017,AL\nZB", },
+
+{ UCALL, INTAREG,
+ SAREG|STAREG, TANY,
+ SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " pushj 017,(AL)\nZB", },
+
+{ UCALL, INTAREG,
+ SNAME|SOREG, TANY,
+ SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT,
+ NAREG, RESC1, /* should be 0 */
+ " pushj 017,@AL\nZB", },
+
+/*
+ * MOVE nodes are usually inserted late (at register assignment).
+ */
+{ MOVE, FOREFF,
+ SANY, TWORD,
+ STAREG|SAREG|SNAME|SOREG, TWORD,
+ 0, RRIGHT,
+ " move AR,AL\n", },
+
+{ MOVE, FOREFF,
+ SANY, TLL,
+ STAREG|SAREG|SNAME|SOREG, TLL,
+ 0, RRIGHT,
+ " dmove AR,AL\n", },
+
+/*
+ * INCR can be slightly optimized.
+ */
+{ INCR, INTAREG,
+ STAREG|SAREG|SNAME|SOREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO,
+ SONE, TANY,
+ NAREG, RESC1,
+ " move A1,AL\n"
+ " ibp AL\n", },
+
+#ifdef notyet
+/* Fix check of return value */
+{ INCR, FOREFF,
+ STAREG|SAREG|SNAME|SOREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO,
+ SONE, TANY,
+ 0, 0,
+ " ibp AL\n", },
+#endif
+
+/*
+ * PLUS operators.
+ */
+/* Add a value to a char/short pointer */
+{ PLUS, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG|SNAME|SOREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SAREG|STAREG, TWORD,
+ 0, RRIGHT,
+ " adjbp AR,AL\n", },
+
+/* No more search for char/short pointer addition */
+{ PLUS, INAREG|INTAREG|FOREFF,
+ SANY, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SANY, TANY,
+ REWRITE, 0,
+ "DIEDIEDIE!\n", },
+
+/* Add char/short/int to register */
+{ PLUS, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TWORD,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ 0, RLEFT,
+ " add AL,AR\n", },
+
+/* Add char/short/int to memory */
+{ PLUS, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ SAREG|STAREG, TWORD,
+ 0, RLEFT,
+ " addm AR,AL\n", },
+
+/* Add a small constant to a register */
+{ PLUS, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD|TPOINT,
+ SUSHCON, TWORD,
+ 0, RLEFT,
+ " addi AL,AR\n", },
+
+/* Add a larger constant to a register */
+{ PLUS, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD|TPOINT,
+ SCON, TWORD,
+ 0, RLEFT,
+ " add AL,[ .long AR ]\n", },
+
+/* Add long long to register */
+{ PLUS, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG, TLL,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ 0, RLEFT,
+ " dadd AL,AR\n", },
+
+/* Add int (or int pointer) to register */
+{ PLUS, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TWORD|TPOINT,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ 0, RLEFT,
+ " add AL,AR # foo \n", },
+
+/* char/short are allowed to be added if they are in registers */
+{ PLUS, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ 0, RLEFT,
+ " add AL,AR\n", },
+
+/* get address of an memory position into a register */
+{ PLUS, INAREG|INTAREG,
+ SAREG|STAREG, TWORD|TPTRTO,
+ SCON, TANY,
+ NAREG, RESC1,
+ " xmovei A1,AR(AL)\n", },
+
+/* Safety belt for plus */
+{ PLUS, FORREW|FOREFF|INAREG|INTAREG,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, 0,
+ "DIEDIEDIE", },
+
+/*
+ * MINUS operators.
+ */
+/* Rewrite subtracts from char/short pointers (to negative adds) */
+{ MINUS, FORREW|FOREFF|INAREG|INTAREG,
+ SANY, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO,
+ SANY, TANY,
+ REWRITE, BITYPE,
+ "DIEDIEDIE", },
+
+/* Subtract char/short/int word in memory from reg */
+{ MINUS, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TWORD|TPOINT,
+ SAREG|STAREG|SNAME|SOREG, TWORD|TPOINT,
+ 0, RLEFT,
+ " sub AL,AR\n", },
+
+/* Subtract a small constant from reg */
+{ MINUS, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TWORD|TPOINT,
+ SUSHCON, TWORD|TPOINT,
+ 0, RLEFT,
+ " subi AL,AR\n", },
+
+/* Subtract a large constant from reg */
+{ MINUS, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TWORD|TPOINT,
+ SCON, TWORD|TPOINT,
+ 0, RLEFT,
+ " sub AL,[ .long AR ]\n", },
+
+/* Subtract char/short/int word in memory from reg, save in memory */
+{ MINUS, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TWORD,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ 0, RRIGHT,
+ " subm AL,AR\n", },
+
+/* Subtract long long from register */
+{ MINUS, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG, TLL,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ 0, RLEFT,
+ " dsub AL,AR\n", },
+
+/* char/short are allowed to be subtracted if they are in registers */
+{ MINUS, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ 0, RLEFT,
+ " sub AL,AR\n", },
+
+/* Safety belt for plus */
+{ MINUS, FORREW|FOREFF|INAREG|INTAREG,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, 0,
+ "DIEDIEDIE", },
+
+/*
+ * AND/OR/ER operators.
+ * Simpler that the ops above in that they only work on integral types.
+ */
+/* And char/short/int with integer memory */
+{ AND, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ 0, RLEFT,
+ " and AL,AR\n", },
+
+/* And char/short/int with register */
+{ AND, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ 0, RLEFT,
+ " and AL,AR\n", },
+
+/* And char/short/int with small constant */
+{ AND, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SUSHCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ 0, RLEFT,
+ " andi AL,AR\n", },
+
+/* And char/short/int with large constant */
+{ AND, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ 0, RLEFT,
+ " and AL,[ .long AR ]\n", },
+
+/* long long AND */
+{ AND, INAREG|FOREFF,
+ SAREG|STAREG, TLL,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ 0, RLEFT,
+ " and AL,AR\n"
+ " and UL,UR\n", },
+
+/* Safety belt for AND */
+{ AND, FORREW|FOREFF|INAREG|INTAREG,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, 0,
+ "DIEDIEDIE", },
+
+
+/* OR char/short/int with integer memory */
+{ OR, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ 0, RLEFT,
+ " ior AL,AR\n", },
+
+/* OR char/short/int with register */
+{ OR, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ 0, RLEFT,
+ " ior AL,AR\n", },
+
+/* OR char/short/int with small constant */
+{ OR, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SUSHCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ 0, RLEFT,
+ " iori AL,AR\n", },
+
+/* OR char/short/int with large constant */
+{ OR, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ 0, RLEFT,
+ " ior AL,[ .long AR ]\n", },
+
+/* long long OR */
+{ OR, INAREG|FOREFF,
+ SAREG|STAREG, TLL,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ 0, RLEFT,
+ " ior AL,AR\n"
+ " ior UL,UR\n", },
+
+/* Safety belt for OR */
+{ OR, FORREW|FOREFF|INAREG|INTAREG,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, 0,
+ "DIEDIEDIE", },
+
+
+/* ER char/short/int with integer memory */
+{ ER, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ 0, RLEFT,
+ " xor AL,AR\n", },
+
+/* ER char/short/int with register */
+{ ER, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ 0, RLEFT,
+ " xor AL,AR\n", },
+
+/* ER char/short/int with small constant */
+{ ER, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SUSHCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ 0, RLEFT,
+ " xori AL,AR\n", },
+
+/* ER char/short/int with large constant */
+{ ER, FOREFF|INAREG|INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ 0, RLEFT,
+ " xor AL,[ .long AR ]\n", },
+
+/* long long ER */
+{ ER, INAREG|FOREFF,
+ SAREG|STAREG, TLL,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ 0, RLEFT,
+ " xor AL,AR\n"
+ " xor UL,UR\n", },
+
+/* Safety belt for ER */
+{ ER, FORREW|FOREFF|INAREG|INTAREG,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, 0,
+ "DIEDIEDIE", },
+
+/*
+ * The next rules handle all shift operators.
+ */
+{ LS, INTAREG|INAREG|FOREFF,
+ SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ 0, RLEFT,
+ " lsh AL,(AR)\n", },
+
+{ LS, INTAREG|INAREG|FOREFF,
+ SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SNAME|SOREG, TWORD,
+ 0, RLEFT,
+ " lsh AL,@AR\n", },
+
+{ LS, INTAREG|INAREG|FOREFF,
+ STAREG|SAREG, TLL,
+ SCON, TANY,
+ 0, RLEFT,
+ " ashc AL,ZH\n", },
+
+{ LS, INTAREG|INAREG|FOREFF,
+ STAREG|SAREG, TLL,
+ SAREG|STAREG /* |SNAME|SOREG */, TANY,
+ 0, RLEFT,
+ " ashc AL,(AR)\n", },
+
+{ RS, INTAREG|INAREG|FOREFF,
+ STAREG|SAREG, TSWORD,
+ SCON, TWORD,
+ 0, RLEFT,
+ " ash AL,-ZH\n", },
+
+{ RS, INTAREG|INAREG|FOREFF,
+ STAREG|SAREG, TUWORD,
+ SCON, TWORD,
+ 0, RLEFT,
+ " lsh AL,-ZH\n", },
+
+/* Safety belt for LS/RS */
+{ LS, FORREW|FOREFF|INAREG|INTAREG,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, 0,
+ "DIEDIEDIE", },
+
+{ RS, FORREW|FOREFF|INAREG|INTAREG,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, 0,
+ "DIEDIEDIE", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+/* Match zeroed registers first */
+{ ASSIGN, INTAREG|FOREFF,
+ SAREG|STAREG, TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT,
+ SZERO, TANY,
+ 0, RLEFT,
+ " setz AL,\n", },
+
+{ ASSIGN, FOREFF,
+ SAREG|SNAME|SOREG, TWORD|TPOINT,
+ SZERO, TANY,
+ 0, 0,
+ " setzm AL\n", },
+
+{ ASSIGN, INTAREG|FOREFF,
+ SAREG|STAREG, TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT,
+ SMONE, TANY,
+ 0, RLEFT,
+ " setom AL\n", },
+
+{ ASSIGN, FOREFF,
+ SAREG|SNAME|SOREG, TWORD|TPOINT,
+ SMONE, TANY,
+ 0, 0,
+ " setom AL\n", },
+
+{ ASSIGN, INAREG|INTAREG|FOREFF,
+ STAREG|SAREG, TWORD|TPOINT,
+ SCON, TWORD|TPOINT,
+ 0, RLEFT,
+ " ZC\n", },
+
+{ ASSIGN, INAREG|INTAREG|FOREFF,
+ SAREG|SNAME|SOREG, TWORD|TPOINT|TFLOAT,
+ SAREG|STAREG, TUCHAR|TUSHORT|TWORD|TPOINT|TFLOAT,
+ 0, RRIGHT,
+ " movem AR,AL\n", },
+
+{ ASSIGN, INAREG|INTAREG|FOREFF,
+ SAREG|SNAME|SOREG, TWORD|TPOINT|TFLOAT,
+ SAREG|STAREG, TSHORT,
+ 0, 0,
+ " hrrem AR,AL\n", },
+
+{ ASSIGN, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG, TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT,
+ SAREG|STAREG|SNAME|SOREG, TWORD|TPOINT,
+ 0, RLEFT,
+ " move AL,AR\n", },
+
+{ ASSIGN, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG, TUCHAR|TUSHORT|TCHAR|TSHORT,
+ SAREG|STAREG, TUCHAR|TUSHORT|TCHAR|TSHORT,
+ 0, RLEFT,
+ " move AL,AR\n", },
+
+{ ASSIGN, INAREG|INTAREG|FOREFF,
+ SAREG|SNAME|SOREG, TLL|TDOUBLE,
+ SAREG|STAREG, TLL|TDOUBLE,
+ 0, RRIGHT,
+ " dmovem AR,AL\n", },
+
+{ ASSIGN, INAREG|INTAREG|FOREFF,
+ SOREG|SNAME, TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG|STAREG, TANY,
+ 0, RRIGHT,
+ "ZV", },
+
+{ ASSIGN, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG, TUSHORT|TUCHAR,
+ SOREG, TANY,
+ 0, RLEFT,
+ " ldb AL,Zg\n", },
+
+{ ASSIGN, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG, TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SSCON, TANY,
+ 0, RLEFT,
+ " movei AL,AR\n", },
+
+{ ASSIGN, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG, TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SCON, TANY,
+ 0, RLEFT,
+ " move AL,[ .long AR]\n", },
+
+/*
+ * DIV/MOD/MUL
+ * These can be done way more efficient.
+ */
+/* long long div. XXX - work only with unsigned */
+{ DIV, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ (2*NAREG)|NASL, RESC1,
+ " dmove A2,AL ; dmove A1,[ .long 0,0 ]\n"
+ " ddiv A1,AR\n", },
+
+/* long long div. with constant. XXX - work only with unsigned */
+{ DIV, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ SCON, TLL,
+ (2*NAREG)|NASL, RESC1,
+ " dmove A2,AL ; dmove A1,[ .long 0,0 ]\n"
+ " ddiv A1,ZP\n", },
+
+/* Simple divide. XXX - fix so next reg can be free */
+{ DIV, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ 0, RRIGHT,
+ " idivm AL,AR\n", },
+
+/* Safety belt for DIV */
+{ DIV, FORREW|FOREFF|INAREG|INTAREG,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, 0,
+ "DIEDIEDIE", },
+
+/* long long MOD */
+{ MOD, INTAREG|INAREG|FOREFF,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ 2*NAREG|NASL, RESC2,
+ " dmove A2,AL ; dmove A1,[ .long 0,0 ]\n"
+ " ddiv A1,AR\n", },
+
+/* integer MOD */
+{ MOD, INTAREG|INAREG|FOREFF,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ 2*NAREG|NASL, RESC2,
+ " move A2,AL\n"
+ " setz A1,\n"
+ " idiv A1,AR\n", },
+
+/* integer MOD for char/short */
+{ MOD, INTAREG|INAREG|FOREFF,
+ SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ 2*NAREG|NASL, RESC2,
+ " move A2,AL\n"
+ " setz A1,\n"
+ " idiv A1,AR\n", },
+
+/* Safety belt for MOD */
+{ MOD, FORREW|FOREFF|INAREG|INTAREG,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, 0,
+ "DIEDIEDIE", },
+
+/* long long MUL */
+{ MUL, INTAREG|INAREG|FOREFF,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ 2*NAREG|NASL, RESC2,
+ " dmove A1,AL\n"
+ " dmul A1,AR\n", },
+
+/* integer multiply to memory*/
+{ MUL, INTAREG|INAREG|FOREFF,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ SAREG|STAREG, TWORD,
+ 0, RLEFT,
+ " imulm AR,AL\n", },
+
+/* integer multiply */
+{ MUL, INTAREG|INAREG|FOREFF,
+ SAREG|STAREG, TWORD,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ 0, RLEFT,
+ " imul AL,AR\n", },
+
+/* integer multiply for char/short */
+{ MUL, INTAREG|INAREG|FOREFF,
+ SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ 0, RLEFT,
+ " imul AL,AR\n", },
+
+/* integer multiply with small constant */
+{ MUL, INTAREG|INAREG|FOREFF,
+ SAREG|STAREG, TWORD,
+ SUSHCON, TWORD,
+ 0, RLEFT,
+ " imuli AL,AR\n", },
+
+/* integer multiply with large constant */
+{ MUL, INTAREG|INAREG|FOREFF,
+ SAREG|STAREG, TWORD,
+ SCON, TWORD,
+ 0, RLEFT,
+ " imul AL,[ .long AR ]\n", },
+
+/* Safety belt for MUL */
+{ MUL, FORREW|FOREFF|INAREG|INTAREG,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, 0,
+ "DIEDIEDIE", },
+
+/* read an indirect long long value into register */
+{ UMUL, INTAREG,
+ SAREG|STAREG, TPTRTO|TLL|TWORD,
+ SANY, TLL,
+ NAREG|NASL, RESC1,
+ " dmove A1,(AL)\n", },
+
+/* read an indirect integer value into register */
+{ UMUL, INTAREG,
+ SAREG|STAREG, TWORD|TPOINT,
+ SANY, TWORD|TPOINT,
+ NAREG|NASL, RESC1,
+ " move A1,(AL)\n", },
+
+/* read an indirect value into register */
+{ UMUL, INTAREG,
+ SOREG, TWORD|TPOINT,
+ SANY, TWORD|TPOINT,
+ NAREG, RESC1,
+ " move A1,@AL\n", },
+
+/* read an indirect value into register */
+{ UMUL, INTAREG,
+ SAREG|STAREG|SOREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO,
+ SANY, TCHAR|TUCHAR|TSHORT|TUSHORT,
+ NAREG|NASL, RESC1,
+ " ldb A1,AL\n", },
+
+#ifdef notyet
+/* Match tree shape for ildb */
+{ UMUL, INTAREG,
+ SANY, TANY,
+ SILDB, TUCHAR|TCHAR|TPTRTO,
+ NAREG, RESC1,
+ " ildb A1,ZA\n", },
+#endif
+
+/* Match char/short pointers first, requires special handling */
+{ OPLOG, FORCC,
+ SAREG|STAREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SAREG|STAREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ 0, RESCC,
+ "ZZ", },
+
+/* Can check anything by just comparing if EQ/NE */
+{ OPLOG, FORCC,
+ SAREG|STAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SZERO, TANY,
+ 0, RESCC,
+ " jumpZe AL,LC # bu\n", },
+
+{ EQ, FORCC,
+ SAREG|STAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SAREG|STAREG|SOREG|SNAME|SCON, TWORD|TPOINT,
+ 0, RESCC,
+ "ZR", },
+
+{ NE, FORCC,
+ SAREG|STAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SAREG|STAREG|SOREG|SNAME|SCON, TWORD|TPOINT,
+ 0, RESCC,
+ "ZR", },
+
+{ OPLOG, FORCC,
+ SAREG|STAREG, TWORD,
+ SAREG|STAREG|SOREG|SNAME|SCON, TSWORD,
+ 0, RESCC,
+ "ZR", },
+
+{ OPLOG, FORCC,
+ SAREG|STAREG, TCHAR|TUCHAR,
+ SCON, TANY,
+ 0, RESCC,
+ "ZR", },
+
+{ OPLOG, FORCC,
+ SAREG|STAREG, TWORD|TPOINT|TFLOAT,
+ SAREG|STAREG|SOREG|SNAME|SCON, TWORD|TPOINT|TFLOAT,
+ 0, RESCC,
+ "ZR", },
+
+{ OPLOG, FORCC,
+ SAREG|STAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SAREG|STAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ 0, RESCC,
+ "ZR", },
+
+{ OPLOG, FORCC,
+ SAREG|STAREG, TLL|TDOUBLE, /* XXX - does double work here? */
+ SAREG|STAREG|SOREG|SNAME, TLL|TDOUBLE,
+ 0, RESCC,
+ "ZQ", },
+
+/*
+ * Jumps.
+ */
+{ GOTO, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ 0, RNOP,
+ " jrst LL\n", },
+
+/*
+ * Convert LTYPE to reg.
+ */
+{ OPLTYPE, INAREG|INTAREG,
+ SANY, TANY,
+ SMONE, TLL,
+ NAREG, RESC1,
+ " seto A1,\n seto U1,\n", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SANY, TANY,
+ SMONE, TANY,
+ NAREG, RESC1,
+ " seto A1,\n", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SANY, TANY,
+ SZERO, TLL,
+ NAREG, RESC1,
+ " setz A1,\n setz U1,\n", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SANY, TANY,
+ SZERO, TANY,
+ NAREG, RESC1,
+ " setz A1,\n", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SANY, TANY,
+ SUSHCON, TLL,
+ NAREG, RESC1,
+ " setz A1,\n movei U1,AR\n", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SANY, TANY,
+ SUSHCON, ANYFIXED,
+ NAREG, RESC1,
+ " movei A1,AR\n", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SANY, ANYFIXED,
+ SNSHCON, ANYFIXED,
+ NAREG, RESC1,
+ " hrroi A1,AR\n", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SANY, ANYFIXED,
+ SCON, ANYFIXED,
+ NAREG|NASR, RESC1,
+ " ZD A1,ZE # suspekt\n", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SANY, TWORD|TPOINT|TFLOAT,
+ SAREG|STAREG|SOREG|SNAME, TWORD|TPOINT|TFLOAT,
+ NAREG|NASR, RESC1,
+ " move A1,AR\n", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SANY, TLL,
+ SCON, TLL,
+ NAREG, RESC1,
+ " dmove A1,ZO\n", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SANY, TLL|TDOUBLE,
+ SANY, TLL|TDOUBLE,
+ NAREG|NASR, RESC1,
+ " dmove A1,AR\n", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SOREG, TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SOREG, TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASR, RESC1,
+ "ZU", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SNAME, TUCHAR,
+ SNAME, TUCHAR,
+ NAREG|NASR, RESC1,
+ " ldb A1,[ .long AL ]\n" },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SNAME, TCHAR,
+ SNAME, TCHAR,
+ NAREG|NASR, RESC1,
+ " ldb A1,[ .long AL ]\n"
+ " ash A1,033\n"
+ " ash A1,-033\n", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SANY, TANY,
+ SNAME, TSHORT|TUSHORT,
+ NAREG|NASR, RESC1,
+ "Zi", },
+
+{ OPLTYPE, INAREG|INTAREG,
+ SANY, TWORD|TPOINT,
+ SCON, TWORD|TPOINT,
+ NAREG|NASR, RESC1,
+ "Zc", },
+
+{ OPLTYPE, INAREG,
+ SAREG|STAREG, TUSHORT|TUCHAR,
+ SAREG|STAREG, TUSHORT|TUCHAR|TWORD,
+ NAREG, RESC1,
+ " move A1,AL\n", },
+
+/*
+ * Negate a word.
+ */
+{ UMINUS, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ SANY, TWORD,
+ NAREG|NASL, RESC1,
+ " movn A1,AL\n", },
+
+{ UMINUS, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG, TWORD,
+ SANY, TCHAR|TUCHAR|TSHORT|TUSHORT,
+ 0, RLEFT,
+ " movn AL,AL\n", },
+
+{ UMINUS, INAREG|INTAREG|FOREFF,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ SANY, TLL,
+ NAREG|NASR, RESC1,
+ " dmovn A1,AL\n", },
+
+{ COMPL, INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TLL,
+ SANY, TANY,
+ NAREG|NASL, RESC1,
+ " setcm A1,AL\n"
+ " setcm U1,UL\n", },
+
+{ COMPL, INTAREG,
+ SAREG|STAREG|SNAME|SOREG, TWORD,
+ SANY, TANY,
+ NAREG|NASL, RESC1,
+ " setcm A1,AL\n", },
+
+{ COMPL, INTAREG,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SANY, TCHAR|TUCHAR|TSHORT|TUSHORT,
+ NAREG|NASL, RESC1,
+ " setcm A1,AL\n", },
+
+/*
+ * Arguments to functions.
+ */
+{ FUNARG, FOREFF,
+ SAREG|SNAME|SOREG, TWORD|TPOINT|TFLOAT,
+ SANY, TANY,
+ 0, RNULL,
+ " push 017,AL\n", },
+
+{ FUNARG, FOREFF,
+ SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT,
+ SANY, TANY,
+ 0, RNULL,
+ " push 017,AL\n", },
+
+{ FUNARG, FOREFF,
+ SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TPOINT|TWORD,
+ SANY, TANY,
+ 0, RNULL,
+ " push 017,[ .long AL]\n", },
+
+{ FUNARG, FOREFF,
+ SAREG|STAREG, TLL|TDOUBLE,
+ SANY, TANY,
+ 0, RNULL,
+ " push 017,AL\n push 017,UL\n", },
+
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ INCR, DF(INCR), },
+
+{ DECR, DF(INCR), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ OPLEAF, DF(NAME), },
+
+{ INIT, DF(INIT), },
+
+{ OPUNARY, DF(UMINUS), },
+
+{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
diff --git a/usr.bin/pcc/arch/vax/code.c b/usr.bin/pcc/arch/vax/code.c
new file mode 100644
index 00000000000..d048a337fd9
--- /dev/null
+++ b/usr.bin/pcc/arch/vax/code.c
@@ -0,0 +1,452 @@
+/* $Id: code.c,v 1.1 2007/09/15 18:12:30 otto Exp $ */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed or owned by Caldera
+ * International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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.
+ */
+
+# include "mfile1"
+#include <a.out.h>
+
+int proflg = 0; /* are we generating profiling code? */
+int strftn = 0; /* is the current function one which returns a value */
+int gdebug;
+int fdefflag; /* are we within a function definition ? */
+char NULLNAME[8];
+int labelno;
+
+branch( n ){
+ /* output a branch to label n */
+ /* exception is an ordinary function branching to retlab: then, return */
+ if( n == retlab && !strftn ){
+ printf( " ret\n" );
+ }
+ else printf( " jbr L%d\n", n );
+ }
+
+int lastloc = { -1 };
+
+short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3};
+#define LOG2SZ 9
+
+defalign(n) {
+ /* cause the alignment to become a multiple of n */
+ n /= SZCHAR;
+ if( lastloc != PROG && n > 1 ) printf( " .align %d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 );
+ }
+
+locctr( l ){
+ register temp;
+ /* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */
+
+ if( l == lastloc ) return(l);
+ temp = lastloc;
+ lastloc = l;
+ switch( l ){
+
+ case PROG:
+ printf( " .text\n" );
+ psline();
+ break;
+
+ case DATA:
+ case ADATA:
+ printf( " .data\n" );
+ break;
+
+ case STRNG:
+ printf( " .data 1\n" );
+ break;
+
+ case ISTRNG:
+ printf( " .data 2\n" );
+ break;
+
+ case STAB:
+ printf( " .stab\n" );
+ break;
+
+ default:
+ cerror( "illegal location counter" );
+ }
+
+ return( temp );
+ }
+
+deflab( n ){
+ /* output something to define the current position as label n */
+ printf( "L%d:\n", n );
+ }
+
+int crslab = 10;
+
+getlab(){
+ /* return a number usable for a label */
+ return( ++crslab );
+ }
+
+
+int ent_mask[] = {
+ 0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0};
+
+int reg_use = 11;
+
+efcode(){
+ /* code for the end of a function */
+
+ if( strftn ){ /* copy output (in R2) to caller */
+ register NODE *l, *r;
+ register struct symtab *p;
+ register TWORD t;
+ register int j;
+ int i;
+
+ p = &stab[curftn];
+ t = p->stype;
+ t = DECREF(t);
+
+ deflab( retlab );
+
+ i = getlab(); /* label for return area */
+ printf(" .data\n" );
+ printf(" .align 2\n" );
+ printf("L%d: .space %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR );
+ printf(" .text\n" );
+ psline();
+ printf(" movab L%d,r1\n", i);
+
+ reached = 1;
+ l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
+ l->rval = 1; /* R1 */
+ l->lval = 0; /* no offset */
+ r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
+ r->rval = 0; /* R0 */
+ r->lval = 0;
+ l = buildtree( UNARY MUL, l, NIL );
+ r = buildtree( UNARY MUL, r, NIL );
+ l = buildtree( ASSIGN, l, r );
+ l->op = FREE;
+ ecomp( l->left );
+ printf( " movab L%d,r0\n", i );
+ /* turn off strftn flag, so return sequence will be generated */
+ strftn = 0;
+ }
+ branch( retlab );
+ printf( " .set .R%d,0x%x\n", ftnno, ent_mask[reg_use] );
+ reg_use = 11;
+ p2bend();
+ fdefflag = 0;
+ }
+
+bfcode( a, n ) int a[]; {
+ /* code for the beginning of a function; a is an array of
+ indices in stab for the arguments; n is the number */
+ register i;
+ register temp;
+ register struct symtab *p;
+ int off;
+ char *toreg();
+
+ locctr( PROG );
+ p = &stab[curftn];
+ printf( " .align 1\n");
+ defnam( p );
+ temp = p->stype;
+ temp = DECREF(temp);
+ strftn = (temp==STRTY) || (temp==UNIONTY);
+
+ retlab = getlab();
+
+ /* routine prolog */
+
+ printf( " .word .R%d\n", ftnno);
+ if (gdebug) {
+ pstab(NULLNAME, N_SLINE);
+ printf("0,%d,LL%d\n", lineno, labelno);
+ printf("LL%d:\n", labelno++);
+ }
+ printf( " subl2 $.F%d,sp\n", ftnno);
+ if( proflg ) { /* profile code */
+ i = getlab();
+ printf(" movab L%d,r0\n", i);
+ printf(" jsb mcount\n");
+ printf(" .data\n");
+ printf(" .align 2\n");
+ printf("L%d: .long 0\n", i);
+ printf(" .text\n");
+ psline();
+ }
+
+ off = ARGINIT;
+
+ for( i=0; i<n; ++i ){
+ p = &stab[a[i]];
+ if( p->sclass == REGISTER ){
+ temp = p->offset; /* save register number */
+ p->sclass = PARAM; /* forget that it is a register */
+ p->offset = NOOFFSET;
+ oalloc( p, &off );
+/*tbl*/ printf( " %s %d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp );
+ p->offset = temp; /* remember register number */
+ p->sclass = REGISTER; /* remember that it is a register */
+ }
+ else {
+ if( oalloc( p, &off ) ) cerror( "bad argument" );
+ }
+
+ }
+ fdefflag = 1;
+ }
+
+bccode(){ /* called just before the first executable statment */
+ /* by now, the automatics and register variables are allocated */
+ SETOFF( autooff, SZINT );
+ /* set aside store area offset */
+ p2bbeg( autooff, regvar );
+ reg_use = (reg_use > regvar ? regvar : reg_use);
+ }
+
+ejobcode( flag ){
+ /* called just before final exit */
+ /* flag is 1 if errors, 0 if none */
+ }
+
+aobeg(){
+ /* called before removing automatics from stab */
+ }
+
+aocode(p) struct symtab *p; {
+ /* called when automatic p removed from stab */
+ }
+
+aoend(){
+ /* called after removing all automatics from stab */
+ }
+
+defnam( p ) register struct symtab *p; {
+ /* define the current location as the name p->sname */
+
+ if( p->sclass == EXTDEF ){
+ printf( " .globl %s\n", exname( p->sname ) );
+ }
+ if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset );
+ else printf( "%s:\n", exname( p->sname ) );
+
+ }
+
+bycode( t, i ){
+ /* put byte i+1 in a string */
+
+ i &= 07;
+ if( t < 0 ){ /* end of the string */
+ if( i != 0 ) printf( "\n" );
+ }
+
+ else { /* stash byte t into string */
+ if( i == 0 ) printf( " .byte " );
+ else printf( "," );
+ printf( "0x%x", t );
+ if( i == 07 ) printf( "\n" );
+ }
+ }
+
+zecode( n ){
+ /* n integer words of zeros */
+ OFFSZ temp;
+ if( n <= 0 ) return;
+ printf( " .space %d\n", (SZINT/SZCHAR)*n );
+ temp = n;
+ inoff += temp*SZINT;
+ }
+
+fldal( t ) unsigned t; { /* return the alignment of field of type t */
+ uerror( "illegal field type" );
+ return( ALINT );
+ }
+
+fldty( p ) struct symtab *p; { /* fix up type of field p */
+ ;
+ }
+
+where(c){ /* print location of error */
+ /* c is either 'u', 'c', or 'w' */
+ /* GCOS version */
+ fprintf( stderr, "%s, line %d: ", ftitle, lineno );
+ }
+
+
+/* tbl - toreg() returns a pointer to a char string
+ which is the correct "register move" for the passed type
+ */
+struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] =
+ {
+ CHAR, "cvtbl",
+ SHORT, "cvtwl",
+ INT, "movl",
+ LONG, "movl",
+ FLOAT, "movf",
+ DOUBLE, "movd",
+ UCHAR, "movzbl",
+ USHORT, "movzwl",
+ UNSIGNED, "movl",
+ ULONG, "movl",
+ -1, ""
+ };
+
+char
+*toreg(type)
+ TWORD type;
+{
+ struct type_move *p;
+
+ for ( p=toreg_strs; p->fromtype > 0; p++)
+ if (p->fromtype == type) return(p->tostrng);
+
+ /* type not found, must be a pointer type */
+ return("movl");
+}
+/* tbl */
+
+
+main( argc, argv ) char *argv[]; {
+ return(mainp1( argc, argv ));
+ }
+
+struct sw heapsw[SWITSZ]; /* heap for switches */
+
+genswitch(p,n) register struct sw *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
+ */
+ register i;
+ register CONSZ j, range;
+ register dlab, swlab;
+
+ range = p[n].sval-p[1].sval;
+
+ if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */
+
+ swlab = getlab();
+ dlab = p->slab >= 0 ? p->slab : getlab();
+
+ /* already in r0 */
+ printf(" casel r0,$%ld,$%ld\n", p[1].sval, range);
+ printf("L%d:\n", swlab);
+ for( i=1,j=p[1].sval; i<=n; j++) {
+ printf(" .word L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab),
+ swlab);
+ }
+
+ if( p->slab >= 0 ) branch( dlab );
+ else printf("L%d:\n", dlab);
+ return;
+
+ }
+
+ if( n>8 ) { /* heap switch */
+
+ heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab();
+ makeheap(p, n, 1); /* build heap */
+
+ walkheap(1, n); /* produce code */
+
+ if( p->slab >= 0 )
+ branch( dlab );
+ else
+ printf("L%d:\n", dlab);
+ return;
+ }
+
+ /* debugging code */
+
+ /* out for the moment
+ if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) );
+ */
+
+ /* simple switch code */
+
+ for( i=1; i<=n; ++i ){
+ /* already in r0 */
+
+ printf( " cmpl r0,$" );
+ printf( CONFMT, p[i].sval );
+ printf( "\n jeql L%d\n", p[i].slab );
+ }
+
+ if( p->slab>=0 ) branch( p->slab );
+ }
+
+makeheap(p, m, n)
+register struct sw *p;
+{
+ register int q;
+
+ q = select(m);
+ heapsw[n] = p[q];
+ if( q>1 ) makeheap(p, q-1, 2*n);
+ if( q<m ) makeheap(p+q, m-q, 2*n+1);
+}
+
+select(m) {
+ register int l,i,k;
+
+ for(i=1; ; i*=2)
+ if( (i-1) > m ) break;
+ l = ((k = i/2 - 1) + 1)/2;
+ return( l + (m-k < l ? m-k : l));
+}
+
+walkheap(start, limit)
+{
+ int label;
+
+
+ if( start > limit ) return;
+ printf(" cmpl r0,$%d\n", heapsw[start].sval);
+ printf(" jeql L%d\n", heapsw[start].slab);
+ if( (2*start) > limit ) {
+ printf(" jbr L%d\n", heapsw[0].slab);
+ return;
+ }
+ if( (2*start+1) <= limit ) {
+ label = getlab();
+ printf(" jgtr L%d\n", label);
+ } else
+ printf(" jgtr L%d\n", heapsw[0].slab);
+ walkheap( 2*start, limit);
+ if( (2*start+1) <= limit ) {
+ printf("L%d:\n", label);
+ walkheap( 2*start+1, limit);
+ }
+}
diff --git a/usr.bin/pcc/arch/vax/local.c b/usr.bin/pcc/arch/vax/local.c
new file mode 100644
index 00000000000..82bc670eb6b
--- /dev/null
+++ b/usr.bin/pcc/arch/vax/local.c
@@ -0,0 +1,528 @@
+/* $Id: local.c,v 1.1 2007/09/15 18:12:30 otto Exp $ */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed or owned by Caldera
+ * International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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.
+ */
+
+# include "mfile1"
+
+/* this file contains code which is dependent on the target machine */
+
+NODE *
+cast( p, t ) register NODE *p; TWORD t; {
+ /* cast node p to type t */
+
+ p = buildtree( CAST, block( NAME, NIL, NIL, t, 0, (int)t ), p );
+ p->left->op = FREE;
+ p->op = FREE;
+ return( p->right );
+ }
+
+NODE *
+clocal(p) 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;
+ register o;
+ register m, ml;
+
+ switch( o = p->op ){
+
+ case NAME:
+ if( p->rval < 0 ) { /* already processed; ignore... */
+ return(p);
+ }
+ q = &stab[p->rval];
+ switch( q->sclass ){
+
+ case AUTO:
+ case PARAM:
+ /* fake up a structure reference */
+ r = block( REG, NIL, NIL, PTR+STRTY, 0, 0 );
+ r->lval = 0;
+ r->rval = (q->sclass==AUTO?STKREG:ARGREG);
+ p = stref( block( STREF, r, p, 0, 0, 0 ) );
+ break;
+
+ case ULABEL:
+ case LABEL:
+ case STATIC:
+ if( q->slevel == 0 ) break;
+ p->lval = 0;
+ p->rval = -q->offset;
+ break;
+
+ case REGISTER:
+ p->op = REG;
+ p->lval = 0;
+ p->rval = q->offset;
+ break;
+
+ }
+ break;
+
+ case PCONV:
+ /* do pointer conversions for char and longs */
+ ml = p->left->type;
+ if( ( ml==CHAR || ml==UCHAR || ml==SHORT || ml==USHORT ) && p->left->op != ICON ) break;
+
+ /* pointers all have the same representation; the type is inherited */
+
+ inherit:
+ p->left->type = p->type;
+ p->left->cdim = p->cdim;
+ p->left->csiz = p->csiz;
+ p->op = FREE;
+ return( p->left );
+
+ case SCONV:
+ m = (p->type == FLOAT || p->type == DOUBLE );
+ ml = (p->left->type == FLOAT || p->left->type == DOUBLE );
+ if( m != ml ) break;
+
+ /* now, look for conversions downwards */
+
+ m = p->type;
+ ml = p->left->type;
+ if( p->left->op == ICON ){ /* simulate the conversion here */
+ CONSZ val;
+ val = p->left->lval;
+ switch( m ){
+ case CHAR:
+ p->left->lval = (char) val;
+ break;
+ case UCHAR:
+ p->left->lval = val & 0XFF;
+ break;
+ case USHORT:
+ p->left->lval = val & 0XFFFFL;
+ break;
+ case SHORT:
+ p->left->lval = (short)val;
+ break;
+ case UNSIGNED:
+ p->left->lval = val & 0xFFFFFFFFL;
+ break;
+ case INT:
+ p->left->lval = (int)val;
+ break;
+ }
+ p->left->type = m;
+ }
+ else {
+ /* meaningful ones are conversion of int to char, int to short,
+ and short to char, and unsigned version of them */
+ if( m==CHAR || m==UCHAR ){
+ if( ml!=CHAR && ml!= UCHAR ) break;
+ }
+ else if( m==SHORT || m==USHORT ){
+ if( ml!=CHAR && ml!=UCHAR && ml!=SHORT && ml!=USHORT ) break;
+ }
+ }
+
+ /* clobber conversion */
+ if( tlen(p) == tlen(p->left) ) goto inherit;
+ p->op = FREE;
+ return( p->left ); /* conversion gets clobbered */
+
+ case PVCONV:
+ case PMCONV:
+ if( p->right->op != ICON ) cerror( "bad conversion", 0);
+ p->op = FREE;
+ return( buildtree( o==PMCONV?MUL:DIV, p->left, p->right ) );
+
+ case RS:
+ case ASG RS:
+ /* convert >> to << with negative shift count */
+ /* only if type of left operand is not unsigned */
+ if( ISUNSIGNED(p->left->type) ) break;
+ p->right = buildtree( UNARY MINUS, p->right, NIL );
+ if( p->op == RS ) p->op = LS;
+ else p->op = ASG LS;
+ break;
+
+ }
+
+ return(p);
+ }
+
+andable( p ) NODE *p; {
+ return(1); /* all names can have & taken on them */
+ }
+
+cendarg(){ /* at the end of the arguments of a ftn, set the automatic offset */
+ autooff = AUTOINIT;
+ }
+
+cisreg( t ) TWORD t; { /* is an automatic variable of type t OK for a register variable */
+
+ if( t==INT || t==UNSIGNED || t==LONG || t==ULONG /* tbl */
+ || t==CHAR || t==UCHAR || t==SHORT || t==USHORT /* tbl */
+ || ISPTR(t)) return(1); /* tbl */
+ return(0);
+ }
+
+NODE *
+offcon( off, t, d, s ) OFFSZ off; TWORD t; {
+
+ /* 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 */
+
+ register NODE *p;
+
+ /* t, d, and s are the type, dimension offset, and sizeoffset */
+ /* in general they are necessary for offcon, but not on H'well */
+
+ p = bcon(0);
+ p->lval = off/SZCHAR;
+ return(p);
+
+ }
+
+
+incode( p, sz ) register NODE *p; {
+
+ /* generate initialization code for assigning a constant c
+ to a field of width sz */
+ /* we assume that the proper alignment has been obtained */
+ /* inoff is updated to have the proper final value */
+ /* we also assume sz < SZINT */
+
+ inoff += sz;
+ if (sz>SZSHORT)
+ printf(" .long %d:%d\n", sz, p->lval);
+ else if (sz>SZCHAR)
+ printf(" .word %d:%d\n", sz, p->lval);
+ else
+ printf(" .byte %d:%d\n", sz, p->lval);
+ }
+
+fincode( d, sz ) double d; {
+ /* output code to initialize space of size sz to the value d */
+ /* the proper alignment has been obtained */
+ /* inoff is updated to have the proper final value */
+ /* on the target machine, write it out in octal! */
+
+
+ printf(" %s 0%c%.20e\n", sz == SZDOUBLE ? ".double" : ".float",
+ sz == SZDOUBLE ? 'd' : 'f', d);
+ inoff += sz;
+ }
+
+cinit( p, sz ) NODE *p; {
+ /* arrange for the initialization of p into a space of
+ size sz */
+ /* the proper alignment has been opbtained */
+ /* inoff is updated to have the proper final value */
+ ecode( p );
+ inoff += sz;
+ }
+
+vfdzero( n ){ /* define n bits of zeros in a vfd */
+ register i;
+
+ if( n <= 0 ) return;
+
+ inoff += n;
+ i = n;
+ while (i>=SZCHAR) {
+ printf(" .byte 0\n");
+ i -= SZCHAR;
+ }
+ if (i) printf(" .byte %d:0\n", i);
+ }
+
+
+char *
+exname( p ) char *p; {
+ /* make a name look like an external name in the local machine */
+
+ static char text[NCHNAM+1];
+
+ register i;
+
+ text[0] = '_';
+ for( i=1; *p&&i<NCHNAM; ++i ){
+ text[i] = *p++;
+ }
+
+ text[i] = '\0';
+ text[NCHNAM] = '\0'; /* truncate */
+
+ return( text );
+ }
+
+ctype( type ){ /* map types which are not defined on the local machine */
+ switch( BTYPE(type) ){
+
+ case LONG:
+ MODTYPE(type,INT);
+ break;
+
+ case ULONG:
+ MODTYPE(type,UNSIGNED);
+ }
+ return( type );
+ }
+
+noinit( t ) { /* curid is a variable which is defined but
+ is not initialized (and not a function );
+ This routine returns the stroage class for an uninitialized declaration */
+
+ return(EXTERN);
+
+ }
+
+commdec( id ){ /* make a common declaration for id, if reasonable */
+ register struct symtab *q;
+ OFFSZ off, tsize();
+
+ q = &stab[id];
+ printf( " .comm %s,", exname( q->sname ) );
+ off = tsize( q->stype, q->dimoff, q->sizoff );
+ printf( CONFMT, off/SZCHAR );
+ printf( "\n" );
+ }
+
+isitlong( cb, ce ){ /* is lastcon to be long or short */
+ /* cb is the first character of the representation, ce the last */
+
+ if( ce == 'l' || ce == 'L' ||
+ lastcon >= (1L << (SZINT-1) ) ) return (1);
+ return(0);
+ }
+
+
+isitfloat( s ) char *s; {
+ double atof();
+ dcon = atof(s);
+ return( FCON );
+ }
+
+ecode( p ) NODE *p; {
+
+ /* walk the tree and write out the nodes.. */
+
+ if( nerrors ) return;
+ p2tree( p );
+ p2compile( p );
+ }
+
+#include "a.out.h"
+int ddebug;
+int gdebug;
+
+
+outstab(p)
+struct symtab *p; {
+ register TWORD ptype;
+ register char *pname;
+ register char pclass;
+ register int poffset;
+
+ if (!gdebug) return;
+
+ ptype = p->stype;
+ pname = p->sname;
+ pclass = p->sclass;
+ poffset = p->offset;
+
+ if (ISFTN(ptype)) {
+ return;
+ }
+
+ switch (pclass) {
+
+ case AUTO:
+ pstab(pname, N_LSYM);
+ printf("0,%d,%d\n", ptype, (-poffset)/SZCHAR);
+ poffs(p);
+ return;
+
+ case EXTDEF:
+ case EXTERN:
+ pstab(pname, N_GSYM);
+ printf("0,%d,0\n", ptype);
+ poffs(p);
+ return;
+
+ case STATIC:
+ pstab(pname, N_STSYM);
+ if (p->slevel > 1) {
+ printf("0,%d,L%d\n", ptype, poffset);
+ } else {
+ printf("0,%d,%s\n", ptype, exname(pname));
+ }
+ poffs(p);
+ return;
+
+ case REGISTER:
+ pstab(pname, N_RSYM);
+ printf("0,%d,%d\n", ptype, poffset);
+ poffs(p);
+ return;
+
+ case MOS:
+ case MOU:
+ pstab(pname, N_SSYM);
+ printf("0,%d,%d\n", ptype, poffset/SZCHAR);
+ poffs(p);
+ return;
+
+ case PARAM:
+ /* parameter stab entries are processed in dclargs() */
+ return;
+
+ default:
+ if (ddebug) printf(" No .stab for %.8s\n", pname);
+ }
+}
+
+pstab(name, type)
+char *name;
+int type; {
+ register int i;
+ register char c;
+ if (!gdebug) return;
+ printf(" .stab ");
+ for(i=0; i<8; i++)
+ if (c = name[i]) printf("'%c,", c);
+ else printf("0,");
+ printf("0%o,", type);
+}
+
+poffs(p)
+register struct symtab *p; {
+ int s;
+ if (!gdebug) return;
+ if ((s = dimtab[p->sizoff]/SZCHAR) > 1) {
+ pstab(p->sname, N_LENG);
+ printf("1,0,%d\n", s);
+ }
+}
+
+char NULLNAME[8];
+int labelno;
+int fdefflag;
+
+psline() {
+ static int lastlineno;
+ register char *cp, *cq;
+ register int i;
+
+ if (!gdebug) return;
+
+ cq = ititle;
+ cp = ftitle;
+
+ while ( *cq ) if ( *cp++ != *cq++ ) goto neq;
+ if ( *cp == '\0' ) goto eq;
+
+neq: for (i=0; i<100; i++)
+ ititle[i] = '\0';
+ cp = ftitle;
+ cq = ititle;
+ while ( *cp )
+ *cq++ = *cp++;
+ *cq = '\0';
+ *--cq = '\0';
+ for ( cp = ititle+1; *(cp-1); cp += 8 ) {
+ pstab(cp, N_SOL);
+ if (gdebug) printf("0,0,LL%d\n", labelno);
+ }
+ *cq = '"';
+ printf("LL%d:\n", labelno++);
+
+eq: if (lineno == lastlineno) return;
+ lastlineno = lineno;
+
+ if (fdefflag) {
+ pstab(NULLNAME, N_SLINE);
+ printf("0,%d,LL%d\n", lineno, labelno);
+ printf("LL%d:\n", labelno++);
+ }
+ }
+
+plcstab(level) {
+ if (!gdebug) return;
+ pstab(NULLNAME, N_LBRAC);
+ printf("0,%d,LL%d\n", level, labelno);
+ printf("LL%d:\n", labelno++);
+ }
+
+prcstab(level) {
+ if (!gdebug) return;
+ pstab(NULLNAME, N_RBRAC);
+ printf("0,%d,LL%d\n", level, labelno);
+ printf("LL%d:\n", labelno++);
+ }
+
+pfstab(sname)
+char *sname; {
+ if (!gdebug) return;
+ pstab(sname, N_FUN);
+ printf("0,%d,_%.7s\n", lineno, sname);
+}
+
+#ifndef ONEPASS
+tlen(p) NODE *p;
+{
+ switch(p->type) {
+ case CHAR:
+ case UCHAR:
+ return(1);
+
+ case SHORT:
+ case USHORT:
+ return(2);
+
+ case DOUBLE:
+ return(8);
+
+ default:
+ return(4);
+ }
+ }
+#endif
diff --git a/usr.bin/pcc/arch/vax/local2.c b/usr.bin/pcc/arch/vax/local2.c
new file mode 100644
index 00000000000..0aa8e2b0e9e
--- /dev/null
+++ b/usr.bin/pcc/arch/vax/local2.c
@@ -0,0 +1,923 @@
+/* $Id: local2.c,v 1.1 2007/09/15 18:12:30 otto Exp $ */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed or owned by Caldera
+ * International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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.
+ */
+
+# include "mfile2"
+# include "ctype.h"
+/* a lot of the machine dependent parts of the second pass */
+
+# define BITMASK(n) ((1L<<n)-1)
+
+where(c){
+ fprintf( stderr, "%s, line %d: ", filename, lineno );
+ }
+
+lineid( l, fn ) char *fn; {
+ /* identify line l and file fn */
+ printf( "# line %d, file %s\n", l, fn );
+ }
+
+eobl2(){
+ OFFSZ spoff; /* offset from stack pointer */
+
+ spoff = maxoff;
+ if( spoff >= AUTOINIT ) spoff -= AUTOINIT;
+ spoff /= SZCHAR;
+ SETOFF(spoff,4);
+ printf( " .set .F%d,%Ld\n", ftnno, spoff );
+ maxargs = -1;
+ }
+
+struct hoptab { int opmask; char * opstring; } ioptab[] = {
+
+ ASG PLUS, "add",
+ ASG MINUS, "sub",
+ ASG MUL, "mul",
+ ASG DIV, "div",
+ ASG OR, "bis",
+ ASG ER, "xor",
+ ASG AND, "bic",
+ PLUS, "add",
+ MINUS, "sub",
+ MUL, "mul",
+ DIV, "div",
+ OR, "bis",
+ ER, "xor",
+ AND, "bic",
+ -1, "" };
+
+hopcode( f, o ){
+ /* output the appropriate string from the above table */
+
+ register struct hoptab *q;
+
+ for( q = ioptab; q->opmask>=0; ++q ){
+ if( q->opmask == o ){
+ printf( "%s", q->opstring );
+/* tbl
+ if( f == 'F' ) printf( "e" );
+ else if( f == 'D' ) printf( "d" );
+ tbl */
+/* tbl */
+ switch( f ) {
+ case 'L':
+ case 'W':
+ case 'B':
+ case 'D':
+ case 'F':
+ printf("%c", tolower(f));
+ break;
+
+ }
+/* tbl */
+ return;
+ }
+ }
+ cerror( "no hoptab for %s", opst[o] );
+ }
+
+char *
+rnames[] = { /* keyed to register number tokens */
+
+ "r0", "r1",
+ "r2", "r3", "r4", "r5",
+ "r6", "r7", "r8", "r9", "r10", "r11",
+ "ap", "fp", "sp", "pc",
+
+ };
+
+int rstatus[] = {
+ SAREG|STAREG, SAREG|STAREG,
+ SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
+ SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
+ SAREG, SAREG, SAREG, SAREG,
+
+ };
+
+tlen(p) NODE *p;
+{
+ switch(p->type) {
+ case CHAR:
+ case UCHAR:
+ return(1);
+
+ case SHORT:
+ case USHORT:
+ return(2);
+
+ case DOUBLE:
+ return(8);
+
+ default:
+ return(4);
+ }
+}
+
+mixtypes(p, q) NODE *p, *q;
+{
+ register tp, tq;
+
+ tp = p->type;
+ tq = q->type;
+
+ return( (tp==FLOAT || tp==DOUBLE) !=
+ (tq==FLOAT || tq==DOUBLE) );
+}
+
+prtype(n) NODE *n;
+{
+ switch (n->type)
+ {
+ case DOUBLE:
+ printf("d");
+ return;
+
+ case FLOAT:
+ printf("f");
+ return;
+
+ case LONG:
+ case ULONG:
+ case INT:
+ case UNSIGNED:
+ printf("l");
+ return;
+
+ case SHORT:
+ case USHORT:
+ printf("w");
+ return;
+
+ case CHAR:
+ case UCHAR:
+ printf("b");
+ return;
+
+ default:
+ if ( !ISPTR( n->type ) ) cerror("zzzcode- bad type");
+ else {
+ printf("l");
+ return;
+ }
+ }
+}
+
+zzzcode( p, c ) register NODE *p; {
+ register m;
+ CONSZ val;
+ switch( c ){
+
+ case 'N': /* logical ops, turned into 0-1 */
+ /* use register given by register 1 */
+ cbgen( 0, m=getlab(), 'I' );
+ deflab( p->label );
+ printf( " clrl %s\n", rnames[getlr( p, '1' )->rval] );
+ deflab( m );
+ return;
+
+ case 'I':
+ case 'P':
+ cbgen( p->op, p->label, c );
+ return;
+
+ case 'A':
+ {
+ register NODE *l, *r;
+
+ if (xdebug) eprint(p, 0, &val, &val);
+ r = getlr(p, 'R');
+ if (optype(p->op) == LTYPE || p->op == UNARY MUL)
+ {
+ l = resc;
+ l->type = (r->type==FLOAT || r->type==DOUBLE ? DOUBLE : INT);
+ }
+ else
+ l = getlr(p, 'L');
+ if (r->op == ICON && r->name[0] == '\0')
+ {
+ if (r->lval == 0)
+ {
+ printf("clr");
+ prtype(l);
+ printf(" ");
+ adrput(l);
+ return;
+ }
+ if (r->lval < 0 && r->lval >= -63)
+ {
+ printf("mneg");
+ prtype(l);
+ r->lval = -r->lval;
+ goto ops;
+ }
+ r->type = (r->lval < 0 ?
+ (r->lval >= -128 ? CHAR
+ : (r->lval >= -32768 ? SHORT
+ : INT )) : r->type);
+ r->type = (r->lval >= 0 ?
+ (r->lval <= 63 ? INT
+ : ( r->lval <= 127 ? CHAR
+ : (r->lval <= 255 ? UCHAR
+ : (r->lval <= 32767 ? SHORT
+ : (r->lval <= 65535 ? USHORT
+ : INT ))))) : r->type );
+ }
+ if (l->op == REG && l->type != FLOAT && l->type != DOUBLE)
+ l->type = INT;
+ if (!mixtypes(l,r))
+ {
+ if (tlen(l) == tlen(r))
+ {
+ printf("mov");
+ prtype(l);
+ goto ops;
+ }
+ else if (tlen(l) > tlen(r) && ISUNSIGNED(r->type))
+ {
+ printf("movz");
+ }
+ else
+ {
+ printf("cvt");
+ }
+ }
+ else
+ {
+ printf("cvt");
+ }
+ prtype(r);
+ prtype(l);
+ ops:
+ printf(" ");
+ adrput(r);
+ printf(",");
+ adrput(l);
+ return;
+ }
+
+ case 'C': /* num words pushed on arg stack */
+ {
+ extern int gc_numbytes;
+ extern int xdebug;
+
+ if (xdebug) printf("->%d<-",gc_numbytes);
+
+ printf("$%d", gc_numbytes/(SZLONG/SZCHAR) );
+ return;
+ }
+
+ case 'D': /* INCR and DECR */
+ zzzcode(p->left, 'A');
+ printf("\n ");
+
+ case 'E': /* INCR and DECR, FOREFF */
+ if (p->right->lval == 1)
+ {
+ printf("%s", (p->op == INCR ? "inc" : "dec") );
+ prtype(p->left);
+ printf(" ");
+ adrput(p->left);
+ return;
+ }
+ printf("%s", (p->op == INCR ? "add" : "sub") );
+ prtype(p->left);
+ printf("2 ");
+ adrput(p->right);
+ printf(",");
+ adrput(p->left);
+ return;
+
+ case 'F': /* register type of right operand */
+ {
+ register NODE *n;
+ extern int xdebug;
+ register int ty;
+
+ n = getlr( p, 'R' );
+ ty = n->type;
+
+ if (xdebug) printf("->%d<-", ty);
+
+ if ( ty==DOUBLE) printf("d");
+ else if ( ty==FLOAT ) printf("f");
+ else printf("l");
+ return;
+ }
+
+ case 'L': /* type of left operand */
+ case 'R': /* type of right operand */
+ {
+ register NODE *n;
+ extern int xdebug;
+
+ n = getlr ( p, c);
+ if (xdebug) printf("->%d<-", n->type);
+
+ prtype(n);
+ return;
+ }
+
+ case 'Z': /* complement mask for bit instr */
+ printf("$%Ld", ~p->right->lval);
+ return;
+
+ case 'U': /* 32 - n, for unsigned right shifts */
+ printf("$%d", 32 - p->right->lval );
+ return;
+
+ case 'T': /* rounded structure length for arguments */
+ {
+ int size;
+
+ size = p->stsize;
+ SETOFF( size, 4);
+ printf("$%d", size);
+ return;
+ }
+
+ case 'S': /* structure assignment */
+ {
+ register NODE *l, *r;
+ register size;
+
+ if( p->op == STASG ){
+ l = p->left;
+ r = p->right;
+
+ }
+ else if( p->op == STARG ){ /* store an arg into a temporary */
+ l = getlr( p, '3' );
+ r = p->left;
+ }
+ else cerror( "STASG bad" );
+
+ if( r->op == ICON ) r->op = NAME;
+ else if( r->op == REG ) r->op = OREG;
+ else if( r->op != OREG ) cerror( "STASG-r" );
+
+ size = p->stsize;
+
+ if( size <= 0 || size > 65535 )
+ cerror("structure size <0=0 or >65535");
+
+ switch(size) {
+ case 1:
+ printf(" movb ");
+ break;
+ case 2:
+ printf(" movw ");
+ break;
+ case 4:
+ printf(" movl ");
+ break;
+ case 8:
+ printf(" movq ");
+ break;
+ default:
+ printf(" movc3 $%d,", size);
+ break;
+ }
+ adrput(r);
+ printf(",");
+ adrput(l);
+ printf("\n");
+
+ if( r->op == NAME ) r->op = ICON;
+ else if( r->op == OREG ) r->op = REG;
+
+ }
+ break;
+
+ default:
+ cerror( "illegal zzzcode" );
+ }
+ }
+
+rmove( rt, rs, t ){
+ printf( " %s %s,%s\n",
+ (t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")),
+ rnames[rs], rnames[rt] );
+ }
+
+struct respref
+respref[] = {
+ INTAREG|INTBREG, INTAREG|INTBREG,
+ INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
+ INTEMP, INTEMP,
+ FORARG, FORARG,
+ INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
+ 0, 0 };
+
+setregs(){ /* set up temporary registers */
+ fregs = 6; /* tbl- 6 free regs on VAX (0-5) */
+ ;
+ }
+
+szty(t){ /* size, in registers, needed to hold thing of type t */
+ return( (t==DOUBLE||t==FLOAT) ? 2 : 1 );
+ }
+
+rewfld( p ) NODE *p; {
+ return(1);
+ }
+
+callreg(p) NODE *p; {
+ return( R0 );
+ }
+
+base( p ) register NODE *p; {
+ register int o = p->op;
+
+ if( (o==ICON && p->name[0] != '\0')) return( 100 ); /* ie no base reg */
+ if( o==REG ) return( p->rval );
+ if( (o==PLUS || o==MINUS) && p->left->op == REG && p->right->op==ICON)
+ return( p->left->rval );
+ if( o==OREG && !R2TEST(p->rval) && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) )
+ return( p->rval + 0200*1 );
+ if( o==INCR && p->left->op==REG ) return( p->left->rval + 0200*2 );
+ if( o==ASG MINUS && p->left->op==REG) return( p->left->rval + 0200*4 );
+ if( o==UNARY MUL && p->left->op==INCR && p->left->left->op==REG
+ && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) )
+ return( p->left->left->rval + 0200*(1+2) );
+ return( -1 );
+ }
+
+offset( p, tyl ) register NODE *p; int tyl; {
+
+ if( tyl==1 && p->op==REG && (p->type==INT || p->type==UNSIGNED) ) return( p->rval );
+ if( (p->op==LS && p->left->op==REG && (p->left->type==INT || p->left->type==UNSIGNED) &&
+ (p->right->op==ICON && p->right->name[0]=='\0')
+ && (1<<p->right->lval)==tyl))
+ return( p->left->rval );
+ return( -1 );
+ }
+
+makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
+ register NODE *t;
+ register int i;
+ NODE *f;
+
+ p->op = OREG;
+ f = p->left; /* have to free this subtree later */
+
+ /* init base */
+ switch (q->op) {
+ case ICON:
+ case REG:
+ case OREG:
+ t = q;
+ break;
+
+ case MINUS:
+ q->right->lval = -q->right->lval;
+ case PLUS:
+ t = q->right;
+ break;
+
+ case INCR:
+ case ASG MINUS:
+ t = q->left;
+ break;
+
+ case UNARY MUL:
+ t = q->left->left;
+ break;
+
+ default:
+ cerror("illegal makeor2");
+ }
+
+ p->lval = t->lval;
+ for(i=0; i<NCHNAM; ++i)
+ p->name[i] = t->name[i];
+
+ /* init offset */
+ p->rval = R2PACK( (b & 0177), o, (b>>7) );
+
+ tfree(f);
+ return;
+ }
+
+canaddr( p ) NODE *p; {
+ register int o = p->op;
+
+ if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->left)) ) return(1);
+ return(0);
+ }
+
+shltype( o, p ) register NODE *p; {
+ return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->left)) );
+ }
+
+flshape( p ) register NODE *p; {
+ return( p->op == REG || p->op == NAME || p->op == ICON ||
+ (p->op == OREG && (!R2TEST(p->rval) || tlen(p) == 1)) );
+ }
+
+shtemp( p ) register NODE *p; {
+ if( p->op == STARG ) p = p->left;
+ return( p->op==NAME || p->op ==ICON || p->op == OREG || (p->op==UNARY MUL && shumul(p->left)) );
+ }
+
+shumul( p ) register NODE *p; {
+ register o;
+ extern int xdebug;
+
+ if (xdebug) {
+ printf("\nshumul:op=%d,lop=%d,rop=%d", p->op, p->left->op, p->right->op);
+ printf(" prname=%s,plty=%d, prlval=%D\n", p->right->name, p->left->type, p->right->lval);
+ }
+
+
+ o = p->op;
+ if( o == NAME || (o == OREG && !R2TEST(p->rval)) || o == ICON ) return( STARNM );
+
+ if( ( o == INCR || o == ASG MINUS ) &&
+ ( p->left->op == REG && p->right->op == ICON ) &&
+ p->right->name[0] == '\0' )
+ {
+ switch (p->left->type)
+ {
+ case CHAR|PTR:
+ case UCHAR|PTR:
+ o = 1;
+ break;
+
+ case SHORT|PTR:
+ case USHORT|PTR:
+ o = 2;
+ break;
+
+ case INT|PTR:
+ case UNSIGNED|PTR:
+ case LONG|PTR:
+ case ULONG|PTR:
+ case FLOAT|PTR:
+ o = 4;
+ break;
+
+ case DOUBLE|PTR:
+ o = 8;
+ break;
+
+ default:
+ if ( ISPTR(p->left->type) ) {
+ o = 4;
+ break;
+ }
+ else return(0);
+ }
+ return( p->right->lval == o ? STARREG : 0);
+ }
+
+ return( 0 );
+ }
+
+adrcon( val ) CONSZ val; {
+ printf( "$" );
+ printf( CONFMT, val );
+ }
+
+conput( p ) register NODE *p; {
+ switch( p->op ){
+
+ case ICON:
+ acon( p );
+ return;
+
+ case REG:
+ printf( "%s", rnames[p->rval] );
+ return;
+
+ default:
+ cerror( "illegal conput" );
+ }
+ }
+
+insput( p ) register NODE *p; {
+ cerror( "insput" );
+ }
+
+upput( p ) register NODE *p; {
+ cerror( "upput" );
+ }
+
+adrput( p ) register NODE *p; {
+ register int r;
+ /* output an address, with offsets, from p */
+
+ if( p->op == FLD ){
+ p = p->left;
+ }
+ switch( p->op ){
+
+ case NAME:
+ acon( p );
+ return;
+
+ case ICON:
+ /* addressable value of the constant */
+ printf( "$" );
+ acon( p );
+ return;
+
+ case REG:
+ printf( "%s", rnames[p->rval] );
+ return;
+
+ case OREG:
+ r = p->rval;
+ if( R2TEST(r) ){ /* double indexing */
+ register int flags;
+
+ flags = R2UPK3(r);
+ if( flags & 1 ) printf("*");
+ if( flags & 4 ) printf("-");
+ if( p->lval != 0 || p->name[0] != '\0' ) acon(p);
+ if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] );
+ if( flags & 2 ) printf("+");
+ printf( "[%s]", rnames[R2UPK2(r)] );
+ return;
+ }
+ if( r == AP ){ /* in the argument region */
+ if( p->lval <= 0 || p->name[0] != '\0' ) werror( "bad arg temp" );
+ printf( CONFMT, p->lval );
+ printf( "(ap)" );
+ return;
+ }
+ if( p->lval != 0 || p->name[0] != '\0') acon( p );
+ printf( "(%s)", rnames[p->rval] );
+ return;
+
+ case UNARY MUL:
+ /* STARNM or STARREG found */
+ if( tshape(p, STARNM) ) {
+ printf( "*" );
+ adrput( p->left);
+ }
+ else { /* STARREG - really auto inc or dec */
+ register NODE *q;
+
+/* tbl
+ p = p->left;
+ p->left->op = OREG;
+ if( p->op == INCR ) {
+ adrput( p->left );
+ printf( "+" );
+ }
+ else {
+ printf( "-" );
+ adrput( p->left );
+ }
+ tbl */
+ printf("%c(%s)%c", (p->left->op==INCR ? '\0' : '-'),
+ rnames[p->left->left->rval],
+ (p->left->op==INCR ? '+' : '\0') );
+ p->op = OREG;
+ p->rval = p->left->left->rval;
+ q = p->left;
+ p->lval = (p->left->op == INCR ? -p->left->right->lval : 0);
+ p->name[0] = '\0';
+ tfree(q);
+ }
+ return;
+
+ default:
+ cerror( "illegal address" );
+ return;
+
+ }
+
+ }
+
+acon( p ) register NODE *p; { /* print out a constant */
+
+ if( p->name[0] == '\0' ){
+ printf( CONFMT, p->lval);
+ }
+ else if( p->lval == 0 ) {
+ printf( "%.8s", p->name );
+ }
+ else {
+ printf( "%.8s+", p->name );
+ printf( CONFMT, p->lval );
+ }
+ }
+
+/*
+aacon( p ) register NODE *p; { /* print out a constant */
+/*
+
+ if( p->name[0] == '\0' ){
+ printf( CONFMT, p->lval);
+ return( 0 );
+ }
+ else if( p->lval == 0 ) {
+ printf( "$%.8s", p->name );
+ return( 1 );
+ }
+ else {
+ printf( "$(" );
+ printf( CONFMT, p->lval );
+ printf( "+" );
+ printf( "%.8s)", p->name );
+ return(1);
+ }
+ }
+ */
+
+genscall( p, cookie ) register NODE *p; {
+ /* structure valued call */
+ return( gencall( p, cookie ) );
+ }
+
+/* tbl */
+int gc_numbytes;
+/* tbl */
+
+gencall( p, cookie ) register NODE *p; {
+ /* generate the call given by p */
+ register NODE *p1, *ptemp;
+ register temp, temp1;
+ register m;
+
+ if( p->right ) temp = argsize( p->right );
+ else temp = 0;
+
+ if( p->op == STCALL || p->op == UNARY STCALL ){
+ /* set aside room for structure return */
+
+ if( p->stsize > temp ) temp1 = p->stsize;
+ else temp1 = temp;
+ }
+
+ if( temp > maxargs ) maxargs = temp;
+ SETOFF(temp1,4);
+
+ if( p->right ){ /* make temp node, put offset in, and generate args */
+ ptemp = talloc();
+ ptemp->op = OREG;
+ ptemp->lval = -1;
+ ptemp->rval = SP;
+ ptemp->name[0] = '\0';
+ ptemp->rall = NOPREF;
+ ptemp->su = 0;
+ genargs( p->right, ptemp );
+ ptemp->op = FREE;
+ }
+
+ p1 = p->left;
+ if( p1->op != ICON ){
+ if( p1->op != REG ){
+ if( p1->op != OREG || R2TEST(p1->rval) ){
+ if( p1->op != NAME ){
+ order( p1, INAREG );
+ }
+ }
+ }
+ }
+
+/*
+ if( p1->op == REG && p->rval == R5 ){
+ cerror( "call register overwrite" );
+ }
+ */
+/* tbl
+ setup gc_numbytes so reference to ZC works */
+
+ gc_numbytes = temp;
+/* tbl */
+
+ p->op = UNARY CALL;
+ m = match( p, INTAREG|INTBREG );
+/* tbl
+ switch( temp ) {
+ case 0:
+ break;
+ case 2:
+ printf( " tst (sp)+\n" );
+ break;
+ case 4:
+ printf( " cmp (sp)+,(sp)+\n" );
+ break;
+ default:
+ printf( " add $%d,sp\n", temp);
+ }
+ tbl */
+ return(m != MDONE);
+ }
+
+/* tbl */
+char *
+ccbranches[] = {
+ " jeql L%d\n",
+ " jneq L%d\n",
+ " jleq L%d\n",
+ " jlss L%d\n",
+ " jgeq L%d\n",
+ " jgtr L%d\n",
+ " jlequ L%d\n",
+ " jlssu L%d\n",
+ " jgequ L%d\n",
+ " jgtru L%d\n",
+ };
+/* tbl */
+
+cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */
+
+/* tbl */
+ if( o == 0 ) printf( " jbr L%d\n", lab );
+/* tbl */
+ else {
+ if( o > UGT ) cerror( "bad conditional branch: %s", opst[o] );
+ printf( ccbranches[o-EQ], lab );
+ }
+ }
+
+nextcook( p, cookie ) NODE *p; {
+ /* we have failed to match p with cookie; try another */
+ if( cookie == FORREW ) return( 0 ); /* hopeless! */
+ if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
+ if( !(cookie&INTEMP) && asgop(p->op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
+ return( FORREW );
+ }
+
+lastchance( p, cook ) NODE *p; {
+ /* forget it! */
+ return(0);
+ }
+
+optim2( p ) register NODE *p; {
+ /* do local tree transformations and optimizations */
+
+ register NODE *r;
+
+ switch( p->op ) {
+
+ case AND:
+ /* commute L and R to eliminate compliments and constants */
+ if( (p->left->op==ICON&&p->left->name[0]==0) || p->left->op==COMPL ) {
+ r = p->left;
+ p->left = p->right;
+ p->right = r;
+ }
+ case ASG AND:
+ /* change meaning of AND to ~R&L - bic on pdp11 */
+ r = p->right;
+ if( r->op==ICON && r->name[0]==0 ) { /* compliment constant */
+ r->lval = ~r->lval;
+ }
+ else if( r->op==COMPL ) { /* ~~A => A */
+ r->op = FREE;
+ p->right = r->left;
+ }
+ else { /* insert complement node */
+ p->right = talloc();
+ p->right->op = COMPL;
+ p->right->rall = NOPREF;
+ p->right->type = r->type;
+ p->right->left = r;
+ p->right->right = NULL;
+ }
+ break;
+
+ }
+ }
+
+
+# ifndef ONEPASS
+main( argc, argv ) char *argv[]; {
+ return( mainp2( argc, argv ) );
+ }
+# endif
diff --git a/usr.bin/pcc/arch/vax/macdefs.h b/usr.bin/pcc/arch/vax/macdefs.h
new file mode 100644
index 00000000000..095e55ad910
--- /dev/null
+++ b/usr.bin/pcc/arch/vax/macdefs.h
@@ -0,0 +1,155 @@
+/* $Id: macdefs.h,v 1.1 2007/09/15 18:12:30 otto Exp $ */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed or owned by Caldera
+ * International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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.
+ */
+
+# define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24);
+
+# define ARGINIT 32
+# define AUTOINIT 0
+# define SZCHAR 8
+# define SZINT 32
+# define SZFLOAT 32
+# define SZDOUBLE 64
+# define SZLONG 32
+# define SZSHORT 16
+# define SZPOINT 32
+# define ALCHAR 8
+# define ALINT 32
+# define ALFLOAT 32
+# define ALDOUBLE 32
+# define ALLONG 32
+# define ALSHORT 16
+# define ALPOINT 32
+# define ALSTRUCT 8
+# define ALSTACK 32
+
+/* size in which constants are converted */
+/* should be long if feasable */
+
+# define CONSZ long
+# define CONFMT "%Ld"
+
+/* size in which offsets are kept
+/* should be large enough to cover address space in bits
+*/
+
+# define OFFSZ long
+
+/* character set macro */
+
+# define CCTRANS(x) x
+
+/* register cookie for stack poINTer */
+
+# define STKREG 13
+# define ARGREG 12
+
+/* maximum and minimum register variables */
+
+# define MAXRVAR 11
+# define MINRVAR 6
+
+ /* various standard pieces of code are used */
+# define STDPRTREE
+# define LABFMT "L%d"
+
+/* show stack grows negatively */
+#define BACKAUTO
+#define BACKTEMP
+
+/* show field hardware support on VAX */
+#define FIELDOPS
+
+/* bytes are numbered from right to left */
+#define RTOLBYTES
+
+/* we want prtree included */
+# define STDPRTREE
+# ifndef FORT
+# define ONEPASS
+#endif
+
+# define ENUMSIZE(high,low) INT
+
+/* VAX-11/780 Registers */
+
+ /* scratch registers */
+# define R0 0
+# define R1 1
+# define R2 2
+# define R3 3
+# define R4 4
+# define R5 5
+
+ /* register variables */
+# define R6 6
+# define R7 7
+# define R8 8
+# define R9 9
+# define R10 10
+# define R11 11
+
+ /* special purpose */
+# define AP 12 /* argument pointer */
+# define FP 13 /* frame pointer */
+# define SP 14 /* stack pointer */
+# define PC 15 /* program counter */
+
+ /* floating registers */
+
+ /* there are no floating point registers on the VAX */
+
+extern int fregs;
+extern int maxargs;
+
+# define BYTEOFF(x) ((x)&03)
+# define wdal(k) (BYTEOFF(k)==0)
+# define BITOOR(x) ((x)>>3) /* bit offset to oreg offset */
+
+# define REGSZ 16
+
+# define TMPREG FP
+
+# define R2REGS /* permit double indexing */
+
+# define STOARG(p) /* just evaluate the arguments, and be done with it... */
+# define STOFARG(p)
+# define STOSTARG(p)
+# define genfcall(a,b) gencall(a,b)
+
+# define NESTCALL
+
+# define MYREADER(p) walkf(p, optim2)
+int optim2();
+# define special(a, b) 0
diff --git a/usr.bin/pcc/arch/vax/order.c b/usr.bin/pcc/arch/vax/order.c
new file mode 100644
index 00000000000..b1f1006adcd
--- /dev/null
+++ b/usr.bin/pcc/arch/vax/order.c
@@ -0,0 +1,533 @@
+/* $Id: order.c,v 1.1 2007/09/15 18:12:30 otto Exp $ */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed or owned by Caldera
+ * International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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.
+ */
+
+# include "mfile2"
+
+int maxargs = { -1 };
+
+stoasg( p, o ) register NODE *p; {
+ /* should the assignment op p be stored,
+ given that it lies as the right operand of o
+ (or the left, if o==UNARY MUL) */
+/*
+ if( p->op == INCR || p->op == DECR ) return;
+ if( o==UNARY MUL && p->left->op == REG && !isbreg(p->left->rval) ) SETSTO(p,INAREG);
+ */
+ }
+
+deltest( p ) register NODE *p; {
+ /* should we delay the INCR or DECR operation p */
+ p = p->left;
+ return( p->op == REG || p->op == NAME || p->op == OREG );
+ }
+
+autoincr( p ) NODE *p; {
+ register NODE *q = p->left, *r;
+
+ if( q->op == INCR && (r=q->left)->op == REG &&
+ ISPTR(q->type) && p->type == DECREF(q->type) &&
+ tlen(p) == q->right->lval ) return(1);
+
+ return(0);
+ }
+
+mkadrs(p) register NODE *p; {
+ register o;
+
+ o = p->op;
+
+ if( asgop(o) ){
+ if( p->left->su >= p->right->su ){
+ if( p->left->op == UNARY MUL ){
+ SETSTO( p->left->left, INTEMP );
+ }
+ else if( p->left->op == FLD && p->left->left->op == UNARY MUL ){
+ SETSTO( p->left->left->left, INTEMP );
+ }
+ else { /* should be only structure assignment */
+ SETSTO( p->left, INTEMP );
+ }
+ }
+ else SETSTO( p->right, INTEMP );
+ }
+ else {
+ if( p->left->su > p->right->su ){
+ SETSTO( p->left, INTEMP );
+ }
+ else {
+ SETSTO( p->right, INTEMP );
+ }
+ }
+ }
+
+notoff( t, r, off, cp) CONSZ off; char *cp; {
+ /* 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 */
+
+/* if( r == R0 ) return( 1 ); /* NO */
+ return(0); /* YES */
+ }
+
+# define max(x,y) ((x)<(y)?(y):(x))
+
+sucomp( p ) register NODE *p; {
+
+ /* set the su field in the node to the sethi-ullman
+ number, or local equivalent */
+
+ register o, ty, sul, sur, r;
+
+ o = p->op;
+ ty = optype( o );
+ p->su = szty( p->type ); /* 2 for float or double, else 1 */;
+
+ if( ty == LTYPE ){
+ if( o == OREG ){
+ r = p->rval;
+ /* oreg cost is (worst case) 1 + number of temp registers used */
+ if( R2TEST(r) ){
+ if( R2UPK1(r)!=100 && istreg(R2UPK1(r)) ) ++p->su;
+ if( istreg(R2UPK2(r)) ) ++p->su;
+ }
+ else {
+ if( istreg( r ) ) ++p->su;
+ }
+ }
+ if( p->su == szty(p->type) &&
+ (p->op!=REG || !istreg(p->rval)) &&
+ (p->type==INT || p->type==UNSIGNED || p->type==DOUBLE) )
+ p->su = 0;
+ return;
+ }
+
+ else if( ty == UTYPE ){
+ switch( o ) {
+ case UNARY CALL:
+ case UNARY STCALL:
+ p->su = fregs; /* all regs needed */
+ return;
+
+ default:
+ p->su = p->left->su + (szty( p->type ) > 1 ? 2 : 0) ;
+ return;
+ }
+ }
+
+
+ /* If rhs needs n, lhs needs m, regular su computation */
+
+ sul = p->left->su;
+ sur = p->right->su;
+
+ if( o == ASSIGN ){
+ /* computed by doing right, then left (if not in mem), then doing it */
+ p->su = max(sur,sul+1);
+ return;
+ }
+
+ if( o == CALL || o == STCALL ){
+ /* in effect, takes all free registers */
+ p->su = fregs;
+ return;
+ }
+
+ if( o == STASG ){
+ /* right, then left */
+ p->su = max( max( 1+sul, sur), fregs );
+ return;
+ }
+
+ if( asgop(o) ){
+ /* computed by doing right, doing left address, doing left, op, and store */
+ p->su = max(sur,sul+2);
+/*
+ if( o==ASG MUL || o==ASG DIV || o==ASG MOD) p->su = max(p->su,fregs);
+ */
+ return;
+ }
+
+ switch( o ){
+ case ANDAND:
+ case OROR:
+ case QUEST:
+ case COLON:
+ case COMOP:
+ p->su = max( max(sul,sur), 1);
+ return;
+
+ case PLUS:
+ case OR:
+ case ER:
+ /* commutative ops; put harder on left */
+ if( p->right->su > p->left->su && !istnode(p->left) ){
+ register NODE *temp;
+ temp = p->left;
+ p->left = p->right;
+ p->right = temp;
+ }
+ break;
+ }
+
+ /* binary op, computed by left, then right, then do op */
+ p->su = max(sul,szty(p->right->type)+sur);
+/*
+ if( o==MUL||o==DIV||o==MOD) p->su = max(p->su,fregs);
+ */
+
+ }
+
+int radebug = 0;
+
+rallo( p, down ) NODE *p; {
+ /* do register allocation */
+ register o, type, down1, down2, ty;
+
+ if( radebug ) printf( "rallo( %o, %d )\n", p, down );
+
+ down2 = NOPREF;
+ p->rall = down;
+ down1 = ( down &= ~MUSTDO );
+
+ ty = optype( o = p->op );
+ type = p->type;
+
+
+ if( type == DOUBLE || type == FLOAT ){
+ if( o == FORCE ) down1 = R0|MUSTDO;
+ }
+ else switch( o ) {
+ case ASSIGN:
+ down1 = NOPREF;
+ down2 = down;
+ break;
+
+/*
+ case MUL:
+ case DIV:
+ case MOD:
+ down1 = R3|MUSTDO;
+ down2 = R5|MUSTDO;
+ break;
+
+ case ASG MUL:
+ case ASG DIV:
+ case ASG MOD:
+ p->left->rall = down1 = R3|MUSTDO;
+ if( p->left->op == UNARY MUL ){
+ rallo( p->left->left, R4|MUSTDO );
+ }
+ else if( p->left->op == FLD && p->left->left->op == UNARY MUL ){
+ rallo( p->left->left->left, R4|MUSTDO );
+ }
+ else rallo( p->left, R3|MUSTDO );
+ rallo( p->right, R5|MUSTDO );
+ return;
+ */
+
+ case CALL:
+ case STASG:
+ case EQ:
+ case NE:
+ case GT:
+ case GE:
+ case LT:
+ case LE:
+ case NOT:
+ case ANDAND:
+ case OROR:
+ down1 = NOPREF;
+ break;
+
+ case FORCE:
+ down1 = R0|MUSTDO;
+ break;
+
+ }
+
+ if( ty != LTYPE ) rallo( p->left, down1 );
+ if( ty == BITYPE ) rallo( p->right, down2 );
+
+ }
+
+offstar( p ) register NODE *p; {
+ if( p->op == PLUS ) {
+ if( p->left->su == fregs ) {
+ order( p->left, INTAREG|INAREG );
+ return;
+ } else if( p->right->su == fregs ) {
+ order( p->right, INTAREG|INAREG );
+ return;
+ }
+ if( p->left->op==LS &&
+ (p->left->left->op!=REG || tlen(p->left->left)!=sizeof(int) ) ) {
+ order( p->left->left, INTAREG|INAREG );
+ return;
+ }
+ if( p->right->op==LS &&
+ (p->right->left->op!=REG || tlen(p->right->left)!=sizeof(int) ) ) {
+ order( p->right->left, INTAREG|INAREG );
+ return;
+ }
+ if( p->type == (PTR|CHAR) || p->type == (PTR|UCHAR) ) {
+ if( p->left->op!=REG || tlen(p->left)!=sizeof(int) ) {
+ order( p->left, INTAREG|INAREG );
+ return;
+ }
+ else if( p->right->op!=REG || tlen(p->right)!=sizeof(int) ) {
+ order(p->right, INTAREG|INAREG);
+ return;
+ }
+ }
+ }
+ if( p->op == PLUS || p->op == MINUS ){
+ if( p->right->op == ICON ){
+ p = p->left;
+ order( p , INTAREG|INAREG);
+ return;
+ }
+ }
+
+ if( p->op == UNARY MUL && !canaddr(p) ) {
+ offstar( p->left );
+ return;
+ }
+
+ order( p, INTAREG|INAREG );
+ }
+
+setincr( p ) NODE *p; {
+ return( 0 ); /* for the moment, don't bother */
+ }
+
+setbin( p ) register NODE *p; {
+ register ro, rt;
+
+ rt = p->right->type;
+ ro = p->right->op;
+
+ if( canaddr( p->left ) && !canaddr( p->right ) ) { /* address rhs */
+ if( ro == UNARY MUL ) {
+ offstar( p->right->left );
+ return(1);
+ } else {
+ order( p->right, INAREG|INTAREG|SOREG );
+ return(1);
+ }
+ }
+ if( !istnode( p->left) ) { /* try putting LHS into a reg */
+/* order( p->left, logop(p->op)?(INAREG|INBREG|INTAREG|INTBREG|SOREG):(INTAREG|INTBREG|SOREG) );*/
+ order( p->left, INAREG|INTAREG|INBREG|INTBREG|SOREG );
+ return(1);
+ }
+ else if( ro == UNARY MUL && rt != CHAR && rt != UCHAR ){
+ offstar( p->right->left );
+ return(1);
+ }
+ else if( rt == CHAR || rt == UCHAR || rt == SHORT || rt == USHORT || (ro != REG &&
+ ro != NAME && ro != OREG && ro != ICON ) ){
+ order( p->right, INAREG|INBREG );
+ return(1);
+ }
+/*
+ else if( logop(p->op) && rt==USHORT ){ /* must get rhs into register */
+/*
+ order( p->right, INAREG );
+ return( 1 );
+ }
+ */
+ return(0);
+ }
+
+setstr( p ) register NODE *p; { /* structure assignment */
+ if( p->right->op != REG ){
+ order( p->right, INTAREG );
+ return(1);
+ }
+ p = p->left;
+ if( p->op != NAME && p->op != OREG ){
+ if( p->op != UNARY MUL ) cerror( "bad setstr" );
+ order( p->left, INTAREG );
+ return( 1 );
+ }
+ return( 0 );
+ }
+
+setasg( p ) register NODE *p; {
+ /* setup for assignment operator */
+
+ if( !canaddr(p->right) ) {
+ if( p->right->op == UNARY MUL )
+ offstar(p->right->left);
+ else
+ order( p->right, INAREG|INBREG|SOREG );
+ return(1);
+ }
+ if( p->left->op == UNARY MUL ) {
+ offstar( p->left->left );
+ return(1);
+ }
+ if( p->left->op == FLD && p->left->left->op == UNARY MUL ){
+ offstar( p->left->left->left );
+ return(1);
+ }
+/* FLD patch */
+ if( p->left->op == FLD && !(p->right->type==INT || p->right->type==UNSIGNED)) {
+ order( p->right, INAREG);
+ return(1);
+ }
+/* end of FLD patch */
+ return(0);
+ }
+
+setasop( p ) register NODE *p; {
+ /* setup for =ops */
+ register rt, ro;
+
+ rt = p->right->type;
+ ro = p->right->op;
+
+ if( ro == UNARY MUL && rt != CHAR ){
+ offstar( p->right->left );
+ return(1);
+ }
+ if( ( rt == CHAR || rt == SHORT || rt == UCHAR || rt == USHORT ||
+ ( ro != REG && ro != ICON && ro != NAME && ro != OREG ) ) ){
+ order( p->right, INAREG|INBREG );
+ return(1);
+ }
+/*
+ if( (p->op == ASG LS || p->op == ASG RS) && ro != ICON && ro != REG ){
+ order( p->right, INAREG );
+ return(1);
+ }
+ */
+
+
+ p = p->left;
+ if( p->op == FLD ) p = p->left;
+
+ switch( p->op ){
+
+ case REG:
+ case ICON:
+ case NAME:
+ case OREG:
+ return(0);
+
+ case UNARY MUL:
+ if( p->left->op==OREG )
+ return(0);
+ else
+ offstar( p->left );
+ return(1);
+
+ }
+ cerror( "illegal setasop" );
+ }
+
+int crslab = 9999; /* Honeywell */
+
+getlab(){
+ return( crslab-- );
+ }
+
+deflab( l ){
+ printf( "L%d:\n", l );
+ }
+
+genargs( p, ptemp ) register NODE *p, *ptemp; {
+ register NODE *pasg;
+ register align;
+ register size;
+ register TWORD type;
+
+ /* generate code for the arguments */
+
+ /* first, do the arguments on the right */
+ while( p->op == CM ){
+ genargs( p->right, ptemp );
+ p->op = FREE;
+ p = p->left;
+ }
+
+ if( p->op == STARG ){ /* structure valued argument */
+
+ size = p->stsize;
+ align = p->stalign;
+
+ /* ptemp->lval = (ptemp->lval/align)*align; /* SETOFF for negative numbers */
+ ptemp->lval = 0; /* all moves to (sp) */
+
+ p->op = STASG;
+ p->right = p->left;
+ p->left = tcopy( ptemp );
+
+ /* the following line is done only with the knowledge
+ that it will be undone by the STASG node, with the
+ offset (lval) field retained */
+
+ if( p->right->op == OREG ) p->right->op = REG; /* only for temporaries */
+
+ order( p, FORARG );
+ ptemp->lval += size;
+ return;
+ }
+
+ /* ordinary case */
+
+ order( p, FORARG );
+ }
+
+argsize( p ) register NODE *p; {
+ register t;
+ t = 0;
+ if( p->op == CM ){
+ t = argsize( p->left );
+ p = p->right;
+ }
+ if( p->type == DOUBLE || p->type == FLOAT ){
+ SETOFF( t, 4 );
+ return( t+8 );
+ }
+ else if( p->op == STARG ){
+ SETOFF( t, 4 ); /* alignment */
+ return( t + ((p->stsize+3)/4)*4 ); /* size */
+ }
+ else {
+ SETOFF( t, 4 );
+ return( t+4 );
+ }
+ }
diff --git a/usr.bin/pcc/arch/vax/table.c b/usr.bin/pcc/arch/vax/table.c
new file mode 100644
index 00000000000..12d8de17e10
--- /dev/null
+++ b/usr.bin/pcc/arch/vax/table.c
@@ -0,0 +1,652 @@
+/* $Id: table.c,v 1.1 2007/09/15 18:12:30 otto Exp $ */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed or owned by Caldera
+ * International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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.
+ */
+
+# include "mfile2"
+
+# define WPTR TPTRTO|TINT|TLONG|TFLOAT|TDOUBLE|TPOINT|TUNSIGNED|TULONG
+# define AWD SNAME|SOREG|SCON|STARNM|STARREG
+/* tbl */
+# define ANYSIGNED TPOINT|TINT|TLONG|TSHORT|TCHAR
+# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TWORD TINT|TUNSIGNED|TPOINT|TLONG|TULONG
+/* tbl */
+
+struct optab table[] = {
+
+PCONV, INAREG|INTAREG,
+ SAREG|AWD, TCHAR|TSHORT,
+ SANY, TPOINT,
+ NAREG|NASL, RESC1,
+ " cvtZLl AL,A1\n",
+
+PCONV, INAREG|INTAREG,
+ SAREG|AWD, TUCHAR|TUSHORT,
+ SANY, TPOINT,
+ NAREG|NASL, RESC1,
+ " movzZLl AL,A1\n",
+
+SCONV, INTAREG|FORCC,
+ SAREG, TDOUBLE,
+ SANY, TDOUBLE,
+ 0, RLEFT,
+ "",
+
+SCONV, INTAREG|FORCC,
+ SAREG|AWD, TANY,
+ SANY, TFLOAT|TDOUBLE,
+ NAREG|NASL, RESC1|RESCC,
+ " cvtZLd AL,A1\n",
+
+SCONV, INTAREG|FORCC,
+ SAREG|AWD, TFLOAT|TDOUBLE,
+ SANY, ANYFIXED,
+ NAREG|NASL, RESC1|RESCC,
+ " cvtZLZF AL,A1\n",
+
+SCONV, INTAREG|FORCC,
+ SAREG|SNAME|SCON|STARNM, TANY,
+ SANY, ANYUSIGNED,
+ NAREG|NASL, RESC1|RESCC,
+ " movzZRl AL,A1\n",
+
+SCONV, INTAREG|FORCC,
+ SSOREG, TANY,
+ SANY, ANYUSIGNED,
+ NAREG|NASL, RESC1|RESCC,
+ " movzZRl AL,A1\n",
+
+SCONV, INTAREG|FORCC,
+ SAREG|SNAME|SCON|STARNM, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1|RESCC,
+ " cvtZRl AL,A1\n",
+
+SCONV, INTAREG|FORCC,
+ SSOREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1|RESCC,
+ " cvtZRl AL,A1\n",
+
+
+INIT, FOREFF,
+ SCON, TANY,
+ SANY, TWORD,
+ 0, RNOP,
+ " .long CL\n",
+
+INIT, FOREFF,
+ SCON, TANY,
+ SANY, TSHORT|TUSHORT,
+ 0, RNOP,
+ " .word CL\n",
+
+INIT, FOREFF,
+ SCON, TANY,
+ SANY, TCHAR|TUCHAR,
+ 0, RNOP,
+ " .byte CL\n",
+
+ /* for the use of fortran only */
+
+GOTO, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ 0, RNOP,
+ " jbr CL\n",
+
+GOTO, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, RNOP,
+ " jmp (AL)\n",
+
+STARG, INTEMP,
+ SCON|SAREG, TANY,
+ SANY, TANY,
+ NTEMP+2*NAREG, RESC3,
+ "ZS",
+
+STASG, FORARG,
+ SNAME|SOREG, TANY,
+ SCON|SAREG, TANY,
+ 0, RNULL,
+ " subl2 ZT,sp\nZS",
+
+STASG, FOREFF,
+ SNAME|SOREG, TANY,
+ SCON|SAREG, TANY,
+ 0, RNOP,
+ "ZS",
+
+STASG, INAREG,
+ SNAME|SOREG, TANY,
+ SCON, TANY,
+ NAREG, RESC1,
+ "ZS movl AR,A1\n",
+
+STASG, INAREG,
+ SNAME|SOREG, TANY,
+ SAREG, TANY,
+ 0, RRIGHT,
+ " pushl AR\nZS movl (sp)+,AR\n",
+
+FLD, INAREG|INTAREG,
+ SANY, TANY,
+ SFLD, ANYSIGNED,
+ NAREG|NASR, RESC1,
+ " extv H,S,AR,A1\n",
+
+FLD, INAREG|INTAREG,
+ SANY, TANY,
+ SFLD, ANYUSIGNED,
+ NAREG|NASR, RESC1,
+ " extzv H,S,AR,A1\n",
+
+FLD, FORARG,
+ SANY, TANY,
+ SFLD, ANYSIGNED,
+ 0, RNULL,
+ " extv H,S,AR,-(sp)\n",
+
+FLD, FORARG,
+ SANY, TANY,
+ SFLD, ANYUSIGNED,
+ 0, RNULL,
+ " extzv H,S,AR,-(sp)\n",
+
+OPLOG, FORCC,
+ SAREG|AWD, TWORD,
+ SAREG|AWD, TWORD,
+ 0, RESCC,
+ " cmpl AL,AR\nZP",
+
+OPLOG, FORCC,
+ SAREG|AWD, TSHORT|TUSHORT,
+ SAREG|AWD, TSHORT|TUSHORT,
+ 0, RESCC,
+ " cmpw AL,AR\nZP",
+
+OPLOG, FORCC,
+ SAREG|AWD, TCHAR|TUCHAR,
+ SAREG|AWD, TCHAR|TUCHAR,
+ 0, RESCC,
+ " cmpb AL,AR\nZP",
+
+OPLOG, FORCC,
+ SAREG|AWD, TSHORT|TUSHORT,
+ SSCON, TANY,
+ 0, RESCC,
+ " cmpw AL,AR\nZP",
+
+OPLOG, FORCC,
+ SAREG|AWD, TCHAR|TUCHAR,
+ SCCON, TANY,
+ 0, RESCC,
+ " cmpb AL,AR\nZP",
+
+OPLOG, FORCC,
+ SAREG|AWD, TDOUBLE,
+ SAREG|AWD, TDOUBLE,
+ 0, RESCC,
+ " cmpd AL,AR\nZP",
+
+OPLOG, FORCC,
+ SAREG|AWD, TFLOAT|TDOUBLE,
+ SAREG|AWD, TFLOAT|TDOUBLE,
+ 0, RESCC,
+ " cmpf AL,AR\nZP",
+
+CCODES, INAREG|INTAREG,
+ SANY, TANY,
+ SANY, TANY,
+ NAREG, RESC1,
+ " movl $1,A1\nZN",
+
+UNARY CALL, INTAREG,
+ SCON, TANY,
+ SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE,
+ NAREG|NASL, RESC1, /* should be register 0 */
+ " calls ZC,CL\n",
+
+UNARY CALL, INTAREG,
+ SAREG, TANY,
+ SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " calls ZC,(AL)\n",
+
+UNARY CALL, INAREG|INTAREG,
+ SNAME, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* really reg 0 */
+ " calls ZC,*AL\n",
+
+UNARY CALL, INAREG|INTAREG,
+ SSOREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* really reg 0 */
+ " calls ZC,*AL\n",
+
+ASG RS, INAREG|FOREFF|FORCC,
+ SAREG, TWORD,
+ SCON, TINT,
+ 0, RLEFT|RESCC,
+ " extzv AR,ZU,AL,AL\n",
+
+ASG RS, INAREG|FOREFF|FORCC,
+ SAREG, TWORD,
+ SAREG, ANYFIXED,
+ NAREG, RLEFT|RESCC,
+ " subl3 AR,$32,A1\n extzv AR,A1,AL,AL\n",
+
+ASG RS, INAREG|FOREFF|FORCC,
+ SAREG, TWORD,
+ SAREG|AWD, TWORD,
+ NAREG, RLEFT|RESCC,
+ " subl3 AR,$32,A1\n extzv AR,A1,AL,AL\n",
+
+RS, INAREG|INTAREG|FORCC,
+ SAREG, TWORD,
+ SCON, TINT,
+ NAREG|NASL, RESC1|RESCC,
+ " extzv AR,ZU,AL,A1\n",
+
+ASG LS, INAREG|FOREFF|FORCC,
+ SAREG|AWD, TWORD,
+ SAREG|AWD, ANYSIGNED|ANYUSIGNED,
+ 0, RLEFT|RESCC,
+ " ashl AR,AL,AL\n",
+
+LS, INAREG|INTAREG|FORCC,
+ SAREG|AWD, TWORD,
+ SAREG|AWD, ANYSIGNED|ANYUSIGNED,
+ NAREG|NASL|NASR, RESC1|RESCC,
+ " ashl AR,AL,A1\n",
+
+INCR, FOREFF,
+ SAREG|AWD, TANY,
+ SANY, TANY,
+ 0, RLEFT,
+ " ZE\n",
+
+DECR, FOREFF,
+ SAREG|AWD, TANY,
+ SCON, TANY,
+ 0, RLEFT,
+ " ZE\n",
+
+INCR, INAREG|INTAREG,
+ SAREG|AWD, TANY,
+ SCON, TANY,
+ NAREG, RESC1,
+ " ZD\n",
+
+DECR, INAREG|INTAREG,
+ SAREG|AWD, TANY,
+ SCON, TANY,
+ NAREG, RESC1,
+ " ZD\n",
+
+ASSIGN, INAREG|FOREFF|FORCC,
+ SAREG|AWD, TANY,
+ SAREG|AWD, TANY,
+ 0, RLEFT|RRIGHT|RESCC,
+ " ZA\n",
+
+ASSIGN, INAREG|FOREFF|FORCC,
+ SFLD, TANY,
+ SAREG|AWD, TWORD,
+ 0, RRIGHT|RESCC,
+ " insv AR,H,S,AL\n",
+
+ASSIGN, INAREG|FOREFF|FORCC,
+ SAREG|AWD, TWORD,
+ SFLD, ANYSIGNED,
+ 0, RLEFT|RESCC,
+ " extv H,S,AR,AL\n",
+
+ASSIGN, INAREG|FOREFF|FORCC,
+ SAREG|AWD, TWORD,
+ SFLD, ANYUSIGNED,
+ 0, RLEFT|RESCC,
+ " extzv H,S,AR,AL\n",
+
+/* dummy UNARY MUL entry to get U* to possibly match OPLTYPE */
+UNARY MUL, FOREFF,
+ SCC, TANY,
+ SCC, TANY,
+ 0, RNULL,
+ " HELP HELP HELP\n",
+
+REG, FORARG,
+ SANY, TANY,
+ SAREG, TDOUBLE|TFLOAT,
+ 0, RNULL,
+ " movZR AR,-(sp)\n",
+
+REG, INTEMP,
+ SANY, TANY,
+ SAREG, TDOUBLE,
+ 2*NTEMP, RESC1,
+ " movd AR,A1\n",
+
+REG, INTEMP,
+ SANY, TANY,
+ SAREG, TANY,
+ NTEMP, RESC1,
+ " movZF AR,A1\n",
+
+OPLEAF, FOREFF,
+ SANY, TANY,
+ SAREG|AWD, TANY,
+ 0, RLEFT,
+ "",
+
+OPLTYPE, INAREG|INTAREG,
+ SANY, TANY,
+ SANY, TFLOAT|TDOUBLE,
+ 2*NAREG|NASR, RESC1,
+ " ZA\n",
+
+OPLTYPE, INAREG|INTAREG,
+ SANY, TANY,
+ SANY, TANY,
+ NAREG|NASR, RESC1,
+ " ZA\n",
+
+OPLTYPE, FORCC,
+ SANY, TANY,
+ SANY, TANY,
+ 0, RESCC,
+ " tstZR AR\n",
+
+OPLTYPE, FORARG,
+ SANY, TANY,
+ SANY, TWORD,
+ 0, RNULL,
+ " pushl AR\n",
+
+OPLTYPE, FORARG,
+ SANY, TANY,
+ SANY, TCHAR|TSHORT,
+ 0, RNULL,
+ " cvtZRl AR,-(sp)\n",
+
+OPLTYPE, FORARG,
+ SANY, TANY,
+ SANY, TUCHAR|TUSHORT,
+ 0, RNULL,
+ " movzZRl AR,-(sp)\n",
+
+OPLTYPE, FORARG,
+ SANY, TANY,
+ SANY, TDOUBLE,
+ 0, RNULL,
+ " movd AR,-(sp)\n",
+
+OPLTYPE, FORARG,
+ SANY, TANY,
+ SANY, TFLOAT,
+ 0, RNULL,
+ " cvtfd AR,-(sp)\n",
+
+UNARY MINUS, INTAREG|FORCC,
+ SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG|TDOUBLE,
+ SANY, TANY,
+ NAREG|NASL, RESC1|RESCC,
+ " mnegZL AL,A1\n",
+
+COMPL, INTAREG|FORCC,
+ SAREG|AWD, TINT|TUNSIGNED,
+ SANY, TANY,
+ NAREG|NASL, RESC1|RESCC,
+ " mcomZL AL,A1\n",
+
+COMPL, INTAREG|FORCC,
+ SAREG|AWD, ANYSIGNED|ANYUSIGNED,
+ SANY, TANY,
+ NAREG|NASL, RESC1|RESCC,
+ " cvtZLl AL,A1\n mcoml A1,A1\n",
+
+AND, FORCC,
+ SAREG|AWD, TWORD,
+ SCON, TWORD,
+ 0, RESCC,
+ " bitl ZZ,AL\n",
+
+AND, FORCC,
+ SAREG|AWD, TSHORT|TUSHORT,
+ SSCON, TWORD,
+ 0, RESCC,
+ " bitw ZZ,AL\n",
+
+AND, FORCC,
+ SAREG|AWD, TCHAR|TUCHAR,
+ SCCON, TWORD,
+ 0, RESCC,
+ " bitb ZZ,AL\n",
+
+ASG AND, INAREG|FOREFF|FORCC,
+ SAREG, ANYFIXED,
+ SCON, TWORD,
+ 0, RLEFT|RESCC,
+ " bicl2 AR,AL\n",
+
+ASG OPMUL, INAREG|FOREFF|FORCC,
+ SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG,
+ SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG,
+ 0, RLEFT|RESCC,
+ " OL2 AR,AL\n",
+
+OPMUL, INAREG|INTAREG|FORCC,
+ STAREG, TINT|TUNSIGNED|TLONG|TULONG,
+ SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG,
+ 0, RLEFT|RESCC,
+ " OL2 AR,AL\n",
+
+OPMUL, INAREG|INTAREG|FORCC,
+ SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG,
+ SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG,
+ NAREG|NASL|NASR, RESC1|RESCC,
+ " OL3 AR,AL,A1\n",
+
+ASG MOD, INAREG|INTAREG|FOREFF|FORCC,
+ SAREG, TINT|TUNSIGNED|TLONG|TULONG,
+ SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG,
+ NAREG, RLEFT|RESCC,
+ " divl3 AR,AL,A1\n mull2 AR,A1\n subl2 A1,AL\n",
+
+MOD, INAREG|INTAREG,
+ SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG,
+ SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG,
+ NAREG, RESC1,
+ " divl3 AR,AL,A1\n mull2 AR,A1\n subl3 A1,AL,A1\n",
+
+ASG PLUS, INAREG|FOREFF|FORCC,
+ SAREG|AWD, ANYSIGNED|ANYUSIGNED,
+ SONE, TINT|TLONG,
+ 0, RLEFT|RESCC,
+ " incZL AL\n",
+
+ASG MINUS, INAREG|FOREFF|FORCC,
+ SAREG|AWD, ANYSIGNED|ANYUSIGNED,
+ SONE, TINT|TLONG,
+ 0, RLEFT|RESCC,
+ " decZL AL\n",
+
+PLUS, INAREG|INTAREG|FORCC,
+ STAREG, ANYFIXED,
+ SONE, TWORD,
+ 0, RLEFT|RESCC,
+ " incZL AL\n",
+
+MINUS, INAREG|INTAREG|FORCC,
+ STAREG, ANYFIXED,
+ SONE, TWORD,
+ 0, RLEFT|RESCC,
+ " decZL AL\n",
+
+ASG OPSIMP, INAREG|FOREFF|FORCC,
+ SAREG|AWD, TWORD,
+ SAREG|AWD, TWORD,
+ 0, RLEFT|RESCC,
+ " OL2 AR,AL\n",
+
+ASG OPSIMP, INAREG|FOREFF|FORCC,
+ AWD, TSHORT|TUSHORT,
+ SAREG|AWD, TSHORT|TUSHORT,
+ 0, RLEFT|RESCC,
+ " OW2 AR,AL\n",
+
+ASG OPSIMP, INAREG|FOREFF|FORCC,
+ AWD, TSHORT|TUSHORT,
+ SSCON, TWORD,
+ 0, RLEFT|RESCC,
+ " OW2 AR,AL\n",
+
+ASG OPSIMP, INAREG|FOREFF|FORCC,
+ AWD, TCHAR|TUCHAR,
+ SAREG|AWD, TCHAR|TUCHAR,
+ 0, RLEFT|RESCC,
+ " OB2 AR,AL\n",
+
+ASG OPSIMP, INAREG|FOREFF|FORCC,
+ AWD, TCHAR|TUCHAR,
+ SCCON, TWORD,
+ 0, RLEFT|RESCC,
+ " OB2 AR,AL\n",
+
+OPSIMP, INAREG|INTAREG|FORCC,
+ STAREG, ANYFIXED,
+ SAREG|AWD, TWORD,
+ 0, RLEFT|RESCC,
+ " OL2 AR,AL\n",
+
+OPSIMP, INAREG|INTAREG|FORCC,
+ SAREG|AWD, TWORD,
+ SAREG|AWD, TWORD,
+ NAREG|NASL|NASR, RESC1|RESCC,
+ " OL3 AR,AL,A1\n",
+
+ASG OPFLOAT, INAREG|FOREFF|FORCC,
+ SAREG|AWD, TDOUBLE,
+ SAREG|AWD, TDOUBLE,
+ 0, RLEFT|RESCC,
+ " OD2 AR,AL\n",
+
+ASG OPFLOAT, INAREG|FOREFF|FORCC,
+ SAREG|AWD, TFLOAT,
+ SAREG|AWD, TFLOAT,
+ 0, RLEFT|RESCC,
+ " OF2 AR,AL\n",
+
+ASG OPFLOAT, INAREG|FOREFF|FORCC,
+ SAREG|AWD, TDOUBLE,
+ SAREG|AWD, TFLOAT,
+ NAREG|NASR, RLEFT|RESCC,
+ " cvtfd AR,A1\n OD2 A1,AL\n",
+
+ASG OPFLOAT, INAREG|INTAREG|FOREFF|FORCC,
+ SAREG|AWD, TFLOAT,
+ SAREG|AWD, TDOUBLE,
+ NAREG, RLEFT|RESC1|RESCC,
+ " cvtfd AL,A1\n OD2 AR,A1\n cvtdf A1,AL\n",
+
+OPFLOAT, INAREG|INTAREG|FORCC,
+ STAREG, TDOUBLE,
+ SAREG|AWD, TDOUBLE,
+ 0, RLEFT|RESCC,
+ " OD2 AR,AL\n",
+
+OPFLOAT, INAREG|INTAREG|FORCC,
+ SAREG|AWD, TDOUBLE,
+ SAREG|AWD, TDOUBLE,
+ NAREG|NASL|NASR, RESC1|RESCC,
+ " OD3 AR,AL,A1\n",
+
+OPFLOAT, INAREG|INTAREG|FORCC,
+ SAREG|AWD, TFLOAT,
+ SAREG|AWD, TDOUBLE,
+ NAREG|NASL, RESC1|RESCC,
+ " cvtfd AL,A1\n OD2 AR,A1\n",
+
+OPFLOAT, INAREG|INTAREG|FORCC,
+ SAREG|AWD, TDOUBLE,
+ SAREG|AWD, TFLOAT,
+ NAREG|NASR, RESC1|RESCC,
+ " cvtfd AR,A1\n OD3 A1,AL,A1\n",
+
+OPFLOAT, INAREG|INTAREG|FORCC,
+ SAREG|AWD, TFLOAT,
+ SAREG|AWD, TFLOAT,
+ NAREG|NASL|NASR, RESC1|RESCC,
+ " OF3 AR,AL,A1\n cvtfd A1,A1\n",
+
+ /* Default actions for hard trees ... */
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+UNARY MUL, DF( UNARY MUL ),
+
+INCR, DF(INCR),
+
+DECR, DF(INCR),
+
+ASSIGN, DF(ASSIGN),
+
+STASG, DF(STASG),
+
+OPLEAF, DF(NAME),
+
+OPLOG, FORCC,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, BITYPE,
+ "",
+
+OPLOG, DF(NOT),
+
+COMOP, DF(COMOP),
+
+INIT, DF(INIT),
+
+OPUNARY, DF(UNARY MINUS),
+
+
+ASG OPANY, DF(ASG PLUS),
+
+OPANY, DF(BITYPE),
+
+FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" };
diff --git a/usr.bin/pcc/arch/x86/code.c b/usr.bin/pcc/arch/x86/code.c
new file mode 100644
index 00000000000..dad9c3b57aa
--- /dev/null
+++ b/usr.bin/pcc/arch/x86/code.c
@@ -0,0 +1,213 @@
+/* $Id: code.c,v 1.1 2007/09/15 18:12:30 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.
+ */
+
+
+# include "pass1.h"
+
+/*
+ * 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;
+ /* address of return struct is in eax */
+ /* create a call to memcpy() */
+ /* will get the result in eax */
+ p = block(REG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+ p->n_rval = EAX;
+ q = block(OREG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+ q->n_rval = EBP;
+ q->n_lval = 8; /* return buffer offset */
+ p = block(CM, q, p, INT, 0, MKSUE(INT));
+ sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR;
+ p = block(CM, p, bcon(sz), INT, 0, MKSUE(INT));
+ p->n_right->n_name = "";
+ p = block(CALL, bcon(0), p, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+ p->n_left->n_name = "memcpy";
+ p = clocal(p);
+ send_passt(IP_NODE, p);
+}
+
+/*
+ * 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;
+
+ if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+ return;
+ /* Function returns struct, adjust arg offset */
+ for (i = 0; i < n; i++)
+ a[i]->soffset += SZPOINT(INT);
+}
+
+
+/*
+ * 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(int num, struct swents **p, int n)
+{
+ NODE *r;
+ int i;
+
+ /* simple switch code */
+ for (i = 1; i <= n; ++i) {
+ /* already in 1 */
+ r = tempnode(num, INT, 0, MKSUE(INT));
+ r = buildtree(NE, r, bcon(p[i]->sval));
+ cbranch(buildtree(NOT, r, NIL), bcon(p[i]->slab));
+ }
+ if (p[0]->slab > 0)
+ branch(p[0]->slab);
+}
diff --git a/usr.bin/pcc/arch/x86/local.c b/usr.bin/pcc/arch/x86/local.c
new file mode 100644
index 00000000000..88b622d4317
--- /dev/null
+++ b/usr.bin/pcc/arch/x86/local.c
@@ -0,0 +1,743 @@
+/* $Id: local.c,v 1.1 2007/09/15 18:12:30 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.
+ */
+
+
+#include "pass1.h"
+
+/* this file contains code which is dependent on the target machine */
+
+/* clocal() 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
+ */
+NODE *
+clocal(NODE *p)
+{
+
+ register struct symtab *q;
+ register NODE *r, *l;
+ register int o;
+ register int m;
+ TWORD t;
+
+#ifdef PCC_DEBUG
+ if (xdebug) {
+ printf("clocal: %p\n", p);
+ fwalk(p, eprint, 0);
+ }
+#endif
+ 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 STCALL:
+ case CALL:
+ /* Fix function call arguments. On x86, just add funarg */
+ for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+ if (r->n_right->n_op != STARG &&
+ r->n_right->n_op != FUNARG)
+ r->n_right = block(FUNARG, r->n_right, NIL,
+ r->n_right->n_type, r->n_right->n_df,
+ r->n_right->n_sue);
+ }
+ if (r->n_op != STARG && r->n_op != FUNARG) {
+ l = talloc();
+ *l = *r;
+ r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type;
+ }
+ 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;
+ }
+ }
+ break;
+
+ case PCONV:
+ /* Remove redundant PCONV's. Be careful */
+ l = p->n_left;
+ if (l->n_op == ICON) {
+ l->n_lval = (unsigned)l->n_lval;
+ goto delp;
+ }
+ if (l->n_type < INT || l->n_type == LONGLONG ||
+ l->n_type == ULONGLONG) {
+ /* float etc? */
+ p->n_left = block(SCONV, l, NIL,
+ UNSIGNED, 0, MKSUE(UNSIGNED));
+ break;
+ }
+ /* if left is SCONV, cannot remove */
+ if (l->n_op == SCONV)
+ break;
+
+ /* avoid ADDROF TEMP */
+ if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
+ break;
+
+ /* if conversion to another pointer type, just remove */
+ if (p->n_type > BTMASK && l->n_type > BTMASK)
+ goto delp;
+ break;
+
+ delp: 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_op == TEMP) {
+ l->n_type = p->n_type;
+ nfree(p);
+ return l;
+ }
+ }
+ }
+
+ if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+ coptype(l->n_op) == BITYPE) {
+ l->n_type = p->n_type;
+ nfree(p);
+ return l;
+ }
+
+ 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 BOOL:
+ l->n_lval = l->n_lval != 0;
+ break;
+ 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;
+ l->n_sue = MKSUE(m);
+ nfree(p);
+ return l;
+ }
+ if (DEUNSIGN(p->n_type) == SHORT &&
+ DEUNSIGN(l->n_type) == SHORT) {
+ nfree(p);
+ p = l;
+ }
+ if ((p->n_type == CHAR || p->n_type == UCHAR ||
+ p->n_type == SHORT || p->n_type == USHORT) &&
+ (l->n_type == FLOAT || l->n_type == DOUBLE ||
+ l->n_type == LDOUBLE)) {
+ p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
+ p->n_left->n_type = INT;
+ return p;
+ }
+ 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 = p->n_left->n_type == BOOL ?
+ RETREG(CHAR) : RETREG(p->n_type);
+ break;
+
+ case LS:
+ case RS:
+ /* shift count must be in a char
+ * unless longlong, where it must be int */
+ if (p->n_right->n_op == ICON)
+ break; /* do not do anything */
+ if (p->n_type == LONGLONG || p->n_type == ULONGLONG) {
+ if (p->n_right->n_type != INT)
+ p->n_right = block(SCONV, p->n_right, NIL,
+ INT, 0, MKSUE(INT));
+ break;
+ }
+ if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
+ break;
+ p->n_right = block(SCONV, p->n_right, NIL,
+ CHAR, 0, MKSUE(CHAR));
+ break;
+ }
+#ifdef PCC_DEBUG
+ if (xdebug) {
+ printf("clocal end: %p\n", p);
+ fwalk(p, eprint, 0);
+ }
+#endif
+ 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;
+}
+
+/*
+ * Return 1 if a variable of type type is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+ if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+ return 0; /* not yet */
+ return 1;
+}
+
+/*
+ * 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 storeable node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+ NODE *sp;
+
+ p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
+
+ /* sub the size from sp */
+ sp = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
+ sp->n_lval = 0;
+ sp->n_rval = STKREG;
+ ecomp(buildtree(MINUSEQ, sp, p));
+
+ /* 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! */
+
+}
+
+#if 0
+/*
+ * Print out an integer constant of size size.
+ * can only be sizes <= SZINT.
+ */
+void
+indata(CONSZ val, int size)
+{
+ switch (size) {
+ case SZCHAR:
+ printf("\t.byte %d\n", (int)val & 0xff);
+ break;
+ case SZSHORT:
+ printf("\t.word %d\n", (int)val & 0xffff);
+ break;
+ case SZINT:
+ printf("\t.long %d\n", (int)val & 0xffffffff);
+ break;
+ default:
+ cerror("indata");
+ }
+}
+#endif
+
+/*
+ * Print out a string of characters.
+ * Assume that the assembler understands C-style escape
+ * sequences. Location is already set.
+ */
+void
+instring(char *str)
+{
+ char *s;
+
+ /* be kind to assemblers and avoid long strings */
+ printf("\t.ascii \"");
+ for (s = str; *s != 0; ) {
+ if (*s++ == '\\') {
+ (void)esccon(&s);
+ }
+ if (s - str > 64) {
+ fwrite(str, 1, s - str, stdout);
+ printf("\"\n\t.ascii \"");
+ str = s;
+ }
+ }
+ fwrite(str, 1, s - str, stdout);
+ printf("\\0\"\n");
+}
+
+static int inbits, inval;
+
+/*
+ * set fsz bits in sequence to zero.
+ */
+void
+zbits(OFFSZ off, int fsz)
+{
+ int m;
+
+ if (idebug)
+ printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
+ if ((m = (inbits % SZCHAR))) {
+ m = SZCHAR - m;
+ if (fsz < m) {
+ inbits += fsz;
+ return;
+ } else {
+ fsz -= m;
+ printf("\t.byte %d\n", inval);
+ inval = inbits = 0;
+ }
+ }
+ if (fsz >= SZCHAR) {
+ printf("\t.zero %d\n", fsz/SZCHAR);
+ fsz -= (fsz/SZCHAR) * SZCHAR;
+ }
+ if (fsz) {
+ inval = 0;
+ inbits = fsz;
+ }
+}
+
+/*
+ * Initialize a bitfield.
+ */
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+ if (idebug)
+ printf("infld off %lld, fsz %d, val %lld inbits %d\n",
+ off, fsz, val, inbits);
+ val &= (1 << fsz)-1;
+ while (fsz + inbits >= SZCHAR) {
+ inval |= (val << inbits);
+ printf("\t.byte %d\n", inval & 255);
+ fsz -= (SZCHAR - inbits);
+ val >>= (SZCHAR - inbits);
+ inval = inbits = 0;
+ }
+ if (fsz) {
+ inval |= (val << inbits);
+ inbits += fsz;
+ }
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ */
+void
+ninval(CONSZ off, int fsz, NODE *p)
+{
+ union { float f; double d; long double l; int i[3]; } u;
+ struct symtab *q;
+ TWORD t;
+ int i;
+
+ t = p->n_type;
+ if (t > BTMASK)
+ t = INT; /* pointer */
+
+ if (p->n_op != ICON && p->n_op != FCON)
+ cerror("ninval: init node not constant");
+
+ if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
+ uerror("element not constant");
+
+ switch (t) {
+ case LONGLONG:
+ case ULONGLONG:
+ i = (p->n_lval >> 32);
+ p->n_lval &= 0xffffffff;
+ p->n_type = INT;
+ ninval(off, 32, p);
+ p->n_lval = i;
+ ninval(off+32, 32, p);
+ 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;
+ case SHORT:
+ case USHORT:
+ printf("\t.short 0x%x\n", (int)p->n_lval & 0xffff);
+ break;
+ case BOOL:
+ if (p->n_lval > 1)
+ p->n_lval = p->n_lval != 0;
+ /* FALLTHROUGH */
+ case CHAR:
+ case UCHAR:
+ printf("\t.byte %d\n", (int)p->n_lval & 0xff);
+ break;
+ case LDOUBLE:
+ u.i[2] = 0;
+ u.l = (long double)p->n_dcon;
+ printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+ break;
+ case DOUBLE:
+ u.d = (double)p->n_dcon;
+ printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+ break;
+ case FLOAT:
+ u.f = (float)p->n_dcon;
+ printf("\t.long\t0x%x\n", u.i[0]);
+ break;
+ default:
+ cerror("ninval");
+ }
+}
+
+#if 0
+/*
+ * 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)
+{
+ union { float f; double d; long double l; int i[3]; } u;
+
+ switch (p->n_type) {
+ case LDOUBLE:
+ u.i[2] = 0;
+ u.l = (long double)p->n_dcon;
+ printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+ break;
+ case DOUBLE:
+ u.d = (double)p->n_dcon;
+ printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+ break;
+ case FLOAT:
+ u.f = (float)p->n_dcon;
+ printf("\t.long\t0x%x\n", u.i[0]);
+ break;
+ }
+}
+#endif
+
+/* 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);
+}
+
+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]);
+}
+
+#if 0
+int
+ftoint(NODE *p, CONSZ **c)
+{
+ static CONSZ cc[3];
+ union { float f; double d; long double l; int i[3]; } u;
+ int n;
+
+ switch (p->n_type) {
+ case LDOUBLE:
+ u.i[2] = 0;
+ u.l = (long double)p->n_dcon;
+ n = SZLDOUBLE;
+ break;
+ case DOUBLE:
+ u.d = (double)p->n_dcon;
+ n = SZDOUBLE;
+ break;
+ case FLOAT:
+ u.f = (float)p->n_dcon;
+ n = SZFLOAT;
+ break;
+ }
+ cc[0] = u.i[0];
+ cc[1] = u.i[1];
+ cc[2] = u.i[2];
+ *c = cc;
+ return n;
+}
+#endif
diff --git a/usr.bin/pcc/arch/x86/local2.c b/usr.bin/pcc/arch/x86/local2.c
new file mode 100644
index 00000000000..ec3c521a3db
--- /dev/null
+++ b/usr.bin/pcc/arch/x86/local2.c
@@ -0,0 +1,1051 @@
+/* $Id: local2.c,v 1.1 2007/09/15 18:12:31 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.
+ */
+
+
+# include "pass2.h"
+# include <ctype.h>
+# include <string.h>
+
+void acon(NODE *p);
+int argsize(NODE *p);
+
+static int stkpos;
+
+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[7];
+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(" pushl %%ebp\n");
+ printf(" movl %%esp,%%ebp\n");
+ if (addto)
+ printf(" subl $%d,%%esp\n", addto);
+ for (i = ipp->ipp_regs, j = 0; i; i >>= 1, j++)
+ if (i & 1)
+ fprintf(stdout, " movl %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/SZCHAR)
+ addto -= AUTOINIT/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;
+
+ 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, " movl -%d(%s),%s\n",
+ regoff[j], rnames[FPREG], rnames[j]);
+
+ }
+
+ /* struct return needs special treatment */
+ if (ftype == STRTY || ftype == UNIONTY) {
+ printf(" movl 8(%%ebp),%%eax\n");
+ printf(" leave\n");
+ printf(" ret $4\n");
+ } else {
+ printf(" leave\n");
+ printf(" ret\n");
+ }
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+ char *str;
+
+ switch (o) {
+ case PLUS:
+ str = "add";
+ break;
+ case MINUS:
+ str = "sub";
+ 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);
+}
+
+/*
+ * Return type size in bytes. Used by R2REGS, arg 2 to offset().
+ */
+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;
+ }
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+ int o = p->n_op;
+ int s = getlab();
+ int e = p->n_label;
+ int cb1, cb2;
+
+ if (o >= ULE)
+ o -= (ULE-LE);
+ switch (o) {
+ case NE:
+ cb1 = 0;
+ cb2 = NE;
+ break;
+ case EQ:
+ cb1 = NE;
+ cb2 = 0;
+ break;
+ case LE:
+ case LT:
+ cb1 = GT;
+ cb2 = LT;
+ break;
+ case GE:
+ case GT:
+ cb1 = LT;
+ cb2 = GT;
+ break;
+
+ default:
+ cb1 = cb2 = 0; /* XXX gcc */
+ }
+ if (p->n_op >= ULE)
+ cb1 += 4, cb2 += 4;
+ expand(p, 0, " cmpl UR,UL\n");
+ if (cb1) cbgen(cb1, s);
+ if (cb2) cbgen(cb2, e);
+ expand(p, 0, " cmpl AR,AL\n");
+ cbgen(p->n_op, e);
+ deflab(s);
+}
+
+/*
+ * Assign to a bitfield.
+ * Clumsy at least, but what to do?
+ */
+static void
+bfasg(NODE *p)
+{
+ NODE *fn = p->n_left;
+ int shift = UPKFOFF(fn->n_rval);
+ int fsz = UPKFSZ(fn->n_rval);
+ int andval, tch = 0;
+
+ /* get instruction size */
+ switch (p->n_type) {
+ case CHAR: case UCHAR: tch = 'b'; break;
+ case SHORT: case USHORT: tch = 'w'; break;
+ case INT: case UNSIGNED: tch = 'l'; break;
+ default: comperr("bfasg");
+ }
+
+ /* put src into a temporary reg */
+ fprintf(stdout, " mov%c ", tch);
+ adrput(stdout, getlr(p, 'R'));
+ fprintf(stdout, ",");
+ adrput(stdout, getlr(p, '1'));
+ fprintf(stdout, "\n");
+
+ /* AND away the bits from dest */
+ andval = ~(((1 << fsz) - 1) << shift);
+ fprintf(stdout, " and%c $%d,", tch, andval);
+ adrput(stdout, fn->n_left);
+ fprintf(stdout, "\n");
+
+ /* AND away unwanted bits from src */
+ andval = ((1 << fsz) - 1);
+ fprintf(stdout, " and%c $%d,", tch, andval);
+ adrput(stdout, getlr(p, '1'));
+ fprintf(stdout, "\n");
+
+ /* SHIFT left src number of bits */
+ if (shift) {
+ fprintf(stdout, " sal%c $%d,", tch, shift);
+ adrput(stdout, getlr(p, '1'));
+ fprintf(stdout, "\n");
+ }
+
+ /* OR in src to dest */
+ fprintf(stdout, " or%c ", tch);
+ adrput(stdout, getlr(p, '1'));
+ fprintf(stdout, ",");
+ adrput(stdout, fn->n_left);
+ fprintf(stdout, "\n");
+}
+
+/*
+ * Push a structure on stack as argument.
+ * the scratch registers are already free here
+ */
+static void
+starg(NODE *p)
+{
+ FILE *fp = stdout;
+
+ fprintf(fp, " subl $%d,%%esp\n", p->n_stsize);
+ fprintf(fp, " pushl $%d\n", p->n_stsize);
+ expand(p, 0, " pushl AL\n");
+ expand(p, 0, " leal 8(%esp),A1\n");
+ expand(p, 0, " pushl A1\n");
+ fprintf(fp, " call memcpy\n");
+ fprintf(fp, " addl $12,%%esp\n");
+}
+
+/*
+ * Compare two floating point numbers.
+ */
+static void
+fcomp(NODE *p)
+{
+
+ if (p->n_left->n_op == REG) {
+ if (p->n_su & DORIGHT)
+ expand(p, 0, " fxch\n");
+ expand(p, 0, " fucompp\n"); /* emit compare insn */
+ } else if (p->n_left->n_type == DOUBLE)
+ expand(p, 0, " fcompl AL\n"); /* emit compare insn */
+ else if (p->n_left->n_type == FLOAT)
+ expand(p, 0, " fcomp AL\n"); /* emit compare insn */
+ else
+ comperr("bad compare %p\n", p);
+ expand(p, 0, " fnstsw %ax\n"); /* move status reg to ax */
+
+ switch (p->n_op) {
+ case EQ:
+ expand(p, 0, " andb $64,%ah\n jne LC\n");
+ break;
+ case NE:
+ expand(p, 0, " andb $64,%ah\n je LC\n");
+ break;
+ case LE:
+ expand(p, 0, " andb $65,%ah\n cmpb $1,%ah\n jne LC\n");
+ break;
+ case LT:
+ expand(p, 0, " andb $65,%ah\n je LC\n");
+ break;
+ case GT:
+ expand(p, 0, " andb $1,%ah\n jne LC\n");
+ break;
+ case GE:
+ expand(p, 0, " andb $65,%ah\n jne LC\n");
+ break;
+ default:
+ comperr("fcomp op %d\n", p->n_op);
+ }
+}
+
+/*
+ * Convert an unsigned long long to floating point number.
+ */
+static void
+ulltofp(NODE *p)
+{
+ static int loadlab;
+ int jmplab;
+
+ if (loadlab == 0) {
+ loadlab = getlab();
+ expand(p, 0, " .data\n");
+ printf(LABFMT ": .long 0,0x80000000,0x403f\n", loadlab);
+ expand(p, 0, " .text\n");
+ }
+ jmplab = getlab();
+ expand(p, 0, " pushl UL\n pushl AL\n");
+ expand(p, 0, " fildq (%esp)\n");
+ expand(p, 0, " addl $8,%esp\n");
+ expand(p, 0, " cmpl $0,UL\n");
+ printf(" jge " LABFMT "\n", jmplab);
+ printf(" fldt " LABFMT "\n", loadlab);
+ printf(" faddp %%st,%%st(1)\n");
+ printf(LABFMT ":\n", jmplab);
+}
+
+static int
+argsiz(NODE *p)
+{
+ TWORD t = p->n_type;
+
+ if (t < LONGLONG || t == FLOAT || t > BTMASK)
+ return 4;
+ if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
+ return 8;
+ if (t == LDOUBLE)
+ return 12;
+ if (t == STRTY || t == UNIONTY)
+ return p->n_stsize;
+ comperr("argsiz");
+ return 0;
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+ NODE *r, *l;
+ int pr, lr, s;
+ char *ch;
+
+ switch (c) {
+ case 'A': /* swap st0 and st1 if right is evaluated second */
+ if ((p->n_su & DORIGHT) == 0) {
+ if (logop(p->n_op))
+ printf(" fxch\n");
+ else
+ printf("r");
+ }
+ break;
+
+ case 'C': /* remove from stack after subroutine call */
+ pr = p->n_qual;
+ if (p->n_op == STCALL || p->n_op == USTCALL)
+ pr += 4;
+ if (p->n_op == UCALL)
+ return; /* XXX remove ZC from UCALL */
+ if (pr)
+ printf(" addl $%d, %s\n", pr, rnames[ESP]);
+ break;
+
+ case 'D': /* Long long comparision */
+ twollcomp(p);
+ break;
+
+ case 'E': /* Assign to bitfield */
+ bfasg(p);
+ break;
+
+ case 'F': /* Structure argument */
+ if (p->n_stalign != 0) /* already on stack */
+ starg(p);
+ break;
+
+ case 'G': /* Floating point compare */
+ fcomp(p);
+ break;
+
+ case 'J': /* convert unsigned long long to floating point */
+ ulltofp(p);
+ break;
+
+ case 'M': /* Output sconv move, if needed */
+ l = getlr(p, 'L');
+ /* XXX fixneed: regnum */
+ pr = DECRA(p->n_reg, 0);
+ lr = DECRA(l->n_reg, 0);
+ if ((pr == AL && lr == EAX) || (pr == BL && lr == EBX) ||
+ (pr == CL && lr == ECX) || (pr == DL && lr == EDX))
+ ;
+ else
+ printf(" movb %%%cl,%s\n",
+ rnames[lr][2], rnames[pr]);
+ l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
+ break;
+
+ case 'N': /* output extended reg name */
+ printf("%s", rnames[getlr(p, '1')->n_rval]);
+ break;
+
+ case 'O': /* print out emulated ops */
+ pr = 16;
+ if (p->n_op == RS || p->n_op == LS) {
+ expand(p, INAREG, "\tpushl AR\n");
+ pr = 12;
+ } else
+ expand(p, INCREG, "\tpushl UR\n\tpushl AR\n");
+ expand(p, INCREG, "\tpushl UL\n\tpushl AL\n");
+ if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv";
+ else if (p->n_op == DIV) ch = "div";
+ else if (p->n_op == MUL) ch = "mul";
+ else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod";
+ else if (p->n_op == MOD) ch = "mod";
+ else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshr";
+ else if (p->n_op == RS) ch = "ashr";
+ else if (p->n_op == LS) ch = "ashl";
+ else ch = 0, comperr("ZO");
+ printf("\tcall __%sdi3\n\taddl $%d,%s\n", ch, pr, rnames[ESP]);
+ break;
+
+ case 'P': /* push hidden argument on stack */
+ r = (NODE *)p->n_sue;
+ printf("\tleal -%d(%%ebp),", stkpos);
+ adrput(stdout, getlr(p, '1'));
+ printf("\n\tpushl ");
+ adrput(stdout, getlr(p, '1'));
+ putchar('\n');
+ break;
+
+ case 'Q': /* emit struct assign */
+ /* XXX - optimize for small structs */
+ printf("\tpushl $%d\n", p->n_stsize);
+ expand(p, INAREG, "\tpushl AR\n");
+ expand(p, INAREG, "\tleal AL,%eax\n\tpushl %eax\n");
+ printf("\tcall memcpy\n");
+ printf("\taddl $12,%%esp\n");
+ break;
+
+ case 'S': /* emit eventual move after cast from longlong */
+ pr = DECRA(p->n_reg, 0);
+ lr = p->n_left->n_rval;
+ switch (p->n_type) {
+ case CHAR:
+ case UCHAR:
+ if (rnames[pr][2] == 'l' && rnames[lr][2] == 'x' &&
+ rnames[pr][1] == rnames[lr][1])
+ break;
+ if (rnames[lr][2] == 'x') {
+ printf("\tmovb %%%cl,%s\n",
+ rnames[lr][1], rnames[pr]);
+ break;
+ }
+ /* Must go via stack */
+ s = BITOOR(freetemp(1));
+ printf("\tmovl %%e%ci,%d(%%ebp)\n", rnames[lr][1], s);
+ printf("\tmovb %d(%%ebp),%s\n", s, rnames[pr]);
+// comperr("SCONV1 %s->%s", rnames[lr], rnames[pr]);
+ break;
+
+ case SHORT:
+ case USHORT:
+ if (rnames[lr][1] == rnames[pr][2] &&
+ rnames[lr][2] == rnames[pr][3])
+ break;
+ printf("\tmovw %%%c%c,%%%s\n",
+ rnames[lr][1], rnames[lr][2], rnames[pr]+2);
+ break;
+ case INT:
+ case UNSIGNED:
+ if (rnames[lr][1] == rnames[pr][2] &&
+ rnames[lr][2] == rnames[pr][3])
+ break;
+ printf("\tmovl %%e%c%c,%s\n",
+ rnames[lr][1], rnames[lr][2], rnames[pr]);
+ break;
+
+ default:
+ if (rnames[lr][1] == rnames[pr][2] &&
+ rnames[lr][2] == rnames[pr][3])
+ break;
+ comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]);
+ break;
+ }
+ break;
+
+ default:
+ comperr("zzzcode %c", c);
+ }
+}
+
+/*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, p %p", p);
+ }
+}
+
+/*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:
+ fprintf(stdout, "%%%s", &rnames[p->n_rval][3]);
+ 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);
+ } else
+ fprintf(io, CONFMT, p->n_lval);
+ return;
+
+ case OREG:
+ r = p->n_rval;
+ if (p->n_lval)
+ fprintf(io, "%d", (int)p->n_lval);
+ if (R2TEST(r)) {
+ fprintf(io, "(%s,%s,4)", rnames[R2UPK1(r)],
+ rnames[R2UPK2(r)]);
+ } else
+ 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:
+ switch (p->n_type) {
+ case LONGLONG:
+ case ULONGLONG:
+ fprintf(io, "%%%c%c%c", rnames[p->n_rval][0],
+ rnames[p->n_rval][1], rnames[p->n_rval][2]);
+ break;
+ case SHORT:
+ case USHORT:
+ fprintf(io, "%%%s", &rnames[p->n_rval][2]);
+ break;
+ default:
+ fprintf(io, "%s", rnames[p->n_rval]);
+ }
+ return;
+
+ default:
+ comperr("illegal address, op %d, node %p", p->n_op, p);
+ return;
+
+ }
+}
+
+static char *
+ccbranches[] = {
+ "je", /* jumpe */
+ "jne", /* jumpn */
+ "jle", /* jumple */
+ "jl", /* jumpl */
+ "jge", /* jumpge */
+ "jg", /* jumpg */
+ "jbe", /* jumple (jlequ) */
+ "jb", /* jumpl (jlssu) */
+ "jae", /* jumpge (jgequ) */
+ "ja", /* jumpg (jgtru) */
+};
+
+
+/* printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+ if (o < EQ || o > UGT)
+ comperr("bad conditional branch: %s", opst[o]);
+ printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab);
+}
+
+static void
+fixcalls(NODE *p)
+{
+ /* Prepare for struct return by allocating bounce space on stack */
+ switch (p->n_op) {
+ case STCALL:
+ case USTCALL:
+ if (p->n_stsize+p2autooff > stkpos)
+ stkpos = p->n_stsize+p2autooff;
+ break;
+ }
+}
+
+/*
+ * Must store floats in memory if there are two function calls involved.
+ */
+static int
+storefloat(struct interpass *ip, NODE *p)
+{
+ int l, r;
+
+ switch (optype(p->n_op)) {
+ case BITYPE:
+ l = storefloat(ip, p->n_left);
+ r = storefloat(ip, p->n_right);
+ if (p->n_op == CM)
+ return 0; /* arguments, don't care */
+ if (callop(p->n_op))
+ return 1; /* found one */
+#define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \
+ (p)->n_type == LDOUBLE)
+ if (ISF(p->n_left) && ISF(p->n_right) && l && r) {
+ /* must store one. store left */
+ struct interpass *nip;
+ TWORD t = p->n_left->n_type;
+ NODE *ll;
+ int off;
+
+ off = BITOOR(freetemp(szty(t)));
+ ll = mklnode(OREG, off, FPREG, t);
+ nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t));
+ p->n_left = mklnode(OREG, off, FPREG, t);
+ DLIST_INSERT_BEFORE(ip, nip, qelem);
+ }
+ return l|r;
+
+ case UTYPE:
+ l = storefloat(ip, p->n_left);
+ if (callop(p->n_op))
+ l = 1;
+ return l;
+ default:
+ return 0;
+ }
+}
+
+void
+myreader(struct interpass *ipole)
+{
+ struct interpass *ip;
+
+ stkpos = p2autooff;
+ DLIST_FOREACH(ip, ipole, qelem) {
+ if (ip->type != IP_NODE)
+ continue;
+ walkf(ip->ip_node, fixcalls);
+ storefloat(ip, ip->ip_node);
+ }
+ if (stkpos > p2autooff)
+ p2autooff = stkpos;
+ if (stkpos > p2maxautooff)
+ p2maxautooff = stkpos;
+ if (x2debug)
+ printip(ipole);
+}
+
+/*
+ * 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
+myoptim(struct interpass *ip)
+{
+}
+
+static char rl[] =
+ { EAX, EAX, EAX, EAX, EAX, EDX, EDX, EDX, EDX, ECX, ECX, ECX, EBX, EBX, ESI };
+static char rh[] =
+ { EDX, ECX, EBX, ESI, EDI, ECX, EBX, ESI, EDI, EBX, ESI, EDI, ESI, EDI, EDI };
+
+void
+rmove(int s, int d, TWORD t)
+{
+ int sl, sh, dl, dh;
+
+ switch (t) {
+ case LONGLONG:
+ case ULONGLONG:
+#if 1
+ sl = rl[s-EAXEDX];
+ sh = rh[s-EAXEDX];
+ dl = rl[d-EAXEDX];
+ dh = rh[d-EAXEDX];
+
+ /* sanity checks, remove when satisfied */
+ if (memcmp(rnames[s], rnames[sl]+1, 3) != 0 ||
+ memcmp(rnames[s]+3, rnames[sh]+1, 3) != 0)
+ comperr("rmove source error");
+ if (memcmp(rnames[d], rnames[dl]+1, 3) != 0 ||
+ memcmp(rnames[d]+3, rnames[dh]+1, 3) != 0)
+ comperr("rmove dest error");
+#define SW(x,y) { int i = x; x = y; y = i; }
+ if (sl == dh || sh == dl) {
+ /* Swap if moving to itself */
+ SW(sl, sh);
+ SW(dl, dh);
+ }
+ if (sl != dl)
+ printf(" movl %s,%s\n", rnames[sl], rnames[dl]);
+ if (sh != dh)
+ printf(" movl %s,%s\n", rnames[sh], rnames[dh]);
+#else
+ if (memcmp(rnames[s], rnames[d], 3) != 0)
+ printf(" movl %%%c%c%c,%%%c%c%c\n",
+ rnames[s][0],rnames[s][1],rnames[s][2],
+ rnames[d][0],rnames[d][1],rnames[d][2]);
+ if (memcmp(&rnames[s][3], &rnames[d][3], 3) != 0)
+ printf(" movl %%%c%c%c,%%%c%c%c\n",
+ rnames[s][3],rnames[s][4],rnames[s][5],
+ rnames[d][3],rnames[d][4],rnames[d][5]);
+#endif
+ break;
+ case CHAR:
+ case UCHAR:
+ printf(" movb %s,%s\n", rnames[s], rnames[d]);
+ break;
+ case FLOAT:
+ case DOUBLE:
+ case LDOUBLE:
+#ifdef notdef
+ /* a=b()*c(); will generate this */
+ comperr("bad float rmove: %d %d", s, d);
+#endif
+ break;
+ default:
+ printf(" movl %s,%s\n", rnames[s], rnames[d]);
+ }
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+ int num;
+
+ switch (c) {
+ case CLASSA:
+ num = r[CLASSB] > 4 ? 4 : r[CLASSB];
+ num += 2*r[CLASSC];
+ num += r[CLASSA];
+ return num < 6;
+ case CLASSB:
+ num = r[CLASSA];
+ num += 2*r[CLASSC];
+ num += r[CLASSB];
+ return num < 4;
+ case CLASSC:
+ num = r[CLASSA];
+ num += r[CLASSB] > 4 ? 4 : r[CLASSB];
+ num += 2*r[CLASSC];
+ return num < 5;
+ case CLASSD:
+ return r[CLASSD] < DREGCNT;
+ }
+ return 0; /* XXX gcc */
+}
+
+char *rnames[] = {
+ "%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp",
+ "%al", "%ah", "%dl", "%dh", "%cl", "%ch", "%bl", "%bh",
+ "eaxedx", "eaxecx", "eaxebx", "eaxesi", "eaxedi", "edxecx",
+ "edxebx", "edxesi", "edxedi", "ecxebx", "ecxesi", "ecxedi",
+ "ebxesi", "ebxedi", "esiedi",
+ "%st0", "%st1", "%st2", "%st3", "%st4", "%st5", "%st6", "%st7",
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+ if (t == CHAR || t == UCHAR)
+ return CLASSB;
+ if (t == LONGLONG || t == ULONGLONG)
+ return CLASSC;
+ if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+ return CLASSD;
+ return CLASSA;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+ NODE *op = p;
+ int size = 0;
+
+ p->n_qual = 0;
+ if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+ return;
+ for (p = p->n_right; p->n_op == CM; p = p->n_left)
+ size += argsiz(p->n_right);
+ size += argsiz(p);
+ op->n_qual = size; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+ int o = p->n_op;
+
+ switch (shape) {
+ case SFUNCALL:
+ if (o == STCALL || o == USTCALL)
+ return SRREG;
+ break;
+ case SPCON:
+ if (o != ICON || p->n_name[0] || p->n_lval < 0)
+ break;
+ return SRDIR;
+ }
+ return SRNOPE;
+}
diff --git a/usr.bin/pcc/arch/x86/macdefs.h b/usr.bin/pcc/arch/x86/macdefs.h
new file mode 100644
index 00000000000..46cf123c4ae
--- /dev/null
+++ b/usr.bin/pcc/arch/x86/macdefs.h
@@ -0,0 +1,301 @@
+/* $Id: macdefs.h,v 1.1 2007/09/15 18:12:31 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.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+/*
+ * Convert (multi-)character constant to 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 SZBOOL 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 ALBOOL 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 signed */
+#undef CHAR_UNSIGNED
+#define BOOL_TYPE CHAR /* what used to store _Bool */
+#define WCHAR_TYPE INT /* what used to store wchar_t */
+
+/*
+ * 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) /* bit offset to oreg offset XXX die! */
+
+#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 : (t) == LDOUBLE ? 3 : 1)
+
+/*
+ * The x86 has a bunch of register classes, most of them interfering
+ * with each other. All registers are given a sequential number to
+ * identify it which must match rnames[] in local2.c.
+ * Class membership and overlaps are defined in the macros RSTATUS
+ * and ROVERLAP below.
+ *
+ * The classes used on x86 are:
+ * A - short and int regs
+ * B - char regs
+ * C - long long regs
+ * D - floating point
+ */
+#define EAX 000 /* Scratch and return register */
+#define EDX 001 /* Scratch and secondary return register */
+#define ECX 002 /* Scratch (and shift count) register */
+#define EBX 003 /* GDT pointer or callee-saved temporary register */
+#define ESI 004 /* Callee-saved temporary register */
+#define EDI 005 /* Callee-saved temporary register */
+#define EBP 006 /* Frame pointer */
+#define ESP 007 /* Stack pointer */
+
+#define AL 010
+#define AH 011
+#define DL 012
+#define DH 013
+#define CL 014
+#define CH 015
+#define BL 016
+#define BH 017
+
+#define EAXEDX 020
+#define EAXECX 021
+#define EAXEBX 022
+#define EAXESI 023
+#define EAXEDI 024
+#define EDXECX 025
+#define EDXEBX 026
+#define EDXESI 027
+#define EDXEDI 030
+#define ECXEBX 031
+#define ECXESI 032
+#define ECXEDI 033
+#define EBXESI 034
+#define EBXEDI 035
+#define ESIEDI 036
+
+/* The 8 math registers in class D lacks names */
+
+#define MAXREGS 047 /* 39 registers */
+
+#define RSTATUS \
+ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, \
+ SAREG|PERMREG, SAREG|PERMREG, 0, 0, \
+ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \
+ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \
+ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \
+ SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG,
+
+#define ROVERLAP \
+ /* 8 basic registers */\
+ { AL, AH, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\
+ { DL, DH, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\
+ { CL, CH, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\
+ { BL, BH, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+ { EAXESI, EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\
+ { EAXEDI, EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\
+ { -1 },\
+ { -1 },\
+\
+ /* 8 char registers */\
+ { EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\
+ { EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\
+ { EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\
+ { EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\
+ { ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\
+ { ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\
+ { EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+ { EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+\
+ /* 15 long-long-emulating registers */\
+ { EAX, AL, AH, EDX, DL, DH, EAXECX, EAXEBX, EAXESI, /* eaxedx */\
+ EAXEDI, EDXECX, EDXEBX, EDXESI, EDXEDI, -1, },\
+ { EAX, AL, AH, ECX, CL, CH, EAXEDX, EAXEBX, EAXESI, /* eaxecx */\
+ EAXEDI, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\
+ { EAX, AL, AH, EBX, BL, BH, EAXEDX, EAXECX, EAXESI, /* eaxebx */\
+ EAXEDI, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+ { EAX, AL, AH, ESI, EAXEDX, EAXECX, EAXEBX, EAXEDI, /* eaxesi */\
+ EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\
+ { EAX, AL, AH, EDI, EAXEDX, EAXECX, EAXEBX, EAXESI, /* eaxedi */\
+ EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\
+ { EDX, DL, DH, ECX, CL, CH, EAXEDX, EAXECX, EDXEBX, /* edxecx */\
+ EDXESI, EDXEDI, ECXEBX, ECXESI, ECXEDI, -1 },\
+ { EDX, DL, DH, EBX, BL, BH, EAXEDX, EDXECX, EDXESI, /* edxebx */\
+ EDXEDI, EAXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+ { EDX, DL, DH, ESI, EAXEDX, EDXECX, EDXEBX, EDXEDI, /* edxesi */\
+ EAXESI, ECXESI, EBXESI, ESIEDI, -1 },\
+ { EDX, DL, DH, EDI, EAXEDX, EDXECX, EDXEBX, EDXESI, /* edxedi */\
+ EAXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\
+ { ECX, CL, CH, EBX, BL, BH, EAXECX, EDXECX, ECXESI, /* ecxebx */\
+ ECXEDI, EAXEBX, EDXEBX, EBXESI, EBXEDI, -1 },\
+ { ECX, CL, CH, ESI, EAXECX, EDXECX, ECXEBX, ECXEDI, /* ecxesi */\
+ EAXESI, EDXESI, EBXESI, ESIEDI, -1 },\
+ { ECX, CL, CH, EDI, EAXECX, EDXECX, ECXEBX, ECXESI, /* ecxedi */\
+ EAXEDI, EDXEDI, EBXEDI, ESIEDI, -1 },\
+ { EBX, BL, BH, ESI, EAXEBX, EDXEBX, ECXEBX, EBXEDI, /* ebxesi */\
+ EAXESI, EDXESI, ECXESI, ESIEDI, -1 },\
+ { EBX, BL, BH, EDI, EAXEBX, EDXEBX, ECXEBX, EBXESI, /* ebxedi */\
+ EAXEDI, EDXEDI, ECXEDI, ESIEDI, -1 },\
+ { ESI, EDI, EAXESI, EDXESI, ECXESI, EBXESI, /* esiedi */\
+ EAXEDI, EDXEDI, ECXEDI, EBXEDI, -1 },\
+\
+ /* The fp registers do not overlap with anything */\
+ { -1 },\
+ { -1 },\
+ { -1 },\
+ { -1 },\
+ { -1 },\
+ { -1 },\
+ { -1 },\
+ { -1 },
+
+
+/* Return a register class based on the type of the node */
+#define PCLASS(p) (p->n_type <= UCHAR ? SBREG : \
+ (p->n_type == LONGLONG || p->n_type == ULONGLONG ? SCREG : \
+ (p->n_type >= FLOAT && p->n_type <= LDOUBLE ? SDREG : SAREG)))
+
+#define NUMCLASS 4 /* highest number of reg classes used */
+
+int COLORMAP(int c, int *r);
+#define GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : x < 31 ? CLASSC : CLASSD)
+#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */
+#define ENCRD(x) (x) /* Encode dest reg in n_reg */
+#define ENCRA1(x) ((x) << 6) /* A1 */
+#define ENCRA2(x) ((x) << 12) /* A2 */
+#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */
+/* XXX - return char in al? */
+#define RETREG(x) (x == CHAR || x == UCHAR ? AL : \
+ x == LONGLONG || x == ULONGLONG ? EAXEDX : \
+ x == FLOAT || x == DOUBLE || x == LDOUBLE ? 31 : EAX)
+
+//#define R2REGS 1 /* permit double indexing */
+
+/* XXX - to die */
+#define FPREG EBP /* frame pointer */
+#define STKREG ESP /* stack pointer */
+
+#define MYREADER(p) myreader(p)
+#define MYCANON(p) mycanon(p)
+#define MYOPTIM
+
+#define SHSTR (MAXSPECIAL+1) /* short struct */
+#define SFUNCALL (MAXSPECIAL+2) /* struct assign after function call */
+#define SPCON (MAXSPECIAL+3) /* positive nonnamed constant */
diff --git a/usr.bin/pcc/arch/x86/order.c b/usr.bin/pcc/arch/x86/order.c
new file mode 100644
index 00000000000..35bd53c1f9b
--- /dev/null
+++ b/usr.bin/pcc/arch/x86/order.c
@@ -0,0 +1,287 @@
+/* $Id: order.c,v 1.1 2007/09/15 18:12:31 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.
+ */
+
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/* 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.
+ * Be careful about register classes, this is a place where classes change.
+ */
+void
+offstar(NODE *p, int shape)
+{
+ NODE *r;
+
+ if (x2debug)
+ printf("offstar(%p)\n", p);
+
+ if (isreg(p))
+ return; /* Is already OREG */
+
+ r = p->n_right;
+ if( p->n_op == PLUS || p->n_op == MINUS ){
+ if( r->n_op == ICON ){
+ if (isreg(p->n_left) == 0)
+ (void)geninsn(p->n_left, INAREG);
+ /* Converted in ormake() */
+ return;
+ }
+ if (r->n_op == LS && r->n_right->n_op == ICON &&
+ r->n_right->n_lval == 2 && p->n_op == PLUS) {
+ if (isreg(p->n_left) == 0)
+ (void)geninsn(p->n_left, INAREG);
+ if (isreg(r->n_left) == 0)
+ (void)geninsn(r->n_left, INAREG);
+ return;
+ }
+ }
+ (void)geninsn(p, INAREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *q)
+{
+ NODE *p, *r;
+
+ if (x2debug)
+ printf("myormake(%p)\n", q);
+
+ p = q->n_left;
+ if (p->n_op == PLUS && (r = p->n_right)->n_op == LS &&
+ r->n_right->n_op == ICON && r->n_right->n_lval == 2 &&
+ p->n_left->n_op == REG && r->n_left->n_op == REG) {
+ q->n_op = OREG;
+ q->n_lval = 0;
+ q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0);
+ tfree(p);
+ }
+}
+
+/*
+ * Shape matches for UMUL. Cooperates with offstar().
+ */
+int
+shumul(NODE *p)
+{
+
+ if (x2debug)
+ printf("shumul(%p)\n", p);
+
+ /* Turns currently anything 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.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+ switch (q->op) {
+ case OPLOG:
+ {
+ static struct rspecial s[] = { { NEVER, EAX }, { 0 } };
+ return s;
+ }
+
+ case STASG:
+ case STARG:
+ {
+ static struct rspecial s[] = {
+ { NEVER, EAX }, { NEVER, EDX },
+ { NEVER, ECX }, { 0 } };
+ return s;
+ }
+
+ case SCONV:
+ if ((q->ltype & (TINT|TUNSIGNED|TSHORT|TUSHORT)) &&
+ q->rtype == (TCHAR|TUCHAR)) {
+ static struct rspecial s[] = {
+ { NOLEFT, ESI }, { NOLEFT, EDI }, { 0 } };
+ return s;
+ } else if ((q->ltype & (TINT|TUNSIGNED)) &&
+ q->rtype == TLONGLONG) {
+ static struct rspecial s[] = {
+ { NLEFT, EAX }, { NRES, EAXEDX },
+ { NEVER, EAX }, { NEVER, EDX }, { 0 } };
+ return s;
+ } else if (q->ltype == TSHORT &&
+ q->rtype == (TLONGLONG|TULONGLONG)) {
+ static struct rspecial s[] = {
+ { NRES, EAXEDX },
+ { NEVER, EAX }, { NEVER, EDX }, { 0 } };
+ return s;
+ } else if (q->ltype == TCHAR &&
+ q->rtype == (TLONGLONG|TULONGLONG)) {
+ static struct rspecial s[] = {
+ { NRES, EAXEDX },
+ { NEVER, EAX }, { NEVER, EDX }, { 0 } };
+ return s;
+ }
+ break;
+ case DIV:
+ if (q->lshape == SBREG) {
+ static struct rspecial s[] = {
+ { NEVER, AL }, { NEVER, AH },
+ { NLEFT, AL }, { NRES, AL },
+ { NORIGHT, AH }, { NORIGHT, AL }, { 0 } };
+ return s;
+ } else if (q->lshape == SAREG) {
+ static struct rspecial s[] = {
+ { NEVER, EAX }, { NEVER, EDX },
+ { NLEFT, EAX }, { NRES, EAX },
+ { NORIGHT, EDX }, { NORIGHT, EAX }, { 0 } };
+ return s;
+ } else if (q->lshape & SCREG) {
+ static struct rspecial s[] = {
+ { NEVER, EAX }, { NEVER, EDX },
+ { NEVER, ECX }, { NRES, EAXEDX }, { 0 } };
+ return s;
+ }
+ break;
+ case MOD:
+ if (q->lshape == SBREG) {
+ static struct rspecial s[] = {
+ { NEVER, AL }, { NEVER, AH },
+ { NLEFT, AL }, { NRES, AH },
+ { NORIGHT, AH }, { NORIGHT, AL }, { 0 } };
+ return s;
+ } else if (q->lshape == SAREG) {
+ static struct rspecial s[] = {
+ { NEVER, EAX }, { NEVER, EDX },
+ { NLEFT, EAX }, { NRES, EDX },
+ { NORIGHT, EDX }, { NORIGHT, EAX }, { 0 } };
+ return s;
+ } else if (q->lshape & SCREG) {
+ static struct rspecial s[] = {
+ { NEVER, EAX }, { NEVER, EDX },
+ { NEVER, ECX }, { NRES, EAXEDX }, { 0 } };
+ return s;
+ }
+ break;
+ case MUL:
+ if (q->lshape == SBREG) {
+ static struct rspecial s[] = {
+ { NEVER, AL }, { NEVER, AH },
+ { NLEFT, AL }, { NRES, AL }, { 0 } };
+ return s;
+ } else if (q->lshape & SCREG) {
+ static struct rspecial s[] = {
+ { NEVER, EAX }, { NEVER, EDX },
+ { NEVER, ECX }, { NRES, EAXEDX }, { 0 } };
+ return s;
+ }
+ break;
+ case LS:
+ case RS:
+ if (q->visit & (INAREG|INBREG)) {
+ static struct rspecial s[] = {
+ { NRIGHT, CL }, { NOLEFT, ECX }, { 0 } };
+ return s;
+ } else if (q->visit & INCREG) {
+ static struct rspecial s[] = {
+ { NEVER, EAX }, { NEVER, EDX },
+ { NEVER, ECX }, { NRES, EAXEDX }, { 0 } };
+ return s;
+ }
+ break;
+
+ default:
+ break;
+ }
+ comperr("nspecial entry %d", q - table);
+ return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+ return 0; /* nothing differs on x86 */
+}
diff --git a/usr.bin/pcc/arch/x86/table.c b/usr.bin/pcc/arch/x86/table.c
new file mode 100644
index 00000000000..cf41ecb1bc4
--- /dev/null
+++ b/usr.bin/pcc/arch/x86/table.c
@@ -0,0 +1,1453 @@
+/* $Id: table.c,v 1.1 2007/09/15 18:12:31 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.
+ */
+
+
+# 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
+#define SHINT SAREG /* short and int */
+#define ININT INAREG
+#define SHCH SBREG /* shape for char */
+#define INCH INBREG
+#define SHLL SCREG /* shape for long long */
+#define INLL INCREG
+#define SHFL SDREG /* shape for float/double */
+#define INFL INDREG /* shape for float/double */
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are usually not necessary */
+{ PCONV, INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RLEFT,
+ "", },
+
+/*
+ * A bunch conversions of integral<->integral types
+ * There are lots of them, first in table conversions to itself
+ * and then conversions from each type to the others.
+ */
+
+/* itself to itself, including pointers */
+
+/* convert (u)char to (u)char. */
+{ SCONV, INCH,
+ SHCH, TCHAR|TUCHAR,
+ SHCH, TCHAR|TUCHAR,
+ 0, RLEFT,
+ "", },
+
+/* convert pointers to int. */
+{ SCONV, ININT,
+ SHINT, TPOINT|TWORD,
+ SANY, TWORD,
+ 0, RLEFT,
+ "", },
+
+/* convert (u)longlong to (u)longlong. */
+{ SCONV, INLL,
+ SHLL, TLL,
+ SHLL, TLL,
+ 0, RLEFT,
+ "", },
+
+/* convert double <-> float. nothing to do here */
+{ SCONV, INFL,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RLEFT,
+ "", },
+
+/* convert pointers to pointers. */
+{ SCONV, ININT,
+ SHINT, TPOINT,
+ SANY, TPOINT,
+ 0, RLEFT,
+ "", },
+
+/* char to something */
+
+/* convert char to (unsigned) short. */
+{ SCONV, ININT,
+ SBREG|SOREG|SNAME, TCHAR,
+ SAREG, TSHORT|TUSHORT,
+ NASL|NAREG, RESC1,
+ " movsbw AL,A1\n", },
+
+/* convert unsigned char to (u)short. */
+{ SCONV, ININT,
+ SHCH|SOREG|SNAME, TUCHAR,
+ SAREG, TSHORT|TUSHORT,
+ NASL|NAREG, RESC1,
+ " movzbw AL,A1\n", },
+
+/* convert signed char to int (or pointer). */
+{ SCONV, ININT,
+ SHCH|SOREG|SNAME, TCHAR,
+ SAREG, TWORD|TPOINT,
+ NASL|NAREG, RESC1,
+ " movsbl AL,A1\n", },
+
+/* convert unsigned char to (u)int. */
+{ SCONV, ININT,
+ SHCH|SOREG|SNAME, TUCHAR,
+ SAREG, TWORD,
+ NASL|NAREG, RESC1,
+ " movzbl AL,A1\n", },
+
+/* convert char to (u)long long */
+{ SCONV, INLL,
+ SHCH|SOREG|SNAME, TCHAR,
+ SANY, TLL,
+ NSPECIAL|NAREG|NASL, RESC1,
+ " movsbl AL,%eax\n cltd\n", },
+
+/* convert unsigned char to (u)long long */
+{ SCONV, INLL,
+ SHCH|SOREG|SNAME, TUCHAR,
+ SANY, TLL,
+ NCREG|NCSL, RESC1,
+ " movzbl AL,A1\n xorl U1,U1\n", },
+
+/* convert char (in register) to double XXX - use NTEMP */
+{ SCONV, INFL,
+ SHCH|SOREG|SNAME, TCHAR,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NAREG|NASL|NDREG, RESC2,
+ " movsbl AL,A1\n pushl A1\n"
+ " fildl (%esp)\n addl $4,%esp\n", },
+
+/* convert (u)char (in register) to double XXX - use NTEMP */
+{ SCONV, INFL,
+ SHCH|SOREG|SNAME, TUCHAR,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NAREG|NASL|NDREG, RESC2,
+ " movzbl AL,A1\n pushl A1\n"
+ " fildl (%esp)\n addl $4,%esp\n", },
+
+/* short to something */
+
+/* convert short (in memory) to char */
+{ SCONV, INCH,
+ SNAME|SOREG, TSHORT|TUSHORT,
+ SHCH, TCHAR|TUCHAR,
+ NBREG|NBSL, RESC1,
+ " movb AL,A1\n", },
+
+/* convert short (in reg) to char. */
+{ SCONV, INCH,
+ SAREG|SNAME|SOREG, TSHORT|TUSHORT,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL|NBREG|NBSL, RESC1,
+ "ZM", },
+
+/* convert short to (u)int. */
+{ SCONV, ININT,
+ SAREG|SOREG|SNAME, TSHORT,
+ SAREG, TWORD,
+ NASL|NAREG, RESC1,
+ " movswl AL,A1\n", },
+
+/* convert unsigned short to (u)int. */
+{ SCONV, ININT,
+ SAREG|SOREG|SNAME, TUSHORT,
+ SAREG, TWORD,
+ NASL|NAREG, RESC1,
+ " movzwl AL,A1\n", },
+
+/* convert short to (u)long long */
+{ SCONV, INLL,
+ SAREG|SOREG|SNAME, TSHORT,
+ SHLL, TLL,
+ NSPECIAL|NCREG|NCSL, RESC1,
+ " movswl AL,%eax\n cltd\n", },
+
+/* convert unsigned short to (u)long long */
+{ SCONV, INLL,
+ SAREG|SOREG|SNAME, TUSHORT,
+ SHLL, TLL,
+ NCREG|NCSL, RESC1,
+ " movzwl AL,A1\n xorl U1,U1\n", },
+
+/* convert short (in memory) to float/double */
+{ SCONV, INFL,
+ SOREG|SNAME, TSHORT,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ NDREG, RESC1,
+ " fild AL\n", },
+
+/* convert short (in register) to float/double */
+{ SCONV, INFL,
+ SAREG, TSHORT,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ NTEMP|NDREG, RESC1,
+ " pushw AL\n fild (%esp)\n addl $2,%esp\n", },
+
+/* convert unsigned short to double XXX - use NTEMP */
+{ SCONV, INFL,
+ SAREG|SOREG|SNAME, TUSHORT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NAREG|NASL|NDREG|NTEMP, RESC2,
+ " movzwl AL,A1\n pushl A1\n"
+ " fildl (%esp)\n addl $4,%esp\n", },
+
+/* int to something */
+
+/* convert int to char. This is done when register is loaded */
+{ SCONV, INCH,
+ SAREG, TWORD,
+ SANY, TCHAR|TUCHAR,
+ NSPECIAL|NBREG|NBSL, RESC1,
+ "ZM", },
+
+/* convert int to short. Nothing to do */
+{ SCONV, INAREG,
+ SAREG, TWORD,
+ SANY, TSHORT|TUSHORT,
+ 0, RLEFT,
+ "", },
+
+/* convert int to long long */
+{ SCONV, INLL,
+ SAREG, TWORD|TPOINT,
+ SCREG, TLONGLONG,
+ NSPECIAL|NCREG|NCSL, RESC1,
+ " cltd\n", },
+
+/* convert int to unsigned long long */
+{ SCONV, INLL,
+ SAREG|SOREG|SNAME, TWORD|TPOINT,
+ SHLL, TULONGLONG,
+ NCSL|NCREG, RESC1,
+ " movl AL,A1\n xorl U1,U1\n", },
+
+/* convert int (in memory) to double */
+{ SCONV, INFL,
+ SOREG|SNAME, TWORD,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NDREG, RESC1,
+ " fildl AL\n", },
+
+/* convert int (in register) to double */
+{ SCONV, INFL,
+ SAREG, TWORD,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NTEMP|NDREG, RESC1,
+ " pushl AL\n fildl (%esp)\n addl $4,%esp\n", },
+
+/* long long to something */
+
+/* convert (u)long long to (u)char (mem->reg) */
+{ SCONV, INCH,
+ SOREG|SNAME, TLL,
+ SANY, TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " movb AL,A1\n", },
+
+/* convert (u)long long to (u)char (reg->reg, hopefully nothing) */
+{ SCONV, INCH,
+ SHLL, TLL,
+ SANY, TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ "ZS", },
+
+/* convert (u)long long to (u)short (mem->reg) */
+{ SCONV, INAREG,
+ SOREG|SNAME, TLL,
+ SAREG, TSHORT|TUSHORT,
+ NAREG|NASL, RESC1,
+ " movw AL,A1\n", },
+
+/* convert (u)long long to (u)short (reg->reg, hopefully nothing) */
+{ SCONV, INAREG,
+ SHLL|SOREG|SNAME, TLL,
+ SAREG, TSHORT|TUSHORT,
+ NAREG|NASL, RESC1,
+ "ZS", },
+
+/* convert long long to int (mem->reg) */
+{ SCONV, INAREG,
+ SOREG|SNAME, TLL,
+ SAREG, TWORD|TPOINT,
+ NAREG|NASL, RESC1,
+ " movl AL,A1\n", },
+
+/* convert long long to int (reg->reg, hopefully nothing) */
+{ SCONV, INAREG,
+ SHLL|SOREG|SNAME, TLL,
+ SAREG, TWORD|TPOINT,
+ NAREG|NASL, RESC1,
+ "ZS", },
+
+/* convert long long (in memory) to floating */
+{ SCONV, INFL,
+ SOREG|SNAME, TLONGLONG,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NDREG, RESC1,
+ " fildq AL\n", },
+
+/* convert long long (in register) to floating */
+{ SCONV, INFL,
+ SHLL, TLONGLONG,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ NTEMP|NDREG, RESC1,
+ " pushl UL\n pushl AL\n"
+ " fildq (%esp)\n addl $8,%esp\n", },
+
+/* convert unsigned long long to floating */
+{ SCONV, INFL,
+ SCREG, TULONGLONG,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ NDREG, RESC1,
+ "ZJ", },
+
+/* float to something */
+
+#if 0 /* go via int by adding an extra sconv in clocal() */
+/* convert float/double to (u) char. XXX should use NTEMP here */
+{ SCONV, INCH,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NBREG, RESC1,
+ " subl $4,%esp\n fistpl (%esp)\n popl A1\n", },
+
+/* convert float/double to (u) int/short/char. XXX should use NTEMP here */
+{ SCONV, INCH,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NCREG, RESC1,
+ " subl $4,%esp\n fistpl (%esp)\n popl A1\n", },
+#endif
+
+/* convert float/double to (u)int. XXX should use NTEMP here */
+{ SCONV, INAREG,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SAREG, TWORD,
+ NAREG, RESC1,
+ " subl $4,%esp\n fistpl (%esp)\n popl A1\n", },
+
+/* convert float/double (in register) to (unsigned) long long */
+/* XXX - unsigned is not handled correct */
+{ SCONV, INLL,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHLL, TLONGLONG|TULONGLONG,
+ NCREG, RESC1,
+ " subl $8,%esp\n fistpq (%esp)\n"
+ " popl A1\n popl U1\n", },
+
+/* slut sconv */
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ 0, 0,
+ " call CL\nZC", },
+
+{ UCALL, FOREFF,
+ SCON, TANY,
+ SAREG, TWORD|TPOINT,
+ 0, 0,
+ " call CL\n", },
+
+{ CALL, INAREG,
+ SCON, TANY,
+ SAREG, TWORD|TPOINT,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " call CL\nZC", },
+
+{ UCALL, INAREG,
+ SCON, TANY,
+ SAREG, TWORD|TPOINT,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " call CL\n", },
+
+{ CALL, INBREG,
+ SCON, TANY,
+ SBREG, TCHAR|TUCHAR,
+ NBREG, RESC1, /* should be 0 */
+ " call CL\nZC", },
+
+{ UCALL, INBREG,
+ SCON, TANY,
+ SBREG, TCHAR|TUCHAR,
+ NBREG, RESC1, /* should be 0 */
+ " call CL\n", },
+
+{ CALL, INCREG,
+ SCON, TANY,
+ SCREG, TANY,
+ NCREG|NCSL, RESC1, /* should be 0 */
+ " call CL\nZC", },
+
+{ UCALL, INCREG,
+ SCON, TANY,
+ SCREG, TANY,
+ NCREG|NCSL, RESC1, /* should be 0 */
+ " call CL\n", },
+
+{ CALL, INDREG,
+ SCON, TANY,
+ SDREG, TANY,
+ NDREG|NDSL, RESC1, /* should be 0 */
+ " call CL\nZC", },
+
+{ UCALL, INDREG,
+ SCON, TANY,
+ SDREG, TANY,
+ NDREG|NDSL, RESC1, /* should be 0 */
+ " call CL\nZC", },
+
+{ CALL, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, 0,
+ " call *AL\nZC", },
+
+{ UCALL, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, 0,
+ " call *AL\nZC", },
+
+{ CALL, INAREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ UCALL, INAREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ CALL, INBREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NBREG|NBSL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ UCALL, INBREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NBREG|NBSL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ CALL, INCREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NCREG|NCSL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ UCALL, INCREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NCREG|NCSL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ CALL, INDREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NDREG|NDSL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+{ UCALL, INDREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NDREG|NDSL, RESC1, /* should be 0 */
+ " call *AL\nZC", },
+
+/* struct return */
+{ USTCALL, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, 0,
+ "ZP call CL\nZC", },
+
+{ USTCALL, INAREG,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ "ZP call CL\nZC", },
+
+{ USTCALL, INAREG,
+ SNAME|SAREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ "ZP call *AL\nZC", },
+
+{ STCALL, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, 0,
+ "ZP call CL\nZC", },
+
+{ STCALL, INAREG,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ "ZP call CL\nZC", },
+
+{ STCALL, INAREG,
+ SNAME|SAREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ "ZP call *AL\nZC", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+/* Special treatment for long long */
+{ PLUS, INLL|FOREFF,
+ SHLL, TLL,
+ SHLL|SNAME|SOREG, TLL,
+ 0, RLEFT,
+ " addl AR,AL\n adcl UR,UL\n", },
+
+/* Special treatment for long long XXX - fix commutative check */
+{ PLUS, INLL|FOREFF,
+ SHLL|SNAME|SOREG, TLL,
+ SHLL, TLL,
+ 0, RRIGHT,
+ " addl AL,AR\n adcl UL,UR\n", },
+
+{ PLUS, INFL,
+ SHFL, TDOUBLE,
+ SNAME|SOREG, TDOUBLE,
+ 0, RLEFT,
+ " faddl AR\n", },
+
+{ PLUS, INFL|FOREFF,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RLEFT,
+ " faddp\n", },
+
+{ PLUS, INAREG,
+ SAREG|SNAME|SOREG, TWORD|TPOINT,
+ SONE, TANY,
+ 0, RLEFT,
+ " incl AL\n", },
+
+{ PLUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SCON, TANY,
+ NAREG|NASL, RESC1,
+ " leal CR(AL),A1\n", },
+
+{ PLUS, INCH,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ SONE, TANY,
+ 0, RLEFT,
+ " incb AL\n", },
+
+{ PLUS, INAREG,
+ SAREG, TWORD,
+ SAREG, TWORD,
+ NAREG|NASL|NASR, RESC1,
+ " leal (AL,AR),A1\n", },
+
+
+/* address as register offset, negative */
+{ MINUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SPCON, TANY,
+ NAREG|NASL, RESC1,
+ " leal -CR(AL),A1\n", },
+
+{ MINUS, INLL|FOREFF,
+ SHLL, TLL,
+ SHLL|SNAME|SOREG, TLL,
+ 0, RLEFT,
+ " subl AR,AL\n sbbl UR,UL\n", },
+
+{ MINUS, INFL,
+ SHFL, TDOUBLE,
+ SNAME|SOREG, TDOUBLE,
+ 0, RLEFT,
+ " fsubl AR\n", },
+
+{ MINUS, INFL|FOREFF,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RLEFT,
+ " fsubZAp\n", },
+
+/* Simple r/m->reg ops */
+{ OPSIMP, INAREG|FOREFF,
+ SAREG, TWORD|TPOINT,
+ SAREG|SNAME|SOREG, TWORD|TPOINT,
+ 0, RLEFT,
+ " Ol AR,AL\n", },
+
+{ OPSIMP, INAREG|FOREFF,
+ SHINT, TSHORT|TUSHORT,
+ SHINT|SNAME|SOREG, TSHORT|TUSHORT,
+ 0, RLEFT,
+ " Ow AR,AL\n", },
+
+{ OPSIMP, INCH|FOREFF,
+ SHCH, TCHAR|TUCHAR,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ 0, RLEFT,
+ " Ob AR,AL\n", },
+
+{ OPSIMP, INAREG|FOREFF,
+ SAREG, TWORD|TPOINT,
+ SCON, TWORD|TPOINT,
+ 0, RLEFT,
+ " Ol AR,AL\n", },
+
+{ OPSIMP, INAREG|FOREFF,
+ SHINT|SNAME|SOREG, TSHORT|TUSHORT,
+ SCON, TANY,
+ 0, RLEFT,
+ " Ow AR,AL\n", },
+
+{ OPSIMP, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ SCON, TANY,
+ 0, RLEFT,
+ " Ob AR,AL\n", },
+
+{ OPSIMP, INLL|FOREFF,
+ SHLL, TLL,
+ SHLL|SNAME|SOREG, TLL,
+ 0, RLEFT,
+ " Ol AR,AL\n Ol UR,UL\n", },
+
+
+/*
+ * The next rules handle all shift operators.
+ */
+/* (u)longlong left shift is emulated */
+{ LS, INCREG,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ SAREG|SNAME|SOREG|SCON, TINT, /* will be int */
+ NSPECIAL|NCREG|NCSL|NCSR, RESC1,
+ "ZO", },
+
+{ LS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TWORD,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " sall AR,AL\n", },
+
+{ LS, INAREG|FOREFF,
+ SAREG, TWORD,
+ SCON, TANY,
+ 0, RLEFT,
+ " sall AR,AL\n", },
+
+{ LS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TSHORT|TUSHORT,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " shlw AR,AL\n", },
+
+{ LS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TSHORT|TUSHORT,
+ SCON, TANY,
+ 0, RLEFT,
+ " shlw AR,AL\n", },
+
+{ LS, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " salb AR,AL\n", },
+
+{ LS, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ SCON, TANY,
+ 0, RLEFT,
+ " salb AR,AL\n", },
+
+/* (u)longlong right shift is emulated */
+{ RS, INCREG,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ SAREG|SNAME|SOREG|SCON, TINT, /* will be int */
+ NSPECIAL|NCREG|NCSL|NCSR, RESC1,
+ "ZO", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TSWORD,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " sarl AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TSWORD,
+ SCON, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ 0, RLEFT,
+ " sarl AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TUWORD,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " shrl AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TUWORD,
+ SCON, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+ 0, RLEFT,
+ " shrl AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TSHORT,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " sarw AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TSHORT,
+ SCON, TANY,
+ 0, RLEFT,
+ " sarw AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TUSHORT,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " shrw AR,AL\n", },
+
+{ RS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TUSHORT,
+ SCON, TANY,
+ 0, RLEFT,
+ " shrw AR,AL\n", },
+
+{ RS, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TCHAR,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " sarb AR,AL\n", },
+
+{ RS, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TCHAR,
+ SCON, TANY,
+ 0, RLEFT,
+ " sarb AR,AL\n", },
+
+{ RS, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TUCHAR,
+ SHCH, TCHAR|TUCHAR,
+ NSPECIAL, RLEFT,
+ " shrb AR,AL\n", },
+
+{ RS, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TUCHAR,
+ SCON, TANY,
+ 0, RLEFT,
+ " shrb AR,AL\n", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+{ ASSIGN, FOREFF,
+ SHLL|SNAME|SOREG, TLL,
+ SCON, TANY,
+ 0, 0,
+ " movl AR,AL\n movl UR,UL\n", },
+
+{ ASSIGN, FOREFF|INLL,
+ SHLL, TLL,
+ SCON, TANY,
+ 0, RDEST,
+ " movl AR,AL\n movl UR,UL\n", },
+
+{ ASSIGN, FOREFF,
+ SAREG|SNAME|SOREG, TWORD|TPOINT,
+ SCON, TANY,
+ 0, 0,
+ " movl AR,AL\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TWORD|TPOINT,
+ SCON, TANY,
+ 0, RDEST,
+ " movl AR,AL\n", },
+
+{ ASSIGN, FOREFF,
+ SAREG|SNAME|SOREG, TSHORT|TUSHORT,
+ SCON, TANY,
+ 0, 0,
+ " movw AR,AL\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TSHORT|TUSHORT,
+ SCON, TANY,
+ 0, RDEST,
+ " movw AR,AL\n", },
+
+{ ASSIGN, FOREFF,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ SCON, TANY,
+ 0, 0,
+ " movb AR,AL\n", },
+
+{ ASSIGN, FOREFF|INCH,
+ SHCH, TCHAR|TUCHAR,
+ SCON, TANY,
+ 0, RDEST,
+ " movb AR,AL\n", },
+
+{ ASSIGN, FOREFF|INLL,
+ SHLL|SNAME|SOREG, TLL,
+ SHLL, TLL,
+ 0, RDEST,
+ " movl AR,AL\n movl UR,UL\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SAREG|SNAME|SOREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RDEST,
+ " movl AR,AL\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG|SNAME|SOREG, TWORD|TPOINT,
+ 0, RDEST,
+ " movl AR,AL\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SAREG|SNAME|SOREG, TSHORT|TUSHORT,
+ SAREG, TSHORT|TUSHORT,
+ 0, RDEST,
+ " movw AR,AL\n", },
+
+{ ASSIGN, FOREFF|INCH,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ SHCH, TCHAR|TUCHAR|TWORD,
+ 0, RDEST,
+ " movb AR,AL\n", },
+
+{ ASSIGN, FOREFF|INBREG,
+ SFLD, TCHAR|TUCHAR,
+ SBREG|SCON, TCHAR|TUCHAR,
+ NBREG, RDEST,
+ "ZE", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SFLD, TANY,
+ SAREG, TANY,
+ NAREG, RDEST,
+ "ZE", },
+
+{ ASSIGN, FOREFF,
+ SFLD, TANY,
+ SAREG|SNAME|SOREG|SCON, TANY,
+ NAREG, 0,
+ "ZE", },
+
+{ ASSIGN, INDREG|FOREFF,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, RDEST,
+ "", }, /* This will always be in the correct register */
+
+/* order of table entries is very important here! */
+{ ASSIGN, INFL,
+ SNAME|SOREG, TLDOUBLE,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, RDEST,
+ " fstt AL\n", },
+
+{ ASSIGN, FOREFF,
+ SNAME|SOREG, TLDOUBLE,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, 0,
+ " fstpt AL\n", },
+
+{ ASSIGN, INFL,
+ SNAME|SOREG, TDOUBLE,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, RDEST,
+ " fstl AL\n", },
+
+{ ASSIGN, FOREFF,
+ SNAME|SOREG, TDOUBLE,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, 0,
+ " fstpl AL\n", },
+
+{ ASSIGN, INFL,
+ SNAME|SOREG, TFLOAT,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, RDEST,
+ " fsts AL\n", },
+
+{ ASSIGN, FOREFF,
+ SNAME|SOREG, TFLOAT,
+ SHFL, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, 0,
+ " fstps AL\n", },
+/* end very important order */
+
+{ ASSIGN, INFL|FOREFF,
+ SHFL, TLDOUBLE,
+ SHFL|SOREG|SNAME, TLDOUBLE,
+ 0, RDEST,
+ " fldt AR\n", },
+
+{ ASSIGN, INFL|FOREFF,
+ SHFL, TDOUBLE,
+ SHFL|SOREG|SNAME, TDOUBLE,
+ 0, RDEST,
+ " fldl AR\n", },
+
+{ ASSIGN, INFL|FOREFF,
+ SHFL, TFLOAT,
+ SHFL|SOREG|SNAME, TFLOAT,
+ 0, RDEST,
+ " flds AR\n", },
+
+/* Do not generate memcpy if return from funcall */
+#if 0
+{ STASG, INAREG|FOREFF,
+ SOREG|SNAME|SAREG, TPTRTO|TSTRUCT,
+ SFUNCALL, TPTRTO|TSTRUCT,
+ 0, RRIGHT,
+ "", },
+#endif
+
+{ STASG, INAREG|FOREFF,
+ SOREG|SNAME, TANY,
+ SAREG|SOREG|SNAME, TPTRTO|TANY,
+ NSPECIAL, RRIGHT,
+ "ZQ", },
+
+/*
+ * DIV/MOD/MUL
+ */
+/* long long div is emulated */
+{ DIV, INCREG,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ NSPECIAL|NCREG|NCSL|NCSR, RESC1,
+ "ZO", },
+
+{ DIV, INAREG,
+ SAREG, TSWORD,
+ SAREG|SNAME|SOREG, TWORD,
+ NSPECIAL, RDEST,
+ " cltd\n idivl AR\n", },
+
+{ DIV, INAREG,
+ SAREG, TUWORD|TPOINT,
+ SAREG|SNAME|SOREG, TUWORD|TPOINT,
+ NSPECIAL, RDEST,
+ " xorl %edx,%edx\n divl AR\n", },
+
+{ DIV, INAREG,
+ SAREG, TUSHORT,
+ SAREG|SNAME|SOREG, TUSHORT,
+ NSPECIAL, RDEST,
+ " xorl %edx,%edx\n divw AR\n", },
+
+{ DIV, INCH,
+ SHCH, TUCHAR,
+ SHCH|SNAME|SOREG, TUCHAR,
+ NSPECIAL, RDEST,
+ " xorb %ah,%ah\n divb AR\n", },
+
+{ DIV, INFL,
+ SHFL, TDOUBLE,
+ SNAME|SOREG, TDOUBLE,
+ 0, RLEFT,
+ " fdivl AR\n", },
+
+{ DIV, INFL,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RLEFT,
+ " fdivZAp\n", },
+
+/* (u)longlong mod is emulated */
+{ MOD, INCREG,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ NSPECIAL|NCREG|NCSL|NCSR, RESC1,
+ "ZO", },
+
+{ MOD, INAREG,
+ SAREG, TSWORD,
+ SAREG|SNAME|SOREG, TSWORD,
+ NAREG|NSPECIAL, RESC1,
+ " cltd\n idivl AR\n", },
+
+{ MOD, INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG|SNAME|SOREG, TUWORD|TPOINT,
+ NAREG|NSPECIAL, RESC1,
+ " xorl %edx,%edx\n divl AR\n", },
+
+{ MOD, INAREG,
+ SAREG, TUSHORT,
+ SAREG|SNAME|SOREG, TUSHORT,
+ NAREG|NSPECIAL, RESC1,
+ " xorl %edx,%edx\n divw AR\n", },
+
+{ MOD, INCH,
+ SHCH, TUCHAR,
+ SHCH|SNAME|SOREG, TUCHAR,
+ NBREG|NSPECIAL, RESC1,
+ " xorb %ah,%ah\n divb AR\n", },
+
+/* (u)longlong mul is emulated */
+{ MUL, INCREG,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ SCREG|SNAME|SOREG|SCON, TLL,
+ NSPECIAL|NCREG|NCSL|NCSR, RESC1,
+ "ZO", },
+
+{ MUL, INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG|SNAME|SOREG|SCON, TWORD|TPOINT,
+ 0, RLEFT,
+ " imull AR,AL\n", },
+
+{ MUL, INAREG,
+ SAREG, TSHORT|TUSHORT,
+ SAREG|SNAME|SOREG, TSHORT|TUSHORT,
+ 0, RLEFT,
+ " imulw AR,AL\n", },
+
+{ MUL, INCH,
+ SHCH, TCHAR|TUCHAR,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ NSPECIAL, RDEST,
+ " imulb AR\n", },
+
+{ MUL, INFL,
+ SHFL, TDOUBLE,
+ SNAME|SOREG, TDOUBLE,
+ 0, RLEFT,
+ " fmull AR\n", },
+
+{ MUL, INFL,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RLEFT,
+ " fmulp\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL, INLL,
+ SANY, TANY,
+ SOREG, TLL,
+ NCREG|NCSL, RESC1,
+ " movl UL,U1\n movl AL,A1\n", },
+
+{ UMUL, INAREG,
+ SANY, TPOINT|TWORD,
+ SOREG, TPOINT|TWORD,
+ NAREG|NASL, RESC1,
+ " movl AL,A1\n", },
+
+{ UMUL, INCH,
+ SANY, TANY,
+ SOREG, TCHAR|TUCHAR,
+ NBREG|NBSL, RESC1,
+ " movb AL,A1\n", },
+
+{ UMUL, INAREG,
+ SANY, TANY,
+ SOREG, TSHORT|TUSHORT,
+ NAREG|NASL, RESC1,
+ " movw AL,A1\n", },
+
+{ UMUL, INFL,
+ SANY, TANY,
+ SOREG, TLDOUBLE,
+ NDREG|NDSL, RESC1,
+ " fldt AL\n", },
+
+{ UMUL, INFL,
+ SANY, TANY,
+ SOREG, TDOUBLE,
+ NDREG|NDSL, RESC1,
+ " fldl AL\n", },
+
+{ UMUL, INFL,
+ SANY, TANY,
+ SOREG, TFLOAT,
+ NDREG|NDSL, RESC1,
+ " flds AL\n", },
+
+/*
+ * Logical/branching operators
+ */
+
+/* Comparisions, take care of everything */
+{ OPLOG, FORCC,
+ SHLL|SOREG|SNAME, TLL,
+ SHLL, TLL,
+ 0, 0,
+ "ZD", },
+
+{ OPLOG, FORCC,
+ SAREG|SOREG|SNAME, TWORD|TPOINT,
+ SCON|SAREG, TWORD|TPOINT,
+ 0, RESCC,
+ " cmpl AR,AL\n", },
+
+{ OPLOG, FORCC,
+ SCON|SAREG, TWORD|TPOINT,
+ SAREG|SOREG|SNAME, TWORD|TPOINT,
+ 0, RESCC,
+ " cmpl AR,AL\n", },
+
+{ OPLOG, FORCC,
+ SAREG|SOREG|SNAME, TSHORT|TUSHORT,
+ SCON|SAREG, TANY,
+ 0, RESCC,
+ " cmpw AR,AL\n", },
+
+{ OPLOG, FORCC,
+ SBREG|SOREG|SNAME, TCHAR|TUCHAR,
+ SCON|SBREG, TANY,
+ 0, RESCC,
+ " cmpb AR,AL\n", },
+
+{ OPLOG, FORCC,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ NSPECIAL, 0,
+ "ZG", },
+
+{ OPLOG, FORCC,
+ SOREG|SNAME, TDOUBLE|TFLOAT,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ NSPECIAL, 0,
+ "ZG", },
+
+#if 0
+/* Ppro and later only */
+{ OPLOG, FORCC,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ SDREG, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RESCC,
+ "ZA fucomip %st,%st(1)\n", },
+#endif
+
+{ OPLOG, FORCC,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, 0,
+ "diediedie!", },
+
+/* AND/OR/ER/NOT */
+{ AND, INAREG|FOREFF,
+ SAREG|SOREG|SNAME, TWORD,
+ SCON|SAREG, TWORD,
+ 0, RLEFT,
+ " andl AR,AL\n", },
+
+{ AND, INCREG|FOREFF,
+ SCREG, TLL,
+ SCREG|SOREG|SNAME, TLL,
+ 0, RLEFT,
+ " andl AR,AL\n andl UR,UL\n", },
+
+{ AND, INAREG|FOREFF,
+ SAREG, TWORD,
+ SAREG|SOREG|SNAME, TWORD,
+ 0, RLEFT,
+ " andl AR,AL\n", },
+
+{ AND, INAREG|FOREFF,
+ SAREG|SOREG|SNAME, TSHORT|TUSHORT,
+ SCON|SAREG, TSHORT|TUSHORT,
+ 0, RLEFT,
+ " andw AR,AL\n", },
+
+{ AND, INAREG|FOREFF,
+ SAREG, TSHORT|TUSHORT,
+ SAREG|SOREG|SNAME, TSHORT|TUSHORT,
+ 0, RLEFT,
+ " andw AR,AL\n", },
+
+{ AND, INBREG|FOREFF,
+ SBREG|SOREG|SNAME, TCHAR|TUCHAR,
+ SCON|SBREG, TCHAR|TUCHAR,
+ 0, RLEFT,
+ " andb AR,AL\n", },
+
+{ AND, INBREG|FOREFF,
+ SBREG, TCHAR|TUCHAR,
+ SBREG|SOREG|SNAME, TCHAR|TUCHAR,
+ 0, RLEFT,
+ " andb AR,AL\n", },
+/* AND/OR/ER/NOT */
+
+/*
+ * Jumps.
+ */
+{ GOTO, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ 0, RNOP,
+ " jmp LL\n", },
+
+#ifdef GCC_COMPAT
+{ GOTO, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, RNOP,
+ " jmp *AL\n", },
+#endif
+
+/*
+ * Convert LTYPE to reg.
+ */
+{ OPLTYPE, INLL,
+ SANY, TANY,
+ SCREG|SCON|SOREG|SNAME, TLL,
+ NCREG, RESC1,
+ " movl UL,U1\n movl AL,A1\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SAREG|SCON|SOREG|SNAME, TWORD|TPOINT,
+ NAREG|NASL, RESC1,
+ " movl AL,A1\n", },
+
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SBREG|SOREG|SNAME|SCON, TCHAR|TUCHAR,
+ NBREG, RESC1,
+ " movb AL,A1\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SAREG|SOREG|SNAME|SCON, TSHORT|TUSHORT,
+ NAREG, RESC1,
+ " movw AL,A1\n", },
+
+{ OPLTYPE, INDREG,
+ SANY, TLDOUBLE,
+ SOREG|SNAME, TLDOUBLE,
+ NDREG, RESC1,
+ " fldt AL\n", },
+
+{ OPLTYPE, INDREG,
+ SANY, TDOUBLE,
+ SOREG|SNAME, TDOUBLE,
+ NDREG, RESC1,
+ " fldl AL\n", },
+
+{ OPLTYPE, INDREG,
+ SANY, TFLOAT,
+ SOREG|SNAME, TFLOAT,
+ NDREG, RESC1,
+ " flds AL\n", },
+
+/* Only used in ?: constructs. The stack already contains correct value */
+{ OPLTYPE, INDREG,
+ SANY, TFLOAT|TDOUBLE|TLDOUBLE,
+ SDREG, TFLOAT|TDOUBLE|TLDOUBLE,
+ NDREG, RESC1,
+ "", },
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS, INCREG|FOREFF,
+ SCREG, TLL,
+ SCREG, TLL,
+ 0, RLEFT,
+ " negl AL\n adcl $0,UL\n negl UL\n", },
+
+{ UMINUS, INAREG|FOREFF,
+ SAREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RLEFT,
+ " negl AL\n", },
+
+{ UMINUS, INAREG|FOREFF,
+ SAREG, TSHORT|TUSHORT,
+ SAREG, TSHORT|TUSHORT,
+ 0, RLEFT,
+ " negw AL\n", },
+
+{ UMINUS, INBREG|FOREFF,
+ SBREG, TCHAR|TUCHAR,
+ SBREG, TCHAR|TUCHAR,
+ 0, RLEFT,
+ " negb AL\n", },
+
+{ UMINUS, INFL|FOREFF,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ SHFL, TLDOUBLE|TDOUBLE|TFLOAT,
+ 0, RLEFT,
+ " fchs\n", },
+
+{ COMPL, INCREG,
+ SCREG, TLL,
+ SANY, TANY,
+ 0, RLEFT,
+ " notl AL\n notl UL\n", },
+
+{ COMPL, INAREG,
+ SAREG, TWORD,
+ SANY, TANY,
+ 0, RLEFT,
+ " notl AL\n", },
+
+{ COMPL, INAREG,
+ SAREG, TSHORT|TUSHORT,
+ SANY, TANY,
+ 0, RLEFT,
+ " notw AL\n", },
+
+{ COMPL, INBREG,
+ SBREG, TCHAR|TUCHAR,
+ SANY, TANY,
+ 0, RLEFT,
+ " notb AL\n", },
+
+/*
+ * Arguments to functions.
+ */
+{ FUNARG, FOREFF,
+ SCON|SCREG|SNAME|SOREG, TLL,
+ SANY, TLL,
+ 0, RNULL,
+ " pushl UL\n pushl AL\n", },
+
+{ FUNARG, FOREFF,
+ SCON|SAREG|SNAME|SOREG, TWORD|TPOINT,
+ SANY, TWORD|TPOINT,
+ 0, RNULL,
+ " pushl AL\n", },
+
+{ FUNARG, FOREFF,
+ SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SANY, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ 0, RNULL,
+ " pushl AL\n", },
+
+{ FUNARG, FOREFF,
+ SAREG|SNAME|SOREG, TSHORT,
+ SANY, TSHORT,
+ NAREG, 0,
+ " movswl AL,ZN\n pushl ZN\n", },
+
+{ FUNARG, FOREFF,
+ SAREG|SNAME|SOREG, TUSHORT,
+ SANY, TUSHORT,
+ NAREG, 0,
+ " movzwl AL,ZN\n pushl ZN\n", },
+
+{ FUNARG, FOREFF,
+ SHCH|SNAME|SOREG, TCHAR,
+ SANY, TCHAR,
+ NAREG, 0,
+ " movsbl AL,A1\n pushl A1\n", },
+
+{ FUNARG, FOREFF,
+ SHCH|SNAME|SOREG, TUCHAR,
+ SANY, TUCHAR,
+ NAREG, 0,
+ " movzbl AL,A1\n pushl A1\n", },
+
+{ FUNARG, FOREFF,
+ SNAME|SOREG, TDOUBLE,
+ SANY, TDOUBLE,
+ 0, 0,
+ " pushl UL\n pushl AL\n", },
+
+{ FUNARG, FOREFF,
+ SDREG, TDOUBLE,
+ SANY, TDOUBLE,
+ 0, 0,
+ " subl $8,%esp\n fstpl (%esp)\n", },
+
+{ FUNARG, FOREFF,
+ SNAME|SOREG, TFLOAT,
+ SANY, TFLOAT,
+ 0, 0,
+ " pushl AL\n", },
+
+{ FUNARG, FOREFF,
+ SDREG, TFLOAT,
+ SANY, TFLOAT,
+ 0, 0,
+ " subl $4,%esp\n fstps (%esp)\n", },
+
+{ FUNARG, FOREFF,
+ SDREG, TLDOUBLE,
+ SANY, TLDOUBLE,
+ 0, 0,
+ " subl $12,%esp\n fstpt (%esp)\n", },
+
+{ STARG, FOREFF,
+ SAREG|SOREG|SNAME|SCON, TANY,
+ SANY, TSTRUCT,
+ NSPECIAL|NAREG, 0,
+ "ZF", },
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);