diff options
author | Stefan Kempf <stefan@cvs.openbsd.org> | 2007-12-22 14:12:27 +0000 |
---|---|---|
committer | Stefan Kempf <stefan@cvs.openbsd.org> | 2007-12-22 14:12:27 +0000 |
commit | 6c7d5c4a39afd9cf51518e7b1661b6583a390f15 (patch) | |
tree | 6b2ab6881a011cd79367ee7bc343e30a80c012a4 /usr.bin | |
parent | 364275c5dd83730a39ae5a9a474e904ff4f2b27a (diff) |
Sync with main repo.
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/pcc/mips/TODO | 9 | ||||
-rw-r--r-- | usr.bin/pcc/mips/code.c | 439 | ||||
-rw-r--r-- | usr.bin/pcc/mips/local.c | 396 | ||||
-rw-r--r-- | usr.bin/pcc/mips/local2.c | 691 | ||||
-rw-r--r-- | usr.bin/pcc/mips/macdefs.h | 216 | ||||
-rw-r--r-- | usr.bin/pcc/mips/order.c | 298 | ||||
-rw-r--r-- | usr.bin/pcc/mips/table.c | 905 |
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], ®); + else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE || + DEUNSIGN(sp[i]->stype) == LONGLONG) + param_64bit(sp[i], ®, xtemps && !saveallargs); + else + param_32bit(sp[i], ®, 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, ®num); + 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, ®num); + 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" }, }; |