summaryrefslogtreecommitdiff
path: root/usr.bin/pcc
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2007-11-25 18:45:07 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2007-11-25 18:45:07 +0000
commit3c2f541d3e23df847b1c1a21f4b872d9dbf7a77f (patch)
treea76920c888f85b6fb1f9f4468c2e490081c15d20 /usr.bin/pcc
parent65aba424613ac0024be70850b638392a82317dba (diff)
arm backend from Gregory McGarry, untested
Diffstat (limited to 'usr.bin/pcc')
-rw-r--r--usr.bin/pcc/arm/code.c451
-rw-r--r--usr.bin/pcc/arm/local.c640
-rw-r--r--usr.bin/pcc/arm/local2.c954
-rw-r--r--usr.bin/pcc/arm/macdefs.h229
-rw-r--r--usr.bin/pcc/arm/order.c293
-rw-r--r--usr.bin/pcc/arm/table.c1501
6 files changed, 4068 insertions, 0 deletions
diff --git a/usr.bin/pcc/arm/code.c b/usr.bin/pcc/arm/code.c
new file mode 100644
index 00000000000..76004e533e9
--- /dev/null
+++ b/usr.bin/pcc/arm/code.c
@@ -0,0 +1,451 @@
+/* $OpenBSD: code.c,v 1.1 2007/11/25 18:45:06 otto Exp $ */
+/*
+ * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
+ * 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.
+ */
+
+/*
+ * Stuff for pass1.
+ */
+
+#include <assert.h>
+
+#include "pass1.h"
+#include "pass2.h"
+
+/*
+ * Modify the alignment in the data section to become a multiple of n.
+ */
+void
+defalign(int n)
+{
+ n /= SZCHAR;
+ if (n == 1)
+ return;
+ printf("\t.align %d\n", n);
+}
+
+/*
+ * Define the current location as an internal label.
+ */
+void
+deflab(int label)
+{
+ printf(LABFMT ":\n", label);
+}
+
+/*
+ * Define the current location in the data section to be 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("\t.global %s\n", exname(c));
+ printf("%s:\n", exname(c));
+}
+
+int rvnr;
+
+/*
+ * End-of-Function code:
+ */
+void
+efcode()
+{
+ NODE *p, *q;
+ int tempnr;
+
+ if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+ return;
+
+ /*
+ * At this point, the address of the return structure on
+ * has been FORCEd to RETREG, which is R0.
+ * We want to copy the contents from there to the address
+ * we placed into the tempnode "rvnr".
+ */
+
+ /* move the pointer out of R0 to a tempnode */
+ q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
+ q->n_rval = R0;
+ p = tempnode(0, PTR+STRTY, 0, cftnsp->ssue);
+ tempnr = p->n_lval;
+ p = buildtree(ASSIGN, p, q);
+ ecomp(p);
+
+ /* get the address from the tempnode */
+ q = tempnode(tempnr, PTR+STRTY, 0, cftnsp->ssue);
+ q = buildtree(UMUL, q, NIL);
+
+ /* now, get the structure destination */
+ p = tempnode(rvnr, PTR+STRTY, 0, cftnsp->ssue);
+ p = buildtree(UMUL, p, NIL);
+
+ /* struct assignment */
+ p = buildtree(ASSIGN, p, q);
+ ecomp(p);
+}
+
+/*
+ * Beginning-of-function code:
+ *
+ * 'a' is an array of indices in symtab for the arguments
+ * 'n' is the number of arguments
+ */
+void
+bfcode(struct symtab **sp, int cnt)
+{
+ NODE *p, *q;
+ int i, n, start = 0;
+
+ /* if returning a structure, more the hidden argument into a TEMP */
+ if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+ p = tempnode(0, PTR+STRTY, 0, cftnsp->ssue);
+ rvnr = p->n_lval;
+ q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
+ q->n_rval = start++;
+ p = buildtree(ASSIGN, p, q);
+ ecomp(p);
+ }
+
+ /* recalculate the arg offset and create TEMP moves */
+ for (n = start, i = 0; i < cnt; i++) {
+ int sz = szty(sp[i]->stype);
+ if (n + sz <= 4) {
+ /* put stack args in temps */
+ p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->ssue);
+ spname = sp[i];
+ q = block(REG, NIL, NIL,
+ sp[i]->stype, sp[i]->sdf, sp[i]->ssue);
+ q->n_rval = (sz == 2 ? R0R1 + n : R0+n);
+ p = buildtree(ASSIGN, p, q);
+ sp[i]->soffset = p->n_left->n_lval;
+ sp[i]->sflags |= STNODE;
+ ecomp(p);
+ } else {
+ sp[i]->soffset -= SZINT * 4;
+ if (xtemps) {
+ /* put stack args in temps if optimizing */
+ spname = sp[i];
+ p = tempnode(0, sp[i]->stype,
+ sp[i]->sdf, sp[i]->ssue);
+ p = buildtree(ASSIGN, p, buildtree(NAME, 0, 0));
+ sp[i]->soffset = p->n_left->n_lval;
+ sp[i]->sflags |= STNODE;
+ ecomp(p);
+ }
+
+ }
+ n += szty(sp[i]->stype);
+ }
+}
+
+
+/*
+ * Beginning-of-code: finished generating function prologue
+ *
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+ SETOFF(autooff, SZINT);
+}
+
+/*
+ * End-of-job: called just before final exit.
+ */
+void
+ejobcode(int flag )
+{
+#define OSB(x) __STRING(x)
+#define OS OSB(TARGOS)
+ printf("\t.ident \"%s (%s)\"\n", PACKAGE_STRING, OS);
+}
+
+/*
+ * Beginning-of-job: called before compilation starts
+ *
+ * Initialise data structures specific for the local machine.
+ */
+void
+bjobcode()
+{
+}
+
+/*
+ * Output ascii string: print character 't' at position 'i' until 't' == -1.
+ */
+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);
+ }
+ }
+}
+
+/*
+ * Compute the alignment of object with type 't'.
+ */
+int
+fldal(unsigned int t)
+{
+ uerror("illegal field type");
+ return(ALINT);
+}
+
+/*
+ * fix up type of field p
+ */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * Build target-dependent switch tree/table.
+ *
+ * Return 1 if successfull, otherwise return 0 and the
+ * target-independent tree will be used.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+ return 0;
+}
+
+static int regoff[7];
+static TWORD ftype;
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog *ipp)
+{
+ int i, j, addto;
+
+#ifdef PCC_DEBUG
+ if (x2debug)
+ printf("offcalc: p2maxautooff=%d\n", p2maxautooff);
+#endif
+
+ addto = p2maxautooff;
+
+ // space is always allocated on the stack to save the permanents
+ for (i = ipp->ipp_regs, j = 0; i ; i >>= 1, j++) {
+ if (i & 1) {
+ addto += SZINT/SZCHAR;
+ regoff[j] = addto;
+ }
+ }
+
+#if 0
+ addto += 7;
+ addto &= ~7;
+#endif
+
+#ifdef PCC_DEBUG
+ if (x2debug)
+ printf("offcalc: addto=%d\n", addto);
+#endif
+
+ addto -= AUTOINIT / SZCHAR;
+
+ return addto;
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+ int i, j;
+ int addto;
+
+#ifdef PCC_DEBUG
+ if (x2debug)
+ printf("prologue: type=%d, lineno=%d, name=%s, vis=%d, ipptype=%d, regs=0x%x, autos=%d, tmpnum=%d, lblnum=%d\n",
+ ipp->ipp_ip.type,
+ ipp->ipp_ip.lineno,
+ ipp->ipp_name,
+ ipp->ipp_vis,
+ ipp->ipp_type,
+ ipp->ipp_regs,
+ ipp->ipp_autos,
+ ipp->ip_tmpnum,
+ ipp->ip_lblnum);
+#endif
+
+ ftype = ipp->ipp_type;
+
+ printf("\t.align 2\n");
+ if (ipp->ipp_vis)
+ printf("\t.global %s\n", exname(ipp->ipp_name));
+ printf("\t.type %s,%%function\n", exname(ipp->ipp_name));
+ printf("%s:\n", exname(ipp->ipp_name));
+
+ /*
+ * We here know what register to save and how much to
+ * add to the stack.
+ */
+ addto = offcalc(ipp);
+
+ printf("\tmov %s,%s\n", rnames[IP], rnames[SP]);
+ printf("\tstmfd %s!,{%s,%s,%s,%s}\n", rnames[SP], rnames[FP],
+ rnames[IP], rnames[LR], rnames[PC]);
+ printf("\tsub %s,%s,#4\n", rnames[FP], rnames[IP]);
+ if (addto)
+ printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], addto);
+
+ for (i = ipp->ipp_regs, j = 0; i; i >>= 1, j++) {
+ if (i & 1) {
+ printf("\tstr %s,[%s,#-%d]\n",
+ rnames[j], rnames[FP], regoff[j]);
+ }
+ }
+
+}
+
+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)
+ printf("\tldr %s,[%s,#-%d]\n",
+ rnames[j], rnames[FP], regoff[j]);
+
+ }
+
+ /* struct return needs special treatment */
+ if (ftype == STRTY || ftype == UNIONTY) {
+ assert(0);
+ } else {
+ printf("\tldmea %s,{%s,%s,%s}\n", rnames[FP], rnames[FP],
+ rnames[SP], rnames[PC]);
+ }
+ printf("\t.size %s,.-%s\n", exname(ipp->ipp_name),
+ exname(ipp->ipp_name));
+}
+
+char *rnames[] = {
+ "r0", "r1", "r2", "r3","r4","r5", "r6", "r7", "r8",
+ "r9", "r10", "fp", "ip", "sp", "lr", "pc",
+ "r0r1", "r1r2", "r2r3", "r3r4", "r4r5", "r5r6",
+ "r6r7", "r7r8", "r8r9", "r9r10",
+};
+
+static void
+moveargs(NODE **n, int *regp)
+{
+ NODE *r = *n;
+ NODE *t;
+ int sz;
+ int regnum;
+
+ if (r->n_op == CM) {
+ moveargs(&r->n_left, regp);
+ n = &r->n_right;
+ r = r->n_right;
+ }
+
+ regnum = *regp;
+ sz = szty(r->n_type);
+
+ if (regnum + sz <= R4) {
+ t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_sue);
+ switch (r->n_type) {
+ case DOUBLE:
+ case LDOUBLE:
+#if defined(ARM_HAS_FPA) || defined(ARM_HAS_VFP)
+ t->n_rval = regnum + F0;
+ break;
+#endif
+ case LONGLONG:
+ case ULONGLONG:
+ t->n_rval = regnum + R0R1;
+ break;
+ default:
+ t->n_rval = regnum;
+ }
+ t = buildtree(ASSIGN, t, r);
+ } else {
+ t = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_sue);
+ }
+
+ *n = t;
+ *regp += sz;
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+ int regnum = R0;
+ int ty;
+
+ ty = DECREF(p->n_left->n_type);
+ if (ty == STRTY+FTN || ty == UNIONTY+FTN)
+ regnum = R1;
+
+ moveargs(&p->n_right, &regnum);
+ return p;
+}
diff --git a/usr.bin/pcc/arm/local.c b/usr.bin/pcc/arm/local.c
new file mode 100644
index 00000000000..70e9bfb4419
--- /dev/null
+++ b/usr.bin/pcc/arm/local.c
@@ -0,0 +1,640 @@
+/* $OpenBSD: local.c,v 1.1 2007/11/25 18:45:06 otto Exp $ */
+/*
+ * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
+ * 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.
+ */
+
+/*
+ * We define location operations which operate on the expression tree
+ * during the first pass (before sending to the backend for code generation.)
+ */
+
+#include <assert.h>
+
+#include "pass1.h"
+
+/*
+ * clocal() is called to do local transformations on
+ * an expression tree before being sent to the backend.
+ */
+NODE *
+clocal(NODE *p)
+{
+ struct symtab *q;
+ NODE *l, *r, *t;
+ int o;
+ int ty;
+
+ o = p->n_op;
+ switch (o) {
+
+ case STASG:
+
+ l = p->n_left;
+ r = p->n_right;
+ if (r->n_op == STCALL || r->n_op == USTCALL) {
+ /* assign left node as first argument to function */
+ nfree(p);
+ t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_sue);
+ l->n_rval = R0;
+ l = buildtree(ADDROF, l, NIL);
+ l = buildtree(ASSIGN, t, l);
+ ecomp(l);
+ t = tempnode(0, r->n_type, r->n_df, r->n_sue);
+ r = buildtree(ASSIGN, t, r);
+ ecomp(r);
+ t = tempnode(t->n_lval, r->n_type, r->n_df, r->n_sue);
+ return t;
+ }
+ break;
+
+#if 0
+ case CALL:
+ r = tempnode(0, p->n_type, p->n_df, p->n_sue);
+ ecomp(buildtree(ASSIGN, r, p));
+ return r;
+#endif
+
+ case NAME:
+ if ((q = p->n_sp) == NULL)
+ return p;
+ if (blevel == 0)
+ return p;
+
+ 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 REGISTER:
+ p->n_op = REG;
+ p->n_lval = 0;
+ p->n_rval = q->soffset;
+ break;
+ case STATIC:
+ if (q->slevel > 0) {
+ p->n_lval = 0;
+ p->n_sp = q;
+ }
+ break;
+ default:
+ ty = p->n_type;
+ p = block(ADDROF, p, NIL, INCREF(ty), p->n_df, p->n_sue);
+ p = block(UMUL, p, NIL, ty, p->n_df, p->n_sue);
+ break;
+ }
+ break;
+
+ case STNAME:
+ if ((q = p->n_sp) == NULL)
+ return p;
+ if (q->sclass != STNAME)
+ return p;
+ ty = p->n_type;
+ p = block(ADDROF, p, NIL, INCREF(ty),
+ p->n_df, p->n_sue);
+ p = block(UMUL, p, NIL, ty, p->n_df, p->n_sue);
+ break;
+
+ 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(BOOL_TYPE) : RETREG(p->n_type);
+ break;
+
+ case PMCONV:
+ case PVCONV:
+ nfree(p);
+ return buildtree(o == PMCONV ? MUL : DIV, p->n_left, p->n_right);
+
+ 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 0 // table.c will handle these okay
+ 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;
+ }
+#endif
+
+ if (l->n_op == ICON) {
+ CONSZ val = l->n_lval;
+
+ if (!ISPTR(p->n_type)) /* Pointers don't need to be conv'd */
+ switch (p->n_type) {
+ 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 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", l->n_type);
+ }
+ l->n_type = p->n_type;
+ l->n_sue = MKSUE(p->n_type);
+ nfree(p);
+ return l;
+ }
+#if 0 // table.c will handle these okay
+ if (DEUNSIGN(p->n_type) == SHORT &&
+ DEUNSIGN(l->n_type) == SHORT) {
+ nfree(p);
+ p = l;
+ }
+#endif
+ if ((DEUNSIGN(p->n_type) == CHAR ||
+ DEUNSIGN(p->n_type) == SHORT) &&
+ (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 PCONV:
+ l = p->n_left;
+ if (l->n_op == ICON) {
+ l->n_lval = (unsigned)l->n_lval;
+ goto delp;
+ }
+ if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
+ p->n_left = block(SCONV, l, NIL,
+ UNSIGNED, 0, MKSUE(UNSIGNED));
+ break;
+ }
+ if (l->n_op == SCONV)
+ break;
+ if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
+ goto delp;
+ 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;
+ }
+
+ return p;
+}
+
+/*
+ * Called before sending the tree to the backend.
+ */
+void
+myp2tree(NODE *p)
+{
+}
+
+/*
+ * Called during the first pass to determine if a NAME can be addressed.
+ *
+ * Return nonzero if supported, otherwise return 0.
+ */
+int
+andable(NODE *p)
+{
+ if (blevel == 0)
+ return 1;
+ if (ISFTN(p->n_type))
+ return 1;
+ return 0;
+}
+
+/*
+ * Called just after function arguments are built. Re-initialize the
+ * offset of the arguments on the stack.
+ * Is this necessary anymore? bfcode() is called immediately after.
+ */
+void
+cendarg()
+{
+ autooff = AUTOINIT;
+}
+
+/*
+ * Return 1 if a variable of type 't' is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+ if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+ return 0; /* not yet */
+ return 1;
+}
+
+/*
+ * Used for generating pointer offsets into structures and arrays.
+ *
+ * For a pointer of type 't', generate an the offset 'off'.
+ */
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
+{
+ return bcon(off/SZCHAR);
+}
+
+/*
+ * Allocate bits from the stack for dynamic-sized arrays.
+ *
+ * 'p' is the tree which represents the type being allocated.
+ * 'off' is the number of 'p's to be allocated.
+ * 't' is the storeable node where the address is written.
+ */
+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 = SP;
+ 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 = SP;
+ t->n_type = sp->n_type;
+ ecomp(buildtree(ASSIGN, t, sp));
+}
+
+static int inbits = 0, inval = 0;
+
+/*
+ * 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.space %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 an integer 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; int i[2]; } u;
+ struct symtab *q;
+ TWORD t;
+ int i, j;
+
+ 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);
+ j = (p->n_lval & 0xffffffff);
+ p->n_type = INT;
+#ifdef TARGET_BIG_ENDIAN
+ p->n_lval = i;
+ ninval(off+32, 32, p);
+ p->n_lval = j;
+ ninval(off, 32, p);
+#else
+ p->n_lval = j;
+ ninval(off, 32, p);
+ p->n_lval = i;
+ ninval(off+32, 32, p);
+#endif
+ break;
+ case INT:
+ case UNSIGNED:
+ printf("\t.word 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:
+ case DOUBLE:
+ u.d = (double)p->n_dcon;
+#if (defined(TARGET_BIG_ENDIAN) && defined(HOST_LITTLE_ENDIAN)) || \
+ (defined(TARGET_LITTLE_ENDIAN) && defined(HOST_BIG_ENDIAN))
+ printf("\t.word\t0x%x\n\t.word\t0x%x\n", u.i[0], u.i[1]);
+#else
+ printf("\t.word\t0x%x\n\t.word\t0x%x\n", u.i[1], u.i[0]);
+#endif
+ break;
+ case FLOAT:
+ u.f = (float)p->n_dcon;
+ printf("\t.word\t0x%x\n", u.i[0]);
+ break;
+ default:
+ cerror("ninval");
+ }
+}
+
+/*
+ * Prefix a leading underscore to a global variable (if necessary).
+ */
+char *
+exname(char *p)
+{
+ return (p == NULL ? "" : 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);
+ break;
+ }
+ return (type);
+}
+
+/*
+ * Before calling a function do any tree re-writing for the local machine.
+ *
+ * 'p' is the function tree (NAME)
+ * 'q' is the CM-separated list of arguments.
+ */
+void
+calldec(NODE *p, NODE *q)
+{
+}
+
+/*
+ * While handling uninitialised variables, handle variables marked extern.
+ */
+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("\t.comm %s,%d,%d\n", exname(gcc_findname(q)), off, 4);
+#else
+ printf("\t.comm %s,%,%d\n", exname(q->sname), off, 4);
+#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("\t.lcomm %s,%d\n", exname(gcc_findname(q)), off);
+#else
+ printf("\t.lcomm %s,%d\n", exname(q->sname), off);
+#endif
+ else
+ printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off);
+}
+
+/*
+ * Print a (non-prog) label.
+ */
+void
+deflab1(int label)
+{
+ printf(LABFMT ":\n", label);
+}
+
+static char *loctbl[] = { "text", "data", "text", "section .rodata" };
+
+void
+setloc1(int locc)
+{
+ if (locc == lastloc)
+ return;
+ lastloc = locc;
+ printf("\t.%s\n", loctbl[locc]);
+}
+
+/*
+ * va_start(ap, last) implementation.
+ *
+ * f is the NAME node for this builtin function.
+ * a is the argument list containing:
+ * CM
+ * ap last
+ */
+NODE *
+arm_builtin_stdarg_start(NODE *f, NODE *a)
+{
+ NODE *p;
+ int sz = 1;
+
+ /* check num args and type */
+ if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+ !ISPTR(a->n_left->n_type))
+ goto bad;
+
+ /* must first deal with argument size; use int size */
+ p = a->n_right;
+ if (p->n_type < INT)
+ sz = SZINT / tsize(p->n_type, p->n_df, p->n_sue);
+
+bad:
+ return bcon(0);
+}
+
+NODE *
+arm_builtin_va_arg(NODE *f, NODE *a)
+{
+ return bcon(0);
+}
+
+NODE *
+arm_builtin_va_end(NODE *f, NODE *a)
+{
+ return bcon(0);
+}
+
+NODE *
+arm_builtin_va_copy(NODE *f, NODE *a)
+{
+ return bcon(0);
+}
+
diff --git a/usr.bin/pcc/arm/local2.c b/usr.bin/pcc/arm/local2.c
new file mode 100644
index 00000000000..b278573efb1
--- /dev/null
+++ b/usr.bin/pcc/arm/local2.c
@@ -0,0 +1,954 @@
+/* $OpenBSD: local2.c,v 1.1 2007/11/25 18:45:06 otto Exp $ */
+/*
+ * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
+ * 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 <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "pass1.h"
+#include "pass2.h"
+
+/*
+ * these mnemonics match the order of the preprocessor decls
+ * EQ, NE, LE, LT, GE, GT, ULE, ULT, UGE, UGT
+ */
+
+static char *
+ccbranches[] = {
+ "beq", /* branch if equal */
+ "bne", /* branch if not-equal */
+ "ble", /* branch if less-than-or-equal */
+ "blt", /* branch if less-than */
+ "bge", /* branch if greater-than-or-equal */
+ "bgt", /* branch if greater-than */
+ /* what should these be ? */
+ "bls", /* branch if lower-than-or-same */
+ "blo", /* branch if lower-than */
+ "bhs", /* branch if higher-than-or-same */
+ "bhi", /* branch if higher-than */
+};
+
+/*
+ * 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 = "orr";
+ break;
+ case ER:
+ str = "eor";
+ 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(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, "\tcmp UR,UL\t@ compare 64-bit values (upper)\n");
+ if (cb1) cbgen(cb1, s);
+ if (cb2) cbgen(cb2, e);
+ expand(p, 0, "\tcmp AR,AL\t@ (and lower)\n");
+ cbgen(p->n_op, e);
+ deflab(s);
+}
+
+#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
+
+/*
+ * Push a structure on stack as argument.
+ * the scratch registers are already free here
+ */
+static void
+stasg(NODE *p)
+{
+ NODE *l = p->n_left;
+
+ printf("\tldr %s,=%d\n", rnames[R2], p->n_stsize);
+ if (l->n_rval != R0 || l->n_lval != 0)
+ printf("\tadd %s,%s," CONFMT "\n", rnames[R0],
+ rnames[l->n_rval], l->n_lval);
+ printf("\tbl %s\n", exname("memcpy"));
+}
+
+static void
+shiftop(NODE *p)
+{
+ NODE *r = p->n_right;
+ TWORD ty = p->n_type;
+
+ if (p->n_op == LS && r->n_op == ICON && r->n_lval < 32) {
+ expand(p, INBREG, "\tmov A1,AL,lsr ");
+ printf(CONFMT "\t@ 64-bit left-shift\n", 32 - r->n_lval);
+ expand(p, INBREG, "\tmov U1,UL,asl AR\n");
+ expand(p, INBREG, "\torr U1,U1,A1\n");
+ expand(p, INBREG, "\tmov A1,AL,asl AR\n");
+ } else if (p->n_op == LS && r->n_op == ICON && r->n_lval < 64) {
+ expand(p, INBREG, "\tldr A1,=0\t@ 64-bit left-shift\n");
+ expand(p, INBREG, "\tmov U1,AL,asl ");
+ printf(CONFMT "\n", r->n_lval - 32);
+ } else if (p->n_op == LS && r->n_op == ICON) {
+ expand(p, INBREG, "\tldr A1,=0\t@ 64-bit left-shift\n");
+ expand(p, INBREG, "\tldr U1,=0\n");
+ } else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 32) {
+ expand(p, INBREG, "\tmov U1,UL,asl ");
+ printf(CONFMT "\t@ 64-bit right-shift\n", 32 - r->n_lval);
+ expand(p, INBREG, "\tmov A1,AL,lsr AR\n");
+ expand(p, INBREG, "\torr A1,A1,U1\n");
+ if (ty == LONGLONG)
+ expand(p, INBREG, "\tmov U1,UL,asr AR\n");
+ else
+ expand(p, INBREG, "\tmov U1,UL,lsr AR\n");
+ } else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 64) {
+ if (ty == LONGLONG) {
+ expand(p, INBREG, "\tldr U1,=-1\t@ 64-bit right-shift\n");
+ expand(p, INBREG, "\tmov A1,UL,asr ");
+ }else {
+ expand(p, INBREG, "\tldr U1,=0\t@ 64-bit right-shift\n");
+ expand(p, INBREG, "\tmov A1,UL,lsr ");
+ }
+ printf(CONFMT "\n", r->n_lval - 32);
+ } else if (p->n_op == LS && r->n_op == ICON) {
+ expand(p, INBREG, "\tldr A1,=0\t@ 64-bit right-shift\n");
+ expand(p, INBREG, "\tldr U1,=0\n");
+ }
+}
+
+/*
+ * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
+ */
+static void
+fpemul(NODE *p)
+{
+ NODE *l = p->n_left;
+ char *ch = NULL;
+
+ if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3";
+ else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3";
+ else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3";
+
+ else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3";
+ else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3";
+ else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3";
+
+ else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3";
+ else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3";
+ else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3";
+
+ else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3";
+ else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3";
+ else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3";
+
+ else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2";
+ else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2";
+ else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2";
+
+ else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2";
+ else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2";
+ else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2";
+
+ else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2";
+ else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2";
+ else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2";
+
+ else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2";
+ else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2";
+ else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2";
+
+ else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2";
+ else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2";
+ else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2";
+
+ else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2";
+ else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2";
+ else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2";
+
+ else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2";
+ else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2";
+ else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2";
+
+ else if (p->n_op == SCONV && p->n_type == FLOAT) {
+ if (l->n_type == DOUBLE) ch = "truncdfsf2";
+ else if (l->n_type == LDOUBLE) ch = "trunctfsf2";
+ else if (l->n_type == ULONGLONG) ch = "floatuntisf";
+ else if (l->n_type == LONGLONG) ch = "floattisf";
+ else if (l->n_type == LONG) ch = "floatdisf";
+ else if (l->n_type == ULONG) ch = "floatundisf";
+ else if (l->n_type == INT) ch = "floatsisf";
+ else if (l->n_type == UNSIGNED) ch = "floatunsisf";
+ } else if (p->n_op == SCONV && p->n_type == DOUBLE) {
+ if (l->n_type == FLOAT) ch = "extendsfdf2";
+ else if (l->n_type == LDOUBLE) ch = "trunctfdf2";
+ else if (l->n_type == ULONGLONG) ch = "floatuntidf";
+ else if (l->n_type == LONGLONG) ch = "floattidf";
+ else if (l->n_type == LONG) ch = "floatdidf";
+ else if (l->n_type == ULONG) ch = "floatundidf";
+ else if (l->n_type == INT) ch = "floatsidf";
+ else if (l->n_type == UNSIGNED) ch = "floatunsidf";
+ } else if (p->n_op == SCONV && p->n_type == LDOUBLE) {
+ if (l->n_type == FLOAT) ch = "extendsftf2";
+ else if (l->n_type == DOUBLE) ch = "extenddftf2";
+ else if (l->n_type == ULONGLONG) ch = "floatuntitf";
+ else if (l->n_type == LONGLONG) ch = "floattitf";
+ else if (l->n_type == LONG) ch = "floatditf";
+ else if (l->n_type == ULONG) ch = "floatunsditf";
+ else if (l->n_type == INT) ch = "floatsitf";
+ else if (l->n_type == UNSIGNED) ch = "floatunsitf";
+ } else if (p->n_op == SCONV && p->n_type == ULONGLONG) {
+ if (l->n_type == FLOAT) ch = "fixunssfti";
+ else if (l->n_type == DOUBLE) ch = "fixunsdfti";
+ else if (l->n_type == LDOUBLE) ch = "fixunstfti";
+ } else if (p->n_op == SCONV && p->n_type == LONGLONG) {
+ if (l->n_type == FLOAT) ch = "fixsfti";
+ else if (l->n_type == DOUBLE) ch = "fixdfti";
+ else if (l->n_type == LDOUBLE) ch = "fixtfti";
+ } else if (p->n_op == SCONV && p->n_type == LONG) {
+ if (l->n_type == FLOAT) ch = "fixsfdi";
+ else if (l->n_type == DOUBLE) ch = "fixdfdi";
+ else if (l->n_type == LDOUBLE) ch = "fixtfdi";
+ } else if (p->n_op == SCONV && p->n_type == ULONG) {
+ if (l->n_type == FLOAT) ch = "fixunssfdi";
+ else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
+ else if (l->n_type == LDOUBLE) ch = "fixunstfdi";
+ } else if (p->n_op == SCONV && p->n_type == INT) {
+ if (l->n_type == FLOAT) ch = "fixsfsi";
+ else if (l->n_type == DOUBLE) ch = "fixdfsi";
+ else if (l->n_type == LDOUBLE) ch = "fixtfsi";
+ } else if (p->n_op == SCONV && p->n_type == UNSIGNED) {
+ if (l->n_type == FLOAT) ch = "fixunssfsi";
+ else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
+ else if (l->n_type == LDOUBLE) ch = "fixunstfsi";
+ }
+
+ if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op);
+
+ printf("\tbl __%s\t@ softfloat operation\n", exname(ch));
+
+ if (p->n_op >= EQ && p->n_op <= GT)
+ printf("\tcmp %s,#0\n", rnames[R0]);
+}
+
+
+/*
+ * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
+ */
+
+static void
+emul(NODE *p)
+{
+ char *ch = NULL;
+
+/**/ if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashlti3";
+ else if (p->n_op == LS && DEUNSIGN(p->n_type) == LONG) ch = "ashldi3";
+ else if (p->n_op == LS && DEUNSIGN(p->n_type) == INT) ch = "ashlsi3";
+
+/**/ else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrti3";
+ else if (p->n_op == RS && p->n_type == ULONG) ch = "lshrdi3";
+ else if (p->n_op == RS && p->n_type == UNSIGNED) ch = "lshrsi3";
+
+/**/ else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrti3";
+ else if (p->n_op == RS && p->n_type == LONG) ch = "ashrdi3";
+ else if (p->n_op == RS && p->n_type == INT) ch = "ashrsi3";
+
+ else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divti3";
+ else if (p->n_op == DIV && p->n_type == LONG) ch = "divdi3";
+ else if (p->n_op == DIV && p->n_type == INT) ch = "divsi3";
+
+ else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivti3";
+ else if (p->n_op == DIV && p->n_type == ULONG) ch = "udivdi3";
+ else if (p->n_op == DIV && p->n_type == UNSIGNED) ch = "udivsi3";
+
+ else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "modti3";
+ else if (p->n_op == MOD && p->n_type == LONG) ch = "moddi3";
+ else if (p->n_op == MOD && p->n_type == INT) ch = "modsi3";
+
+ else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umodti3";
+ else if (p->n_op == MOD && p->n_type == ULONG) ch = "umoddi3";
+ else if (p->n_op == MOD && p->n_type == UNSIGNED) ch = "umodsi3";
+
+ else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "multi3";
+ else if (p->n_op == MUL && p->n_type == LONG) ch = "muldi3";
+ else if (p->n_op == MUL && p->n_type == INT) ch = "mulsi3";
+
+ else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negti2";
+ else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negdi2";
+
+ else ch = 0, comperr("ZE");
+ printf("\tbl __%s\t@ emulated operation\n", exname(ch));
+}
+
+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)
+{
+ int pr;
+
+ switch (c) {
+
+#if 0
+ case 'B': /* Assign to bitfield */
+ bfasg(p);
+ break;
+#endif
+
+ case 'C': /* remove from stack after subroutine call */
+ pr = p->n_qual;
+#if 0
+ if (p->n_op == STCALL || p->n_op == USTCALL)
+ pr += 4;
+#endif
+ if (p->n_op == UCALL)
+ return; /* XXX remove ZC from UCALL */
+ if (pr > 0)
+ printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], pr);
+ break;
+
+ case 'D': /* Long long comparision */
+ twollcomp(p);
+ break;
+
+ case 'E': /* print out emulated ops */
+ emul(p);
+ break;
+
+ case 'F': /* print out emulated floating-point ops */
+ fpemul(p);
+ break;
+
+ case 'I': /* init constant */
+ if (p->n_name[0] != '\0')
+ comperr("named init");
+ fprintf(stdout, "=%lld", p->n_lval & 0xffffffff);
+ break;
+
+ case 'J': /* init longlong constant */
+ expand(p, INBREG, "\tldr A1,");
+ fprintf(stdout, "=%lld\t@ load 64-bit constant\n",
+ p->n_lval & 0xffffffff);
+ expand(p, INBREG, "\tldr U1,");
+ fprintf(stdout, "=%lld\n", (p->n_lval >> 32));
+ break;
+
+ case 'O': /* 64-bit left and right shift operators */
+ shiftop(p);
+ break;
+
+ case 'Q': /* emit struct assign */
+ stasg(p);
+ break;
+
+ default:
+ comperr("zzzcode %c", c);
+ }
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+ return(1);
+}
+
+/*
+ * 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)
+{
+ char *s;
+ int val = p->n_lval;
+
+ switch (p->n_op) {
+ case ICON:
+#if 0
+ if (p->n_sp)
+ printf(" [class=%d,level=%d] ", p->n_sp->sclass, p->n_sp->slevel);
+#endif
+ if (p->n_sp == NULL || (p->n_sp->sclass == ILABEL ||
+ (p->n_sp->sclass == STATIC && p->n_sp->slevel > 0)))
+ s = p->n_name;
+ else
+ s = exname(p->n_name);
+
+ if (*s != '\0') {
+ fprintf(fp, "%s", s);
+ if (val > 0)
+ fprintf(fp, "+%d", val);
+ else if (val < 0)
+ fprintf(fp, "-%d", -val);
+ } else
+ fprintf(fp, CONFMT, (CONSZ)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-R0R1+1]);
+ 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, "+%lld", p->n_lval);
+ } else
+ fprintf(io, CONFMT, p->n_lval);
+ return;
+
+ case OREG:
+ r = p->n_rval;
+ fprintf(io, "[%s,#%d]", rnames[p->n_rval], (int)p->n_lval);
+ return;
+
+ case ICON:
+ /* addressable value of the constant */
+ conput(io, p);
+ return;
+
+ case MOVE:
+ case REG:
+ switch (p->n_type) {
+#if !defined(ARM_HAS_FPA) && !defined(ARM_HAS_VFP)
+ case DOUBLE:
+ case LDOUBLE:
+#endif
+ case LONGLONG:
+ case ULONGLONG:
+ fprintf(stdout, "%s", rnames[p->n_rval-R0R1]);
+ 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)
+{
+ if (o < EQ || o > UGT)
+ comperr("bad conditional branch: %s", opst[o]);
+ printf("\t%s " LABFMT "\t@ conditional branch\n",
+ ccbranches[o-EQ], lab);
+}
+
+struct addrsymb {
+ DLIST_ENTRY(addrsymb) link;
+ struct symtab *orig;
+ struct symtab *new;
+};
+struct addrsymb addrsymblist;
+
+static void
+prtaddr(NODE *p)
+{
+ NODE *l = p->n_left;
+ struct addrsymb *el;
+ int found = 0;
+ int lab;
+
+ if (p->n_op != ADDROF || l->n_op != NAME)
+ return;
+
+ /* write address to byte stream */
+
+ DLIST_FOREACH(el, &addrsymblist, link) {
+ if (el->orig == l->n_sp) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ setloc1(PROG);
+ defalign(SZPOINT(l->n_type));
+ deflab1(lab = getlab());
+ printf("\t.word ");
+ adrput(stdout, l);
+ printf("\n");
+ el = tmpalloc(sizeof(struct addrsymb));
+ el->orig = l->n_sp;
+ el->new = tmpalloc(sizeof(struct symtab_hdr));
+ el->new->sclass = ILABEL;
+ el->new->soffset = lab;
+ el->new->sflags = 0;
+ DLIST_INSERT_BEFORE(&addrsymblist, el, link);
+ }
+
+ nfree(l);
+ p->n_op = NAME;
+ p->n_lval = 0;
+ p->n_sp = el->new;
+ p2tree(p);
+}
+
+void
+myreader(struct interpass *ipole)
+{
+ struct interpass *ip;
+
+ DLIST_INIT(&addrsymblist, link);
+
+ DLIST_FOREACH(ip, ipole, qelem) {
+ if (ip->type != IP_NODE)
+ continue;
+ walkf(ip->ip_node, prtaddr);
+ }
+ 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 *ipp)
+{
+}
+
+/*
+ * Register move: move contents of register 's' to register 'r'.
+ */
+void
+rmove(int s, int d, TWORD t)
+{
+ switch (t) {
+#if !defined(ARM_HAS_FPU) && !defined(ARM_HAS_VFP)
+ case DOUBLE:
+ case LDOUBLE:
+#endif
+ case LONGLONG:
+ case ULONGLONG:
+#define LONGREG(x, y) rnames[(x)-(R0R1-(y))]
+ if (s == d+1) {
+ /* dh = sl, copy low word first */
+ printf("\tmov %s,%s @ rmove\n",
+ LONGREG(d,0), LONGREG(s,0));
+ printf("\tmov %s,%s\n",
+ LONGREG(d,1), LONGREG(s,1));
+ } else {
+ /* copy high word first */
+ printf("\tmov %s,%s @ rmove\n",
+ LONGREG(d,1), LONGREG(s,1));
+ printf("\tmov %s,%s\n",
+ LONGREG(d,0), LONGREG(s,0));
+ }
+#undef LONGREG
+ break;
+ default:
+ printf("\tmov %s,%s @ rmove\n", rnames[d], rnames[s]);
+ }
+}
+
+/*
+ * Can we assign a register from class 'c', given the set
+ * of number of assigned registers in each class 'r'.
+ *
+ * On ARM, we have:
+ * 11 CLASSA registers (32-bit hard registers)
+ * 10 CLASSB registers (64-bit composite registers)
+ * 8 or 32 CLASSC registers (floating-point)
+ *
+ * There is a problem calculating the available composite registers
+ * (ie CLASSB). The algorithm below assumes that given any two
+ * registers, we can make a composite register. But this isn't true
+ * here (or with other targets), since the number of combinations
+ * of register pairs could become very large. Additionally,
+ * having so many combinations really isn't so practical, since
+ * most register pairs cannot be used to pass function arguments.
+ * Consequently, when there is pressure composite registers,
+ * "beenhere" compilation failures are common.
+ *
+ * [We need to know which registers are allocated, not simply
+ * the number in each class]
+ */
+int
+COLORMAP(int c, int *r)
+{
+ int num = 0; /* number of registers used */
+
+#if 0
+ static const char classes[] = { 'X', 'A', 'B', 'C', 'D' };
+ printf("COLORMAP: requested class %c\n", classes[c]);
+ printf("COLORMAP: class A: %d\n", r[CLASSA]);
+ printf("COLORMAP: class B: %d\n", r[CLASSB]);
+#endif
+
+ switch (c) {
+ case CLASSA:
+ num += r[CLASSA];
+ num += 2*r[CLASSB];
+ return num < 11;
+ case CLASSB:
+ num += 2*r[CLASSB];
+ num += r[CLASSA];
+ return num < 6; /* XXX see comments above */
+ case CLASSC:
+ num += r[CLASSC];
+ return num < 8;
+ }
+ assert(0);
+ return 0; /* XXX gcc */
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+#if defined(ARM_HAS_FPA) || defined(ARM_HAS_VFP)
+ if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+ return CLASSC;
+#endif
+ if (t == DOUBLE || t == LDOUBLE || t == LONGLONG || t == ULONGLONG)
+ return CLASSB;
+ 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 - 16; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+ return SRNOPE;
+}
diff --git a/usr.bin/pcc/arm/macdefs.h b/usr.bin/pcc/arm/macdefs.h
new file mode 100644
index 00000000000..c125945eb43
--- /dev/null
+++ b/usr.bin/pcc/arm/macdefs.h
@@ -0,0 +1,229 @@
+/* $Id: macdefs.h,v 1.1 2007/11/25 18:45:06 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);
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR 8
+#define SZBOOL 32
+#define SZINT 32
+#define SZFLOAT 32
+#define SZDOUBLE 64
+#define SZLDOUBLE 64
+#define SZLONG 32
+#define SZSHORT 16
+#define SZLONGLONG 64
+#define SZPOINT(t) 32
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR 8
+#define ALBOOL 32
+#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
+
+#define BOOL_TYPE INT /* 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 */
+#define STAB_LINE_ABSOLUTE /* S_LINE fields use absolute addresses */
+
+#undef FIELDOPS /* no bit-field instructions */
+
+#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 szty(t) (((t) == DOUBLE || (t) == LDOUBLE || \
+ (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1)
+
+#define R0 0
+#define R1 1
+#define R2 2
+#define R3 3
+#define R4 4
+#define R5 5
+#define R6 6
+#define R7 7
+#define R8 8
+#define R9 9
+#define R10 10
+
+#define FP 11
+#define IP 12
+#define SP 13
+#define LR 14
+#define PC 15
+
+#define R0R1 16
+#define R1R2 17
+#define R2R3 18
+#define R3R4 19
+#define R4R5 20
+#define R5R6 21
+#define R6R7 22
+#define R7R8 23
+#define R8R9 24
+#define R9R10 25
+
+#define NUMCLASS 2
+#define MAXREGS 26
+
+#define RSTATUS \
+ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \
+ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \
+ 0, 0, 0, 0, 0, \
+ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG, \
+ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \
+
+#define ROVERLAP \
+ { R0R1, -1 }, \
+ { R0R1, R1R2, -1 }, \
+ { R1R2, R2R3, -1 }, \
+ { R2R3, R3R4, -1 }, \
+ { R3R4, R4R5, -1 }, \
+ { R4R5, R5R6, -1 }, \
+ { R5R6, R6R7, -1 }, \
+ { R6R7, R7R8, -1 }, \
+ { R7R8, R8R9, -1 }, \
+ { R8R9, R9R10, -1 }, \
+ { R9R10, -1 }, \
+ { -1 }, \
+ { -1 }, \
+ { -1 }, \
+ { -1 }, \
+ { -1 }, \
+ { R0, R1, R1R2, -1 }, \
+ { R1, R2, R0R1, R2R3, -1 }, \
+ { R2, R3, R1R2, R3R4, -1 }, \
+ { R3, R4, R2R3, R4R5, -1 }, \
+ { R4, R5, R3R4, R5R6, -1 }, \
+ { R5, R6, R4R5, R6R7, -1 }, \
+ { R6, R7, R5R6, R7R8, -1 }, \
+ { R7, R8, R6R7, R8R9, -1 }, \
+ { R8, R9, R7R8, R9R10, -1 }, \
+ { R9, R10, R8R9, -1 }, \
+
+#define BACKTEMP /* stack grows negatively for temporaries */
+#define BACKAUTO /* stack grows negatively for automatics */
+
+#define ARGINIT (4*8) /* # bits above fp where arguments start */
+#define AUTOINIT (12*8) /* # bits above fp where automatics start */
+
+/* XXX - to die */
+#define FPREG FP /* frame pointer */
+
+/* Return a register class based on the type of the node */
+#define PCLASS(p) (1 << gclass((p)->n_type))
+
+#define GCLASS(x) (x < 16 ? CLASSA : CLASSB)
+#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 */
+
+#if defined(ARM_HAS_FPA) || defined(ARM_HAS_VFP)
+#define RETREG(x) (DEUNSIGN(x) == LONGLONG ? R0R1 : \
+ (x) == DOUBLE || (x) == LDOUBLE || (x) == FLOAT ? \
+ F0 : R0)
+#else
+#define RETREG(x) (DEUNSIGN(x) == LONGLONG || \
+ (x) == DOUBLE || (x) == LDOUBLE ? R0R1 : R0)
+#endif
+
+int COLORMAP(int c, int *r);
+
+#define TARGET_STDARGS \
+ { "__builtin_stdarg_start, arm_builtin_stdarg_start }, \
+ { "__builtin_va_arg, arm_builtin_va_arg }, \
+ { "__builtin_va_end, arm_builtin_va_end }, \
+ { "__builtin_va_copy, arm_builtin_va_copy },
+
+#define NODE struct node
+struct node;
+NODE *arm_builtin_stdarg_start(NODE *f, NODE *a);
+NODE *arm_builtin_va_arg(NODE *f, NODE *a);
+NODE *arm_builtin_va_end(NODE *f, NODE *a);
+NODE *arm_builtin_va_copy(NODE *f, NODE *a);
+#undef NODE
diff --git a/usr.bin/pcc/arm/order.c b/usr.bin/pcc/arm/order.c
new file mode 100644
index 00000000000..09f4bbcde60
--- /dev/null
+++ b/usr.bin/pcc/arm/order.c
@@ -0,0 +1,293 @@
+/* $OpenBSD: order.c,v 1.1 2007/11/25 18:45:06 otto Exp $ */
+/*
+ * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
+ * 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 code-generation strategy (pass 2).
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "pass2.h"
+
+/*
+ * Check size of offset in OREG. Called by oregok() to see if an
+ * OREG can be generated.
+ */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+ if (cp && cp[0]) return 1;
+ return !(off < 32768 && off > -32769); /* YES */
+}
+
+/*
+ * Generate instructions for an OREG. Why is this routine MD?
+ * Called by swmatch().
+ */
+void
+offstar(NODE *p, int shape)
+{
+ NODE *r;
+
+ 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;
+ }
+ /* usually for arraying indexing: */
+ 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);
+}
+
+/*
+ * It is OK to do an OREG - Modify the expression tree to be an OREG.
+ */
+void
+myormake(NODE *q)
+{
+}
+
+/*
+ * Check to if the UMUL node can be converted into an OREG.
+ */
+int
+shumul(NODE *p)
+{
+ /* Turns currently anything into OREG */
+ return SOREG;
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of a failed table lookup.
+ *
+ * Return nonzero to retry table search on new tree, or zero to fail.
+ */
+int
+setbin(NODE *p)
+{
+ return 0;
+
+}
+
+/*
+ * Rewrite assignment operations.
+ * Called as a result of a failed table lookup.
+ *
+ * Return nonzero to retry table search on new tree, or zero to fail.
+ */
+int
+setasg(NODE *p, int cookie)
+{
+ return 0;
+}
+
+/*
+ * Rewrite UMUL operation.
+ * Called as a result of a failed table lookup.
+ *
+ * Return nonzero to retry table search on new tree, or zero to fail.
+ */
+int
+setuni(NODE *p, int cookie)
+{
+ return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ *
+ * Called as a result of specifying NSPECIAL in the table.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+
+ switch (q->op) {
+
+#if !defined(ARM_HAS_FPA) && !defined(ARM_HAS_VFP)
+ case UMINUS:
+ case SCONV:
+ if (q->lshape == SBREG && q->rshape == SAREG) {
+ static struct rspecial s[] = {
+ { NLEFT, R0R1 },
+ { NRES, R0 },
+ { 0 }
+ };
+ return s;
+ } else if (q->lshape == SAREG && q->rshape == SBREG) {
+ static struct rspecial s[] = {
+ { NLEFT, R0 },
+ { NRES, R0R1 },
+ { 0 }
+ };
+ return s;
+ } else if (q->lshape == SAREG && q->rshape == SAREG) {
+ static struct rspecial s[] = {
+ { NLEFT, R0 },
+ { NRES, R0 },
+ { 0 }
+ };
+ return s;
+ } else if (q->lshape == SBREG && q->rshape == SBREG) {
+ static struct rspecial s[] = {
+ { NLEFT, R0R1 },
+ { NRES, R0R1 },
+ { 0 }
+ };
+ return s;
+ }
+
+ case OPLOG:
+ if (q->lshape == SBREG) {
+ static struct rspecial s[] = {
+ { NLEFT, R0R1 },
+ { NRIGHT, R2R3 },
+ { NRES, R0 },
+ { 0 }
+ };
+ return s;
+ } else if (q->lshape == SAREG) {
+ static struct rspecial s[] = {
+ { NLEFT, R0 },
+ { NRIGHT, R1 },
+ { NRES, R0 },
+ { 0 }
+ };
+ return s;
+ }
+ case PLUS:
+ case MINUS:
+ case MUL:
+#endif
+ case MOD:
+ case DIV:
+ if (q->lshape == SBREG) {
+ static struct rspecial s[] = {
+ { NLEFT, R0R1 },
+ { NRIGHT, R2R3 },
+ { NRES, R0R1 },
+ { 0 }
+ };
+ return s;
+ } else if (q->lshape == SAREG) {
+ static struct rspecial s[] = {
+ { NLEFT, R0 },
+ { NRIGHT, R1 },
+ { NRES, R0 },
+ { 0 }
+ };
+ return s;
+ }
+ case LS:
+ case RS:
+ if (q->lshape == SBREG) {
+ static struct rspecial s[] = {
+ { NLEFT, R0R1 },
+ { NRIGHT, R2 },
+ { NRES, R0R1 },
+ { 0 }
+ };
+ return s;
+ } else if (q->lshape == SAREG) {
+ static struct rspecial s[] = {
+ { NLEFT, R0 },
+ { NRIGHT, R1 },
+ { NRES, R0 },
+ { 0 }
+ };
+ return s;
+ }
+ case STASG:
+ {
+ static struct rspecial s[] = {
+ { NEVER, R0 },
+ { NRIGHT, R1 },
+ { NEVER, R2 },
+ { 0 } };
+ return s;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+#ifdef PCC_DEBUG
+ comperr("nspecial entry %d [0x%x]: %s", q - table, q->op, q->cstring);
+#endif
+ return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node ('+','-', '*', '/', etc) if it
+ * differs from default.
+ */
+int
+setorder(NODE *p)
+{
+ return 0;
+}
+
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+ static int r[] = { R3, R2, R1, R0, -1 };
+ int num = 1;
+
+ if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+ return &r[4-0];
+
+ for (p = p->n_right; p->n_op == CM; p = p->n_left)
+ num += szty(p->n_right->n_type);
+ num += szty(p->n_right->n_type);
+
+ num = (num > 4 ? 4 : num);
+
+ return &r[4 - num];
+}
diff --git a/usr.bin/pcc/arm/table.c b/usr.bin/pcc/arm/table.c
new file mode 100644
index 00000000000..fcf715dbc09
--- /dev/null
+++ b/usr.bin/pcc/arm/table.c
@@ -0,0 +1,1501 @@
+/* $OpenBSD: table.c,v 1.1 2007/11/25 18:45:06 otto Exp $ */
+/*-
+ * Copyright (c) 2007 Gregory McGarry <g.mcgarry@ieee.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * A template has five logical sections:
+ *
+ * 1) subtree (operator); goal to achieve (cookie)
+ * 2) left node descendent of operator (node class; type)
+ * 3) right node descendent of operator (node class; type)
+ * 4) resource requirements (number of scratch registers);
+ * subtree rewriting rule
+ * 5) emitted instructions
+ */
+
+#include "pass2.h"
+
+#define TUWORD TUNSIGNED|TULONG
+#define TSWORD TINT|TLONG
+#define TWORD TUWORD|TSWORD
+
+#if defined(ARM_HAS_FPA) || defined(ARM_HAS_VFP)
+#define INFREG INCREG
+#define NFREG NCREG
+#define SFREG SCREG
+#define NFSL NCSL
+#define NFSR NCSR
+#define INXREG INCREG
+#define NXREG NCREG
+#define SXREG SCREG
+#define NXSL NCSL
+#define NXSR NCSR
+#else
+#define INFREG INAREG
+#define NFREG NAREG
+#define SFREG SAREG
+#define NFSL NASL
+#define NFSR NASR
+#define INXREG INBREG
+#define NXREG NBREG
+#define SXREG SBREG
+#define NXSL NBSL
+#define NXSR NBSR
+#endif
+
+#define COM " @ "
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are not necessary */
+{ PCONV, INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RLEFT,
+ COM "pointer conversion\n", },
+
+/*
+ * Conversions of integral types
+ *
+ * For each deunsigned type, they look something like this:
+ *
+ * signed -> bigger signed - nothing to do
+ * signed -> bigger unsigned - clear the top bits (of source type)
+ *
+ * signed -> smaller signed - sign-extend the bits (to dest type)
+ * signed -> smaller unsigned - clear the top bits (of dest type)
+ * unsigned -> smaller signed - sign-extend top bits (to dest type)
+ * unsigned -> smaller unsigned - clear the top bits (of dest type)
+ *
+ * unsigned -> bigger - nothing to do
+ */
+
+{ SCONV, INAREG,
+ INAREG, TCHAR,
+ INAREG, TSWORD|TSHORT,
+ NAREG|NASL, RESC1,
+ COM "convert char to short/int\n", },
+
+{ SCONV, INAREG,
+ INAREG, TCHAR,
+ INAREG, TUWORD|TUSHORT|TUCHAR,
+ NAREG|NASL, RESC1,
+ " and A1,AL,#255" COM "convert char to uchar/ushort/uint\n", },
+
+{ SCONV, INAREG,
+ INAREG, TUCHAR,
+ INAREG, TCHAR,
+ NAREG|NASL, RESC1,
+ " mov A1,AL,asl #24" COM "convert uchar to char\n"
+ " mov A1,A1,asr #24\n", },
+
+{ SCONV, INAREG,
+ INAREG, TUCHAR,
+ INAREG, TWORD|TSHORT|TUSHORT,
+ 0, RLEFT,
+ COM "convert uchar to (u)short/(u)int\n", },
+
+{ SCONV, INAREG,
+ INAREG, TSHORT,
+ INAREG, TSWORD,
+ 0, RLEFT,
+ COM "convert short to int\n", },
+
+{ SCONV, INAREG,
+ INAREG, TSHORT,
+ INAREG, TUWORD,
+ NAREG|NASL, RESC1,
+ " mov A1,AL,asl #16" COM "convert short to uint\n"
+ " mov A1,AL,lsr #16\n", },
+
+{ SCONV, INAREG,
+ INAREG, TUSHORT,
+ INAREG, TSHORT,
+ NAREG|NASL, RESC1,
+ " mov A1,AL,asl #16" COM "convert ushort to short\n"
+ " mov A1,A1,asr #16\n", },
+
+{ SCONV, INAREG,
+ INAREG, TSHORT|TUSHORT,
+ INAREG, TCHAR,
+ NAREG|NASL, RESC1,
+ " mov A1,AL,asl #24" COM "convert (u)short to char\n"
+ " mov A1,A1,asr #24\n", },
+
+{ SCONV, INAREG,
+ INAREG, TSHORT|TUSHORT,
+ INAREG, TUCHAR,
+ NAREG|NASL, RESC1,
+ " and A1,AL,#255" COM "convert (u)short to uchar\n", },
+
+{ SCONV, INAREG,
+ INAREG, TUSHORT,
+ INAREG, TWORD,
+ NAREG|NASL, RESC1,
+ COM "convert ushort to (u)int\n", },
+
+{ SCONV, INAREG,
+ INAREG, TWORD,
+ INAREG, TCHAR,
+ NAREG|NASL, RESC1,
+ " mov A1,AL,asl #24" COM "convert (u)int to char\n"
+ " mov A1,A1,asr #24\n", },
+
+{ SCONV, INAREG,
+ INAREG, TWORD,
+ INAREG, TSHORT,
+ NAREG|NASL, RESC1,
+ " mov A1,AL,asl #16" COM "convert (u)int to short\n"
+ " mov A1,A1,asr #16\n", },
+
+{ SCONV, INAREG,
+ INAREG, TWORD,
+ INAREG, TUCHAR,
+ NAREG|NASL, RESC1,
+ " and A1,AL,#255" COM "convert uchar to char\n", },
+
+{ SCONV, INAREG,
+ INAREG, TWORD,
+ INAREG, TUSHORT,
+ NAREG|NASL, RESC1,
+ " mov A1,AL,asl #16" COM "convert int to ushort\n"
+ " mov A1,AL,lsr #16\n", },
+
+{ SCONV, INAREG,
+ SAREG, TPOINT|TWORD,
+ SAREG, TWORD|TPOINT,
+ 0, RLEFT,
+ COM "convert between pointers and words\n", },
+
+{ SCONV, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ 0, RLEFT,
+ COM "convert (u)longlong to (u)longlong\n", },
+
+/* convert (u)char/(u)short/(u)int to longlong */
+{ SCONV, INBREG,
+ SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1,
+ " mov A1,AL" COM "convert (u)char/(u)short/(u)int to (u)longlong\n"
+ " mov U1,AL,asr #31\n", },
+
+{ SCONV, INAREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SAREG, TCHAR,
+ NAREG, RESC1,
+ " mov A1,AL,asl #24" COM "convert (u)longlong to char\n"
+ " mov A1,A1,asr #24\n", },
+
+{ SCONV, INAREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SAREG, TSHORT,
+ NAREG, RESC1,
+ " mov A1,AL,asl #16" COM "convert (u)longlong to short\n"
+ " mov A1,A1,asr #16\n", },
+
+{ SCONV, INAREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SAREG, TWORD,
+ NAREG, RESC1,
+ " mov A1,AL" COM "convert (u)longlong to (u)int\n", },
+
+{ SCONV, INAREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SAREG, TUCHAR,
+ NAREG, RESC1,
+ " and A1,AL,#255" COM "convert (u)longlong to uchar\n", },
+
+{ SCONV, INAREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SAREG, TUSHORT,
+ NAREG, RESC1,
+ " mov A1,AL,asl #16" COM "convert (u)longlong to ushort\n"
+ " mov A1,A1,lsr #16\n", },
+
+/* conversions on load from memory */
+
+/* char */
+{ SCONV, INAREG,
+ SOREG, TCHAR,
+ SAREG, TWORD,
+ NASL|NAREG, RESC1,
+ " ldrsb A1,AL" COM "convert char to int/long\n", },
+
+/* uchar */
+{ SCONV, INAREG,
+ SOREG, TUCHAR,
+ SAREG, TWORD,
+ NASL|NAREG, RESC1,
+ " ldrb A1,AL" COM "convert uchar to int/long\n", },
+
+/* short */
+{ SCONV, INAREG,
+ SOREG, TSHORT,
+ SAREG, TWORD,
+ NASL|NAREG, RESC1,
+ " ldrsh A1,AL" COM "convert short to int/long\n", },
+
+/* ushort */
+{ SCONV, INAREG,
+ SOREG, TSHORT,
+ SAREG, TWORD,
+ NASL|NAREG, RESC1,
+ " ldrh A1,AL" COM "convert ushort to int/long\n", },
+
+{ SCONV, INAREG,
+ SFREG, TFLOAT,
+ SAREG, TSWORD,
+ NSPECIAL|NAREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " fix AL,AR" COM "convert float to int\n", },
+#elifdef ARM_HAS_VFP
+ " ftosis AL,AR" COM "convert float to int\n", },
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INAREG,
+ SFREG, TFLOAT,
+ SAREG, TUWORD,
+ NSPECIAL|NAREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " fix AL,AR" COM "convert float to int\n", },
+#elifdef ARM_HAS_VFP
+ " ftouis AL,AR" COM "convert float to int\n", },
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INBREG,
+ SFREG, TFLOAT,
+ SBREG, TULONGLONG,
+ NSPECIAL|NAREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INBREG,
+ SFREG, TFLOAT,
+ SBREG, TLONGLONG,
+ NSPECIAL|NAREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INAREG,
+ SXREG, TDOUBLE|TLDOUBLE,
+ SAREG, TSWORD,
+ NSPECIAL|NAREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " fix AL,AR" COM "convert double/ldouble to int\n", },
+#elifdef ARM_HAS_VFP
+ " ftosid AL,AR" COM "convert double/ldouble to int\n", },
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INAREG,
+ SXREG, TDOUBLE|TLDOUBLE,
+ SAREG, TUWORD,
+ NSPECIAL|NAREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " fix AL,AR" COM "convert double/ldouble to int\n", },
+#elifdef ARM_HAS_VFP
+ " ftouid AL,AR" COM "convert double/ldouble to int\n", },
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INBREG,
+ SXREG, TDOUBLE|TLDOUBLE,
+ SBREG, TULONGLONG,
+ NSPECIAL|NAREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INBREG,
+ SXREG, TDOUBLE|TLDOUBLE,
+ SBREG, TLONGLONG,
+ NSPECIAL|NAREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INFREG,
+ SAREG, TSWORD,
+ SFREG, TFLOAT,
+ NSPECIAL|NFREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " flts AL,AR" COM "convert int to float\n" },
+#elifdef ARM_HAS_VFP
+ " fsitos AL,AR" COM "convert int to float\n" },
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INFREG,
+ SAREG, TUWORD,
+ SFREG, TFLOAT,
+ NSPECIAL|NFREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " flts AL,AR" COM "convert int to float\n" },
+#elifdef ARM_HAS_VFP
+ " fuitos AL,AR" COM "convert int to float\n" },
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INFREG,
+ SBREG, TLONGLONG,
+ SFREG, TFLOAT,
+ NSPECIAL|NFREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INFREG,
+ SBREG, TULONGLONG,
+ SFREG, TFLOAT,
+ NSPECIAL|NFREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INXREG,
+ SAREG, TSWORD,
+ SXREG, TDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " fltd AL,AR" COM "convert int to double\n" },
+#elifdef ARM_HAS_VFP
+ " fsitod AL,AR" COM "convert int to double\n" },
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INXREG,
+ SAREG, TUWORD,
+ SXREG, TDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " fltd AL,AR" COM "convert int to double\n" },
+#elifdef ARM_HAS_VFP
+ " fuitod AL,AR" COM "convert int to double\n" },
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INXREG,
+ SBREG, TLONGLONG,
+ SXREG, TDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INXREG,
+ SBREG, TULONGLONG,
+ SXREG, TDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INXREG,
+ SAREG, TSWORD,
+ SXREG, TLDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " flte AL,AR" COM "convert int to ldouble\n" },
+#elifdef ARM_HAS_VFP
+ " fsitod AL,AR" COM "convert int to ldouble\n" },
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INXREG,
+ SAREG, TUWORD,
+ SXREG, TLDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " flte AL,AR" COM "convert int to ldouble\n" },
+#elifdef ARM_HAS_VFP
+ " fuitod AL,AR" COM "convert int to ldouble\n" },
+#else
+ "ZF", },
+#endif
+
+
+{ SCONV, INXREG,
+ SBREG, TLONGLONG,
+ SXREG, TLDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INXREG,
+ SBREG, TULONGLONG,
+ SXREG, TLDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INFREG,
+ SXREG, TDOUBLE,
+ SFREG, TFLOAT,
+ NSPECIAL|NFREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+ " fcvtds AL,AR" COM "convert float to double\n" },
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INFREG,
+ SXREG, TLDOUBLE,
+ SFREG, TFLOAT,
+ NSPECIAL|NFREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+ " fcvtds AL,AR" COM "convert float to double\n" },
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INXREG,
+ SFREG, TFLOAT,
+ SXREG, TDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+ " fcvtsd AL,AR" COM "convert float to double\n" },
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INXREG,
+ SFREG, TFLOAT,
+ SXREG, TLDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+#elifdef ARM_HAS_VFP
+ " fcvtsd AL,AR" COM "convert float to double\n" },
+#else
+ "ZF", },
+#endif
+
+{ SCONV, INXREG,
+ SXREG, TDOUBLE|TLDOUBLE,
+ SXREG, TDOUBLE|TLDOUBLE,
+ 0, RLEFT,
+ COM "convert (l)double to (l)double", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL, FOREFF,
+ SCON|SNAME, TANY,
+ SANY, TANY,
+ 0, 0,
+ " bl CL" COM "call (args, no result) to scon/sname (CL)\n"
+ "ZC", },
+
+{ UCALL, FOREFF,
+ SCON|SNAME, TANY,
+ SANY, TANY,
+ 0, 0,
+ " bl CL" COM "call (no args, no result) to scon/sname (CL)\n", },
+
+{ CALL, INAREG,
+ SCON|SNAME, TANY,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " bl CL" COM "call (args, result in r0) to scon/sname (CL)\n"
+ "ZC", },
+
+{ CALL, INBREG,
+ SCON|SNAME, TANY,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1, /* should be 0 */
+ " bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n"
+ "ZC", },
+
+{ CALL, INFREG,
+ SCON|SNAME, TANY,
+ SFREG, TFLOAT,
+ NFREG|NASL, RESC1, /* should be 0 */
+ " bl CL" COM "call (args, result r0) to scon/sname (CL)\n"
+ "ZC", },
+
+{ CALL, INXREG,
+ SCON|SNAME, TANY,
+ SXREG, TDOUBLE|TLDOUBLE,
+ NXREG|NXSL, RESC1, /* should be 0 */
+ " bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n"
+ "ZC", },
+
+{ UCALL, INAREG,
+ SCON|SNAME, TANY,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", },
+
+{ UCALL, INBREG,
+ SCON|SNAME, TANY,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1, /* should be 0 */
+ " bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", },
+
+{ UCALL, INFREG,
+ SCON|SNAME, TANY,
+ SFREG, TFLOAT,
+ NFREG|NFSL, RESC1, /* should be 0 */
+ " bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", },
+
+{ UCALL, INXREG,
+ SCON|SNAME, TANY,
+ SXREG, TDOUBLE|TLDOUBLE,
+ NXREG|NXSL, RESC1, /* should be 0 */
+ " bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", },
+
+{ CALL, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, 0,
+ " mov lr,pc\n"
+ " mov pc,AL\n"
+ "ZC", },
+
+{ UCALL, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, 0,
+ " mov lr,pc\n"
+ " mov pc,AL\n", },
+
+/* struct return */
+{ USTCALL, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, 0,
+ " bl CL\n", },
+
+{ USTCALL, INAREG,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " bl CL\n", },
+
+{ USTCALL, INAREG,
+ SNAME|SAREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " mov lr,pc\n"
+ " mov pc,AL\n", },
+
+{ STCALL, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, 0,
+ " bl CL\n"
+ "ZC", },
+
+{ STCALL, INAREG,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " bl CL\n"
+ "ZC", },
+
+{ STCALL, INAREG,
+ SNAME|SAREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " mov lr,pc\n"
+ " mov pc,AL\n"
+ "ZC", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+
+{ PLUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SCCON, TANY,
+ NAREG, RESC1,
+ " add A1,AL,AR" COM "addition of constant\n", },
+
+{ PLUS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SSCON, TANY,
+ NBREG|NBSL, RESC1,
+ " adds A1,AL,AR" COM "64-bit addition of constant\n"
+ " adc U1,UL,UR\n", },
+
+{ PLUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ NAREG|NASL, RESC1,
+ " add A1,AL,AR" COM "addition\n", },
+
+{ PLUS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1,
+ " adds A1,AL,AR" COM "64-bit addition\n"
+ " adc U1,UL,UR\n", },
+
+{ PLUS, INFREG,
+ SFREG, TFLOAT,
+ SFREG, TFLOAT,
+ NSPECIAL|NFREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " adfs A1,AL,AR" COM "float add\n", },
+#elifdef ARM_HAS_VFP
+ " fadds A1,AL,AR" COM "float add\n", },
+#else
+ "ZF", },
+#endif
+
+{ PLUS, INXREG,
+ SXREG, TDOUBLE,
+ SXREG, TDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " adfd A1,AL,AR" COM "double add\n", },
+#elifdef ARM_HAS_VFP
+ " faddd A1,AL,AR" COM "double add\n", },
+#else
+ "ZF", },
+#endif
+
+{ PLUS, INXREG,
+ SXREG, TLDOUBLE,
+ SXREG, TLDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " adfe A1,AL,AR" COM "ldouble add\n", },
+#elifdef ARM_HAS_VFP
+ " faddd A1,AL,AR" COM "ldouble add\n", },
+#else
+ "ZF", },
+#endif
+
+{ MINUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SCCON, TANY,
+ NAREG|NASL, RESC1,
+ " sub A1,AL,AR" COM "subtraction of constant\n", },
+
+{ MINUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ NAREG|NASL, RESC1,
+ " sub A1,AR,AL" COM "subtraction\n", },
+
+{ MINUS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SCCON, TANY,
+ NBREG|NBSL, RESC1,
+ " subs A1,AL,AR" COM "64-bit subtraction of constant\n"
+ " rsc U1,UL,AR\n", },
+
+{ MINUS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1,
+ " subs A1,AL,AR" COM "64-bit subtraction\n"
+ " sbc U1,UL,AR\n", },
+
+{ MINUS, INFREG,
+ SFREG, TFLOAT,
+ SFREG, TFLOAT,
+ NSPECIAL|NFREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " sufs A1,AL,AR" COM "float subtraction\n", },
+#elifdef ARM_HAS_VFP
+ " fsubs A1,AL,AR" COM "float subtraction\n", },
+#else
+ "ZF", },
+#endif
+
+{ MINUS, INXREG,
+ SXREG, TDOUBLE,
+ SXREG, TDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " sufd A1,AL,AR" COM "double subtraction\n", },
+#elifdef ARM_HAS_VFP
+ " fsubd A1,AL,AR" COM "double subtraction\n", },
+#else
+ "ZF", },
+#endif
+
+{ MINUS, INXREG,
+ SXREG, TLDOUBLE,
+ SXREG, TLDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " sufe A1,AL,AR" COM "ldouble subtraction\n", },
+#elifdef ARM_HAS_VFP
+ " fsubd A1,AL,AR" COM "double subtraction\n", },
+#else
+ "ZF", },
+#endif
+
+/*
+ * The next rules handle all shift operators.
+ */
+
+{ LS, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " mov A1,AL,asl AR" COM "left shift\n", },
+
+{ LS, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SCCON, TANY,
+ NAREG|NASL, RESC1,
+ " mov A1,AL,asl AR" COM "left shift by constant\n", },
+
+{ LS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SCON, TANY,
+ NBREG, RESC1,
+ "ZO" },
+
+{ RS, INAREG,
+ SAREG, TSWORD|TSHORT|TCHAR,
+ SAREG, TSWORD|TSHORT|TCHAR,
+ NAREG|NASL, RESC1,
+ " mov A1,AL,asr AR" COM "right shift\n", },
+
+{ RS, INAREG,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
+ NAREG|NASL, RESC1,
+ " mov A1,AL,lsr AR" COM "right shift\n", },
+
+{ RS, INAREG,
+ SAREG, TSWORD|TSHORT|TCHAR,
+ SCCON, TANY,
+ NAREG|NASL, RESC1,
+ " mov A1,AL,asr AR" COM "right shift by constant\n", },
+
+{ RS, INAREG,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
+ SCCON, TANY,
+ NAREG|NASL, RESC1,
+ " mov A1,AL,lsr AR" COM "right shift by constant\n", },
+
+{ RS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SCON, TANY,
+ NBREG, RESC1,
+ "ZO" },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+
+{ ASSIGN, FOREFF|INAREG,
+ SOREG|SNAME, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ 0, RDEST,
+ " str AR,AL" COM "assign word\n", },
+
+{ ASSIGN, FOREFF|INBREG,
+ SOREG|SNAME, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ 0, RDEST,
+ " str AR,AL" COM "assign 64-bit value\n"
+ " str UR,UL\n", },
+
+/* XXX don't know if this works */
+{ ASSIGN, FOREFF|INBREG,
+ SAREG, TPTRTO|TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ 0, RDEST,
+ " stmdb AL,{AR-UR}" COM "assign 64-bit value\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SOREG|SNAME, TCHAR|TUCHAR,
+ SAREG, TCHAR|TUCHAR,
+ 0, RDEST,
+ " strb AR,AL" COM "assign (u)char\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SOREG|SNAME, TSHORT|TUSHORT,
+ SAREG, TSHORT|TUSHORT,
+ 0, RDEST,
+ " strh AR,AL" COM "assign (u)short\n", },
+
+{ ASSIGN, FOREFF|INFREG,
+ SOREG|SNAME, TFLOAT,
+ SFREG, TFLOAT,
+ 0, RDEST,
+#ifdef ARM_HAS_FPA
+ " stfs AR,AL" COM "assign float\n", },
+#elifdef ARM_HAS_VFP
+#else
+ " str AR,AL" COM "assign float\n", },
+#endif
+
+{ ASSIGN, FOREFF|INXREG,
+ SOREG|SNAME, TDOUBLE,
+ SXREG, TDOUBLE,
+ 0, RDEST,
+#ifdef ARM_HAS_FPA
+ " stfd AR,AL" COM "assign double\n", },
+#elifdef ARM_HAS_VFP
+#else
+ " str AR,AL" COM "assign double\n"
+ " str UR,UL\n", },
+#endif
+
+{ ASSIGN, FOREFF|INXREG,
+ SOREG|SNAME, TLDOUBLE,
+ SXREG, TLDOUBLE,
+ 0, RDEST,
+#ifdef ARM_HAS_FPA
+ " stfe AR,AL" COM "assign ldouble\n", },
+#elifdef ARM_HAS_VFP
+#else
+ " str AR,AL" COM "assign ldouble\n"
+ " str UR,UL\n", },
+#endif
+
+/* assign register to register */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ 0, RDEST,
+ " mov AL,AR" COM "assign AR to AL\n", },
+
+{ ASSIGN, FOREFF|INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ 0, RDEST,
+ " mov AL,AR" COM "assign UR:AR to UL:AL\n"
+ " mov UL,UR\n", },
+
+{ ASSIGN, FOREFF|INFREG,
+ SFREG, TFLOAT,
+ SFREG, TFLOAT,
+ 0, RDEST,
+#ifdef ARM_HAS_FPA
+ " mvf AL,AR" COM "assign float reg to float reg\n", },
+#elifdef ARM_HAS_VFP
+ " fcpys AL,AR" COM "assign float reg to float reg\n", },
+#else
+ " mov AL,AR" COM "assign float reg to float reg\n", },
+#endif
+
+{ ASSIGN, FOREFF|INXREG,
+ SXREG, TDOUBLE|TLDOUBLE,
+ SXREG, TDOUBLE|TLDOUBLE,
+ 0, RDEST,
+#ifdef ARM_HAS_FPA
+ " mvf AL,AR" COM "assign float reg to float reg\n", },
+#elifdef ARM_HAS_VFP
+ " fcpyd AL,AR" COM "assign float reg to float reg\n", },
+#else
+ " mov AL,AR" COM "assign (l)double reg to (l)double reg\n"
+ " mov UL,UR\n", },
+#endif
+
+#if 0
+{ ASSIGN, FOREFF|INAREG,
+ SFLD, TANY,
+ SAREG, TANY,
+ NAREG, RDEST,
+ "ZE", },
+
+{ ASSIGN, FOREFF,
+ SFLD, TANY,
+ SAREG, TANY,
+ NAREG, 0,
+ "ZE", },
+#endif
+
+{ STASG, INAREG|FOREFF,
+ SOREG|SNAME, TANY,
+ SAREG, TPTRTO|TANY,
+ NSPECIAL, RRIGHT,
+ "ZQ", },
+
+/*
+ * DIV/MOD/MUL
+ */
+
+{ DIV, INAREG,
+ SAREG, TWORD,
+ SAREG, TWORD,
+ NSPECIAL|NAREG|NASL, RESC1,
+ "ZE", },
+
+{ DIV, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NSPECIAL|NBREG|NBSL, RESC1,
+ "ZE", },
+
+{ DIV, INFREG,
+ SFREG, TFLOAT,
+ SFREG, TFLOAT,
+ NSPECIAL|NFREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " dvfs A1,AL,AL" COM "fast (float) divide\n", },
+#elifdef ARM_HAS_VFP
+ " fdivs A1,AL,AL" COM "fast (float) divide\n", },
+#else
+ "ZF", },
+#endif
+
+{ DIV, INXREG,
+ SXREG, TDOUBLE,
+ SXREG, TDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " dvfd A1,AL,AL" COM "double divide\n", },
+#elifdef ARM_HAS_VFP
+ " fdivd A1,AL,AL" COM "double divide\n", },
+#else
+ "ZF", },
+#endif
+
+{ DIV, INXREG,
+ SXREG, TLDOUBLE,
+ SXREG, TLDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " dvfe A1,AL,AL" COM "ldouble divide\n", },
+#elifdef ARM_HAS_VFP
+ " fdivd A1,AL,AL" COM "double divide\n", },
+#else
+ "ZF", },
+#endif
+
+{ MOD, INAREG,
+ SAREG, TWORD,
+ SAREG, TWORD,
+ NSPECIAL|NAREG, RESC1,
+ "ZE", },
+
+{ MOD, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NSPECIAL|NBREG, RESC1,
+ "ZE", },
+
+{ MUL, INAREG,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NSPECIAL|NAREG, RESC1,
+ " mul A1,AL,AR\n", },
+
+{ MUL, INBREG,
+ SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR,
+ SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR,
+ NSPECIAL|NBREG, RESC1,
+#ifdef ARM_HAS_MULL
+ " smull U1,A1,AL,AR\n", },
+#else
+ " mul A1,AL,AR\n"
+ " mul U1,AL,AR\n", },
+#endif
+
+{ MUL, INBREG,
+ SAREG, TSWORD|TSHORT|TCHAR,
+ SAREG, TSWORD|TSHORT|TCHAR,
+ NSPECIAL|NBREG, RESC1,
+#ifdef ARM_HAS_MULL
+ " umull U1,A1,AL,AR\n", },
+#else
+ " mul A1,AL,AR\n"
+ " mul U1,AL,AR\n", },
+#endif
+
+{ MUL, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NSPECIAL|NBREG, RESC1,
+#ifdef ARM_HAS_MULL
+ " umull U1,A1,AL,AR\n", },
+#else
+ " mul A1,AL,AR\n"
+ " mul U1,AL,AR\n", },
+#endif
+
+{ MUL, INFREG,
+ SFREG, TFLOAT,
+ SFREG, TFLOAT,
+ NSPECIAL|NFREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " fmls A1,AL,AL" COM "fast (float) multiply\n", },
+#elifdef ARM_HAS_VFP
+ " fmuls A1,AL,AL" COM "float multiply\n", },
+#else
+ "ZF", },
+#endif
+
+{ MUL, INXREG,
+ SXREG, TDOUBLE|TLDOUBLE,
+ SXREG, TDOUBLE|TLDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " mufd A1,AL,AL" COM "fast (l)double multiply\n", },
+#elifdef ARM_HAS_VFP
+ " muld A1,AL,AL" COM "(l)double multiply\n", },
+#else
+ "ZF", },
+#endif
+
+/*
+ * Indirection operators.
+ */
+
+{ UMUL, INAREG,
+ SANY, TANY,
+ SOREG|SNAME, TWORD|TPOINT,
+ NAREG, RESC1,
+ " ldr A1,AL" COM "word load\n", },
+
+{ UMUL, INAREG,
+ SANY, TANY,
+ SOREG|SNAME, TCHAR,
+ NAREG, RESC1,
+ " ldrsb A1,AL" COM "char load\n", },
+
+{ UMUL, INAREG,
+ SANY, TANY,
+ SOREG|SNAME, TUCHAR,
+ NAREG, RESC1,
+ " ldrb A1,AL" COM "uchar load\n", },
+
+{ UMUL, INAREG,
+ SANY, TANY,
+ SOREG|SNAME, TUSHORT,
+ NAREG, RESC1,
+ " ldrh A1,AL" COM "short load\n", },
+
+{ UMUL, INAREG,
+ SANY, TANY,
+ SOREG|SNAME, TSHORT,
+ NAREG, RESC1,
+ " ldrsh A1,AL" COM "short load\n", },
+
+{ UMUL, INBREG,
+ SANY, TANY,
+ SOREG|SNAME, TLONGLONG|TULONGLONG,
+ NBREG, RESC1,
+ " ldr A1,AL" COM "64-bit load\n"
+ " ldr U1,UL\n", },
+
+{ UMUL, INFREG,
+ SANY, TANY,
+ SOREG|SNAME, TFLOAT,
+ NFREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " ldfs A1,AL" COM "float load\n", },
+#elifdef ARM_HAS_VFP
+#else
+ " ldr A1,AL" COM "float load\n", },
+#endif
+
+{ UMUL, INXREG,
+ SANY, TANY,
+ SOREG|SNAME, TDOUBLE,
+ NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " ldfd AL" COM "double load\n", },
+#elifdef ARM_HAS_VFP
+#else
+ " ldr A1,AL" COM "double load\n"
+ " ldr U1,UL\n", },
+#endif
+
+{ UMUL, INXREG,
+ SANY, TANY,
+ SOREG|SNAME, TLDOUBLE,
+ NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " ldfe AL" COM "long double load\n", },
+#elifdef ARM_HAS_VFP
+#else
+ " ldr A1,AL" COM "long double load\n"
+ " ldr U1,UL\n", },
+#endif
+
+/*
+ * Logical/branching operators
+ */
+
+/* compare with register */
+{ OPLOG, FORCC,
+ SAREG, TSWORD|TSHORT|TCHAR,
+ SAREG, TSWORD|TSHORT|TCHAR,
+ 0, RESCC,
+ " cmp AL,AR" COM "AR-AL (sets flags)\n", },
+
+/* compare with register */
+{ OPLOG, FORCC,
+ SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR,
+ SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR,
+ 0, RESCC,
+ " cmp AL,AR" COM "AR-AL (sets flags)\n", },
+
+/* compare with register */
+{ OPLOG, FORCC,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ 0, RESCC,
+ "ZD", },
+
+{ OPLOG, FORCC,
+ SFREG, TFLOAT,
+ SFREG, TFLOAT,
+ NSPECIAL, RESCC,
+#ifdef ARM_HAS_FPA
+ " cmfs AL,AR" COM "float compare\n", },
+#elifdef ARM_HAS_VFP
+ " fcmps AL,AR" COM "float compare\n", },
+#else
+ "ZF", },
+#endif
+
+{ OPLOG, FORCC,
+ SXREG, TDOUBLE,
+ SXREG, TDOUBLE,
+ NSPECIAL, RESCC,
+#ifdef ARM_HAS_FPA
+ " cmfd AL,AR" COM "double compare\n", },
+#elifdef ARM_HAS_VFP
+ " fcmpd AL,AR" COM "double compare\n", },
+#else
+ "ZF", },
+#endif
+
+{ OPLOG, FORCC,
+ SXREG, TLDOUBLE,
+ SXREG, TLDOUBLE,
+ NSPECIAL, RESCC,
+#ifdef ARM_HAS_FPA
+ " cmfe AL,AR" COM "ldouble compare\n", },
+#elifdef ARM_HAS_VFP
+ " fcmpd AL,AR" COM "double compare\n", },
+#else
+ "ZF", },
+#endif
+
+/* AND/OR/ER */
+{ AND, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1|RESCC,
+ " and A1,AL,AR" COM "64-bit and\n"
+ " and U1,UL,UR\n", },
+
+{ OR, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1,
+ " orr A1,AL,AR" COM "64-bit or\n"
+ " orr U1,UL,UR\n" },
+
+{ ER, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1,
+ " eor A1,AL,AR" COM "64-bit xor\n"
+ " eor U1,UL,UR\n" },
+
+{ OPSIMP, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1|RESCC,
+ " O A1,AL,AR\n", },
+
+{ OPSIMP, INAREG|FORCC,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " Os A1,AL,AR\n", },
+
+
+/*
+ * Jumps.
+ */
+{ GOTO, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ 0, RNOP,
+ " b LL\n", },
+
+#if 0
+{ GOTO, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, RNOP,
+ " mov pc,AL\n", },
+#endif
+
+/*
+ * Convert LTYPE to reg.
+ */
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SOREG|SNAME, TWORD|TPOINT,
+ NAREG, RESC1,
+ " ldr A1,AL" COM "load word from memory\n", },
+
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SOREG|SNAME, TLONGLONG|TULONGLONG,
+ NBREG, RESC1,
+ " ldr A1,AL" COM "load long long from memory\n"
+ " ldr U1,UL\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SOREG|SNAME, TCHAR,
+ NAREG, RESC1,
+ " ldrsb A1,AL" COM "load char from memory\n" },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SOREG|SNAME, TUCHAR,
+ NAREG, RESC1,
+ " ldrb A1,AL" COM "load uchar from memory\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SOREG|SNAME, TSHORT,
+ NAREG, RESC1,
+ " ldrsh A1,AL" COM "load short from memory\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SOREG|SNAME, TUSHORT,
+ NAREG, RESC1,
+ " ldrh A1,AL" COM "load ushort from memory\n", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SCON, TANY,
+ NAREG, RESC1,
+ " ldr A1,ZI" COM "load integer constant\n", },
+
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SCON, TANY,
+ NBREG, RESC1,
+ "ZJ", },
+
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SAREG, TANY,
+ NAREG, RESC1,
+ " mov A1,AL" COM "load AL into A1\n" },
+
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG, RESC1,
+ " mov A1,AL" COM "load UL:AL into U1:A1\n"
+ " mov U1,UL\n", },
+
+{ OPLTYPE, INFREG,
+ SANY, TANY,
+ SOREG|SNAME, TFLOAT,
+ NFREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " ldfs A1,AL" COM "load float\n", },
+#elifdef ARM_HAS_VFP
+#else
+ " ldr A1,AL" COM "load float\n", },
+#endif
+
+{ OPLTYPE, INXREG,
+ SANY, TANY,
+ SOREG|SNAME, TDOUBLE,
+ NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " ldfd A1,AL" COM "load double\n", },
+#elifdef ARM_HAS_VFP
+#else
+ " ldr A1,AL" COM "load double\n"
+ " ldr U1,UL\n", },
+#endif
+
+{ OPLTYPE, INXREG,
+ SANY, TANY,
+ SOREG|SNAME, TLDOUBLE,
+ NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " ldfe A1,AL" COM "load ldouble\n", },
+#elifdef ARM_HAS_VFP
+#else
+ " ldr A1,AL" COM "load ldouble\n"
+ " ldr U1,UL\n", },
+#endif
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS, INAREG,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " neg A1,AL" COM "negation\n", },
+
+{ UMINUS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1,
+ " rsbs A1,AL,#0" COM "64-bit negation\n"
+ " rsc U1,UL,#0\n", },
+
+{ UMINUS, INFREG,
+ SFREG, TFLOAT,
+ SFREG, TFLOAT,
+ NSPECIAL|NFREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " mvfs A1,AL" COM "float negation\n", },
+#elifdef ARM_HAS_VFP
+ " negs A1,AL" COM "float negation\n", },
+#else
+ "ZF", },
+#endif
+
+{ UMINUS, INXREG,
+ SXREG, TDOUBLE,
+ SXREG, TDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " mvfd A1,AL" COM "double negation\n", },
+#elifdef ARM_HAS_VFP
+ " negd A1,AL" COM "double negation\n", },
+#else
+ "ZF", },
+#endif
+
+{ UMINUS, INXREG,
+ SXREG, TLDOUBLE,
+ SXREG, TLDOUBLE,
+ NSPECIAL|NXREG, RESC1,
+#ifdef ARM_HAS_FPA
+ " mvfe A1,AL" COM "ldouble negation\n", },
+#elifdef ARM_HAS_VFP
+ " negd A1,AL" COM "ldouble negation\n", },
+#else
+ "ZF", },
+#endif
+
+{ COMPL, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SANY, TANY,
+ NAREG|NASL, RESC1,
+ " mvn A1,AL" COM "complement\n", },
+
+{ COMPL, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SANY, TANY,
+ NBREG|NBSL, RESC1,
+ " mvn A1,AL" COM "64-bit complement\n"
+ " mvn U1,UL\n", },
+
+/*
+ * Arguments to functions.
+ */
+
+{ FUNARG, FOREFF,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SANY, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ 0, 0,
+ " stmfd sp!,{AL}" COM "save function arg to stack\n", },
+
+{ FUNARG, FOREFF,
+ SBREG, TLONGLONG|TULONGLONG,
+ SANY, TLONGLONG|TULONGLONG,
+ 0, 0,
+ " stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", },
+
+{ FUNARG, FOREFF,
+ SFREG, TFLOAT,
+ SANY, TFLOAT,
+ 0, 0,
+ " stmfd sp!,{AL}" COM "save function arg to stack\n", },
+
+{ FUNARG, FOREFF,
+ SXREG, TDOUBLE|TLDOUBLE,
+ SANY, TDOUBLE|TLDOUBLE,
+ 0, 0,
+ " stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", },
+
+# 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]);