diff options
Diffstat (limited to 'usr.bin/pcc/arch')
39 files changed, 20160 insertions, 0 deletions
diff --git a/usr.bin/pcc/arch/m16c/TODO b/usr.bin/pcc/arch/m16c/TODO new file mode 100644 index 00000000000..5ef0ba4b478 --- /dev/null +++ b/usr.bin/pcc/arch/m16c/TODO @@ -0,0 +1 @@ +* Mul/Div does not work.
\ No newline at end of file diff --git a/usr.bin/pcc/arch/m16c/code.c b/usr.bin/pcc/arch/m16c/code.c new file mode 100644 index 00000000000..536a5eb1435 --- /dev/null +++ b/usr.bin/pcc/arch/m16c/code.c @@ -0,0 +1,376 @@ +/* $Id: code.c,v 1.1 2007/09/15 18:12:27 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass1.h" + +/* + * cause the alignment to become a multiple of n + */ +void +defalign(int n) +{ +#if 0 + char *s; + + n /= SZCHAR; + if (lastloc == PROG || n == 1) + return; + s = (isinlining ? permalloc(40) : tmpalloc(40)); + sprintf(s, ".align %d", n); + send_passt(IP_ASM, s); +#endif +} + +/* + * define the current location as the name p->sname + */ +void +defnam(struct symtab *p) +{ + char *c = p->sname; + +#ifdef GCC_COMPAT + c = gcc_findname(p); +#endif + if (p->sclass == EXTDEF) + printf(" PUBLIC %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; + /* address of return struct is in eax */ + /* create a call to memcpy() */ + /* will get the result in eax */ + p = block(REG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR)); + p->n_rval = R0; + q = block(OREG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR)); + q->n_rval = FB; + q->n_lval = 8; /* return buffer offset */ + p = block(CM, q, p, INT, 0, MKSUE(INT)); + sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR; + p = block(CM, p, bcon(sz), INT, 0, MKSUE(INT)); + p->n_right->n_name = ""; + p = block(CALL, bcon(0), p, CHAR+PTR, 0, MKSUE(CHAR+PTR)); + p->n_left->n_name = "memcpy"; + send_passt(IP_NODE, p); +} + +/* + * helper for bfcode() to put register arguments on stack. + */ +static void +argmove(struct symtab *s, int regno) +{ + NODE *p, *r; + + s->sclass = AUTO; + s->soffset = NOOFFSET; + oalloc(s, &autooff); + 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 + * On m16k, space is allocated on stack for register arguments, + * arguments are moved to the stack and symtab is updated accordingly. + */ +void +bfcode(struct symtab **a, int n) +{ + struct symtab *s; + int i, r0l, r0h, a0, r2, sz, hasch, stk; + int argoff = ARGINIT; + + 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); + } + /* first check if there are 1-byte parameters */ + for (hasch = i = 0; i < n && i < 6; i++) + if (DEUNSIGN(a[i]->stype) == CHAR) + hasch = 1; + + stk = r0l = r0h = a0 = r2 = 0; + for (i = 0; i < n; i++) { + s = a[i]; + sz = tsize(s->stype, s->sdf, s->ssue); + if (ISPTR(s->stype) && ISFTN(DECREF(s->stype))) + sz = SZLONG; /* function pointers are always 32 */ + if (stk == 0) + switch (sz) { + case SZCHAR: + if (r0l) { + if (r0h) + break; + argmove(s, 1); + r0h = 1; + } else { + argmove(s, 0); + r0l = 1; + } + continue; + + case SZINT: + if (s->stype > BTMASK) { + /* is a pointer */ + if (a0) { + if (r0l || hasch) { + if (r2) + break; + argmove(s, R2); + r2 = 1; + } else { + argmove(s, R0); + r0l = r0h = 1; + } + } else { + argmove(s, A0); + a0 = 1; + } + } else if (r0l || hasch) { + if (r2) { + if (a0) + break; + argmove(s, A0); + a0 = 1; + } else { + argmove(s, R2); + r2 = 1; + } + } else { + argmove(s, R0); + r0l = r0h = 1; + } + continue; + case SZLONG: + if (r0l||r0h||r2) + break; + argmove(s, R0); + r0l = r0h = r2 = 1; + continue; + + default: + break; + } + stk = 1; + s->soffset = argoff; + argoff += sz; + } +} + +/* + * Add a symbol to an internal list printed out at the end. + */ +void addsym(struct symtab *); +static struct symlst { + struct symlst *next; + struct symtab *sp; +} *sympole; + +void +addsym(struct symtab *q) +{ + struct symlst *w = sympole; + + if (q == NULL) + return; + + while (w) { + if (q == w->sp) + return; /* exists */ + w = w->next; + } + w = permalloc(sizeof(struct symlst)); + w->sp = q; + w->next = sympole; + sympole = w; +} + +/* + * by now, the automatics and register variables are allocated + */ +void +bccode() +{ +} + +struct caps { + char *cap, *stat; +} caps[] = { + { "__64bit_doubles", "Disabled" }, + { "__calling_convention", "Normal" }, + { "__constant_data", "near" }, + { "__data_alignment", "2" }, + { "__data_model", "near" }, + { "__processor", "M16C" }, + { "__rt_version", "1" }, + { "__variable_data", "near" }, + { NULL, NULL }, +}; +/* + * Called before parsing begins. + */ +void +bjobcode() +{ + struct caps *c; + + printf(" NAME gurka.c\n"); /* Don't have the name */ + for (c = caps; c->cap; c++) + printf(" RTMODEL \"%s\", \"%s\"\n", c->cap, c->stat); + //printf(" RSEG CODE:CODE:REORDER:NOROOT(0)\n"); +} + +/* called just before final exit */ +/* flag is 1 if errors, 0 if none */ +void +ejobcode(int flag ) +{ + struct symlst *w = sympole; + + for (w = sympole; w; w = w->next) { + if (w->sp->sclass != EXTERN) + continue; + printf(" EXTERN %s\n", w->sp->sname); + } + + printf(" END\n"); +} + +/* + * 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) +{ + uerror("switch() statements unsopported"); +#if 0 + int i; + char *s; + + /* simple switch code */ + for (i = 1; i <= n; ++i) { + /* already in 1 */ + s = (isinlining ? permalloc(40) : tmpalloc(40)); + sprintf(s, " cmpl $%lld,%%eax", p[i]->sval); + send_passt(IP_ASM, s); + s = (isinlining ? permalloc(40) : tmpalloc(40)); + sprintf(s, " je " LABFMT, p[i]->slab); + send_passt(IP_ASM, s); + } + if (p[0]->slab > 0) + branch(p[0]->slab); +#endif +} diff --git a/usr.bin/pcc/arch/m16c/local.c b/usr.bin/pcc/arch/m16c/local.c new file mode 100644 index 00000000000..ddc6276d36a --- /dev/null +++ b/usr.bin/pcc/arch/m16c/local.c @@ -0,0 +1,487 @@ +/* $Id: local.c,v 1.1 2007/09/15 18:12:26 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "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 */ + + struct symtab *q; + NODE *l, *r; + int o; + TWORD ml; + + 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 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 PCONV: + ml = p->n_left->n_type; + l = p->n_left; + if ((ml == CHAR || ml == UCHAR) && 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 (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT) { + nfree(p); + return l; + } + if (l->n_op == ICON) { + CONSZ val = l->n_lval; + switch (p->n_type) { + case CHAR: + l->n_lval = (char)val; + break; + case UCHAR: + l->n_lval = val & 0377; + break; + case SHORT: + case INT: + l->n_lval = (short)val; + break; + case USHORT: + case UNSIGNED: + l->n_lval = val & 0177777; + break; + case ULONG: + case ULONGLONG: + l->n_lval = val & 0xffffffff; + break; + case LONG: + case LONGLONG: + l->n_lval = (int)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", p->n_type); + } + l->n_type = p->n_type; + nfree(p); + return l; + } + break; + + + } + + return(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 == CHAR || t == UCHAR || + ISPTR(t)) + 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 LONG: + case ULONG: + 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: + fwalk(p, eprint, 0); + 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 SHORT: + MODTYPE(type,INT); + break; + + case USHORT: + MODTYPE(type,UNSIGNED); + break; + + case LONGLONG: + MODTYPE(type,LONG); + break; + + case ULONGLONG: + MODTYPE(type,ULONG); + break; + + case LDOUBLE: + MODTYPE(type,DOUBLE); + break; + } + 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); +} + +/* + * Extern variable not necessary common. + */ +void +extdec(struct symtab *q) +{ + extern void addsym(struct symtab *); + addsym(q); +} + +/* + * Call to a function + */ +void +calldec(NODE *p, NODE *r) +{ + struct symtab *q = p->n_sp; + extern void addsym(struct symtab *); + addsym(q); +} + +/* make a common declaration for id, if reasonable */ +void +commdec(struct symtab *q) +{ + int off; + char *c = q->sname; + + off = tsize(q->stype, q->sdf, q->ssue); + off = (off+(SZCHAR-1))/SZCHAR; + +#ifdef GCC_COMPAT + c = gcc_findname(q); +#endif + printf(" PUBLIC %s\n", c); + /* XXX - NOROOT??? */ + printf(" RSEG DATA16_Z:NEARDATA:SORT:NOROOT(1)\n"); + printf("%s:\n", c); + printf(" DS8 %d\n", off); + printf(" REQUIRE __data16_zero\n"); +} + +/* 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); +} + +void +setloc1(int locc) +{ + if (locc == lastloc) + return; + lastloc = locc; +} + +/* + * special handling before tree is written out. + */ +void +myp2tree(NODE *p) +{ + union dimfun *df; + union arglist *al; + NODE *q; + int i; + + switch (p->n_op) { + case MOD: + case DIV: + if (p->n_type == LONG || p->n_type == ULONG) { + /* Swap arguments for hardops() later */ + q = p->n_left; + p->n_left = p->n_right; + p->n_right = q; + } + break; + + case CALL: + case STCALL: + /* + * inform pass2 about varargs. + * store first variadic argument number in n_stalign + * in the CM node. + */ + if (p->n_right->n_op != CM) + break; /* nothing to care about */ + df = p->n_left->n_df; + if (df && (al = df->dfun)) { + for (i = 0; i < 6; i++, al++) { + if (al->type == TELLIPSIS || al->type == TNULL) + break; + } + p->n_right->n_stalign = al->type == TELLIPSIS ? i : 0; + } else + p->n_right->n_stalign = 0; + break; + } + +} diff --git a/usr.bin/pcc/arch/m16c/local2.c b/usr.bin/pcc/arch/m16c/local2.c new file mode 100644 index 00000000000..09f7e6f1204 --- /dev/null +++ b/usr.bin/pcc/arch/m16c/local2.c @@ -0,0 +1,639 @@ +/* $Id: local2.c,v 1.1 2007/09/15 18:12:27 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass2.h" +# include <ctype.h> + +void acon(NODE *p); +int argsize(NODE *p); +void genargs(NODE *p); + +static int ftlab1, ftlab2; + +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 TWORD ftype; +static int addto; + +void +prologue(struct interpass_prolog *ipp) +{ + ftype = ipp->ipp_type; + +#if 0 + if (ipp->ipp_regs > 0 && ipp->ipp_regs != MINRVAR) + comperr("fix prologue register savings", ipp->ipp_regs); +#endif + + printf(" RSEG CODE:CODE:REORDER:NOROOT(0)\n"); + if (ipp->ipp_vis) + printf(" PUBLIC %s\n", ipp->ipp_name); + printf("%s:\n", ipp->ipp_name); + +#if 0 + if (xsaveip) { + /* Optimizer running, save space on stack */ + addto = (p2maxautooff - AUTOINIT)/SZCHAR; + printf(" enter #%d\n", addto); + } else { +#endif + + /* non-optimized code, jump to epilogue for code generation */ + ftlab1 = getlab(); + ftlab2 = getlab(); + printf(" jmp.w " LABFMT "\n", ftlab1); + deflab(ftlab2); +} + +/* + * End of block. + */ +void +eoftn(struct interpass_prolog *ipp) +{ +#if 0 + if (ipp->ipp_regs != MINRVAR) + comperr("fix eoftn register savings %x", ipp->ipp_regs); +#endif + + // if (xsaveip == 0) + addto = (p2maxautooff - AUTOINIT)/SZCHAR; + + /* return from function code */ + //deflab(ipp->ipp_ip.ip_lbl); //XXX - is this necessary? + + /* If retval is a pointer and not a function pointer, put in A0 */ + if (ISPTR(DECREF(ipp->ipp_type)) && + !ISFTN(DECREF(DECREF(ipp->ipp_type)))) + printf(" mov.w r0,a0\n"); + + /* struct return needs special treatment */ + if (ftype == STRTY || ftype == UNIONTY) { + comperr("fix struct return in eoftn"); + } else + printf(" exitd\n"); + + /* Prolog code */ + // if (xsaveip == 0) { + deflab(ftlab1); + printf(" enter #%d\n", addto); + printf(" jmp.w " LABFMT "\n", ftlab2); + //} +} + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str; + + switch (o) { + case PLUS: + str = "add"; + break; + case MINUS: + str = "sub"; + 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 */ + "r0", "r2", "r1", "r3", "a0", "a1", "fb", "sp", "r0h", "r0l", + "r1h", "r1l", +}; + +/* + * Return the size (in bytes) of some types. + */ +int +tlen(p) NODE *p; +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case INT: + case UNSIGNED: + case FLOAT: + return 2; + + case DOUBLE: + case LONG: + case ULONG: + return 4; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type)/SZCHAR; + } +} + +/* + * Emit code to compare two longlong numbers. + */ +static void +twollcomp(NODE *p) +{ + int o = p->n_op; + int s = getlab(); + int e = p->n_label; + int cb1, cb2; + + if (o >= ULE) + o -= (ULE-LE); + switch (o) { + case NE: + cb1 = 0; + cb2 = NE; + break; + case EQ: + cb1 = NE; + cb2 = 0; + break; + case LE: + case LT: + cb1 = GT; + cb2 = LT; + break; + case GE: + case GT: + cb1 = LT; + cb2 = GT; + break; + + default: + cb1 = cb2 = 0; /* XXX gcc */ + } + if (p->n_op >= ULE) + cb1 += 4, cb2 += 4; + expand(p, 0, " cmp.w UR,UL\n"); + if (cb1) cbgen(cb1, s); + if (cb2) cbgen(cb2, e); + expand(p, 0, " cmp.w AR,AL\n"); + cbgen(p->n_op, e); + deflab(s); +} + + +void +zzzcode(NODE *p, int c) +{ + NODE *l; + + switch (c) { + case 'A': /* print negative shift constant */ + p = getlr(p, 'R'); + if (p->n_op != ICON) + comperr("ZA bad use"); + p->n_lval = -p->n_lval; + adrput(stdout, p); + p->n_lval = -p->n_lval; + break; + + case 'B': + if (p->n_rval) + printf(" add.b #%d,%s\n", + p->n_rval, rnames[STKREG]); + break; + + case 'C': /* Print label address */ + p = p->n_left; + if (p->n_lval) + printf(LABFMT, (int)p->n_lval); + else + printf("%s", p->n_name); + break; + + case 'D': /* copy function pointers */ + l = p->n_left; + printf("\tmov.w #HWRD(%s),%s\n\tmov.w #LWRD(%s),%s\n", + p->n_right->n_name, rnames[l->n_rval+1], + p->n_right->n_name, rnames[l->n_rval]); + break; + + case 'E': /* double-reg printout */ + /* XXX - always r0r2 here */ + printf("%s%s", rnames[R0], rnames[R2]); + break; + + case 'F': /* long comparisions */ + twollcomp(p); + break; + + case 'G': + printf("R0R2"); + break; + + case 'H': /* push 32-bit address (for functions) */ + printf("\tpush.w #HWRD(%s)\n\tpush.w #LWRD(%s)\n", + p->n_left->n_name, p->n_left->n_name); + break; + + case 'I': /* push 32-bit address (for functions) */ + l = p->n_left; + printf("\tpush.w %d[%s]\n\tpush.w %d[%s]\n", + (int)l->n_lval, rnames[l->n_rval], + (int)l->n_lval+2, rnames[l->n_rval]); + break; + + default: + comperr("bad zzzcode %c", c); + } +} + +/*ARGSUSED*/ +int +rewfld(NODE *p) +{ + return(1); +} + +int canaddr(NODE *); +int +canaddr(NODE *p) +{ + int o = p->n_op; + + if (o==NAME || o==REG || o==ICON || o==OREG || + (o==UMUL && shumul(p->n_left) == SRDIR)) + 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; +} + +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 /= SZINT; + 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 >> 16); + break; + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +} + +void +adrput(FILE *io, NODE *p) +{ + /* 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: + 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) == CHAR) { + fprintf(io, "R%c%c", p->n_rval < 2 ? '0' : '1', + (p->n_rval & 1) ? 'H' : 'L'); + } else*/ + fprintf(io, "%s", rnames[p->n_rval]); + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +static char * +ccbranches[] = { + "jeq", /* jumpe */ + "jne", /* jumpn */ + "jle", /* jumple */ + "jlt", /* jumpl */ + "jge", /* jumpge */ + "jgt", /* jumpg */ + "jleu", /* jumple (jlequ) */ + "jltu", /* jumpl (jlssu) */ + "jgeu", /* jumpge (jgequ) */ + "jgtu", /* jumpg (jgtru) */ +}; + + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ + if (o < EQ || o > UGT) + comperr("bad conditional branch: %s", opst[o]); + printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); +} + +#if 0 +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; + +} +#endif + +struct hardops hardops[] = { + { PLUS, FLOAT, "?F_ADD_L04" }, + { MUL, LONG, "?L_MUL_L03" }, + { MUL, ULONG, "?L_MUL_L03" }, + { DIV, LONG, "?SL_DIV_L03" }, + { DIV, ULONG, "?UL_DIV_L03" }, + { MOD, LONG, "?SL_MOD_L03" }, + { MOD, ULONG, "?UL_MOD_L03" }, + { RS, LONGLONG, "__ashrdi3" }, + { RS, ULONGLONG, "__lshrdi3" }, + { LS, LONGLONG, "__ashldi3" }, + { LS, ULONGLONG, "__ashldi3" }, + { 0 }, +}; + +int +special(NODE *p, int shape) +{ + switch (shape) { + case SFTN: + if (ISPTR(p->n_type) && ISFTN(DECREF(p->n_type))) { + if (p->n_op == NAME || p->n_op == OREG) + return SRDIR; + else + return SRREG; + } + break; + } + return SRNOPE; +} + +void +myreader(NODE *p) +{ + NODE *q, *r, *s, *right; + + if (optype(p->n_op) == LTYPE) + return; + if (optype(p->n_op) != UTYPE) + myreader(p->n_right); + myreader(p->n_left); + + switch (p->n_op) { + case PLUS: + case MINUS: + if (p->n_type != LONG && p->n_type != ULONG) + break; + if (p->n_right->n_op == NAME || p->n_right->n_op == OREG) + break; + /* Must convert right into OREG */ + right = p->n_right; + q = mklnode(OREG, BITOOR(freetemp(szty(right->n_type))), + FPREG, right->n_type); + s = mkbinode(ASSIGN, q, right, right->n_type); + r = talloc(); + *r = *q; + p->n_right = r; + pass2_compile(ipnode(s)); + break; + } +} + + +void +rmove(int s, int d, TWORD t) +{ + switch (t) { + case CHAR: + case UCHAR: + printf(" mov.b %s,%s\n", rnames[s], rnames[d]); + break; + default: + printf(" mov.w %s,%s\n", rnames[s], rnames[d]); + } +} + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + */ +int +COLORMAP(int c, int *r) +{ + int num; + + switch (c) { + case CLASSA: + num = r[CLASSA]; + num += r[CLASSC]; + return num < 4; + case CLASSB: + num = r[CLASSB]; + return num < 2; + case CLASSC: + num = 2*r[CLASSA]; + num += r[CLASSC]; + return num < 4; + } + return 0; /* XXX gcc */ +} + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + if (t == CHAR || t == UCHAR) + return CLASSC; + + if(ISPTR(t)) + return CLASSB; + + return CLASSA; +} + +static int sizen; + +/* XXX: Fix this. */ +static int +argsiz(NODE *p) +{ + TWORD t = p->n_type; + + if (t < LONGLONG || t > MAXTYPES) + return 4; + if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) + return 8; + if (t == LDOUBLE) + return 12; + if (t == STRTY) + return p->n_stsize; + comperr("argsiz"); + return 0; +} + +/* + * Calculate argument sizes. + * XXX: Fix this. + */ +void +lastcall(NODE *p) +{ + sizen = 0; + for (p = p->n_right; p->n_op == CM; p = p->n_left) + sizen += argsiz(p->n_right); + sizen += argsiz(p); +} diff --git a/usr.bin/pcc/arch/m16c/macdefs.h b/usr.bin/pcc/arch/m16c/macdefs.h new file mode 100644 index 00000000000..010a2464b55 --- /dev/null +++ b/usr.bin/pcc/arch/m16c/macdefs.h @@ -0,0 +1,205 @@ +/* $Id: macdefs.h,v 1.1 2007/09/15 18:12:27 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Machine-dependent defines for both passes. + */ +#define makecc(val,i) lastcon = (lastcon<<8)|((val<<8)>>8); + +#define ARGINIT 40 /* # bits above fp where arguments start */ +#define AUTOINIT 0 /* # bits below fp where automatics start */ + +/* + * Convert (multi-)character constant to integer. + * Assume: If only one value; store at left side (char size), otherwise + * treat it as an integer. + */ + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZINT 16 +#define SZFLOAT 16 +#define SZDOUBLE 16 +#define SZLDOUBLE 16 +#define SZLONG 32 +#define SZSHORT 16 +#define SZLONGLONG 32 +/* pointers are of different sizes on m16c */ +#define SZPOINT(t) (ISFTN(DECREF(t)) ? 32 : 16) + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALINT 16 +#define ALFLOAT 16 +#define ALDOUBLE 16 +#define ALLDOUBLE 16 +#define ALLONG 16 +#define ALLONGLONG 16 +#define ALSHORT 16 +#define ALPOINT 16 +#define ALSTRUCT 16 +#define ALSTACK 16 + +/* + * 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 -32768 +#define MAX_INT 32767 +#define MAX_UNSIGNED 65535 +#define MIN_LONG -2147483648 +#define MAX_LONG 2147483647 +#define MAX_ULONG 4294967295UL +#define MIN_LONGLONG -2147483648 +#define MAX_LONGLONG 2147483647 +#define MAX_ULONGLONG 4294967295UL + +/* 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 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 */ + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) 1 +#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) == LONG || (t) == ULONG || \ + (ISPTR(t) && ISFTN(DECREF(t)))) ? 2 : 1) + +/* + * m16c register classes: + * A - 16-bit data registers R0-R3 + * B - 16-bit address registers A0-A1 + * C - 8-bit data registers R0H, R0L, R1H, R1L + */ + +#define R0 0 +#define R2 1 +#define R1 2 +#define R3 3 + +#define A0 4 +#define A1 5 +#define FB 6 +#define SP 7 + +#define R0H 8 +#define R0L 9 +#define R1H 10 +#define R1L 11 + +#define NUMCLASS 4 /* Number of register classes */ + +#define RETREG(x) (x == CHAR || x == UCHAR ? R0L : R0) + +#define FPREG FB /* frame pointer */ +#define STKREG SP /* stack pointer */ + +#if 0 +#define REGSZ 8 /* Number of registers */ +#define MINRVAR R1 /* first register variable */ +#define MAXRVAR R2 /* last register variable */ +#endif + +#define MAXREGS 12 /* 12 registers */ + +#define RSTATUS \ + SAREG|TEMPREG, SAREG|PERMREG, SAREG|TEMPREG, SAREG|PERMREG, \ + SBREG|TEMPREG, SBREG|PERMREG, 0, 0, SCREG, SCREG, SCREG, SCREG, + +#define ROVERLAP \ + {R0H, R0L, -1},\ + {-1},\ + {R1H, R1L, -1},\ + {-1},\ +\ + {-1},\ + {-1},\ +\ + {-1},\ + {-1},\ +\ + {R0, -1},\ + {R0, -1},\ + {R1, -1},\ + {R1, -1}, + +#define PCLASS(p) (p->n_type <= UCHAR ? SCREG : ISPTR(p->n_type) ? SBREG:SAREG) + +int COLORMAP(int c, int *r); +#define GCLASS(x) (x < 4 ? CLASSA : x < 6 ? CLASSB : x < 12 ? CLASSC : CLASSD) +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 6) /* A1 */ +#define ENCRA2(x) ((x) << 12) /* A2 */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ + +#define MYADDEDGE(x, t) +#define MYREADER(p) myreader(p) +#define MYP2TREE(p) myp2tree(p) + +#if 0 +#define MYCANON(p) mycanon(p) +#define MYOPTIM +#endif + +#ifndef NEW_READER +//#define TAILCALL +#endif +#define SFTN (SPECIAL|6) diff --git a/usr.bin/pcc/arch/m16c/order.c b/usr.bin/pcc/arch/m16c/order.c new file mode 100644 index 00000000000..4c648c01ef0 --- /dev/null +++ b/usr.bin/pcc/arch/m16c/order.c @@ -0,0 +1,600 @@ +/* $Id: order.c,v 1.1 2007/09/15 18:12:27 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass2.h" +# include <strings.h> + +int canaddr(NODE *); + +/* + * should the assignment op p be stored, + * given that it lies as the right operand of o + * (or the left, if o==UNARY MUL) + */ +/* +void +stoasg(NODE *p, int o) +{ + if (x2debug) + printf("stoasg(%p, %o)\n", p, o); +} +*/ +/* 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, 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, INBREG); + p->n_su = -1; + return 1; + } + } + geninsn(p, INBREG); + return 0; +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p) +{ +// NODE *l = p->n_left; + +#ifdef PCC_DEBUG + if (x2debug) { + printf("shumul(%p)\n", p); + fwalk(p, e2print, 0); + } +#endif + + /* Can only generate OREG of BREGs (or FB) */ + if (p->n_op == REG && (isbreg(p->n_rval) || p->n_rval == FB)) + return SOREG; +#if 0 + if ((p->n_op == PLUS || p->n_op == MINUS) && + (l->n_op == REG && (isbreg(l->n_rval) || l->n_rval == FB)) && + p->n_right->n_op == ICON) + return SOREG; + return 0; +#else + return SOREG; +#endif +} + +/* + * 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; +} + +#if 0 +/* + * register allocation for instructions with special preferences. + */ +regcode +regalloc(NODE *p, struct optab *q, int wantreg) +{ + regcode regc; + + if (q->op == DIV || q->op == MOD) { + /* + * 16-bit div. + */ + if (regblk[R0] & 1 || regblk[R2] & 1) + comperr("regalloc: needed regs inuse, node %p", p); + if (p->n_su & DORIGHT) { + regc = alloregs(p->n_right, A0); + if (REGNUM(regc) != A0) { + p->n_right = movenode(p->n_right, A0); + if ((p->n_su & RMASK) == ROREG) { + p->n_su &= ~RMASK; + p->n_su |= RREG; + p->n_right->n_su &= ~LMASK; + p->n_right->n_su |= LOREG; + } + freeregs(regc); + regblk[A0] |= 1; + } + } + regc = alloregs(p->n_left, R0); + if (REGNUM(regc) != R0) { + p->n_left = movenode(p->n_left, R0); + freeregs(regc); + regblk[R0] |= 1; + } + if ((p->n_su & RMASK) && !(p->n_su & DORIGHT)) { + regc = alloregs(p->n_right, A0); + if (REGNUM(regc) != A0) { + p->n_right = movenode(p->n_right, A0); + if ((p->n_su & RMASK) == ROREG) { + p->n_su &= ~RMASK; + p->n_su |= RREG; + p->n_right->n_su &= ~LMASK; + p->n_right->n_su |= LOREG; + } + } + } + regblk[A0] &= ~1; + regblk[R0] &= ~1; + regblk[R2] &= ~1; + if (q->op == DIV) { + MKREGC(regc, R0, 1); + regblk[R0] |= 1; + } else { + MKREGC(regc, R2, 1); + regblk[R2] |= 1; + } + } else + comperr("regalloc"); + p->n_rall = REGNUM(regc); + return regc; +} +#endif + +/* + * 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. + * + * XXX - Fix this function + */ +struct rspecial * +nspecial(struct optab *q) +{ + switch (q->op) { + + case DIV: + case MOD: + if(q->ltype & (TINT|TSHORT)){ + static struct rspecial s[] = { + { NRES, R0 }, { NRES, R2}, { 0 } }; + return s; + } + /* + else if(q->ltype & TCHAR) { + static struct rspecial s[] = { + { NRES, R0L }, { NRES, R0H}, { 0 } }; + return s; + }*/ + break; + + case MUL: + /* + if(q->ltype & (TINT|TSHORT)){ + static struct rspecial s[] = { + { NRES, R0 }, { NRES, R2}, { 0 } }; + return s; + }*/ + comperr("multiplication not implemented"); + break; + + default: + break; + } + comperr("nspecial entry %d", q - table); + return 0; /* XXX gcc */ +} + + +/* + * Splitup a function call and give away its arguments first. + * Calling convention used ("normal" in IAR syntax) is: + * - 1-byte parameters in R0L if possible, otherwise in R0H. + * - 2-byte pointers in A0. + * - 2-byte non-pointers in R0 if no byte-size arguments are found in + * in the first 6 bytes of parameters, otherwise R2 or at last A0. + * - 4-byte parameters in R2R0. + */ +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: + /* swap arguments on some hardop-converted insns */ + /* Normal call, just push args and be done with it */ + p->n_op = UCALL; +//printf("call\n"); + /* Check if left can be evaluated directly */ + if (p->n_left->n_op == UMUL) { + TWORD t = p->n_left->n_type; + int k = BITOOR(freetemp(szty(t))); + NODE *n = mklnode(OREG, k, FB, t); + NODE *q = tcopy(n); + pass2_compile(ipnode(mkbinode(ASSIGN, n, p->n_left,t))); + p->n_left = q; + } + gencall(p->n_left, p); + p->n_rval = storearg(p->n_right); +//printf("end call\n"); + 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. + * This is partly ticky, the strange calling convention + * may cause a bunch of code reorganization here. + */ +static int +storearg(NODE *p) +{ + NODE *n, *q, **narry; + int nch, k, i, nn, rary[4]; + int r0l, r0h, r2, a0, stk, sz; + TWORD t; + int maxrargs = 0; + + if (p->n_op == CM) + maxrargs = p->n_stalign; + + /* count the arguments */ + for (i = 1, q = p; q->n_op == CM; q = q->n_left) + i++; + nn = i; + + /* allocate array to store arguments */ + narry = tmpalloc(sizeof(NODE *)*nn); + + /* enter nodes into array */ + for (q = p; q->n_op == CM; q = q->n_left) + narry[--i] = q->n_right; + narry[--i] = q; + + /* free CM nodes */ + for (q = p; q->n_op == CM; ) { + n = q->n_left; + nfree(q); + q = n; + } + + /* count char args */ + r0l = r0h = r2 = a0 = 0; + for (sz = nch = i = 0; i < nn && i < 6; i++) { + TWORD t = narry[i]->n_type; + if (sz >= 6) + break; + if (t == CHAR || t == UCHAR) { + nch++; + sz++; + } else if ((t >= SHORT && t <= UNSIGNED) || + t > BTMASK || t == FLOAT) { + sz += 2; + } else /* long, double */ + sz += 4; + + } + + /* + * Now the tricky part. The parameters that should be on stack + * must be found and pushed first, then the register parameters. + * For the latter, be sure that evaluating them do not use any + * registers where argument values already are inserted. + * XXX - function pointers? + * XXX foo(long a, char b) ??? + */ + for (stk = 0; stk < 4; stk++) { + TWORD t; + + if (stk == nn) + break; + t = narry[stk]->n_type; + if (ISFTN(DECREF(t))) + t = LONG; + switch (t) { + case CHAR: case UCHAR: + if (r0l) { + if (r0h) + break; + rary[stk] = R2; /* char talk for 'R0H' */ + r0h = 1; + } else { + rary[stk] = R0; + r0l = 1; + } + continue; + + case INT: case UNSIGNED: + if (r0l || nch) { + if (r2) { + if (a0) + break; + rary[stk] = A0; + a0 = 1; + } else { + rary[stk] = R2; + r2 = 1; + } + } else { + rary[stk] = R0; + r0l = r0h = 1; + } + continue; + + case LONG: case ULONG: + if (r0l || r2) + break; + rary[stk] = R0; + r0l = r0h = r2 = 1; + continue; + + default: + if (ISPTR(narry[stk]->n_type) && + !ISFTN(DECREF(narry[stk]->n_type))) { + if (a0) { + if (r0l || nch) { + if (r2) + break; + rary[stk] = R2; + r2 = 1; + } else { + rary[stk] = R0; + r0l = r0h = 1; + } + } else { + rary[stk] = A0; + a0 = 1; + } + continue; + } + break; + } + break; + } + + /* + * The arguments that must be on stack are stk->nn args. + * Argument 0->stk-1 should be put in the rary[] register. + */ + for (sz = 0, i = nn-1; i >= stk; i--) { /* first stack args */ + NODE nod; + pass2_compile(ipnode(mkunode(FUNARG, + narry[i], 0, narry[i]->n_type))); + nod.n_type = narry[i]->n_type; + sz += tlen(&nod); + } + /* if param cannot be addressed directly, evaluate and put on stack */ + for (i = 0; i < stk; i++) { + + if (canaddr(narry[i])) + continue; + t = narry[i]->n_type; + k = BITOOR(freetemp(szty(t))); + n = mklnode(OREG, k, FB, t); + q = tcopy(n); + pass2_compile(ipnode(mkbinode(ASSIGN, n, narry[i], t))); + narry[i] = q; + } + /* move args to registers */ + for (i = 0; i < stk; i++) { + t = narry[i]->n_type; + pass2_compile(ipnode(mkbinode(ASSIGN, + mklnode(REG, 0, rary[i], t), narry[i], t))); + } + return sz; +} + +/* + * Tell if a register can hold a specific datatype. + */ +#if 0 +int +mayuse(int reg, TWORD type) +{ + return 1; /* Everything is OK */ +} +#endif + +#ifdef TAILCALL +void +mktailopt(struct interpass *ip1, struct interpass *ip2) +{ + extern int earlylab; + extern char *cftname; + char *fn; + NODE *p; + + p = ip1->ip_node->n_left->n_left; + if (p->n_op == ICON) { + fn = p->n_name; + /* calling ourselves */ + p = ip1->ip_node->n_left; + if (p->n_op == CALL) { + if (storearg(p->n_right)) + comperr("too many args: fix mktailopt"); + p->n_op = UCALL; + } + tfree(ip1->ip_node); + p = ip2->ip_node->n_left; + if (strcmp(fn, cftname)) { + /* Not us, must generate fake prologue */ + ip1->type = IP_ASM; + ip1->ip_asm = "mov.w FB,SP\n\tpop.w FB"; + pass2_compile(ip1); + p->n_lval = p->n_rval = 0; + p->n_name = fn; + } else + p->n_lval = earlylab; + } else { + pass2_compile(ip1); + } + pass2_compile(ip2); +} +#endif diff --git a/usr.bin/pcc/arch/m16c/table.c b/usr.bin/pcc/arch/m16c/table.c new file mode 100644 index 00000000000..879a41334c7 --- /dev/null +++ b/usr.bin/pcc/arch/m16c/table.c @@ -0,0 +1,595 @@ +#include "pass2.h" + +# define ANYSIGNED TINT|TLONG|TCHAR +# define ANYUSIGNED TUNSIGNED|TULONG|TUCHAR +# define ANYFIXED ANYSIGNED|ANYUSIGNED +# define TL TLONG|TULONG +# define TWORD TUNSIGNED|TINT +# define TCH TCHAR|TUCHAR + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* (signed) char -> int/pointer */ +{ SCONV, INAREG, + SCREG, TCHAR, + SANY, TINT|TPOINT, + NAREG, RESC1, + " mov.b AL, A1\n\texts.b A1\n", }, + +/* (unsigned) char -> int/pointer */ +{ SCONV, INAREG, + SCREG, TUCHAR, + SANY, TINT|TPOINT, + NAREG, RESC1, + " mov.b AL, A1\n", }, + +/* unsigned char -> long */ +{ SCONV, INAREG, + SCREG, TUCHAR, + SANY, TL, + NAREG|NASL, RESC1, + " mov.b AL, A1\n mov.w #0,U1\n", }, + +/* int or pointer -> (unsigned) long */ +{ SCONV, INAREG, + SAREG|SNAME, TWORD|TPOINT, + SANY, TL, + NAREG|NASL, RESC1, + " mov.w AL,A1\n mov.w #0,U1\n", }, + +/* char -> (signed) long */ +{ SCONV, INAREG, + SAREG|SNAME, TCHAR, + SANY, TLONG, + NAREG|NASL, RESC1, + " exts.b AL\n exts.w AL\n", }, + +/* long -> ulong */ +{ SCONV, INAREG, + SAREG, TL, + SANY, TL, + 0, RLEFT, + "", }, + +/* long -> int or pointer */ +{ SCONV, INAREG, + SAREG|SOREG|SNAME, TL, + SANY, TWORD|TPOINT, + NAREG|NASL, RESC1, + " mov.w AL,A1\n", }, + +/* int -> char */ +{ SCONV, INCREG, + SAREG, TWORD, + SANY, TCH, + NCREG, RESC1, + " mov.b AL, A1\n", }, + +/* int -> long */ +{ SCONV, INAREG, + SAREG, TWORD, + SANY, TLONG, + NAREG|NASL, RESC1, + " exts.w AL", }, + +/* long -> char */ +{ SCONV, INAREG, + SAREG, TL, + SANY, TCH, + NAREG|NASL, RESC1, + "", }, + +{ SCONV, INAREG, + SAREG, TPOINT, + SANY, TWORD, + 0, RLEFT, + "", }, + +{ PLUS, INAREG|FOREFF, + SAREG, TL, + SCON|SNAME|SOREG, TL, + 0, RLEFT, + " add.w AR,AL\n adc.w UR,UL\n", }, + +{ MINUS, INAREG|FOREFF, + SAREG, TL, + SCON|SNAME|SOREG, TL, + 0, RLEFT, + " sub.w AR,AL\n sbb.w UR,UL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TL, + SAREG|SNAME|SOREG, TL, + 0, RLEFT, + " and.w AR,AL\n and.w UR,UL\n", }, + +{ ER, INAREG|FOREFF, + SAREG, TL, + SAREG|SNAME|SOREG, TL, + 0, RLEFT, + " xor.w AR,AL\n xor.w UR,UL\n", }, + +{ OR, INAREG|FOREFF, + SAREG, TL, + SAREG|SNAME|SOREG, TL, + 0, RLEFT, + " xor.w AR,AL\n xor.w UR,UL\n", }, + +{ COMPL, INAREG|FOREFF, + SAREG, TL, + SAREG|SNAME|SOREG, TL, + 0, RLEFT, + " not.w AR,AL\n not.w UR,UL\n", }, + +{ OPSIMP, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RLEFT, + " Ow AR,AL\n", }, + +/* XXX - Is this rule really correct? Having a SAREG shape seems kind of + strange. Doesn't work. Gives a areg as A1. */ +#if 0 +{ OPSIMP, INBREG, + SAREG, TWORD|TPOINT, + SAREG|SBREG|SNAME|SOREG|SCON, TWORD|TPOINT, + NBREG, RESC1, + " ++Ow AR,A1\n", }, +#endif + +{ OPSIMP, INBREG, + SBREG, TWORD|TPOINT, + SAREG|SBREG|SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RLEFT, + " Ow AR,AL\n", }, + +{ OPSIMP, INCREG|FOREFF, + SCREG, TCH, + SCREG|SNAME|SOREG|SCON, TCH, + 0, RLEFT, + " Ob AR,AL\n", }, + +/* XXX - Do these work? check nspecial in order.c */ +/* signed integer division */ +{ DIV, INAREG, + SAREG, TINT, + SAREG|SNAME|SOREG, TWORD, + /*2*NAREG|NASL|*/NSPECIAL, RLEFT, + " div.w AR\n mov.w r0,AL\n", }, + // " xor.w r2\n div.w AR\n", }, + + +/* signed integer/char division - separate entry for FOREFF */ +{ DIV, FOREFF, + SAREG, TINT, + SAREG|SNAME|SOREG, TWORD, + 0, 0, + "", }, + +#if 0 +/* signed char division */ +{ DIV, INCREG, + SCREG, TCHAR, + SCREG|SNAME|SOREG, TCH, + 2*NCREG|NCSL|NSPECIAL, RLEFT, + " div.b AR\n\tmov.b r0l,AL\n", }, + // " xor.w r2\n div.w AR\n", }, +#endif + +/* signed integer modulus, equal to above */ +{ MOD, INAREG, + SAREG, TINT, + SAREG|SNAME|SOREG, TWORD, + /*2*NAREG|NASL|*/NSPECIAL, RLEFT, + " div.w AR\n\tmov r2,AL\n", }, + +/* signed integer modulus - separate entry for FOREFF */ +{ MOD, FOREFF, + SAREG, TINT, + SAREG|SNAME|SOREG, TWORD, + 0, 0, + "", }, + +/* signed integer multiplication */ +{ MUL, INAREG, + SAREG, TINT, + SAREG|SNAME|SOREG, TWORD, + 2*NAREG|NASL|NSPECIAL, RESC1, + " mul.w AL,AR\n", }, + +{ MUL, FOREFF, + SAREG, TINT, + SAREG|SNAME|SOREG, TWORD, + 0, 0, + "", }, + +#if 0 +{ LS, INAREG, + SAREG, TWORD, + SCON, TANY, + 0, RLEFT, + " shl.w AR,AL\n", }, +#endif + +{ LS, INAREG, + SAREG, TWORD, + SAREG, TWORD, + 0, RLEFT, + " push.b r1h\n" + " mov.b AR,r1h\n" + " shl.w r1h,AL\n" + " pop.b r1h\n", }, + +{ LS, INAREG, + SAREG, TL, + SAREG, TWORD, + 0, RLEFT, + " push.b r1h\n" + " mov.b AR,r1h\n" + " shl.l r1h,ZG\n" + " pop.b r1h\n", }, + +{ RS, INAREG, + SAREG, TWORD, + SAREG, TWORD, + 0, RLEFT, + " push.b r1h\n" + " mov.b AR,r1h\n" + " neg.b r1h\n" + " shl.w r1h,AL\n" + " pop.b r1h\n", }, + +{ RS, INAREG, + SAREG, TL, + SAREG, TWORD, + 0, RLEFT, + " push.b r1h\n" + " mov.b AR,r1h\n" + " neg.b r1h\n" + " shl.l r1h,ZG\n" + " pop.b r1h\n", }, + +#if 0 +{ RS, INAREG, + SAREG, TUNSIGNED, + SCON, TANY, + 0, RLEFT, + " shl ZA,AL\n", }, + +{ RS, INAREG, + SAREG, TINT, + SCON, TANY, + 0, RLEFT, + " sha ZA,AL\n", }, +#endif + +{ OPLOG, FORCC, + SAREG|SBREG|SOREG|SNAME, TL, + SAREG|SBREG|SOREG|SNAME, TL, + 0, 0, + "ZF", }, + +{ OPLOG, FORCC, + SBREG|SOREG, TWORD|TPOINT, + SCON, TWORD|TPOINT, + 0, RESCC, + " cmp.w AR,AL\n", }, + +{ OPLOG, FORCC, + SAREG|SBREG|SOREG|SNAME, TWORD|TPOINT, + SAREG|SBREG|SOREG|SNAME, TWORD|TPOINT, + 0, RESCC, + " cmp.w AR,AL\n", }, + +{ OPLOG, FORCC, + SCREG|SOREG|SNAME, TCH, + SCREG|SOREG|SNAME, TCH, + 0, RESCC, + " cmp.b AR,AL\n", }, + +{ OPLOG, FORCC, + SCREG|SOREG|SNAME, TCH, + SCREG|SOREG|SNAME, TCH, + 0, RESCC, + " cmp.b AR,AL\n", }, + +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " jmp.w ZC\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SCON|SNAME|SOREG|SAREG, TL|TFTN, + NAREG, RESC1, + " mov.w AR,A1\n mov.w UR,U1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SCON|SNAME|SOREG|SAREG|SBREG, TWORD|TPOINT, + NAREG, RESC1, + " mov.w AR,A1\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SBREG|SCON|SNAME|SOREG|SAREG, TWORD|TPOINT, + NBREG, RESC1, + " mov.w AR,A1\n", }, + /* +{ OPLTYPE, INAREG, + SANY, TANY, + SCON|SNAME|SOREG, TCH, + NAREG, RESC1, + " mov.b AR, A1\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SCON|SNAME|SOREG, TCHAR|TUCHAR, + NBREG, RESC1, + " mov.b AR,A1\n", }, + */ + +{ OPLTYPE, INCREG, + SANY, TANY, + SCON|SNAME|SOREG, TCHAR|TUCHAR, + NCREG, RESC1, + " mov.b AR,A1\n", }, + +{ COMPL, INAREG, + SAREG, TWORD, + SANY, TANY, + 0, RLEFT, + " not.w AL\n", }, + +{ COMPL, INCREG, + SCREG, TCH, + SANY, TANY, + 0, RLEFT, + " not.b AL\n", }, + +/* Push function address */ +{ FUNARG, FOREFF, + SCON, TFTN, + SANY, TANY, + 0, RNULL, + "ZH", }, + +{ FUNARG, FOREFF, + SOREG, TFTN, + SANY, TANY, + 0, RNULL, + "ZI", }, + +{ FUNARG, FOREFF, + SNAME|SAREG, TL|TFTN, + SANY, TANY, + 0, RNULL, + " push.w UL\n push.w AL\n", }, + +{ FUNARG, FOREFF, + SCON|SAREG|SNAME|SOREG, TWORD|TPOINT, + SANY, TANY, + 0, RNULL, + " push.w AL\n", }, + +{ FUNARG, FOREFF, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + SANY, TANY, + 0, RNULL, + " push.b AL\n", }, + +/* Match function pointers first */ +#if 0 +{ ASSIGN, FOREFF, + SFTN, TWORD|TPOINT, + SFTN, TWORD|TPOINT, + NAREG, 0, + "ZD", }, +#endif + +{ ASSIGN, INAREG, + SAREG, TFTN, + SCON, TFTN, + 0, RLEFT, + "ZD", }, + +{ ASSIGN, INBREG, + SBREG, TFTN, + SCON, TFTN, + 0, RLEFT, + "ZD", }, + +{ ASSIGN, INAREG, + SAREG, TFTN, + SBREG|SAREG|SOREG|SNAME, TFTN, + 0, RLEFT, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +{ ASSIGN, INBREG, + SBREG, TFTN, + SBREG|SAREG|SOREG|SNAME, TFTN, + 0, RLEFT, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +{ ASSIGN, INAREG, + SBREG|SAREG|SOREG|SNAME, TFTN, + SAREG, TFTN, + 0, RRIGHT, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +{ ASSIGN, INBREG, + SBREG|SAREG|SOREG|SNAME, TFTN, + SBREG, TFTN, + 0, RRIGHT, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +/* a reg -> a reg */ +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + " mov.w AR,AL\n", }, + +{ ASSIGN, INAREG, + SBREG|SAREG|SOREG|SNAME, TL, + SAREG, TL, + 0, RRIGHT, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +{ ASSIGN, INBREG, + SBREG|SAREG|SOREG|SNAME, TL, + SBREG, TL, + 0, RRIGHT, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +{ ASSIGN, FOREFF, + SBREG|SAREG|SOREG|SNAME, TL, + SCON|SBREG|SAREG|SOREG|SNAME, TL, + 0, 0, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +{ ASSIGN, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SCON, TANY, + 0, RLEFT, + " mov.w AR,AL\n", }, + +{ ASSIGN, INBREG|FOREFF, + SBREG, TWORD|TPOINT, + SCON, TANY, + 0, RLEFT, + " mov.w AR,AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TWORD|TPOINT, + SCON, TANY, + 0, 0, + " mov.w AR,AL\n", }, + +/* char, oreg/name -> c reg */ +{ ASSIGN, FOREFF|INCREG, + SCREG, TCHAR|TUCHAR, + SOREG|SNAME|SCON, TCHAR|TUCHAR, + 0, RLEFT, + " mov.b AR,AL\n", }, + +/* int, oreg/name -> a reg */ +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SOREG|SNAME, TWORD|TPOINT, + 0, RLEFT, + " mov.w AR,AL\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TWORD|TPOINT, + SOREG|SNAME, TWORD|TPOINT, + 0, RLEFT, + " mov.w AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RRIGHT, + " mov.w AR,AL\n", }, + +{ ASSIGN, FOREFF|INBREG, + SOREG|SNAME, TWORD|TPOINT, + SBREG, TWORD|TPOINT, + 0, RRIGHT, + " mov.w AR,AL\n", }, + +{ ASSIGN, FOREFF|INCREG, + SOREG|SNAME, TCHAR|TUCHAR, + SCREG, TCHAR|TUCHAR, + 0, RRIGHT, + " mov.b AR,AL\n", }, + +{ ASSIGN, FOREFF|INCREG, + SCREG, TCHAR|TUCHAR, + SCREG, TCHAR|TUCHAR, + 0, RRIGHT, + " mov.b AR,AL\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TWORD|TPOINT, + SBREG, TWORD|TPOINT, + 0, RRIGHT, + " mov.w AR,AL\n", }, + + /* +{ MOVE, FOREFF|INAREG, + SAREG|SBREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + NAREG, RESC1, + " mov.w AL, AR\n", }, + */ + +{ UMUL, INAREG, + SBREG, TPOINT|TWORD, + SANY, TFTN, + NAREG, RESC1, + " mov.w [AL],A1\n mov.w 2[AL],U1\n", }, + +{ UMUL, INAREG, + SBREG, TPOINT|TWORD, + SANY, TPOINT|TWORD, + NAREG, RESC1, + " mov.w [AL],A1\n", }, + +{ UMUL, INBREG, + SBREG, TPOINT|TWORD, + SANY, TPOINT|TWORD, + NBREG|NBSL, RESC1, + " mov.w [AL],A1\n", }, + +{ UMUL, INAREG, + SBREG, TCHAR|TUCHAR|TPTRTO, + SANY, TCHAR|TUCHAR, + NAREG, RESC1, + " mov.b [AL], A1\n", }, + +{ UCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " jsr.w CL\nZB", }, + +{ UCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG, RESC1, + " jsr.w CL\nZB", }, + +{ UCALL, INAREG, + SNAME|SOREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " jsri.a AL\nZB", }, + +{ UCALL, FOREFF, + SNAME|SOREG, TANY, + SANY, TANY, + 0, 0, + " jsri.a AL\nZB", }, + +{ UCALL, INAREG, + SBREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " jsri.a [AL]\nZB", }, + +{ UCALL, FOREFF, + SBREG, TANY, + SANY, TANY, + 0, 0, + " jsri.a [AL]\nZB", }, + + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); + diff --git a/usr.bin/pcc/arch/mips/TODO b/usr.bin/pcc/arch/mips/TODO new file mode 100644 index 00000000000..63b5f67c34a --- /dev/null +++ b/usr.bin/pcc/arch/mips/TODO @@ -0,0 +1,7 @@ +* 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/arch/mips/code.c b/usr.bin/pcc/arch/mips/code.c new file mode 100644 index 00000000000..397210ece14 --- /dev/null +++ b/usr.bin/pcc/arch/mips/code.c @@ -0,0 +1,239 @@ +/* $Id: code.c,v 1.1 2007/09/15 18:12:27 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/arch/mips/local.c b/usr.bin/pcc/arch/mips/local.c new file mode 100644 index 00000000000..33baa4e8cd2 --- /dev/null +++ b/usr.bin/pcc/arch/mips/local.c @@ -0,0 +1,533 @@ +/* $Id: local.c,v 1.1 2007/09/15 18:12:27 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/arch/mips/local2.c b/usr.bin/pcc/arch/mips/local2.c new file mode 100644 index 00000000000..37fa54f13fb --- /dev/null +++ b/usr.bin/pcc/arch/mips/local2.c @@ -0,0 +1,774 @@ +/* $Id: local2.c,v 1.1 2007/09/15 18:12:27 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/arch/mips/macdefs.h b/usr.bin/pcc/arch/mips/macdefs.h new file mode 100644 index 00000000000..87534a64660 --- /dev/null +++ b/usr.bin/pcc/arch/mips/macdefs.h @@ -0,0 +1,227 @@ +/* $Id: macdefs.h,v 1.1 2007/09/15 18:12:27 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/arch/mips/order.c b/usr.bin/pcc/arch/mips/order.c new file mode 100644 index 00000000000..2173d8db624 --- /dev/null +++ b/usr.bin/pcc/arch/mips/order.c @@ -0,0 +1,350 @@ +/* $Id: order.c,v 1.1 2007/09/15 18:12:27 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/arch/mips/table.c b/usr.bin/pcc/arch/mips/table.c new file mode 100644 index 00000000000..e7d10ad1fe7 --- /dev/null +++ b/usr.bin/pcc/arch/mips/table.c @@ -0,0 +1,776 @@ +/* $Id: table.c,v 1.1 2007/09/15 18:12:28 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]); diff --git a/usr.bin/pcc/arch/nova/README b/usr.bin/pcc/arch/nova/README new file mode 100644 index 00000000000..939f8061c2a --- /dev/null +++ b/usr.bin/pcc/arch/nova/README @@ -0,0 +1,120 @@ +Calling conventions, stack frame and zero page: + +The variables that normally are placed on the stack or in registers in C +are instead allocated in the zero page and saved on a (fictive) stack +when calling functions. Some locations have predefined functions though. +Arrays allocated as automatics are stored on the stack with a pointer +in zero page to its destination. + +0-7 Unused +10 Stack pointer +11 Frame pointer +12-14 Unused +15 Used by prolog +16 Prolog address, written in crt0 +17 Epilog address, written in crt0 +20-27 Auto-increment, scratch +30-37 Auto-decrement, scratch +40-47 Unused +50-57 Scratch/Arguments +60-77 Permanent, save before use. +100-377 Addresses for subroutines, written by the assembler + +The normal registers (AC0-AC3) are all considered scratch registers. + +Register classes are assigned as: + AC0-AC3: AREGs. + AC2-AC3: BREGs. + 50-77: CREGs. + ...and eventually register pairs as DREGs. + +In byte code the low half of a word is the first byte (little-endian). +This is bit 8-15 in Nova syntax. + +The stack is growing towards lower adresses (as opposed to the Eclipse stack). +Stack layout: + + ! arg1 ! + ! arg0 ! + fp -> ! old pc! + ! old fp! + pc -> ! saved ! + +A reference to a struct member in assembler, a = b->c; b is in ZP 50 ++ is zeropage-addressing +* is fp-adressing + +# offset 0 ++ lda 0,@50 # load value from indirect ZP 50 into ac0 +* lda 2,,3 # load value from (ac3) into ac2 +* lda 0,,2 # load value from (ac2) into ac0 + +# offset 12 ++ lda 2,50 # load value from ZP 50 into ac2 ++ lda 0,12,2 # load value from (ac2+12) into ac0 +* lda 2,,3 # load value from (ac3) into ac2 +* lda 0,12,2 # load value from 12(ac2) into ac0 + +# offset 517 ++ lda 2,50 # load value from ZP 50 into ac2 ++ lda 0,.L42-.,1 # load offset from .L42 PC-indexed ++ addz 0,2,skp # add offset to ac2 and skip ++.L42: .word 517 # offset value ++ lda 0,,2 # load value from (ac2) into ac0 + +The prolog/epilog implementation; it is implemented as subroutines. + +.L42: .word 13 # number of words to save +func: + sta 3,@40 # save return address on stack + lda 2,.L42-.,1 # get save word count + jsr @45 # go to prolog + ... + lda 2,.L42-.,1 # get restore word count + jmp @46 # jump to epilog + +# words to save in 2, return address in 3 +prolog: + sta 2,45 # save # of words to move at scratch + lda 0,41 # get old fp + lda 1,40 # get sp + sta 1,41 # save new fp + dsz 40 # decrement stack, will never be 0 + sta 0,@40 # save old fp + dsz 40 + + lda 0,off57 # fetch address of regs to save - 1 + sta 0,20 # store address at autoincr +1: lda 0,@20 # get word to copy + sta 0,@40 # push on stack + dsz 40 # manually decrement sp + dsz 45 # copied all words? + jmp 1b,1 # no, continue + jmp 0,3 # return + +epilog: + sta 2,45 # save # of words to move at scratch + + lda 3,off57 # fetch address of regs to save + sta 3,20 # store at autoincr + lda 3,41 # fetch fp + sta 3,30 # store at autodecr + lda 3,@30 # get old fp + +1: lda 2,@30 # fetch word from stack + sta 2,@20 # store at orig place + dsz 45 # enough? + jmp 1b,1 # no, continue + + lda 2,41 # get new fp + sta 2,40 # restore stack + sta 3,41 # restore old fp + jmp @40 # Return + +Assembler syntax and functions. + +The assembler syntax mimics the DG assembler. +Load and store to addresses is written "lda 0,foo" to load from address foo. +If foo is not in zero page then the assembler will put the lda in the +text area close to the instruction and do an indirect pc-relative load. + diff --git a/usr.bin/pcc/arch/nova/code.c b/usr.bin/pcc/arch/nova/code.c new file mode 100644 index 00000000000..78bcdd4d4be --- /dev/null +++ b/usr.bin/pcc/arch/nova/code.c @@ -0,0 +1,212 @@ +/* $Id: code.c,v 1.1 2007/09/15 18:12:28 otto Exp $ */ +/* + * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass1.h" + +/* + * cause the alignment to become a multiple of n + * never called for text segment. + */ +void +defalign(int n) +{ + /* alignment are always correct */ +} + +/* + * 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; +cerror("efcode"); + /* address of return struct is in eax */ + /* create a call to memcpy() */ + /* will get the result in eax */ + p = block(REG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR)); +// p->n_rval = EAX; + q = block(OREG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR)); +// q->n_rval = EBP; + q->n_lval = 8; /* return buffer offset */ + p = block(CM, q, p, INT, 0, MKSUE(INT)); + sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR; + p = block(CM, p, bcon(sz), INT, 0, MKSUE(INT)); + p->n_right->n_name = ""; + p = block(CALL, bcon(0), p, CHAR+PTR, 0, MKSUE(CHAR+PTR)); + p->n_left->n_name = "memcpy"; + p = clocal(p); + send_passt(IP_NODE, p); +} + +/* + * 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; + + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; +cerror("bfcode"); + /* Function returns struct, adjust arg offset */ + for (i = 0; i < n; i++) + a[i]->soffset += SZPOINT(INT); +} + + +/* + * 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(int num, struct swents **p, int n) +{ + NODE *r; + int i; + + /* simple switch code */ + for (i = 1; i <= n; ++i) { + /* already in 1 */ + r = tempnode(num, INT, 0, MKSUE(INT)); + r = buildtree(NE, r, bcon(p[i]->sval)); + cbranch(buildtree(NOT, r, NIL), bcon(p[i]->slab)); + } + if (p[0]->slab > 0) + branch(p[0]->slab); +} diff --git a/usr.bin/pcc/arch/nova/local.c b/usr.bin/pcc/arch/nova/local.c new file mode 100644 index 00000000000..61ccb9429e9 --- /dev/null +++ b/usr.bin/pcc/arch/nova/local.c @@ -0,0 +1,618 @@ +/* $Id: local.c,v 1.1 2007/09/15 18:12:28 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass1.h" + +/* this file contains code which is dependent on the target machine */ + +NODE * +clocal(NODE *p) +{ + struct symtab *q; + NODE *r, *l; + int o; + + switch( o = p->n_op ){ + case NAME: + /* handle variables */ + if ((q = p->n_sp) == NULL) + return p; /* Nothing to care about */ + switch (q->sclass) { + 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; + default: + break; + } + 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 PCONV: + l = p->n_left; + /* if conversion to another pointer type, just remove */ + if (p->n_type > BTMASK && l->n_type > BTMASK) + goto delp; + break; + + delp: l->n_type = p->n_type; + l->n_qual = p->n_qual; + l->n_df = p->n_df; + l->n_sue = p->n_sue; + nfree(p); + p = l; + break; + } + +#if 0 + register struct symtab *q; + register NODE *r, *l; + register int o; + register int m; + 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 STCALL: + case CALL: + /* Fix function call arguments. On x86, just add funarg */ + for (r = p->n_right; r->n_op == CM; r = r->n_left) { + if (r->n_right->n_op != STARG && + r->n_right->n_op != FUNARG) + r->n_right = block(FUNARG, r->n_right, NIL, + r->n_right->n_type, r->n_right->n_df, + r->n_right->n_sue); + } + if (r->n_op != STARG && r->n_op != FUNARG) { + l = talloc(); + *l = *r; + r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type; + } + break; + + case CBRANCH: + l = p->n_left; + + /* + * Remove unneccessary conversion ops. + */ + if (clogop(l->n_op) && l->n_left->n_op == SCONV) { + if (coptype(l->n_op) != BITYPE) + break; + if (l->n_right->n_op == ICON) { + r = l->n_left->n_left; + if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) + break; + /* Type must be correct */ + t = r->n_type; + nfree(l->n_left); + l->n_left = r; + l->n_type = t; + l->n_right->n_type = t; + } + } + break; + + case PCONV: + /* Remove redundant PCONV's. Be careful */ + l = p->n_left; + if (l->n_op == ICON) { + l->n_lval = (unsigned)l->n_lval; + goto delp; + } + if (l->n_type < INT || l->n_type == LONGLONG || + l->n_type == ULONGLONG) { + /* float etc? */ + p->n_left = block(SCONV, l, NIL, + UNSIGNED, 0, MKSUE(UNSIGNED)); + break; + } + /* if left is SCONV, cannot remove */ + if (l->n_op == SCONV) + break; + /* if conversion to another pointer type, just remove */ + if (p->n_type > BTMASK && l->n_type > BTMASK) + goto delp; + break; + + delp: l->n_type = p->n_type; + l->n_qual = p->n_qual; + l->n_df = p->n_df; + l->n_sue = p->n_sue; + nfree(p); + p = l; + break; + + case SCONV: + l = p->n_left; + + if (p->n_type == l->n_type) { + nfree(p); + return l; + } + + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + btdims[p->n_type].suesize == btdims[l->n_type].suesize) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE && + l->n_type != LDOUBLE && p->n_type != LDOUBLE) { + if (l->n_op == NAME || l->n_op == UMUL || + l->n_op == TEMP) { + l->n_type = p->n_type; + nfree(p); + return l; + } + } + } + + if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && + coptype(l->n_op) == BITYPE) { + l->n_type = p->n_type; + nfree(p); + return l; + } + + o = l->n_op; + m = p->n_type; + + if (o == ICON) { + CONSZ val = l->n_lval; + + if (!ISPTR(m)) /* Pointers don't need to be conv'd */ + switch (m) { + case CHAR: + l->n_lval = (char)val; + break; + case UCHAR: + l->n_lval = val & 0377; + break; + case SHORT: + l->n_lval = (short)val; + break; + case USHORT: + l->n_lval = val & 0177777; + break; + case ULONG: + case UNSIGNED: + l->n_lval = val & 0xffffffff; + break; + case ENUMTY: + case MOETY: + case LONG: + case INT: + l->n_lval = (int)val; + break; + case LONGLONG: + l->n_lval = (long long)val; + break; + case ULONGLONG: + l->n_lval = val; + break; + case VOID: + break; + case LDOUBLE: + case DOUBLE: + case FLOAT: + l->n_op = FCON; + l->n_dcon = val; + break; + default: + cerror("unknown type %d", m); + } + l->n_type = m; + l->n_sue = MKSUE(m); + nfree(p); + return l; + } + if (DEUNSIGN(p->n_type) == SHORT && + DEUNSIGN(l->n_type) == SHORT) { + nfree(p); + p = l; + } + if ((p->n_type == CHAR || p->n_type == UCHAR || + p->n_type == SHORT || p->n_type == USHORT) && + (l->n_type == FLOAT || l->n_type == DOUBLE || + l->n_type == LDOUBLE)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue); + p->n_left->n_type = INT; + return p; + } + break; + + case MOD: + 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(p->n_type); + break; + + case LS: + case RS: + /* shift count must be in a char + * unless longlong, where it must be int */ + if (p->n_right->n_op == ICON) + break; /* do not do anything */ + if (p->n_type == LONGLONG || p->n_type == ULONGLONG) { + if (p->n_right->n_type != INT) + p->n_right = block(SCONV, p->n_right, NIL, + INT, 0, MKSUE(INT)); + break; + } + if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR) + break; + p->n_right = block(SCONV, p->n_right, NIL, + CHAR, 0, MKSUE(CHAR)); + break; + } +//printf("ut:\n"); +//fwalk(p, eprint, 0); + +#endif + + return(p); +} + +void +myp2tree(NODE *p) +{ +} + +/*ARGSUSED*/ +int +andable(NODE *p) +{ + return(1); /* all names can have & taken on them */ +} + +/* + * at the end of the arguments of a ftn, set the automatic offset + */ +void +cendarg() +{ + autooff = AUTOINIT; +} + +/* + * Return 1 if a variable of type type is OK to put in register. + */ +int +cisreg(TWORD t) +{ + return 1; /* try to put anything in a register */ +} + +/* + * 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 nova, return the type-specific index number which calculation + * is based on its size. For example, char 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 %ld type %x dim %p siz %d\n", + off, t, d, sue->suesize); + + p = bcon(0); + p->n_lval = off/SZINT; /* Default */ + if (ISPTR(DECREF(t))) + return p; + if (t == VOID || t == CHAR || t == UCHAR) + p->n_lval = off/SZCHAR; /* pointer to char */ + 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; + +cerror("spalloc"); + 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 */ + + if (p->n_op != ICON) + cerror("ninval: init node not constant"); + + switch (t) { + case LONG: + case ULONG: + inval(p->n_lval & 0xffff); + inval(p->n_lval >> 16); + break; + case INT: + case UNSIGNED: + printf("\t.word 0%o", (short)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 &= 0xffff; + printf(" .word 0%o\n", (int)word); +} + +/* output code to initialize a floating point value */ +/* the proper alignment has been obtained */ +void +finval(NODE *p) +{ + union { float f; double d; long double l; int i[3]; } u; + +cerror("finval"); + switch (p->n_type) { + case LDOUBLE: + u.i[2] = 0; + u.l = (long double)p->n_dcon; + printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]); + break; + case DOUBLE: + u.d = (double)p->n_dcon; + printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]); + break; + case FLOAT: + u.f = (float)p->n_dcon; + printf("\t.long\t0x%x\n", u.i[0]); + break; + } +} + +/* 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 LONGLONG: + MODTYPE(type,LONG); + break; + + case ULONGLONG: + MODTYPE(type,ULONG); + break; + case SHORT: + MODTYPE(type,INT); + break; + case USHORT: + MODTYPE(type,UNSIGNED); + break; + } + 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/arch/nova/local2.c b/usr.bin/pcc/arch/nova/local2.c new file mode 100644 index 00000000000..93c2f843781 --- /dev/null +++ b/usr.bin/pcc/arch/nova/local2.c @@ -0,0 +1,563 @@ +/* $Id: local2.c,v 1.1 2007/09/15 18:12:28 otto Exp $ */ +/* + * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass2.h" +# include <ctype.h> +# include <string.h> + +void acon(NODE *p); +int argsize(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 prolnum; +static struct ldq { + struct ldq *next; + int val; + int lab; + char *name; +} *ldq; + + +void +prologue(struct interpass_prolog *ipp) +{ + int i, j; + + for (i = ipp->ipp_regs, j = 0; i; i >>= 1) + if (i&1) + j++; + printf(".LP%d: .word 0%o\n", prolnum, j); + if (ipp->ipp_vis) + printf(" .globl %s\n", ipp->ipp_name); + printf("%s:\n", ipp->ipp_name); + printf(" sta 3,@40\n"); /* save ret pc on stack */ + printf(" lda 2,.LP%d-.,1\n", prolnum); + printf(" jsr @45\n"); + prolnum++; +} + +void +eoftn(struct interpass_prolog *ipp) +{ + int i, j; + + 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) + if (i & 1) + j++; + printf(" lda 2,.LP%d-.,1\n", prolnum); + printf(" jmp @46\n"); + printf(".LP%d: .word 0%o\n", prolnum, j); + prolnum++; + while (ldq) { + printf(".LP%d: .word 0%o", ldq->lab, ldq->val); + if (ldq->name && *ldq->name) + printf("+%s", ldq->name); + printf("\n"); + ldq = ldq->next; + } +} + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str = 0; + + switch (o) { + case PLUS: + str = "add"; + break; + case MINUS: + str = "sub"; + break; + case AND: + str = "and"; + break; + case OR: + cerror("hopcode OR"); + break; + case ER: + cerror("hopcode xor"); + str = "xor"; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + printf("%s%c", str, f); +} + +#if 0 +/* + * Return type size in bytes. Used by R2REGS, arg 2 to offset(). + */ +int +tlen(p) NODE *p; +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(SZSHORT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case INT: + case UNSIGNED: + case LONG: + case ULONG: + return(SZINT/SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type)/SZCHAR; + } +} +#endif + +#if 0 +/* + * Assign to a bitfield. + * Clumsy at least, but what to do? + */ +static void +bfasg(NODE *p) +{ + NODE *fn = p->n_left; + int shift = UPKFOFF(fn->n_rval); + int fsz = UPKFSZ(fn->n_rval); + int andval, tch = 0; + + /* get instruction size */ + switch (p->n_type) { + case CHAR: case UCHAR: tch = 'b'; break; + case SHORT: case USHORT: tch = 'w'; break; + case INT: case UNSIGNED: tch = 'l'; break; + default: comperr("bfasg"); + } + + /* put src into a temporary reg */ + fprintf(stdout, " mov%c ", tch); + adrput(stdout, getlr(p, 'R')); + fprintf(stdout, ","); + adrput(stdout, getlr(p, '1')); + fprintf(stdout, "\n"); + + /* AND away the bits from dest */ + andval = ~(((1 << fsz) - 1) << shift); + fprintf(stdout, " and%c $%d,", tch, andval); + adrput(stdout, fn->n_left); + fprintf(stdout, "\n"); + + /* AND away unwanted bits from src */ + andval = ((1 << fsz) - 1); + fprintf(stdout, " and%c $%d,", tch, andval); + adrput(stdout, getlr(p, '1')); + fprintf(stdout, "\n"); + + /* SHIFT left src number of bits */ + if (shift) { + fprintf(stdout, " sal%c $%d,", tch, shift); + adrput(stdout, getlr(p, '1')); + fprintf(stdout, "\n"); + } + + /* OR in src to dest */ + fprintf(stdout, " or%c ", tch); + adrput(stdout, getlr(p, '1')); + fprintf(stdout, ","); + adrput(stdout, fn->n_left); + fprintf(stdout, "\n"); +} +#endif + +#if 0 +/* + * Push a structure on stack as argument. + * the scratch registers are already free here + */ +static void +starg(NODE *p) +{ + FILE *fp = stdout; + + fprintf(fp, " subl $%d,%%esp\n", p->n_stsize); + fprintf(fp, " pushl $%d\n", p->n_stsize); + expand(p, 0, " pushl AL\n"); + expand(p, 0, " leal 8(%esp),A1\n"); + expand(p, 0, " pushl A1\n"); + fprintf(fp, " call memcpy\n"); + fprintf(fp, " addl $12,%%esp\n"); +} +#endif + +void +zzzcode(NODE *p, int c) +{ + struct ldq *ld; + + switch (c) { + case 'A': /* print out a skip ending if any numbers in queue */ + if (ldq == NULL) + return; + printf(",skp\n.LP%d: .word 0%o", ldq->lab, ldq->val); + if (ldq->name && *ldq->name) + printf("+%s", ldq->name); + printf("\n"); + ldq = ldq->next; + break; + + case 'B': /* print a label for later load */ + ld = tmpalloc(sizeof(struct ldq)); + ld->val = p->n_lval; + ld->name = p->n_name; + ld->lab = prolnum++; + ld->next = ldq; + ldq = ld; + printf(".LP%d-.", ld->lab); + break; + + case 'C': /* fix reference to external variable via indirection */ + zzzcode(p->n_left, 'B'); + break; + + case 'D': /* fix reference to external variable via indirection */ + zzzcode(p, 'B'); + break; + + default: + comperr("zzzcode %c", c); + } +} + +/*ARGSUSED*/ +int +rewfld(NODE *p) +{ + return(1); +} + +int canaddr(NODE *); +int +canaddr(NODE *p) +{ + int o = p->n_op; + + if (o==NAME || o==REG || o==ICON || o==OREG || + (o==UMUL && shumul(p->n_left))) + return(1); + return(0); +} + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE *p) +{ + int o = p->n_op; + +cerror("flshape"); + 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); +} + +/* + * Conput should only be used by e2print on Nova. + */ +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, p %p", p); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + comperr("insput"); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ +comperr("upput"); +#if 0 + size /= SZCHAR; + switch (p->n_op) { + case REG: + fprintf(stdout, "%%%s", &rnames[p->n_rval][3]); + 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); + } +#endif +} + +void +adrput(FILE *io, NODE *p) +{ + /* 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: + printf("%d,%s", (int)p->n_lval, rnames[p->n_rval]); + return; + + case ICON: + /* addressable value of the constant */ + fputc('$', io); + conput(io, p); + return; + + case MOVE: + case REG: + switch (p->n_type) { + case LONGLONG: + case ULONGLONG: + fprintf(io, "%%%c%c%c", rnames[p->n_rval][0], + rnames[p->n_rval][1], rnames[p->n_rval][2]); + break; + case SHORT: + case USHORT: + fprintf(io, "%%%s", &rnames[p->n_rval][2]); + break; + default: + fprintf(io, "%s", rnames[p->n_rval]); + } + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ + comperr("cbgen"); +} + +void +myreader(struct interpass *ipole) +{ + if (x2debug) + printip(ipole); +} + +void +mycanon(NODE *p) +{ +} + +void +myoptim(struct interpass *ip) +{ +} + +void +rmove(int s, int d, TWORD t) +{ + comperr("rmove"); +} + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + * Return true if we always can find a color. + */ +int +COLORMAP(int c, int *r) +{ + int num; + + switch (c) { + case CLASSA: + num = r[CLASSB] + r[CLASSA]; + return num < 4; + case CLASSB: + num = r[CLASSB] + r[CLASSA]; + return num < 2; + case CLASSC: + return r[CLASSC] < CREGCNT; + case CLASSD: + return r[CLASSD] < DREGCNT; + } + return 0; /* XXX gcc */ +} + +char *rnames[] = { + "0", "1", "2", "3", + "050", "051", "052", "053", "054", "055", "056", "057", + "060", "061", "062", "063", "064", "065", "066", "067", + "070", "071", "072", "073", "074", "075", "076", "077", + "041", "040" +}; + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + return CLASSA; +} + +/* + * Calculate argument sizes. + */ +void +lastcall(NODE *p) +{ +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + return SRNOPE; +} diff --git a/usr.bin/pcc/arch/nova/macdefs.h b/usr.bin/pcc/arch/nova/macdefs.h new file mode 100644 index 00000000000..3104c900ef4 --- /dev/null +++ b/usr.bin/pcc/arch/nova/macdefs.h @@ -0,0 +1,195 @@ +/* $Id: macdefs.h,v 1.1 2007/09/15 18:12:28 otto Exp $ */ +/* + * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Machine-dependent defines for Data General Nova. + */ + +/* + * Convert (multi-)character constant to integer. + */ +#define makecc(val,i) lastcon = (lastcon<<8)|(val); + +#define ARGINIT 16 /* adjusted in MD code */ +#define AUTOINIT 16 /* adjusted in MD code */ + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZINT 16 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#define SZLDOUBLE 64 +#define SZLONG 32 +#define SZSHORT 16 +#define SZLONGLONG 32 +#define SZPOINT(t) 16 /* Actually 15 */ + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALINT 16 +#define ALFLOAT 16 +#define ALDOUBLE 16 +#define ALLDOUBLE 16 +#define ALLONG 16 +#define ALLONGLONG 16 +#define ALSHORT 16 +#define ALPOINT 16 +#define ALSTRUCT 16 +#define ALSTACK 16 + +/* + * 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 MIN_SHORT +#define MAX_INT MAX_SHORT +#define MAX_UNSIGNED MAX_USHORT +#define MIN_LONG 0x80000000L +#define MAX_LONG 0x7fffffffL +#define MAX_ULONG 0xffffffffUL +#define MIN_LONGLONG MIN_LONG +#define MAX_LONGLONG MAX_LONG +#define MAX_ULONGLONG MAX_ULONG + +/* Default char is unsigned */ +#define CHAR_UNSIGNED + +/* + * Use large-enough types. + */ +typedef long CONSZ; +typedef unsigned long U_CONSZ; +typedef long OFFSZ; + +#define CONFMT "%ld" /* 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)&01) +#define wdal(k) (BYTEOFF(k)==0) +#define BITOOR(x) (x) /* bit offset to oreg offset XXX die! */ + +#define STOARG(p) +#define STOFARG(p) +#define STOSTARG(p) +#define genfcall(a,b) gencall(a,b) + +#define szty(t) (((t) == DOUBLE || (t) == LDOUBLE) ? 4 : \ + ((t) == LONGLONG || (t) == ULONGLONG || \ + (t) == LONG || (t) == ULONG) ? 2 : 1) + +/* + * The Nova has three register classes. Note that the space used in + * zero page is considered registers. + * Register 28 and 29 are FP and SP. + * + * The classes used on Nova are: + * A - AC0-AC3 (as non-index registers) : reg 0-3 + * B - AC2-AC3 (as index registers) : reg 2-3 + * C - address 50-77 in memory : reg 4-27 + */ +#define MAXREGS 30 /* 0-29 */ + +#define RSTATUS \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|SBREG|TEMPREG, SAREG|SBREG|TEMPREG,\ + SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG, \ + SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG, \ + SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, \ + SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, \ + SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, \ + SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, \ + 0, 0 + +#define ROVERLAP \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, + + +/* Return a register class based on the type of the node */ +/* all types in all classes */ +#define PCLASS(p) (SAREG|SBREG|SCREG) + +#define NUMCLASS 4 /* highest number of reg classes used */ + /* XXX - must be 4 */ + +int COLORMAP(int c, int *r); +#define GCLASS(x) (x < 4 ? CLASSA : CLASSC) +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 6) /* A1 */ +#define ENCRA2(x) ((x) << 12) /* A2 */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ +#define RETREG(x) (0) /* ? Sanity */ + +/* XXX - to die */ +#define FPREG 28 /* frame pointer */ +#define STKREG 29 /* stack pointer */ + +#define MYREADER(p) myreader(p) +#define MYCANON(p) mycanon(p) +#define MYOPTIM diff --git a/usr.bin/pcc/arch/nova/order.c b/usr.bin/pcc/arch/nova/order.c new file mode 100644 index 00000000000..fc6b2191d2c --- /dev/null +++ b/usr.bin/pcc/arch/nova/order.c @@ -0,0 +1,164 @@ +/* $Id: order.c,v 1.1 2007/09/15 18:12:28 otto Exp $ */ +/* + * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass2.h" + +#include <string.h> + +int canaddr(NODE *); + +/* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + if (r != 2 && r != 3) + return 1; /* can only index ac2 and ac3 */ + if (t == CHAR || t == UCHAR) { + if (off < -256 || off > 254) + return 1; + } else if (off < -128 || off > 127) + return 1; + return(0); /* YES */ +} + +/* + * Turn a UMUL-referenced node into OREG. + * Be careful about register classes, this is a place where classes change. + */ +void +offstar(NODE *p, int shape) +{ + NODE *r; + + if (x2debug) + printf("offstar(%p)\n", p); + + if (isreg(p)) + return; /* Is already OREG */ + + r = p->n_right; + if( p->n_op == PLUS || p->n_op == MINUS ){ + if( r->n_op == ICON ){ + if (isreg(p->n_left) == 0 || + (p->n_left->n_op == REG && + p->n_left->n_rval != 2 && p->n_left->n_rval != 3)) + (void)geninsn(p->n_left, INBREG); + /* Converted in ormake() */ + return; + } + } + (void)geninsn(p, INBREG); +} + +/* + * Do the actual conversion of offstar-found OREGs into real OREGs. + */ +void +myormake(NODE *q) +{ + if (x2debug) + printf("myormake(%p)\n", q); +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p) +{ + + if (x2debug) + printf("shumul(%p)\n", p); + + /* Turns currently anything into OREG on x86 */ + return SOREG; +} + +/* + * Rewrite increment/decrement operation. + */ +int +setincr(NODE *p) +{ + if (x2debug) + printf("setincr(%p)\n", p); + + return(0); +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE *p) +{ + + if (x2debug) + printf("setbin(%p)\n", p); + return 0; + +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + if (x2debug) + printf("setasg(%p)\n", p); + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +/* + * Special handling of some instruction register allocation. + */ +struct rspecial * +nspecial(struct optab *q) +{ + comperr("nspecial entry %d", q - table); + return 0; /* XXX gcc */ +} + +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE *p) +{ + return 0; +} diff --git a/usr.bin/pcc/arch/nova/table.c b/usr.bin/pcc/arch/nova/table.c new file mode 100644 index 00000000000..d2d7bdd6513 --- /dev/null +++ b/usr.bin/pcc/arch/nova/table.c @@ -0,0 +1,1514 @@ +/* $Id: table.c,v 1.1 2007/09/15 18:12:28 otto Exp $ */ +/* + * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass2.h" + +# 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, "", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RDEST, + " mov AR,ALZA\n", }, + +{ ASSIGN, FOREFF|INAREG, + SNAME, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RDEST, + " sta AR,ZC,1\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RDEST, + " sta AR,AL\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SONE, TWORD, + NAREG, RESC1, + " subzl A1,A1ZA\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SCON, TWORD, + NAREG, RESC1, + " lda A1,ZB,1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SZERO, TWORD, + NAREG, RESC1, + " sub A1,A1ZA\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SNAME, TWORD|TPOINT, + NAREG, RESC1, + " lda A1,ZD,1\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SNAME, TWORD|TPOINT, + NBREG, RESC1, + " lda A1,ZD,1\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SCREG, TWORD|TPOINT, + NBREG, RESC1, + " lda A1,AR\n", }, + +{ PLUS, INBREG|INAREG, + SAREG|SBREG, TWORD|TPOINT, + SONE, TANY, + 0, RLEFT, + " inc AL,AL\n", }, + +{ OPSIMP, INBREG|INAREG|FOREFF, + SAREG|SBREG, TWORD|TPOINT, + SAREG|SBREG, TWORD|TPOINT, + 0, RLEFT, + " O AR,AL\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SOREG, TPOINT|TWORD, + NAREG|NASL, RESC1, + " lda A1,AL\n", }, + +#if 0 + +/* PCONVs are usually not necessary */ +{ PCONV, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + "", }, + +/* + * A bunch conversions of integral<->integral types + * There are lots of them, first in table conversions to itself + * and then conversions from each type to the others. + */ + +/* itself to itself, including pointers */ + +/* convert (u)char to (u)char. */ +{ SCONV, INCH, + SHCH, TCHAR|TUCHAR, + SHCH, TCHAR|TUCHAR, + 0, RLEFT, + "", }, + +/* convert pointers to int. */ +{ SCONV, ININT, + SHINT, TPOINT|TWORD, + SANY, TWORD, + 0, RLEFT, + "", }, + +/* convert (u)longlong to (u)longlong. */ +{ SCONV, INLL, + SHLL, TLL, + SHLL, TLL, + 0, RLEFT, + "", }, + +/* convert double <-> float. nothing to do here */ +{ SCONV, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + "", }, + +/* convert pointers to pointers. */ +{ SCONV, ININT, + SHINT, TPOINT, + SANY, TPOINT, + 0, RLEFT, + "", }, + +/* char to something */ + +/* convert char to (unsigned) short. */ +{ SCONV, ININT, + SBREG|SOREG|SNAME, TCHAR, + SAREG, TSHORT|TUSHORT, + NASL|NAREG, RESC1, + " movsbw AL,A1\n", }, + +/* convert unsigned char to (u)short. */ +{ SCONV, ININT, + SHCH|SOREG|SNAME, TUCHAR, + SAREG, TSHORT|TUSHORT, + NASL|NAREG, RESC1, + " movzbw AL,A1\n", }, + +/* convert signed char to int (or pointer). */ +{ SCONV, ININT, + SHCH|SOREG|SNAME, TCHAR, + SAREG, TWORD|TPOINT, + NASL|NAREG, RESC1, + " movsbl AL,A1\n", }, + +/* convert unsigned char to (u)int. */ +{ SCONV, ININT, + SHCH|SOREG|SNAME, TUCHAR, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movzbl AL,A1\n", }, + +/* convert char to (u)long long */ +{ SCONV, INLL, + SHCH|SOREG|SNAME, TCHAR, + SANY, TLL, + NSPECIAL|NAREG|NASL, RESC1, + " movsbl AL,%eax\n cltd\n", }, + +/* convert unsigned char to (u)long long */ +{ SCONV, INLL, + SHCH|SOREG|SNAME, TUCHAR, + SANY, TLL, + NCREG|NCSL, RESC1, + " movzbl AL,A1\n xorl U1,U1\n", }, + +/* convert char (in register) to double XXX - use NTEMP */ +{ SCONV, INFL, + SHCH|SOREG|SNAME, TCHAR, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG, RESC2, + " movsbl AL,A1\n pushl A1\n" + " fildl (%esp)\n addl $4,%esp\n", }, + +/* convert (u)char (in register) to double XXX - use NTEMP */ +{ SCONV, INFL, + SHCH|SOREG|SNAME, TUCHAR, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG, RESC2, + " movzbl AL,A1\n pushl A1\n" + " fildl (%esp)\n addl $4,%esp\n", }, + +/* short to something */ + +/* convert short (in memory) to char */ +{ SCONV, INCH, + SNAME|SOREG, TSHORT|TUSHORT, + SHCH, TCHAR|TUCHAR, + NBREG|NBSL, RESC1, + " movb AL,A1\n", }, + +/* convert short (in reg) to char. */ +{ SCONV, INCH, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL|NBREG|NBSL, RESC1, + "ZM", }, + +/* convert short to (u)int. */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movswl AL,A1\n", }, + +/* convert unsigned short to (u)int. */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TUSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movzwl AL,A1\n", }, + +/* convert short to (u)long long */ +{ SCONV, INLL, + SAREG|SOREG|SNAME, TSHORT, + SHLL, TLL, + NSPECIAL|NCREG|NCSL, RESC1, + " movswl AL,%eax\n cltd\n", }, + +/* convert unsigned short to (u)long long */ +{ SCONV, INLL, + SAREG|SOREG|SNAME, TUSHORT, + SHLL, TLL, + NCREG|NCSL, RESC1, + " movzwl AL,A1\n xorl U1,U1\n", }, + +/* convert short (in memory) to float/double */ +{ SCONV, INFL, + SOREG|SNAME, TSHORT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fild AL\n", }, + +/* convert short (in register) to float/double */ +{ SCONV, INFL, + SAREG, TSHORT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NTEMP|NDREG, RESC1, + " pushw AL\n fild (%esp)\n addl $2,%esp\n", }, + +/* convert unsigned short to double XXX - use NTEMP */ +{ SCONV, INFL, + SAREG|SOREG|SNAME, TUSHORT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG|NTEMP, RESC2, + " movzwl AL,A1\n pushl A1\n" + " fildl (%esp)\n addl $4,%esp\n", }, + +/* int to something */ + +/* convert int to char. This is done when register is loaded */ +{ SCONV, INCH, + SAREG, TWORD, + SANY, TCHAR|TUCHAR, + NSPECIAL|NBREG|NBSL, RESC1, + "ZM", }, + +/* convert int to short. Nothing to do */ +{ SCONV, INAREG, + SAREG, TWORD, + SANY, TSHORT|TUSHORT, + 0, RLEFT, + "", }, + +/* convert int to long long */ +{ SCONV, INLL, + SAREG, TWORD|TPOINT, + SCREG, TLONGLONG, + NSPECIAL|NCREG|NCSL, RESC1, + " cltd\n", }, + +/* convert int to unsigned long long */ +{ SCONV, INLL, + SAREG|SOREG|SNAME, TWORD|TPOINT, + SHLL, TULONGLONG, + NCSL|NCREG, RESC1, + " movl AL,A1\n xorl U1,U1\n", }, + +/* convert int (in memory) to double */ +{ SCONV, INFL, + SOREG|SNAME, TWORD, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fildl AL\n", }, + +/* convert int (in register) to double */ +{ SCONV, INFL, + SAREG, TWORD, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NTEMP|NDREG, RESC1, + " pushl AL\n fildl (%esp)\n addl $4,%esp\n", }, + +/* long long to something */ + +/* convert (u)long long to (u)char (mem->reg) */ +{ SCONV, INCH, + SOREG|SNAME, TLL, + SANY, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " movb AL,A1\n", }, + +/* convert (u)long long to (u)char (reg->reg, hopefully nothing) */ +{ SCONV, INCH, + SHLL, TLL, + SANY, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + "ZS", }, + +/* convert (u)long long to (u)short (mem->reg) */ +{ SCONV, INAREG, + SOREG|SNAME, TLL, + SAREG, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " movw AL,A1\n", }, + +/* convert (u)long long to (u)short (reg->reg, hopefully nothing) */ +{ SCONV, INAREG, + SHLL|SOREG|SNAME, TLL, + SAREG, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + "ZS", }, + +/* convert long long to int (mem->reg) */ +{ SCONV, INAREG, + SOREG|SNAME, TLL, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +/* convert long long to int (reg->reg, hopefully nothing) */ +{ SCONV, INAREG, + SHLL|SOREG|SNAME, TLL, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + "ZS", }, + +/* convert long long (in memory) to floating */ +{ SCONV, INFL, + SOREG|SNAME, TLONGLONG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fildq AL\n", }, + +/* convert long long (in register) to floating */ +{ SCONV, INFL, + SHLL, TLONGLONG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NTEMP|NDREG, RESC1, + " pushl UL\n pushl AL\n" + " fildq (%esp)\n addl $8,%esp\n", }, + +/* convert unsigned long long to floating */ +{ SCONV, INFL, + SCREG, TULONGLONG, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + "ZJ", }, + +/* float to something */ + +#if 0 /* go via int by adding an extra sconv in clocal() */ +/* convert float/double to (u) char. XXX should use NTEMP here */ +{ SCONV, INCH, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NBREG, RESC1, + " subl $4,%esp\n fistpl (%esp)\n popl A1\n", }, + +/* convert float/double to (u) int/short/char. XXX should use NTEMP here */ +{ SCONV, INCH, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NCREG, RESC1, + " subl $4,%esp\n fistpl (%esp)\n popl A1\n", }, +#endif + +/* convert float/double to (u)int. XXX should use NTEMP here */ +{ SCONV, INAREG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SAREG, TWORD, + NAREG, RESC1, + " subl $4,%esp\n fistpl (%esp)\n popl A1\n", }, + +/* convert float/double (in register) to (unsigned) long long */ +/* XXX - unsigned is not handled correct */ +{ SCONV, INLL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHLL, TLONGLONG|TULONGLONG, + NCREG, RESC1, + " subl $8,%esp\n fistpq (%esp)\n" + " popl A1\n popl U1\n", }, + +/* slut sconv */ + +/* + * Subroutine calls. + */ + +{ CALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " call CL\nZC", }, + +{ UCALL, FOREFF, + SCON, TANY, + SAREG, TWORD|TPOINT, + 0, 0, + " call CL\n", }, + +{ CALL, INAREG, + SCON, TANY, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INAREG, + SCON, TANY, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\n", }, + +{ CALL, INBREG, + SCON, TANY, + SBREG, TCHAR|TUCHAR, + NBREG, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INBREG, + SCON, TANY, + SBREG, TCHAR|TUCHAR, + NBREG, RESC1, /* should be 0 */ + " call CL\n", }, + +{ CALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call CL\n", }, + +{ CALL, INDREG, + SCON, TANY, + SDREG, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INDREG, + SCON, TANY, + SDREG, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call *AL\nZC", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call *AL\nZC", }, + +{ CALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INCREG, + SAREG, TANY, + SANY, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INCREG, + SAREG, TANY, + SANY, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INDREG, + SAREG, TANY, + SANY, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INDREG, + SAREG, TANY, + SANY, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +/* struct return */ +{ USTCALL, FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, 0, + "ZP call CL\nZC", }, + +{ USTCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call CL\nZC", }, + +{ USTCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call *AL\nZC", }, + +{ STCALL, FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, 0, + "ZP call CL\nZC", }, + +{ STCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call CL\nZC", }, + +{ STCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call *AL\nZC", }, + +/* + * The next rules handle all binop-style operators. + */ +/* Special treatment for long long */ +{ PLUS, INLL|FOREFF, + SHLL, TLL, + SHLL|SNAME|SOREG, TLL, + 0, RLEFT, + " addl AR,AL\n adcl UR,UL\n", }, + +/* Special treatment for long long XXX - fix commutative check */ +{ PLUS, INLL|FOREFF, + SHLL|SNAME|SOREG, TLL, + SHLL, TLL, + 0, RRIGHT, + " addl AL,AR\n adcl UL,UR\n", }, + +{ PLUS, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " faddl AR\n", }, + +{ PLUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " faddp\n", }, + +{ PLUS, INAREG, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SONE, TANY, + 0, RLEFT, + " incl AL\n", }, + +{ PLUS, INAREG, + SAREG, TWORD|TPOINT, + SCON, TANY, + NAREG|NASL, RESC1, + " leal CR(AL),A1\n", }, + +{ PLUS, INCH, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SONE, TANY, + 0, RLEFT, + " incb AL\n", }, + +{ PLUS, INAREG, + SAREG, TWORD, + SAREG, TWORD, + NAREG|NASL|NASR, RESC1, + " leal (AL,AR),A1\n", }, + + +/* address as register offset, negative */ +{ MINUS, INAREG, + SAREG, TWORD|TPOINT, + SPCON, TANY, + NAREG|NASL, RESC1, + " leal -CR(AL),A1\n", }, + +{ MINUS, INLL|FOREFF, + SHLL, TLL, + SHLL|SNAME|SOREG, TLL, + 0, RLEFT, + " subl AR,AL\n sbbl UR,UL\n", }, + +{ MINUS, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fsubl AR\n", }, + +{ MINUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fsubZAp\n", }, + +/* Simple r/m->reg ops */ +{ OPSIMP, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG, TWORD|TPOINT, + 0, RLEFT, + " Ol AR,AL\n", }, + +{ OPSIMP, INAREG|FOREFF, + SHINT, TSHORT|TUSHORT, + SHINT|SNAME|SOREG, TSHORT|TUSHORT, + 0, RLEFT, + " Ow AR,AL\n", }, + +{ OPSIMP, INCH|FOREFF, + SHCH, TCHAR|TUCHAR, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + 0, RLEFT, + " Ob AR,AL\n", }, + +{ OPSIMP, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SCON, TWORD|TPOINT, + 0, RLEFT, + " Ol AR,AL\n", }, + +{ OPSIMP, INAREG|FOREFF, + SHINT|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RLEFT, + " Ow AR,AL\n", }, + +{ OPSIMP, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, RLEFT, + " Ob AR,AL\n", }, + +{ OPSIMP, INLL|FOREFF, + SHLL, TLL, + SHLL|SNAME|SOREG, TLL, + 0, RLEFT, + " Ol AR,AL\n Ol UR,UL\n", }, + + +/* + * The next rules handle all shift operators. + */ +/* (u)longlong left shift is emulated */ +{ LS, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SAREG|SNAME|SOREG|SCON, TINT, /* will be int */ + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sall AR,AL\n", }, + +{ LS, INAREG|FOREFF, + SAREG, TWORD, + SCON, TANY, + 0, RLEFT, + " sall AR,AL\n", }, + +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shlw AR,AL\n", }, + +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RLEFT, + " shlw AR,AL\n", }, + +{ LS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " salb AR,AL\n", }, + +{ LS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, RLEFT, + " salb AR,AL\n", }, + +/* (u)longlong right shift is emulated */ +{ RS, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SAREG|SNAME|SOREG|SCON, TINT, /* will be int */ + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSWORD, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSWORD, + SCON, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RLEFT, + " sarl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUWORD, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUWORD, + SCON, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RLEFT, + " shrl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SCON, TANY, + 0, RLEFT, + " sarw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SCON, TANY, + 0, RLEFT, + " shrw AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarb AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SCON, TANY, + 0, RLEFT, + " sarb AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrb AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SCON, TANY, + 0, RLEFT, + " shrb AR,AL\n", }, + +/* + * The next rules takes care of assignments. "=". + */ +{ ASSIGN, FOREFF, + SHLL|SNAME|SOREG, TLL, + SCON, TANY, + 0, 0, + " movl AR,AL\n movl UR,UL\n", }, + +{ ASSIGN, FOREFF|INLL, + SHLL, TLL, + SCON, TANY, + 0, RDEST, + " movl AR,AL\n movl UR,UL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SCON, TANY, + 0, 0, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SCON, TANY, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, 0, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RDEST, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, 0, + " movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INCH, + SHCH, TCHAR|TUCHAR, + SCON, TANY, + 0, RDEST, + " movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INLL, + SHLL|SNAME|SOREG, TLL, + SHLL, TLL, + 0, RDEST, + " movl AR,AL\n movl UR,UL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG, TWORD|TPOINT, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RDEST, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF|INCH, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SHCH, TCHAR|TUCHAR|TWORD, + 0, RDEST, + " movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SFLD, TANY, + SAREG, TANY, + NAREG, RDEST, + "ZE", }, + +{ ASSIGN, FOREFF, + SFLD, TANY, + SAREG|SNAME|SOREG|SCON, TANY, + NAREG, 0, + "ZE", }, + +{ ASSIGN, INDREG|FOREFF, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + "", }, /* This will always be in the correct register */ + +/* order of table entries is very important here! */ +{ ASSIGN, INFL, + SNAME|SOREG, TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fstt AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstpt AL\n", }, + +{ ASSIGN, INFL, + SNAME|SOREG, TDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fstl AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstpl AL\n", }, + +{ ASSIGN, INFL, + SNAME|SOREG, TFLOAT, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fsts AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TFLOAT, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstps AL\n", }, +/* end very important order */ + +{ ASSIGN, INFL|FOREFF, + SHFL, TLDOUBLE, + SHFL|SOREG|SNAME, TLDOUBLE, + 0, RDEST, + " fldt AR\n", }, + +{ ASSIGN, INFL|FOREFF, + SHFL, TDOUBLE, + SHFL|SOREG|SNAME, TDOUBLE, + 0, RDEST, + " fldl AR\n", }, + +{ ASSIGN, INFL|FOREFF, + SHFL, TFLOAT, + SHFL|SOREG|SNAME, TFLOAT, + 0, RDEST, + " flds AR\n", }, + +/* Do not generate memcpy if return from funcall */ +#if 0 +{ STASG, INAREG|FOREFF, + SOREG|SNAME|SAREG, TPTRTO|TSTRUCT, + SFUNCALL, TPTRTO|TSTRUCT, + 0, RRIGHT, + "", }, +#endif + +{ STASG, INAREG|FOREFF, + SOREG|SNAME, TANY, + SAREG|SOREG|SNAME, TPTRTO|TANY, + NSPECIAL, RRIGHT, + "ZQ", }, + +/* + * DIV/MOD/MUL + */ +/* long long div is emulated */ +{ DIV, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SCREG|SNAME|SOREG|SCON, TLL, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ DIV, INAREG, + SAREG, TSWORD, + SAREG|SNAME|SOREG, TWORD, + NSPECIAL, RDEST, + " cltd\n idivl AR\n", }, + +{ DIV, INAREG, + SAREG, TUWORD|TPOINT, + SAREG|SNAME|SOREG, TUWORD|TPOINT, + NSPECIAL, RDEST, + " xorl %edx,%edx\n divl AR\n", }, + +{ DIV, INAREG, + SAREG, TUSHORT, + SAREG|SNAME|SOREG, TUSHORT, + NSPECIAL, RDEST, + " xorl %edx,%edx\n divw AR\n", }, + +{ DIV, INCH, + SHCH, TUCHAR, + SHCH|SNAME|SOREG, TUCHAR, + NSPECIAL, RDEST, + " xorb %ah,%ah\n divb AR\n", }, + +{ DIV, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fdivl AR\n", }, + +{ DIV, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fdivZAp\n", }, + +/* (u)longlong mod is emulated */ +{ MOD, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SCREG|SNAME|SOREG|SCON, TLL, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ MOD, INAREG, + SAREG, TSWORD, + SAREG|SNAME|SOREG, TSWORD, + NAREG|NSPECIAL, RESC1, + " cltd\n idivl AR\n", }, + +{ MOD, INAREG, + SAREG, TUWORD|TPOINT, + SAREG|SNAME|SOREG, TUWORD|TPOINT, + NAREG|NSPECIAL, RESC1, + " xorl %edx,%edx\n divl AR\n", }, + +{ MOD, INAREG, + SAREG, TUSHORT, + SAREG|SNAME|SOREG, TUSHORT, + NAREG|NSPECIAL, RESC1, + " xorl %edx,%edx\n divw AR\n", }, + +{ MOD, INCH, + SHCH, TUCHAR, + SHCH|SNAME|SOREG, TUCHAR, + NBREG|NSPECIAL, RESC1, + " xorb %ah,%ah\n divb AR\n", }, + +/* (u)longlong mul is emulated */ +{ MUL, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SCREG|SNAME|SOREG|SCON, TLL, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ MUL, INAREG, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RLEFT, + " imull AR,AL\n", }, + +{ MUL, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + 0, RLEFT, + " imulw AR,AL\n", }, + +{ MUL, INCH, + SHCH, TCHAR|TUCHAR, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + NSPECIAL, RDEST, + " imulb AR\n", }, + +{ MUL, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fmull AR\n", }, + +{ MUL, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fmulp\n", }, + +/* + * Indirection operators. + */ +{ UMUL, INLL, + SANY, TANY, + SOREG, TLL, + NCREG|NCSL, RESC1, + " movl UL,U1\n movl AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SOREG, TPOINT|TWORD, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +{ UMUL, INCH, + SANY, TANY, + SOREG, TCHAR|TUCHAR, + NBREG|NBSL, RESC1, + " movb AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " movw AL,A1\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TLDOUBLE, + NDREG|NDSL, RESC1, + " fldt AL\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TDOUBLE, + NDREG|NDSL, RESC1, + " fldl AL\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TFLOAT, + NDREG|NDSL, RESC1, + " flds AL\n", }, + +/* + * Logical/branching operators + */ + +/* Comparisions, take care of everything */ +{ OPLOG, FORCC, + SHLL|SOREG|SNAME, TLL, + SHLL, TLL, + 0, 0, + "ZD", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TWORD|TPOINT, + SCON|SAREG, TWORD|TPOINT, + 0, RESCC, + " cmpl AR,AL\n", }, + +{ OPLOG, FORCC, + SCON|SAREG, TWORD|TPOINT, + SAREG|SOREG|SNAME, TWORD|TPOINT, + 0, RESCC, + " cmpl AR,AL\n", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + SCON|SAREG, TANY, + 0, RESCC, + " cmpw AR,AL\n", }, + +{ OPLOG, FORCC, + SBREG|SOREG|SNAME, TCHAR|TUCHAR, + SCON|SBREG, TANY, + 0, RESCC, + " cmpb AR,AL\n", }, + +{ OPLOG, FORCC, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NSPECIAL, 0, + "ZG", }, + +{ OPLOG, FORCC, + SOREG|SNAME, TDOUBLE|TFLOAT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NSPECIAL, 0, + "ZG", }, + +#if 0 +/* Ppro and later only */ +{ OPLOG, FORCC, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RESCC, + "ZA fucomip %st,%st(1)\n", }, +#endif + +{ OPLOG, FORCC, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "diediedie!", }, + +/* AND/OR/ER/NOT */ +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, TWORD, + SCON|SAREG, TWORD, + 0, RLEFT, + " andl AR,AL\n", }, + +{ AND, INCREG|FOREFF, + SCREG, TLL, + SCREG|SOREG|SNAME, TLL, + 0, RLEFT, + " andl AR,AL\n andl UR,UL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TWORD, + SAREG|SOREG|SNAME, TWORD, + 0, RLEFT, + " andl AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + SCON|SAREG, TSHORT|TUSHORT, + 0, RLEFT, + " andw AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TSHORT|TUSHORT, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + 0, RLEFT, + " andw AR,AL\n", }, + +{ AND, INBREG|FOREFF, + SBREG|SOREG|SNAME, TCHAR|TUCHAR, + SCON|SBREG, TCHAR|TUCHAR, + 0, RLEFT, + " andb AR,AL\n", }, + +{ AND, INBREG|FOREFF, + SBREG, TCHAR|TUCHAR, + SBREG|SOREG|SNAME, TCHAR|TUCHAR, + 0, RLEFT, + " andb AR,AL\n", }, +/* AND/OR/ER/NOT */ + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " jmp LL\n", }, + +#ifdef GCC_COMPAT +{ GOTO, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, RNOP, + " jmp *AL\n", }, +#endif + +/* + * Convert LTYPE to reg. + */ +{ OPLTYPE, INLL, + SANY, TANY, + SCREG|SCON|SOREG|SNAME, TLL, + NCREG, RESC1, + " movl UL,U1\n movl AL,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SCON|SOREG|SNAME, TWORD|TPOINT, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SBREG|SOREG|SNAME|SCON, TCHAR|TUCHAR, + NBREG, RESC1, + " movb AL,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SOREG|SNAME|SCON, TSHORT|TUSHORT, + NAREG, RESC1, + " movw AL,A1\n", }, + +{ OPLTYPE, INDREG, + SANY, TLDOUBLE, + SOREG|SNAME, TLDOUBLE, + NDREG, RESC1, + " fldt AL\n", }, + +{ OPLTYPE, INDREG, + SANY, TDOUBLE, + SOREG|SNAME, TDOUBLE, + NDREG, RESC1, + " fldl AL\n", }, + +{ OPLTYPE, INDREG, + SANY, TFLOAT, + SOREG|SNAME, TFLOAT, + NDREG, RESC1, + " flds AL\n", }, + +/* Only used in ?: constructs. The stack already contains correct value */ +{ OPLTYPE, INDREG, + SANY, TFLOAT|TDOUBLE|TLDOUBLE, + SDREG, TFLOAT|TDOUBLE|TLDOUBLE, + NDREG, RESC1, + "", }, + +/* + * Negate a word. + */ + +{ UMINUS, INCREG|FOREFF, + SCREG, TLL, + SCREG, TLL, + 0, RLEFT, + " negl AL\n adcl $0,UL\n negl UL\n", }, + +{ UMINUS, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + " negl AL\n", }, + +{ UMINUS, INAREG|FOREFF, + SAREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RLEFT, + " negw AL\n", }, + +{ UMINUS, INBREG|FOREFF, + SBREG, TCHAR|TUCHAR, + SBREG, TCHAR|TUCHAR, + 0, RLEFT, + " negb AL\n", }, + +{ UMINUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fchs\n", }, + +{ COMPL, INCREG, + SCREG, TLL, + SANY, TANY, + 0, RLEFT, + " notl AL\n notl UL\n", }, + +{ COMPL, INAREG, + SAREG, TWORD, + SANY, TANY, + 0, RLEFT, + " notl AL\n", }, + +{ COMPL, INAREG, + SAREG, TSHORT|TUSHORT, + SANY, TANY, + 0, RLEFT, + " notw AL\n", }, + +{ COMPL, INBREG, + SBREG, TCHAR|TUCHAR, + SANY, TANY, + 0, RLEFT, + " notb AL\n", }, + +/* + * Arguments to functions. + */ +{ FUNARG, FOREFF, + SCON|SCREG|SNAME|SOREG, TLL, + SANY, TLL, + 0, RNULL, + " pushl UL\n pushl AL\n", }, + +{ FUNARG, FOREFF, + SCON|SAREG|SNAME|SOREG, TWORD|TPOINT, + SANY, TWORD|TPOINT, + 0, RNULL, + " pushl AL\n", }, + +{ FUNARG, FOREFF, + SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + 0, RNULL, + " pushl AL\n", }, + +{ FUNARG, FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SANY, TSHORT, + NAREG, 0, + " movswl AL,ZN\n pushl ZN\n", }, + +{ FUNARG, FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SANY, TUSHORT, + NAREG, 0, + " movzwl AL,ZN\n pushl ZN\n", }, + +{ FUNARG, FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SANY, TCHAR, + NAREG, 0, + " movsbl AL,A1\n pushl A1\n", }, + +{ FUNARG, FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SANY, TUCHAR, + NAREG, 0, + " movzbl AL,A1\n pushl A1\n", }, + +{ FUNARG, FOREFF, + SNAME|SOREG, TDOUBLE, + SANY, TDOUBLE, + 0, 0, + " pushl UL\n pushl AL\n", }, + +{ FUNARG, FOREFF, + SDREG, TDOUBLE, + SANY, TDOUBLE, + 0, 0, + " subl $8,%esp\n fstpl (%esp)\n", }, + +{ FUNARG, FOREFF, + SNAME|SOREG, TFLOAT, + SANY, TFLOAT, + 0, 0, + " pushl AL\n", }, + +{ FUNARG, FOREFF, + SDREG, TFLOAT, + SANY, TFLOAT, + 0, 0, + " subl $4,%esp\n fstps (%esp)\n", }, + +{ FUNARG, FOREFF, + SDREG, TLDOUBLE, + SANY, TLDOUBLE, + 0, 0, + " subl $12,%esp\n fstpt (%esp)\n", }, + +{ STARG, FOREFF, + SAREG|SOREG|SNAME|SCON, TANY, + SANY, TSTRUCT, + NSPECIAL|NAREG, 0, + "ZF", }, + +#endif + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ STASG, DF(STASG), }, + +{ FLD, DF(FLD), }, + +{ OPLEAF, DF(NAME), }, + +{ INIT, DF(INIT), }, + +{ OPUNARY, DF(UMINUS), }, + +{ OPANY, DF(BITYPE), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/usr.bin/pcc/arch/pdp10/code.c b/usr.bin/pcc/arch/pdp10/code.c new file mode 100644 index 00000000000..6121bdc6219 --- /dev/null +++ b/usr.bin/pcc/arch/pdp10/code.c @@ -0,0 +1,167 @@ +/* $Id: code.c,v 1.1 2007/09/15 18:12:29 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass1.h" + +/* + * cause the alignment to become a multiple of n + * Nothing to do on PDP10. + */ +void +defalign(int n) +{ +} + +/* + * code for the end of a function + */ +void +efcode() +{ +} + +/* + * code for the beginning of a function; a is an array of + * indices in stab for the arguments; n is the number + */ +void +bfcode(struct symtab **a, int n) +{ + send_passt(IP_LOCCTR, PROG); + defnam(cftnsp); +} + + +/* + * 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 ) +{ +} + +/* + * 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(" .block %d\n", n); + 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) +{ + int i; + char *s; + + /* simple switch code */ + for (i = 1; i <= n; ++i) { + /* already in 1 */ + s = (isinlining ? permalloc(40) : tmpalloc(40)); + if (p[i]->sval >= 0 && p[i]->sval <= 0777777) + sprintf(s, " cain 1,0%llo", p[i]->sval); + else if (p[i]->sval < 0) + sprintf(s, " camn 1,[ .long -0%llo ]", -p[i]->sval); + else + sprintf(s, " camn 1,[ .long 0%llo ]", p[i]->sval); + send_passt(IP_ASM, s); + branch(p[i]->slab); + } + if (p[0]->slab > 0) { + send_passt(IP_DEFLAB, getlab()); /* XXX - fool optimizer */ + branch(p[0]->slab); + } +} diff --git a/usr.bin/pcc/arch/pdp10/local.c b/usr.bin/pcc/arch/pdp10/local.c new file mode 100644 index 00000000000..8d18720aa1e --- /dev/null +++ b/usr.bin/pcc/arch/pdp10/local.c @@ -0,0 +1,782 @@ +/* $Id: local.c,v 1.1 2007/09/15 18:12:29 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass1.h" + +/* this file contains code which is dependent on the target machine */ + +static int pointp(TWORD t); +static struct symtab *newfun(char *name, TWORD type); + +#define PTRNORMAL 1 +#define PTRCHAR 2 +#define PTRSHORT 3 +static int ptype(TWORD t); + +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, *oop; + register int o; + register int m, ml; + int siz; + + 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 */ + if (q->stype == CHAR || q->stype == UCHAR || + q->stype == SHORT || q->stype == USHORT) + r = block(REG, NIL, NIL, PTR+q->stype, 0, 0); + else + 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; + if ((q->sflags & SLABEL) == 0) + cerror("STATIC"); + break; + + case REGISTER: + p->n_op = REG; + p->n_lval = 0; + p->n_rval = q->soffset; + break; + + } + break; + + case PCONV: + l = p->n_left; + /* + * Handle frame pointer directly without conversion, + * for efficiency. + */ + if (l->n_op == REG && l->n_rval == 0) { +rmpc: l->n_type = p->n_type; + l->n_df = p->n_df; + l->n_sue = p->n_sue; + nfree(p); + return l; + } + /* Convert ICON with name to new type */ + if (l->n_op == ICON && l->n_sp != NULL && + l->n_type == INCREF(STRTY) && + (p->n_type == INCREF(CHAR) || + p->n_type == INCREF(UCHAR) || + p->n_type == INCREF(SHORT) || + p->n_type == INCREF(USHORT))) { + l->n_lval *= (BTYPE(p->n_type) == CHAR || + BTYPE(p->n_type) == UCHAR ? 4 : 2); + goto rmpc; + } + /* Convert only address constants, never convert other */ + if (l->n_op == ICON) { + if (l->n_sp == NULL) + goto rmpc; + if (p->n_type == INCREF(CHAR) || + p->n_type == INCREF(UCHAR) || + p->n_type == INCREF(VOID)) + l->n_lval = (l->n_lval & 07777777777) | + 0700000000000LL; + else if (p->n_type == INCREF(SHORT) || + p->n_type == INCREF(USHORT)) + l->n_lval = (l->n_lval & 07777777777) | + 0750000000000LL; + else + l->n_lval = l->n_lval & 07777777777; + goto rmpc; + } + + /* Remove more conversions of identical pointers */ + /* Be careful! optim() may do bad things */ + if (ISPTR(DECREF(p->n_type))) { + if (ISPTR(DECREF(l->n_type))) { + if ((coptype(l->n_op) == UTYPE || + coptype(l->n_op) == BITYPE) && + (l->n_left->n_op == REG)) + l->n_left->n_type = p->n_type; + goto rmpc; + } + } + + /* Change PCONV from int to double pointer to right shift */ + if (ISPTR(p->n_type) && ISPTR(DECREF(p->n_type)) && + (l->n_type == INT || l->n_type == UNSIGNED)) { + p->n_op = RS; + p->n_right = bcon(2); + break; + } + + /* Check for cast integral -> pointer */ + if (BTYPE(l->n_type) == l->n_type) + break; + + /* Remove conversions to identical pointers */ + switch (ptype(p->n_type)) { + case PTRNORMAL: + if (ptype(l->n_type) == PTRNORMAL) + goto rmpc; + break; + + case PTRSHORT: + if (ptype(l->n_type) == PTRSHORT) + goto rmpc; + break; + + case PTRCHAR: + if (ptype(l->n_type) == PTRCHAR) + goto rmpc; + break; + } + + break; + + case SCONV: + l = p->n_left; + + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + btdim[p->n_type] == btdim[l->n_type]) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE) { + nfree(p); + return l; + } + } + /* cast to (void) XXX should be removed in MI code */ + if (p->n_type == VOID) { + nfree(p); + return l; + } + m = p->n_type; + ml = l->n_type; + if (m == ml) { + nfree(p); + return l; + } + o = l->n_op; + if (ml == FLOAT || ml == DOUBLE) { + if (o != FCON) + break; + ml = ISUNSIGNED(m) ? UNSIGNED : INT; /* LONG? */ + r = block(ICON, (NODE *)NULL, (NODE *)NULL, ml, 0, 0); + r->n_lval = ml == INT ? + (int) p->n_left->n_dcon : + (unsigned) p->n_left->n_dcon; + r->n_sp = NULL; + nfree(p->n_left); + p->n_left = r; + o = ICON; + if (m == ml) { + r = p->n_left; + nfree(p); + return r; + } + } + if (o == ICON) { + CONSZ val = l->n_lval; + + switch (m) { + case CHAR: + l->n_lval = val & 0777; + if (val & 0400) + l->n_lval |= ~((CONSZ)0777); + break; + case UCHAR: + l->n_lval = val & 0777; + break; + case USHORT: + l->n_lval = val & 0777777; + break; + case SHORT: + l->n_lval = val & 0777777; + if (val & 0400000) + l->n_lval |= ~((CONSZ)0777777); + break; + case UNSIGNED: + l->n_lval = val & 0777777777777LL; + break; + case ENUMTY: + case MOETY: + case INT: + l->n_lval = val & 0777777777777LL; + if (val & 0400000000000LL) + l->n_lval |= ~(0777777777777LL); + break; + case LONGLONG: /* XXX */ + case ULONGLONG: + l->n_lval = val; + break; + case VOID: + break; + case DOUBLE: + case FLOAT: + l->n_op = FCON; + l->n_dcon = 0; + break; + default: + cerror("unknown type %d", m); + } + l->n_type = m; + l->n_sue = MKSUE(m); + nfree(p); + return l; + } + 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 RS: + case RSEQ: + /* convert >> to << with negative shift count */ + /* Beware! constant shifts will be converted back in optim() */ + + if (p->n_right->n_op != UMINUS) { + p->n_right = buildtree(UMINUS, p->n_right, NIL); + } else { + r = p->n_right; + p->n_right = p->n_right->n_left; + nfree(r); + } + if (p->n_op == RS) + p->n_op = LS; + else + p->n_op = LSEQ; + break; + + case UMUL: /* Convert structure assignment to memcpy() */ + if (p->n_left->n_op == PLUS && + p->n_left->n_left->n_op == PCONV && + p->n_left->n_right->n_op == ICON && + (p->n_type == CHAR || p->n_type == UCHAR || + p->n_type == SHORT || p->n_type == USHORT)) { + /* Can remove the left SCONV */ + l = p->n_left->n_left; + p->n_left->n_left = l->n_left; + nfree(l); + break; + + } + if (p->n_left->n_op != STASG) + break; + oop = p; + p = p->n_left; + siz = p->n_sue->suesize/SZCHAR; + l = p->n_left; + r = p->n_right; + if (l->n_type == STRTY || l->n_type == UNIONTY) { + if (l->n_op == UMUL) { + p->n_left = l->n_left; + nfree(l); + l = p->n_left; + } else { + l = block(ADDROF, l, NIL, INCREF(l->n_type), + 0, MKSUE(INT)); + } + } + if ((l->n_type != (STRTY+PTR) && l->n_type != (UNIONTY+PTR)) || + (r->n_type != (STRTY+PTR) && r->n_type != (UNIONTY+PTR))) + cerror("bad stasg, l = %o, r = %o", l->n_type, r->n_type); + q = newfun("__structcpy", p->n_type); + + /* structure pointer block */ + l = block(CM, l, r, INT, 0, MKSUE(INT)); + /* Size block */ + r = block(CM, l, bcon(siz), INT, 0, MKSUE(INT)); + + l = block(ICON, NIL, NIL, q->stype, 0, MKSUE(INT)); + l->n_sp = q; + p->n_left = l; + p->n_right = r; + p->n_op = CALL; + oop->n_left = p; + return oop; + + } + + return(p); +} + +void +myp2tree(NODE *p) +{ + NODE *r; + + switch (p->n_op) { + case ULT: /* exor sign bit to avoid unsigned comparitions */ + case ULE: + case UGT: + case UGE: + if (ISLONGLONG(p->n_left->n_type)) { + r = block(ICON, NIL, NIL, LONGLONG, 0, MKSUE(LONGLONG)); + r->n_lval = 0x8000000000000000ULL; /* XXX */ + } else { + r = block(ICON, NIL, NIL, INT, 0, MKSUE(INT)); + r->n_lval = 0400000000000LL; + } + r->n_sp = NULL; + p->n_left = buildtree(ER, p->n_left, r); + if (ISUNSIGNED(p->n_left->n_type)) + p->n_left->n_type = DEUNSIGN(p->n_left->n_type); + + if (ISLONGLONG(p->n_right->n_type)) { + r = block(ICON, NIL, NIL, LONGLONG, 0, MKSUE(LONGLONG)); + r->n_lval = 0x8000000000000000ULL; /* XXX */ + } else { + r = block(ICON, NIL, NIL, INT, 0, MKSUE(INT)); + r->n_lval = 0400000000000LL; + } + r->n_sp = NULL; + p->n_right = buildtree(ER, p->n_right, r); + if (ISUNSIGNED(p->n_right->n_type)) + p->n_right->n_type = DEUNSIGN(p->n_right->n_type); + + p->n_op -= (ULT-LT); + break; + } +} + + +struct symtab * +newfun(char *name, TWORD type) +{ + struct symtab *sp; + + sp = lookup(name, 0); + if (sp->stype == VOID) { + sp->stype = INCREF(type | FTN); + sp->sclass = EXTERN; + sp->soffset = 0; + } +#ifdef notdef + else if (!ISFTN(DECREF(sp->stype))) + uerror("reserved name '%s' used illegally", name); +#endif + return sp; +} + +/*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 + * Everything is trusted to be in register here. + */ +int +cisreg(TWORD t) +{ + return(1); +} + +int +ptype(TWORD t) +{ + int tt = BTYPE(t); + int e, rv; + + if (!ISPTR(t)) + cerror("not a pointer"); + + e = t & ~BTMASK; + while (e) { + rv = e; + if (DECREF(e) == 0) + break; + e = DECREF(e); + } + if (ISFTN(rv)) + return PTRNORMAL; + + switch (tt) { + case INT: + case LONG: + case LONGLONG: + case FLOAT: + case DOUBLE: + case STRTY: + case UNIONTY: + case ENUMTY: + case UNSIGNED: + case ULONG: + case ULONGLONG: + return PTRNORMAL; + case VOID: + case CHAR: + case UCHAR: + if (DECREF(t) == tt || ISARY(rv)) + return PTRCHAR; + return PTRNORMAL; + case SHORT: + case USHORT: + if (DECREF(t) == tt || ISARY(rv)) + return PTRSHORT; + return PTRNORMAL; + default: + break; + } + cerror("unknown type"); + return PTRNORMAL; /* XXX */ +} + +/* + * Help routine to the one below; return true if it's not a word pointer. + */ +static int +pointp(TWORD t) +{ + int rv = 0; + + if (ISPTR(t) && ((t & TMASK1) == 0)) + return 1; + + t &= ~BTMASK; + while (t) { + rv = ISARY(t); + t = DECREF(t); + } + return rv; +} + +/* + * 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/SZINT; /* Default */ + if (ISPTR(DECREF(t))) + return p; /* Pointer/pointer reference */ + switch (BTMASK & t) { + case INT: + case UNSIGNED: + case LONG: + case ULONG: + case STRTY: + case UNIONTY: + case ENUMTY: + case LONGLONG: + case ULONGLONG: + case FLOAT: + case DOUBLE: + break; + + case SHORT: + case USHORT: + if (pointp(t)) + p->n_lval = off/SZSHORT; + break; + + case VOID: /* void pointers */ + case CHAR: + case UCHAR: + if (pointp(t)) + p->n_lval = off/SZCHAR; + break; + + default: + cerror("offcon, off %llo size %d type %x", off, sue->suesize, t); + } + if (xdebug) + printf("offcon return 0%llo\n", p->n_lval); + 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. + * Be aware that a pointer conversion may be needed when saving + * to node t! + */ +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; + /* Cast sp to destination type (may be redundant) */ + sp = buildtree(CAST, + block(NAME, NIL, NIL, t->n_type, t->n_df, t->n_sue), sp); + nfree(sp->n_left); + nfree(sp); + sp = sp->n_right; + 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)); +} + +static int inwd; /* current bit offsed in word */ +static CONSZ word; /* word being built from fields */ + +/* + * Generate initialization code for assigning a constant c + * to a field of width sz + * we assume that the proper alignment has been obtained + * inoff is updated to have the proper final value + * we also assume sz < SZINT + */ +void +incode(NODE *p, int sz) +{ + char *s; + + inoff += sz; + if ((sz + inwd) > SZINT) + cerror("incode: field > int"); + + word |= ((p->n_lval & ((1 << sz) - 1)) << (36 - inwd - sz)); + + inwd += sz; + if (inoff % SZINT == 0) { + s = isinlining ? permalloc(30) : tmpalloc(30); + sprintf(s, " .long 0%llo", word); + send_passt(IP_ASM, s); + word = inwd = 0; + } + tfree(p); +} + +/* output code to initialize space of size sz to the value d */ +/* the proper alignment has been obtained */ +/* inoff is updated to have the proper final value */ +/* on the target machine, write it out in octal! */ +void +fincode(NODE *p, int sz) +{ + double d = p->n_dcon; + + if(!nerrors) + printf(" %s 0%c%.20e\n", + sz == SZDOUBLE ? ".double" : ".float", + sz == SZDOUBLE ? 'd' : 'f', d); + inoff += sz; +} + +void +cinit(NODE *p, int sz) +{ + NODE *l; + + /* + * as a favor (?) to people who want to write + * int i = 9600/134.5; + * we will, under the proper circumstances, do + * a coercion here. + */ + switch (p->n_type) { + case INT: + case UNSIGNED: + l = p->n_left; + if (l->n_op != SCONV || l->n_left->n_op != FCON) + break; + nfree(l); + l = l->n_left; + l->n_lval = (long)(l->n_dcon); + l->n_sp = NULL; + l->n_op = ICON; + l->n_type = INT; + p->n_left = l; + break; + } + /* arrange for the initialization of p into a space of size sz */ + /* the proper alignment has been opbtained */ + /* inoff is updated to have the proper final value */ + ecode( p ); + inoff += sz; +} + +/* + * define n bits of zeros in a vfd + */ +void +vfdzero(int n) +{ + char *s; + + inoff += n; + inwd += n; + if (inoff%ALINT ==0) { + s = isinlining ? permalloc(30) : tmpalloc(30); + sprintf(s, " .long 0%llo", word); + send_passt(IP_ASM, s); + word = inwd = 0; + } +} + +/* 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 + */ +int +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 stroage class for an uninitialized declaration + */ +int +noinit() +{ + return(EXTERN); +} + +/* 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+(SZINT-1))/SZINT; + printf(" .comm %s,0%o\n", exname(q->sname), off); +} + +/* 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+(SZINT-1))/SZINT; + if (q->slevel == 0) + printf(" .lcomm %s,0%o\n", exname(q->sname), off); + else + printf(" .lcomm " LABFMT ",0%o\n", q->soffset, off); +} + +/* + * Debugger code - ignore. + */ +void +prcstab(int a) +{ +} + +void +pfstab(char *a) +{ +} diff --git a/usr.bin/pcc/arch/pdp10/local2.c b/usr.bin/pcc/arch/pdp10/local2.c new file mode 100644 index 00000000000..8591a44f4fc --- /dev/null +++ b/usr.bin/pcc/arch/pdp10/local2.c @@ -0,0 +1,1237 @@ +/* $Id: local2.c,v 1.1 2007/09/15 18:12:29 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass2.h" +# include <ctype.h> + +# define putstr(s) fputs((s), stdout) + +void acon(FILE *, NODE *p); +int argsize(NODE *p); +void genargs(NODE *p); + +static int ftlab1, ftlab2; +static int offlab; +int offarg; + +void +lineid(int l, char *fn) +{ + /* identify line l and file fn */ + printf("# line %d, file %s\n", l, fn); +} + +void +defname(char *name, int visib) +{ + if (visib) + printf(" .globl %s\n", name); + printf("%s:\n", name); +} + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +static int isoptim; + +void +prologue(int regs, int autos) +{ + int i, addto; + + offlab = getlab(); + if (regs < 0 || autos < 0) { + /* + * non-optimized code, jump to epilogue for code generation. + */ + ftlab1 = getlab(); + ftlab2 = getlab(); + printf(" jrst L%d\n", ftlab1); + printf("L%d:\n", ftlab2); + } else { + /* + * We here know what register to save and how much to + * add to the stack. + */ + autos = autos + (SZINT-1); + addto = (autos - AUTOINIT)/SZINT + (MAXRVAR-regs); + if (addto || gflag) { + printf(" push %s,%s\n",rnames[017], rnames[016]); + printf(" move %s,%s\n", rnames[016],rnames[017]); + for (i = regs; i < MAXRVAR; i++) { + int db = ((i+1) < MAXRVAR); + printf(" %smovem %s,0%o(%s)\n", + db ? "d" : "", + rnames[i+1], i+1-regs, rnames[016]); + if (db) + i++; + } + if (addto) + printf(" addi %s,0%o\n", rnames[017], addto); + } else + offarg = 1; + isoptim = 1; + } +} + +/* + * End of block. + */ +void +eoftn(int regs, int autos, int retlab) +{ + register OFFSZ spoff; /* offset from stack pointer */ + int i; + + spoff = autos + (SZINT-1); + if (spoff >= AUTOINIT) + spoff -= AUTOINIT; + spoff /= SZINT; + /* return from function code */ + printf("L%d:\n", retlab); + if (gflag || isoptim == 0 || autos != AUTOINIT || regs != MAXRVAR) { + for (i = regs; i < MAXRVAR; i++) { + int db = ((i+1) < MAXRVAR); + printf(" %smove %s,0%o(%s)\n", db ? "d" : "", + rnames[i+1], i+1-regs, rnames[016]); + if (db) + i++; + } + printf(" move %s,%s\n", rnames[017], rnames[016]); + printf(" pop %s,%s\n", rnames[017], rnames[016]); + } + printf(" popj %s,\n", rnames[017]); + + /* Prolog code */ + if (isoptim == 0) { + printf("L%d:\n", ftlab1); + printf(" push %s,%s\n", rnames[017], rnames[016]); + printf(" move %s,%s\n", rnames[016], rnames[017]); + for (i = regs; i < MAXRVAR; i++) { + int db = ((i+1) < MAXRVAR); + printf(" %smovem %s,0%o(%s)\n", db ? "d" : "", + rnames[i+1], i+1-regs, rnames[016]); + spoff++; + if (db) + i++, spoff++; + } + if (spoff) + printf(" addi %s,0%llo\n", rnames[017], spoff); + printf(" jrst L%d\n", ftlab2); + } + printf(" .set " LABFMT ",0%o\n", offlab, MAXRVAR-regs); + offarg = isoptim = 0; +} + +static char *loctbl[] = { "text", "data", "data", "text", "text", "stab" }; + +void +setlocc(int locctr) +{ + static int lastloc; + + if (locctr == lastloc) + return; + + lastloc = locctr; + printf(" .%s\n", loctbl[locctr]); +} + +/* + * add/sub/... + * + * Param given: + * R - Register + * M - Memory + * C - Constant + */ +void +hopcode(int f, int o) +{ + cerror("hopcode: f %d %d", f, o); +} + +char * +rnames[] = { /* keyed to register number tokens */ + "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7", + "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", +}; + +int rstatus[] = { + 0, STAREG, STAREG, STAREG, STAREG, STAREG, STAREG, STAREG, + SAREG, SAREG, SAREG, SAREG, SAREG, SAREG, 0, 0, +}; + +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)) + cerror("tlen type %d not pointer"); + return SZPOINT/SZCHAR; + } +} + +static char * +binskip[] = { + "e", /* jumpe */ + "n", /* jumpn */ + "le", /* jumple */ + "l", /* jumpl */ + "ge", /* jumpge */ + "g", /* jumpg */ +}; + +/* + * Extract the higher 36 bits from a longlong. + */ +static CONSZ +gethval(CONSZ lval) +{ + CONSZ hval = (lval >> 35) & 03777777777LL; + + if ((hval & 03000000000LL) == 03000000000LL) { + hval |= 0777000000000LL; + } else if ((hval & 03000000000LL) == 02000000000LL) { + hval &= 01777777777LL; + hval |= 0400000000000LL; + } + return hval; +} + +/* + * Do a binary comparision, and jump accordingly. + */ +static void +twocomp(NODE *p) +{ + int o = p->n_op; + extern int negrel[]; + int isscon = 0, iscon = p->n_right->n_op == ICON; + + if (o < EQ || o > GT) + cerror("bad binary conditional branch: %s", opst[o]); + + if (iscon && p->n_right->n_name[0] != 0) { + printf(" cam%s ", binskip[negrel[o-EQ]-EQ]); + adrput(stdout, getlr(p, 'L')); + putchar(','); + printf("[ .long "); + adrput(stdout, getlr(p, 'R')); + putchar(']'); + printf("\n jrst L%d\n", p->n_label); + return; + } + if (iscon) + isscon = p->n_right->n_lval >= 0 && + p->n_right->n_lval < 01000000; + + printf(" ca%c%s ", iscon && isscon ? 'i' : 'm', + binskip[negrel[o-EQ]-EQ]); + adrput(stdout, getlr(p, 'L')); + putchar(','); + if (iscon && (isscon == 0)) { + printf("[ .long "); + adrput(stdout, getlr(p, 'R')); + putchar(']'); + } else + adrput(stdout, getlr(p, 'R')); + printf("\n jrst L%d\n", p->n_label); +} + +/* + * Compare byte/word pointers. + * XXX - do not work for highest bit set in address + */ +static void +ptrcomp(NODE *p) +{ + printf(" rot "); adrput(stdout, getlr(p, 'L')); printf(",6\n"); + printf(" rot "); adrput(stdout, getlr(p, 'R')); printf(",6\n"); + twocomp(p); +} + +/* + * Do a binary comparision of two long long, and jump accordingly. + * XXX - can optimize for constants. + */ +static void +twollcomp(NODE *p) +{ + int o = p->n_op; + int iscon = p->n_right->n_op == ICON; + int m; + + if (o < EQ || o > GT) + cerror("bad long long conditional branch: %s", opst[o]); + + /* Special strategy for equal/not equal */ + if (o == EQ || o == NE) { + if (o == EQ) + m = getlab(); + printf(" came "); + upput(getlr(p, 'L'), SZLONG); + putchar(','); + if (iscon) + printf("[ .long "); + upput(getlr(p, 'R'), SZLONG); + if (iscon) + putchar(']'); + printf("\n jrst L%d\n", o == EQ ? m : p->n_label); + printf(" cam%c ", o == EQ ? 'n' : 'e'); + adrput(stdout, getlr(p, 'L')); + putchar(','); + if (iscon) + printf("[ .long "); + adrput(stdout, getlr(p, 'R')); + if (iscon) + putchar(']'); + printf("\n jrst L%d\n", p->n_label); + if (o == EQ) + printf("L%d:\n", m); + return; + } + /* First test highword */ + printf(" cam%ce ", o == GT || o == GE ? 'l' : 'g'); + adrput(stdout, getlr(p, 'L')); + putchar(','); + if (iscon) + printf("[ .long "); + adrput(stdout, getlr(p, 'R')); + if (iscon) + putchar(']'); + printf("\n jrst L%d\n", p->n_label); + + /* Test equality */ + printf(" came "); + adrput(stdout, getlr(p, 'L')); + putchar(','); + if (iscon) + printf("[ .long "); + adrput(stdout, getlr(p, 'R')); + if (iscon) + putchar(']'); + printf("\n jrst L%d\n", m = getlab()); + + /* Test lowword. Only works with pdp10 format for longlongs */ + printf(" cam%c%c ", o == GT || o == GE ? 'l' : 'g', + o == LT || o == GT ? 'e' : ' '); + upput(getlr(p, 'L'), SZLONG); + putchar(','); + if (iscon) + printf("[ .long "); + upput(getlr(p, 'R'), SZLONG); + if (iscon) + putchar(']'); + printf("\n jrst L%d\n", p->n_label); + printf("L%d:\n", m); +} + +/* + * Print the correct instruction for constants. + */ +static void +constput(NODE *p) +{ + CONSZ val = p->n_right->n_lval; + int reg = p->n_left->n_rval; + + /* Only numeric constant */ + if (p->n_right->n_name[0] == '\0') { + if (val == 0) { + printf("movei %s,0", rnames[reg]); + } else if ((val & 0777777000000LL) == 0) { + printf("movei %s,0%llo", rnames[reg], val); + } else if ((val & 0777777) == 0) { + printf("hrlzi %s,0%llo", rnames[reg], val >> 18); + } else { + printf("move %s,[ .long 0%llo]", rnames[reg], + szty(p->n_right->n_type) > 1 ? val : + val & 0777777777777LL); + } + /* Can have more tests here, hrloi etc */ + return; + } else { + printf("xmovei %s,%s", rnames[reg], p->n_right->n_name); + if (val) + printf("+" CONFMT, val); + } +} + +/* + * Return true if the constant can be bundled in an instruction (immediate). + */ +static int +oneinstr(NODE *p) +{ + if (p->n_name[0] != '\0') + return 0; + if ((p->n_lval & 0777777000000ULL) != 0) + return 0; + return 1; +} + +/* + * Emit a halfword or byte instruction, from OREG to REG. + * Sign extension must also be done here. + */ +static void +emitshort(NODE *p) +{ + CONSZ off = p->n_lval; + TWORD type = p->n_type; + int reg = p->n_rval; + int issigned = !ISUNSIGNED(type); + int ischar = type == CHAR || type == UCHAR; + int reg1 = getlr(p, '1')->n_rval; + + if (off < 0) { /* argument, use move instead */ + printf(" move "); + } else if (off == 0 && p->n_name[0] == 0) { + printf(" ldb %s,%s\n", rnames[reg1], rnames[reg]); + /* XXX must sign extend here even if not necessary */ + switch (type) { + case CHAR: + printf(" lsh %s,033\n", rnames[reg1]); + printf(" ash %s,-033\n", rnames[reg1]); + break; + case SHORT: + printf(" hrre %s,%s\n", + rnames[reg1], rnames[reg1]); + break; + } + return; + } else if (ischar) { + if (off >= 0700000000000LL && p->n_name[0] != '\0') { + cerror("emitsh"); + /* reg contains index integer */ + if (!istreg(reg)) + cerror("emitshort !istreg"); + printf(" adjbp %s,[ .long 0%llo+%s ]\n", + rnames[reg], off, p->n_name); + printf(" ldb "); + adrput(stdout, getlr(p, '1')); + printf(",%s\n", rnames[reg]); + goto signe; + } + printf(" ldb "); + adrput(stdout, getlr(p, '1')); + if (off) + printf(",[ .long 0%02o11%02o%06o ]\n", + (int)(27-(9*(off&3))), reg, (int)off/4); + else + printf(",%s\n", rnames[reg]); +signe: if (issigned) { + printf(" lsh "); + adrput(stdout, getlr(p, '1')); + printf(",033\n ash "); + adrput(stdout, getlr(p, '1')); + printf(",-033\n"); + } + return; + } else { + printf(" h%cr%c ", off & 1 ? 'r' : 'l', + issigned ? 'e' : 'z'); + } + p->n_lval /= (ischar ? 4 : 2); + adrput(stdout, getlr(p, '1')); + putchar(','); + adrput(stdout, getlr(p, 'L')); + putchar('\n'); +} + +/* + * Store a short from a register. Destination is a OREG. + */ +static void +storeshort(NODE *p) +{ + NODE *l = p->n_left; + CONSZ off = l->n_lval; + int reg = l->n_rval; + int ischar = BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR; + + if (l->n_op == NAME) { + if (ischar) { + printf(" dpb "); + adrput(stdout, getlr(p, 'R')); + printf(",[ .long 0%02o%010o+%s ]\n", + 070+((int)off&3), (int)(off/4), l->n_name); + return; + } + printf(" hr%cm ", off & 1 ? 'r' : 'l'); + l->n_lval /= 2; + adrput(stdout, getlr(p, 'R')); + putchar(','); + adrput(stdout, getlr(p, 'L')); + putchar('\n'); + return; + } + + if (off || reg == FPREG) { /* Can emit halfword instructions */ + if (off < 0) { /* argument, use move instead */ + printf(" movem "); + } else if (ischar) { + printf(" dpb "); + adrput(stdout, getlr(p, '1')); + printf(",[ .long 0%02o11%02o%06o ]\n", + (int)(27-(9*(off&3))), reg, (int)off/4); + return; + } else { + printf(" hr%cm ", off & 1 ? 'r' : 'l'); + } + l->n_lval /= 2; + adrput(stdout, getlr(p, 'R')); + putchar(','); + adrput(stdout, getlr(p, 'L')); + } else { + printf(" dpb "); + adrput(stdout, getlr(p, 'R')); + putchar(','); + l = getlr(p, 'L'); + l->n_op = REG; + adrput(stdout, l); + l->n_op = OREG; + } + putchar('\n'); +} + +/* + * Multiply a register with a constant. + */ +static void +imuli(NODE *p) +{ + NODE *r = p->n_right; + + if (r->n_lval >= 0 && r->n_lval <= 0777777) { + printf(" imuli "); + adrput(stdout, getlr(p, 'L')); + printf(",0%llo\n", r->n_lval); + } else { + printf(" imul "); + adrput(stdout, getlr(p, 'L')); + printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL); + } +} + +/* + * Divide a register with a constant. + */ +static void +idivi(NODE *p) +{ + NODE *r = p->n_right; + + if (r->n_lval >= 0 && r->n_lval <= 0777777) { + printf(" idivi "); + adrput(stdout, getlr(p, '1')); + printf(",0%llo\n", r->n_lval); + } else { + printf(" idiv "); + adrput(stdout, getlr(p, '1')); + printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL); + } +} + +/* + * move a constant into a register. + */ +static void +xmovei(NODE *p) +{ + /* + * Trick: If this is an unnamed constant, just move it directly, + * otherwise use xmovei to get section number. + */ + if (p->n_name[0] == '\0' || p->n_lval > 0777777) { + printf(" "); + zzzcode(p, 'D'); + putchar(' '); + adrput(stdout, getlr(p, '1')); + putchar(','); + zzzcode(p, 'E'); + } else { + printf(" xmovei "); + adrput(stdout, getlr(p, '1')); + printf(",%s", p->n_name); + if (p->n_lval != 0) + printf("+0%llo", p->n_lval); + } + putchar('\n'); +} + +static void +printcon(NODE *p) +{ + CONSZ cz; + + p = p->n_left; + if (p->n_lval >= 0700000000000LL) { + /* converted to pointer in clocal() */ + conput(p); + return; + } + if (p->n_lval == 0 && p->n_name[0] == '\0') { + putchar('0'); + return; + } + if (BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR) + cz = (p->n_lval/4) | ((p->n_lval & 3) << 30); + else + cz = (p->n_lval/2) | (((p->n_lval & 1) + 5) << 30); + cz |= 0700000000000LL; + printf("0%llo", cz); + if (p->n_name[0] != '\0') + printf("+%s", p->n_name); +} + +static void +putcond(NODE *p) +{ + char *c; + + switch (p->n_op) { + case EQ: c = "e"; break; + case NE: c = "n"; break; + case LE: c = "le"; break; + case LT: c = "l"; break; + case GT: c = "g"; break; + case GE: c = "ge"; break; + default: + cerror("putcond"); + } + printf("%s", c); +} + +void +zzzcode(NODE *p, int c) +{ + NODE *l; + CONSZ hval; + + switch (c) { + case 'A': /* ildb right arg */ + adrput(stdout, p->n_left->n_left); + break; + + case 'B': /* remove from stack after subroutine call */ + if (p->n_rval) + printf(" subi %%17,0%o\n", p->n_rval/SZINT); + break; + + case 'C': + constput(p); + break; + + case 'D': /* Find out which type of const load insn to use */ + if (p->n_op != ICON) + cerror("zzzcode not ICON"); + if (p->n_name[0] == '\0') { + if ((p->n_lval <= 0777777) && (p->n_lval > 0)) + printf("movei"); + else if ((p->n_lval & 0777777) == 0) + printf("hrlzi"); + else + printf("move"); + } else + printf("move"); + break; + + case 'E': /* Print correct constant expression */ + if (p->n_name[0] == '\0') { + if ((p->n_lval <= 0777777) && (p->n_lval > 0)){ + printf("0%llo", p->n_lval); + } else if ((p->n_lval & 0777777) == 0) { + printf("0%llo", p->n_lval >> 18); + } else { + if (p->n_lval < 0) + printf("[ .long -0%llo]", -p->n_lval); + else + printf("[ .long 0%llo]", p->n_lval); + } + } else { + if (p->n_lval == 0) + printf("[ .long %s]", p->n_name); + else + printf("[ .long %s+0%llo]", + p->n_name, p->n_lval); + } + break; + + case 'P': + p = getlr(p, 'R'); + /* FALLTHROUGH */ + case 'O': + /* + * Print long long expression. + */ + hval = gethval(p->n_lval); + printf("[ .long 0%llo,0%llo", hval, + (p->n_lval & 0377777777777LL) | (hval & 0400000000000LL)); + if (p->n_name[0] != '\0') + printf("+%s", p->n_name); + printf(" ]"); + break; + + case 'F': /* Print an "opsimp" instruction based on its const type */ + hopcode(oneinstr(p->n_right) ? 'C' : 'R', p->n_op); + break; + + case 'H': /* Print a small constant */ + p = p->n_right; + printf("0%llo", p->n_lval & 0777777); + break; + + case 'Q': /* two-param long long comparisions */ + twollcomp(p); + break; + + case 'R': /* two-param conditionals */ + twocomp(p); + break; + + case 'U': + emitshort(p); + break; + + case 'V': + storeshort(p); + break; + + case 'Z': + ptrcomp(p); + break; + + case 'a': + imuli(p); + break; + + case 'b': + idivi(p); + break; + + case 'c': + xmovei(p); + break; + + case 'd': + printcon(p); + break; + + case 'e': + putcond(p); + break; + + case 'g': + if (p->n_right->n_op != OREG || p->n_right->n_lval != 0) + comperr("bad Zg oreg"); + printf("%s", rnames[p->n_right->n_rval]); + break; + +#if 0 + case '1': /* double upput */ + p = getlr(p, '1'); + p->n_rval += 2; + adrput(stdout, p); + p->n_rval -= 2; + break; +#endif + + case 'i': /* Write instruction for short load from name */ + l = getlr(p, 'L'); + printf(" h%cr%c %s,%s+" CONFMT "\n", + l->n_lval & 1 ? 'r' : 'l', + ISUNSIGNED(p->n_type) ? 'z' : 'e', + rnames[getlr(p, '1')->n_rval], + l->n_name, l->n_lval >> 1); + break; + + default: + cerror("zzzcode %c", c); + } +} + +/* set up temporary registers */ +void +setregs() +{ + fregs = 7; /* 7 free regs on PDP10 (1-7) */ +} + +/*ARGSUSED*/ +int +rewfld(NODE *p) +{ + return(1); +} + +int +flshape(NODE *p) +{ + register int o = p->n_op; + + return (o == REG || o == NAME || o == ICON || + (o == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1))); +} + +/* INTEMP shapes must not contain any temporary registers */ +int +shtemp(NODE *p) +{ + 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); +} + +int +shumul(NODE *p) +{ + register int o; + + if (x2debug) { + int val; + printf("shumul(%p)\n", p); + eprint(p, 0, &val, &val); + } + + o = p->n_op; +#if 0 + if (o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON) + return(STARNM); +#endif + + if ((o == INCR) && + (p->n_left->n_op == REG && p->n_right->n_op == ICON) && + p->n_right->n_name[0] == '\0') { + switch (p->n_type) { + case CHAR|PTR: + case UCHAR|PTR: + o = 1; + break; + + case SHORT|PTR: + case USHORT|PTR: + o = 2; + break; + + case INT|PTR: + case UNSIGNED|PTR: + case LONG|PTR: + case ULONG|PTR: + case FLOAT|PTR: + o = 4; + break; + + case DOUBLE|PTR: + case LONGLONG|PTR: + case ULONGLONG|PTR: + o = 8; + break; + + default: + if (ISPTR(p->n_type) && + ISPTR(DECREF(p->n_type))) { + o = 4; + break; + } else + return(0); + } + return( 0); + } + + return( 0 ); +} + +void +adrcon(CONSZ val) +{ + cerror("adrcon: val %llo\n", val); +} + +void +conput(NODE *p) +{ + switch (p->n_op) { + case ICON: + if (p->n_lval != 0) { + acon(stdout, p); + if (p->n_name[0] != '\0') + putchar('+'); + } + if (p->n_name[0] != '\0') + printf("%s", p->n_name); + if (p->n_name[0] == '\0' && p->n_lval == 0) + putchar('0'); + return; + + case REG: + putstr(rnames[p->n_rval]); + return; + + default: + cerror("illegal conput"); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + cerror("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 /= SZLONG; + switch (p->n_op) { + case REG: + putstr(rnames[p->n_rval + size]); + break; + + case NAME: + case OREG: + p->n_lval += size; + adrput(stdout, p); + p->n_lval -= size; + break; + case ICON: + printf(CONFMT, p->n_lval >> (36 * size)); + break; + default: + cerror("upput bad op %d size %d", p->n_op, size); + } +} + +void +adrput(FILE *fp, 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, fp); + if (p->n_lval != 0) + fprintf(fp, "+" CONFMT, p->n_lval & 0777777777777LL); + return; + + case OREG: + r = p->n_rval; +#if 0 + if (R2TEST(r)) { /* double indexing */ + register int flags; + + flags = R2UPK3(r); + if (flags & 1) + putc('*', fp); + if (flags & 4) + putc('-', fp); + if (p->n_lval != 0 || p->n_name[0] != '\0') + acon(p); + if (R2UPK1(r) != 100) + printf("(%s)", rnames[R2UPK1(r)]); + if (flags & 2) + putchar('+'); + printf("[%s]", rnames[R2UPK2(r)]); + return; + } +#endif + if (R2TEST(r)) + cerror("adrput: unwanted double indexing: r %o", r); + if (p->n_rval != FPREG && p->n_lval < 0 && p->n_name[0]) { + fprintf(fp, "%s", p->n_name); + acon(fp, p); + fprintf(fp, "(%s)", rnames[p->n_rval]); + return; + } + if (p->n_lval < 0 && p->n_rval == FPREG && offarg) { + p->n_lval -= offarg-2; acon(fp, p); p->n_lval += offarg-2; + } else if (p->n_lval != 0) + acon(fp, p); + if (p->n_name[0] != '\0') + fprintf(fp, "%s%s", p->n_lval ? "+" : "", p->n_name); + if (p->n_lval > 0 && p->n_rval == FPREG && offlab) + fprintf(fp, "+" LABFMT, offlab); + if (p->n_lval < 0 && p->n_rval == FPREG && offarg) + fprintf(fp, "(017)"); + else + fprintf(fp, "(%s)", rnames[p->n_rval]); + return; + case ICON: + /* addressable value of the constant */ + if (p->n_lval > 0) { + acon(fp, p); + if (p->n_name[0] != '\0') + putc('+', fp); + } + if (p->n_name[0] != '\0') + fprintf(fp, "%s", p->n_name); + if (p->n_lval < 0) + acon(fp, p); + if (p->n_name[0] == '\0' && p->n_lval == 0) + putc('0', fp); + return; + + case REG: + fputs(rnames[p->n_rval], fp); + return; + + case MOVE: /* Specially generated node */ + fputs(rnames[p->n_rall], fp); + return; + + default: + cerror("illegal address, op %d", p->n_op); + return; + + } +} + +/* + * print out a constant +*/ +void +acon(FILE *fp, NODE *p) +{ + if (p->n_lval < 0 && p->n_lval > -0777777777777ULL) + fprintf(fp, "-" CONFMT, -p->n_lval); + else + fprintf(fp, CONFMT, p->n_lval); +} + +/* printf conditional and unconditional branches */ +void +cbgen(int o,int lab) +{ +} + +/* + * 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; + if (op == ICON) { + if ((p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR)) + && p->n_lval == 0 && p->n_name[0] != '\0') + p->n_lval = 0700000000000LL; + if ((p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) + && p->n_lval == 0 && p->n_name[0] != '\0') + p->n_lval = 0750000000000LL; + } + if (op == MINUS) { + if ((p->n_left->n_type == (PTR|CHAR) || + p->n_left->n_type == (PTR|UCHAR)) && + (p->n_right->n_type == (PTR|CHAR) || + p->n_right->n_type == (PTR|UCHAR))) { + l = talloc(); + l->n_op = SCONV; + l->n_type = INT; + l->n_left = p->n_right; + p->n_right = l; + l = talloc(); + l->n_op = SCONV; + l->n_type = INT; + l->n_left = p->n_left; + p->n_left = l; + } + } +} + +void +myreader(NODE *p) +{ + int e2print(NODE *p, int down, int *a, int *b); + walkf(p, optim2); + 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); +} + +/* + * Remove last goto. + */ +void +myoptim(struct interpass *ip) +{ + while (ip->sqelem.sqe_next->type != IP_EPILOG) + ip = ip->sqelem.sqe_next; + if (ip->type != IP_NODE || ip->ip_node->n_op != GOTO) + cerror("myoptim"); + tfree(ip->ip_node); + *ip = *ip->sqelem.sqe_next; +} diff --git a/usr.bin/pcc/arch/pdp10/macdefs.h b/usr.bin/pcc/arch/pdp10/macdefs.h new file mode 100644 index 00000000000..600427e554f --- /dev/null +++ b/usr.bin/pcc/arch/pdp10/macdefs.h @@ -0,0 +1,148 @@ +/* $Id: macdefs.h,v 1.1 2007/09/15 18:12:29 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Machine-dependent defines for both passes. + */ + +/* + * Convert (multi-)character constant to integer. + * Assume: If only one value; store at left side (char size), otherwise + * treat it as an integer. + */ +#define makecc(val,i) { \ + if (i == 0) { lastcon = val; \ + } else if (i == 1) { lastcon = (lastcon << 9) | val; lastcon <<= 18; \ + } else { lastcon |= (val << (27 - (i * 9))); } } + +#define ARGINIT 36 /* # bits below fp where arguments start */ +#define AUTOINIT 36 /* # bits above fp where automatics start */ + +/* + * Storage space requirements + */ +#define SZCHAR 9 +#define SZINT 36 +#define SZFLOAT 36 +#define SZDOUBLE 72 +#define SZLONG 36 +#define SZSHORT 18 +#define SZPOINT 36 +#define SZLONGLONG 72 + +/* + * Alignment constraints + */ +#define ALCHAR 9 +#define ALINT 36 +#define ALFLOAT 36 +#define ALDOUBLE 36 +#define ALLONG 36 +#define ALLONGLONG 36 +#define ALSHORT 18 +#define ALPOINT 36 +#define ALSTRUCT 36 +#define ALSTACK 36 + +/* + * Max values. + */ +#define MAX_INT 0377777777777LL +#define MAX_UNSIGNED 0777777777777ULL +#define MAX_LONG 0377777777777LL +#define MAX_ULONG 0777777777777ULL +#define MAX_LONGLONG 000777777777777777777777LL /* XXX cross */ +#define MAX_ULONGLONG 001777777777777777777777ULL /* XXX cross */ + +/* Default char is unsigned */ +#define CHAR_UNSIGNED + +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "0%llo" /* format for printing constants */ +#define LABFMT "L%d" /* format for printing labels */ + +#define FPREG 016 /* frame pointer */ +#define STKREG 017 /* stack pointer */ + +/* + * Maximum and minimum register variables + */ +#define MINRVAR 010 /* use 10 thru ... */ +#define MAXRVAR 015 /* ... 15 */ + +#define PARAMS_UPWARD /* stack grows upwards for parameters */ +#undef BACKAUTO /* stack grows negatively for automatics */ +#undef BACKTEMP /* stack grows negatively for temporaries */ + +#define MYP2TREE(p) myp2tree(p); + +#undef FIELDOPS /* no bit-field instructions */ +#undef RTOLBYTES /* bytes are numbered left to right */ + +#define ENUMSIZE(high,low) INT /* enums are always stored in full int */ + +/* Definitions mostly used in pass2 */ + +#define REGSZ 020 +#define TMPREG 016 + +#define BYTEOFF(x) ((x)&03) +#define wdal(k) (BYTEOFF(k)==0) +#define BITOOR(x) ((x)/36) /* 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) + +#define shltype(o, p) \ + ((o) == REG || (o) == NAME || (o) == ICON || \ + (o) == OREG || ((o) == UMUL && shumul((p)->n_left))) + +#define MYREADER(p) myreader(p) +#define MYCANON(p) mycanon(p) +#define MYOPTIM + +#undef SPECIAL_INTEGERS + +/* + * Special shapes used in code generation. + */ +#define SUSHCON (SPECIAL|6) /* unsigned short constant */ +#define SNSHCON (SPECIAL|7) /* negative short constant */ +#define SILDB (SPECIAL|8) /* use ildb here */ + diff --git a/usr.bin/pcc/arch/pdp10/order.c b/usr.bin/pcc/arch/pdp10/order.c new file mode 100644 index 00000000000..b548c294b8d --- /dev/null +++ b/usr.bin/pcc/arch/pdp10/order.c @@ -0,0 +1,187 @@ +/* $Id: order.c,v 1.1 2007/09/15 18:12:29 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass2.h" + +int canaddr(NODE *); + +/* + * should the assignment op p be stored, + * given that it lies as the right operand of o + * (or the left, if o==UMUL) + */ +void +stoasg(NODE *p, int o) +{ + if (x2debug) + printf("stoasg(%p, %o)\n", p, o); +} + +/* should we delay the INCR or DECR operation p */ +int +deltest(NODE *p) +{ + TWORD ty = p->n_type; + + return ty == PTR+CHAR || ty == PTR+UCHAR || + ty == PTR+SHORT || ty == PTR+USHORT; +} + +/* + * Check if p can be autoincremented. + * Nothing can be autoincremented on PDP10. + */ +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 */ +} + +int radebug = 0; + +int +offstar(NODE *p) +{ + NODE *q; + + if (x2debug) + printf("offstar(%p)\n", p); + + if( p->n_op == PLUS || p->n_op == MINUS ){ + if( p->n_right->n_op == ICON ){ + q = p->n_left; + if (q->n_op != REG) + geninsn(q, INTAREG|INAREG); + p->n_su = -1; + return 1; + } + } + geninsn(p, INTAREG|INAREG); + return 0; +} + +/* + * Rewrite increment/decrement operation. + */ +int +setincr(NODE *p) +{ + if (x2debug) + printf("setincr(%p)\n", p); + + return(0); +} + +/* + * findops() failed, see if we can rewrite it to match. + */ +int +setbin(NODE *p) +{ + TWORD ty; + NODE *r, *s; + + ty = p->n_type; + switch (p->n_op) { + case MINUS: + switch (ty) { + case PTR+CHAR: + case PTR+UCHAR: + case PTR+SHORT: + case PTR+USHORT: + /* + * Must negate the right side and change op to PLUS. + */ + r = p->n_right; + if (r->n_op == ICON) { + r->n_lval = -r->n_lval; + } else { + s = talloc(); + s->n_type = r->n_type; + s->n_op = UMINUS; + s->n_left = r; + p->n_right = s; + } + p->n_op = PLUS; + return 1; + } + } + return 0; +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +int +special(NODE *p, int shape) +{ + switch (shape) { + case SUSHCON: + if (p->n_op == ICON && p->n_name[0] == '\0' && + (p->n_lval > 0 && p->n_lval <= 0777777)) + return 1; + break; + + case SNSHCON: + if (p->n_op == ICON && p->n_name[0] == '\0' && + (p->n_lval < 0 && p->n_lval > -01000000)) + return 1; + break; + case SILDB: + if (p->n_op == ASSIGN && p->n_left->n_op == REG && + p->n_right->n_op == PLUS && + p->n_right->n_left->n_op == REG && + p->n_right->n_right->n_op == ICON && + p->n_right->n_right->n_lval == 1 && + p->n_right->n_left->n_rval == p->n_left->n_rval) + return 1; + break; + } + return 0; +} diff --git a/usr.bin/pcc/arch/pdp10/table.c b/usr.bin/pcc/arch/pdp10/table.c new file mode 100644 index 00000000000..321b88cb94e --- /dev/null +++ b/usr.bin/pcc/arch/pdp10/table.c @@ -0,0 +1,1153 @@ +/* $Id: table.c,v 1.1 2007/09/15 18:12:30 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "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[] = { +{ -1, FORREW,SANY,TANY,SANY,TANY,REWRITE,-1,"", }, +/* + * A bunch of pointer conversions. + * First pointer to integer. + */ +/* Convert char pointer to int */ +{ SCONV, INTAREG, + SAREG|STAREG, TPTRTO|TCHAR|TUCHAR, + SANY, TWORD, + NAREG, RLEFT, + " lsh AL,2\n" + " move A1,AL\n" + " lsh A1,-040\n" + " trz A1,074\n" + " ior AL,A1\n" + " tlz AL,0740000\n", }, + +/* Convert short pointer to int */ +{ SCONV, INTAREG, + SAREG|STAREG, TPTRTO|TSHORT|TUSHORT, + SANY, TWORD, + NAREG, RLEFT, + " lsh AL,2\n" + " move A1,AL\n" + " lsh A1,-041\n" + " trz A1,2\n" + " ior AL,A1\n" + " tlz AL,0740000\n", }, + +/* Convert int/unsigned/long/ulong/struct/union/func ptr to int */ +{ SCONV, INTAREG, + SAREG|STAREG, TPTRTO|TWORD|TSTRUCT|TPOINT, + SANY, TWORD, + 0, RLEFT, + " lsh AL,2\n", }, + +/* + * Convert int/long to pointers. + */ +/* Convert int to char pointer */ +{ PCONV, INTAREG, + STAREG, TWORD, + SANY, TPTRTO|TCHAR|TUCHAR, + NAREG, RLEFT, + " move A1,AL\n" + " lsh A1,036\n" + " tlo A1,0700000\n" + " tlz A1,0040000\n" + " lsh AL,-2\n" + " ior AL,A1\n", }, + +/* Convert int/long to short pointer */ +{ PCONV, INTAREG, + STAREG, TWORD, + SANY, TPTRTO|TSHORT|TUSHORT, + NAREG, RLEFT, + " move A1,AL\n" + " lsh AL,-2\n" + " tlo AL,0750000\n" + " lsh A1,035\n" + " tlz A1,0760000\n" + " add AL,A1\n", }, + +/* Convert int/long to int/struct/multiple ptr */ +{ PCONV, INTAREG, + STAREG, TWORD, + SANY, TPOINT|TWORD|TSTRUCT, + 0, RLEFT, + " lsh AL,-2\n", }, + +/* + * Pointer to pointer conversions. + */ +/* Convert char ptr to short ptr */ +{ PCONV, INTAREG, + STAREG, TPTRTO|TCHAR|TUCHAR, + SANY, TPTRTO|TSHORT|TUSHORT, + 0, RLEFT, + " tlo AL,050000\n" + " tlne AL,020000\n" + " tlz AL,010000\n", }, + +/* Convert char/short pointer to int/struct/multiple ptr */ +{ PCONV, INTAREG, + STAREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, + SANY, TPOINT|TWORD|TSTRUCT, + 0, RLEFT, + " tlz AL,0770000\n", }, + +/* Convert short pointer to char ptr */ +{ PCONV, INTAREG, + STAREG, TPTRTO|TSHORT|TUSHORT, + SANY, TPTRTO|TCHAR|TUCHAR, + 0, RLEFT, + " tlz AL,050000\n", }, + +/* Convert int/struct/foo pointer to char ptr */ +{ PCONV, INTAREG, + STAREG, TPOINT|TWORD|TSTRUCT, + SANY, TPTRTO|TCHAR|TUCHAR, + 0, RLEFT, + " tlo AL,0700000\n", }, + +/* Convert int/struct/foo pointer to short ptr */ +{ PCONV, INTAREG, + STAREG, TPTRTO|TWORD|TSTRUCT, + SANY, TPTRTO|TSHORT|TUSHORT, + 0, RLEFT, + " tlo AL,0750000\n", }, + +/* + * A bunch conversions of integral<->integral types + */ + +/* convert short/char to int. This is done when register is loaded */ +{ SCONV, INTAREG, + STAREG, TSHORT|TUSHORT|TCHAR|TUCHAR|TWORD, + SANY, TWORD, + 0, RLEFT, + "", }, + +/* convert int to short/char. This is done when register is loaded */ +{ SCONV, INTAREG, + STAREG, TWORD, + SANY, TSHORT|TUSHORT|TCHAR|TUCHAR|TWORD, + 0, RLEFT, + "", }, + +/* convert int/long to unsigned long long */ +{ SCONV, INTAREG, + SAREG|STAREG|SNAME|SOREG, TWORD, + SANY, TULONGLONG, + NAREG|NASL, RESC1, + " move U1,AL\n" + " setz A1,\n" + " tlze U1,0400000\n" + " tro A1,01\n" , }, + +/* convert int/long to long long */ +{ SCONV, INTAREG, + SAREG|STAREG|SNAME|SOREG, TWORD, + SANY, TLONGLONG, + NAREG|NASL, RESC1, + " move U1,AL\n" + " move A1,U1\n" + " ash A1,-043\n", }, + +/* convert uchar/ushort to (unsigned) long long */ +{ SCONV, INTAREG, + SAREG|STAREG|SNAME|SOREG, TUCHAR|TUSHORT, + SANY, TLL, + NAREG|NASL, RESC1, + " move U1,AL\n" + " setz A1,\n", }, + +/* convert long long to int/long */ +{ SCONV, INTAREG, + SAREG|STAREG|SNAME|SOREG, TLL, + SANY, TWORD, + NAREG|NASL, RESC1, + " move A1,UL\n", }, + +/* convert long long to unsigned char - XXX - signed char */ +{ SCONV, INTAREG, + SAREG|STAREG|SNAME|SOREG, TLL, + SANY, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " move A1,UL\n" + " andi A1,0777\n", }, + +/* convert long long to short - XXX - signed short */ +{ SCONV, INTAREG, + SAREG|STAREG|SNAME|SOREG, TLL, + SANY, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " move A1,UL\n" + " hrrz A1,A1\n", }, + +/* floating point conversions */ +{ SCONV, INTAREG, + SAREG|STAREG|SNAME|SOREG, TDOUBLE|TFLOAT, + SANY, TWORD, + NAREG|NASL, RESC1, + " fix A1,AL\n", }, + +{ SCONV, INTAREG, + SAREG|STAREG|SNAME|SOREG, TWORD, + SANY, TFLOAT, + NAREG|NASL, RESC1, + " fltr A1,AL\n", }, + +{ SCONV, INTAREG, + SAREG|STAREG|SNAME|SOREG, TWORD, + SANY, TDOUBLE, + NAREG|NASL, RESC1, + " fltr A1,AL\n setz U1,\n", }, + +{ SCONV, INTAREG, + SAREG|STAREG|SNAME|SOREG, TDOUBLE, + SANY, TFLOAT, + NAREG|NASL, RESC1, + " move A1,AL\n", }, + +{ SCONV, INTAREG, + SAREG|STAREG|SNAME|SOREG, TFLOAT, + SANY, TDOUBLE, + NAREG|NASL, RESC1, + " move A1,AL\n setz U1,\n", }, + +/* + * Store constant initializers. + */ +{ INIT, FOREFF, + SCON, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, + SANY, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RNOP, + " .long Zd\n", }, +{ INIT, FOREFF, + SCON, TANY, + SANY, TWORD|TPOINT, + 0, RNOP, + " .long CL\n", }, + +{ INIT, FOREFF, + SCON, TANY, + SANY, TLL, + 0, RNOP, + " .long UL\n .long CL\n", }, + +/* + * Subroutine calls. + */ + +{ UCALL, INTAREG, + SCON, TANY, + SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT, + NAREG, RESC1, /* should be 0 */ + " pushj 017,AL\nZB", }, + +{ UCALL, INTAREG, + SAREG|STAREG, TANY, + SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT, + NAREG|NASL, RESC1, /* should be 0 */ + " pushj 017,(AL)\nZB", }, + +{ UCALL, INTAREG, + SNAME|SOREG, TANY, + SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT, + NAREG, RESC1, /* should be 0 */ + " pushj 017,@AL\nZB", }, + +/* + * MOVE nodes are usually inserted late (at register assignment). + */ +{ MOVE, FOREFF, + SANY, TWORD, + STAREG|SAREG|SNAME|SOREG, TWORD, + 0, RRIGHT, + " move AR,AL\n", }, + +{ MOVE, FOREFF, + SANY, TLL, + STAREG|SAREG|SNAME|SOREG, TLL, + 0, RRIGHT, + " dmove AR,AL\n", }, + +/* + * INCR can be slightly optimized. + */ +{ INCR, INTAREG, + STAREG|SAREG|SNAME|SOREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO, + SONE, TANY, + NAREG, RESC1, + " move A1,AL\n" + " ibp AL\n", }, + +#ifdef notyet +/* Fix check of return value */ +{ INCR, FOREFF, + STAREG|SAREG|SNAME|SOREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO, + SONE, TANY, + 0, 0, + " ibp AL\n", }, +#endif + +/* + * PLUS operators. + */ +/* Add a value to a char/short pointer */ +{ PLUS, INAREG|INTAREG|FOREFF, + SAREG|STAREG|SNAME|SOREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|STAREG, TWORD, + 0, RRIGHT, + " adjbp AR,AL\n", }, + +/* No more search for char/short pointer addition */ +{ PLUS, INAREG|INTAREG|FOREFF, + SANY, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE!\n", }, + +/* Add char/short/int to register */ +{ PLUS, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TWORD, + SAREG|STAREG|SNAME|SOREG, TWORD, + 0, RLEFT, + " add AL,AR\n", }, + +/* Add char/short/int to memory */ +{ PLUS, FOREFF|INAREG|INTAREG, + SAREG|STAREG|SNAME|SOREG, TWORD, + SAREG|STAREG, TWORD, + 0, RLEFT, + " addm AR,AL\n", }, + +/* Add a small constant to a register */ +{ PLUS, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD|TPOINT, + SUSHCON, TWORD, + 0, RLEFT, + " addi AL,AR\n", }, + +/* Add a larger constant to a register */ +{ PLUS, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD|TPOINT, + SCON, TWORD, + 0, RLEFT, + " add AL,[ .long AR ]\n", }, + +/* Add long long to register */ +{ PLUS, INAREG|INTAREG|FOREFF, + SAREG|STAREG, TLL, + SAREG|STAREG|SNAME|SOREG, TLL, + 0, RLEFT, + " dadd AL,AR\n", }, + +/* Add int (or int pointer) to register */ +{ PLUS, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TWORD|TPOINT, + SAREG|STAREG|SNAME|SOREG, TWORD, + 0, RLEFT, + " add AL,AR # foo \n", }, + +/* char/short are allowed to be added if they are in registers */ +{ PLUS, INAREG|INTAREG|FOREFF, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " add AL,AR\n", }, + +/* get address of an memory position into a register */ +{ PLUS, INAREG|INTAREG, + SAREG|STAREG, TWORD|TPTRTO, + SCON, TANY, + NAREG, RESC1, + " xmovei A1,AR(AL)\n", }, + +/* Safety belt for plus */ +{ PLUS, FORREW|FOREFF|INAREG|INTAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* + * MINUS operators. + */ +/* Rewrite subtracts from char/short pointers (to negative adds) */ +{ MINUS, FORREW|FOREFF|INAREG|INTAREG, + SANY, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO, + SANY, TANY, + REWRITE, BITYPE, + "DIEDIEDIE", }, + +/* Subtract char/short/int word in memory from reg */ +{ MINUS, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TWORD|TPOINT, + SAREG|STAREG|SNAME|SOREG, TWORD|TPOINT, + 0, RLEFT, + " sub AL,AR\n", }, + +/* Subtract a small constant from reg */ +{ MINUS, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TWORD|TPOINT, + SUSHCON, TWORD|TPOINT, + 0, RLEFT, + " subi AL,AR\n", }, + +/* Subtract a large constant from reg */ +{ MINUS, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TWORD|TPOINT, + SCON, TWORD|TPOINT, + 0, RLEFT, + " sub AL,[ .long AR ]\n", }, + +/* Subtract char/short/int word in memory from reg, save in memory */ +{ MINUS, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TWORD, + SAREG|STAREG|SNAME|SOREG, TWORD, + 0, RRIGHT, + " subm AL,AR\n", }, + +/* Subtract long long from register */ +{ MINUS, INAREG|INTAREG|FOREFF, + SAREG|STAREG, TLL, + SAREG|STAREG|SNAME|SOREG, TLL, + 0, RLEFT, + " dsub AL,AR\n", }, + +/* char/short are allowed to be subtracted if they are in registers */ +{ MINUS, INAREG|INTAREG|FOREFF, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " sub AL,AR\n", }, + +/* Safety belt for plus */ +{ MINUS, FORREW|FOREFF|INAREG|INTAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* + * AND/OR/ER operators. + * Simpler that the ops above in that they only work on integral types. + */ +/* And char/short/int with integer memory */ +{ AND, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|STAREG|SNAME|SOREG, TWORD, + 0, RLEFT, + " and AL,AR\n", }, + +/* And char/short/int with register */ +{ AND, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " and AL,AR\n", }, + +/* And char/short/int with small constant */ +{ AND, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SUSHCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " andi AL,AR\n", }, + +/* And char/short/int with large constant */ +{ AND, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " and AL,[ .long AR ]\n", }, + +/* long long AND */ +{ AND, INAREG|FOREFF, + SAREG|STAREG, TLL, + SAREG|STAREG|SNAME|SOREG, TLL, + 0, RLEFT, + " and AL,AR\n" + " and UL,UR\n", }, + +/* Safety belt for AND */ +{ AND, FORREW|FOREFF|INAREG|INTAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + + +/* OR char/short/int with integer memory */ +{ OR, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|STAREG|SNAME|SOREG, TWORD, + 0, RLEFT, + " ior AL,AR\n", }, + +/* OR char/short/int with register */ +{ OR, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " ior AL,AR\n", }, + +/* OR char/short/int with small constant */ +{ OR, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SUSHCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " iori AL,AR\n", }, + +/* OR char/short/int with large constant */ +{ OR, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " ior AL,[ .long AR ]\n", }, + +/* long long OR */ +{ OR, INAREG|FOREFF, + SAREG|STAREG, TLL, + SAREG|STAREG|SNAME|SOREG, TLL, + 0, RLEFT, + " ior AL,AR\n" + " ior UL,UR\n", }, + +/* Safety belt for OR */ +{ OR, FORREW|FOREFF|INAREG|INTAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + + +/* ER char/short/int with integer memory */ +{ ER, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|STAREG|SNAME|SOREG, TWORD, + 0, RLEFT, + " xor AL,AR\n", }, + +/* ER char/short/int with register */ +{ ER, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " xor AL,AR\n", }, + +/* ER char/short/int with small constant */ +{ ER, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SUSHCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " xori AL,AR\n", }, + +/* ER char/short/int with large constant */ +{ ER, FOREFF|INAREG|INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " xor AL,[ .long AR ]\n", }, + +/* long long ER */ +{ ER, INAREG|FOREFF, + SAREG|STAREG, TLL, + SAREG|STAREG|SNAME|SOREG, TLL, + 0, RLEFT, + " xor AL,AR\n" + " xor UL,UR\n", }, + +/* Safety belt for ER */ +{ ER, FORREW|FOREFF|INAREG|INTAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* + * The next rules handle all shift operators. + */ +{ LS, INTAREG|INAREG|FOREFF, + SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RLEFT, + " lsh AL,(AR)\n", }, + +{ LS, INTAREG|INAREG|FOREFF, + SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + SNAME|SOREG, TWORD, + 0, RLEFT, + " lsh AL,@AR\n", }, + +{ LS, INTAREG|INAREG|FOREFF, + STAREG|SAREG, TLL, + SCON, TANY, + 0, RLEFT, + " ashc AL,ZH\n", }, + +{ LS, INTAREG|INAREG|FOREFF, + STAREG|SAREG, TLL, + SAREG|STAREG /* |SNAME|SOREG */, TANY, + 0, RLEFT, + " ashc AL,(AR)\n", }, + +{ RS, INTAREG|INAREG|FOREFF, + STAREG|SAREG, TSWORD, + SCON, TWORD, + 0, RLEFT, + " ash AL,-ZH\n", }, + +{ RS, INTAREG|INAREG|FOREFF, + STAREG|SAREG, TUWORD, + SCON, TWORD, + 0, RLEFT, + " lsh AL,-ZH\n", }, + +/* Safety belt for LS/RS */ +{ LS, FORREW|FOREFF|INAREG|INTAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +{ RS, FORREW|FOREFF|INAREG|INTAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* + * The next rules takes care of assignments. "=". + */ +/* Match zeroed registers first */ +{ ASSIGN, INTAREG|FOREFF, + SAREG|STAREG, TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT, + SZERO, TANY, + 0, RLEFT, + " setz AL,\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SZERO, TANY, + 0, 0, + " setzm AL\n", }, + +{ ASSIGN, INTAREG|FOREFF, + SAREG|STAREG, TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT, + SMONE, TANY, + 0, RLEFT, + " setom AL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SMONE, TANY, + 0, 0, + " setom AL\n", }, + +{ ASSIGN, INAREG|INTAREG|FOREFF, + STAREG|SAREG, TWORD|TPOINT, + SCON, TWORD|TPOINT, + 0, RLEFT, + " ZC\n", }, + +{ ASSIGN, INAREG|INTAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT|TFLOAT, + SAREG|STAREG, TUCHAR|TUSHORT|TWORD|TPOINT|TFLOAT, + 0, RRIGHT, + " movem AR,AL\n", }, + +{ ASSIGN, INAREG|INTAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT|TFLOAT, + SAREG|STAREG, TSHORT, + 0, 0, + " hrrem AR,AL\n", }, + +{ ASSIGN, INAREG|INTAREG|FOREFF, + SAREG|STAREG, TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT, + SAREG|STAREG|SNAME|SOREG, TWORD|TPOINT, + 0, RLEFT, + " move AL,AR\n", }, + +{ ASSIGN, INAREG|INTAREG|FOREFF, + SAREG|STAREG, TUCHAR|TUSHORT|TCHAR|TSHORT, + SAREG|STAREG, TUCHAR|TUSHORT|TCHAR|TSHORT, + 0, RLEFT, + " move AL,AR\n", }, + +{ ASSIGN, INAREG|INTAREG|FOREFF, + SAREG|SNAME|SOREG, TLL|TDOUBLE, + SAREG|STAREG, TLL|TDOUBLE, + 0, RRIGHT, + " dmovem AR,AL\n", }, + +{ ASSIGN, INAREG|INTAREG|FOREFF, + SOREG|SNAME, TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG|STAREG, TANY, + 0, RRIGHT, + "ZV", }, + +{ ASSIGN, INAREG|INTAREG|FOREFF, + SAREG|STAREG, TUSHORT|TUCHAR, + SOREG, TANY, + 0, RLEFT, + " ldb AL,Zg\n", }, + +{ ASSIGN, INAREG|INTAREG|FOREFF, + SAREG|STAREG, TSHORT|TUSHORT|TCHAR|TUCHAR, + SSCON, TANY, + 0, RLEFT, + " movei AL,AR\n", }, + +{ ASSIGN, INAREG|INTAREG|FOREFF, + SAREG|STAREG, TSHORT|TUSHORT|TCHAR|TUCHAR, + SCON, TANY, + 0, RLEFT, + " move AL,[ .long AR]\n", }, + +/* + * DIV/MOD/MUL + * These can be done way more efficient. + */ +/* long long div. XXX - work only with unsigned */ +{ DIV, INAREG|INTAREG|FOREFF, + SAREG|STAREG|SNAME|SOREG, TLL, + SAREG|STAREG|SNAME|SOREG, TLL, + (2*NAREG)|NASL, RESC1, + " dmove A2,AL ; dmove A1,[ .long 0,0 ]\n" + " ddiv A1,AR\n", }, + +/* long long div. with constant. XXX - work only with unsigned */ +{ DIV, INAREG|INTAREG|FOREFF, + SAREG|STAREG|SNAME|SOREG, TLL, + SCON, TLL, + (2*NAREG)|NASL, RESC1, + " dmove A2,AL ; dmove A1,[ .long 0,0 ]\n" + " ddiv A1,ZP\n", }, + +/* Simple divide. XXX - fix so next reg can be free */ +{ DIV, INAREG|INTAREG|FOREFF, + SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RRIGHT, + " idivm AL,AR\n", }, + +/* Safety belt for DIV */ +{ DIV, FORREW|FOREFF|INAREG|INTAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* long long MOD */ +{ MOD, INTAREG|INAREG|FOREFF, + SAREG|STAREG|SNAME|SOREG, TLL, + SAREG|STAREG|SNAME|SOREG, TLL, + 2*NAREG|NASL, RESC2, + " dmove A2,AL ; dmove A1,[ .long 0,0 ]\n" + " ddiv A1,AR\n", }, + +/* integer MOD */ +{ MOD, INTAREG|INAREG|FOREFF, + SAREG|STAREG|SNAME|SOREG, TWORD, + SAREG|STAREG|SNAME|SOREG, TWORD, + 2*NAREG|NASL, RESC2, + " move A2,AL\n" + " setz A1,\n" + " idiv A1,AR\n", }, + +/* integer MOD for char/short */ +{ MOD, INTAREG|INAREG|FOREFF, + SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 2*NAREG|NASL, RESC2, + " move A2,AL\n" + " setz A1,\n" + " idiv A1,AR\n", }, + +/* Safety belt for MOD */ +{ MOD, FORREW|FOREFF|INAREG|INTAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* long long MUL */ +{ MUL, INTAREG|INAREG|FOREFF, + SAREG|STAREG|SNAME|SOREG, TLL, + SAREG|STAREG|SNAME|SOREG, TLL, + 2*NAREG|NASL, RESC2, + " dmove A1,AL\n" + " dmul A1,AR\n", }, + +/* integer multiply to memory*/ +{ MUL, INTAREG|INAREG|FOREFF, + SAREG|STAREG|SNAME|SOREG, TWORD, + SAREG|STAREG, TWORD, + 0, RLEFT, + " imulm AR,AL\n", }, + +/* integer multiply */ +{ MUL, INTAREG|INAREG|FOREFF, + SAREG|STAREG, TWORD, + SAREG|STAREG|SNAME|SOREG, TWORD, + 0, RLEFT, + " imul AL,AR\n", }, + +/* integer multiply for char/short */ +{ MUL, INTAREG|INAREG|FOREFF, + SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|STAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RLEFT, + " imul AL,AR\n", }, + +/* integer multiply with small constant */ +{ MUL, INTAREG|INAREG|FOREFF, + SAREG|STAREG, TWORD, + SUSHCON, TWORD, + 0, RLEFT, + " imuli AL,AR\n", }, + +/* integer multiply with large constant */ +{ MUL, INTAREG|INAREG|FOREFF, + SAREG|STAREG, TWORD, + SCON, TWORD, + 0, RLEFT, + " imul AL,[ .long AR ]\n", }, + +/* Safety belt for MUL */ +{ MUL, FORREW|FOREFF|INAREG|INTAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* read an indirect long long value into register */ +{ UMUL, INTAREG, + SAREG|STAREG, TPTRTO|TLL|TWORD, + SANY, TLL, + NAREG|NASL, RESC1, + " dmove A1,(AL)\n", }, + +/* read an indirect integer value into register */ +{ UMUL, INTAREG, + SAREG|STAREG, TWORD|TPOINT, + SANY, TWORD|TPOINT, + NAREG|NASL, RESC1, + " move A1,(AL)\n", }, + +/* read an indirect value into register */ +{ UMUL, INTAREG, + SOREG, TWORD|TPOINT, + SANY, TWORD|TPOINT, + NAREG, RESC1, + " move A1,@AL\n", }, + +/* read an indirect value into register */ +{ UMUL, INTAREG, + SAREG|STAREG|SOREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO, + SANY, TCHAR|TUCHAR|TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " ldb A1,AL\n", }, + +#ifdef notyet +/* Match tree shape for ildb */ +{ UMUL, INTAREG, + SANY, TANY, + SILDB, TUCHAR|TCHAR|TPTRTO, + NAREG, RESC1, + " ildb A1,ZA\n", }, +#endif + +/* Match char/short pointers first, requires special handling */ +{ OPLOG, FORCC, + SAREG|STAREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|STAREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RESCC, + "ZZ", }, + +/* Can check anything by just comparing if EQ/NE */ +{ OPLOG, FORCC, + SAREG|STAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, + SZERO, TANY, + 0, RESCC, + " jumpZe AL,LC # bu\n", }, + +{ EQ, FORCC, + SAREG|STAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|STAREG|SOREG|SNAME|SCON, TWORD|TPOINT, + 0, RESCC, + "ZR", }, + +{ NE, FORCC, + SAREG|STAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|STAREG|SOREG|SNAME|SCON, TWORD|TPOINT, + 0, RESCC, + "ZR", }, + +{ OPLOG, FORCC, + SAREG|STAREG, TWORD, + SAREG|STAREG|SOREG|SNAME|SCON, TSWORD, + 0, RESCC, + "ZR", }, + +{ OPLOG, FORCC, + SAREG|STAREG, TCHAR|TUCHAR, + SCON, TANY, + 0, RESCC, + "ZR", }, + +{ OPLOG, FORCC, + SAREG|STAREG, TWORD|TPOINT|TFLOAT, + SAREG|STAREG|SOREG|SNAME|SCON, TWORD|TPOINT|TFLOAT, + 0, RESCC, + "ZR", }, + +{ OPLOG, FORCC, + SAREG|STAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|STAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RESCC, + "ZR", }, + +{ OPLOG, FORCC, + SAREG|STAREG, TLL|TDOUBLE, /* XXX - does double work here? */ + SAREG|STAREG|SOREG|SNAME, TLL|TDOUBLE, + 0, RESCC, + "ZQ", }, + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " jrst LL\n", }, + +/* + * Convert LTYPE to reg. + */ +{ OPLTYPE, INAREG|INTAREG, + SANY, TANY, + SMONE, TLL, + NAREG, RESC1, + " seto A1,\n seto U1,\n", }, + +{ OPLTYPE, INAREG|INTAREG, + SANY, TANY, + SMONE, TANY, + NAREG, RESC1, + " seto A1,\n", }, + +{ OPLTYPE, INAREG|INTAREG, + SANY, TANY, + SZERO, TLL, + NAREG, RESC1, + " setz A1,\n setz U1,\n", }, + +{ OPLTYPE, INAREG|INTAREG, + SANY, TANY, + SZERO, TANY, + NAREG, RESC1, + " setz A1,\n", }, + +{ OPLTYPE, INAREG|INTAREG, + SANY, TANY, + SUSHCON, TLL, + NAREG, RESC1, + " setz A1,\n movei U1,AR\n", }, + +{ OPLTYPE, INAREG|INTAREG, + SANY, TANY, + SUSHCON, ANYFIXED, + NAREG, RESC1, + " movei A1,AR\n", }, + +{ OPLTYPE, INAREG|INTAREG, + SANY, ANYFIXED, + SNSHCON, ANYFIXED, + NAREG, RESC1, + " hrroi A1,AR\n", }, + +{ OPLTYPE, INAREG|INTAREG, + SANY, ANYFIXED, + SCON, ANYFIXED, + NAREG|NASR, RESC1, + " ZD A1,ZE # suspekt\n", }, + +{ OPLTYPE, INAREG|INTAREG, + SANY, TWORD|TPOINT|TFLOAT, + SAREG|STAREG|SOREG|SNAME, TWORD|TPOINT|TFLOAT, + NAREG|NASR, RESC1, + " move A1,AR\n", }, + +{ OPLTYPE, INAREG|INTAREG, + SANY, TLL, + SCON, TLL, + NAREG, RESC1, + " dmove A1,ZO\n", }, + +{ OPLTYPE, INAREG|INTAREG, + SANY, TLL|TDOUBLE, + SANY, TLL|TDOUBLE, + NAREG|NASR, RESC1, + " dmove A1,AR\n", }, + +{ OPLTYPE, INAREG|INTAREG, + SOREG, TSHORT|TUSHORT|TCHAR|TUCHAR, + SOREG, TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASR, RESC1, + "ZU", }, + +{ OPLTYPE, INAREG|INTAREG, + SNAME, TUCHAR, + SNAME, TUCHAR, + NAREG|NASR, RESC1, + " ldb A1,[ .long AL ]\n" }, + +{ OPLTYPE, INAREG|INTAREG, + SNAME, TCHAR, + SNAME, TCHAR, + NAREG|NASR, RESC1, + " ldb A1,[ .long AL ]\n" + " ash A1,033\n" + " ash A1,-033\n", }, + +{ OPLTYPE, INAREG|INTAREG, + SANY, TANY, + SNAME, TSHORT|TUSHORT, + NAREG|NASR, RESC1, + "Zi", }, + +{ OPLTYPE, INAREG|INTAREG, + SANY, TWORD|TPOINT, + SCON, TWORD|TPOINT, + NAREG|NASR, RESC1, + "Zc", }, + +{ OPLTYPE, INAREG, + SAREG|STAREG, TUSHORT|TUCHAR, + SAREG|STAREG, TUSHORT|TUCHAR|TWORD, + NAREG, RESC1, + " move A1,AL\n", }, + +/* + * Negate a word. + */ +{ UMINUS, INAREG|INTAREG|FOREFF, + SAREG|STAREG|SNAME|SOREG, TWORD, + SANY, TWORD, + NAREG|NASL, RESC1, + " movn A1,AL\n", }, + +{ UMINUS, INAREG|INTAREG|FOREFF, + SAREG|STAREG, TWORD, + SANY, TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RLEFT, + " movn AL,AL\n", }, + +{ UMINUS, INAREG|INTAREG|FOREFF, + SAREG|STAREG|SNAME|SOREG, TLL, + SANY, TLL, + NAREG|NASR, RESC1, + " dmovn A1,AL\n", }, + +{ COMPL, INTAREG, + SAREG|STAREG|SNAME|SOREG, TLL, + SANY, TANY, + NAREG|NASL, RESC1, + " setcm A1,AL\n" + " setcm U1,UL\n", }, + +{ COMPL, INTAREG, + SAREG|STAREG|SNAME|SOREG, TWORD, + SANY, TANY, + NAREG|NASL, RESC1, + " setcm A1,AL\n", }, + +{ COMPL, INTAREG, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT, + SANY, TCHAR|TUCHAR|TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " setcm A1,AL\n", }, + +/* + * Arguments to functions. + */ +{ FUNARG, FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT|TFLOAT, + SANY, TANY, + 0, RNULL, + " push 017,AL\n", }, + +{ FUNARG, FOREFF, + SAREG|STAREG, TCHAR|TUCHAR|TSHORT|TUSHORT, + SANY, TANY, + 0, RNULL, + " push 017,AL\n", }, + +{ FUNARG, FOREFF, + SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TPOINT|TWORD, + SANY, TANY, + 0, RNULL, + " push 017,[ .long AL]\n", }, + +{ FUNARG, FOREFF, + SAREG|STAREG, TLL|TDOUBLE, + SANY, TANY, + 0, RNULL, + " push 017,AL\n push 017,UL\n", }, + + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ INCR, DF(INCR), }, + +{ DECR, DF(INCR), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ OPLEAF, DF(NAME), }, + +{ INIT, DF(INIT), }, + +{ OPUNARY, DF(UMINUS), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/usr.bin/pcc/arch/vax/code.c b/usr.bin/pcc/arch/vax/code.c new file mode 100644 index 00000000000..d048a337fd9 --- /dev/null +++ b/usr.bin/pcc/arch/vax/code.c @@ -0,0 +1,452 @@ +/* $Id: code.c,v 1.1 2007/09/15 18:12:30 otto Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +# include "mfile1" +#include <a.out.h> + +int proflg = 0; /* are we generating profiling code? */ +int strftn = 0; /* is the current function one which returns a value */ +int gdebug; +int fdefflag; /* are we within a function definition ? */ +char NULLNAME[8]; +int labelno; + +branch( n ){ + /* output a branch to label n */ + /* exception is an ordinary function branching to retlab: then, return */ + if( n == retlab && !strftn ){ + printf( " ret\n" ); + } + else printf( " jbr L%d\n", n ); + } + +int lastloc = { -1 }; + +short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3}; +#define LOG2SZ 9 + +defalign(n) { + /* cause the alignment to become a multiple of n */ + n /= SZCHAR; + if( lastloc != PROG && n > 1 ) printf( " .align %d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 ); + } + +locctr( l ){ + register temp; + /* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */ + + if( l == lastloc ) return(l); + temp = lastloc; + lastloc = l; + switch( l ){ + + case PROG: + printf( " .text\n" ); + psline(); + break; + + case DATA: + case ADATA: + printf( " .data\n" ); + break; + + case STRNG: + printf( " .data 1\n" ); + break; + + case ISTRNG: + printf( " .data 2\n" ); + break; + + case STAB: + printf( " .stab\n" ); + break; + + default: + cerror( "illegal location counter" ); + } + + return( temp ); + } + +deflab( n ){ + /* output something to define the current position as label n */ + printf( "L%d:\n", n ); + } + +int crslab = 10; + +getlab(){ + /* return a number usable for a label */ + return( ++crslab ); + } + + +int ent_mask[] = { + 0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0}; + +int reg_use = 11; + +efcode(){ + /* code for the end of a function */ + + if( strftn ){ /* copy output (in R2) to caller */ + register NODE *l, *r; + register struct symtab *p; + register TWORD t; + register int j; + int i; + + p = &stab[curftn]; + t = p->stype; + t = DECREF(t); + + deflab( retlab ); + + i = getlab(); /* label for return area */ + printf(" .data\n" ); + printf(" .align 2\n" ); + printf("L%d: .space %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR ); + printf(" .text\n" ); + psline(); + printf(" movab L%d,r1\n", i); + + reached = 1; + l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); + l->rval = 1; /* R1 */ + l->lval = 0; /* no offset */ + r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); + r->rval = 0; /* R0 */ + r->lval = 0; + l = buildtree( UNARY MUL, l, NIL ); + r = buildtree( UNARY MUL, r, NIL ); + l = buildtree( ASSIGN, l, r ); + l->op = FREE; + ecomp( l->left ); + printf( " movab L%d,r0\n", i ); + /* turn off strftn flag, so return sequence will be generated */ + strftn = 0; + } + branch( retlab ); + printf( " .set .R%d,0x%x\n", ftnno, ent_mask[reg_use] ); + reg_use = 11; + p2bend(); + fdefflag = 0; + } + +bfcode( a, n ) int a[]; { + /* code for the beginning of a function; a is an array of + indices in stab for the arguments; n is the number */ + register i; + register temp; + register struct symtab *p; + int off; + char *toreg(); + + locctr( PROG ); + p = &stab[curftn]; + printf( " .align 1\n"); + defnam( p ); + temp = p->stype; + temp = DECREF(temp); + strftn = (temp==STRTY) || (temp==UNIONTY); + + retlab = getlab(); + + /* routine prolog */ + + printf( " .word .R%d\n", ftnno); + if (gdebug) { + pstab(NULLNAME, N_SLINE); + printf("0,%d,LL%d\n", lineno, labelno); + printf("LL%d:\n", labelno++); + } + printf( " subl2 $.F%d,sp\n", ftnno); + if( proflg ) { /* profile code */ + i = getlab(); + printf(" movab L%d,r0\n", i); + printf(" jsb mcount\n"); + printf(" .data\n"); + printf(" .align 2\n"); + printf("L%d: .long 0\n", i); + printf(" .text\n"); + psline(); + } + + off = ARGINIT; + + for( i=0; i<n; ++i ){ + p = &stab[a[i]]; + if( p->sclass == REGISTER ){ + temp = p->offset; /* save register number */ + p->sclass = PARAM; /* forget that it is a register */ + p->offset = NOOFFSET; + oalloc( p, &off ); +/*tbl*/ printf( " %s %d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp ); + p->offset = temp; /* remember register number */ + p->sclass = REGISTER; /* remember that it is a register */ + } + else { + if( oalloc( p, &off ) ) cerror( "bad argument" ); + } + + } + fdefflag = 1; + } + +bccode(){ /* called just before the first executable statment */ + /* by now, the automatics and register variables are allocated */ + SETOFF( autooff, SZINT ); + /* set aside store area offset */ + p2bbeg( autooff, regvar ); + reg_use = (reg_use > regvar ? regvar : reg_use); + } + +ejobcode( flag ){ + /* called just before final exit */ + /* flag is 1 if errors, 0 if none */ + } + +aobeg(){ + /* called before removing automatics from stab */ + } + +aocode(p) struct symtab *p; { + /* called when automatic p removed from stab */ + } + +aoend(){ + /* called after removing all automatics from stab */ + } + +defnam( p ) register struct symtab *p; { + /* define the current location as the name p->sname */ + + if( p->sclass == EXTDEF ){ + printf( " .globl %s\n", exname( p->sname ) ); + } + if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset ); + else printf( "%s:\n", exname( p->sname ) ); + + } + +bycode( t, i ){ + /* put byte i+1 in a string */ + + i &= 07; + if( t < 0 ){ /* end of the string */ + if( i != 0 ) printf( "\n" ); + } + + else { /* stash byte t into string */ + if( i == 0 ) printf( " .byte " ); + else printf( "," ); + printf( "0x%x", t ); + if( i == 07 ) printf( "\n" ); + } + } + +zecode( n ){ + /* n integer words of zeros */ + OFFSZ temp; + if( n <= 0 ) return; + printf( " .space %d\n", (SZINT/SZCHAR)*n ); + temp = n; + inoff += temp*SZINT; + } + +fldal( t ) unsigned t; { /* return the alignment of field of type t */ + uerror( "illegal field type" ); + return( ALINT ); + } + +fldty( p ) struct symtab *p; { /* fix up type of field p */ + ; + } + +where(c){ /* print location of error */ + /* c is either 'u', 'c', or 'w' */ + /* GCOS version */ + fprintf( stderr, "%s, line %d: ", ftitle, lineno ); + } + + +/* tbl - toreg() returns a pointer to a char string + which is the correct "register move" for the passed type + */ +struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] = + { + CHAR, "cvtbl", + SHORT, "cvtwl", + INT, "movl", + LONG, "movl", + FLOAT, "movf", + DOUBLE, "movd", + UCHAR, "movzbl", + USHORT, "movzwl", + UNSIGNED, "movl", + ULONG, "movl", + -1, "" + }; + +char +*toreg(type) + TWORD type; +{ + struct type_move *p; + + for ( p=toreg_strs; p->fromtype > 0; p++) + if (p->fromtype == type) return(p->tostrng); + + /* type not found, must be a pointer type */ + return("movl"); +} +/* tbl */ + + +main( argc, argv ) char *argv[]; { + return(mainp1( argc, argv )); + } + +struct sw heapsw[SWITSZ]; /* heap for switches */ + +genswitch(p,n) register struct sw *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 + */ + register i; + register CONSZ j, range; + register dlab, swlab; + + range = p[n].sval-p[1].sval; + + if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */ + + swlab = getlab(); + dlab = p->slab >= 0 ? p->slab : getlab(); + + /* already in r0 */ + printf(" casel r0,$%ld,$%ld\n", p[1].sval, range); + printf("L%d:\n", swlab); + for( i=1,j=p[1].sval; i<=n; j++) { + printf(" .word L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab), + swlab); + } + + if( p->slab >= 0 ) branch( dlab ); + else printf("L%d:\n", dlab); + return; + + } + + if( n>8 ) { /* heap switch */ + + heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab(); + makeheap(p, n, 1); /* build heap */ + + walkheap(1, n); /* produce code */ + + if( p->slab >= 0 ) + branch( dlab ); + else + printf("L%d:\n", dlab); + return; + } + + /* debugging code */ + + /* out for the moment + if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) ); + */ + + /* simple switch code */ + + for( i=1; i<=n; ++i ){ + /* already in r0 */ + + printf( " cmpl r0,$" ); + printf( CONFMT, p[i].sval ); + printf( "\n jeql L%d\n", p[i].slab ); + } + + if( p->slab>=0 ) branch( p->slab ); + } + +makeheap(p, m, n) +register struct sw *p; +{ + register int q; + + q = select(m); + heapsw[n] = p[q]; + if( q>1 ) makeheap(p, q-1, 2*n); + if( q<m ) makeheap(p+q, m-q, 2*n+1); +} + +select(m) { + register int l,i,k; + + for(i=1; ; i*=2) + if( (i-1) > m ) break; + l = ((k = i/2 - 1) + 1)/2; + return( l + (m-k < l ? m-k : l)); +} + +walkheap(start, limit) +{ + int label; + + + if( start > limit ) return; + printf(" cmpl r0,$%d\n", heapsw[start].sval); + printf(" jeql L%d\n", heapsw[start].slab); + if( (2*start) > limit ) { + printf(" jbr L%d\n", heapsw[0].slab); + return; + } + if( (2*start+1) <= limit ) { + label = getlab(); + printf(" jgtr L%d\n", label); + } else + printf(" jgtr L%d\n", heapsw[0].slab); + walkheap( 2*start, limit); + if( (2*start+1) <= limit ) { + printf("L%d:\n", label); + walkheap( 2*start+1, limit); + } +} diff --git a/usr.bin/pcc/arch/vax/local.c b/usr.bin/pcc/arch/vax/local.c new file mode 100644 index 00000000000..82bc670eb6b --- /dev/null +++ b/usr.bin/pcc/arch/vax/local.c @@ -0,0 +1,528 @@ +/* $Id: local.c,v 1.1 2007/09/15 18:12:30 otto Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +# include "mfile1" + +/* this file contains code which is dependent on the target machine */ + +NODE * +cast( p, t ) register NODE *p; TWORD t; { + /* cast node p to type t */ + + p = buildtree( CAST, block( NAME, NIL, NIL, t, 0, (int)t ), p ); + p->left->op = FREE; + p->op = FREE; + return( p->right ); + } + +NODE * +clocal(p) 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; + register o; + register m, ml; + + switch( o = p->op ){ + + case NAME: + if( p->rval < 0 ) { /* already processed; ignore... */ + return(p); + } + q = &stab[p->rval]; + switch( q->sclass ){ + + case AUTO: + case PARAM: + /* fake up a structure reference */ + r = block( REG, NIL, NIL, PTR+STRTY, 0, 0 ); + r->lval = 0; + r->rval = (q->sclass==AUTO?STKREG:ARGREG); + p = stref( block( STREF, r, p, 0, 0, 0 ) ); + break; + + case ULABEL: + case LABEL: + case STATIC: + if( q->slevel == 0 ) break; + p->lval = 0; + p->rval = -q->offset; + break; + + case REGISTER: + p->op = REG; + p->lval = 0; + p->rval = q->offset; + break; + + } + break; + + case PCONV: + /* do pointer conversions for char and longs */ + ml = p->left->type; + if( ( ml==CHAR || ml==UCHAR || ml==SHORT || ml==USHORT ) && p->left->op != ICON ) break; + + /* pointers all have the same representation; the type is inherited */ + + inherit: + p->left->type = p->type; + p->left->cdim = p->cdim; + p->left->csiz = p->csiz; + p->op = FREE; + return( p->left ); + + case SCONV: + m = (p->type == FLOAT || p->type == DOUBLE ); + ml = (p->left->type == FLOAT || p->left->type == DOUBLE ); + if( m != ml ) break; + + /* now, look for conversions downwards */ + + m = p->type; + ml = p->left->type; + if( p->left->op == ICON ){ /* simulate the conversion here */ + CONSZ val; + val = p->left->lval; + switch( m ){ + case CHAR: + p->left->lval = (char) val; + break; + case UCHAR: + p->left->lval = val & 0XFF; + break; + case USHORT: + p->left->lval = val & 0XFFFFL; + break; + case SHORT: + p->left->lval = (short)val; + break; + case UNSIGNED: + p->left->lval = val & 0xFFFFFFFFL; + break; + case INT: + p->left->lval = (int)val; + break; + } + p->left->type = m; + } + else { + /* meaningful ones are conversion of int to char, int to short, + and short to char, and unsigned version of them */ + if( m==CHAR || m==UCHAR ){ + if( ml!=CHAR && ml!= UCHAR ) break; + } + else if( m==SHORT || m==USHORT ){ + if( ml!=CHAR && ml!=UCHAR && ml!=SHORT && ml!=USHORT ) break; + } + } + + /* clobber conversion */ + if( tlen(p) == tlen(p->left) ) goto inherit; + p->op = FREE; + return( p->left ); /* conversion gets clobbered */ + + case PVCONV: + case PMCONV: + if( p->right->op != ICON ) cerror( "bad conversion", 0); + p->op = FREE; + return( buildtree( o==PMCONV?MUL:DIV, p->left, p->right ) ); + + case RS: + case ASG RS: + /* convert >> to << with negative shift count */ + /* only if type of left operand is not unsigned */ + if( ISUNSIGNED(p->left->type) ) break; + p->right = buildtree( UNARY MINUS, p->right, NIL ); + if( p->op == RS ) p->op = LS; + else p->op = ASG LS; + break; + + } + + return(p); + } + +andable( p ) NODE *p; { + return(1); /* all names can have & taken on them */ + } + +cendarg(){ /* at the end of the arguments of a ftn, set the automatic offset */ + autooff = AUTOINIT; + } + +cisreg( t ) TWORD t; { /* is an automatic variable of type t OK for a register variable */ + + if( t==INT || t==UNSIGNED || t==LONG || t==ULONG /* tbl */ + || t==CHAR || t==UCHAR || t==SHORT || t==USHORT /* tbl */ + || ISPTR(t)) return(1); /* tbl */ + return(0); + } + +NODE * +offcon( off, t, d, s ) OFFSZ off; TWORD t; { + + /* 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 */ + + register NODE *p; + + /* t, d, and s are the type, dimension offset, and sizeoffset */ + /* in general they are necessary for offcon, but not on H'well */ + + p = bcon(0); + p->lval = off/SZCHAR; + return(p); + + } + + +incode( p, sz ) register NODE *p; { + + /* generate initialization code for assigning a constant c + to a field of width sz */ + /* we assume that the proper alignment has been obtained */ + /* inoff is updated to have the proper final value */ + /* we also assume sz < SZINT */ + + inoff += sz; + if (sz>SZSHORT) + printf(" .long %d:%d\n", sz, p->lval); + else if (sz>SZCHAR) + printf(" .word %d:%d\n", sz, p->lval); + else + printf(" .byte %d:%d\n", sz, p->lval); + } + +fincode( d, sz ) double d; { + /* output code to initialize space of size sz to the value d */ + /* the proper alignment has been obtained */ + /* inoff is updated to have the proper final value */ + /* on the target machine, write it out in octal! */ + + + printf(" %s 0%c%.20e\n", sz == SZDOUBLE ? ".double" : ".float", + sz == SZDOUBLE ? 'd' : 'f', d); + inoff += sz; + } + +cinit( p, sz ) NODE *p; { + /* arrange for the initialization of p into a space of + size sz */ + /* the proper alignment has been opbtained */ + /* inoff is updated to have the proper final value */ + ecode( p ); + inoff += sz; + } + +vfdzero( n ){ /* define n bits of zeros in a vfd */ + register i; + + if( n <= 0 ) return; + + inoff += n; + i = n; + while (i>=SZCHAR) { + printf(" .byte 0\n"); + i -= SZCHAR; + } + if (i) printf(" .byte %d:0\n", i); + } + + +char * +exname( p ) char *p; { + /* make a name look like an external name in the local machine */ + + static char text[NCHNAM+1]; + + register i; + + text[0] = '_'; + for( i=1; *p&&i<NCHNAM; ++i ){ + text[i] = *p++; + } + + text[i] = '\0'; + text[NCHNAM] = '\0'; /* truncate */ + + return( text ); + } + +ctype( type ){ /* map types which are not defined on the local machine */ + switch( BTYPE(type) ){ + + case LONG: + MODTYPE(type,INT); + break; + + case ULONG: + MODTYPE(type,UNSIGNED); + } + return( type ); + } + +noinit( t ) { /* curid is a variable which is defined but + is not initialized (and not a function ); + This routine returns the stroage class for an uninitialized declaration */ + + return(EXTERN); + + } + +commdec( id ){ /* make a common declaration for id, if reasonable */ + register struct symtab *q; + OFFSZ off, tsize(); + + q = &stab[id]; + printf( " .comm %s,", exname( q->sname ) ); + off = tsize( q->stype, q->dimoff, q->sizoff ); + printf( CONFMT, off/SZCHAR ); + printf( "\n" ); + } + +isitlong( cb, ce ){ /* is lastcon to be long or short */ + /* cb is the first character of the representation, ce the last */ + + if( ce == 'l' || ce == 'L' || + lastcon >= (1L << (SZINT-1) ) ) return (1); + return(0); + } + + +isitfloat( s ) char *s; { + double atof(); + dcon = atof(s); + return( FCON ); + } + +ecode( p ) NODE *p; { + + /* walk the tree and write out the nodes.. */ + + if( nerrors ) return; + p2tree( p ); + p2compile( p ); + } + +#include "a.out.h" +int ddebug; +int gdebug; + + +outstab(p) +struct symtab *p; { + register TWORD ptype; + register char *pname; + register char pclass; + register int poffset; + + if (!gdebug) return; + + ptype = p->stype; + pname = p->sname; + pclass = p->sclass; + poffset = p->offset; + + if (ISFTN(ptype)) { + return; + } + + switch (pclass) { + + case AUTO: + pstab(pname, N_LSYM); + printf("0,%d,%d\n", ptype, (-poffset)/SZCHAR); + poffs(p); + return; + + case EXTDEF: + case EXTERN: + pstab(pname, N_GSYM); + printf("0,%d,0\n", ptype); + poffs(p); + return; + + case STATIC: + pstab(pname, N_STSYM); + if (p->slevel > 1) { + printf("0,%d,L%d\n", ptype, poffset); + } else { + printf("0,%d,%s\n", ptype, exname(pname)); + } + poffs(p); + return; + + case REGISTER: + pstab(pname, N_RSYM); + printf("0,%d,%d\n", ptype, poffset); + poffs(p); + return; + + case MOS: + case MOU: + pstab(pname, N_SSYM); + printf("0,%d,%d\n", ptype, poffset/SZCHAR); + poffs(p); + return; + + case PARAM: + /* parameter stab entries are processed in dclargs() */ + return; + + default: + if (ddebug) printf(" No .stab for %.8s\n", pname); + } +} + +pstab(name, type) +char *name; +int type; { + register int i; + register char c; + if (!gdebug) return; + printf(" .stab "); + for(i=0; i<8; i++) + if (c = name[i]) printf("'%c,", c); + else printf("0,"); + printf("0%o,", type); +} + +poffs(p) +register struct symtab *p; { + int s; + if (!gdebug) return; + if ((s = dimtab[p->sizoff]/SZCHAR) > 1) { + pstab(p->sname, N_LENG); + printf("1,0,%d\n", s); + } +} + +char NULLNAME[8]; +int labelno; +int fdefflag; + +psline() { + static int lastlineno; + register char *cp, *cq; + register int i; + + if (!gdebug) return; + + cq = ititle; + cp = ftitle; + + while ( *cq ) if ( *cp++ != *cq++ ) goto neq; + if ( *cp == '\0' ) goto eq; + +neq: for (i=0; i<100; i++) + ititle[i] = '\0'; + cp = ftitle; + cq = ititle; + while ( *cp ) + *cq++ = *cp++; + *cq = '\0'; + *--cq = '\0'; + for ( cp = ititle+1; *(cp-1); cp += 8 ) { + pstab(cp, N_SOL); + if (gdebug) printf("0,0,LL%d\n", labelno); + } + *cq = '"'; + printf("LL%d:\n", labelno++); + +eq: if (lineno == lastlineno) return; + lastlineno = lineno; + + if (fdefflag) { + pstab(NULLNAME, N_SLINE); + printf("0,%d,LL%d\n", lineno, labelno); + printf("LL%d:\n", labelno++); + } + } + +plcstab(level) { + if (!gdebug) return; + pstab(NULLNAME, N_LBRAC); + printf("0,%d,LL%d\n", level, labelno); + printf("LL%d:\n", labelno++); + } + +prcstab(level) { + if (!gdebug) return; + pstab(NULLNAME, N_RBRAC); + printf("0,%d,LL%d\n", level, labelno); + printf("LL%d:\n", labelno++); + } + +pfstab(sname) +char *sname; { + if (!gdebug) return; + pstab(sname, N_FUN); + printf("0,%d,_%.7s\n", lineno, sname); +} + +#ifndef ONEPASS +tlen(p) NODE *p; +{ + switch(p->type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(2); + + case DOUBLE: + return(8); + + default: + return(4); + } + } +#endif diff --git a/usr.bin/pcc/arch/vax/local2.c b/usr.bin/pcc/arch/vax/local2.c new file mode 100644 index 00000000000..0aa8e2b0e9e --- /dev/null +++ b/usr.bin/pcc/arch/vax/local2.c @@ -0,0 +1,923 @@ +/* $Id: local2.c,v 1.1 2007/09/15 18:12:30 otto Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +# include "mfile2" +# include "ctype.h" +/* a lot of the machine dependent parts of the second pass */ + +# define BITMASK(n) ((1L<<n)-1) + +where(c){ + fprintf( stderr, "%s, line %d: ", filename, lineno ); + } + +lineid( l, fn ) char *fn; { + /* identify line l and file fn */ + printf( "# line %d, file %s\n", l, fn ); + } + +eobl2(){ + OFFSZ spoff; /* offset from stack pointer */ + + spoff = maxoff; + if( spoff >= AUTOINIT ) spoff -= AUTOINIT; + spoff /= SZCHAR; + SETOFF(spoff,4); + printf( " .set .F%d,%Ld\n", ftnno, spoff ); + maxargs = -1; + } + +struct hoptab { int opmask; char * opstring; } ioptab[] = { + + ASG PLUS, "add", + ASG MINUS, "sub", + ASG MUL, "mul", + ASG DIV, "div", + ASG OR, "bis", + ASG ER, "xor", + ASG AND, "bic", + PLUS, "add", + MINUS, "sub", + MUL, "mul", + DIV, "div", + OR, "bis", + ER, "xor", + AND, "bic", + -1, "" }; + +hopcode( f, o ){ + /* output the appropriate string from the above table */ + + register struct hoptab *q; + + for( q = ioptab; q->opmask>=0; ++q ){ + if( q->opmask == o ){ + printf( "%s", q->opstring ); +/* tbl + if( f == 'F' ) printf( "e" ); + else if( f == 'D' ) printf( "d" ); + tbl */ +/* tbl */ + switch( f ) { + case 'L': + case 'W': + case 'B': + case 'D': + case 'F': + printf("%c", tolower(f)); + break; + + } +/* tbl */ + return; + } + } + cerror( "no hoptab for %s", opst[o] ); + } + +char * +rnames[] = { /* keyed to register number tokens */ + + "r0", "r1", + "r2", "r3", "r4", "r5", + "r6", "r7", "r8", "r9", "r10", "r11", + "ap", "fp", "sp", "pc", + + }; + +int rstatus[] = { + SAREG|STAREG, SAREG|STAREG, + SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, + SAREG, SAREG, SAREG, SAREG, SAREG, SAREG, + SAREG, SAREG, SAREG, SAREG, + + }; + +tlen(p) NODE *p; +{ + switch(p->type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(2); + + case DOUBLE: + return(8); + + default: + return(4); + } +} + +mixtypes(p, q) NODE *p, *q; +{ + register tp, tq; + + tp = p->type; + tq = q->type; + + return( (tp==FLOAT || tp==DOUBLE) != + (tq==FLOAT || tq==DOUBLE) ); +} + +prtype(n) NODE *n; +{ + switch (n->type) + { + case DOUBLE: + printf("d"); + return; + + case FLOAT: + printf("f"); + return; + + case LONG: + case ULONG: + case INT: + case UNSIGNED: + printf("l"); + return; + + case SHORT: + case USHORT: + printf("w"); + return; + + case CHAR: + case UCHAR: + printf("b"); + return; + + default: + if ( !ISPTR( n->type ) ) cerror("zzzcode- bad type"); + else { + printf("l"); + return; + } + } +} + +zzzcode( p, c ) register NODE *p; { + register m; + CONSZ val; + switch( c ){ + + case 'N': /* logical ops, turned into 0-1 */ + /* use register given by register 1 */ + cbgen( 0, m=getlab(), 'I' ); + deflab( p->label ); + printf( " clrl %s\n", rnames[getlr( p, '1' )->rval] ); + deflab( m ); + return; + + case 'I': + case 'P': + cbgen( p->op, p->label, c ); + return; + + case 'A': + { + register NODE *l, *r; + + if (xdebug) eprint(p, 0, &val, &val); + r = getlr(p, 'R'); + if (optype(p->op) == LTYPE || p->op == UNARY MUL) + { + l = resc; + l->type = (r->type==FLOAT || r->type==DOUBLE ? DOUBLE : INT); + } + else + l = getlr(p, 'L'); + if (r->op == ICON && r->name[0] == '\0') + { + if (r->lval == 0) + { + printf("clr"); + prtype(l); + printf(" "); + adrput(l); + return; + } + if (r->lval < 0 && r->lval >= -63) + { + printf("mneg"); + prtype(l); + r->lval = -r->lval; + goto ops; + } + r->type = (r->lval < 0 ? + (r->lval >= -128 ? CHAR + : (r->lval >= -32768 ? SHORT + : INT )) : r->type); + r->type = (r->lval >= 0 ? + (r->lval <= 63 ? INT + : ( r->lval <= 127 ? CHAR + : (r->lval <= 255 ? UCHAR + : (r->lval <= 32767 ? SHORT + : (r->lval <= 65535 ? USHORT + : INT ))))) : r->type ); + } + if (l->op == REG && l->type != FLOAT && l->type != DOUBLE) + l->type = INT; + if (!mixtypes(l,r)) + { + if (tlen(l) == tlen(r)) + { + printf("mov"); + prtype(l); + goto ops; + } + else if (tlen(l) > tlen(r) && ISUNSIGNED(r->type)) + { + printf("movz"); + } + else + { + printf("cvt"); + } + } + else + { + printf("cvt"); + } + prtype(r); + prtype(l); + ops: + printf(" "); + adrput(r); + printf(","); + adrput(l); + return; + } + + case 'C': /* num words pushed on arg stack */ + { + extern int gc_numbytes; + extern int xdebug; + + if (xdebug) printf("->%d<-",gc_numbytes); + + printf("$%d", gc_numbytes/(SZLONG/SZCHAR) ); + return; + } + + case 'D': /* INCR and DECR */ + zzzcode(p->left, 'A'); + printf("\n "); + + case 'E': /* INCR and DECR, FOREFF */ + if (p->right->lval == 1) + { + printf("%s", (p->op == INCR ? "inc" : "dec") ); + prtype(p->left); + printf(" "); + adrput(p->left); + return; + } + printf("%s", (p->op == INCR ? "add" : "sub") ); + prtype(p->left); + printf("2 "); + adrput(p->right); + printf(","); + adrput(p->left); + return; + + case 'F': /* register type of right operand */ + { + register NODE *n; + extern int xdebug; + register int ty; + + n = getlr( p, 'R' ); + ty = n->type; + + if (xdebug) printf("->%d<-", ty); + + if ( ty==DOUBLE) printf("d"); + else if ( ty==FLOAT ) printf("f"); + else printf("l"); + return; + } + + case 'L': /* type of left operand */ + case 'R': /* type of right operand */ + { + register NODE *n; + extern int xdebug; + + n = getlr ( p, c); + if (xdebug) printf("->%d<-", n->type); + + prtype(n); + return; + } + + case 'Z': /* complement mask for bit instr */ + printf("$%Ld", ~p->right->lval); + return; + + case 'U': /* 32 - n, for unsigned right shifts */ + printf("$%d", 32 - p->right->lval ); + return; + + case 'T': /* rounded structure length for arguments */ + { + int size; + + size = p->stsize; + SETOFF( size, 4); + printf("$%d", size); + return; + } + + case 'S': /* structure assignment */ + { + register NODE *l, *r; + register size; + + if( p->op == STASG ){ + l = p->left; + r = p->right; + + } + else if( p->op == STARG ){ /* store an arg into a temporary */ + l = getlr( p, '3' ); + r = p->left; + } + else cerror( "STASG bad" ); + + if( r->op == ICON ) r->op = NAME; + else if( r->op == REG ) r->op = OREG; + else if( r->op != OREG ) cerror( "STASG-r" ); + + size = p->stsize; + + if( size <= 0 || size > 65535 ) + cerror("structure size <0=0 or >65535"); + + switch(size) { + case 1: + printf(" movb "); + break; + case 2: + printf(" movw "); + break; + case 4: + printf(" movl "); + break; + case 8: + printf(" movq "); + break; + default: + printf(" movc3 $%d,", size); + break; + } + adrput(r); + printf(","); + adrput(l); + printf("\n"); + + if( r->op == NAME ) r->op = ICON; + else if( r->op == OREG ) r->op = REG; + + } + break; + + default: + cerror( "illegal zzzcode" ); + } + } + +rmove( rt, rs, t ){ + printf( " %s %s,%s\n", + (t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")), + rnames[rs], rnames[rt] ); + } + +struct respref +respref[] = { + INTAREG|INTBREG, INTAREG|INTBREG, + INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON, + INTEMP, INTEMP, + FORARG, FORARG, + INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM, + 0, 0 }; + +setregs(){ /* set up temporary registers */ + fregs = 6; /* tbl- 6 free regs on VAX (0-5) */ + ; + } + +szty(t){ /* size, in registers, needed to hold thing of type t */ + return( (t==DOUBLE||t==FLOAT) ? 2 : 1 ); + } + +rewfld( p ) NODE *p; { + return(1); + } + +callreg(p) NODE *p; { + return( R0 ); + } + +base( p ) register NODE *p; { + register int o = p->op; + + if( (o==ICON && p->name[0] != '\0')) return( 100 ); /* ie no base reg */ + if( o==REG ) return( p->rval ); + if( (o==PLUS || o==MINUS) && p->left->op == REG && p->right->op==ICON) + return( p->left->rval ); + if( o==OREG && !R2TEST(p->rval) && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) ) + return( p->rval + 0200*1 ); + if( o==INCR && p->left->op==REG ) return( p->left->rval + 0200*2 ); + if( o==ASG MINUS && p->left->op==REG) return( p->left->rval + 0200*4 ); + if( o==UNARY MUL && p->left->op==INCR && p->left->left->op==REG + && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) ) + return( p->left->left->rval + 0200*(1+2) ); + return( -1 ); + } + +offset( p, tyl ) register NODE *p; int tyl; { + + if( tyl==1 && p->op==REG && (p->type==INT || p->type==UNSIGNED) ) return( p->rval ); + if( (p->op==LS && p->left->op==REG && (p->left->type==INT || p->left->type==UNSIGNED) && + (p->right->op==ICON && p->right->name[0]=='\0') + && (1<<p->right->lval)==tyl)) + return( p->left->rval ); + return( -1 ); + } + +makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { + register NODE *t; + register int i; + NODE *f; + + p->op = OREG; + f = p->left; /* have to free this subtree later */ + + /* init base */ + switch (q->op) { + case ICON: + case REG: + case OREG: + t = q; + break; + + case MINUS: + q->right->lval = -q->right->lval; + case PLUS: + t = q->right; + break; + + case INCR: + case ASG MINUS: + t = q->left; + break; + + case UNARY MUL: + t = q->left->left; + break; + + default: + cerror("illegal makeor2"); + } + + p->lval = t->lval; + for(i=0; i<NCHNAM; ++i) + p->name[i] = t->name[i]; + + /* init offset */ + p->rval = R2PACK( (b & 0177), o, (b>>7) ); + + tfree(f); + return; + } + +canaddr( p ) NODE *p; { + register int o = p->op; + + if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->left)) ) return(1); + return(0); + } + +shltype( o, p ) register NODE *p; { + return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->left)) ); + } + +flshape( p ) register NODE *p; { + return( p->op == REG || p->op == NAME || p->op == ICON || + (p->op == OREG && (!R2TEST(p->rval) || tlen(p) == 1)) ); + } + +shtemp( p ) register NODE *p; { + if( p->op == STARG ) p = p->left; + return( p->op==NAME || p->op ==ICON || p->op == OREG || (p->op==UNARY MUL && shumul(p->left)) ); + } + +shumul( p ) register NODE *p; { + register o; + extern int xdebug; + + if (xdebug) { + printf("\nshumul:op=%d,lop=%d,rop=%d", p->op, p->left->op, p->right->op); + printf(" prname=%s,plty=%d, prlval=%D\n", p->right->name, p->left->type, p->right->lval); + } + + + o = p->op; + if( o == NAME || (o == OREG && !R2TEST(p->rval)) || o == ICON ) return( STARNM ); + + if( ( o == INCR || o == ASG MINUS ) && + ( p->left->op == REG && p->right->op == ICON ) && + p->right->name[0] == '\0' ) + { + switch (p->left->type) + { + case CHAR|PTR: + case UCHAR|PTR: + o = 1; + break; + + case SHORT|PTR: + case USHORT|PTR: + o = 2; + break; + + case INT|PTR: + case UNSIGNED|PTR: + case LONG|PTR: + case ULONG|PTR: + case FLOAT|PTR: + o = 4; + break; + + case DOUBLE|PTR: + o = 8; + break; + + default: + if ( ISPTR(p->left->type) ) { + o = 4; + break; + } + else return(0); + } + return( p->right->lval == o ? STARREG : 0); + } + + return( 0 ); + } + +adrcon( val ) CONSZ val; { + printf( "$" ); + printf( CONFMT, val ); + } + +conput( p ) register NODE *p; { + switch( p->op ){ + + case ICON: + acon( p ); + return; + + case REG: + printf( "%s", rnames[p->rval] ); + return; + + default: + cerror( "illegal conput" ); + } + } + +insput( p ) register NODE *p; { + cerror( "insput" ); + } + +upput( p ) register NODE *p; { + cerror( "upput" ); + } + +adrput( p ) register NODE *p; { + register int r; + /* output an address, with offsets, from p */ + + if( p->op == FLD ){ + p = p->left; + } + switch( p->op ){ + + case NAME: + acon( p ); + return; + + case ICON: + /* addressable value of the constant */ + printf( "$" ); + acon( p ); + return; + + case REG: + printf( "%s", rnames[p->rval] ); + return; + + case OREG: + r = p->rval; + if( R2TEST(r) ){ /* double indexing */ + register int flags; + + flags = R2UPK3(r); + if( flags & 1 ) printf("*"); + if( flags & 4 ) printf("-"); + if( p->lval != 0 || p->name[0] != '\0' ) acon(p); + if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] ); + if( flags & 2 ) printf("+"); + printf( "[%s]", rnames[R2UPK2(r)] ); + return; + } + if( r == AP ){ /* in the argument region */ + if( p->lval <= 0 || p->name[0] != '\0' ) werror( "bad arg temp" ); + printf( CONFMT, p->lval ); + printf( "(ap)" ); + return; + } + if( p->lval != 0 || p->name[0] != '\0') acon( p ); + printf( "(%s)", rnames[p->rval] ); + return; + + case UNARY MUL: + /* STARNM or STARREG found */ + if( tshape(p, STARNM) ) { + printf( "*" ); + adrput( p->left); + } + else { /* STARREG - really auto inc or dec */ + register NODE *q; + +/* tbl + p = p->left; + p->left->op = OREG; + if( p->op == INCR ) { + adrput( p->left ); + printf( "+" ); + } + else { + printf( "-" ); + adrput( p->left ); + } + tbl */ + printf("%c(%s)%c", (p->left->op==INCR ? '\0' : '-'), + rnames[p->left->left->rval], + (p->left->op==INCR ? '+' : '\0') ); + p->op = OREG; + p->rval = p->left->left->rval; + q = p->left; + p->lval = (p->left->op == INCR ? -p->left->right->lval : 0); + p->name[0] = '\0'; + tfree(q); + } + return; + + default: + cerror( "illegal address" ); + return; + + } + + } + +acon( p ) register NODE *p; { /* print out a constant */ + + if( p->name[0] == '\0' ){ + printf( CONFMT, p->lval); + } + else if( p->lval == 0 ) { + printf( "%.8s", p->name ); + } + else { + printf( "%.8s+", p->name ); + printf( CONFMT, p->lval ); + } + } + +/* +aacon( p ) register NODE *p; { /* print out a constant */ +/* + + if( p->name[0] == '\0' ){ + printf( CONFMT, p->lval); + return( 0 ); + } + else if( p->lval == 0 ) { + printf( "$%.8s", p->name ); + return( 1 ); + } + else { + printf( "$(" ); + printf( CONFMT, p->lval ); + printf( "+" ); + printf( "%.8s)", p->name ); + return(1); + } + } + */ + +genscall( p, cookie ) register NODE *p; { + /* structure valued call */ + return( gencall( p, cookie ) ); + } + +/* tbl */ +int gc_numbytes; +/* tbl */ + +gencall( p, cookie ) register NODE *p; { + /* generate the call given by p */ + register NODE *p1, *ptemp; + register temp, temp1; + register m; + + if( p->right ) temp = argsize( p->right ); + else temp = 0; + + if( p->op == STCALL || p->op == UNARY STCALL ){ + /* set aside room for structure return */ + + if( p->stsize > temp ) temp1 = p->stsize; + else temp1 = temp; + } + + if( temp > maxargs ) maxargs = temp; + SETOFF(temp1,4); + + if( p->right ){ /* make temp node, put offset in, and generate args */ + ptemp = talloc(); + ptemp->op = OREG; + ptemp->lval = -1; + ptemp->rval = SP; + ptemp->name[0] = '\0'; + ptemp->rall = NOPREF; + ptemp->su = 0; + genargs( p->right, ptemp ); + ptemp->op = FREE; + } + + p1 = p->left; + if( p1->op != ICON ){ + if( p1->op != REG ){ + if( p1->op != OREG || R2TEST(p1->rval) ){ + if( p1->op != NAME ){ + order( p1, INAREG ); + } + } + } + } + +/* + if( p1->op == REG && p->rval == R5 ){ + cerror( "call register overwrite" ); + } + */ +/* tbl + setup gc_numbytes so reference to ZC works */ + + gc_numbytes = temp; +/* tbl */ + + p->op = UNARY CALL; + m = match( p, INTAREG|INTBREG ); +/* tbl + switch( temp ) { + case 0: + break; + case 2: + printf( " tst (sp)+\n" ); + break; + case 4: + printf( " cmp (sp)+,(sp)+\n" ); + break; + default: + printf( " add $%d,sp\n", temp); + } + tbl */ + return(m != MDONE); + } + +/* tbl */ +char * +ccbranches[] = { + " jeql L%d\n", + " jneq L%d\n", + " jleq L%d\n", + " jlss L%d\n", + " jgeq L%d\n", + " jgtr L%d\n", + " jlequ L%d\n", + " jlssu L%d\n", + " jgequ L%d\n", + " jgtru L%d\n", + }; +/* tbl */ + +cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */ + +/* tbl */ + if( o == 0 ) printf( " jbr L%d\n", lab ); +/* tbl */ + else { + if( o > UGT ) cerror( "bad conditional branch: %s", opst[o] ); + printf( ccbranches[o-EQ], lab ); + } + } + +nextcook( p, cookie ) NODE *p; { + /* we have failed to match p with cookie; try another */ + if( cookie == FORREW ) return( 0 ); /* hopeless! */ + if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG ); + if( !(cookie&INTEMP) && asgop(p->op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG ); + return( FORREW ); + } + +lastchance( p, cook ) NODE *p; { + /* forget it! */ + return(0); + } + +optim2( p ) register NODE *p; { + /* do local tree transformations and optimizations */ + + register NODE *r; + + switch( p->op ) { + + case AND: + /* commute L and R to eliminate compliments and constants */ + if( (p->left->op==ICON&&p->left->name[0]==0) || p->left->op==COMPL ) { + r = p->left; + p->left = p->right; + p->right = r; + } + case ASG AND: + /* change meaning of AND to ~R&L - bic on pdp11 */ + r = p->right; + if( r->op==ICON && r->name[0]==0 ) { /* compliment constant */ + r->lval = ~r->lval; + } + else if( r->op==COMPL ) { /* ~~A => A */ + r->op = FREE; + p->right = r->left; + } + else { /* insert complement node */ + p->right = talloc(); + p->right->op = COMPL; + p->right->rall = NOPREF; + p->right->type = r->type; + p->right->left = r; + p->right->right = NULL; + } + break; + + } + } + + +# ifndef ONEPASS +main( argc, argv ) char *argv[]; { + return( mainp2( argc, argv ) ); + } +# endif diff --git a/usr.bin/pcc/arch/vax/macdefs.h b/usr.bin/pcc/arch/vax/macdefs.h new file mode 100644 index 00000000000..095e55ad910 --- /dev/null +++ b/usr.bin/pcc/arch/vax/macdefs.h @@ -0,0 +1,155 @@ +/* $Id: macdefs.h,v 1.1 2007/09/15 18:12:30 otto Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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. + */ + +# define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); + +# define ARGINIT 32 +# define AUTOINIT 0 +# define SZCHAR 8 +# define SZINT 32 +# define SZFLOAT 32 +# define SZDOUBLE 64 +# define SZLONG 32 +# define SZSHORT 16 +# define SZPOINT 32 +# define ALCHAR 8 +# define ALINT 32 +# define ALFLOAT 32 +# define ALDOUBLE 32 +# define ALLONG 32 +# define ALSHORT 16 +# define ALPOINT 32 +# define ALSTRUCT 8 +# define ALSTACK 32 + +/* size in which constants are converted */ +/* should be long if feasable */ + +# define CONSZ long +# define CONFMT "%Ld" + +/* size in which offsets are kept +/* should be large enough to cover address space in bits +*/ + +# define OFFSZ long + +/* character set macro */ + +# define CCTRANS(x) x + +/* register cookie for stack poINTer */ + +# define STKREG 13 +# define ARGREG 12 + +/* maximum and minimum register variables */ + +# define MAXRVAR 11 +# define MINRVAR 6 + + /* various standard pieces of code are used */ +# define STDPRTREE +# define LABFMT "L%d" + +/* show stack grows negatively */ +#define BACKAUTO +#define BACKTEMP + +/* show field hardware support on VAX */ +#define FIELDOPS + +/* bytes are numbered from right to left */ +#define RTOLBYTES + +/* we want prtree included */ +# define STDPRTREE +# ifndef FORT +# define ONEPASS +#endif + +# define ENUMSIZE(high,low) INT + +/* VAX-11/780 Registers */ + + /* scratch registers */ +# define R0 0 +# define R1 1 +# define R2 2 +# define R3 3 +# define R4 4 +# define R5 5 + + /* register variables */ +# define R6 6 +# define R7 7 +# define R8 8 +# define R9 9 +# define R10 10 +# define R11 11 + + /* special purpose */ +# define AP 12 /* argument pointer */ +# define FP 13 /* frame pointer */ +# define SP 14 /* stack pointer */ +# define PC 15 /* program counter */ + + /* floating registers */ + + /* there are no floating point registers on the VAX */ + +extern int fregs; +extern int maxargs; + +# define BYTEOFF(x) ((x)&03) +# define wdal(k) (BYTEOFF(k)==0) +# define BITOOR(x) ((x)>>3) /* bit offset to oreg offset */ + +# define REGSZ 16 + +# define TMPREG FP + +# define R2REGS /* permit double indexing */ + +# define STOARG(p) /* just evaluate the arguments, and be done with it... */ +# define STOFARG(p) +# define STOSTARG(p) +# define genfcall(a,b) gencall(a,b) + +# define NESTCALL + +# define MYREADER(p) walkf(p, optim2) +int optim2(); +# define special(a, b) 0 diff --git a/usr.bin/pcc/arch/vax/order.c b/usr.bin/pcc/arch/vax/order.c new file mode 100644 index 00000000000..b1f1006adcd --- /dev/null +++ b/usr.bin/pcc/arch/vax/order.c @@ -0,0 +1,533 @@ +/* $Id: order.c,v 1.1 2007/09/15 18:12:30 otto Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +# include "mfile2" + +int maxargs = { -1 }; + +stoasg( p, o ) register NODE *p; { + /* should the assignment op p be stored, + given that it lies as the right operand of o + (or the left, if o==UNARY MUL) */ +/* + if( p->op == INCR || p->op == DECR ) return; + if( o==UNARY MUL && p->left->op == REG && !isbreg(p->left->rval) ) SETSTO(p,INAREG); + */ + } + +deltest( p ) register NODE *p; { + /* should we delay the INCR or DECR operation p */ + p = p->left; + return( p->op == REG || p->op == NAME || p->op == OREG ); + } + +autoincr( p ) NODE *p; { + register NODE *q = p->left, *r; + + if( q->op == INCR && (r=q->left)->op == REG && + ISPTR(q->type) && p->type == DECREF(q->type) && + tlen(p) == q->right->lval ) return(1); + + return(0); + } + +mkadrs(p) register NODE *p; { + register o; + + o = p->op; + + if( asgop(o) ){ + if( p->left->su >= p->right->su ){ + if( p->left->op == UNARY MUL ){ + SETSTO( p->left->left, INTEMP ); + } + else if( p->left->op == FLD && p->left->left->op == UNARY MUL ){ + SETSTO( p->left->left->left, INTEMP ); + } + else { /* should be only structure assignment */ + SETSTO( p->left, INTEMP ); + } + } + else SETSTO( p->right, INTEMP ); + } + else { + if( p->left->su > p->right->su ){ + SETSTO( p->left, INTEMP ); + } + else { + SETSTO( p->right, INTEMP ); + } + } + } + +notoff( t, r, off, cp) CONSZ off; char *cp; { + /* 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 */ + +/* if( r == R0 ) return( 1 ); /* NO */ + return(0); /* YES */ + } + +# define max(x,y) ((x)<(y)?(y):(x)) + +sucomp( p ) register NODE *p; { + + /* set the su field in the node to the sethi-ullman + number, or local equivalent */ + + register o, ty, sul, sur, r; + + o = p->op; + ty = optype( o ); + p->su = szty( p->type ); /* 2 for float or double, else 1 */; + + if( ty == LTYPE ){ + if( o == OREG ){ + r = p->rval; + /* oreg cost is (worst case) 1 + number of temp registers used */ + if( R2TEST(r) ){ + if( R2UPK1(r)!=100 && istreg(R2UPK1(r)) ) ++p->su; + if( istreg(R2UPK2(r)) ) ++p->su; + } + else { + if( istreg( r ) ) ++p->su; + } + } + if( p->su == szty(p->type) && + (p->op!=REG || !istreg(p->rval)) && + (p->type==INT || p->type==UNSIGNED || p->type==DOUBLE) ) + p->su = 0; + return; + } + + else if( ty == UTYPE ){ + switch( o ) { + case UNARY CALL: + case UNARY STCALL: + p->su = fregs; /* all regs needed */ + return; + + default: + p->su = p->left->su + (szty( p->type ) > 1 ? 2 : 0) ; + return; + } + } + + + /* If rhs needs n, lhs needs m, regular su computation */ + + sul = p->left->su; + sur = p->right->su; + + if( o == ASSIGN ){ + /* computed by doing right, then left (if not in mem), then doing it */ + p->su = max(sur,sul+1); + return; + } + + if( o == CALL || o == STCALL ){ + /* in effect, takes all free registers */ + p->su = fregs; + return; + } + + if( o == STASG ){ + /* right, then left */ + p->su = max( max( 1+sul, sur), fregs ); + return; + } + + if( asgop(o) ){ + /* computed by doing right, doing left address, doing left, op, and store */ + p->su = max(sur,sul+2); +/* + if( o==ASG MUL || o==ASG DIV || o==ASG MOD) p->su = max(p->su,fregs); + */ + return; + } + + switch( o ){ + case ANDAND: + case OROR: + case QUEST: + case COLON: + case COMOP: + p->su = max( max(sul,sur), 1); + return; + + case PLUS: + case OR: + case ER: + /* commutative ops; put harder on left */ + if( p->right->su > p->left->su && !istnode(p->left) ){ + register NODE *temp; + temp = p->left; + p->left = p->right; + p->right = temp; + } + break; + } + + /* binary op, computed by left, then right, then do op */ + p->su = max(sul,szty(p->right->type)+sur); +/* + if( o==MUL||o==DIV||o==MOD) p->su = max(p->su,fregs); + */ + + } + +int radebug = 0; + +rallo( p, down ) NODE *p; { + /* do register allocation */ + register o, type, down1, down2, ty; + + if( radebug ) printf( "rallo( %o, %d )\n", p, down ); + + down2 = NOPREF; + p->rall = down; + down1 = ( down &= ~MUSTDO ); + + ty = optype( o = p->op ); + type = p->type; + + + if( type == DOUBLE || type == FLOAT ){ + if( o == FORCE ) down1 = R0|MUSTDO; + } + else switch( o ) { + case ASSIGN: + down1 = NOPREF; + down2 = down; + break; + +/* + case MUL: + case DIV: + case MOD: + down1 = R3|MUSTDO; + down2 = R5|MUSTDO; + break; + + case ASG MUL: + case ASG DIV: + case ASG MOD: + p->left->rall = down1 = R3|MUSTDO; + if( p->left->op == UNARY MUL ){ + rallo( p->left->left, R4|MUSTDO ); + } + else if( p->left->op == FLD && p->left->left->op == UNARY MUL ){ + rallo( p->left->left->left, R4|MUSTDO ); + } + else rallo( p->left, R3|MUSTDO ); + rallo( p->right, R5|MUSTDO ); + return; + */ + + case CALL: + case STASG: + case EQ: + case NE: + case GT: + case GE: + case LT: + case LE: + case NOT: + case ANDAND: + case OROR: + down1 = NOPREF; + break; + + case FORCE: + down1 = R0|MUSTDO; + break; + + } + + if( ty != LTYPE ) rallo( p->left, down1 ); + if( ty == BITYPE ) rallo( p->right, down2 ); + + } + +offstar( p ) register NODE *p; { + if( p->op == PLUS ) { + if( p->left->su == fregs ) { + order( p->left, INTAREG|INAREG ); + return; + } else if( p->right->su == fregs ) { + order( p->right, INTAREG|INAREG ); + return; + } + if( p->left->op==LS && + (p->left->left->op!=REG || tlen(p->left->left)!=sizeof(int) ) ) { + order( p->left->left, INTAREG|INAREG ); + return; + } + if( p->right->op==LS && + (p->right->left->op!=REG || tlen(p->right->left)!=sizeof(int) ) ) { + order( p->right->left, INTAREG|INAREG ); + return; + } + if( p->type == (PTR|CHAR) || p->type == (PTR|UCHAR) ) { + if( p->left->op!=REG || tlen(p->left)!=sizeof(int) ) { + order( p->left, INTAREG|INAREG ); + return; + } + else if( p->right->op!=REG || tlen(p->right)!=sizeof(int) ) { + order(p->right, INTAREG|INAREG); + return; + } + } + } + if( p->op == PLUS || p->op == MINUS ){ + if( p->right->op == ICON ){ + p = p->left; + order( p , INTAREG|INAREG); + return; + } + } + + if( p->op == UNARY MUL && !canaddr(p) ) { + offstar( p->left ); + return; + } + + order( p, INTAREG|INAREG ); + } + +setincr( p ) NODE *p; { + return( 0 ); /* for the moment, don't bother */ + } + +setbin( p ) register NODE *p; { + register ro, rt; + + rt = p->right->type; + ro = p->right->op; + + if( canaddr( p->left ) && !canaddr( p->right ) ) { /* address rhs */ + if( ro == UNARY MUL ) { + offstar( p->right->left ); + return(1); + } else { + order( p->right, INAREG|INTAREG|SOREG ); + return(1); + } + } + if( !istnode( p->left) ) { /* try putting LHS into a reg */ +/* order( p->left, logop(p->op)?(INAREG|INBREG|INTAREG|INTBREG|SOREG):(INTAREG|INTBREG|SOREG) );*/ + order( p->left, INAREG|INTAREG|INBREG|INTBREG|SOREG ); + return(1); + } + else if( ro == UNARY MUL && rt != CHAR && rt != UCHAR ){ + offstar( p->right->left ); + return(1); + } + else if( rt == CHAR || rt == UCHAR || rt == SHORT || rt == USHORT || (ro != REG && + ro != NAME && ro != OREG && ro != ICON ) ){ + order( p->right, INAREG|INBREG ); + return(1); + } +/* + else if( logop(p->op) && rt==USHORT ){ /* must get rhs into register */ +/* + order( p->right, INAREG ); + return( 1 ); + } + */ + return(0); + } + +setstr( p ) register NODE *p; { /* structure assignment */ + if( p->right->op != REG ){ + order( p->right, INTAREG ); + return(1); + } + p = p->left; + if( p->op != NAME && p->op != OREG ){ + if( p->op != UNARY MUL ) cerror( "bad setstr" ); + order( p->left, INTAREG ); + return( 1 ); + } + return( 0 ); + } + +setasg( p ) register NODE *p; { + /* setup for assignment operator */ + + if( !canaddr(p->right) ) { + if( p->right->op == UNARY MUL ) + offstar(p->right->left); + else + order( p->right, INAREG|INBREG|SOREG ); + return(1); + } + if( p->left->op == UNARY MUL ) { + offstar( p->left->left ); + return(1); + } + if( p->left->op == FLD && p->left->left->op == UNARY MUL ){ + offstar( p->left->left->left ); + return(1); + } +/* FLD patch */ + if( p->left->op == FLD && !(p->right->type==INT || p->right->type==UNSIGNED)) { + order( p->right, INAREG); + return(1); + } +/* end of FLD patch */ + return(0); + } + +setasop( p ) register NODE *p; { + /* setup for =ops */ + register rt, ro; + + rt = p->right->type; + ro = p->right->op; + + if( ro == UNARY MUL && rt != CHAR ){ + offstar( p->right->left ); + return(1); + } + if( ( rt == CHAR || rt == SHORT || rt == UCHAR || rt == USHORT || + ( ro != REG && ro != ICON && ro != NAME && ro != OREG ) ) ){ + order( p->right, INAREG|INBREG ); + return(1); + } +/* + if( (p->op == ASG LS || p->op == ASG RS) && ro != ICON && ro != REG ){ + order( p->right, INAREG ); + return(1); + } + */ + + + p = p->left; + if( p->op == FLD ) p = p->left; + + switch( p->op ){ + + case REG: + case ICON: + case NAME: + case OREG: + return(0); + + case UNARY MUL: + if( p->left->op==OREG ) + return(0); + else + offstar( p->left ); + return(1); + + } + cerror( "illegal setasop" ); + } + +int crslab = 9999; /* Honeywell */ + +getlab(){ + return( crslab-- ); + } + +deflab( l ){ + printf( "L%d:\n", l ); + } + +genargs( p, ptemp ) register NODE *p, *ptemp; { + register NODE *pasg; + register align; + register size; + register TWORD type; + + /* generate code for the arguments */ + + /* first, do the arguments on the right */ + while( p->op == CM ){ + genargs( p->right, ptemp ); + p->op = FREE; + p = p->left; + } + + if( p->op == STARG ){ /* structure valued argument */ + + size = p->stsize; + align = p->stalign; + + /* ptemp->lval = (ptemp->lval/align)*align; /* SETOFF for negative numbers */ + ptemp->lval = 0; /* all moves to (sp) */ + + p->op = STASG; + p->right = p->left; + p->left = tcopy( ptemp ); + + /* the following line is done only with the knowledge + that it will be undone by the STASG node, with the + offset (lval) field retained */ + + if( p->right->op == OREG ) p->right->op = REG; /* only for temporaries */ + + order( p, FORARG ); + ptemp->lval += size; + return; + } + + /* ordinary case */ + + order( p, FORARG ); + } + +argsize( p ) register NODE *p; { + register t; + t = 0; + if( p->op == CM ){ + t = argsize( p->left ); + p = p->right; + } + if( p->type == DOUBLE || p->type == FLOAT ){ + SETOFF( t, 4 ); + return( t+8 ); + } + else if( p->op == STARG ){ + SETOFF( t, 4 ); /* alignment */ + return( t + ((p->stsize+3)/4)*4 ); /* size */ + } + else { + SETOFF( t, 4 ); + return( t+4 ); + } + } diff --git a/usr.bin/pcc/arch/vax/table.c b/usr.bin/pcc/arch/vax/table.c new file mode 100644 index 00000000000..12d8de17e10 --- /dev/null +++ b/usr.bin/pcc/arch/vax/table.c @@ -0,0 +1,652 @@ +/* $Id: table.c,v 1.1 2007/09/15 18:12:30 otto Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +# include "mfile2" + +# define WPTR TPTRTO|TINT|TLONG|TFLOAT|TDOUBLE|TPOINT|TUNSIGNED|TULONG +# define AWD SNAME|SOREG|SCON|STARNM|STARREG +/* tbl */ +# define ANYSIGNED TPOINT|TINT|TLONG|TSHORT|TCHAR +# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR +# define ANYFIXED ANYSIGNED|ANYUSIGNED +# define TWORD TINT|TUNSIGNED|TPOINT|TLONG|TULONG +/* tbl */ + +struct optab table[] = { + +PCONV, INAREG|INTAREG, + SAREG|AWD, TCHAR|TSHORT, + SANY, TPOINT, + NAREG|NASL, RESC1, + " cvtZLl AL,A1\n", + +PCONV, INAREG|INTAREG, + SAREG|AWD, TUCHAR|TUSHORT, + SANY, TPOINT, + NAREG|NASL, RESC1, + " movzZLl AL,A1\n", + +SCONV, INTAREG|FORCC, + SAREG, TDOUBLE, + SANY, TDOUBLE, + 0, RLEFT, + "", + +SCONV, INTAREG|FORCC, + SAREG|AWD, TANY, + SANY, TFLOAT|TDOUBLE, + NAREG|NASL, RESC1|RESCC, + " cvtZLd AL,A1\n", + +SCONV, INTAREG|FORCC, + SAREG|AWD, TFLOAT|TDOUBLE, + SANY, ANYFIXED, + NAREG|NASL, RESC1|RESCC, + " cvtZLZF AL,A1\n", + +SCONV, INTAREG|FORCC, + SAREG|SNAME|SCON|STARNM, TANY, + SANY, ANYUSIGNED, + NAREG|NASL, RESC1|RESCC, + " movzZRl AL,A1\n", + +SCONV, INTAREG|FORCC, + SSOREG, TANY, + SANY, ANYUSIGNED, + NAREG|NASL, RESC1|RESCC, + " movzZRl AL,A1\n", + +SCONV, INTAREG|FORCC, + SAREG|SNAME|SCON|STARNM, TANY, + SANY, TANY, + NAREG|NASL, RESC1|RESCC, + " cvtZRl AL,A1\n", + +SCONV, INTAREG|FORCC, + SSOREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1|RESCC, + " cvtZRl AL,A1\n", + + +INIT, FOREFF, + SCON, TANY, + SANY, TWORD, + 0, RNOP, + " .long CL\n", + +INIT, FOREFF, + SCON, TANY, + SANY, TSHORT|TUSHORT, + 0, RNOP, + " .word CL\n", + +INIT, FOREFF, + SCON, TANY, + SANY, TCHAR|TUCHAR, + 0, RNOP, + " .byte CL\n", + + /* for the use of fortran only */ + +GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " jbr CL\n", + +GOTO, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, RNOP, + " jmp (AL)\n", + +STARG, INTEMP, + SCON|SAREG, TANY, + SANY, TANY, + NTEMP+2*NAREG, RESC3, + "ZS", + +STASG, FORARG, + SNAME|SOREG, TANY, + SCON|SAREG, TANY, + 0, RNULL, + " subl2 ZT,sp\nZS", + +STASG, FOREFF, + SNAME|SOREG, TANY, + SCON|SAREG, TANY, + 0, RNOP, + "ZS", + +STASG, INAREG, + SNAME|SOREG, TANY, + SCON, TANY, + NAREG, RESC1, + "ZS movl AR,A1\n", + +STASG, INAREG, + SNAME|SOREG, TANY, + SAREG, TANY, + 0, RRIGHT, + " pushl AR\nZS movl (sp)+,AR\n", + +FLD, INAREG|INTAREG, + SANY, TANY, + SFLD, ANYSIGNED, + NAREG|NASR, RESC1, + " extv H,S,AR,A1\n", + +FLD, INAREG|INTAREG, + SANY, TANY, + SFLD, ANYUSIGNED, + NAREG|NASR, RESC1, + " extzv H,S,AR,A1\n", + +FLD, FORARG, + SANY, TANY, + SFLD, ANYSIGNED, + 0, RNULL, + " extv H,S,AR,-(sp)\n", + +FLD, FORARG, + SANY, TANY, + SFLD, ANYUSIGNED, + 0, RNULL, + " extzv H,S,AR,-(sp)\n", + +OPLOG, FORCC, + SAREG|AWD, TWORD, + SAREG|AWD, TWORD, + 0, RESCC, + " cmpl AL,AR\nZP", + +OPLOG, FORCC, + SAREG|AWD, TSHORT|TUSHORT, + SAREG|AWD, TSHORT|TUSHORT, + 0, RESCC, + " cmpw AL,AR\nZP", + +OPLOG, FORCC, + SAREG|AWD, TCHAR|TUCHAR, + SAREG|AWD, TCHAR|TUCHAR, + 0, RESCC, + " cmpb AL,AR\nZP", + +OPLOG, FORCC, + SAREG|AWD, TSHORT|TUSHORT, + SSCON, TANY, + 0, RESCC, + " cmpw AL,AR\nZP", + +OPLOG, FORCC, + SAREG|AWD, TCHAR|TUCHAR, + SCCON, TANY, + 0, RESCC, + " cmpb AL,AR\nZP", + +OPLOG, FORCC, + SAREG|AWD, TDOUBLE, + SAREG|AWD, TDOUBLE, + 0, RESCC, + " cmpd AL,AR\nZP", + +OPLOG, FORCC, + SAREG|AWD, TFLOAT|TDOUBLE, + SAREG|AWD, TFLOAT|TDOUBLE, + 0, RESCC, + " cmpf AL,AR\nZP", + +CCODES, INAREG|INTAREG, + SANY, TANY, + SANY, TANY, + NAREG, RESC1, + " movl $1,A1\nZN", + +UNARY CALL, INTAREG, + SCON, TANY, + SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE, + NAREG|NASL, RESC1, /* should be register 0 */ + " calls ZC,CL\n", + +UNARY CALL, INTAREG, + SAREG, TANY, + SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE, + NAREG|NASL, RESC1, /* should be 0 */ + " calls ZC,(AL)\n", + +UNARY CALL, INAREG|INTAREG, + SNAME, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* really reg 0 */ + " calls ZC,*AL\n", + +UNARY CALL, INAREG|INTAREG, + SSOREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* really reg 0 */ + " calls ZC,*AL\n", + +ASG RS, INAREG|FOREFF|FORCC, + SAREG, TWORD, + SCON, TINT, + 0, RLEFT|RESCC, + " extzv AR,ZU,AL,AL\n", + +ASG RS, INAREG|FOREFF|FORCC, + SAREG, TWORD, + SAREG, ANYFIXED, + NAREG, RLEFT|RESCC, + " subl3 AR,$32,A1\n extzv AR,A1,AL,AL\n", + +ASG RS, INAREG|FOREFF|FORCC, + SAREG, TWORD, + SAREG|AWD, TWORD, + NAREG, RLEFT|RESCC, + " subl3 AR,$32,A1\n extzv AR,A1,AL,AL\n", + +RS, INAREG|INTAREG|FORCC, + SAREG, TWORD, + SCON, TINT, + NAREG|NASL, RESC1|RESCC, + " extzv AR,ZU,AL,A1\n", + +ASG LS, INAREG|FOREFF|FORCC, + SAREG|AWD, TWORD, + SAREG|AWD, ANYSIGNED|ANYUSIGNED, + 0, RLEFT|RESCC, + " ashl AR,AL,AL\n", + +LS, INAREG|INTAREG|FORCC, + SAREG|AWD, TWORD, + SAREG|AWD, ANYSIGNED|ANYUSIGNED, + NAREG|NASL|NASR, RESC1|RESCC, + " ashl AR,AL,A1\n", + +INCR, FOREFF, + SAREG|AWD, TANY, + SANY, TANY, + 0, RLEFT, + " ZE\n", + +DECR, FOREFF, + SAREG|AWD, TANY, + SCON, TANY, + 0, RLEFT, + " ZE\n", + +INCR, INAREG|INTAREG, + SAREG|AWD, TANY, + SCON, TANY, + NAREG, RESC1, + " ZD\n", + +DECR, INAREG|INTAREG, + SAREG|AWD, TANY, + SCON, TANY, + NAREG, RESC1, + " ZD\n", + +ASSIGN, INAREG|FOREFF|FORCC, + SAREG|AWD, TANY, + SAREG|AWD, TANY, + 0, RLEFT|RRIGHT|RESCC, + " ZA\n", + +ASSIGN, INAREG|FOREFF|FORCC, + SFLD, TANY, + SAREG|AWD, TWORD, + 0, RRIGHT|RESCC, + " insv AR,H,S,AL\n", + +ASSIGN, INAREG|FOREFF|FORCC, + SAREG|AWD, TWORD, + SFLD, ANYSIGNED, + 0, RLEFT|RESCC, + " extv H,S,AR,AL\n", + +ASSIGN, INAREG|FOREFF|FORCC, + SAREG|AWD, TWORD, + SFLD, ANYUSIGNED, + 0, RLEFT|RESCC, + " extzv H,S,AR,AL\n", + +/* dummy UNARY MUL entry to get U* to possibly match OPLTYPE */ +UNARY MUL, FOREFF, + SCC, TANY, + SCC, TANY, + 0, RNULL, + " HELP HELP HELP\n", + +REG, FORARG, + SANY, TANY, + SAREG, TDOUBLE|TFLOAT, + 0, RNULL, + " movZR AR,-(sp)\n", + +REG, INTEMP, + SANY, TANY, + SAREG, TDOUBLE, + 2*NTEMP, RESC1, + " movd AR,A1\n", + +REG, INTEMP, + SANY, TANY, + SAREG, TANY, + NTEMP, RESC1, + " movZF AR,A1\n", + +OPLEAF, FOREFF, + SANY, TANY, + SAREG|AWD, TANY, + 0, RLEFT, + "", + +OPLTYPE, INAREG|INTAREG, + SANY, TANY, + SANY, TFLOAT|TDOUBLE, + 2*NAREG|NASR, RESC1, + " ZA\n", + +OPLTYPE, INAREG|INTAREG, + SANY, TANY, + SANY, TANY, + NAREG|NASR, RESC1, + " ZA\n", + +OPLTYPE, FORCC, + SANY, TANY, + SANY, TANY, + 0, RESCC, + " tstZR AR\n", + +OPLTYPE, FORARG, + SANY, TANY, + SANY, TWORD, + 0, RNULL, + " pushl AR\n", + +OPLTYPE, FORARG, + SANY, TANY, + SANY, TCHAR|TSHORT, + 0, RNULL, + " cvtZRl AR,-(sp)\n", + +OPLTYPE, FORARG, + SANY, TANY, + SANY, TUCHAR|TUSHORT, + 0, RNULL, + " movzZRl AR,-(sp)\n", + +OPLTYPE, FORARG, + SANY, TANY, + SANY, TDOUBLE, + 0, RNULL, + " movd AR,-(sp)\n", + +OPLTYPE, FORARG, + SANY, TANY, + SANY, TFLOAT, + 0, RNULL, + " cvtfd AR,-(sp)\n", + +UNARY MINUS, INTAREG|FORCC, + SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG|TDOUBLE, + SANY, TANY, + NAREG|NASL, RESC1|RESCC, + " mnegZL AL,A1\n", + +COMPL, INTAREG|FORCC, + SAREG|AWD, TINT|TUNSIGNED, + SANY, TANY, + NAREG|NASL, RESC1|RESCC, + " mcomZL AL,A1\n", + +COMPL, INTAREG|FORCC, + SAREG|AWD, ANYSIGNED|ANYUSIGNED, + SANY, TANY, + NAREG|NASL, RESC1|RESCC, + " cvtZLl AL,A1\n mcoml A1,A1\n", + +AND, FORCC, + SAREG|AWD, TWORD, + SCON, TWORD, + 0, RESCC, + " bitl ZZ,AL\n", + +AND, FORCC, + SAREG|AWD, TSHORT|TUSHORT, + SSCON, TWORD, + 0, RESCC, + " bitw ZZ,AL\n", + +AND, FORCC, + SAREG|AWD, TCHAR|TUCHAR, + SCCON, TWORD, + 0, RESCC, + " bitb ZZ,AL\n", + +ASG AND, INAREG|FOREFF|FORCC, + SAREG, ANYFIXED, + SCON, TWORD, + 0, RLEFT|RESCC, + " bicl2 AR,AL\n", + +ASG OPMUL, INAREG|FOREFF|FORCC, + SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, + SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, + 0, RLEFT|RESCC, + " OL2 AR,AL\n", + +OPMUL, INAREG|INTAREG|FORCC, + STAREG, TINT|TUNSIGNED|TLONG|TULONG, + SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, + 0, RLEFT|RESCC, + " OL2 AR,AL\n", + +OPMUL, INAREG|INTAREG|FORCC, + SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, + SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, + NAREG|NASL|NASR, RESC1|RESCC, + " OL3 AR,AL,A1\n", + +ASG MOD, INAREG|INTAREG|FOREFF|FORCC, + SAREG, TINT|TUNSIGNED|TLONG|TULONG, + SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, + NAREG, RLEFT|RESCC, + " divl3 AR,AL,A1\n mull2 AR,A1\n subl2 A1,AL\n", + +MOD, INAREG|INTAREG, + SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, + SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, + NAREG, RESC1, + " divl3 AR,AL,A1\n mull2 AR,A1\n subl3 A1,AL,A1\n", + +ASG PLUS, INAREG|FOREFF|FORCC, + SAREG|AWD, ANYSIGNED|ANYUSIGNED, + SONE, TINT|TLONG, + 0, RLEFT|RESCC, + " incZL AL\n", + +ASG MINUS, INAREG|FOREFF|FORCC, + SAREG|AWD, ANYSIGNED|ANYUSIGNED, + SONE, TINT|TLONG, + 0, RLEFT|RESCC, + " decZL AL\n", + +PLUS, INAREG|INTAREG|FORCC, + STAREG, ANYFIXED, + SONE, TWORD, + 0, RLEFT|RESCC, + " incZL AL\n", + +MINUS, INAREG|INTAREG|FORCC, + STAREG, ANYFIXED, + SONE, TWORD, + 0, RLEFT|RESCC, + " decZL AL\n", + +ASG OPSIMP, INAREG|FOREFF|FORCC, + SAREG|AWD, TWORD, + SAREG|AWD, TWORD, + 0, RLEFT|RESCC, + " OL2 AR,AL\n", + +ASG OPSIMP, INAREG|FOREFF|FORCC, + AWD, TSHORT|TUSHORT, + SAREG|AWD, TSHORT|TUSHORT, + 0, RLEFT|RESCC, + " OW2 AR,AL\n", + +ASG OPSIMP, INAREG|FOREFF|FORCC, + AWD, TSHORT|TUSHORT, + SSCON, TWORD, + 0, RLEFT|RESCC, + " OW2 AR,AL\n", + +ASG OPSIMP, INAREG|FOREFF|FORCC, + AWD, TCHAR|TUCHAR, + SAREG|AWD, TCHAR|TUCHAR, + 0, RLEFT|RESCC, + " OB2 AR,AL\n", + +ASG OPSIMP, INAREG|FOREFF|FORCC, + AWD, TCHAR|TUCHAR, + SCCON, TWORD, + 0, RLEFT|RESCC, + " OB2 AR,AL\n", + +OPSIMP, INAREG|INTAREG|FORCC, + STAREG, ANYFIXED, + SAREG|AWD, TWORD, + 0, RLEFT|RESCC, + " OL2 AR,AL\n", + +OPSIMP, INAREG|INTAREG|FORCC, + SAREG|AWD, TWORD, + SAREG|AWD, TWORD, + NAREG|NASL|NASR, RESC1|RESCC, + " OL3 AR,AL,A1\n", + +ASG OPFLOAT, INAREG|FOREFF|FORCC, + SAREG|AWD, TDOUBLE, + SAREG|AWD, TDOUBLE, + 0, RLEFT|RESCC, + " OD2 AR,AL\n", + +ASG OPFLOAT, INAREG|FOREFF|FORCC, + SAREG|AWD, TFLOAT, + SAREG|AWD, TFLOAT, + 0, RLEFT|RESCC, + " OF2 AR,AL\n", + +ASG OPFLOAT, INAREG|FOREFF|FORCC, + SAREG|AWD, TDOUBLE, + SAREG|AWD, TFLOAT, + NAREG|NASR, RLEFT|RESCC, + " cvtfd AR,A1\n OD2 A1,AL\n", + +ASG OPFLOAT, INAREG|INTAREG|FOREFF|FORCC, + SAREG|AWD, TFLOAT, + SAREG|AWD, TDOUBLE, + NAREG, RLEFT|RESC1|RESCC, + " cvtfd AL,A1\n OD2 AR,A1\n cvtdf A1,AL\n", + +OPFLOAT, INAREG|INTAREG|FORCC, + STAREG, TDOUBLE, + SAREG|AWD, TDOUBLE, + 0, RLEFT|RESCC, + " OD2 AR,AL\n", + +OPFLOAT, INAREG|INTAREG|FORCC, + SAREG|AWD, TDOUBLE, + SAREG|AWD, TDOUBLE, + NAREG|NASL|NASR, RESC1|RESCC, + " OD3 AR,AL,A1\n", + +OPFLOAT, INAREG|INTAREG|FORCC, + SAREG|AWD, TFLOAT, + SAREG|AWD, TDOUBLE, + NAREG|NASL, RESC1|RESCC, + " cvtfd AL,A1\n OD2 AR,A1\n", + +OPFLOAT, INAREG|INTAREG|FORCC, + SAREG|AWD, TDOUBLE, + SAREG|AWD, TFLOAT, + NAREG|NASR, RESC1|RESCC, + " cvtfd AR,A1\n OD3 A1,AL,A1\n", + +OPFLOAT, INAREG|INTAREG|FORCC, + SAREG|AWD, TFLOAT, + SAREG|AWD, TFLOAT, + NAREG|NASL|NASR, RESC1|RESCC, + " OF3 AR,AL,A1\n cvtfd A1,A1\n", + + /* Default actions for hard trees ... */ + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +UNARY MUL, DF( UNARY MUL ), + +INCR, DF(INCR), + +DECR, DF(INCR), + +ASSIGN, DF(ASSIGN), + +STASG, DF(STASG), + +OPLEAF, DF(NAME), + +OPLOG, FORCC, + SANY, TANY, + SANY, TANY, + REWRITE, BITYPE, + "", + +OPLOG, DF(NOT), + +COMOP, DF(COMOP), + +INIT, DF(INIT), + +OPUNARY, DF(UNARY MINUS), + + +ASG OPANY, DF(ASG PLUS), + +OPANY, DF(BITYPE), + +FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }; diff --git a/usr.bin/pcc/arch/x86/code.c b/usr.bin/pcc/arch/x86/code.c new file mode 100644 index 00000000000..dad9c3b57aa --- /dev/null +++ b/usr.bin/pcc/arch/x86/code.c @@ -0,0 +1,213 @@ +/* $Id: code.c,v 1.1 2007/09/15 18:12:30 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass1.h" + +/* + * cause the alignment to become a multiple of n + * never called for text segment. + */ +void +defalign(int n) +{ + n /= SZCHAR; + if (n == 1) + return; + printf(" .align %d\n", n); +} + +/* + * define the current location as the name p->sname + * never called for text segment. + */ +void +defnam(struct symtab *p) +{ + char *c = p->sname; + +#ifdef GCC_COMPAT + c = gcc_findname(p); +#endif + if (p->sclass == EXTDEF) + printf(" .globl %s\n", 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; + /* address of return struct is in eax */ + /* create a call to memcpy() */ + /* will get the result in eax */ + p = block(REG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR)); + p->n_rval = EAX; + q = block(OREG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR)); + q->n_rval = EBP; + q->n_lval = 8; /* return buffer offset */ + p = block(CM, q, p, INT, 0, MKSUE(INT)); + sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR; + p = block(CM, p, bcon(sz), INT, 0, MKSUE(INT)); + p->n_right->n_name = ""; + p = block(CALL, bcon(0), p, CHAR+PTR, 0, MKSUE(CHAR+PTR)); + p->n_left->n_name = "memcpy"; + p = clocal(p); + send_passt(IP_NODE, p); +} + +/* + * 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; + + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; + /* Function returns struct, adjust arg offset */ + for (i = 0; i < n; i++) + a[i]->soffset += SZPOINT(INT); +} + + +/* + * 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(int num, struct swents **p, int n) +{ + NODE *r; + int i; + + /* simple switch code */ + for (i = 1; i <= n; ++i) { + /* already in 1 */ + r = tempnode(num, INT, 0, MKSUE(INT)); + r = buildtree(NE, r, bcon(p[i]->sval)); + cbranch(buildtree(NOT, r, NIL), bcon(p[i]->slab)); + } + if (p[0]->slab > 0) + branch(p[0]->slab); +} diff --git a/usr.bin/pcc/arch/x86/local.c b/usr.bin/pcc/arch/x86/local.c new file mode 100644 index 00000000000..88b622d4317 --- /dev/null +++ b/usr.bin/pcc/arch/x86/local.c @@ -0,0 +1,743 @@ +/* $Id: local.c,v 1.1 2007/09/15 18:12:30 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "pass1.h" + +/* this file contains code which is dependent on the target machine */ + +/* clocal() is called to do local transformations on + * an expression tree preparitory to its being + * written out in intermediate code. + * + * the major essential job is rewriting the + * automatic variables and arguments in terms of + * REG and OREG nodes + * conversion ops which are not necessary are also clobbered here + * in addition, any special features (such as rewriting + * exclusive or) are easily handled here as well + */ +NODE * +clocal(NODE *p) +{ + + register struct symtab *q; + register NODE *r, *l; + register int o; + register int m; + TWORD t; + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + 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 STCALL: + case CALL: + /* Fix function call arguments. On x86, just add funarg */ + for (r = p->n_right; r->n_op == CM; r = r->n_left) { + if (r->n_right->n_op != STARG && + r->n_right->n_op != FUNARG) + r->n_right = block(FUNARG, r->n_right, NIL, + r->n_right->n_type, r->n_right->n_df, + r->n_right->n_sue); + } + if (r->n_op != STARG && r->n_op != FUNARG) { + l = talloc(); + *l = *r; + r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type; + } + break; + + case CBRANCH: + l = p->n_left; + + /* + * Remove unneccessary conversion ops. + */ + if (clogop(l->n_op) && l->n_left->n_op == SCONV) { + if (coptype(l->n_op) != BITYPE) + break; + if (l->n_right->n_op == ICON) { + r = l->n_left->n_left; + if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) + break; + /* Type must be correct */ + t = r->n_type; + nfree(l->n_left); + l->n_left = r; + l->n_type = t; + l->n_right->n_type = t; + } + } + break; + + case PCONV: + /* Remove redundant PCONV's. Be careful */ + l = p->n_left; + if (l->n_op == ICON) { + l->n_lval = (unsigned)l->n_lval; + goto delp; + } + if (l->n_type < INT || l->n_type == LONGLONG || + l->n_type == ULONGLONG) { + /* float etc? */ + p->n_left = block(SCONV, l, NIL, + UNSIGNED, 0, MKSUE(UNSIGNED)); + break; + } + /* if left is SCONV, cannot remove */ + if (l->n_op == SCONV) + break; + + /* avoid ADDROF TEMP */ + if (l->n_op == ADDROF && l->n_left->n_op == TEMP) + break; + + /* if conversion to another pointer type, just remove */ + if (p->n_type > BTMASK && l->n_type > BTMASK) + goto delp; + break; + + delp: l->n_type = p->n_type; + l->n_qual = p->n_qual; + l->n_df = p->n_df; + l->n_sue = p->n_sue; + nfree(p); + p = l; + break; + + case SCONV: + l = p->n_left; + + if (p->n_type == l->n_type) { + nfree(p); + return l; + } + + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + btdims[p->n_type].suesize == btdims[l->n_type].suesize) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE && + l->n_type != LDOUBLE && p->n_type != LDOUBLE) { + if (l->n_op == NAME || l->n_op == UMUL || + l->n_op == TEMP) { + l->n_type = p->n_type; + nfree(p); + return l; + } + } + } + + if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && + coptype(l->n_op) == BITYPE) { + l->n_type = p->n_type; + nfree(p); + return l; + } + + o = l->n_op; + m = p->n_type; + + if (o == ICON) { + CONSZ val = l->n_lval; + + if (!ISPTR(m)) /* Pointers don't need to be conv'd */ + switch (m) { + case BOOL: + l->n_lval = l->n_lval != 0; + break; + case CHAR: + l->n_lval = (char)val; + break; + case UCHAR: + l->n_lval = val & 0377; + break; + case SHORT: + l->n_lval = (short)val; + break; + case USHORT: + l->n_lval = val & 0177777; + break; + case ULONG: + case UNSIGNED: + l->n_lval = val & 0xffffffff; + break; + case ENUMTY: + case MOETY: + case LONG: + case INT: + l->n_lval = (int)val; + break; + case LONGLONG: + l->n_lval = (long long)val; + break; + case ULONGLONG: + l->n_lval = val; + break; + case VOID: + break; + case LDOUBLE: + case DOUBLE: + case FLOAT: + l->n_op = FCON; + l->n_dcon = val; + break; + default: + cerror("unknown type %d", m); + } + l->n_type = m; + l->n_sue = MKSUE(m); + nfree(p); + return l; + } + if (DEUNSIGN(p->n_type) == SHORT && + DEUNSIGN(l->n_type) == SHORT) { + nfree(p); + p = l; + } + if ((p->n_type == CHAR || p->n_type == UCHAR || + p->n_type == SHORT || p->n_type == USHORT) && + (l->n_type == FLOAT || l->n_type == DOUBLE || + l->n_type == LDOUBLE)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue); + p->n_left->n_type = INT; + return p; + } + break; + + case MOD: + 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 = p->n_left->n_type == BOOL ? + RETREG(CHAR) : RETREG(p->n_type); + break; + + case LS: + case RS: + /* shift count must be in a char + * unless longlong, where it must be int */ + if (p->n_right->n_op == ICON) + break; /* do not do anything */ + if (p->n_type == LONGLONG || p->n_type == ULONGLONG) { + if (p->n_right->n_type != INT) + p->n_right = block(SCONV, p->n_right, NIL, + INT, 0, MKSUE(INT)); + break; + } + if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR) + break; + p->n_right = block(SCONV, p->n_right, NIL, + CHAR, 0, MKSUE(CHAR)); + break; + } +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal end: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + return(p); +} + +void +myp2tree(NODE *p) +{ +} + +/*ARGSUSED*/ +int +andable(NODE *p) +{ + return(1); /* all names can have & taken on them */ +} + +/* + * at the end of the arguments of a ftn, set the automatic offset + */ +void +cendarg() +{ + autooff = AUTOINIT; +} + +/* + * Return 1 if a variable of type type is OK to put in register. + */ +int +cisreg(TWORD t) +{ + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) + return 0; /* not yet */ + return 1; +} + +/* + * return a node, for structure references, which is suitable for + * being added to a pointer of type t, in order to be off bits offset + * into a structure + * t, d, and s are the type, dimension offset, and sizeoffset + * For pdp10, return the type-specific index number which calculation + * is based on its size. For example, short a[3] would return 3. + * Be careful about only handling first-level pointers, the following + * indirections must be fullword. + */ +NODE * +offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue) +{ + register NODE *p; + + 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 storeable node where to write + * the allocated address. + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + + p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ + + /* sub the size from sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT)); + sp->n_lval = 0; + sp->n_rval = STKREG; + ecomp(buildtree(MINUSEQ, sp, p)); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue); + sp->n_lval = 0; + sp->n_rval = STKREG; + t->n_type = sp->n_type; + ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ + +} + +#if 0 +/* + * Print out an integer constant of size size. + * can only be sizes <= SZINT. + */ +void +indata(CONSZ val, int size) +{ + switch (size) { + case SZCHAR: + printf("\t.byte %d\n", (int)val & 0xff); + break; + case SZSHORT: + printf("\t.word %d\n", (int)val & 0xffff); + break; + case SZINT: + printf("\t.long %d\n", (int)val & 0xffffffff); + break; + default: + cerror("indata"); + } +} +#endif + +/* + * Print out a string of characters. + * Assume that the assembler understands C-style escape + * sequences. Location is already set. + */ +void +instring(char *str) +{ + char *s; + + /* be kind to assemblers and avoid long strings */ + printf("\t.ascii \""); + for (s = str; *s != 0; ) { + if (*s++ == '\\') { + (void)esccon(&s); + } + if (s - str > 64) { + fwrite(str, 1, s - str, stdout); + printf("\"\n\t.ascii \""); + str = s; + } + } + fwrite(str, 1, s - str, stdout); + printf("\\0\"\n"); +} + +static int inbits, inval; + +/* + * set fsz bits in sequence to zero. + */ +void +zbits(OFFSZ off, int fsz) +{ + int m; + + if (idebug) + printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits); + if ((m = (inbits % SZCHAR))) { + m = SZCHAR - m; + if (fsz < m) { + inbits += fsz; + return; + } else { + fsz -= m; + printf("\t.byte %d\n", inval); + inval = inbits = 0; + } + } + if (fsz >= SZCHAR) { + printf("\t.zero %d\n", fsz/SZCHAR); + fsz -= (fsz/SZCHAR) * SZCHAR; + } + if (fsz) { + inval = 0; + inbits = fsz; + } +} + +/* + * Initialize a bitfield. + */ +void +infld(CONSZ off, int fsz, CONSZ val) +{ + if (idebug) + printf("infld off %lld, fsz %d, val %lld inbits %d\n", + off, fsz, val, inbits); + val &= (1 << fsz)-1; + while (fsz + inbits >= SZCHAR) { + inval |= (val << inbits); + printf("\t.byte %d\n", inval & 255); + fsz -= (SZCHAR - inbits); + val >>= (SZCHAR - inbits); + inval = inbits = 0; + } + if (fsz) { + inval |= (val << inbits); + inbits += fsz; + } +} + +/* + * print out a constant node, may be associated with a label. + * Do not free the node after use. + * off is bit offset from the beginning of the aggregate + * fsz is the number of bits this is referring to + */ +void +ninval(CONSZ off, int fsz, NODE *p) +{ + union { float f; double d; long double l; int i[3]; } u; + struct symtab *q; + TWORD t; + int i; + + t = p->n_type; + if (t > BTMASK) + t = INT; /* pointer */ + + if (p->n_op != ICON && p->n_op != FCON) + cerror("ninval: init node not constant"); + + if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) + uerror("element not constant"); + + switch (t) { + case LONGLONG: + case ULONGLONG: + i = (p->n_lval >> 32); + p->n_lval &= 0xffffffff; + p->n_type = INT; + ninval(off, 32, p); + p->n_lval = i; + ninval(off+32, 32, p); + break; + case INT: + case UNSIGNED: + printf("\t.long 0x%x", (int)p->n_lval); + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0) || + q->sclass == ILABEL) { + printf("+" LABFMT, q->soffset); + } else + printf("+%s", exname(q->sname)); + } + printf("\n"); + break; + case SHORT: + case USHORT: + printf("\t.short 0x%x\n", (int)p->n_lval & 0xffff); + break; + case BOOL: + if (p->n_lval > 1) + p->n_lval = p->n_lval != 0; + /* FALLTHROUGH */ + case CHAR: + case UCHAR: + printf("\t.byte %d\n", (int)p->n_lval & 0xff); + break; + case LDOUBLE: + u.i[2] = 0; + u.l = (long double)p->n_dcon; + printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]); + break; + case DOUBLE: + u.d = (double)p->n_dcon; + printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]); + break; + case FLOAT: + u.f = (float)p->n_dcon; + printf("\t.long\t0x%x\n", u.i[0]); + break; + default: + cerror("ninval"); + } +} + +#if 0 +/* + * print out an integer. + */ +void +inval(CONSZ word) +{ + word &= 0xffffffff; + printf(" .long 0x%llx\n", word); +} + +/* output code to initialize a floating point value */ +/* the proper alignment has been obtained */ +void +finval(NODE *p) +{ + union { float f; double d; long double l; int i[3]; } u; + + switch (p->n_type) { + case LDOUBLE: + u.i[2] = 0; + u.l = (long double)p->n_dcon; + printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]); + break; + case DOUBLE: + u.d = (double)p->n_dcon; + printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]); + break; + case FLOAT: + u.f = (float)p->n_dcon; + printf("\t.long\t0x%x\n", u.i[0]); + break; + } +} +#endif + +/* make a name look like an external name in the local machine */ +char * +exname(char *p) +{ + 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); +} + +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]); +} + +#if 0 +int +ftoint(NODE *p, CONSZ **c) +{ + static CONSZ cc[3]; + union { float f; double d; long double l; int i[3]; } u; + int n; + + switch (p->n_type) { + case LDOUBLE: + u.i[2] = 0; + u.l = (long double)p->n_dcon; + n = SZLDOUBLE; + break; + case DOUBLE: + u.d = (double)p->n_dcon; + n = SZDOUBLE; + break; + case FLOAT: + u.f = (float)p->n_dcon; + n = SZFLOAT; + break; + } + cc[0] = u.i[0]; + cc[1] = u.i[1]; + cc[2] = u.i[2]; + *c = cc; + return n; +} +#endif diff --git a/usr.bin/pcc/arch/x86/local2.c b/usr.bin/pcc/arch/x86/local2.c new file mode 100644 index 00000000000..ec3c521a3db --- /dev/null +++ b/usr.bin/pcc/arch/x86/local2.c @@ -0,0 +1,1051 @@ +/* $Id: local2.c,v 1.1 2007/09/15 18:12:31 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass2.h" +# include <ctype.h> +# include <string.h> + +void acon(NODE *p); +int argsize(NODE *p); + +static int stkpos; + +void +lineid(int l, char *fn) +{ + /* identify line l and file fn */ + printf("# line %d, file %s\n", l, fn); +} + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +static int regoff[7]; +static TWORD ftype; + +/* + * Print out the prolog assembler. + * addto and regoff are already calculated. + */ +static void +prtprolog(struct interpass_prolog *ipp, int addto) +{ + int i, j; + + printf(" pushl %%ebp\n"); + printf(" movl %%esp,%%ebp\n"); + if (addto) + printf(" subl $%d,%%esp\n", addto); + for (i = ipp->ipp_regs, j = 0; i; i >>= 1, j++) + if (i & 1) + fprintf(stdout, " movl %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/SZCHAR) + addto -= AUTOINIT/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; + + 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, " movl -%d(%s),%s\n", + regoff[j], rnames[FPREG], rnames[j]); + + } + + /* struct return needs special treatment */ + if (ftype == STRTY || ftype == UNIONTY) { + printf(" movl 8(%%ebp),%%eax\n"); + printf(" leave\n"); + printf(" ret $4\n"); + } else { + printf(" leave\n"); + printf(" ret\n"); + } +} + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str; + + switch (o) { + case PLUS: + str = "add"; + break; + case MINUS: + str = "sub"; + break; + case AND: + str = "and"; + break; + case OR: + str = "or"; + break; + case ER: + str = "xor"; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + printf("%s%c", str, f); +} + +/* + * Return type size in bytes. Used by R2REGS, arg 2 to offset(). + */ +int +tlen(p) NODE *p; +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(SZSHORT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case INT: + case UNSIGNED: + case LONG: + case ULONG: + return(SZINT/SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type)/SZCHAR; + } +} + +/* + * Emit code to compare two longlong numbers. + */ +static void +twollcomp(NODE *p) +{ + int o = p->n_op; + int s = getlab(); + int e = p->n_label; + int cb1, cb2; + + if (o >= ULE) + o -= (ULE-LE); + switch (o) { + case NE: + cb1 = 0; + cb2 = NE; + break; + case EQ: + cb1 = NE; + cb2 = 0; + break; + case LE: + case LT: + cb1 = GT; + cb2 = LT; + break; + case GE: + case GT: + cb1 = LT; + cb2 = GT; + break; + + default: + cb1 = cb2 = 0; /* XXX gcc */ + } + if (p->n_op >= ULE) + cb1 += 4, cb2 += 4; + expand(p, 0, " cmpl UR,UL\n"); + if (cb1) cbgen(cb1, s); + if (cb2) cbgen(cb2, e); + expand(p, 0, " cmpl AR,AL\n"); + cbgen(p->n_op, e); + deflab(s); +} + +/* + * Assign to a bitfield. + * Clumsy at least, but what to do? + */ +static void +bfasg(NODE *p) +{ + NODE *fn = p->n_left; + int shift = UPKFOFF(fn->n_rval); + int fsz = UPKFSZ(fn->n_rval); + int andval, tch = 0; + + /* get instruction size */ + switch (p->n_type) { + case CHAR: case UCHAR: tch = 'b'; break; + case SHORT: case USHORT: tch = 'w'; break; + case INT: case UNSIGNED: tch = 'l'; break; + default: comperr("bfasg"); + } + + /* put src into a temporary reg */ + fprintf(stdout, " mov%c ", tch); + adrput(stdout, getlr(p, 'R')); + fprintf(stdout, ","); + adrput(stdout, getlr(p, '1')); + fprintf(stdout, "\n"); + + /* AND away the bits from dest */ + andval = ~(((1 << fsz) - 1) << shift); + fprintf(stdout, " and%c $%d,", tch, andval); + adrput(stdout, fn->n_left); + fprintf(stdout, "\n"); + + /* AND away unwanted bits from src */ + andval = ((1 << fsz) - 1); + fprintf(stdout, " and%c $%d,", tch, andval); + adrput(stdout, getlr(p, '1')); + fprintf(stdout, "\n"); + + /* SHIFT left src number of bits */ + if (shift) { + fprintf(stdout, " sal%c $%d,", tch, shift); + adrput(stdout, getlr(p, '1')); + fprintf(stdout, "\n"); + } + + /* OR in src to dest */ + fprintf(stdout, " or%c ", tch); + adrput(stdout, getlr(p, '1')); + fprintf(stdout, ","); + adrput(stdout, fn->n_left); + fprintf(stdout, "\n"); +} + +/* + * Push a structure on stack as argument. + * the scratch registers are already free here + */ +static void +starg(NODE *p) +{ + FILE *fp = stdout; + + fprintf(fp, " subl $%d,%%esp\n", p->n_stsize); + fprintf(fp, " pushl $%d\n", p->n_stsize); + expand(p, 0, " pushl AL\n"); + expand(p, 0, " leal 8(%esp),A1\n"); + expand(p, 0, " pushl A1\n"); + fprintf(fp, " call memcpy\n"); + fprintf(fp, " addl $12,%%esp\n"); +} + +/* + * Compare two floating point numbers. + */ +static void +fcomp(NODE *p) +{ + + if (p->n_left->n_op == REG) { + if (p->n_su & DORIGHT) + expand(p, 0, " fxch\n"); + expand(p, 0, " fucompp\n"); /* emit compare insn */ + } else if (p->n_left->n_type == DOUBLE) + expand(p, 0, " fcompl AL\n"); /* emit compare insn */ + else if (p->n_left->n_type == FLOAT) + expand(p, 0, " fcomp AL\n"); /* emit compare insn */ + else + comperr("bad compare %p\n", p); + expand(p, 0, " fnstsw %ax\n"); /* move status reg to ax */ + + switch (p->n_op) { + case EQ: + expand(p, 0, " andb $64,%ah\n jne LC\n"); + break; + case NE: + expand(p, 0, " andb $64,%ah\n je LC\n"); + break; + case LE: + expand(p, 0, " andb $65,%ah\n cmpb $1,%ah\n jne LC\n"); + break; + case LT: + expand(p, 0, " andb $65,%ah\n je LC\n"); + break; + case GT: + expand(p, 0, " andb $1,%ah\n jne LC\n"); + break; + case GE: + expand(p, 0, " andb $65,%ah\n jne LC\n"); + break; + default: + comperr("fcomp op %d\n", p->n_op); + } +} + +/* + * Convert an unsigned long long to floating point number. + */ +static void +ulltofp(NODE *p) +{ + static int loadlab; + int jmplab; + + if (loadlab == 0) { + loadlab = getlab(); + expand(p, 0, " .data\n"); + printf(LABFMT ": .long 0,0x80000000,0x403f\n", loadlab); + expand(p, 0, " .text\n"); + } + jmplab = getlab(); + expand(p, 0, " pushl UL\n pushl AL\n"); + expand(p, 0, " fildq (%esp)\n"); + expand(p, 0, " addl $8,%esp\n"); + expand(p, 0, " cmpl $0,UL\n"); + printf(" jge " LABFMT "\n", jmplab); + printf(" fldt " LABFMT "\n", loadlab); + printf(" faddp %%st,%%st(1)\n"); + printf(LABFMT ":\n", jmplab); +} + +static int +argsiz(NODE *p) +{ + TWORD t = p->n_type; + + if (t < LONGLONG || t == FLOAT || t > BTMASK) + return 4; + if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) + return 8; + if (t == LDOUBLE) + return 12; + if (t == STRTY || t == UNIONTY) + return p->n_stsize; + comperr("argsiz"); + return 0; +} + +void +zzzcode(NODE *p, int c) +{ + NODE *r, *l; + int pr, lr, s; + char *ch; + + switch (c) { + case 'A': /* swap st0 and st1 if right is evaluated second */ + if ((p->n_su & DORIGHT) == 0) { + if (logop(p->n_op)) + printf(" fxch\n"); + else + printf("r"); + } + break; + + case 'C': /* remove from stack after subroutine call */ + pr = p->n_qual; + if (p->n_op == STCALL || p->n_op == USTCALL) + pr += 4; + if (p->n_op == UCALL) + return; /* XXX remove ZC from UCALL */ + if (pr) + printf(" addl $%d, %s\n", pr, rnames[ESP]); + break; + + case 'D': /* Long long comparision */ + twollcomp(p); + break; + + case 'E': /* Assign to bitfield */ + bfasg(p); + break; + + case 'F': /* Structure argument */ + if (p->n_stalign != 0) /* already on stack */ + starg(p); + break; + + case 'G': /* Floating point compare */ + fcomp(p); + break; + + case 'J': /* convert unsigned long long to floating point */ + ulltofp(p); + break; + + case 'M': /* Output sconv move, if needed */ + l = getlr(p, 'L'); + /* XXX fixneed: regnum */ + pr = DECRA(p->n_reg, 0); + lr = DECRA(l->n_reg, 0); + if ((pr == AL && lr == EAX) || (pr == BL && lr == EBX) || + (pr == CL && lr == ECX) || (pr == DL && lr == EDX)) + ; + else + printf(" movb %%%cl,%s\n", + rnames[lr][2], rnames[pr]); + l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */ + break; + + case 'N': /* output extended reg name */ + printf("%s", rnames[getlr(p, '1')->n_rval]); + break; + + case 'O': /* print out emulated ops */ + pr = 16; + if (p->n_op == RS || p->n_op == LS) { + expand(p, INAREG, "\tpushl AR\n"); + pr = 12; + } else + expand(p, INCREG, "\tpushl UR\n\tpushl AR\n"); + expand(p, INCREG, "\tpushl UL\n\tpushl AL\n"); + if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv"; + else if (p->n_op == DIV) ch = "div"; + else if (p->n_op == MUL) ch = "mul"; + else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod"; + else if (p->n_op == MOD) ch = "mod"; + else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshr"; + else if (p->n_op == RS) ch = "ashr"; + else if (p->n_op == LS) ch = "ashl"; + else ch = 0, comperr("ZO"); + printf("\tcall __%sdi3\n\taddl $%d,%s\n", ch, pr, rnames[ESP]); + break; + + case 'P': /* push hidden argument on stack */ + r = (NODE *)p->n_sue; + printf("\tleal -%d(%%ebp),", stkpos); + adrput(stdout, getlr(p, '1')); + printf("\n\tpushl "); + adrput(stdout, getlr(p, '1')); + putchar('\n'); + break; + + case 'Q': /* emit struct assign */ + /* XXX - optimize for small structs */ + printf("\tpushl $%d\n", p->n_stsize); + expand(p, INAREG, "\tpushl AR\n"); + expand(p, INAREG, "\tleal AL,%eax\n\tpushl %eax\n"); + printf("\tcall memcpy\n"); + printf("\taddl $12,%%esp\n"); + break; + + case 'S': /* emit eventual move after cast from longlong */ + pr = DECRA(p->n_reg, 0); + lr = p->n_left->n_rval; + switch (p->n_type) { + case CHAR: + case UCHAR: + if (rnames[pr][2] == 'l' && rnames[lr][2] == 'x' && + rnames[pr][1] == rnames[lr][1]) + break; + if (rnames[lr][2] == 'x') { + printf("\tmovb %%%cl,%s\n", + rnames[lr][1], rnames[pr]); + break; + } + /* Must go via stack */ + s = BITOOR(freetemp(1)); + printf("\tmovl %%e%ci,%d(%%ebp)\n", rnames[lr][1], s); + printf("\tmovb %d(%%ebp),%s\n", s, rnames[pr]); +// comperr("SCONV1 %s->%s", rnames[lr], rnames[pr]); + break; + + case SHORT: + case USHORT: + if (rnames[lr][1] == rnames[pr][2] && + rnames[lr][2] == rnames[pr][3]) + break; + printf("\tmovw %%%c%c,%%%s\n", + rnames[lr][1], rnames[lr][2], rnames[pr]+2); + break; + case INT: + case UNSIGNED: + if (rnames[lr][1] == rnames[pr][2] && + rnames[lr][2] == rnames[pr][3]) + break; + printf("\tmovl %%e%c%c,%s\n", + rnames[lr][1], rnames[lr][2], rnames[pr]); + break; + + default: + if (rnames[lr][1] == rnames[pr][2] && + rnames[lr][2] == rnames[pr][3]) + break; + comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]); + break; + } + break; + + default: + comperr("zzzcode %c", c); + } +} + +/*ARGSUSED*/ +int +rewfld(NODE *p) +{ + return(1); +} + +int canaddr(NODE *); +int +canaddr(NODE *p) +{ + int o = p->n_op; + + if (o==NAME || o==REG || o==ICON || o==OREG || + (o==UMUL && shumul(p->n_left))) + return(1); + return(0); +} + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE *p) +{ + int o = p->n_op; + + if (o == OREG || o == REG || o == NAME) + return SRDIR; /* Direct match */ + if (o == UMUL && shumul(p->n_left)) + return SROREG; /* Convert into oreg */ + return SRREG; /* put it into a register */ +} + +/* INTEMP shapes must not contain any temporary registers */ +/* XXX should this go away now? */ +int +shtemp(NODE *p) +{ + 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, p %p", p); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + comperr("insput"); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ + + size /= SZCHAR; + switch (p->n_op) { + case REG: + fprintf(stdout, "%%%s", &rnames[p->n_rval][3]); + 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); + } else + fprintf(io, CONFMT, p->n_lval); + return; + + case OREG: + r = p->n_rval; + if (p->n_lval) + fprintf(io, "%d", (int)p->n_lval); + if (R2TEST(r)) { + fprintf(io, "(%s,%s,4)", rnames[R2UPK1(r)], + rnames[R2UPK2(r)]); + } else + 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: + switch (p->n_type) { + case LONGLONG: + case ULONGLONG: + fprintf(io, "%%%c%c%c", rnames[p->n_rval][0], + rnames[p->n_rval][1], rnames[p->n_rval][2]); + break; + case SHORT: + case USHORT: + fprintf(io, "%%%s", &rnames[p->n_rval][2]); + break; + default: + fprintf(io, "%s", rnames[p->n_rval]); + } + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +static char * +ccbranches[] = { + "je", /* jumpe */ + "jne", /* jumpn */ + "jle", /* jumple */ + "jl", /* jumpl */ + "jge", /* jumpge */ + "jg", /* jumpg */ + "jbe", /* jumple (jlequ) */ + "jb", /* jumpl (jlssu) */ + "jae", /* jumpge (jgequ) */ + "ja", /* jumpg (jgtru) */ +}; + + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ + if (o < EQ || o > UGT) + comperr("bad conditional branch: %s", opst[o]); + printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); +} + +static void +fixcalls(NODE *p) +{ + /* Prepare for struct return by allocating bounce space on stack */ + switch (p->n_op) { + case STCALL: + case USTCALL: + if (p->n_stsize+p2autooff > stkpos) + stkpos = p->n_stsize+p2autooff; + break; + } +} + +/* + * Must store floats in memory if there are two function calls involved. + */ +static int +storefloat(struct interpass *ip, NODE *p) +{ + int l, r; + + switch (optype(p->n_op)) { + case BITYPE: + l = storefloat(ip, p->n_left); + r = storefloat(ip, p->n_right); + if (p->n_op == CM) + return 0; /* arguments, don't care */ + if (callop(p->n_op)) + return 1; /* found one */ +#define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \ + (p)->n_type == LDOUBLE) + if (ISF(p->n_left) && ISF(p->n_right) && l && r) { + /* must store one. store left */ + struct interpass *nip; + TWORD t = p->n_left->n_type; + NODE *ll; + int off; + + off = BITOOR(freetemp(szty(t))); + ll = mklnode(OREG, off, FPREG, t); + nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t)); + p->n_left = mklnode(OREG, off, FPREG, t); + DLIST_INSERT_BEFORE(ip, nip, qelem); + } + return l|r; + + case UTYPE: + l = storefloat(ip, p->n_left); + if (callop(p->n_op)) + l = 1; + return l; + default: + return 0; + } +} + +void +myreader(struct interpass *ipole) +{ + struct interpass *ip; + + stkpos = p2autooff; + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + walkf(ip->ip_node, fixcalls); + storefloat(ip, ip->ip_node); + } + if (stkpos > p2autooff) + p2autooff = stkpos; + if (stkpos > p2maxautooff) + p2maxautooff = stkpos; + if (x2debug) + printip(ipole); +} + +/* + * Remove some PCONVs after OREGs are created. + */ +static void +pconv2(NODE *p) +{ + NODE *q; + + if (p->n_op == PLUS) { + if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { + if (p->n_right->n_op != ICON) + return; + if (p->n_left->n_op != PCONV) + return; + if (p->n_left->n_left->n_op != OREG) + return; + q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + /* + * This will be converted to another OREG later. + */ + } + } +} + +void +mycanon(NODE *p) +{ + walkf(p, pconv2); +} + +void +myoptim(struct interpass *ip) +{ +} + +static char rl[] = + { EAX, EAX, EAX, EAX, EAX, EDX, EDX, EDX, EDX, ECX, ECX, ECX, EBX, EBX, ESI }; +static char rh[] = + { EDX, ECX, EBX, ESI, EDI, ECX, EBX, ESI, EDI, EBX, ESI, EDI, ESI, EDI, EDI }; + +void +rmove(int s, int d, TWORD t) +{ + int sl, sh, dl, dh; + + switch (t) { + case LONGLONG: + case ULONGLONG: +#if 1 + sl = rl[s-EAXEDX]; + sh = rh[s-EAXEDX]; + dl = rl[d-EAXEDX]; + dh = rh[d-EAXEDX]; + + /* sanity checks, remove when satisfied */ + if (memcmp(rnames[s], rnames[sl]+1, 3) != 0 || + memcmp(rnames[s]+3, rnames[sh]+1, 3) != 0) + comperr("rmove source error"); + if (memcmp(rnames[d], rnames[dl]+1, 3) != 0 || + memcmp(rnames[d]+3, rnames[dh]+1, 3) != 0) + comperr("rmove dest error"); +#define SW(x,y) { int i = x; x = y; y = i; } + if (sl == dh || sh == dl) { + /* Swap if moving to itself */ + SW(sl, sh); + SW(dl, dh); + } + if (sl != dl) + printf(" movl %s,%s\n", rnames[sl], rnames[dl]); + if (sh != dh) + printf(" movl %s,%s\n", rnames[sh], rnames[dh]); +#else + if (memcmp(rnames[s], rnames[d], 3) != 0) + printf(" movl %%%c%c%c,%%%c%c%c\n", + rnames[s][0],rnames[s][1],rnames[s][2], + rnames[d][0],rnames[d][1],rnames[d][2]); + if (memcmp(&rnames[s][3], &rnames[d][3], 3) != 0) + printf(" movl %%%c%c%c,%%%c%c%c\n", + rnames[s][3],rnames[s][4],rnames[s][5], + rnames[d][3],rnames[d][4],rnames[d][5]); +#endif + break; + case CHAR: + case UCHAR: + printf(" movb %s,%s\n", rnames[s], rnames[d]); + break; + case FLOAT: + case DOUBLE: + case LDOUBLE: +#ifdef notdef + /* a=b()*c(); will generate this */ + comperr("bad float rmove: %d %d", s, d); +#endif + break; + default: + printf(" movl %s,%s\n", rnames[s], rnames[d]); + } +} + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + */ +int +COLORMAP(int c, int *r) +{ + int num; + + switch (c) { + case CLASSA: + num = r[CLASSB] > 4 ? 4 : r[CLASSB]; + num += 2*r[CLASSC]; + num += r[CLASSA]; + return num < 6; + case CLASSB: + num = r[CLASSA]; + num += 2*r[CLASSC]; + num += r[CLASSB]; + return num < 4; + case CLASSC: + num = r[CLASSA]; + num += r[CLASSB] > 4 ? 4 : r[CLASSB]; + num += 2*r[CLASSC]; + return num < 5; + case CLASSD: + return r[CLASSD] < DREGCNT; + } + return 0; /* XXX gcc */ +} + +char *rnames[] = { + "%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp", + "%al", "%ah", "%dl", "%dh", "%cl", "%ch", "%bl", "%bh", + "eaxedx", "eaxecx", "eaxebx", "eaxesi", "eaxedi", "edxecx", + "edxebx", "edxesi", "edxedi", "ecxebx", "ecxesi", "ecxedi", + "ebxesi", "ebxedi", "esiedi", + "%st0", "%st1", "%st2", "%st3", "%st4", "%st5", "%st6", "%st7", +}; + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + if (t == CHAR || t == UCHAR) + return CLASSB; + if (t == LONGLONG || t == ULONGLONG) + return CLASSC; + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) + return CLASSD; + return CLASSA; +} + +/* + * Calculate argument sizes. + */ +void +lastcall(NODE *p) +{ + NODE *op = p; + int size = 0; + + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + for (p = p->n_right; p->n_op == CM; p = p->n_left) + size += argsiz(p->n_right); + size += argsiz(p); + op->n_qual = size; /* XXX */ +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + int o = p->n_op; + + switch (shape) { + case SFUNCALL: + if (o == STCALL || o == USTCALL) + return SRREG; + break; + case SPCON: + if (o != ICON || p->n_name[0] || p->n_lval < 0) + break; + return SRDIR; + } + return SRNOPE; +} diff --git a/usr.bin/pcc/arch/x86/macdefs.h b/usr.bin/pcc/arch/x86/macdefs.h new file mode 100644 index 00000000000..46cf123c4ae --- /dev/null +++ b/usr.bin/pcc/arch/x86/macdefs.h @@ -0,0 +1,301 @@ +/* $Id: macdefs.h,v 1.1 2007/09/15 18:12:31 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Machine-dependent defines for both passes. + */ + +/* + * Convert (multi-)character constant to integer. + */ +#define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); + +#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 SZBOOL 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 ALBOOL 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 signed */ +#undef CHAR_UNSIGNED +#define BOOL_TYPE CHAR /* what used to store _Bool */ +#define WCHAR_TYPE INT /* what used to store wchar_t */ + +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "%lld" /* format for printing constants */ +#define LABFMT ".L%d" /* format for printing labels */ +#define STABLBL ".LL%d" /* format for stab (debugging) labels */ +#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) /* bit offset to oreg offset XXX die! */ + +#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 : (t) == LDOUBLE ? 3 : 1) + +/* + * The x86 has a bunch of register classes, most of them interfering + * with each other. All registers are given a sequential number to + * identify it which must match rnames[] in local2.c. + * Class membership and overlaps are defined in the macros RSTATUS + * and ROVERLAP below. + * + * The classes used on x86 are: + * A - short and int regs + * B - char regs + * C - long long regs + * D - floating point + */ +#define EAX 000 /* Scratch and return register */ +#define EDX 001 /* Scratch and secondary return register */ +#define ECX 002 /* Scratch (and shift count) register */ +#define EBX 003 /* GDT pointer or callee-saved temporary register */ +#define ESI 004 /* Callee-saved temporary register */ +#define EDI 005 /* Callee-saved temporary register */ +#define EBP 006 /* Frame pointer */ +#define ESP 007 /* Stack pointer */ + +#define AL 010 +#define AH 011 +#define DL 012 +#define DH 013 +#define CL 014 +#define CH 015 +#define BL 016 +#define BH 017 + +#define EAXEDX 020 +#define EAXECX 021 +#define EAXEBX 022 +#define EAXESI 023 +#define EAXEDI 024 +#define EDXECX 025 +#define EDXEBX 026 +#define EDXESI 027 +#define EDXEDI 030 +#define ECXEBX 031 +#define ECXESI 032 +#define ECXEDI 033 +#define EBXESI 034 +#define EBXEDI 035 +#define ESIEDI 036 + +/* The 8 math registers in class D lacks names */ + +#define MAXREGS 047 /* 39 registers */ + +#define RSTATUS \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, 0, 0, \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, + +#define ROVERLAP \ + /* 8 basic registers */\ + { AL, AH, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\ + { DL, DH, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\ + { CL, CH, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ + { BL, BH, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ + { EAXESI, EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\ + { EAXEDI, EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\ + { -1 },\ + { -1 },\ +\ + /* 8 char registers */\ + { EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\ + { EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\ + { EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\ + { EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\ + { ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ + { ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ + { EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ + { EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ +\ + /* 15 long-long-emulating registers */\ + { EAX, AL, AH, EDX, DL, DH, EAXECX, EAXEBX, EAXESI, /* eaxedx */\ + EAXEDI, EDXECX, EDXEBX, EDXESI, EDXEDI, -1, },\ + { EAX, AL, AH, ECX, CL, CH, EAXEDX, EAXEBX, EAXESI, /* eaxecx */\ + EAXEDI, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ + { EAX, AL, AH, EBX, BL, BH, EAXEDX, EAXECX, EAXESI, /* eaxebx */\ + EAXEDI, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ + { EAX, AL, AH, ESI, EAXEDX, EAXECX, EAXEBX, EAXEDI, /* eaxesi */\ + EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\ + { EAX, AL, AH, EDI, EAXEDX, EAXECX, EAXEBX, EAXESI, /* eaxedi */\ + EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\ + { EDX, DL, DH, ECX, CL, CH, EAXEDX, EAXECX, EDXEBX, /* edxecx */\ + EDXESI, EDXEDI, ECXEBX, ECXESI, ECXEDI, -1 },\ + { EDX, DL, DH, EBX, BL, BH, EAXEDX, EDXECX, EDXESI, /* edxebx */\ + EDXEDI, EAXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ + { EDX, DL, DH, ESI, EAXEDX, EDXECX, EDXEBX, EDXEDI, /* edxesi */\ + EAXESI, ECXESI, EBXESI, ESIEDI, -1 },\ + { EDX, DL, DH, EDI, EAXEDX, EDXECX, EDXEBX, EDXESI, /* edxedi */\ + EAXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\ + { ECX, CL, CH, EBX, BL, BH, EAXECX, EDXECX, ECXESI, /* ecxebx */\ + ECXEDI, EAXEBX, EDXEBX, EBXESI, EBXEDI, -1 },\ + { ECX, CL, CH, ESI, EAXECX, EDXECX, ECXEBX, ECXEDI, /* ecxesi */\ + EAXESI, EDXESI, EBXESI, ESIEDI, -1 },\ + { ECX, CL, CH, EDI, EAXECX, EDXECX, ECXEBX, ECXESI, /* ecxedi */\ + EAXEDI, EDXEDI, EBXEDI, ESIEDI, -1 },\ + { EBX, BL, BH, ESI, EAXEBX, EDXEBX, ECXEBX, EBXEDI, /* ebxesi */\ + EAXESI, EDXESI, ECXESI, ESIEDI, -1 },\ + { EBX, BL, BH, EDI, EAXEBX, EDXEBX, ECXEBX, EBXESI, /* ebxedi */\ + EAXEDI, EDXEDI, ECXEDI, ESIEDI, -1 },\ + { ESI, EDI, EAXESI, EDXESI, ECXESI, EBXESI, /* esiedi */\ + EAXEDI, EDXEDI, ECXEDI, EBXEDI, -1 },\ +\ + /* The fp registers do not overlap with anything */\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 }, + + +/* Return a register class based on the type of the node */ +#define PCLASS(p) (p->n_type <= UCHAR ? SBREG : \ + (p->n_type == LONGLONG || p->n_type == ULONGLONG ? SCREG : \ + (p->n_type >= FLOAT && p->n_type <= LDOUBLE ? SDREG : SAREG))) + +#define NUMCLASS 4 /* highest number of reg classes used */ + +int COLORMAP(int c, int *r); +#define GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : x < 31 ? CLASSC : CLASSD) +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 6) /* A1 */ +#define ENCRA2(x) ((x) << 12) /* A2 */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ +/* XXX - return char in al? */ +#define RETREG(x) (x == CHAR || x == UCHAR ? AL : \ + x == LONGLONG || x == ULONGLONG ? EAXEDX : \ + x == FLOAT || x == DOUBLE || x == LDOUBLE ? 31 : EAX) + +//#define R2REGS 1 /* permit double indexing */ + +/* XXX - to die */ +#define FPREG EBP /* frame pointer */ +#define STKREG ESP /* stack pointer */ + +#define MYREADER(p) myreader(p) +#define MYCANON(p) mycanon(p) +#define MYOPTIM + +#define SHSTR (MAXSPECIAL+1) /* short struct */ +#define SFUNCALL (MAXSPECIAL+2) /* struct assign after function call */ +#define SPCON (MAXSPECIAL+3) /* positive nonnamed constant */ diff --git a/usr.bin/pcc/arch/x86/order.c b/usr.bin/pcc/arch/x86/order.c new file mode 100644 index 00000000000..35bd53c1f9b --- /dev/null +++ b/usr.bin/pcc/arch/x86/order.c @@ -0,0 +1,287 @@ +/* $Id: order.c,v 1.1 2007/09/15 18:12:31 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "pass2.h" + +#include <string.h> + +int canaddr(NODE *); + +/* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + return(0); /* YES */ +} + +/* + * Turn a UMUL-referenced node into OREG. + * Be careful about register classes, this is a place where classes change. + */ +void +offstar(NODE *p, int shape) +{ + NODE *r; + + if (x2debug) + printf("offstar(%p)\n", p); + + if (isreg(p)) + return; /* Is already OREG */ + + r = p->n_right; + if( p->n_op == PLUS || p->n_op == MINUS ){ + if( r->n_op == ICON ){ + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + /* Converted in ormake() */ + return; + } + if (r->n_op == LS && r->n_right->n_op == ICON && + r->n_right->n_lval == 2 && p->n_op == PLUS) { + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + if (isreg(r->n_left) == 0) + (void)geninsn(r->n_left, INAREG); + return; + } + } + (void)geninsn(p, INAREG); +} + +/* + * Do the actual conversion of offstar-found OREGs into real OREGs. + */ +void +myormake(NODE *q) +{ + NODE *p, *r; + + if (x2debug) + printf("myormake(%p)\n", q); + + p = q->n_left; + if (p->n_op == PLUS && (r = p->n_right)->n_op == LS && + r->n_right->n_op == ICON && r->n_right->n_lval == 2 && + p->n_left->n_op == REG && r->n_left->n_op == REG) { + q->n_op = OREG; + q->n_lval = 0; + q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0); + tfree(p); + } +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p) +{ + + if (x2debug) + printf("shumul(%p)\n", p); + + /* Turns currently anything into OREG on x86 */ + return SOREG; +} + +/* + * Rewrite increment/decrement operation. + */ +int +setincr(NODE *p) +{ + if (x2debug) + printf("setincr(%p)\n", p); + + return(0); +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE *p) +{ + + if (x2debug) + printf("setbin(%p)\n", p); + return 0; + +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + if (x2debug) + printf("setasg(%p)\n", p); + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +/* + * Special handling of some instruction register allocation. + */ +struct rspecial * +nspecial(struct optab *q) +{ + switch (q->op) { + case OPLOG: + { + static struct rspecial s[] = { { NEVER, EAX }, { 0 } }; + return s; + } + + case STASG: + case STARG: + { + static struct rspecial s[] = { + { NEVER, EAX }, { NEVER, EDX }, + { NEVER, ECX }, { 0 } }; + return s; + } + + case SCONV: + if ((q->ltype & (TINT|TUNSIGNED|TSHORT|TUSHORT)) && + q->rtype == (TCHAR|TUCHAR)) { + static struct rspecial s[] = { + { NOLEFT, ESI }, { NOLEFT, EDI }, { 0 } }; + return s; + } else if ((q->ltype & (TINT|TUNSIGNED)) && + q->rtype == TLONGLONG) { + static struct rspecial s[] = { + { NLEFT, EAX }, { NRES, EAXEDX }, + { NEVER, EAX }, { NEVER, EDX }, { 0 } }; + return s; + } else if (q->ltype == TSHORT && + q->rtype == (TLONGLONG|TULONGLONG)) { + static struct rspecial s[] = { + { NRES, EAXEDX }, + { NEVER, EAX }, { NEVER, EDX }, { 0 } }; + return s; + } else if (q->ltype == TCHAR && + q->rtype == (TLONGLONG|TULONGLONG)) { + static struct rspecial s[] = { + { NRES, EAXEDX }, + { NEVER, EAX }, { NEVER, EDX }, { 0 } }; + return s; + } + break; + case DIV: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NEVER, AL }, { NEVER, AH }, + { NLEFT, AL }, { NRES, AL }, + { NORIGHT, AH }, { NORIGHT, AL }, { 0 } }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NEVER, EAX }, { NEVER, EDX }, + { NLEFT, EAX }, { NRES, EAX }, + { NORIGHT, EDX }, { NORIGHT, EAX }, { 0 } }; + return s; + } else if (q->lshape & SCREG) { + static struct rspecial s[] = { + { NEVER, EAX }, { NEVER, EDX }, + { NEVER, ECX }, { NRES, EAXEDX }, { 0 } }; + return s; + } + break; + case MOD: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NEVER, AL }, { NEVER, AH }, + { NLEFT, AL }, { NRES, AH }, + { NORIGHT, AH }, { NORIGHT, AL }, { 0 } }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NEVER, EAX }, { NEVER, EDX }, + { NLEFT, EAX }, { NRES, EDX }, + { NORIGHT, EDX }, { NORIGHT, EAX }, { 0 } }; + return s; + } else if (q->lshape & SCREG) { + static struct rspecial s[] = { + { NEVER, EAX }, { NEVER, EDX }, + { NEVER, ECX }, { NRES, EAXEDX }, { 0 } }; + return s; + } + break; + case MUL: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NEVER, AL }, { NEVER, AH }, + { NLEFT, AL }, { NRES, AL }, { 0 } }; + return s; + } else if (q->lshape & SCREG) { + static struct rspecial s[] = { + { NEVER, EAX }, { NEVER, EDX }, + { NEVER, ECX }, { NRES, EAXEDX }, { 0 } }; + return s; + } + break; + case LS: + case RS: + if (q->visit & (INAREG|INBREG)) { + static struct rspecial s[] = { + { NRIGHT, CL }, { NOLEFT, ECX }, { 0 } }; + return s; + } else if (q->visit & INCREG) { + static struct rspecial s[] = { + { NEVER, EAX }, { NEVER, EDX }, + { NEVER, ECX }, { NRES, EAXEDX }, { 0 } }; + return s; + } + break; + + default: + break; + } + comperr("nspecial entry %d", q - table); + return 0; /* XXX gcc */ +} + +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE *p) +{ + return 0; /* nothing differs on x86 */ +} diff --git a/usr.bin/pcc/arch/x86/table.c b/usr.bin/pcc/arch/x86/table.c new file mode 100644 index 00000000000..cf41ecb1bc4 --- /dev/null +++ b/usr.bin/pcc/arch/x86/table.c @@ -0,0 +1,1453 @@ +/* $Id: table.c,v 1.1 2007/09/15 18:12:31 otto Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +# include "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 SHINT SAREG /* short and int */ +#define ININT INAREG +#define SHCH SBREG /* shape for char */ +#define INCH INBREG +#define SHLL SCREG /* shape for long long */ +#define INLL INCREG +#define SHFL SDREG /* shape for float/double */ +#define INFL INDREG /* shape for float/double */ + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* PCONVs are usually not necessary */ +{ PCONV, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + "", }, + +/* + * A bunch conversions of integral<->integral types + * There are lots of them, first in table conversions to itself + * and then conversions from each type to the others. + */ + +/* itself to itself, including pointers */ + +/* convert (u)char to (u)char. */ +{ SCONV, INCH, + SHCH, TCHAR|TUCHAR, + SHCH, TCHAR|TUCHAR, + 0, RLEFT, + "", }, + +/* convert pointers to int. */ +{ SCONV, ININT, + SHINT, TPOINT|TWORD, + SANY, TWORD, + 0, RLEFT, + "", }, + +/* convert (u)longlong to (u)longlong. */ +{ SCONV, INLL, + SHLL, TLL, + SHLL, TLL, + 0, RLEFT, + "", }, + +/* convert double <-> float. nothing to do here */ +{ SCONV, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + "", }, + +/* convert pointers to pointers. */ +{ SCONV, ININT, + SHINT, TPOINT, + SANY, TPOINT, + 0, RLEFT, + "", }, + +/* char to something */ + +/* convert char to (unsigned) short. */ +{ SCONV, ININT, + SBREG|SOREG|SNAME, TCHAR, + SAREG, TSHORT|TUSHORT, + NASL|NAREG, RESC1, + " movsbw AL,A1\n", }, + +/* convert unsigned char to (u)short. */ +{ SCONV, ININT, + SHCH|SOREG|SNAME, TUCHAR, + SAREG, TSHORT|TUSHORT, + NASL|NAREG, RESC1, + " movzbw AL,A1\n", }, + +/* convert signed char to int (or pointer). */ +{ SCONV, ININT, + SHCH|SOREG|SNAME, TCHAR, + SAREG, TWORD|TPOINT, + NASL|NAREG, RESC1, + " movsbl AL,A1\n", }, + +/* convert unsigned char to (u)int. */ +{ SCONV, ININT, + SHCH|SOREG|SNAME, TUCHAR, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movzbl AL,A1\n", }, + +/* convert char to (u)long long */ +{ SCONV, INLL, + SHCH|SOREG|SNAME, TCHAR, + SANY, TLL, + NSPECIAL|NAREG|NASL, RESC1, + " movsbl AL,%eax\n cltd\n", }, + +/* convert unsigned char to (u)long long */ +{ SCONV, INLL, + SHCH|SOREG|SNAME, TUCHAR, + SANY, TLL, + NCREG|NCSL, RESC1, + " movzbl AL,A1\n xorl U1,U1\n", }, + +/* convert char (in register) to double XXX - use NTEMP */ +{ SCONV, INFL, + SHCH|SOREG|SNAME, TCHAR, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG, RESC2, + " movsbl AL,A1\n pushl A1\n" + " fildl (%esp)\n addl $4,%esp\n", }, + +/* convert (u)char (in register) to double XXX - use NTEMP */ +{ SCONV, INFL, + SHCH|SOREG|SNAME, TUCHAR, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG, RESC2, + " movzbl AL,A1\n pushl A1\n" + " fildl (%esp)\n addl $4,%esp\n", }, + +/* short to something */ + +/* convert short (in memory) to char */ +{ SCONV, INCH, + SNAME|SOREG, TSHORT|TUSHORT, + SHCH, TCHAR|TUCHAR, + NBREG|NBSL, RESC1, + " movb AL,A1\n", }, + +/* convert short (in reg) to char. */ +{ SCONV, INCH, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL|NBREG|NBSL, RESC1, + "ZM", }, + +/* convert short to (u)int. */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movswl AL,A1\n", }, + +/* convert unsigned short to (u)int. */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TUSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movzwl AL,A1\n", }, + +/* convert short to (u)long long */ +{ SCONV, INLL, + SAREG|SOREG|SNAME, TSHORT, + SHLL, TLL, + NSPECIAL|NCREG|NCSL, RESC1, + " movswl AL,%eax\n cltd\n", }, + +/* convert unsigned short to (u)long long */ +{ SCONV, INLL, + SAREG|SOREG|SNAME, TUSHORT, + SHLL, TLL, + NCREG|NCSL, RESC1, + " movzwl AL,A1\n xorl U1,U1\n", }, + +/* convert short (in memory) to float/double */ +{ SCONV, INFL, + SOREG|SNAME, TSHORT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fild AL\n", }, + +/* convert short (in register) to float/double */ +{ SCONV, INFL, + SAREG, TSHORT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NTEMP|NDREG, RESC1, + " pushw AL\n fild (%esp)\n addl $2,%esp\n", }, + +/* convert unsigned short to double XXX - use NTEMP */ +{ SCONV, INFL, + SAREG|SOREG|SNAME, TUSHORT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG|NTEMP, RESC2, + " movzwl AL,A1\n pushl A1\n" + " fildl (%esp)\n addl $4,%esp\n", }, + +/* int to something */ + +/* convert int to char. This is done when register is loaded */ +{ SCONV, INCH, + SAREG, TWORD, + SANY, TCHAR|TUCHAR, + NSPECIAL|NBREG|NBSL, RESC1, + "ZM", }, + +/* convert int to short. Nothing to do */ +{ SCONV, INAREG, + SAREG, TWORD, + SANY, TSHORT|TUSHORT, + 0, RLEFT, + "", }, + +/* convert int to long long */ +{ SCONV, INLL, + SAREG, TWORD|TPOINT, + SCREG, TLONGLONG, + NSPECIAL|NCREG|NCSL, RESC1, + " cltd\n", }, + +/* convert int to unsigned long long */ +{ SCONV, INLL, + SAREG|SOREG|SNAME, TWORD|TPOINT, + SHLL, TULONGLONG, + NCSL|NCREG, RESC1, + " movl AL,A1\n xorl U1,U1\n", }, + +/* convert int (in memory) to double */ +{ SCONV, INFL, + SOREG|SNAME, TWORD, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fildl AL\n", }, + +/* convert int (in register) to double */ +{ SCONV, INFL, + SAREG, TWORD, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NTEMP|NDREG, RESC1, + " pushl AL\n fildl (%esp)\n addl $4,%esp\n", }, + +/* long long to something */ + +/* convert (u)long long to (u)char (mem->reg) */ +{ SCONV, INCH, + SOREG|SNAME, TLL, + SANY, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " movb AL,A1\n", }, + +/* convert (u)long long to (u)char (reg->reg, hopefully nothing) */ +{ SCONV, INCH, + SHLL, TLL, + SANY, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + "ZS", }, + +/* convert (u)long long to (u)short (mem->reg) */ +{ SCONV, INAREG, + SOREG|SNAME, TLL, + SAREG, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " movw AL,A1\n", }, + +/* convert (u)long long to (u)short (reg->reg, hopefully nothing) */ +{ SCONV, INAREG, + SHLL|SOREG|SNAME, TLL, + SAREG, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + "ZS", }, + +/* convert long long to int (mem->reg) */ +{ SCONV, INAREG, + SOREG|SNAME, TLL, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +/* convert long long to int (reg->reg, hopefully nothing) */ +{ SCONV, INAREG, + SHLL|SOREG|SNAME, TLL, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + "ZS", }, + +/* convert long long (in memory) to floating */ +{ SCONV, INFL, + SOREG|SNAME, TLONGLONG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fildq AL\n", }, + +/* convert long long (in register) to floating */ +{ SCONV, INFL, + SHLL, TLONGLONG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NTEMP|NDREG, RESC1, + " pushl UL\n pushl AL\n" + " fildq (%esp)\n addl $8,%esp\n", }, + +/* convert unsigned long long to floating */ +{ SCONV, INFL, + SCREG, TULONGLONG, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + "ZJ", }, + +/* float to something */ + +#if 0 /* go via int by adding an extra sconv in clocal() */ +/* convert float/double to (u) char. XXX should use NTEMP here */ +{ SCONV, INCH, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NBREG, RESC1, + " subl $4,%esp\n fistpl (%esp)\n popl A1\n", }, + +/* convert float/double to (u) int/short/char. XXX should use NTEMP here */ +{ SCONV, INCH, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NCREG, RESC1, + " subl $4,%esp\n fistpl (%esp)\n popl A1\n", }, +#endif + +/* convert float/double to (u)int. XXX should use NTEMP here */ +{ SCONV, INAREG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SAREG, TWORD, + NAREG, RESC1, + " subl $4,%esp\n fistpl (%esp)\n popl A1\n", }, + +/* convert float/double (in register) to (unsigned) long long */ +/* XXX - unsigned is not handled correct */ +{ SCONV, INLL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHLL, TLONGLONG|TULONGLONG, + NCREG, RESC1, + " subl $8,%esp\n fistpq (%esp)\n" + " popl A1\n popl U1\n", }, + +/* slut sconv */ + +/* + * Subroutine calls. + */ + +{ CALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " call CL\nZC", }, + +{ UCALL, FOREFF, + SCON, TANY, + SAREG, TWORD|TPOINT, + 0, 0, + " call CL\n", }, + +{ CALL, INAREG, + SCON, TANY, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INAREG, + SCON, TANY, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\n", }, + +{ CALL, INBREG, + SCON, TANY, + SBREG, TCHAR|TUCHAR, + NBREG, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INBREG, + SCON, TANY, + SBREG, TCHAR|TUCHAR, + NBREG, RESC1, /* should be 0 */ + " call CL\n", }, + +{ CALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call CL\n", }, + +{ CALL, INDREG, + SCON, TANY, + SDREG, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INDREG, + SCON, TANY, + SDREG, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call *AL\nZC", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call *AL\nZC", }, + +{ CALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INCREG, + SAREG, TANY, + SANY, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INCREG, + SAREG, TANY, + SANY, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INDREG, + SAREG, TANY, + SANY, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INDREG, + SAREG, TANY, + SANY, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +/* struct return */ +{ USTCALL, FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, 0, + "ZP call CL\nZC", }, + +{ USTCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call CL\nZC", }, + +{ USTCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call *AL\nZC", }, + +{ STCALL, FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, 0, + "ZP call CL\nZC", }, + +{ STCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call CL\nZC", }, + +{ STCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call *AL\nZC", }, + +/* + * The next rules handle all binop-style operators. + */ +/* Special treatment for long long */ +{ PLUS, INLL|FOREFF, + SHLL, TLL, + SHLL|SNAME|SOREG, TLL, + 0, RLEFT, + " addl AR,AL\n adcl UR,UL\n", }, + +/* Special treatment for long long XXX - fix commutative check */ +{ PLUS, INLL|FOREFF, + SHLL|SNAME|SOREG, TLL, + SHLL, TLL, + 0, RRIGHT, + " addl AL,AR\n adcl UL,UR\n", }, + +{ PLUS, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " faddl AR\n", }, + +{ PLUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " faddp\n", }, + +{ PLUS, INAREG, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SONE, TANY, + 0, RLEFT, + " incl AL\n", }, + +{ PLUS, INAREG, + SAREG, TWORD|TPOINT, + SCON, TANY, + NAREG|NASL, RESC1, + " leal CR(AL),A1\n", }, + +{ PLUS, INCH, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SONE, TANY, + 0, RLEFT, + " incb AL\n", }, + +{ PLUS, INAREG, + SAREG, TWORD, + SAREG, TWORD, + NAREG|NASL|NASR, RESC1, + " leal (AL,AR),A1\n", }, + + +/* address as register offset, negative */ +{ MINUS, INAREG, + SAREG, TWORD|TPOINT, + SPCON, TANY, + NAREG|NASL, RESC1, + " leal -CR(AL),A1\n", }, + +{ MINUS, INLL|FOREFF, + SHLL, TLL, + SHLL|SNAME|SOREG, TLL, + 0, RLEFT, + " subl AR,AL\n sbbl UR,UL\n", }, + +{ MINUS, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fsubl AR\n", }, + +{ MINUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fsubZAp\n", }, + +/* Simple r/m->reg ops */ +{ OPSIMP, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG, TWORD|TPOINT, + 0, RLEFT, + " Ol AR,AL\n", }, + +{ OPSIMP, INAREG|FOREFF, + SHINT, TSHORT|TUSHORT, + SHINT|SNAME|SOREG, TSHORT|TUSHORT, + 0, RLEFT, + " Ow AR,AL\n", }, + +{ OPSIMP, INCH|FOREFF, + SHCH, TCHAR|TUCHAR, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + 0, RLEFT, + " Ob AR,AL\n", }, + +{ OPSIMP, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SCON, TWORD|TPOINT, + 0, RLEFT, + " Ol AR,AL\n", }, + +{ OPSIMP, INAREG|FOREFF, + SHINT|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RLEFT, + " Ow AR,AL\n", }, + +{ OPSIMP, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, RLEFT, + " Ob AR,AL\n", }, + +{ OPSIMP, INLL|FOREFF, + SHLL, TLL, + SHLL|SNAME|SOREG, TLL, + 0, RLEFT, + " Ol AR,AL\n Ol UR,UL\n", }, + + +/* + * The next rules handle all shift operators. + */ +/* (u)longlong left shift is emulated */ +{ LS, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SAREG|SNAME|SOREG|SCON, TINT, /* will be int */ + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sall AR,AL\n", }, + +{ LS, INAREG|FOREFF, + SAREG, TWORD, + SCON, TANY, + 0, RLEFT, + " sall AR,AL\n", }, + +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shlw AR,AL\n", }, + +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RLEFT, + " shlw AR,AL\n", }, + +{ LS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " salb AR,AL\n", }, + +{ LS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, RLEFT, + " salb AR,AL\n", }, + +/* (u)longlong right shift is emulated */ +{ RS, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SAREG|SNAME|SOREG|SCON, TINT, /* will be int */ + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSWORD, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSWORD, + SCON, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RLEFT, + " sarl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUWORD, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUWORD, + SCON, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RLEFT, + " shrl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SCON, TANY, + 0, RLEFT, + " sarw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SCON, TANY, + 0, RLEFT, + " shrw AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarb AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SCON, TANY, + 0, RLEFT, + " sarb AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrb AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SCON, TANY, + 0, RLEFT, + " shrb AR,AL\n", }, + +/* + * The next rules takes care of assignments. "=". + */ +{ ASSIGN, FOREFF, + SHLL|SNAME|SOREG, TLL, + SCON, TANY, + 0, 0, + " movl AR,AL\n movl UR,UL\n", }, + +{ ASSIGN, FOREFF|INLL, + SHLL, TLL, + SCON, TANY, + 0, RDEST, + " movl AR,AL\n movl UR,UL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SCON, TANY, + 0, 0, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SCON, TANY, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, 0, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RDEST, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, 0, + " movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INCH, + SHCH, TCHAR|TUCHAR, + SCON, TANY, + 0, RDEST, + " movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INLL, + SHLL|SNAME|SOREG, TLL, + SHLL, TLL, + 0, RDEST, + " movl AR,AL\n movl UR,UL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG, TWORD|TPOINT, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RDEST, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF|INCH, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SHCH, TCHAR|TUCHAR|TWORD, + 0, RDEST, + " movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INBREG, + SFLD, TCHAR|TUCHAR, + SBREG|SCON, TCHAR|TUCHAR, + NBREG, RDEST, + "ZE", }, + +{ ASSIGN, FOREFF|INAREG, + SFLD, TANY, + SAREG, TANY, + NAREG, RDEST, + "ZE", }, + +{ ASSIGN, FOREFF, + SFLD, TANY, + SAREG|SNAME|SOREG|SCON, TANY, + NAREG, 0, + "ZE", }, + +{ ASSIGN, INDREG|FOREFF, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + "", }, /* This will always be in the correct register */ + +/* order of table entries is very important here! */ +{ ASSIGN, INFL, + SNAME|SOREG, TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fstt AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstpt AL\n", }, + +{ ASSIGN, INFL, + SNAME|SOREG, TDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fstl AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstpl AL\n", }, + +{ ASSIGN, INFL, + SNAME|SOREG, TFLOAT, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fsts AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TFLOAT, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstps AL\n", }, +/* end very important order */ + +{ ASSIGN, INFL|FOREFF, + SHFL, TLDOUBLE, + SHFL|SOREG|SNAME, TLDOUBLE, + 0, RDEST, + " fldt AR\n", }, + +{ ASSIGN, INFL|FOREFF, + SHFL, TDOUBLE, + SHFL|SOREG|SNAME, TDOUBLE, + 0, RDEST, + " fldl AR\n", }, + +{ ASSIGN, INFL|FOREFF, + SHFL, TFLOAT, + SHFL|SOREG|SNAME, TFLOAT, + 0, RDEST, + " flds AR\n", }, + +/* Do not generate memcpy if return from funcall */ +#if 0 +{ STASG, INAREG|FOREFF, + SOREG|SNAME|SAREG, TPTRTO|TSTRUCT, + SFUNCALL, TPTRTO|TSTRUCT, + 0, RRIGHT, + "", }, +#endif + +{ STASG, INAREG|FOREFF, + SOREG|SNAME, TANY, + SAREG|SOREG|SNAME, TPTRTO|TANY, + NSPECIAL, RRIGHT, + "ZQ", }, + +/* + * DIV/MOD/MUL + */ +/* long long div is emulated */ +{ DIV, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SCREG|SNAME|SOREG|SCON, TLL, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ DIV, INAREG, + SAREG, TSWORD, + SAREG|SNAME|SOREG, TWORD, + NSPECIAL, RDEST, + " cltd\n idivl AR\n", }, + +{ DIV, INAREG, + SAREG, TUWORD|TPOINT, + SAREG|SNAME|SOREG, TUWORD|TPOINT, + NSPECIAL, RDEST, + " xorl %edx,%edx\n divl AR\n", }, + +{ DIV, INAREG, + SAREG, TUSHORT, + SAREG|SNAME|SOREG, TUSHORT, + NSPECIAL, RDEST, + " xorl %edx,%edx\n divw AR\n", }, + +{ DIV, INCH, + SHCH, TUCHAR, + SHCH|SNAME|SOREG, TUCHAR, + NSPECIAL, RDEST, + " xorb %ah,%ah\n divb AR\n", }, + +{ DIV, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fdivl AR\n", }, + +{ DIV, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fdivZAp\n", }, + +/* (u)longlong mod is emulated */ +{ MOD, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SCREG|SNAME|SOREG|SCON, TLL, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ MOD, INAREG, + SAREG, TSWORD, + SAREG|SNAME|SOREG, TSWORD, + NAREG|NSPECIAL, RESC1, + " cltd\n idivl AR\n", }, + +{ MOD, INAREG, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG, TUWORD|TPOINT, + NAREG|NSPECIAL, RESC1, + " xorl %edx,%edx\n divl AR\n", }, + +{ MOD, INAREG, + SAREG, TUSHORT, + SAREG|SNAME|SOREG, TUSHORT, + NAREG|NSPECIAL, RESC1, + " xorl %edx,%edx\n divw AR\n", }, + +{ MOD, INCH, + SHCH, TUCHAR, + SHCH|SNAME|SOREG, TUCHAR, + NBREG|NSPECIAL, RESC1, + " xorb %ah,%ah\n divb AR\n", }, + +/* (u)longlong mul is emulated */ +{ MUL, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SCREG|SNAME|SOREG|SCON, TLL, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ MUL, INAREG, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RLEFT, + " imull AR,AL\n", }, + +{ MUL, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + 0, RLEFT, + " imulw AR,AL\n", }, + +{ MUL, INCH, + SHCH, TCHAR|TUCHAR, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + NSPECIAL, RDEST, + " imulb AR\n", }, + +{ MUL, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fmull AR\n", }, + +{ MUL, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fmulp\n", }, + +/* + * Indirection operators. + */ +{ UMUL, INLL, + SANY, TANY, + SOREG, TLL, + NCREG|NCSL, RESC1, + " movl UL,U1\n movl AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SOREG, TPOINT|TWORD, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +{ UMUL, INCH, + SANY, TANY, + SOREG, TCHAR|TUCHAR, + NBREG|NBSL, RESC1, + " movb AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " movw AL,A1\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TLDOUBLE, + NDREG|NDSL, RESC1, + " fldt AL\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TDOUBLE, + NDREG|NDSL, RESC1, + " fldl AL\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TFLOAT, + NDREG|NDSL, RESC1, + " flds AL\n", }, + +/* + * Logical/branching operators + */ + +/* Comparisions, take care of everything */ +{ OPLOG, FORCC, + SHLL|SOREG|SNAME, TLL, + SHLL, TLL, + 0, 0, + "ZD", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TWORD|TPOINT, + SCON|SAREG, TWORD|TPOINT, + 0, RESCC, + " cmpl AR,AL\n", }, + +{ OPLOG, FORCC, + SCON|SAREG, TWORD|TPOINT, + SAREG|SOREG|SNAME, TWORD|TPOINT, + 0, RESCC, + " cmpl AR,AL\n", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + SCON|SAREG, TANY, + 0, RESCC, + " cmpw AR,AL\n", }, + +{ OPLOG, FORCC, + SBREG|SOREG|SNAME, TCHAR|TUCHAR, + SCON|SBREG, TANY, + 0, RESCC, + " cmpb AR,AL\n", }, + +{ OPLOG, FORCC, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NSPECIAL, 0, + "ZG", }, + +{ OPLOG, FORCC, + SOREG|SNAME, TDOUBLE|TFLOAT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NSPECIAL, 0, + "ZG", }, + +#if 0 +/* Ppro and later only */ +{ OPLOG, FORCC, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RESCC, + "ZA fucomip %st,%st(1)\n", }, +#endif + +{ OPLOG, FORCC, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "diediedie!", }, + +/* AND/OR/ER/NOT */ +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, TWORD, + SCON|SAREG, TWORD, + 0, RLEFT, + " andl AR,AL\n", }, + +{ AND, INCREG|FOREFF, + SCREG, TLL, + SCREG|SOREG|SNAME, TLL, + 0, RLEFT, + " andl AR,AL\n andl UR,UL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TWORD, + SAREG|SOREG|SNAME, TWORD, + 0, RLEFT, + " andl AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + SCON|SAREG, TSHORT|TUSHORT, + 0, RLEFT, + " andw AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TSHORT|TUSHORT, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + 0, RLEFT, + " andw AR,AL\n", }, + +{ AND, INBREG|FOREFF, + SBREG|SOREG|SNAME, TCHAR|TUCHAR, + SCON|SBREG, TCHAR|TUCHAR, + 0, RLEFT, + " andb AR,AL\n", }, + +{ AND, INBREG|FOREFF, + SBREG, TCHAR|TUCHAR, + SBREG|SOREG|SNAME, TCHAR|TUCHAR, + 0, RLEFT, + " andb AR,AL\n", }, +/* AND/OR/ER/NOT */ + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " jmp LL\n", }, + +#ifdef GCC_COMPAT +{ GOTO, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, RNOP, + " jmp *AL\n", }, +#endif + +/* + * Convert LTYPE to reg. + */ +{ OPLTYPE, INLL, + SANY, TANY, + SCREG|SCON|SOREG|SNAME, TLL, + NCREG, RESC1, + " movl UL,U1\n movl AL,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SCON|SOREG|SNAME, TWORD|TPOINT, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SBREG|SOREG|SNAME|SCON, TCHAR|TUCHAR, + NBREG, RESC1, + " movb AL,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SOREG|SNAME|SCON, TSHORT|TUSHORT, + NAREG, RESC1, + " movw AL,A1\n", }, + +{ OPLTYPE, INDREG, + SANY, TLDOUBLE, + SOREG|SNAME, TLDOUBLE, + NDREG, RESC1, + " fldt AL\n", }, + +{ OPLTYPE, INDREG, + SANY, TDOUBLE, + SOREG|SNAME, TDOUBLE, + NDREG, RESC1, + " fldl AL\n", }, + +{ OPLTYPE, INDREG, + SANY, TFLOAT, + SOREG|SNAME, TFLOAT, + NDREG, RESC1, + " flds AL\n", }, + +/* Only used in ?: constructs. The stack already contains correct value */ +{ OPLTYPE, INDREG, + SANY, TFLOAT|TDOUBLE|TLDOUBLE, + SDREG, TFLOAT|TDOUBLE|TLDOUBLE, + NDREG, RESC1, + "", }, + +/* + * Negate a word. + */ + +{ UMINUS, INCREG|FOREFF, + SCREG, TLL, + SCREG, TLL, + 0, RLEFT, + " negl AL\n adcl $0,UL\n negl UL\n", }, + +{ UMINUS, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + " negl AL\n", }, + +{ UMINUS, INAREG|FOREFF, + SAREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RLEFT, + " negw AL\n", }, + +{ UMINUS, INBREG|FOREFF, + SBREG, TCHAR|TUCHAR, + SBREG, TCHAR|TUCHAR, + 0, RLEFT, + " negb AL\n", }, + +{ UMINUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fchs\n", }, + +{ COMPL, INCREG, + SCREG, TLL, + SANY, TANY, + 0, RLEFT, + " notl AL\n notl UL\n", }, + +{ COMPL, INAREG, + SAREG, TWORD, + SANY, TANY, + 0, RLEFT, + " notl AL\n", }, + +{ COMPL, INAREG, + SAREG, TSHORT|TUSHORT, + SANY, TANY, + 0, RLEFT, + " notw AL\n", }, + +{ COMPL, INBREG, + SBREG, TCHAR|TUCHAR, + SANY, TANY, + 0, RLEFT, + " notb AL\n", }, + +/* + * Arguments to functions. + */ +{ FUNARG, FOREFF, + SCON|SCREG|SNAME|SOREG, TLL, + SANY, TLL, + 0, RNULL, + " pushl UL\n pushl AL\n", }, + +{ FUNARG, FOREFF, + SCON|SAREG|SNAME|SOREG, TWORD|TPOINT, + SANY, TWORD|TPOINT, + 0, RNULL, + " pushl AL\n", }, + +{ FUNARG, FOREFF, + SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + 0, RNULL, + " pushl AL\n", }, + +{ FUNARG, FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SANY, TSHORT, + NAREG, 0, + " movswl AL,ZN\n pushl ZN\n", }, + +{ FUNARG, FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SANY, TUSHORT, + NAREG, 0, + " movzwl AL,ZN\n pushl ZN\n", }, + +{ FUNARG, FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SANY, TCHAR, + NAREG, 0, + " movsbl AL,A1\n pushl A1\n", }, + +{ FUNARG, FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SANY, TUCHAR, + NAREG, 0, + " movzbl AL,A1\n pushl A1\n", }, + +{ FUNARG, FOREFF, + SNAME|SOREG, TDOUBLE, + SANY, TDOUBLE, + 0, 0, + " pushl UL\n pushl AL\n", }, + +{ FUNARG, FOREFF, + SDREG, TDOUBLE, + SANY, TDOUBLE, + 0, 0, + " subl $8,%esp\n fstpl (%esp)\n", }, + +{ FUNARG, FOREFF, + SNAME|SOREG, TFLOAT, + SANY, TFLOAT, + 0, 0, + " pushl AL\n", }, + +{ FUNARG, FOREFF, + SDREG, TFLOAT, + SANY, TFLOAT, + 0, 0, + " subl $4,%esp\n fstps (%esp)\n", }, + +{ FUNARG, FOREFF, + SDREG, TLDOUBLE, + SANY, TLDOUBLE, + 0, 0, + " subl $12,%esp\n fstpt (%esp)\n", }, + +{ STARG, FOREFF, + SAREG|SOREG|SNAME|SCON, TANY, + SANY, TSTRUCT, + NSPECIAL|NAREG, 0, + "ZF", }, + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ STASG, DF(STASG), }, + +{ FLD, DF(FLD), }, + +{ OPLEAF, DF(NAME), }, + +/* { INIT, DF(INIT), }, */ + +{ OPUNARY, DF(UMINUS), }, + +{ OPANY, DF(BITYPE), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); |