summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorStefan Kempf <stefan@cvs.openbsd.org>2007-12-22 14:12:27 +0000
committerStefan Kempf <stefan@cvs.openbsd.org>2007-12-22 14:12:27 +0000
commit6c7d5c4a39afd9cf51518e7b1661b6583a390f15 (patch)
tree6b2ab6881a011cd79367ee7bc343e30a80c012a4 /usr.bin
parent364275c5dd83730a39ae5a9a474e904ff4f2b27a (diff)
Sync with main repo.
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/pcc/mips/TODO9
-rw-r--r--usr.bin/pcc/mips/code.c439
-rw-r--r--usr.bin/pcc/mips/local.c396
-rw-r--r--usr.bin/pcc/mips/local2.c691
-rw-r--r--usr.bin/pcc/mips/macdefs.h216
-rw-r--r--usr.bin/pcc/mips/order.c298
-rw-r--r--usr.bin/pcc/mips/table.c905
7 files changed, 2082 insertions, 872 deletions
diff --git a/usr.bin/pcc/mips/TODO b/usr.bin/pcc/mips/TODO
index 63b5f67c34a..07072de7274 100644
--- a/usr.bin/pcc/mips/TODO
+++ b/usr.bin/pcc/mips/TODO
@@ -1,7 +1,2 @@
-* Look at long long support for the new register allocator.
-
-* Add floating point support.
-
-* Add support for struct/union arguments and return values.
-
-* See if the workaround for the function arguments can be removed/rewritten.
+* Fix floating-point arguments in registers
+* Fix structure arguments in registers
diff --git a/usr.bin/pcc/mips/code.c b/usr.bin/pcc/mips/code.c
index 99847602da6..be0598d4ae1 100644
--- a/usr.bin/pcc/mips/code.c
+++ b/usr.bin/pcc/mips/code.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: code.c,v 1.3 2007/11/22 15:06:43 stefan Exp $ */
+/* $OpenBSD: code.c,v 1.4 2007/12/22 14:12:26 stefan Exp $ */
/*
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
@@ -32,11 +32,8 @@
* Simon Olsson (simols-1@student.ltu.se) 2005.
*/
-# include "pass1.h"
-# include "manifest.h"
-
-/* Offset to arguments passed to a function. */
-int passedargoff;
+#include <assert.h>
+#include "pass1.h"
/*
* cause the alignment to become a multiple of n
@@ -72,6 +69,8 @@ defnam(struct symtab *p)
printf("%s:\n", c);
}
+static int rvnr;
+
/*
* code for the end of a function
* deals with struct return here
@@ -79,8 +78,161 @@ defnam(struct symtab *p)
void
efcode()
{
+ NODE *p, *q;
+ int tempnr;
+ int ty;
+
if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
return;
+
+ ty = cftnsp->stype - FTN;
+
+ q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->ssue);
+ q->n_rval = V0;
+ p = tempnode(0, INCREF(ty), 0, cftnsp->ssue);
+ tempnr = p->n_lval;
+ p = buildtree(ASSIGN, p, q);
+ ecomp(p);
+
+ q = tempnode(tempnr, INCREF(ty), 0, cftnsp->ssue);
+ q = buildtree(UMUL, q, NIL);
+
+ p = tempnode(rvnr, INCREF(ty), 0, cftnsp->ssue);
+ p = buildtree(UMUL, p, NIL);
+
+ p = buildtree(ASSIGN, p, q);
+ ecomp(p);
+
+ q = tempnode(rvnr, INCREF(ty), 0, cftnsp->ssue);
+ p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->ssue);
+ p->n_rval = V0;
+ p = buildtree(ASSIGN, p, q);
+ ecomp(p);
+}
+
+/* Put a symbol in a temporary
+ * used by bfcode() and its helpers */
+static void
+putintemp(struct symtab *sym)
+{
+ NODE *p;
+ spname = sym;
+ p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
+ p = buildtree(ASSIGN, p, buildtree(NAME, 0, 0));
+ sym->soffset = p->n_left->n_lval;
+ sym->sflags |= STNODE;
+ ecomp(p);
+}
+
+/* setup the hidden pointer to struct return parameter
+ * used by bfcode() */
+static void
+param_retptr(void)
+{
+ NODE *p, *q;
+
+ p = tempnode(0, PTR+STRTY, 0, cftnsp->ssue);
+ rvnr = p->n_lval;
+ q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
+ q->n_rval = A0;
+ p = buildtree(ASSIGN, p, q);
+ ecomp(p);
+}
+
+/* setup struct parameter
+ * push the registers out to memory
+ * used by bfcode() */
+static void
+param_struct(struct symtab *sym, int *regp)
+{
+ int reg = *regp;
+ NODE *p, *q;
+ int navail;
+ int sz;
+ int off;
+ int num;
+ int i;
+
+ navail = nargregs - (reg - A0);
+ sz = tsize(sym->stype, sym->sdf, sym->ssue) / SZINT;
+ off = ARGINIT/SZINT + (reg - A0);
+ num = sz > navail ? navail : sz;
+ for (i = 0; i < num; i++) {
+ q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+ q->n_rval = reg++;
+ p = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+ p->n_rval = FP;
+ p = block(PLUS, p, bcon(4*off++), INT, 0, MKSUE(INT));
+ p = block(UMUL, p, NIL, INT, 0, MKSUE(INT));
+ p = buildtree(ASSIGN, p, q);
+ ecomp(p);
+ }
+
+ *regp = reg;
+}
+
+/* setup a 64-bit parameter (double/ldouble/longlong)
+ * used by bfcode() */
+static void
+param_64bit(struct symtab *sym, int *regp, int dotemps)
+{
+ int reg = *regp;
+ NODE *p, *q;
+ int navail;
+ int sz;
+
+ /* alignment */
+ ++reg;
+ reg &= ~1;
+
+ navail = nargregs - (reg - A0);
+ sz = szty(sym->stype);
+
+ if (sz > navail) {
+ /* would have appeared half in registers/half
+ * on the stack, but alignment ensures it
+ * appears on the stack */
+ if (dotemps)
+ putintemp(sym);
+ } else {
+ q = block(REG, NIL, NIL,
+ sym->stype, sym->sdf, sym->ssue);
+ q->n_rval = A0A1 + (reg - A0);
+ if (dotemps) {
+ p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
+ sym->soffset = p->n_lval;
+ sym->sflags |= STNODE;
+ } else {
+ spname = sym;
+ p = buildtree(NAME, 0, 0);
+ }
+ p = buildtree(ASSIGN, p, q);
+ ecomp(p);
+ reg += 2;
+ }
+
+ *regp = reg;
+}
+
+/* setup a 32-bit param on the stack
+ * used by bfcode() */
+static void
+param_32bit(struct symtab *sym, int *regp, int dotemps)
+{
+ NODE *p, *q;
+
+ q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->ssue);
+ q->n_rval = (*regp)++;
+ if (dotemps) {
+ p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
+ sym->soffset = p->n_lval;
+ sym->sflags |= STNODE;
+ } else {
+ spname = sym;
+ p = buildtree(NAME, 0, 0);
+ }
+ p = buildtree(ASSIGN, p, q);
+ ecomp(p);
}
/*
@@ -90,53 +242,63 @@ efcode()
void
bfcode(struct symtab **sp, int cnt)
{
- NODE *p, *q;
- int i, n;
+ union arglist *usym;
+ int lastreg = A0 + nargregs - 1;
+ int saveallargs = 0;
+ int i, reg;
+
+ /*
+ * Detect if this function has ellipses and save all
+ * argument register onto stack.
+ */
+ usym = cftnsp->sdf->dfun;
+ while (usym && usym->type != TNULL) {
+ if (usym->type == TELLIPSIS) {
+ saveallargs = 1;
+ break;
+ }
+ ++usym;
+ }
+
+ reg = A0;
+ /* assign hidden return structure to temporary */
if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
- /* Function returns struct, adjust arg offset */
- for (i = 0; i < cnt; i++)
- sp[i]->soffset += SZPOINT(INT);
+ param_retptr();
+ ++reg;
}
/* recalculate the arg offset and create TEMP moves */
- for (n = A0, i = 0; i < cnt; i++) {
- if (n + szty(sp[i]->stype) <= A0 + MIPS_NARGREGS) {
- if (xtemps) {
- p = tempnode(0, sp[i]->stype,
- sp[i]->sdf, sp[i]->ssue);
- spname = sp[i];
- q = block(REG, NIL, NIL,
- sp[i]->stype, sp[i]->sdf, sp[i]->ssue);
- q->n_rval = n;
- p = buildtree(ASSIGN, p, q);
- sp[i]->soffset = p->n_left->n_lval;
- sp[i]->sflags |= STNODE;
- } else {
- // sp[i]->soffset += ARGINIT;
- spname = sp[i];
- q = block(REG, NIL, NIL,
- sp[i]->stype, sp[i]->sdf, sp[i]->ssue);
- q->n_rval = n;
- p = buildtree(ASSIGN, buildtree(NAME, 0, 0), q);
- }
- ecomp(p);
- } else {
- // sp[i]->soffset += ARGINIT;
- if (xtemps) {
- /* put stack args in temps if optimizing */
- spname = sp[i];
- p = tempnode(0, sp[i]->stype,
- sp[i]->sdf, sp[i]->ssue);
- p = buildtree(ASSIGN, p, buildtree(NAME, 0, 0));
- sp[i]->soffset = p->n_left->n_lval;
- sp[i]->sflags |= STNODE;
- ecomp(p);
- }
-
- }
- n += szty(sp[i]->stype);
- }
+ for (i = 0; i < cnt; i++) {
+
+ if ((reg > lastreg) && !xtemps)
+ break;
+ else if (reg > lastreg)
+ putintemp(sp[i]);
+ else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY)
+ param_struct(sp[i], &reg);
+ else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE ||
+ DEUNSIGN(sp[i]->stype) == LONGLONG)
+ param_64bit(sp[i], &reg, xtemps && !saveallargs);
+ else
+ param_32bit(sp[i], &reg, xtemps && !saveallargs);
+ }
+
+ /* if saveallargs, save the rest of the args onto the stack */
+ if (!saveallargs)
+ return;
+ while (reg <= lastreg) {
+ NODE *p, *q;
+ int off = ARGINIT/SZINT + (reg - A0);
+ q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+ q->n_rval = reg++;
+ p = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+ p->n_rval = FP;
+ p = block(PLUS, p, bcon(4*off), INT, 0, MKSUE(INT));
+ p = block(UMUL, p, NIL, INT, 0, MKSUE(INT));
+ p = buildtree(ASSIGN, p, q);
+ ecomp(p);
+ }
}
@@ -160,6 +322,9 @@ ejobcode(int flag )
void
bjobcode()
{
+ printf("\t.section .mdebug.abi32\n");
+ printf("\t.previous\n");
+ printf("\t.abicalls\n");
}
/*
@@ -225,33 +390,142 @@ mygenswitch(int num, TWORD type, struct swents **p, int n)
return 0;
}
-static void
-moveargs(NODE **n, int *regp)
+
+/* setup call stack with a structure */
+/* called from moveargs() */
+static NODE *
+movearg_struct(NODE *p, NODE *parent, int *regp)
{
- NODE *r = *n;
- NODE *t;
+ int reg = *regp;
+ NODE *q, *t, *r;
+ int navail;
+ int off;
+ int num;
int sz;
- int regnum;
+ int i;
+
+ navail = nargregs - (reg - A0);
+ sz = tsize(p->n_type, p->n_df, p->n_sue) / SZINT;
+ num = sz > navail ? navail : sz;
+
+ if (p != parent)
+ q = parent->n_left;
+ else
+ q = NULL;
+
+ /* copy structure into registers */
+ for (i = 0; i < num; i++) {
+ t = tcopy(p->n_left);
+ t = block(SCONV, t, NIL, PTR+INT, 0, MKSUE(PTR+INT));
+ t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKSUE(PTR+INT));
+ t = buildtree(UMUL, t, NIL);
+
+ r = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+ r->n_rval = reg++;
+
+ r = buildtree(ASSIGN, r, t);
+ if (q == NULL)
+ q = r;
+ else
+ q = block(CM, q, r, INT, 0, MKSUE(INT));
+ }
+ off = ARGINIT/SZINT + nargregs;
+ for (i = num; i < sz; i++) {
+ t = tcopy(p->n_left);
+ t = block(SCONV, t, NIL, PTR+INT, 0, MKSUE(PTR+INT));
+ t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKSUE(PTR+INT));
+ t = buildtree(UMUL, t, NIL);
+
+ r = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+ r->n_rval = FP;
+ r = block(PLUS, r, bcon(4*off++), INT, 0, MKSUE(INT));
+ r = block(UMUL, r, NIL, INT, 0, MKSUE(INT));
+
+ r = buildtree(ASSIGN, r, t);
+ if (q == NULL)
+ q = r;
+ else
+ q = block(CM, q, r, INT, 0, MKSUE(INT));
+ }
+ tfree(p);
- if (r->n_op == CM) {
- moveargs(&r->n_left, regp);
- n = &r->n_right;
- r = r->n_right;
- }
+ if (parent->n_op == CM) {
+ parent->n_left = q->n_left;
+ t = q;
+ q = q->n_right;
+ nfree(t);
+ }
- regnum = *regp;
- sz = szty(r->n_type);
+ *regp = reg;
+ return q;
+}
- if (regnum + sz <= A0 + MIPS_NARGREGS) {
- t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_sue);
- t->n_rval = regnum;
- t = buildtree(ASSIGN, t, r);
+/* setup call stack with 64-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_64bit(NODE *p, int *regp)
+{
+ int reg = *regp;
+ NODE *q;
+
+ /* alignment */
+ ++reg;
+ reg &= ~1;
+
+ q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue);
+ q->n_rval = A0A1 + (reg++ - A0);
+ q = buildtree(ASSIGN, q, p);
+
+ *regp = reg;
+ return q;
+}
+
+/* setup call stack with 32-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_32bit(NODE *p, int *regp)
+{
+ int reg = *regp;
+ NODE *q;
+
+ q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue);
+ q->n_rval = reg++;
+ q = buildtree(ASSIGN, q, p);
+
+ *regp = reg;
+ return q;
+}
+
+static NODE *
+moveargs(NODE *p, int *regp)
+{
+ NODE *r, **rp;
+ int lastreg;
+ int reg;
+
+ if (p->n_op == CM) {
+ p->n_left = moveargs(p->n_left, regp);
+ r = p->n_right;
+ rp = &p->n_right;
} else {
- t = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_sue);
- }
+ r = p;
+ rp = &p;
+ }
+
+ lastreg = A0 + nargregs - 1;
+ reg = *regp;
- *n = t;
- *regp += sz;
+ if (reg > lastreg && r->n_op != STARG)
+ *rp = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_sue);
+ else if (r->n_op == STARG) {
+ *rp = movearg_struct(r, p, regp);
+ } else if (DEUNSIGN(r->n_type) == LONGLONG || r->n_type == DOUBLE ||
+ r->n_type == LDOUBLE)
+ *rp = movearg_64bit(r, regp);
+ else
+ *rp = movearg_32bit(r, regp);
+
+ return p;
}
/*
@@ -262,6 +536,33 @@ NODE *
funcode(NODE *p)
{
int regnum = A0;
- moveargs(&p->n_right, &regnum);
+ NODE *l, *r, *t, *q;
+ int ty;
+
+ l = p->n_left;
+ r = p->n_right;
+
+ /*
+ * if returning a structure, make the first argument
+ * a hidden pointer to return structure.
+ */
+ ty = DECREF(l->n_type);
+ if (ty == STRTY+FTN || ty == UNIONTY+FTN) {
+ ty = DECREF(l->n_type) - FTN;
+ q = tempnode(0, ty, l->n_df, l->n_sue);
+ q = buildtree(ADDROF, q, NIL);
+ if (r->n_op != CM) {
+ p->n_right = block(CM, q, r, INCREF(ty),
+ l->n_df, l->n_sue);
+ } else {
+ for (t = r; t->n_left->n_op == CM; t = t->n_left)
+ ;
+ t->n_left = block(CM, q, t->n_left, INCREF(ty),
+ l->n_df, l->n_sue);
+ }
+ }
+
+ p->n_right = moveargs(p->n_right, &regnum);
+
return p;
}
diff --git a/usr.bin/pcc/mips/local.c b/usr.bin/pcc/mips/local.c
index 0df1346481c..e821be7ed2c 100644
--- a/usr.bin/pcc/mips/local.c
+++ b/usr.bin/pcc/mips/local.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: local.c,v 1.3 2007/11/18 17:39:55 ragge Exp $ */
+/* $OpenBSD: local.c,v 1.4 2007/12/22 14:12:26 stefan Exp $ */
/*
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
@@ -31,57 +31,11 @@
* Simon Olsson (simols-1@student.ltu.se) 2005.
*/
+#include <assert.h>
#include "pass1.h"
static int inbits, inval;
-#ifdef MIPS_BIGENDIAN
-/*
- * If we're big endian, then all OREG loads of a type
- * larger than the destination, must have the
- * offset changed to point to the correct bytes in memory.
- */
-static NODE *
-offchg(NODE *p)
-{
- NODE *l = p->n_left;
-
- if (p->n_op != SCONV)
- return;
-
- switch (l->n_type) {
- case SHORT:
- case USHORT:
- if (DEUNSIGN(p->n_type) == CHAR)
- l->n_lval += 1;
- break;
- case LONG:
- case ULONG:
- case INT:
- case UNSIGNED:
- if (DEUNSIGN(p->n_type) == CHAR)
- l->n_lval += 3;
- else if (DEUNSIGNED(p->n_type) == SHORT)
- l->n_lval += 2;
- break;
- case LONGLONG:
- case ULONGLONG:
- if (DEUNSIGN(p->n_type) == CHAR)
- l->n_lval += 7;
- else if (DEUNSIGNED(p->n_type) == SHORT)
- l->n_lval += 6;
- else if (DEUNSIGN(p->n_type) == INT ||
- DEUNSIGN(p->n_type) == LONG)
- p->n_lval += 4;
- default:
- comperr("offchg: unknown type");
- break;
- }
-
- return p;
-}
-#endif
-
/* this is called to do local transformations on
* an expression tree preparitory to its being
* written out in intermediate code.
@@ -92,13 +46,45 @@ clocal(NODE *p)
struct symtab *q;
NODE *r, *l;
int o;
- int m, ml;
- TWORD t;
+ int m;
+ TWORD ty;
+ int tmpnr, isptrvoid = 0;
+
+#ifdef PCC_DEBUG
+ if (xdebug) {
+ printf("clocal in: %p\n", p);
+ fwalk(p, eprint, 0);
+ }
+#endif
-//printf("in:\n");
-//fwalk(p, eprint, 0);
+ switch (o = p->n_op) {
- switch( o = p->n_op ){
+ case UCALL:
+ case CALL:
+ case STCALL:
+ case USTCALL:
+ if (p->n_type == VOID)
+ break;
+ /*
+ * if the function returns void*, ecode() invokes
+ * delvoid() to convert it to uchar*.
+ * We just let this happen on the ASSIGN to the temp,
+ * and cast the pointer back to void* on access
+ * from the temp.
+ */
+ if (p->n_type == PTR+VOID)
+ isptrvoid = 1;
+ r = tempnode(0, p->n_type, p->n_df, p->n_sue);
+ tmpnr = r->n_lval;
+ r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_sue);
+
+ p = tempnode(tmpnr, r->n_type, r->n_df, r->n_sue);
+ if (isptrvoid) {
+ p = block(PCONV, p, NIL, PTR+VOID,
+ p->n_df, MKSUE(PTR+VOID));
+ }
+ p = buildtree(COMOP, r, p);
+ break;
case NAME:
if ((q = p->n_sp) == NULL)
@@ -128,7 +114,7 @@ clocal(NODE *p)
p->n_rval = q->soffset;
break;
- }
+ }
break;
case FUNARG:
@@ -156,11 +142,11 @@ clocal(NODE *p)
if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
break;
/* Type must be correct */
- t = r->n_type;
+ ty = r->n_type;
nfree(l->n_left);
l->n_left = r;
- l->n_type = t;
- l->n_right->n_type = t;
+ l->n_type = ty;
+ l->n_right->n_type = ty;
}
#if 0
else if (l->n_right->n_op == SCONV &&
@@ -177,12 +163,32 @@ clocal(NODE *p)
break;
case PCONV:
- ml = p->n_left->n_type;
+ /* Remove redundant PCONV's. Be careful */
l = p->n_left;
- if ((ml == CHAR || ml == UCHAR || ml == SHORT || ml == USHORT)
- && l->n_op != ICON)
+ if (l->n_op == ICON) {
+ l->n_lval = (unsigned)l->n_lval;
+ goto delp;
+ }
+ if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
+ /* 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;
- l->n_type = p->n_type;
+
+ /* 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;
@@ -195,38 +201,57 @@ clocal(NODE *p)
if (p->n_type == l->n_type) {
nfree(p);
- return l;
+ p = l;
+ break;
}
-#ifdef MIPS_BIGENDIAN
- /*
- * If we're big endian, then all OREG loads of a type
- * larger than the destination, must have the
- * offset changed to point to the correct bytes in memory.
- */
- if (l->n_type == OREG)
- p = offchg(p);
-#endif
-
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) {
+ if (l->n_op == NAME || l->n_op == UMUL ||
+ l->n_op == TEMP) {
l->n_type = p->n_type;
nfree(p);
- return l;
+ p = l;
+ break;
}
}
}
- if ((p->n_type == INT || p->n_type == UNSIGNED) &&
- ISPTR(l->n_type)) {
+ if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+ coptype(l->n_op) == BITYPE) {
+ l->n_type = p->n_type;
+ nfree(p);
+ p = l;
+ }
+
+ if (DEUNSIGN(p->n_type) == SHORT &&
+ DEUNSIGN(l->n_type) == SHORT) {
nfree(p);
- return l;
+ p = l;
}
+ /* convert float/double to int before to (u)char/(u)short */
+ if ((DEUNSIGN(p->n_type) == CHAR ||
+ DEUNSIGN(p->n_type) == SHORT) &&
+ (l->n_type == FLOAT || l->n_type == DOUBLE ||
+ l->n_type == LDOUBLE)) {
+ p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
+ p->n_left->n_type = INT;
+ break;
+ }
+
+ /* convert (u)char/(u)short to int before float/double */
+ if ((p->n_type == FLOAT || p->n_type == DOUBLE ||
+ p->n_type == LDOUBLE) && (DEUNSIGN(l->n_type) == CHAR ||
+ DEUNSIGN(l->n_type) == SHORT)) {
+ p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
+ p->n_left->n_type = INT;
+ break;
+ }
+
o = l->n_op;
m = p->n_type;
@@ -274,11 +299,6 @@ clocal(NODE *p)
}
l->n_type = m;
nfree(p);
- return l;
- }
- if (DEUNSIGN(p->n_type) == SHORT &&
- DEUNSIGN(l->n_type) == SHORT) {
- nfree(p);
p = l;
}
break;
@@ -300,7 +320,8 @@ clocal(NODE *p)
case PVCONV:
if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
nfree(p);
- return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
+ p = buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right);
+ break;
case FORCE:
/* put return value in return reg */
@@ -311,8 +332,12 @@ clocal(NODE *p)
break;
}
-//printf("ut:\n");
-//fwalk(p, eprint, 0);
+#ifdef PCC_DEBUG
+ if (xdebug) {
+ printf("clocal out: %p\n", p);
+ fwalk(p, eprint, 0);
+ }
+#endif
return(p);
}
@@ -395,16 +420,15 @@ spalloc(NODE *t, NODE *p, OFFSZ off)
/* 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;
+ sp->n_rval = SP;
t->n_type = sp->n_type;
ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
- /* add the size to sp */
+ /* subtract the size from sp */
sp = block(REG, NIL, NIL, p->n_type, 0, 0);
sp->n_lval = 0;
- sp->n_rval = STKREG;
- ecomp(buildtree(PLUSEQ, sp, p));
+ sp->n_rval = SP;
+ ecomp(buildtree(MINUSEQ, sp, p));
}
/*
@@ -418,7 +442,7 @@ ninval(CONSZ off, int fsz, NODE *p)
struct symtab *q;
TWORD t;
#ifndef USE_GAS
- int i;
+ int i, j;
#endif
t = p->n_type;
@@ -437,12 +461,20 @@ ninval(CONSZ off, int fsz, NODE *p)
#ifdef USE_GAS
printf("\t.dword 0x%llx\n", (long long)p->n_lval);
#else
- i = (p->n_lval >> 32);
- p->n_lval &= 0xffffffff;
+ i = p->n_lval >> 32;
+ j = p->n_lval & 0xffffffff;
p->n_type = INT;
- ninval(off, 32, p);
- p->n_lval = i;
- ninval(off+32, 32, p);
+ if (bigendian) {
+ p->n_lval = j;
+ ninval(off, 32, p);
+ p->n_lval = i;
+ ninval(off+32, 32, p);
+ } else {
+ p->n_lval = i;
+ ninval(off, 32, p);
+ p->n_lval = j;
+ ninval(off+32, 32, p);
+ }
#endif
break;
case BOOL:
@@ -470,14 +502,15 @@ ninval(CONSZ off, int fsz, NODE *p)
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.word\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.word\t0x%x\n", u.i[0]);
- printf("\t.word\t0x%x\n", u.i[1]);
+ if (bigendian) {
+ printf("\t.word\t0x%x\n", u.i[0]);
+ printf("\t.word\t0x%x\n", u.i[1]);
+ } else {
+ printf("\t.word\t0x%x\n", u.i[1]);
+ printf("\t.word\t0x%x\n", u.i[0]);
+ }
break;
case FLOAT:
u.f = (float)p->n_dcon;
@@ -545,9 +578,9 @@ commdec(struct symtab *q)
off = (off+(SZCHAR-1))/SZCHAR;
#ifdef GCC_COMPAT
- printf(" .comm %s,0%o\n", gcc_findname(q), off);
+ printf(" .comm %s,%d\n", gcc_findname(q), off);
#else
- printf(" .comm %s,0%o\n", exname(q->sname), off);
+ printf(" .comm %s,%d\n", exname(q->sname), off);
#endif
}
@@ -561,12 +594,12 @@ lcommdec(struct symtab *q)
off = (off+(SZCHAR-1))/SZCHAR;
if (q->slevel == 0)
#ifdef GCC_COMPAT
- printf("\t.lcomm %s,0%o\n", gcc_findname(q), off);
+ printf("\t.lcomm %s,%d\n", gcc_findname(q), off);
#else
- printf("\t.lcomm %s,0%o\n", exname(q->sname), off);
+ printf("\t.lcomm %s,%d\n", exname(q->sname), off);
#endif
else
- printf("\t.lcomm " LABFMT ",0%o\n", q->soffset, off);
+ printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off);
}
/*
@@ -578,13 +611,14 @@ deflab1(int label)
printf(LABFMT ":\n", label);
}
-static char *loctbl[] = { "text", "data", "bss", "data" };
+/* ro-text, rw-data, ro-data, ro-strings */
+static char *loctbl[] = { "text", "data", "rdata", "rdata" };
void
setloc1(int locc)
{
- //printf("setloc1(%d)\n", locc);
- if ((locc == lastloc) || (lastloc == DATA && locc == STRNG) || (locc == STRNG || lastloc == DATA))
+ if ((locc == lastloc) || (lastloc == DATA && locc == STRNG) ||
+ (locc == STRNG && lastloc == DATA))
return;
lastloc = locc;
printf("\t.%s\n", loctbl[locc]);
@@ -643,3 +677,145 @@ zbits(OFFSZ off, int fsz)
inbits = fsz;
}
}
+
+/*
+ * va_start(ap, last) implementation.
+ *
+ * f is the NAME node for this builtin function.
+ * a is the argument list containing:
+ * CM
+ * ap last
+ *
+ * It turns out that this is easy on MIPS. Just write the
+ * argument registers to the stack in va_arg_start() and
+ * use the traditional method of walking the stackframe.
+ */
+NODE *
+mips_builtin_stdarg_start(NODE *f, NODE *a)
+{
+ NODE *p, *q;
+ int sz = 1;
+ int i;
+
+ /* check num args and type */
+ if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+ !ISPTR(a->n_left->n_type))
+ goto bad;
+
+ /*
+ * look at the offset of the last org to calculate the
+ * number of remain registers that need to be written
+ * to the stack.
+ */
+ if (xtemps) {
+ for (i = 0; i < nargregs; i++) {
+ q = block(REG, NIL, NIL, PTR+INT, 0, MKSUE(INT));
+ q->n_rval = A0 + i;
+ p = block(REG, NIL, NIL, PTR+INT, 0, MKSUE(INT));
+ p->n_rval = SP;
+ p = block(PLUS, p, bcon(ARGINIT+i), PTR+INT, 0, MKSUE(INT));
+ p = buildtree(UMUL, p, NIL);
+ p = buildtree(ASSIGN, p, q);
+ ecomp(p);
+ }
+ }
+
+ /* must first deal with argument size; use int size */
+ p = a->n_right;
+ if (p->n_type < INT) {
+ /* round up to word */
+ sz = SZINT / tsize(p->n_type, p->n_df, p->n_sue);
+ }
+
+ /*
+ * Once again, if xtemps, the register is written to a
+ * temp. We cannot take the address of the temp and
+ * walk from there.
+ *
+ * No solution at the moment...
+ */
+ assert(!xtemps);
+
+ p = buildtree(ADDROF, p, NIL); /* address of last arg */
+ p = optim(buildtree(PLUS, p, bcon(sz)));
+ q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
+ q = buildtree(CAST, q, p);
+ p = q->n_right;
+ nfree(q->n_left);
+ nfree(q);
+ p = buildtree(ASSIGN, a->n_left, p);
+ tfree(f);
+ nfree(a);
+
+ return p;
+
+bad:
+ uerror("bad argument to __builtin_stdarg_start");
+ return bcon(0);
+}
+
+NODE *
+mips_builtin_va_arg(NODE *f, NODE *a)
+{
+ NODE *p, *q, *r;
+ int sz, tmpnr;
+
+ /* check num args and type */
+ if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+ !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
+ goto bad;
+
+ /* create a copy to a temp node */
+ p = tcopy(a->n_left);
+ q = tempnode(0, p->n_type, p->n_df, p->n_sue);
+ tmpnr = q->n_lval;
+ p = buildtree(ASSIGN, q, p);
+
+ r = a->n_right;
+ sz = tsize(r->n_type, r->n_df, r->n_sue) / SZCHAR;
+ if (sz < SZINT/SZCHAR) {
+ werror("%s%s promoted to int when passed through ...",
+ r->n_type & 1 ? "unsigned " : "",
+ DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
+ sz = SZINT/SZCHAR;
+ }
+ q = buildtree(PLUSEQ, a->n_left, bcon(sz));
+ q = buildtree(COMOP, p, q);
+
+ nfree(a->n_right);
+ nfree(a);
+ nfree(f);
+
+ p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_sue);
+ p = buildtree(UMUL, p, NIL);
+ p = buildtree(COMOP, q, p);
+
+ return p;
+
+bad:
+ uerror("bad argument to __builtin_va_arg");
+ return bcon(0);
+}
+
+NODE *
+mips_builtin_va_end(NODE *f, NODE *a)
+{
+ tfree(f);
+ tfree(a);
+ return bcon(0);
+}
+
+NODE *
+mips_builtin_va_copy(NODE *f, NODE *a)
+{
+ if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
+ goto bad;
+ tfree(f);
+ f = buildtree(ASSIGN, a->n_left, a->n_right);
+ nfree(a);
+ return f;
+
+bad:
+ uerror("bad argument to __buildtin_va_copy");
+ return bcon(0);
+}
diff --git a/usr.bin/pcc/mips/local2.c b/usr.bin/pcc/mips/local2.c
index 056762c1d61..1a1dcb0d71e 100644
--- a/usr.bin/pcc/mips/local2.c
+++ b/usr.bin/pcc/mips/local2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: local2.c,v 1.2 2007/11/16 08:34:55 otto Exp $ */
+/* $OpenBSD: local2.c,v 1.3 2007/12/22 14:12:26 stefan Exp $ */
/*
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
@@ -32,11 +32,20 @@
*/
#include <ctype.h>
+#include <string.h>
#include <assert.h>
#include "pass1.h"
#include "pass2.h"
+#ifdef TARGET_BIG_ENDIAN
+int bigendian = 1;
+#else
+int bigendian = 0;
+#endif
+
+int nargregs = MIPS_O32_NARGREGS;
+
static int argsiz(NODE * p);
void
@@ -65,6 +74,10 @@ offcalc(struct interpass_prolog * ipp)
}
}
+ /* round to 8-byte boundary */
+ addto += 7;
+ addto &= ~7;
+
return addto;
}
@@ -85,28 +98,26 @@ prologue(struct interpass_prolog * ipp)
printf("%s:\n", ipp->ipp_name);
addto = offcalc(ipp);
-#ifdef USE_GAS
- if (kflag) {
- printf("\t.frame %s,%d,%s\n", rnames[FP], 12, rnames[RA]);
- printf("\t.set noreorder\n");
- printf("\t.cpload $25 # pseudo-op to load GOT ptr into $25\n");
- printf("\t.set reorder\n");
- }
-#endif
- printf("\taddi %s,%s,-%d\n", rnames[SP], rnames[SP], 12);
-#ifdef USE_GAS
- if (kflag)
- printf("\t.cprestore 8 # pseudo-op to store GOT ptr at 8(sp)\n");
-#endif
- printf("\tsw %s,%d(%s)\n", rnames[RA], 4, rnames[SP]);
- printf("\tsw %s,0(%s)\n", rnames[FP], rnames[SP]);
+
+ /* for the moment, just emit this PIC stuff - NetBSD does it */
+ printf("\t.frame %s,%d,%s\n", rnames[FP], ARGINIT/SZCHAR, rnames[RA]);
+ printf("\t.set noreorder\n");
+ printf("\t.cpload $25\t# pseudo-op to load GOT ptr into $25\n");
+ printf("\t.set reorder\n");
+
+ printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], ARGINIT/SZCHAR);
+ /* for the moment, just emit PIC stuff - NetBSD does it */
+ printf("\t.cprestore 8\t# pseudo-op to store GOT ptr at 8(sp)\n");
+
+ printf("\tsw %s,4(%s)\n", rnames[RA], rnames[SP]);
+ printf("\tsw %s,(%s)\n", rnames[FP], rnames[SP]);
printf("\tmove %s,%s\n", rnames[FP], rnames[SP]);
if (addto)
- printf("\taddi %s,%s,-%d\n", rnames[SP], rnames[SP], addto);
+ printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], addto);
for (i = ipp->ipp_regs, j = 0; i; i >>= 1, j++)
if (i & 1)
- fprintf(stdout, "\tsw %s,-%d(%s) # save permanents\n",
+ fprintf(stdout, "\tsw %s,-%d(%s) # save permanent\n",
rnames[j], regoff[j], rnames[FP]);
}
@@ -115,15 +126,8 @@ eoftn(struct interpass_prolog * ipp)
{
int i, j;
int addto;
- int off;
addto = offcalc(ipp);
- off = 8;
-
-#ifdef USE_GAS
- if (kflag)
- off += 4;
-#endif
if (ipp->ipp_ip.ip_lbl == 0)
return; /* no code needs to be generated */
@@ -131,21 +135,17 @@ eoftn(struct interpass_prolog * ipp)
/* return from function code */
for (i = ipp->ipp_regs, j = 0; i; i >>= 1, j++) {
if (i & 1)
- fprintf(stdout, "\tlw %s,-%d(%s)\n",
+ fprintf(stdout, "\tlw %s,-%d(%s)\n\tnop\n",
rnames[j], regoff[j], rnames[FP]);
}
- printf("\tlw %s,%d($sp)\n", rnames[RA], addto + 4);
- printf("\tlw %s,%d($sp)\n", rnames[FP], addto);
- printf("\taddi %s,%s,%d\n", rnames[SP], rnames[SP], addto + off);
+ printf("\taddu %s,%s,%d\n", rnames[SP], rnames[FP], ARGINIT/SZCHAR);
+ printf("\tlw %s,%d(%s)\n", rnames[RA], 4-ARGINIT/SZCHAR, rnames[SP]);
+ printf("\tlw %s,%d(%s)\n", rnames[FP], 0-ARGINIT/SZCHAR, rnames[SP]);
+
+ printf("\tjr %s\n", rnames[RA]);
+ printf("\tnop\n");
- /* struct return needs special treatment */
- if (ftype == STRTY || ftype == UNIONTY) {
- /* XXX - implement struct return support. */
- } else {
- printf("\tjr %s\n", rnames[RA]);
- printf("\tnop\n");
- }
#ifdef USE_GAS
printf("\t.end %s\n", ipp->ipp_name);
printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name);
@@ -169,23 +169,27 @@ hopcode(int f, int o)
case NE:
str = "bnez"; /* pseudo-op */
break;
+ case ULE:
case LE:
str = "blez";
break;
+ case ULT:
case LT:
str = "bltz";
break;
+ case UGE:
case GE:
str = "bgez";
break;
+ case UGT:
case GT:
str = "bgtz";
break;
case PLUS:
- str = "addu";
+ str = "add";
break;
case MINUS:
- str = "subu";
+ str = "sub";
break;
case AND:
str = "and";
@@ -205,7 +209,7 @@ hopcode(int f, int o)
}
char *
-rnames[] = { /* keyed to register number tokens */
+rnames[] = {
#ifdef USE_GAS
/* gnu assembler */
"$zero", "$at", "$2", "$3", "$4", "$5", "$6", "$7",
@@ -213,31 +217,51 @@ rnames[] = { /* keyed to register number tokens */
"$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
"$24", "$25",
"$kt0", "$kt1", "$gp", "$sp", "$fp", "$ra",
- "$2\0$3\0",
- "$4\0$5\0", "$5\0$6\0", "$6\0$7\0", "$7\0$8\0",
- "$8\0$9", "$9\0$10", "$10$11", "$11$12", "$12$13", "$13$14", "$14$15",
- "$24$25",
- "$16$17", "$17$18", "$18$19", "$19$20", "$2021", "$21$22", "$22$23",
+ "$2!!$3!!",
+ "$4!!$5!!", "$5!!$6!!", "$6!!$7!!", "$7!!$8!!",
+ "$8!!$9!!", "$9!!$10!", "$10!$11!", "$11!$12!",
+ "$12!$13!", "$13!$14!", "$14!$15!", "$15!$24!", "$24!$25!",
+ "$16!$17!", "$17!$18!", "$18!$19!", "$19!$20!",
+ "$20!$21!", "$21!$22!", "$22!$23!",
#else
/* mips assembler */
"$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
-#if defined(MIPS_N32) || defined(MIPS_N64)
- "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3",
-#else
"$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
-#endif
"$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
"$t8", "$t9",
"$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
- "$v0$v1",
- "$a0a1", "$a1$a2", "$a2$a3", "$a3$t0",
- "$t0t1", "$t1$t2", "$t2$t3", "$t3$t4", "$t4t5", "$t5t6", "$t6t7",
- "$t8t9",
- "$s0s1", "$s1$s2", "$s2$s3", "$s3$s4", "$s4$s5", "$s5$s6", "$s6s7",
+ "$v0!$v1!",
+ "$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$t0!",
+ "$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t4!",
+ "$t4!$t5!", "$t5!$t6!", "$t6!$t7!", "$t7!$t8!", "$t8!$t9!",
+ "$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!",
+ "$s4!$s5!", "$s5!$s6!", "$s6!$s7!",
#endif
- "$f0", "$f1", "$f2",
+ "$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!",
+ "$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15",
+ "$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23",
+ "$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31",
};
+char *
+rnames_n32[] = {
+ /* mips assembler */
+ "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
+ "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3",
+ "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
+ "$t8", "$t9",
+ "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
+ "$v0!$v1!",
+ "$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$a4!",
+ "$a4!$a5!", "$a5!$a6!", "$a6!$a7!", "$a7!$t0!",
+ "$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t8!", "$t8!$t9!",
+ "$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!",
+ "$s4!$s5!", "$s5!$s6!", "$s6!$s7!",
+ "$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!",
+ "$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15",
+ "$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23",
+ "$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31",
+};
int
tlen(NODE *p)
@@ -272,18 +296,22 @@ tlen(NODE *p)
}
-#if 0
/*
* Push a structure on stack as argument.
- * the scratch registers are already free here
*/
static void
-starg(NODE * p)
+starg(NODE *p)
{
- if (p->n_left->n_op == REG && p->n_left->n_type == PTR + STRTY)
- return; /* already on stack */
+ //assert(p->n_rval == A1);
+ printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], p->n_stsize);
+ /* A0 = dest, A1 = src, A2 = len */
+ printf("\tmove %s,%s\n", rnames[A0], rnames[SP]);
+ printf("\tli %s,%d\t# structure size\n", rnames[A2], p->n_stsize);
+ printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
+ printf("\tjal %s\t# structure copy\n", exname("memcpy"));
+ printf("\tnop\n");
+ printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
}
-#endif
/*
* Structure assignment.
@@ -293,10 +321,9 @@ stasg(NODE *p)
{
assert(p->n_right->n_rval == A1);
/* A0 = dest, A1 = src, A2 = len */
- printf("\tli %s,%d # structure size\n",
- rnames[A2], p->n_stsize);
+ printf("\tli %s,%d\t# structure size\n", rnames[A2], p->n_stsize);
if (p->n_left->n_op == OREG) {
- printf("\taddi %s,%s," CONFMT " # dest address\n",
+ printf("\taddi %s,%s," CONFMT "\t# dest address\n",
rnames[A0], rnames[p->n_left->n_rval],
p->n_left->n_lval);
} else if (p->n_left->n_op == NAME) {
@@ -304,58 +331,335 @@ stasg(NODE *p)
adrput(stdout, p->n_left);
printf("\n");
}
- printf("\taddi %s,%s,-16\n", rnames[SP], rnames[SP]);
- printf("\tbl %s # structure copy\n",
- exname("memcpy"));
+ printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
+ printf("\tjal %s\t# structure copy\n", exname("memcpy"));
printf("\tnop\n");
- printf("\taddi %s,%s,16\n", rnames[SP], rnames[SP]);
+ printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
}
static void
-llshiftop(NODE *p)
+shiftop(NODE *p)
{
- assert(p->n_right->n_op == ICON);
+ NODE *r = p->n_right;
+ TWORD ty = p->n_type;
- if (p->n_op == LS && p->n_right->n_lval < 32) {
- expand(p, INBREG, "\tsrl A1,AL,32-AR ; 64-bit left-shift\n");
+ if (p->n_op == LS && r->n_op == ICON && r->n_lval < 32) {
+ expand(p, INBREG, "\tsrl A1,AL,");
+ printf(CONFMT "\t# 64-bit left-shift\n", 32 - r->n_lval);
expand(p, INBREG, "\tsll U1,UL,AR\n");
expand(p, INBREG, "\tor U1,U1,A1\n");
expand(p, INBREG, "\tsll A1,AL,AR\n");
- } else if (p->n_op == LS) {
- expand(p, INBREG, "\tli A1,0 ; 64-bit left-shift\n");
- expand(p, INBREG, "\tsll U1,AL,AR-32\n");
- } else if (p->n_op == RS && p->n_right->n_lval < 32) {
- expand(p, INBREG, "\tsll U1,UL,32-AR ; 64-bit right-shift\n");
+ } else if (p->n_op == LS && r->n_op == ICON && r->n_lval < 64) {
+ expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n");
+ expand(p, INBREG, "\tsll U1,AL,");
+ printf(CONFMT "\n", r->n_lval - 32);
+ } else if (p->n_op == LS && r->n_op == ICON) {
+ expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n");
+ expand(p, INBREG, "\tli U1,0\n");
+ } else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 32) {
+ expand(p, INBREG, "\tsll U1,UL,");
+ printf(CONFMT "\t# 64-bit right-shift\n", 32 - r->n_lval);
expand(p, INBREG, "\tsrl A1,AL,AR\n");
expand(p, INBREG, "\tor A1,A1,U1\n");
- expand(p, INBREG, "\tsrl U1,UL,AR\n");
- } else if (p->n_op == RS) {
- expand(p, INBREG, "\tli U1,0 ; 64-bit right-shift\n");
- expand(p, INBREG, "\tsrl A1,UL,AR-32\n");
+ if (ty == LONGLONG)
+ expand(p, INBREG, "\tsra U1,UL,AR\n");
+ else
+ expand(p, INBREG, "\tsrl U1,UL,AR\n");
+ } else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 64) {
+ if (ty == LONGLONG) {
+ expand(p, INBREG, "\tli U1,-1\t# 64-bit right-shift\n");
+ expand(p, INBREG, "\tsra A1,UL,");
+ }else {
+ expand(p, INBREG, "\tli U1,0\t# 64-bit right-shift\n");
+ expand(p, INBREG, "\tsrl A1,UL,");
+ }
+ printf(CONFMT "\n", r->n_lval - 32);
+ } else if (p->n_op == LS && r->n_op == ICON) {
+ expand(p, INBREG, "\tli A1,0\t# 64-bit right-shift\n");
+ expand(p, INBREG, "\tli U1,0\n");
}
}
/*
- * Emulate unsupported instruction.
+ * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
+ */
+static void
+fpemulop(NODE *p)
+{
+ NODE *l = p->n_left;
+ char *ch = NULL;
+
+ if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3";
+ else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3";
+ else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3";
+
+ else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3";
+ else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3";
+ else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3";
+
+ else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3";
+ else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3";
+ else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3";
+
+ else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3";
+ else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3";
+ else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3";
+
+ else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2";
+ else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2";
+ else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2";
+
+ else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2";
+ else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2";
+ else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2";
+
+ else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2";
+ else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2";
+ else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2";
+
+ else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2";
+ else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2";
+ else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2";
+
+ else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2";
+ else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2";
+ else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2";
+
+ else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2";
+ else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2";
+ else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2";
+
+ else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2";
+ else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2";
+ else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2";
+
+ else if (p->n_op == SCONV && p->n_type == FLOAT) {
+ if (l->n_type == DOUBLE) ch = "truncdfsf2";
+ else if (l->n_type == LDOUBLE) ch = "trunctfsf2";
+ else if (l->n_type == ULONGLONG) ch = "floatdisf"; /**/
+ else if (l->n_type == LONGLONG) ch = "floatdisf";
+ else if (l->n_type == LONG) ch = "floatsisf";
+ else if (l->n_type == ULONG) ch = "floatunsisf";
+ else if (l->n_type == INT) ch = "floatsisf";
+ else if (l->n_type == UNSIGNED) ch = "floatunsisf";
+ } else if (p->n_op == SCONV && p->n_type == DOUBLE) {
+ if (l->n_type == FLOAT) ch = "extendsfdf2";
+ else if (l->n_type == LDOUBLE) ch = "trunctfdf2";
+ else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+ else if (l->n_type == LONGLONG) ch = "floatdidf";
+ else if (l->n_type == LONG) ch = "floatsidf";
+ else if (l->n_type == ULONG) ch = "floatunsidf";
+ else if (l->n_type == INT) ch = "floatsidf";
+ else if (l->n_type == UNSIGNED) ch = "floatunsidf";
+ } else if (p->n_op == SCONV && p->n_type == LDOUBLE) {
+ if (l->n_type == FLOAT) ch = "extendsftf2";
+ else if (l->n_type == DOUBLE) ch = "extenddfdf2";
+ else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+ else if (l->n_type == LONGLONG) ch = "floatdidf";
+ else if (l->n_type == LONG) ch = "floatsidf";
+ else if (l->n_type == ULONG) ch = "floatunssidf";
+ else if (l->n_type == INT) ch = "floatsidf";
+ else if (l->n_type == UNSIGNED) ch = "floatunsidf";
+ } else if (p->n_op == SCONV && p->n_type == ULONGLONG) {
+ if (l->n_type == FLOAT) ch = "fixunssfdi";
+ else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
+ else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
+ } else if (p->n_op == SCONV && p->n_type == LONGLONG) {
+ if (l->n_type == FLOAT) ch = "fixsfdi";
+ else if (l->n_type == DOUBLE) ch = "fixdfdi";
+ else if (l->n_type == LDOUBLE) ch = "fixdfdi";
+ } else if (p->n_op == SCONV && p->n_type == LONG) {
+ if (l->n_type == FLOAT) ch = "fixsfsi";
+ else if (l->n_type == DOUBLE) ch = "fixdfsi";
+ else if (l->n_type == LDOUBLE) ch = "fixdfsi";
+ } else if (p->n_op == SCONV && p->n_type == ULONG) {
+ if (l->n_type == FLOAT) ch = "fixunssfsi";
+ else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
+ else if (l->n_type == LDOUBLE) ch = "fixunsdfsi";
+ } else if (p->n_op == SCONV && p->n_type == INT) {
+ if (l->n_type == FLOAT) ch = "fixsfsi";
+ else if (l->n_type == DOUBLE) ch = "fixdfsi";
+ else if (l->n_type == LDOUBLE) ch = "fixdfsi";
+ } else if (p->n_op == SCONV && p->n_type == UNSIGNED) {
+ if (l->n_type == FLOAT) ch = "fixunssfsi";
+ else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
+ else if (l->n_type == LDOUBLE) ch = "fixunsdfsi";
+ }
+
+ if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op);
+
+ printf("\tjal __%s\t# softfloat operation\n", exname(ch));
+ printf("\tnop\n");
+
+ if (p->n_op >= EQ && p->n_op <= GT)
+ printf("\tcmp %s,0\n", rnames[V0]);
+}
+
+/*
+ * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
*/
static void
emulop(NODE *p)
{
- char *ch;
+ char *ch = NULL;
+
+ if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3";
+ else if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG ||
+ DEUNSIGN(p->n_type) == INT))
+ ch = "ashlsi3";
+
+ else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3";
+ else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == INT))
+ ch = "lshrsi3";
+
+ else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3";
+ else if (p->n_op == RS && (p->n_type == LONG || p->n_type == INT))
+ ch = "ashrsi3";
+
+ else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3";
+ else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == INT))
+ ch = "divsi3";
+
+ else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3";
+ else if (p->n_op == DIV && (p->n_type == ULONG ||
+ p->n_type == UNSIGNED))
+ ch = "udivsi3";
+
+ else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3";
+ else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == INT))
+ ch = "modsi3";
+
+ else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3";
+ else if (p->n_op == MOD && (p->n_type == ULONG ||
+ p->n_type == UNSIGNED))
+ ch = "umodsi3";
+
+ else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3";
+ else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == INT))
+ ch = "mulsi3";
+
+ else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2";
+ else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2";
- 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("ZE");
- printf("\taddi %s,%s,-16\n", rnames[SP], rnames[SP]);
- printf("\tbl __%sdi3\n", ch);
+ printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
+ printf("\tjal __%s\t# emulated operation\n", exname(ch));
printf("\tnop\n");
- printf("\taddi %s,%s,16\n", rnames[SP], rnames[SP]);
+ printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
+}
+
+/*
+ * 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, "\tsub A1,UL,UR\t# compare 64-bit values (upper)\n");
+ if (cb1) {
+ printf("\t");
+ hopcode(' ', cb1);
+ expand(p, 0, "A1");
+ printf("," LABFMT "\n", s);
+ printf("\tnop\n");
+ }
+ if (cb2) {
+ printf("\t");
+ hopcode(' ', cb2);
+ expand(p, 0, "A1");
+ printf("," LABFMT "\n", e);
+ printf("\tnop\n");
+ }
+ expand(p, 0, "\tsub A1,AL,AR\t# (and lower)\n");
+ printf("\t");
+ hopcode(' ', o);
+ expand(p, 0, "A1");
+ printf("," LABFMT "\n", e);
+ printf("\tnop\n");
+ deflab(s);
+}
+
+static void
+fpcmpops(NODE *p)
+{
+ NODE *l = p->n_left;
+
+ switch (p->n_op) {
+ case EQ:
+ if (l->n_type == FLOAT)
+ expand(p, 0, "\tc.eq.s AL,AR\n");
+ else
+ expand(p, 0, "\tc.eq.d AL,AR\n");
+ expand(p, 0, "\tnop\n\tbc1t LC\n");
+ break;
+ case NE:
+ if (l->n_type == FLOAT)
+ expand(p, 0, "\tc.eq.s AL,AR\n");
+ else
+ expand(p, 0, "\tc.eq.d AL,AR\n");
+ expand(p, 0, "\tnop\n\tbc1f LC\n");
+ break;
+ case LT:
+ if (l->n_type == FLOAT)
+ expand(p, 0, "\tc.lt.s AL,AR\n");
+ else
+ expand(p, 0, "\tc.lt.d AL,AR\n");
+ expand(p, 0, "\tnop\n\tbc1t LC\n");
+ break;
+ case GE:
+ if (l->n_type == FLOAT)
+ expand(p, 0, "\tc.lt.s AL,AR\n");
+ else
+ expand(p, 0, "\tc.lt.d AL,AR\n");
+ expand(p, 0, "\tnop\n\tbc1f LC\n");
+ break;
+ case LE:
+ if (l->n_type == FLOAT)
+ expand(p, 0, "\tc.le.s AL,AR\n");
+ else
+ expand(p, 0, "\tc.le.d AL,AR\n");
+ expand(p, 0, "\tnop\n\tbc1t LC\n");
+ break;
+ case GT:
+ if (l->n_type == FLOAT)
+ expand(p, 0, "\tc.le.s AL,AR\n");
+ else
+ expand(p, 0, "\tc.le.d AL,AR\n");
+ expand(p, 0, "\tnop\n\tbc1f LC\n");
+ break;
+ }
+ printf("\tnop\n\tnop\n");
}
void
@@ -367,8 +671,28 @@ zzzcode(NODE * p, int c)
case 'C': /* remove arguments from stack after subroutine call */
sz = p->n_qual > 16 ? p->n_qual : 16;
- printf("\taddi %s,%s,%d\n",
- rnames[STKREG], rnames[STKREG], sz);
+ printf("\taddiu %s,%s,%d\n",
+ rnames[SP], rnames[SP], sz);
+ break;
+
+ case 'D': /* long long comparison */
+ twollcomp(p);
+ break;
+
+ case 'E': /* emit emulated ops */
+ emulop(p);
+ break;
+
+ case 'F': /* emit emulate floating point ops */
+ fpemulop(p);
+ break;
+
+ case 'G': /* emit hardware floating-point compare op */
+ fpcmpops(p);
+ break;
+
+ case 'H': /* structure argument */
+ starg(p);
break;
case 'I': /* high part of init constant */
@@ -377,16 +701,12 @@ zzzcode(NODE * p, int c)
fprintf(stdout, CONFMT, (p->n_lval >> 32) & 0xffffffff);
break;
- case 'Q': /* emit struct assign */
- stasg(p);
- break;
-
case 'O': /* 64-bit left and right shift operators */
- llshiftop(p);
+ shiftop(p);
break;
- case 'E': /* emit emulated ops */
- emulop(p);
+ case 'Q': /* emit struct assign */
+ stasg(p);
break;
default:
@@ -461,16 +781,14 @@ adrcon(CONSZ val)
void
conput(FILE * fp, NODE * p)
{
- int val = p->n_lval;
-
switch (p->n_op) {
case ICON:
if (p->n_name[0] != '\0') {
fprintf(fp, "%s", p->n_name);
- if (val)
- fprintf(fp, "+%d", val);
+ if (p->n_lval)
+ fprintf(fp, "+%d", (int)p->n_lval);
} else
- fprintf(fp, "%d", val);
+ fprintf(fp, CONFMT, p->n_lval & 0xffffffff);
return;
default:
@@ -491,13 +809,16 @@ insput(NODE * p)
static void
print_reg64name(FILE *fp, int rval, int hi)
{
- int off = 3 * (hi != 0);
+ int off = 4 * (hi != 0);
+ char *regname = rnames[rval];
fprintf(fp, "%c%c",
- rnames[rval][off],
- rnames[rval][off + 1]);
- if (rnames[rval][off + 2])
- fputc(rnames[rval][off + 2], fp);
+ regname[off],
+ regname[off + 1]);
+ if (regname[off + 2] != '!')
+ fputc(regname[off + 2], fp);
+ if (regname[off + 3] != '!')
+ fputc(regname[off + 3], fp);
}
/*
@@ -511,7 +832,10 @@ upput(NODE * p, int size)
size /= SZCHAR;
switch (p->n_op) {
case REG:
- print_reg64name(stdout, p->n_rval, 1);
+ if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC)
+ print_reg64name(stdout, p->n_rval, 1);
+ else
+ fputs(rnames[p->n_rval], stdout);
break;
case NAME:
@@ -556,13 +880,12 @@ adrput(FILE * io, NODE * p)
return;
case ICON:
/* addressable value of the constant */
- //fputc('$', io);
conput(io, p);
return;
case MOVE:
case REG:
- if (DEUNSIGN(p->n_type) == LONGLONG)
+ if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC)
print_reg64name(io, p->n_rval, 0);
else
fputs(rnames[p->n_rval], io);
@@ -587,6 +910,55 @@ myreader(struct interpass * ipole)
}
/*
+ * If we're big endian, then all OREG loads of a type
+ * larger than the destination, must have the
+ * offset changed to point to the correct bytes in memory.
+ */
+static void
+offchg(NODE *p)
+{
+ NODE *l;
+
+ if (p->n_op != SCONV)
+ return;
+
+ l = p->n_left;
+
+ if (l->n_op != OREG)
+ return;
+
+ switch (l->n_type) {
+ case SHORT:
+ case USHORT:
+ if (DEUNSIGN(p->n_type) == CHAR)
+ l->n_lval += 1;
+ break;
+ case LONG:
+ case ULONG:
+ case INT:
+ case UNSIGNED:
+ if (DEUNSIGN(p->n_type) == CHAR)
+ l->n_lval += 3;
+ else if (DEUNSIGN(p->n_type) == SHORT)
+ l->n_lval += 2;
+ break;
+ case LONGLONG:
+ case ULONGLONG:
+ if (DEUNSIGN(p->n_type) == CHAR)
+ l->n_lval += 7;
+ else if (DEUNSIGN(p->n_type) == SHORT)
+ l->n_lval += 6;
+ else if (DEUNSIGN(p->n_type) == INT ||
+ DEUNSIGN(p->n_type) == LONG)
+ l->n_lval += 4;
+ break;
+ default:
+ comperr("offchg: unknown type");
+ break;
+ }
+}
+
+/*
* Remove some PCONVs after OREGs are created.
*/
static void
@@ -619,8 +991,16 @@ mycanon(NODE * p)
}
void
-myoptim(struct interpass * ip)
+myoptim(struct interpass * ipole)
{
+ struct interpass *ip;
+
+ DLIST_FOREACH(ip, ipole, qelem) {
+ if (ip->type != IP_NODE)
+ continue;
+ if (bigendian)
+ walkf(ip->ip_node, offchg);
+ }
}
/*
@@ -637,29 +1017,42 @@ rmove(int s, int d, TWORD t)
/* dh = sl, copy low word first */
printf("\tmove ");
print_reg64name(stdout, d, 0);
+ printf(",");
print_reg64name(stdout, s, 0);
+ printf("\t# 64-bit rmove\n");
printf("\tmove ");
print_reg64name(stdout, d, 1);
+ printf(",");
print_reg64name(stdout, s, 1);
+ printf("\n");
} else {
/* copy high word first */
printf("\tmove ");
print_reg64name(stdout, d, 1);
+ printf(",");
print_reg64name(stdout, s, 1);
+ printf(" # 64-bit rmove\n");
printf("\tmove ");
print_reg64name(stdout, d, 0);
+ printf(",");
print_reg64name(stdout, s, 0);
+ printf("\n");
}
- printf("\n");
break;
+ case FLOAT:
+ case DOUBLE:
case LDOUBLE:
-#ifdef notdef
- /* a=b()*c(); will generate this */
- comperr("bad float rmove: %d %d", s, d);
-#endif
+ if (t == FLOAT)
+ printf("\tmov.s ");
+ else
+ printf("\tmov.d ");
+ print_reg64name(stdout, d, 0);
+ printf(",");
+ print_reg64name(stdout, s, 0);
+ printf("\t# float/double rmove\n");
break;
default:
- printf("\tmove %s,%s\n", rnames[d], rnames[s]);
+ printf("\tmove %s,%s\t#default rmove\n", rnames[d], rnames[s]);
}
}
@@ -672,7 +1065,7 @@ rmove(int s, int d, TWORD t)
*
* 32 32-bit registers (8 reserved)
* 26 64-bit pseudo registers (1 unavailable)
- * 3? floating-point registers
+ * 16 floating-point register pairs
*/
int
COLORMAP(int c, int *r)
@@ -690,9 +1083,9 @@ COLORMAP(int c, int *r)
return num < 25;
case CLASSC:
num += r[CLASSC];
- return num < 3;
+ return num < 6;
}
- assert(0);
+ comperr("COLORMAP");
return 0; /* XXX gcc */
}
@@ -702,6 +1095,10 @@ COLORMAP(int c, int *r)
int
gclass(TWORD t)
{
+ if (t == LONGLONG || t == ULONGLONG)
+ return CLASSB;
+ if (t >= FLOAT && t <= LDOUBLE)
+ return CLASSC;
return CLASSA;
}
@@ -735,10 +1132,9 @@ argsiz(NODE * p)
if (t < LONGLONG || t == FLOAT || t > BTMASK)
return 4;
- if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
+ if (t == LONGLONG || t == ULONGLONG ||
+ t == DOUBLE || t == LDOUBLE)
return 8;
- if (t == LDOUBLE)
- return 12;
if (t == STRTY || t == UNIONTY)
return p->n_stsize;
comperr("argsiz");
@@ -749,7 +1145,44 @@ argsiz(NODE * p)
* Special shapes.
*/
int
-special(NODE * p, int shape)
+special(NODE *p, int shape)
{
+ int o = p->n_op;
+ switch(shape) {
+ case SPCON:
+ if (o == ICON && p->n_name[0] == 0 &&
+ (p->n_lval & ~0xffff) == 0)
+ return SRDIR;
+ break;
+ }
+
return SRNOPE;
}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+ if (strcasecmp(str, "big-endian") == 0) {
+ bigendian = 1;
+ } else if (strcasecmp(str, "little-endian") == 0) {
+ bigendian = 0;
+ }
+#if 0
+ else if (strcasecmp(str, "ips2")) {
+ } else if (strcasecmp(str, "ips2")) {
+ } else if (strcasecmp(str, "ips3")) {
+ } else if (strcasecmp(str, "ips4")) {
+ } else if (strcasecmp(str, "hard-float")) {
+ } else if (strcasecmp(str, "soft-float")) {
+ } else if (strcasecmp(str, "abi=32")) {
+ nargregs = MIPS_O32_NARGREGS;
+ } else if (strcasecmp(str, "abi=n32")) {
+ nargregs = MIPS_N32_NARGREGS;
+ } else if (strcasecmp(str, "abi=64")) {
+ nargregs = MIPS_N32_NARGREGS;
+ }
+#endif
+}
diff --git a/usr.bin/pcc/mips/macdefs.h b/usr.bin/pcc/mips/macdefs.h
index 20f0cf37d02..7474f6d8a06 100644
--- a/usr.bin/pcc/mips/macdefs.h
+++ b/usr.bin/pcc/mips/macdefs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: macdefs.h,v 1.2 2007/11/16 08:34:55 otto Exp $ */
+/* $OpenBSD: macdefs.h,v 1.3 2007/12/22 14:12:26 stefan Exp $ */
/*
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
@@ -46,7 +46,7 @@
*/
#define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24);
-#define ARGINIT (12*8) /* # bits above fp where arguments start */
+#define ARGINIT (16*8) /* # bits above fp where arguments start */
#define AUTOINIT (0) /* # bits below fp where automatics start */
/*
@@ -57,7 +57,7 @@
#define SZINT 32
#define SZFLOAT 32
#define SZDOUBLE 64
-#define SZLDOUBLE 128
+#define SZLDOUBLE 64
#define SZLONG 32
#define SZSHORT 16
#define SZLONGLONG 64
@@ -69,15 +69,15 @@
#define ALCHAR 8
#define ALBOOL 32
#define ALINT 32
-#define ALFLOAT 32
-#define ALDOUBLE 32
-#define ALLDOUBLE 32
+#define ALFLOAT 64
+#define ALDOUBLE 64
+#define ALLDOUBLE 64
#define ALLONG 32
-#define ALLONGLONG 32
+#define ALLONGLONG 64
#define ALSHORT 16
#define ALPOINT 32
#define ALSTRUCT 32
-#define ALSTACK 32
+#define ALSTACK 64
/*
* Min/max values.
@@ -99,7 +99,6 @@
#define MAX_ULONGLONG 0xffffffffffffffffULL
#undef CHAR_UNSIGNED
-#define TARGET_STDARGS
#define BOOL_TYPE INT
#define WCHAR_TYPE INT
@@ -146,11 +145,11 @@ typedef long long OFFSZ;
#define A1 5
#define A2 6
#define A3 7
-#if defined(MIPS_N32) || defined(MIPS_N64)
#define A4 8
#define A5 9
#define A6 10
#define A7 11
+#if defined(MIPS_N32) || defined(MIPS_N64)
#define T0 12
#define T1 13
#define T2 14
@@ -160,11 +159,11 @@ typedef long long OFFSZ;
#define T1 9
#define T2 10
#define T3 11
+#endif
#define T4 12
#define T5 13
#define T6 14
#define T7 15
-#endif
#define S0 16
#define S1 17
#define S2 18
@@ -186,15 +185,9 @@ typedef long long OFFSZ;
#define A0A1 33
#define A1A2 34
#define A2A3 35
-#if defined(MIPS_N32) || defined(MIPS_N64)
-#define A3A4 36
-#define A4A5 37
-#define A5A6 38
-#define A6A7 39
-#define T0T1 41
-#define T1T2 42
-#define T2T3 43
-#else
+
+/* we just use o32 naming here, but it works ok for n32/n64 */
+#define A3T0 36
#define T0T1 37
#define T1T2 38
#define T2T3 39
@@ -202,32 +195,45 @@ typedef long long OFFSZ;
#define T4T5 41
#define T5T6 42
#define T6T7 43
-#endif
-#define T8T9 44
-#define S0S1 45
-#define S1S2 46
-#define S2S3 47
-#define S3S4 48
-#define S4S5 49
-#define S5S6 50
-#define S6S7 51
-
-#define F0 52
-#define F1 53
+#define T7T8 44
+
+#define T8T9 45
+#define S0S1 46
+#define S1S2 47
+#define S2S3 48
+#define S3S4 49
+#define S4S5 50
+#define S5S6 51
+#define S6S7 52
+
+#define F0 53
#define F2 54
+#define F4 55
+#define F6 56
+#define F8 57
+#define F10 58
+#define F12 59
+#define F14 60
+#define F16 61
+#define F18 62
+#define F20 63
+/* and the rest for later */
+#define F22 64
+#define F24 65
+#define F26 66
+#define F28 67
+#define F30 68
-#define MAXREGS 55
+#define MAXREGS 64
#define NUMCLASS 3
-#define RETREG(x) ((x) == ULONGLONG || (x) == LONGLONG ? V0V1 : V0)
+#define RETREG(x) (DEUNSIGN(x) == LONGLONG ? V0V1 : \
+ (x) == DOUBLE || (x) == LDOUBLE || (x) == FLOAT ? \
+ F0 : V0)
#define FPREG FP /* frame pointer */
-#define STKREG SP
-#if defined(MIPS_N32) || defined(MIPS_N64)
-#define MIPS_NARGREGS 8
-#else
-#define MIPS_NARGREGS 4
-#endif
+#define MIPS_N32_NARGREGS 8
+#define MIPS_O32_NARGREGS 4
#define RSTATUS \
0, 0, \
@@ -243,65 +249,70 @@ typedef long long OFFSZ;
\
SBREG|TEMPREG, \
SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \
- SBREG|TEMPREG, /* only available on n32/n64 */ \
- SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \
- SBREG|TEMPREG, /* only available on o32 */ \
- SBREG|TEMPREG, \
+ SBREG|TEMPREG, \
SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \
+ SBREG|TEMPREG, SBREG|TEMPREG, \
+ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \
SBREG, SBREG, SBREG, SBREG, \
SBREG, SBREG, SBREG, \
- SCREG, SCREG, SCREG
+ SCREG, SCREG, SCREG, SCREG, \
+ SCREG, SCREG, SCREG, SCREG, \
+ SCREG, SCREG, SCREG, \
#define ROVERLAP \
- { -1 }, { -1 }, \
- { V0V1, -1 }, { V0V1, -1 }, \
- { A0A1, -1 }, \
- { A0A1, A1A2, -1 }, \
- { A1A2, A2A3, -1 }, \
- { A2A3, -1 }, \
+ { -1 }, /* $zero */ \
+ { -1 }, /* $at */ \
+ { V0V1, -1 }, /* $v0 */ \
+ { V0V1, -1 }, /* $v1 */ \
+ { A0A1, -1 }, /* $a0 */ \
+ { A0A1, A1A2, -1 }, /* $a1 */ \
+ { A1A2, A2A3, -1 }, /* $a2 */ \
+ { A2A3, A3T0, -1 }, /* $a3 */ \
+ { A3T0, T0T1, -1 }, /* $t0 */ \
+ { T0T1, T1T2, -1 }, /* $t1 */ \
+ { T1T2, T2T3, -1 }, /* $t2 */ \
+ { T2T3, T3T4, -1 }, /* $t3 */ \
+ { T3T4, T4T5, -1 }, /* $t4 */ \
+ { T4T5, T5T6, -1 }, /* $t5 */ \
+ { T6T7, T7T8, -1 }, /* $t6 */ \
+ { T7T8, T8T9, -1 }, /* $t7 */ \
\
- { T0T1, -1 }, \
- { T0T1, T1T2, -1 }, \
- { T1T2, T2T3, -1 }, \
- { T2T3, T3T4, -1 }, \
- { T3T4, T4T5, -1 }, \
- { T4T5, T5T6, -1 }, \
- { T5T6, T6T7, -1 }, \
- { T6T7, -1 }, \
+ { S0S1, -1 }, /* $s0 */ \
+ { S0S1, S1S2, -1 }, /* $s1 */ \
+ { S1S2, S2S3, -1 }, /* $s2 */ \
+ { S2S3, S3S4, -1 }, /* $s3 */ \
+ { S3S4, S4S5, -1 }, /* $s4 */ \
+ { S4S5, S5S6, -1 }, /* $s5 */ \
+ { S5S6, S6S7, -1 }, /* $s6 */ \
+ { S6S7, -1 }, /* $s7 */ \
\
- { S0S1, -1 }, \
- { S0S1, S1S2, -1 }, \
- { S1S2, S2S3, -1 }, \
- { S2S3, S3S4, -1 }, \
- { S3S4, S4S5, -1 }, \
- { S4S5, S5S6, -1 }, \
- { S5S6, S6S7, -1 }, \
- { S6S7, -1 }, \
+ { T7T8, T8T9, -1 }, /* $t8 */ \
+ { T8T9, -1 }, /* $t9 */ \
\
- { T8T9, -1 }, \
- { T8T9, -1 }, \
- \
- { -1 }, { -1 }, \
- { -1 }, { -1 }, { -1 }, { -1 }, \
+ { -1 }, /* $k0 */ \
+ { -1 }, /* $k1 */ \
+ { -1 }, /* $gp */ \
+ { -1 }, /* $sp */ \
+ { -1 }, /* $fp */ \
+ { -1 }, /* $ra */ \
\
- { V0, V1, -1 }, \
+ { V0, V1, -1 }, /* $v0:$v1 */ \
\
- { A0, A1, -1 }, \
- { A1, A2, -1 }, \
- { A2, A3, -1 }, \
+ { A0, A1, A1A2, -1 }, /* $a0:$a1 */ \
+ { A1, A2, A0A1, A2A3, -1 }, /* $a1:$a2 */ \
+ { A2, A3, A1A2, A3T0, -1 }, /* $a2:$a3 */ \
+ { A3, T0, A2A3, T0T1, -1 }, /* $a3:$t0 */ \
+ { T0, T1, A3T0, T1T2, -1 }, /* $t0:$t1 */ \
+ { T1, T2, T0T1, T2T3, -1 }, /* $t1:$t2 */ \
+ { T2, T3, T1T2, T3T4, -1 }, /* $t2:$t3 */ \
+ { T3, T4, T2T3, T4T5, -1 }, /* $t3:$t4 */ \
+ { T4, T5, T3T4, T5T6, -1 }, /* $t4:$t5 */ \
+ { T5, T6, T4T5, T6T7, -1 }, /* $t5:$t6 */ \
+ { T6, T7, T5T6, T7T8, -1 }, /* $t6:$t7 */ \
+ { T7, T8, T6T7, T8T9, -1 }, /* $t7:$t8 */ \
+ { T8, T9, T7T8, -1 }, /* $t8:$t9 */ \
\
- { -1 }, /* only useful on n32/n64 */ \
- { T0, T1, T1T2, -1 }, \
- { T1, T2, T0T1, T2T3, -1 }, \
- { T2, T3, T1T2, T3T4, -1 }, \
- { T3, T4, T2T3, T4T5, -1 }, /* only useful on o32 */ \
- { T4, T5, T3T4, T5T6, -1 }, \
- { T5, T6, T4T5, T6T7, -1 }, \
- { T6, T7, T5T6, -1 }, \
- \
- { T8, T9, -1 }, \
- \
- { S0, S1, S1S2, -1 }, \
+ { S0, S1, S1S2, -1 }, /* $s0:$s1 */ \
{ S1, S2, S0S1, S2S3, -1 }, \
{ S2, S3, S1S2, S3S4, -1 }, \
{ S3, S4, S2S3, S4S5, -1 }, \
@@ -309,15 +320,32 @@ typedef long long OFFSZ;
{ S5, S6, S4S5, S6S7, -1 }, \
{ S6, S7, S5S6, -1 }, \
\
- { -1 }, \
- { -1 }, \
- { -1 },
-
+ { -1 }, { -1 }, { -1 }, { -1 }, \
+ { -1 }, { -1 }, { -1 }, { -1 }, \
+ { -1 }, { -1 }, { -1 }, \
#define GCLASS(x) (x < 32 ? CLASSA : (x < 52 ? CLASSB : CLASSC))
-#define PCLASS(p) (p->n_type == LONGLONG || p->n_type == ULONGLONG ? SBREG : \
- (p->n_type >= FLOAT && p->n_type <= LDOUBLE ? SCREG : SAREG))
+#define PCLASS(p) (1 << gclass((p)->n_type))
#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */
#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */
+#define ENCRD(x) (x) /* Encode dest reg in n_reg */
int COLORMAP(int c, int *r);
+
+extern int bigendian;
+extern int nargregs;
+
+#define SPCON (MAXSPECIAL+1) /* positive constant */
+
+#define TARGET_STDARGS
+#define TARGET_BUILTINS \
+ { "__builtin_stdarg_start", mips_builtin_stdarg_start }, \
+ { "__builtin_va_arg", mips_builtin_va_arg }, \
+ { "__builtin_va_end", mips_builtin_va_end }, \
+ { "__builtin_va_copy", mips_builtin_va_copy },
+
+struct node;
+struct node *mips_builtin_stdarg_start(struct node *f, struct node *a);
+struct node *mips_builtin_va_arg(struct node *f, struct node *a);
+struct node *mips_builtin_va_end(struct node *f, struct node *a);
+struct node *mips_builtin_va_copy(struct node *f, struct node *a);
diff --git a/usr.bin/pcc/mips/order.c b/usr.bin/pcc/mips/order.c
index bd6850a6f89..940d43a9a20 100644
--- a/usr.bin/pcc/mips/order.c
+++ b/usr.bin/pcc/mips/order.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: order.c,v 1.2 2007/11/16 08:34:55 otto Exp $ */
+/* $OpenBSD: order.c,v 1.3 2007/12/22 14:12:26 stefan Exp $ */
/*
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
@@ -33,23 +33,6 @@
#include "pass2.h"
-/* should we delay the INCR or DECR operation p */
-int
-deltest(NODE * p)
-{
- return 0;
-}
-
-/*
- * Check if p can be autoincremented.
- * XXX - nothing can be autoincremented for now.
- */
-int
-autoincr(NODE * p)
-{
- return 0;
-}
-
/*
* is it legal to make an OREG or NAME entry which has an offset of off,
* (from a register of r), if the resulting thing had type t
@@ -57,7 +40,8 @@ autoincr(NODE * p)
int
notoff(TWORD t, int r, CONSZ off, char *cp)
{
- return (0); /* YES */
+ if (off > 65535) return 1;
+ return 0; /* YES */
}
/*
@@ -145,34 +129,91 @@ nspecial(struct optab * q)
{
switch (q->op) {
+ case SCONV:
+ if (q->lshape == SBREG && q->rshape == SCREG) {
+ static struct rspecial s[] = {
+ { NLEFT, A0A1 },
+ { NRES, F0 },
+ { 0 }
+ };
+ return s;
+ } else if (q->lshape == SCREG && q->rshape == SBREG) {
+ static struct rspecial s[] = {
+ { NLEFT, F0 },
+ { NRES, A0A1 },
+ { 0 }
+ };
+ return s;
+ } else if (q->lshape == SAREG && q->rshape == SCREG) {
+ static struct rspecial s[] = {
+ { NLEFT, A0 },
+ { NRES, F0 },
+ { 0 }
+ };
+ return s;
+ }
+ break;
+
case MOD:
case DIV:
+ if (q->lshape == SBREG) {
+ static struct rspecial s[] = {
+ { NLEFT, A0A1 },
+ { NRIGHT, A2A3 },
+ { NRES, V0V1 },
+ { 0 },
+ };
+ return s;
+ } else if (q->lshape == SAREG) {
+ static struct rspecial s[] = {
+ { NLEFT, A0 },
+ { NRIGHT, A1 },
+ { NRES, V0 },
+ { 0 },
+ };
+ return s;
+ }
+
case RS:
case LS:
if (q->lshape == SBREG) {
static struct rspecial s[] = {
-#if 0
-// <stdin>, line 6: compiler error: Coalesce: src class 1, dst class 2
{ NLEFT, A0A1 },
- { NRIGHT, A2A3 },
+ { NRIGHT, A2 },
{ NRES, V0V1 },
-#endif
+ { 0 },
+ };
+ return s;
+ } else if (q->lshape == SAREG) {
+ static struct rspecial s[] = {
+ { NLEFT, A0 },
+ { NRIGHT, A1 },
+ { NRES, V0 },
{ 0 },
};
return s;
}
- printf("op: %d\n", q->op);
- printf("::: > %d\n", q->ltype);
break;
+ case STARG:
+ {
+ static struct rspecial s[] = {
+ { NEVER, A0 },
+ { NLEFT, A1 },
+ { NEVER, A2 },
+ { 0 }
+ };
+ return s;
+ }
+
case STASG:
{
static struct rspecial s[] = {
{ NEVER, A0 },
{ NRIGHT, A1 },
{ NEVER, A2 },
- { NRES, A0 },
- { 0 } };
+ { 0 }
+ };
return s;
}
}
@@ -182,200 +223,6 @@ nspecial(struct optab * q)
return 0; /* XXX gcc */
}
-#if 0
-/*
- * Splitup a function call and give away its arguments first.
- */
-void
-gencall(NODE * p, NODE * prev)
-{
- NODE *n = 0; /* XXX gcc */
- static int storearg(NODE *);
- int o = p->n_op;
- int ty = optype(o);
-
- if (ty == LTYPE)
- return;
-
- switch (o) {
- case CALL:
- /* Normal call, just push args and be done with it */
- p->n_op = UCALL;
-
- gencall(p->n_left, p);
- p->n_rval = storearg(p->n_right);
-
- break;
-
- case UFORTCALL:
- case FORTCALL:
- comperr("FORTCALL");
-
- case USTCALL:
- case STCALL:
- /*
- * Structure return. Look at the node above
- * to decide about buffer address:
- * - FUNARG, allocate space on stack, don't remove.
- * - nothing, allocate space on stack and remove.
- * - STASG, get the address of the left side as arg.
- * - FORCE, this ends up in a return, get supplied addr.
- * (this is not pretty, but what to do?)
- */
- if (prev == NULL || prev->n_op == FUNARG) {
- /* Create nodes to generate stack space */
- n = mkbinode(ASSIGN, mklnode(REG, 0, STKREG, INT),
- mkbinode(MINUS, mklnode(REG, 0, STKREG, INT),
- mklnode(ICON, p->n_stsize, 0, INT), INT), INT);
- //printf("stsize %d\n", p->n_stsize);
- pass2_compile(ipnode(n));
- } else if (prev->n_op == STASG) {
- n = prev->n_left;
- if (n->n_op == UMUL)
- n = nfree(n);
- else if (n->n_op == NAME) {
- n->n_op = ICON; /* Constant reference */
- n->n_type = INCREF(n->n_type);
- } else
- comperr("gencall stasg");
- } else if (prev->n_op == FORCE) {
- ; /* do nothing here */
- } else {
- comperr("gencall bad op %d", prev->n_op);
- }
-
- /* Deal with standard arguments */
- gencall(p->n_left, p);
- if (o == STCALL) {
- p->n_op = USTCALL;
- p->n_rval = storearg(p->n_right);
- } else
- p->n_rval = 0;
- /* push return struct address */
- if (prev == NULL || prev->n_op == FUNARG) {
- n = mklnode(REG, 0, STKREG, INT);
- if (p->n_rval)
- n = mkbinode(PLUS, n,
- mklnode(ICON, p->n_rval, 0, INT), INT);
- pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
- if (prev == NULL)
- p->n_rval += p->n_stsize / 4;
- } else if (prev->n_op == FORCE) {
- /* return value for this function */
- n = mklnode(OREG, 8, FP, INT);
- pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
- p->n_rval++;
- } else {
- pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
- n = p;
- *prev = *p;
- nfree(n);
- }
- //printf("end stcall\n");
- break;
-
- default:
- if (ty != UTYPE)
- gencall(p->n_right, p);
- gencall(p->n_left, p);
- break;
- }
-}
-
-/*
- * Create separate node trees for function arguments.
- * Returns the number of registers needed to hold the argument.
- */
-static int
-storearg(NODE * p)
-{
- static void storecall(NODE *);
- struct interpass *ip;
- NODE *np;
- int tsz, recval;
- TWORD t;
- extern int thisline;
- static int counter = 0; /* Count number of register arguments */
-
- ip = tmpalloc(sizeof(struct interpass));
- ip->type = IP_NODE;
- ip->lineno = thisline;
-
- if (p->n_op == CM) {
- np = p->n_left;
-
- if (p->n_right->n_op == STARG) {
- NODE *op = p;
- p = p->n_right;
- nfree(op);
- tsz = (p->n_stsize + 3) / 4;
- } else {
- p->n_type = p->n_right->n_type;
- p->n_left = p->n_right;
-
-
- /*
- * Process left subtree first, to get arguments in
- * the correct order on the stack as well as in the
- * registers.
- */
- recval = storearg(np);
-
- /* Not a register argument */
- if (!(counter < 4)) {
- p->n_op = FUNARG;
- ip->ip_node = p;
- pass2_compile(ip);
- tsz = szty(p->n_type);
-
- } else {/* Else fetch value from stack to register */
- t = p->n_type;
-
- pass2_compile(ipnode(mkbinode(ASSIGN,
- mklnode(REG, 0, A0 + counter, t),
- p->n_right, t)));
- tsz = 0;
- counter++;
-
- /* Free the comma node */
- nfree(p);
-
- }
- }
-
- return recval + tsz;
- } else {
- if (p->n_op != STARG) {
- /* Register argument */
- if (counter < 4) {
- t = p->n_type;
-
- pass2_compile(ipnode(mkbinode(ASSIGN,
- mklnode(REG, 0, A0 + counter, t),
- p, t)));
- counter++;
-
- return 0;
- } else {
- np = talloc();
-
- np->n_type = p->n_type;
- np->n_op = FUNARG;
- np->n_left = p;
- p = np;
- tsz = szty(p->n_type);
- }
- } else {
- p->n_op = FUNARG;
- tsz = (p->n_stsize + 3) / 4;
- }
- ip->ip_node = p;
- pass2_compile(ip);
- return tsz;
- }
-}
-#endif
-
/*
* Set evaluation order of a binary node if it differs from default.
*/
@@ -384,6 +231,7 @@ setorder(NODE * p)
{
return 0; /* nothing differs */
}
+
/*
* Set registers "live" at function calls (like arguments in registers).
* This is for liveness analysis of registers.
@@ -396,3 +244,11 @@ livecall(NODE *p)
return &r[0];
}
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+ return 1;
+}
diff --git a/usr.bin/pcc/mips/table.c b/usr.bin/pcc/mips/table.c
index 20073097182..b293a2614a4 100644
--- a/usr.bin/pcc/mips/table.c
+++ b/usr.bin/pcc/mips/table.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: table.c,v 1.2 2007/11/16 08:34:55 otto Exp $ */
+/* $OpenBSD: table.c,v 1.3 2007/12/22 14:12:26 stefan Exp $ */
/*
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
@@ -54,13 +54,13 @@ struct optab table[] = {
{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
/*
- * A bunch conversions of integral<->integral types
+ * Conversions of integral<->integral types
*/
/* convert char to (u)short */
{ SCONV, INAREG,
SOREG, TCHAR,
- SAREG, TWORD|SHORT|TUSHORT,
+ SAREG, TWORD|TSHORT|TUSHORT,
NAREG, RESC1,
" lb A1,AL # convert oreg char to (u)short/word\n"
" nop\n", },
@@ -73,7 +73,7 @@ struct optab table[] = {
" lbu A1,AL # convert oreg uchar to (u)short\n"
" nop\n", },
-/* convert char to (u)long long */
+/* convert char to (u)long long - big endian*/
{ SCONV, INBREG,
SOREG, TCHAR,
SBREG, TLL,
@@ -81,7 +81,7 @@ struct optab table[] = {
" lb U1,AL # convert oreg char to (u)longlong\n"
" nop\n"
" sra A1,U1,31\n"
- " sub A1,0,A1\n", },
+ " sub A1,$zero,A1\n", },
/* convert uchar to (u)long long */
{ SCONV, INBREG,
@@ -89,7 +89,7 @@ struct optab table[] = {
SBREG, TLL,
NBREG, RESC1,
" lbu U1,AL # convert oreg uchar to (u)longlong\n"
- " move A1,0\n", },
+ " move A1,$zero\n", },
/* convert (u)short to char */
{ SCONV, INAREG,
@@ -131,7 +131,7 @@ struct optab table[] = {
" lh U1,AL # convert oreg short to (u)longlong\n"
" nop\n"
" sra A1,U1,31\n"
- " sub A1,0,A1\n", },
+ " sub A1,$zero,A1\n", },
/* convert ushort to (u)long long */
{ SCONV, INBREG,
@@ -139,7 +139,7 @@ struct optab table[] = {
SBREG, TLL,
NBREG, RESC1,
" lhu U1,AL # convert oreg (u)short to (u)longlong\n"
- " move A1,0\n", },
+ " move A1,$zero\n", },
/* convert (u)long to char */
{ SCONV, INAREG,
@@ -154,7 +154,7 @@ struct optab table[] = {
SOREG, TWORD,
SAREG, TUCHAR,
NAREG, RESC1,
- " lbu AL,AR # convert oreg word to uchar (endianness problem here?)\n"
+ " lbu A1,AL # convert oreg word to uchar (endianness problem here?)\n"
" nop\n", },
/* convert (u)long to short */
@@ -162,7 +162,7 @@ struct optab table[] = {
SOREG, TWORD,
SAREG, TSHORT,
NAREG, RESC1,
- " lh AL,AR # convert oreg word to short (endianness problem here?)\n"
+ " lh A1,AL # convert oreg word to short (endianness problem here?)\n"
" nop\n", },
/* convert (u)long to ushort */
@@ -170,7 +170,7 @@ struct optab table[] = {
SOREG, TWORD,
SAREG, TUSHORT,
NAREG, RESC1,
- " lhu A1,AR # convert oreg word to ushort (endianness problem here?)\n"
+ " lhu A1,AL # convert oreg word to ushort (endianness problem here?)\n"
" nop\n", },
/* convert long to (u)long long */
@@ -181,7 +181,7 @@ struct optab table[] = {
" lw A1,AL # convert oreg int/long to (u)llong (endianness problem here?)\n"
" nop\n"
" sra U1,A1,31\n"
- " sub U1,0,U1\n", },
+ " sub U1,$zero,U1\n", },
/* convert ulong to (u)long long */
{ SCONV, INBREG,
@@ -189,7 +189,7 @@ struct optab table[] = {
SBREG, TLL,
NBREG, RESC1,
" lw A1,AL # convert oreg (u)int to (u)llong (endianness problem here?)\n"
- " move U1,0\n", },
+ " move U1,$zero\n", },
/* convert (u)long long to char */
{ SCONV, INAREG,
@@ -236,7 +236,7 @@ struct optab table[] = {
SOREG, TLL,
SAREG, TUWORD,
NAREG, RESC1,
- " lwu U1,AL # convert oreg (u)longlong to uint (endianness problem here?)\n"
+ " lw U1,AL # convert oreg (u)longlong to uint (endianness problem here?)\n"
" nop\n", },
/* Register to register conversion with long long */
@@ -244,68 +244,165 @@ struct optab table[] = {
{ SCONV, INBREG,
SBREG, TLL,
SBREG, TLL,
- 0, 0,
- " ; convert (u)longlong to (u)longlong", },
+ 0, RLEFT,
+ " # convert (u)longlong to (u)longlong", },
{ SCONV, INBREG,
- SAREG, TPOINT|TWORD|SHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TPOINT|TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
SBREG, TLL,
- NBREG, 0,
- " move A1,AR\n"
- " move U1,0\n", },
+ NBREG, RESC1,
+ " move A1,AL # convert (u)int/(u)short/(u)char to (u)longlong\n"
+ " sra A1,AL,31\n", },
{ SCONV, INAREG,
- SAREG, TLL,
- SAREG, TPOINT|TWORD|SHORT|TUSHORT|TCHAR|TUCHAR,
- NAREG, 0,
+ SBREG, TLL,
+ SAREG, TPOINT|TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG, RESC1,
" move A1,AL\n", },
/* For register to register conversion with bit length <= 32, do nothing */
-
+/* XXX This doesn't seem correct. USHORT->TCHAR must be sign extended */
{ SCONV, INAREG,
SAREG, TPOINT|TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
SAREG, TPOINT|TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
- 0, 0,
- " ; convert reg to reg", },
+ 0, RLEFT,
+ " # convert reg to reg\n", },
+
+{ SCONV, INCREG,
+ SCREG, TFLOAT,
+ SCREG, TDOUBLE|TLDOUBLE,
+ NCREG, RESC1,
+ " cvt.d.s A1,AL # convert float to (l)double\n", },
+
+{ SCONV, INCREG,
+ SCREG, TDOUBLE|TLDOUBLE,
+ SCREG, TFLOAT,
+ NCREG, RESC1,
+ " cvt.s.d A1,AL # convert (l)double to float\n", },
+
+{ SCONV, INCREG,
+ SAREG, TWORD,
+ SCREG, TFLOAT,
+ NCREG, RESC1,
+ " mtc1 AL,A1 # convert (u)int to float\n"
+ " nop\n"
+ " cvt.s.w A1,A1\n", },
+
+{ SCONV, INCREG,
+ SOREG, TWORD,
+ SCREG, TFLOAT,
+ NCREG, RESC1,
+ " l.s A1,AL # convert (u)int to float\n"
+ " nop\n"
+ " cvt.s.w A1,A1\n", },
+
+{ SCONV, INCREG,
+ SAREG, TWORD,
+ SCREG, TDOUBLE|TLDOUBLE,
+ NCREG, RESC1,
+ " mtc1 AL,A1 # convert (u)int to (l)double\n"
+ " nop\n"
+ " cvt.d.w A1,A1\n", },
+
+{ SCONV, INCREG,
+ SOREG, TWORD,
+ SCREG, TDOUBLE|TLDOUBLE,
+ NCREG, RESC1,
+ " l.d A1,AL # convert (u)int to (l)double\n"
+ " nop\n"
+ " cvt.d.w A1,A1\n", },
+
+{ SCONV, INAREG,
+ SCREG, TFLOAT,
+ SAREG, TWORD,
+ NCREG|NAREG, RESC1,
+ " cvt.w.s A2,AL # convert float to (u)int\n"
+ " mfc1 A1,A2\n"
+ " nop\n", },
+
+{ SCONV, FOREFF,
+ SCREG, TFLOAT,
+ SOREG, TWORD,
+ NCREG, RDEST,
+ " cvt.w.s A1,AL # convert float to (u)int\n"
+ " s.s A1,AR\n"
+ " nop\n", },
+
+{ SCONV, INAREG,
+ SCREG, TDOUBLE|TLDOUBLE,
+ SAREG, TWORD,
+ NCREG|NAREG, RESC1,
+ " cvt.w.d A2,AL # convert (l)double to (u)int\n"
+ " mfc1 A1,A2\n"
+ " nop\n", },
+
+{ SCONV, INCREG,
+ SCREG, TDOUBLE|TLDOUBLE,
+ SCREG, TDOUBLE|TLDOUBLE,
+ 0, RLEFT,
+ " # convert between double and ldouble\n", },
+
+{ SCONV, INCREG,
+ SBREG, TLL,
+ SCREG, TFLOAT,
+ NSPECIAL|NCREG, RESC1,
+ "ZF", },
+
+{ SCONV, INCREG,
+ SBREG, TLL,
+ SCREG, TDOUBLE|TLDOUBLE,
+ NSPECIAL|NCREG, RESC1,
+ "ZF", },
+
+{ SCONV, INBREG,
+ SCREG, TDOUBLE|TLDOUBLE,
+ SBREG, TLL,
+ NSPECIAL|NBREG, RESC1,
+ "ZF", },
+
+{ SCONV, INBREG,
+ SCREG, TFLOAT,
+ SBREG, TLL,
+ NSPECIAL|NBREG, RESC1,
+ "ZF", },
/*
* Multiplication and division
*/
{ MUL, INAREG,
- SAREG, TSWORD|TSHORT|TCHAR,
- SAREG, TSWORD|TSHORT|TCHAR,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
NAREG|NASR|NASL, RESC1,
- " mult AL,AR # signed multiply\n"
+ " multu AL,AR # unsigned multiply\n"
" mflo A1\n"
" nop\n"
" nop\n", },
+/* this previous will match on unsigned/unsigned multiplication first */
{ MUL, INAREG,
- SAREG, TUWORD|TUSHORT|TUCHAR,
- SAREG, TUWORD|TUSHORT|TUCHAR,
+ SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+ SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
NAREG|NASR|NASL, RESC1,
- " multu AL,AR # unsigned multiply\n"
+ " mult AL,AR # signed multiply\n"
" mflo A1\n"
" nop\n"
" nop\n", },
+
{ MUL, INBREG,
SBREG, TLL,
SBREG, TLL,
- 2*NBREG|NASR|NASL, RESC1,
- " li A2,AR\n"
- " multu AL,A2\n"
+ 2*NBREG, RESC1,
+ " multu AL,AR\n"
" mfhi U1\n"
" mflo A1\n"
- " move A2,UR\n"
- " mult AL,A2\n"
- " mflo U2\n"
+ " mult AL,UR\n"
+ " mflo A2\n"
" nop\n"
" nop\n"
- " addu A2,U1,U2\n"
- " li U2,AR\n"
- " mult UL,U2\n"
+ " addu A2,U1,A2\n"
+ " mult UL,AR\n"
" mflo U2\n"
" nop\n"
" nop\n"
@@ -315,47 +412,51 @@ struct optab table[] = {
SCREG, TFLOAT,
SCREG, TFLOAT,
NCREG, RESC1,
- " mul.s A1,Al,AR #floating-point multiply\n", },
+ " mul.s A1,AL,AR # floating-point multiply\n", },
{ MUL, INCREG,
- SCREG, TDOUBLE,
- SCREG, TDOUBLE,
+ SCREG, TDOUBLE|TLDOUBLE,
+ SCREG, TDOUBLE|TLDOUBLE,
NCREG, RESC1,
" mul.d A1,AL,AR # double-floating-point multiply\n", },
+
{ DIV, INAREG,
- SAREG, TSWORD|TSHORT|TCHAR,
- SAREG, TSWORD|TSHORT|TCHAR,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
NAREG|NASR|NASL, RESC1,
- " div AL,AR # signed division\n"
+ " divu AL,AR # unsigned division\n"
" mflo A1\n"
" nop\n"
" nop\n", },
+/* the previous rule will match unsigned/unsigned first */
{ DIV, INAREG,
- SAREG, TUWORD|TUSHORT|TUCHAR,
- SAREG, TUWORD|TUSHORT|TUCHAR,
+ SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+ SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
NAREG|NASR|NASL, RESC1,
- " divu AL,AR # unsigned division\n"
+ " div AL,AR # signed division\n"
" mflo A1\n"
" nop\n"
" nop\n", },
{ DIV, INBREG,
SBREG, TLL,
- SBREG|SCON, TLL,
- NBREG, RESC1,
+ SBREG, TLL,
+ NSPECIAL|NBREG, RESC1,
"ZE", },
-{ MOD, INAREG,
- SAREG, TSWORD|TSHORT|TCHAR,
- SAREG, TSWORD|TSHORT|TCHAR,
- NAREG, RESC1,
- " div AL,AR # signed modulo\n"
- " mfhi A1\n"
- " nop\n"
- " nop\n"
- " sub A1,A1,AL\n", },
+{ DIV, INCREG,
+ SCREG, TFLOAT,
+ SCREG, TFLOAT,
+ NCREG, RESC1,
+ " div.s A1,AL,AR # floating-point division\n", },
+
+{ DIV, INCREG,
+ SCREG, TDOUBLE|TLDOUBLE,
+ SCREG, TDOUBLE|TLDOUBLE,
+ NCREG, RESC1,
+ " div.d A1,AL,AR # double-floating-point division\n", },
{ MOD, INAREG,
SAREG, TUWORD|TUSHORT|TUCHAR,
@@ -364,8 +465,17 @@ struct optab table[] = {
" divu AL,AR # signed modulo\n"
" mfhi A1\n"
" nop\n"
+ " nop\n", },
+
+/* the previous rule will match unsigned%unsigned first */
+{ MOD, INAREG,
+ SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+ SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+ NAREG, RESC1,
+ " div AL,AR # signed modulo\n"
+ " mfhi A1\n"
" nop\n"
- " sub A1,A1,AL\n", },
+ " nop\n", },
{ MOD, INBREG,
SBREG, TLL,
@@ -378,10 +488,10 @@ struct optab table[] = {
*/
{ PLUS, INBREG,
- SBREG, TULONGLONG,
- SBREG, TULONGLONG,
- NBREG|NAREG, RESC1,
- " addu A1,AL,AR\n"
+ SBREG, TULONGLONG|TLONGLONG,
+ SBREG, TULONGLONG|TLONGLONG,
+ 2*NBREG, RESC1,
+ " addu A1,AL,AR # 64-bit addition\n"
" sltu A2,A1,AR\n"
" addu U1,UL,UR\n"
" addu U1,U1,A2\n", },
@@ -408,13 +518,25 @@ struct optab table[] = {
SAREG, TUWORD|TUSHORT|TUCHAR,
SSCON, TANY,
NAREG|NASL, RESC1,
- " addui A1,AL,AR\n", },
+ " addiu A1,AL,AR\n", },
+
+{ PLUS, INCREG,
+ SCREG, TFLOAT,
+ SCREG, TFLOAT,
+ NCREG|NCSL, RESC1,
+ " add.s A1,AL,AR\n", },
+
+{ PLUS, INCREG,
+ SCREG, TDOUBLE|TLDOUBLE,
+ SCREG, TDOUBLE|TLDOUBLE,
+ NCREG|NCSL, RESC1,
+ " add.d A1,AL,AR\n", },
{ MINUS, INBREG,
- SBREG, TULONGLONG,
- SBREG, TULONGLONG,
- NBREG|NAREG, RESC1,
- " sltu A2,AL,AR\n"
+ SBREG, TLONGLONG|TULONGLONG,
+ SBREG, TLONGLONG|TULONGLONG,
+ 2*NBREG, RESC1,
+ " sltu A2,AL,AR # 64-bit subtraction\n"
" subu A1,AL,AR\n"
" subu U1,UL,UR\n"
" subu U1,U1,A2\n", },
@@ -435,7 +557,19 @@ struct optab table[] = {
SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
SSCON, TANY,
NAREG|NASL, RESC1,
- " subui A1,AL,AR\n", },
+ " subu A1,AL,AR\n", },
+
+{ MINUS, INCREG,
+ SCREG, TFLOAT,
+ SCREG, TFLOAT,
+ NCREG|NCSL, RESC1,
+ " sub.s A1,AL,AR\n", },
+
+{ MINUS, INCREG,
+ SCREG, TDOUBLE|TLDOUBLE,
+ SCREG, TDOUBLE|TLDOUBLE,
+ NCREG|NCSL, RESC1,
+ " sub.d A1,AL,AR\n", },
{ UMINUS, INAREG,
SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
@@ -447,11 +581,23 @@ struct optab table[] = {
SBREG, TLL,
SANY, TANY,
NBREG|NAREG|NBSL, RESC1,
- " subu A1,0,AL\n"
- " subu U1,0,UL\n"
- " sltu A2,0,A1\n"
+ " subu A1,$zero,AL\n"
+ " subu U1,$zero,UL\n"
+ " sltu A2,$zero,A1\n"
" subu U1,U1,A2\n", },
+{ UMINUS, INCREG,
+ SCREG, TFLOAT,
+ SCREG, TFLOAT,
+ NCREG|NCSL, RESC1,
+ " neg.s A1,AL\n", },
+
+{ UMINUS, INCREG,
+ SCREG, TDOUBLE|TLDOUBLE,
+ SCREG, TDOUBLE|TLDOUBLE,
+ NCREG|NCSL, RESC1,
+ " neg.d A1,AL\n", },
+
/* Simple 'op rd, rs, rt' or 'op rt, rs, imm' operations */
{ OPSIMP, INBREG,
@@ -469,7 +615,7 @@ struct optab table[] = {
{ OPSIMP, INAREG,
SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR,
- SSCON, TSHORT|TUSHORT|TUCHAR|TCHAR,
+ SPCON, TSHORT|TUSHORT|TUCHAR|TCHAR,
NAREG|NASL, RESC1,
" Oi A1,AL,AR\n", },
@@ -478,7 +624,13 @@ struct optab table[] = {
*/
{ RS, INAREG,
- SAREG, TWORD|TUSHORT|TSHORT|TCHAR|TUCHAR,
+ SAREG, TSWORD|TSHORT|TCHAR,
+ SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESC1,
+ " sra A1,AL,AR # shift right by constant\n", },
+
+{ RS, INAREG,
+ SAREG, TUWORD|TUSHORT|TUCHAR,
SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
NAREG|NASL, RESC1,
" srl A1,AL,AR # shift right by constant\n", },
@@ -504,13 +656,13 @@ struct optab table[] = {
{ RS, INBREG,
SBREG, TLL,
SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
- NBREG|NBSL, RESC1,
+ NBREG, RESC1,
"ZO", },
{ LS, INBREG,
SBREG, TLL,
SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
- NBREG|NBSL, RESC1,
+ NBREG, RESC1,
"ZO", },
{ RS, INBREG,
@@ -550,7 +702,7 @@ struct optab table[] = {
SOREG|SNAME, TWORD|TPOINT,
SAREG, TWORD|TPOINT,
0, RDEST,
- " sw AR,AL # store (u)int/(u)long\n"
+ " sw AR,AL # store (u)int/(u)long\n"
" nop\n", },
{ ASSIGN, FOREFF|INAREG,
@@ -576,32 +728,6 @@ struct optab table[] = {
" sw AR,AL\n"
" nop\n", },
-#if 0
-{ ASSIGN, FOREFF|INAREG,
- SNAME, TWORD|TPOINT,
- SAREG, TWORD|TPOINT,
- NAREG, RDEST,
- " la A1,AL # store word into sname\n"
- " sw AR,0(A1)\n"
- " nop\n", },
-
-{ ASSIGN, FOREFF|INAREG,
- SNAME, TSHORT|TUSHORT,
- SAREG, TSHORT|TUSHORT,
- NAREG, RDEST,
- " la A1,AL # store (u)short into sname\n"
- " sh AR,0(A1)\n"
- " nop\n", },
-
-{ ASSIGN, FOREFF|INAREG,
- SNAME, TCHAR|TUCHAR,
- SAREG, TCHAR|TUCHAR,
- NAREG, RDEST,
- " la A1,AL # store (u)char into sname\n"
- " sb AR,0(A1)\n"
- " nop\n", },
-#endif
-
{ ASSIGN, FOREFF|INBREG,
SBREG, TLL,
SBREG, TLL,
@@ -616,16 +742,95 @@ struct optab table[] = {
" move AL,AR # register move\n", },
{ ASSIGN, FOREFF|INCREG,
- SNAME|OREG, TFLOAT,
+ SCREG, TFLOAT,
+ SCREG, TFLOAT,
+ 0, RDEST,
+ " mov.s AL,AR # register move\n", },
+
+{ ASSIGN, FOREFF|INCREG,
+ SCREG, TDOUBLE|TLDOUBLE,
+ SCREG, TDOUBLE|TLDOUBLE,
+ 0, RDEST,
+ " mov.d AL,AR # register move\n", },
+
+{ ASSIGN, FOREFF|INCREG,
+ SNAME|SOREG, TFLOAT,
SCREG, TFLOAT,
0, RDEST,
- " s.s AR,AL # store floating-point reg to sname\n", },
+ " s.s AR,AL # store floating-point reg to sname\n"
+ " nop\n", },
{ ASSIGN, FOREFF|INCREG,
- SNAME|OREG, TDOUBLE,
- SCREG, TDOUBLE,
+ SNAME|SOREG, TDOUBLE|TLDOUBLE,
+ SCREG, TDOUBLE|TLDOUBLE,
0, RDEST,
- " s.d AR,AL # store double-floating-point reg to sname\n", },
+ " s.d AR,AL # store double floating-point reg to sname\n"
+ " nop\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SFLD, TANY,
+ SOREG|SNAME, TANY,
+ 3*NAREG, RDEST,
+ " lw A1,AR # bit-field assignment\n"
+ " li A3,ML\n"
+ " lw A2,AL\n"
+ " sll A1,A1,HL\n"
+ " and A1,A1,A3\n"
+ " nor A3,A3\n"
+ " and A2,A2,A3\n"
+ " or A2,A2,A1\n"
+ " sw A2,AL\n"
+ " nop\n", },
+
+/* XXX we can optimise this away */
+{ ASSIGN, FOREFF|INAREG,
+ SFLD, TANY,
+ SCON, TANY,
+ 3*NAREG, RDEST,
+ " li A1,AR # bit-field assignment\n"
+ " lw A2,AL\n"
+ " li A3,ML\n"
+ " sll A1,A1,HL\n"
+ " and A1,A1,A3\n"
+ " nor A3,A3\n"
+ " and A2,A2,A3\n"
+ " or A2,A2,A1\n"
+ " sw A2,AL\n"
+ " nop\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SFLD, TANY,
+ SAREG, TANY,
+ 3*NAREG, RDEST,
+ " move A1,AR # bit-field assignment\n"
+ " lw A2,AL\n"
+ " li A3,ML\n"
+ " sll A1,A1,HL\n"
+ " and A1,A1,A3\n"
+ " nor A3,A3\n"
+ " and A2,A2,A3\n"
+ " or A2,A2,A1\n"
+ " sw A2,AL\n"
+ " nop\n", },
+
+{ ASSIGN, FOREFF|INAREG,
+ SFLD, TANY,
+ SFLD, TANY,
+ 2*NAREG, RDEST,
+ " lw A1,AR # bit-field copy\n"
+ " li A3,MR\n"
+ " and A1,A1,A3\n"
+ " sll A1,A1,32-SR-HR\n"
+ " sra A1,A1,32-SR\n"
+ " lw A2,AL\n"
+ " li A3,ML\n"
+ " sll A1,A1,HL\n"
+ " and A1,A1,A3\n"
+ " nor A3,A3\n"
+ " and A2,A2,A3\n"
+ " or A2,A2,A1\n"
+ " sw A2,AL\n"
+ " nop\n", } ,
{ STASG, INAREG|FOREFF,
SOREG|SNAME, TANY,
@@ -633,35 +838,58 @@ struct optab table[] = {
NSPECIAL, RRIGHT,
"ZQ", },
-
/*
* Compare instructions
*/
-{ EQ, FORCC,
- SAREG, TANY,
- SAREG, TANY,
+{ EQ, FORCC,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
0, RESCC,
- " beq AL,AR,LC\n", },
+ " beq AL,AR,LC\n"
+ " nop\n", },
-{ NE, FORCC,
- SAREG, TANY,
- SAREG, TANY,
+{ NE, FORCC,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
0, RESCC,
- " bne AL,AR,LC\n", },
+ " bne AL,AR,LC\n"
+ " nop\n", },
-{ OPLOG, FORCC,
- SAREG, TANY,
+{ OPLOG, FORCC,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
SZERO, TANY,
0, RESCC,
- " O AL,LC\n", },
+ " O AL,LC\n"
+ " nop\n", },
-{ OPLOG, FORCC,
- SAREG, TANY,
- SAREG|SCON, TANY,
- NAREG|NBSL, RESCC,
+{ OPLOG, FORCC,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESCC,
" sub A1,AL,AR\n"
- " O A1,LC\n", },
+ " O A1,LC\n"
+ " nop\n", },
+
+{ OPLOG, FORCC,
+ SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+ NAREG|NASL, RESCC,
+ " sub A1,AL,AR\n"
+ " O A1,LC\n"
+ " nop\n", },
+
+{ OPLOG, FORCC,
+ SBREG, TLL,
+ SBREG, TLL,
+ NAREG, RESCC,
+ "ZD", },
+
+{ OPLOG, FORCC,
+ SCREG, TFLOAT|TDOUBLE|TLDOUBLE,
+ SCREG, TFLOAT|TDOUBLE|TLDOUBLE,
+ 0, RESCC,
+ "ZG", },
/*
* Convert LTYPE to reg.
@@ -671,155 +899,112 @@ struct optab table[] = {
SANY, TANY,
SOREG|SNAME, TCHAR,
NAREG, RESC1,
- " lb A1,AR # load char to reg\n"
+ " lb A1,AL # load char to reg\n"
" nop\n", },
{ OPLTYPE, INAREG,
SANY, TANY,
SOREG|SNAME, TUCHAR,
NAREG, RESC1,
- " lbu A1,AR # load uchar to reg\n"
+ " lbu A1,AL # load uchar to reg\n"
" nop\n", },
{ OPLTYPE, INAREG,
SANY, TANY,
SOREG|SNAME, TSHORT,
NAREG, RESC1,
- " lh A1,AR # load short to reg\n"
+ " lh A1,AL # load short to reg\n"
" nop\n", },
{ OPLTYPE, INAREG,
SANY, TANY,
SOREG|SNAME, TUSHORT,
NAREG, RESC1,
- " lhu A1,AR # load ushort to reg\n"
+ " lhu A1,AL # load ushort to reg\n"
" nop\n", },
{ OPLTYPE, INAREG,
SANY, TANY,
SOREG|SNAME, TWORD|TPOINT,
NAREG, RESC1,
- " lw A1,AR # load (u)int/(u)long to reg\n"
+ " lw A1,AL # load (u)int/(u)long to reg\n"
" nop\n", },
{ OPLTYPE, INBREG,
SANY, TANY,
SOREG|SNAME, TLL,
NBREG, RESC1,
- " lw U1,UR # load (u)longlong to reg\n"
- " nop\n"
- " lw A1,AR\n"
- " nop\n", },
-
-#if 0
-
-// don't need these with the gas assembler
-
-{ OPLTYPE, INAREG,
- SANY, TANY,
- SNAME, TCHAR,
- 2*NAREG, RESC1,
- " la A2,AL # load char sname to reg\n"
- " lb A1,0(A2)\n"
- " nop\n", },
-
-{ OPLTYPE, INAREG,
- SANY, TANY,
- SNAME, TUCHAR,
- 2*NAREG, RESC1,
- " la A2,AR # load uchar sname to reg\n"
- " lbu A1,0(A2)\n"
- " nop\n", },
-
-{ OPLTYPE, INAREG,
- SANY, TANY,
- SNAME, TSHORT,
- 2*NAREG, RESC1,
- " la A2,AR # load short sname to reg\n"
- " lh A1,0(A2)\n"
- " nop\n", },
-
-{ OPLTYPE, INAREG,
- SANY, TANY,
- SNAME, TUSHORT,
- 2*NAREG, RESC1,
- " la A2,AR # load ushort sname to reg\n"
- " lhu A1,0(A2)\n"
- " nop\n", },
-
-{ OPLTYPE, INAREG,
- SANY, TANY,
- SNAME, TWORD|TPOINT,
- 2*NAREG, RESC1,
- " la A2,AR # load (u)int/(u)long to reg\n"
- " lw A1,0(A2)\n"
- " nop\n", },
-
-{ OPLTYPE, INBREG,
- SANY, TANY,
- SNAME, TLL,
- 2*NBREG, RESC1,
- " la A2,UR # load (u)longlong to reg (endiannes problems?)\n"
- " lw U1,0(A2)\n"
+ " lw U1,UL # load (u)longlong to reg\n"
" nop\n"
- " la A2,AR\n"
- " lw A1,0(A2)\n"
+ " lw A1,AL\n"
" nop\n", },
-#endif
-
{ OPLTYPE, INAREG,
SANY, TANY,
SCON, TPOINT,
NAREG, RESC1,
- " la A1,AR # load constant address to reg\n", },
+ " la A1,AL # load constant address to reg\n", },
{ OPLTYPE, INAREG,
SANY, TANY,
SCON, TANY,
NAREG, RESC1,
- " li A1,AR # load constant to reg\n", },
+ " li A1,AL # load constant to reg\n", },
{ OPLTYPE, INAREG,
SANY, TANY,
SZERO, TANY,
NAREG, RESC1,
- " move A1,0 # load 0 to reg\n", },
+ " move A1,$zero # load 0 to reg\n", },
{ OPLTYPE, INBREG,
SANY, TANY,
SCON, TANY,
NBREG, RESC1,
- " li A1,AR # load constant to reg\n"
- " li U1,UR\n", },
+ " li A1,AL # load constant to reg\n"
+ " li U1,UL\n", },
{ OPLTYPE, INBREG,
SANY, TANY,
SZERO, TANY,
NBREG, RESC1,
- " move A1,0 # load 0 to reg\n"
- " move U1,0\n", },
+ " move A1,$zero # load 0 to reg\n"
+ " move U1,$zero\n", },
-#if 0
-/* Matches REG nodes. XXX - shouldn't be necessary? */
{ OPLTYPE, INAREG,
SANY, TANY,
SANY, TANY,
NAREG, RESC1,
- " move A1,AR\n", },
-#endif
+ " move A1,AL\n", },
+
+{ OPLTYPE, INCREG,
+ SANY, TANY,
+ SZERO, TFLOAT,
+ NCREG, RESC1,
+ " mtc1 $zero,A1 # load 0 to float reg\n"
+ " nop\n", },
+
+{ OPLTYPE, INCREG,
+ SANY, TANY,
+ SZERO, TDOUBLE|TLDOUBLE,
+ NCREG, RESC1,
+ " mtc1 $zero,A1 # load 0 to (l)double reg\n"
+ " mtc1 $zero,U1\n"
+ " nop\n", },
{ OPLTYPE, INCREG,
SANY, TANY,
SOREG|SNAME, TFLOAT,
NCREG, RESC1,
- " l.s A1,AR # load into floating-point reg\n", },
+ " l.s A1,AL # load into floating-point reg\n"
+ " nop\n", },
{ OPLTYPE, INCREG,
SANY, TANY,
- OREG|SNAME, TDOUBLE,
+ OREG|SNAME, TDOUBLE|TLDOUBLE,
NCREG, RESC1,
- " l.d A1,AR # load into double-floating-point reg\n", },
+ " l.d A1,AL # load into double floating-point reg\n"
+ " nop\n", },
/*
* Jumps.
@@ -829,6 +1014,7 @@ struct optab table[] = {
SANY, TANY,
0, RNOP,
" j LL # goto label\n"
+ " nop\n"
" nop\n", },
/*
@@ -836,73 +1022,254 @@ struct optab table[] = {
*/
{ CALL, FOREFF,
- SCON|SNAME, TANY,
+ SCON, TANY,
SANY, TANY,
0, 0,
- " addi $sp,$sp,-16 # call (args, no result) to scon/sname\n"
+ " subu $sp,$sp,16 # call (args, no result) to scon/sname\n"
" jal CL\n"
" nop\n"
"ZC", },
{ UCALL, FOREFF,
- SCON|SNAME, TANY,
+ SCON, TANY,
SANY, TANY,
0, 0,
" jal CL # call (no args, no result) to scon/sname\n"
" nop\n", },
{ CALL, INAREG,
- SCON|SNAME, TANY,
+ SCON, TANY,
SAREG, TANY,
NAREG, RESC1, /* should be 0 */
- " addi $sp,$sp,-16 # call (args, result in v0) to scon/sname\n"
+ " subu $sp,$sp,16 # call (args, result in v0) to scon/sname\n"
" jal CL\n"
" nop\n"
"ZC", },
{ UCALL, INAREG,
- SCON|SNAME, TANY,
+ SCON, TANY,
SAREG, TANY,
NAREG, RESC1, /* should be 0 */
- " jal CL ; call (no args, result in v0) to scon/sname\n"
+ " jal CL # call (no args, result in v0) to scon/sname\n"
+ " nop\n",
+ },
+
+{ CALL, INBREG,
+ SCON, TANY,
+ SBREG, TANY,
+ NBREG, RESC1, /* should be 0 */
+ " subu $sp,$sp,16 # call (args, result in v0:v1) to scon/sname\n"
+ " jal CL\n"
+ " nop\n"
+ "ZC", },
+
+{ UCALL, INBREG,
+ SCON, TANY,
+ SBREG, TANY,
+ NBREG, RESC1, /* should be 0 */
+ " jal CL # call (no args, result in v0:v1) to scon/sname\n"
+ " nop\n",
+ },
+
+{ CALL, INCREG,
+ SCON, TANY,
+ SCREG, TANY,
+ NCREG, RESC1, /* should be 0 */
+ " subu $sp,$sp,16 # call (args, result in f0:f1) to scon/sname\n"
+ " jal CL\n"
+ " nop\n"
+ "ZC", },
+
+{ UCALL, INCREG,
+ SCON, TANY,
+ SCREG, TANY,
+ NCREG, RESC1, /* should be 0 */
+ " jal CL # call (no args, result in v0:v1) to scon/sname\n"
" nop\n",
},
+{ CALL, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, 0,
+ " subu $sp,$sp,16 # call (args, no result) to reg\n"
+ " move $25,AL\n"
+ " jal $25\n"
+ " nop\n"
+ "ZC", },
+
+{ UCALL, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, 0,
+ " move $25,AL\n"
+ " jal $25 # call (no args, no result) to reg\n"
+ " nop\n", },
+
+{ CALL, INAREG,
+ SAREG, TANY,
+ SAREG, TANY,
+ NAREG, RESC1, /* should be 0 */
+ " subu $sp,$sp,16 # call (args, result) to reg\n"
+ " move $25,AL\n"
+ " jal $25\n"
+ " nop\n"
+ "ZC", },
+
+{ UCALL, INAREG,
+ SAREG, TANY,
+ SAREG, TANY,
+ NAREG, RESC1, /* should be 0 */
+ " move $25,AL\n"
+ " jal $25 # call (no args, result) to reg\n"
+ " nop\n", },
+
+{ CALL, INBREG,
+ SAREG, TANY,
+ SBREG, TANY,
+ NBREG, RESC1, /* should be 0 */
+ " subu $sp,$sp,16 # call (args, result) to reg\n"
+ " move $25,AL\n"
+ " jal $25\n"
+ " nop\n"
+ "ZC", },
+
+{ UCALL, INBREG,
+ SAREG, TANY,
+ SBREG, TANY,
+ NBREG, RESC1, /* should be 0 */
+ " move $25,AL\n"
+ " jal $25 # call (no args, result) to reg\n"
+ " nop\n", },
+
+{ CALL, INCREG,
+ SAREG, TANY,
+ SCREG, TANY,
+ NCREG, RESC1, /* should be 0 */
+ " subu $sp,$sp,16 # call (args, result) to reg\n"
+ " move $25,AL\n"
+ " jal $25\n"
+ " nop\n"
+ "ZC", },
+
+{ UCALL, INCREG,
+ SCREG, TANY,
+ SCREG, TANY,
+ NCREG, RESC1, /* should be 0 */
+ " move $25,AL\n"
+ " jal $25 # call (no args, result) to reg\n"
+ " nop\n", },
+
+
/* struct return */
{ USTCALL, FOREFF,
- SCON|SNAME, TANY,
- SANY, TANY,
- 0, 0,
- " call CL\n"
- " ZC", },
+ SCON|SNAME, TANY,
+ SANY, TANY,
+ 0, 0,
+ " jal CL\n"
+ " nop\n", },
+
+{ USTCALL, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, 0,
+ " move $25,AL\n"
+ " jal $25\n"
+ " nop\n", },
+
+{ USTCALL, INAREG,
+ SCON|SNAME, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1,
+ " jal CL\n"
+ " nop\n", },
+
+{ USTCALL, INAREG,
+ SAREG, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1,
+ " move $25,AL\n"
+ " jal $25\n"
+ " nop\n", },
+
+{ STCALL, FOREFF,
+ SCON|SNAME, TANY,
+ SANY, TANY,
+ 0, 0,
+ " jal CL\n"
+ " nop\n"
+ "ZC", },
+
+{ STCALL, FOREFF,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, 0,
+ " move $25,AL\n"
+ " jal $25\n"
+ " nop\n"
+ "ZC", },
+
+{ STCALL, INAREG,
+ SCON|SNAME, TANY,
+ SANY, TANY,
+ NAREG|NASL, RESC1,
+ " jal CL\n"
+ " nop\n"
+ "ZC", },
+
+{ STCALL, INAREG,
+ SAREG, TANY,
+ SANY, TANY,
+ 0, 0,
+ " move $25,AL\n"
+ " jal $25\n"
+ " nop\n"
+ "ZC", },
+
/*
* Function arguments
*/
+/* intentionally write out the register for (u)short/(u)char */
{ FUNARG, FOREFF,
- SAREG, TWORD|TPOINT,
- SANY, TWORD|TPOINT,
+ SAREG, TWORD|TPOINT|TUSHORT|TSHORT|TUCHAR|TCHAR,
+ SANY, TWORD|TPOINT|TUSHORT|TSHORT|TUCHAR|TCHAR,
0, 0,
- " addi $sp,$sp,-4 # save function arg to stack\n"
- " sw AL,0($sp)\n"
+ " subu $sp,$sp,4 # save function arg to stack\n"
+ " sw AL,($sp)\n"
" #nop\n", },
-{ FUNARG, FOREFF,
- SAREG, TSHORT|TUSHORT,
- SANY, TSHORT|TUSHORT,
- 0, 0,
- " addi $sp,$sp,-4 # save function arg to stack\n"
- " sh AL,0($sp)\n"
+{ FUNARG, FOREFF,
+ SBREG, TLL,
+ SANY, TLL,
+ 0, 0,
+ " addi $sp,$sp,-8 # save function arg to stack (endian problem here?\n"
+ " sw UL,4($sp)\n"
+ " sw AL,($sp)\n"
" #nop\n", },
-{ FUNARG, FOREFF,
- SAREG, TCHAR|TUCHAR,
- SANY, TCHAR|TUCHAR,
- 0, 0,
- " addi $sp,$sp,-4 # save function arg to stack\n"
- " sb AL,0($sp)\n"
- " #nop\n", },
+{ FUNARG, FOREFF,
+ SCREG, TFLOAT,
+ SANY, TFLOAT,
+ 0, 0,
+ " addi $sp,$sp,-4 # save function arg to stack\n"
+ " s.s AL,($sp)\n"
+ " #nop\n", },
+
+{ FUNARG, FOREFF,
+ SCREG, TDOUBLE|TLDOUBLE,
+ SANY, TDOUBLE|TLDOUBLE,
+ 0, 0,
+ " addi $sp,$sp,-8 # save function arg to stack\n"
+ " s.d AL,($sp)\n"
+ " #nop\n", },
+
+{ STARG, FOREFF,
+ SAREG, TANY,
+ SANY, TSTRUCT,
+ NSPECIAL, 0,
+ "ZH", },
/*
* Indirection operators.
@@ -927,13 +1294,43 @@ struct optab table[] = {
NAREG, RESC1,
" lb A1,AL # (u)char load\n"
" nop\n", },
+
+{ UMUL, INBREG,
+ SANY, TLL,
+ SOREG, TLL,
+ NBREG, RESC1,
+ " lw A1,AL # (u)longlong load - endian problem here?\n"
+ " nop\n"
+ " lw U1,AL\n"
+ " nop\n", },
+
+{ UMUL, INCREG,
+ SANY, TFLOAT,
+ SOREG, TFLOAT,
+ NCREG, RESC1,
+ " l.s A1,AL # float load\n"
+ " nop\n", },
+
+{ UMUL, INCREG,
+ SANY, TDOUBLE|TLDOUBLE,
+ SOREG, TDOUBLE|TLDOUBLE,
+ NCREG, RESC1,
+ " l.d A1,AL # float load\n"
+ " nop\n", },
+
+{ UMUL, INCREG,
+ SANY, TDOUBLE|TLDOUBLE,
+ SAREG, TPOINT,
+ NCREG, RESC1,
+ " l.d A1,(AL)\n"
+ " nop\n", },
{ UMUL, INAREG,
SANY, TPOINT|TWORD,
SNAME, TPOINT|TWORD,
NAREG, RESC1,
" la A1,AL # sname word load\n"
- " lw A1,0(A1)\n"
+ " lw A1,(A1)\n"
" nop\n", },
{ UMUL, INAREG,
@@ -941,7 +1338,7 @@ struct optab table[] = {
SNAME, TSHORT|TUSHORT,
NAREG, RESC1,
" la A1,AL # sname (u)short load\n"
- " lh A1,0(A1)\n"
+ " lh A1,(A1)\n"
" nop\n", },
{ UMUL, INAREG,
@@ -949,30 +1346,54 @@ struct optab table[] = {
SNAME, TCHAR|TUCHAR,
NAREG, RESC1,
" la A1,AL # sname (u)char load\n"
- " lb A1,0(A1)\n"
+ " lb A1,(A1)\n"
" nop\n", },
+{ UMUL, INBREG,
+ SANY, TLL,
+ SNAME, TLL,
+ NBREG|NAREG, RESC1,
+ " la A2,AL # sname (u)long long load - endian problems here?\n"
+ " lw A1,(A1)\n"
+ " nop\n"
+ " lw U1,4(A1)\n"
+ " nop\n", },
+
+
{ UMUL, INAREG,
SANY, TPOINT|TWORD,
SAREG, TPOINT|TWORD,
NAREG, RESC1,
- " lw A1,0(AL) # word load\n"
+ " lw A1,(AL) # word load\n"
" nop\n", },
{ UMUL, INAREG,
SANY, TSHORT|TUSHORT,
SAREG, TSHORT|TUSHORT,
NAREG, RESC1,
- " lh A1,0(AL) # (u)short load\n"
+ " lh A1,(AL) # (u)short load\n"
" nop\n", },
{ UMUL, INAREG,
SANY, TCHAR|TUCHAR,
SAREG, TCHAR|TUCHAR,
NAREG|NASL, RESC1,
- " lb A1,0(AL) # (u)char load\n"
+ " lb A1,(AL) # (u)char load\n"
" nop\n", },
-
+
+{ UMUL, INBREG,
+ SANY, TLL,
+ SCREG, TLL,
+ NBREG, RESC1,
+ " lw A1,(AL) # (u)long long load - endianness problems?\n"
+ " nop\n"
+ " lw U1,4(AL)"
+ " nop\n", },
+
+#define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ FLD, DF(FLD), },
+
{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" },
};