summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2007-10-20 10:01:39 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2007-10-20 10:01:39 +0000
commitd94416c5dca2f5b39992748e5863b8727399b411 (patch)
treeb29c5064911e9081fddf8f9a6b7b8ecd79910c60
parenta1bfc88d4c56fa70cf43d0feb95b8c06da3e7523 (diff)
Start of a powerpc backend by Gregory McGarry. Not complete yet.
-rw-r--r--usr.bin/pcc/powerpc/README22
-rw-r--r--usr.bin/pcc/powerpc/code.c338
-rw-r--r--usr.bin/pcc/powerpc/local.c958
-rw-r--r--usr.bin/pcc/powerpc/local2.c1219
-rw-r--r--usr.bin/pcc/powerpc/macdefs.h270
-rw-r--r--usr.bin/pcc/powerpc/order.c245
-rw-r--r--usr.bin/pcc/powerpc/table.c1102
7 files changed, 4154 insertions, 0 deletions
diff --git a/usr.bin/pcc/powerpc/README b/usr.bin/pcc/powerpc/README
new file mode 100644
index 00000000000..d81683ef881
--- /dev/null
+++ b/usr.bin/pcc/powerpc/README
@@ -0,0 +1,22 @@
+macdefs.h ; machine-dependent definitions
+code.c ; machine-dependent code for prologs, switches (pass 1)
+local.c ; machine-dependent code for prologs, switches (pass 1)
+local2.c ; misc routines and tables of register names (pass 2)
+order.c ; machine-dependent code-generation strategy (pass 2)
+table.c ; code templates (pass 2)
+
+On OS X, binaries are not ELF and all binaries are compiled PIC. To use pcc
+on OS X while linking against the system libraries, use the -k option.
+
+Current issues:
+
+- no floating point
+- mod/div on longlong not supported
+- problems with static variables with PIC
+- the stack frame is always 200 bytes - need to calculate size and patch
+ OREGs to temporaries and arguments
+- function arguments are always saved to the stack
+- permanent registers >R13 are not saved
+- structure arguments don't work
+- return of structure doesn't work
+- no built-in vararg support
diff --git a/usr.bin/pcc/powerpc/code.c b/usr.bin/pcc/powerpc/code.c
new file mode 100644
index 00000000000..288e9d79f34
--- /dev/null
+++ b/usr.bin/pcc/powerpc/code.c
@@ -0,0 +1,338 @@
+/* $OpenBSD: code.c,v 1.1 2007/10/20 10:01:38 otto Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+
+# include "pass1.h"
+#include "pass2.h"
+
+/*
+ * cause the alignment to become a multiple of n
+ * never called for text segment.
+ */
+void
+defalign(int n)
+{
+ n /= SZCHAR;
+ if (n == 1)
+ return;
+ printf(" .align %d\n", n);
+}
+
+/*
+ * define the current location as the name p->sname
+ * never called for text segment.
+ */
+void
+defnam(struct symtab *p)
+{
+ char *c = p->sname;
+
+#ifdef GCC_COMPAT
+ c = gcc_findname(p);
+#endif
+ if (p->sclass == EXTDEF)
+ printf(" .globl %s\n", exname(c));
+ printf("%s:\n", exname(c));
+}
+
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode()
+{
+#if 0
+ NODE *p, *q;
+ int sz;
+#endif
+
+#if 0
+ printf("EFCODE:\n");
+#endif
+
+ if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+ return;
+ assert(0);
+#if 0
+ /* address of return struct is in eax */
+ /* create a call to memcpy() */
+ /* will get the result in eax */
+ p = block(REG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+ p->n_rval = EAX;
+ q = block(OREG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+ q->n_rval = EBP;
+ q->n_lval = 8; /* return buffer offset */
+ p = block(CM, q, p, INT, 0, MKSUE(INT));
+ sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR;
+ p = block(CM, p, bcon(sz), INT, 0, MKSUE(INT));
+ p->n_right->n_name = "";
+ p = block(CALL, bcon(0), p, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+ p->n_left->n_name = "memcpy";
+ p = clocal(p);
+ send_passt(IP_NODE, p);
+#endif
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **a, int n)
+{
+ int i, m;
+
+#if 0
+ printf("BFCODE start with %d arguments\n", n);
+#endif
+
+ if (cftnsp->stype == STRTY+FTN && cftnsp->stype == UNIONTY+FTN) {
+ /* Function returns struct, adjust arg offset */
+ for (i = 0; i < n; i++)
+ a[i]->soffset += SZPOINT(INT);
+ }
+
+ m = n <= 8 ? n : 8;
+
+#if 0
+ /* if optimised, assign parameters to registers */
+ /* XXX consider the size of the types */
+ for (i=0; i < m; i++) {
+ a[i]->hdr.h_sclass = REGISTER;
+ a[i]->hdr.h_offset = R3 + i;
+ }
+#endif
+
+ /* if not optimised, */
+ /* save the register arguments (R3-R10) onto the stack */
+ int passedargoff = ARGINIT + FIXEDSTACKSIZE*8; // XXX must add the size of the stack frame
+ int reg = R3;
+ for (i=0; i < m; i++) {
+ NODE *r, *p;
+ a[i]->hdr.h_sclass = PARAM;
+ a[i]->hdr.h_offset = NOOFFSET;
+ oalloc(a[i], &passedargoff);
+ spname = a[i];
+ p = buildtree(NAME, NIL, NIL);
+ r = bcon(0);
+ r->n_op = REG;
+ if (BTYPE(p->n_type) == LONGLONG || BTYPE(p->n_type) == ULONGLONG) {
+ r->n_rval = R3R4+(reg-R3);
+ reg += 2;
+ } else {
+ r->n_rval = reg++;
+ }
+ r->n_type = p->n_type;
+ r->n_sue = p->n_sue;
+ r->n_df = p->n_df;
+ ecode(buildtree(ASSIGN, p, r));
+ }
+
+#if 1
+ /* XXXHACK save the rest of the registers too, for varargs */
+ for (; reg < R11; reg++) {
+ NODE *r, *l;
+ l = bcon(0);
+ l->n_op = OREG;
+ l->n_lval = (passedargoff/SZCHAR);
+ l->n_rval = FPREG;
+ l->n_type = INT;
+ passedargoff += SZINT;
+ r = bcon(0);
+ r->n_op = REG;
+ r->n_rval = reg;
+ r->n_type = INT;
+ ecode(buildtree(ASSIGN, l, r));
+ }
+#endif
+
+#if 0
+ printf("BFCODE end\n");
+#endif
+}
+
+
+/*
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+#if 0
+ printf("BCCODE: autooff=%d, SZINT=%d\n", autooff, SZINT);
+#endif
+ SETOFF(autooff, SZINT);
+}
+
+struct stub stublist;
+struct stub nlplist;
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag )
+{
+#if 0
+ printf("EJOBCODE:\n");
+#endif
+
+ if (kflag) {
+ // iterate over the stublist and output the PIC stubs
+ struct stub *p;
+
+ DLIST_FOREACH(p, &stublist, link) {
+ printf("\t.section __TEXT, __picsymbolstub1,symbol_stubs,pure_instructions,32\n");
+ printf("\t.align 5\n");
+ printf("%s$stub:\n", p->name);
+ printf("\t.indirect_symbol %s\n", p->name);
+ printf("\tmflr r0\n");
+ printf("\tbcl 20,31,L%s$stub$spb\n", p->name);
+ printf("L%s$stub$spb:\n", p->name);
+ printf("\tmflr r11\n");
+ printf("\taddis r11,r11,ha16(L%s$lazy_ptr-L%s$stub$spb)\n", p->name, p->name);
+ printf("\tmtlr r0\n");
+ printf("\tlwzu r12,lo16(L%s$lazy_ptr-L%s$stub$spb)(r11)\n", p->name, p->name);
+ printf("\tmtctr r12\n");
+ printf("\tbctr\n");
+ printf("\t.lazy_symbol_pointer\n");
+ printf("L%s$lazy_ptr:\n", p->name);
+ printf("\t.indirect_symbol %s\n", p->name);
+ printf("\t.long dyld_stub_binding_helper\n");
+ printf("\t.subsections_via_symbols\n");
+
+ }
+
+ printf("\t.non_lazy_symbol_pointer\n");
+ DLIST_FOREACH(p, &nlplist, link) {
+ printf("L%s$non_lazy_ptr:\n", p->name);
+ printf("\t.indirect_symbol %s\n", p->name);
+ printf("\t.long 0\n");
+ }
+
+ // memory leak here
+ }
+}
+
+void
+bjobcode()
+{
+#if 0
+ printf("BJOBCODE:\n");
+#endif
+
+ DLIST_INIT(&stublist, link);
+ DLIST_INIT(&nlplist, link);
+}
+
+/*
+ * Print character t at position i in one string, until t == -1.
+ * Locctr & label is already defined.
+ */
+void
+bycode(int t, int i)
+{
+ static int lastoctal = 0;
+
+ /* put byte i+1 in a string */
+
+ if (t < 0) {
+ if (i != 0)
+ puts("\"");
+ } else {
+ if (i == 0)
+ printf("\t.ascii \"");
+ if (t == '\\' || t == '"') {
+ lastoctal = 0;
+ putchar('\\');
+ putchar(t);
+ } else if (t < 040 || t >= 0177) {
+ lastoctal++;
+ printf("\\%o",t);
+ } else if (lastoctal && '0' <= t && t <= '9') {
+ lastoctal = 0;
+ printf("\"\n\t.ascii \"%c", t);
+ } else {
+ lastoctal = 0;
+ putchar(t);
+ }
+ }
+}
+
+/*
+ * n integer words of zeros
+ */
+void
+zecode(int n)
+{
+ printf(" .zero %d\n", n * (SZINT/SZCHAR));
+// inoff += n * SZINT;
+}
+
+/*
+ * return the alignment of field of type t
+ */
+int
+fldal(unsigned int t)
+{
+ uerror("illegal field type");
+ return(ALINT);
+}
+
+/* fix up type of field p */
+void
+fldty(struct symtab *p)
+{
+}
+
+/* p points to an array of structures, each consisting
+ * of a constant value and a label.
+ * The first is >=0 if there is a default label;
+ * its value is the label number
+ * The entries p[1] to p[n] are the nontrivial cases
+ * XXX - fix genswitch.
+ * n is the number of case statemens (length of list)
+ */
+void
+genswitch(int num, struct swents **p, int n)
+{
+ NODE *r;
+ int i;
+
+ /* simple switch code */
+ for (i = 1; i <= n; ++i) {
+ /* already in 1 */
+ r = tempnode(num, INT, 0, MKSUE(INT));
+ r = buildtree(NE, r, bcon(p[i]->sval));
+ cbranch(buildtree(NOT, r, NIL), bcon(p[i]->slab));
+ }
+ if (p[0]->slab > 0)
+ branch(p[0]->slab);
+}
diff --git a/usr.bin/pcc/powerpc/local.c b/usr.bin/pcc/powerpc/local.c
new file mode 100644
index 00000000000..4020abc41dc
--- /dev/null
+++ b/usr.bin/pcc/powerpc/local.c
@@ -0,0 +1,958 @@
+/* $OpenBSD: local.c,v 1.1 2007/10/20 10:01:38 otto Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+
+#include "pass1.h"
+
+extern int kflag;
+
+static
+void simmod(NODE *p);
+
+/* this file contains code which is dependent on the target machine */
+
+/* don't permit CALLs to be arguments to other CALLs (nest CALLs) */
+
+static NODE *
+emitinnercall(NODE *r)
+{
+ NODE *tmp1, *tmp2;
+
+#ifdef PCC_DEBUG
+ if (xdebug) {
+ printf("clocal::emitinnercall():\n");
+ fwalk(r, eprint, 0);
+ }
+#endif
+
+ tmp1 = tempnode(0, r->n_type, r->n_df, r->n_sue);
+ tmp2 = tempnode(tmp1->n_lval, r->n_type, r->n_df, r->n_sue);
+ ecode(buildtree(ASSIGN, tmp1, r));
+
+ return tmp2;
+}
+
+static void
+breaknestedcalls(NODE *p)
+{
+ NODE *r;
+
+ for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+ if (r->n_right->n_op == CALL)
+ r->n_right = emitinnercall(r->n_right);
+ if (r->n_left->n_op == CALL)
+ r->n_left = emitinnercall(r->n_left);
+ }
+
+#ifdef PCC_DEBUG
+ if (xdebug) {
+ printf("clocal::breaknestedcalls(): exiting with tree:\n");
+ fwalk(p, eprint, 0);
+ }
+#endif
+}
+
+static void
+fixupfuncargs(NODE *r, int *reg)
+{
+#ifdef PCC_DEBUG
+ if (xdebug)
+ printf("fixupfuncargs(): r=%p\n", r);
+#endif
+
+ if (r->n_op == CM) {
+ /* recurse to the bottom of the tree */
+ fixupfuncargs(r->n_left, reg);
+
+ r->n_right = block(ASSIGN, NIL, r->n_right,
+ r->n_right->n_type, r->n_right->n_df,
+ r->n_right->n_sue);
+ r->n_right->n_left = block(REG, NIL, NIL, r->n_right->n_type, 0, MKSUE(INT));
+
+ if (r->n_right->n_type == ULONGLONG || r->n_right->n_type == LONGLONG) {
+ r->n_right->n_left->n_rval = R3R4 + (*reg) - R3;
+ (*reg) += 2;
+ } else {
+ r->n_right->n_left->n_rval = (*reg);
+ (*reg)++;
+ }
+
+ } else {
+ NODE *l = talloc();
+ *l = *r;
+ r->n_op = ASSIGN;
+ r->n_left = block(REG, NIL, NIL, l->n_type, 0, MKSUE(INT));
+ r->n_right = l;
+ if (r->n_right->n_type == ULONGLONG || r->n_right->n_type == LONGLONG) {
+ r->n_left->n_rval = R3R4 + (*reg) - R3;
+ (*reg) += 2;
+ } else {
+ r->n_left->n_rval = (*reg);
+ (*reg)++;
+ }
+ }
+}
+
+/* clocal() is called to do local transformations on
+ * an expression tree preparitory to its being
+ * written out in intermediate code.
+ *
+ * the major essential job is rewriting the
+ * automatic variables and arguments in terms of
+ * REG and OREG nodes
+ * conversion ops which are not necessary are also clobbered here
+ * in addition, any special features (such as rewriting
+ * exclusive or) are easily handled here as well
+ */
+NODE *
+clocal(NODE *p)
+{
+
+ struct symtab *q;
+ NODE *r, *l;
+ int o;
+ int m;
+ TWORD t;
+
+#ifdef PCC_DEBUG
+ if (xdebug) {
+ printf("clocal: %p\n", p);
+ fwalk(p, eprint, 0);
+ }
+#endif
+ switch (o = p->n_op) {
+
+#if 1
+ case ADDROF:
+#ifdef PCC_DEBUG
+ if (xdebug) {
+ printf("clocal(): ADDROF\n");
+ printf("type: 0x%x\n", p->n_type);
+ }
+#endif
+
+ if (kflag && p->n_left->n_op == NAME) {
+
+ TWORD t = DECREF(p->n_type);
+
+ if (!ISFTN(t)) {
+ r = talloc();
+ *r = *p;
+
+ l = block(REG, NIL, NIL, INT, p->n_df, p->n_sue);
+ l->n_lval = 0;
+ l->n_rval = R31;
+
+ p->n_op = PLUS;
+ p->n_lval = 0;
+ p->n_left = l;
+ p->n_rval = 0;
+ p->n_right = r;
+ }
+
+ }
+ break;
+#endif
+
+ case NAME:
+ if ((q = p->n_sp) == NULL)
+ return p; /* Nothing to care about */
+
+ switch (q->sclass) {
+
+ case PARAM:
+ case AUTO:
+ /* fake up a structure reference */
+ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+ r->n_lval = 0;
+ r->n_rval = FPREG;
+ p = stref(block(STREF, r, p, 0, 0, 0));
+ break;
+
+ case STATIC:
+ if (q->slevel == 0)
+ break;
+ p->n_lval = 0;
+ p->n_sp = q;
+ break;
+
+ case REGISTER:
+ p->n_op = REG;
+ p->n_lval = 0;
+ p->n_rval = q->soffset;
+ break;
+
+#if 1
+ default:
+ if (kflag && !ISFTN(p->n_type)) {
+
+ TWORD t = p->n_type;
+ l = block(REG, NIL, NIL, INCREF(t), p->n_df, p->n_sue);
+ l->n_lval = 0;
+ l->n_rval = R31;
+
+ p->n_op = ICON;
+ p->n_type = INCREF(p->n_type);
+
+ p = block(PLUS, l, p, INCREF(t), p->n_df, p->n_sue);
+ p = block(UMUL, p, NIL, t, p->n_df, p->n_sue);
+ }
+#endif
+
+ }
+ break;
+
+ case STCALL:
+ case CALL:
+ {
+
+ /* break nested CALLs */
+ breaknestedcalls(p);
+
+ /* Fix function call arguments. */
+ /* move everything into the registers */
+ /* XXX have to save the old values of R3-R10 on the stack
+ (but only once per function */
+ {
+ int reg = R3;
+ fixupfuncargs(p->n_right, &reg);
+ }
+
+#if 0
+ for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+ if (r->n_right->n_op != STARG &&
+ r->n_right->n_op != FUNARG) {
+ printf("HERE\n");
+ r->n_right = block(FUNARG, r->n_right, NIL,
+ r->n_right->n_type, r->n_right->n_df,
+ r->n_right->n_sue);
+ }
+ }
+ if (r->n_op != STARG && r->n_op != FUNARG) {
+ printf("HERE2\n");
+ l = talloc();
+ *l = *r;
+ r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type;
+ }
+#endif
+ break;
+ }
+
+ case CBRANCH:
+ l = p->n_left;
+
+ /*
+ * Remove unneccessary conversion ops.
+ */
+ if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
+ if (coptype(l->n_op) != BITYPE)
+ break;
+ if (l->n_right->n_op == ICON) {
+ r = l->n_left->n_left;
+ if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
+ break;
+ /* Type must be correct */
+ t = r->n_type;
+ nfree(l->n_left);
+ l->n_left = r;
+ l->n_type = t;
+ l->n_right->n_type = t;
+ }
+ }
+ break;
+
+ case PCONV:
+ /* Remove redundant PCONV's. Be careful */
+ l = p->n_left;
+ if (l->n_op == ICON) {
+ l->n_lval = (unsigned)l->n_lval;
+ goto delp;
+ }
+ if (l->n_type < INT || l->n_type == LONGLONG ||
+ l->n_type == ULONGLONG) {
+ /* float etc? */
+ p->n_left = block(SCONV, l, NIL,
+ UNSIGNED, 0, MKSUE(UNSIGNED));
+ break;
+ }
+ /* if left is SCONV, cannot remove */
+ if (l->n_op == SCONV)
+ break;
+
+ /* avoid ADDROF TEMP */
+ if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
+ break;
+
+ /* if conversion to another pointer type, just remove */
+ if (p->n_type > BTMASK && l->n_type > BTMASK)
+ goto delp;
+ break;
+
+ delp: l->n_type = p->n_type;
+ l->n_qual = p->n_qual;
+ l->n_df = p->n_df;
+ l->n_sue = p->n_sue;
+ nfree(p);
+ p = l;
+ break;
+
+ case SCONV:
+ l = p->n_left;
+
+ if (p->n_type == l->n_type) {
+ nfree(p);
+ return l;
+ }
+
+ if (xdebug)
+ printf("SCONV 1\n");
+
+ if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+ btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
+ if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+ l->n_type != FLOAT && l->n_type != DOUBLE &&
+ l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+ if (l->n_op == NAME || l->n_op == UMUL ||
+ l->n_op == TEMP) {
+ l->n_type = p->n_type;
+ nfree(p);
+ return l;
+ }
+ }
+ }
+
+ if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+ coptype(l->n_op) == BITYPE) {
+ l->n_type = p->n_type;
+ nfree(p);
+ return l;
+ }
+
+ o = l->n_op;
+ m = p->n_type;
+
+ if (o == ICON) {
+ CONSZ val = l->n_lval;
+
+ if (!ISPTR(m)) /* Pointers don't need to be conv'd */
+ switch (m) {
+ case BOOL:
+ l->n_lval = l->n_lval != 0;
+ break;
+ case CHAR:
+ l->n_lval = (char)val;
+ break;
+ case UCHAR:
+ l->n_lval = val & 0377;
+ break;
+ case SHORT:
+ l->n_lval = (short)val;
+ break;
+ case USHORT:
+ l->n_lval = val & 0177777;
+ break;
+ case ULONG:
+ case UNSIGNED:
+ l->n_lval = val & 0xffffffff;
+ break;
+ case ENUMTY:
+ case MOETY:
+ case LONG:
+ case INT:
+ l->n_lval = (int)val;
+ break;
+ case LONGLONG:
+ l->n_lval = (long long)val;
+ break;
+ case ULONGLONG:
+ l->n_lval = val;
+ break;
+ case VOID:
+ break;
+ case LDOUBLE:
+ case DOUBLE:
+ case FLOAT:
+ l->n_op = FCON;
+ l->n_dcon = val;
+ break;
+ default:
+ cerror("unknown type %d", m);
+ }
+ l->n_type = m;
+ l->n_sue = MKSUE(m);
+ nfree(p);
+ return l;
+ }
+ if (DEUNSIGN(p->n_type) == SHORT &&
+ DEUNSIGN(l->n_type) == SHORT) {
+ nfree(p);
+ p = l;
+ }
+ if ((p->n_type == CHAR || p->n_type == UCHAR ||
+ p->n_type == SHORT || p->n_type == USHORT) &&
+ (l->n_type == FLOAT || l->n_type == DOUBLE ||
+ l->n_type == LDOUBLE)) {
+ p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
+ p->n_left->n_type = INT;
+ return p;
+ }
+ break;
+
+ case MOD:
+ simmod(p);
+ break;
+
+ case DIV:
+ if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
+ break;
+ /* make it an int division by inserting conversions */
+ p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKSUE(INT));
+ p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKSUE(INT));
+ p = block(SCONV, p, NIL, p->n_type, 0, MKSUE(p->n_type));
+ p->n_left->n_type = INT;
+ break;
+
+ case PMCONV:
+ case PVCONV:
+
+ nfree(p);
+ return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
+
+ case FORCE:
+ /* put return value in return reg */
+ p->n_op = ASSIGN;
+ p->n_right = p->n_left;
+ p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
+ p->n_left->n_rval = p->n_left->n_type == BOOL ?
+ RETREG(CHAR) : RETREG(p->n_type);
+ break;
+
+ case LS:
+ case RS:
+ /* unless longlong, where it must be int */
+ if (p->n_right->n_op == ICON)
+ break; /* do not do anything */
+ if (p->n_type == LONGLONG || p->n_type == ULONGLONG) {
+ if (p->n_right->n_type != INT)
+ p->n_right = block(SCONV, p->n_right, NIL,
+ INT, 0, MKSUE(INT));
+ }
+ break;
+ }
+#ifdef PCC_DEBUG
+ if (xdebug) {
+ printf("clocal end: %p\n", p);
+ fwalk(p, eprint, 0);
+ }
+#endif
+ return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+ return(1); /* all names can have & taken on them */
+}
+
+/*
+ * at the end of the arguments of a ftn, set the automatic offset
+ */
+void
+cendarg()
+{
+#ifdef PCC_DEBUG
+ if (xdebug)
+ printf("cendarg: autooff=%d (was %d)\n", AUTOINIT, autooff);
+#endif
+ autooff = AUTOINIT;
+}
+
+/*
+ * Return 1 if a variable of type type is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+ if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+ return 0; /* not yet */
+ return 1;
+}
+
+/*
+ * return a node, for structure references, which is suitable for
+ * being added to a pointer of type t, in order to be off bits offset
+ * into a structure
+ * t, d, and s are the type, dimension offset, and sizeoffset
+ * For pdp10, return the type-specific index number which calculation
+ * is based on its size. For example, short a[3] would return 3.
+ * Be careful about only handling first-level pointers, the following
+ * indirections must be fullword.
+ */
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
+{
+ register NODE *p;
+
+#ifdef PCC_DEBUG
+ if (xdebug)
+ printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
+ off, t, d, sue->suesize);
+#endif
+
+ p = bcon(0);
+ p->n_lval = off/SZCHAR; /* Default */
+ return(p);
+}
+
+/*
+ * Allocate off bits on the stack. p is a tree that when evaluated
+ * is the multiply count for off, t is a storeable node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+#if 0
+ NODE *sp;
+#endif
+
+ p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
+
+ assert(0);
+#if 0
+ /* sub the size from sp */
+ sp = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
+ sp->n_lval = 0;
+ sp->n_rval = STKREG;
+ ecomp(buildtree(MINUSEQ, sp, p));
+
+ /* save the address of sp */
+ sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
+ sp->n_lval = 0;
+ sp->n_rval = STKREG;
+ t->n_type = sp->n_type;
+ ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+#endif
+
+}
+
+#if 0
+/*
+ * Print out an integer constant of size size.
+ * can only be sizes <= SZINT.
+ */
+void
+indata(CONSZ val, int size)
+{
+ switch (size) {
+ case SZCHAR:
+ printf("\t.byte %d\n", (int)val & 0xff);
+ break;
+ case SZSHORT:
+ printf("\t.word %d\n", (int)val & 0xffff);
+ break;
+ case SZINT:
+ printf("\t.long %d\n", (int)val & 0xffffffff);
+ break;
+ default:
+ cerror("indata");
+ }
+}
+#endif
+
+#if 0
+/*
+ * Print out a string of characters.
+ * Assume that the assembler understands C-style escape
+ * sequences. Location is already set.
+ */
+void
+instring(char *str)
+{
+ char *s;
+
+ /* be kind to assemblers and avoid long strings */
+ printf("\t.ascii \"");
+ for (s = str; *s != 0; ) {
+ if (*s++ == '\\') {
+ (void)esccon(&s);
+ }
+ if (s - str > 64) {
+ fwrite(str, 1, s - str, stdout);
+ printf("\"\n\t.ascii \"");
+ str = s;
+ }
+ }
+ fwrite(str, 1, s - str, stdout);
+ printf("\\0\"\n");
+}
+#endif
+
+static int inbits, inval;
+
+/*
+ * set fsz bits in sequence to zero.
+ */
+void
+zbits(OFFSZ off, int fsz)
+{
+ int m;
+
+ if (idebug)
+ printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
+ if ((m = (inbits % SZCHAR))) {
+ m = SZCHAR - m;
+ if (fsz < m) {
+ inbits += fsz;
+ return;
+ } else {
+ fsz -= m;
+ printf("\t.byte %d\n", inval);
+ inval = inbits = 0;
+ }
+ }
+ if (fsz >= SZCHAR) {
+ printf("\t.zero %d\n", fsz/SZCHAR);
+ fsz -= (fsz/SZCHAR) * SZCHAR;
+ }
+ if (fsz) {
+ inval = 0;
+ inbits = fsz;
+ }
+}
+
+/*
+ * Initialize a bitfield.
+ */
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+ if (idebug)
+ printf("infld off %lld, fsz %d, val %lld inbits %d\n",
+ off, fsz, val, inbits);
+ val &= (1 << fsz)-1;
+ while (fsz + inbits >= SZCHAR) {
+ inval |= (val << inbits);
+ printf("\t.byte %d\n", inval & 255);
+ fsz -= (SZCHAR - inbits);
+ val >>= (SZCHAR - inbits);
+ inval = inbits = 0;
+ }
+ if (fsz) {
+ inval |= (val << inbits);
+ inbits += fsz;
+ }
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ */
+void
+ninval(CONSZ off, int fsz, NODE *p)
+{
+ union { float f; double d; long double l; int i[3]; } u;
+ struct symtab *q;
+ TWORD t;
+ int i;
+
+ t = p->n_type;
+ if (t > BTMASK)
+ t = INT; /* pointer */
+
+ if (p->n_op != ICON && p->n_op != FCON)
+ cerror("ninval: init node not constant");
+
+ if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
+ uerror("element not constant");
+
+ switch (t) {
+ case LONGLONG:
+ case ULONGLONG:
+ i = (p->n_lval >> 32);
+ p->n_lval &= 0xffffffff;
+ p->n_type = INT;
+ ninval(off, 32, p);
+ p->n_lval = i;
+ ninval(off+32, 32, p);
+ break;
+ case INT:
+ case UNSIGNED:
+ printf("\t.long 0x%x", (int)p->n_lval);
+ if ((q = p->n_sp) != NULL) {
+ if ((q->sclass == STATIC && q->slevel > 0) ||
+ q->sclass == ILABEL) {
+ printf("+" LABFMT, q->soffset);
+ } else
+ printf("+%s", exname(q->sname));
+ }
+ printf("\n");
+ break;
+ case SHORT:
+ case USHORT:
+ printf("\t.short 0x%x\n", (int)p->n_lval & 0xffff);
+ break;
+ case BOOL:
+ if (p->n_lval > 1)
+ p->n_lval = p->n_lval != 0;
+ /* FALLTHROUGH */
+ case CHAR:
+ case UCHAR:
+ printf("\t.byte %d\n", (int)p->n_lval & 0xff);
+ break;
+ case LDOUBLE:
+ u.i[2] = 0;
+ u.l = (long double)p->n_dcon;
+ printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+ break;
+ case DOUBLE:
+ u.d = (double)p->n_dcon;
+ printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+ break;
+ case FLOAT:
+ u.f = (float)p->n_dcon;
+ printf("\t.long\t0x%x\n", u.i[0]);
+ break;
+ default:
+ cerror("ninval");
+ }
+}
+
+#if 0
+/*
+ * print out an integer.
+ */
+void
+inval(CONSZ word)
+{
+ word &= 0xffffffff;
+ printf(" .long 0x%llx\n", word);
+}
+
+/* output code to initialize a floating point value */
+/* the proper alignment has been obtained */
+void
+finval(NODE *p)
+{
+ union { float f; double d; long double l; int i[3]; } u;
+
+ switch (p->n_type) {
+ case LDOUBLE:
+ u.i[2] = 0;
+ u.l = (long double)p->n_dcon;
+ printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+ break;
+ case DOUBLE:
+ u.d = (double)p->n_dcon;
+ printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+ break;
+ case FLOAT:
+ u.f = (float)p->n_dcon;
+ printf("\t.long\t0x%x\n", u.i[0]);
+ break;
+ }
+}
+#endif
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+#define NCHNAM 256
+ static char text[NCHNAM+1];
+ int i;
+
+ if (p == NULL)
+ return "";
+
+ text[0] = '_';
+ for (i=1; *p && i<NCHNAM; ++i)
+ text[i] = *p++;
+
+ text[i] = '\0';
+ text[NCHNAM] = '\0'; /* truncate */
+
+ return (text);
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+ switch (BTYPE(type)) {
+ case LONG:
+ MODTYPE(type,INT);
+ break;
+
+ case ULONG:
+ MODTYPE(type,UNSIGNED);
+
+ }
+ return (type);
+}
+
+void
+calldec(NODE *p, NODE *q)
+{
+#ifdef PCC_DEBUG
+ if (xdebug)
+ printf("calldec:\n");
+#endif
+}
+
+void
+extdec(struct symtab *q)
+{
+#ifdef PCC_DEBUG
+ if (xdebug)
+ printf("extdec:\n");
+#endif
+}
+
+/* make a common declaration for id, if reasonable */
+void
+commdec(struct symtab *q)
+{
+ int off;
+
+ off = tsize(q->stype, q->sdf, q->ssue);
+ off = (off+(SZCHAR-1))/SZCHAR;
+#ifdef GCC_COMPAT
+ printf(" .comm %s,0%o\n", exname(gcc_findname(q)), off);
+#else
+ printf(" .comm %s,0%o\n", exname(q->sname), off);
+#endif
+}
+
+/* make a local common declaration for id, if reasonable */
+void
+lcommdec(struct symtab *q)
+{
+ int off;
+
+ off = tsize(q->stype, q->sdf, q->ssue);
+ off = (off+(SZCHAR-1))/SZCHAR;
+ if (q->slevel == 0)
+#ifdef GCC_COMPAT
+ printf(" .lcomm %s,0%o\n", exname(gcc_findname(q)), off);
+#else
+ printf(" .lcomm %s,0%o\n", exname(q->sname), off);
+#endif
+ else
+ printf(" .lcomm " LABFMT ",0%o\n", q->soffset, off);
+}
+
+/*
+ * print a (non-prog) label.
+ */
+void
+deflab1(int label)
+{
+ printf(LABFMT ":\n", label);
+}
+
+static char *loctbl[] = { "text", "data", "section .rodata,", "cstring" };
+
+void
+setloc1(int locc)
+{
+#ifdef PCC_DEBUG
+ if (xdebug)
+ printf("setloc1: locc=%d, lastloc=%d\n", locc, lastloc);
+#endif
+
+ if (locc == lastloc)
+ return;
+ lastloc = locc;
+ printf(" .%s\n", loctbl[locc]);
+}
+
+#if 0
+int
+ftoint(NODE *p, CONSZ **c)
+{
+ static CONSZ cc[3];
+ union { float f; double d; long double l; int i[3]; } u;
+ int n;
+
+ switch (p->n_type) {
+ case LDOUBLE:
+ u.i[2] = 0;
+ u.l = (long double)p->n_dcon;
+ n = SZLDOUBLE;
+ break;
+ case DOUBLE:
+ u.d = (double)p->n_dcon;
+ n = SZDOUBLE;
+ break;
+ case FLOAT:
+ u.f = (float)p->n_dcon;
+ n = SZFLOAT;
+ break;
+ }
+ cc[0] = u.i[0];
+ cc[1] = u.i[1];
+ cc[2] = u.i[2];
+ *c = cc;
+ return n;
+}
+#endif
+
+/* simulate and optimise the MOD opcode */
+static void
+simmod(NODE *p)
+{
+ NODE *r = p->n_right;
+
+ assert(p->n_op == MOD);
+
+#define ISPOW2(n) ((n) && (((n)&((n)-1)) == 0))
+
+ // if the right is a constant power of two, then replace with AND
+ if (r->n_op == ICON && ISPOW2(r->n_lval)) {
+ p->n_op = AND;
+ r->n_lval--;
+ return;
+ }
+
+#undef ISPOW2
+
+ /* other optimizations can go here */
+
+}
diff --git a/usr.bin/pcc/powerpc/local2.c b/usr.bin/pcc/powerpc/local2.c
new file mode 100644
index 00000000000..77d1001a248
--- /dev/null
+++ b/usr.bin/pcc/powerpc/local2.c
@@ -0,0 +1,1219 @@
+/* $OpenBSD: local2.c,v 1.1 2007/10/20 10:01:38 otto Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+
+#include "pass1.h" // for exname()
+#include "pass2.h"
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+int argsize(NODE *p);
+
+static int stkpos;
+
+extern struct stub stublist;
+extern struct stub nlplist;
+
+static void
+addstub(struct stub *list, char *name)
+{
+ struct stub *s;
+
+ DLIST_FOREACH(s, list, link) {
+ if (strcmp(s->name, name) == 0)
+ return;
+ }
+
+ s = malloc(sizeof(struct stub));
+ s->name = strdup(name);
+ DLIST_INSERT_BEFORE(list, s, link);
+}
+
+void
+lineid(int l, char *fn)
+{
+ /* identify line l and file fn */
+ printf("# line %d, file %s\n", l, fn);
+}
+
+void
+deflab(int label)
+{
+ printf(LABFMT ":\n", label);
+}
+
+static int regoff[7];
+static TWORD ftype;
+
+static char *funcname = NULL;
+/*
+ * Print out the prolog assembler.
+ * addto and regoff are already calculated.
+ */
+static void
+prtprolog(struct interpass_prolog *ipp, int addto)
+{
+#if 1
+ int i, j;
+#endif
+ addto = FIXEDSTACKSIZE;
+
+ // get return address (not required for leaf function)
+ printf(" mflr %s\n", rnames[R0]);
+ // save registers R30 and R31
+ printf(" stmw %s, -8(%s)\n", rnames[R30], rnames[R1]);
+ // save return address (not required for leaf function)
+ printf(" stw %s, 8(%s)\n", rnames[R0], rnames[R1]);
+ // create the new stack frame
+ printf(" stwu %s, -%d(%s)\n", rnames[R1], addto, rnames[R1]);
+
+ if (kflag) {
+ funcname = ipp->ipp_name;
+ printf(" bcl 20,31,L%s$pb\n", exname(ipp->ipp_name));
+ printf("L%s$pb:\n", exname(ipp->ipp_name));
+ printf(" mflr %s\n", rnames[R31]);
+ }
+
+#ifdef PCC_DEBUG
+ if (x2debug) {
+ printf("ipp_regs = 0x%x\n", ipp->ipp_regs);
+ }
+#endif
+
+ for (i = ipp->ipp_regs, j = 0; i; i >>= 1, j++) {
+ if (i & 1) {
+ printf(" stw %s,%d(%s)\n",
+ rnames[j], regoff[j], rnames[FPREG]);
+ }
+ }
+}
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog *ipp)
+{
+ int i, j, addto;
+
+#ifdef PCC_DEBUG
+ if (x2debug)
+ printf("offcalc: p2maxautooff=%d\n", p2maxautooff);
+#endif
+
+ addto = p2maxautooff;
+
+ // space is always allocated on the stack to save the registers
+ for (i = ipp->ipp_regs, j = 0; i ; i >>= 1, j++) {
+ if (i & 1) {
+ addto += SZINT/SZCHAR;
+ regoff[j] = addto;
+ }
+ }
+
+ addto += 8; /* for R31 and R30 */
+
+ /* round to 16-byte boundary */
+ addto += 15;
+ addto &= ~15;
+
+#ifdef PCC_DEBUG
+ if (x2debug)
+ printf("offcalc: addto=%d\n", addto);
+#endif
+
+ return addto;
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+ 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;
+ if (ipp->ipp_vis)
+ printf(" .globl %s\n", exname(ipp->ipp_name));
+ printf(" .align 2\n");
+ 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);
+ prtprolog(ipp, addto);
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+ int i, j;
+
+#ifdef PCC_DEBUG
+ if (x2debug)
+ printf("eoftn:\n");
+#endif
+
+ 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(" lwz %s, %d(%s)\n",
+ rnames[j], regoff[j], rnames[FPREG]);
+
+ }
+
+// assert(ftype != ipp->ipp_type);
+
+ /* struct return needs special treatment */
+ if (ftype == STRTY || ftype == UNIONTY) {
+ assert(0);
+ printf(" movl 8(%%ebp),%%eax\n");
+ printf(" leave\n");
+ printf(" ret $4\n");
+ } else {
+ // unwind stack frame
+ printf(" lwz %s,0(%s)\n", rnames[R1], rnames[R1]);
+ printf(" lwz %s,8(%s)\n", rnames[R0], rnames[R1]);
+ printf(" mtlr %s\n", rnames[R0]);
+ printf(" lmw %s,-8(%s)\n", rnames[R30], rnames[R1]);
+ printf(" blr\n");
+ }
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+ char *str;
+
+ switch (o) {
+ case PLUS:
+ str = "addw";
+ break;
+ case MINUS:
+ str = "subw";
+ break;
+ case AND:
+ str = "and";
+ break;
+ case OR:
+ str = "or";
+ break;
+ case ER:
+ str = "xor";
+ break;
+ default:
+ comperr("hopcode2: %d", o);
+ str = 0; /* XXX gcc */
+ }
+ printf("%s%c", str, f);
+}
+
+/*
+ * Return type size in bytes. Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(p) NODE *p;
+{
+ switch(p->n_type) {
+ case CHAR:
+ case UCHAR:
+ return(1);
+
+ case SHORT:
+ case USHORT:
+ return(SZSHORT/SZCHAR);
+
+ case DOUBLE:
+ return(SZDOUBLE/SZCHAR);
+
+ case INT:
+ case UNSIGNED:
+ case LONG:
+ case ULONG:
+ return(SZINT/SZCHAR);
+
+ case LONGLONG:
+ case ULONGLONG:
+ return SZLONGLONG/SZCHAR;
+
+ default:
+ if (!ISPTR(p->n_type))
+ comperr("tlen type %d not pointer");
+ return SZPOINT(p->n_type)/SZCHAR;
+ }
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+ int o = p->n_op;
+ int s = getlab();
+ int e = p->n_label;
+ int cb1, cb2;
+
+ if (o >= ULE)
+ o -= (ULE-LE);
+ switch (o) {
+ case NE:
+ cb1 = 0;
+ cb2 = NE;
+ break;
+ case EQ:
+ cb1 = NE;
+ cb2 = 0;
+ break;
+ case LE:
+ case LT:
+ cb1 = GT;
+ cb2 = LT;
+ break;
+ case GE:
+ case GT:
+ cb1 = LT;
+ cb2 = GT;
+ break;
+
+ default:
+ cb1 = cb2 = 0; /* XXX gcc */
+ }
+ if (p->n_op >= ULE)
+ cb1 += 4, cb2 += 4;
+ expand(p, 0, " cmpl UR,UL\n");
+ if (cb1) cbgen(cb1, s);
+ if (cb2) cbgen(cb2, e);
+ expand(p, 0, " cmpl AR,AL\n");
+ cbgen(p->n_op, e);
+ deflab(s);
+}
+
+#if 0
+/*
+ * Assign to a bitfield.
+ * Clumsy at least, but what to do?
+ */
+static void
+bfasg(NODE *p)
+{
+ NODE *fn = p->n_left;
+ int shift = UPKFOFF(fn->n_rval);
+ int fsz = UPKFSZ(fn->n_rval);
+ int andval, tch = 0;
+
+ /* get instruction size */
+ switch (p->n_type) {
+ case CHAR: case UCHAR: tch = 'b'; break;
+ case SHORT: case USHORT: tch = 'w'; break;
+ case INT: case UNSIGNED: tch = 'l'; break;
+ default: comperr("bfasg");
+ }
+
+ /* put src into a temporary reg */
+ fprintf(stdout, " mov%c ", tch);
+ adrput(stdout, getlr(p, 'R'));
+ fprintf(stdout, ",");
+ adrput(stdout, getlr(p, '1'));
+ fprintf(stdout, "\n");
+
+ /* AND away the bits from dest */
+ andval = ~(((1 << fsz) - 1) << shift);
+ fprintf(stdout, " and%c $%d,", tch, andval);
+ adrput(stdout, fn->n_left);
+ fprintf(stdout, "\n");
+
+ /* AND away unwanted bits from src */
+ andval = ((1 << fsz) - 1);
+ fprintf(stdout, " and%c $%d,", tch, andval);
+ adrput(stdout, getlr(p, '1'));
+ fprintf(stdout, "\n");
+
+ /* SHIFT left src number of bits */
+ if (shift) {
+ fprintf(stdout, " sal%c $%d,", tch, shift);
+ adrput(stdout, getlr(p, '1'));
+ fprintf(stdout, "\n");
+ }
+
+ /* OR in src to dest */
+ fprintf(stdout, " or%c ", tch);
+ adrput(stdout, getlr(p, '1'));
+ fprintf(stdout, ",");
+ adrput(stdout, fn->n_left);
+ fprintf(stdout, "\n");
+}
+#endif
+
+#if 0
+/*
+ * Push a structure on stack as argument.
+ * the scratch registers are already free here
+ */
+static void
+starg(NODE *p)
+{
+ FILE *fp = stdout;
+
+ fprintf(fp, " subl $%d,%%esp\n", p->n_stsize);
+ fprintf(fp, " pushl $%d\n", p->n_stsize);
+ expand(p, 0, " pushl AL\n");
+ expand(p, 0, " leal 8(%esp),A1\n");
+ expand(p, 0, " pushl A1\n");
+ fprintf(fp, " call memcpy\n");
+ fprintf(fp, " addl $12,%%esp\n");
+}
+#endif
+
+#if 0
+/*
+ * Compare two floating point numbers.
+ */
+static void
+fcomp(NODE *p)
+{
+ if (p->n_left->n_op == REG) {
+ if (p->n_su & DORIGHT)
+ expand(p, 0, " fxch\n");
+ expand(p, 0, " fucompp\n"); /* emit compare insn */
+ } else if (p->n_left->n_type == DOUBLE)
+ expand(p, 0, " fcompl AL\n"); /* emit compare insn */
+ else if (p->n_left->n_type == FLOAT)
+ expand(p, 0, " fcomp AL\n"); /* emit compare insn */
+ else
+ comperr("bad compare %p\n", p);
+ expand(p, 0, " fnstsw %ax\n"); /* move status reg to ax */
+
+ switch (p->n_op) {
+ case EQ:
+ expand(p, 0, " andb $64,%ah\n jne LC\n");
+ break;
+ case NE:
+ expand(p, 0, " andb $64,%ah\n je LC\n");
+ break;
+ case LE:
+ expand(p, 0, " andb $65,%ah\n cmpb $1,%ah\n jne LC\n");
+ break;
+ case LT:
+ expand(p, 0, " andb $65,%ah\n je LC\n");
+ break;
+ case GT:
+ expand(p, 0, " andb $1,%ah\n jne LC\n");
+ break;
+ case GE:
+ expand(p, 0, " andb $65,%ah\n jne LC\n");
+ break;
+ default:
+ comperr("fcomp op %d\n", p->n_op);
+ }
+}
+#endif
+
+#if 0
+/*
+ * Convert an unsigned long long to floating point number.
+ */
+static void
+ulltofp(NODE *p)
+{
+ static int loadlab;
+ int jmplab;
+
+ if (loadlab == 0) {
+ loadlab = getlab();
+ expand(p, 0, " .data\n");
+ printf(LABFMT ": .long 0,0x80000000,0x403f\n", loadlab);
+ expand(p, 0, " .text\n");
+ }
+ jmplab = getlab();
+ expand(p, 0, " pushl UL\n pushl AL\n");
+ expand(p, 0, " fildq (%esp)\n");
+ expand(p, 0, " addl $8,%esp\n");
+ expand(p, 0, " cmpl $0,UL\n");
+ printf(" jge " LABFMT "\n", jmplab);
+ printf(" fldt " LABFMT "\n", loadlab);
+ printf(" faddp %%st,%%st(1)\n");
+ printf(LABFMT ":\n", jmplab);
+}
+#endif
+
+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)
+{
+#if 0
+ NODE *r, *l;
+ int pr, lr, s;
+ char *ch;
+#endif
+
+ switch (c) {
+#if 0
+ case 'C': /* remove from stack after subroutine call */
+ pr = p->n_qual;
+ if (p->n_op == STCALL || p->n_op == USTCALL)
+ pr += 4;
+ if (p->n_op == UCALL)
+ return; /* XXX remove ZC from UCALL */
+ if (pr)
+ printf(" addl $%d, %s\n", pr, rnames[ESP]);
+ break;
+#endif
+
+ case 'D': /* Long long comparision */
+ twollcomp(p);
+ break;
+
+#if 0
+ case 'E': /* Assign to bitfield */
+ bfasg(p);
+ break;
+
+ case 'F': /* Structure argument */
+ if (p->n_stalign != 0) /* already on stack */
+ starg(p);
+ break;
+
+ case 'G': /* Floating point compare */
+ fcomp(p);
+ break;
+
+ case 'J': /* convert unsigned long long to floating point */
+ ulltofp(p);
+ break;
+
+ case 'N': /* output extended reg name */
+ printf("%s", rnames[getlr(p, '1')->n_rval]);
+ break;
+#endif
+
+ case 'O': /* 64-bit left and right shift operators */
+
+ if (p->n_op == LS && p->n_right->n_lval < 32) {
+ expand(p, INBREG, "\tsrwi A1,AL,32-AR ; 64-bit left-shift\n");
+ expand(p, INBREG, "\tslwi U1,UL,AR\n");
+ expand(p, INBREG, "\tor U1,U1,A1\n");
+ expand(p, INBREG, "\tslwi A1,AL,AR\n");
+ } else if (p->n_op == LS) {
+ expand(p, INBREG, "\tli A1,0 ; 64-bit left-shift\n");
+ expand(p, INBREG, "\tslwi U1,AL,AR-32\n");
+ } else if (p->n_op == RS && p->n_right->n_lval < 32) {
+ expand(p, INBREG, "\tslwi U1,UL,32-AR ; 64-bit right-shift\n");
+ expand(p, INBREG, "\tsrwi A1,AL,AR\n");
+ expand(p, INBREG, "\tor A1,A1,U1\n");
+ expand(p, INBREG, "\tsrwi U1,UL,AR\n");
+ } else if (p->n_op == RS) {
+ expand(p, INBREG, "\tli U1,0 ; 64-bit right-shift\n");
+ expand(p, INBREG, "\tsrwi A1,UL,AR-32\n");
+ }
+ break;
+
+
+#if 0
+ case 'O': /* print out emulated ops */
+ pr = 16;
+ if (p->n_op == RS || p->n_op == LS) {
+ expand(p, INAREG, "\tpushl AR\n");
+ pr = 12;
+ } else
+ expand(p, INCREG, "\tpushl UR\n\tpushl AR\n");
+ expand(p, INCREG, "\tpushl UL\n\tpushl AL\n");
+ if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv";
+ else if (p->n_op == DIV) ch = "div";
+ else if (p->n_op == MUL) ch = "mul";
+ else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod";
+ else if (p->n_op == MOD) ch = "mod";
+ else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshr";
+ else if (p->n_op == RS) ch = "ashr";
+ else if (p->n_op == LS) ch = "ashl";
+ else ch = 0, comperr("ZO");
+ printf("\tbl __%sdi3\n\n", ch,);
+ break;
+#endif
+
+#if 0
+ case 'P': /* push hidden argument on stack */
+ r = (NODE *)p->n_sue;
+ printf("\tleal -%d(%%ebp),", stkpos);
+ adrput(stdout, getlr(p, '1'));
+ printf("\n\tpushl ");
+ adrput(stdout, getlr(p, '1'));
+ putchar('\n');
+ break;
+#endif
+
+#if 0
+ case 'Q': /* emit struct assign */
+ /* XXX - optimize for small structs */
+ printf("\tpushl $%d\n", p->n_stsize);
+ expand(p, INAREG, "\tpushl AR\n");
+ expand(p, INAREG, "\tleal AL,%eax\n\tpushl %eax\n");
+ printf("\tcall memcpy\n");
+ printf("\taddl $12,%%esp\n");
+ break;
+#endif
+
+#if 0
+ case 'S': /* emit eventual move after cast from longlong */
+ pr = DECRA(p->n_reg, 0);
+ lr = p->n_left->n_rval;
+ switch (p->n_type) {
+ case CHAR:
+ case UCHAR:
+ if (rnames[pr][2] == 'l' && rnames[lr][2] == 'x' &&
+ rnames[pr][1] == rnames[lr][1])
+ break;
+ if (rnames[lr][2] == 'x') {
+ printf("\tmovb %%%cl,%s\n",
+ rnames[lr][1], rnames[pr]);
+ break;
+ }
+ /* Must go via stack */
+ s = BITOOR(freetemp(1));
+ printf("\tmovl %%e%ci,%d(%%ebp)\n", rnames[lr][1], s);
+ printf("\tmovb %d(%%ebp),%s\n", s, rnames[pr]);
+// comperr("SCONV1 %s->%s", rnames[lr], rnames[pr]);
+ break;
+
+ case SHORT:
+ case USHORT:
+ if (rnames[lr][1] == rnames[pr][2] &&
+ rnames[lr][2] == rnames[pr][3])
+ break;
+ printf("\tmovw %%%c%c,%%%s\n",
+ rnames[lr][1], rnames[lr][2], rnames[pr]+2);
+ break;
+ case INT:
+ case UNSIGNED:
+ if (rnames[lr][1] == rnames[pr][2] &&
+ rnames[lr][2] == rnames[pr][3])
+ break;
+ printf("\tmovl %%e%c%c,%s\n",
+ rnames[lr][1], rnames[lr][2], rnames[pr]);
+ break;
+
+ default:
+ if (rnames[lr][1] == rnames[pr][2] &&
+ rnames[lr][2] == rnames[pr][3])
+ break;
+ comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]);
+ break;
+ }
+ break;
+
+#endif
+
+ default:
+ comperr("zzzcode %c", c);
+ }
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+ return(1);
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+ int o = p->n_op;
+
+ if (o==NAME || o==REG || o==ICON || o==OREG ||
+ (o==UMUL && shumul(p->n_left)))
+ return(1);
+ return(0);
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+ int o = p->n_op;
+
+ if (o == OREG || o == REG || o == NAME)
+ return SRDIR; /* Direct match */
+ if (o == UMUL && shumul(p->n_left))
+ return SROREG; /* Convert into oreg */
+ return SRREG; /* put it into a register */
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE *p)
+{
+ printf("; shtemp\n");
+ 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
+ printf("XXX type = %x\n", p->n_type);
+#endif
+ if (p->n_sp != NULL &&
+#if 0
+ (p->n_sp->sclass != STATIC) &&
+#endif
+ (p->n_sp->sclass != ILABEL))
+ s = exname(p->n_name);
+ else
+ s = p->n_name;
+
+ if (*s != '\0') {
+ if (kflag && p->n_sp && ISFTN(p->n_sp->stype)) {
+ fprintf(fp, "%s$stub", s);
+ addstub(&stublist, s);
+ } else if (kflag && p->n_sp) {
+// printf("sclass=%x sflags=%x\n", p->n_sp->sclass, p->n_sp->sflags);
+ if (p->n_sp && (p->n_sp->sclass != STATIC && p->n_sp->sflags != SSTRING)) {
+ fprintf(fp, "L%s$non_lazy_ptr", s);
+ addstub(&nlplist, s);
+ } else {
+ fprintf(fp, "%s", s);
+ }
+ fprintf(fp, "-L%s$pb", exname(funcname));
+ } else {
+ fprintf(fp, "%s", s);
+ }
+ if (val > 0)
+ fprintf(fp, "+%d", val);
+ else if (val < 0)
+ fprintf(fp, "-%d", -val);
+ } else
+ fprintf(fp, "%d", val);
+ return;
+
+ default:
+ comperr("illegal conput, p %p", p);
+ }
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+ comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+ size /= SZCHAR;
+ switch (p->n_op) {
+ case REG:
+ fprintf(stdout, "%c%c",
+ rnames[p->n_rval][3],
+ rnames[p->n_rval][4]);
+ if (rnames[p->n_rval][5])
+ fputc(rnames[p->n_rval][5], stdout);
+ break;
+
+ case NAME:
+ case OREG:
+ p->n_lval += size;
+ adrput(stdout, p);
+ p->n_lval -= size;
+ break;
+ case ICON:
+ fprintf(stdout, CONFMT, p->n_lval >> 32);
+ break;
+ default:
+ comperr("upput bad op %d size %d", p->n_op, size);
+ }
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+ int r;
+ /* output an address, with offsets, from p */
+
+ if (p->n_op == FLD)
+ p = p->n_left;
+
+ switch (p->n_op) {
+
+ case NAME:
+ if (p->n_name[0] != '\0') {
+ if (kflag && p->n_sp && (p->n_sp->sclass == STATIC || p->n_sp->sflags != SSTRING)) {
+ fprintf(io, "L%s$non_lazy_ptr", exname(p->n_name));
+ addstub(&nlplist, exname(p->n_name));
+ fprintf(io, "-L%s$pb", exname(funcname));
+ } else if (kflag) {
+ fprintf(io, "%s", exname(p->n_name));
+ fprintf(io, "-L%s$pb", exname(funcname));
+ } else
+ fputs(exname(p->n_name), io);
+ if (p->n_lval != 0)
+ fprintf(io, "+" CONFMT, p->n_lval);
+ } else
+ fprintf(io, CONFMT, p->n_lval);
+ return;
+
+ case OREG:
+ r = p->n_rval;
+ fprintf(io, "%d", (int)p->n_lval);
+ fprintf(io, "(%s)", rnames[p->n_rval]);
+ return;
+
+ case ICON:
+ /* addressable value of the constant */
+ conput(io, p);
+ return;
+
+ case MOVE:
+ case REG:
+ switch (p->n_type) {
+ case LONGLONG:
+ case ULONGLONG:
+ fprintf(stdout, "%c%c",
+ rnames[p->n_rval][0],
+ rnames[p->n_rval][1]);
+ if (rnames[p->n_rval][2])
+ fputc(rnames[p->n_rval][2], stdout);
+ break;
+ default:
+ fprintf(io, "%s", rnames[p->n_rval]);
+ }
+ return;
+
+ default:
+ comperr("illegal address, op %d, node %p", p->n_op, p);
+ return;
+
+ }
+}
+
+/*
+ * 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 ? */
+ "ble", /* branch if less-than-or-equal */
+ "blt", /* branch if less-than */
+ "bge", /* branch if greater-than-or-equal */
+ "bgt", /* branch if greater-than */
+
+};
+
+
+/* printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+ if (o < EQ || o > UGT)
+ comperr("bad conditional branch: %s", opst[o]);
+ printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab);
+}
+
+static void
+fixcalls(NODE *p)
+{
+ /* Prepare for struct return by allocating bounce space on stack */
+ switch (p->n_op) {
+ case STCALL:
+ case USTCALL:
+ if (p->n_stsize+p2autooff > stkpos)
+ stkpos = p->n_stsize+p2autooff;
+ break;
+ }
+}
+
+/*
+ * Must store floats in memory if there are two function calls involved.
+ */
+static int
+storefloat(struct interpass *ip, NODE *p)
+{
+ int l, r;
+
+ switch (optype(p->n_op)) {
+ case BITYPE:
+ l = storefloat(ip, p->n_left);
+ r = storefloat(ip, p->n_right);
+ if (p->n_op == CM)
+ return 0; /* arguments, don't care */
+ if (callop(p->n_op))
+ return 1; /* found one */
+#define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \
+ (p)->n_type == LDOUBLE)
+ if (ISF(p->n_left) && ISF(p->n_right) && l && r) {
+ /* must store one. store left */
+ struct interpass *nip;
+ TWORD t = p->n_left->n_type;
+ NODE *ll;
+ int off;
+
+ off = BITOOR(freetemp(szty(t)));
+ ll = mklnode(OREG, off, FPREG, t);
+ nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t));
+ p->n_left = mklnode(OREG, off, FPREG, t);
+ DLIST_INSERT_BEFORE(ip, nip, qelem);
+ }
+ return l|r;
+
+ case UTYPE:
+ l = storefloat(ip, p->n_left);
+ if (callop(p->n_op))
+ l = 1;
+ return l;
+ default:
+ return 0;
+ }
+}
+
+void
+myreader(struct interpass *ipole)
+{
+ struct interpass *ip;
+
+ stkpos = p2autooff;
+ DLIST_FOREACH(ip, ipole, qelem) {
+ if (ip->type != IP_NODE)
+ continue;
+ walkf(ip->ip_node, fixcalls);
+ storefloat(ip, ip->ip_node);
+ }
+ if (stkpos > p2autooff)
+ p2autooff = stkpos;
+ if (stkpos > p2maxautooff)
+ p2maxautooff = stkpos;
+ if (x2debug)
+ printip(ipole);
+}
+
+/*
+ * Remove some PCONVs after OREGs are created.
+ */
+static void
+pconv2(NODE *p)
+{
+ NODE *q;
+
+ if (p->n_op == PLUS) {
+ if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
+ if (p->n_right->n_op != ICON)
+ return;
+ if (p->n_left->n_op != PCONV)
+ return;
+ if (p->n_left->n_left->n_op != OREG)
+ return;
+ q = p->n_left->n_left;
+ nfree(p->n_left);
+ p->n_left = q;
+ /*
+ * This will be converted to another OREG later.
+ */
+ }
+ }
+}
+
+void
+mycanon(NODE *p)
+{
+ walkf(p, pconv2);
+}
+
+void
+myoptim(struct interpass *ip)
+{
+#ifdef PCC_DEBUG
+ if (x2debug) {
+ printf("myoptim\n");
+ }
+#endif
+}
+
+#if 0
+static char rl[] =
+ { EAX, EAX, EAX, EAX, EAX, EDX, EDX, EDX, EDX, ECX, ECX, ECX, EBX, EBX, ESI };
+static char rh[] =
+ { EDX, ECX, EBX, ESI, EDI, ECX, EBX, ESI, EDI, EBX, ESI, EDI, ESI, EDI, EDI };
+#endif
+
+void
+rmove(int s, int d, TWORD t)
+{
+#if 0
+ int sl, sh, dl, dh;
+
+ switch (t) {
+ case LONGLONG:
+ case ULONGLONG:
+#if 1
+ sl = rl[s-EAXEDX];
+ sh = rh[s-EAXEDX];
+ dl = rl[d-EAXEDX];
+ dh = rh[d-EAXEDX];
+
+ /* sanity checks, remove when satisfied */
+ if (memcmp(rnames[s], rnames[sl]+1, 3) != 0 ||
+ memcmp(rnames[s]+3, rnames[sh]+1, 3) != 0)
+ comperr("rmove source error");
+ if (memcmp(rnames[d], rnames[dl]+1, 3) != 0 ||
+ memcmp(rnames[d]+3, rnames[dh]+1, 3) != 0)
+ comperr("rmove dest error");
+#define SW(x,y) { int i = x; x = y; y = i; }
+ if (sl == dh || sh == dl) {
+ /* Swap if moving to itself */
+ SW(sl, sh);
+ SW(dl, dh);
+ }
+ if (sl != dl)
+ printf(" movl %s,%s\n", rnames[sl], rnames[dl]);
+ if (sh != dh)
+ printf(" movl %s,%s\n", rnames[sh], rnames[dh]);
+#else
+ if (memcmp(rnames[s], rnames[d], 3) != 0)
+ printf(" movl %%%c%c%c,%%%c%c%c\n",
+ rnames[s][0],rnames[s][1],rnames[s][2],
+ rnames[d][0],rnames[d][1],rnames[d][2]);
+ if (memcmp(&rnames[s][3], &rnames[d][3], 3) != 0)
+ printf(" movl %%%c%c%c,%%%c%c%c\n",
+ rnames[s][3],rnames[s][4],rnames[s][5],
+ rnames[d][3],rnames[d][4],rnames[d][5]);
+#endif
+ break;
+ case CHAR:
+ case UCHAR:
+ printf(" movb %s,%s\n", rnames[s], rnames[d]);
+ break;
+ case FLOAT:
+ case DOUBLE:
+ case LDOUBLE:
+#ifdef notdef
+ /* a=b()*c(); will generate this */
+ comperr("bad float rmove: %d %d", s, d);
+#endif
+ break;
+ default:
+ printf(" movl %s,%s\n", rnames[s], rnames[d]);
+ }
+#endif
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+ return 1;
+#if 0
+ int num;
+
+ switch (c) {
+ case CLASSA:
+ num = r[CLASSB] > 4 ? 4 : r[CLASSB];
+ num += 2*r[CLASSC];
+ num += r[CLASSA];
+ return num < 6;
+ case CLASSB:
+ num = r[CLASSA];
+ num += 2*r[CLASSC];
+ num += r[CLASSB];
+ return num < 4;
+ case CLASSC:
+ num = r[CLASSA];
+ num += r[CLASSB] > 4 ? 4 : r[CLASSB];
+ num += 2*r[CLASSC];
+ return num < 5;
+ case CLASSD:
+ return r[CLASSD] < DREGCNT;
+ }
+ return 0; /* XXX gcc */
+#endif
+}
+
+char *rnames[] = {
+ "r0", "r1", "r2", "r3","r4","r5", "r6", "r7", "r8",
+ "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16",
+ "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24",
+ "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+ /* the order is flipped, because we are big endian */
+ "r4\0r3\0", "r5\0r4\0", "r6\0r5\0", "r7\0r6\0",
+ "r8\0r7\0", "r9\0r8\0", "r10r9\0", "r15r14", "r17r16",
+ "r19r18", "r21r20", "r23r22", "r25r24", "r27r26",
+ "r29r28", "r31r30",
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+ if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+ return CLASSB;
+ return CLASSA;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+ NODE *op = p;
+ int size = 0;
+
+#ifdef PCC_DEBUG
+ if (x2debug)
+ printf("lastcall:\n");
+#endif
+
+ p->n_qual = 0;
+ if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+ return;
+ for (p = p->n_right; p->n_op == CM; p = p->n_left)
+ size += argsiz(p->n_right);
+ size += argsiz(p);
+ op->n_qual = size; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+ int o = p->n_op;
+
+ switch (shape) {
+ case SFUNCALL:
+ if (o == STCALL || o == USTCALL)
+ return SRREG;
+ break;
+#if 0
+ case SSYMBOL:
+ if (p->n_op == NAME && !kflag)
+ return SRDIR;
+#endif
+ }
+ return SRNOPE;
+}
diff --git a/usr.bin/pcc/powerpc/macdefs.h b/usr.bin/pcc/powerpc/macdefs.h
new file mode 100644
index 00000000000..3f58fb9604d
--- /dev/null
+++ b/usr.bin/pcc/powerpc/macdefs.h
@@ -0,0 +1,270 @@
+/* $OpenBSD: macdefs.h,v 1.1 2007/10/20 10:01:38 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 96
+#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 CHAR_UNSIGNED
+#define TARGET_STDARGS
+#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 MYP2TREE(p) myp2tree(p);
+
+#undef FIELDOPS /* no bit-field instructions */
+#if 0
+#define RTOLBYTES /* bytes are numbered right to left */
+#endif
+
+#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) == FLOAT || \
+ (t) == LONGLONG || (t) == ULONGLONG) ? 2 : (t) == LDOUBLE ? 3 : 1)
+
+/*
+ * The PPC register definition are taken from apple docs.
+ *
+ * The classes used are:
+ * A - general registers
+ * B - 64-bit register pairs
+ */
+
+#define R0 0 // scratch register
+#define R1 1 // stack base pointer
+#define R2 2
+#define R3 3 // return register / argument 0
+#define R4 4 // return register (for longlong) / argument 1
+#define R5 5 // scratch register / argument 2
+#define R6 6 // scratch register / argument 3
+#define R7 7 // scratch register / argument 4
+#define R8 8 // scratch register / argument 5
+#define R9 9 // scratch register / argument 6
+#define R10 10 // scratch register / argument 7
+#define R11 11 // scratch register
+#define R12 12 // scratch register
+#define R13 13
+#define R14 14
+#define R15 15
+#define R16 16
+#define R17 17
+#define R18 18
+#define R19 19
+#define R20 20
+#define R21 21
+#define R22 22
+#define R23 23
+#define R24 24
+#define R25 25
+#define R26 26
+#define R27 27
+#define R28 28
+#define R29 29
+#define R30 30
+#define R31 31
+
+#define R3R4 32
+#define R4R5 33
+#define R5R6 34
+#define R6R7 35
+#define R7R8 36
+#define R8R9 37
+#define R9R10 38
+#define R14R15 39
+#define R16R17 40
+#define R18R19 41
+#define R20R21 42
+#define R22R23 43
+#define R24R25 44
+#define R26R27 45
+#define R28R29 46
+#define R30R31 47
+
+#define NUMCLASS 4 // XXX must always be 4
+#define MAXREGS 48
+
+#define RSTATUS \
+ 0, 0, SAREG|TEMPREG, SAREG|TEMPREG, \
+ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG, \
+ SAREG, SAREG, SAREG, SAREG, \
+ SAREG, SAREG, SAREG, SAREG, \
+ SAREG, SAREG, SAREG, SAREG, \
+ SAREG, SAREG, SAREG, SAREG, \
+ SAREG, SAREG, SAREG, SAREG, \
+ \
+ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \
+ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \
+ \
+ SBREG, SBREG, SBREG, SBREG, \
+ SBREG, SBREG, SBREG, SBREG, \
+ SBREG,
+
+#define ROVERLAP \
+ { -1 }, { -1 }, { -1 }, \
+ { 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 }, \
+ { R14R15, -1 }, { R14R15, -1 }, \
+ { R16R17, -1 }, { R16R17, -1 }, \
+ { R18R19, -1 }, { R18R19, -1 }, \
+ { R20R21, -1 }, { R20R21, -1 }, \
+ { R22R23, -1 }, { R22R23, -1 }, \
+ { R24R25, -1 }, { R24R25, -1 }, \
+ { R26R27, -1 }, { R26R27, -1 }, \
+ { R28R29, -1 }, { R28R29, -1 }, \
+ { R30R31, -1 }, { R30R31, -1 }, \
+ \
+ { R3, R4, 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, R8R9, -1 }, \
+ { R9, R10, R8R9, -1 }, \
+ { R14, R15, -1 }, { R16, R17, -1 }, \
+ { R18, R19, -1 }, { R20, R21, -1 }, \
+ { R22, R23, -1 }, { R24, R25, -1 }, \
+ { R26, R27, -1 }, { R28, R29, -1 }, \
+ { R30, R31, -1 },
+
+#if 0
+#define BACKAUTO /* stack grows negatively for automatics */
+#define BACKTEMP /* stack grows negatively for temporaries */
+#endif
+
+#define ARGINIT (24*8) /* # bits above fp where arguments start */
+#define AUTOINIT (56*8) /* # bits above fp where automatics start */
+
+/* XXX - to die */
+#define FPREG R1 /* frame pointer */
+#if 0
+#define STKREG R30 /* stack pointer */
+#endif
+
+/* Return a register class based on the type of the node */
+#define PCLASS(p) (p->n_type == LONGLONG || p->n_type == ULONGLONG ? SBREG : \
+ (p->n_type >= FLOAT && p->n_type <= LDOUBLE ? SCREG : SAREG))
+
+#define GCLASS(x) (x < 32 ? 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 */
+#define RETREG(x) ((x) == ULONGLONG || (x) == LONGLONG ? R3R4 : R3)
+
+int COLORMAP(int c, int *r);
+
+#define MYREADER(p) myreader(p)
+#define MYCANON(p) mycanon(p)
+#define MYOPTIM
+
+#define SHSTR (MAXSPECIAL+1) /* short struct */
+#define SFUNCALL (MAXSPECIAL+2) /* struct assign after function call */
+
+struct stub {
+ struct { struct stub *q_forw, *q_back; } link;
+ char *name;
+};
+
+#define FIXEDSTACKSIZE 200 /* in bytes */
diff --git a/usr.bin/pcc/powerpc/order.c b/usr.bin/pcc/powerpc/order.c
new file mode 100644
index 00000000000..215a2a3f20c
--- /dev/null
+++ b/usr.bin/pcc/powerpc/order.c
@@ -0,0 +1,245 @@
+/* $OpenBSD: order.c,v 1.1 2007/10/20 10:01:38 otto Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+// if (cp) return 1;
+ return !(off < 32768 && off > -32769); /* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ * Be careful about register classes, this is a place where classes change.
+ */
+void
+offstar(NODE *p, int shape)
+{
+ NODE *r;
+
+ if (x2debug)
+ printf("offstar(%p)\n", p);
+
+ if (isreg(p))
+ return; /* Is already OREG */
+
+ r = p->n_right;
+ if( p->n_op == PLUS || p->n_op == MINUS ){
+ if( r->n_op == ICON ){
+ if (isreg(p->n_left) == 0)
+ (void)geninsn(p->n_left, INAREG);
+ /* Converted in ormake() */
+ return;
+ }
+ if (r->n_op == LS && r->n_right->n_op == ICON &&
+ r->n_right->n_lval == 2 && p->n_op == PLUS) {
+ if (isreg(p->n_left) == 0)
+ (void)geninsn(p->n_left, INAREG);
+ if (isreg(r->n_left) == 0)
+ (void)geninsn(r->n_left, INAREG);
+ return;
+ }
+ }
+ (void)geninsn(p, INAREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *q)
+{
+#if 0
+ NODE *p;
+#endif
+
+ if (x2debug)
+ printf("myormake(%p)\n", q);
+
+#if 0
+ p = q->n_left;
+ if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_right->n_op == ICON) {
+ if (isreg(p->n_left) == 0)
+ (void)geninsn(p->n_left, INAREG);
+ if (isreg(p->n_right) == 0)
+ (void)geninsn(p->n_right, INAREG);
+ (void)geninsn(p, INAREG);
+ } else if (p->n_op == REG) {
+ q->n_op = OREG;
+ q->n_lval = p->n_lval;
+ q->n_rval = p->n_rval;
+ tfree(p);
+ }
+#endif
+}
+
+/*
+ * Shape matches for UMUL. Cooperates with offstar().
+ */
+int
+shumul(NODE *p)
+{
+
+ if (x2debug)
+ printf("shumul(%p)\n", p);
+
+ /* Turns currently anything into OREG on x86 */
+ return SOREG;
+}
+
+/*
+ * Rewrite increment/decrement operation.
+ */
+int
+setincr(NODE *p)
+{
+ if (x2debug)
+ printf("setincr(%p)\n", p);
+
+ return(0);
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE *p)
+{
+
+ if (x2debug)
+ printf("setbin(%p)\n", p);
+ return 0;
+
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+ if (x2debug)
+ printf("setasg(%p)\n", p);
+ return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+ return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+
+ if (x2debug)
+ printf("nspecial: op=%d, visit=0x%x: %s", q->op, q->visit, q->cstring);
+
+ switch (q->op) {
+
+ case OPLTYPE:
+ {
+ if (q->visit & SAREG) {
+ static struct rspecial s[] = {
+ { NEVER, R0 },
+// { NRES, R3 }, // hack - i don't know why
+ { 0 } };
+ return s;
+ }
+ }
+ break;
+
+ case ASSIGN:
+ if (q->lshape & SNAME) {
+ static struct rspecial s[] = {
+ { NEVER, R0 },
+ { 0 } };
+ return s;
+ } else if (q->rshape & SNAME) {
+ static struct rspecial s[] = {
+ { NOLEFT, R0 },
+ { 0 } };
+ return s;
+ } else if (q->lshape & SOREG) {
+ static struct rspecial s[] = {
+ { NOLEFT, R0 },
+ { 0 } };
+ return s;
+ } else if (q->rshape & SOREG) {
+ static struct rspecial s[] = {
+ { NORIGHT, R0 },
+ { 0 } };
+ return s;
+ }
+ /* fallthough */
+
+ case SCONV:
+ case UMUL:
+ case MINUS:
+ case AND:
+ case OR:
+ case ER:
+ case PLUS:
+ {
+ static struct rspecial s[] = {
+ { NOLEFT, R0 },
+ { 0 } };
+ return s;
+ }
+
+ default:
+ break;
+ }
+
+ comperr("nspecial entry %d", q - table);
+ return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+ return 0; /* nothing differs on x86 */
+}
diff --git a/usr.bin/pcc/powerpc/table.c b/usr.bin/pcc/powerpc/table.c
new file mode 100644
index 00000000000..ad65ad2ffcc
--- /dev/null
+++ b/usr.bin/pcc/powerpc/table.c
@@ -0,0 +1,1102 @@
+/*
+ * $OpenBSD: table.c,v 1.1 2007/10/20 10:01:38 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
+
+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,
+ " ; pointer conversion", },
+
+/*
+ * Conversions of integral types
+ */
+
+/* convert (u)char to (u)char */
+{ SCONV, INAREG,
+ INAREG, TCHAR|TUCHAR,
+ INAREG, TCHAR|TUCHAR,
+ 0, RLEFT,
+ " ; convert a between (u)uchar and (u)char\n", },
+
+/* convert pointers to (u)int/(u)long */
+{ SCONV, INAREG,
+ SAREG, TPOINT|TWORD,
+ SAREG, TWORD,
+ 0, RLEFT,
+ " ; convert a pointer/word to an int\n", },
+
+/* convert pointers to pointers */
+{ SCONV, INAREG,
+ SAREG, TPOINT,
+ SAREG, TPOINT,
+ 0, RLEFT,
+ " ; convert pointers\n", },
+
+/* convert (u)longlong to (u)longlong */
+{ SCONV, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ 0, RLEFT,
+ " ; convert (u)longlong to (u)longlong\n", },
+
+
+/* convert char to short */
+{ SCONV, INAREG,
+ SAREG, TCHAR,
+ SAREG, TSHORT|TSWORD,
+ NASL|NAREG, RESC1,
+ " extsb A1,AL ; convert char to short/int\n", },
+
+/* convert uchar to short */
+{ SCONV, INAREG,
+ SAREG, TUCHAR,
+ SAREG, TSHORT|TSWORD,
+ NASL|NAREG, RESC1,
+ " ; convert uchar to short/int\n", },
+
+#if 0
+/* convert char to short in memory */
+{ SCONV, INAREG,
+ SOREG, TCHAR,
+ SAREG, TSHORT|TSWORD,
+ NASL|NAREG|NSPECIAL, RESC1,
+ " lbz A1,AL ; convert char to short/int\n"
+ " extsb A1,A1\n", },
+#endif
+
+/* convert (u)char to ushort/uint/ulong */
+{ SCONV, INAREG,
+ SAREG, TCHAR|TUCHAR,
+ SAREG, TUSHORT|TUWORD,
+ NASL|NAREG|NSPECIAL, RESC1,
+ " andi. A1,AL,255 ; convert (u)char (AL) to ushort/unsigned (A1)\n", },
+
+#if 0
+/* convert uchar to short/int/long in memory */
+{ SCONV, INAREG,
+ SOREG, TUCHAR,
+ SAREG, TSHORT|TSWORD,
+ NASL|NAREG|NSPECIAL, RESC1,
+ " lbz A1,AL ; convert uchar to short/int\n", },
+#endif
+
+#if 0
+/* convert (u)char to ushort/uint/ulong in memory */
+{ SCONV, INAREG,
+ SOREG, TCHAR|TUCHAR,
+ SAREG, TUSHORT|TUWORD|TULONG,
+ NASL|NAREG, RESC1,
+ " lbz A1,AL ; convert (u)char to ushort/unsigned/ulong\n", },
+#endif
+
+/* convert uchar/ushort/uint to (u)longlong */
+{ SCONV, INBREG,
+ SAREG, TUCHAR|TUSHORT|TUNSIGNED,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG, RESC1,
+ " mr A1,AL ; convert uchar/ushort/uint to (u)longlong\n"
+ " li U1,0\n", },
+
+/* convert char/short/int to ulonglong */
+{ SCONV, INBREG,
+ SAREG, TCHAR|TSHORT|TSWORD,
+ SBREG, TULONGLONG,
+ NBREG, RESC1,
+ " mr A1,AL ; convert char/short/int to ulonglong\n"
+ " li U1,0\n", },
+
+/* convert char/short/int to longlong */
+{ SCONV, INBREG,
+ SAREG, TCHAR|TSHORT|TSWORD,
+ SBREG, TLONGLONG,
+ NBREG|NBSL, RESC1,
+ " mr A1,AL ; convert char/short/int to longlong\n"
+ " srawi U1,AL,31\n", },
+
+/* convert (u)short to (u)char */
+{ SCONV, INAREG,
+ SAREG, TSHORT|TUSHORT,
+ SAREG, TCHAR|TUCHAR,
+ NSPECIAL|NAREG|NASL, RESC1,
+ " andi. A1,AL,255 ; convert (u)short to (u)char\n", },
+
+#if 0
+/* convert (u)short to (u)char */
+{ SCONV, INAREG,
+ SOREG, TSHORT|TUSHORT,
+ SAREG, TCHAR|TUCHAR,
+ NSPECIAL|NAREG|NASL, RESC1,
+ " lbz A1,AL ; convert (u)short to (u)char\n", },
+#endif
+
+/* convert short to int */
+{ SCONV, INAREG,
+ SAREG, TSHORT,
+ SAREG, TWORD,
+ NAREG|NASL|NSPECIAL, RESC1,
+ " andi. A1,AL,63356 ; convert short to int\n", },
+
+#if 0
+/* convert (u)short to uint int memory */
+{ SCONV, INAREG,
+ SOREG, TUSHORT|TSHORT,
+ SAREG, TWORD,
+ NAREG|NASL|NSPECIAL, RESC1,
+ " lha A1,AL ; convert (u)short to int\n", },
+#endif
+
+/* convert ushort to (u)int. */
+{ SCONV, INAREG,
+ SAREG, TUSHORT,
+ SAREG, TWORD,
+ NASL|NAREG|NSPECIAL, RESC1,
+ " andi. A1,AL,65535 ; convert ushort to word\n", },
+
+/* convert (u)int to (u)char */
+{ SCONV, INAREG,
+ SAREG, TWORD,
+ SAREG, TCHAR|TUCHAR,
+ NAREG|NASL|NSPECIAL, RESC1,
+ " andi. A1,AL,255 ; convert (u)int to (u)char", },
+
+/* convert (u)int to (u)char */
+{ SCONV, INAREG,
+ SAREG, TWORD,
+ SANY, TCHAR|TUCHAR,
+ 0, RLEFT,
+ " ; convert (u)int to (u)char\n", },
+
+/* convert (u)int to (u)short */
+{ SCONV, INAREG,
+ SAREG, TWORD,
+ SAREG, TSHORT|TUSHORT,
+ NAREG|NASL|NSPECIAL, RESC1,
+ " andi. A1,AL,65535 ; convert (u)int to (u)short\n", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL, FOREFF,
+ SCON|SNAME, TANY,
+ SANY, TANY,
+ 0, 0,
+ " bl CL ; call (args, no result) to scon/sname (CL)\n", },
+
+{ UCALL, FOREFF,
+ SCON|SNAME, TANY,
+ SANY, TANY,
+ 0, 0,
+ " bl CL ; call (no args, no result) to scon/sname (CL)\n", },
+
+{ CALL, INAREG,
+ SCON|SNAME, TANY,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " bl CL ; call (args, result in r3) to scon/sname (CL)\n", },
+
+{ CALL, INBREG,
+ SCON|SNAME, TANY,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1, /* should be 0 */
+ " bl CL ; call (args, result in r3:r4) to scon/sname (CL)\n", },
+
+{ UCALL, INAREG,
+ SCON|SNAME, TANY,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT,
+ NAREG|NASL, RESC1, /* should be 0 */
+ " bl CL ; call (no args, result in r3) to scon/sname (CL)\n", },
+
+{ UCALL, INBREG,
+ SCON|SNAME, TANY,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1, /* should be 0 */
+ " bl CL ; call (no args, result in r3:r4) to scon/sname (CL)\n", },
+
+/* struct return */
+{ USTCALL, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, 0,
+ "ZP call CL\n", },
+
+{ USTCALL, INAREG,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ "ZP call CL\n", },
+
+{ USTCALL, INAREG,
+ SNAME|SAREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ "ZP call *AL\n", },
+
+{ STCALL, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, 0,
+ "ZP call CL\n", },
+
+{ STCALL, INAREG,
+ SCON, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ "ZP call CL\n", },
+
+{ STCALL, INAREG,
+ SNAME|SAREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1, /* should be 0 */
+ "ZP call *AL\n", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+
+/* XXX AL cannot be R0 */
+{ PLUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SONE, TANY,
+ NSPECIAL, RLEFT,
+ " addi AL,AL,AR ; 1\n", },
+
+/* XXX AL cannot be R0 */
+{ PLUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SSCON, TANY,
+ NAREG|NASL|NSPECIAL, RESC1,
+ " addi A1,AL,AR ; addition of constant\n", },
+
+{ PLUS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SSCON, TANY,
+ NBREG|NBSL, RESC1,
+ " addic A1,AL,AR ; 64-bit addition of constant\n"
+ " addze U1,UL", },
+
+{ PLUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ NAREG|NASL|NSPECIAL, RESC1,
+ " add A1,AL,AR\n", },
+
+{ PLUS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1,
+ " addc A1,AL,AR ; 64-bit add\n"
+ " adde U1,UL,UR\n", },
+
+{ MINUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SONE, TANY,
+ NAREG|NASL|NSPECIAL, RESC1,
+ " addi A1,AL,-1\n", },
+
+{ MINUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SSCON, TANY,
+ NAREG|NASL|NSPECIAL, RESC1,
+ " addi A1,AL,AR\n", },
+
+{ MINUS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SSCON, TANY,
+ NBREG|NBSL, RESC1,
+ " addic A1,AL,-AR"
+ " addme U1,UL\n", },
+
+{ MINUS, INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ NAREG|NASL|NSPECIAL, RESC1,
+ " subf A1,AR,AL\n", },
+
+{ MINUS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1,
+ " subfc A1,AR,AL ; 64-bit subtraction\n"
+ " subfe U1,UR,UL\n", },
+
+/*
+ * The next rules handle all shift operators.
+ */
+
+{ LS, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " slw A1,AL,AR ; left shift\n", },
+
+{ LS, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SCON, TANY,
+ NAREG|NASL, RESC1,
+ " slwi A1,AL,AR ; left shift by constant\n", },
+
+{ LS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SCON, TANY,
+ NBREG, RESC1,
+ "ZO" },
+
+{ RS, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " srw A1,AL,AR ; right shift\n", },
+
+{ RS, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SCON, TANY,
+ NAREG|NASL, RESC1,
+ " srwi A1,AL,AR ; right shift by constant\n", },
+
+{ RS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SCON, TANY,
+ NBREG, RESC1,
+ "ZO" },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+
+/* assign 16-bit constant to register */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TANY,
+ SSCON, TANY,
+ 0, RDEST,
+ " li AL,AR\n", },
+
+/* assign 16-bit constant to register */
+{ ASSIGN, FOREFF|INBREG,
+ SBREG, TANY,
+ SSCON, TANY,
+ 0, RDEST,
+ " li AL,AR\n"
+ " li UL,0\n", },
+
+/* assign constant to register */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TANY,
+ SCON, TANY,
+ 0, RDEST,
+ " lis AL,ha16(AR)\n"
+ " addi AL,AL,lo16(AR)\n", },
+
+/* assign constant to register */
+{ ASSIGN, FOREFF|INBREG,
+ SBREG, TANY,
+ SCON, TANY,
+ 0, RDEST,
+ " lis AL,ha16(AR)\n"
+ " addi AL,AL,lo16(AR)\n"
+ " lis UL,ha16(UR)\n"\
+ " addi UL,UL,lo16(UR)\n", },
+
+/* assign memory to register */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TWORD|TPOINT,
+ SOREG, TWORD|TPOINT,
+ NSPECIAL, RDEST,
+ " lwz AL,AR\n", },
+
+/* assign memory to register */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TWORD|TPOINT,
+ SNAME, TWORD|TPOINT,
+ NSPECIAL, RDEST,
+ " lis AL,ha16(AR) ; assign sname to reg\n"
+ " lwz AL,lo16(AR)(AL)\n", },
+
+/* assign memory to register */
+{ ASSIGN, FOREFF|INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SOREG, TLONGLONG|TULONGLONG,
+ NSPECIAL, RDEST,
+ " lwz AL,AR ; assign llong to reg\n"
+ " lwz UL,UR\n" },
+
+{ ASSIGN, FOREFF|INAREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SNAME, TLONGLONG|TULONGLONG,
+ NSPECIAL, RDEST,
+ " lis AL,ha16(AR) ; assign 64-bit sname to reg\n"
+ " lwz AL,lo16(AR)(AL)\n"
+ " lis UL,ha16(UR)\n"
+ " lwz UL,lo16(UR)(UL)\n", },
+
+/* assign memory to register */
+{ ASSIGN, FOREFF|INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SOREG, TSWORD,
+ NSPECIAL, RDEST,
+ " lwz AL,AR ; load int/pointer into llong\n"
+ " srawi UL,AR,31\n" },
+
+/* assign memory to register */
+{ ASSIGN, FOREFF|INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SOREG, TUNSIGNED|TPOINT,
+ NSPECIAL, RDEST,
+ " lwz AL,AR ; load uint/pointer into (u)llong\n"
+ " li UL, 0\n" },
+
+/* assign memory to register */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TUCHAR,
+ SOREG, TUCHAR,
+ NSPECIAL, RDEST,
+ " lbz AL,AR\n", },
+
+/* assign memory to register */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TUCHAR,
+ SNAME, TUCHAR,
+ NSPECIAL, RDEST,
+ " lis AL,ha16(AR) ; assign uchar sname to reg\n"
+ " lbz AL,lo16(AR)(AL)\n", },
+
+/* assign memory to register */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TCHAR,
+ SOREG, TCHAR,
+ NSPECIAL, RDEST,
+ " lbz AL,AR\n"
+ " extsb AL,AL\n", },
+
+/* assign memory to register */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TCHAR,
+ SNAME, TCHAR,
+ NSPECIAL, RDEST,
+ " lis AL,ha16(AR) ; assign char sname to reg\n"
+ " lbz AL,lo16(AR)(AL)\n"
+ " extsb AL,AL\n", },
+
+/* assign memory to register */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TWORD|TPOINT,
+ SOREG, TSHORT|TUSHORT,
+ NSPECIAL, RDEST,
+ " lha AL,AR\n", },
+
+/* assign memory to register */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TWORD|TPOINT,
+ SNAME, TSHORT|TUSHORT,
+ NSPECIAL, RDEST,
+ " lis AL,ha16(AR)\n"
+ " lha AL,lo16(AR)(AL)\n", },
+
+/* assign register to memory */
+{ ASSIGN, FOREFF|INAREG,
+ SOREG, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ NSPECIAL, RDEST,
+ " stw AR,AL\n", },
+
+/* assign register to memory */
+{ ASSIGN, FOREFF|INAREG,
+ SNAME, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT,
+ NAREG|NSPECIAL, RDEST,
+ " lis A1,ha16(AL) ; assign reg to sname\n"
+ " stw AR,lo16(AL)(A1)\n", },
+
+/* assign register to memory */
+{ ASSIGN, FOREFF|INBREG,
+ SOREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NSPECIAL, RDEST,
+ " stw AR,AL ; store 64-bit value\n"
+ " stw UR,UL\n", },
+
+/* assign register to memory */
+{ ASSIGN, FOREFF|INBREG,
+ SNAME, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NSPECIAL, RDEST,
+ " lis A1,ha16(AL) ; assign reg to 64-bit sname\n"
+ " stw AR,lo16(AL)(A1)\n"
+ " lis U1,ha16(UL)\n"
+ " stw UR,lo16(UL)(U1)\n", },
+
+/* assign register to memory */
+{ ASSIGN, FOREFF|INAREG,
+ SOREG, TCHAR|TUCHAR,
+ SAREG, TCHAR|TUCHAR,
+ NSPECIAL, RDEST,
+ " stb AR,AL\n", },
+
+/* assign register to memory */
+{ ASSIGN, FOREFF|INAREG,
+ SNAME, TCHAR|TUCHAR,
+ SAREG, TCHAR|TUCHAR,
+ NAREG|NSPECIAL, RDEST,
+ " lis A1,ha16(AL)"
+ " stb AR,lo16(AL)(A1)\n", },
+
+/* assign register to memory */
+{ ASSIGN, FOREFF|INAREG,
+ SOREG, TSHORT|TUSHORT,
+ SAREG, TSHORT|TUSHORT,
+ NSPECIAL, RDEST,
+ " sth AR,AL\n", },
+
+/* assign register to memory */
+{ ASSIGN, FOREFF|INAREG,
+ SNAME, TSHORT|TUSHORT,
+ SAREG, TSHORT|TUSHORT,
+ NAREG|NSPECIAL, RDEST,
+ " lis A1,ha16(AL)\n"
+ " sth AR,lo16(AL)(A1)\n", },
+
+/* assign register to register */
+{ ASSIGN, FOREFF|INAREG,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ 0, RDEST,
+ " mr AL,AR ; assign AR to AL\n", },
+
+{ ASSIGN, FOREFF|INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ 0, RDEST,
+ " mr AL,AR ; assign UR:AR to UL:AL\n"
+ " mr UL,UR\n", },
+
+#if 0
+{ ASSIGN, FOREFF|INAREG,
+ SFLD, TANY,
+ SAREG, TANY,
+ NAREG, RDEST,
+ "ZE", },
+
+{ ASSIGN, FOREFF,
+ SFLD, TANY,
+ SAREG, TANY,
+ NAREG, 0,
+ "ZE", },
+#endif
+
+/* Do not generate memcpy if return from funcall */
+#if 0
+{ STASG, INAREG|FOREFF,
+ SOREG|SNAME|SAREG, TPTRTO|TSTRUCT,
+ SFUNCALL, TPTRTO|TSTRUCT,
+ 0, RRIGHT,
+ "", },
+#endif
+
+{ STASG, INAREG|FOREFF,
+ SOREG|SNAME, TANY,
+ SAREG|SOREG|SNAME, TPTRTO|TANY,
+ NSPECIAL, RRIGHT,
+ "ZQ", },
+
+/*
+ * DIV/MOD/MUL
+ */
+
+{ DIV, INAREG,
+ SAREG, TSWORD,
+ SAREG, TWORD,
+ NAREG|NASL, RESC1,
+ " divw A1,AL,AR\n", },
+
+{ DIV, INAREG,
+ SAREG, TUWORD|TPOINT,
+ SAREG, TUWORD|TPOINT,
+ NAREG|NASL, RESC1,
+ " divwu A1,AL,AR\n", },
+
+{ MOD, INAREG,
+ SAREG, TSWORD,
+ SAREG, TSWORD,
+ NAREG, RESC1,
+ " divw A1,AL,AR ; signed modulo\n"
+ " mullw A1,A1,AR\n"
+ " subf A1,A1,AL\n", },
+
+{ MOD, INAREG,
+ SAREG, TWORD|TPOINT,
+ SAREG, TUWORD|TPOINT,
+ NAREG, RESC1,
+ " divwu A1,AL,AR ; unsigned modulo\n"
+ " mullw A1,A1,AR\n"
+ " subf A1,A1,AL\n", },
+
+{ MUL, INAREG,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SSCON, TANY,
+ NAREG|NASL, RESC1,
+ " mulli A1,AL,AR\n", },
+
+{ MUL, INAREG,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " mullw A1,AL,AR\n", },
+
+{ MUL, INBREG,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NBREG, RESC1,
+ " mullw A1,AL,AR\n"
+ " mulhw U1,AL,AR\n", },
+
+{ MUL, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG, RESC1,
+ " mullw A1,AL,AR\n"
+ " mulhw U1,AL,AR\n", },
+
+/*
+ * Indirection operators.
+ */
+
+{ UMUL, INAREG,
+ SANY, TPOINT|TWORD,
+ SOREG, TPOINT|TWORD,
+ NAREG|NSPECIAL, RESC1,
+ " lwz A1,AL ; word load\n", },
+
+{ UMUL, INAREG,
+ SANY, TANY,
+ SOREG, TCHAR,
+ NAREG|NSPECIAL, RESC1,
+ " lbz A1,AL ; char load\n"
+ " extsb A1,A1\n", },
+
+{ UMUL, INAREG,
+ SANY, TANY,
+ SOREG, TUCHAR,
+ NAREG|NSPECIAL, RESC1,
+ " lbz A1,AL ; uchar load\n", },
+
+{ UMUL, INAREG,
+ SANY, TANY,
+ SOREG, TSHORT,
+ NAREG|NSPECIAL, RESC1,
+ " lhz A1,AL ; short load\n"
+ " extsh A1,A1\n", },
+
+{ UMUL, INAREG,
+ SANY, TANY,
+ SOREG, TUSHORT,
+ NAREG|NSPECIAL, RESC1,
+ " lhz A1,AL ; ushort load\n", },
+
+{ UMUL, INBREG,
+ SANY, TANY,
+ SOREG, TLONGLONG|TULONGLONG,
+ NBREG, RESC1,
+ " lwz A1,AL ; 64-bit load\n"
+ " lwz U1,UL\n", },
+
+/*
+ * Logical/branching operators
+ */
+
+/* compare with constant */
+{ OPLOG, FORCC,
+ SAREG, TANY,
+ SSCON, TANY,
+ 0, RESCC,
+ " cmpwi AL,AR\n", },
+
+/* compare with register */
+{ OPLOG, FORCC,
+ SAREG, TWORD|TPOINT|TSHORT|TCHAR,
+ SAREG, TWORD|TPOINT|TSHORT|TCHAR,
+ 0, RESCC,
+ " cmpw AL,AR\n", },
+
+/* compare with register */
+{ OPLOG, FORCC,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ 0, 0,
+ "ZD", },
+
+{ OPLOG, FORCC,
+ SANY, TANY,
+ SANY, TANY,
+ REWRITE, 0,
+ "diediedie!", },
+
+/* AND/OR/ER */
+{ AND, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL|NSPECIAL, RESC1,
+ " and A1,AL,AR\n", },
+
+#if 0
+/* AR must be positive */
+{ AND, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TCHAR,
+ SSCON, TANY,
+ 0, RLEFT,
+ " andi. AL,AL,AR\n", },
+#endif
+
+{ AND, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1,
+ " and A1,AL,AR ; 64-bit and\n"
+ " and U1,UL,UR\n" },
+
+{ AND, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SSCON, TANY,
+ 0, RLEFT,
+ " andi. AL,AL,AR ; 64-bit and with constant\n"
+ " li UL,0\n" },
+
+{ OR, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL|NSPECIAL, RESC1,
+ " or A1,AL,AR\n", },
+
+{ OR, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TCHAR,
+ SSCON, TANY,
+ 0, RLEFT,
+ " ori AL,AL,AR\n", },
+
+{ OR, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ 0, RLEFT,
+ " or AL,AL,AR ; 64-bit or\n"
+ " or UL,UL,UR\n" },
+
+{ OR, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SSCON, TANY,
+ 0, RLEFT,
+ " ori AL,AL,AR ; 64-bit or with constant\n" },
+
+{ ER, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL|NSPECIAL, RESC1,
+ " xor A1,AL,AR\n", },
+
+{ ER, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TCHAR,
+ SSCON, TANY,
+ 0, RLEFT,
+ " xori AL,AL,AR\n", },
+
+{ ER, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1,
+ " xor A1,AL,AR ; 64-bit xor\n"
+ " xor U1,UL,UR\n" },
+
+{ ER, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SSCON, TANY,
+ 0, RLEFT,
+ " xori AL,AL,AR ; 64-bit xor with constant\n" },
+
+/*
+ * Jumps.
+ */
+{ GOTO, FOREFF,
+ SCON, TANY,
+ SANY, TANY,
+ 0, RNOP,
+ " ba LL\n", },
+
+#ifdef GCC_COMPAT
+{ GOTO, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, RNOP,
+ " ba *AL\n", },
+#endif
+
+/*
+ * Convert LTYPE to reg.
+ */
+
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SOREG, TLONGLONG|TULONGLONG,
+ NBREG, RESC1,
+ " lwz A1,AL ; load long from memory\n"
+ " lwz U1,UL\n", },
+
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SNAME, TLONGLONG|TULONGLONG,
+ NBREG, RESC1,
+ " lis A1,ha16(AL) ; load long from sname\n"
+ " lwz A1,lo16(AL)(A1)\n"
+ " lis U1,ha16(UL)\n"
+ " lwz U1,lo16(UL)(U1)\n", },
+
+/* load word from memory */
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SOREG, TWORD|TPOINT,
+ NAREG, RESC1,
+ " lwz A1,AL ; load word from memory\n", },
+
+/* load word from memory */
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SNAME, TWORD|TPOINT,
+ NAREG|NSPECIAL, RESC1,
+ " lis A1,ha16(AL) ; load word from sname\n"
+ " lwz A1,lo16(AL)(A1)\n", },
+
+/* load char from memory */
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SOREG, TCHAR,
+ NAREG, RESC1,
+ " lbz A1,AL ; load char from memory\n"
+ " extsb A1,A1\n", },
+
+/* load char from memory */
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SNAME, TCHAR,
+ NAREG|NSPECIAL, RESC1,
+ " lis A1,ha16(AL) ; load char from sname\n"
+ " lbz A1,lo16(AL)(A1)\n"
+ " extsb A1,A1\n", },
+
+/* load uchar from memory */
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SOREG, TUCHAR,
+ NAREG, RESC1,
+ " lbz A1,AL ; load uchar from memory\n", },
+
+/* load uchar from memory */
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SNAME, TUCHAR,
+ NAREG|NSPECIAL, RESC1,
+ " lis A1,ha16(AL) ; load uchar from sname"
+ " lbz A1,lo16(AL)(A1)\n", },
+
+/* load short from memory */
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SOREG, TSHORT|TUSHORT,
+ NAREG, RESC1,
+ " lha A1,AL ; load (u)short from memory\n", },
+
+/* load short from memory */
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SOREG, TSHORT|TUSHORT,
+ NAREG|NSPECIAL, RESC1,
+ " lis A1,ha16(AL) ; load (u)short from sname\n"
+ " lha A1,lo16(AL)(A1)\n", },
+
+/* load from 16-bit constant */
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SSCON, TANY,
+ NAREG, RESC1,
+ " li A1,AL ; load 16-bit constant\n", },
+
+/* load from 16-bit constant */
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SSCON, TANY,
+ NBREG, RESC1,
+ " li A1,AL ; load 16-bit constant\n"
+ " li U1,0\n", },
+
+/* load from constant */
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SCON, TANY,
+ NAREG|NASL|NSPECIAL, RESC1,
+ " lis A1,ha16(AL) ; load constant into register\n"
+ " addi A1,A1,lo16(AL)\n", },
+
+/* load from constant */
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SCON, TANY,
+ NBREG, RESC1,
+ " lis A1,ha16(AL) ; load constant into register\n"
+ " addi A1,A1,lo16(AL)\n"
+ " lis U1,ha16(UL)\n"
+ " addi U1,U1,lo16(UL)\n", },
+
+/* load from register */
+{ OPLTYPE, INAREG,
+ SANY, TANY,
+ SAREG, TANY,
+ NAREG, RESC1,
+ " mr A1,AL ; load AL into A1\n" },
+
+/* load from register */
+{ OPLTYPE, INBREG,
+ SANY, TANY,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG, RESC1,
+ " mr A1,AL ; load UL:AL into U1:A1\n"
+ " mr U1,UL\n", },
+
+
+/*
+ * 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\n", },
+
+{ UMINUS, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ NBREG|NBSL, RESC1,
+ " subfic A1,AL,0\n"
+ " subfze U1,UL\n", },
+
+{ COMPL, INAREG,
+ SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SANY, TANY,
+ NAREG|NASL, RESC1,
+ " not A1,AL\n", },
+
+{ COMPL, INBREG,
+ SBREG, TLONGLONG|TULONGLONG,
+ SANY, TANY,
+ NBREG|NBSL, RESC1,
+ " not A1,AL"
+ " not U1,UL\n", },
+
+/*
+ * Arguments to functions.
+ */
+
+#if 0
+{ FUNARG, FOREFF,
+ SCON|SAREG|SNAME|SOREG, TWORD|TPOINT,
+ SANY, TWORD|TPOINT,
+ 0, RNULL,
+ " pushl AL\n", },
+
+{ FUNARG, FOREFF,
+ SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SANY, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ 0, RNULL,
+ " pushl AL\n", },
+
+{ FUNARG, FOREFF,
+ SAREG|SNAME|SOREG, TSHORT,
+ SANY, TSHORT,
+ NAREG, 0,
+ " movswl AL,ZN\n pushl ZN\n", },
+#endif
+
+{ FUNARG, FOREFF,
+ SAREG|SNAME|SOREG, TUSHORT,
+ SANY, TUSHORT,
+ NAREG, 0,
+ " movzwl AL,ZN\n pushl ZN\n", },
+
+#if 0
+{ FUNARG, FOREFF,
+ SHCH|SNAME|SOREG, TCHAR,
+ SANY, TCHAR,
+ NAREG, 0,
+ " movsbl AL,A1\n pushl A1\n", },
+#endif
+
+#if 0
+{ FUNARG, FOREFF,
+ SHCH|SNAME|SOREG, TUCHAR,
+ SANY, TUCHAR,
+ NAREG, 0,
+ " movzbl AL,A1\n pushl A1\n", },
+#endif
+
+#if 0
+{ STARG, FOREFF,
+ SAREG|SOREG|SNAME|SCON, TANY,
+ SANY, TSTRUCT,
+ NSPECIAL|NAREG, 0,
+ "ZF", },
+#endif
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);