diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-11-16 08:34:56 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-11-16 08:34:56 +0000 |
commit | 2811f223c5884b622e45a2352c89b8654da77b35 (patch) | |
tree | 4d7c2ae0e613bf90f29c140770fa0751b6b07861 | |
parent | 64b2ea406a218d1075510d5fdbb6bd30b2c0825f (diff) |
sync with repe; commit from gmcgarry@:
Bring MIPS support fully up-to-date. Includes the following changes:
Support use of different assemblers.
Handle big-endian and little-endian code generation.
Start support for n32/n64
PIC code generation
Update to arguments-in-registers infrastructure.
Cleanup handling of branches.
Fix register coloring
Fix structure assignment.
Add longlong instructions
Remove unused functions.
Indentation fixes.
Tested on NetBSD/pmax (little endian).
-rw-r--r-- | usr.bin/pcc/mips/TODO | 2 | ||||
-rw-r--r-- | usr.bin/pcc/mips/code.c | 181 | ||||
-rw-r--r-- | usr.bin/pcc/mips/local.c | 298 | ||||
-rw-r--r-- | usr.bin/pcc/mips/local2.c | 1139 | ||||
-rw-r--r-- | usr.bin/pcc/mips/macdefs.h | 304 | ||||
-rw-r--r-- | usr.bin/pcc/mips/order.c | 502 | ||||
-rw-r--r-- | usr.bin/pcc/mips/table.c | 1039 |
7 files changed, 1974 insertions, 1491 deletions
diff --git a/usr.bin/pcc/mips/TODO b/usr.bin/pcc/mips/TODO index 4b104cf8ee2..63b5f67c34a 100644 --- a/usr.bin/pcc/mips/TODO +++ b/usr.bin/pcc/mips/TODO @@ -1,5 +1,3 @@ -$OpenBSD: TODO,v 1.1 2007/10/07 17:58:51 otto Exp $ - * Look at long long support for the new register allocator. * Add floating point support. diff --git a/usr.bin/pcc/mips/code.c b/usr.bin/pcc/mips/code.c index 1ada0196529..bbeecd96146 100644 --- a/usr.bin/pcc/mips/code.c +++ b/usr.bin/pcc/mips/code.c @@ -1,4 +1,4 @@ -/* $OpenBSD: code.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* $OpenBSD: code.c,v 1.2 2007/11/16 08:34:55 otto Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. @@ -48,7 +48,7 @@ defalign(int n) n /= SZCHAR; if (n == 1) return; - printf(" .align %d\n", n); + printf("\t.align %d\n", n); } /* @@ -64,11 +64,14 @@ defnam(struct symtab *p) c = gcc_findname(p); #endif if (p->sclass == EXTDEF) - printf(" .globl %s\n", c); + printf("\t.globl %s\n", c); +#ifdef USE_GAS + printf("\t.type %s,@object\n", c); + printf("\t.size %s," CONFMT "\n", c, tsize(p->stype, p->sdf, p->ssue)); +#endif printf("%s:\n", c); } - /* * code for the end of a function * deals with struct return here @@ -76,72 +79,65 @@ defnam(struct symtab *p) void efcode() { - NODE *p, *q; - int sz; - if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; } /* - * helper for bfcode() to put register arguments on stack. - */ -static void -argmove(struct symtab *s, int regno) -{ - NODE *p, *r; - - s->sclass = PARAM; - s->soffset = NOOFFSET; - - oalloc(s, &passedargoff); - - spname = s; - p = buildtree(NAME, NIL, NIL); - r = bcon(0); - r->n_op = REG; - r->n_rval = regno; - r->n_type = p->n_type; - r->n_sue = p->n_sue; - r->n_df = p->n_df; - ecode(buildtree(ASSIGN, p, r)); -} - -/* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number */ void -bfcode(struct symtab **a, int n) +bfcode(struct symtab **sp, int cnt) { - int i, m; + NODE *p, *q; + int i, n; - /* Passed arguments start 64 bits above the framepointer. */ - passedargoff = 64; - if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { /* Function returns struct, adjust arg offset */ - for (i = 0; i < n; i++) - a[i]->soffset += SZPOINT(INT); + for (i = 0; i < cnt; i++) + sp[i]->soffset += SZPOINT(INT); } - m = n <= 4 ? n : 4; - - for(i = 0; i < m; i++) { - /* - if(a[i]->stype == LONGLONG || a[i]->stype == ULONGLONG) { - printf("longlong\n"); - argmove(a[i], A0+i); + /* 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); + } - if(i+1 < 4) { - argmove(a[i], A0+i+1); - } - - i++; - } else*/ - argmove(a[i], A0+i); - - } } @@ -173,7 +169,7 @@ bjobcode() void bycode(int t, int i) { - static int lastoctal = 0; + static int lastoctal = 0; /* put byte i+1 in a string */ @@ -182,17 +178,21 @@ bycode(int t, int i) puts("\""); } else { if (i == 0) - printf("\t.ascii \""); - if (t == '\\' || t == '"') { + printf("\t.asciiz \""); + if (t == 0) + return; + else if (t == '\\' || t == '"') { lastoctal = 0; putchar('\\'); putchar(t); + } else if (t == 012) { + printf("\\n"); } else if (t < 040 || t >= 0177) { lastoctal++; printf("\\%o",t); } else if (lastoctal && '0' <= t && t <= '9') { lastoctal = 0; - printf("\"\n\t.ascii \"%c", t); + printf("\"\n\t.asciiz \"%c", t); } else { lastoctal = 0; putchar(t); @@ -201,16 +201,6 @@ bycode(int t, int i) } /* - * n integer words of zeros - */ -void -zecode(int n) -{ - printf(" .zero %d\n", n * (SZINT/SZCHAR)); - inoff += n * SZINT; -} - -/* * return the alignment of field of type t */ int @@ -234,6 +224,59 @@ fldty(struct symtab *p) * XXX - fix genswitch. */ void -genswitch(struct swents **p, int n) +genswitch(int num, struct swents **p, int n) +{ + NODE *r; + int i; + + /* simple switch code */ + for (i = 1; i <= n; ++i) { + /* already in 1 */ + r = tempnode(num, INT, 0, MKSUE(INT)); + r = buildtree(NE, r, bcon(p[i]->sval)); + cbranch(buildtree(NOT, r, NIL), bcon(p[i]->slab)); + } + if (p[0]->slab > 0) + branch(p[0]->slab); +} + +static void +moveargs(NODE **n, int *regp) +{ + NODE *r = *n; + NODE *t; + int sz; + int regnum; + + if (r->n_op == CM) { + moveargs(&r->n_left, regp); + n = &r->n_right; + r = r->n_right; + } + + regnum = *regp; + sz = szty(r->n_type); + + if (regnum + sz <= 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); + } else { + t = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_sue); + } + + *n = t; + *regp += sz; +} + +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + */ +NODE * +funcode(NODE *p) { + int regnum = A0; + moveargs(&p->n_right, ®num); + return p; } diff --git a/usr.bin/pcc/mips/local.c b/usr.bin/pcc/mips/local.c index 554b53190f3..113e420ce6e 100644 --- a/usr.bin/pcc/mips/local.c +++ b/usr.bin/pcc/mips/local.c @@ -1,4 +1,4 @@ -/* $OpenBSD: local.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* $OpenBSD: local.c,v 1.2 2007/11/16 08:34:55 otto Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. @@ -31,33 +31,73 @@ * Simon Olsson (simols-1@student.ltu.se) 2005. */ -# include "pass1.h" +#include "pass1.h" -/* this file contains code which is dependent on the target machine */ +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. + */ NODE * clocal(NODE *p) { - /* this is called to do local transformations on - an expression tree preparitory to its being - written out in intermediate code. - */ - - /* the major essential job is rewriting the - automatic variables and arguments in terms of - REG and OREG nodes */ - /* conversion ops which are not necessary are also clobbered here */ - /* in addition, any special features (such as rewriting - exclusive or) are easily handled here as well */ - - register struct symtab *q; - register NODE *r, *l; - register int o; - register int m, ml; + struct symtab *q; + NODE *r, *l; + int o; + int m, ml; TWORD t; //printf("in:\n"); //fwalk(p, eprint, 0); + switch( o = p->n_op ){ case NAME: @@ -71,7 +111,7 @@ clocal(NODE *p) /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); r->n_lval = 0; - r->n_rval = FPREG; + r->n_rval = FP; p = stref(block(STREF, r, p, 0, 0, 0)); break; @@ -158,6 +198,16 @@ clocal(NODE *p) return l; } +#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 && @@ -171,13 +221,11 @@ clocal(NODE *p) } } -#if 0 if ((p->n_type == INT || p->n_type == UNSIGNED) && ISPTR(l->n_type)) { nfree(p); return l; } -#endif o = l->n_op; m = p->n_type; @@ -260,15 +308,14 @@ clocal(NODE *p) /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; - p->n_left = block(REG, NIL, NIL, p->n_type, 0, - MKSUE(INT)); - p->n_left->n_rval = RETREG; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT)); + p->n_left->n_rval = RETREG(p->n_type); break; } + //printf("ut:\n"); //fwalk(p, eprint, 0); - return(p); } @@ -309,23 +356,20 @@ cisreg(TWORD t) * being added to a pointer of type t, in order to be off bits offset * into a structure * t, d, and s are the type, dimension offset, and sizeoffset - * For pdp10, return the type-specific index number which calculation - * is based on its size. For example, short a[3] would return 3. * Be careful about only handling first-level pointers, the following * indirections must be fullword. */ NODE * offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue) { - register NODE *p; + NODE *p; if (xdebug) printf("offcon: OFFSZ %lld type %x dim %p siz %d\n", off, t, d, sue->suesize); - p = bcon(0); - p->n_lval = off/SZCHAR; /* Default */ - return(p); + p = bcon(off/SZCHAR); + return p; } /* @@ -370,65 +414,80 @@ spalloc(NODE *t, NODE *p, OFFSZ off) * mat be associated with a label */ void -ninval(NODE *p) +ninval(CONSZ off, int fsz, NODE *p) { - struct symtab *q; - TWORD t; + union { float f; double d; long double l; int i[3]; } u; + struct symtab *q; + TWORD t; +#ifndef USE_GAS + int i; +#endif - p = p->n_left; - t = p->n_type; - if (t > BTMASK) - t = INT; /* pointer */ + t = p->n_type; + if (t > BTMASK) + t = INT; /* pointer */ - switch (t) { - case LONGLONG: - case ULONGLONG: - inval(p->n_lval & 0xffffffff); - inval(p->n_lval >> 32); - break; - case INT: - case UNSIGNED: - printf("\t.long 0x%x", (int)p->n_lval); - if ((q = p->n_sp) != NULL) { - if ((q->sclass == STATIC && q->slevel > 0) || - q->sclass == ILABEL) { - printf("+" LABFMT, q->soffset); - } else - printf("+%s", exname(q->sname)); - } - printf("\n"); - break; - default: - cerror("ninval"); - } -} + if (p->n_op != ICON && p->n_op != FCON) + cerror("ninval: init node not constant"); -/* - * print out an integer. - */ -void -inval(CONSZ word) -{ - word &= 0xffffffff; - printf(" .long 0x%llx\n", word); -} + if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) + uerror("element not constant"); -/* output code to initialize a floating point value */ -/* the proper alignment has been obtained */ -void -finval(NODE *p) -{ - switch (p->n_type) { - case LDOUBLE: - printf("\t.tfloat\t0t%.20Le\n", p->n_dcon); - break; - case DOUBLE: - printf("\t.dfloat\t0d%.20e\n", (double)p->n_dcon); - break; - case FLOAT: - printf("\t.ffloat\t0f%.20e\n", (float)p->n_dcon); - break; - } + switch (t) { + case LONGLONG: + case ULONGLONG: +#ifdef USE_GAS + printf("\t.dword 0x%llx\n", (long long)p->n_lval); +#else + i = (p->n_lval >> 32); + p->n_lval &= 0xffffffff; + p->n_type = INT; + ninval(off, 32, p); + p->n_lval = i; + ninval(off+32, 32, p); +#endif + break; + case BOOL: + if (p->n_lval > 1) + p->n_lval = p->n_lval != 0; + /* FALLTHROUGH */ + case INT: + case UNSIGNED: + printf("\t.word 0x%x", (int)p->n_lval); + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0) || + q->sclass == ILABEL) { + printf("+" LABFMT, q->soffset); + } else + printf("+%s", exname(q->sname)); + } + printf("\n"); + break; + case SHORT: + case USHORT: + printf("\t.half 0x%x\n", (int)p->n_lval & 0xffff); + break; + case CHAR: + case UCHAR: + printf("\t.byte %d\n", (int)p->n_lval & 0xff); + break; + case LDOUBLE: + u.i[2] = 0; + u.l = (long double)p->n_dcon; + printf("\t.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]); + break; + case FLOAT: + u.f = (float)p->n_dcon; + printf("\t.word\t0x%x\n", u.i[0]); + break; + default: + cerror("ninval"); + } } /* make a name look like an external name in the local machine */ @@ -504,12 +563,12 @@ lcommdec(struct symtab *q) off = (off+(SZCHAR-1))/SZCHAR; if (q->slevel == 0) #ifdef GCC_COMPAT - printf(" .lcomm %s,0%o\n", gcc_findname(q), off); + printf("\t.lcomm %s,0%o\n", gcc_findname(q), off); #else - printf(" .lcomm %s,0%o\n", exname(q->sname), off); + printf("\t.lcomm %s,0%o\n", exname(q->sname), off); #endif else - printf(" .lcomm " LABFMT ",0%o\n", q->soffset, off); + printf("\t.lcomm " LABFMT ",0%o\n", q->soffset, off); } /* @@ -521,13 +580,68 @@ deflab1(int label) printf(LABFMT ":\n", label); } -static char *loctbl[] = { "text", "data", "section .rodata", "section .rodata" }; +static char *loctbl[] = { "text", "data", "bss", "data" }; void setloc1(int locc) { - if (locc == lastloc) + //printf("setloc1(%d)\n", locc); + if ((locc == lastloc) || (lastloc == DATA && locc == STRNG) || (locc == STRNG || lastloc == DATA)) return; lastloc = locc; - printf(" .%s\n", loctbl[locc]); + printf("\t.%s\n", loctbl[locc]); +} + +/* + * Initialize a bitfield. + */ +void +infld(CONSZ off, int fsz, CONSZ val) +{ + if (idebug) + printf("infld off %lld, fsz %d, val %lld inbits %d\n", + off, fsz, val, inbits); + val &= (1 << fsz)-1; + while (fsz + inbits >= SZCHAR) { + inval |= (val << inbits); + printf("\t.byte %d\n", inval & 255); + fsz -= (SZCHAR - inbits); + val >>= (SZCHAR - inbits); + inval = inbits = 0; + } + if (fsz) { + inval |= (val << inbits); + inbits += fsz; + } +} + +/* + * set fsz bits in sequence to zero. + */ +void +zbits(OFFSZ off, int fsz) +{ + int m; + + if (idebug) + printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits); + if ((m = (inbits % SZCHAR))) { + m = SZCHAR - m; + if (fsz < m) { + inbits += fsz; + return; + } else { + fsz -= m; + printf("\t.byte %d\n", inval); + inval = inbits = 0; + } + } + if (fsz >= SZCHAR) { + printf("\t.zero %d\n", fsz/SZCHAR); + fsz -= (fsz/SZCHAR) * SZCHAR; + } + if (fsz) { + inval = 0; + inbits = fsz; + } } diff --git a/usr.bin/pcc/mips/local2.c b/usr.bin/pcc/mips/local2.c index 11d151a7f05..056762c1d61 100644 --- a/usr.bin/pcc/mips/local2.c +++ b/usr.bin/pcc/mips/local2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: local2.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* $OpenBSD: local2.c,v 1.2 2007/11/16 08:34:55 otto Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. @@ -31,121 +31,125 @@ * Simon Olsson (simols-1@student.ltu.se) 2005. */ -# include "pass2.h" -# include <ctype.h> +#include <ctype.h> +#include <assert.h> -void acon(NODE *p); -int argsize(NODE *p); -void genargs(NODE *p); -static void sconv(NODE *p); -void branchfunc(NODE *p); -void offchg(NODE *p); +#include "pass1.h" +#include "pass2.h" -void -lineid(int l, char *fn) -{ - /* identify line l and file fn */ - printf("# line %d, file %s\n", l, fn); -} +static int argsiz(NODE * p); void deflab(int label) { - printf(LABFMT ":\n", label); + printf(LABFMT ":\n", label); } static int regoff[32]; static TWORD ftype; /* - * Print out the prolog assembler. - * addto and regoff are already calculated. - */ -static void -prtprolog(struct interpass_prolog *ipp, int addto) -{ - int i, j; - - printf(" addi $sp, $sp, -%d\n", addto + 8); - printf(" sw $ra, %d($sp)\n", addto + 4); - printf(" sw $fp, %d($sp)\n", addto); - printf(" addi $fp, $sp, %d\n", addto); - - for (i = ipp->ipp_regs, j = 0; i; i >>= 1, j++) - if (i & 1) - fprintf(stdout, " sw %s, -%d(%s)\n", - rnames[j], regoff[j], rnames[FPREG]); -} - -/* * calculate stack size and offsets */ static int -offcalc(struct interpass_prolog *ipp) +offcalc(struct interpass_prolog * ipp) { - int i, j, addto; + int i, j, addto; - addto = p2maxautooff; - if (addto >= AUTOINIT) - addto -= AUTOINIT; - addto /= SZCHAR; + addto = p2maxautooff; - for (i = ipp->ipp_regs, j = 0; i ; i >>= 1, j++) { - if (i & 1) { - addto += SZINT/SZCHAR; - regoff[j] = addto; + for (i = ipp->ipp_regs, j = 0; i; i >>= 1, j++) { + if (i & 1) { + addto += SZINT / SZCHAR; + regoff[j] = addto; + } } - } - - return addto; + + return addto; } +/* + * Print out the prolog assembler. + */ void -prologue(struct interpass_prolog *ipp) +prologue(struct interpass_prolog * ipp) { - int addto; - - ftype = ipp->ipp_type; - if (ipp->ipp_vis) - printf(" .globl %s\n", ipp->ipp_name); - printf(" .align 4\n"); - printf("%s:\n", ipp->ipp_name); - /* - * We here know what register to save and how much to - * add to the stack. - */ - addto = offcalc(ipp); - prtprolog(ipp, addto); + int addto; + int i, j; + + ftype = ipp->ipp_type; + printf("\t.align 2\n"); + if (ipp->ipp_vis) + printf("\t.globl %s\n", ipp->ipp_name); + printf("\t.ent %s\n", ipp->ipp_name); + 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]); + printf("\tmove %s,%s\n", rnames[FP], rnames[SP]); + if (addto) + printf("\taddi %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", + rnames[j], regoff[j], rnames[FP]); } void -eoftn(struct interpass_prolog *ipp) +eoftn(struct interpass_prolog * ipp) { - int i, j; - int addto; - - addto = offcalc(ipp); - - if (ipp->ipp_ip.ip_lbl == 0) - return; /* no code needs to be generated */ - - /* return from function code */ - for (i = ipp->ipp_regs, j = 0; i ; i >>= 1, j++) { - if (i & 1) - fprintf(stdout, " lw %s, -%d(%s)\n", - rnames[j], regoff[j], rnames[FPREG]); - } - - printf(" lw $ra, %d($sp)\n", addto + 4); - printf(" lw $fp, %d($sp)\n", addto); - printf(" addi $sp, $sp, %d\n", addto + 8); - - /* struct return needs special treatment */ - if (ftype == STRTY || ftype == UNIONTY) { - /* XXX - implement struct return support. */ - } else { - printf(" jr $ra\n nop\n"); - } + 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 */ + + /* 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", + 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); + + /* 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); +#endif } /* @@ -156,619 +160,596 @@ eoftn(struct interpass_prolog *ipp) void hopcode(int f, int o) { - char *str; - - switch (o) { - case PLUS: - str = "addu"; - break; - case MINUS: - str = "subu"; - break; - case AND: - str = "and"; - break; - case OR: - str = "or"; - break; - case ER: - str = "xor"; - break; - default: - comperr("hopcode2: %d", o); - str = 0; /* XXX gcc */ - } - - printf("%s%c", str, f); + char *str; + + switch (o) { + case EQ: + str = "beqz"; /* pseudo-op */ + break; + case NE: + str = "bnez"; /* pseudo-op */ + break; + case LE: + str = "blez"; + break; + case LT: + str = "bltz"; + break; + case GE: + str = "bgez"; + break; + case GT: + str = "bgtz"; + break; + case PLUS: + str = "addu"; + break; + case MINUS: + str = "subu"; + break; + case AND: + str = "and"; + break; + case OR: + str = "or"; + break; + case ER: + str = "xor"; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + + printf("%s%c", str, f); } char * -rnames[] = { /* keyed to register number tokens */ - "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8", - "$t9", "$v0", "$v1", "$zero", "$at", "$a0", "$a1", "$a2", "$a3", - "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", "$k0", - "$k1", "$gp", "$sp", "$fp", "$ra", +rnames[] = { /* keyed to register number tokens */ +#ifdef USE_GAS + /* gnu assembler */ + "$zero", "$at", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$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", +#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", +#endif + "$f0", "$f1", "$f2", }; + int -tlen(p) NODE *p; +tlen(NODE *p) { - switch(p->n_type) { - case CHAR: - case UCHAR: - return(1); - - case SHORT: - case USHORT: - return(SZSHORT/SZCHAR); - - case DOUBLE: - return(SZDOUBLE/SZCHAR); - - case INT: - case UNSIGNED: - case LONG: - case ULONG: - return(SZINT/SZCHAR); - - case LONGLONG: - case ULONGLONG: - return SZLONGLONG/SZCHAR; - - default: - if (!ISPTR(p->n_type)) - comperr("tlen type %d not pointer"); - return SZPOINT(p->n_type)/SZCHAR; - } + switch (p->n_type) { + case CHAR: + case UCHAR: + return (1); + + case SHORT: + case USHORT: + return (SZSHORT / SZCHAR); + + case DOUBLE: + return (SZDOUBLE / SZCHAR); + + case INT: + case UNSIGNED: + case LONG: + case ULONG: + return (SZINT / SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG / SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type) / SZCHAR; + } } +#if 0 /* * Push a structure on stack as argument. * the scratch registers are already free here */ static void -starg(NODE *p) +starg(NODE * p) { - FILE *fp = stdout; - - if (p->n_left->n_op == REG && p->n_left->n_type == PTR+STRTY) - return; /* already on stack */ + if (p->n_left->n_op == REG && p->n_left->n_type == PTR + STRTY) + return; /* already on stack */ +} +#endif +/* + * Structure assignment. + */ +static void +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); + if (p->n_left->n_op == OREG) { + printf("\taddi %s,%s," CONFMT " # dest address\n", + rnames[A0], rnames[p->n_left->n_rval], + p->n_left->n_lval); + } else if (p->n_left->n_op == NAME) { + printf("\tla %s,", rnames[A0]); + 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("\tnop\n"); + printf("\taddi %s,%s,16\n", rnames[SP], rnames[SP]); } -void -zzzcode(NODE *p, int c) +static void +llshiftop(NODE *p) { - NODE *r; - - switch (c) { - case 'A': /* Set the right offset for SCON OREG to REG */ - offchg(p); - break; - - case 'B': - /* - * Function arguments - */ - - break; - - case 'C': /* remove arguments from stack after subroutine call */ - printf(" addi %s, %s, %d\n", - rnames[STKREG], rnames[STKREG], (p->n_rval + 4) * 4); - break; - - case 'H': /* Fix correct order of sub from stack */ - /* Check which leg was evaluated first */ - if ((p->n_su & DORIGHT) == 0) - putchar('r'); - break; - - case 'I': /* high part of init constant */ - if (p->n_name[0] != '\0') - comperr("named highword"); - fprintf(stdout, CONFMT, (p->n_lval >> 32) & 0xffffffff); - break; - - case 'Q': /* Branch instructions */ - branchfunc(p); - break; - - default: - comperr("zzzcode %c", c); - } + assert(p->n_right->n_op == ICON); + + if (p->n_op == LS && p->n_right->n_lval < 32) { + expand(p, INBREG, "\tsrl A1,AL,32-AR ; 64-bit left-shift\n"); + 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"); + 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"); + } } -/* set up temporary registers */ -void -setregs() +/* + * Emulate unsupported instruction. + */ +static void +emulop(NODE *p) { - /* 12 free regs on the mips (0-9, temporary and 10-11 is v0 and v1). */ - fregs = 12; + char *ch; + + 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("\tnop\n"); + printf("\taddi %s,%s,16\n", rnames[SP], rnames[SP]); } -/*ARGSUSED*/ -int -rewfld(NODE *p) +void +zzzcode(NODE * p, int c) { - return(1); + int sz; + + switch (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); + break; + + case 'I': /* high part of init constant */ + if (p->n_name[0] != '\0') + comperr("named highword"); + fprintf(stdout, CONFMT, (p->n_lval >> 32) & 0xffffffff); + break; + + case 'Q': /* emit struct assign */ + stasg(p); + break; + + case 'O': /* 64-bit left and right shift operators */ + llshiftop(p); + break; + + case 'E': /* emit emulated ops */ + emulop(p); + break; + + default: + comperr("zzzcode %c", c); + } } -int canaddr(NODE *); +/* ARGSUSED */ int -canaddr(NODE *p) +rewfld(NODE * p) { - int o = p->n_op; - - if (o==NAME || o==REG || o==ICON || o==OREG || - (o==UMUL && shumul(p->n_left))) - return(1); - return(0); + return (1); } /* * Does the bitfield shape match? */ int -flshape(NODE *p) +flshape(NODE * p) { - int o = p->n_op; + int o = p->n_op; - if (o == OREG || o == REG || o == NAME) - return SRDIR; /* Direct match */ - if (o == UMUL && shumul(p->n_left)) - return SROREG; /* Convert into oreg */ - return SRREG; /* put it into a register */ + if (o == OREG || o == REG || o == NAME) + return SRDIR; /* Direct match */ + if (o == UMUL && shumul(p->n_left)) + return SROREG; /* Convert into oreg */ + return SRREG; /* put it into a register */ } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int -shtemp(NODE *p) +shtemp(NODE * p) { - return 0; + return 0; #if 0 - int r; + int r; - if (p->n_op == STARG ) - p = p->n_left; + if (p->n_op == STARG) + p = p->n_left; - switch (p->n_op) { - case REG: - return (!istreg(p->n_rval)); + switch (p->n_op) { + case REG: + return (!istreg(p->n_rval)); - case OREG: - r = p->n_rval; - if (R2TEST(r)) { - if (istreg(R2UPK1(r))) - return(0); - r = R2UPK2(r); - } - return (!istreg(r)); + case OREG: + r = p->n_rval; + if (R2TEST(r)) { + if (istreg(R2UPK1(r))) + return (0); + r = R2UPK2(r); + } + return (!istreg(r)); - case UMUL: - p = p->n_left; - return (p->n_op != UMUL && shtemp(p)); - } + case UMUL: + p = p->n_left; + return (p->n_op != UMUL && shtemp(p)); + } - if (optype(p->n_op) != LTYPE) - return(0); - return(1); + if (optype(p->n_op) != LTYPE) + return (0); + return (1); #endif } void adrcon(CONSZ val) { - printf(CONFMT, val); + printf(CONFMT, val); } void -conput(FILE *fp, NODE *p) +conput(FILE * fp, NODE * p) { - int val = p->n_lval; - - switch (p->n_op) { - case ICON: - if (p->n_name[0] != '\0') { - fprintf(fp, "%s", p->n_name); - if (val) - fprintf(fp, "+%d", val); - } else - fprintf(fp, "%d", val); - return; - - default: - comperr("illegal conput"); - } + int val = p->n_lval; + + switch (p->n_op) { + case ICON: + if (p->n_name[0] != '\0') { + fprintf(fp, "%s", p->n_name); + if (val) + fprintf(fp, "+%d", val); + } else + fprintf(fp, "%d", val); + return; + + default: + comperr("illegal conput"); + } } -/*ARGSUSED*/ +/* ARGSUSED */ void -insput(NODE *p) +insput(NODE * p) { - comperr("insput"); + comperr("insput"); } /* - * Write out the upper address, like the upper register of a 2-register - * reference, or the next memory location. + * Print lower or upper name of 64-bit register. */ -void -upput(NODE *p, int size) +static void +print_reg64name(FILE *fp, int rval, int hi) { + int off = 3 * (hi != 0); - size /= SZCHAR; - switch (p->n_op) { - case REG: - fputs(rnames[p->n_rval + 1], stdout); - break; - - case NAME: - case OREG: - p->n_lval += size; - adrput(stdout, p); - p->n_lval -= size; - break; - case ICON: - fprintf(stdout, CONFMT, p->n_lval >> 32); - break; - default: - comperr("upput bad op %d size %d", p->n_op, size); - } + fprintf(fp, "%c%c", + rnames[rval][off], + rnames[rval][off + 1]); + if (rnames[rval][off + 2]) + fputc(rnames[rval][off + 2], fp); } +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ void -adrput(FILE *io, NODE *p) +upput(NODE * p, int size) { - int r; - /* output an address, with offsets, from p */ - - if (p->n_op == FLD) - p = p->n_left; - - switch (p->n_op) { - - case NAME: - if (p->n_name[0] != '\0') - fputs(p->n_name, io); - if (p->n_lval != 0) - fprintf(io, "+" CONFMT, p->n_lval); - return; - - case OREG: - r = p->n_rval; - - if (p->n_lval) - fprintf(io, "%d", (int)p->n_lval); - - fprintf(io, "(%s)", rnames[p->n_rval]); - return; - case ICON: - /* addressable value of the constant */ - //fputc('$', io); - conput(io, p); - return; - - case MOVE: - case REG: - fprintf(io, "%s", rnames[p->n_rval]); - return; - - default: - comperr("illegal address, op %d, node %p", p->n_op, p); - return; - - } + + size /= SZCHAR; + switch (p->n_op) { + case REG: + print_reg64name(stdout, p->n_rval, 1); + break; + + case NAME: + case OREG: + p->n_lval += size; + adrput(stdout, p); + p->n_lval -= size; + break; + case ICON: + fprintf(stdout, CONFMT, p->n_lval >> 32); + break; + default: + comperr("upput bad op %d size %d", p->n_op, size); + } } -/* This function changes the offset of a OREG when doing a type cast. */ void -offchg(NODE *p) +adrput(FILE * io, NODE * p) { + int r; + /* output an address, with offsets, from p */ - if (p->n_op != SCONV) { - comperr("illegal offchg"); - } - -#ifndef RTOLBYTES - /* change the offset depending on source and target types */ - switch(p->n_left->n_type) { - case SHORT: - case USHORT: - if (p->n_type == CHAR || p->n_type == UCHAR) { - p->n_left->n_lval += 1; - } - break; - - case UNSIGNED: - case ULONG: - case INT: - case LONG: - if (p->n_type == CHAR || p->n_type == UCHAR) { - p->n_left->n_lval += 3; - } else if (p->n_type == SHORT || p->n_type == USHORT) { - p->n_left->n_lval += 2; - } - break; - - /* This code is not tested! - case LONGLONG: - case ULONGLONG: - if (p->n_type == CHAR || p->n_type == UCHAR) { - p->n_lval += 7; - } else if (p->n_type == SHORT || p->n_type == USHORT) { - p->n_lval += 6; - } else if (p->n_type == UNSIGNED || p->n_type == ULONG || - p->n_type == INT || p->n_type == LONG) { - - p->n_lval += 4; - } - break; - */ - } -#endif + if (p->n_op == FLD) + p = p->n_left; - /* print the code for the OREG */ - if (p->n_left->n_lval) { - printf("%d", (int)p->n_left->n_lval); - } - - printf("(%s)", rnames[p->n_left->n_rval]); - -} + switch (p->n_op) { + + case NAME: + if (p->n_name[0] != '\0') + fputs(p->n_name, io); + if (p->n_lval != 0) + fprintf(io, "+" CONFMT, p->n_lval); + return; + + case OREG: + r = p->n_rval; + + if (p->n_lval) + fprintf(io, "%d", (int) p->n_lval); + + fprintf(io, "(%s)", rnames[p->n_rval]); + return; + case ICON: + /* addressable value of the constant */ + //fputc('$', io); + conput(io, p); + return; + case MOVE: + case REG: + if (DEUNSIGN(p->n_type) == LONGLONG) + print_reg64name(io, p->n_rval, 0); + else + fputs(rnames[p->n_rval], io); + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; -/* printf conditional and unconditional branches */ + } +} + +/* printf conditional and unconditional branches */ void cbgen(int o, int lab) { } -void branchfunc(NODE *p) +void +myreader(struct interpass * ipole) { - int o = p->n_op; - - if (o < EQ || o > GT) - cerror("bad binary conditional branch: %s", opst[o]); - - switch(o) { - case EQ: - printf("beq "); - adrput(stdout, getlr(p, 'L')); - printf(", "); - adrput(stdout, getlr(p, 'R')); - printf(", "); - break; - case NE: - printf("bne "); - adrput(stdout, getlr(p, 'L')); - printf(", "); - adrput(stdout, getlr(p, 'R')); - printf(", "); - break; - case LE: - expand(p, 0, "blez A1, "); - break; - case LT: - expand(p, 0, "bltz A1, "); - break; - case GE: - expand(p, 0, "bgez A1, "); - break; - case GT: - expand(p, 0, "bgez A1, "); - break; - } - printf(".L%d\n", p->n_label); - printf(" nop\n"); } -#if 0 /* - * Do some local optimizations that must be done after optim is called. + * Remove some PCONVs after OREGs are created. */ static void -optim2(NODE *p) +pconv2(NODE * p) { - int op = p->n_op; - int m, ml; - NODE *l; - - /* Remove redundant PCONV's */ - if (op == PCONV) { - l = p->n_left; - m = BTYPE(p->n_type); - ml = BTYPE(l->n_type); - if ((m == INT || m == LONG || m == LONGLONG || m == FLOAT || - m == DOUBLE || m == STRTY || m == UNIONTY || m == ENUMTY || - m == UNSIGNED || m == ULONG || m == ULONGLONG) && - (ml == INT || ml == LONG || ml == LONGLONG || ml == FLOAT || - ml == DOUBLE || ml == STRTY || ml == UNIONTY || - ml == ENUMTY || ml == UNSIGNED || ml == ULONG || - ml == ULONGLONG) && ISPTR(l->n_type)) { - *p = *l; - nfree(l); - op = p->n_op; - } else - if (ISPTR(DECREF(p->n_type)) && - (l->n_type == INCREF(STRTY))) { - *p = *l; - nfree(l); - op = p->n_op; - } else - if (ISPTR(DECREF(l->n_type)) && - (p->n_type == INCREF(INT) || - p->n_type == INCREF(STRTY) || - p->n_type == INCREF(UNSIGNED))) { - *p = *l; - nfree(l); - op = p->n_op; + NODE *q; + + if (p->n_op == PLUS) { + if (p->n_type == (PTR | SHORT) || p->n_type == (PTR | USHORT)) { + if (p->n_right->n_op != ICON) + return; + if (p->n_left->n_op != PCONV) + return; + if (p->n_left->n_left->n_op != OREG) + return; + q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + /* + * This will be converted to another OREG later. + */ } - - } - /* Add constands, similar to the one in optim() */ - if (op == PLUS && p->n_right->n_op == ICON) { - l = p->n_left; - if (l->n_op == PLUS && l->n_right->n_op == ICON && - (p->n_right->n_name[0] == '\0' || - l->n_right->n_name[0] == '\0')) { - l->n_right->n_lval += p->n_right->n_lval; - if (l->n_right->n_name[0] == '\0') - l->n_right->n_name = p->n_right->n_name; - nfree(p->n_right); - *p = *l; - nfree(l); } - } - - /* Convert "PTR undef" (void *) to "PTR uchar" */ - /* XXX - should be done in MI code */ - if (BTYPE(p->n_type) == VOID) - p->n_type = (p->n_type & ~BTMASK) | UCHAR; } -#endif -static void -myhardops(NODE *p) +void +mycanon(NODE * p) { - int ty = optype(p->n_op); - NODE *l, *r, *q; - - if (ty == UTYPE) - return myhardops(p->n_left); - if (ty != BITYPE) - return; - myhardops(p->n_right); - if (p->n_op != STASG) - return; - - /* - * If the structure size to copy is less than 32 byte, let it - * be and generate move instructions later. Otherwise convert it - * to memcpy() calls, unless it has a STCALL function as its - * right node, in which case it is untouched. - * STCALL returns are handled special. - */ - if (p->n_right->n_op == STCALL || p->n_right->n_op == USTCALL) - return; - l = p->n_left; - if (l->n_op == UMUL) - l = nfree(l); - else if (l->n_op == NAME) { - l->n_op = ICON; /* Constant reference */ - l->n_type = INCREF(l->n_type); - } else - comperr("myhardops"); - r = p->n_right; - q = mkbinode(CM, l, r, 0); - q = mkbinode(CM, q, mklnode(ICON, p->n_stsize, 0, INT), 0); - p->n_op = CALL; - p->n_right = q; - p->n_left = mklnode(ICON, 0, 0, 0); - p->n_left->n_name = "memcpy"; + walkf(p, pconv2); } void -myreader(NODE *p) +myoptim(struct interpass * ip) { - int e2print(NODE *p, int down, int *a, int *b); - // walkf(p, optim2); - myhardops(p); - if (x2debug) { - printf("myreader final tree:\n"); - fwalk(p, e2print, 0); - } } /* - * Remove some PCONVs after OREGs are created. + * Move data between registers. While basic registers aren't a problem, + * we have to handle the special case of overlapping composite registers. */ -static void -pconv2(NODE *p) +void +rmove(int s, int d, TWORD t) { - NODE *q; - - if (p->n_op == PLUS) { - if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { - if (p->n_right->n_op != ICON) - return; - if (p->n_left->n_op != PCONV) - return; - if (p->n_left->n_left->n_op != OREG) - return; - q = p->n_left->n_left; - nfree(p->n_left); - p->n_left = q; - /* - * This will be converted to another OREG later. - */ - } - } + switch (t) { + case LONGLONG: + case ULONGLONG: + if (s == d+1) { + /* dh = sl, copy low word first */ + printf("\tmove "); + print_reg64name(stdout, d, 0); + print_reg64name(stdout, s, 0); + printf("\tmove "); + print_reg64name(stdout, d, 1); + print_reg64name(stdout, s, 1); + } else { + /* copy high word first */ + printf("\tmove "); + print_reg64name(stdout, d, 1); + print_reg64name(stdout, s, 1); + printf("\tmove "); + print_reg64name(stdout, d, 0); + print_reg64name(stdout, s, 0); + } + printf("\n"); + break; + case LDOUBLE: +#ifdef notdef + /* a=b()*c(); will generate this */ + comperr("bad float rmove: %d %d", s, d); +#endif + break; + default: + printf("\tmove %s,%s\n", rnames[d], rnames[s]); + } } -void -mycanon(NODE *p) + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + * + * On MIPS, we have: + * + * 32 32-bit registers (8 reserved) + * 26 64-bit pseudo registers (1 unavailable) + * 3? floating-point registers + */ +int +COLORMAP(int c, int *r) { - walkf(p, pconv2); + int num = 0; + + switch (c) { + case CLASSA: + num += r[CLASSA]; + num += 2*r[CLASSB]; + return num < 24; + case CLASSB: + num += 2*r[CLASSB]; + num += r[CLASSA]; + return num < 25; + case CLASSC: + num += r[CLASSC]; + return num < 3; + } + assert(0); + return 0; /* XXX gcc */ } -void -mygenregs(NODE *p) +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) { - if (p->n_op == MINUS && p->n_type == DOUBLE && - (p->n_su & (LMASK|RMASK)) == (LREG|RREG)) { - p->n_su |= DORIGHT; - } - /* Must walk down correct node first for logops to work */ - if (p->n_op != CBRANCH) - return; - p = p->n_left; - if ((p->n_su & (LMASK|RMASK)) != (LREG|RREG)) - return; - p->n_su &= ~DORIGHT; + return CLASSA; } /* - * Remove last goto. + * Calculate argument sizes. */ void -myoptim(struct interpass *ip) +lastcall(NODE * p) { -#if 0 - while (ip->sqelem.sqe_next->type != IP_EPILOG) - ip = ip->sqelem.sqe_next; - if (ip->type != IP_NODE || ip->ip_node->n_op != GOTO) - comperr("myoptim"); - tfree(ip->ip_node); - *ip = *ip->sqelem.sqe_next; -#endif -} + NODE *op = p; + int size = 0; -struct hardops hardops[] = { - { MUL, LONGLONG, "__muldi3" }, - { MUL, ULONGLONG, "__muldi3" }, - { DIV, LONGLONG, "__divdi3" }, - { DIV, ULONGLONG, "__udivdi3" }, - { MOD, LONGLONG, "__moddi3" }, - { MOD, ULONGLONG, "__umoddi3" }, - { RS, LONGLONG, "__ashrdi3" }, - { RS, ULONGLONG, "__lshrdi3" }, - { LS, LONGLONG, "__ashldi3" }, - { LS, ULONGLONG, "__ashldi3" }, -#if 0 - { STASG, PTR+STRTY, "memcpy" }, - { STASG, PTR+UNIONTY, "memcpy" }, +#ifdef PCC_DEBUG + if (x2debug) + printf("lastcall:\n"); #endif - { 0 }, -}; -void -rmove(int s, int d, TWORD t) -{ - printf(" move %s, %s\n", rnames[d], rnames[s]); + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + for (p = p->n_right; p->n_op == CM; p = p->n_left) + size += argsiz(p->n_right); + size += argsiz(p); + op->n_qual = size; /* XXX */ } +static int +argsiz(NODE * p) +{ + TWORD t = p->n_type; + + if (t < LONGLONG || t == FLOAT || t > BTMASK) + return 4; + if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) + return 8; + if (t == LDOUBLE) + return 12; + if (t == STRTY || t == UNIONTY) + return p->n_stsize; + comperr("argsiz"); + return 0; +} - +/* + * Special shapes. + */ +int +special(NODE * p, int shape) +{ + return SRNOPE; +} diff --git a/usr.bin/pcc/mips/macdefs.h b/usr.bin/pcc/mips/macdefs.h index 71e5b17f955..20f0cf37d02 100644 --- a/usr.bin/pcc/mips/macdefs.h +++ b/usr.bin/pcc/mips/macdefs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: macdefs.h,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* $OpenBSD: macdefs.h,v 1.2 2007/11/16 08:34:55 otto Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. @@ -35,6 +35,10 @@ * Machine-dependent defines for both passes. */ +#if TARGOS == netbsd +#define USE_GAS +#endif + /* * Convert (multi-)character constant to integer. * Assume: If only one value; store at left side (char size), otherwise @@ -42,17 +46,18 @@ */ #define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); -#define ARGINIT 64 /* # bits above fp where arguments start */ -#define AUTOINIT 0 /* # bits below fp where automatics start */ +#define ARGINIT (12*8) /* # bits above fp where arguments start */ +#define AUTOINIT (0) /* # bits below fp where automatics start */ /* * Storage space requirements */ #define SZCHAR 8 +#define SZBOOL 32 #define SZINT 32 #define SZFLOAT 32 #define SZDOUBLE 64 -#define SZLDOUBLE 96 +#define SZLDOUBLE 128 #define SZLONG 32 #define SZSHORT 16 #define SZLONGLONG 64 @@ -62,6 +67,7 @@ * Alignment constraints */ #define ALCHAR 8 +#define ALBOOL 32 #define ALINT 32 #define ALFLOAT 32 #define ALDOUBLE 32 @@ -92,8 +98,10 @@ #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL -/* Default char is unsigned */ #undef CHAR_UNSIGNED +#define TARGET_STDARGS +#define BOOL_TYPE INT +#define WCHAR_TYPE INT /* * Use large-enough types. @@ -103,31 +111,17 @@ typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "%lld" /* format for printing constants */ -#define LABFMT ".L%d" /* format for printing labels */ -#define STABLBL ".LL%d" /* format for stab (debugging) labels */ -#ifdef FORTRAN -#define XL 8 -#define FLABELFMT "%s:\n" -#define USETEXT ".text" -#define USECONST ".data\t0" /* XXX - fix */ -#define USEBSS ".data\t1" /* XXX - fix */ -#define USEINIT ".data\t2" /* XXX - fix */ -#define MAXREGVAR 3 /* XXX - fix */ -#define BLANKCOMMON "_BLNK_" -#define MSKIREG (M(TYSHORT)|M(TYLONG)) -#define TYIREG TYLONG -#define FSZLENG FSZLONG -#define FUDGEOFFSET 1 -#define AUTOREG EBP -#define ARGREG EBP -#define ARGOFFSET 4 +#ifdef USE_GAS +#define LABFMT "$L%d" /* format for printing labels */ +#define STABLBL "$LL%d" /* format for stab (debugging) labels */ +#else +#define LABFMT "L%d" /* format for printing labels */ +#define STABLBL "LL%d" /* format for stab (debugging) labels */ #endif #define BACKAUTO /* stack grows negatively for automatics */ #define BACKTEMP /* stack grows negatively for temporaries */ -#define MYP2TREE(p) myp2tree(p); - #undef FIELDOPS /* no bit-field instructions */ #define RTOLBYTES /* bytes are numbered right to left */ @@ -136,92 +130,194 @@ typedef long long OFFSZ; /* Definitions mostly used in pass2 */ #define BYTEOFF(x) ((x)&03) -#define wdal(k) (BYTEOFF(k)==0) -#define BITOOR(x) ((x)/SZCHAR) /* bit offset to oreg offset */ - -#define STOARG(p) -#define STOFARG(p) -#define STOSTARG(p) -#define genfcall(a,b) gencall(a,b) +#define BITOOR(x) (x) /* bit offset to oreg offset */ #define szty(t) (((t) == DOUBLE || (t) == FLOAT || \ (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1) /* * Register names. These must match rnames[] and rstatus[] in local2.c. - * The crazy order of the registers are due to the current register - * allocations strategy and should be fixed. */ -#define T0 0 -#define T1 1 -#define T2 2 -#define T3 3 -#define T4 4 -#define T5 5 -#define T6 6 -#define T7 7 -#define T8 8 -#define T9 9 - -#define V0 10 -#define V1 11 - -#define ZERO 12 -#define AT 13 - -#define A0 14 -#define A1 15 -#define A2 16 -#define A3 17 - -#define S0 18 -#define S1 19 -#define S2 20 -#define S3 21 -#define S4 22 -#define S5 23 -#define S6 24 -#define S7 25 - -#define K0 26 -#define K1 27 - -#define GP 28 -#define SP 29 -#define FP 30 -#define RA 31 - -#define RETREG V0 /* Return register */ -#define REGSZ 32 /* number of registers */ +#define ZERO 0 +#define AT 1 +#define V0 2 +#define V1 3 +#define A0 4 +#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 +#define T0 12 +#define T1 13 +#define T2 14 +#define T3 15 +#else +#define T0 8 +#define T1 9 +#define T2 10 +#define T3 11 +#define T4 12 +#define T5 13 +#define T6 14 +#define T7 15 +#endif +#define S0 16 +#define S1 17 +#define S2 18 +#define S3 19 +#define S4 20 +#define S5 21 +#define S6 22 +#define S7 23 +#define T8 24 +#define T9 25 +#define K0 26 +#define K1 27 +#define GP 28 +#define SP 29 +#define FP 30 +#define RA 31 + +#define V0V1 32 +#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 +#define T0T1 37 +#define T1T2 38 +#define T2T3 39 +#define T3T4 40 +#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 F2 54 + +#define MAXREGS 55 +#define NUMCLASS 3 + +#define RETREG(x) ((x) == ULONGLONG || (x) == LONGLONG ? V0V1 : V0) #define FPREG FP /* frame pointer */ -#define STKREG SP /* stack pointer */ -#define MINRVAR S0 /* first register variable */ -#define MAXRVAR S7 /* last register variable */ +#define STKREG SP -#define NREGREG (MAXRVAR-MINRVAR+1) +#if defined(MIPS_N32) || defined(MIPS_N64) +#define MIPS_NARGREGS 8 +#else +#define MIPS_NARGREGS 4 +#endif -/* - * Register types are described by bitmasks. - */ -#define AREGS (REGBIT(T0)|REGBIT(T1)|REGBIT(T2)|REGBIT(T3)| \ - REGBIT(T4)|REGBIT(T5)|REGBIT(T6)|REGBIT(T7)|REGBIT(T8)|REGBIT(T9)|\ - REGBIT(V0)|REGBIT(V1)|REGBIT(A0)|REGBIT(A1)|REGBIT(A2)|REGBIT(A3)|\ - REGBIT(S0)|REGBIT(S1)|REGBIT(S2)|REGBIT(S3)|REGBIT(S4)|REGBIT(S5)|\ - REGBIT(S6)|REGBIT(S7)) -#define TAREGS (REGBIT(T0)|REGBIT(T1)|REGBIT(T2)|REGBIT(T3)|REGBIT(T4)|\ - REGBIT(T5)|REGBIT(T6)|REGBIT(T7)|REGBIT(T8)|REGBIT(T9)|\ - REGBIT(V0)|REGBIT(V1)) - -/* For floating point? */ -#define BREGS 0xff00 -#define TBREGS BREGS - -//#define MYADDEDGE(x, t) if (t < INT) { AddEdge(x, ESI); AddEdge(x, EDI); } -#define MYADDEDGE(x, t) -#define PCLASS(p) SAREG - -#define MYREADER(p) myreader(p) -#define MYCANON(p) mycanon(p) -#define MYOPTIM - -#define special(a, b) SRNOPE +#define RSTATUS \ + 0, 0, \ + SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, \ + 0, 0, \ + 0, 0, 0, 0, \ + \ + 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, SBREG, SBREG, SBREG, \ + SBREG, SBREG, SBREG, \ + SCREG, SCREG, SCREG + +#define ROVERLAP \ + { -1 }, { -1 }, \ + { V0V1, -1 }, { V0V1, -1 }, \ + { A0A1, -1 }, \ + { A0A1, A1A2, -1 }, \ + { A1A2, A2A3, -1 }, \ + { A2A3, -1 }, \ + \ + { T0T1, -1 }, \ + { T0T1, T1T2, -1 }, \ + { T1T2, T2T3, -1 }, \ + { T2T3, T3T4, -1 }, \ + { T3T4, T4T5, -1 }, \ + { T4T5, T5T6, -1 }, \ + { T5T6, T6T7, -1 }, \ + { T6T7, -1 }, \ + \ + { S0S1, -1 }, \ + { S0S1, S1S2, -1 }, \ + { S1S2, S2S3, -1 }, \ + { S2S3, S3S4, -1 }, \ + { S3S4, S4S5, -1 }, \ + { S4S5, S5S6, -1 }, \ + { S5S6, S6S7, -1 }, \ + { S6S7, -1 }, \ + \ + { T8T9, -1 }, \ + { T8T9, -1 }, \ + \ + { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, \ + \ + { V0, V1, -1 }, \ + \ + { A0, A1, -1 }, \ + { A1, A2, -1 }, \ + { A2, A3, -1 }, \ + \ + { -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 }, \ + { S1, S2, S0S1, S2S3, -1 }, \ + { S2, S3, S1S2, S3S4, -1 }, \ + { S3, S4, S2S3, S4S5, -1 }, \ + { S4, S5, S3S4, S5S6, -1 }, \ + { S5, S6, S4S5, S6S7, -1 }, \ + { S6, S7, S5S6, -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 DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ + +int COLORMAP(int c, int *r); diff --git a/usr.bin/pcc/mips/order.c b/usr.bin/pcc/mips/order.c index 9a028f6092c..bd6850a6f89 100644 --- a/usr.bin/pcc/mips/order.c +++ b/usr.bin/pcc/mips/order.c @@ -1,4 +1,4 @@ -/* $OpenBSD: order.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* $OpenBSD: order.c,v 1.2 2007/11/16 08:34:55 otto Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. @@ -31,15 +31,13 @@ * Simon Olsson (simols-1@student.ltu.se) 2005. */ -# include "pass2.h" - -int canaddr(NODE *); +#include "pass2.h" /* should we delay the INCR or DECR operation p */ int -deltest(NODE *p) +deltest(NODE * p) { - return 0; + return 0; } /* @@ -47,64 +45,62 @@ deltest(NODE *p) * XXX - nothing can be autoincremented for now. */ int -autoincr(NODE *p) +autoincr(NODE * p) { - return 0; + 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 */ +/* + * is it legal to make an OREG or NAME entry which has an offset of off, + * (from a register of r), if the resulting thing had type t + */ int notoff(TWORD t, int r, CONSZ off, char *cp) { - return(0); /* YES */ + return (0); /* YES */ } /* * Turn a UMUL-referenced node into OREG. */ -int -offstar(NODE *p) +void +offstar(NODE * p, int shape) { - if (x2debug) - printf("offstar(%p)\n", p); - - if( p->n_op == PLUS || p->n_op == MINUS ){ - if( p->n_right->n_op == ICON ){ - geninsn(p->n_left, INTAREG|INAREG); - p->n_su = -1; - return 1; + if (x2debug) + printf("offstar(%p)\n", p); + + if (p->n_op == PLUS || p->n_op == MINUS) { + if (p->n_right->n_op == ICON) { + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + /* Converted in ormake() */ + return; + } } - } - geninsn(p, INTAREG|INAREG); - return 0; + (void)geninsn(p, INAREG); } /* - * Shape matches for UMUL. Cooperates with offstar(). + * Do the actual conversion of offstar-found OREGs into real OREGs. */ -int -shumul(NODE *p) +void +myormake(NODE * q) { - - if (x2debug) - printf("shumul(%p)\n", p); - - /* Always turn it into OREG on x86 */ - return SOREG; + if (x2debug) + printf("myormake(%p)\n", q); } /* - * Rewrite increment/decrement operation. + * Shape matches for UMUL. Cooperates with offstar(). */ int -setincr(NODE *p) +shumul(NODE * p) { - if (x2debug) - printf("setincr(%p)\n", p); + if (x2debug) + printf("shumul(%p)\n", p); - return(0); + /* Always turn it into OREG */ + return SOREG; } /* @@ -112,29 +108,29 @@ setincr(NODE *p) * Called as a result of table lookup. */ int -setbin(NODE *p) +setbin(NODE * p) { - if (x2debug) - printf("setbin(%p)\n", p); - return 0; + if (x2debug) + printf("setbin(%p)\n", p); + return 0; } /* setup for assignment operator */ int -setasg(NODE *p, int cookie) +setasg(NODE * p, int cookie) { - if (x2debug) - printf("setasg(%p)\n", p); - return(0); + if (x2debug) + printf("setasg(%p)\n", p); + return (0); } /* setup for unary operator */ int -setuni(NODE *p, int cookie) +setuni(NODE * p, int cookie) { - return 0; + return 0; } /* @@ -145,118 +141,145 @@ setuni(NODE *p, int cookie) * - mask is registers that will be clobbered. */ struct rspecial * -nspecial(struct optab *q) +nspecial(struct optab * q) { - static int v0[] = { V0, -1 }; - static int v0v1[] = { V0, V1, -1 }; - - static struct rspecial ucall = { v0, 0, v0v1, v0 }; + switch (q->op) { + + case MOD: + case DIV: + 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 }, + { NRES, V0V1 }, +#endif + { 0 }, + }; + return s; + } + printf("op: %d\n", q->op); + printf("::: > %d\n", q->ltype); + break; + + case STASG: + { + static struct rspecial s[] = { + { NEVER, A0 }, + { NRIGHT, A1 }, + { NEVER, A2 }, + { NRES, A0 }, + { 0 } }; + return s; + } + } - switch (q->op) { + comperr("nspecial entry %d: %s", q - table, q->cstring); - default: - comperr("nspecial entry %d", q - table); - } - return 0; /* XXX gcc */ + return 0; /* XXX gcc */ } +#if 0 /* * Splitup a function call and give away its arguments first. */ void -gencall(NODE *p, NODE *prev) +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); + 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; } - - /* Deal with standard arguments */ - gencall(p->n_left, p); - if (o == STCALL) { - p->n_op = USTCALL; - p->n_rval = storearg(p->n_right); - } else - p->n_rval = 0; - /* push return struct address */ - if (prev == NULL || prev->n_op == FUNARG) { - n = mklnode(REG, 0, STKREG, INT); - if (p->n_rval) - n = mkbinode(PLUS, n, - mklnode(ICON, p->n_rval, 0, INT), INT); - pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT))); - if (prev == NULL) - p->n_rval += p->n_stsize/4; - } else if (prev->n_op == FORCE) { - /* return value for this function */ - n = mklnode(OREG, 8, FPREG, INT); - pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT))); - p->n_rval++; - } else { - pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT))); - n = p; - *prev = *p; - nfree(n); - } - //printf("end stcall\n"); - break; - - default: - if (ty != UTYPE) - gencall(p->n_right, p); - gencall(p->n_left, p); - break; - } } /* @@ -264,87 +287,112 @@ gencall(NODE *p, NODE *prev) * Returns the number of registers needed to hold the argument. */ static int -storearg(NODE *p) +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; + 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 { - 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; + 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); - 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++; + return tsz; + } +} +#endif - /* Free the comma node */ - nfree(p); +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE * p) +{ + return 0; /* nothing differs */ +} +/* + * Set registers "live" at function calls (like arguments in registers). + * This is for liveness analysis of registers. + */ +int * +livecall(NODE *p) +{ + static int r[1] = { -1 }; /* Terminate with -1 */ - } - } - - 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; - } + return &r[0]; } + diff --git a/usr.bin/pcc/mips/table.c b/usr.bin/pcc/mips/table.c index 78d0555c28a..20073097182 100644 --- a/usr.bin/pcc/mips/table.c +++ b/usr.bin/pcc/mips/table.c @@ -1,9 +1,7 @@ -/* $OpenBSD: table.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* $OpenBSD: table.c,v 1.2 2007/11/16 08:34:55 otto Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. - - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,638 +29,797 @@ /* * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and * Simon Olsson (simols-1@student.ltu.se) 2005. + * + * It appears that the target machine was big endian. The original + * code contained many endian aspects which are now handled in + * machine-independent code. + * + * On MIPS, the assembler does an amazing amount of work for us. + * We don't have to worry about PIC, nor about finding the address + * of SNAMES. Whenever possible, we defer the work to the assembler. */ -# include "pass2.h" +#include "pass2.h" -# define TLL TLONGLONG|TULONGLONG -# define ANYSIGNED TINT|TLONG|TSHORT|TCHAR -# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR -# define ANYFIXED ANYSIGNED|ANYUSIGNED -# define TUWORD TUNSIGNED|TULONG -# define TSWORD TINT|TLONG -# define TWORD TUWORD|TSWORD +#define TLL TLONGLONG|TULONGLONG +#define ANYSIGNED TINT|TLONG|TSHORT|TCHAR +#define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR +#define ANYFIXED ANYSIGNED|ANYUSIGNED +#define TUWORD TUNSIGNED|TULONG +#define TSWORD TINT|TLONG +#define TWORD TUWORD|TSWORD struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, - /* * A bunch conversions of integral<->integral types */ - - - - - /* convert char to (u)short */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TCHAR, - SAREG, TSHORT|TUSHORT, + SAREG, TWORD|SHORT|TUSHORT, NAREG, RESC1, - " lb A1, ZA\n nop\n", }, + " lb A1,AL # convert oreg char to (u)short/word\n" + " nop\n", }, /* convert uchar to (u)short */ -{ SCONV, INTAREG, - SOREG, TUCHAR, - SAREG, TSHORT|TUSHORT, - NAREG, RESC1, - " lbu A1, ZA\n nop\n", }, - -/* convert char to (u)long */ -{ SCONV, INTAREG, - SOREG, TCHAR, - SAREG, TWORD, - NAREG, RESC1, - " lb A1, ZA\n nop\n", }, - -/* convert uchar to (u)long */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TUCHAR, - SAREG, TWORD, + SAREG, TWORD|TSHORT|TUSHORT, NAREG, RESC1, - " lbu A1, ZA\n nop\n", }, + " lbu A1,AL # convert oreg uchar to (u)short\n" + " nop\n", }, /* convert char to (u)long long */ -{ SCONV, INTAREG, +{ SCONV, INBREG, SOREG, TCHAR, - SAREG, TLL, - NAREG, RESC1, - " lb U1, ZA\n" + SBREG, TLL, + NBREG, RESC1, + " lb U1,AL # convert oreg char to (u)longlong\n" " nop\n" - " sra A1, U1, 31\n" - " sub A1, $zero, A1\n", }, + " sra A1,U1,31\n" + " sub A1,0,A1\n", }, /* convert uchar to (u)long long */ -{ SCONV, INTAREG, +{ SCONV, INBREG, SOREG, TUCHAR, - SAREG, TLL, - NAREG, RESC1, - " lbu U1, ZA\n" - " move A1, $zero\n", }, - - - - + SBREG, TLL, + NBREG, RESC1, + " lbu U1,AL # convert oreg uchar to (u)longlong\n" + " move A1,0\n", }, /* convert (u)short to char */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TSHORT|TUSHORT, SAREG, TCHAR, NAREG, RESC1, - " lb A1, ZA\n nop\n", }, + " lb A1,AL # convert oreg (u)short to char (endianness problem?)\n" + " nop\n", }, /* convert (u)short to uchar */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TSHORT|TUSHORT, SAREG, TUCHAR, NAREG, RESC1, - " lbu A1, ZA\n nop\n", }, - + " lbu A1,AL # convert oreg (u)short to uchar (endianness problem?)\n" + " nop\n", }, /* convert short to (u)long */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TSHORT, SAREG, TWORD, NAREG, RESC1, - " lh A1, ZA\n nop\n", }, + " lh A1,AL # convert oreg short to (u)int\n" + " nop\n", }, /* convert ushort to (u)long */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TUSHORT, SAREG, TWORD, NAREG, RESC1, - " lhu A1, ZA\n nop\n", }, + " lhu A1,AL # convert oreg ushort to (u)int\n" + " nop\n", }, /* convert short to (u)long long */ -{ SCONV, INTAREG, +{ SCONV, INBREG, SOREG, TSHORT, - SAREG, TLL, - NAREG, RESC1, - " lh U1, ZA\n" + SBREG, TLL, + NBREG, RESC1, + " lh U1,AL # convert oreg short to (u)longlong\n" " nop\n" - " sra A1, U1, 31\n" - " sub A1, $zero, A1\n", }, + " sra A1,U1,31\n" + " sub A1,0,A1\n", }, /* convert ushort to (u)long long */ -{ SCONV, INTAREG, +{ SCONV, INBREG, SOREG, TUSHORT, - SAREG, TLL, - NAREG, RESC1, - " lhu U1, ZA\n" - " move A1, $zero\n", }, - - - - + SBREG, TLL, + NBREG, RESC1, + " lhu U1,AL # convert oreg (u)short to (u)longlong\n" + " move A1,0\n", }, /* convert (u)long to char */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TWORD, SAREG, TCHAR, NAREG, RESC1, - " lb A1, ZA\n nop\n", }, + " lb A1,AL # convert oreg word to char (endianness problem here?)\n" + " nop\n", }, /* convert (u)long to uchar */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TWORD, SAREG, TUCHAR, NAREG, RESC1, - " lbu A1, ZA\n nop\n", }, + " lbu AL,AR # convert oreg word to uchar (endianness problem here?)\n" + " nop\n", }, /* convert (u)long to short */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TWORD, SAREG, TSHORT, NAREG, RESC1, - " lh A1, ZA\n nop\n", }, + " lh AL,AR # convert oreg word to short (endianness problem here?)\n" + " nop\n", }, /* convert (u)long to ushort */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TWORD, SAREG, TUSHORT, NAREG, RESC1, - " lhu A1, ZA\n nop\n", }, + " lhu A1,AR # convert oreg word to ushort (endianness problem here?)\n" + " nop\n", }, /* convert long to (u)long long */ -{ SCONV, INTAREG, +{ SCONV, INBREG, SOREG, TSWORD, - SAREG, TLL, - NAREG, RESC1, - " lw U1, ZA\n" + SBREG, TLL, + NBREG, RESC1, + " lw A1,AL # convert oreg int/long to (u)llong (endianness problem here?)\n" " nop\n" - " sra A1, U1, 31\n" - " sub A1, $zero, A1\n", }, + " sra U1,A1,31\n" + " sub U1,0,U1\n", }, /* convert ulong to (u)long long */ -{ SCONV, INTAREG, +{ SCONV, INBREG, SOREG, TUWORD, - SAREG, TLL, - NAREG, RESC1, - " lw U1, ZA\n" - " move A1, $zero\n", }, - - - - + SBREG, TLL, + NBREG, RESC1, + " lw A1,AL # convert oreg (u)int to (u)llong (endianness problem here?)\n" + " move U1,0\n", }, /* convert (u)long long to char */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TLL, SAREG, TCHAR, NAREG, RESC1, - " lb A1, ZA\n nop\n", }, + " lb A1,AL # convert oreg (u)llong to char (endianness problem here?)\n" + " nop\n", }, /* convert (u)long long to uchar */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TLL, SAREG, TUCHAR, NAREG, RESC1, - " lbu A1, ZA\n nop\n", }, + " lbu A1,AL # convert oreg (u)llong to uchar (endianness problem?)\n" + " nop\n", }, /* convert (u)long long to short */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TLL, SAREG, TSHORT, NAREG, RESC1, - " lh A1, ZA\n nop\n", }, + " lh A1,AL # convert oreg (u)llong to short (endianness problem?)\n" + " nop\n", }, /* convert (u)long long to ushort */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TLL, SAREG, TUSHORT, NAREG, RESC1, - " lhu A1, ZA\n nop\n", }, + " lhu A1,AL # convert oreg (u)llong to ushort (endianness problem here?)\n" + " nop\n", }, /* convert (u)long long to long */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SOREG, TLL, SAREG, TSWORD, NAREG, RESC1, - " lw U1, ZA\n nop\n", }, + " lw U1,AL # convert oreg (u)llong to short (endianness problem here?)\n" + " nop\n", }, -/* convert (u)long long to (u)long long */ -{ SCONV, INTAREG, +/* convert (u)long long to ulong */ +{ SCONV, INAREG, SOREG, TLL, SAREG, TUWORD, NAREG, RESC1, - " lwu U1, ZA\n nop\n", }, - - - - - - + " lwu U1,AL # convert oreg (u)longlong to uint (endianness problem here?)\n" + " nop\n", }, /* Register to register conversion with long long */ -{ SCONV, INTAREG, - SAREG, TLL, - SAREG, TLL, +{ SCONV, INBREG, + SBREG, TLL, + SBREG, TLL, 0, 0, - "", }, + " ; convert (u)longlong to (u)longlong", }, -{ SCONV, INTAREG, +{ SCONV, INBREG, SAREG, TPOINT|TWORD|SHORT|TUSHORT|TCHAR|TUCHAR, - SAREG, TLL, - NAREG, 0, - "move A1, AR\n" - "move U1, $zero\n", }, + SBREG, TLL, + NBREG, 0, + " move A1,AR\n" + " move U1,0\n", }, -{ SCONV, INTAREG, +{ SCONV, INAREG, SAREG, TLL, SAREG, TPOINT|TWORD|SHORT|TUSHORT|TCHAR|TUCHAR, NAREG, 0, - "move A1, AL\n", }, - - - + " move A1,AL\n", }, /* For register to register conversion with bit length <= 32, do nothing */ -{ SCONV, INTAREG, +{ SCONV, INAREG, SAREG, TPOINT|TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TPOINT|TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, 0, 0, - "", }, - + " ; convert reg to reg", }, - - - - /* * Multiplication and division */ -{ MUL, INAREG|FOREFF, +{ MUL, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TSWORD|TSHORT|TCHAR, NAREG|NASR|NASL, RESC1, - " mult AL, AR\n mflo A1\n nop\n nop\n", }, + " mult AL,AR # signed multiply\n" + " mflo A1\n" + " nop\n" + " nop\n", }, -{ MUL, INAREG|FOREFF, +{ MUL, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TUWORD|TUSHORT|TUCHAR, NAREG|NASR|NASL, RESC1, - " multu AL, AR\n mflo A1\n nop\n nop\n", }, - -{ DIV, INAREG|FOREFF, + " multu AL,AR # unsigned 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" + " mfhi U1\n" + " mflo A1\n" + " move A2,UR\n" + " mult AL,A2\n" + " mflo U2\n" + " nop\n" + " nop\n" + " addu A2,U1,U2\n" + " li U2,AR\n" + " mult UL,U2\n" + " mflo U2\n" + " nop\n" + " nop\n" + " addu U1,A2,U2\n", }, + +{ MUL, INCREG, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " mul.s A1,Al,AR #floating-point multiply\n", }, + +{ MUL, INCREG, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG, RESC1, + " mul.d A1,AL,AR # double-floating-point multiply\n", }, + +{ DIV, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TSWORD|TSHORT|TCHAR, NAREG|NASR|NASL, RESC1, - " div AL, AR\n mflo A1\n nop\n nop\n", }, + " div AL,AR # signed division\n" + " mflo A1\n" + " nop\n" + " nop\n", }, -{ DIV, INAREG|FOREFF, +{ DIV, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TUWORD|TUSHORT|TUCHAR, NAREG|NASR|NASL, RESC1, - " divu AL, AR\n mflo A1\n nop\n nop\n", }, - + " divu AL,AR # unsigned division\n" + " mflo A1\n" + " nop\n" + " nop\n", }, + +{ DIV, INBREG, + SBREG, TLL, + SBREG|SCON, TLL, + 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", }, + +{ MOD, INAREG, + SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TUWORD|TUSHORT|TUCHAR, + NAREG, RESC1, + " divu AL,AR # signed modulo\n" + " mfhi A1\n" + " nop\n" + " nop\n" + " sub A1,A1,AL\n", }, + +{ MOD, INBREG, + SBREG, TLL, + SBREG, TLL, + NSPECIAL|NBREG, RESC1, + "ZE", }, + /* * Templates for unsigned values needs to come before OPSIMP */ -{ PLUS, INAREG|FOREFF, - SAREG, TLL, - SAREG, TLL, - 3*NAREG, RESC3, - " addu A1, AL, AR\n" - " sltu A2, A1, AR\n" - " addu A3, UL, UR\n" - " addu A3, A3, A2\n", }, - -{ PLUS, INAREG|FOREFF, - SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, - SCON, TUSHORT|TSHORT|TCHAR|TUCHAR, - NAREG|NASR|NASL, RESC1, - " addiu A1, AL, AR\n", }, - - /* -{ PLUS, INAREG|FOREFF, - SAREG, TUWORD|TUSHORT|TUCHAR, +{ PLUS, INBREG, + SBREG, TULONGLONG, + SBREG, TULONGLONG, + NBREG|NAREG, RESC1, + " addu A1,AL,AR\n" + " sltu A2,A1,AR\n" + " addu U1,UL,UR\n" + " addu U1,U1,A2\n", }, + +{ PLUS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + NBREG|NAREG, RESC1, + " add A1,AL,AR\n", }, + +{ PLUS, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, - NAREG|NASR|NASL, RESC1, - " addu A1, AL, AR\n", }, - -{ MINUS, INAREG|FOREFF, SAREG, TUWORD|TUSHORT|TUCHAR, + NBREG|NAREG, RESC1, + " addu A1,AL,AR\n", }, + +{ PLUS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SSCON, TANY, + NAREG|NASL, RESC1, + " addi A1,AL,AR\n", }, + +{ PLUS, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, - NAREG|NASR|NASL, RESC1, - " subu A1, AL, AR\n", }, - */ + SSCON, TANY, + NAREG|NASL, RESC1, + " addui A1,AL,AR\n", }, + +{ MINUS, INBREG, + SBREG, TULONGLONG, + SBREG, TULONGLONG, + NBREG|NAREG, RESC1, + " sltu A2,AL,AR\n" + " subu A1,AL,AR\n" + " subu U1,UL,UR\n" + " subu U1,U1,A2\n", }, + +{ MINUS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + NBREG|NAREG, RESC1, + " sub A1,AL,AR\n", }, -{ MINUS, INAREG|FOREFF, - SAREG, TLL, - SAREG, TLL, - NAREG|NASR|NASL, RESC1, - " sltu A1, AL, AR\n" - " subu AR, AL, AR\n" - " subu UR, UL, UR\n" - " subu UR, UR, A1\n", }, - -{ MINUS, INAREG|FOREFF, - SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, - SCON, TUSHORT|TSHORT|TCHAR|TUCHAR, - NAREG|NASR|NASL, RESC1, - " subiu A1, AL, AR\n", }, +{ MINUS, INAREG, + SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TUWORD|TUSHORT|TUCHAR, + NBREG|NAREG, RESC1, + " subu A1,AL,AR\n", }, +{ MINUS, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SSCON, TANY, + NAREG|NASL, RESC1, + " subui A1,AL,AR\n", }, -{ UMINUS, INAREG|FOREFF|INTAREG, +{ UMINUS, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SANY, TANY, NAREG|NASL, RESC1, - " neg A1, AL\n", }, + " neg A1,AL\n", }, + +{ UMINUS, INBREG, + SBREG, TLL, + SANY, TANY, + NBREG|NAREG|NBSL, RESC1, + " subu A1,0,AL\n" + " subu U1,0,UL\n" + " sltu A2,0,A1\n" + " subu U1,U1,A2\n", }, - /* Simple 'op rd, rs, rt' or 'op rt, rs, imm' operations */ -{ OPSIMP, INAREG|FOREFF, - SAREG, TLL, - SAREG, TLL, - NAREG|NASR|NASL, RESC1, - " O A1, AL, AR\n" - " O U1, UL, UR\n", }, +{ OPSIMP, INBREG, + SBREG, TLL, + SBREG, TLL, + NBREG|NBSR|NBSL, RESC1, + " O A1,AL,AR\n" + " O U1,UL,UR\n", }, -{ OPSIMP, INAREG|FOREFF, +{ OPSIMP, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, NAREG|NASR|NASL, RESC1, - " O A1, AL, AR\n", }, + " O A1,AL,AR\n", }, -{ OPSIMP, INAREG|FOREFF, +{ OPSIMP, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, - SCON, TSHORT|TUSHORT|TUCHAR|TCHAR, - NAREG|NASR|NASL, RESC1, - " Oi A1, AL, AR\n", }, + SSCON, TSHORT|TUSHORT|TUCHAR|TCHAR, + NAREG|NASL, RESC1, + " Oi A1,AL,AR\n", }, /* * Shift instructions */ - /* order.c SPECIAL -{ RS, INAREG|INTAREG|FOREFF, +{ RS, INAREG, SAREG, TWORD|TUSHORT|TSHORT|TCHAR|TUCHAR, SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, - " srl A1, AL, AR\n", }, + " srl A1,AL,AR # shift right by constant\n", }, -{ LS, INAREG|INTAREG|FOREFF, +{ LS, INAREG, SAREG, TWORD|TUSHORT|TSHORT|TCHAR|TUCHAR, SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, - " sll A1, AL, AR\n", }, - */ + " sll A1,AL,AR # shift left by constant\n", }, -{ RS, INAREG|INTAREG|FOREFF, +{ RS, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, - " srlv A1, AL, AR\n", }, + " srlv A1,AL,AR # shift right by register\n", }, -{ LS, INAREG|INTAREG|FOREFF, +{ LS, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, - " sllv A1, AL, AR\n", }, + " sllv A1,AL,AR # shift left by register\n", }, + +{ RS, INBREG, + SBREG, TLL, + SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NBREG|NBSL, RESC1, + "ZO", }, + +{ LS, INBREG, + SBREG, TLL, + SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NBREG|NBSL, RESC1, + "ZO", }, + +{ RS, INBREG, + SBREG, TLL, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +{ LS, INBREG, + SBREG, TLL, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NSPECIAL|NBREG, RESC1, + "ZE", }, /* * Rule for unary one's complement */ -{ COMPL, INTAREG, +{ COMPL, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SANY, TANY, NAREG|NASL, RESC1, - " not A1, AL\n", }, + " nor A1,AL # complement\n", }, + +{ COMPL, INBREG, + SBREG, TLL, + SANY, TANY, + NBREG|NBSL, RESC1, + " nor A1,AL # complement\n" + " nor U1,UL\n", }, /* * The next rules takes care of assignments. "=". */ -{ ASSIGN, INTAREG, - SOREG, TWORD|TPOINT, - SAREG, TWORD|TPOINT, - 0, RRIGHT, - " sw AR, AL\n", }, - -{ ASSIGN, INTAREG, - SOREG, TSHORT|TUSHORT, - SAREG, TSHORT|TUSHORT, - 0, RRIGHT, - " sh AR, AL\n", }, - -{ ASSIGN, INTAREG, - SOREG, TCHAR|TUCHAR, - SAREG, TCHAR|TUCHAR, - 0, RRIGHT, - " sb AR, AL\n", }, - -{ ASSIGN, INTAREG, - SOREG, TLL, - SAREG, TLL, - 0, RRIGHT, - " sw UR, UL\n" - " sw AR, AL\n", }, +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RDEST, + " sw AR,AL # store (u)int/(u)long\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RDEST, + " sh AR,AL # store (u)short\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + 0, RDEST, + " sb AR,AL # store (u)char\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INBREG, + SOREG|SNAME, TLL, + SBREG, TLL, + 0, RDEST, + " sw UR,UL # store (u)longlong\n" + " nop\n" + " sw AR,AL\n" + " nop\n", }, -{ ASSIGN, INTAREG, // XXX: Funkar ej A1 == AR +#if 0 +{ ASSIGN, FOREFF|INAREG, SNAME, TWORD|TPOINT, SAREG, TWORD|TPOINT, - NAREG, RRIGHT, - " la A1, AL\n sw AR, 0(A1)\n", }, + NAREG, RDEST, + " la A1,AL # store word into sname\n" + " sw AR,0(A1)\n" + " nop\n", }, -{ ASSIGN, INTAREG, +{ ASSIGN, FOREFF|INAREG, SNAME, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, - NAREG, RRIGHT, - " la A1, AL\n sh AR, 0(A1)\n", }, + NAREG, RDEST, + " la A1,AL # store (u)short into sname\n" + " sh AR,0(A1)\n" + " nop\n", }, -{ ASSIGN, INTAREG, +{ ASSIGN, FOREFF|INAREG, SNAME, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, - NAREG, RRIGHT, - " la A1, AL\n sb AR, 0(A1)\n", }, - -{ ASSIGN, INTAREG, - SNAME, TLL, - SAREG, TLL, - 0, RRIGHT, - " sw UR, UL\n" - " sw AR, AL\n", }, + NAREG, RDEST, + " la A1,AL # store (u)char into sname\n" + " sb AR,0(A1)\n" + " nop\n", }, +#endif -{ ASSIGN, INTAREG, - SAREG, TLL, - SAREG, TLL, - 0, RRIGHT, - " move UR, UL\n" - " move AR, AL\n", }, +{ ASSIGN, FOREFF|INBREG, + SBREG, TLL, + SBREG, TLL, + 0, RDEST, + " move UL,UR # register move\n" + " move AL,AR\n", }, -{ ASSIGN, INTAREG|FOREFF, +{ ASSIGN, FOREFF|INAREG, SAREG, TANY, SAREG, TANY, - 0, RLEFT, - " move AL, AR\n", }, + 0, RDEST, + " move AL,AR # register move\n", }, -#if 0 -/* XXX - Stupid rule, shouldn't exist */ -{ ASSIGN, INTAREG, - SANY, TANY, - SAREG, TANY, - 0, RLEFT, - " move AL, AR\n", }, -#endif - -/* - * Compare instructions - */ - -{ EQ, FORCC, - SAREG, TANY, - SAREG, TANY, - 0, RESCC, - " ZQ\n", }, +{ ASSIGN, FOREFF|INCREG, + SNAME|OREG, TFLOAT, + SCREG, TFLOAT, + 0, RDEST, + " s.s AR,AL # store floating-point reg to sname\n", }, -{ NE, FORCC, - SAREG, TANY, - SAREG, TANY, - 0, RESCC, - " ZQ\n", }, +{ ASSIGN, FOREFF|INCREG, + SNAME|OREG, TDOUBLE, + SCREG, TDOUBLE, + 0, RDEST, + " s.d AR,AL # store double-floating-point reg to sname\n", }, -{ LE, FORCC, - SAREG, TANY, - SAREG, TANY, - NAREG|NASL, RESCC, - " sub A1, AL, AR\n ZQ\n", }, +{ STASG, INAREG|FOREFF, + SOREG|SNAME, TANY, + SAREG, TPTRTO|TANY, + NSPECIAL, RRIGHT, + "ZQ", }, -{ LT, FORCC, - SAREG, TANY, - SAREG, TANY, - NAREG|NASL, RESCC, - " sub A1, AL, AR\n ZQ\n", }, -{ GE, FORCC, - SAREG, TANY, - SAREG, TANY, - NAREG|NASL, RESCC, - " sub A1, AL, AR\n ZQ\n", }, +/* + * Compare instructions + */ -{ GT, FORCC, - SAREG, TANY, - SAREG, TANY, - NAREG|NASL, RESCC, - " sub A1, AL, AR\n ZQ\n", }, +{ EQ, FORCC, + SAREG, TANY, + SAREG, TANY, + 0, RESCC, + " beq AL,AR,LC\n", }, + +{ NE, FORCC, + SAREG, TANY, + SAREG, TANY, + 0, RESCC, + " bne AL,AR,LC\n", }, + +{ OPLOG, FORCC, + SAREG, TANY, + SZERO, TANY, + 0, RESCC, + " O AL,LC\n", }, + +{ OPLOG, FORCC, + SAREG, TANY, + SAREG|SCON, TANY, + NAREG|NBSL, RESCC, + " sub A1,AL,AR\n" + " O A1,LC\n", }, - /* * Convert LTYPE to reg. */ - -/* from OREG to REG */ - -{ OPLTYPE, INTAREG, - SANY, TANY, - SOREG, TCHAR, +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TCHAR, NAREG, RESC1, - " lb A1,AR\n nop\n", }, + " lb A1,AR # load char to reg\n" + " nop\n", }, -{ OPLTYPE, INTAREG, - SANY, TANY, - SOREG, TUCHAR, +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TUCHAR, NAREG, RESC1, - " lbu A1,AR\n nop\n", }, + " lbu A1,AR # load uchar to reg\n" + " nop\n", }, -{ OPLTYPE, INTAREG, - SANY, TANY, - SOREG, TSHORT, +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TSHORT, NAREG, RESC1, - " lh A1,AR\n nop\n", }, + " lh A1,AR # load short to reg\n" + " nop\n", }, -{ OPLTYPE, INTAREG, - SANY, TANY, - SOREG, TUSHORT, +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TUSHORT, NAREG, RESC1, - " lhu A1,AR\n nop\n", }, + " lhu A1,AR # load ushort to reg\n" + " nop\n", }, -{ OPLTYPE, INTAREG, - SANY, TANY, - SOREG, TWORD|TPOINT, +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TWORD|TPOINT, NAREG, RESC1, - " lw A1, AR\n nop\n", }, + " lw A1,AR # load (u)int/(u)long to reg\n" + " nop\n", }, -{ OPLTYPE, INTAREG, - SANY, TANY, - SOREG, TLL, - NAREG, RESC1, - " lw U1, UR\n" - " lw A1, AR\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", }, -/* from NAME to REG */ +#if 0 + +// don't need these with the gas assembler -{ OPLTYPE, INTAREG, +{ OPLTYPE, INAREG, SANY, TANY, SNAME, TCHAR, 2*NAREG, RESC1, - " la A2, AR\n lb A1, 0(A2)\n nop\n", }, + " la A2,AL # load char sname to reg\n" + " lb A1,0(A2)\n" + " nop\n", }, -{ OPLTYPE, INTAREG, +{ OPLTYPE, INAREG, SANY, TANY, SNAME, TUCHAR, 2*NAREG, RESC1, - " la A2, AR\n lbu A1, 0(A2)\n nop\n", }, + " la A2,AR # load uchar sname to reg\n" + " lbu A1,0(A2)\n" + " nop\n", }, -{ OPLTYPE, INTAREG, +{ OPLTYPE, INAREG, SANY, TANY, SNAME, TSHORT, 2*NAREG, RESC1, - " la A2, AR\n lh A1, 0(A2)\n nop\n", }, + " la A2,AR # load short sname to reg\n" + " lh A1,0(A2)\n" + " nop\n", }, -{ OPLTYPE, INTAREG, +{ OPLTYPE, INAREG, SANY, TANY, SNAME, TUSHORT, 2*NAREG, RESC1, - " la A2, AR\n lhu A1, 0(A2)\n nop\n", }, + " la A2,AR # load ushort sname to reg\n" + " lhu A1,0(A2)\n" + " nop\n", }, -{ OPLTYPE, INTAREG, +{ OPLTYPE, INAREG, SANY, TANY, SNAME, TWORD|TPOINT, 2*NAREG, RESC1, - " la A2, AR\n lw A1, 0(A2)\n nop\n", }, + " la A2,AR # load (u)int/(u)long to reg\n" + " lw A1,0(A2)\n" + " nop\n", }, -{ OPLTYPE, INTAREG, +{ OPLTYPE, INBREG, SANY, TANY, SNAME, TLL, - 2*NAREG, RESC1, - " la A2, UR\n" - " lw U1, 0(A2)\n" - " la A2, AR\n" - " lw A1, 0(A2)\n" + 2*NBREG, RESC1, + " la A2,UR # load (u)longlong to reg (endiannes problems?)\n" + " lw U1,0(A2)\n" + " nop\n" + " la A2,AR\n" + " lw A1,0(A2)\n" " nop\n", }, -/* from CON to REG */ -{ OPLTYPE, INTAREG, +#endif + +{ OPLTYPE, INAREG, SANY, TANY, SCON, TPOINT, NAREG, RESC1, - " la A1, AR\n", }, + " la A1,AR # load constant address to reg\n", }, -{ OPLTYPE, INTAREG, +{ OPLTYPE, INAREG, SANY, TANY, SCON, TANY, NAREG, RESC1, - " li A1, AR\n", }, + " li A1,AR # load constant to reg\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SZERO, TANY, + NAREG, RESC1, + " move A1,0 # 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", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SZERO, TANY, + NBREG, RESC1, + " move A1,0 # load 0 to reg\n" + " move U1,0\n", }, #if 0 /* Matches REG nodes. XXX - shouldn't be necessary? */ -{ OPLTYPE, INTAREG, +{ OPLTYPE, INAREG, SANY, TANY, SANY, TANY, NAREG, RESC1, - " move A1, AR\n", }, + " move A1,AR\n", }, #endif + +{ OPLTYPE, INCREG, + SANY, TANY, + SOREG|SNAME, TFLOAT, + NCREG, RESC1, + " l.s A1,AR # load into floating-point reg\n", }, + +{ OPLTYPE, INCREG, + SANY, TANY, + OREG|SNAME, TDOUBLE, + NCREG, RESC1, + " l.d A1,AR # load into double-floating-point reg\n", }, /* * Jumps. @@ -671,104 +828,150 @@ struct optab table[] = { SCON, TANY, SANY, TANY, 0, RNOP, - " j LL\n nop\n", }, + " j LL # goto label\n" + " nop\n", }, /* * Subroutine calls. */ -{ UCALL, INTAREG|FOREFF, - SCON, TANY, - SANY, TANY, - NAREG, RESC1, - " addi $sp, $sp, -16\n jal AL\n nop\nZC\n", }, +{ CALL, FOREFF, + SCON|SNAME, TANY, + SANY, TANY, + 0, 0, + " addi $sp,$sp,-16 # call (args, no result) to scon/sname\n" + " jal CL\n" + " nop\n" + "ZC", }, + +{ UCALL, FOREFF, + SCON|SNAME, TANY, + SANY, TANY, + 0, 0, + " jal CL # call (no args, no result) to scon/sname\n" + " nop\n", }, + +{ CALL, INAREG, + SCON|SNAME, TANY, + SAREG, TANY, + NAREG, RESC1, /* should be 0 */ + " addi $sp,$sp,-16 # call (args, result in v0) to scon/sname\n" + " jal CL\n" + " nop\n" + "ZC", }, + +{ UCALL, INAREG, + SCON|SNAME, TANY, + SAREG, TANY, + NAREG, RESC1, /* should be 0 */ + " jal CL ; call (no args, result in v0) to scon/sname\n" + " nop\n", + }, /* struct return */ -{ USTCALL, INTAREG|FOREFF, - SCON, TANY, +{ USTCALL, FOREFF, + SCON|SNAME, TANY, SANY, TANY, - NAREG|NASL, RESC1, /* should be 0 */ - " call CL\nZC", }, + 0, 0, + " call CL\n" + " ZC", }, /* * Function arguments */ - - + { FUNARG, FOREFF, - SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, SANY, TWORD|TPOINT, - 0, RNULL, - " addi $sp, $sp, -4\n sw AL, 0($sp)\n", }, + 0, 0, + " addi $sp,$sp,-4 # save function arg to stack\n" + " sw AL,0($sp)\n" + " #nop\n", }, { FUNARG, FOREFF, - SAREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, SANY, TSHORT|TUSHORT, - 0, RNULL, - " addi $sp, $sp, -4\n sh AL, 0($sp)\n", }, + 0, 0, + " addi $sp,$sp,-4 # save function arg to stack\n" + " sh AL,0($sp)\n" + " #nop\n", }, + { FUNARG, FOREFF, - SAREG, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, SANY, TCHAR|TUCHAR, - 0, RNULL, - " addi $sp, $sp, -4\n sb AL, 0($sp)\n", }, - + 0, 0, + " addi $sp,$sp,-4 # save function arg to stack\n" + " sb AL,0($sp)\n" + " #nop\n", }, /* * Indirection operators. */ -{ UMUL, INTAREG, - SOREG, TPOINT|TWORD|TPTRTO, +{ UMUL, INAREG, SANY, TPOINT|TWORD, - NAREG|NASL, RESC1, - " lw A1, AL\n nop\n", }, + SOREG, TPOINT|TWORD, + NAREG, RESC1, + " lw A1,AL # word load\n" + " nop\n", }, -{ UMUL, INTAREG, - SOREG, TSHORT|TUSHORT|TPTRTO, +{ UMUL, INAREG, SANY, TSHORT|TUSHORT, - NAREG|NASL, RESC1, - " lh A1, AL\n nop\n", }, + SOREG, TSHORT|TUSHORT, + NAREG, RESC1, + " lh A1,AL # (u)short load\n" + " nop\n", }, -{ UMUL, INTAREG, - SOREG, TCHAR|TUCHAR|TPTRTO, +{ UMUL, INAREG, SANY, TCHAR|TUCHAR, - NAREG|NASL, RESC1, - " lb A1, AL\n nop\n", }, + SOREG, TCHAR|TUCHAR, + NAREG, RESC1, + " lb A1,AL # (u)char load\n" + " nop\n", }, -{ UMUL, INTAREG, - SNAME, TPOINT|TWORD|TPTRTO, +{ UMUL, INAREG, SANY, TPOINT|TWORD, - NAREG|NASL, RESC1, - " la A1, AL\n lw A1, 0(A1)\n nop\n", }, + SNAME, TPOINT|TWORD, + NAREG, RESC1, + " la A1,AL # sname word load\n" + " lw A1,0(A1)\n" + " nop\n", }, -{ UMUL, INTAREG, - SNAME, TSHORT|TUSHORT|TPTRTO, +{ UMUL, INAREG, SANY, TSHORT|TUSHORT, - NAREG|NASL, RESC1, - " la A1, AL\n lh A1, 0(A1)\n nop\n", }, + SNAME, TSHORT|TUSHORT, + NAREG, RESC1, + " la A1,AL # sname (u)short load\n" + " lh A1,0(A1)\n" + " nop\n", }, -{ UMUL, INTAREG, - SNAME, TCHAR|TUCHAR|TPTRTO, +{ UMUL, INAREG, SANY, TCHAR|TUCHAR, - NAREG|NASL, RESC1, - " la A1, AL\n lb A1, 0(A1)\n nop\n", }, + SNAME, TCHAR|TUCHAR, + NAREG, RESC1, + " la A1,AL # sname (u)char load\n" + " lb A1,0(A1)\n" + " nop\n", }, -{ UMUL, INTAREG, - SAREG, TPOINT|TWORD|TPTRTO, +{ UMUL, INAREG, SANY, TPOINT|TWORD, - NAREG|NASL, RESC1, - " lw A1, 0(AL)\n nop\n", }, + SAREG, TPOINT|TWORD, + NAREG, RESC1, + " lw A1,0(AL) # word load\n" + " nop\n", }, -{ UMUL, INTAREG, - SAREG, TSHORT|TUSHORT|TPTRTO, +{ UMUL, INAREG, SANY, TSHORT|TUSHORT, - NAREG|NASL, RESC1, - " lh A1, 0(AL)\n nop\n", }, + SAREG, TSHORT|TUSHORT, + NAREG, RESC1, + " lh A1,0(AL) # (u)short load\n" + " nop\n", }, -{ UMUL, INTAREG, - SAREG, TCHAR|TUCHAR|TPTRTO, +{ UMUL, INAREG, SANY, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, NAREG|NASL, RESC1, - " lb A1, 0(AL)\n nop\n", }, + " lb A1,0(AL) # (u)char load\n" + " nop\n", }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, }; |