diff options
Diffstat (limited to 'usr.bin/pcc/arch/x86')
-rw-r--r-- | usr.bin/pcc/arch/x86/code.c | 213 | ||||
-rw-r--r-- | usr.bin/pcc/arch/x86/local.c | 743 | ||||
-rw-r--r-- | usr.bin/pcc/arch/x86/local2.c | 1051 | ||||
-rw-r--r-- | usr.bin/pcc/arch/x86/macdefs.h | 301 | ||||
-rw-r--r-- | usr.bin/pcc/arch/x86/order.c | 287 | ||||
-rw-r--r-- | usr.bin/pcc/arch/x86/table.c | 1453 |
6 files changed, 4048 insertions, 0 deletions
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]); |