diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-10-07 17:58:53 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-10-07 17:58:53 +0000 |
commit | 14b353bdf99a61b29314822d06fff3f7250019ac (patch) | |
tree | cfb9b82ab66c64756933986a1d66b0b133819ab4 /usr.bin/pcc/mips | |
parent | 71267fa7f73e6e874cf9cb489551cb44ead37aba (diff) |
reorg pcc tree; requested by and ok deraadt@; ok ragge@
Diffstat (limited to 'usr.bin/pcc/mips')
-rw-r--r-- | usr.bin/pcc/mips/TODO | 9 | ||||
-rw-r--r-- | usr.bin/pcc/mips/code.c | 239 | ||||
-rw-r--r-- | usr.bin/pcc/mips/local.c | 533 | ||||
-rw-r--r-- | usr.bin/pcc/mips/local2.c | 774 | ||||
-rw-r--r-- | usr.bin/pcc/mips/macdefs.h | 227 | ||||
-rw-r--r-- | usr.bin/pcc/mips/order.c | 350 | ||||
-rw-r--r-- | usr.bin/pcc/mips/table.c | 776 |
7 files changed, 2908 insertions, 0 deletions
diff --git a/usr.bin/pcc/mips/TODO b/usr.bin/pcc/mips/TODO new file mode 100644 index 00000000000..4b104cf8ee2 --- /dev/null +++ b/usr.bin/pcc/mips/TODO @@ -0,0 +1,9 @@ +$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. + +* Add support for struct/union arguments and return values. + +* See if the workaround for the function arguments can be removed/rewritten. diff --git a/usr.bin/pcc/mips/code.c b/usr.bin/pcc/mips/code.c new file mode 100644 index 00000000000..1ada0196529 --- /dev/null +++ b/usr.bin/pcc/mips/code.c @@ -0,0 +1,239 @@ +/* $OpenBSD: code.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/* + * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and + * Simon Olsson (simols-1@student.ltu.se) 2005. + */ + +# include "pass1.h" +# include "manifest.h" + +/* Offset to arguments passed to a function. */ +int passedargoff; + +/* + * cause the alignment to become a multiple of n + * never called for text segment. + */ +void +defalign(int n) +{ + n /= SZCHAR; + if (n == 1) + return; + printf(" .align %d\n", n); +} + +/* + * define the current location as the name p->sname + * never called for text segment. + */ +void +defnam(struct symtab *p) +{ + char *c = p->sname; + +#ifdef GCC_COMPAT + c = gcc_findname(p); +#endif + if (p->sclass == EXTDEF) + printf(" .globl %s\n", c); + printf("%s:\n", c); +} + + +/* + * code for the end of a function + * deals with struct return here + */ +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) +{ + int i, m; + + /* 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); + } + + 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); + + if(i+1 < 4) { + argmove(a[i], A0+i+1); + } + + i++; + } else*/ + argmove(a[i], A0+i); + + } +} + + +/* + * by now, the automatics and register variables are allocated + */ +void +bccode() +{ + SETOFF(autooff, SZINT); +} + +/* called just before final exit */ +/* flag is 1 if errors, 0 if none */ +void +ejobcode(int flag ) +{ +} + +void +bjobcode() +{ +} + +/* + * Print character t at position i in one string, until t == -1. + * Locctr & label is already defined. + */ +void +bycode(int t, int i) +{ + static int lastoctal = 0; + + /* put byte i+1 in a string */ + + if (t < 0) { + if (i != 0) + puts("\""); + } else { + if (i == 0) + printf("\t.ascii \""); + if (t == '\\' || t == '"') { + lastoctal = 0; + putchar('\\'); + putchar(t); + } else if (t < 040 || t >= 0177) { + lastoctal++; + printf("\\%o",t); + } else if (lastoctal && '0' <= t && t <= '9') { + lastoctal = 0; + printf("\"\n\t.ascii \"%c", t); + } else { + lastoctal = 0; + putchar(t); + } + } +} + +/* + * n integer words of zeros + */ +void +zecode(int n) +{ + printf(" .zero %d\n", n * (SZINT/SZCHAR)); + inoff += n * SZINT; +} + +/* + * return the alignment of field of type t + */ +int +fldal(unsigned int t) +{ + uerror("illegal field type"); + return(ALINT); +} + +/* fix up type of field p */ +void +fldty(struct symtab *p) +{ +} + +/* p points to an array of structures, each consisting + * of a constant value and a label. + * The first is >=0 if there is a default label; + * its value is the label number + * The entries p[1] to p[n] are the nontrivial cases + * XXX - fix genswitch. + */ +void +genswitch(struct swents **p, int n) +{ +} diff --git a/usr.bin/pcc/mips/local.c b/usr.bin/pcc/mips/local.c new file mode 100644 index 00000000000..554b53190f3 --- /dev/null +++ b/usr.bin/pcc/mips/local.c @@ -0,0 +1,533 @@ +/* $OpenBSD: local.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and + * Simon Olsson (simols-1@student.ltu.se) 2005. + */ + +# include "pass1.h" + +/* this file contains code which is dependent on the target machine */ + +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; + TWORD t; + +//printf("in:\n"); +//fwalk(p, eprint, 0); + switch( o = p->n_op ){ + + case NAME: + if ((q = p->n_sp) == NULL) + return p; /* Nothing to care about */ + + switch (q->sclass) { + + case PARAM: + case AUTO: + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + r->n_lval = 0; + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + + case STATIC: + if (q->slevel == 0) + break; + p->n_lval = 0; + p->n_sp = q; + break; + + case REGISTER: + p->n_op = REG; + p->n_lval = 0; + p->n_rval = q->soffset; + break; + + } + break; + + case FUNARG: + /* Args smaller than int are given as int */ + if (p->n_type != CHAR && p->n_type != UCHAR && + p->n_type != SHORT && p->n_type != USHORT) + break; + p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKSUE(INT)); + p->n_type = INT; + p->n_sue = MKSUE(INT); + p->n_rval = SZINT; + break; + + case CBRANCH: + l = p->n_left; + + /* + * Remove unneccessary conversion ops. + */ + if (clogop(l->n_op) && l->n_left->n_op == SCONV) { + if (coptype(l->n_op) != BITYPE) + break; + if (l->n_right->n_op == ICON) { + r = l->n_left->n_left; + if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) + break; + /* Type must be correct */ + t = r->n_type; + nfree(l->n_left); + l->n_left = r; + l->n_type = t; + l->n_right->n_type = t; + } +#if 0 + else if (l->n_right->n_op == SCONV && + l->n_left->n_type == l->n_right->n_type) { + r = l->n_left->n_left; + nfree(l->n_left); + l->n_left = r; + r = l->n_right->n_left; + nfree(l->n_right); + l->n_right = r; + } +#endif + } + break; + + case PCONV: + ml = p->n_left->n_type; + l = p->n_left; + if ((ml == CHAR || ml == UCHAR || ml == SHORT || ml == USHORT) + && l->n_op != ICON) + break; + l->n_type = p->n_type; + l->n_qual = p->n_qual; + l->n_df = p->n_df; + l->n_sue = p->n_sue; + nfree(p); + p = l; + break; + + case SCONV: + l = p->n_left; + + if (p->n_type == l->n_type) { + nfree(p); + return l; + } + + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + btdims[p->n_type].suesize == btdims[l->n_type].suesize) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE && + l->n_type != LDOUBLE && p->n_type != LDOUBLE) { + if (l->n_op == NAME || l->n_op == UMUL) { + l->n_type = p->n_type; + nfree(p); + return l; + } + } + } + +#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; + + if (o == ICON) { + CONSZ val = l->n_lval; + + if (!ISPTR(m)) /* Pointers don't need to be conv'd */ + switch (m) { + case CHAR: + l->n_lval = (char)val; + break; + case UCHAR: + l->n_lval = val & 0377; + break; + case SHORT: + l->n_lval = (short)val; + break; + case USHORT: + l->n_lval = val & 0177777; + break; + case ULONG: + case UNSIGNED: + l->n_lval = val & 0xffffffff; + break; + case ENUMTY: + case MOETY: + case LONG: + case INT: + l->n_lval = (int)val; + break; + case LONGLONG: + l->n_lval = (long long)val; + break; + case ULONGLONG: + l->n_lval = val; + break; + case VOID: + break; + case LDOUBLE: + case DOUBLE: + case FLOAT: + l->n_op = FCON; + l->n_dcon = val; + break; + default: + cerror("unknown type %d", m); + } + l->n_type = m; + nfree(p); + return l; + } + if (DEUNSIGN(p->n_type) == SHORT && + DEUNSIGN(l->n_type) == SHORT) { + nfree(p); + p = l; + } + break; + + case MOD: + case DIV: + if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) + break; + if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) + break; + /* make it an int division by inserting conversions */ + p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKSUE(INT)); + p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKSUE(INT)); + p = block(SCONV, p, NIL, p->n_type, 0, MKSUE(p->n_type)); + p->n_left->n_type = INT; + break; + + case PMCONV: + case PVCONV: + 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)); + + case FORCE: + /* put return value in return reg */ + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, + MKSUE(INT)); + p->n_left->n_rval = RETREG; + break; + } +//printf("ut:\n"); +//fwalk(p, eprint, 0); + + + return(p); +} + +void +myp2tree(NODE *p) +{ +} + +/*ARGSUSED*/ +int +andable(NODE *p) +{ + return(1); /* all names can have & taken on them */ +} + +/* + * at the end of the arguments of a ftn, set the automatic offset + */ +void +cendarg() +{ + autooff = AUTOINIT; +} + +/* + * is an automatic variable of type t OK for a register variable + */ +int +cisreg(TWORD t) +{ + if (t == INT || t == UNSIGNED || t == LONG || t == ULONG) + return(1); + return 0; /* XXX - fix reg assignment in pftn.c */ +} + +/* + * return a node, for structure references, which is suitable for + * being added to a pointer of type t, in order to be off bits offset + * into a structure + * t, d, and s are the type, dimension offset, and sizeoffset + * For pdp10, return the type-specific index number which calculation + * is based on its size. For example, short a[3] would return 3. + * Be careful about only handling first-level pointers, the following + * indirections must be fullword. + */ +NODE * +offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue) +{ + register NODE *p; + + 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); +} + +/* + * Allocate off bits on the stack. p is a tree that when evaluated + * is the multiply count for off, t is a NAME node where to write + * the allocated address. + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + + if ((off % SZINT) == 0) + p = buildtree(MUL, p, bcon(off/SZINT)); + else if ((off % SZSHORT) == 0) { + p = buildtree(MUL, p, bcon(off/SZSHORT)); + p = buildtree(PLUS, p, bcon(1)); + p = buildtree(RS, p, bcon(1)); + } else if ((off % SZCHAR) == 0) { + p = buildtree(MUL, p, bcon(off/SZCHAR)); + p = buildtree(PLUS, p, bcon(3)); + p = buildtree(RS, p, bcon(2)); + } else + cerror("roundsp"); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue); + sp->n_lval = 0; + sp->n_rval = STKREG; + t->n_type = sp->n_type; + ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ + + /* add the size to sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + sp->n_lval = 0; + sp->n_rval = STKREG; + ecomp(buildtree(PLUSEQ, sp, p)); +} + +/* + * print out a constant node + * mat be associated with a label + */ +void +ninval(NODE *p) +{ + struct symtab *q; + TWORD t; + + p = p->n_left; + 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"); + } +} + +/* + * print out an integer. + */ +void +inval(CONSZ word) +{ + word &= 0xffffffff; + printf(" .long 0x%llx\n", word); +} + +/* output code to initialize a floating point value */ +/* the proper alignment has been obtained */ +void +finval(NODE *p) +{ + 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; + } +} + +/* make a name look like an external name in the local machine */ +char * +exname(char *p) +{ + if (p == NULL) + return ""; + return p; +} + +/* + * map types which are not defined on the local machine + */ +TWORD +ctype(TWORD type) +{ + switch (BTYPE(type)) { + case LONG: + MODTYPE(type,INT); + break; + + case ULONG: + MODTYPE(type,UNSIGNED); + + } + return (type); +} + +/* curid is a variable which is defined but + * is not initialized (and not a function ); + * This routine returns the storage class for an uninitialized declaration + */ +int +noinit() +{ + return(EXTERN); +} + +void +calldec(NODE *p, NODE *q) +{ +} + +void +extdec(struct symtab *q) +{ +} + +/* make a common declaration for id, if reasonable */ +void +commdec(struct symtab *q) +{ + int off; + + off = tsize(q->stype, q->sdf, q->ssue); + off = (off+(SZCHAR-1))/SZCHAR; + +#ifdef GCC_COMPAT + printf(" .comm %s,0%o\n", gcc_findname(q), off); +#else + printf(" .comm %s,0%o\n", exname(q->sname), off); +#endif +} + +/* make a local common declaration for id, if reasonable */ +void +lcommdec(struct symtab *q) +{ + int off; + + off = tsize(q->stype, q->sdf, q->ssue); + off = (off+(SZCHAR-1))/SZCHAR; + if (q->slevel == 0) +#ifdef GCC_COMPAT + printf(" .lcomm %s,0%o\n", gcc_findname(q), off); +#else + printf(" .lcomm %s,0%o\n", exname(q->sname), off); +#endif + else + printf(" .lcomm " LABFMT ",0%o\n", q->soffset, off); +} + +/* + * print a (non-prog) label. + */ +void +deflab1(int label) +{ + printf(LABFMT ":\n", label); +} + +static char *loctbl[] = { "text", "data", "section .rodata", "section .rodata" }; + +void +setloc1(int locc) +{ + if (locc == lastloc) + return; + lastloc = locc; + printf(" .%s\n", loctbl[locc]); +} diff --git a/usr.bin/pcc/mips/local2.c b/usr.bin/pcc/mips/local2.c new file mode 100644 index 00000000000..11d151a7f05 --- /dev/null +++ b/usr.bin/pcc/mips/local2.c @@ -0,0 +1,774 @@ +/* $OpenBSD: local2.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and + * Simon Olsson (simols-1@student.ltu.se) 2005. + */ + +# include "pass2.h" +# include <ctype.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); + +void +lineid(int l, char *fn) +{ + /* identify line l and file fn */ + printf("# line %d, file %s\n", l, fn); +} + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +static int regoff[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) +{ + int i, j, addto; + + addto = p2maxautooff; + if (addto >= AUTOINIT) + addto -= AUTOINIT; + addto /= SZCHAR; + + for (i = ipp->ipp_regs, j = 0; i ; i >>= 1, j++) { + if (i & 1) { + addto += SZINT/SZCHAR; + regoff[j] = addto; + } + } + + return addto; +} + +void +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); +} + +void +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"); + } +} + +/* + * add/sub/... + * + * Param given: + */ +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 * +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", +}; + +int +tlen(p) NODE *p; +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(SZSHORT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case INT: + case UNSIGNED: + case LONG: + case ULONG: + return(SZINT/SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type)/SZCHAR; + } +} + + +/* + * Push a structure on stack as argument. + * the scratch registers are already free here + */ +static void +starg(NODE *p) +{ + FILE *fp = stdout; + + if (p->n_left->n_op == REG && p->n_left->n_type == PTR+STRTY) + return; /* already on stack */ + +} + +void +zzzcode(NODE *p, int c) +{ + 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); + } +} + +/* set up temporary registers */ +void +setregs() +{ + /* 12 free regs on the mips (0-9, temporary and 10-11 is v0 and v1). */ + fregs = 12; +} + +/*ARGSUSED*/ +int +rewfld(NODE *p) +{ + return(1); +} + +int canaddr(NODE *); +int +canaddr(NODE *p) +{ + int o = p->n_op; + + if (o==NAME || o==REG || o==ICON || o==OREG || + (o==UMUL && shumul(p->n_left))) + return(1); + return(0); +} + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE *p) +{ + int o = p->n_op; + + if (o == OREG || o == REG || o == NAME) + return SRDIR; /* Direct match */ + if (o == UMUL && shumul(p->n_left)) + return SROREG; /* Convert into oreg */ + return SRREG; /* put it into a register */ +} + +/* INTEMP shapes must not contain any temporary registers */ +/* XXX should this go away now? */ +int +shtemp(NODE *p) +{ + return 0; +#if 0 + int r; + + if (p->n_op == STARG ) + p = p->n_left; + + switch (p->n_op) { + case REG: + return (!istreg(p->n_rval)); + + case OREG: + r = p->n_rval; + if (R2TEST(r)) { + if (istreg(R2UPK1(r))) + return(0); + r = R2UPK2(r); + } + return (!istreg(r)); + + case UMUL: + p = p->n_left; + return (p->n_op != UMUL && shtemp(p)); + } + + if (optype(p->n_op) != LTYPE) + return(0); + return(1); +#endif +} + +void +adrcon(CONSZ val) +{ + printf(CONFMT, val); +} + +void +conput(FILE *fp, NODE *p) +{ + 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*/ +void +insput(NODE *p) +{ + comperr("insput"); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ + + size /= SZCHAR; + switch (p->n_op) { + case REG: + 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); + } +} + +void +adrput(FILE *io, NODE *p) +{ + int r; + /* output an address, with offsets, from p */ + + if (p->n_op == FLD) + p = p->n_left; + + switch (p->n_op) { + + case NAME: + if (p->n_name[0] != '\0') + fputs(p->n_name, io); + if (p->n_lval != 0) + fprintf(io, "+" 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; + + } +} + +/* This function changes the offset of a OREG when doing a type cast. */ +void +offchg(NODE *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 + + /* 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]); + +} + + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ +} + +void branchfunc(NODE *p) +{ + 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. + */ +static void +optim2(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; + } + + } + /* 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) +{ + 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"; +} + +void +myreader(NODE *p) +{ + 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. + */ +static void +pconv2(NODE *p) +{ + NODE *q; + + if (p->n_op == PLUS) { + if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { + if (p->n_right->n_op != ICON) + return; + if (p->n_left->n_op != PCONV) + return; + if (p->n_left->n_left->n_op != OREG) + return; + q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + /* + * This will be converted to another OREG later. + */ + } + } +} + +void +mycanon(NODE *p) +{ + walkf(p, pconv2); +} + +void +mygenregs(NODE *p) +{ + 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; +} + +/* + * Remove last goto. + */ +void +myoptim(struct interpass *ip) +{ +#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 +} + +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" }, +#endif + { 0 }, +}; + +void +rmove(int s, int d, TWORD t) +{ + printf(" move %s, %s\n", rnames[d], rnames[s]); +} + + + diff --git a/usr.bin/pcc/mips/macdefs.h b/usr.bin/pcc/mips/macdefs.h new file mode 100644 index 00000000000..71e5b17f955 --- /dev/null +++ b/usr.bin/pcc/mips/macdefs.h @@ -0,0 +1,227 @@ +/* $OpenBSD: macdefs.h,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and + * Simon Olsson (simols-1@student.ltu.se) 2005. + */ + +/* + * Machine-dependent defines for both passes. + */ + +/* + * Convert (multi-)character constant to integer. + * Assume: If only one value; store at left side (char size), otherwise + * treat it as an integer. + */ +#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 */ + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZINT 32 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#define SZLDOUBLE 96 +#define SZLONG 32 +#define SZSHORT 16 +#define SZLONGLONG 64 +#define SZPOINT(t) 32 + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALINT 32 +#define ALFLOAT 32 +#define ALDOUBLE 32 +#define ALLDOUBLE 32 +#define ALLONG 32 +#define ALLONGLONG 32 +#define ALSHORT 16 +#define ALPOINT 32 +#define ALSTRUCT 32 +#define ALSTACK 32 + +/* + * Min/max values. + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT -1 +#define MAX_INT 0x7fffffff +#define MAX_UNSIGNED 0xffffffff +#define MIN_LONG MIN_INT +#define MAX_LONG MAX_INT +#define MAX_ULONG MAX_UNSIGNED +#define MIN_LONGLONG 0x8000000000000000LL +#define MAX_LONGLONG 0x7fffffffffffffffLL +#define MAX_ULONGLONG 0xffffffffffffffffULL + +/* Default char is unsigned */ +#undef CHAR_UNSIGNED + +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "%lld" /* format for printing constants */ +#define LABFMT ".L%d" /* format for printing labels */ +#define STABLBL ".LL%d" /* format for stab (debugging) labels */ +#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 +#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 */ + +#define ENUMSIZE(high,low) INT /* enums are always stored in full int */ + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) ((x)&03) +#define wdal(k) (BYTEOFF(k)==0) +#define BITOOR(x) ((x)/SZCHAR) /* bit offset to oreg offset */ + +#define STOARG(p) +#define STOFARG(p) +#define STOSTARG(p) +#define genfcall(a,b) gencall(a,b) + +#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 FPREG FP /* frame pointer */ +#define STKREG SP /* stack pointer */ +#define MINRVAR S0 /* first register variable */ +#define MAXRVAR S7 /* last register variable */ + +#define NREGREG (MAXRVAR-MINRVAR+1) + +/* + * 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 diff --git a/usr.bin/pcc/mips/order.c b/usr.bin/pcc/mips/order.c new file mode 100644 index 00000000000..9a028f6092c --- /dev/null +++ b/usr.bin/pcc/mips/order.c @@ -0,0 +1,350 @@ +/* $OpenBSD: order.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and + * Simon Olsson (simols-1@student.ltu.se) 2005. + */ + +# include "pass2.h" + +int canaddr(NODE *); + +/* 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 */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + return(0); /* YES */ +} + +/* + * Turn a UMUL-referenced node into OREG. + */ +int +offstar(NODE *p) +{ + 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; + } + } + geninsn(p, INTAREG|INAREG); + return 0; +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p) +{ + + if (x2debug) + printf("shumul(%p)\n", p); + + /* Always turn it into OREG on x86 */ + return SOREG; +} + +/* + * Rewrite increment/decrement operation. + */ +int +setincr(NODE *p) +{ + if (x2debug) + printf("setincr(%p)\n", p); + + return(0); +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE *p) +{ + + if (x2debug) + printf("setbin(%p)\n", p); + return 0; + +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + if (x2debug) + printf("setasg(%p)\n", p); + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +/* + * Special handling of some instruction register allocation. + * - left is the register that left node wants. + * - right is the register that right node wants. + * - res is in which register the result will end up. + * - mask is registers that will be clobbered. + */ +struct rspecial * +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) { + + default: + comperr("nspecial entry %d", q - table); + } + return 0; /* XXX gcc */ +} + +/* + * 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, 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; + } +} + +/* + * 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; + } +} diff --git a/usr.bin/pcc/mips/table.c b/usr.bin/pcc/mips/table.c new file mode 100644 index 00000000000..78d0555c28a --- /dev/null +++ b/usr.bin/pcc/mips/table.c @@ -0,0 +1,776 @@ +/* $OpenBSD: table.c,v 1.1 2007/10/07 17:58:51 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + + + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and + * Simon Olsson (simols-1@student.ltu.se) 2005. + */ + +# 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 + +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, + SOREG, TCHAR, + SAREG, TSHORT|TUSHORT, + NAREG, RESC1, + " lb A1, ZA\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, + SOREG, TUCHAR, + SAREG, TWORD, + NAREG, RESC1, + " lbu A1, ZA\n nop\n", }, + +/* convert char to (u)long long */ +{ SCONV, INTAREG, + SOREG, TCHAR, + SAREG, TLL, + NAREG, RESC1, + " lb U1, ZA\n" + " nop\n" + " sra A1, U1, 31\n" + " sub A1, $zero, A1\n", }, + +/* convert uchar to (u)long long */ +{ SCONV, INTAREG, + SOREG, TUCHAR, + SAREG, TLL, + NAREG, RESC1, + " lbu U1, ZA\n" + " move A1, $zero\n", }, + + + + + +/* convert (u)short to char */ +{ SCONV, INTAREG, + SOREG, TSHORT|TUSHORT, + SAREG, TCHAR, + NAREG, RESC1, + " lb A1, ZA\n nop\n", }, + +/* convert (u)short to uchar */ +{ SCONV, INTAREG, + SOREG, TSHORT|TUSHORT, + SAREG, TUCHAR, + NAREG, RESC1, + " lbu A1, ZA\n nop\n", }, + + +/* convert short to (u)long */ +{ SCONV, INTAREG, + SOREG, TSHORT, + SAREG, TWORD, + NAREG, RESC1, + " lh A1, ZA\n nop\n", }, + +/* convert ushort to (u)long */ +{ SCONV, INTAREG, + SOREG, TUSHORT, + SAREG, TWORD, + NAREG, RESC1, + " lhu A1, ZA\n nop\n", }, + +/* convert short to (u)long long */ +{ SCONV, INTAREG, + SOREG, TSHORT, + SAREG, TLL, + NAREG, RESC1, + " lh U1, ZA\n" + " nop\n" + " sra A1, U1, 31\n" + " sub A1, $zero, A1\n", }, + +/* convert ushort to (u)long long */ +{ SCONV, INTAREG, + SOREG, TUSHORT, + SAREG, TLL, + NAREG, RESC1, + " lhu U1, ZA\n" + " move A1, $zero\n", }, + + + + + +/* convert (u)long to char */ +{ SCONV, INTAREG, + SOREG, TWORD, + SAREG, TCHAR, + NAREG, RESC1, + " lb A1, ZA\n nop\n", }, + +/* convert (u)long to uchar */ +{ SCONV, INTAREG, + SOREG, TWORD, + SAREG, TUCHAR, + NAREG, RESC1, + " lbu A1, ZA\n nop\n", }, + +/* convert (u)long to short */ +{ SCONV, INTAREG, + SOREG, TWORD, + SAREG, TSHORT, + NAREG, RESC1, + " lh A1, ZA\n nop\n", }, + +/* convert (u)long to ushort */ +{ SCONV, INTAREG, + SOREG, TWORD, + SAREG, TUSHORT, + NAREG, RESC1, + " lhu A1, ZA\n nop\n", }, + +/* convert long to (u)long long */ +{ SCONV, INTAREG, + SOREG, TSWORD, + SAREG, TLL, + NAREG, RESC1, + " lw U1, ZA\n" + " nop\n" + " sra A1, U1, 31\n" + " sub A1, $zero, A1\n", }, + +/* convert ulong to (u)long long */ +{ SCONV, INTAREG, + SOREG, TUWORD, + SAREG, TLL, + NAREG, RESC1, + " lw U1, ZA\n" + " move A1, $zero\n", }, + + + + + +/* convert (u)long long to char */ +{ SCONV, INTAREG, + SOREG, TLL, + SAREG, TCHAR, + NAREG, RESC1, + " lb A1, ZA\n nop\n", }, + +/* convert (u)long long to uchar */ +{ SCONV, INTAREG, + SOREG, TLL, + SAREG, TUCHAR, + NAREG, RESC1, + " lbu A1, ZA\n nop\n", }, + +/* convert (u)long long to short */ +{ SCONV, INTAREG, + SOREG, TLL, + SAREG, TSHORT, + NAREG, RESC1, + " lh A1, ZA\n nop\n", }, + +/* convert (u)long long to ushort */ +{ SCONV, INTAREG, + SOREG, TLL, + SAREG, TUSHORT, + NAREG, RESC1, + " lhu A1, ZA\n nop\n", }, + +/* convert (u)long long to long */ +{ SCONV, INTAREG, + SOREG, TLL, + SAREG, TSWORD, + NAREG, RESC1, + " lw U1, ZA\n nop\n", }, + +/* convert (u)long long to (u)long long */ +{ SCONV, INTAREG, + SOREG, TLL, + SAREG, TUWORD, + NAREG, RESC1, + " lwu U1, ZA\n nop\n", }, + + + + + + + +/* Register to register conversion with long long */ + +{ SCONV, INTAREG, + SAREG, TLL, + SAREG, TLL, + 0, 0, + "", }, + +{ SCONV, INTAREG, + SAREG, TPOINT|TWORD|SHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TLL, + NAREG, 0, + "move A1, AR\n" + "move U1, $zero\n", }, + +{ SCONV, INTAREG, + SAREG, TLL, + SAREG, TPOINT|TWORD|SHORT|TUSHORT|TCHAR|TUCHAR, + NAREG, 0, + "move A1, AL\n", }, + + + + +/* For register to register conversion with bit length <= 32, do nothing */ + +{ SCONV, INTAREG, + SAREG, TPOINT|TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TPOINT|TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + 0, 0, + "", }, + + + + + + +/* + * Multiplication and division + */ + +{ MUL, INAREG|FOREFF, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + NAREG|NASR|NASL, RESC1, + " mult AL, AR\n mflo A1\n nop\n nop\n", }, + +{ MUL, INAREG|FOREFF, + 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, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + NAREG|NASR|NASL, RESC1, + " div AL, AR\n mflo A1\n nop\n nop\n", }, + +{ DIV, INAREG|FOREFF, + SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TUWORD|TUSHORT|TUCHAR, + NAREG|NASR|NASL, RESC1, + " divu AL, AR\n mflo A1\n nop\n nop\n", }, + +/* + * 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, + SAREG, TUWORD|TUSHORT|TUCHAR, + NAREG|NASR|NASL, RESC1, + " addu A1, AL, AR\n", }, + +{ MINUS, INAREG|FOREFF, + SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TUWORD|TUSHORT|TUCHAR, + NAREG|NASR|NASL, RESC1, + " subu 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", }, + + +{ UMINUS, INAREG|FOREFF|INTAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TANY, + NAREG|NASL, RESC1, + " neg A1, AL\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, INAREG|FOREFF, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, + NAREG|NASR|NASL, RESC1, + " O A1, AL, AR\n", }, + +{ OPSIMP, INAREG|FOREFF, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, + SCON, TSHORT|TUSHORT|TUCHAR|TCHAR, + NAREG|NASR|NASL, RESC1, + " Oi A1, AL, AR\n", }, + +/* + * Shift instructions + */ + + /* order.c SPECIAL +{ RS, INAREG|INTAREG|FOREFF, + SAREG, TWORD|TUSHORT|TSHORT|TCHAR|TUCHAR, + SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " srl A1, AL, AR\n", }, + +{ LS, INAREG|INTAREG|FOREFF, + SAREG, TWORD|TUSHORT|TSHORT|TCHAR|TUCHAR, + SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " sll A1, AL, AR\n", }, + */ + +{ RS, INAREG|INTAREG|FOREFF, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " srlv A1, AL, AR\n", }, + +{ LS, INAREG|INTAREG|FOREFF, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " sllv A1, AL, AR\n", }, + +/* + * Rule for unary one's complement + */ + +{ COMPL, INTAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TANY, + NAREG|NASL, RESC1, + " not A1, AL\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, INTAREG, // XXX: Funkar ej A1 == AR + SNAME, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + NAREG, RRIGHT, + " la A1, AL\n sw AR, 0(A1)\n", }, + +{ ASSIGN, INTAREG, + SNAME, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + NAREG, RRIGHT, + " la A1, AL\n sh AR, 0(A1)\n", }, + +{ ASSIGN, INTAREG, + 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", }, + +{ ASSIGN, INTAREG, + SAREG, TLL, + SAREG, TLL, + 0, RRIGHT, + " move UR, UL\n" + " move AR, AL\n", }, + +{ ASSIGN, INTAREG|FOREFF, + SAREG, TANY, + SAREG, TANY, + 0, RLEFT, + " move AL, AR\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", }, + +{ NE, FORCC, + SAREG, TANY, + SAREG, TANY, + 0, RESCC, + " ZQ\n", }, + +{ LE, FORCC, + SAREG, TANY, + SAREG, TANY, + NAREG|NASL, RESCC, + " sub A1, AL, AR\n ZQ\n", }, + +{ 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", }, + +{ GT, FORCC, + SAREG, TANY, + SAREG, TANY, + NAREG|NASL, RESCC, + " sub A1, AL, AR\n ZQ\n", }, + + +/* + * Convert LTYPE to reg. + */ + + +/* from OREG to REG */ + +{ OPLTYPE, INTAREG, + SANY, TANY, + SOREG, TCHAR, + NAREG, RESC1, + " lb A1,AR\n nop\n", }, + +{ OPLTYPE, INTAREG, + SANY, TANY, + SOREG, TUCHAR, + NAREG, RESC1, + " lbu A1,AR\n nop\n", }, + +{ OPLTYPE, INTAREG, + SANY, TANY, + SOREG, TSHORT, + NAREG, RESC1, + " lh A1,AR\n nop\n", }, + +{ OPLTYPE, INTAREG, + SANY, TANY, + SOREG, TUSHORT, + NAREG, RESC1, + " lhu A1,AR\n nop\n", }, + +{ OPLTYPE, INTAREG, + SANY, TANY, + SOREG, TWORD|TPOINT, + NAREG, RESC1, + " lw A1, AR\n nop\n", }, + +{ OPLTYPE, INTAREG, + SANY, TANY, + SOREG, TLL, + NAREG, RESC1, + " lw U1, UR\n" + " lw A1, AR\n" + " nop\n", }, + +/* from NAME to REG */ + +{ OPLTYPE, INTAREG, + SANY, TANY, + SNAME, TCHAR, + 2*NAREG, RESC1, + " la A2, AR\n lb A1, 0(A2)\n nop\n", }, + +{ OPLTYPE, INTAREG, + SANY, TANY, + SNAME, TUCHAR, + 2*NAREG, RESC1, + " la A2, AR\n lbu A1, 0(A2)\n nop\n", }, + +{ OPLTYPE, INTAREG, + SANY, TANY, + SNAME, TSHORT, + 2*NAREG, RESC1, + " la A2, AR\n lh A1, 0(A2)\n nop\n", }, + +{ OPLTYPE, INTAREG, + SANY, TANY, + SNAME, TUSHORT, + 2*NAREG, RESC1, + " la A2, AR\n lhu A1, 0(A2)\n nop\n", }, + +{ OPLTYPE, INTAREG, + SANY, TANY, + SNAME, TWORD|TPOINT, + 2*NAREG, RESC1, + " la A2, AR\n lw A1, 0(A2)\n nop\n", }, + +{ OPLTYPE, INTAREG, + 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" + " nop\n", }, + +/* from CON to REG */ +{ OPLTYPE, INTAREG, + SANY, TANY, + SCON, TPOINT, + NAREG, RESC1, + " la A1, AR\n", }, + +{ OPLTYPE, INTAREG, + SANY, TANY, + SCON, TANY, + NAREG, RESC1, + " li A1, AR\n", }, + +#if 0 +/* Matches REG nodes. XXX - shouldn't be necessary? */ +{ OPLTYPE, INTAREG, + SANY, TANY, + SANY, TANY, + NAREG, RESC1, + " move A1, AR\n", }, +#endif + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " j LL\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", }, + +/* struct return */ +{ USTCALL, INTAREG|FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +/* + * Function arguments + */ + + +{ FUNARG, FOREFF, + SAREG, TWORD|TPOINT, + SANY, TWORD|TPOINT, + 0, RNULL, + " addi $sp, $sp, -4\n sw AL, 0($sp)\n", }, + +{ FUNARG, FOREFF, + SAREG, TSHORT|TUSHORT, + SANY, TSHORT|TUSHORT, + 0, RNULL, + " addi $sp, $sp, -4\n sh AL, 0($sp)\n", }, +{ FUNARG, FOREFF, + SAREG, TCHAR|TUCHAR, + SANY, TCHAR|TUCHAR, + 0, RNULL, + " addi $sp, $sp, -4\n sb AL, 0($sp)\n", }, + + +/* + * Indirection operators. + */ +{ UMUL, INTAREG, + SOREG, TPOINT|TWORD|TPTRTO, + SANY, TPOINT|TWORD, + NAREG|NASL, RESC1, + " lw A1, AL\n nop\n", }, + +{ UMUL, INTAREG, + SOREG, TSHORT|TUSHORT|TPTRTO, + SANY, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " lh A1, AL\n nop\n", }, + +{ UMUL, INTAREG, + SOREG, TCHAR|TUCHAR|TPTRTO, + SANY, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " lb A1, AL\n nop\n", }, + +{ UMUL, INTAREG, + SNAME, TPOINT|TWORD|TPTRTO, + SANY, TPOINT|TWORD, + NAREG|NASL, RESC1, + " la A1, AL\n lw A1, 0(A1)\n nop\n", }, + +{ UMUL, INTAREG, + SNAME, TSHORT|TUSHORT|TPTRTO, + SANY, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " la A1, AL\n lh A1, 0(A1)\n nop\n", }, + +{ UMUL, INTAREG, + SNAME, TCHAR|TUCHAR|TPTRTO, + SANY, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " la A1, AL\n lb A1, 0(A1)\n nop\n", }, + +{ UMUL, INTAREG, + SAREG, TPOINT|TWORD|TPTRTO, + SANY, TPOINT|TWORD, + NAREG|NASL, RESC1, + " lw A1, 0(AL)\n nop\n", }, + +{ UMUL, INTAREG, + SAREG, TSHORT|TUSHORT|TPTRTO, + SANY, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " lh A1, 0(AL)\n nop\n", }, + +{ UMUL, INTAREG, + SAREG, TCHAR|TUCHAR|TPTRTO, + SANY, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " lb A1, 0(AL)\n nop\n", }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); |