diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-09-15 18:12:38 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2007-09-15 18:12:38 +0000 |
commit | 288752b760425fddc6fe00d317697ef966764b4c (patch) | |
tree | 6bee0a7eedda0f3e0b663d60edb6ee68e7cbe197 | |
parent | edb2678b922125cc3a94923d29e556e735c9b7e7 (diff) |
Import ragge's version of PCC into our tree, so we can hack on it more
easy. ok deraadt@ miod@
108 files changed, 51533 insertions, 0 deletions
diff --git a/usr.bin/pcc/Makefile.in b/usr.bin/pcc/Makefile.in new file mode 100644 index 00000000000..a5780ed6a92 --- /dev/null +++ b/usr.bin/pcc/Makefile.in @@ -0,0 +1,32 @@ +# $Id: Makefile.in,v 1.1 2007/09/15 18:12:23 otto Exp $ +# +# Makefile.in for top-level of pcc. +# + +@SET_MAKE@ +CC=@CC@ +CFLAGS=@CFLAGS@ +LDFLAGS=@LDFLAGS@ +CPPFLAGS=@CPPFLAGS@ +YACC=@YACC@ +LEX=@LEX@ + +SUBDIR=cc + +all: ${SUBDIR} + +install: + cd cc && ${MAKE} install + +clean: + cd cc && ${MAKE} clean + +distclean: + cd cc && ${MAKE} distclean + /bin/rm -rf Makefile config.log stamp-h1 config.status \ + configure.lineno config.h autom4te.cache + +${SUBDIR}: nonexistant + cd $@ && $(MAKE) all $(MFLAGS) + +nonexistant: 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]); diff --git a/usr.bin/pcc/cc/Makefile.in b/usr.bin/pcc/cc/Makefile.in new file mode 100644 index 00000000000..f457e761f53 --- /dev/null +++ b/usr.bin/pcc/cc/Makefile.in @@ -0,0 +1,38 @@ +# $Id: Makefile.in,v 1.1 2007/09/15 18:12:31 otto Exp $ +# +# Makefile.in for top-level of pcc. +# + +@SET_MAKE@ +CC=@CC@ +CFLAGS=@CFLAGS@ +LDFLAGS=@LDFLAGS@ +CPPFLAGS=@CPPFLAGS@ +YACC=@YACC@ +LEX=@LEX@ + +SUBDIR=cc cpp ccom + +all: ${SUBDIR} + +install: + cd cc && ${MAKE} install + cd cpp && ${MAKE} install + cd ccom && ${MAKE} install + +clean: + cd cc && ${MAKE} clean + cd cpp && ${MAKE} clean + cd ccom && ${MAKE} clean + +distclean: + cd cc && ${MAKE} distclean + cd cpp && ${MAKE} distclean + cd ccom && ${MAKE} distclean + /bin/rm -rf Makefile config.log stamp-h1 config.status \ + configure.lineno config.h autom4te.cache + +${SUBDIR}: nonexistant + cd $@; $(MAKE) all $(MFLAGS) + +nonexistant: diff --git a/usr.bin/pcc/cc/cc/Makefile.in b/usr.bin/pcc/cc/cc/Makefile.in new file mode 100644 index 00000000000..11efe29fbbb --- /dev/null +++ b/usr.bin/pcc/cc/cc/Makefile.in @@ -0,0 +1,44 @@ +# $Id: Makefile.in,v 1.1 2007/09/15 18:12:31 otto Exp $ +# +# Makefile.in for the cc part of pcc. +# +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libexecdir = @libexecdir@ +includedir = @includedir@ +strip = @strip@ +CC = @CC@ +TARGOS = @targos@ +TARGMACH = @targmach@ +CFLAGS = @CFLAGS@ -DLIBEXECDIR=\"${libexecdir}\" -DINCLUDEDIR=\"${includedir}\" +CPPFLAGS = @CPPFLAGS@ -I../../os/${TARGOS} -Dmach_${TARGMACH} -Dos_${TARGOS} +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ + +OBJS=cc.o +DEST=pcc + +all: ${DEST} + +${DEST}: $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@ + +.c.o: + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $< + +install: + test -z "${DESTDIR}$(bindir)" || mkdir -p "${DESTDIR}$(bindir)" + ${INSTALL_PROGRAM} ${DEST} ${DESTDIR}${bindir} + @if [ ${strip} = yes ]; then \ + strip ${DESTDIR}${bindir}/${DEST} ; \ + echo strip ${DESTDIR}${bindir}/${DEST} ; \ + fi + +clean: + /bin/rm -f $(OBJS) ${DEST} + +distclean: clean + /bin/rm -f Makefile diff --git a/usr.bin/pcc/cc/cc/cc.1 b/usr.bin/pcc/cc/cc/cc.1 new file mode 100644 index 00000000000..be599e48782 --- /dev/null +++ b/usr.bin/pcc/cc/cc/cc.1 @@ -0,0 +1,179 @@ +.\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net> +.\" +.\" Permission to use, copy, modify, and/or distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM +.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND +.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +.\" THIS SOFTWARE. +.\" +.Dd September 14, 2007 +.Dt cc 1 +.Os +.Sh NAME +.Nm cc +.Nd front-end to the C compiler +.Sh SYNOPSIS +.Nm +.Op Fl TODO +.Op infile... +.Pp +.Sh DESCRIPTION +The +.Nm +utility provides a front-end to the PCC C compiler. +Multiple files may be given on the command line. +Unrecognized options are all sent directly to +.Xr ld 1 . +.Pp +.\" Brief description of its syntax: +Filenames that end with +.Sy .c +are passed via +.Xr cpp 1 -> +.Xr ccom 1 -> +.Xr as 1 -> +.Xr ld 1 . +.Pp +Filenames that end with +.Sy .s +are passed via +.Xr as 1 -> +.Xr ld 1 . +.Pp +Filenames that end with +.Sy .o +are passed directly to +.Xr ld 1 . +.Pp +.\" TODO: document when -D__ASSEMBLER__ ?? +.\" TODO: document __PCC__, __PCC_MINOR__, and __PCC_MINORMINOR__ +.\" +The options are as follows: +.Bl -tag -width Ds +.It Fl B Ar prefix +Define alternate prefix path for +.Xr cpp 1 , +.Xr ccom 1 , +.Xr as 1 , +or +.Xr ld 1 +executables. +.\" TODO: provide an example of -B +.It Fl c +Only compile or assemble and then stop. +Do not link. +Note: cannot be combined with +.Fl o +if multiple files are given. +.It Fl d +Sent to assembler. TODO? +.It Fl E +Stop after preprocessing with +.Xr cpp 1 . +Do not compile, assemble, or link. +.It Fl fPIC +Generate PIC code. +See +.Fl k +option. +.\" other -f GCC compatibility flags are ignored for now +.It Fl g +Send +.Fl g +flag to +.Xr ccom 1 +to create debug output. +.It Fl include Ar path +.\" TODO +.It Fl isystem Ar path +.\" TODO +.It Fl k +Tells C compiler to generate PIC code +and tells assembler that PIC code has been generated. +.It Fl L +.\" TODO +.It Fl M +Pass +.Fl M +flag to +.Xr cpp 1 +to generate dependencies for +.Xr make 1 . +.It Fl nostdinc +.\" TODO +.It Fl nostdlib +.\" TODO +.\" implies -nostartfiles ?? +.It Fl nostartfiles +.\" TODO +.It Fl o Ar outfile +Save result to +.Ar outfile . +.It Fl P +TODO: what is this? +.It Fl pg +Not implemented. +.It Fl O +.\" TODO: sets -xtemps for ccom?? +Note: this is unset if +.Fl g +option is set. +.It Fl pthread +Defines +.Sy _PTHREADS +preprocessor directive for +.Xr cpp 1 . +Uses +.Sy -lpthread +for +.Xr ld 1 linker. +.It Fl static +Do not use dynamic linkage. +By default, it will link using the dynamic linker options +and/or shared objects for the platform. +.It Fl S +Stop after compilation by +.Xr ccom 1 . +Do not assemble and do not link. +Note: cannot be combined with +.Fl o +if multiple files are given. +.It Fl t +Passes +.Fl t +to +.Xr cpp 1 +for traditional C preprocessor syntax. +.It Fl v +Outputs the version of +.Nm +and shows what commands will be ran with their command line arguments. +.It Fl x +TODO +.It Fl X +TODO +.It Fl Wl Ar flags +Options for the linker +.\" what is ignored? llist? +.\" TODO: DIUC options? +.El +.Sh SEE ALSO +.Xr as 1 , +.Xr ccom 1 , +.Xr cpp 1 +.Sh HISTORY +The +.Nm +command comes from the original Portable C Compiler by S. C. +Johnson, written in the late 70's. +.Pp +This product includes software developed or owned by Caldera +International, Inc. + diff --git a/usr.bin/pcc/cc/cc/cc.c b/usr.bin/pcc/cc/cc/cc.c new file mode 100644 index 00000000000..8d5fc2900f2 --- /dev/null +++ b/usr.bin/pcc/cc/cc/cc.c @@ -0,0 +1,701 @@ +/* $Id: cc.c,v 1.1 2007/09/15 18:12:32 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. + */ + +/* + * Front-end to the C compiler. + * + * Brief description of its syntax: + * - Files that end with .c are passed via cpp->ccom->as->ld + * - Files that end with .s are passed as->ld + * - Files that end with .o are passed directly to ld + * - Multiple files may be given on the command line. + * - Unrecognized options are all sent directly to ld. + * -c or -S cannot be combined with -o if multiple files are given. + * + * This file should be rewritten readable. + */ +#include <sys/types.h> +#include <sys/wait.h> + +#include <stdio.h> +#include <ctype.h> +#include <signal.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdarg.h> +#include <libgen.h> +#include <errno.h> + +#include "../../config.h" + +#include "ccconfig.h" +/* C command */ + +#define MKS(x) _MKS(x) +#define _MKS(x) #x + +/* + * Many specific definitions, should be declared elsewhere. + */ +#define STDINC "/usr/include" + +#define SBSIZE 10000 +#define MAXINC 100 +#define MAXFIL 100 +#define MAXLIB 10000 +#define MAXAV 10000 +#define MAXOPT 100 +char *tmp3; +char *tmp4; +char *outfile; +char *copy(char *as),*setsuf(char *as, char ch); +int getsuf(char []); +int main(int, char *[]); +void error(char *, ...); +void errorx(int eval, char *, ...); +int nodup(char **, char *); +int callsys(char [], char *[]); +int cunlink(char *); +void dexit(int eval); +void idexit(int); +char *gettmp(); +char *av[MAXAV]; +char *clist[MAXFIL]; +char *llist[MAXLIB]; +char alist[20]; +char *xlist[100]; +int xnum; +int dflag; +int pflag; +int sflag; +int cflag; +int eflag; +int gflag; +int vflag; +int tflag; +int Eflag; +int Oflag; +int kflag; /* generate PIC code */ +int Mflag; /* dependencies only */ +int pgflag; +int exfail; +int Xflag; +int nostartfiles, Bstatic; +int nostdinc, nostdlib; +int onlyas; +int pthreads; + +char *pass0 = LIBEXECDIR "/ccom"; +char *passp = LIBEXECDIR "/cpp"; +char *Bflag; +char *cppadd[] = CPPADD; +char *dynlinker[] = DYNLINKER; +char *crt0file = CRT0FILE; +char *startfiles[] = STARTFILES; +char *endfiles[] = ENDFILES; +char *cppmdadd[] = CPPMDADD; +#ifdef LIBCLIBS +char *libclibs[] = LIBCLIBS; +#else +char *libclibs[] = { "-lc", NULL }; +#endif +#ifndef STARTLABEL +#define STARTLABEL "__start" +#endif + +int +main(int argc, char *argv[]) +{ + char *t, *u; + char *assource; + char **pv, *ptemp[MAXOPT], **pvt; + int nc, nl, i, j, c, nxo, na; + + i = nc = nl = nxo = 0; + pv = ptemp; + while(++i < argc) { + if (argv[i][0] == '-') + switch (argv[i][1]) { + default: + goto passa; + + case 'B': /* other search paths for binaries */ + Bflag = &argv[i][2]; + break; + + case 'X': + Xflag++; + break; + case 'W': /* Ignore (most of) W-flags */ + if (strncmp(argv[i], "-Wl,", 4) == 0) { + /* options to the linker */ + t = &argv[i][4]; + while ((u = strchr(t, ','))) { + *u++ = 0; + llist[nl++] = t; + t = u; + } + llist[nl++] = t; + } + break; + + case 'f': /* GCC compatibility flags */ + if (strcmp(argv[i], "-fPIC") == 0) + kflag++; + /* silently ignore the rest */ + break; + + case 'g': /* create debug output */ + gflag++; + break; + + case 'i': + if (strcmp(argv[i], "-isystem") == 0) { + *pv++ = "-S"; + *pv++ = argv[++i]; + } else if (strcmp(argv[i], "-include") == 0) { + *pv++ = "-i"; + *pv++ = argv[++i]; + } else + goto passa; + break; + + case 'k': /* generate PIC code */ + kflag++; + break; + + case 'n': /* handle -n flags */ + if (strcmp(argv[i], "-nostdinc") == 0) + nostdinc++; + if (strcmp(argv[i], "-nostdlib") == 0) { + nostdlib++; + nostartfiles++; + } else if (strcmp(argv[i], "-nostartfiles") == 0) + nostartfiles = 1; + else + goto passa; + break; + + case 'p': + if (strcmp(argv[i], "-pg") == 0) + pgflag++; + else if (strcmp(argv[i], "-pthread") == 0) + pthreads++; + else + errorx(1, "unknown option %s", argv[i]); + break; + + case 'x': + xlist[xnum++] = argv[i]; + break; + case 't': + tflag++; + break; + case 'S': + sflag++; + cflag++; + break; + case 'o': + if (outfile) + errorx(8, "too many -o"); + outfile = argv[++i]; + break; + case 'O': + Oflag++; + break; + case 'E': + Eflag++; + break; + case 'P': + pflag++; + *pv++ = argv[i]; + case 'c': + cflag++; + break; + +#if 0 + case '2': + if(argv[i][2] == '\0') + pref = "/lib/crt2.o"; + else { + pref = "/lib/crt20.o"; + } + break; +#endif + case 'D': + case 'I': + case 'U': + case 'C': + *pv++ = argv[i]; + if (argv[i][2] == 0) + *pv++ = argv[++i]; + if (pv >= ptemp+MAXOPT) + { + error("Too many DIUC options"); + --pv; + } + break; + + case 'M': + Mflag++; + break; + + case 'd': + dflag++; + strncpy(alist, argv[i], 19); + break; + case 'v': + printf("%s\n", VERSSTR); + vflag++; + break; + + case 's': + if (strcmp(argv[i], "-static") == 0) + Bstatic = 1; + else + goto passa; + break; + } else { + passa: + t = argv[i]; + if (*argv[i] == '-' && argv[i][1] == 'L') + ; + else if((c=getsuf(t))=='c' || c=='S' || + c=='s'|| Eflag) { + clist[nc++] = t; + if (nc>=MAXFIL) + { + error("Too many source files"); + exit(1); + } + t = setsuf(t, 'o'); + } + if (nodup(llist, t)) { + llist[nl++] = t; + if (nl >= MAXLIB) + { + error("Too many object/library files"); + exit(1); + } + if (getsuf(t)=='o') + nxo++; + } + } + } + /* Sanity checking */ + if (nc == 0 && nl == 0) + errorx(8, "no input files"); + if (outfile && (cflag || sflag) && nc > 1) + errorx(8, "-o given with -c || -S and more than one file"); + if (outfile && clist[0] && strcmp(outfile, clist[0]) == 0) + errorx(8, "output file will be clobbered"); + + if (gflag) Oflag = 0; +#if 0 + if (proflag) + pref = "/lib/mcrt0.o"; +#endif + if(nc==0) + goto nocom; + if (pflag==0) { + tmp3 = gettmp(); + tmp4 = gettmp(); + } + if (signal(SIGINT, SIG_IGN) != SIG_IGN) /* interrupt */ + signal(SIGINT, idexit); + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) /* terminate */ + signal(SIGTERM, idexit); + pvt = pv; + for (i=0; i<nc; i++) { + /* + * C preprocessor + */ + if (nc>1 && !Eflag) + printf("%s:\n", clist[i]); + onlyas = 0; + assource = tmp3; + if (getsuf(clist[i])=='s') { + assource = clist[i]; + onlyas = 1; + goto assemble; + } else if (getsuf(clist[i])=='S') { + assource = clist[i]; + onlyas = 1; + } + if (pflag) + tmp4 = setsuf(clist[i], 'i'); + na = 0; + av[na++] = "cpp"; + av[na++] = "-D__PCC__=" MKS(PCC_MAJOR); + av[na++] = "-D__PCC_MINOR__=" MKS(PCC_MINOR); + av[na++] = "-D__PCC_MINORMINOR__=" MKS(PCC_MINORMINOR); + if (getsuf(clist[i])=='S') + av[na++] = "-D__ASSEMBLER__"; + if (pthreads) + av[na++] = "-D_PTHREADS"; + if (Mflag) + av[na++] = "-M"; + for (j = 0; cppadd[j]; j++) + av[na++] = cppadd[j]; + for (j = 0; cppmdadd[j]; j++) + av[na++] = cppmdadd[j]; + if (tflag) + av[na++] = "-t"; + for(pv=ptemp; pv <pvt; pv++) + av[na++] = *pv; + if (!nostdinc) + av[na++] = "-S", av[na++] = STDINC; + av[na++] = clist[i]; + if (!Eflag && !Mflag) + av[na++] = tmp4; + av[na++]=0; + if (callsys(passp, av)) + {exfail++; eflag++;} + if (Eflag || Mflag) + continue; + if (onlyas) + goto assemble; + + /* + * C compiler + */ + na = 0; + av[na++]= "ccom"; + if (gflag) + av[na++] = "-g"; + if (kflag) + av[na++] = "-k"; + if (Oflag) { + av[na++] = "-xtemps"; + } + for (j = 0; j < xnum; j++) + av[na++] = xlist[j]; + av[na++] = tmp4; + if (pflag || exfail) + { + cflag++; + continue; + } + if(sflag) { + if (outfile) + assource = tmp3 = outfile; + else + assource = tmp3 = setsuf(clist[i], 's'); + } + av[na++] = tmp3; +#if 0 + if (proflag) { + av[3] = "-XP"; + av[4] = 0; + } else + av[3] = 0; +#endif + av[na++] = NULL; + if (callsys(pass0, av)) { + cflag++; + eflag++; + continue; + } + if (sflag) + continue; + + /* + * Assembler + */ + assemble: + na = 0; + av[na++] = "as"; + if (kflag) + av[na++] = "-k"; + av[na++] = "-o"; + if (outfile && cflag) + av[na++] = outfile; + else + av[na++] = setsuf(clist[i], 'o'); + av[na++] = onlyas ? tmp4 : assource; + if (dflag) + av[na++] = alist; + av[na++] = 0; + if (callsys("/bin/as", av)) { + cflag++; + eflag++; + cunlink(tmp4); + continue; + } + cunlink(tmp4); + } + + if (Eflag || Mflag) + dexit(eflag); + + /* + * Linker + */ +nocom: + if (cflag==0 && nl!=0) { + j = 0; + av[j++] = "ld"; + av[j++] = "-X"; + av[j++] = "-d"; + av[j++] = "-e"; + av[j++] = STARTLABEL; + if (Bstatic == 0) { /* Dynamic linkage */ + for (i = 0; dynlinker[i]; i++) + av[j++] = dynlinker[i]; + } else + av[j++] = "-Bstatic"; + if (outfile) { + av[j++] = "-o"; + av[j++] = outfile; + } + if (!nostartfiles) { + av[j++] = crt0file; + for (i = 0; startfiles[i]; i++) + av[j++] = startfiles[i]; + } + i = 0; + while(i<nl) { + av[j++] = llist[i++]; + if (j >= MAXAV) + error("Too many ld options"); + } +#if 0 + if (gflag) + av[j++] = "-lg"; +#endif + if (pthreads) + av[j++] = "-lpthread"; + if (!nostdlib) + for (i = 0; libclibs[i]; i++) + av[j++] = libclibs[i]; + if (!nostartfiles) { + for (i = 0; endfiles[i]; i++) + av[j++] = endfiles[i]; + } + av[j++] = 0; + eflag |= callsys("/bin/ld", av); + if (nc==1 && nxo==1 && eflag==0) + cunlink(setsuf(clist[0], 'o')); + else if (nc > 0 && eflag == 0) { + /* remove .o files XXX ugly */ + for (i = 0; i < nc; i++) + cunlink(setsuf(clist[i], 'o')); + } + } + dexit(eflag); + return 0; +} + +/* + * exit and cleanup after interrupt. + */ +void +idexit(int arg) +{ + dexit(100); +} + +/* + * exit and cleanup. + */ +void +dexit(int eval) +{ + if (!pflag && !Xflag) { + if (sflag==0) + cunlink(tmp3); + cunlink(tmp4); + } + exit(eval); +} + +static void +ccerror(char *s, va_list ap) +{ + vfprintf(Eflag ? stderr : stdout, s, ap); + putc('\n', Eflag? stderr : stdout); + exfail++; + cflag++; + eflag++; +} + +/* + * complain a bit. + */ +void +error(char *s, ...) +{ + va_list ap; + + va_start(ap, s); + ccerror(s, ap); + va_end(ap); +} + +/* + * complain a bit and then exit. + */ +void +errorx(int eval, char *s, ...) +{ + va_list ap; + + va_start(ap, s); + ccerror(s, ap); + va_end(ap); + dexit(eval); +} + +int +getsuf(as) +char as[]; +{ + register char *s; + + if ((s = strrchr(as, '.')) && s[1] != '\0' && s[2] == '\0') + return s[1]; + return(0); +} + +/* + * Get basename of string s and change its suffix to ch. + */ +char * +setsuf(char *s, char ch) +{ + s = copy(basename(s)); + s[strlen(s) - 1] = ch; + return(s); +} + +int +callsys(f, v) +char f[], *v[]; { + int t, status; + char *s; + + if (vflag) { + fprintf(stderr, "%s ", f); + for (t = 1; v[t]; t++) + fprintf(stderr, "%s ", v[t]); + fprintf(stderr, "\n"); + } + + if ((t=fork())==0) { + if (Bflag) { + int len = strlen(Bflag) + 8; + char *a = malloc(len); + if ((s = strrchr(f, '/'))) { + strlcpy(a, Bflag, len); + strlcat(a, s, len); + execv(a, v); + } + } + execv(f, v); + if ((s = strrchr(f, '/'))) + execvp(s+1, v); + printf("Can't find %s\n", f); + exit(100); + } else + if (t == -1) { + printf("Try again\n"); + return(100); + } + while(t!=wait(&status)); + if ((t=(status&0377)) != 0 && t!=14) { + if (t!=2) /* interrupt */ + errorx(8, "Fatal error in %s", f); + dexit(eflag); + } + return((status>>8) & 0377); +} + +char * +copy(char *as) +{ + char *p; + + if ((p = strdup(as)) == NULL) + errorx(8, "no space for file names"); + + return p; +} + +int +nodup(l, os) +char **l, *os; +{ + register char *t, *s; + register int c; + + s = os; + if (getsuf(s) != 'o') + return(1); + while((t = *l++)) { + while((c = *s++)) + if (c != *t++) + break; + if (*t=='\0' && c=='\0') + return(0); + s = os; + } + return(1); +} + +int +cunlink(f) +char *f; +{ + if (f==0 || Xflag) + return(0); + return(unlink(f)); +} + +char * +gettmp() +{ + char *sfn = strdup("/tmp/ctm.XXXXXX"); + int fd = -1; + + if ((fd = mkstemp(sfn)) == -1) { + fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); + exit(8); + } + close(fd); + + return sfn; +} diff --git a/usr.bin/pcc/cc/ccom/Makefile.in b/usr.bin/pcc/cc/ccom/Makefile.in new file mode 100644 index 00000000000..0cc29c5a565 --- /dev/null +++ b/usr.bin/pcc/cc/ccom/Makefile.in @@ -0,0 +1,107 @@ +# $Id: Makefile.in,v 1.1 2007/09/15 18:12:32 otto Exp $ +# +# Makefile.in for ccom +# +XFL=-DPCC_DEBUG -DGCC_COMPAT \ + -Wall -Wmissing-prototypes -Wstrict-prototypes -Werror + +CC = @CC@ +CFLAGS = @CFLAGS@ $(XFL) -I. -I${MIPDIR} -I$(MDIR) -Dmach_${TARGMACH} \ + -I../../os/${TARGOS} +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +YACC = @YACC@ +TARGOS = @targos@ +TARGMACH = @targmach@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +libexecdir = @libexecdir@ +strip = @strip@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ + +MDIR=../../arch/$(TARGMACH) +MIPDIR=../../mip + +OBJS1=optim.o pftn.o scan.o trees.o cgram.o inline.o symtabs.o \ + gcc_compat.o init.o local.o code.o stabs.o + +OBJS2=match.o reader.o optim2.o regs.o local2.o order.o table.o + +OBJS=$(OBJS1) $(OBJS2) common.o main.o external.o + +DEST=ccom + +all: ${DEST} + +${DEST}: $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@ + +.c.o: + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< + +local.o: $(MDIR)/local.c + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MDIR)/local.c + +local2.o: $(MDIR)/local2.c + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MDIR)/local2.c + +code.o: $(MDIR)/code.c + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MDIR)/code.c + +order.o: $(MDIR)/order.c + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MDIR)/order.c + +table.o: $(MDIR)/table.c + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MDIR)/table.c + +match.o: $(MIPDIR)/match.c + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/match.c + +reader.o: $(MIPDIR)/reader.c + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/reader.c + +optim2.o: $(MIPDIR)/optim2.c + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/optim2.c + +regs.o: $(MIPDIR)/regs.c + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/regs.c + +common.o: $(MIPDIR)/common.c + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/common.c + +external.h external.c: ${MIPDIR}/mkext.c $(MDIR)/table.c + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -DMKEXT -o mkext ${MIPDIR}/mkext.c \ + $(MDIR)/table.c ${MIPDIR}/common.c + ./mkext + +trees.c: pass2.h + +pass2.h: external.h + +cgram.c: cgram.y + $(YACC) $(YFLAGS) -d $< + mv y.tab.c cgram.c + mv y.tab.h cgram.h + +scan.c: scan.l cgram.c + $(LEX) $(LFLAGS) $< + mv lex.yy.c scan.c + +optim2.o reader.o: external.h + +install: + test -z "${DESTDIR}$(libexecdir)" || mkdir -p "${DESTDIR}$(libexecdir)" + ${INSTALL_PROGRAM} ${DEST} ${DESTDIR}${libexecdir} + @if [ ${strip} = yes ]; then \ + strip ${DESTDIR}${libexecdir}/${DEST} ; \ + echo strip ${DESTDIR}${libexecdir}/${DEST} ; \ + fi + +clean: + /bin/rm -f $(OBJS) ccom scan.c cgram.[ch] mkext external.[ch] + +distclean: clean + /bin/rm -f Makefile diff --git a/usr.bin/pcc/cc/ccom/ccom.1 b/usr.bin/pcc/cc/ccom/ccom.1 new file mode 100644 index 00000000000..3205366a5a7 --- /dev/null +++ b/usr.bin/pcc/cc/ccom/ccom.1 @@ -0,0 +1,148 @@ +.\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net> +.\" Permission to use, copy, modify, and/or distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM +.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND +.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +.\" THIS SOFTWARE. +.Dd September 14, 2007 +.Dt ccom 1 +.Os +.Sh NAME +.Nm ccom +.Nd C compiler +.Sh SYNOPSIS +.Nm +.Op Fl X Ar flags +.Op infile +.Op outfile +.Pp +.Sh DESCRIPTION +The +.Nm +utility provides a C compiler. +The frontend is usually +.Xr pcc 1 . +It is \fBnot\fR intended to be run directly. +.Pp +.Nm +reads the C source from +.Ar infile +or standard input and writes the assembler source +to +.Ar outfile +or to standard output. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl g +Enable debugging. +.\" built into binary, explain stabs? +.It Fl s +Print statistics to standard error when complete. +This includes: +name table entries, name string size, permanent allocated memory, +temporary allocated memory, lost memory, argument list unions, +dimension/function unions, struct/union/enum blocks, inline node count, +inline control blocks, and permanent symtab entries. +.\" TODO: explain units for above? +.It Fl W Ar flags +Report warnings. +(Do some basic checks.) +NOTE! These are subject to change RSN! +.Ar Flags +is one or more of the following: +.Bl -tag -width Ds +.It Sy implicit +Implies +.Sy implicit-int +and +.Sy implicit-function-declaration . +.It Sy implicit-int +TODO +.It Sy implicit-function-declaration +Report if no prototype for function. +.It Sy missing-prototypes +TODO +.It Sy strict-prototypes +TODO +.El +.\" +.It Fl x Ar optimizations +.Ar optimizations +is one or more of the following: +.Bl -tag -width deljumps +.It Sy deljumps +Delete redundant jumps and dead code. +.It Sy ssa +Convert statements into SSA form for optimization. Not yet finished. +.It Sy tailcall +Currently not implemented. +.It Sy temps +Setting this flag allow variables to be put into registers, for further +optimization by the register allocator. +.El +.\" +.It Fl X Ar C specific debugging flags +.Ar Flags +is one or more of the following: +.Bl -tag -width Ds +.It Sy b +Building of parse trees +.It Sy d +Declarations, more d gives more output +.It Sy t +Type conversions +.It Sy i +Initializations +.It Sy e +Pass1 trees at exit +.It Sy x +Target-specific flag, used in machine-dependent code +.El +.\" +.It Fl Z Ar Code generator (pass2) specific debugging flags +.Ar Flags +is one or more of the following: +.Bl -tag -width Ds +.It Sy e +Trees when entering pass2 +.It Sy o +Instruction generator +.It Sy f +Instruction matcher, may provide much output +.It Sy r +Register allocator +.It Sy t +Type matching in instruction generator +.It Sy s +Shape matching in instruction generator +.It Sy u +Sethi-Ullman computations +.It Sy x +Target-specific flag, used in machine-dependent code +.El +.Sh SEE ALSO +.Xr as 1 , +.Xr cpp 1 , +.Xr pcc 1 +.Sh HISTORY +The +.Nm +compiler is based on the original Portable C Compiler by S. C. +Johnson, written in the late 70's. +Even though much of the compiler has been rewritten, some of the +basics still remain. +About 50% of the frontend code and 80% of the backend code has been +rewritten. +Most is written by Anders Magnusson, with the exception of +the data-flow analysis part and the SSA conversion code which is +written by Peter A Jonsson, and the Mips port that were written as +part of a project by undergraduate students at Lulea University of +Technology. diff --git a/usr.bin/pcc/cc/ccom/cgram.y b/usr.bin/pcc/cc/ccom/cgram.y new file mode 100644 index 00000000000..3393bf6e13b --- /dev/null +++ b/usr.bin/pcc/cc/ccom/cgram.y @@ -0,0 +1,1399 @@ +/* $Id: cgram.y,v 1.1 2007/09/15 18:12:33 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. + */ + +/* + * 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 conditions and 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. + */ + +/* + * Comments for this grammar file. Ragge 021123 + * + * ANSI support required rewrite of the function header and declaration + * rules almost totally. + * + * The lex/yacc shared keywords are now split from the keywords used + * in the rest of the compiler, to simplify use of other frontends. + */ + +/* + * At last count, there were 3 shift/reduce and no reduce/reduce conflicts + * Two was funct_idn and the third was "dangling else". + */ + +/* + * Token used in C lex/yacc communications. + */ +%token C_WSTRING /* a wide string constant */ +%token C_STRING /* a string constant */ +%token C_ICON /* an integer constant */ +%token C_FCON /* a floating point constant */ +%token C_NAME /* an identifier */ +%token C_TYPENAME /* a typedef'd name */ +%token C_ANDAND /* && */ +%token C_OROR /* || */ +%token C_GOTO /* unconditional goto */ +%token C_RETURN /* return from function */ +%token C_TYPE /* a type */ +%token C_CLASS /* a storage class */ +%token C_ASOP /* assignment ops */ +%token C_RELOP /* <=, <, >=, > */ +%token C_EQUOP /* ==, != */ +%token C_DIVOP /* /, % */ +%token C_SHIFTOP /* <<, >> */ +%token C_INCOP /* ++, -- */ +%token C_UNOP /* !, ~ */ +%token C_STROP /* ., -> */ +%token C_STRUCT +%token C_IF +%token C_ELSE +%token C_SWITCH +%token C_BREAK +%token C_CONTINUE +%token C_WHILE +%token C_DO +%token C_FOR +%token C_DEFAULT +%token C_CASE +%token C_SIZEOF +%token C_ENUM +%token C_ELLIPSIS +%token C_QUALIFIER +%token C_FUNSPEC +%token C_ASM + +/* + * Precedence + */ +%left ',' +%right '=' C_ASOP +%right '?' ':' +%left C_OROR +%left C_ANDAND +%left '|' +%left '^' +%left '&' +%left C_EQUOP +%left C_RELOP +%left C_SHIFTOP +%left '+' '-' +%left '*' C_DIVOP +%right C_UNOP +%right C_INCOP C_SIZEOF +%left '[' '(' C_STROP +%{ +# include "pass1.h" +# include <stdarg.h> +# include <string.h> + +static int fun_inline; /* Reading an inline function */ +int oldstyle; /* Current function being defined */ +int noretype; +static struct symtab *xnf; +#ifdef GCC_COMPAT +char *renname; /* for renaming of variables */ +#endif + + +static NODE *bdty(int op, ...); +static void fend(void); +static void fundef(NODE *tp, NODE *p); +static void olddecl(NODE *p); +static struct symtab *init_declarator(NODE *tn, NODE *p, int assign); +static void resetbc(int mask); +static void swend(void); +static void addcase(NODE *p); +static void adddef(void); +static void savebc(void); +static void swstart(int); +static NODE * structref(NODE *p, int f, char *name); +static char *mkpstr(char *str); +static struct symtab *clbrace(NODE *); + +/* + * State for saving current switch state (when nested switches). + */ +struct savbc { + struct savbc *next; + int brklab; + int contlab; + int flostat; + int swx; +} *savbc, *savctx; + +%} + +%union { + int intval; + NODE *nodep; + struct symtab *symp; + struct rstack *rp; + char *strp; +} + + /* define types */ +%start ext_def_list + +%type <intval> con_e ifelprefix ifprefix whprefix forprefix doprefix switchpart + type_qualifier_list +%type <nodep> e .e term enum_dcl struct_dcl cast_type funct_idn declarator + direct_declarator elist type_specifier merge_attribs + parameter_declaration abstract_declarator initializer + parameter_type_list parameter_list addrlbl + declaration_specifiers pointer direct_abstract_declarator + specifier_qualifier_list merge_specifiers nocon_e + identifier_list arg_param_list arg_declaration arg_dcl_list + designator_list designator +%type <strp> string wstring C_STRING C_WSTRING +%type <rp> enum_head str_head +%type <symp> xnfdeclarator clbrace + +%type <intval> C_CLASS C_STRUCT C_RELOP C_DIVOP C_SHIFTOP + C_ANDAND C_OROR C_STROP C_INCOP C_UNOP C_ASOP C_EQUOP +%type <nodep> C_TYPE C_QUALIFIER C_ICON C_FCON +%type <strp> C_NAME C_TYPENAME + +%% + +ext_def_list: ext_def_list external_def + | { ftnend(); } + ; + +external_def: function_definition { blevel = 0; } + | declaration { blevel = 0; symclear(0); } + | asmstatement ';' + | ';' + | error { blevel = 0; } + ; + +function_definition: + /* Ansi (or K&R header without parameter types) */ + declaration_specifiers declarator { + fundef($1, $2); + } compoundstmt { fend(); } + /* Same as above but without declaring function type */ + | declarator { + noretype = 1; + fundef(mkty(INT, 0, MKSUE(INT)), $1); + } compoundstmt { fend(); noretype = 0; } + /* K&R function without type declaration */ + | declarator { + noretype = 1; + if (oldstyle == 0) + uerror("bad declaration in ansi function"); + fundef(mkty(INT, 0, MKSUE(INT)), $1); + } arg_dcl_list compoundstmt { fend(); noretype = 0; } + /* K&R function with type declaration */ + | declaration_specifiers declarator { + if (oldstyle == 0) + uerror("bad declaration in ansi function"); + fundef($1, $2); + } arg_dcl_list compoundstmt { fend(); } + ; + +/* + * Returns a node pointer or NULL, if no types at all given. + * Type trees are checked for correctness and merged into one + * type node in typenode(). + */ +declaration_specifiers: + merge_attribs { $$ = typenode($1); } + ; + +merge_attribs: C_CLASS { $$ = block(CLASS, NIL, NIL, $1, 0, 0); } + | C_CLASS merge_attribs { $$ = block(CLASS, $2, NIL, $1,0,0);} + | type_specifier { $$ = $1; } + | type_specifier merge_attribs { $1->n_left = $2; $$ = $1; } + | C_QUALIFIER { $$ = $1; } + | C_QUALIFIER merge_attribs { $1->n_left = $2; $$ = $1; } + | function_specifiers { $$ = NIL; } + | function_specifiers merge_attribs { $$ = $2; } + ; + +function_specifiers: + C_FUNSPEC { + if (fun_inline) + uerror("too many inline"); + fun_inline = 1; + } + ; + +type_specifier: C_TYPE { $$ = $1; } + | C_TYPENAME { + struct symtab *sp = lookup($1, 0); + $$ = mkty(sp->stype, sp->sdf, sp->ssue); + $$->n_sp = sp; + } + | struct_dcl { $$ = $1; } + | enum_dcl { $$ = $1; } + ; + +/* + * Adds a pointer list to front of the declarators. + * Note the UMUL right node pointer usage. + */ +declarator: pointer direct_declarator { + $$ = $1; $1->n_right->n_left = $2; + } + | direct_declarator { $$ = $1; } + ; + +/* + * Return an UMUL node type linked list of indirections. + */ +pointer: '*' { $$ = bdty(UMUL, NIL); $$->n_right = $$; } + | '*' type_qualifier_list { + $$ = bdty(UMUL, NIL); + $$->n_qual = $2; + $$->n_right = $$; + } + | '*' pointer { + $$ = bdty(UMUL, $2); + $$->n_right = $2->n_right; + } + | '*' type_qualifier_list pointer { + $$ = bdty(UMUL, $3); + $$->n_qual = $2; + $$->n_right = $3->n_right; + } + ; + +type_qualifier_list: + C_QUALIFIER { $$ = $1->n_type; nfree($1); } + | type_qualifier_list C_QUALIFIER { + $$ = $1 | $2->n_type; nfree($2); + } + ; + +/* + * Sets up a function declarator. The call node will have its parameters + * connected to its right node pointer. + */ +direct_declarator: C_NAME { $$ = bdty(NAME, $1); } + | '(' declarator ')' { $$ = $2; } + | direct_declarator '[' nocon_e ']' { + $$ = block(LB, $1, $3, INT, 0, MKSUE(INT)); + } + | direct_declarator '[' ']' { $$ = bdty(LB, $1, 0); } + | direct_declarator '(' notype parameter_type_list ')' { + $$ = bdty(CALL, $1, $4); + } + | direct_declarator '(' notype identifier_list ')' { + $$ = bdty(CALL, $1, $4); + if (blevel != 0) + uerror("function declaration in bad context"); + oldstyle = 1; + } + | direct_declarator '(' ')' { $$ = bdty(UCALL, $1); } + ; + +notype: { /* extern int notype, doproto; notype = 0; doproto=1; printf("notype\n"); */ } + ; + +identifier_list: C_NAME { $$ = bdty(NAME, $1); $$->n_type = FARG; } + | identifier_list ',' C_NAME { + $$ = bdty(NAME, $3); + $$->n_type = FARG; + $$ = block(CM, $1, $$, 0, 0, 0); + } + ; + +/* + * Returns as parameter_list, but can add an additional ELLIPSIS node. + * Calls revert() to get the parameter list in the forward order. + */ +parameter_type_list: + parameter_list { $$ = $1; } + | parameter_list ',' C_ELLIPSIS { + $$ = block(CM, $1, block(ELLIPSIS, NIL, NIL, 0, 0, 0), + 0, 0, 0); + } + ; + +/* + * Returns a linked lists of nodes of op CM with parameters on + * its right and additional CM nodes of its left pointer. + * No CM nodes if only one parameter. + */ +parameter_list: parameter_declaration { $$ = $1; } + | parameter_list ',' parameter_declaration { + $$ = block(CM, $1, $3, 0, 0, 0); + } + ; + +/* + * Returns a node pointer to the declaration. + */ +parameter_declaration: + declaration_specifiers declarator { + $$ = tymerge($1, $2); + nfree($1); + } + | declaration_specifiers abstract_declarator { + $$ = tymerge($1, $2); + nfree($1); + } + | declaration_specifiers { + $$ = tymerge($1, bdty(NAME, NULL)); + nfree($1); + } + ; + +abstract_declarator: + pointer { $$ = $1; $1->n_right->n_left = bdty(NAME, NULL); } + | direct_abstract_declarator { $$ = $1; } + | pointer direct_abstract_declarator { + $$ = $1; $1->n_right->n_left = $2; + } + ; + +direct_abstract_declarator: + '(' abstract_declarator ')' { $$ = $2; } + | '[' ']' { $$ = bdty(LB, bdty(NAME, NULL), 0); } + | '[' con_e ']' { $$ = bdty(LB, bdty(NAME, NULL), $2); } + | direct_abstract_declarator '[' ']' { $$ = bdty(LB, $1, 0); } + | direct_abstract_declarator '[' con_e ']' { + $$ = bdty(LB, $1, $3); + } + | '(' ')' { $$ = bdty(UCALL, bdty(NAME, NULL)); } + | '(' notype parameter_type_list ')' { + $$ = bdty(CALL, bdty(NAME, NULL), $3); + } + | direct_abstract_declarator '(' ')' { + $$ = bdty(UCALL, $1); + } + | direct_abstract_declarator '(' notype parameter_type_list ')' { + $$ = bdty(CALL, $1, $4); + } + ; + +/* + * K&R arg declaration, between ) and { + */ +arg_dcl_list: arg_declaration + | arg_dcl_list arg_declaration + ; + + +arg_declaration: declaration_specifiers arg_param_list ';' { + nfree($1); + } + ; + +arg_param_list: declarator { olddecl(tymerge($<nodep>0, $1)); } + | arg_param_list ',' declarator { + olddecl(tymerge($<nodep>0, $3)); + } + ; + +/* + * Declarations in beginning of blocks. + */ +declaration_list: declaration + | declaration_list declaration + ; + +/* + * Here starts the old YACC code. + */ + +stmt_list: stmt_list statement + | { bccode(); } + ; + +/* + * Variables are declared in init_declarator. + */ +declaration: declaration_specifiers ';' { nfree($1); goto inl; } + | declaration_specifiers init_declarator_list ';' { + nfree($1); + inl: + fun_inline = 0; + } + ; + +/* + * Normal declaration of variables. curtype contains the current type node. + * Returns nothing, variables are declared in init_declarator. + */ +init_declarator_list: + init_declarator + | init_declarator_list ',' { $<nodep>$ = $<nodep>0; } init_declarator + ; + +enum_dcl: enum_head '{' moe_list optcomma '}' { $$ = dclstruct($1); } + | C_ENUM C_NAME { $$ = rstruct($2,0); } + | C_ENUM C_TYPENAME { $$ = rstruct($2,0); } + ; + +enum_head: C_ENUM { $$ = bstruct(NULL,0); } + | C_ENUM C_NAME { $$ = bstruct($2,0); } + | C_ENUM C_TYPENAME { $$ = bstruct($2,0); } + ; + +moe_list: moe + | moe_list ',' moe + ; + +moe: C_NAME { moedef( $1 ); } + | C_NAME '=' con_e { strucoff = $3; moedef( $1 ); } + ; + +struct_dcl: str_head '{' struct_dcl_list '}' { $$ = dclstruct($1); } + | C_STRUCT C_NAME { $$ = rstruct($2,$1); } + | C_STRUCT C_TYPENAME { $$ = rstruct($2,$1); } + | str_head '{' '}' { +#ifndef GCC_COMPAT + werror("gcc extension"); +#endif + $$ = dclstruct($1); + } + ; + +str_head: C_STRUCT { $$ = bstruct(NULL, $1); } + | C_STRUCT C_NAME { $$ = bstruct($2,$1); } + | C_STRUCT C_TYPENAME { $$ = bstruct($2,$1); } + ; + +struct_dcl_list: struct_declaration + | struct_dcl_list struct_declaration + ; + +struct_declaration: + specifier_qualifier_list struct_declarator_list ';' { + nfree($1); + } + ; + +specifier_qualifier_list: + merge_specifiers { $$ = typenode($1); } + ; + +merge_specifiers: type_specifier merge_specifiers { $1->n_left = $2;$$ = $1; } + | type_specifier { $$ = $1; } + | C_QUALIFIER merge_specifiers { $1->n_left = $2; $$ = $1; } + | C_QUALIFIER { $$ = $1; } + ; + +struct_declarator_list: + struct_declarator { } + | struct_declarator_list ',' { $<nodep>$=$<nodep>0; } + struct_declarator { } + ; + +struct_declarator: declarator { + tymerge($<nodep>0, $1); + $1->n_sp = getsymtab((char *)$1->n_sp, SMOSNAME); /* XXX */ + defid($1, $<nodep>0->n_lval); + nfree($1); + } + | ':' con_e { + if (!(instruct&INSTRUCT)) + uerror( "field outside of structure" ); + falloc(NULL, $2, -1, $<nodep>0); + } + | declarator ':' con_e { + if (!(instruct&INSTRUCT)) + uerror( "field outside of structure" ); + if( $3<0 || $3 >= FIELD ){ + uerror( "illegal field size" ); + $3 = 1; + } + if ($1->n_op == NAME) { + tymerge($<nodep>0, $1); + $1->n_sp = getsymtab((char *)$1->n_sp,SMOSNAME); + defid($1, FIELD|$3); + nfree($1); + } else + uerror("illegal declarator"); + } + ; + + /* always preceeded by attributes */ +xnfdeclarator: declarator { $$ = xnf = init_declarator($<nodep>0, $1, 1); } + ; + +/* + * Handles declarations and assignments. + * Returns nothing. + */ +init_declarator: declarator { init_declarator($<nodep>0, $1, 0); } + | declarator C_ASM '(' string ')' { +#ifdef GCC_COMPAT + renname = $4; + init_declarator($<nodep>0, $1, 0); +#else + werror("gcc extension"); + init_declarator($<nodep>0, $1, 0); +#endif + } + | xnfdeclarator '=' e { simpleinit($1, $3); xnf = NULL; } + | xnfdeclarator '=' begbr init_list optcomma '}' { + endinit(); + xnf = NULL; + } + | xnfdeclarator '=' addrlbl { simpleinit($1, $3); xnf = NULL; } + ; + +begbr: '{' { beginit($<symp>-1); } + ; + +initializer: e %prec ',' { $$ = $1; } + | addrlbl { $$ = $1; } + | ibrace init_list optcomma '}' { $$ = NULL; } + ; + +init_list: designation initializer { asginit($2); } + | init_list ',' designation initializer { asginit($4); } + ; + +designation: designator_list '=' { desinit($1); } + | { /* empty */ } + ; + +designator_list: designator { $$ = $1; } + | designator_list designator { $$ = $2; $$->n_left = $1; } + ; + +designator: '[' con_e ']' { $$ = bdty(LB, NULL, $2); } + | C_STROP C_NAME { $$ = bdty(NAME, $2); } + ; + +optcomma : /* VOID */ + | ',' + ; + +ibrace: '{' { ilbrace(); } + ; + +/* STATEMENTS */ + +compoundstmt: begin declaration_list stmt_list '}' { +#ifdef STABS + if (gflag && blevel > 2) + stabs_rbrac(blevel); +#endif + --blevel; + if( blevel == 1 ) + blevel = 0; + symclear(blevel); /* Clean ut the symbol table */ + if (autooff > maxautooff) + maxautooff = autooff; + autooff = savctx->contlab; + savctx = savctx->next; + } + | begin stmt_list '}' { +#ifdef STABS + if (gflag && blevel > 2) + stabs_rbrac(blevel); +#endif + --blevel; + if( blevel == 1 ) + blevel = 0; + symclear(blevel); /* Clean ut the symbol table */ + if (autooff > maxautooff) + maxautooff = autooff; + autooff = savctx->contlab; + savctx = savctx->next; + } + ; + +begin: '{' { + struct savbc *bc = tmpalloc(sizeof(struct savbc)); + if (blevel == 1) { +#ifdef STABS + if (gflag) + stabs_line(lineno); +#endif + dclargs(); + } +#ifdef STABS + if (gflag && blevel > 1) + stabs_lbrac(blevel+1); +#endif + ++blevel; + oldstyle = 0; + bc->contlab = autooff; + bc->next = savctx; + savctx = bc; + } + ; + +statement: e ';' { ecomp( $1 ); } + | compoundstmt + | ifprefix statement { plabel($1); reached = 1; } + | ifelprefix statement { + if ($1 != NOLAB) { + plabel( $1); + reached = 1; + } + } + | whprefix statement { + branch(contlab); + plabel( brklab ); + if( (flostat&FBRK) || !(flostat&FLOOP)) + reached = 1; + else + reached = 0; + resetbc(0); + } + | doprefix statement C_WHILE '(' e ')' ';' { + plabel(contlab); + if (flostat & FCONT) + reached = 1; + if (reached) + cbranch($5, bcon($1)); + else + tfree($5); + plabel( brklab); + reached = 1; + resetbc(0); + } + | forprefix .e ')' statement + { plabel( contlab ); + if( flostat&FCONT ) reached = 1; + if( $2 ) ecomp( $2 ); + branch($1); + plabel( brklab ); + if( (flostat&FBRK) || !(flostat&FLOOP) ) reached = 1; + else reached = 0; + resetbc(0); + } + | switchpart statement + { if( reached ) branch( brklab ); + plabel( $1 ); + swend(); + plabel( brklab); + if( (flostat&FBRK) || !(flostat&FDEF) ) reached = 1; + resetbc(FCONT); + } + | C_BREAK ';' { + if (brklab == NOLAB) + uerror("illegal break"); + else if (reached) + branch(brklab); + flostat |= FBRK; + reached = 0; + } + | C_CONTINUE ';' { + if (contlab == NOLAB) + uerror("illegal continue"); + else + branch(contlab); + flostat |= FCONT; + goto rch; + } + | C_RETURN ';' { + branch(retlab); + if (cftnsp->stype != VOID && noretype && + cftnsp->stype != VOID+FTN) + uerror("return value required"); + rch: + if (!reached) + werror( "statement is not reached"); + reached = 0; + } + | C_RETURN e ';' { + register NODE *temp; + + spname = cftnsp; + temp = buildtree( NAME, NIL, NIL ); + temp->n_type = DECREF(temp->n_type); + temp = buildtree(RETURN, temp, $2); + + if (temp->n_type == VOID) + ecomp(temp->n_right); + else + ecomp(buildtree(FORCE, temp->n_right, NIL)); + nfree(temp->n_left); + nfree(temp); + branch(retlab); + reached = 0; + } + | C_GOTO C_NAME ';' { gotolabel($2); goto rch; } + | C_GOTO '*' e ';' { + ecomp(block(GOTO, $3, NIL, INT, 0, 0)); + } + | asmstatement ';' + | ';' + | error ';' + | error '}' + | label statement + ; + +asmstatement: C_ASM '(' string ')' { send_passt(IP_ASM, mkpstr($3)); } + ; + +label: C_NAME ':' { deflabel($1); reached = 1; } + | C_CASE e ':' { addcase($2); reached = 1; } + | C_DEFAULT ':' { reached = 1; adddef(); flostat |= FDEF; } + ; + +doprefix: C_DO { + savebc(); + if (!reached) + werror("loop not entered at top"); + brklab = getlab(); + contlab = getlab(); + plabel( $$ = getlab()); + reached = 1; + } + ; +ifprefix: C_IF '(' e ')' { + cbranch(buildtree(NOT, $3, NIL), bcon($$ = getlab())); + reached = 1; + } + ; +ifelprefix: ifprefix statement C_ELSE { + if (reached) + branch($$ = getlab()); + else + $$ = NOLAB; + plabel( $1); + reached = 1; + } + ; + +whprefix: C_WHILE '(' e ')' { + savebc(); + if (!reached) + werror("loop not entered at top"); + if ($3->n_op == ICON && $3->n_lval != 0) + flostat = FLOOP; + plabel( contlab = getlab()); + reached = 1; + brklab = getlab(); + if (flostat == FLOOP) + tfree($3); + else + cbranch(buildtree(NOT, $3, NIL), bcon(brklab)); + } + ; +forprefix: C_FOR '(' .e ';' .e ';' { + if ($3) + ecomp($3); + else if (!reached) + werror("loop not entered at top"); + savebc(); + contlab = getlab(); + brklab = getlab(); + plabel( $$ = getlab()); + reached = 1; + if ($5) + cbranch(buildtree(NOT, $5, NIL), bcon(brklab)); + else + flostat |= FLOOP; + } + ; +switchpart: C_SWITCH '(' e ')' { + NODE *p; + int num; + + savebc(); + brklab = getlab(); + if ($3->n_type != INT) { + /* must cast to integer */ + p = block(NAME, NIL, NIL, INT, 0, MKSUE(INT)); + p = buildtree(CAST, p, $3); + $3 = p->n_right; + nfree(p->n_left); + nfree(p); + } +// ecomp( buildtree( FORCE, $3, NIL ) ); + p = tempnode(0, INT, 0, MKSUE(INT)); + num = p->n_lval; + ecomp(buildtree(ASSIGN, p, $3)); + branch( $$ = getlab()); + swstart(num); + reached = 0; + } + ; +/* EXPRESSIONS */ +con_e: { $<intval>$=instruct; instruct=0; } e %prec ',' { + $$ = icons( $2 ); + instruct=$<intval>1; + } + ; + +nocon_e: { $<intval>$=instruct; instruct=0; } e %prec ',' { + instruct=$<intval>1; + $$ = $2; + } + ; + +.e: e + | { $$=0; } + ; + +elist: e %prec ',' + | elist ',' e { $$ = buildtree(CM, $1, $3); } + ; + +/* + * Precedence order of operators. + */ +e: e ',' e { $$ = buildtree(COMOP, $1, $3); } + | e '=' e { $$ = buildtree(ASSIGN, $1, $3); } + | e C_ASOP e { $$ = buildtree($2, $1, $3); } + | e '?' e ':' e { + $$=buildtree(QUEST, $1, buildtree(COLON, $3, $5)); + } + | e C_OROR e { $$ = buildtree($2, $1, $3); } + | e C_ANDAND e { $$ = buildtree($2, $1, $3); } + | e '|' e { $$ = buildtree(OR, $1, $3); } + | e '^' e { $$ = buildtree(ER, $1, $3); } + | e '&' e { $$ = buildtree(AND, $1, $3); } + | e C_EQUOP e { $$ = buildtree($2, $1, $3); } + | e C_RELOP e { $$ = buildtree($2, $1, $3); } + | e C_SHIFTOP e { $$ = buildtree($2, $1, $3); } + | e '+' e { $$ = buildtree(PLUS, $1, $3); } + | e '-' e { $$ = buildtree(MINUS, $1, $3); } + | e C_DIVOP e { $$ = buildtree($2, $1, $3); } + | e '*' e { $$ = buildtree(MUL, $1, $3); } + | e '=' addrlbl { $$ = buildtree(ASSIGN, $1, $3); } + | term + ; + +addrlbl: C_ANDAND C_NAME { +#ifdef GCC_COMPAT + struct symtab *s = lookup($2, SLBLNAME); + if (s->soffset == 0) + s->soffset = -getlab(); + spname = s; + $$ = buildtree(ADDROF, buildtree(NAME, NIL, NIL), NIL); +#else + uerror("gcc extension"); +#endif + } + ; + +term: term C_INCOP { $$ = buildtree( $2, $1, bcon(1) ); } + | '*' term { $$ = buildtree(UMUL, $2, NIL); } + | '&' term { + if( ISFTN($2->n_type) || ISARY($2->n_type) ){ +#ifdef notdef + werror( "& before array or function: ignored" ); +#endif + $$ = $2; + } else + $$ = buildtree(ADDROF, $2, NIL); + } + | '-' term { $$ = buildtree(UMINUS, $2, NIL ); } + | '+' term { $$ = $2; } + | C_UNOP term { $$ = buildtree( $1, $2, NIL ); } + | C_INCOP term { + $$ = buildtree($1 == INCR ? PLUSEQ : MINUSEQ, + $2, bcon(1)); + } + | C_SIZEOF term { $$ = doszof($2); } + | '(' cast_type ')' term %prec C_INCOP { + $$ = buildtree(CAST, $2, $4); + nfree($$->n_left); + nfree($$); + $$ = $$->n_right; + } + | C_SIZEOF '(' cast_type ')' %prec C_SIZEOF { + $$ = doszof($3); + } + | '(' cast_type ')' clbrace init_list '}' { + endinit(); + spname = $4; + $$ = buildtree(NAME, NIL, NIL); + } + | term '[' e ']' { + $$ = buildtree( UMUL, + buildtree( PLUS, $1, $3 ), NIL ); + } + | funct_idn ')' { $$ = doacall($1, NIL); } + | funct_idn elist ')' { $$ = doacall($1, $2); } + | term C_STROP C_NAME { $$ = structref($1, $2, $3); } + | term C_STROP C_TYPENAME { $$ = structref($1, $2, $3); } + | C_NAME { + spname = lookup($1, 0); + /* recognize identifiers in initializations */ + if (blevel==0 && spname->stype == UNDEF) { + register NODE *q; + werror("undeclared initializer name %s", + spname->sname); + q = block(NAME, NIL, NIL, INT, 0, MKSUE(INT)); + q->n_sp = spname; + defid(q, EXTERN); + nfree(q); + } + if (spname->sflags & SINLINE) + inline_ref($1); + $$ = buildtree(NAME, NIL, NIL); + spname->suse = -lineno; + if (spname->sflags & SDYNARRAY) + $$ = buildtree(UMUL, $$, NIL); + } + | C_ICON { $$ = $1; } + | C_FCON { $$ = $1; } + | string { $$ = strend($1); /* get string contents */ } + | wstring { $$ = wstrend($1); } + | '(' e ')' { $$=$2; } + ; + +clbrace: '{' { $$ = clbrace($<nodep>-1); } + ; + +string: C_STRING { + int len = strlen($1) + 1; + $$ = tmpalloc(len); + strlcpy($$, $1, len); + } + | string C_STRING { + int len = strlen($1) + strlen($2) + 1; + $$ = tmpalloc(len); + strlcpy($$, $1, len); + strlcat($$, $2, len); + } + ; + +wstring: C_WSTRING { + int len = strlen($1) + 1; + $$ = tmpalloc(len); + strlcpy($$, $1, len); + } + | string C_WSTRING { + int len = strlen($1) + strlen($2) + 1; + $$ = tmpalloc(len); + strlcpy($$, $1, len); + strlcat($$, $2, len); + } + ; + +cast_type: specifier_qualifier_list { + $$ = tymerge($1, bdty(NAME, NULL)); + nfree($1); + } + | specifier_qualifier_list abstract_declarator { + $$ = tymerge($1, $2); + nfree($1); + } + ; + +funct_idn: C_NAME '(' { + struct symtab *s = lookup($1, 0); + if (s->stype == UNDEF) { + register NODE *q; + q = block(NAME, NIL, NIL, FTN|INT, 0, MKSUE(INT)); + q->n_sp = s; + defid(q, EXTERN); + nfree(q); + } + if (s->sflags & SINLINE) + inline_ref($1); + spname = s; + $$ = buildtree(NAME, NIL, NIL); + s->suse = -lineno; + } + | term '(' + ; +%% + +NODE * +mkty(TWORD t, union dimfun *d, struct suedef *sue) +{ + return block(TYPE, NIL, NIL, t, d, sue); +} + +static NODE * +bdty(int op, ...) +{ + va_list ap; + register NODE *q; + + va_start(ap, op); + q = block(op, NIL, NIL, INT, 0, MKSUE(INT)); + + switch (op) { + case UMUL: + case UCALL: + q->n_left = va_arg(ap, NODE *); + q->n_rval = 0; + break; + + case CALL: + q->n_left = va_arg(ap, NODE *); + q->n_right = va_arg(ap, NODE *); + break; + + case LB: + q->n_left = va_arg(ap, NODE *); + q->n_right = bcon(va_arg(ap, int)); + break; + + case NAME: + q->n_sp = va_arg(ap, struct symtab *); /* XXX survive tymerge */ + break; + + default: + cerror("bad bdty"); + } + va_end(ap); + + return q; +} + +static void +savebc(void) +{ + struct savbc *bc = tmpalloc(sizeof(struct savbc)); + + bc->brklab = brklab; + bc->contlab = contlab; + bc->flostat = flostat; + bc->next = savbc; + savbc = bc; + flostat = 0; +} + +static void +resetbc(int mask) +{ + flostat = savbc->flostat | (flostat&mask); + contlab = savbc->contlab; + brklab = savbc->brklab; + savbc = savbc->next; +} + +struct swdef { + struct swdef *next; /* Next in list */ + int deflbl; /* Label for "default" */ + struct swents *ents; /* Linked sorted list of case entries */ + int nents; /* # of entries in list */ + int num; /* Node value will end up in */ +} *swpole; + +/* + * add case to switch + */ +static void +addcase(NODE *p) +{ + struct swents *w, *sw = tmpalloc(sizeof(struct swents)); + + p = optim(p); /* change enum to ints */ + if (p->n_op != ICON || p->n_sp != NULL) { + uerror( "non-constant case expression"); + return; + } + if (swpole == NULL) { + uerror("case not in switch"); + return; + } + + sw->sval = p->n_lval; + plabel( sw->slab = getlab()); + w = swpole->ents; + if (swpole->ents == NULL) { + sw->next = NULL; + swpole->ents = sw; + } else if (swpole->ents->next == NULL) { + if (swpole->ents->sval == sw->sval) { + uerror("duplicate case in switch"); + } else if (swpole->ents->sval < sw->sval) { + sw->next = NULL; + swpole->ents->next = sw; + } else { + sw->next = swpole->ents; + swpole->ents = sw; + } + } else { + while (w->next->next != NULL && w->next->sval < sw->sval) { + w = w->next; + } + if (w->next->sval == sw->sval) { + uerror("duplicate case in switch"); + } else if (w->next->sval > sw->sval) { + sw->next = w->next; + w->next = sw; + } else { + sw->next = NULL; + w->next->next = sw; + } + } + swpole->nents++; + tfree(p); +} + +/* + * add default case to switch + */ +static void +adddef(void) +{ + if (swpole == NULL) + uerror("default not inside switch"); + else if (swpole->deflbl != 0) + uerror("duplicate default in switch"); + else + plabel( swpole->deflbl = getlab()); +} + +static void +swstart(int num) +{ + struct swdef *sw = tmpalloc(sizeof(struct swdef)); + + sw->deflbl = sw->nents = 0; + sw->ents = NULL; + sw->next = swpole; + sw->num = num; + swpole = sw; +} + +/* + * end a switch block + */ +static void +swend(void) +{ + struct swents *sw, **swp; + int i; + + sw = tmpalloc(sizeof(struct swents)); + swp = tmpalloc(sizeof(struct swents *) * (swpole->nents+1)); + + sw->slab = swpole->deflbl; + swp[0] = sw; + + for (i = 1; i <= swpole->nents; i++) { + swp[i] = swpole->ents; + swpole->ents = swpole->ents->next; + } + genswitch(swpole->num, swp, swpole->nents); + + swpole = swpole->next; +} + +/* + * Declare a variable or prototype. + */ +static struct symtab * +init_declarator(NODE *tn, NODE *p, int assign) +{ + int class = tn->n_lval; + NODE *typ; + + typ = tymerge(tn, p); + typ->n_sp = lookup((char *)typ->n_sp, 0); /* XXX */ + + if (fun_inline && ISFTN(typ->n_type)) + typ->n_sp->sflags |= SINLINE; + + if (ISFTN(typ->n_type) == 0) { + setloc1(DATA); + if (assign) { + defid(typ, class); + typ->n_sp->sflags |= SASG; + lcommdel(typ->n_sp); + } else { + nidcl(typ, class); + } + } else { + if (assign) + uerror("cannot initialise function"); + defid(typ, uclass(class)); + } + nfree(p); + return typ->n_sp; +} + +/* + * Declare a function. + */ +static void +fundef(NODE *tp, NODE *p) +{ + extern int prolab; + struct symtab *s; + int class = tp->n_lval, oclass; + char *c; + + setloc1(PROG); + /* Enter function args before they are clobbered in tymerge() */ + /* Typecheck against prototype will be done in defid(). */ + ftnarg(p); + + tymerge(tp, p); + s = p->n_sp = lookup((char *)p->n_sp, 0); /* XXX */ + + oclass = s->sclass; + if (class == STATIC && oclass == EXTERN) + werror("%s was first declared extern, then static", s->sname); + + if ((oclass == SNULL || oclass == USTATIC) && + class == STATIC && fun_inline) { + /* Unreferenced, store it for (eventual) later use */ + /* Ignore it if it not declared static */ + s->sflags |= SINLINE; + inline_start(s->sname); + } + if (class == EXTERN) + class = SNULL; /* same result */ + + cftnsp = s; + defid(p, class); + prolab = getlab(); + c = cftnsp->sname; +#ifdef GCC_COMPAT + c = gcc_findname(cftnsp); +#endif + send_passt(IP_PROLOG, -1, -1, c, cftnsp->stype, + cftnsp->sclass == EXTDEF, prolab); + blevel = 1; +#ifdef STABS + if (gflag) + stabs_func(s); +#endif + nfree(tp); + nfree(p); + +} + +static void +fend(void) +{ + if (blevel) + cerror("function level error"); + ftnend(); + fun_inline = 0; + cftnsp = NULL; +} + +static NODE * +structref(NODE *p, int f, char *name) +{ + NODE *r; + + if (f == DOT) + p = buildtree(ADDROF, p, NIL); + r = block(NAME, NIL, NIL, INT, 0, MKSUE(INT)); + r->n_name = name; + return buildtree(STREF, p, r); +} + +static void +olddecl(NODE *p) +{ + struct symtab *s; + + s = lookup((char *)p->n_sp, 0); + if (s->slevel != 1 || s->stype == UNDEF) + uerror("parameter '%s' not defined", s->sname); + else if (s->stype != FARG) + uerror("parameter '%s' redefined", s->sname); + s->stype = p->n_type; + s->sdf = p->n_df; + s->ssue = p->n_sue; + nfree(p); +} + +void +branch(int lbl) +{ + int r = reached++; + ecomp(block(GOTO, bcon(lbl), NIL, INT, 0, 0)); + reached = r; +} + +/* + * Create a printable string based on an encoded string. + */ +static char * +mkpstr(char *str) +{ + char *s, *os; + int v, l = strlen(str)+1; + + os = s = isinlining ? permalloc(l) : tmpalloc(l); + for (; *str; ) { + if (*str++ == '\\') + v = esccon(&str); + else + v = str[-1]; + *s++ = v; + } + *s = 0; + return os; +} + +static struct symtab * +clbrace(NODE *p) +{ + struct symtab *sp; + + if (blevel == 0 && xnf != NULL) + cerror("no level0 compound literals"); + + sp = getsymtab("cl", STEMP); + sp->stype = p->n_type; + sp->squal = p->n_qual; + sp->sdf = p->n_df; + sp->ssue = p->n_sue; + sp->sclass = blevel ? AUTO : STATIC; + if (!ISARY(sp->stype) || sp->sdf->ddim != 0) { + sp->soffset = NOOFFSET; + oalloc(sp, &autooff); + } + tfree(p); + beginit(sp); + return sp; +} diff --git a/usr.bin/pcc/cc/ccom/gcc_compat.c b/usr.bin/pcc/cc/ccom/gcc_compat.c new file mode 100644 index 00000000000..56de6783bf0 --- /dev/null +++ b/usr.bin/pcc/cc/ccom/gcc_compat.c @@ -0,0 +1,126 @@ +/* $Id: gcc_compat.c,v 1.1 2007/09/15 18:12:33 otto Exp $ */ +/* + * Copyright (c) 2004 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. + */ + +/* + * Routines to support some of the gcc extensions to C. + */ +#ifdef GCC_COMPAT + +#include "pass1.h" +#include "cgram.h" + +#include <string.h> + +static struct kw { + char *name, *ptr; + int rv; +} kw[] = { + { "__asm", NULL, C_ASM }, + { "__signed", NULL, 0 }, + { "__inline", NULL, C_FUNSPEC }, + { "__const", NULL, 0 }, + { "__asm__", NULL, C_ASM }, + { NULL, NULL, 0 }, +}; + +void +gcc_init() +{ + struct kw *kwp; + + for (kwp = kw; kwp->name; kwp++) + kwp->ptr = addname(kwp->name); + +} + +/* + * See if a string matches a gcc keyword. + */ +int +gcc_keyword(char *str, NODE **n) +{ + struct kw *kwp; + int i; + + for (i = 0, kwp = kw; kwp->name; kwp++, i++) + if (str == kwp->ptr) + break; + if (kwp->name == NULL) + return 0; + if (kwp->rv) + return kwp->rv; + switch (i) { + case 1: /* __signed */ + *n = mkty((TWORD)SIGNED, 0, MKSUE(SIGNED)); + return C_TYPE; + case 3: /* __const */ + *n = block(QUALIFIER, NIL, NIL, CON, 0, 0); + return C_QUALIFIER; + } + cerror("gcc_keyword"); + return 0; +} + +static struct ren { + struct ren *next; + char *old, *new; +} *renp; +/* + * Save a name for later renaming of a variable. + */ +void +gcc_rename(struct symtab *sp, char *newname) +{ + struct ren *ren = permalloc(sizeof(struct ren)); + + sp->sflags |= SRENAME; + ren->old = sp->sname; + ren->new = newstring(newname, strlen(newname)+1); + ren->next = renp; + renp = ren; +} + +/* + * Get a renamed variable. + */ +char * +gcc_findname(struct symtab *sp) +{ + struct ren *w; + + if ((sp->sflags & SRENAME) == 0) + return exname(sp->sname); + + for (w = renp; w; w = w->next) { + if (w->old == sp->sname) + return exname(w->new); + } + cerror("gcc_findname %s", sp->sname); + return NULL; +} +#endif diff --git a/usr.bin/pcc/cc/ccom/init.c b/usr.bin/pcc/cc/ccom/init.c new file mode 100644 index 00000000000..58084f966f4 --- /dev/null +++ b/usr.bin/pcc/cc/ccom/init.c @@ -0,0 +1,951 @@ +/* $Id: init.c,v 1.1 2007/09/15 18:12:33 otto Exp $ */ + +/* + * Copyright (c) 2004, 2007 Anders Magnusson (ragge@ludd.ltu.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. + */ + +/* + * 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 conditions and 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 "pass1.h" +#include <string.h> + +/* + * Four machine-dependent routines may be called during initialization: + * + * instring(char *str) - Print out a string. + * zbits(OFFSZ, int) - sets int bits of zero at position OFFSZ. + * infld(CONSZ off, int fsz, CONSZ val) + * - sets the bitfield val starting at off and size fsz. + * inval(CONSZ off, int fsz, NODE *) + * - prints an integer constant which may have + * a label associated with it, located at off and + * size fsz. + * + * Initialization may be of different kind: + * - Initialization at compile-time, all values are constants and laid + * out in memory. Static or extern variables outside functions. + * - Initialization at run-time, written to their values as code. + * + * Currently run-time-initialized variables are only initialized by using + * move instructions. An optimization might be to detect that it is + * initialized with constants and therefore copied from readonly memory. + */ + +/* + * The base element(s) of an initialized variable is kept in a linked + * list, allocated while initialized. + * + * When a scalar is found, entries are popped of the instk until it's + * possible to find an entry for a new scalar; then onstk() is called + * to get the correct type and size of that scalar. + * + * If a right brace is found, pop the stack until a matching left brace + * were found while filling the elements with zeros. This left brace is + * also marking where the current level is for designated initializations. + * + * Position entries are increased when traversing back down into the stack. + */ + +/* + * Good-to-know entries from symtab: + * soffset - # of bits from beginning of this structure. + */ + +/* + * TO FIX: + * - Alignment of structs on like i386 char members. + */ + +int idebug; + +/* + * Struct used in array initialisation. + */ +static struct instk { + struct instk *in_prev; /* linked list */ + struct symtab **in_xp; /* member in structure initializations */ + struct symtab *in_sym; /* stab index */ + union dimfun *in_df; /* dimenston of array */ + TWORD in_t; /* type for this level */ + int in_n; /* number of arrays seen so far */ + int in_fl; /* flag which says if this level is controlled by {} */ +} *pstk, pbase; + +static struct symtab *csym; + +#define ISSOU(ty) (ty == STRTY || ty == UNIONTY) + +#ifdef PCC_DEBUG +static void prtstk(struct instk *in); +#endif + +/* + * Linked lists for initializations. + */ +struct ilist { + struct ilist *next; + CONSZ off; /* bit offset of this entry */ + int fsz; /* bit size of this entry */ + NODE *n; /* node containing this data info */ +}; + +struct llist { + SLIST_ENTRY(llist) next; + CONSZ begsz; /* bit offset of this entry */ + struct ilist *il; +} *curll; +static SLIST_HEAD(, llist) lpole; +static CONSZ basesz; +static int numents; /* # of array entries allocated */ + +static struct ilist * +getil(struct ilist *next, CONSZ b, int sz, NODE *n) +{ + struct ilist *il = tmpalloc(sizeof(struct ilist)); + + il->off = b; + il->fsz = sz; + il->n = n; + il->next = next; + return il; +} + +/* + * Allocate a new struct defining a block of initializers appended to the + * end of the llist. Return that entry. + */ +static struct llist * +getll(void) +{ + struct llist *ll; + + ll = tmpalloc(sizeof(struct llist)); + ll->begsz = numents * basesz; + ll->il = NULL; + SLIST_INSERT_LAST(&lpole, ll, next); + numents++; + return ll; +} + +/* + * Return structure containing off bitnumber. + * Allocate more entries, if needed. + * This is not bright implemented. + */ +static struct llist * +setll(OFFSZ off) +{ + struct llist *ll; + + /* Ensure that we have enough entries */ + while (off >= basesz * numents) + (void)getll(); + SLIST_FOREACH(ll, &lpole, next) + if (ll->begsz <= off && ll->begsz + basesz > off) + break; + return ll; /* ``cannot fail'' */ +} + +/* + * beginning of initialization; allocate space to store initialized data. + * remember storage class for writeout in endinit(). + * p is the newly declarated type. + */ +void +beginit(struct symtab *sp) +{ + struct instk *is = &pbase; + struct llist *ll; + +#ifdef PCC_DEBUG + if (idebug) + printf("beginit(), sclass %s\n", scnames(sp->sclass)); +#endif + + csym = sp; + + numents = 0; /* no entries in array list */ + if (ISARY(sp->stype)) + basesz = tsize(DECREF(sp->stype), sp->sdf+1, sp->ssue); + else + basesz = tsize(DECREF(sp->stype), sp->sdf, sp->ssue); + SLIST_INIT(&lpole); + curll = ll = getll(); /* at least first entry in list */ + + /* first element */ + is->in_xp = ISSOU(sp->stype) ? sp->ssue->suelem : NULL; + is->in_n = 0; + is->in_t = sp->stype; + is->in_sym = sp; + is->in_df = sp->sdf; + is->in_fl = 0; + is->in_prev = NULL; + pstk = is; +} + +/* + * Push a new entry on the initializer stack. + * The new entry will be "decremented" to the new sub-type of the previous + * entry when called. + * Popping of entries is done elsewhere. + */ +static void +stkpush(void) +{ + struct instk *is; + struct symtab *sq, *sp; + TWORD t; + + if (pstk == NULL) { + sp = csym; + t = 0; + } else { + t = pstk->in_t; + sp = pstk->in_sym; + } + +#ifdef PCC_DEBUG + if (idebug) { + printf("stkpush: '%s' %s ", sp->sname, scnames(sp->sclass)); + tprint(stdout, t, 0); + } +#endif + + /* + * Figure out what the next initializer will be, and push it on + * the stack. If this is an array, just decrement type, if it + * is a struct or union, extract the next element. + */ + is = tmpalloc(sizeof(struct instk)); + is->in_fl = 0; + is->in_n = 0; + if (pstk == NULL) { + /* stack empty */ + is->in_xp = ISSOU(sp->stype) ? sp->ssue->suelem : NULL; + is->in_t = sp->stype; + is->in_sym = sp; + is->in_df = sp->sdf; + } else if (ISSOU(t)) { + sq = *pstk->in_xp; + is->in_xp = ISSOU(sq->stype) ? sq->ssue->suelem : 0; + is->in_t = sq->stype; + is->in_sym = sq; + is->in_df = sq->sdf; + } else if (ISARY(t)) { + is->in_xp = ISSOU(DECREF(t)) ? pstk->in_sym->ssue->suelem : 0; + is->in_t = DECREF(t); + is->in_sym = sp; + if (pstk->in_df->ddim && pstk->in_n >= pstk->in_df->ddim) { + werror("excess of initializing elements"); + pstk->in_n--; + } + if (ISARY(is->in_t)) + is->in_df = pstk->in_df+1; + } else + cerror("onstk"); + is->in_prev = pstk; + pstk = is; + +#ifdef PCC_DEBUG + if (idebug) { + printf(" newtype "); + tprint(stdout, is->in_t, 0); + printf("\n"); + } +#endif +} + +/* + * pop down to either next level that can handle a new initializer or + * to the next braced level. + */ +static void +stkpop(void) +{ +#ifdef PCC_DEBUG + if (idebug) + printf("stkpop\n"); +#endif + for (; pstk; pstk = pstk->in_prev) { + if (pstk->in_t == STRTY) { + pstk->in_xp++; + if (*pstk->in_xp != NULL) + break; + } + if (ISSOU(pstk->in_t) && pstk->in_fl) + break; /* need } */ + if (ISARY(pstk->in_t)) { + pstk->in_n++; + if (pstk->in_fl) + break; + if (pstk->in_df->ddim == 0 || + pstk->in_n < pstk->in_df->ddim) + break; /* ger more elements */ + } + } +#ifdef PCC_DEBUG + if (idebug > 1) + prtstk(pstk); +#endif +} + +/* + * Count how many elements an array may consist of. + */ +static int +acalc(struct instk *is, int n) +{ + if (is == NULL || !ISARY(is->in_t)) + return 0; + return acalc(is->in_prev, n * is->in_df->ddim) + n * is->in_n; +} + +/* + * Find current bit offset of the top element on the stack from + * the beginning of the aggregate. + */ +static CONSZ +findoff(void) +{ + struct instk *is; + OFFSZ off; + +#ifdef PCC_DEBUG + if (ISARY(pstk->in_t) || ISSOU(pstk->in_t)) + cerror("findoff on bad type"); +#endif + + /* + * Offset calculations. If: + * - previous type is STRTY, soffset has in-struct offset. + * - this type is ARY, offset is ninit*stsize. + */ + for (off = 0, is = pstk; is; is = is->in_prev) { + if (is->in_prev && is->in_prev->in_t == STRTY) + off += is->in_sym->soffset; + if (ISARY(is->in_t)) { + /* suesize is the basic type, so adjust */ + TWORD t = is->in_t; + OFFSZ o; + while (ISARY(t)) + t = DECREF(t); + o = ISPTR(t) ? SZPOINT(t) : is->in_sym->ssue->suesize; + off += o * acalc(is, 1); + while (is->in_prev && ISARY(is->in_prev->in_t)) + is = is->in_prev; + } + } + if (idebug>1) { + printf("findoff: off %lld\n", off); + prtstk(pstk); + } + return off; +} + +/* + * Insert the node p with size fsz at position off. + * Bit fields are already dealt with, so a node of correct type + * with correct alignment and correct bit offset is given. + */ +static void +nsetval(CONSZ off, int fsz, NODE *p) +{ + struct llist *ll; + struct ilist *il; + + if (idebug>1) + printf("setval: off %lld fsz %d p %p\n", off, fsz, p); + + if (fsz == 0) + return; + + ll = setll(off); + off -= ll->begsz; + if (ll->il == NULL) { + ll->il = getil(NULL, off, fsz, p); + } else { + il = ll->il; + if (il->off > off) { + ll->il = getil(ll->il, off, fsz, p); + } else { + for (il = ll->il; il->next; il = il->next) + if (il->off <= off && il->next->off > off) + break; + if (il->off == off) { + /* replace */ + nfree(il->n); + il->n = p; + } else + il->next = getil(il->next, off, fsz, p); + } + } +} + +/* + * Align data and set correct location. + */ +static void +setscl(struct symtab *sp) +{ + setloc1((sp->squal << TSHIFT) & CON ? RDATA : DATA); + defalign(talign(sp->stype, sp->ssue)); + if (sp->sclass == EXTDEF || + (sp->sclass == STATIC && sp->slevel == 0)) { + defnam(sp); + } else { + if (sp->soffset == NOOFFSET) + cerror("setscl"); + deflab1(sp->soffset); + } +} + +/* + * take care of generating a value for the initializer p + * inoff has the current offset (last bit written) + * in the current word being generated + */ +void +scalinit(NODE *p) +{ + CONSZ woff; + NODE *q; + int fsz; + +#ifdef PCC_DEBUG + if (idebug > 2) { + printf("scalinit(%p)\n", p); + fwalk(p, eprint, 0); + prtstk(pstk); + } +#endif + + if (nerrors) + return; + + p = optim(p); + + if (csym->sclass != AUTO && p->n_op != ICON && + p->n_op != FCON && p->n_op != NAME) + cerror("scalinit not leaf"); + + /* Out of elements? */ + if (pstk == NULL) { + uerror("excess of initializing elements"); + return; + } + + /* + * Get to the simple type if needed. + */ + while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) + stkpush(); + + /* let buildtree do typechecking (and casting) */ + q = block(NAME, NIL,NIL, pstk->in_t, pstk->in_sym->sdf, + pstk->in_sym->ssue); + p = buildtree(ASSIGN, q, p); + nfree(p->n_left); + q = optim(p->n_right); + nfree(p); + + /* bitfield sizes are special */ + if (pstk->in_sym->sclass & FIELD) + fsz = -(pstk->in_sym->sclass & FLDSIZ); + else + fsz = tsize(pstk->in_t, pstk->in_sym->sdf, pstk->in_sym->ssue); + woff = findoff(); + + nsetval(woff, fsz, q); + + stkpop(); +#ifdef PCC_DEBUG + if (idebug > 2) { + printf("scalinit e(%p)\n", p); + } +#endif +} + +/* + * Generate code to insert a value into a bitfield. + */ +static void +insbf(OFFSZ off, int fsz, int val) +{ + struct symtab sym; + NODE *p, *r; + TWORD typ; + +#ifdef PCC_DEBUG + if (idebug > 1) + printf("insbf: off %lld fsz %d val %d\n", off, fsz, val); +#endif + + if (fsz == 0) + return; + + /* small opt: do char instead of bf asg */ + if ((off & (ALCHAR-1)) == 0 && fsz == SZCHAR) + typ = CHAR; + else + typ = INT; + /* Fake a struct reference */ + spname = csym; + p = buildtree(ADDROF, + buildtree(NAME, NIL, NIL), NIL); + r = block(ICON, NIL, NIL, typ, 0, MKSUE(typ)); + sym.stype = typ; + sym.squal = 0; + sym.sdf = 0; + sym.ssue = MKSUE(typ); + sym.soffset = off; + sym.sclass = typ == INT ? FIELD | fsz : MOU; + r->n_sp = &sym; + p = block(STREF, p, r, INT, 0, MKSUE(INT)); + ecode(buildtree(ASSIGN, stref(p), bcon(val))); +} + +/* + * Clear a bitfield, starting at off and size fsz. + */ +static void +clearbf(OFFSZ off, OFFSZ fsz) +{ + /* Pad up to the next even initializer */ + if ((off & (ALCHAR-1)) || (fsz < SZCHAR)) { + int ba = ((off + (SZCHAR-1)) & ~(SZCHAR-1)) - off; + if (ba > fsz) + ba = fsz; + insbf(off, ba, 0); + off += ba; + fsz -= ba; + } + while (fsz >= SZCHAR) { + insbf(off, SZCHAR, 0); + off += SZCHAR; + fsz -= SZCHAR; + } + if (fsz) + insbf(off, fsz, 0); +} + +/* + * final step of initialization. + * print out init nodes and generate copy code (if needed). + */ +void +endinit(void) +{ + struct llist *ll; + struct ilist *il; + int fsz; + OFFSZ lastoff, tbit; + +#ifdef PCC_DEBUG + if (idebug) + printf("endinit()\n"); +#endif + + if (csym->sclass != AUTO) + setscl(csym); + + /* Calculate total block size */ + if (ISARY(csym->stype) && csym->sdf->ddim == 0) { + tbit = numents*basesz; /* open-ended arrays */ + csym->sdf->ddim = numents; + if (csym->sclass == AUTO) { /* Get stack space */ + csym->soffset = NOOFFSET; + oalloc(csym, &autooff); + } + } else + tbit = tsize(csym->stype, csym->sdf, csym->ssue); + + /* Traverse all entries and print'em out */ + lastoff = 0; + SLIST_FOREACH(ll, &lpole, next) { + for (il = ll->il; il; il = il->next) { +#ifdef PCC_DEBUG + if (idebug > 1) { + printf("off %lld size %d val %lld type ", + ll->begsz+il->off, il->fsz, il->n->n_lval); + tprint(stdout, il->n->n_type, 0); + printf("\n"); + } +#endif + fsz = il->fsz; + if (csym->sclass == AUTO) { + struct symtab sym; + NODE *p, *r, *n; + + if (ll->begsz + il->off > lastoff) + clearbf(lastoff, + (ll->begsz + il->off) - lastoff); + + /* Fake a struct reference */ + spname = csym; + p = buildtree(ADDROF, + buildtree(NAME, NIL, NIL), NIL); + n = il->n; + r = block(ICON, NIL, NIL, INT, 0, MKSUE(INT)); + sym.stype = n->n_type; + sym.squal = n->n_qual; + sym.sdf = n->n_df; + sym.ssue = n->n_sue; + sym.soffset = ll->begsz + il->off; + sym.sclass = fsz < 0 ? FIELD | -fsz : 0; + r->n_sp = &sym; + p = block(STREF, p, r, INT, 0, MKSUE(INT)); + ecode(buildtree(ASSIGN, stref(p), il->n)); + if (fsz < 0) + fsz = -fsz; + + } else { + if (ll->begsz + il->off > lastoff) + zbits(lastoff, + (ll->begsz + il->off) - lastoff); + if (fsz < 0) { + fsz = -fsz; + infld(il->off, fsz, il->n->n_lval); + } else + ninval(il->off, fsz, il->n); + nfree(il->n); + } + lastoff = ll->begsz + il->off + fsz; + } + } + if (csym->sclass == AUTO) { + clearbf(lastoff, tbit-lastoff); + } else + zbits(lastoff, tbit-lastoff); +} + +/* + * process an initializer's left brace + */ +void +ilbrace() +{ + +#ifdef PCC_DEBUG + if (idebug) + printf("ilbrace()\n"); +#endif + + if (pstk == NULL) + return; + + stkpush(); + pstk->in_fl = 1; /* mark lbrace */ +#ifdef PCC_DEBUG + if (idebug > 1) + prtstk(pstk); +#endif +} + +/* + * called when a '}' is seen + */ +void +irbrace() +{ +#ifdef PCC_DEBUG + if (idebug) + printf("irbrace()\n"); + if (idebug > 2) + prtstk(pstk); +#endif + + if (pstk == NULL) + return; + + /* Got right brace, search for corresponding in the stack */ + for (; pstk->in_prev != NULL; pstk = pstk->in_prev) { + if(!pstk->in_fl) + continue; + + /* we have one now */ + + pstk->in_fl = 0; /* cancel { */ + if (ISARY(pstk->in_t)) + pstk->in_n = pstk->in_df->ddim; + else if (pstk->in_t == STRTY) { + while (pstk->in_xp[1] != NULL) + pstk->in_xp++; + } + stkpop(); + return; + } +} + +/* + * Create a new init stack based on given elements. + */ +static void +mkstack(NODE *p) +{ + +#ifdef PCC_DEBUG + if (idebug) + printf("mkstack: %p\n", p); +#endif + + if (p == NULL) + return; + mkstack(p->n_left); + + switch (p->n_op) { + case LB: /* Array index */ + if (p->n_right->n_op != ICON) + cerror("mkstack"); + if (!ISARY(pstk->in_t)) + uerror("array indexing non-array"); + pstk->in_n = p->n_right->n_lval; + nfree(p->n_right); + break; + + case NAME: + if (pstk->in_xp) { + for (; pstk->in_xp[0]; pstk->in_xp++) + if (pstk->in_xp[0]->sname == (char *)p->n_sp) + break; + if (pstk->in_xp[0] == NULL) + uerror("member missing"); + } else { + uerror("not a struct/union"); + } + break; + default: + cerror("mkstack2"); + } + nfree(p); + stkpush(); + +} + +/* + * Initialize a specific element, as per C99. + */ +void +desinit(NODE *p) +{ + int op = p->n_op; + + if (pstk == NULL) + stkpush(); /* passed end of array */ + while (pstk->in_prev && pstk->in_fl == 0) + pstk = pstk->in_prev; /* Empty stack */ + + if (ISSOU(pstk->in_t)) + pstk->in_xp = pstk->in_sym->ssue->suelem; + + mkstack(p); /* Setup for assignment */ + + /* pop one step if SOU, ilbrace will push */ + if (op == NAME) + pstk = pstk->in_prev; + +#ifdef PCC_DEBUG + if (idebug > 1) { + printf("desinit e\n"); + prtstk(pstk); + } +#endif +} + +/* + * Convert a string to an array of char/wchar for asginit. + */ +static void +strcvt(NODE *p) +{ + char *s; + int i; + + for (s = p->n_sp->sname; *s != 0; ) { + if (*s++ == '\\') { + i = esccon(&s); + } else + i = (unsigned char)s[-1]; + asginit(bcon(i)); + } + nfree(p); +} + +/* + * Do an assignment to a struct element. + */ +void +asginit(NODE *p) +{ + int g; + +#ifdef PCC_DEBUG + if (idebug) + printf("asginit %p\n", p); + if (idebug > 1 && p) + fwalk(p, eprint, 0); +#endif + + /* convert string to array of char */ + if (p && DEUNSIGN(p->n_type) == ARY+CHAR) { + /* + * ...but only if next element is ARY+CHAR, otherwise + * just fall through. + */ + + /* HACKHACKHACK */ + struct instk *is = pstk; + + while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) + stkpush(); + if (pstk->in_prev && + DEUNSIGN(pstk->in_prev->in_t) == ARY+CHAR) { + pstk = pstk->in_prev; + if ((g = pstk->in_fl) == 0) + pstk->in_fl = 1; /* simulate ilbrace */ + + strcvt(p); + if (g == 0) + irbrace(); + return; + } else + pstk = is; /* no array of char */ + /* END HACKHACKHACK */ + } + + if (p == NULL) { /* only end of compound stmt */ + irbrace(); + } else /* assign next element */ + scalinit(p); +} + +#ifdef PCC_DEBUG +void +prtstk(struct instk *in) +{ + int i, o = 0; + + printf("init stack:\n"); + for (; in != NULL; in = in->in_prev) { + for (i = 0; i < o; i++) + printf(" "); + printf("%p) '%s' ", in, in->in_sym->sname); + tprint(stdout, in->in_t, 0); + printf(" %s ", scnames(in->in_sym->sclass)); + if (in->in_df && in->in_df->ddim) + printf("arydim=%d ", in->in_df->ddim); + printf("ninit=%d ", in->in_n); + if (BTYPE(in->in_t) == STRTY || ISARY(in->in_t)) + printf("stsize=%d ", in->in_sym->ssue->suesize); + if (in->in_fl) printf("{ "); + printf("soff=%d ", in->in_sym->soffset); + if (in->in_t == STRTY) { + if (in->in_xp && in->in_xp[0]) + printf("curel %s ", in->in_xp[0]->sname); + else + printf("END struct"); + } + printf("\n"); + o++; + } +} +#endif + +/* + * Do a simple initialization. + * At block 0, just print out the value, at higher levels generate + * appropriate code. + */ +void +simpleinit(struct symtab *sp, NODE *p) +{ + /* May be an initialization of an array of char by a string */ + if ((DEUNSIGN(p->n_type) == ARY+CHAR && + DEUNSIGN(sp->stype) == ARY+CHAR) || + (DEUNSIGN(p->n_type) == ARY+WCHAR_TYPE && + DEUNSIGN(sp->stype) == ARY+WCHAR_TYPE)) { + /* Handle "aaa" as { 'a', 'a', 'a' } */ + beginit(sp); + strcvt(p); + if (csym->sdf->ddim == 0) + scalinit(bcon(0)); /* Null-term arrays */ + endinit(); + return; + } + + switch (sp->sclass) { + case STATIC: + case EXTDEF: + spname = sp; + p = optim(buildtree(ASSIGN, buildtree(NAME, NIL, NIL), p)); + setscl(sp); + ninval(0, p->n_right->n_sue->suesize, p->n_right); + tfree(p); + break; + + case AUTO: + case REGISTER: + if (ISARY(sp->stype)) + cerror("no array init"); + spname = sp; + ecomp(buildtree(ASSIGN, buildtree(NAME, NIL, NIL), p)); + break; + + default: + uerror("illegal initialization"); + } +} diff --git a/usr.bin/pcc/cc/ccom/inline.c b/usr.bin/pcc/cc/ccom/inline.c new file mode 100644 index 00000000000..b0567573487 --- /dev/null +++ b/usr.bin/pcc/cc/ccom/inline.c @@ -0,0 +1,209 @@ +/* $Id: inline.c,v 1.1 2007/09/15 18:12:33 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" + +#include <stdarg.h> + +/* + * ilink from ipole points to the next struct in the list of functions. + */ +static struct istat { + struct istat *ilink; + char *name; + int type; +#define NOTYETR 0 /* saved but not yet referenced */ +#define NOTYETW 1 /* saved and referenced but not yet written out */ +#define WRITTEN 2 /* is written out */ +#define NOTYETD 3 /* referenced but not yet saved */ + struct interpass shead; +} *ipole, *cifun; + +#define IP_REF (MAXIP+1) + +int isinlining, recovernodes; +int inlnodecnt, inlstatcnt; + +#define ialloc() permalloc(sizeof(struct istat)); inlstatcnt++ +#define nalloc() permalloc(sizeof(NODE)) + +static void +tcnt(NODE *p) +{ + inlnodecnt++; +} + +static struct istat * +findfun(char *name) +{ + struct istat *is = ipole; + while (is) { + if (is->name == name) + return is; + is = is->ilink; + } + return NULL; +} + +static void +refnode(char *str) +{ + struct interpass *ip; + + if (sdebug) + printf("refnode(%s)\n", str); + + ip = permalloc(sizeof(*ip)); + ip->type = IP_REF; + ip->ip_name = str; + inline_addarg(ip); +} + +void +inline_addarg(struct interpass *ip) +{ + DLIST_INSERT_BEFORE(&cifun->shead, ip, qelem); + if (ip->type == IP_NODE) + walkf(ip->ip_node, tcnt); /* Count as saved */ +} + +/* + * Called to setup for inlining of a new function. + */ +void +inline_start(char *name) +{ + struct istat *is; + + if (sdebug) + printf("inline_start(\"%s\")\n", name); + + if (isinlining) + cerror("already inlining function"); + + if ((is = findfun(name)) == 0) { + is = ialloc(); + is->ilink = ipole; + ipole = is; + is->name = name; + is->type = NOTYETR; + } else { + if (is->type != NOTYETD) + cerror("inline function already defined"); + is->type = NOTYETW; + } + DLIST_INIT(&is->shead, qelem); + cifun = is; + isinlining++; +} + +void +inline_end() +{ + if (sdebug) + printf("inline_end()\n"); + + isinlining = 0; +} + +/* + * Called when an inline function is found, to be sure that it will + * be written out. + * The function may not be defined when inline_ref() is called. + */ +void +inline_ref(char *name) +{ + struct istat *w = ipole; + + if (sdebug) + printf("inline_ref(\"%s\")\n", name); + if (isinlining) { + refnode(name); + } else { + while (w != NULL) { + if (w->name == name) { + if (w->type == NOTYETR) + w->type = NOTYETW; + return; /* setup for writeout */ + } + w = w->ilink; + } + /* function not yet defined, print out when found */ + w = ialloc(); + w->ilink = ipole; + ipole = w; + w->name = name; + w->type = NOTYETD; + } +} + +static void +puto(struct istat *w) +{ + struct interpass *ip, *nip; + + /* if -O, list will be saved again so foreach cannot be used */ + ip = DLIST_NEXT(&w->shead, qelem); + while (ip != (&w->shead)) { + nip = DLIST_NEXT(ip, qelem); + DLIST_REMOVE(ip, qelem); + if (ip->type == IP_REF) + inline_ref(ip->ip_name); + else + pass2_compile(ip); + ip = nip; + } + DLIST_INIT(&w->shead, qelem); +} + +/* + * printout functions that are referenced. + */ +void +inline_prtout() +{ + struct istat *w = ipole; + int gotone = 0; + + if (w == NULL) + return; + recovernodes++; + while (w != NULL) { + if (w->type == NOTYETW) { + puto(w); + w->type = WRITTEN; + gotone++; + } + w = w->ilink; + } + if (gotone) + inline_prtout(); + recovernodes--; +} diff --git a/usr.bin/pcc/cc/ccom/main.c b/usr.bin/pcc/cc/ccom/main.c new file mode 100644 index 00000000000..40560e455d0 --- /dev/null +++ b/usr.bin/pcc/cc/ccom/main.c @@ -0,0 +1,313 @@ +/* $Id: main.c,v 1.1 2007/09/15 18:12:33 otto Exp $ */ + +/* + * Copyright (c) 2002 Anders Magnusson. 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 <unistd.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> + +#include "pass1.h" +#include "pass2.h" + +int sflag, nflag, oflag, kflag; +int lflag, odebug, rdebug, radebug, vdebug, s2debug, udebug, x2debug; +#if !defined(MULTIPASS) || defined(PASST) +int iTflag, oTflag; +#endif +int xdebug, mdebug, sdebug, gflag, c2debug, pdebug; +int Wstrict_prototypes, Wmissing_prototypes, Wimplicit_int, + Wimplicit_function_declaration; +int xssaflag, xtailcallflag, xtemps, xdeljumps; + +int e2debug, t2debug, f2debug, b2debug; + +struct suedef btdims[24]; +char *prgname; + +static void prtstats(void); + +static struct { + char *n; int *f; +} flagstr[] = { + { "strict-prototypes", &Wstrict_prototypes, }, + { "missing-prototypes", &Wmissing_prototypes, }, + { "implicit-int", &Wimplicit_int, }, + { "implicit-function-declaration", &Wimplicit_function_declaration, }, + { NULL, NULL, }, +}; + +static void +usage(void) +{ + (void)fprintf(stderr, "usage: %s [option] [infile] [outfile]...\n", + prgname); + exit(1); +} + +static void +segvcatch(int a) +{ + fprintf(stderr, "%sinternal compiler error: %s, line %d\n", + nerrors ? "" : "major ", ftitle, lineno); + fflush(stderr); + exit(1); +} + +/* + * "emulate" the gcc warning flags. + */ +static void +Wflags(char *str) +{ + int i, found = 0, all; + + if (strcmp(str, "implicit") == 0) { + Wimplicit_int = Wimplicit_function_declaration = 1; + return; + } + all = strcmp(str, "W") == 0; + for (i = 0; flagstr[i].n; i++) + if (all || strcmp(flagstr[i].n, str) == 0) { + *flagstr[i].f = 1; + found++; + } + if (found == 0) + usage(); +} + + +/* control multiple files */ +int +main(int argc, char *argv[]) +{ + + int ch; + + prgname = argv[0]; + + while ((ch = getopt(argc, argv, "VlwX:Z:W:sOT:gx:k")) != -1) + switch (ch) { +#if !defined(MULTIPASS) || defined(PASS1) + case 'X': + while (*optarg) + switch (*optarg++) { + case 'd': ++ddebug; break; /* declarations */ + case 'i': ++idebug; break; /* initializations */ + case 'b': ++bdebug; break; + case 't': ++tdebug; break; + case 'e': ++edebug; break; /* pass1 exit */ + case 'x': ++xdebug; break; /* MD code */ + case 's': ++sdebug; break; + case 'n': ++nflag; break; + case 'o': ++oflag; break; + case 'p': ++pdebug; break; /* prototype */ + default: + fprintf(stderr, "unknown X flag '%c'\n", + optarg[-1]); + exit(1); + } +#endif + break; +#if !defined(MULTIPASS) || defined(PASST) + case 'T': + while (*optarg) + switch (*optarg++) { + case 'i': ++iTflag; break; + case 'o': ++oTflag; break; + case 'n': ++nflag; break; + default: + fprintf(stderr, "unknown T flag '%c'\n", + optarg[-1]); + exit(1); + } +#endif + break; +#if !defined(MULTIPASS) || defined(PASS2) + case 'Z': + while (*optarg) + switch (*optarg++) { + case 'f': /* instruction matching */ + ++f2debug; + break; + case 'e': /* print tree upon pass2 enter */ + ++e2debug; + break; + case 'o': ++odebug; break; + case 'r': /* register alloc/graph coloring */ + ++rdebug; + break; + case 'a': ++radebug; break; + case 'b': /* basic block and SSA building */ + ++b2debug; + break; + case 'c': /* code printout */ + ++c2debug; + break; + case 'm': ++mdebug; break; + case 'v': ++vdebug; break; + case 't': ++t2debug; break; + case 's': /* shape matching */ + ++s2debug; + break; + case 'u': /* Sethi-Ullman debugging */ + ++udebug; + break; + case 'x': ++x2debug; break; + case 'n': ++nflag; break; + default: + fprintf(stderr, "unknown Z flag '%c'\n", + optarg[-1]); + exit(1); + } +#endif + break; + + case 'k': /* PIC code */ + ++kflag; + break; + + case 'l': /* linenos */ + ++lflag; + break; + + case 'g': /* Debugging */ + gflag = 1; + break; + + case 's': /* Statistics */ + ++sflag; + break; + + case 'W': /* Enable different warnings */ + Wflags(optarg); + break; + + case 'x': /* Different optimizations */ + if (strcmp(optarg, "ssa") == 0) + xssaflag++; + else if (strcmp(optarg, "tailcall") == 0) + xtailcallflag++; + else if (strcmp(optarg, "temps") == 0) + xtemps++; + else if (strcmp(optarg, "deljumps") == 0) + xdeljumps++; + else + usage(); + break; + + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc != 0) { + if (freopen(argv[0], "r", stdin) == NULL) { + fprintf(stderr, "open input file '%s':", + argv[0]); + perror(NULL); + exit(1); + } + if (argc != 1) + if (freopen(argv[1], "w", stdout) == NULL) { + fprintf(stderr, "open output file '%s':", + argv[1]); + perror(NULL); + exit(1); + } + } + + mkdope(); + signal(SIGSEGV, segvcatch); + fregs = FREGS; /* number of free registers */ + lineno = 1; +#ifdef GCC_COMPAT + gcc_init(); +#endif + + /* dimension table initialization */ + + btdims[VOID].suesize = 0; + btdims[BOOL].suesize = SZBOOL; + btdims[CHAR].suesize = SZCHAR; + btdims[INT].suesize = SZINT; + btdims[FLOAT].suesize = SZFLOAT; + btdims[DOUBLE].suesize = SZDOUBLE; + btdims[LDOUBLE].suesize = SZLDOUBLE; + btdims[LONG].suesize = SZLONG; + btdims[LONGLONG].suesize = SZLONGLONG; + btdims[SHORT].suesize = SZSHORT; + btdims[UCHAR].suesize = SZCHAR; + btdims[USHORT].suesize = SZSHORT; + btdims[UNSIGNED].suesize = SZINT; + btdims[ULONG].suesize = SZLONG; + btdims[ULONGLONG].suesize = SZLONGLONG; + /* starts past any of the above */ + reached = 1; + + bjobcode(); + +#ifdef STABS + if (gflag) { + stabs_file(argc ? argv[0] : ""); + stabs_init(); + } +#endif + + (void) yyparse(); + yyaccpt(); + + ejobcode( nerrors ? 1 : 0 ); + lcommprint(); + + if (sflag) + prtstats(); + return(nerrors?1:0); + +} + +void +prtstats(void) +{ + extern int nametabs, namestrlen, tmpallocsize, permallocsize; + extern int lostmem, arglistcnt, dimfuncnt, inlnodecnt, inlstatcnt; + extern int symtabcnt, suedefcnt; + + fprintf(stderr, "Name table entries: %d pcs\n", nametabs); + fprintf(stderr, "Name string size: %d B\n", namestrlen); + fprintf(stderr, "Permanent allocated memory: %d B\n", permallocsize); + fprintf(stderr, "Temporary allocated memory: %d B\n", tmpallocsize); + fprintf(stderr, "Lost memory: %d B\n", lostmem); + fprintf(stderr, "Argument list unions: %d pcs\n", arglistcnt); + fprintf(stderr, "Dimension/function unions: %d pcs\n", dimfuncnt); + fprintf(stderr, "Struct/union/enum blocks: %d pcs\n", suedefcnt); + fprintf(stderr, "Inline node count: %d pcs\n", inlnodecnt); + fprintf(stderr, "Inline control blocks: %d pcs\n", inlstatcnt); + fprintf(stderr, "Permanent symtab entries: %d pcs\n", symtabcnt); +} diff --git a/usr.bin/pcc/cc/ccom/optim.c b/usr.bin/pcc/cc/ccom/optim.c new file mode 100644 index 00000000000..848e8535659 --- /dev/null +++ b/usr.bin/pcc/cc/ccom/optim.c @@ -0,0 +1,355 @@ +/* $Id: optim.c,v 1.1 2007/09/15 18:12:34 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 "pass1.h" + +# define SWAP(p,q) {sp=p; p=q; q=sp;} +# define RCON(p) (p->n_right->n_op==ICON) +# define RO(p) p->n_right->n_op +# define RV(p) p->n_right->n_lval +# define LCON(p) (p->n_left->n_op==ICON) +# define LO(p) p->n_left->n_op +# define LV(p) p->n_left->n_lval + +static int nncon(NODE *); + +int oflag = 0; + +/* remove left node */ +static NODE * +zapleft(NODE *p) +{ + NODE *q; + + q = p->n_left; + nfree(p->n_right); + nfree(p); + return q; +} + +/* + * fortran function arguments + */ +static NODE * +fortarg(NODE *p) +{ + if( p->n_op == CM ){ + p->n_left = fortarg( p->n_left ); + p->n_right = fortarg( p->n_right ); + return(p); + } + + while( ISPTR(p->n_type) ){ + p = buildtree( UMUL, p, NIL ); + } + return( optim(p) ); +} + + /* mapping relationals when the sides are reversed */ +short revrel[] ={ EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT }; + +/* + * local optimizations, most of which are probably + * machine independent + */ +NODE * +optim(NODE *p) +{ + int o, ty; + NODE *sp, *q; + int i; + TWORD t; + + if( (t=BTYPE(p->n_type))==ENUMTY || t==MOETY ) econvert(p); + if( oflag ) return(p); + + ty = coptype(p->n_op); + if( ty == LTYPE ) return(p); + + if( ty == BITYPE ) p->n_right = optim(p->n_right); + p->n_left = optim(p->n_left); + + /* collect constants */ +again: o = p->n_op; + switch(o){ + + case SCONV: + case PCONV: + return( clocal(p) ); + + case FORTCALL: + p->n_right = fortarg( p->n_right ); + break; + + case ADDROF: + if (LO(p) == TEMP) + return p; + if( LO(p) != NAME ) cerror( "& error" ); + + if( !andable(p->n_left) ) return(p); + + LO(p) = ICON; + + setuleft: + /* paint over the type of the left hand side with the type of the top */ + p->n_left->n_type = p->n_type; + p->n_left->n_df = p->n_df; + p->n_left->n_sue = p->n_sue; + q = p->n_left; + nfree(p); + return q; + + case UMUL: + if( LO(p) != ICON ) break; + LO(p) = NAME; + goto setuleft; + + case RS: + if (LO(p) == RS && RCON(p->n_left) && RCON(p)) { + /* two right-shift by constants */ + RV(p) += RV(p->n_left); + p->n_left = zapleft(p->n_left); + } +#if 0 + else if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { + RV(p) -= RV(p->n_left); + if (RV(p) < 0) + o = p->n_op = LS, RV(p) = -RV(p); + p->n_left = zapleft(p->n_left); + } +#endif + if (RO(p) == ICON) { + if (RV(p) < 0) { + RV(p) = -RV(p); + p->n_op = LS; + goto again; + } +#ifdef notyet /* must check for side effects, --a >> 32; */ + if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue) && + ISUNSIGNED(p->n_type)) { /* ignore signed shifts */ + /* too many shifts */ + tfree(p->n_left); + nfree(p->n_right); + p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL; + } else +#endif + /* avoid larger shifts than type size */ + if (RV(p) >= p->n_sue->suesize) { + RV(p) = RV(p) % p->n_sue->suesize; + werror("shift larger than type"); + } + if (RV(p) == 0) + p = zapleft(p); + } + break; + + case LS: + if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { + /* two left-shift by constants */ + RV(p) += RV(p->n_left); + p->n_left = zapleft(p->n_left); + } +#if 0 + else if (LO(p) == RS && RCON(p->n_left) && RCON(p)) { + RV(p) -= RV(p->n_left); + p->n_left = zapleft(p->n_left); + } +#endif + if (RO(p) == ICON) { + if (RV(p) < 0) { + RV(p) = -RV(p); + p->n_op = RS; + goto again; + } +#ifdef notyet /* must check for side effects */ + if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue)) { + /* too many shifts */ + tfree(p->n_left); + nfree(p->n_right); + p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL; + } else +#endif + /* avoid larger shifts than type size */ + if (RV(p) >= p->n_sue->suesize) { + RV(p) = RV(p) % p->n_sue->suesize; + werror("shift larger than type"); + } + if (RV(p) == 0) + p = zapleft(p); + } + break; + + case MINUS: + if (LCON(p) && RCON(p) && p->n_left->n_sp == p->n_right->n_sp) { + /* link-time constants, but both are the same */ + /* solve it now by forgetting the symbols */ + p->n_left->n_sp = p->n_right->n_sp = NULL; + } + if( !nncon(p->n_right) ) break; + RV(p) = -RV(p); + o = p->n_op = PLUS; + + case MUL: + case PLUS: + case AND: + case OR: + case ER: + /* commutative ops; for now, just collect constants */ + /* someday, do it right */ + if( nncon(p->n_left) || ( LCON(p) && !RCON(p) ) ) + SWAP( p->n_left, p->n_right ); + /* make ops tower to the left, not the right */ + if( RO(p) == o ){ + NODE *t1, *t2, *t3; + t1 = p->n_left; + sp = p->n_right; + t2 = sp->n_left; + t3 = sp->n_right; + /* now, put together again */ + p->n_left = sp; + sp->n_left = t1; + sp->n_right = t2; + p->n_right = t3; + } + if(o == PLUS && LO(p) == MINUS && RCON(p) && RCON(p->n_left) && + conval(p->n_right, MINUS, p->n_left->n_right)){ + zapleft: + + q = p->n_left->n_left; + nfree(p->n_left->n_right); + nfree(p->n_left); + p->n_left = q; + } + if( RCON(p) && LO(p)==o && RCON(p->n_left) && + conval( p->n_right, o, p->n_left->n_right ) ){ + goto zapleft; + } + else if( LCON(p) && RCON(p) && conval( p->n_left, o, p->n_right ) ){ + zapright: + nfree(p->n_right); + q = makety(p->n_left, p->n_type, p->n_qual, + p->n_df, p->n_sue); + nfree(p); + return clocal(q); + } + + /* change muls to shifts */ + + if( o == MUL && nncon(p->n_right) && (i=ispow2(RV(p)))>=0){ + if( i == 0 ) { /* multiplication by 1 */ + goto zapright; + } + o = p->n_op = LS; + p->n_right->n_type = INT; + p->n_right->n_df = NULL; + RV(p) = i; + } + + /* change +'s of negative consts back to - */ + if( o==PLUS && nncon(p->n_right) && RV(p)<0 ){ + RV(p) = -RV(p); + o = p->n_op = MINUS; + } + + /* remove ops with RHS 0 */ + if ((o == PLUS || o == MINUS || o == OR || o == ER) && + nncon(p->n_right) && RV(p) == 0) { + goto zapright; + } + break; + + case DIV: + if( nncon( p->n_right ) && p->n_right->n_lval == 1 ) + goto zapright; + if (LCON(p) && RCON(p) && conval(p->n_left, DIV, p->n_right)) + goto zapright; + if (RCON(p) && ISUNSIGNED(p->n_type) && (i=ispow2(RV(p))) > 0) { + p->n_op = RS; + RV(p) = i; + q = p->n_right; + if(tsize(q->n_type, q->n_df, q->n_sue) > SZINT) + p->n_right = makety(q, INT, 0, 0, MKSUE(INT)); + + break; + } + break; + + case MOD: + if (RCON(p) && ISUNSIGNED(p->n_type) && ispow2(RV(p)) > 0) { + p->n_op = AND; + RV(p) = RV(p) -1; + break; + } + break; + + case EQ: + case NE: + case LT: + case LE: + case GT: + case GE: + case ULT: + case ULE: + case UGT: + case UGE: + if( !LCON(p) ) break; + + /* exchange operands */ + + sp = p->n_left; + p->n_left = p->n_right; + p->n_right = sp; + p->n_op = revrel[p->n_op - EQ ]; + break; + + } + + return(p); + } + +int +ispow2(CONSZ c) +{ + int i; + if( c <= 0 || (c&(c-1)) ) return(-1); + for( i=0; c>1; ++i) c >>= 1; + return(i); +} + +int +nncon( p ) NODE *p; { + /* is p a constant without a name */ + return( p->n_op == ICON && p->n_sp == NULL ); + } diff --git a/usr.bin/pcc/cc/ccom/pass1.h b/usr.bin/pcc/cc/ccom/pass1.h new file mode 100644 index 00000000000..8513888fff5 --- /dev/null +++ b/usr.bin/pcc/cc/ccom/pass1.h @@ -0,0 +1,394 @@ +/* $Id: pass1.h,v 1.1 2007/09/15 18:12:34 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 <sys/types.h> +#include <stdarg.h> + +#include "manifest.h" + +#include "protos.h" +#include "ccconfig.h" + +/* + * Storage classes + */ +#define SNULL 0 +#define AUTO 1 +#define EXTERN 2 +#define STATIC 3 +#define REGISTER 4 +#define EXTDEF 5 +/* #define LABEL 6*/ +/* #define ULABEL 7*/ +#define MOS 8 +#define PARAM 9 +#define STNAME 10 +#define MOU 11 +#define UNAME 12 +#define TYPEDEF 13 +#define FORTRAN 14 +#define ENAME 15 +#define MOE 16 +#define UFORTRAN 17 +#define USTATIC 18 +#define ILABEL 19 + + /* field size is ORed in */ +#define FIELD 0100 +#define FLDSIZ 077 +extern char *scnames(int); + +/* + * Symbol table flags + */ +#define SNORMAL 0 +#define STAGNAME 01 +#define SLBLNAME 02 +#define SMOSNAME 03 +#define SSTRING 04 +#define NSTYPES 05 +#define SMASK 07 + +#define SSET 00010 +#define SREF 00020 +#define SNOCREAT 00040 +#define STEMP 00100 +#define SDYNARRAY 00200 +#define SINLINE 00400 +#define STNODE 01000 +#ifdef GCC_COMPAT +#define SRENAME 02000 /* Node is renamed */ +#endif +#define SASG 04000 + +#ifndef FIXDEF +#define FIXDEF(p) +#endif + + /* alignment of initialized quantities */ +#ifndef AL_INIT +#define AL_INIT ALINT +#endif + +struct rstack; +struct symtab; +union arglist; + +/* + * Dimension/prototype information. + * ddim > 0 holds the dimension of an array. + * ddim < 0 is a dynamic array and refers to a tempnode. + */ +union dimfun { + int ddim; /* Dimension of an array */ + union arglist *dfun; /* Prototype index */ +}; + +/* + * Struct/union/enum definition. + * The first element (size) is used for other types as well. + */ +struct suedef { + int suesize; /* Size of the struct */ + struct symtab **suelem;/* points to the list of elements */ + int suealign; /* Alignment of this struct */ +}; + +/* + * Argument list member info when storing prototypes. + */ +union arglist { + TWORD type; + union dimfun *df; + struct suedef *sue; +}; +#define TNULL INCREF(MOETY) /* pointer to MOETY -- impossible type */ +#define TELLIPSIS INCREF(INCREF(MOETY)) + +/* + * Symbol table definition. + * + * The symtab_hdr struct is used to save label info in NAME and ICON nodes. + */ +struct symtab_hdr { + struct symtab *h_next; /* link to other symbols in the same scope */ + int h_offset; /* offset or value */ + char h_sclass; /* storage class */ + char h_slevel; /* scope level */ + short h_sflags; /* flags, see below */ +}; + +struct symtab { + struct symtab_hdr hdr; + char *sname; + TWORD stype; /* type word */ + TWORD squal; /* qualifier word */ + union dimfun *sdf; /* ptr to the dimension/prototype array */ + struct suedef *ssue; /* ptr to the definition table */ + int suse; /* line number of last use of the variable */ +}; + +#define snext hdr.h_next +#define soffset hdr.h_offset +#define sclass hdr.h_sclass +#define slevel hdr.h_slevel +#define sflags hdr.h_sflags + +#define MKSUE(type) &btdims[type] +extern struct suedef btdims[]; + +/* + * External definitions + */ +struct swents { /* switch table */ + struct swents *next; /* Next struct in linked list */ + CONSZ sval; /* case value */ + int slab; /* associated label */ +}; +void genswitch(int, struct swents **, int); + +extern int blevel; +extern int instruct, got_type; +extern int oldstyle; + +extern int lineno, nerrors; + +extern char *ftitle; +extern struct symtab *cftnsp; +extern int autooff, maxautooff, argoff, strucoff; +extern int brkflag; +extern int lastloc; + +extern OFFSZ inoff; + +extern int reached; +extern int isinlining; + +/* tunnel to buildtree for name id's */ + +extern struct symtab *spname; + +extern int sdebug, idebug, pdebug; + +/* various labels */ +extern int brklab; +extern int contlab; +extern int flostat; +extern int retlab; + +/* + * Flags used in structures/unions + */ +#define INSTRUCT 02 +#define INUNION 04 + +/* + * Flags used in the (elementary) flow analysis ... + */ +#define FBRK 02 +#define FCONT 04 +#define FDEF 010 +#define FLOOP 020 + +/* mark an offset which is undefined */ + +#define NOOFFSET (-10201) + +/* declarations of various functions */ +extern NODE + *buildtree(int, NODE *l, NODE *r), + *mkty(unsigned, union dimfun *, struct suedef *), + *rstruct(char *, int), + *dclstruct(struct rstack *), + *strend(char *), + *wstrend(char *), + *tymerge(NODE *typ, NODE *idp), + *stref(NODE *), + *offcon(OFFSZ, TWORD, union dimfun *, struct suedef *), + *bcon(int), + *bpsize(NODE *), + *convert(NODE *, int), + *pconvert(NODE *), + *oconvert(NODE *), + *ptmatch(NODE *), + *tymatch(NODE *), + *makety(NODE *, TWORD, TWORD, union dimfun *, struct suedef *), + *block(int, NODE *, NODE *r, TWORD, union dimfun *, struct suedef *), + *doszof(NODE *), + *talloc(void), + *optim(NODE *), + *clocal(NODE *), + *ccopy(NODE *), + *btsize(TWORD, union dimfun *, struct suedef *), + *tempnode(int, TWORD type, union dimfun *df, struct suedef *sue), + *doacall(NODE *f, NODE *a); +OFFSZ tsize(TWORD, union dimfun *, struct suedef *), + psize(NODE *); +NODE * typenode(NODE *new); +void spalloc(NODE *, NODE *, OFFSZ); +char *exname(char *); + +int oalloc(struct symtab *p, int *poff); +void deflabel(char *); +void deflab1(int); +void setloc1(int); +void gotolabel(char *); +unsigned int esccon(char **sptr); +void inline_start(char *name); +void inline_end(void); +void inline_addarg(struct interpass *); +void inline_ref(char *); +void inline_prtout(void); +void ftnarg(NODE *); +struct rstack *bstruct(char *, int); +void moedef(char *); +void beginit(struct symtab *); +void simpleinit(struct symtab *, NODE *); +struct symtab *lookup(char *name, int s); +struct symtab *getsymtab(char *name, int flags); +char *addstring(char *); +char *addname(char *); +char *newstring(char *, int len); +void symclear(int level); +void schedremove(struct symtab *p); +struct symtab *hide(struct symtab *p); +int talign(unsigned int, struct suedef *); +void bfcode(struct symtab **, int); +int chkftn(union arglist *, union arglist *); +void branch(int); +void cbranch(NODE *p, NODE *q); +void extdec(struct symtab *); +void commdec(struct symtab *); +void lcommdec(struct symtab *); +int falloc(struct symtab *p, int w, int new, NODE *pty); +TWORD ctype(TWORD); +void ninval(CONSZ off, int fsz, NODE *); +void infld(CONSZ off, int fsz, CONSZ); +void zbits(CONSZ off, int fsz); +void indata(CONSZ, int); +void instring(char *); +void defnam(struct symtab *); +void plabel(int lab); +void bjobcode(void); +void ejobcode(int); +void calldec(NODE *, NODE *); +int cisreg(TWORD); +char *tmpsprintf(char *fmt, ...); +char *tmpvsprintf(char *fmt, va_list ap); +void asginit(NODE *); +void desinit(NODE *); +void endinit(void); +void ilbrace(void); +void irbrace(void); +void scalinit(NODE *p); +int ftoint(NODE *, CONSZ **); +void p1print(char *fmt, ...); +char *copst(int); +int cdope(int); +void myp2tree(NODE *); +void lcommprint(void); +void lcommdel(struct symtab *); + +#ifdef GCC_COMPAT +void gcc_init(void); +int gcc_keyword(char *, NODE **); +void gcc_rename(struct symtab *sp, char *newname); +char *gcc_findname(struct symtab *sp); +#endif + +#ifdef STABS +void stabs_init(void); +void stabs_file(char *); +void stabs_line(int); +void stabs_rbrac(int); +void stabs_lbrac(int); +void stabs_func(struct symtab *); +void stabs_newsym(struct symtab *); +void stabs_chgsym(struct symtab *); +void stabs_struct(struct symtab *p, struct suedef *sue); +#endif + +#ifndef CHARCAST +/* to make character constants into character connstants */ +/* this is a macro to defend against cross-compilers, etc. */ +#define CHARCAST(x) (char)(x) +#endif + +/* + * C compiler first pass extra defines. + */ +#define QUALIFIER (MAXOP+1) +#define CLASS (MAXOP+2) +#define RB (MAXOP+3) +#define DOT (MAXOP+4) +#define ELLIPSIS (MAXOP+5) +#define TYPE (MAXOP+6) +#define LB (MAXOP+7) +#define COMOP (MAXOP+8) +#define QUEST (MAXOP+9) +#define COLON (MAXOP+10) +#define ANDAND (MAXOP+11) +#define OROR (MAXOP+12) +#define NOT (MAXOP+13) +#define CAST (MAXOP+14) +/* #define STRING (MAXOP+15) */ + +/* The following must be in the same order as their NOASG counterparts */ +#define PLUSEQ (MAXOP+16) +#define MINUSEQ (MAXOP+17) +#define DIVEQ (MAXOP+18) +#define MODEQ (MAXOP+19) +#define MULEQ (MAXOP+20) +#define ANDEQ (MAXOP+21) +#define OREQ (MAXOP+22) +#define EREQ (MAXOP+23) +#define LSEQ (MAXOP+24) +#define RSEQ (MAXOP+25) + +#define UNASG (-(PLUSEQ-PLUS))+ + +#define INCR (MAXOP+26) +#define DECR (MAXOP+27) +/* + * The following types are only used in pass1. + */ +#define SIGNED (MAXTYPES+1) +#define BOOL (MAXTYPES+2) + + +#define coptype(o) (cdope(o)&TYFLG) +#define clogop(o) (cdope(o)&LOGFLG) +#define casgop(o) (cdope(o)&ASGFLG) + diff --git a/usr.bin/pcc/cc/ccom/pftn.c b/usr.bin/pcc/cc/ccom/pftn.c new file mode 100644 index 00000000000..f5be111dc2c --- /dev/null +++ b/usr.bin/pcc/cc/ccom/pftn.c @@ -0,0 +1,2549 @@ +/* $Id: pftn.c,v 1.1 2007/09/15 18:12:34 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. + */ +/* + * 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. + */ + +/* + * Many changes from the 32V sources, among them: + * - New symbol table manager (moved to another file). + * - Prototype saving/checks. + */ + +# include "pass1.h" + +#include <string.h> /* XXX - for strcmp */ + +struct symtab *spname; +struct symtab *cftnsp; +static int strunem; /* currently parsed member type */ +int arglistcnt, dimfuncnt; /* statistics */ +int symtabcnt, suedefcnt; /* statistics */ +int autooff, /* the next unused automatic offset */ + maxautooff, /* highest used automatic offset in function */ + argoff, /* the next unused argument offset */ + strucoff; /* the next structure offset position */ +int retlab = NOLAB; /* return label for subroutine */ +int brklab; +int contlab; +int flostat; +int instruct, blevel; +int reached, prolab; + +struct params; + +#define ISSTR(ty) (ty == STRTY || ty == UNIONTY || ty == ENUMTY) +#define ISSOU(ty) (ty == STRTY || ty == UNIONTY) +#define MKTY(p, t, d, s) r = talloc(); *r = *p; \ + r = argcast(r, t, d, s); *p = *r; nfree(r); + +/* + * Info stored for delaying string printouts. + */ +struct strsched { + struct strsched *next; + int locctr; + struct symtab *sym; +} *strpole; + +/* + * Linked list stack while reading in structs. + */ +struct rstack { + struct rstack *rnext; + int rinstruct; + int rclass; + int rstrucoff; + struct params *rlparam; + struct symtab *rsym; +}; + +/* + * Linked list for parameter (and struct elements) declaration. + */ +static struct params { + struct params *next, *prev; + struct symtab *sym; +} *lpole, *lparam; +static int nparams; + +/* defines used for getting things off of the initialization stack */ + +static NODE *arrstk[10]; +static int arrstkp; +static int intcompare; + +void fixtype(NODE *p, int class); +int fixclass(int class, TWORD type); +int falloc(struct symtab *p, int w, int new, NODE *pty); +static void dynalloc(struct symtab *p, int *poff); +void inforce(OFFSZ n); +void vfdalign(int n); +static void ssave(struct symtab *); +static void strprint(void); +static void alprint(union arglist *al, int in); +static void lcommadd(struct symtab *sp); + +int ddebug = 0; + +/* + * Declaration of an identifier. Handles redeclarations, hiding, + * incomplete types and forward declarations. + */ + +void +defid(NODE *q, int class) +{ + struct symtab *p; + TWORD type, qual; + TWORD stp, stq; + int scl; + union dimfun *dsym, *ddef; + int slev, temp, changed; + + if (q == NIL) + return; /* an error was detected */ + + p = q->n_sp; + +#ifdef PCC_DEBUG + if (ddebug) { + printf("defid(%s (%p), ", p->sname, p); + tprint(stdout, q->n_type, q->n_qual); + printf(", %s, (%p,%p)), level %d\n", scnames(class), + q->n_df, q->n_sue, blevel); + } +#endif + + fixtype(q, class); + + type = q->n_type; + qual = q->n_qual; + class = fixclass(class, type); + + stp = p->stype; + stq = p->squal; + slev = p->slevel; + +#ifdef PCC_DEBUG + if (ddebug) { + printf(" modified to "); + tprint(stdout, type, qual); + printf(", %s\n", scnames(class)); + printf(" previous def'n: "); + tprint(stdout, stp, stq); + printf(", %s, (%p,%p)), level %d\n", + scnames(p->sclass), p->sdf, p->ssue, slev); + } +#endif + + if (blevel == 1) { + switch (class) { + default: + if (!(class&FIELD)) + uerror("declared argument %s missing", + p->sname ); + case MOS: + case STNAME: + case MOU: + case UNAME: + case MOE: + case ENAME: + case TYPEDEF: + ; + } + } + + if (stp == UNDEF) + goto enter; /* New symbol */ + + if (type != stp) + goto mismatch; + + if (blevel > slev && (class == AUTO || class == REGISTER)) + /* new scope */ + goto mismatch; + + /* + * test (and possibly adjust) dimensions. + * also check that prototypes are correct. + */ + dsym = p->sdf; + ddef = q->n_df; + changed = 0; + for (temp = type; temp & TMASK; temp = DECREF(temp)) { + if (ISARY(temp)) { + if (dsym->ddim == 0) { + dsym->ddim = ddef->ddim; + changed = 1; + } else if (ddef->ddim != 0 && dsym->ddim!=ddef->ddim) { + goto mismatch; + } + ++dsym; + ++ddef; + } else if (ISFTN(temp)) { + /* add a late-defined prototype here */ + if (cftnsp == NULL && dsym->dfun == NULL) + dsym->dfun = ddef->dfun; + if (!oldstyle && ddef->dfun != NULL && + chkftn(dsym->dfun, ddef->dfun)) + uerror("declaration doesn't match prototype"); + dsym++, ddef++; + } + } +#ifdef STABS + if (changed && gflag) + stabs_chgsym(p); /* symbol changed */ +#endif + + /* check that redeclarations are to the same structure */ + if ((temp == STRTY || temp == UNIONTY || temp == ENUMTY) && + p->ssue != q->n_sue && + class != STNAME && class != UNAME && class != ENAME) { + goto mismatch; + } + + scl = p->sclass; + +#ifdef PCC_DEBUG + if (ddebug) + printf(" previous class: %s\n", scnames(scl)); +#endif + + if (class&FIELD) { + /* redefinition */ + if (!falloc(p, class&FLDSIZ, 1, NIL)) { + /* successful allocation */ + ssave(p); + return; + } + /* blew it: resume at end of switch... */ + } else switch(class) { + + case EXTERN: + switch( scl ){ + case STATIC: + case USTATIC: + if( slev==0 ) return; + break; + case EXTDEF: + case EXTERN: + case FORTRAN: + case UFORTRAN: + return; + } + break; + + case STATIC: + if (scl==USTATIC || (scl==EXTERN && blevel==0)) { + p->sclass = STATIC; + return; + } + if (changed || (scl == STATIC && blevel == slev)) + return; /* identical redeclaration */ + break; + + case USTATIC: + if (scl==STATIC || scl==USTATIC) + return; + break; + + case TYPEDEF: + if (scl == class) + return; + break; + + case UFORTRAN: + if (scl == UFORTRAN || scl == FORTRAN) + return; + break; + + case FORTRAN: + if (scl == UFORTRAN) { + p->sclass = FORTRAN; + return; + } + break; + + case MOU: + case MOS: + if (scl == class) { + if (oalloc(p, &strucoff)) + break; + if (class == MOU) + strucoff = 0; + ssave(p); + return; + } + break; + + case MOE: + break; + + case EXTDEF: + switch (scl) { + case EXTERN: + p->sclass = EXTDEF; + return; + case USTATIC: + p->sclass = STATIC; + return; + } + break; + + case STNAME: + case UNAME: + case ENAME: + if (scl != class) + break; + if (p->ssue->suesize == 0) + return; /* previous entry just a mention */ + break; + + case AUTO: + case REGISTER: + ; /* mismatch.. */ + } + + mismatch: + + /* + * Only allowed for automatic variables. + */ + if (blevel == slev || class == EXTERN || class == FORTRAN || + class == UFORTRAN) { + if (ISSTR(class) && !ISSTR(p->sclass)) { + uerror("redeclaration of %s", p->sname); + return; + } + } + if (blevel == 0) + uerror("redeclaration of %s", p->sname); + q->n_sp = p = hide(p); + + enter: /* make a new entry */ + +#ifdef PCC_DEBUG + if(ddebug) + printf(" new entry made\n"); +#endif + p->stype = type; + p->squal = qual; + p->sclass = class; + p->slevel = blevel; + p->soffset = NOOFFSET; + p->suse = lineno; + if (class == STNAME || class == UNAME || class == ENAME) { + p->ssue = permalloc(sizeof(struct suedef)); + suedefcnt++; + p->ssue->suesize = 0; + p->ssue->suelem = NULL; + p->ssue->suealign = ALSTRUCT; + } else { + switch (BTYPE(type)) { + case STRTY: + case UNIONTY: + case ENUMTY: + p->ssue = q->n_sue; + break; + default: + p->ssue = MKSUE(BTYPE(type)); + } + } + + /* copy dimensions */ + p->sdf = q->n_df; + /* Do not save param info for old-style functions */ + if (ISFTN(type) && oldstyle) + p->sdf->dfun = NULL; + + /* allocate offsets */ + if (class&FIELD) { + (void) falloc(p, class&FLDSIZ, 0, NIL); /* new entry */ + ssave(p); + } else switch (class) { + + case REGISTER: + cerror("register var"); + + case AUTO: + if (arrstkp) + dynalloc(p, &autooff); + else + oalloc(p, &autooff); + break; + case STATIC: + case EXTDEF: + p->soffset = getlab(); +#ifdef GCC_COMPAT + { extern char *renname; + if (renname) + gcc_rename(p, renname); + renname = NULL; + } +#endif + break; + + case EXTERN: + case UFORTRAN: + case FORTRAN: + p->soffset = getlab(); +#ifdef notdef + /* Cannot reset level here. What does the standard say??? */ + p->slevel = 0; +#endif +#ifdef GCC_COMPAT + { extern char *renname; + if (renname) + gcc_rename(p, renname); + renname = NULL; + } +#endif + break; + case MOU: + case MOS: + oalloc(p, &strucoff); + if (class == MOU) + strucoff = 0; + ssave(p); + break; + + case MOE: + p->soffset = strucoff++; + ssave(p); + break; + + } + +#ifdef STABS + if (gflag) + stabs_newsym(p); +#endif + +#ifdef PCC_DEBUG + if (ddebug) + printf( " sdf, ssue, offset: %p, %p, %d\n", + p->sdf, p->ssue, p->soffset); +#endif + +} + +void +ssave(struct symtab *sym) +{ + struct params *p; + + p = tmpalloc(sizeof(struct params)); + p->next = NULL; + p->sym = sym; + + if (lparam == NULL) { + p->prev = (struct params *)&lpole; + lpole = p; + } else { + lparam->next = p; + p->prev = lparam; + } + lparam = p; +} + +/* + * end of function + */ +void +ftnend() +{ + extern struct savbc *savbc; + extern struct swdef *swpole; + char *c; + + if (retlab != NOLAB && nerrors == 0) { /* inside a real function */ + plabel(retlab); + efcode(); /* struct return handled here */ + c = cftnsp->sname; +#ifdef GCC_COMPAT + c = gcc_findname(cftnsp); +#endif + SETOFF(maxautooff, ALCHAR); + send_passt(IP_EPILOG, 0, maxautooff/SZCHAR, c, + cftnsp->stype, cftnsp->sclass == EXTDEF, retlab); + } + + tcheck(); + brklab = contlab = retlab = NOLAB; + flostat = 0; + if (nerrors == 0) { + if (savbc != NULL) + cerror("bcsave error"); + if (lparam != NULL) + cerror("parameter reset error"); + if (swpole != NULL) + cerror("switch error"); + } + savbc = NULL; + lparam = NULL; + maxautooff = autooff = AUTOINIT; + reached = 1; + + if (isinlining) + inline_end(); + inline_prtout(); + + strprint(); + + tmpfree(); /* Release memory resources */ +} + +void +dclargs() +{ + union dimfun *df; + union arglist *al, *al2, *alb; + struct params *a; + struct symtab *p, **parr = NULL; /* XXX gcc */ + char *c; + int i; + + argoff = ARGINIT; + + /* + * Deal with fun(void) properly. + */ + if (nparams == 1 && lparam->sym->stype == VOID) + goto done; + + /* + * Generate a list for bfcode(). + * Parameters were pushed in reverse order. + */ + if (nparams != 0) + parr = tmpalloc(sizeof(struct symtab *) * nparams); + + if (nparams) + for (a = lparam, i = 0; a != NULL && a != (struct params *)&lpole; + a = a->prev) { + + p = a->sym; + parr[i++] = p; + if (p->stype == FARG) { + p->stype = INT; + p->ssue = MKSUE(INT); + } + if (ISARY(p->stype)) { + p->stype += (PTR-ARY); + p->sdf++; + } else if (ISFTN(p->stype)) { + werror("function declared as argument"); + p->stype = INCREF(p->stype); + } + /* always set aside space, even for register arguments */ + oalloc(p, &argoff); +#ifdef STABS + if (gflag) + stabs_newsym(p); +#endif + } + if (oldstyle && (df = cftnsp->sdf) && (al = df->dfun)) { + /* + * Check against prototype of oldstyle function. + */ + alb = al2 = tmpalloc(sizeof(union arglist) * nparams * 3 + 1); + for (i = 0; i < nparams; i++) { + TWORD type = parr[i]->stype; + (al2++)->type = type; + if (ISSTR(BTYPE(type))) + (al2++)->sue = parr[i]->ssue; + while (!ISFTN(type) && !ISARY(type) && type > BTMASK) + type = DECREF(type); + if (type > BTMASK) + (al2++)->df = parr[i]->sdf; + } + al2->type = TNULL; + intcompare = 1; + if (chkftn(al, alb)) + uerror("function doesn't match prototype"); + intcompare = 0; + } +done: cendarg(); + c = cftnsp->sname; +#ifdef GCC_COMPAT + c = gcc_findname(cftnsp); +#endif +#if 0 + prolab = getlab(); + send_passt(IP_PROLOG, -1, -1, c, cftnsp->stype, + cftnsp->sclass == EXTDEF, prolab); +#endif + plabel(prolab); /* after prolog, used in optimization */ + retlab = getlab(); + bfcode(parr, nparams); + if (xtemps) { + /* put arguments in temporaries */ + for (i = 0; i < nparams; i++) { + NODE *q, *r, *s; + + p = parr[i]; + if (p->stype == STRTY || p->stype == UNIONTY || + cisreg(p->stype) == 0) + continue; + spname = p; + q = buildtree(NAME, 0, 0); + r = tempnode(0, p->stype, p->sdf, p->ssue); + s = buildtree(ASSIGN, r, q); + p->soffset = r->n_lval; + p->sflags |= STNODE; + ecomp(s); + } + plabel(getlab()); /* used when spilling */ + } + lparam = NULL; + nparams = 0; +} + +/* + * reference to a structure or union, with no definition + */ +NODE * +rstruct(char *tag, int soru) +{ + struct symtab *p; + NODE *q; + + p = (struct symtab *)lookup(tag, STAGNAME); + switch (p->stype) { + + case UNDEF: + def: + q = block(NAME, NIL, NIL, 0, 0, 0); + q->n_sp = p; + q->n_type = (soru&INSTRUCT) ? STRTY : + ((soru&INUNION) ? UNIONTY : ENUMTY); + defid(q, (soru&INSTRUCT) ? STNAME : + ((soru&INUNION) ? UNAME : ENAME)); + nfree(q); + break; + + case STRTY: + if (soru & INSTRUCT) + break; + goto def; + + case UNIONTY: + if (soru & INUNION) + break; + goto def; + + case ENUMTY: + if (!(soru&(INUNION|INSTRUCT))) + break; + goto def; + + } + q = mkty(p->stype, 0, p->ssue); + q->n_sue = p->ssue; + return q; +} + +void +moedef(char *name) +{ + NODE *q; + + q = block(NAME, NIL, NIL, MOETY, 0, 0); + q->n_sp = lookup(name, 0); + defid(q, MOE); + nfree(q); +} + +/* + * begining of structure or union declaration + */ +struct rstack * +bstruct(char *name, int soru) +{ + struct rstack *r; + struct symtab *s; + NODE *q; + + if (name != NULL) + s = lookup(name, STAGNAME); + else + s = NULL; + + r = tmpalloc(sizeof(struct rstack)); + r->rinstruct = instruct; + r->rclass = strunem; + r->rstrucoff = strucoff; + + strucoff = 0; + instruct = soru; + q = block(NAME, NIL, NIL, 0, 0, 0); + q->n_sp = s; + if (instruct==INSTRUCT) { + strunem = MOS; + q->n_type = STRTY; + if (s != NULL) + defid(q, STNAME); + } else if(instruct == INUNION) { + strunem = MOU; + q->n_type = UNIONTY; + if (s != NULL) + defid(q, UNAME); + } else { /* enum */ + strunem = MOE; + q->n_type = ENUMTY; + if (s != NULL) + defid(q, ENAME); + } + r->rsym = q->n_sp; + r->rlparam = lparam; + nfree(q); + + return r; +} + +/* + * Called after a struct is declared to restore the environment. + */ +NODE * +dclstruct(struct rstack *r) +{ + NODE *n; + struct params *l, *m; + struct suedef *sue; + struct symtab *p; + int al, sa, sz; + TWORD temp; + int i, high, low; + + if (r->rsym == NULL) { + sue = permalloc(sizeof(struct suedef)); + suedefcnt++; + sue->suesize = 0; + sue->suealign = ALSTRUCT; + } else + sue = r->rsym->ssue; + +#ifdef PCC_DEBUG + if (ddebug) + printf("dclstruct(%s)\n", r->rsym ? r->rsym->sname : "??"); +#endif + temp = (instruct&INSTRUCT)?STRTY:((instruct&INUNION)?UNIONTY:ENUMTY); + instruct = r->rinstruct; + strunem = r->rclass; + al = ALSTRUCT; + + high = low = 0; + + if ((l = r->rlparam) == NULL) + l = lpole; + else + l = l->next; + + /* memory for the element array must be allocated first */ + for (m = l, i = 1; m != NULL; m = m->next) + i++; + sue->suelem = permalloc(sizeof(struct symtab *) * i); + + for (i = 0; l != NULL; l = l->next) { + sue->suelem[i++] = p = l->sym; + + if (p == NULL) + cerror("gummy structure member"); + if (temp == ENUMTY) { + if (p->soffset < low) + low = p->soffset; + if (p->soffset > high) + high = p->soffset; + p->ssue = sue; + continue; + } + sa = talign(p->stype, p->ssue); + if (p->sclass & FIELD) { + sz = p->sclass&FLDSIZ; + } else { + sz = tsize(p->stype, p->sdf, p->ssue); + } + if (sz > strucoff) + strucoff = sz; /* for use with unions */ + /* + * set al, the alignment, to the lcm of the alignments + * of the members. + */ + SETOFF(al, sa); + } + sue->suelem[i] = NULL; + SETOFF(strucoff, al); + + if (temp == ENUMTY) { + TWORD ty; + +#ifdef ENUMSIZE + ty = ENUMSIZE(high,low); +#else + if ((char)high == high && (char)low == low) + ty = ctype(CHAR); + else if ((short)high == high && (short)low == low) + ty = ctype(SHORT); + else + ty = ctype(INT); +#endif + strucoff = tsize(ty, 0, MKSUE(ty)); + sue->suealign = al = talign(ty, MKSUE(ty)); + } + + sue->suesize = strucoff; + sue->suealign = al; + +#ifdef STABS + if (gflag) + stabs_struct(r->rsym, sue); +#endif + +#ifdef PCC_DEBUG + if (ddebug>1) { + int i; + + printf("\tsize %d align %d elem %p\n", + sue->suesize, sue->suealign, sue->suelem); + for (i = 0; sue->suelem[i] != NULL; ++i) { + printf("\tmember %s(%p)\n", + sue->suelem[i]->sname, sue->suelem[i]); + } + } +#endif + + strucoff = r->rstrucoff; + if ((lparam = r->rlparam) != NULL) + lparam->next = NULL; + n = mkty(temp, 0, sue); + return n; +} + +/* + * error printing routine in parser + */ +void yyerror(char *s); +void +yyerror(char *s) +{ + uerror(s); +} + +void yyaccpt(void); +void +yyaccpt(void) +{ + ftnend(); +} + +/* + * p is top of type list given to tymerge later. + * Find correct CALL node and declare parameters from there. + */ +void +ftnarg(NODE *p) +{ + NODE *q; + struct symtab *s; + +#ifdef PCC_DEBUG + if (ddebug > 2) + printf("ftnarg(%p)\n", p); +#endif + /* + * Enter argument onto param stack. + * Do not declare parameters until later (in dclargs); + * the function must be declared first. + * put it on the param stack in reverse order, due to the + * nature of the stack it will be reclaimed correct. + */ + for (; p->n_op != NAME; p = p->n_left) { + if (p->n_op == (UCALL) && p->n_left->n_op == NAME) + return; /* Nothing to enter */ + if (p->n_op == CALL && p->n_left->n_op == NAME) + break; + } + + p = p->n_right; + blevel = 1; + + while (p->n_op == CM) { + q = p->n_right; + if (q->n_op != ELLIPSIS) { + s = lookup((char *)q->n_sp, 0); + if (s->stype != UNDEF) { + if (s->slevel > 0) + uerror("parameter '%s' redefined", + s->sname); + s = hide(s); + } + s->soffset = NOOFFSET; + s->sclass = PARAM; + s->stype = q->n_type; + s->sdf = q->n_df; + s->ssue = q->n_sue; + ssave(s); + nparams++; +#ifdef PCC_DEBUG + if (ddebug > 2) + printf(" saving sym %s (%p) from (%p)\n", + s->sname, s, q); +#endif + } + p = p->n_left; + } + s = lookup((char *)p->n_sp, 0); + if (s->stype != UNDEF) { + if (s->slevel > 0) + uerror("parameter '%s' redefined", s->sname); + s = hide(s); + } + s->soffset = NOOFFSET; + s->sclass = PARAM; + s->stype = p->n_type; + s->sdf = p->n_df; + s->ssue = p->n_sue; + ssave(s); + if (p->n_type != VOID) + nparams++; + blevel = 0; + +#ifdef PCC_DEBUG + if (ddebug > 2) + printf(" saving sym %s (%p) from (%p)\n", + s->sname, s, p); +#endif +} + +/* + * compute the alignment of an object with type ty, sizeoff index s + */ +int +talign(unsigned int ty, struct suedef *sue) +{ + int i; + + if (ISPTR(ty)) + return(ALPOINT); /* shortcut */ + + if(sue == NULL && ty!=INT && ty!=CHAR && ty!=SHORT && + ty!=UNSIGNED && ty!=UCHAR && ty!=USHORT) { + return(fldal(ty)); + } + + for( i=0; i<=(SZINT-BTSHIFT-1); i+=TSHIFT ){ + switch( (ty>>i)&TMASK ){ + + case FTN: + cerror("compiler takes alignment of function"); + case PTR: + return(ALPOINT); + case ARY: + continue; + case 0: + break; + } + } + + switch( BTYPE(ty) ){ + + case UNIONTY: + case ENUMTY: + case STRTY: + return((unsigned int)sue->suealign); + case BOOL: + return (ALBOOL); + case CHAR: + case UCHAR: + return (ALCHAR); + case FLOAT: + return (ALFLOAT); + case LDOUBLE: + return (ALLDOUBLE); + case DOUBLE: + return (ALDOUBLE); + case LONGLONG: + case ULONGLONG: + return (ALLONGLONG); + case LONG: + case ULONG: + return (ALLONG); + case SHORT: + case USHORT: + return (ALSHORT); + default: + return (ALINT); + } +} + +/* compute the size associated with type ty, + * dimoff d, and sizoff s */ +/* BETTER NOT BE CALLED WHEN t, d, and s REFER TO A BIT FIELD... */ +OFFSZ +tsize(TWORD ty, union dimfun *d, struct suedef *sue) +{ + + int i; + OFFSZ mult, sz; + + mult = 1; + + for( i=0; i<=(SZINT-BTSHIFT-1); i+=TSHIFT ){ + switch( (ty>>i)&TMASK ){ + + case FTN: + uerror( "cannot take size of function"); + case PTR: + return( SZPOINT(ty) * mult ); + case ARY: + mult *= d->ddim; + d++; + continue; + case 0: + break; + + } + } + + if (sue == NULL) + cerror("bad tsize sue"); + sz = sue->suesize; +#ifdef GCC_COMPAT + if (ty == VOID) + sz = SZCHAR; +#endif + if (ty != STRTY && ty != UNIONTY) { + if (sz == 0) { + uerror("unknown size"); + return(SZINT); + } + } else { + if (sue->suelem == NULL) + uerror("unknown structure/union/enum"); + } + + return((unsigned int)sz * mult); +} + +/* + * Write last part of wide string. + * Do not bother to save wide strings. + */ +NODE * +wstrend(char *str) +{ + struct symtab *sp = getsymtab(str, SSTRING|STEMP); + struct strsched *sc = tmpalloc(sizeof(struct strsched)); + NODE *p = block(NAME, NIL, NIL, WCHAR_TYPE+ARY, + tmpalloc(sizeof(union dimfun)), MKSUE(WCHAR_TYPE)); + int i; + char *c; + + sp->sclass = ILABEL; + sp->soffset = getlab(); + sp->stype = WCHAR_TYPE+ARY; + + sc = tmpalloc(sizeof(struct strsched)); + sc->locctr = STRNG; + sc->sym = sp; + sc->next = strpole; + strpole = sc; + + /* length calculation, used only for sizeof */ + for (i = 0, c = str; *c; ) { + if (*c++ == '\\') + (void)esccon(&c); + i++; + } + p->n_df->ddim = (i+1) * ((MKSUE(WCHAR_TYPE))->suesize/SZCHAR); + p->n_sp = sp; + return(p); +} + +/* + * Write last part of string. + */ +NODE * +strend(char *str) +{ +// extern int maystr; + struct symtab *s; + NODE *p; + int i; + char *c; + + /* If an identical string is already emitted, just forget this one */ + str = addstring(str); /* enter string in string table */ + s = lookup(str, SSTRING); /* check for existance */ + + if (s->soffset == 0 /* && maystr == 0 */) { /* No string */ + struct strsched *sc; + s->sclass = ILABEL; + + /* + * Delay printout of this string until after the current + * function, or the end of the statement. + */ + sc = tmpalloc(sizeof(struct strsched)); + sc->locctr = STRNG; + sc->sym = s; + sc->next = strpole; + strpole = sc; + s->soffset = getlab(); + } + + p = block(NAME, NIL, NIL, CHAR+ARY, + tmpalloc(sizeof(union dimfun)), MKSUE(CHAR)); +#ifdef CHAR_UNSIGNED + p->n_type = UCHAR+ARY; +#endif + /* length calculation, used only for sizeof */ + for (i = 0, c = str; *c; ) { + if (*c++ == '\\') + (void)esccon(&c); + i++; + } + p->n_df->ddim = i+1; + p->n_sp = s; + return(p); +} + +/* + * Print out new strings, before temp memory is cleared. + */ +void +strprint() +{ + char *wr; + int i, val, isw; + NODE *p = bcon(0); + + while (strpole != NULL) { + setloc1(STRNG); + deflab1(strpole->sym->soffset); + isw = strpole->sym->stype == WCHAR_TYPE+ARY; + + i = 0; + wr = strpole->sym->sname; + while (*wr != 0) { + if (*wr++ == '\\') + val = esccon(&wr); + else + val = (unsigned char)wr[-1]; + if (isw) { + p->n_lval = val; + p->n_type = WCHAR_TYPE; + ninval(i*(WCHAR_TYPE/SZCHAR), + (MKSUE(WCHAR_TYPE))->suesize, p); + } else + bycode(val, i); + i++; + } + if (isw) { + p->n_lval = 0; + ninval(i*(WCHAR_TYPE/SZCHAR), + (MKSUE(WCHAR_TYPE))->suesize, p); + } else { + bycode(0, i++); + bycode(-1, i); + } + strpole = strpole->next; + } + nfree(p); +} + +#if 0 +/* + * simulate byte v appearing in a list of integer values + */ +void +putbyte(int v) +{ + NODE *p; + p = bcon(v); + incode( p, SZCHAR ); + tfree( p ); +// gotscal(); +} +#endif + +/* + * update the offset pointed to by poff; return the + * offset of a value of size `size', alignment `alignment', + * given that off is increasing + */ +int +upoff(int size, int alignment, int *poff) +{ + int off; + + off = *poff; + SETOFF(off, alignment); + if (off < 0) + cerror("structure or stack overgrown"); /* wrapped */ + *poff = off+size; + return (off); +} + +/* + * allocate p with offset *poff, and update *poff + */ +int +oalloc(struct symtab *p, int *poff ) +{ + int al, off, tsz; + int noff; + + /* + * Only generate tempnodes if we are optimizing, + * and only for integers, floats or pointers, + * and not if the basic type is volatile. + */ +/* XXX OLDSTYLE */ + if (xtemps && ((p->sclass == AUTO) || (p->sclass == REGISTER)) && + (p->stype < STRTY || ISPTR(p->stype)) && + !ISVOL((p->squal << TSHIFT)) && cisreg(p->stype)) { + NODE *tn = tempnode(0, p->stype, p->sdf, p->ssue); + p->soffset = tn->n_lval; + p->sflags |= STNODE; + nfree(tn); + return 0; + } + + al = talign(p->stype, p->ssue); + noff = off = *poff; + tsz = tsize(p->stype, p->sdf, p->ssue); +#ifdef BACKAUTO + if (p->sclass == AUTO) { + noff = off + tsz; + if (noff < 0) + cerror("stack overflow"); + SETOFF(noff, al); + off = -noff; + } else +#endif + if (p->sclass == PARAM && (p->stype == CHAR || p->stype == UCHAR || + p->stype == SHORT || p->stype == USHORT)) { + off = upoff(SZINT, ALINT, &noff); +#ifndef RTOLBYTES + off = noff - tsz; +#endif + } else { + off = upoff(tsz, al, &noff); + } + + if (p->sclass != REGISTER) { + /* in case we are allocating stack space for register arguments */ + if (p->soffset == NOOFFSET) + p->soffset = off; + else if(off != p->soffset) + return(1); + } + + *poff = noff; + return(0); +} + +/* + * Allocate space on the stack for dynamic arrays. + * Strategy is as follows: + * - first entry is a pointer to the dynamic datatype. + * - if it's a one-dimensional array this will be the only entry used. + * - if it's a multi-dimensional array the following (numdim-1) integers + * will contain the sizes to multiply the indexes with. + * - code to write the dimension sizes this will be generated here. + * - code to allocate space on the stack will be generated here. + */ +static void +dynalloc(struct symtab *p, int *poff) +{ + union dimfun *df; + NODE *n, *nn, *tn, *pol; + TWORD t; + int i, no; + + /* + * The pointer to the array is stored in a TEMP node, which number + * is in the soffset field; + */ + t = p->stype; + p->sflags |= (STNODE|SDYNARRAY); + p->stype = INCREF(p->stype); /* Make this an indirect pointer */ + tn = tempnode(0, p->stype, p->sdf, p->ssue); + p->soffset = tn->n_lval; + + df = p->sdf; + + pol = NIL; + for (i = 0; ISARY(t); t = DECREF(t), df++) { + if (df->ddim >= 0) + continue; + n = arrstk[i++]; + nn = tempnode(0, INT, 0, MKSUE(INT)); + no = nn->n_lval; + ecomp(buildtree(ASSIGN, nn, n)); /* Save size */ + + df->ddim = -no; + n = tempnode(no, INT, 0, MKSUE(INT)); + if (pol == NIL) + pol = n; + else + pol = buildtree(MUL, pol, n); + } + /* Create stack gap */ + spalloc(tn, pol, tsize(t, 0, p->ssue)); + arrstkp = 0; +} + +/* + * allocate a field of width w + * new is 0 if new entry, 1 if redefinition, -1 if alignment + */ +int +falloc(struct symtab *p, int w, int new, NODE *pty) +{ + int al,sz,type; + + type = (new<0)? pty->n_type : p->stype; + + /* this must be fixed to use the current type in alignments */ + switch( new<0?pty->n_type:p->stype ){ + + case ENUMTY: { + struct suedef *sue; + sue = new < 0 ? pty->n_sue : p->ssue; + al = sue->suealign; + sz = sue->suesize; + break; + } + + case CHAR: + case UCHAR: + al = ALCHAR; + sz = SZCHAR; + break; + + case SHORT: + case USHORT: + al = ALSHORT; + sz = SZSHORT; + break; + + case INT: + case UNSIGNED: + al = ALINT; + sz = SZINT; + break; + + default: + if( new < 0 ) { + uerror( "illegal field type" ); + al = ALINT; + } else + al = fldal( p->stype ); + sz =SZINT; + } + + if( w > sz ) { + uerror( "field too big"); + w = sz; + } + + if( w == 0 ){ /* align only */ + SETOFF( strucoff, al ); + if( new >= 0 ) uerror( "zero size field"); + return(0); + } + + if( strucoff%al + w > sz ) SETOFF( strucoff, al ); + if( new < 0 ) { + strucoff += w; /* we know it will fit */ + return(0); + } + + /* establish the field */ + + if( new == 1 ) { /* previous definition */ + if( p->soffset != strucoff || p->sclass != (FIELD|w) ) return(1); + } + p->soffset = strucoff; + strucoff += w; + p->stype = type; + fldty( p ); + return(0); +} + +/* + * handle unitialized declarations assumed to be not functions: + * int a; + * extern int a; + * static int a; + */ +void +nidcl(NODE *p, int class) +{ + struct symtab *sp; + int commflag = 0; + + /* compute class */ + if (class == SNULL) { + if (blevel > 1) + class = AUTO; + else if (blevel != 0 || instruct) + cerror( "nidcl error" ); + else /* blevel = 0 */ + commflag = 1, class = EXTERN; + } + + defid(p, class); + + sp = p->n_sp; + /* check if forward decl */ + if (ISARY(sp->stype) && sp->sdf->ddim == 0) + return; + + if (sp->sflags & SASG) + return; /* already initialized */ + + switch (class) { + case EXTDEF: + /* simulate initialization by 0 */ + simpleinit(p->n_sp, bcon(0)); + break; + case EXTERN: + if (commflag) + lcommadd(p->n_sp); + else + extdec(p->n_sp); + break; + case STATIC: + if (blevel == 0) + lcommadd(p->n_sp); + else + lcommdec(p->n_sp); + break; + } +} + +struct lcd { + SLIST_ENTRY(lcd) next; + struct symtab *sp; +}; + +static SLIST_HEAD(, lcd) lhead = { NULL, &lhead.q_forw}; + +/* + * Add a local common statement to the printout list. + */ +void +lcommadd(struct symtab *sp) +{ + struct lcd *lc, *lcp; + + lcp = NULL; + SLIST_FOREACH(lc, &lhead, next) { + if (lc->sp == sp) + return; /* already exists */ + if (lc->sp == NULL && lcp == NULL) + lcp = lc; + } + if (lcp == NULL) { + lc = permalloc(sizeof(struct lcd)); + lc->sp = sp; + SLIST_INSERT_LAST(&lhead, lc, next); + } else + lcp->sp = sp; +} + +/* + * Delete a local common statement. + */ +void +lcommdel(struct symtab *sp) +{ + struct lcd *lc; + + SLIST_FOREACH(lc, &lhead, next) { + if (lc->sp == sp) { + lc->sp = NULL; + return; + } + } +} + +/* + * Print out the remaining common statements. + */ +void +lcommprint(void) +{ + struct lcd *lc; + + SLIST_FOREACH(lc, &lhead, next) { + if (lc->sp != NULL) { + if (lc->sp->sclass == STATIC) + lcommdec(lc->sp); + else + commdec(lc->sp); + } + } +} + +/* + * Merges a type tree into one type. Returns one type node with merged types + * and class stored in the su field. Frees all other nodes. + * XXX - classes in typedefs? + */ +NODE * +typenode(NODE *p) +{ + NODE *l, *sp = NULL; + int class = 0, adj, noun, sign; + TWORD qual = 0; + + adj = INT; /* INT, LONG or SHORT */ + noun = UNDEF; /* INT, CHAR or FLOAT */ + sign = 0; /* 0, SIGNED or UNSIGNED */ + + /* Remove initial QUALIFIERs */ + if (p && p->n_op == QUALIFIER) { + qual = p->n_type; + l = p->n_left; + nfree(p); + p = l; + } + + /* Handle initial classes special */ + if (p && p->n_op == CLASS) { + class = p->n_type; + l = p->n_left; + nfree(p); + p = l; + } + + /* Remove more QUALIFIERs */ + if (p && p->n_op == QUALIFIER) { + qual |= p->n_type; + l = p->n_left; + nfree(p); + p = l; + } + +ag: if (p && p->n_op == TYPE) { + if (p->n_left == NIL) { +#ifdef CHAR_UNSIGNED + if (p->n_type == CHAR) + p->n_type = UCHAR; +#endif + if (p->n_type == SIGNED) + p->n_type = INT; +uni: p->n_lval = class; + p->n_qual = qual >> TSHIFT; + return p; + } else if (p->n_left->n_op == QUALIFIER) { + qual |= p->n_left->n_type; + l = p->n_left; + p->n_left = l->n_left; + nfree(l); + goto ag; + } else if (ISSTR(p->n_type)) { + /* Save node; needed for return */ + sp = p; + p = p->n_left; + } + } + + while (p != NIL) { + if (p->n_op == QUALIFIER) { + qual |= p->n_type; + goto next; + } + if (p->n_op == CLASS) { + if (class != 0) + uerror("too many storage classes"); + class = p->n_type; + goto next; + } + if (p->n_op != TYPE) + cerror("typenode got notype %d", p->n_op); + switch (p->n_type) { + case UCHAR: + case USHORT: /* may come from typedef */ + if (sign != 0 || adj != INT) + goto bad; + noun = p->n_type; + break; + case SIGNED: + case UNSIGNED: + if (sign != 0) + goto bad; + sign = p->n_type; + break; + case LONG: + if (adj == LONG) { + adj = LONGLONG; + break; + } + /* FALLTHROUGH */ + case SHORT: + if (adj != INT) + goto bad; + adj = p->n_type; + break; + case INT: + case CHAR: + case FLOAT: + case DOUBLE: + if (noun != UNDEF) + goto bad; + noun = p->n_type; + break; + case VOID: + if (noun != UNDEF || adj != INT) + goto bad; + adj = noun = VOID; + break; + case STRTY: + case UNIONTY: + break; + default: + goto bad; + } + next: + l = p->n_left; + nfree(p); + p = l; + } + + if (sp) { + p = sp; + goto uni; + } + +#ifdef CHAR_UNSIGNED + if (noun == CHAR && sign == 0) + sign = UNSIGNED; +#endif + if (noun == UNDEF) { + noun = INT; + } else if (noun == FLOAT) { + if (sign != 0 || adj == SHORT) + goto bad; + noun = (adj == LONG ? DOUBLE : FLOAT); + } else if (noun == DOUBLE) { + if (sign != 0 || adj == SHORT) + goto bad; + noun = (adj == LONG ? LDOUBLE : DOUBLE); + } else if (noun == CHAR && adj != INT) + goto bad; + + if (adj != INT && (noun != DOUBLE && noun != LDOUBLE)) + noun = adj; + if (sign == UNSIGNED) + noun += (UNSIGNED-INT); + + p = block(TYPE, NIL, NIL, noun, 0, 0); + p->n_qual = qual >> TSHIFT; + if (strunem != 0) + class = strunem; + p->n_lval = class; + return p; + +bad: uerror("illegal type combination"); + return mkty(INT, 0, 0); +} + +struct tylnk { + struct tylnk *next; + union dimfun df; +}; + +static void tyreduce(NODE *p, struct tylnk **, int *); + +static void +tylkadd(union dimfun dim, struct tylnk **tylkp, int *ntdim) +{ + (*tylkp)->next = tmpalloc(sizeof(struct tylnk)); + *tylkp = (*tylkp)->next; + (*tylkp)->next = NULL; + (*tylkp)->df = dim; + (*ntdim)++; +} + +/* merge type typ with identifier idp */ +NODE * +tymerge(NODE *typ, NODE *idp) +{ + NODE *p; + union dimfun *j; + struct tylnk *base, tylnk, *tylkp; + unsigned int t; + int ntdim, i; + + if (typ->n_op != TYPE) + cerror("tymerge: arg 1"); + +#ifdef PCC_DEBUG + if (ddebug > 2) { + printf("tymerge(%p,%p)\n", typ, idp); + fwalk(typ, eprint, 0); + fwalk(idp, eprint, 0); + } +#endif + + idp->n_type = typ->n_type; + idp->n_qual = (typ->n_qual << TSHIFT) | idp->n_qual; /* XXX ??? */ + + tylkp = &tylnk; + tylkp->next = NULL; + ntdim = 0; + + tyreduce(idp, &tylkp, &ntdim); + idp->n_sue = typ->n_sue; + + for (t = typ->n_type, j = typ->n_df; t&TMASK; t = DECREF(t)) + if (ISARY(t) || ISFTN(t)) + tylkadd(*j++, &tylkp, &ntdim); + + if (ntdim) { + union dimfun *a = permalloc(sizeof(union dimfun) * ntdim); + dimfuncnt += ntdim; + for (i = 0, base = tylnk.next; base; base = base->next, i++) + a[i] = base->df; + idp->n_df = a; + } else + idp->n_df = NULL; + + /* now idp is a single node: fix up type */ + + idp->n_type = ctype(idp->n_type); + idp->n_qual = DECQAL(idp->n_qual); + + /* in case ctype has rewritten things */ + if ((t = BTYPE(idp->n_type)) != STRTY && t != UNIONTY && t != ENUMTY) + idp->n_sue = MKSUE(t); + + if (idp->n_op != NAME) { + for (p = idp->n_left; p->n_op != NAME; p = p->n_left) + nfree(p); + nfree(p); + idp->n_op = NAME; + } + + return(idp); +} + +/* + * Retrieve all CM-separated argument types, sizes and dimensions and + * put them in an array. + * XXX - can only check first type level, side effects? + */ +static union arglist * +arglist(NODE *n) +{ + union arglist *al; + NODE *w = n, **ap; + int num, cnt, i, j, k; + TWORD ty; + +#ifdef PCC_DEBUG + if (pdebug) { + printf("arglist %p\n", n); + fwalk(n, eprint, 0); + } +#endif + /* First: how much to allocate */ + for (num = cnt = 0, w = n; w->n_op == CM; w = w->n_left) { + cnt++; /* Number of levels */ + num++; /* At least one per step */ + if (w->n_right->n_op == ELLIPSIS) + continue; + ty = w->n_right->n_type; + if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY || + BTYPE(ty) == ENUMTY) + num++; + while (ISFTN(ty) == 0 && ISARY(ty) == 0 && ty > BTMASK) + ty = DECREF(ty); + if (ty > BTMASK) + num++; + } + cnt++; + ty = w->n_type; + if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY || + BTYPE(ty) == ENUMTY) + num++; + while (ISFTN(ty) == 0 && ISARY(ty) == 0 && ty > BTMASK) + ty = DECREF(ty); + if (ty > BTMASK) + num++; + num += 2; /* TEND + last arg type */ + + /* Second: Create list to work on */ + ap = tmpalloc(sizeof(NODE *) * cnt); + al = permalloc(sizeof(union arglist) * num); + arglistcnt += num; + + for (w = n, i = 0; w->n_op == CM; w = w->n_left) + ap[i++] = w->n_right; + ap[i] = w; + + /* Third: Create actual arg list */ + for (k = 0, j = i; j >= 0; j--) { + if (ap[j]->n_op == ELLIPSIS) { + al[k++].type = TELLIPSIS; + ap[j]->n_op = ICON; /* for tfree() */ + continue; + } + /* Convert arrays to pointers */ + if (ISARY(ap[j]->n_type)) { + ap[j]->n_type += (PTR-ARY); + ap[j]->n_df++; + } + /* Convert (silently) functions to pointers */ + if (ISFTN(ap[j]->n_type)) + ap[j]->n_type = INCREF(ap[j]->n_type); + ty = ap[j]->n_type; + al[k++].type = ty; + if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY || + BTYPE(ty) == ENUMTY) + al[k++].sue = ap[j]->n_sue; + while (ISFTN(ty) == 0 && ISARY(ty) == 0 && ty > BTMASK) + ty = DECREF(ty); + if (ty > BTMASK) + al[k++].df = ap[j]->n_df; + } + al[k++].type = TNULL; + if (k > num) + cerror("arglist: k%d > num%d", k, num); + tfree(n); + if (pdebug) + alprint(al, 0); + return al; +} + +/* + * build a type, and stash away dimensions, + * from a parse tree of the declaration + * the type is build top down, the dimensions bottom up + */ +void +tyreduce(NODE *p, struct tylnk **tylkp, int *ntdim) +{ + union dimfun dim; + NODE *r = NULL; + int o; + TWORD t, q; + + o = p->n_op; + if (o == NAME) + return; + + t = INCREF(p->n_type); + q = p->n_qual; + switch (o) { + case CALL: + t += (FTN-PTR); + dim.dfun = arglist(p->n_right); + break; + case UCALL: + t += (FTN-PTR); + dim.dfun = NULL; + break; + case LB: + t += (ARY-PTR); + if (p->n_right->n_op != ICON) { + r = p->n_right; + o = RB; + } else { + dim.ddim = p->n_right->n_lval; + nfree(p->n_right); +#ifdef notdef + /* XXX - check dimensions at usage time */ + if (dim.ddim == 0 && p->n_left->n_op == LB) + uerror("null dimension"); +#endif + } + break; + } + + p->n_left->n_type = t; + p->n_left->n_qual = INCQAL(q) | p->n_left->n_qual; + tyreduce(p->n_left, tylkp, ntdim); + + if (o == LB || o == (UCALL) || o == CALL) + tylkadd(dim, tylkp, ntdim); + if (o == RB) { + dim.ddim = -1; + tylkadd(dim, tylkp, ntdim); + arrstk[arrstkp++] = r; + } + + p->n_sp = p->n_left->n_sp; + p->n_type = p->n_left->n_type; + p->n_qual = p->n_left->n_qual; +} + +static NODE * +argcast(NODE *p, TWORD t, union dimfun *d, struct suedef *sue) +{ + NODE *u, *r = talloc(); + + r->n_op = NAME; + r->n_type = t; + r->n_qual = 0; /* XXX */ + r->n_df = d; + r->n_sue = sue; + + u = buildtree(CAST, r, p); + nfree(u->n_left); + r = u->n_right; + nfree(u); + return r; +} + +#ifndef NO_C_BUILTINS +/* + * replace an alloca function with direct allocation on stack. + * return a destination temp node. + */ +static NODE * +builtin_alloca(NODE *f, NODE *a) +{ + struct symtab *sp; + NODE *t, *u; + +#ifdef notyet + if (xnobuiltins) + return NULL; +#endif + + if (f->n_op != NAME) + return NULL; /* not direct call */ + sp = f->n_sp; + + /* XXX - strcmp is bad, use pointer comparision, redo someday */ + if (strcmp(sp->sname, "__builtin_alloca")) /* use GCC name */ + return NULL; /* not alloca */ + + if (a == NULL || a->n_op == CM) { + uerror("wrong arg count for alloca"); + return NULL; + } + t = tempnode(0, VOID|PTR, 0, MKSUE(INT) /* XXX */); + u = tempnode(t->n_lval, VOID|PTR, 0, MKSUE(INT) /* XXX */); + spalloc(t, a, SZCHAR); + tfree(f); + return u; +} +#endif + +#ifdef PCC_DEBUG +/* + * Print a prototype. + */ +static void +alprint(union arglist *al, int in) +{ + int i = 0, j; + + for (; al->type != TNULL; al++) { + for (j = in; j > 0; j--) + printf(" "); + printf("arg %d: ", i++); + tprint(stdout, al->type, 0); + if (BTYPE(al->type) == STRTY || + BTYPE(al->type) == UNIONTY || BTYPE(al->type) == ENUMTY) { + al++; + printf("dim %d\n", al->df->ddim); + } + printf("\n"); + if (ISFTN(DECREF(al->type))) { + al++; + alprint(al->df->dfun, in+1); + } + } + if (in == 0) + printf("end arglist\n"); +} +#endif +/* + * Do prototype checking and add conversions before calling a function. + * Argument f is function and a is a CM-separated list of arguments. + * Returns a merged node (via buildtree() of function and arguments. + */ +NODE * +doacall(NODE *f, NODE *a) +{ + NODE *w, *r; + union arglist *al; + struct ap { + struct ap *next; + NODE *node; + } *at, *apole = NULL; + int argidx/* , hasarray = 0*/; + TWORD type, arrt; + +#ifdef PCC_DEBUG + if (ddebug) { + printf("doacall.\n"); + fwalk(f, eprint, 0); + fwalk(a, eprint, 0); + } +#endif + + /* First let MD code do something */ + calldec(f, a); +/* XXX XXX hack */ + if ((f->n_op == CALL || f->n_op == CALL) && + f->n_left->n_op == ADDROF && + f->n_left->n_left->n_op == NAME && + (f->n_left->n_left->n_type & 0x7e0) == 0x4c0) + goto build; +/* XXX XXX hack */ + +#ifndef NO_C_BUILTINS + /* check for alloca */ + if ((w = builtin_alloca(f, a))) + return w; +#endif + /* + * Do some basic checks. + */ + if (f->n_df == NULL || (al = f->n_df[0].dfun) == NULL) { + if (Wimplicit_function_declaration) { + if (f->n_sp != NULL) + werror("no prototype for function '%s()'", + f->n_sp->sname); + else + werror("no prototype for function pointer"); + } + /* floats must be cast to double */ + if (a == NULL) + goto build; + for (w = a; w->n_op == CM; w = w->n_left) { + if (w->n_right->n_type != FLOAT) + continue; + w->n_right = argcast(w->n_right, DOUBLE, + NULL, MKSUE(DOUBLE)); + } + if (a->n_type == FLOAT) { + MKTY(a, DOUBLE, 0, 0); + } + goto build; + } + if (al->type == VOID) { + if (a != NULL) + uerror("function takes no arguments"); + goto build; /* void function */ + } else { + if (a == NULL) { + uerror("function needs arguments"); + goto build; + } + } +#ifdef PCC_DEBUG + if (pdebug) { + printf("arglist for %p\n", + f->n_sp != NULL ? f->n_sp->sname : "function pointer"); + alprint(al, 0); + } +#endif + + /* + * Create a list of pointers to the nodes given as arg. + */ + for (w = a; w->n_op == CM; w = w->n_left) { + at = tmpalloc(sizeof(struct ap)); + at->node = w->n_right; + at->next = apole; + apole = at; + } + at = tmpalloc(sizeof(struct ap)); + at->node = w; + at->next = apole; + apole = at; + + /* + * Do the typechecking by walking up the list. + */ + argidx = 1; + while (al->type != TNULL) { + if (al->type == TELLIPSIS) { + /* convert the rest of float to double */ + for (; apole; apole = apole->next) { + if (apole->node->n_type != FLOAT) + continue; + MKTY(apole->node, DOUBLE, 0, 0); + } + goto build; + } + if (apole == NULL) { + uerror("too few arguments to function"); + goto build; + } +/* al = prototyp, apole = argument till ftn */ +/* type = argumentets typ, arrt = prototypens typ */ + type = apole->node->n_type; + arrt = al->type; +#if 0 + if ((hasarray = ISARY(arrt))) + arrt += (PTR-ARY); +#endif + if (ISARY(type)) + type += (PTR-ARY); + + /* Check structs */ + if (type <= BTMASK && arrt <= BTMASK) { + if (type != arrt) { + if (ISSOU(BTYPE(type)) || ISSOU(BTYPE(arrt))) { +incomp: uerror("incompatible types for arg %d", + argidx); + } else { + MKTY(apole->node, arrt, 0, 0) + } + } else if (ISSOU(BTYPE(type))) { + if (apole->node->n_sue != al[1].sue) + goto incomp; + } + goto out; + } + + /* Hereafter its only pointers (or arrays) left */ + /* Check for struct/union intermixing with other types */ + if (((type <= BTMASK) && ISSOU(BTYPE(type))) || + ((arrt <= BTMASK) && ISSOU(BTYPE(arrt)))) + goto incomp; + + /* Check for struct/union compatibility */ + if (type == arrt) { + if (ISSOU(BTYPE(type))) { + if (apole->node->n_sue == al[1].sue) + goto out; + } else + goto out; + } + if (BTYPE(arrt) == ENUMTY && BTYPE(type) == INT && + (arrt & ~BTMASK) == (type & ~BTMASK)) + goto skip; /* XXX enumty destroyed in optim() */ + if (BTYPE(arrt) == VOID && type > BTMASK) + goto skip; /* void *f = some pointer */ + if (arrt > BTMASK && BTYPE(type) == VOID) + goto skip; /* some *f = void pointer */ + if (apole->node->n_op == ICON && apole->node->n_lval == 0) + goto skip; /* Anything assigned a zero */ + + if ((type & ~BTMASK) == (arrt & ~BTMASK)) { + /* do not complain for intermixed char/uchar */ + if ((BTYPE(type) == CHAR || BTYPE(type) == UCHAR) && + (BTYPE(arrt) == CHAR || BTYPE(arrt) == UCHAR)) + goto skip; + } + + werror("implicit conversion of argument %d due to prototype", + argidx); + +skip: if (ISSTR(BTYPE(arrt))) { + MKTY(apole->node, arrt, 0, al[1].sue) + } else { + MKTY(apole->node, arrt, 0, 0) + } + +out: al++; + if (ISSTR(BTYPE(arrt))) + al++; +#if 0 + while (arrt > BTMASK && !ISFTN(arrt)) + arrt = DECREF(arrt); + if (ISFTN(arrt) || hasarray) + al++; +#else + while (arrt > BTMASK) { + if (ISARY(arrt) || ISFTN(arrt)) { + al++; + break; + } + arrt = DECREF(arrt); + } +#endif + apole = apole->next; + argidx++; + } + if (apole != NULL) + uerror("too many arguments to function"); + +build: return buildtree(a == NIL ? UCALL : CALL, f, a); +} + +static int +chk2(TWORD type, union dimfun *dsym, union dimfun *ddef) +{ + while (type > BTMASK) { + switch (type & TMASK) { + case ARY: + /* may be declared without dimension */ + if (dsym->ddim == 0) + dsym->ddim = ddef->ddim; + if (ddef->ddim && dsym->ddim != ddef->ddim) + return 1; + dsym++, ddef++; + break; + case FTN: + /* old-style function headers with function pointers + * will most likely not have a prototype. + * This is not considered an error. */ + if (ddef->dfun == NULL) { +#ifdef notyet + werror("declaration not a prototype"); +#endif + } else if (chkftn(dsym->dfun, ddef->dfun)) + return 1; + dsym++, ddef++; + break; + } + type = DECREF(type); + } + return 0; +} + +/* + * Compare two function argument lists to see if they match. + */ +int +chkftn(union arglist *usym, union arglist *udef) +{ + TWORD t2; + int ty, tyn; + + if (usym == NULL) + return 0; + if (cftnsp != NULL && udef == NULL && usym->type == VOID) + return 0; /* foo() { function with foo(void); prototype */ + if (udef == NULL && usym->type != TNULL) + return 1; + while (usym->type != TNULL) { + if (usym->type == udef->type) + goto done; + /* + * If an old-style declaration, then all types smaller than + * int are given as int parameters. + */ + if (intcompare) { + ty = BTYPE(usym->type); + tyn = BTYPE(udef->type); + if (ty == tyn || ty != INT) + return 1; + if (tyn == CHAR || tyn == UCHAR || + tyn == SHORT || tyn == USHORT) + goto done; + return 1; + } else + return 1; + +done: ty = BTYPE(usym->type); + t2 = usym->type; + if (ISSTR(ty)) { + usym++, udef++; + if (usym->sue != udef->sue) + return 1; + } + + while (ISFTN(t2) == 0 && ISARY(t2) == 0 && t2 > BTMASK) + t2 = DECREF(t2); + if (t2 > BTMASK) { + usym++, udef++; + if (chk2(t2, usym->df, udef->df)) + return 1; + } + usym++, udef++; + } + if (usym->type != udef->type) + return 1; + return 0; +} + +void +fixtype(NODE *p, int class) +{ + unsigned int t, type; + int mod1, mod2; + /* fix up the types, and check for legality */ + + if( (type = p->n_type) == UNDEF ) return; + if ((mod2 = (type&TMASK))) { + t = DECREF(type); + while( mod1=mod2, mod2 = (t&TMASK) ){ + if( mod1 == ARY && mod2 == FTN ){ + uerror( "array of functions is illegal" ); + type = 0; + } + else if( mod1 == FTN && ( mod2 == ARY || mod2 == FTN ) ){ + uerror( "function returns illegal type" ); + type = 0; + } + t = DECREF(t); + } + } + + /* detect function arguments, watching out for structure declarations */ + if (instruct && ISFTN(type)) { + uerror("function illegal in structure or union"); + type = INCREF(type); + } + p->n_type = type; +} + +/* + * give undefined version of class + */ +int +uclass(int class) +{ + if (class == SNULL) + return(EXTERN); + else if (class == STATIC) + return(USTATIC); + else if (class == FORTRAN) + return(UFORTRAN); + else + return(class); +} + +int +fixclass(int class, TWORD type) +{ + /* first, fix null class */ + if (class == SNULL) { + if (instruct&INSTRUCT) + class = MOS; + else if (instruct&INUNION) + class = MOU; + else if (blevel == 0) + class = EXTDEF; + else + class = AUTO; + } + + /* now, do general checking */ + + if( ISFTN( type ) ){ + switch( class ) { + default: + uerror( "function has illegal storage class" ); + case AUTO: + class = EXTERN; + case EXTERN: + case EXTDEF: + case FORTRAN: + case TYPEDEF: + case STATIC: + case UFORTRAN: + case USTATIC: + ; + } + } + + if( class&FIELD ){ + if( !(instruct&INSTRUCT) ) uerror( "illegal use of field" ); + return( class ); + } + + switch( class ){ + + case MOU: + if( !(instruct&INUNION) ) uerror( "illegal MOU class" ); + return( class ); + + case MOS: + if( !(instruct&INSTRUCT) ) uerror( "illegal MOS class" ); + return( class ); + + case MOE: + if( instruct & (INSTRUCT|INUNION) ) uerror( "illegal MOE class" ); + return( class ); + + case REGISTER: + if (blevel == 0) + uerror( "illegal register declaration" ); + if (blevel == 1) + return(PARAM); + else + return(AUTO); + + case AUTO: + if( blevel < 2 ) uerror( "illegal ULABEL class" ); + return( class ); + + case UFORTRAN: + case FORTRAN: +# ifdef NOFORTRAN + NOFORTRAN; /* a condition which can regulate the FORTRAN usage */ +# endif + if( !ISFTN(type) ) uerror( "fortran declaration must apply to function" ); + else { + type = DECREF(type); + if( ISFTN(type) || ISARY(type) || ISPTR(type) ) { + uerror( "fortran function has wrong type" ); + } + } + case STNAME: + case UNAME: + case ENAME: + case EXTERN: + case STATIC: + case EXTDEF: + case TYPEDEF: + case USTATIC: + return( class ); + + default: + cerror( "illegal class: %d", class ); + /* NOTREACHED */ + + } + return 0; /* XXX */ +} + +/* + * Generates a goto statement; sets up label number etc. + */ +void +gotolabel(char *name) +{ + struct symtab *s = lookup(name, SLBLNAME); + + if (s->soffset == 0) + s->soffset = -getlab(); + branch(s->soffset < 0 ? -s->soffset : s->soffset); +} + +/* + * Sets a label for gotos. + */ +void +deflabel(char *name) +{ + struct symtab *s = lookup(name, SLBLNAME); + + if (s->soffset > 0) + uerror("label '%s' redefined", name); + if (s->soffset == 0) + s->soffset = getlab(); + if (s->soffset < 0) + s->soffset = -s->soffset; + plabel( s->soffset); +} + +struct symtab * +getsymtab(char *name, int flags) +{ + struct symtab *s; + + if (flags & STEMP) { + s = tmpalloc(sizeof(struct symtab)); + } else { + s = permalloc(sizeof(struct symtab)); + symtabcnt++; + } + s->sname = name; + s->snext = NULL; + s->stype = UNDEF; + s->squal = 0; + s->sclass = SNULL; + s->sflags = flags & SMASK; + s->soffset = 0; + s->slevel = blevel; + return s; +} + +#ifdef PCC_DEBUG +static char * +ccnames[] = { /* names of storage classes */ + "SNULL", + "AUTO", + "EXTERN", + "STATIC", + "REGISTER", + "EXTDEF", + "LABEL", + "ULABEL", + "MOS", + "PARAM", + "STNAME", + "MOU", + "UNAME", + "TYPEDEF", + "FORTRAN", + "ENAME", + "MOE", + "UFORTRAN", + "USTATIC", + }; + +char * +scnames(int c) +{ + /* return the name for storage class c */ + static char buf[12]; + if( c&FIELD ){ + snprintf( buf, sizeof(buf), "FIELD[%d]", c&FLDSIZ ); + return( buf ); + } + return( ccnames[c] ); + } +#endif diff --git a/usr.bin/pcc/cc/ccom/scan.l b/usr.bin/pcc/cc/ccom/scan.l new file mode 100644 index 00000000000..0a5470bb829 --- /dev/null +++ b/usr.bin/pcc/cc/ccom/scan.l @@ -0,0 +1,465 @@ +%{ +/* $Id: scan.l,v 1.1 2007/09/15 18:12:34 otto Exp $ */ + +/* + * Copyright (c) 2002 Anders Magnusson. 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. + */ +%} + + +D [0-9] +L [a-zA-Z_] +H [a-fA-F0-9] +E [Ee][+-]?{D}+ +P [Pp][+-]?{D}+ +FS (f|F|l|L) +IS (u|U|l|L)* + +%{ +#include <errno.h> +#include <string.h> +#include <stdarg.h> + +#include "pass1.h" +#include "cgram.h" + +static NODE *cvtdig(int radix); +static NODE *charcon(void); +static void control(int); +static NODE *floatcon(void); +static NODE *fhexcon(void); +int notype, parbal; + +#define CPP_PRAGMA 1 +#define CPP_IDENT 2 +#define CPP_LINE 3 +#define CPP_HASH 4 + +#ifdef STABS +#define STABS_LINE(x) if (gflag && blevel) stabs_line(x) +#else +#define STABS_LINE(x) +#endif +#if defined(FLEX_SCANNER) && YY_FLEX_SUBMINOR_VERSION >= 31 +/* Hack to avoid unneccessary warnings */ +FILE *yyget_in (void); +FILE *yyget_out (void); +int yyget_leng (void); +char *yyget_text (void); +void yyset_in (FILE * in_str ); +void yyset_out (FILE * out_str ); +int yyget_debug (void); +void yyset_debug (int bdebug ); +int yylex_destroy (void); +#endif + +%} + +%% + +"__func__" { + if (cftnsp == NULL) + uerror("__func__ outside function"); + yylval.strp = cftnsp->sname; /* XXX - not C99 */ + return(C_STRING); + } +"asm" { return(C_ASM); } +"auto" { yylval.intval = AUTO; return(C_CLASS); } +"_Bool" { yylval.nodep = mkty((TWORD)BOOL, 0, MKSUE(BOOL)); + return(C_TYPE); } +"break" { return(C_BREAK); } +"case" { return(C_CASE); } +"char" { yylval.nodep = mkty((TWORD)CHAR, 0, MKSUE(CHAR)); + notype=1; return(C_TYPE); } +"const" { yylval.nodep = + block(QUALIFIER, NIL, NIL, CON, 0, 0); + return(C_QUALIFIER); } +"continue" { return(C_CONTINUE); } +"default" { return(C_DEFAULT); } +"do" { return(C_DO); } +"double" { yylval.nodep = mkty((TWORD)DOUBLE, 0, MKSUE(DOUBLE)); + notype=1; return(C_TYPE); } +"else" { return(C_ELSE); } +"enum" { notype=1; return(C_ENUM); } +"extern" { yylval.intval = EXTERN; return(C_CLASS); } +"float" { yylval.nodep = mkty((TWORD)FLOAT, 0, MKSUE(FLOAT)); + notype=1; return(C_TYPE); } +"for" { return(C_FOR); } +"goto" { return(C_GOTO); } +"if" { return(C_IF); } +"inline" { return(C_FUNSPEC); } +"int" { yylval.nodep = mkty((TWORD)INT, 0, MKSUE(INT)); + notype=1; return(C_TYPE); } +"long" { yylval.nodep = mkty((TWORD)LONG, 0, MKSUE(LONG)); + notype=1; return(C_TYPE); } +"register" { yylval.intval = REGISTER; return(C_CLASS); } +"restrict" { ; /* just ignore */ } +"return" { return(C_RETURN); } +"short" { yylval.nodep = mkty((TWORD)SHORT, 0, MKSUE(SHORT)); + notype=1; return(C_TYPE); } +"signed" { yylval.nodep = mkty((TWORD)SIGNED, 0, MKSUE(SIGNED)); + notype=1; return(C_TYPE); } +"sizeof" { return(C_SIZEOF); } +"static" { yylval.intval = STATIC; return(C_CLASS); } +"struct" { yylval.intval = INSTRUCT; notype=1; return(C_STRUCT); } +"switch" { return(C_SWITCH); } +"typedef" { yylval.intval = TYPEDEF; return(C_CLASS); } +"union" { yylval.intval = INUNION; notype=1; return(C_STRUCT); } +"unsigned" { yylval.nodep = mkty((TWORD)UNSIGNED, 0, MKSUE(UNSIGNED)); + notype=1; return(C_TYPE); } +"void" { yylval.nodep = mkty((TWORD)VOID, 0, MKSUE(VOID)); + notype=1; return(C_TYPE); } +"volatile" { yylval.nodep = + block(QUALIFIER, NIL, NIL, VOL, 0, 0); + return(C_QUALIFIER); } +"while" { return(C_WHILE); } + +{L}({L}|{D})* { struct symtab *s; + int i; + + yylval.strp = addname(yytext); + if ((i = gcc_keyword(yylval.strp, + &yylval.nodep)) != 0) + return i; +// printf("str: %s notype %d parbal %d\n", yytext, notype, parbal); + if (!notype) { + s = lookup(yylval.strp, SNOCREAT); + if (s && s->sclass == TYPEDEF) + return notype=1, C_TYPENAME; + } + return(C_NAME); + } + +0[xX]{H}+{IS}? { yylval.nodep = cvtdig(16); return(C_ICON); } +0{D}+{IS}? { yylval.nodep = cvtdig(8); return(C_ICON); } +{D}+{IS}? { yylval.nodep = cvtdig(10); return(C_ICON); } +L?'(\\.|[^\\'])+' { yylval.nodep = charcon(); return(C_ICON); } + +{D}+{E}{FS}? { yylval.nodep = floatcon(); return(C_FCON); } +{D}*"."{D}+({E})?{FS}? { yylval.nodep = floatcon(); return(C_FCON); } +{D}+"."{D}*({E})?{FS}? { yylval.nodep = floatcon(); return(C_FCON); } +0[xX]{H}*"."{H}+{P}{FS}? { yylval.nodep = fhexcon(); return(C_FCON); } +0[xX]{H}+"."{P}{FS}? { yylval.nodep = fhexcon(); return(C_FCON); } +0[xX]{H}+{P}{FS}? { yylval.nodep = fhexcon(); return(C_FCON); } + +L?\"(\\.|[^\\"])*\" { + char *c = yytext; + int i = yyleng-2, rv; + + if (*c++ == 'L') { + c++, i--; + rv = C_WSTRING; + } else + rv = C_STRING; + c[i] = 0; /* last " */ + yylval.strp = c; + return rv; + } +"..." { return(C_ELLIPSIS); } +">>=" { yylval.intval = RSEQ; return(C_ASOP); } +"<<=" { yylval.intval = LSEQ; return(C_ASOP); } +"+=" { yylval.intval = PLUSEQ; return(C_ASOP); } +"-=" { yylval.intval = MINUSEQ; return(C_ASOP); } +"*=" { yylval.intval = MULEQ; return(C_ASOP); } +"/=" { yylval.intval = DIVEQ; return(C_ASOP); } +"%=" { yylval.intval = MODEQ; return(C_ASOP); } +"&=" { yylval.intval = ANDEQ; return(C_ASOP); } +"^=" { yylval.intval = EREQ; return(C_ASOP); } +"|=" { yylval.intval = OREQ; return(C_ASOP); } +">>" { yylval.intval = RS; return(C_SHIFTOP); } +"<<" { yylval.intval = LS; return(C_SHIFTOP); } +"++" { yylval.intval = INCR; return(C_INCOP); } +"--" { yylval.intval = DECR; return(C_INCOP); } +"->" { yylval.intval = STREF; return(C_STROP); } +"&&" { yylval.intval = ANDAND; return(C_ANDAND); } +"||" { yylval.intval = OROR; return(C_OROR); } +"<=" { yylval.intval = LE; return(C_RELOP); } +">=" { yylval.intval = GE; return(C_RELOP); } +"==" { yylval.intval = EQ; return(C_EQUOP); } +"!=" { yylval.intval = NE; return(C_EQUOP); } +";" { notype = 0; return(';'); } +("{"|"<%") { notype = 0; return('{'); } +("}"|"%>") { return('}'); } +"," { if (parbal) notype = 0; return(','); } +":" { return(':'); } +"=" { return('='); } +"(" { parbal++; notype = 0; return('('); } +")" { parbal--; if (parbal==0) { notype = 0; } return(')'); } +("["|"<:") { return('['); } +("]"|":>") { return(']'); } +"." { yylval.intval = DOT; return(C_STROP); } +"&" { return('&'); } +"!" { yylval.intval = NOT; return(C_UNOP); } +"~" { yylval.intval = COMPL; return(C_UNOP); } +"-" { return('-'); } +"+" { return('+'); } +"*" { return('*'); } +"/" { yylval.intval = DIV; return(C_DIVOP); } +"%" { yylval.intval = MOD; return(C_DIVOP); } +"<" { yylval.intval = LT; return(C_RELOP); } +">" { yylval.intval = GT; return(C_RELOP); } +"^" { return('^'); } +"|" { return('|'); } +"?" { return('?'); } +^#pragma[ \t].* { control(CPP_PRAGMA); } +^#ident[ \t].* { control(CPP_IDENT); } +^#line[ \t].* { control(CPP_LINE); } +^#.* { control(CPP_HASH); } + +[ \t\v\f] { } +"\n" { ++lineno; STABS_LINE(lineno); } +. { /* ignore bad characters */ } + +%% + +int lineno; +char *ftitle = "<stdin>"; + +int +yywrap(void) +{ + if (0) unput(0); /* quiet gcc */ + return(1); +} + +/* + * XXX floatcon() and fhexcon() should be in support libraries for + * the target floating point. + */ +static NODE * +f2(char *str) +{ + TWORD tw; + NODE *p; + double dc; + char *eptr; + + dc = strtod(str, &eptr); /* XXX - avoid strtod() */ + tw = (*eptr == 'f' || *eptr == 'F' ? FLOAT : DOUBLE); + p = block(FCON, NIL, NIL, tw, 0, MKSUE(tw)); + p->n_dcon = dc; + return p; +} + +NODE * +floatcon(void) +{ + return f2(yytext); +} + +static int +h2n(int ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + return ch - 'A' + 10; + +} + +NODE * +fhexcon(void) +{ + char buf[500]; + char *c = yytext; + unsigned long long num1, num2; + + /* XXX - convert it to a decimal float number and use strtod */ + c+= 2; /* skip 0x */ + for (num1 = 0; *c != '.' && *c != 'p' && *c != 'P'; c++) + num1 = (num1 << 4) | h2n(*c); + if (*c != '.' && *c != 'p' && *c != 'P') + cerror("fhexcon"); + num2 = 0; + if (*c == '.') { + c++; + for (; *c != 'p' && *c != 'P'; c++) + num2 = (num2 << 4) | h2n(*c); + } + if (*c != 'P' && *c != 'p') + cerror("fhexcon2"); + c++; + snprintf(buf, sizeof(buf), "%llu.%lluE%s", num1, num2, c); + return f2(buf); +} + +unsigned int +esccon(char **sptr) +{ + char *wr = *sptr; + unsigned int val; + + switch (*wr++) { + case 'a': val = '\a'; break; + case 'b': val = '\b'; break; + case 'f': val = '\f'; break; + case 'n': val = '\n'; break; + case 'r': val = '\r'; break; + case 't': val = '\t'; break; + case 'v': val = '\v'; break; + case '\"': val = '\"'; break; + case 'x': val = strtoul(wr, &wr, 16); break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + wr--; + val = strtoul(wr, &wr, 8); + break; + default: val = wr[-1]; + } + *sptr = wr; + return val; +} + +NODE * +cvtdig(int radix) +{ + NODE *p; + TWORD ntype; + unsigned long long v; + char *ch = yytext; + int n, numl, numu; + + if (radix == 16) + ch += 2; /* Skip 0x */ + + v = 0; + while ((*ch >= '0' && *ch <= '9') || (*ch >= 'a' && *ch <= 'f') || + (*ch >= 'A' && *ch <= 'F')) { + v *= radix; + n = *ch; + n = (n <= '9' ? n - '0' : (n > 'F' ? n - 'a' : n - 'A') + 10); + ch++; + v += n; + } + /* Parse trailing chars */ + ntype = INT; + numl = numu = 0; + for (n = 0; n < 3; n++) { + if (*ch == 0) + break; + if ((*ch == 'l' || *ch == 'L') && numl < 2) + ntype+=2, numl++; + else if ((*ch == 'u' || *ch == 'U') && numu < 1) + ntype = ENUNSIGN(ntype), numu++; + else + break; + ch++; + } + if (*ch) + uerror("constant has too many '%c'", *ch); + + if (ntype == INT) { + /* v contains a number. Get type correct */ + if (v > MAX_LONGLONG && radix != 10) + ntype = ULONGLONG; + else if (v > MAX_ULONG) + ntype = LONGLONG; + else if (v > MAX_LONG && radix != 10) + ntype = ULONG; + else if (v > MAX_UNSIGNED) + ntype = LONG; + else if (v > MAX_INT && radix != 10) + ntype = UNSIGNED; + } + ntype = ctype(ntype); + p = block(ICON, NIL, NIL, ntype, 0, MKSUE(ntype)); + p->n_lval = v; + ASGLVAL(p->n_slval, v); + + return p; +} + +/* + * Convert a character constant to an integer. + */ +NODE * +charcon(void) +{ + int lastcon = 0; + int val, i = 0; + char *pp = yytext; + + if (*pp == 'L') + pp++; + pp++; + while (*pp != '\'') { + if (*pp++ == '\\') { + val = esccon(&pp); + } else + val = pp[-1]; + makecc(val, i); + i++; + } + + if (i == 0) + uerror("empty character constant"); + if (i > (SZINT/SZCHAR) || (i>1)) + werror("too many characters in character constant"); + return bcon(lastcon); +} + +void +control(int t) +{ + char *wr = yytext; + char *eptr; + int val; + + wr++; /* Skip initial '#' */ + switch (t) { + case CPP_PRAGMA: + case CPP_IDENT: + return; /* Just skip these for now. */ + + case CPP_LINE: + wr += 4; + /* FALLTHROUGH */ + case CPP_HASH: + val = strtol(wr, &eptr, 10); + if (wr == eptr) /* Illegal string */ + goto bad; + wr = eptr; + lineno = val - 1; + while (*wr && *wr != '\"') + wr++; + if (*wr++ != '\"') + goto bad; + eptr = wr; + while (*wr && *wr != '\"') + wr++; + if (*wr != '\"') + goto bad; + *wr = 0; + ftitle = addstring(eptr); +#ifdef STABS + if (gflag) + stabs_file(ftitle); +#endif + } + return; +bad: + werror("%s: illegal control", yytext); +} diff --git a/usr.bin/pcc/cc/ccom/stabs.c b/usr.bin/pcc/cc/ccom/stabs.c new file mode 100644 index 00000000000..122da85d3f3 --- /dev/null +++ b/usr.bin/pcc/cc/ccom/stabs.c @@ -0,0 +1,374 @@ +/* $Id: stabs.c,v 1.1 2007/09/15 18:12:34 otto Exp $ */ + +/* + * Copyright (c) 2004 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. + */ + +/* + * Simple implementation of the "stabs" debugging format. + * Not complete but at least makes it possible to set breakpoints, + * examine simple variables and do stack traces. + * Based on the stabs documentation that follows gdb. + */ + +#include "pass1.h" + +#ifdef STABS + +#include <sys/types.h> +#include <stab.h> +#include <stdarg.h> +#include <string.h> + +#define STABHASH 256 +#define INTNUM 1 /* internal number of type "int" */ +#define BIT2BYTE(x) ((x)/SZCHAR) + +#ifndef STABLBL +#error macdefs.h must define STABLBL +#endif + +/* + * Local type mapping + * Types are defined as a typeword, a dimension pointer (in the case + * of arrays) and struct/union/enum declarations. + * Function prototypes are ignored. + */ +static struct stabtype { + struct stabtype *next; /* linked list */ + TWORD type; /* pcc type number */ + union dimfun *df; /* dimension of arrays */ + struct suedef *sue; /* struct/union/enum declarations */ + int num; /* local type number */ +} *stabhash[STABHASH]; +static int ntypes; +static char *curfun; +static int stablbl = 10; + +void ptype(char *name, int num, int inhnum, long long min, long long max); +struct stabtype *addtype(TWORD, union dimfun *, struct suedef *); +struct stabtype *findtype(TWORD t, union dimfun *df, struct suedef *sue); +void printtype(struct symtab *s, char *str, int len); +void cprint(int p2, char *fmt, ...); + +#define MAXPSTR 100 + +extern int isinlining; +#define savestabs isinlining + +/* + * Output type definitions for the stab debugging format. + * Note that "int" is always internal number 1. + */ +void +stabs_init() +{ + struct stabtype *st; + +#define ADDTYPE(y) addtype(y, NULL, MKSUE(y)) + + ptype("int", ADDTYPE(INT)->num, INTNUM, MIN_INT, MAX_INT); + + st = ADDTYPE(CHAR); + ptype("char", st->num, st->num, 0, MAX_CHAR); + ptype("short", ADDTYPE(SHORT)->num, INTNUM, MIN_SHORT, MAX_SHORT); + ptype("long", ADDTYPE(LONG)->num, INTNUM, MIN_LONG, MAX_LONG); + ptype("long long", ADDTYPE(LONGLONG)->num, INTNUM, + MIN_LONGLONG, MAX_LONGLONG); + ptype("unsigned char", ADDTYPE(UCHAR)->num, INTNUM, 0, MAX_UCHAR); + ptype("unsigned short", ADDTYPE(USHORT)->num, INTNUM, 0, MAX_USHORT); + ptype("unsigned int", ADDTYPE(UNSIGNED)->num, INTNUM, 0, MAX_UNSIGNED); + ptype("unsigned long", ADDTYPE(ULONG)->num, INTNUM, 0, MAX_ULONG); + ptype("unsigned long long", ADDTYPE(ULONGLONG)->num, INTNUM, + 0, MAX_ULONGLONG); + + ptype("float", ADDTYPE(FLOAT)->num, INTNUM, 4, 0); + ptype("double", ADDTYPE(DOUBLE)->num, INTNUM, 8, 0); + ptype("long double", ADDTYPE(LDOUBLE)->num, INTNUM, 12, 0); + st = ADDTYPE(VOID); + cprint(savestabs, ".stabs \"void:t%d=r%d\",%d,0,0,0\n", + st->num, st->num, N_LSYM); + +} + +/* + * Print a type in stabs format + */ +void +ptype(char *name, int num, int inhnum, long long min, long long max) +{ + cprint(savestabs, ".stabs \"%s:t%d=r%d;%lld;%lld;\",%d,0,0,0", + name, num, inhnum, min, max, N_LSYM); +} + +/* + * Add a new local type to the hash table. + * The search key is the (type, df, sue) triple. + */ +struct stabtype * +addtype(TWORD t, union dimfun *df, struct suedef *sue) +{ + struct stabtype *st; + + st = permalloc(sizeof(struct stabtype)); + st->type = t; + st->df = df; + st->sue = sue; + st->num = ++ntypes; + st->next = stabhash[t & (STABHASH-1)]; + stabhash[t & (STABHASH-1)] = st; + return st; +} + +/* + * Search for a given type and return a type pointer (or NULL). + */ +struct stabtype * +findtype(TWORD t, union dimfun *df, struct suedef *sue) +{ + struct stabtype *st; + union dimfun *dw, *dx; + TWORD tw; + + st = stabhash[t & (STABHASH-1)]; + for (; st; st = st->next) { + if (t != st->type || sue != st->sue) + continue; + /* Ok, type and sue matches, check dimensions */ + if (st->df == NULL) + return st; /* no arrays, got match */ + dw = st->df; + dx = df; + tw = t; + for (; tw > BTMASK; tw = DECREF(tw)) { + if (ISARY(tw)) { + if (dw->ddim == dx->ddim) + dw++, dx++; + else + break; + } + } + if (tw <= BTMASK) + return st; + } + return NULL; +} + +/* + * Print current line number. + */ +void +stabs_line(int line) +{ + cprint(savestabs, ".stabn %d,0,%d," STABLBL "-%s", N_SLINE, line, stablbl, curfun); + cprint(1, STABLBL ":", stablbl++); +} + +/* + * Start of block. + */ +void +stabs_lbrac(int blklvl) +{ + cprint(savestabs, ".stabn %d,0,%d," STABLBL "-%s", + N_LBRAC, blklvl, stablbl, curfun); + cprint(1, STABLBL ":", stablbl++); +} + +/* + * End of block. + */ +void +stabs_rbrac(int blklvl) +{ + cprint(savestabs, ".stabn %d,0,%d," STABLBL "-%s\n", + N_RBRAC, blklvl, stablbl, curfun); + cprint(1, STABLBL ":", stablbl++); +} + +/* + * Print current file and set mark. + */ +void +stabs_file(char *fname) +{ + static char *mainfile; + + if (mainfile == NULL) + mainfile = fname; /* first call */ + cprint(savestabs, ".stabs \"%s\",%d,0,0," STABLBL, + fname, fname == mainfile ? N_SO : N_SOL, stablbl); + cprint(savestabs, STABLBL ":", stablbl++); +} + +/* + * Print beginning of function. + */ +void +stabs_func(struct symtab *s) +{ + char str[MAXPSTR]; + + curfun = s->sname; +#ifdef GCC_COMPAT + curfun = gcc_findname(cftnsp); +#endif + printtype(s, str, sizeof(str)); + cprint(savestabs, ".stabs \"%s:%c%s\",%d,0,%d,%s", + curfun, s->sclass == STATIC ? 'f' : 'F', str, + N_FUN, BIT2BYTE(s->ssue->suesize), exname(curfun)); +} + +/* + * Print a (complex) type. + * Will also create subtypes. + * Printed string is like "20=*21=*1". + */ +void +printtype(struct symtab *s, char *ostr, int len) +{ + struct stabtype *st; + union dimfun *df = s->sdf; + struct suedef *sue = s->ssue; + TWORD t = s->stype; + int op = 0; + + /* Print out not-yet-found types */ + if (ISFTN(t)) + t = DECREF(t); + st = findtype(t, df, sue); + while (st == NULL && t > BTMASK) { + st = addtype(t, df, sue); + op+=snprintf(ostr+op, len - op, "%d=", st->num); + if (ISFTN(t)) + ostr[op++] = 'f'; + else if (ISPTR(t)) + ostr[op++] = '*'; + else if (ISARY(t)) { + op+=snprintf(ostr+op, len - op, "ar%d;0;%d;", INTNUM, df->ddim-1); + } else + cerror("printtype: notype"); + if (ISARY(t)) + df++; + t = DECREF(t); + st = findtype(t, df, sue); + if (op > MAXPSTR-10) + cerror("printtype: too difficult expression"); + } + /* print out basic type. may have to be entered in case of sue */ + snprintf(ostr+op, len - op, "%d", st == NULL ? 1 : st->num); + /* snprintf here null-terminated the string */ +} + +void +stabs_newsym(struct symtab *s) +{ + char *sname; + char ostr[MAXPSTR]; + + if (ISFTN(s->stype)) + return; /* functions are handled separate */ + + if (s->sclass == STNAME || s->sclass == UNAME || s->sclass == MOS || + s->sclass == ENAME || s->sclass == MOU || s->sclass == MOE || + s->sclass == TYPEDEF || (s->sclass & FIELD)) + return; /* XXX - fix structs */ + + sname = s->sname; +#ifdef GCC_COMPAT + sname = gcc_findname(s); +#endif + + printtype(s, ostr, sizeof(ostr)); + switch (s->sclass) { + case PARAM: + cprint(savestabs, ".stabs \"%s:p%s\",%d,0,%d,%d", sname, ostr, + N_PSYM, BIT2BYTE(s->ssue->suesize), BIT2BYTE(s->soffset)); + break; + + case AUTO: + cprint(savestabs, ".stabs \"%s:%s\",%d,0,%d,%d", sname, ostr, + N_LSYM, BIT2BYTE(s->ssue->suesize), BIT2BYTE(s->soffset)); + break; + + case STATIC: + if (blevel) + cprint(savestabs, ".stabs \"%s:V%s\",%d,0,%d," LABFMT, sname, ostr, + N_LCSYM, BIT2BYTE(s->ssue->suesize), s->soffset); + else + cprint(savestabs, ".stabs \"%s:S%s\",%d,0,%d,%s", sname, ostr, + N_LCSYM, BIT2BYTE(s->ssue->suesize), exname(sname)); + break; + + case EXTERN: + case EXTDEF: + cprint(savestabs, ".stabs \"%s:G%s\",%d,0,%d,0", sname, ostr, + N_GSYM, BIT2BYTE(s->ssue->suesize)); + break; + + case REGISTER: + cprint(savestabs, ".stabs \"%s:r%s\",%d,0,%d,%d", sname, ostr, + N_RSYM, 1, s->soffset); + break; + + default: + cerror("fix stab_newsym; class %d", s->sclass); + } +} + +void +stabs_chgsym(struct symtab *s) +{ +} + +/* + * define a struct. + */ +void +stabs_struct(struct symtab *p, struct suedef *sue) +{ +} + +void +cprint(int p2, char *fmt, ...) +{ + va_list ap; + char *str; + + va_start(ap, fmt); + if (p2) { + str = tmpvsprintf(fmt, ap); + str = newstring(str, strlen(str)); /* XXX - for inlines */ + send_passt(IP_ASM, str); + } else { + putchar('\t'); + vprintf(fmt, ap); + putchar('\n'); + } + va_end(ap); +} + +#endif diff --git a/usr.bin/pcc/cc/ccom/symtabs.c b/usr.bin/pcc/cc/ccom/symtabs.c new file mode 100644 index 00000000000..1f96d5dc86a --- /dev/null +++ b/usr.bin/pcc/cc/ccom/symtabs.c @@ -0,0 +1,356 @@ +/* $Id: symtabs.c,v 1.1 2007/09/15 18:12:35 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" + +/* + * These definitions are used in the patricia tree that stores + * the strings. + */ +#define LEFT_IS_LEAF 0x80000000 +#define RIGHT_IS_LEAF 0x40000000 +#define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0) +#define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0) +#define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF)) +#define CHECKBITS 8 + +struct tree { + int bitno; + struct tree *lr[2]; +}; + +static struct tree *firstname; +int nametabs, namestrlen; +static struct tree *firststr; +int strtabs, strstrlen; +static char *symtab_add(char *key, struct tree **, int *, int *); + +#define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1 +#define getree() permalloc(sizeof(struct tree)) + +char * +addname(char *key) +{ + return symtab_add(key, &firstname, &nametabs, &namestrlen); +} + +char * +addstring(char *key) +{ + return symtab_add(key, &firststr, &strtabs, &strstrlen); +} + +/* + * Add a name to the name stack (if its non-existing), + * return its address. + * This is a simple patricia implementation. + */ +char * +symtab_add(char *key, struct tree **first, int *tabs, int *stlen) +{ + struct tree *w, *new, *last; + int cix, bit, fbit, svbit, ix, bitno, len; + char *m, *k, *sm; + + /* Count full string length */ + for (k = key, len = 0; *k; k++, len++) + ; + + switch (*tabs) { + case 0: + *first = (struct tree *)newstring(key, len); + *stlen += (len + 1); + (*tabs)++; + return (char *)*first; + + case 1: + m = (char *)*first; + svbit = 0; /* XXX why? */ + break; + + default: + w = *first; + bitno = len * CHECKBITS; + for (;;) { + bit = BITNO(w->bitno); + fbit = bit > bitno ? 0 : P_BIT(key, bit); + svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : + IS_LEFT_LEAF(w->bitno); + w = w->lr[fbit]; + if (svbit) { + m = (char *)w; + break; + } + } + } + + sm = m; + k = key; + + /* Check for correct string and return */ + for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS) + ; + if (*m == 0 && *k == 0) + return sm; + + ix = *m ^ *k; + while ((ix & 1) == 0) + ix >>= 1, cix++; + + /* Create new node */ + new = getree(); + bit = P_BIT(key, cix); + new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + new->lr[bit] = (struct tree *)newstring(key, len); + *stlen += (len + 1); + + if ((*tabs)++ == 1) { + new->lr[!bit] = *first; + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + *first = new; + return (char *)new->lr[bit]; + } + + + w = *first; + last = NULL; + for (;;) { + fbit = w->bitno; + bitno = BITNO(w->bitno); + if (bitno == cix) + cerror("bitno == cix"); + if (bitno > cix) + break; + svbit = P_BIT(key, bitno); + last = w; + w = w->lr[svbit]; + if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) + break; + } + + new->lr[!bit] = w; + if (last == NULL) { + *first = new; + } else { + last->lr[svbit] = new; + last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + } + if (bitno < cix) + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + return (char *)new->lr[bit]; +} + +static struct tree *sympole[NSTYPES]; +static struct symtab *tmpsyms[NSTYPES]; +int numsyms[NSTYPES]; + +/* + * Inserts a symbol into the symbol tree. + * Returns a struct symtab. + */ +struct symtab * +lookup(char *key, int ttype) +{ + struct symtab *sym; + struct tree *w, *new, *last; + int cix, bit, fbit, svbit, ix, bitno, match; + int type, uselvl; + + long code = (long)key; + type = ttype & SMASK; + uselvl = (blevel > 0 && type != SSTRING); + + /* + * The local symbols are kept in a simple linked list. + * Check this list first. + */ + if (blevel > 0) + for (sym = tmpsyms[type]; sym; sym = sym->snext) + if (sym->sname == key) + return sym; + + switch (numsyms[type]) { + case 0: + if (ttype & SNOCREAT) + return NULL; + if (uselvl) { + sym = getsymtab(key, ttype|STEMP); + sym->snext = tmpsyms[type]; + tmpsyms[type] = sym; + return sym; + } + sympole[type] = (struct tree *)getsymtab(key, ttype); + numsyms[type]++; + return (struct symtab *)sympole[type]; + + case 1: + w = (struct tree *)sympole[type]; + svbit = 0; /* XXX why? */ + break; + + default: + w = sympole[type]; + for (;;) { + bit = BITNO(w->bitno); + fbit = (code >> bit) & 1; + svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : + IS_LEFT_LEAF(w->bitno); + w = w->lr[fbit]; + if (svbit) + break; + } + } + + sym = (struct symtab *)w; + match = (long)sym->sname; + + ix = code ^ match; + if (ix == 0) + return sym; + else if (ttype & SNOCREAT) + return NULL; + +#ifdef PCC_DEBUG + if (ddebug) + printf(" adding %s as %s at level %d\n", + key, uselvl ? "temp" : "perm", blevel); +#endif + + /* + * Insert into the linked list, if feasible. + */ + if (uselvl) { + sym = getsymtab(key, ttype|STEMP); + sym->snext = tmpsyms[type]; + tmpsyms[type] = sym; + return sym; + } + + /* + * Need a new node. If type is SNORMAL and inside a function + * the node must be allocated as permanent anyway. + * This could be optimized by adding a remove routine, but it + * may be more trouble than it is worth. + */ + if (ttype == (STEMP|SNORMAL)) + ttype = SNORMAL; + + for (cix = 0; (ix & 1) == 0; ix >>= 1, cix++) + ; + + new = ttype & STEMP ? tmpalloc(sizeof(struct tree)) : + permalloc(sizeof(struct tree)); + bit = (code >> cix) & 1; + new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + new->lr[bit] = (struct tree *)getsymtab(key, ttype); + if (numsyms[type]++ == 1) { + new->lr[!bit] = sympole[type]; + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + sympole[type] = new; + return (struct symtab *)new->lr[bit]; + } + + + w = sympole[type]; + last = NULL; + for (;;) { + fbit = w->bitno; + bitno = BITNO(w->bitno); + if (bitno == cix) + cerror("bitno == cix"); + if (bitno > cix) + break; + svbit = (code >> bitno) & 1; + last = w; + w = w->lr[svbit]; + if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) + break; + } + + new->lr[!bit] = w; + if (last == NULL) { + sympole[type] = new; + } else { + last->lr[svbit] = new; + last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + } + if (bitno < cix) + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + return (struct symtab *)new->lr[bit]; +} + +void +symclear(int level) +{ + struct symtab *s; + int i; + +#ifdef PCC_DEBUG + if (ddebug) + printf("symclear(%d)\n", level); +#endif + if (level < 1) { + for (i = 0; i < NSTYPES; i++) { + s = tmpsyms[i]; + tmpsyms[i] = 0; + if (i != SLBLNAME) + continue; + while (s != NULL) { + if (s->soffset < 0) + uerror("label '%s' undefined",s->sname); + s = s->snext; + } + } + } else { + for (i = 0; i < NSTYPES; i++) { + if (i == SLBLNAME) + continue; /* function scope */ + while (tmpsyms[i] != NULL && + tmpsyms[i]->slevel > level) { + tmpsyms[i] = tmpsyms[i]->snext; + } + } + } +} + +struct symtab * +hide(struct symtab *sym) +{ + struct symtab *new; + + new = getsymtab(sym->sname, SNORMAL|STEMP); + new->snext = tmpsyms[SNORMAL]; + tmpsyms[SNORMAL] = new; +#ifdef PCC_DEBUG + if (ddebug) + printf("\t%s hidden at level %d (%p -> %p)\n", + sym->sname, blevel, sym, new); +#endif + return new; +} diff --git a/usr.bin/pcc/cc/ccom/trees.c b/usr.bin/pcc/cc/ccom/trees.c new file mode 100644 index 00000000000..c45a1767eac --- /dev/null +++ b/usr.bin/pcc/cc/ccom/trees.c @@ -0,0 +1,2447 @@ +/* $Id: trees.c,v 1.1 2007/09/15 18:12:35 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. + */ + +/* + * 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. + */ +/* + * Some of the changes from 32V include: + * - Understand "void" as type. + * - Handle enums as ints everywhere. + * - Convert some C-specific ops into branches. + */ + +# include "pass1.h" +# include "pass2.h" + +# include <stdarg.h> + +static void chkpun(NODE *p); +static int opact(NODE *p); +static int moditype(TWORD); +static NODE *strargs(NODE *); +static void rmcops(NODE *p); + +int lastloc = -1; + +/* some special actions, used in finding the type of nodes */ +# define NCVT 01 +# define PUN 02 +# define TYPL 04 +# define TYPR 010 +# define TYMATCH 040 +# define LVAL 0100 +# define CVTO 0200 +# define CVTL 0400 +# define CVTR 01000 +# define PTMATCH 02000 +# define OTHER 04000 +# define NCVTR 010000 + +/* node conventions: + + NAME: rval>0 is stab index for external + rval<0 is -inlabel number + lval is offset in bits + ICON: lval has the value + rval has the STAB index, or - label number, + if a name whose address is in the constant + rval = NONAME means no name + REG: rval is reg. identification cookie + + */ + +int bdebug = 0; + +NODE * +buildtree(int o, NODE *l, NODE *r) +{ + NODE *p, *q; + int actions; + int opty; + struct symtab *sp = NULL; /* XXX gcc */ + NODE *lr, *ll; + char *name; + struct symtab **elem; + +#ifdef PCC_DEBUG + if (bdebug) { + printf("buildtree(%s, %p, %p)\n", copst(o), l, r); + if (l) fwalk(l, eprint, 0); + if (r) fwalk(r, eprint, 0); + } +#endif + opty = coptype(o); + + /* check for constants */ + + if( opty == UTYPE && l->n_op == ICON ){ + + switch( o ){ + + case NOT: + case UMINUS: + case COMPL: + if( conval( l, o, l ) ) return(l); + break; + } + } else if (o == NOT && l->n_op == FCON) { + l = clocal(block(SCONV, l, NIL, INT, 0, MKSUE(INT))); + } else if( o == UMINUS && l->n_op == FCON ){ + l->n_dcon = -l->n_dcon; + return(l); + + } else if( o==QUEST && l->n_op==ICON ) { + CONSZ c = l->n_lval; + nfree(l); + if (c) { + tfree(r->n_right); + l = r->n_left; + nfree(r); + return(l); + } else { + tfree(r->n_left); + l = r->n_right; + nfree(r); + return(l); + } + } else if( opty == BITYPE && l->n_op == ICON && r->n_op == ICON ){ + + switch( o ){ + + case PLUS: + case MINUS: + case MUL: + case DIV: + case MOD: + /* + * Do type propagation for simple types here. + * The constant value is correct anyway. + * Maybe this op shortcut should be removed? + */ + if (l->n_sp == NULL && r->n_sp == NULL && + l->n_type < BTMASK && r->n_type < BTMASK) { + if (l->n_type > r->n_type) + r->n_type = l->n_type; + else + l->n_type = r->n_type; + } + /* FALLTHROUGH */ + case ULT: + case UGT: + case ULE: + case UGE: + case LT: + case GT: + case LE: + case GE: + case EQ: + case NE: + case ANDAND: + case OROR: + case AND: + case OR: + case ER: + case LS: + case RS: + if( conval( l, o, r ) ) { + nfree(r); + return(l); + } + break; + } + } else if (opty == BITYPE && (l->n_op == FCON || l->n_op == ICON) && + (r->n_op == FCON || r->n_op == ICON) && (o == PLUS || o == MINUS || + o == MUL || o == DIV)) { + switch(o){ + case PLUS: + case MINUS: + case MUL: + case DIV: + if (l->n_op == ICON) + l->n_dcon = l->n_lval; + if (r->n_op == ICON) + r->n_dcon = r->n_lval; + switch (o) { + case PLUS: + l->n_dcon += r->n_dcon; break; + case MINUS: + l->n_dcon -= r->n_dcon; break; + case MUL: + l->n_dcon *= r->n_dcon; break; + case DIV: + if (r->n_dcon == 0) + uerror("division by 0."); + else + l->n_dcon /= r->n_dcon; + } + l->n_op = FCON; + l->n_type = DOUBLE; + l->n_sue = MKSUE(DOUBLE); + nfree(r); + return(l); + } + } + + /* its real; we must make a new node */ + + p = block(o, l, r, INT, 0, MKSUE(INT)); + + actions = opact(p); + + if (actions & LVAL) { /* check left descendent */ + if (notlval(p->n_left)) { + uerror("lvalue required"); +#ifdef notyet + } else { + if ((l->n_type > BTMASK && ISCON(l->n_qual)) || + (l->n_type <= BTMASK && ISCON(l->n_qual << TSHIFT))) + if (blevel > 0) + uerror("lvalue is declared const"); +#endif + } + } + + if( actions & NCVTR ){ + p->n_left = pconvert( p->n_left ); + } + else if( !(actions & NCVT ) ){ + switch( opty ){ + + case BITYPE: + p->n_right = pconvert( p->n_right ); + case UTYPE: + p->n_left = pconvert( p->n_left ); + + } + } + + if ((actions&PUN) && (o!=CAST)) + chkpun(p); + + if( actions & (TYPL|TYPR) ){ + + q = (actions&TYPL) ? p->n_left : p->n_right; + + p->n_type = q->n_type; + p->n_qual = q->n_qual; + p->n_df = q->n_df; + p->n_sue = q->n_sue; + } + + if( actions & CVTL ) p = convert( p, CVTL ); + if( actions & CVTR ) p = convert( p, CVTR ); + if( actions & TYMATCH ) p = tymatch(p); + if( actions & PTMATCH ) p = ptmatch(p); + + if( actions & OTHER ){ + l = p->n_left; + r = p->n_right; + + switch(o){ + + case NAME: + sp = spname; + if (sp->sflags & STNODE) { + /* Generated for optimizer */ + p->n_op = TEMP; + p->n_type = sp->stype; + p->n_sue = sp->ssue; + p->n_df = sp->sdf; + p->n_lval = sp->soffset; + break; + } + +#ifdef GCC_COMPAT + /* Get a label name */ + if (sp->sflags == SLBLNAME) { + p->n_type = VOID; + p->n_sue = MKSUE(VOID); + p->n_lval = 0; + p->n_sp = sp; + break; + } else +#endif + if (sp->stype == UNDEF) { + uerror("%s undefined", sp->sname); + /* make p look reasonable */ + p->n_type = INT; + p->n_sue = MKSUE(INT); + p->n_df = NULL; + p->n_sp = sp; + p->n_lval = 0; + defid(p, SNULL); + break; + } + p->n_type = sp->stype; + p->n_qual = sp->squal; + p->n_df = sp->sdf; + p->n_sue = sp->ssue; + p->n_lval = 0; + p->n_sp = sp; + /* special case: MOETY is really an ICON... */ + if (p->n_type == MOETY) { + p->n_sp = NULL; + p->n_lval = sp->soffset; + p->n_df = NULL; + p->n_type = ENUMTY; + p->n_op = ICON; + } + break; + + case STREF: + /* p->x turned into *(p+offset) */ + /* rhs must be a name; check correctness */ + + /* Find member symbol struct */ + if (l->n_type != PTR+STRTY && l->n_type != PTR+UNIONTY){ + uerror("struct or union required"); + break; + } + + if ((elem = l->n_sue->suelem) == NULL) + uerror("undefined struct or union"); + + name = r->n_name; + for (; *elem != NULL; elem++) { + sp = *elem; + if (sp->sname == name) + break; + } + if (*elem == NULL) + uerror("member '%s' not declared", name); + + r->n_sp = sp; + p = stref(p); + break; + + case UMUL: + if (l->n_op == ADDROF) { + nfree(p); + p = l->n_left; + nfree(l); + } + if( !ISPTR(l->n_type))uerror("illegal indirection"); + p->n_type = DECREF(l->n_type); + p->n_qual = DECREF(l->n_qual); + p->n_df = l->n_df; + p->n_sue = l->n_sue; + break; + + case ADDROF: + switch( l->n_op ){ + + case UMUL: + nfree(p); + p = l->n_left; + nfree(l); + case TEMP: + case NAME: + p->n_type = INCREF(l->n_type); + p->n_qual = INCQAL(l->n_qual); + p->n_df = l->n_df; + p->n_sue = l->n_sue; + break; + + case COMOP: + nfree(p); + lr = buildtree(ADDROF, l->n_right, NIL); + p = buildtree( COMOP, l->n_left, lr ); + nfree(l); + break; + + case QUEST: + lr = buildtree( ADDROF, l->n_right->n_right, NIL ); + ll = buildtree( ADDROF, l->n_right->n_left, NIL ); + nfree(p); nfree(l->n_right); + p = buildtree( QUEST, l->n_left, buildtree( COLON, ll, lr ) ); + nfree(l); + break; + + default: + uerror("unacceptable operand of &: %d", l->n_op ); + break; + } + break; + + case LS: + case RS: /* must make type size at least int... */ + if (p->n_type == CHAR || p->n_type == SHORT) { + p->n_left = makety(l, INT, 0, 0, MKSUE(INT)); + } else if (p->n_type == UCHAR || p->n_type == USHORT) { + p->n_left = makety(l, UNSIGNED, 0, 0, + MKSUE(UNSIGNED)); + } + l = p->n_left; + p->n_type = l->n_type; + p->n_qual = l->n_qual; + p->n_df = l->n_df; + p->n_sue = l->n_sue; + + /* FALLTHROUGH */ + case LSEQ: + case RSEQ: /* ...but not for assigned types */ + if(tsize(r->n_type, r->n_df, r->n_sue) > SZINT) + p->n_right = makety(r, INT, 0, 0, MKSUE(INT)); + break; + + case RETURN: + case ASSIGN: + case CAST: + /* structure assignment */ + /* take the addresses of the two sides; then make an + * operator using STASG and + * the addresses of left and right */ + + { + struct suedef *sue; + TWORD t; + union dimfun *d; + + if (l->n_sue != r->n_sue) + uerror("assignment of different structures"); + + r = buildtree(ADDROF, r, NIL); + t = r->n_type; + d = r->n_df; + sue = r->n_sue; + + l = block(STASG, l, r, t, d, sue); + + if( o == RETURN ){ + nfree(p); + p = l; + break; + } + + p->n_op = UMUL; + p->n_left = l; + p->n_right = NIL; + break; + } + case COLON: + /* structure colon */ + + if (l->n_sue != r->n_sue) + uerror( "type clash in conditional" ); + break; + + case CALL: + p->n_right = r = strargs(p->n_right); + case UCALL: + if (!ISPTR(l->n_type)) + uerror("illegal function"); + p->n_type = DECREF(l->n_type); + if (!ISFTN(p->n_type)) + uerror("illegal function"); + p->n_type = DECREF(p->n_type); + p->n_df = l->n_df; + p->n_sue = l->n_sue; + if (l->n_op == ADDROF && l->n_left->n_op == NAME && + l->n_left->n_sp != NULL && l->n_left->n_sp != NULL && + (l->n_left->n_sp->sclass == FORTRAN || + l->n_left->n_sp->sclass == UFORTRAN)) { + p->n_op += (FORTCALL-CALL); + } + if (p->n_type == STRTY || p->n_type == UNIONTY) { + /* function returning structure */ + /* make function really return ptr to str., with * */ + + p->n_op += STCALL-CALL; + p->n_type = INCREF(p->n_type); + p = clocal(p); /* before recursing */ + p = buildtree(UMUL, p, NIL); + + } + break; + + default: + cerror( "other code %d", o ); + } + + } + + /* + * Allow (void)0 casts. + * XXX - anything on the right side must be possible to cast. + * XXX - remove void types further on. + */ + if (p->n_op == CAST && p->n_type == VOID && + p->n_right->n_op == ICON) + p->n_right->n_type = VOID; + + if (actions & CVTO) + p = oconvert(p); + p = clocal(p); + +#ifdef PCC_DEBUG + if (bdebug) { + printf("End of buildtree:\n"); + fwalk(p, eprint, 0); + } +#endif + + return(p); + + } + +/* + * Do a conditional branch. + */ +void +cbranch(NODE *p, NODE *q) +{ + p = buildtree(CBRANCH, p, q); + if (p->n_left->n_op == ICON) { + if (p->n_left->n_lval != 0) + branch(q->n_lval); /* branch always */ + tfree(p); + tfree(q); + return; + } + ecomp(p); +} + +NODE * +strargs( p ) register NODE *p; { /* rewrite structure flavored arguments */ + + if( p->n_op == CM ){ + p->n_left = strargs( p->n_left ); + p->n_right = strargs( p->n_right ); + return( p ); + } + + if( p->n_type == STRTY || p->n_type == UNIONTY ){ + p = block(STARG, p, NIL, p->n_type, p->n_df, p->n_sue); + p->n_left = buildtree( ADDROF, p->n_left, NIL ); + p = clocal(p); + } + return( p ); +} + +/* + * apply the op o to the lval part of p; if binary, rhs is val + */ +int +conval(NODE *p, int o, NODE *q) +{ + int i, u; + CONSZ val; + U_CONSZ v1, v2; + + val = q->n_lval; + u = ISUNSIGNED(p->n_type) || ISUNSIGNED(q->n_type); + if( u && (o==LE||o==LT||o==GE||o==GT)) o += (UGE-GE); + + if (p->n_sp != NULL && q->n_sp != NULL) + return(0); + if (q->n_sp != NULL && o != PLUS) + return(0); + if (p->n_sp != NULL && o != PLUS && o != MINUS) + return(0); + v1 = p->n_lval; + v2 = q->n_lval; + switch( o ){ + + case PLUS: + p->n_lval += val; + if (p->n_sp == NULL) { + p->n_rval = q->n_rval; + p->n_type = q->n_type; + } + break; + case MINUS: + p->n_lval -= val; + break; + case MUL: + p->n_lval *= val; + break; + case DIV: + if (val == 0) + uerror("division by 0"); + else { + if (u) { + v1 /= v2; + p->n_lval = v1; + } else + p->n_lval /= val; + } + break; + case MOD: + if (val == 0) + uerror("division by 0"); + else { + if (u) { + v1 %= v2; + p->n_lval = v1; + } else + p->n_lval %= val; + } + break; + case AND: + p->n_lval &= val; + break; + case OR: + p->n_lval |= val; + break; + case ER: + p->n_lval ^= val; + break; + case LS: + i = val; + p->n_lval = p->n_lval << i; + break; + case RS: + i = val; + if (u) { + v1 = v1 >> i; + p->n_lval = v1; + } else + p->n_lval = p->n_lval >> i; + break; + + case UMINUS: + p->n_lval = - p->n_lval; + break; + case COMPL: + p->n_lval = ~p->n_lval; + break; + case NOT: + p->n_lval = !p->n_lval; + break; + case LT: + p->n_lval = p->n_lval < val; + break; + case LE: + p->n_lval = p->n_lval <= val; + break; + case GT: + p->n_lval = p->n_lval > val; + break; + case GE: + p->n_lval = p->n_lval >= val; + break; + case ULT: + p->n_lval = v1 < v2; + break; + case ULE: + p->n_lval = v1 <= v2; + break; + case UGT: + p->n_lval = v1 > v2; + break; + case UGE: + p->n_lval = v1 >= v2; + break; + case EQ: + p->n_lval = p->n_lval == val; + break; + case NE: + p->n_lval = p->n_lval != val; + break; + case ANDAND: + p->n_lval = p->n_lval && val; + break; + case OROR: + p->n_lval = p->n_lval || val; + break; + default: + return(0); + } + return(1); + } + +/* + * Checks p for the existance of a pun. This is called when the op of p + * is ASSIGN, RETURN, CAST, COLON, or relational. + * One case is when enumerations are used: this applies only to lint. + * In the other case, one operand is a pointer, the other integer type + * we check that this integer is in fact a constant zero... + * in the case of ASSIGN, any assignment of pointer to integer is illegal + * this falls out, because the LHS is never 0. + */ +void +chkpun(NODE *p) +{ + union dimfun *d1, *d2; + NODE *q; + int t1, t2; + + t1 = p->n_left->n_type; + t2 = p->n_right->n_type; + + switch (p->n_op) { + case RETURN: + /* return of void allowed but nothing else */ + if (t1 == VOID && t2 == VOID) + return; + if (t1 == VOID) + return werror("returning value from void function"); + if (t2 == VOID) + return uerror("using void value"); + case COLON: + if (t1 == VOID && t2 == VOID) + return; + break; + default: + if ((t1 == VOID && t2 != VOID) || (t1 != VOID && t2 == VOID)) + return uerror("value of void expression used"); + break; + } + + /* allow void pointer assignments in any direction */ + if (BTYPE(t1) == VOID && (t2 & TMASK)) + return; + if (BTYPE(t2) == VOID && (t1 & TMASK)) + return; + +#ifdef notdef + /* C99 says that enums always should be handled as ints */ + /* check for enumerations */ + if (t1==ENUMTY || t2==ENUMTY) { + if( clogop( p->n_op ) && p->n_op != EQ && p->n_op != NE ) { + werror( "comparison of enums" ); + return; + } + if (t1==ENUMTY && t2==ENUMTY) { + if (p->n_left->n_sue!=p->n_right->n_sue) + werror("enumeration type clash, " + "operator %s", copst(p->n_op)); + return; + } + if ((t1 == ENUMTY && t2 <= BTMASK) || + (t2 == ENUMTY && t1 <= BTMASK)) + return; + } +#endif + + if (ISPTR(t1) || ISARY(t1)) + q = p->n_right; + else + q = p->n_left; + + if (!ISPTR(q->n_type) && !ISARY(q->n_type)) { + if (q->n_op != ICON || q->n_lval != 0) + werror("illegal combination of pointer and integer"); + } else { + d1 = p->n_left->n_df; + d2 = p->n_right->n_df; + if (t1 == t2) { + if (p->n_left->n_sue != p->n_right->n_sue) + werror("illegal structure pointer combination"); + return; + } + for (;;) { + if (ISARY(t1) || ISPTR(t1)) { + if (!ISARY(t2) && !ISPTR(t2)) + break; + if (ISARY(t1) && ISARY(t2) && d1->ddim != d2->ddim) { + werror("illegal array size combination"); + return; + } + if (ISARY(t1)) + ++d1; + if (ISARY(t2)) + ++d2; + } else if (ISFTN(t1)) { + if (chkftn(d1->dfun, d2->dfun)) { + werror("illegal function " + "pointer combination"); + return; + } + ++d1; + ++d2; + } else + break; + t1 = DECREF(t1); + t2 = DECREF(t2); + } + werror("illegal pointer combination"); + } +} + +NODE * +stref(NODE *p) +{ + NODE *r; + struct suedef *sue; + union dimfun *d; + TWORD t, q; + int dsc; + OFFSZ off; + struct symtab *s; + + /* make p->x */ + /* this is also used to reference automatic variables */ + + s = p->n_right->n_sp; + nfree(p->n_right); + r = p->n_left; + nfree(p); + p = pconvert(r); + + /* make p look like ptr to x */ + + if (!ISPTR(p->n_type)) + p->n_type = PTR+UNIONTY; + + t = INCREF(s->stype); + q = INCQAL(s->squal); + d = s->sdf; + sue = s->ssue; + + p = makety(p, t, q, d, sue); + + /* compute the offset to be added */ + + off = s->soffset; + dsc = s->sclass; + + if (dsc & FIELD) { /* make fields look like ints */ + off = (off/ALINT)*ALINT; + sue = MKSUE(INT); + } + if (off != 0) { + p = block(PLUS, p, offcon(off, t, d, sue), t, d, sue); + p->n_qual = q; + p = optim(p); + } + + p = buildtree(UMUL, p, NIL); + + /* if field, build field info */ + + if (dsc & FIELD) { + p = block(FLD, p, NIL, s->stype, 0, s->ssue); + p->n_qual = q; + p->n_rval = PKFIELD(dsc&FLDSIZ, s->soffset%ALINT); + } + + p = clocal(p); + return p; +} + +int +notlval(p) register NODE *p; { + + /* return 0 if p an lvalue, 1 otherwise */ + + again: + + switch( p->n_op ){ + + case FLD: + p = p->n_left; + goto again; + + case NAME: + case OREG: + case UMUL: + if( ISARY(p->n_type) || ISFTN(p->n_type) ) return(1); + case TEMP: + case REG: + return(0); + + default: + return(1); + + } + + } +/* make a constant node with value i */ +NODE * +bcon(int i) +{ + register NODE *p; + + p = block(ICON, NIL, NIL, INT, 0, MKSUE(INT)); + p->n_lval = i; + p->n_sp = NULL; + return(clocal(p)); +} + +NODE * +bpsize(NODE *p) +{ + return(offcon(psize(p), p->n_type, p->n_df, p->n_sue)); +} + +/* + * p is a node of type pointer; psize returns the + * size of the thing pointed to + */ +OFFSZ +psize(NODE *p) +{ + + if (!ISPTR(p->n_type)) { + uerror("pointer required"); + return(SZINT); + } + /* note: no pointers to fields */ + return(tsize(DECREF(p->n_type), p->n_df, p->n_sue)); +} + +/* + * convert an operand of p + * f is either CVTL or CVTR + * operand has type int, and is converted by the size of the other side + * convert is called when an integer is to be added to a pointer, for + * example in arrays or structures. + */ +NODE * +convert(NODE *p, int f) +{ + union dimfun *df; + TWORD ty, ty2; + NODE *q, *r, *s, *rv; + + if (f == CVTL) { + q = p->n_left; + s = p->n_right; + } else { + q = p->n_right; + s = p->n_left; + } + ty2 = ty = DECREF(s->n_type); + while (ISARY(ty)) + ty = DECREF(ty); + + r = offcon(tsize(ty, s->n_df, s->n_sue), s->n_type, s->n_df, s->n_sue); + ty = ty2; + rv = bcon(1); + df = s->n_df; + while (ISARY(ty)) { + rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) : + tempnode(-df->ddim, INT, 0, MKSUE(INT))); + df++; + ty = DECREF(ty); + } + rv = clocal(block(PMCONV, rv, r, INT, 0, MKSUE(INT))); + rv = optim(rv); + + r = block(PMCONV, q, rv, INT, 0, MKSUE(INT)); + r = clocal(r); + /* + * Indexing is only allowed with integer arguments, so insert + * SCONV here if arg is not an integer. + * XXX - complain? + */ + if (r->n_type != INT) + r = clocal(block(SCONV, r, NIL, INT, 0, MKSUE(INT))); + if (f == CVTL) + p->n_left = r; + else + p->n_right = r; + return(p); +} + +/* + * change enums to ints, or appropriate types + */ +void +econvert( p ) register NODE *p; { + + + register TWORD ty; + + if( (ty=BTYPE(p->n_type)) == ENUMTY || ty == MOETY ) { + if (p->n_sue->suesize == SZCHAR) + ty = INT; + else if (p->n_sue->suesize == SZINT) + ty = INT; + else if (p->n_sue->suesize == SZSHORT) + ty = INT; + else if (p->n_sue->suesize == SZLONGLONG) + ty = LONGLONG; + else + ty = LONG; + ty = ctype(ty); + p->n_sue = MKSUE(ty); + MODTYPE(p->n_type,ty); + if (p->n_op == ICON && ty != LONG && ty != LONGLONG) + p->n_type = INT, p->n_sue = MKSUE(INT); + } +} + +NODE * +pconvert( p ) register NODE *p; { + + /* if p should be changed into a pointer, do so */ + + if( ISARY( p->n_type) ){ + p->n_type = DECREF( p->n_type ); + ++p->n_df; + return( buildtree( ADDROF, p, NIL ) ); + } + if( ISFTN( p->n_type) ) + return( buildtree( ADDROF, p, NIL ) ); + + return( p ); + } + +NODE * +oconvert(p) register NODE *p; { + /* convert the result itself: used for pointer and unsigned */ + + switch(p->n_op) { + + case LE: + case LT: + case GE: + case GT: + if( ISUNSIGNED(p->n_left->n_type) || ISUNSIGNED(p->n_right->n_type) ) p->n_op += (ULE-LE); + case EQ: + case NE: + return( p ); + + case MINUS: + return( clocal( block( PVCONV, + p, bpsize(p->n_left), INT, 0, MKSUE(INT)))); + } + + cerror( "illegal oconvert: %d", p->n_op ); + + return(p); + } + +/* + * makes the operands of p agree; they are + * either pointers or integers, by this time + * with MINUS, the sizes must be the same + * with COLON, the types must be the same + */ +NODE * +ptmatch(NODE *p) +{ + struct suedef *sue, *sue2; + union dimfun *d, *d2; + TWORD t1, t2, t, q1, q2, q; + int o; + + o = p->n_op; + t = t1 = p->n_left->n_type; + q = q1 = p->n_left->n_qual; + t2 = p->n_right->n_type; + q2 = p->n_right->n_qual; + d = p->n_left->n_df; + d2 = p->n_right->n_df; + sue = p->n_left->n_sue; + sue2 = p->n_right->n_sue; + + switch( o ){ + + case ASSIGN: + case RETURN: + case CAST: + { break; } + + case MINUS: + { if( psize(p->n_left) != psize(p->n_right) ){ + uerror( "illegal pointer subtraction"); + } + break; + } + case COLON: + if (t1 != t2) { + /* + * Check for void pointer types. They are allowed + * to cast to/from any pointers. + */ + if (ISPTR(t1) && ISPTR(t2) && + (BTYPE(t1) == VOID || BTYPE(t2) == VOID)) + break; + uerror("illegal types in :"); + } + break; + + default: /* must work harder: relationals or comparisons */ + + if( !ISPTR(t1) ){ + t = t2; + q = q2; + d = d2; + sue = sue2; + break; + } + if( !ISPTR(t2) ){ + break; + } + + /* both are pointers */ + if( talign(t2,sue2) < talign(t,sue) ){ + t = t2; + q = q2; + sue = sue2; + } + break; + } + + p->n_left = makety( p->n_left, t, q, d, sue ); + p->n_right = makety( p->n_right, t, q, d, sue ); + if( o!=MINUS && !clogop(o) ){ + + p->n_type = t; + p->n_qual = q; + p->n_df = d; + p->n_sue = sue; + } + + return(clocal(p)); + } + +int tdebug = 0; + +NODE * +tymatch(p) register NODE *p; { + + /* satisfy the types of various arithmetic binary ops */ + + /* rules are: + if assignment, type of LHS + if any doubles, make double + else if any float make float + else if any longlongs, make long long + else if any longs, make long + else etcetc. + if either operand is unsigned, the result is... + */ + + TWORD t1, t2, t, tu; + int o, lu, ru; + + o = p->n_op; + + t1 = p->n_left->n_type; + t2 = p->n_right->n_type; + + lu = ru = 0; + if( ISUNSIGNED(t1) ){ + lu = 1; + t1 = DEUNSIGN(t1); + } + if( ISUNSIGNED(t2) ){ + ru = 1; + t2 = DEUNSIGN(t2); + } + + if (t1 == ENUMTY || t1 == MOETY) + t1 = INT; /* XXX */ + if (t2 == ENUMTY || t2 == MOETY) + t2 = INT; /* XXX */ +#if 0 + if ((t1 == CHAR || t1 == SHORT) && o!= RETURN) + t1 = INT; + if (t2 == CHAR || t2 == SHORT) + t2 = INT; +#endif + + if (t1 == LDOUBLE || t2 == LDOUBLE) + t = LDOUBLE; + else if (t1 == DOUBLE || t2 == DOUBLE) + t = DOUBLE; + else if (t1 == FLOAT || t2 == FLOAT) + t = FLOAT; + else if (t1==LONGLONG || t2 == LONGLONG) + t = LONGLONG; + else if (t1==LONG || t2==LONG) + t = LONG; + else /* if (t1==INT || t2==INT) */ + t = INT; +#if 0 + else if (t1==SHORT || t2==SHORT) + t = SHORT; + else + t = CHAR; +#endif + + if( casgop(o) ){ + tu = p->n_left->n_type; + t = t1; + } else { + tu = ((ru|lu) && UNSIGNABLE(t))?ENUNSIGN(t):t; + } + + /* because expressions have values that are at least as wide + as INT or UNSIGNED, the only conversions needed + are those involving FLOAT/DOUBLE, and those + from LONG to INT and ULONG to UNSIGNED */ + + + if (t != t1 || (ru && !lu)) + p->n_left = makety( p->n_left, tu, 0, 0, MKSUE(tu)); + + if (t != t2 || o==CAST || (lu && !ru)) + p->n_right = makety(p->n_right, tu, 0, 0, MKSUE(tu)); + + if( casgop(o) ){ + p->n_type = p->n_left->n_type; + p->n_df = p->n_left->n_df; + p->n_sue = p->n_left->n_sue; + } + else if( !clogop(o) ){ + p->n_type = tu; + p->n_df = NULL; + p->n_sue = MKSUE(t); + } + +#ifdef PCC_DEBUG + if (tdebug) { + printf("tymatch(%p): ", p); + tprint(stdout, t1, 0); + printf(" %s ", copst(o)); + tprint(stdout, t2, 0); + printf(" => "); + tprint(stdout, tu, 0); + printf("\n"); + } +#endif + + return(p); + } + +/* + * make p into type t by inserting a conversion + */ +NODE * +makety(NODE *p, TWORD t, TWORD q, union dimfun *d, struct suedef *sue) +{ + + if (p->n_type == ENUMTY && p->n_op == ICON) + econvert(p); + if (t == p->n_type) { + p->n_df = d; + p->n_sue = sue; + p->n_qual = q; + return(p); + } + + if ((p->n_type == FLOAT || p->n_type == DOUBLE || p->n_type == LDOUBLE) + && (t == FLOAT || t == DOUBLE || t == LDOUBLE) && p->n_op == FCON) { + p->n_type = t; + p->n_qual = q; + p->n_df = d; + p->n_sue = sue; + return(p); + } + + if (t & TMASK) { + /* non-simple type */ + p = block(PCONV, p, NIL, t, d, sue); + p->n_qual = q; + return clocal(p); + } + + if (p->n_op == ICON) { + if (t == DOUBLE || t == FLOAT) { + p->n_op = FCON; + if (ISUNSIGNED(p->n_type)) + p->n_dcon = (U_CONSZ) p->n_lval; + else + p->n_dcon = p->n_lval; + p->n_type = t; + p->n_qual = q; + p->n_sue = MKSUE(t); + return (clocal(p)); + } + } + p = block(SCONV, p, NIL, t, d, sue); + p->n_qual = q; + return clocal(p); + +} + +NODE * +block(int o, NODE *l, NODE *r, TWORD t, union dimfun *d, struct suedef *sue) +{ + register NODE *p; + + p = talloc(); + p->n_rval = 0; + p->n_op = o; + p->n_lval = 0; /* Protect against large lval */ + p->n_left = l; + p->n_right = r; + p->n_type = t; + p->n_qual = 0; + p->n_df = d; + p->n_sue = sue; +#if !defined(MULTIPASS) + /* p->n_reg = */p->n_su = 0; + p->n_regw = 0; +#endif + return(p); + } + +int +icons(p) register NODE *p; { + /* if p is an integer constant, return its value */ + int val; + + if( p->n_op != ICON ){ + uerror( "constant expected"); + val = 1; + } + else { + val = p->n_lval; + if( val != p->n_lval ) uerror( "constant too big for cross-compiler" ); + } + tfree( p ); + return(val); +} + +/* + * the intent of this table is to examine the + * operators, and to check them for + * correctness. + * + * The table is searched for the op and the + * modified type (where this is one of the + * types INT (includes char and short), LONG, + * DOUBLE (includes FLOAT), and POINTER + * + * The default action is to make the node type integer + * + * The actions taken include: + * PUN check for puns + * CVTL convert the left operand + * CVTR convert the right operand + * TYPL the type is determined by the left operand + * TYPR the type is determined by the right operand + * TYMATCH force type of left and right to match,by inserting conversions + * PTMATCH like TYMATCH, but for pointers + * LVAL left operand must be lval + * CVTO convert the op + * NCVT do not convert the operands + * OTHER handled by code + * NCVTR convert the left operand, not the right... + * + */ + +# define MINT 01 /* integer */ +# define MDBI 02 /* integer or double */ +# define MSTR 04 /* structure */ +# define MPTR 010 /* pointer */ +# define MPTI 020 /* pointer or integer */ +# define MENU 040 /* enumeration variable or member */ + +int +opact(NODE *p) +{ + int mt12, mt1, mt2, o; + + mt1 = mt2 = mt12 = 0; + + switch (coptype(o = p->n_op)) { + case BITYPE: + mt12=mt2 = moditype(p->n_right->n_type); + case UTYPE: + mt12 &= (mt1 = moditype(p->n_left->n_type)); + break; + } + + switch( o ){ + + case NAME : + case ICON : + case FCON : + case CALL : + case UCALL: + case UMUL: + { return( OTHER ); } + case UMINUS: + if( mt1 & MDBI ) return( TYPL ); + break; + + case COMPL: + if( mt1 & MINT ) return( TYPL ); + break; + + case ADDROF: + return( NCVT+OTHER ); + case NOT: +/* case INIT: */ + case CM: + case CBRANCH: + case ANDAND: + case OROR: + return( 0 ); + + case MUL: + case DIV: + if ((mt1&MDBI) && (mt2&MENU)) return( TYMATCH ); + if ((mt2&MDBI) && (mt1&MENU)) return( TYMATCH ); + if( mt12 & MDBI ) return( TYMATCH ); + break; + + case MOD: + case AND: + case OR: + case ER: + if( mt12 & MINT ) return( TYMATCH ); + break; + + case LS: + case RS: + if( mt12 & MINT ) return( TYPL+OTHER ); + break; + + case EQ: + case NE: + case LT: + case LE: + case GT: + case GE: + if( mt12 & MDBI ) return( TYMATCH+CVTO ); + else if( mt12 & MPTR ) return( PTMATCH+PUN ); + else if( mt12 & MPTI ) return( PTMATCH+PUN ); + else break; + + case QUEST: + case COMOP: + if( mt2&MENU ) return( TYPR+NCVTR ); + return( TYPR ); + + case STREF: + return( NCVTR+OTHER ); + + case FORCE: + return( TYPL ); + + case COLON: + if( mt12 & MDBI ) return( TYMATCH ); + else if( mt12 & MPTR ) return( TYPL+PTMATCH+PUN ); + else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+PUN ); + else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+PUN ); + else if( mt12 & MSTR ) return( NCVT+TYPL+OTHER ); + break; + + case ASSIGN: + case RETURN: + if( mt12 & MSTR ) return( LVAL+NCVT+TYPL+OTHER ); + case CAST: + if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH ); +#if 0 + else if(mt1&MENU && mt2&MDBI) return( TYPL+LVAL+TYMATCH ); + else if(mt2&MENU && mt1&MDBI) return( TYPL+LVAL+TYMATCH ); + else if( (mt1&MENU)||(mt2&MENU) ) + return( LVAL+NCVT+TYPL+PTMATCH+PUN ); +#endif + else if( mt1 & MPTR) return( LVAL+PTMATCH+PUN ); + else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN ); + break; + + case LSEQ: + case RSEQ: + if( mt12 & MINT ) return( TYPL+LVAL+OTHER ); + break; + + case MULEQ: + case DIVEQ: + if( mt12 & MDBI ) return( LVAL+TYMATCH ); + break; + + case MODEQ: + case ANDEQ: + case OREQ: + case EREQ: + if (mt12 & MINT) + return(LVAL+TYMATCH); + break; + + case PLUSEQ: + case MINUSEQ: + case INCR: + case DECR: + if (mt12 & MDBI) + return(TYMATCH+LVAL); + else if ((mt1&MPTR) && (mt2&MINT)) + return(TYPL+LVAL+CVTR); + break; + + case MINUS: + if (mt12 & MPTR) + return(CVTO+PTMATCH+PUN); + if (mt2 & MPTR) + break; + /* FALLTHROUGH */ + case PLUS: + if (mt12 & MDBI) + return(TYMATCH); + else if ((mt1&MPTR) && (mt2&MINT)) + return(TYPL+CVTR); + else if ((mt1&MINT) && (mt2&MPTR)) + return(TYPR+CVTL); + + } + uerror("operands of %s have incompatible types", copst(o)); + return(NCVT); +} + +int +moditype(TWORD ty) +{ + switch (ty) { + + case ENUMTY: + case MOETY: + return( MENU|MINT|MDBI|MPTI ); + + case STRTY: + case UNIONTY: + return( MSTR ); + + case BOOL: + case CHAR: + case SHORT: + case UCHAR: + case USHORT: + case UNSIGNED: + case ULONG: + case ULONGLONG: + case INT: + case LONG: + case LONGLONG: + return( MINT|MDBI|MPTI ); + case FLOAT: + case DOUBLE: + case LDOUBLE: + return( MDBI ); + default: + return( MPTR|MPTI ); + + } +} + +int tvaloff = 100; + +/* + * Returns a TEMP node with temp number nr. + * If nr == 0, return a node with a new number. + */ +NODE * +tempnode(int nr, TWORD type, union dimfun *df, struct suedef *sue) +{ + NODE *r; + + r = block(TEMP, NIL, NIL, type, df, sue); + r->n_lval = nr ? nr : tvaloff; + tvaloff += szty(type); + return r; +} + +/* + * Do sizeof on p. + */ +NODE * +doszof(NODE *p) +{ + union dimfun *df; + TWORD ty; + NODE *rv; + + /* + * Arrays may be dynamic, may need to make computations. + */ + + rv = bcon(1); + df = p->n_df; + ty = p->n_type; + while (ISARY(ty)) { + rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) : + tempnode(-df->ddim, INT, 0, MKSUE(INT))); + df++; + ty = DECREF(ty); + } + rv = buildtree(MUL, rv, bcon(tsize(ty, p->n_df, p->n_sue)/SZCHAR)); + tfree(p); + return rv; +} + +#ifdef PCC_DEBUG +void +eprint(NODE *p, int down, int *a, int *b) +{ + int ty; + + *a = *b = down+1; + while( down > 1 ){ + printf( "\t" ); + down -= 2; + } + if( down ) printf( " " ); + + ty = coptype( p->n_op ); + + printf("%p) %s, ", p, copst(p->n_op)); + if (ty == LTYPE) { + printf(CONFMT, p->n_lval); + printf(", %d, ", p->n_rval); + } + tprint(stdout, p->n_type, p->n_qual); + printf( ", %p, %p\n", p->n_df, p->n_sue ); +} +# endif + +void +prtdcon(NODE *p) +{ + int o = p->n_op, i; + + if (o != FCON) + return; + + /* Write float constants to memory */ + /* Should be volontary per architecture */ + + setloc1(RDATA); + defalign(p->n_type == FLOAT ? ALFLOAT : p->n_type == DOUBLE ? + ALDOUBLE : ALLDOUBLE ); + deflab1(i = getlab()); + ninval(0, btdims[p->n_type].suesize, p); + p->n_op = NAME; + p->n_lval = 0; + p->n_sp = tmpalloc(sizeof(struct symtab_hdr)); + p->n_sp->sclass = ILABEL; + p->n_sp->soffset = i; +} + +extern int negrel[]; + +/* + * Walk up through the tree from the leaves, + * removing constant operators. + */ +static void +logwalk(NODE *p) +{ + int o = coptype(p->n_op); + NODE *l, *r; + + l = p->n_left; + r = p->n_right; + switch (o) { + case LTYPE: + return; + case BITYPE: + logwalk(r); + case UTYPE: + logwalk(l); + } + if (!clogop(p->n_op)) + return; + if (p->n_op == NOT && l->n_op == ICON) { + p->n_lval = l->n_lval == 0; + nfree(l); + p->n_op = ICON; + } + if (l->n_op == ICON && r->n_op == ICON) { + if (conval(l, p->n_op, r) == 0) { + /* + * people sometimes tend to do really odd compares, + * like "if ("abc" == "def")" etc. + * do it runtime instead. + */ + } else { + p->n_lval = l->n_lval; + p->n_op = ICON; + nfree(l); + nfree(r); + } + } +} + +/* + * Removes redundant logical operators for branch conditions. + */ +static void +fixbranch(NODE *p, int label) +{ + + logwalk(p); + + if (p->n_op == ICON) { + if (p->n_lval != 0) + branch(label); + nfree(p); + } else { + if (!clogop(p->n_op)) /* Always conditional */ + p = buildtree(NE, p, bcon(0)); + ecode(buildtree(CBRANCH, p, bcon(label))); + } +} + +/* + * Write out logical expressions as branches. + */ +static void +andorbr(NODE *p, int true, int false) +{ + NODE *q; + int o, lab; + + lab = -1; + switch (o = p->n_op) { + case EQ: + case NE: + /* + * Remove redundant EQ/NE nodes. + */ + while (((o = p->n_left->n_op) == EQ || o == NE) && + p->n_right->n_op == ICON) { + o = p->n_op; + q = p->n_left; + if (p->n_right->n_lval == 0) { + nfree(p->n_right); + *p = *q; + nfree(q); + if (o == EQ) + p->n_op = negrel[p->n_op - EQ]; +// p->n_op = NE; /* toggla */ + } else if (p->n_right->n_lval == 1) { + nfree(p->n_right); + *p = *q; + nfree(q); + if (o == NE) + p->n_op = negrel[p->n_op - EQ]; +// p->n_op = EQ; /* toggla */ + } else + break; /* XXX - should always be false */ + + } + /* FALLTHROUGH */ + case LE: + case LT: + case GE: + case GT: +calc: if (true < 0) { + p->n_op = negrel[p->n_op - EQ]; + true = false; + false = -1; + } + + rmcops(p->n_left); + rmcops(p->n_right); + fixbranch(p, true); + if (false >= 0) + branch(false); + break; + + case ULE: + case UGT: + /* Convert to friendlier ops */ + if (p->n_right->n_op == ICON && p->n_right->n_lval == 0) + p->n_op = o == ULE ? EQ : NE; + goto calc; + + case UGE: + case ULT: + /* Already true/false by definition */ + if (p->n_right->n_op == ICON && p->n_right->n_lval == 0) { + if (true < 0) { + o = o == ULT ? UGE : ULT; + true = false; + } + rmcops(p->n_left); + ecode(p->n_left); + rmcops(p->n_right); + ecode(p->n_right); + nfree(p); + if (o == UGE) /* true */ + branch(true); + break; + } + goto calc; + + case ANDAND: + lab = false<0 ? getlab() : false ; + andorbr(p->n_left, -1, lab); + andorbr(p->n_right, true, false); + if (false < 0) + plabel( lab); + nfree(p); + break; + + case OROR: + lab = true<0 ? getlab() : true; + andorbr(p->n_left, lab, -1); + andorbr(p->n_right, true, false); + if (true < 0) + plabel( lab); + nfree(p); + break; + + case NOT: + andorbr(p->n_left, false, true); + nfree(p); + break; + + default: + rmcops(p); + if (true >= 0) + fixbranch(p, true); + if (false >= 0) { + if (true >= 0) + branch(false); + else + fixbranch(buildtree(EQ, p, bcon(0)), false); + } + } +} + +/* + * Massage the output trees to remove C-specific nodes: + * COMOPs are split into separate statements. + * QUEST/COLON are rewritten to branches. + * ANDAND/OROR/NOT are rewritten to branches for lazy-evaluation. + * CBRANCH conditions are rewritten for lazy-evaluation. + */ +static void +rmcops(NODE *p) +{ + TWORD type; + NODE *q, *r; + int o, ty, lbl, lbl2, tval = 0; + +again: + o = p->n_op; + ty = coptype(o); + switch (o) { + case QUEST: + + /* + * Create a branch node from ?: + * || and && must be taken special care of. + */ + type = p->n_type; + andorbr(p->n_left, -1, lbl = getlab()); + + /* Make ASSIGN node */ + /* Only if type is not void */ + q = p->n_right->n_left; + if (type != VOID) { + r = tempnode(0, q->n_type, q->n_df, q->n_sue); + tval = r->n_lval; + q = buildtree(ASSIGN, r, q); + } + rmcops(q); + ecode(q); /* Done with assign */ + branch(lbl2 = getlab()); + plabel( lbl); + + q = p->n_right->n_right; + if (type != VOID) { + r = tempnode(tval, q->n_type, q->n_df, q->n_sue); + q = buildtree(ASSIGN, r, q); + } + rmcops(q); + ecode(q); /* Done with assign */ + + plabel( lbl2); + + nfree(p->n_right); + if (p->n_type != VOID) { + r = tempnode(tval, p->n_type, p->n_df, p->n_sue); + *p = *r; + nfree(r); + } else + p->n_op = ICON; + break; + + case ULE: + case ULT: + case UGE: + case UGT: + case EQ: + case NE: + case LE: + case LT: + case GE: + case GT: + case ANDAND: + case OROR: + case NOT: +#ifdef SPECIAL_CCODES +#error fix for private CCODES handling +#else + r = talloc(); + *r = *p; + andorbr(r, -1, lbl = getlab()); + q = tempnode(0, p->n_type, p->n_df, p->n_sue); + tval = q->n_lval; + r = tempnode(tval, p->n_type, p->n_df, p->n_sue); + ecode(buildtree(ASSIGN, q, bcon(1))); + branch(lbl2 = getlab()); + plabel( lbl); + ecode(buildtree(ASSIGN, r, bcon(0))); + plabel( lbl2); + r = tempnode(tval, p->n_type, p->n_df, p->n_sue); + *p = *r; + nfree(r); +#endif + break; + case CBRANCH: + andorbr(p->n_left, p->n_right->n_lval, -1); + nfree(p->n_right); + p->n_op = ICON; p->n_type = VOID; + break; + case COMOP: + rmcops(p->n_left); + ecode(p->n_left); + /* Now when left tree is dealt with, rm COMOP */ + q = p->n_right; + *p = *p->n_right; + nfree(q); + goto again; + + default: + if (ty == LTYPE) + return; + rmcops(p->n_left); + if (ty == BITYPE) + rmcops(p->n_right); + } +} + +/* + * Return 1 if an assignment is found. + */ +static int +has_se(NODE *p) +{ + if (cdope(p->n_op) & ASGFLG) + return 1; + if (coptype(p->n_op) == LTYPE) + return 0; + if (has_se(p->n_left)) + return 1; + if (coptype(p->n_op) == BITYPE) + return has_se(p->n_right); + return 0; +} + +/* + * Find and convert asgop's to separate statements. + * Be careful about side effects. + * assign tells whether ASSIGN should be considered giving + * side effects or not. + */ +static NODE * +delasgop(NODE *p) +{ + NODE *q, *r; + int tval; + + if (p->n_op == INCR || p->n_op == DECR) { + /* + * Rewrite x++ to (x += 1) -1; and deal with it further down. + * Pass2 will remove -1 if unneccessary. + */ + q = ccopy(p); + tfree(p->n_left); + q->n_op = (p->n_op==INCR)?PLUSEQ:MINUSEQ; + p->n_op = (p->n_op==INCR)?MINUS:PLUS; + p->n_left = delasgop(q); + + } else if ((cdope(p->n_op)&ASGOPFLG) && + p->n_op != RETURN && p->n_op != CAST) { + NODE *l = p->n_left; + NODE *ll = l->n_left; + + if (has_se(l)) { + q = tempnode(0, ll->n_type, ll->n_df, ll->n_sue); + tval = q->n_lval; + r = tempnode(tval, ll->n_type, ll->n_df,ll->n_sue); + l->n_left = q; + /* Now the left side of node p has no side effects. */ + /* side effects on the right side must be obeyed */ + p = delasgop(p); + + r = buildtree(ASSIGN, r, ll); + r = delasgop(r); + ecode(r); + } else { +#if 0 /* Cannot call buildtree() here, it would invoke double add shifts */ + p->n_right = buildtree(UNASG p->n_op, ccopy(l), + p->n_right); +#else + p->n_right = block(UNASG p->n_op, ccopy(l), + p->n_right, p->n_type, p->n_df, p->n_sue); +#endif + p->n_op = ASSIGN; + p->n_right = delasgop(p->n_right); + p->n_right = clocal(p->n_right); + } + + } else { + if (coptype(p->n_op) == LTYPE) + return p; + p->n_left = delasgop(p->n_left); + if (coptype(p->n_op) == BITYPE) + p->n_right = delasgop(p->n_right); + } + return p; +} + +int edebug = 0; +void +ecomp(NODE *p) +{ + +#ifdef PCC_DEBUG + if (edebug) + fwalk(p, eprint, 0); +#endif + if (!reached) { + werror("statement not reached"); + reached = 1; + } + p = optim(p); + rmcops(p); + p = delasgop(p); + setloc1(PROG); + if (p->n_op == ICON && p->n_type == VOID) + tfree(p); + else + ecode(p); +} + +#if defined(MULTIPASS) +void +p2tree(NODE *p) +{ + struct symtab *q; + int ty; + +# ifdef MYP2TREE + MYP2TREE(p); /* local action can be taken here; then return... */ +# endif + + ty = coptype(p->n_op); + + printf("%d\t", p->n_op); + + if (ty == LTYPE) { + printf(CONFMT, p->n_lval); + printf("\t"); + } + if (ty != BITYPE) { + if (p->n_op == NAME || p->n_op == ICON) + printf("0\t"); + else + printf("%d\t", p->n_rval); + } + + printf("%o\t", p->n_type); + + /* handle special cases */ + + switch (p->n_op) { + + case NAME: + case ICON: + /* print external name */ + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0) || + q->sclass == ILABEL) { + printf(LABFMT, q->soffset); + } else + printf("%s\n", exname(q->sname)); + } else + printf("\n"); + break; + + case STARG: + case STASG: + case STCALL: + case USTCALL: + /* print out size */ + /* use lhs size, in order to avoid hassles + * with the structure `.' operator + */ + + /* note: p->left not a field... */ + printf(CONFMT, (CONSZ)tsize(STRTY, p->n_left->n_df, + p->n_left->n_sue)); + printf("\t%d\t\n", talign(STRTY, p->n_left->n_sue)); + break; + + default: + printf( "\n" ); + } + + if (ty != LTYPE) + p2tree(p->n_left); + if (ty == BITYPE) + p2tree(p->n_right); +} +#else +void +p2tree(NODE *p) +{ + struct symtab *q; + int ty; + +# ifdef MYP2TREE + MYP2TREE(p); /* local action can be taken here; then return... */ +# endif + + ty = coptype(p->n_op); + + switch( p->n_op ){ + + case NAME: + case ICON: + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0) || +#ifdef GCC_COMPAT + q->sflags == SLBLNAME || +#endif + q->sclass == ILABEL) { + char *cp = (isinlining ? + permalloc(32) : tmpalloc(32)); + int n = q->soffset; + if (n < 0) + n = -n; + snprintf(cp, 32, LABFMT, n); + p->n_name = cp; + } else { +#ifdef GCC_COMPAT + p->n_name = gcc_findname(q); +#else + p->n_name = exname(q->sname); +#endif + } + } else + p->n_name = ""; + break; + + case STASG: + /* STASG used for stack array init */ + if (ISARY(p->n_type)) { + int size1 = tsize(p->n_type, p->n_left->n_df, + p->n_left->n_sue)/SZCHAR; + p->n_stsize = tsize(p->n_type, p->n_right->n_df, + p->n_right->n_sue)/SZCHAR; + if (size1 < p->n_stsize) + p->n_stsize = size1; + p->n_stalign = talign(p->n_type, + p->n_left->n_sue)/SZCHAR; + break; + } + /* FALLTHROUGH */ + case STARG: + case STCALL: + case USTCALL: + /* set up size parameters */ + p->n_stsize = (tsize(STRTY, p->n_left->n_df, + p->n_left->n_sue)+SZCHAR-1)/SZCHAR; + p->n_stalign = talign(STRTY,p->n_left->n_sue)/SZCHAR; + break; + + default: + p->n_name = ""; + } + + if( ty != LTYPE ) p2tree( p->n_left ); + if( ty == BITYPE ) p2tree( p->n_right ); + } + +#endif + +/* + * Change void data types into char. + */ +static void +delvoid(NODE *p) +{ + /* Convert "PTR undef" (void *) to "PTR uchar" */ + if (BTYPE(p->n_type) == VOID) + p->n_type = (p->n_type & ~BTMASK) | UCHAR; + if (BTYPE(p->n_type) == BOOL) { + if (p->n_op == SCONV && p->n_type == BOOL) { + /* create a jump and a set */ + NODE *q, *r, *s; + int l, val; + + q = talloc(); + *q = *p; + q->n_type = BOOL_TYPE; + r = tempnode(0, BOOL_TYPE, NULL, MKSUE(BOOL_TYPE)); + val = r->n_lval; + s = tempnode(val, BOOL_TYPE, NULL, MKSUE(BOOL_TYPE)); + *p = *s; + q = buildtree(ASSIGN, r, q); + cbranch(buildtree(EQ, q, bcon(0)), bcon(l = getlab())); + ecode(buildtree(ASSIGN, s, bcon(1))); + plabel(l); + } else + p->n_type = (p->n_type & ~BTMASK) | BOOL_TYPE; + } + +} + +void +ecode(NODE *p) +{ + /* walk the tree and write out the nodes.. */ + + if (nerrors) + return; + + p = optim(p); + p = delasgop(p); + walkf(p, prtdcon); + walkf(p, delvoid); +#ifdef PCC_DEBUG + if (xdebug) { + printf("Fulltree:\n"); + fwalk(p, eprint, 0); + } +#endif + p2tree(p); +#if !defined(MULTIPASS) + send_passt(IP_NODE, p); +#endif +} + +/* + * Send something further on to the next pass. + */ +void +send_passt(int type, ...) +{ + struct interpass *ip; + struct interpass_prolog *ipp; + extern int crslab; + va_list ap; + int sz; + + va_start(ap, type); + if (type == IP_PROLOG || type == IP_EPILOG) + sz = sizeof(struct interpass_prolog); + else + sz = sizeof(struct interpass); + + ip = isinlining ? permalloc(sz) : tmpalloc(sz); + ip->type = type; + ip->lineno = lineno; + switch (type) { + case IP_NODE: + if (lastloc != PROG) + setloc1(PROG); + ip->ip_node = va_arg(ap, NODE *); + break; + case IP_EPILOG: + case IP_PROLOG: + setloc1(PROG); + ipp = (struct interpass_prolog *)ip; + ipp->ipp_regs = va_arg(ap, int); + ipp->ipp_autos = va_arg(ap, int); + ipp->ipp_name = va_arg(ap, char *); + ipp->ipp_type = va_arg(ap, TWORD); + ipp->ipp_vis = va_arg(ap, int); + ip->ip_lbl = va_arg(ap, int); + ipp->ip_tmpnum = tvaloff; + ipp->ip_lblnum = crslab; + if (type == IP_PROLOG) + ipp->ip_lblnum--; + break; + case IP_DEFLAB: + ip->ip_lbl = va_arg(ap, int); + break; + case IP_ASM: + if (blevel == 0) { /* outside function */ + printf("\t%s\n", va_arg(ap, char *)); + va_end(ap); + lastloc = -1; + return; + } + ip->ip_asm = va_arg(ap, char *); + break; + default: + cerror("bad send_passt type %d", type); + } + va_end(ap); + if (isinlining) + inline_addarg(ip); + else + pass2_compile(ip); + if (type == IP_EPILOG) + lastloc = PROG; +} + +char * +copst(int op) +{ + if (op <= MAXOP) + return opst[op]; +#define SNAM(x,y) case x: return #y; + switch (op) { + SNAM(QUALIFIER,QUALIFIER) + SNAM(CLASS,CLASS) + SNAM(RB,]) + SNAM(DOT,.) + SNAM(ELLIPSIS,...) + SNAM(LB,[) + SNAM(TYPE,TYPE) + SNAM(COMOP,COMOP) + SNAM(QUEST,?) + SNAM(COLON,:) + SNAM(ANDAND,&&) + SNAM(OROR,||) + SNAM(NOT,!) + SNAM(CAST,CAST) + SNAM(PLUSEQ,+=) + SNAM(MINUSEQ,-=) + SNAM(MULEQ,*=) + SNAM(DIVEQ,/=) + SNAM(MODEQ,%=) + SNAM(ANDEQ,&=) + SNAM(OREQ,|=) + SNAM(EREQ,^=) + SNAM(LSEQ,<<=) + SNAM(RSEQ,>>=) + SNAM(INCR,++) + SNAM(DECR,--) + default: + cerror("bad copst %d", op); + } + return 0; /* XXX gcc */ +} + +int +cdope(int op) +{ + if (op <= MAXOP) + return dope[op]; + switch (op) { + case QUALIFIER: + case CLASS: + case RB: + case DOT: + case ELLIPSIS: + case TYPE: + return LTYPE; + case COMOP: + case QUEST: + case COLON: + case LB: + return BITYPE; + case ANDAND: + case OROR: + return BITYPE|LOGFLG; + case NOT: + return UTYPE|LOGFLG; + case CAST: + return BITYPE|ASGFLG|ASGOPFLG; + case PLUSEQ: + return BITYPE|ASGFLG|ASGOPFLG|FLOFLG|SIMPFLG|COMMFLG; + case MINUSEQ: + return BITYPE|FLOFLG|SIMPFLG|ASGFLG|ASGOPFLG; + case MULEQ: + return BITYPE|FLOFLG|MULFLG|ASGFLG|ASGOPFLG; + case OREQ: + case EREQ: + case ANDEQ: + return BITYPE|SIMPFLG|COMMFLG|ASGFLG|ASGOPFLG; + case DIVEQ: + return BITYPE|FLOFLG|MULFLG|DIVFLG|ASGFLG|ASGOPFLG; + case MODEQ: + return BITYPE|DIVFLG|ASGFLG|ASGOPFLG; + case LSEQ: + case RSEQ: + return BITYPE|SHFFLG|ASGFLG|ASGOPFLG; + case INCR: + case DECR: + return BITYPE|ASGFLG; + } + return 0; /* XXX gcc */ +} + +/* + * make a fresh copy of p + */ +NODE * +ccopy(NODE *p) +{ + NODE *q; + + q = talloc(); + *q = *p; + + switch (coptype(q->n_op)) { + case BITYPE: + q->n_right = ccopy(p->n_right); + case UTYPE: + q->n_left = ccopy(p->n_left); + } + + return(q); +} + +/* + * set PROG-seg label. + */ +void +plabel(int label) +{ + setloc1(PROG); + reached = 1; /* Will this always be correct? */ + send_passt(IP_DEFLAB, label); +} diff --git a/usr.bin/pcc/cc/cpp/Makefile.in b/usr.bin/pcc/cc/cpp/Makefile.in new file mode 100644 index 00000000000..c293478a71a --- /dev/null +++ b/usr.bin/pcc/cc/cpp/Makefile.in @@ -0,0 +1,79 @@ +# $Id: Makefile.in,v 1.1 2007/09/15 18:12:32 otto Exp $ +# +# Makefile.in for cpp +# +XFL=-DCPP_DEBUG -Wall -Wmissing-prototypes -Wstrict-prototypes -Werror + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libexecdir = @libexecdir@ +strip = @strip@ +CC = @CC@ +CFLAGS = @CFLAGS@ $(XFL) +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +YACC = @YACC@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ + +OBJS=cpp.o cpy.o scanner.o +HEADERS=cpp.h +DEST=cpp + +all: ${DEST} + +${DEST}: $(OBJS) $(HEADERS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@ + +.c.o: + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $< + +.l.o: + $(LEX) $(LFLAGS) $< + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ lex.yy.c + +.y.o: + $(YACC) -d $(YFLAGS) $< + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ y.tab.c + +$(OBJS): $(HEADERS) + +cpp.o: cpy.o + +test: + ./cpp < tests/test1 > tests/run1 + cmp tests/run1 tests/res1 + ./cpp < tests/test2 > tests/run2 + cmp tests/run2 tests/res2 + ./cpp < tests/test3 > tests/run3 + cmp tests/run3 tests/res3 + ./cpp < tests/test4 > tests/run4 + cmp tests/run4 tests/res4 + ./cpp < tests/test5 > tests/run5 + cmp tests/run5 tests/res5 + ./cpp < tests/test6 > tests/run6 + cmp tests/run6 tests/res6 + ./cpp < tests/test7 > tests/run7 + cmp tests/run7 tests/res7 + ./cpp < tests/test8 > tests/run8 + cmp tests/run8 tests/res8 + ./cpp < tests/test9 > tests/run9 + cmp tests/run9 tests/res9 + + +install: + test -z "${DESTDIR}$(libexecdir)" || mkdir -p "${DESTDIR}$(libexecdir)" + ${INSTALL_PROGRAM} ${DEST} ${DESTDIR}${libexecdir} + @if [ ${strip} = yes ]; then \ + strip ${DESTDIR}${libexecdir}/${DEST} ; \ + echo strip ${DESTDIR}${libexecdir}/${DEST} ; \ + fi + +clean: + /bin/rm -f $(OBJS) cpp lex.yy.c y.tab.[ch] tests/run* + +distclean: clean + /bin/rm -f Makefile diff --git a/usr.bin/pcc/cc/cpp/cpp.c b/usr.bin/pcc/cc/cpp/cpp.c new file mode 100644 index 00000000000..d6f042aba71 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/cpp.c @@ -0,0 +1,1447 @@ +/* $Id: cpp.c,v 1.1 2007/09/15 18:12:32 otto Exp $ */ + +/* + * Copyright (c) 2004 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. + */ + +/* + * 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 conditions and 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. + */ +/* + * The C preprocessor. + * This code originates from the V6 preprocessor with some additions + * from V7 cpp, and at last ansi/c99 support. + */ + +#include "../../config.h" + +#include <sys/wait.h> + +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <ctype.h> + +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif + +#include "cpp.h" +#include "y.tab.h" + +#define MAXARG 250 /* # of args to a macro, limited by char value */ +#define SBSIZE 600000 + +static usch sbf[SBSIZE]; +/* C command */ + +int tflag; /* traditional cpp syntax */ +#ifdef CPP_DEBUG +int dflag; /* debug printouts */ +#define DPRINT(x) if (dflag) printf x +#define DDPRINT(x) if (dflag > 1) printf x +#else +#define DPRINT(x) +#define DDPRINT(x) +#endif + +int ofd; +static usch outbuf[CPPBUF]; +static int obufp, istty; +int Cflag, Mflag; +usch *Mfile; +struct initar *initar; + +/* avoid recursion */ +struct recur { + struct recur *next; + struct symtab *sp; +}; + +/* include dirs */ +struct incs { + struct incs *next; + usch *dir; +} *incdir[2]; +#define INCINC 0 +#define SYSINC 1 + +static struct symtab *filloc; +static struct symtab *linloc; +int trulvl; +int flslvl; +int elflvl; +int elslvl; +usch *stringbuf = sbf; + +/* + * Macro replacement list syntax: + * - For object-type macros, replacement strings are stored as-is. + * - For function-type macros, macro args are substituted for the + * character WARN followed by the argument number. + * - The value element points to the end of the string, to simplify + * pushback onto the input queue. + * + * The first character (from the end) in the replacement list is + * the number of arguments: + * VARG - ends with ellipsis, next char is argcount without ellips. + * OBJCT - object-type macro + * 0 - empty parenthesis, foo() + * 1-> - number of args. + */ + +#define VARG 0xfe /* has varargs */ +#define OBJCT 0xff +#define WARN 1 /* SOH, not legal char */ +#define CONC 2 /* STX, not legal char */ +#define SNUFF 3 /* ETX, not legal char */ +#define NOEXP 4 /* EOT, not legal char */ +#define EXPAND 5 /* ENQ, not legal char */ + +/* args for lookup() */ +#define FIND 0 +#define ENTER 1 + +static void expdef(usch *proto, struct recur *, int gotwarn); +void define(void); +static int canexpand(struct recur *, struct symtab *np); +void include(void); +void line(void); +void flbuf(void); +void usage(void); + +int +main(int argc, char **argv) +{ + struct initar *it; + struct incs *w, *w2; + struct symtab *nl; + register int ch; +// usch *osp; + + while ((ch = getopt(argc, argv, "CD:I:MS:U:di:t")) != -1) + switch (ch) { + case 'C': /* Do not discard comments */ + Cflag++; + break; + + case 'i': /* include */ + case 'U': /* undef */ + case 'D': /* define something */ + it = malloc(sizeof(struct initar)); + it->type = ch; + it->str = optarg; + it->next = initar; + initar = it; +#if 0 + osp = (usch *)optarg; + while (*osp && *osp != '=') + osp++; + if (*osp == '=') { + *osp++ = 0; + while (*osp) + osp++; + *osp = OBJCT; + } else { + static usch c[3] = { 0, '1', OBJCT }; + osp = &c[2]; + } + nl = lookup((usch *)optarg, ENTER); + if (nl->value) { + /* check for redefinition */ + usch *o = nl->value, *n = osp; + while (*o && *o == *n) + o--, n--; + if (*o || *o != *n) + error("%s redefined", optarg); + } + nl->value = osp; +#endif + break; + + case 'M': /* Generate dependencies for make */ + Mflag++; + break; + + case 'S': + case 'I': + w = calloc(sizeof(struct incs), 1); + w->dir = (usch *)optarg; + w2 = incdir[ch == 'I' ? INCINC : SYSINC]; + if (w2 != NULL) { + while (w2->next) + w2 = w2->next; + w2->next = w; + } else + incdir[ch == 'I' ? INCINC : SYSINC] = w; + break; + +#if 0 + case 'U': + if ((nl = lookup((usch *)optarg, FIND))) + nl->value = NULL; + break; +#endif +#ifdef CPP_DEBUG + case 'd': + dflag++; + break; +#endif + case 't': + tflag = 1; + break; + +#if 0 + case 'i': + if (ifile) + error("max 1 -i entry"); + ifile = optarg; + break; +#endif + + case '?': + usage(); + default: + error("bad arg %c\n", ch); + } + argc -= optind; + argv += optind; + + filloc = lookup((usch *)"__FILE__", ENTER); + linloc = lookup((usch *)"__LINE__", ENTER); + filloc->value = linloc->value = (usch *)""; /* Just something */ + + if (tflag == 0) { + time_t t = time(NULL); + usch *n = (usch *)ctime(&t); + + /* + * Manually move in the predefined macros. + */ + nl = lookup((usch *)"__TIME__", ENTER); + savch(0); savch('"'); n[19] = 0; savstr(&n[11]); savch('"'); + savch(OBJCT); + nl->value = stringbuf-1; + + nl = lookup((usch *)"__DATE__", ENTER); + savch(0); savch('"'); n[24] = n[11] = 0; savstr(&n[4]); + savstr(&n[20]); savch('"'); savch(OBJCT); + nl->value = stringbuf-1; + + nl = lookup((usch *)"__STDC__", ENTER); + savch(0); savch('1'); savch(OBJCT); + nl->value = stringbuf-1; + } + + if (Mflag) { + usch *c; + + if (argc < 1) + error("-M and no infile"); + if ((c = (usch *)strrchr(argv[0], '/')) == NULL) + c = (usch *)argv[0]; + else + c++; + Mfile = stringbuf; + savstr(c); savch(0); + if ((c = (usch *)strrchr((char *)Mfile, '.')) == NULL) + error("-M and no extension: "); + c[1] = 'o'; + c[2] = 0; + } + + if (argc == 2) { + if ((ofd = open(argv[1], O_WRONLY|O_CREAT, 0600)) < 0) + error("Can't creat %s", argv[1]); + } else + ofd = 1; /* stdout */ + istty = isatty(ofd); + + if (pushfile((usch *)(argc && strcmp(argv[0], "-") ? argv[0] : NULL))) + error("cannot open %s", argv[0]); + + flbuf(); + close(ofd); + return 0; +} + +/* + * Expand the symbol nl read from input. + * Return a pointer to the fully expanded result. + * It is the responsibility of the caller to reset the heap usage. + */ +usch * +gotident(struct symtab *nl) +{ + struct symtab *thisnl; + usch *osp, *ss2, *base; + int c; + + thisnl = NULL; + slow = 1; + base = osp = stringbuf; + goto found; + + while ((c = yylex()) != 0) { + switch (c) { + case IDENT: + if (flslvl) + break; + osp = stringbuf; + + DPRINT(("IDENT0: %s\n", yytext)); + nl = lookup((usch *)yytext, FIND); + if (nl == 0 || thisnl == 0) + goto found; + if (thisnl == nl) { + nl = 0; + goto found; + } + ss2 = stringbuf; + if ((c = yylex()) == WSPACE) { + savstr((usch *)yytext); + c = yylex(); + } + if (c != EXPAND) { + unpstr((usch *)yytext); + if (ss2 != stringbuf) + unpstr(ss2); + unpstr(nl->namep); + (void)yylex(); /* get yytext correct */ + nl = 0; /* ignore */ + } else { + thisnl = NULL; + if (nl->value[0] == OBJCT) { + unpstr(nl->namep); + (void)yylex(); /* get yytext correct */ + nl = 0; + } + } + stringbuf = ss2; + +found: if (nl == 0 || subst(nl, NULL) == 0) { + if (nl) + savstr(nl->namep); + else + savstr((usch *)yytext); + } else if (osp != stringbuf) { + DPRINT(("IDENT1: unput osp %p stringbuf %p\n", + osp, stringbuf)); + ss2 = stringbuf; + cunput(EXPAND); + while (ss2 > osp) + cunput(*--ss2); + thisnl = nl; + stringbuf = osp; /* clean up heap */ + } + break; + + case EXPAND: + DPRINT(("EXPAND!\n")); + thisnl = NULL; + break; + + case STRING: + case '\n': + case NUMBER: + case FPOINT: + case WSPACE: + savstr((usch *)yytext); + break; + + default: + if (c < 256) + savch(c); + else + savstr((usch *)yytext); + break; + } + if (thisnl == NULL) { + slow = 0; + savch(0); + return base; + } + } + error("preamture EOF"); + /* NOTREACHED */ + return NULL; /* XXX gcc */ +} + +void +line() +{ + static usch *lbuf; + static int llen; + int c; + + slow = 1; + if (yylex() != WSPACE) + goto bad; + if ((c = yylex()) != IDENT || !isdigit((int)yytext[0])) + goto bad; + ifiles->lineno = atoi(yytext); + + if ((c = yylex()) != '\n' && c != WSPACE) + goto bad; + if (c == '\n') { + slow = 0; + return; + } + if (yylex() != STRING) + goto bad; + c = strlen((char *)yytext); + if (llen < c) { + /* XXX may loose heap space */ + lbuf = stringbuf; + stringbuf += c; + llen = c; + } + yytext[strlen(yytext)-1] = 0; + strcpy((char *)lbuf, &yytext[1]); + ifiles->fname = lbuf; + if (yylex() != '\n') + goto bad; + slow = 0; + return; + +bad: error("bad line directive"); +} + +/* + * Include a file. Include order: + * - For <...> files, first search -I directories, then system directories. + * - For "..." files, first search "current" dir, then as <...> files. + */ +void +include() +{ + struct incs *w; + struct symtab *nl; + usch *osp; + usch *fn; + int i, c, it; + + if (flslvl) + return; + osp = stringbuf; + slow = 1; + if (yylex() != WSPACE) + goto bad; +again: if ((c = yylex()) != STRING && c != '<' && c != IDENT) + goto bad; + + if (c == IDENT) { + if ((nl = lookup((usch *)yytext, FIND)) == NULL) + goto bad; + if (subst(nl, NULL) == 0) + goto bad; + savch('\0'); + unpstr(osp); + goto again; + } else if (c == '<') { + fn = stringbuf; + while ((c = yylex()) != '>' && c != '\n') { + if (c == '\n') + goto bad; + savstr((usch *)yytext); + } + savch('\0'); + while ((c = yylex()) == WSPACE) + ; + if (c != '\n') + goto bad; + it = SYSINC; + } else { + usch *nm = stringbuf; + + yytext[strlen(yytext)-1] = 0; + fn = (usch *)&yytext[1]; + /* first try to open file relative to previous file */ + /* but only if it is not an absolute path */ + if (*fn != '/') { + savstr(ifiles->orgfn); + if ((stringbuf = + (usch *)strrchr((char *)nm, '/')) == NULL) + stringbuf = nm; + else + stringbuf++; + } + savstr(fn); savch(0); + while ((c = yylex()) == WSPACE) + ; + if (c != '\n') + goto bad; + slow = 0; + if (pushfile(nm) == 0) + return; + stringbuf = nm; + } + + /* create search path and try to open file */ + slow = 0; + for (i = 0; i < 2; i++) { + for (w = incdir[i]; w; w = w->next) { + usch *nm = stringbuf; + + savstr(w->dir); savch('/'); + savstr(fn); savch(0); + if (pushfile(nm) == 0) + return; + stringbuf = nm; + } + } + error("cannot find '%s'", fn); + /* error() do not return */ + +bad: error("bad include"); + /* error() do not return */ +} + +static int +definp(void) +{ + int c; + + do + c = yylex(); + while (c == WSPACE); + return c; +} + +void +define() +{ + struct symtab *np; + usch *args[MAXARG], *ubuf, *sbeg; + int c, i, redef; + int mkstr = 0, narg = -1; + int ellips = 0; + + if (flslvl) + return; + slow = 1; + if (yylex() != WSPACE || yylex() != IDENT) + goto bad; + + if (isdigit((int)yytext[0])) + goto bad; + + np = lookup((usch *)yytext, ENTER); + redef = np->value != NULL; + + sbeg = stringbuf; + if ((c = yylex()) == '(') { + narg = 0; + /* function-like macros, deal with identifiers */ + for (;;) { + c = definp(); + if (c == ')') + break; + if (c == ELLIPS) { + ellips = 1; + if (definp() != ')') + goto bad; + break; + } + if (c == IDENT) { + args[narg] = alloca(strlen(yytext)+1); + strcpy((char *)args[narg], yytext); + narg++; + if ((c = definp()) == ',') + continue; + if (c == ')') + break; + goto bad; + } + goto bad; + } + c = yylex(); + } else if (c == '\n') { + /* #define foo */ + ; + } else if (c != WSPACE) + goto bad; + + while (c == WSPACE) + c = yylex(); + + /* parse replacement-list, substituting arguments */ + savch('\0'); + while (c != '\n') { + switch (c) { + case WSPACE: + /* remove spaces if it surrounds a ## directive */ + ubuf = stringbuf; + savstr((usch *)yytext); + c = yylex(); + if (c == CONCAT) { + stringbuf = ubuf; + savch(CONC); + if ((c = yylex()) == WSPACE) + c = yylex(); + } + continue; + + case CONCAT: + /* No spaces before concat op */ + savch(CONC); + if ((c = yylex()) == WSPACE) + c = yylex(); + continue; + + case MKSTR: + if (narg < 0) { + /* no meaning in object-type macro */ + savch('#'); + break; + } + /* remove spaces between # and arg */ + savch(SNUFF); + if ((c = yylex()) == WSPACE) + c = yylex(); /* whitespace, ignore */ + mkstr = 1; + if (c == VA_ARGS) + continue; + + /* FALLTHROUGH */ + case IDENT: + if (narg < 0) + goto id; /* just add it if object */ + /* check if its an argument */ + for (i = 0; i < narg; i++) + if (strcmp(yytext, (char *)args[i]) == 0) + break; + if (i == narg) { + if (mkstr) + error("not argument"); + goto id; + } + savch(i); + savch(WARN); + if (mkstr) + savch(SNUFF), mkstr = 0; + break; + + case VA_ARGS: + if (ellips == 0) + error("unwanted %s", yytext); + savch(VARG); + savch(WARN); + if (mkstr) + savch(SNUFF), mkstr = 0; + break; + + default: +id: savstr((usch *)yytext); + break; + } + c = yylex(); + } + /* remove trailing whitespace */ + while (stringbuf > sbeg) { + if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t') + stringbuf--; + else + break; + } + if (ellips) { + savch(narg); + savch(VARG); + } else + savch(narg < 0 ? OBJCT : narg); + if (redef) { + usch *o = np->value, *n = stringbuf-1; + + /* Redefinition to identical replacement-list is allowed */ + while (*o && *o == *n) + o--, n--; + if (*o || *o != *n) + error("%s redefined\nprevious define: %s:%d", + np->namep, np->file, np->line); + stringbuf = sbeg; /* forget this space */ + } else + np->value = stringbuf-1; + +#ifdef CPP_DEBUG + if (dflag) { + usch *w = np->value; + + printf("!define: "); + if (*w == OBJCT) + printf("[object]"); + else if (*w == VARG) + printf("[VARG%d]", *--w); + while (*--w) { + switch (*w) { + case WARN: printf("<%d>", *--w); break; + case CONC: printf("<##>"); break; + case SNUFF: printf("<\">"); break; + default: putchar(*w); break; + } + } + putchar('\n'); + } +#endif + slow = 0; + return; + +bad: error("bad define"); +} + +void +xerror(usch *s) +{ + usch *t; + + flbuf(); + savch(0); + if (ifiles != NULL) { + t = sheap("%s:%d: ", ifiles->fname, ifiles->lineno); + write (2, t, strlen((char *)t)); + } + write (2, s, strlen((char *)s)); + write (2, "\n", 1); + exit(1); +} + +/* + * store a character into the "define" buffer. + */ +void +savch(c) +{ + if (stringbuf-sbf < SBSIZE) { + *stringbuf++ = c; + } else { + stringbuf = sbf; /* need space to write error message */ + error("Too much defining"); + } +} + +/* + * substitute namep for sp->value. + */ +int +subst(sp, rp) +struct symtab *sp; +struct recur *rp; +{ + struct recur rp2; + register usch *vp, *cp; + int c, rv = 0, ws; + + DPRINT(("subst: %s\n", sp->namep)); + /* + * First check for special macros. + */ + if (sp == filloc) { + (void)sheap("\"%s\"", ifiles->fname); + return 1; + } else if (sp == linloc) { + (void)sheap("%d", ifiles->lineno); + return 1; + } + vp = sp->value; + + rp2.next = rp; + rp2.sp = sp; + + if (*vp-- != OBJCT) { + int gotwarn = 0; + + /* should we be here at all? */ + /* check if identifier is followed by parentheses */ + rv = 1; + ws = 0; + do { + c = yylex(); + if (c == WARN) { + gotwarn++; + if (rp == NULL) + goto noid; + } else if (c == WSPACE) + ws = 1; + } while (c == WSPACE || c == '\n' || c == WARN); + + cp = (usch *)yytext; + while (*cp) + cp++; + while (cp > (usch *)yytext) + cunput(*--cp); + DPRINT(("c %d\n", c)); + if (c == '(' ) { + expdef(vp, &rp2, gotwarn); + return rv; + } else { + /* restore identifier */ +noid: while (gotwarn--) + cunput(WARN); + if (ws) + cunput(' '); + cp = sp->namep; + while (*cp) + cp++; + while (cp > sp->namep) + cunput(*--cp); + if ((c = yylex()) != IDENT) + error("internal sync error"); + return 0; + } + } else { + cunput(WARN); + cp = vp; + while (*cp) { + if (*cp != CONC) + cunput(*cp); + cp--; + } + expmac(&rp2); + } + return 1; +} + +/* + * do macro-expansion until WARN character read. + * read from lex buffer and store result on heap. + * will recurse into lookup() for recursive expansion. + * when returning all expansions on the token list is done. + */ +void +expmac(struct recur *rp) +{ + struct symtab *nl; + int c, noexp = 0, orgexp; + usch *och, *stksv; + extern int yyleng; + +#ifdef CPP_DEBUG + if (dflag) { + struct recur *rp2 = rp; + printf("\nexpmac\n"); + while (rp2) { + printf("do not expand %s\n", rp->sp->namep); + rp2 = rp2->next; + } + } +#endif + while ((c = yylex()) != WARN) { + switch (c) { + case NOEXP: noexp++; break; + case EXPAND: noexp--; break; + + case IDENT: + /* + * Handle argument concatenation here. + * If an identifier is found and directly + * after EXPAND or NOEXP then push the + * identifier back on the input stream and + * call yylex() again. + * Be careful to keep the noexp balance. + */ + och = stringbuf; + savstr((usch *)yytext); + DDPRINT(("id: str %s\n", och)); + + orgexp = 0; + while ((c = yylex()) == EXPAND || c == NOEXP) + if (c == EXPAND) + orgexp--; + else + orgexp++; + + DDPRINT(("id1: noexp %d orgexp %d\n", noexp, orgexp)); + if (c == IDENT) { /* XXX numbers? */ + DDPRINT(("id2: str %s\n", yytext)); + /* OK to always expand here? */ + savstr((usch *)yytext); + switch (orgexp) { + case 0: /* been EXP+NOEXP */ + if (noexp == 0) + break; + if (noexp != 1) + error("case 0"); + cunput(NOEXP); + noexp = 0; + break; + case -1: /* been EXP */ + if (noexp != 1) + error("case -1"); + noexp = 0; + break; + case 1: + if (noexp != 0) + error("case 1"); + cunput(NOEXP); + break; + default: + error("orgexp = %d", orgexp); + } + unpstr(och); + stringbuf = och; + continue; /* New longer identifier */ + } + unpstr((usch *)yytext); + if (orgexp == -1) + cunput(EXPAND); + else if (orgexp == 1) + cunput(NOEXP); + unpstr(och); + stringbuf = och; + + + yylex(); /* XXX reget last identifier */ + + if ((nl = lookup((usch *)yytext, FIND)) == NULL) + goto def; + + if (canexpand(rp, nl) == 0) + goto def; + /* + * If noexp == 0 then expansion of any macro is + * allowed. If noexp == 1 then expansion of a + * fun-like macro is allowed iff there is an + * EXPAND between the identifier and the '('. + */ + if (noexp == 0) { + if ((c = subst(nl, rp)) == 0) + goto def; + break; + } +//printf("noexp1 %d nl->namep %s\n", noexp, nl->namep); +//if (noexp > 1) goto def; + if (noexp != 1) + error("bad noexp %d", noexp); + stksv = NULL; + if ((c = yylex()) == WSPACE) { + stksv = alloca(yyleng+1); + strcpy((char *)stksv, yytext); + c = yylex(); + } + /* only valid for expansion if fun macro */ + if (c == EXPAND && *nl->value != OBJCT) { + noexp--; + if (subst(nl, rp)) + break; + savstr(nl->namep); + if (stksv) + savstr(stksv); + } else { + unpstr((usch *)yytext); + if (stksv) + unpstr(stksv); + savstr(nl->namep); + } + break; + + case STRING: + /* remove EXPAND/NOEXP from strings */ + if (yytext[1] == NOEXP) { + savch('"'); + och = (usch *)&yytext[2]; + while (*och != EXPAND) + savch(*och++); + savch('"'); + break; + } + /* FALLTHROUGH */ + +def: default: + savstr((usch *)yytext); + break; + } + } + if (noexp) + error("expmac noexp=%d", noexp); + DPRINT(("return from expmac\n")); +} + +/* + * expand a function-like macro. + * vp points to end of replacement-list + * reads function arguments from yylex() + * result is written on top of heap + */ +void +expdef(vp, rp, gotwarn) + usch *vp; + struct recur *rp; +{ + usch **args, *sptr, *ap, *bp, *sp; + int narg, c, i, plev, snuff, instr; + int ellips = 0; + + DPRINT(("expdef %s rp %s\n", vp, (rp ? (char *)rp->sp->namep : ""))); + if ((c = yylex()) != '(') + error("got %c, expected )", c); + if (vp[1] == VARG) { + narg = *vp--; + ellips = 1; + } else + narg = vp[1]; + args = alloca(sizeof(usch *) * (narg+ellips)); + + /* + * read arguments and store them on heap. + * will be removed just before return from this function. + */ + sptr = stringbuf; + for (i = 0; i < narg && c != ')'; i++) { + args[i] = stringbuf; + plev = 0; + while ((c = yylex()) == WSPACE || c == '\n') + ; + for (;;) { + if (plev == 0 && (c == ')' || c == ',')) + break; + if (c == '(') + plev++; + if (c == ')') + plev--; + savstr((usch *)yytext); + while ((c = yylex()) == '\n') + savch('\n'); + } + while (args[i] < stringbuf && + (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')) + stringbuf--; + savch('\0'); + } + if (ellips) + args[i] = (usch *)""; + if (ellips && c != ')') { + args[i] = stringbuf; + plev = 0; + while ((c = yylex()) == WSPACE) + ; + for (;;) { + if (plev == 0 && c == ')') + break; + if (c == '(') + plev++; + if (c == ')') + plev--; + savstr((usch *)yytext); + while ((c = yylex()) == '\n') + savch('\n'); + } + while (args[i] < stringbuf && + (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')) + stringbuf--; + savch('\0'); + + } + if (narg == 0 && ellips == 0) + c = yylex(); + if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1)) + error("wrong arg count"); + + while (gotwarn--) + cunput(WARN); + + sp = vp; + instr = snuff = 0; + + /* + * push-back replacement-list onto lex buffer while replacing + * arguments. + */ + cunput(WARN); + while (*sp != 0) { + if (*sp == SNUFF) + cunput('\"'), snuff ^= 1; + else if (*sp == CONC) + ; + else if (*sp == WARN) { + + if (sp[-1] == VARG) { + bp = ap = args[narg]; + sp--; + } else + bp = ap = args[(int)*--sp]; + if (sp[2] != CONC && !snuff && sp[-1] != CONC) { + cunput(WARN); + while (*bp) + bp++; + while (bp > ap) + cunput(*--bp); + DPRINT(("expand arg %d string %s\n", *sp, ap)); + bp = ap = stringbuf; + savch(NOEXP); + expmac(NULL); + savch(EXPAND); + savch('\0'); + } + while (*bp) + bp++; + while (bp > ap) { + bp--; + if (snuff && !instr && + (*bp == ' ' || *bp == '\t' || *bp == '\n')){ + while (*bp == ' ' || *bp == '\t' || + *bp == '\n') { + bp--; + } + cunput(' '); + } + cunput(*bp); + if ((*bp == '\'' || *bp == '"') + && bp[-1] != '\\' && snuff) { + instr ^= 1; + if (instr == 0 && *bp == '"') + cunput('\\'); + } + if (instr && (*bp == '\\' || *bp == '"')) + cunput('\\'); + } + } else + cunput(*sp); + sp--; + } + stringbuf = sptr; + + /* scan the input buffer (until WARN) and save result on heap */ + expmac(rp); +} + +usch * +savstr(usch *str) +{ + usch *rv = stringbuf; + + do { + if (stringbuf >= &sbf[SBSIZE]) { + stringbuf = sbf; /* need space to write error message */ + error("out of macro space!"); + } + } while ((*stringbuf++ = *str++)); + stringbuf--; + return rv; +} + +int +canexpand(struct recur *rp, struct symtab *np) +{ + struct recur *w; + + for (w = rp; w && w->sp != np; w = w->next) + ; + if (w != NULL) + return 0; + return 1; +} + +void +unpstr(usch *c) +{ + usch *d = c; + + while (*d) + d++; + while (d > c) { + cunput(*--d); + } +} + +void +flbuf() +{ + if (obufp == 0) + return; + if (Mflag == 0 && write(ofd, outbuf, obufp) < 0) + error("obuf write error"); + obufp = 0; +} + +void +putch(int ch) +{ + outbuf[obufp++] = ch; + if (obufp == CPPBUF || (istty && ch == '\n')) + flbuf(); +} + +void +putstr(usch *s) +{ + for (; *s; s++) { + outbuf[obufp++] = *s; + if (obufp == CPPBUF || (istty && *s == '\n')) + flbuf(); + } +} + +/* + * convert a number to an ascii string. Store it on the heap. + */ +static void +num2str(int num) +{ + static usch buf[12]; + usch *b = buf; + int m = 0; + + if (num < 0) + num = -num, m = 1; + do { + *b++ = num % 10 + '0', num /= 10; + } while (num); + if (m) + *b++ = '-'; + while (b > buf) + savch(*--b); +} + +/* + * similar to sprintf, but only handles %s and %d. + * saves result on heap. + */ +usch * +sheap(char *fmt, ...) +{ + va_list ap; + usch *op = stringbuf; + + va_start(ap, fmt); + for (; *fmt; fmt++) { + if (*fmt == '%') { + fmt++; + switch (*fmt) { + case 's': + savstr(va_arg(ap, usch *)); + break; + case 'd': + num2str(va_arg(ap, int)); + break; + case 'c': + savch(va_arg(ap, int)); + break; + default: + break; /* cannot call error() here */ + } + } else + savch(*fmt); + } + va_end(ap); + *stringbuf = 0; + return op; +} + +void +usage() +{ + error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]"); +} + +#ifdef notyet +/* + * Symbol table stuff. + * The data structure used is a patricia tree implementation using only + * bytes to store offsets. + * The information stored is (lower address to higher): + * + * unsigned char bitno[2]; bit number in the string + * unsigned char left[3]; offset from base to left element + * unsigned char right[3]; offset from base to right element + */ +#endif + +/* + * This patricia implementation is more-or-less the same as + * used in ccom for string matching. + */ +struct tree { + int bitno; + struct tree *lr[2]; +}; + +#define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF)) +#define LEFT_IS_LEAF 0x80000000 +#define RIGHT_IS_LEAF 0x40000000 +#define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0) +#define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0) +#define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1 +#define CHECKBITS 8 + +static struct tree *sympole; +static int numsyms; + +#define getree() malloc(sizeof(struct tree)) + +/* + * Allocate a symtab struct and store the string. + */ +static struct symtab * +getsymtab(usch *str) +{ + struct symtab *sp = malloc(sizeof(struct symtab)); + + sp->namep = savstr(str), savch('\0'); + sp->value = NULL; + sp->file = ifiles ? ifiles->orgfn : (usch *)"<initial>"; + sp->line = ifiles ? ifiles->lineno : 0; + return sp; +} + +/* + * Do symbol lookup in a patricia tree. + * Only do full string matching, no pointer optimisations. + */ +struct symtab * +lookup(usch *key, int enterf) +{ + struct symtab *sp; + struct tree *w, *new, *last; + int len, cix, bit, fbit, svbit, ix, bitno; + usch *k, *m, *sm; + + /* Count full string length */ + for (k = key, len = 0; *k; k++, len++) + ; + + switch (numsyms) { + case 0: /* no symbols yet */ + if (enterf != ENTER) + return NULL; + sympole = (struct tree *)getsymtab(key); + numsyms++; + return (struct symtab *)sympole; + + case 1: + w = sympole; + svbit = 0; /* XXX gcc */ + break; + + default: + w = sympole; + bitno = len * CHECKBITS; + for (;;) { + bit = BITNO(w->bitno); + fbit = bit > bitno ? 0 : P_BIT(key, bit); + svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : + IS_LEFT_LEAF(w->bitno); + w = w->lr[fbit]; + if (svbit) + break; + } + } + + sp = (struct symtab *)w; + + sm = m = sp->namep; + k = key; + + /* Check for correct string and return */ + for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS) + ; + if (*m == 0 && *k == 0) { + if (enterf != ENTER && sp->value == NULL) + return NULL; + return sp; + } + + if (enterf != ENTER) + return NULL; /* no string found and do not enter */ + + ix = *m ^ *k; + while ((ix & 1) == 0) + ix >>= 1, cix++; + + /* Create new node */ + new = getree(); + bit = P_BIT(key, cix); + new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + new->lr[bit] = (struct tree *)getsymtab(key); + + if (numsyms++ == 1) { + new->lr[!bit] = sympole; + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + sympole = new; + return (struct symtab *)new->lr[bit]; + } + + w = sympole; + last = NULL; + for (;;) { + fbit = w->bitno; + bitno = BITNO(w->bitno); + if (bitno == cix) + error("bitno == cix"); + if (bitno > cix) + break; + svbit = P_BIT(key, bitno); + last = w; + w = w->lr[svbit]; + if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) + break; + } + + new->lr[!bit] = w; + if (last == NULL) { + sympole = new; + } else { + last->lr[svbit] = new; + last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + } + if (bitno < cix) + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + return (struct symtab *)new->lr[bit]; +} + diff --git a/usr.bin/pcc/cc/cpp/cpp.h b/usr.bin/pcc/cc/cpp/cpp.h new file mode 100644 index 00000000000..ad57e9d3cd8 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/cpp.h @@ -0,0 +1,120 @@ +/* $Id: cpp.h,v 1.1 2007/09/15 18:12:32 otto Exp $ */ + +/* + * Copyright (c) 2004 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 <stdio.h> /* for obuf */ + +#include "../../config.h" + +typedef unsigned char usch; +#ifdef YYTEXT_POINTER +extern char *yytext; +#else +extern char yytext[]; +#endif +extern usch *stringbuf; + +extern int trulvl; +extern int flslvl; +extern int elflvl; +extern int elslvl; +extern int tflag, Cflag; +extern int Mflag; +extern usch *Mfile; +extern int ofd; + +/* args for lookup() */ +#define FIND 0 +#define ENTER 1 + +/* buffer used internally */ +#ifndef CPPBUF +#ifdef __pdp11__ +#define CPPBUF BUFSIZ +#else +#define CPPBUF 65536 +#endif +#endif + +#define NAMEMAX 64 /* max len of identifier */ + +/* definition for include file info */ +struct includ { + struct includ *next; + usch *fname; /* current fn, changed if #line found */ + usch *orgfn; /* current fn, not changed */ + int lineno; + int infil; + usch *curptr; + usch *maxread; + usch *buffer; + usch bbuf[NAMEMAX+CPPBUF+1]; +} *ifiles; + +/* Symbol table entry */ +struct symtab { + usch *namep; + usch *value; + usch *file; + int line; +}; + +struct initar { + struct initar *next; + int type; + char *str; +}; + +struct recur; /* not used outside cpp.c */ +int subst(struct symtab *, struct recur *); +struct symtab *lookup(usch *namep, int enterf); +usch *gotident(struct symtab *nl); +int slow; /* scan slowly for new tokens */ + +int pushfile(usch *fname); +void popfile(void); +void prtline(void); +int yylex(void); +void cunput(int); +int curline(void); +char *curfile(void); +void setline(int); +void setfile(char *); +int yyparse(void); +void yyerror(char *); +void unpstr(usch *); +usch *savstr(usch *str); +void savch(int c); +void mainscan(void); +void putch(int); +void putstr(usch *s); +void line(void); +usch *sheap(char *fmt, ...); +void xerror(usch *); +#define error(...) xerror(sheap(__VA_ARGS__)) +void expmac(struct recur *); diff --git a/usr.bin/pcc/cc/cpp/cpy.y b/usr.bin/pcc/cc/cpp/cpy.y new file mode 100644 index 00000000000..2f39c920306 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/cpy.y @@ -0,0 +1,166 @@ +/* $Id: cpy.y,v 1.1 2007/09/15 18:12:32 otto Exp $ */ + +/* + * Copyright (c) 2004 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. + */ + +/* + * 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 conditions and 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 <stdlib.h> +#include <string.h> +#include <ctype.h> +void yyerror(char *); +int yylex(void); +%} + +%term stop +%term EQ NE LE GE LS RS +%term ANDAND OROR IDENT NUMBER +/* + * The following terminals are not used in the yacc code. + */ +%term STRING FPOINT WSPACE VA_ARGS CONCAT MKSTR ELLIPS + +%left ',' +%right '=' +%right '?' ':' +%left OROR +%left ANDAND +%left '|' '^' +%left '&' +%binary EQ NE +%binary '<' '>' LE GE +%left LS RS +%left '+' '-' +%left '*' '/' '%' +%right '!' '~' UMINUS +%left '(' '.' + +%union { + long long val; +} + +%type <val> term NUMBER e + +%% +S: e '\n' { return($1 != 0);} + + +e: e '*' e + {$$ = $1 * $3;} + | e '/' e + {$$ = $1 / $3;} + | e '%' e + {$$ = $1 % $3;} + | e '+' e + {$$ = $1 + $3;} + | e '-' e + {$$ = $1 - $3;} + | e LS e + {$$ = $1 << $3;} + | e RS e + {$$ = $1 >> $3;} + | e '<' e + {$$ = $1 < $3;} + | e '>' e + {$$ = $1 > $3;} + | e LE e + {$$ = $1 <= $3;} + | e GE e + {$$ = $1 >= $3;} + | e EQ e + {$$ = $1 == $3;} + | e NE e + {$$ = $1 != $3;} + | e '&' e + {$$ = $1 & $3;} + | e '^' e + {$$ = $1 ^ $3;} + | e '|' e + {$$ = $1 | $3;} + | e ANDAND e + {$$ = $1 && $3;} + | e OROR e + {$$ = $1 || $3;} + | e '?' e ':' e + {$$ = $1 ? $3 : $5;} + | e ',' e + {$$ = $3;} + | term + {$$ = $1;} +term: + '-' term %prec UMINUS + {$$ = -$2;} + | '!' term + {$$ = !$2;} + | '~' term + {$$ = ~$2;} + | '(' e ')' + {$$ = $2;} + | NUMBER + {$$= $1;} +%% + +#include "cpp.h" + +void +yyerror(char *err) +{ + error(err); +} diff --git a/usr.bin/pcc/cc/cpp/scanner.l b/usr.bin/pcc/cc/cpp/scanner.l new file mode 100644 index 00000000000..87d4a5285af --- /dev/null +++ b/usr.bin/pcc/cc/cpp/scanner.l @@ -0,0 +1,808 @@ +%{ +/* $Id: scanner.l,v 1.1 2007/09/15 18:12:32 otto Exp $ */ + +/* + * Copyright (c) 2004 Anders Magnusson. 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 <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <fcntl.h> + +#include "cpp.h" +#include "y.tab.h" +%} + +%{ +static long long cvtdig(int rad); +static int charcon(void); +static void elsestmt(void); +static void ifdefstmt(void); +static void ifndefstmt(void); +static void endifstmt(void); +static void ifstmt(void); +static void cpperror(void); +static void pragmastmt(void); +static void undefstmt(void); +static void cpperror(void); +static void elifstmt(void); +//static void linestmt(void); +static void storepb(void); +void include(void); +void define(void); + +static int inch(void); + +static int scale, gotdef, contr; +int inif; + +#ifdef FLEX_SCANNER /* should be set by autoconf instead */ +static int +yyinput(char *b, int m) +{ + int c, i; + + for (i = 0; i < m; i++) { + if ((c = inch()) < 0) + break; + *b++ = c; + if (c == '\n') { + i++; + break; + } + } + return i; +} +#undef YY_INPUT +#undef YY_BUF_SIZE +#define YY_BUF_SIZE 32768 +#define YY_INPUT(b,r,m) (r = yyinput(b, m)) +#define fprintf(x, ...) error(__VA_ARGS__) +#define ECHO putstr((usch *)yytext) +#undef fileno +#define fileno(x) 0 + +#if YY_FLEX_SUBMINOR_VERSION >= 31 +/* Hack to avoid unneccessary warnings */ +FILE *yyget_in (void); +FILE *yyget_out (void); +int yyget_leng (void); +char *yyget_text (void); +void yyset_in (FILE * in_str ); +void yyset_out (FILE * out_str ); +int yyget_debug (void); +void yyset_debug (int bdebug ); +int yylex_destroy (void); +#endif +#else /* Assume lex here */ +#undef input +#undef unput +#define input() inch() +#define unput(ch) unch(ch) +#endif +#define PRTOUT(x) if (YYSTATE || slow) return x; if (!flslvl) putstr((usch *)yytext); +%} + +D [0-9] +L [a-zA-Z_] +H [a-fA-F0-9] +E [Ee][+-]?{D}+ +FS (f|F|l|L) +IS (u|U|l|L)* +WS [\t ] + +%s IFR CONTR DEF + +%% + +"\n" { int os = YYSTATE; + if (os != IFR) + BEGIN 0; + ifiles->lineno++; + if (flslvl == 0) { + if (ifiles->lineno == 1) + prtline(); + else + putch('\n'); + } + if ((os != 0 || slow) && !contr) + return '\n'; + contr = 0; + } + +"\r" { ; /* Ignore CR's */ } + +<IFR>"==" { return EQ; } +<IFR>"!=" { return NE; } +<IFR>"<=" { return LE; } +<IFR>"<<" { return LS; } +<IFR>">>" { return RS; } +<IFR>">=" { return GE; } +<IFR>"||" { return OROR; } +<IFR>"&&" { return ANDAND; } +<IFR>"defined" { int p, c; + gotdef = 1; + if ((p = c = yylex()) == '(') + c = yylex(); + if (c != IDENT || (p != IDENT && p != '(')) + error("syntax error"); + if (p == '(' && yylex() != ')') + error("syntax error"); + return NUMBER; + } + +<IFR>{WS}+ { ; } +<IFR>{L}({L}|{D})* { + if (gotdef) { + yylval.val = + lookup((usch *)yytext, FIND) != 0; + gotdef = 0; + return IDENT; + } + yylval.val = 0; + return NUMBER; + } + +[1-9][0-9]* { if (slow && !YYSTATE) return IDENT; scale = 10; goto num; } + +0[xX]{H}+{IS}? { scale = 16; + num: if (YYSTATE) + yylval.val = cvtdig(scale); + PRTOUT(NUMBER); + } +0{D}+{IS}? { scale = 8; goto num; } +{D}+{IS}? { scale = 10; goto num; } +L?'(\\.|[^\\'])+' { if (YYSTATE) + yylval.val = charcon(); + PRTOUT(NUMBER); + } + +<IFR>. { return yytext[0]; } + +{D}+{E}{FS}? { PRTOUT(FPOINT); } +{D}*"."{D}+({E})?{FS}? { PRTOUT(FPOINT); } +{D}+"."{D}*({E})?{FS}? { PRTOUT(FPOINT); } + +^{WS}*#{WS}* { contr = 1; BEGIN CONTR; } +{WS}+ { PRTOUT(WSPACE); } + +<CONTR>"ifndef" { contr = 0; ifndefstmt(); } +<CONTR>"ifdef" { contr = 0; ifdefstmt(); } +<CONTR>"if"{WS}+ { contr = 0; storepb(); BEGIN IFR; ifstmt(); BEGIN 0; } +<CONTR>"include" { contr = 0; BEGIN 0; include(); prtline(); } +<CONTR>"else" { contr = 0; elsestmt(); } +<CONTR>"endif" { contr = 0; endifstmt(); } +<CONTR>"error" { contr = 0; if (slow) return IDENT; cpperror(); BEGIN 0; } +<CONTR>"define" { contr = 0; BEGIN DEF; define(); BEGIN 0; } +<CONTR>"undef" { contr = 0; if (slow) return IDENT; undefstmt(); } +<CONTR>"line" { contr = 0; storepb(); BEGIN 0; line(); } +<CONTR>"pragma" { contr = 0; pragmastmt(); } +<CONTR>"elif"{WS}+ { contr = 0; storepb(); BEGIN IFR; elifstmt(); BEGIN 0; } + + + +"//".*$ { /* if (tflag) yyless(..) */ + if (Cflag) + putstr((usch *)yytext); + else if (!flslvl) + putch(' '); + } +"/*" { int c, wrn; + if (Cflag) + putstr((usch *)yytext); + wrn = 0; + more: while ((c = input()) && c != '*') { + if (c == '\n') + putch(c), ifiles->lineno++; + else if (c == 1) /* WARN */ + wrn = 1; + else if (Cflag) + putch(c); + } + if (c == 0) + return 0; + if (Cflag) + putch(c); + if ((c = input()) && c != '/') { + if (Cflag) + putch('*'); + unput(c); + goto more; + } + if (Cflag) + putch(c); + if (c == 0) + return 0; + if (!tflag && !Cflag && !flslvl) + unput(' '); + if (wrn) + unput(1); + } + +<DEF>"##" { return CONCAT; } +<DEF>"#" { return MKSTR; } +<DEF>"..." { return ELLIPS; } +<DEF>"__VA_ARGS__" { return VA_ARGS; } + +L?\"(\\.|[^\\"])*\" { PRTOUT(STRING); } +[a-zA-Z_0-9]+ { /* {L}({L}|{D})* */ + struct symtab *nl; + if (slow) + return IDENT; + if (YYSTATE == CONTR) { + if (flslvl == 0) { + /*error("undefined control");*/ + while (input() != '\n') + ; + unput('\n'); + BEGIN 0; + goto xx; + } else { + BEGIN 0; /* do nothing */ + } + } + if (flslvl) { + ; /* do nothing */ + } else if (isdigit((int)yytext[0]) == 0 && + (nl = lookup((usch *)yytext, FIND)) != 0) { + usch *op = stringbuf; + putstr(gotident(nl)); + stringbuf = op; + } else + putstr((usch *)yytext); + xx: ; + } + +. { PRTOUT(yytext[0]); } + +%% + +usch *yyp, yybuf[CPPBUF]; + +int yylex(void); +int yywrap(void); + +static int +inpch(void) +{ + int len; + + if (ifiles->curptr < ifiles->maxread) + return *ifiles->curptr++; + + if ((len = read(ifiles->infil, ifiles->buffer, CPPBUF)) < 0) + error("read error on file %s", ifiles->orgfn); + if (len == 0) + return -1; + ifiles->curptr = ifiles->buffer; + ifiles->maxread = ifiles->buffer + len; + return inpch(); +} + +#define unch(c) *--ifiles->curptr = c + +static int +inch(void) +{ + int c; + +again: switch (c = inpch()) { + case '\\': /* continued lines */ + if ((c = inpch()) == '\n') { + ifiles->lineno++; + putch('\n'); + goto again; + } + unch(c); + return '\\'; + case '?': /* trigraphs */ + if ((c = inpch()) != '?') { + unch(c); + return '?'; + } + switch (c = inpch()) { + case '=': c = '#'; break; + case '(': c = '['; break; + case ')': c = ']'; break; + case '<': c = '{'; break; + case '>': c = '}'; break; + case '/': c = '\\'; break; + case '\'': c = '^'; break; + case '!': c = '|'; break; + case '-': c = '~'; break; + default: + unch(c); + unch('?'); + return '?'; + } + unch(c); + goto again; + default: + return c; + } +} + +/* + * Let the command-line args be faked defines at beginning of file. + */ +static void +prinit(struct initar *it, struct includ *ic) +{ + char *a, *pre, *post; + + if (it->next) + prinit(it->next, ic); + pre = post = NULL; /* XXX gcc */ + switch (it->type) { + case 'D': + pre = "#define "; + if ((a = strchr(it->str, '=')) != NULL) { + *a = ' '; + post = "\n"; + } else + post = " 1\n"; + break; + case 'U': + pre = "#undef "; + post = "\n"; + break; + case 'i': + pre = "#include \""; + post = "\"\n"; + break; + } + strcat((char *)ic->buffer, pre); + strcat((char *)ic->buffer, it->str); + strcat((char *)ic->buffer, post); + ic->lineno--; + while (*ic->maxread) + ic->maxread++; +} + +/* + * A new file included. + * If ifiles == NULL, this is the first file and already opened (stdin). + * Return 0 on success, -1 on failure to open file. + */ +int +pushfile(usch *file) +{ + extern struct initar *initar; + struct includ ibuf; + struct includ *old; + struct includ *ic; + int c, otrulvl; + + ic = &ibuf; + old = ifiles; + + slow = 0; + if (file != NULL) { + if ((ic->infil = open((char *)file, O_RDONLY)) < 0) + return -1; + ic->orgfn = ic->fname = file; + } else { + ic->infil = 0; + ic->orgfn = ic->fname = (usch *)"<stdin>"; + } + ic->buffer = ic->bbuf+NAMEMAX; + ic->curptr = ic->buffer; + ifiles = ic; + ic->lineno = 1; + ic->maxread = ic->curptr; + prtline(); + if (initar) { + *ic->maxread = 0; + prinit(initar, ic); + initar = NULL; + } +#if 0 + if (old == NULL && ifile != NULL) { + strcpy((char *)ic->buffer, "#include \""); + strcat((char *)ic->buffer, ifile); + strcat((char *)ic->buffer, "\"\n"); + while (*ic->maxread) + ic->maxread++; + ic->lineno = 0; + ifile = NULL; + } +#endif + + otrulvl = trulvl; + + if ((c = yylex()) != 0) + error("yylex returned %d", c); + + if (otrulvl != trulvl || flslvl) + error("unterminated conditional"); + + ifiles = old; + close(ic->infil); + return 0; +} + +/* + * Print current position to output file. + */ +void +prtline() +{ + usch *s, *os = stringbuf; + + if (Mflag) { + if (ifiles->lineno == 1) { + s = sheap("%s: %s\n", Mfile, ifiles->fname); + write(ofd, s, strlen((char *)s)); + } + } else + putstr(sheap("# %d \"%s\"\n", ifiles->lineno, ifiles->fname)); + stringbuf = os; +} + +void +cunput(int c) +{ +#ifdef CPP_DEBUG + extern int dflag; + if (dflag)printf(": '%c'(%d)", c, c); +#endif + unput(c); +} + +int yywrap(void) { return 1; } + +static int +dig2num(int c) +{ + if (c >= 'a') + c = c - 'a' + 10; + else if (c >= 'A') + c = c - 'A' + 10; + else + c = c - '0'; + return c; +} + +/* + * Convert some string numbers to long long. + * Do not care about UL trailers, should we? + */ +static long long +cvtdig(int rad) +{ + long long rv = 0; + char *y = yytext; + int c; + + c = *y++; + if (rad == 16) + y++; + while (isxdigit(c)) { + rv = rv * rad + dig2num(c); + c = *y++; + } + return rv; +} + +static int +charcon(void) +{ + usch *p = (usch *)yytext; + int val, c; + + if (*p == 'L') + p++; + p++; /* first ' */ + val = 0; + if (*p++ == '\\') { + switch (*p++) { + case 'a': val = '\a'; break; + case 'b': val = '\b'; break; + case 'f': val = '\f'; break; + case 'n': val = '\n'; break; + case 'r': val = '\r'; break; + case 't': val = '\t'; break; + case 'v': val = '\v'; break; + case '\"': val = '\"'; break; + case '\'': val = '\''; break; + case '\\': val = '\\'; break; + case 'x': + while (isxdigit(c = *p)) { + val = val * 16 + dig2num(c); + p++; + } + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + p--; + while (isdigit(c = *p)) { + val = val * 8 + (c - '0'); + p++; + } + break; + default: val = p[-1]; + } + + } else + val = p[-1]; + return val; +} + +static void +chknl(void) +{ + int t; + + while ((t = yylex()) == WSPACE) + ; + if (t != '\n') + error("newline expected, got %d", t); +} + +static void +elsestmt(void) +{ + if (flslvl) { + if (elflvl > trulvl) + ; + else if (--flslvl!=0) { + flslvl++; + } else { + trulvl++; + prtline(); + } + } else if (trulvl) { + flslvl++; + trulvl--; + } else + error("If-less else"); + if (elslvl==trulvl+flslvl) + error("Too many else"); + elslvl=trulvl+flslvl; + chknl(); +} + +static void +ifdefstmt(void) +{ + if (flslvl) { + /* just ignore the rest of the line */ + while (input() != '\n') + ; + unput('\n'); + yylex(); + flslvl++; + return; + } + slow = 1; + if (yylex() != WSPACE || yylex() != IDENT) + error("bad ifdef"); + slow = 0; + if (flslvl == 0 && lookup((usch *)yytext, FIND) != 0) + trulvl++; + else + flslvl++; + chknl(); +} + +static void +ifndefstmt(void) +{ + slow = 1; + if (yylex() != WSPACE || yylex() != IDENT) + error("bad ifndef"); + slow = 0; + if (flslvl == 0 && lookup((usch *)yytext, FIND) == 0) + trulvl++; + else + flslvl++; + chknl(); +} + +static void +endifstmt(void) +{ + if (flslvl) { + flslvl--; + if (flslvl == 0) + prtline(); + } else if (trulvl) + trulvl--; + else + error("If-less endif"); + if (flslvl == 0) + elflvl = 0; + elslvl = 0; + chknl(); +} + +/* + * Note! Ugly! + * Walk over the string s and search for defined, and replace it with + * spaces and a 1 or 0. + */ +static void +fixdefined(usch *s) +{ + usch *bc, oc; + + for (; *s; s++) { + if (*s != 'd') + continue; + if (memcmp(s, "defined", 7)) + continue; + /* Ok, got defined, can scratch it now */ + memset(s, ' ', 7); + s += 7; +#define WSARG(x) (x == ' ' || x == '\t') + if (*s != '(' && !WSARG(*s)) + continue; + while (WSARG(*s)) + s++; + if (*s == '(') + s++; + while (WSARG(*s)) + s++; +#define IDARG(x) ((x>= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z') || (x == '_')) +#define NUMARG(x) (x >= '0' && x <= '9') + if (!IDARG(*s)) + error("bad defined arg"); + bc = s; + while (IDARG(*s) || NUMARG(*s)) + s++; + oc = *s; + *s = 0; + *bc = (lookup(bc, FIND) != 0) + '0'; + memset(bc+1, ' ', s-bc-1); + *s = oc; + } +} + +/* + * get the full line of identifiers after an #if, pushback a WARN and + * the line and prepare for expmac() to expand. + * This is done before switching state. When expmac is finished, + * pushback the expanded line, change state and call yyparse. + */ +static void +storepb(void) +{ + usch *opb = stringbuf; + int c; + + while ((c = input()) != '\n') + savch(c); + cunput('\n'); + savch(0); + fixdefined(opb); /* XXX can fail if #line? */ + cunput(1); /* WARN XXX */ + unpstr(opb); + stringbuf = opb; + slow = 1; + expmac(NULL); + slow = 0; + /* line now expanded */ + while (stringbuf > opb) + cunput(*--stringbuf); +} + +static void +ifstmt(void) +{ + if (flslvl == 0) { + slow = 1; + if (yyparse()) + ++trulvl; + else + ++flslvl; + slow = 0; + } else + ++flslvl; +} + +static void +elifstmt(void) +{ + if (flslvl == 0) + elflvl = trulvl; + if (flslvl) { + if (elflvl > trulvl) + ; + else if (--flslvl!=0) + ++flslvl; + else { + slow = 1; + if (yyparse()) { + ++trulvl; + prtline(); + } else + ++flslvl; + slow = 0; + } + } else if (trulvl) { + ++flslvl; + --trulvl; + } else + error("If-less elif"); +} + +static usch * +svinp(void) +{ + int c; + usch *cp = stringbuf; + + while ((c = input()) && c != '\n') + savch(c); + savch('\n'); + savch(0); + BEGIN 0; + return cp; +} + +static void +cpperror(void) +{ + usch *cp; + int c; + + if (flslvl) + return; + c = yylex(); + if (c != WSPACE && c != '\n') + error("bad error"); + cp = svinp(); + if (flslvl) + stringbuf = cp; + else + error("error: %s", cp); +} + +static void +undefstmt(void) +{ + struct symtab *np; + + slow = 1; + if (yylex() != WSPACE || yylex() != IDENT) + error("bad undef"); + if (flslvl == 0 && (np = lookup((usch *)yytext, FIND))) + np->value = 0; + slow = 0; + chknl(); +} + +static void +pragmastmt(void) +{ + slow = 1; + if (yylex() != WSPACE) + error("bad pragma"); + while (yylex() != '\n') /* no pragma support */ + ; + slow = 0; +} diff --git a/usr.bin/pcc/cc/cpp/tests/res1 b/usr.bin/pcc/cc/cpp/tests/res1 new file mode 100644 index 00000000000..c0bb48019f3 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/res1 @@ -0,0 +1,7 @@ +# 1 "<stdin>" + + + + +char p[] = "x ## y"; + diff --git a/usr.bin/pcc/cc/cpp/tests/res2 b/usr.bin/pcc/cc/cpp/tests/res2 new file mode 100644 index 00000000000..1eb808aac47 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/res2 @@ -0,0 +1,26 @@ +# 1 "<stdin>" + + + + + + + + + + + + + + +f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t (1); +f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & +f(2 * (0,1))^m (0,1); +int i[] = { 1, 23, 4, 5, }; +char c[2][6] = { "hello", "" }; + + + + + + diff --git a/usr.bin/pcc/cc/cpp/tests/res3 b/usr.bin/pcc/cc/cpp/tests/res3 new file mode 100644 index 00000000000..4219319ddff --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/res3 @@ -0,0 +1,16 @@ +# 1 "<stdin>" + + + + + + + + + +printf("x" "1" "= %d, x" "2" "= %s", x1, x2); +fputs( +"strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s); +\#include "vers2.h" +"hello"; +"hello" ", world" diff --git a/usr.bin/pcc/cc/cpp/tests/res4 b/usr.bin/pcc/cc/cpp/tests/res4 new file mode 100644 index 00000000000..d7046a01507 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/res4 @@ -0,0 +1,5 @@ +# 1 "<stdin>" + + + +(1) diff --git a/usr.bin/pcc/cc/cpp/tests/res5 b/usr.bin/pcc/cc/cpp/tests/res5 new file mode 100644 index 00000000000..291405dcfee --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/res5 @@ -0,0 +1,4 @@ +# 1 "<stdin>" + +int j[] = { 123, 45, 67, 89, + 10, 11, 12, }; diff --git a/usr.bin/pcc/cc/cpp/tests/res6 b/usr.bin/pcc/cc/cpp/tests/res6 new file mode 100644 index 00000000000..0bb0f9a1dbf --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/res6 @@ -0,0 +1,6 @@ +# 1 "<stdin>" + + + + +foo diff --git a/usr.bin/pcc/cc/cpp/tests/res7 b/usr.bin/pcc/cc/cpp/tests/res7 new file mode 100644 index 00000000000..18c492bda72 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/res7 @@ -0,0 +1,5 @@ +# 1 "<stdin>" + + + +a YES diff --git a/usr.bin/pcc/cc/cpp/tests/res8 b/usr.bin/pcc/cc/cpp/tests/res8 new file mode 100644 index 00000000000..e7de0945f47 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/res8 @@ -0,0 +1,8 @@ +# 1 "<stdin>" + + + + + +(hej.s_s.s_pos) + diff --git a/usr.bin/pcc/cc/cpp/tests/res9 b/usr.bin/pcc/cc/cpp/tests/res9 new file mode 100644 index 00000000000..aea239fc9aa --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/res9 @@ -0,0 +1,5 @@ +# 1 "<stdin>" + + + +ao diff --git a/usr.bin/pcc/cc/cpp/tests/test1 b/usr.bin/pcc/cc/cpp/tests/test1 new file mode 100644 index 00000000000..79a3c5dc5d4 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/test1 @@ -0,0 +1,6 @@ +#define hash_hash # ## # +#define mkstr(a) # a +#define in_between(a) mkstr(a) +#define join(c, d) in_between(c hash_hash d) +char p[] = join(x, y); // equivalent to + // char p[] = "x ## y"; diff --git a/usr.bin/pcc/cc/cpp/tests/test2 b/usr.bin/pcc/cc/cpp/tests/test2 new file mode 100644 index 00000000000..283d4fbc1f0 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/test2 @@ -0,0 +1,25 @@ +#define x 3 +#define f(a) f(x * (a)) +#undef x +#define x 2 +#define g f +#define z z[0] +#define h g(~ +#define m(a) a(w) +#define w 0,1 +#define t(a) a +#define p() int +#define q(x) x +#define r(x,y) x ## y +#define str(x) # x +f(y+1) + f(f(z)) % t(t(g)(0) + t)(1); +g(x+(3,4)-w) | h 5) & m +(f)^m(m); +p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) }; +char c[2][6] = { str(hello), str() }; +/* + * f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); + * f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); + * int i[] = { 1, 23, 4, 5, }; + * char c[2][6] = { "hello", "" }; + */ diff --git a/usr.bin/pcc/cc/cpp/tests/test3 b/usr.bin/pcc/cc/cpp/tests/test3 new file mode 100644 index 00000000000..a659245ecbc --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/test3 @@ -0,0 +1,15 @@ +#define str(s) # s +#define xstr(s) str(s) +#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \ + x ## s, x ## t) +#define INCFILE(n) vers ## n +#define glue(a, b) a ## b +#define xglue(a, b) glue(a, b) +#define HIGHLOW "hello" +#define LOW LOW ", world" +debug(1, 2); +fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away + == 0) str(: @\n), s); +\#include xstr(INCFILE(2).h) +glue(HIGH, LOW); +xglue(HIGH, LOW) diff --git a/usr.bin/pcc/cc/cpp/tests/test4 b/usr.bin/pcc/cc/cpp/tests/test4 new file mode 100644 index 00000000000..0068f3751b8 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/test4 @@ -0,0 +1,4 @@ +#define foobar 1 +#define C(x,y) x##y +#define D(x) (C(x,bar)) +D(foo) diff --git a/usr.bin/pcc/cc/cpp/tests/test5 b/usr.bin/pcc/cc/cpp/tests/test5 new file mode 100644 index 00000000000..3ca0bb6c9c0 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/test5 @@ -0,0 +1,3 @@ +#define t(x,y,z) x ## y ## z +int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), + t(10,,), t(,11,), t(,,12), t(,,) }; diff --git a/usr.bin/pcc/cc/cpp/tests/test6 b/usr.bin/pcc/cc/cpp/tests/test6 new file mode 100644 index 00000000000..28cfddece68 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/test6 @@ -0,0 +1,5 @@ +#define X(a,b, \ + c,d) \ + foo + +X(1,2,3,4) diff --git a/usr.bin/pcc/cc/cpp/tests/test7 b/usr.bin/pcc/cc/cpp/tests/test7 new file mode 100644 index 00000000000..b22b22bbcc9 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/test7 @@ -0,0 +1,4 @@ +#define a() YES +#define b() a +b() +b()() diff --git a/usr.bin/pcc/cc/cpp/tests/test8 b/usr.bin/pcc/cc/cpp/tests/test8 new file mode 100644 index 00000000000..c5d2f9a1449 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/test8 @@ -0,0 +1,7 @@ +// test macro expansion in arguments +#define s_pos s_s.s_pos +#define foo(x) (x) + +//hej.s_pos +foo(hej.s_pos) + diff --git a/usr.bin/pcc/cc/cpp/tests/test9 b/usr.bin/pcc/cc/cpp/tests/test9 new file mode 100644 index 00000000000..4d4368d5663 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/tests/test9 @@ -0,0 +1,4 @@ +#define C(a,b,c) a##b##c +#define N(x,y) C(x,_,y) +#define A_O ao +N(A,O) diff --git a/usr.bin/pcc/cc/cpp/token.c b/usr.bin/pcc/cc/cpp/token.c new file mode 100644 index 00000000000..3f18f754cb5 --- /dev/null +++ b/usr.bin/pcc/cc/cpp/token.c @@ -0,0 +1,495 @@ +/* $Id: token.c,v 1.1 2007/09/15 18:12:32 otto Exp $ */ + +/* + * Copyright (c) 2004 Anders Magnusson. 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 <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <fcntl.h> + +#include "cpp.h" + +/* definition for include file info */ +struct includ { + struct includ *next; + char *fname; + int lineno; + int infil; + usch *curptr; + usch *maxread; + usch *ostr; + usch *buffer; + usch bbuf[NAMEMAX+CPPBUF+1]; +} *ifiles; + +usch *yyp, *yystr, yybuf[CPPBUF]; + +int yylex(void); +int yywrap(void); + +static struct includ * +getbuf(usch *file) +{ + struct includ *ic; + usch *ostr = stringbuf; + + stringbuf = (usch *)ROUND((int)stringbuf); + ic = (struct includ *)stringbuf; + stringbuf += sizeof(struct includ); + ic->ostr = ostr; + + return ic; +} + +static void +putbuf(struct includ *ic) +{ +if (stringbuf < (usch *)&ic[1]) +; +else + stringbuf = ic->ostr; +} + +static int +input(void) +{ + struct includ *ic; + int len; + + if (ifiles->curptr < ifiles->maxread) + return *ifiles->curptr++; + + if (ifiles->infil < 0) { + ic = ifiles; + ifiles = ifiles->next; + putbuf(ic); + return input(); + } + if ((len = read(ifiles->infil, ifiles->buffer, CPPBUF)) < 0) + error("read error on file %s", ifiles->fname); + if (len == 0) + return -1; + ifiles->curptr = ifiles->buffer; + ifiles->maxread = ifiles->buffer + len; + return input(); +} + +static void +unput(int c) +{ + struct includ *ic; + + if (ifiles->curptr > ifiles->bbuf) { + *--ifiles->curptr = c; + } else { + ic = getbuf(NULL); + ic->fname = ifiles->fname; + ic->lineno = ifiles->lineno; + ic->infil = -1; + ic->curptr = &ic->bbuf[NAMEMAX+CPPBUF+1]; + ic->maxread = ic->curptr; + ic->next = ifiles; + ifiles = ic; + *--ifiles->curptr = c; + } +} + +#define UNPUT(c) *--ifiles->curptr = c + +static int +slofgetc(void) +{ + int c; + +again: switch (c = input()) { + case '\\': /* continued lines */ + if ((c = input()) == '\n') { + ifiles->lineno++; + putc('\n', obuf); + goto again; + } + cunput(c); + return '\\'; + case '?': /* trigraphs */ + if ((c = input()) != '?') { + cunput(c); + return '?'; + } + switch (c = input()) { + case '=': c = '#'; break; + case '(': c = '['; break; + case ')': c = ']'; break; + case '<': c = '{'; break; + case '>': c = '}'; break; + case '/': c = '\\'; break; + case '\'': c = '^'; break; + case '!': c = '|'; break; + case '-': c = '~'; break; + default: + cunput(c); + cunput('?'); + return '?'; + } + cunput(c); + goto again; + default: + return c; + } +} + +int +yylex() +{ + static int wasnl = 1; + int c, oc, rval; + +fast: yystr = yybuf; + yyp = yystr; + c = input(); + if (c != ' ' && c != '\t' && c != '#') + wasnl = 0; +#define ONEMORE() { *yyp++ = c; c = slofgetc(); } +again: switch (c) { + case -1: + rval = 0; + break; + + case '\'': /* charcon */ + case '"': /* string */ +chstr: oc = c; + if (slow == 0) { + do { + putch(c); + if (c == '\\') + putch(slofgetc()); + } while ((c = slofgetc()) != EOF && c != oc); + if (c == oc) + putch(c); + goto fast; + } else { + do { + *yyp++ = c; + if (c == '\\') + *yyp++ = slofgetc(); + } while ((c = slofgetc()) != EOF && c != oc); + *yyp++ = c; *yyp = 0; + } + rval = oc == '"' ? STRING : CHARCON; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + *yyp++ = c; + c = slofgetc(); + if (yyp[-1] == '0' && (c == 'x' || c == 'X')) { + do { + ONEMORE(); + } while (isxdigit(c)); + } else { + while (isdigit(c)) + ONEMORE(); + } + if (c != '.' && c != 'e' && c != 'E') { + /* not floating point number */ + while (c == 'l' || c == 'L' || c == 'u' || c == 'U') { + ONEMORE(); + } + cunput(c); + *yyp = 0; + rval = NUMBER; + break; + } + /* it's a floating point number here */ + if (c == '.') { /* decimal point */ +F: do { /* may be followed by digits */ + ONEMORE(); + } while (isdigit(c)); + if (c == 'e' || c == 'E') { +E: ONEMORE(); + if (c == '-' || c == '+') { + ONEMORE(); + } + while (isdigit(c)) + ONEMORE(); + } + if (c == 'f' || c == 'F' || c == 'l' || c == 'L') + ONEMORE(); + cunput(c); + *yyp = 0; + rval = FPOINT; + break; + } else + goto E; + + case '.': + ONEMORE(); + if (isdigit(c)) + goto F; + if (!slow) { + UNPUT(c); + putch('.'); + goto fast; + } + if (c == '.') { + ONEMORE(); + if (c == '.') { + *yyp++ = '.'; *yyp = 0; + rval = ELLIPS; + break; + } + cunput(c); + cunput('.'); + *--yyp = 0; + rval = '.'; + break; + } + cunput(c); + *yyp = 0; + rval = '.'; + break; + + case '\\': + c = input(); + if (c == '\n') { + ifiles->lineno++; + putch('\n'); + goto fast; + } + if (!slow) { + putch('\\'); + goto again; + } + UNPUT(c); + *yyp++ = '\\'; *yyp = 0; + rval = '\\'; + break; + + case '\n': + wasnl = 1; + ifiles->lineno++; + rval = NL; + if (slow) + break; + if (flslvl == 0) { + if (curline() == 1) + prtline(); + else + putch('\n'); + } + goto fast; + + case '#': + if (wasnl) { + wasnl = 0; + rval = CONTROL; + break; + } + if (!slow) { + putch('#'); + goto fast; + } + *yyp++ = c; + c = input(); + if (c == '#') { + *yyp++ = c; + *yyp = 0; + rval = CONCAT; + } else { + unput(c); + *yyp = 0; + rval = MKSTR; + } + break; + + case ' ': + case '\t': /* whitespace */ + do { + *yyp++ = c; + c = input(); + } while (c == ' ' || c == '\t'); + if (wasnl && c == '#') { + wasnl = 0; + rval = CONTROL; + } else { + unput(c); + *yyp = 0; + rval = WSPACE; + } + break; + + case '/': + if ((c = slofgetc()) == '/') { + if (Cflag) + fprintf(obuf, "//"); + while ((c = slofgetc()) && c != '\n') + if (Cflag) + putc(c, obuf); + goto again; + } else if (c == '*') { + if (Cflag) + fprintf(obuf, "/*"); + oc = 0; + do { + while ((c = slofgetc()) && c != '*') { + if (c == '\n') { + putc(c, obuf); + ifiles->lineno++; + } else if (Cflag) + putc(c, obuf); + } + if (Cflag) + putc(c, obuf); + if ((c = slofgetc()) == '/') + break; + unput(c); + } while (c); + if (Cflag) + putc(c, obuf); + if (tflag) { + rval = yylex(); + } else { + *yyp++ = ' '; *yyp = 0; + rval = WSPACE; + } + } else { + unput(c); + *yyp++ = '/'; *yyp = 0; + rval = '/'; + } + break; + + case 'L': /* may be STRING, CHARCON or identifier */ + *yyp++ = c; + if ((c = slofgetc()) == '"' || c == '\'') + goto chstr; +gotid: while (isalnum(c) || c == '_') { + *yyp++ = c; + c = slofgetc(); + } + *yyp = 0; + unput(c); + rval = IDENT; + break; + + default: + if (isalpha(c) || c == '_') + goto gotid; + if (!slow && c > 5) { + putch(c); + goto fast; + } + yystr[0] = c; yystr[1] = 0; + rval = c; + break; + } + return rval; +} + +/* + * A new file included. + * If ifiles == NULL, this is the first file and already opened (stdin). + * Return 0 on success, -1 on failure to open file. + */ +int +pushfile(char *file) +{ + struct includ ibuf; + struct includ *old; + struct includ *ic; + + ic = &ibuf; + old = ifiles; + + slow = 0; + if (file != NULL) { + if ((ic->infil = open(file, O_RDONLY)) < 0) + return -1; + ic->fname = file; + } else { + ic->infil = 0; + ic->fname = "<stdin>"; + } + ic->buffer = ic->bbuf+NAMEMAX; + ic->curptr = ic->buffer; + ifiles = ic; + ic->lineno = 0; + ic->maxread = ic->curptr; + unput('\n'); + + mainscan(); + + if (trulvl || flslvl) + error("unterminated conditional"); + + ifiles = old; + close(ic->infil); + return 0; +} + +/* + * Print current position to output file. + */ +void +prtline() +{ + fprintf(obuf, "# %d \"%s\"\n", ifiles->lineno, ifiles->fname); +} + +void +cunput(int c) +{ +extern int dflag; +if (dflag)printf(": '%c'(%d)", c, c); + unput(c); +} + +void +setline(int line) +{ + if (ifiles) + ifiles->lineno = line-1; +} + +void +setfile(char *name) +{ + if (ifiles) + ifiles->fname = strdup(name); +} + +int +curline() +{ + return ifiles ? ifiles->lineno : 0; +} + +char * +curfile() +{ + return ifiles ? ifiles->fname : ""; +} diff --git a/usr.bin/pcc/config.guess b/usr.bin/pcc/config.guess new file mode 100644 index 00000000000..1e6f50b7da5 --- /dev/null +++ b/usr.bin/pcc/config.guess @@ -0,0 +1,1463 @@ +#! /bin/sh +# +# $NetBSD: config.guess,v 1.8 2004/08/14 19:13:55 schmonz Exp $ +# +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +timestamp='2004-06-11' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Per Bothner <per@bothner.com>. +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + amd64:OpenBSD:*:*) + echo x86_64-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + cats:OpenBSD:*:*) + echo arm-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + luna88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + macppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvmeppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mipseb-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit 0 ;; + macppc:MirBSD:*:*) + echo powerppc-unknown-mirbsd${UNAME_RELEASE} + exit 0 ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit 0 ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha*:OpenVMS:*:*) + echo alpha-hp-vms + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit 0 ;; + DRS?6000:UNIX_SV:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7 && exit 0 ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c \ + && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && exit 0 + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit 0 ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + # avoid double evaluation of $set_cc_for_build + test -n "$CC_FOR_BUILD" || eval $set_cc_for_build + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + *:UNICOS/mp:*:*) + echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + # Determine whether the default compiler uses glibc. + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <features.h> + #if __GLIBC__ >= 2 + LIBC=gnu + #else + LIBC= + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + # GNU/KFreeBSD systems have a "k" prefix to indicate we are using + # FreeBSD's kernel, but not the complete OS. + case ${LIBC} in gnu) kernel_only='k' ;; esac + echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit 0 ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit 0 ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit 0 ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit 0 ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit 0 ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit 0 ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit 0 ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit 0 ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit 0 ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit 0 ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <features.h> + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit 0 ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit 0 ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit 0 ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit 0 ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit 0 ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i*86:*:5:[78]*) + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit 0 ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit 0 ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit 0 ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + case `uname -p` in + *86) UNAME_PROCESSOR=i686 ;; + powerpc) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit 0 ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit 0 ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit 0 ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit 0 ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit 0 ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit 0 ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit 0 ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include <sys/param.h> +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 <<EOF +$0: unable to guess system type + +This script, last modified $timestamp, has failed to recognize +the operating system you are using. It is advised that you +download the most up to date version of the config scripts from + + ftp://ftp.gnu.org/pub/gnu/config/ + +If the version you run ($0) is already up to date, please +send the following data and any information you think might be +pertinent to <config-patches@gnu.org> in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/usr.bin/pcc/config.h.in b/usr.bin/pcc/config.h.in new file mode 100644 index 00000000000..4da1b61c085 --- /dev/null +++ b/usr.bin/pcc/config.h.in @@ -0,0 +1,155 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +#undef CRAY_STACKSEG_END + +/* Define to 1 if using `alloca.c'. */ +#undef C_ALLOCA + +/* Define to 1 if you have `alloca', as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). + */ +#undef HAVE_ALLOCA_H + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the <fcntl.h> header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `fork' function. */ +#undef HAVE_FORK + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if stdbool.h conforms to C99. */ +#undef HAVE_STDBOOL_H + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strrchr' function. */ +#undef HAVE_STRRCHR + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#undef HAVE_VFORK + +/* Define to 1 if you have the <vfork.h> header file. */ +#undef HAVE_VFORK_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if `fork' works. */ +#undef HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#undef HAVE_WORKING_VFORK + +/* Define to 1 if the system has the type `_Bool'. */ +#undef HAVE__BOOL + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#undef STACK_DIRECTION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef PCC_MAJOR +#undef PCC_MINOR +#undef PCC_MINORMINOR +#undef VERSSTR + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to `int' if <sys/types.h> does not define. */ +#undef pid_t + +/* Define as `fork' if `vfork' does not work. */ +#undef vfork + +/* target operating system */ +#undef TARGOS + +/* mkstemp() */ +#undef HAVE_MKSTEMP + +/* which lex is used */ +#undef ISFLEX diff --git a/usr.bin/pcc/config.sub b/usr.bin/pcc/config.sub new file mode 100644 index 00000000000..b9e9bc4860a --- /dev/null +++ b/usr.bin/pcc/config.sub @@ -0,0 +1,1555 @@ +#! /bin/sh +# +# $NetBSD: config.sub,v 1.7 2004/08/14 19:14:42 schmonz Exp $ +# +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +timestamp='2004-03-12' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | msp430 \ + | ns16k | ns32k \ + | openrisc | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | msp430-* \ + | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ + | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nv1) + basic_machine=nv1-cray + os=-unicosmp + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + or32 | or32-*) + basic_machine=or32-unknown + os=-coff + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/usr.bin/pcc/configure b/usr.bin/pcc/configure new file mode 100644 index 00000000000..7308715407c --- /dev/null +++ b/usr.bin/pcc/configure @@ -0,0 +1,5655 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61 for pcc 0.9.8. +# +# Report bugs to <BUG-REPORT-ADDRESS>. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 </dev/null 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME='pcc' +PACKAGE_TARNAME='pcc' +PACKAGE_VERSION='0.9.8' +PACKAGE_STRING='pcc 0.9.8' +PACKAGE_BUGREPORT='BUG-REPORT-ADDRESS' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +SET_MAKE +INSTALL_PROGRAM +INSTALL_SCRIPT +INSTALL_DATA +build +build_cpu +build_vendor +build_os +host +host_cpu +host_vendor +host_os +target +target_cpu +target_vendor +target_os +CC +CFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CC +EXEEXT +OBJEXT +LEX +LEX_OUTPUT_ROOT +LEXLIB +YACC +YFLAGS +strip +CPP +GREP +EGREP +ALLOCA +targos +targmach +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +YACC +YFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures pcc 0.9.8 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/pcc] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of pcc 0.9.8:";; + esac + cat <<\_ACEOF + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + YACC The `Yet Another C Compiler' implementation to use. Defaults to + the first program found out of: `bison -y', `byacc', `yacc'. + YFLAGS The list of arguments that will be passed by default to $YACC. + This script will default YFLAGS to the empty string to avoid a + default value of `-d' given by some make applications. + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to <BUG-REPORT-ADDRESS>. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +pcc configure 0.9.8 +generated by GNU Autoconf 2.61 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by pcc $as_me 0.9.8, which was +generated by GNU Autoconf 2.61. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_config_headers="$ac_config_headers config.h" + + +{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; } +set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + SET_MAKE= +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done +IFS=$as_save_IFS + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 +echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} + { (exit 1); exit 1; }; } + +{ echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6; } +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 +echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 +echo "$as_me: error: invalid value of canonical build" >&2;} + { (exit 1); exit 1; }; };; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6; } +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 +echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} + { (exit 1); exit 1; }; } +fi + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 +echo "$as_me: error: invalid value of canonical host" >&2;} + { (exit 1); exit 1; }; };; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ echo "$as_me:$LINENO: checking target system type" >&5 +echo $ECHO_N "checking target system type... $ECHO_C" >&6; } +if test "${ac_cv_target+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&5 +echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&2;} + { (exit 1); exit 1; }; } +fi + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_target" >&5 +echo "${ECHO_T}$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) { { echo "$as_me:$LINENO: error: invalid value of canonical target" >&5 +echo "$as_me: error: invalid value of canonical target" >&2;} + { (exit 1); exit 1; }; };; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + +case "$target_os" in + netbsd*) + targos=netbsd + case "$target_cpu" in + i?86) targmach=x86 ;; + esac + ;; + openbsd*) + targos=openbsd + case "$target_cpu" in + i?86) targmach=x86 ;; + esac + ;; + dragonfly*) + targos=dragonfly + case "$target_cpu" in + i?86) targmach=x86 ;; + esac + ;; + linux*) + targos=linux + case "$target_cpu" in + i?86) targmach=x86 ;; + esac + ;; + *) + targos="$target_os" + case "$target_cpu" in + m16c) targmach=m16c ;; + nova) targmach=nova ;; + esac + ;; +esac + +if test "X$targos" = X -o "X$targmach" = X ; then + { { echo "$as_me:$LINENO: error: '$target' is not (yet) supported by pcc." >&5 +echo "$as_me: error: '$target' is not (yet) supported by pcc." >&2;} + { (exit 1); exit 1; }; } +fi + +# Checks for programs. +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } +if test -z "$ac_file"; then + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +for ac_prog in flex lex +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_LEX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LEX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +LEX=$ac_cv_prog_LEX +if test -n "$LEX"; then + { echo "$as_me:$LINENO: result: $LEX" >&5 +echo "${ECHO_T}$LEX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$LEX" && break +done +test -n "$LEX" || LEX=":" + +if test "x$LEX" != "x:"; then + cat >conftest.l <<_ACEOF +%% +a { ECHO; } +b { REJECT; } +c { yymore (); } +d { yyless (1); } +e { yyless (input () != 0); } +f { unput (yytext[0]); } +. { BEGIN INITIAL; } +%% +#ifdef YYTEXT_POINTER +extern char *yytext; +#endif +int +main (void) +{ + return ! yylex () + ! yywrap (); +} +_ACEOF +{ (ac_try="$LEX conftest.l" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$LEX conftest.l") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ echo "$as_me:$LINENO: checking lex output file root" >&5 +echo $ECHO_N "checking lex output file root... $ECHO_C" >&6; } +if test "${ac_cv_prog_lex_root+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + { { echo "$as_me:$LINENO: error: cannot find output from $LEX; giving up" >&5 +echo "$as_me: error: cannot find output from $LEX; giving up" >&2;} + { (exit 1); exit 1; }; } +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_root" >&5 +echo "${ECHO_T}$ac_cv_prog_lex_root" >&6; } +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +if test -z "${LEXLIB+set}"; then + { echo "$as_me:$LINENO: checking lex library" >&5 +echo $ECHO_N "checking lex library... $ECHO_C" >&6; } +if test "${ac_cv_lib_lex+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + ac_save_LIBS=$LIBS + ac_cv_lib_lex='none needed' + for ac_lib in '' -lfl -ll; do + LIBS="$ac_lib $ac_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_lex=$ac_lib +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + test "$ac_cv_lib_lex" != 'none needed' && break + done + LIBS=$ac_save_LIBS + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_lex" >&5 +echo "${ECHO_T}$ac_cv_lib_lex" >&6; } + test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex +fi + + +{ echo "$as_me:$LINENO: checking whether yytext is a pointer" >&5 +echo $ECHO_N "checking whether yytext is a pointer... $ECHO_C" >&6; } +if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +ac_save_LIBS=$LIBS +LIBS="$LEXLIB $ac_save_LIBS" +cat >conftest.$ac_ext <<_ACEOF +#define YYTEXT_POINTER 1 +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_prog_lex_yytext_pointer=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_save_LIBS + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_yytext_pointer" >&5 +echo "${ECHO_T}$ac_cv_prog_lex_yytext_pointer" >&6; } +if test $ac_cv_prog_lex_yytext_pointer = yes; then + +cat >>confdefs.h <<\_ACEOF +#define YYTEXT_POINTER 1 +_ACEOF + +fi +rm -f conftest.l $LEX_OUTPUT_ROOT.c + +fi +for ac_prog in 'bison -y' byacc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_YACC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_YACC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + { echo "$as_me:$LINENO: result: $YACC" >&5 +echo "${ECHO_T}$YACC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + + +# Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_strip+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$strip"; then + ac_cv_prog_strip="$strip" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_strip="yes" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_strip" && ac_cv_prog_strip="no" +fi +fi +strip=$ac_cv_prog_strip +if test -n "$strip"; then + { echo "$as_me:$LINENO: result: $strip" >&5 +echo "${ECHO_T}$strip" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + +# Checks for libraries. + +# Checks for header files. +# AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h]) +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Extract the first word of "grep ggrep" to use in msg output +if test -z "$GREP"; then +set dummy grep ggrep; ac_prog_name=$2 +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_GREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + # Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_GREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +GREP="$ac_cv_path_GREP" +if test -z "$GREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_GREP=$GREP +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +echo "${ECHO_T}$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + # Extract the first word of "egrep" to use in msg output +if test -z "$EGREP"; then +set dummy egrep; ac_prog_name=$2 +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_EGREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + # Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_EGREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +EGREP="$ac_cv_path_EGREP" +if test -z "$EGREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_EGREP=$EGREP +fi + + + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + +for ac_header in string.h alloca.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## --------------------------------- ## +## Report this to BUG-REPORT-ADDRESS ## +## --------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Checks for library functions. +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +{ echo "$as_me:$LINENO: checking for working alloca.h" >&5 +echo $ECHO_N "checking for working alloca.h... $ECHO_C" >&6; } +if test "${ac_cv_working_alloca_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <alloca.h> +int +main () +{ +char *p = (char *) alloca (2 * sizeof (int)); + if (p) return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_working_alloca_h=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_working_alloca_h=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_working_alloca_h" >&5 +echo "${ECHO_T}$ac_cv_working_alloca_h" >&6; } +if test $ac_cv_working_alloca_h = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_ALLOCA_H 1 +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking for alloca" >&5 +echo $ECHO_N "checking for alloca... $ECHO_C" >&6; } +if test "${ac_cv_func_alloca_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# ifdef _MSC_VER +# include <malloc.h> +# define alloca _alloca +# else +# ifdef HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +int +main () +{ +char *p = (char *) alloca (1); + if (p) return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_func_alloca_works=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_alloca_works=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func_alloca_works" >&5 +echo "${ECHO_T}$ac_cv_func_alloca_works" >&6; } + +if test $ac_cv_func_alloca_works = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_ALLOCA 1 +_ACEOF + +else + # The SVR3 libPW and SVR4 libucb both contain incompatible functions +# that cause trouble. Some versions do not even contain alloca or +# contain a buggy version. If you still want to use their alloca, +# use ar to extract alloca.o from them instead of compiling alloca.c. + +ALLOCA=\${LIBOBJDIR}alloca.$ac_objext + +cat >>confdefs.h <<\_ACEOF +#define C_ALLOCA 1 +_ACEOF + + +{ echo "$as_me:$LINENO: checking whether \`alloca.c' needs Cray hooks" >&5 +echo $ECHO_N "checking whether \`alloca.c' needs Cray hooks... $ECHO_C" >&6; } +if test "${ac_cv_os_cray+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#if defined CRAY && ! defined CRAY2 +webecray +#else +wenotbecray +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "webecray" >/dev/null 2>&1; then + ac_cv_os_cray=yes +else + ac_cv_os_cray=no +fi +rm -f conftest* + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_os_cray" >&5 +echo "${ECHO_T}$ac_cv_os_cray" >&6; } +if test $ac_cv_os_cray = yes; then + for ac_func in _getb67 GETB67 getb67; do + as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + +cat >>confdefs.h <<_ACEOF +#define CRAY_STACKSEG_END $ac_func +_ACEOF + + break +fi + + done +fi + +{ echo "$as_me:$LINENO: checking stack direction for C alloca" >&5 +echo $ECHO_N "checking stack direction for C alloca... $ECHO_C" >&6; } +if test "${ac_cv_c_stack_direction+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_stack_direction=0 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +find_stack_direction () +{ + static char *addr = 0; + auto char dummy; + if (addr == 0) + { + addr = &dummy; + return find_stack_direction (); + } + else + return (&dummy > addr) ? 1 : -1; +} + +int +main () +{ + return find_stack_direction () < 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_stack_direction=1 +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_c_stack_direction=-1 +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_stack_direction" >&5 +echo "${ECHO_T}$ac_cv_c_stack_direction" >&6; } + +cat >>confdefs.h <<_ACEOF +#define STACK_DIRECTION $ac_cv_c_stack_direction +_ACEOF + + +fi + +## AC_FUNC_STRTOD +# AC_FUNC_VPRINTF +# AC_CHECK_FUNCS([memset strchr strdup strrchr strtol]) + +for ac_func in mkstemp +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + + + + + + + +pcc_major=`echo $PACKAGE_VERSION | awk -F. '{print $1}'` +pcc_minor=`echo $PACKAGE_VERSION | awk -F. '{print $2}'` +pcc_minorminor=`echo $PACKAGE_VERSION | awk -F. '{print $3}'` +versstr="\"$PACKAGE_STRING for $target, $USER@`hostname` `date`\"" + +cat >>confdefs.h <<_ACEOF +#define TARGOS $targos +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PCC_MAJOR $pcc_major +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PCC_MINOR $pcc_minor +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PCC_MINORMINOR $pcc_minorminor +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define VERSSTR $versstr +_ACEOF + +if test "$LEX" = flex ; then + cat >>confdefs.h <<_ACEOF +#define ISFLEX 1 +_ACEOF + +fi + +ac_config_files="$ac_config_files Makefile cc/Makefile cc/cc/Makefile cc/cpp/Makefile cc/ccom/Makefile f77/Makefile f77/f77/Makefile f77/fcom/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by pcc $as_me 0.9.8, which was +generated by GNU Autoconf 2.61. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to <bug-autoconf@gnu.org>." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +pcc config.status 0.9.8 +configured by $0, generated by GNU Autoconf 2.61, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + { echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "cc/Makefile") CONFIG_FILES="$CONFIG_FILES cc/Makefile" ;; + "cc/cc/Makefile") CONFIG_FILES="$CONFIG_FILES cc/cc/Makefile" ;; + "cc/cpp/Makefile") CONFIG_FILES="$CONFIG_FILES cc/cpp/Makefile" ;; + "cc/ccom/Makefile") CONFIG_FILES="$CONFIG_FILES cc/ccom/Makefile" ;; + "f77/Makefile") CONFIG_FILES="$CONFIG_FILES f77/Makefile" ;; + "f77/f77/Makefile") CONFIG_FILES="$CONFIG_FILES f77/f77/Makefile" ;; + "f77/fcom/Makefile") CONFIG_FILES="$CONFIG_FILES f77/fcom/Makefile" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +SET_MAKE!$SET_MAKE$ac_delim +INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim +INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim +INSTALL_DATA!$INSTALL_DATA$ac_delim +build!$build$ac_delim +build_cpu!$build_cpu$ac_delim +build_vendor!$build_vendor$ac_delim +build_os!$build_os$ac_delim +host!$host$ac_delim +host_cpu!$host_cpu$ac_delim +host_vendor!$host_vendor$ac_delim +host_os!$host_os$ac_delim +target!$target$ac_delim +target_cpu!$target_cpu$ac_delim +target_vendor!$target_vendor$ac_delim +target_os!$target_os$ac_delim +CC!$CC$ac_delim +CFLAGS!$CFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CC!$ac_ct_CC$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +LEX!$LEX$ac_delim +LEX_OUTPUT_ROOT!$LEX_OUTPUT_ROOT$ac_delim +LEXLIB!$LEXLIB$ac_delim +YACC!$YACC$ac_delim +YFLAGS!$YFLAGS$ac_delim +strip!$strip$ac_delim +CPP!$CPP$ac_delim +GREP!$GREP$ac_delim +EGREP!$EGREP$ac_delim +ALLOCA!$ALLOCA$ac_delim +targos!$targos$ac_delim +targmach!$targmach$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 74; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS <conf$$subs.sed +rm -f conf$$subs.sed +cat >>$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$ac_file_inputs $ac_f" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input="Generated from "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + :H) + # + # CONFIG_HEADER + # +_ACEOF + +# Transform confdefs.h into a sed script `conftest.defines', that +# substitutes the proper values into config.h.in to produce config.h. +rm -f conftest.defines conftest.tail +# First, append a space to every undef/define line, to ease matching. +echo 's/$/ /' >conftest.defines +# Then, protect against being on the right side of a sed subst, or in +# an unquoted here document, in config.status. If some macros were +# called several times there might be several #defines for the same +# symbol, which is useless. But do not sort them, since the last +# AC_DEFINE must be honored. +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where +# NAME is the cpp macro being defined, VALUE is the value it is being given. +# PARAMS is the parameter list in the macro definition--in most cases, it's +# just an empty string. +ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*' +ac_dB='\\)[ (].*,\\1define\\2' +ac_dC=' ' +ac_dD=' ,' + +uniq confdefs.h | + sed -n ' + t rset + :rset + s/^[ ]*#[ ]*define[ ][ ]*// + t ok + d + :ok + s/[\\&,]/\\&/g + s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p + s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p + ' >>conftest.defines + +# Remove the space that was appended to ease matching. +# Then replace #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +# (The regexp can be short, since the line contains either #define or #undef.) +echo 's/ $// +s,^[ #]*u.*,/* & */,' >>conftest.defines + +# Break up conftest.defines: +ac_max_sed_lines=50 + +# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1" +# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2" +# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1" +# et cetera. +ac_in='$ac_file_inputs' +ac_out='"$tmp/out1"' +ac_nxt='"$tmp/out2"' + +while : +do + # Write a here document: + cat >>$CONFIG_STATUS <<_ACEOF + # First, check the format of the line: + cat >"\$tmp/defines.sed" <<\\CEOF +/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def +/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def +b +:def +_ACEOF + sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS + ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in + sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail + grep . conftest.tail >/dev/null || break + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines conftest.tail + +echo "ac_result=$ac_in" >>$CONFIG_STATUS +cat >>$CONFIG_STATUS <<\_ACEOF + if test x"$ac_file" != x-; then + echo "/* $configure_input */" >"$tmp/config.h" + cat "$ac_result" >>"$tmp/config.h" + if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f $ac_file + mv "$tmp/config.h" $ac_file + fi + else + echo "/* $configure_input */" + cat "$ac_result" + fi + rm -f "$tmp/out12" + ;; + + + esac + +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/usr.bin/pcc/configure.ac b/usr.bin/pcc/configure.ac new file mode 100644 index 00000000000..b3f81139dcb --- /dev/null +++ b/usr.bin/pcc/configure.ac @@ -0,0 +1,102 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.59) +AC_INIT([pcc], [0.9.8], BUG-REPORT-ADDRESS) +AC_CONFIG_HEADER([config.h]) + +AC_PROG_MAKE_SET +AC_PROG_INSTALL +AC_CANONICAL_TARGET + + +case "$target_os" in + netbsd*) + targos=netbsd + case "$target_cpu" in + i?86) targmach=x86 ;; + esac + ;; + openbsd*) + targos=openbsd + case "$target_cpu" in + i?86) targmach=x86 ;; + esac + ;; + dragonfly*) + targos=dragonfly + case "$target_cpu" in + i?86) targmach=x86 ;; + esac + ;; + linux*) + targos=linux + case "$target_cpu" in + i?86) targmach=x86 ;; + esac + ;; + *) + targos="$target_os" + case "$target_cpu" in + m16c) targmach=m16c ;; + nova) targmach=nova ;; + esac + ;; +esac + +if test "X$targos" = X -o "X$targmach" = X ; then + AC_MSG_ERROR(['$target' is not (yet) supported by pcc.]) +fi + +# Checks for programs. +AC_PROG_CC +AC_PROG_LEX +AC_PROG_YACC + +AC_CHECK_PROG(strip,strip,yes,no) + +# Checks for libraries. + +# Checks for header files. +# AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h]) +AC_CHECK_HEADERS([string.h alloca.h]) + +# Checks for library functions. +AC_FUNC_ALLOCA +## AC_FUNC_STRTOD +# AC_FUNC_VPRINTF +# AC_CHECK_FUNCS([memset strchr strdup strrchr strtol]) +AC_CHECK_FUNCS(mkstemp) + +AC_SUBST(targos) +AC_SUBST(targmach) +AC_SUBST(prefix) +AC_SUBST(exec_prefix) +AC_SUBST(libexecdir) +AC_SUBST(includedir) +AC_SUBST(strip) + +pcc_major=`echo $PACKAGE_VERSION | awk -F. '{print $1}'` +pcc_minor=`echo $PACKAGE_VERSION | awk -F. '{print $2}'` +pcc_minorminor=`echo $PACKAGE_VERSION | awk -F. '{print $3}'` +versstr="\"$PACKAGE_STRING for $target, $USER@`hostname` `date`\"" + +AC_DEFINE_UNQUOTED(TARGOS, $targos) +AC_DEFINE_UNQUOTED(PCC_MAJOR, $pcc_major) +AC_DEFINE_UNQUOTED(PCC_MINOR, $pcc_minor) +AC_DEFINE_UNQUOTED(PCC_MINORMINOR, $pcc_minorminor) +AC_DEFINE_UNQUOTED(VERSSTR, $versstr) +if test "$LEX" = flex ; then + AC_DEFINE_UNQUOTED(ISFLEX, 1) +fi + +AC_CONFIG_FILES([Makefile + cc/Makefile + cc/cc/Makefile + cc/cpp/Makefile + cc/ccom/Makefile + f77/Makefile + f77/f77/Makefile + f77/fcom/Makefile +]) +AC_OUTPUT diff --git a/usr.bin/pcc/f77/Makefile.in b/usr.bin/pcc/f77/Makefile.in new file mode 100644 index 00000000000..76ad025b263 --- /dev/null +++ b/usr.bin/pcc/f77/Makefile.in @@ -0,0 +1,36 @@ +# $Id: Makefile.in,v 1.1 2007/09/15 18:12:35 otto Exp $ +# +# Makefile.in for top-level of pcc. +# + +@SET_MAKE@ +CC=@CC@ +CFLAGS=@CFLAGS@ +LDFLAGS=@LDFLAGS@ +CPPFLAGS=@CPPFLAGS@ +YACC=@YACC@ +LEX=@LEX@ + +SUBDIR=cc cpp ccom + +all: ${SUBDIR} + +install: + cd cc && ${MAKE} install + cd cpp && ${MAKE} install + cd ccom && ${MAKE} install + +clean: + cd cc && ${MAKE} clean + cd cpp && ${MAKE} clean + cd ccom && ${MAKE} clean + +distclean: + cd cc && ${MAKE} distclean + cd cpp && ${MAKE} distclean + cd ccom && ${MAKE} distclean + /bin/rm -rf Makefile config.log stamp-h1 config.status \ + configure.lineno config.h autom4te.cache + +${SUBDIR}: + cd $@; $(MAKE) all $(MFLAGS) diff --git a/usr.bin/pcc/f77/f77/Makefile.in b/usr.bin/pcc/f77/f77/Makefile.in new file mode 100644 index 00000000000..9ab666faba9 --- /dev/null +++ b/usr.bin/pcc/f77/f77/Makefile.in @@ -0,0 +1,42 @@ +# $Id: Makefile.in,v 1.1 2007/09/15 18:12:35 otto Exp $ +# +# Makefile.in for the cc part of pcc. +# +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libexecdir = @libexecdir@ +strip = @strip@ +CC = @CC@ +TARGOS = @targos@ +TARGMACH = @targmach@ +CFLAGS = @CFLAGS@ -DLIBEXECDIR=\"${libexecdir}\" +CPPFLAGS = @CPPFLAGS@ -I../os/${TARGOS} -Dmach_${TARGMACH} -Dos_${TARGOS} +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ + +OBJS=cc.o +DEST=pcc + +all: ${DEST} + +${DEST}: $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@ + +.c.o: + $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $< + +install: + ${INSTALL_PROGRAM} ${DEST} ${bindir} + @if [ ${strip} = yes ]; then \ + strip ${bindir}/${DEST} ; \ + echo strip ${bindir}/${DEST} ; \ + fi + +clean: + /bin/rm -f $(OBJS) ${DEST} + +distclean: clean + /bin/rm -f Makefile diff --git a/usr.bin/pcc/f77/fcom/Makefile.in b/usr.bin/pcc/f77/fcom/Makefile.in new file mode 100644 index 00000000000..04018acc84e --- /dev/null +++ b/usr.bin/pcc/f77/fcom/Makefile.in @@ -0,0 +1,95 @@ +# $Id: Makefile.in,v 1.1 2007/09/15 18:12:35 otto Exp $ +# +# Makefile for the Fortran 77 command +# Running on the @targmach@ +# Generating code for the @targmach@ +# Using the Johnson C compiler's second pass (binary version) + +TARGOS = @targos@ +TARGMACH = @targmach@ +MDIR=../arch/$(TARGMACH) +YFLAGS=-d + +COMPFLGS = -O -DFORTRAN -DTARGET=@targmach@ -DFAMILY=SCJ -DHERE=VAX -DOUTPUT=BINARY -DPOLISH=POSTFIX -I../os/${TARGOS} -I../arch/${TARGMACH} -I. -Wall -Wmissing-prototypes -Wstrict-prototypes +FILES = Makefile defs.h defines.h ftypes.h scjdefs tokens fio.h\ + driver.c \ + main.c proc.c init.c\ + gram.head gram.dcl gram.expr gram.exec gram.io\ + lex.c equiv.c data.c expr.c exec.c intr.c\ + io.c misc.c error.c put.c putscjb.c f77md.c f77md2.c + + +OBJECTS = main.o init.o proc.o gram.o lex.o \ + equiv.o data.o expr.o exec.o intr.o io.o misc.o error.o\ + put.o putscjb.o f77md.o f77md2.o + +compiler: f77 f77pass1 + +f77 : f77.o f77md.o + $(CC) f77.o f77md.o -o f77 + @size f77 + +f77pass1 : $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) -o f77pass1 + @size f77pass1 + +gram.c: gram.head gram.dcl gram.expr gram.exec gram.io tokdefs + ( sed <tokdefs "s/#define/%token/" ;\ + cat gram.head gram.dcl gram.expr gram.exec gram.io ) >gram.in + $(YACC) $(YFLAGS) gram.in + mv y.tab.c gram.c + mv y.tab.h gram.h + rm gram.in + +tokdefs: tokens + grep -n . <tokens | sed "s/\([^:]*\):\(.*\)/#define \2 \1/" >tokdefs + +lex.o : tokdefs +driver.o $(OBJECTS) : defs.h defines.h ftypes.h + +fio.h :# /usr/sif/fort/libI77/fio.h +# @echo "***Warning : /usr/sif/fort/libI77/fio.h has changed***" + +archall: + ar rc ../fortarch $(FILES) + +arch : ../fortarch + +../fortarch: $(FILES) + @ar uv ../fortarch $? + @wc ../fortarch + + +printall: + pr $(FILES) | $P + touch print + +print: $(FILES) + pr $? | $P + touch print + +lint: + @echo "nohup lint -p ... >Lintout&" + @nohup lint -p error.c exec.c intr.c expr.c gram.c init.c io.c\ + lex.c main.c proc.c misc.c put.c putscjb.c vax.c vaxx.c\ + equiv.c data.c -lS >Lintout& + +clean: + -rm -f gram.c *.o f77 f77pass1 + du + +install: + install -s f77 $(DESTDIR)/usr/bin + install -s f77pass1 $(DESTDIR)/usr/lib + +src : $(FILES) vaxdefs + cp $? /usr/src/cmd/f77 + touch src +.c.o : + cc -c $(CFLAGS) $(COMPFLGS) $*.c + +f77md.o: $(MDIR)/f77md.c + $(CC) -c $(CFLAGS) $(COMPFLGS) -o $@ $(MDIR)/f77md.c + +f77md2.o: $(MDIR)/f77md2.c + $(CC) -c $(CFLAGS) $(COMPFLGS) -o $@ $(MDIR)/f77md2.c diff --git a/usr.bin/pcc/install-sh b/usr.bin/pcc/install-sh new file mode 100644 index 00000000000..0ec27bcd488 --- /dev/null +++ b/usr.bin/pcc/install-sh @@ -0,0 +1,294 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd=$cpprog + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "$0: no input file specified" >&2 + exit 1 +else + : +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d "$dst" ]; then + instcmd=: + chmodcmd="" + else + instcmd=$mkdirprog + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f "$src" ] || [ -d "$src" ] + then + : + else + echo "$0: $src does not exist" >&2 + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "$0: no destination specified" >&2 + exit 1 + else + : + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d "$dst" ] + then + dst=$dst/`basename "$src"` + else + : + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' + ' +IFS="${IFS-$defaultIFS}" + +oIFS=$IFS +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS=$oIFS + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp=$pathcomp$1 + shift + + if [ ! -d "$pathcomp" ] ; + then + $mkdirprog "$pathcomp" + else + : + fi + + pathcomp=$pathcomp/ +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd "$dst" && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename "$dst"` + else + dstfile=`basename "$dst" $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename "$dst"` + else + : + fi + +# Make a couple of temp file names in the proper directory. + + dsttmp=$dstdir/#inst.$$# + rmtmp=$dstdir/#rm.$$# + +# Trap to clean up temp files at exit. + + trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 + trap '(exit $?); exit' 1 2 13 15 + +# Move or copy the file name to the temp name + + $doit $instcmd "$src" "$dsttmp" && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi && + +# Now remove or move aside any old file at destination location. We try this +# two ways since rm can't unlink itself on some systems and the destination +# file might be busy for other reasons. In this case, the final cleanup +# might fail but the new file should still install successfully. + +{ + if [ -f "$dstdir/$dstfile" ] + then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null || + $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null || + { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit + } + else + : + fi +} && + +# Now rename the file to the real destination. + + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + +fi && + +# The final little trick to "correctly" pass the exit status to the exit trap. + +{ + (exit 0); exit +} diff --git a/usr.bin/pcc/mip/common.c b/usr.bin/pcc/mip/common.c new file mode 100644 index 00000000000..e5d49df9282 --- /dev/null +++ b/usr.bin/pcc/mip/common.c @@ -0,0 +1,631 @@ +/* $Id: common.c,v 1.1 2007/09/15 18:12:35 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. + */ + +/* + * 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 <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "pass2.h" + +# ifndef EXIT +# define EXIT exit +# endif + +int nerrors = 0; /* number of errors */ +char *ftitle; +int lineno; + +#ifndef WHERE +#define WHERE(ch) fprintf(stderr, "%s, line %d: ", ftitle, lineno); +#endif + +/* + * nonfatal error message + * the routine where is different for pass 1 and pass 2; + * it tells where the error took place + */ +void +uerror(char *s, ...) +{ + va_list ap; + + va_start(ap, s); + ++nerrors; + WHERE('u'); + vfprintf(stderr, s, ap); + fprintf(stderr, "\n"); + if (nerrors > 30) + cerror("too many errors"); + va_end(ap); +} + +/* + * compiler error: die + */ +void +cerror(char *s, ...) +{ + va_list ap; + + va_start(ap, s); + WHERE('c'); + + /* give the compiler the benefit of the doubt */ + if (nerrors && nerrors <= 30) { + fprintf(stderr, + "cannot recover from earlier errors: goodbye!\n"); + } else { + fprintf(stderr, "compiler error: "); + vfprintf(stderr, s, ap); + fprintf(stderr, "\n"); + } + va_end(ap); + EXIT(1); +} + +/* + * warning + */ +void +werror(char *s, ...) +{ + va_list ap; + + va_start(ap, s); + WHERE('w'); + fprintf(stderr, "warning: "); + vfprintf(stderr, s, ap); + fprintf(stderr, "\n"); +} + +#ifndef MKEXT +static NODE *freelink; +static int usednodes; + +NODE * +talloc() +{ + extern int inlnodecnt, recovernodes; + register NODE *p; + + usednodes++; + + if (recovernodes) + inlnodecnt++; + if (freelink != NULL) { + p = freelink; + freelink = p->next; + if (p->n_op != FREE) + cerror("node not FREE: %p", p); + if (nflag) + printf("alloc node %p from freelist\n", p); + return p; + } + + p = permalloc(sizeof(NODE)); + p->n_op = FREE; + if (nflag) + printf("alloc node %p from memory\n", p); + return p; +} + +/* + * make a fresh copy of p + */ +NODE * +tcopy(NODE *p) +{ + NODE *q; + + q = talloc(); + *q = *p; + + switch (optype(q->n_op)) { + case BITYPE: + q->n_right = tcopy(p->n_right); + case UTYPE: + q->n_left = tcopy(p->n_left); + } + + return(q); +} + + +/* + * ensure that all nodes have been freed + */ +void +tcheck() +{ + extern int inlnodecnt; + + if (nerrors) + return; + + if ((usednodes - inlnodecnt) != 0) + cerror("usednodes == %d, inlnodecnt %d", usednodes, inlnodecnt); +} + +/* + * free the tree p + */ +void +tfree(NODE *p) +{ + if (p->n_op != FREE) + walkf(p, (void (*)(NODE *))nfree); +} + +/* + * Free a node, and return its left descendant. + * It is up to the caller to know whether the return value is usable. + */ +NODE * +nfree(NODE *p) +{ + extern int inlnodecnt, recovernodes; + NODE *l; +#ifdef PCC_DEBUG_NODES + NODE *q; +#endif + + if (p == NULL) + cerror("freeing blank node!"); + + l = p->n_left; + if (p->n_op == FREE) + cerror("freeing FREE node", p); +#ifdef PCC_DEBUG_NODES + q = freelink; + while (q != NULL) { + if (q == p) + cerror("freeing free node %p", p); + q = q->next; + } +#endif + + if (nflag) + printf("freeing node %p\n", p); + p->n_op = FREE; + p->next = freelink; + freelink = p; + usednodes--; + if (recovernodes) + inlnodecnt--; + return l; +} +#endif + +#ifdef MKEXT +#define coptype(o) (dope[o]&TYFLG) +#else +int cdope(int); +#define coptype(o) (cdope(o)&TYFLG) +#endif + +void +fwalk(NODE *t, void (*f)(NODE *, int, int *, int *), int down) +{ + + int down1, down2; + + more: + down1 = down2 = 0; + + (*f)(t, down, &down1, &down2); + + switch (coptype( t->n_op )) { + + case BITYPE: + fwalk( t->n_left, f, down1 ); + t = t->n_right; + down = down2; + goto more; + + case UTYPE: + t = t->n_left; + down = down1; + goto more; + + } +} + +void +walkf(NODE *t, void (*f)(NODE *)) +{ + int opty; + + opty = coptype(t->n_op); + + if (opty != LTYPE) + walkf( t->n_left, f ); + if (opty == BITYPE) + walkf( t->n_right, f ); + (*f)(t); +} + +int dope[DSIZE]; +char *opst[DSIZE]; + +struct dopest { + int dopeop; + char opst[8]; + int dopeval; +} indope[] = { + { NAME, "NAME", LTYPE, }, + { REG, "REG", LTYPE, }, + { OREG, "OREG", LTYPE, }, + { TEMP, "TEMP", LTYPE, }, + { MOVE, "MOVE", UTYPE, }, + { ICON, "ICON", LTYPE, }, + { FCON, "FCON", LTYPE, }, + { CCODES, "CCODES", LTYPE, }, + { UMINUS, "U-", UTYPE, }, + { UMUL, "U*", UTYPE, }, + { FUNARG, "FUNARG", UTYPE, }, + { UCALL, "UCALL", UTYPE|CALLFLG, }, + { UFORTCALL, "UFCALL", UTYPE|CALLFLG, }, + { COMPL, "~", UTYPE, }, + { FORCE, "FORCE", UTYPE, }, +/* { INIT, "INIT", UTYPE, }, */ + { SCONV, "SCONV", UTYPE, }, + { PCONV, "PCONV", UTYPE, }, + { PLUS, "+", BITYPE|FLOFLG|SIMPFLG|COMMFLG, }, + { MINUS, "-", BITYPE|FLOFLG|SIMPFLG, }, + { MUL, "*", BITYPE|FLOFLG|MULFLG, }, + { AND, "&", BITYPE|SIMPFLG|COMMFLG, }, + { CM, ",", BITYPE, }, + { ASSIGN, "=", BITYPE|ASGFLG, }, + { DIV, "/", BITYPE|FLOFLG|MULFLG|DIVFLG, }, + { MOD, "%", BITYPE|DIVFLG, }, + { LS, "<<", BITYPE|SHFFLG, }, + { RS, ">>", BITYPE|SHFFLG, }, + { OR, "|", BITYPE|COMMFLG|SIMPFLG, }, + { ER, "^", BITYPE|COMMFLG|SIMPFLG, }, + { STREF, "->", BITYPE, }, + { CALL, "CALL", BITYPE|CALLFLG, }, + { FORTCALL, "FCALL", BITYPE|CALLFLG, }, + { EQ, "==", BITYPE|LOGFLG, }, + { NE, "!=", BITYPE|LOGFLG, }, + { LE, "<=", BITYPE|LOGFLG, }, + { LT, "<", BITYPE|LOGFLG, }, + { GE, ">=", BITYPE|LOGFLG, }, + { GT, ">", BITYPE|LOGFLG, }, + { UGT, "UGT", BITYPE|LOGFLG, }, + { UGE, "UGE", BITYPE|LOGFLG, }, + { ULT, "ULT", BITYPE|LOGFLG, }, + { ULE, "ULE", BITYPE|LOGFLG, }, + { CBRANCH, "CBRANCH", BITYPE, }, + { FLD, "FLD", UTYPE, }, + { PMCONV, "PMCONV", BITYPE, }, + { PVCONV, "PVCONV", BITYPE, }, + { RETURN, "RETURN", BITYPE|ASGFLG|ASGOPFLG, }, + { GOTO, "GOTO", UTYPE, }, + { STASG, "STASG", BITYPE|ASGFLG, }, + { STARG, "STARG", UTYPE, }, + { STCALL, "STCALL", BITYPE|CALLFLG, }, + { USTCALL, "USTCALL", UTYPE|CALLFLG, }, + { ADDROF, "U&", UTYPE, }, + + { -1, "", 0 }, +}; + +void +mkdope() +{ + struct dopest *q; + + for( q = indope; q->dopeop >= 0; ++q ){ + dope[q->dopeop] = q->dopeval; + opst[q->dopeop] = q->opst; + } +} + +/* + * output a nice description of the type of t + */ +void +tprint(FILE *fp, TWORD t, TWORD q) +{ + static char * tnames[] = { + "undef", + "farg", + "char", + "uchar", + "short", + "ushort", + "int", + "unsigned", + "long", + "ulong", + "longlong", + "ulonglong", + "float", + "double", + "ldouble", + "strty", + "unionty", + "enumty", + "moety", + "void", + "signed", /* pass1 */ + "bool", /* pass1 */ + "?", "?" + }; + + for(;; t = DECREF(t), q = DECREF(q)) { + if (ISCON(q)) + fputc('C', fp); + if (ISVOL(q)) + fputc('V', fp); + + if (ISPTR(t)) + fprintf(fp, "PTR "); + else if (ISFTN(t)) + fprintf(fp, "FTN "); + else if (ISARY(t)) + fprintf(fp, "ARY "); + else { + fprintf(fp, "%s%s%s", ISCON(q << TSHIFT) ? "const " : "", + ISVOL(q << TSHIFT) ? "volatile " : "", tnames[t]); + return; + } + } +} + +int crslab = 10; +/* + * Return a number for internal labels. + */ +int +getlab() +{ + return crslab++; +} + +/* + * Memory allocation routines. + * Memory are allocated from the system in MEMCHUNKSZ blocks. + * permalloc() returns a bunch of memory that is never freed. + * Memory allocated through tmpalloc() will be released the + * next time a function is ended (via tmpfree()). + */ + +#define MEMCHUNKSZ 8192 /* 8k per allocation */ +struct b { + char a1; + union { + long long l; + long double d; + } a2; +}; + +#define ALIGNMENT ((int)&((struct b *)0)->a2) +#define ROUNDUP(x) ((x) + (sizeof(ALIGNMENT)-1)) & ~(sizeof(ALIGNMENT)-1) + +static char *allocpole; +static int allocleft; +static char *tmppole; +static int tmpleft; +int permallocsize, tmpallocsize, lostmem; + +void * +permalloc(int size) +{ + void *rv; + +//printf("permalloc: allocpole %p allocleft %d size %d ", allocpole, allocleft, size); + if (size > MEMCHUNKSZ) + cerror("permalloc"); + if (size <= 0) + cerror("permalloc2"); + if (allocleft < size) { + /* looses unused bytes */ + lostmem += allocleft; +//fprintf(stderr, "allocating perm\n"); + if ((allocpole = malloc(MEMCHUNKSZ)) == NULL) + cerror("permalloc: out of memory"); + allocleft = MEMCHUNKSZ; + } + size = ROUNDUP(size); + rv = &allocpole[MEMCHUNKSZ-allocleft]; +//printf("rv %p\n", rv); + allocleft -= size; + permallocsize += size; + return rv; +} + +static char *tmplink; + +void * +tmpcalloc(int size) +{ + void *rv; + + rv = tmpalloc(size); + memset(rv, 0, size); + return rv; +} + +#define TMPOLE &tmppole[MEMCHUNKSZ-tmpleft] +void * +tmpalloc(int size) +{ + void *rv; + + if (size > MEMCHUNKSZ) { + return malloc(size); + // cerror("tmpalloc %d", size); + } + if (size <= 0) + cerror("tmpalloc2"); +//printf("tmpalloc: tmppole %p tmpleft %d size %d ", tmppole, tmpleft, size); + size = ROUNDUP(size); + if (tmpleft < size) { + if ((tmppole = malloc(MEMCHUNKSZ)) == NULL) + cerror("tmpalloc: out of memory"); +//fprintf(stderr, "allocating tmp\n"); + tmpleft = MEMCHUNKSZ - (ROUNDUP(sizeof(char *))); + *(char **)tmppole = tmplink; + tmplink = tmppole; + } + rv = TMPOLE; +//printf("rv %p\n", rv); + tmpleft -= size; + tmpallocsize += size; + return rv; +} + +#if 0 +/* + * Print and pack strings on heap. + */ +char *tmpsprintf(char *fmt, ...); +char * +tmpsprintf(char *fmt, ...) +{ + va_list ap; + int len; + char *tmp; + + tmp = TMPOLE; + va_start(ap, fmt); + if ((len = vsnprintf(tmp, tmpleft, fmt, ap)) >= tmpleft) { + (void)tmpalloc(tmpleft); /* ugly */ + tmp = TMPOLE; + if ((len = vsnprintf(tmp, tmpleft, fmt, ap)) >= tmpleft) + cerror("bad tmpsprintf len"); + } + va_end(ap); + tmpleft += len; + return tmp; +} +#endif + +/* + * Print and pack vararg string on heap. + */ +char *tmpvsprintf(char *fmt, va_list ap); +char * +tmpvsprintf(char *fmt, va_list ap) +{ + int len; + char *tmp; + + if (tmpleft == 0) + (void)tmpalloc(1); /* XXX ugly */ + tmp = TMPOLE; + if ((len = vsnprintf(tmp, tmpleft, fmt, ap)) >= tmpleft) { + (void)tmpalloc(tmpleft+1); /* ugly */ + tmp = TMPOLE; + if ((len = vsnprintf(tmp, tmpleft, fmt, ap)) >= tmpleft) + cerror("bad tmpsprintf len"); + } + tmpleft -= len+1; + return tmp; +} + +void +tmpfree() +{ + char *f, *of; + + f = tmplink; + if (f == NULL) + return; + if (*(char **)f == NULL) { + tmpleft = MEMCHUNKSZ - (ROUNDUP(sizeof(char *))); + return; + } + while (f != NULL) { + of = f; + f = *(char **)f; + free(of); + } + tmplink = tmppole = NULL; + tmpleft = 0; +//fprintf(stderr, "freeing tmp\n"); + /* XXX - nothing right now */ +} + +/* + * Allocate space on the permanent stack for a string of length len+1 + * and copy it there. + * Return the new address. + */ +char * +newstring(char *s, int len) +{ + char *u, *c; + + len++; + if (allocleft < len) { + u = c = permalloc(len); + } else { + u = c = &allocpole[MEMCHUNKSZ-allocleft]; + allocleft -= ROUNDUP(len+1); + } + while (len--) + *c++ = *s++; + return u; +} diff --git a/usr.bin/pcc/mip/manifest.h b/usr.bin/pcc/mip/manifest.h new file mode 100644 index 00000000000..dd4cf0ecafb --- /dev/null +++ b/usr.bin/pcc/mip/manifest.h @@ -0,0 +1,316 @@ +/* $Id: manifest.h,v 1.1 2007/09/15 18:12:35 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. + */ + +#ifndef MANIFEST +#define MANIFEST + +#include <stdio.h> +#include "../config.h" +#include "macdefs.h" +#include "node.h" + +/* + * Node types + */ +#define LTYPE 02 /* leaf */ +#define UTYPE 04 /* unary */ +#define BITYPE 010 /* binary */ + +/* + * DSIZE is the size of the dope array + */ +#define DSIZE (MAXOP+1) + +/* + * Type names, used in symbol table building. + * The order of the integer types are important. + * Signed types must have bit 0 unset, unsigned types set (used below). + */ +#define UNDEF 0 /* free symbol table entry */ +#define FARG 1 /* function argument */ +#define CHAR 2 +#define UCHAR 3 +#define SHORT 4 +#define USHORT 5 +#define INT 6 +#define UNSIGNED 7 +#define LONG 8 +#define ULONG 9 +#define LONGLONG 10 +#define ULONGLONG 11 +#define FLOAT 12 +#define DOUBLE 13 +#define LDOUBLE 14 +#define STRTY 15 +#define UNIONTY 16 +#define ENUMTY 17 +#define MOETY 18 /* member of enum */ +#define VOID 19 + +#define MAXTYPES 19 /* highest type+1 to be used by lang code */ +/* + * Various flags + */ +#define NOLAB (-1) + +/* + * Type modifiers. + */ +#define PTR 0x20 +#define FTN 0x40 +#define ARY 0x60 +#define CON 0x20 +#define VOL 0x40 + +/* + * Type packing constants + */ +#define TMASK 0x060 +#define TMASK1 0x180 +#define TMASK2 0x1e0 +#define BTMASK 0x1f +#define BTSHIFT 5 +#define TSHIFT 2 + +/* + * Macros + */ +#define MODTYPE(x,y) x = ((x)&(~BTMASK))|(y) /* set basic type of x to y */ +#define BTYPE(x) ((x)&BTMASK) /* basic type of x */ +#define ISLONGLONG(x) ((x) == LONGLONG || (x) == ULONGLONG) +#define ISUNSIGNED(x) (((x) <= ULONGLONG) && (((x) & 1) == (UNSIGNED & 1))) +#define UNSIGNABLE(x) (((x)<=ULONGLONG&&(x)>=CHAR) && !ISUNSIGNED(x)) +#define ENUNSIGN(x) ((x)|1) +#define DEUNSIGN(x) ((x)&~1) +#define ISPTR(x) (((x)&TMASK)==PTR) +#define ISFTN(x) (((x)&TMASK)==FTN) /* is x a function type? */ +#define ISARY(x) (((x)&TMASK)==ARY) /* is x an array type? */ +#define ISCON(x) (((x)&CON)==CON) /* is x const? */ +#define ISVOL(x) (((x)&VOL)==VOL) /* is x volatile? */ +#define INCREF(x) ((((x)&~BTMASK)<<TSHIFT)|PTR|((x)&BTMASK)) +#define INCQAL(x) ((((x)&~BTMASK)<<TSHIFT)|((x)&BTMASK)) +#define DECREF(x) ((((x)>>TSHIFT)&~BTMASK)|((x)&BTMASK)) +#define DECQAL(x) ((((x)>>TSHIFT)&~BTMASK)|((x)&BTMASK)) +#define SETOFF(x,y) { if ((x)%(y) != 0) (x) = (((x)/(y) + 1) * (y)); } + /* advance x to a multiple of y */ +#define NOFIT(x,y,z) (((x)%(z) + (y)) > (z)) + /* can y bits be added to x without overflowing z */ + +#ifndef SPECIAL_INTEGERS +#define ASGLVAL(lval, val) +#endif + +/* + * Pack and unpack field descriptors (size and offset) + */ +#define PKFIELD(s,o) (((o)<<6)| (s)) +#define UPKFSZ(v) ((v)&077) +#define UPKFOFF(v) ((v)>>6) + +/* + * Operator information + */ +#define TYFLG 016 +#define ASGFLG 01 +#define LOGFLG 020 + +#define SIMPFLG 040 +#define COMMFLG 0100 +#define DIVFLG 0200 +#define FLOFLG 0400 +#define LTYFLG 01000 +#define CALLFLG 02000 +#define MULFLG 04000 +#define SHFFLG 010000 +#define ASGOPFLG 020000 + +#define SPFLG 040000 + +/* + * Location counters + */ +#define PROG 0 /* (ro) program segment */ +#define DATA 1 /* (rw) data segment */ +#define RDATA 2 /* (ro) data segment */ +#define STRNG 3 /* (ro) string segment */ + + +/* + * + */ +extern int bdebug, tdebug, edebug; +extern int ddebug, xdebug, f2debug; +extern int iTflag, oTflag; +extern int vdebug, sflag, nflag, gflag; +extern int Wstrict_prototypes, Wmissing_prototypes, Wimplicit_int, + Wimplicit_function_declaration; +extern int xssaflag, xtailcallflag, xtemps, xdeljumps; + +int yyparse(void); +void yyaccpt(void); + +/* + * List handling macros, similar to those in 4.4BSD. + * The double-linked list is insque-style. + */ +/* Double-linked list macros */ +#define DLIST_INIT(h,f) { (h)->f.q_forw = (h); (h)->f.q_back = (h); } +#define DLIST_ENTRY(t) struct { struct t *q_forw, *q_back; } +#define DLIST_NEXT(h,f) (h)->f.q_forw +#define DLIST_PREV(h,f) (h)->f.q_back +#define DLIST_ISEMPTY(h,f) ((h)->f.q_forw == (h)) +#define DLIST_FOREACH(v,h,f) \ + for ((v) = (h)->f.q_forw; (v) != (h); (v) = (v)->f.q_forw) +#define DLIST_FOREACH_REVERSE(v,h,f) \ + for ((v) = (h)->f.q_back; (v) != (h); (v) = (v)->f.q_back) +#define DLIST_INSERT_BEFORE(h,e,f) { \ + (e)->f.q_forw = (h); \ + (e)->f.q_back = (h)->f.q_back; \ + (e)->f.q_back->f.q_forw = (e); \ + (h)->f.q_back = (e); \ +} +#define DLIST_INSERT_AFTER(h,e,f) { \ + (e)->f.q_forw = (h)->f.q_forw; \ + (e)->f.q_back = (h); \ + (e)->f.q_forw->f.q_back = (e); \ + (h)->f.q_forw = (e); \ +} +#define DLIST_REMOVE(e,f) { \ + (e)->f.q_forw->f.q_back = (e)->f.q_back; \ + (e)->f.q_back->f.q_forw = (e)->f.q_forw; \ +} + +/* Single-linked list */ +#define SLIST_INIT(h) \ + { (h)->q_forw = NULL; (h)->q_last = &(h)->q_forw; } +#define SLIST_ENTRY(t) struct { struct t *q_forw; } +#define SLIST_HEAD(n,t) struct n { struct t *q_forw, **q_last; } +#define SLIST_FIRST(h) ((h)->q_forw) +#define SLIST_FOREACH(v,h,f) \ + for ((v) = (h)->q_forw; (v) != NULL; (v) = (v)->f.q_forw) +#define SLIST_INSERT_LAST(h,e,f) { \ + (e)->f.q_forw = NULL; \ + *(h)->q_last = (e); \ + (h)->q_last = &(e)->f.q_forw; \ +} + +/* + * Functions for inter-pass communication. + * + */ +struct interpass { + DLIST_ENTRY(interpass) qelem; + int type; + int lineno; + union { + NODE *_p; + int _locctr; + int _label; + int _curoff; + char *_name; + } _un; +}; + +/* + * Special struct for prologue/epilogue. + * - ip_lblnum contains the lowest/highest+1 label used + * - ip_lbl is set before/after all code and after/before the prolog/epilog. + */ +struct interpass_prolog { + struct interpass ipp_ip; + char *ipp_name; /* Function name */ + int ipp_vis; /* Function visibility */ + TWORD ipp_type; /* Function type */ + int ipp_regs; /* Bitmask of registers to save */ + int ipp_autos; /* Size on stack needed */ + int ip_tmpnum; /* # allocated temp nodes so far */ + int ip_lblnum; /* # used labels so far */ +}; + +/* + * Epilog/prolog takes following arguments (in order): + * - type + * - regs + * - autos + * - name + * - type + * - retlab + */ + +#define ip_node _un._p +#define ip_locc _un._locctr +#define ip_lbl _un._label +#define ip_name _un._name +#define ip_asm _un._name +#define ip_off _un._curoff + +/* Types of inter-pass structs */ +#define IP_NODE 1 +#define IP_PROLOG 2 +#define IP_EPILOG 4 +#define IP_DEFLAB 5 +#define IP_DEFNAM 6 +#define IP_ASM 7 +#define MAXIP 7 + +void send_passt(int type, ...); +/* + * External declarations, typedefs and the like + */ +char *hash(char *s); +char *savestr(char *cp); +char *tstr(char *cp); + +/* memory management stuff */ +void *permalloc(int size); +void *tmpcalloc(int size); +void *tmpalloc(int size); +void tmpfree(void); +char *newstring(char *, int len); + +void tprint(FILE *, TWORD, TWORD); + +/* pass t communication subroutines */ +void topt_compile(struct interpass *); + +/* pass 2 communication subroutines */ +void pass2_compile(struct interpass *); + +/* node routines */ +NODE *nfree(NODE *); +void fwalk(NODE *t, void (*f)(NODE *, int, int *, int *), int down); + +extern int nerrors; /* number of errors seen so far */ +#endif diff --git a/usr.bin/pcc/mip/match.c b/usr.bin/pcc/mip/match.c new file mode 100644 index 00000000000..503b4698ab0 --- /dev/null +++ b/usr.bin/pcc/mip/match.c @@ -0,0 +1,995 @@ +/* $Id: match.c,v 1.1 2007/09/15 18:12:36 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. + */ + +/* + * 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 "pass2.h" + +#include <strings.h> + +void prttype(int t); +void setclass(int tmp, int class); +int getclass(int tmp); + +int fldsz, fldshf; + +int s2debug = 0; + +extern char *ltyp[], *rtyp[]; + +static char *srtyp[] = { "SRNOPE", "SRDIR", "SROREG", "SRREG" }; + +/* + * return true if shape is appropriate for the node p + * side effect for SFLD is to set up fldsz, etc + * + * Return values: + * SRNOPE Cannot match this shape. + * SRDIR Direct match, may or may not traverse down. + * SRREG Will match if put in a regster XXX - kill this? + */ +int +tshape(NODE *p, int shape) +{ + int o, mask; + + o = p->n_op; + +#ifdef PCC_DEBUG + if (s2debug) + printf("tshape(%p, %s) op = %s\n", p, prcook(shape), opst[o]); +#endif + + if (shape & SPECIAL) { + + switch (shape) { + case SZERO: + case SONE: + case SMONE: + case SSCON: + case SCCON: + if (o != ICON || p->n_name[0]) + return SRNOPE; + if (p->n_lval == 0 && shape == SZERO) + return SRDIR; + if (p->n_lval == 1 && shape == SONE) + return SRDIR; + if (p->n_lval == -1 && shape == SMONE) + return SRDIR; + if (p->n_lval > -257 && p->n_lval < 256 && + shape == SCCON) + return SRDIR; + if (p->n_lval > -32769 && p->n_lval < 32768 && + shape == SSCON) + return SRDIR; + return SRNOPE; + + case SSOREG: /* non-indexed OREG */ + if (o == OREG && !R2TEST(p->n_rval)) + return SRDIR; + return SRNOPE; + + default: + return (special(p, shape)); + } + } + + if (shape & SANY) + return SRDIR; + + if ((shape&INTEMP) && shtemp(p)) /* XXX remove? */ + return SRDIR; + + if ((shape&SWADD) && (o==NAME||o==OREG)) + if (BYTEOFF(p->n_lval)) + return SRNOPE; + + switch (o) { + + case NAME: + if (shape & SNAME) + return SRDIR; + break; + + case ICON: + if (shape & SCON) + return SRDIR; + break; + + case FLD: + if (shape & SFLD) { + int sh; + + if ((sh = flshape(p->n_left)) == SRNOPE) + return sh; + /* it is a FIELD shape; make side-effects */ + /* XXX - this will not work for multi-matches */ + o = p->n_rval; + fldsz = UPKFSZ(o); +# ifdef RTOLBYTES + fldshf = UPKFOFF(o); +# else + fldshf = SZINT - fldsz - UPKFOFF(o); +# endif + return sh; + } + break; + + case CCODES: + if (shape & SCC) + return SRDIR; + break; + + case REG: + case TEMP: + mask = PCLASS(p); + if (shape & mask) + return SRDIR; + break; + + case OREG: + if (shape & SOREG) + return SRDIR; + break; + + case UMUL: + if (shumul(p->n_left) & shape) + return SROREG; /* Calls offstar to traverse down */ + break; + + } + return SRNOPE; +} + +/* + * does the type t match tword + */ +int +ttype(TWORD t, int tword) +{ + if (tword & TANY) + return(1); + +#ifdef PCC_DEBUG + if (t2debug) + printf("ttype(%o, %o)\n", t, tword); +#endif + if (ISPTR(t) && ISFTN(DECREF(t)) && (tword & TFTN)) { + /* For funny function pointers */ + return 1; + } + if (ISPTR(t) && (tword&TPTRTO)) { + do { + t = DECREF(t); + } while (ISARY(t)); + /* arrays that are left are usually only + * in structure references... + */ + return (ttype(t, tword&(~TPTRTO))); + } + if (t != BTYPE(t)) + return (tword & TPOINT); /* TPOINT means not simple! */ + if (tword & TPTRTO) + return(0); + + switch (t) { + case CHAR: + return( tword & TCHAR ); + case SHORT: + return( tword & TSHORT ); + case STRTY: + case UNIONTY: + return( tword & TSTRUCT ); + case INT: + return( tword & TINT ); + case UNSIGNED: + return( tword & TUNSIGNED ); + case USHORT: + return( tword & TUSHORT ); + case UCHAR: + return( tword & TUCHAR ); + case ULONG: + return( tword & TULONG ); + case LONG: + return( tword & TLONG ); + case LONGLONG: + return( tword & TLONGLONG ); + case ULONGLONG: + return( tword & TULONGLONG ); + case FLOAT: + return( tword & TFLOAT ); + case DOUBLE: + return( tword & TDOUBLE ); + case LDOUBLE: + return( tword & TLDOUBLE ); + } + + return(0); +} + +/* + * generate code by interpreting table entry + */ +void +expand(NODE *p, int cookie, char *cp) +{ + CONSZ val; + + for( ; *cp; ++cp ){ + switch( *cp ){ + + default: + PUTCHAR( *cp ); + continue; /* this is the usual case... */ + + case 'Z': /* special machine dependent operations */ + zzzcode( p, *++cp ); + continue; + + case 'F': /* this line deleted if FOREFF is active */ + if( cookie & FOREFF ) while( *++cp != '\n' ) ; /* VOID */ + continue; + + case 'S': /* field size */ + printf( "%d", fldsz ); + continue; + + case 'H': /* field shift */ + printf( "%d", fldshf ); + continue; + + case 'M': /* field mask */ + case 'N': /* complement of field mask */ + val = 1; + val <<= fldsz; + --val; + val <<= fldshf; + adrcon( *cp=='M' ? val : ~val ); + continue; + + case 'L': /* output special label field */ + if (*++cp == 'C') + printf(LABFMT, p->n_label); + else + printf(LABFMT, (int)getlr(p,*cp)->n_lval); + continue; + + case 'O': /* opcode string */ + hopcode( *++cp, p->n_op ); + continue; + + case 'B': /* byte offset in word */ + val = getlr(p,*++cp)->n_lval; + val = BYTEOFF(val); + printf( CONFMT, val ); + continue; + + case 'C': /* for constant value only */ + conput(stdout, getlr( p, *++cp ) ); + continue; + + case 'I': /* in instruction */ + insput( getlr( p, *++cp ) ); + continue; + + case 'A': /* address of */ + adrput(stdout, getlr( p, *++cp ) ); + continue; + + case 'U': /* for upper half of address, only */ + upput(getlr(p, *++cp), SZLONG); + continue; + + } + + } + + } + +NODE resc[4]; + +NODE * +getlr(NODE *p, int c) +{ + NODE *q; + + /* return the pointer to the left or right side of p, or p itself, + depending on the optype of p */ + + switch (c) { + + case '1': + case '2': + case '3': + case 'D': + if (c == 'D') + c = 0; + else + c -= '0'; + q = &resc[c]; + q->n_op = REG; + q->n_type = p->n_type; /* XXX should be correct type */ + q->n_rval = DECRA(p->n_reg, c); + q->n_su = p->n_su; + return q; + + case 'L': + return( optype( p->n_op ) == LTYPE ? p : p->n_left ); + + case 'R': + return( optype( p->n_op ) != BITYPE ? p : p->n_right ); + + } + cerror( "bad getlr: %c", c ); + /* NOTREACHED */ + return NULL; +} + +static char *tarr[] = { + "CHAR", "SHORT", "INT", "LONG", "FLOAT", "DOUBLE", "POINT", "UCHAR", + "USHORT", "UINT", "ULONG", "PTRTO", "ANY", "STRUCT", "LONGLONG", + "ULONGLONG", +}; + +void +prttype(int t) +{ + int i, gone = 0; + + for (i = 0; i < 16; i++) + if ((t >> i) & 1) { + if (gone) putchar('|'); + gone++; + printf("%s", tarr[i]); + } +} + + +#ifdef PCC_DEBUG +#define F2DEBUG(x) if (f2debug) printf x +#define F2WALK(x) if (f2debug) fwalk(x, e2print, 0) +#else +#define F2DEBUG(x) +#define F2WALK(x) +#endif + +/* + * Convert a node to REG or OREG. + * Shape is register class where we want the result. + * Returns register class if register nodes. + * If w is: (should be shapes) + * - LREG - result in register, call geninsn(). + * - LOREG - create OREG; call offstar(). + * - 0 - clear su, walk down. + */ +static int +swmatch(NODE *p, int shape, int w) +{ + int rv = 0; + + switch (w) { + case LREG: + rv = geninsn(p, shape); + break; + + case LOREG: + /* should be here only if op == UMUL */ + if (p->n_op != UMUL && p->n_op != FLD) + comperr("swmatch %p", p); + if (p->n_op == FLD) { + offstar(p->n_left->n_left, shape); + p->n_left->n_su = 0; + } else + offstar(p->n_left, shape); + p->n_su = 0; + rv = ffs(shape)-1; + break; + + case 0: + if (optype(p->n_op) == BITYPE) + swmatch(p->n_right, 0, 0); + if (optype(p->n_op) != LTYPE) + swmatch(p->n_left, 0, 0); + p->n_su = 0; + } + return rv; + +} + +/* + * Help routines for find*() functions. + * If the node will be a REG node and it will be rewritten in the + * instruction, ask for it to be put in a register. + */ +static int +chcheck(NODE *p, int shape, int rew) +{ + int sh, sha; + + sha = shape; + if (shape & SPECIAL) + shape = 0; + + switch ((sh = tshape(p, sha))) { + case SRNOPE: + if (shape & INREGS) + sh = SRREG; + break; + + case SROREG: + case SRDIR: + if (rew == 0) + break; + if (shape & INREGS) + sh = SRREG; + else + sh = SRNOPE; + break; + } + return sh; +} + +/* + * Check how to walk further down. + * Merge with swmatch()? + * sh - shape for return value (register class). + * p - node (for this leg) + * shape - given shape for this leg + * cookie - cookie given for parent node + * rv - switch key for traversing down + * returns register class. + */ +static int +shswitch(int sh, NODE *p, int shape, int cookie, int rew, int go) +{ + int lsh; + + switch (go) { + case SRDIR: /* direct match, just clear su */ + (void)swmatch(p, 0, 0); + break; + + case SROREG: /* call offstar to prepare for OREG conversion */ + (void)swmatch(p, shape, LOREG); + break; + + case SRREG: /* call geninsn() to get value into register */ + lsh = shape & INREGS; + if (rew && cookie != FOREFF) + lsh &= (cookie & INREGS); + lsh = swmatch(p, lsh, LREG); + if (rew) + sh = lsh; + break; + } + return sh; +} + +/* + * Find the best instruction to evaluate the given tree. + * Best is to match both subnodes directly, second-best is if + * subnodes must be evaluated into OREGs, thereafter if nodes + * must be put into registers. + * Whether 2-op instructions or 3-op is preferred is depending on in + * which order they are found in the table. + * mtchno is set to the count of regs needed for its legs. + */ +int +findops(NODE *p, int cookie) +{ + extern int *qtable[]; + struct optab *q, *qq = NULL; + int i, shl, shr, *ixp, sh; + int lvl = 10, idx = 0, gol = 0, gor = 0; + NODE *l, *r; + + F2DEBUG(("findops node %p (%s)\n", p, prcook(cookie))); + F2WALK(p); + + ixp = qtable[p->n_op]; + l = getlr(p, 'L'); + r = getlr(p, 'R'); + for (i = 0; ixp[i] >= 0; i++) { + q = &table[ixp[i]]; + + F2DEBUG(("findop: ixp %d\n", ixp[i])); + if (ttype(l->n_type, q->ltype) == 0 || + ttype(r->n_type, q->rtype) == 0) + continue; /* Types must be correct */ + + if ((cookie & q->visit) == 0) + continue; /* must get a result */ + + F2DEBUG(("findop got types\n")); + + if ((shl = chcheck(l, q->lshape, q->rewrite & RLEFT)) == SRNOPE) + continue; + + F2DEBUG(("findop lshape %d\n", shl)); + F2WALK(l); + + if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT))== SRNOPE) continue; + + F2DEBUG(("findop rshape %d\n", shr)); + F2WALK(r); + + if (q->needs & REWRITE) + break; /* Done here */ + + if (lvl <= (shl + shr)) + continue; + lvl = shl + shr; + qq = q; + idx = ixp[i]; + gol = shl; + gor = shr; + } + if (lvl == 10) { + F2DEBUG(("findops failed\n")); + if (setbin(p)) + return FRETRY; + return FFAIL; + } + + F2DEBUG(("findops entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor])); + + sh = -1; + + sh = shswitch(sh, p->n_left, qq->lshape, cookie, + qq->rewrite & RLEFT, gol); + sh = shswitch(sh, p->n_right, qq->rshape, cookie, + qq->rewrite & RRIGHT, gor); + + if (sh == -1) { + if (cookie == FOREFF) + sh = 0; + else + sh = ffs(cookie & qq->visit & INREGS)-1; + } + F2DEBUG(("findops: node %p (%s)\n", p, prcook(1 << sh))); + p->n_su = MKIDX(idx, 0); + SCLASS(p->n_su, sh); + return sh; +} + +/* + * Find the best relation op for matching the two trees it has. + * This is a sub-version of the function findops() above. + * The instruction with the lowest grading is emitted. + * + * Level assignment for priority: + * left right prio + * - - - + * direct direct 1 + * direct OREG 2 # make oreg + * OREG direct 2 # make oreg + * OREG OREG 2 # make both oreg + * direct REG 3 # put in reg + * OREG REG 3 # put in reg, make oreg + * REG direct 3 # put in reg + * REG OREG 3 # put in reg, make oreg + * REG REG 4 # put both in reg + */ +int +relops(NODE *p) +{ + extern int *qtable[]; + struct optab *q; + int i, shl = 0, shr = 0; + NODE *l, *r; + int *ixp, idx = 0; + int lvl = 10, gol = 0, gor = 0; + + F2DEBUG(("relops tree:\n")); + F2WALK(p); + + l = getlr(p, 'L'); + r = getlr(p, 'R'); + ixp = qtable[p->n_op]; + for (i = 0; ixp[i] >= 0; i++) { + q = &table[ixp[i]]; + + F2DEBUG(("relops: ixp %d\n", ixp[i])); + if (ttype(l->n_type, q->ltype) == 0 || + ttype(r->n_type, q->rtype) == 0) + continue; /* Types must be correct */ + + F2DEBUG(("relops got types\n")); + if ((shl = chcheck(l, q->lshape, 0)) == SRNOPE) + continue; + F2DEBUG(("relops lshape %d\n", shl)); + F2WALK(p); + if ((shr = chcheck(r, q->rshape, 0)) == SRNOPE) + continue; + F2DEBUG(("relops rshape %d\n", shr)); + F2WALK(p); + if (q->needs & REWRITE) + break; /* Done here */ + + if (lvl <= (shl + shr)) + continue; + lvl = shl + shr; + idx = ixp[i]; + gol = shl; + gor = shr; + } + if (lvl == 10) { + F2DEBUG(("relops failed\n")); + if (setbin(p)) + return FRETRY; + return FFAIL; + } + F2DEBUG(("relops entry %d(%s %s)\n", idx, srtyp[gol], srtyp[gor])); + + q = &table[idx]; + + (void)shswitch(-1, p->n_left, q->lshape, FORCC, + q->rewrite & RLEFT, gol); + + (void)shswitch(-1, p->n_right, q->rshape, FORCC, + q->rewrite & RRIGHT, gor); + + F2DEBUG(("findops: node %p\n", p)); + p->n_su = MKIDX(idx, 0); + SCLASS(p->n_su, CLASSA); /* XXX */ + return 0; +} + +/* + * Find a matching assign op. + * + * Level assignment for priority: + * left right prio + * - - - + * direct direct 1 + * direct REG 2 + * direct OREG 3 + * OREG direct 4 + * OREG REG 5 + * OREG OREG 6 + */ +int +findasg(NODE *p, int cookie) +{ + extern int *qtable[]; + struct optab *q; + int i, sh, shl, shr, lvl = 10; + NODE *l, *r; + int *ixp; + struct optab *qq = NULL; /* XXX gcc */ + int idx = 0, gol = 0, gor = 0; + + shl = shr = 0; + + F2DEBUG(("findasg tree: %s\n", prcook(cookie))); + F2WALK(p); + + ixp = qtable[p->n_op]; + l = getlr(p, 'L'); + r = getlr(p, 'R'); + for (i = 0; ixp[i] >= 0; i++) { + q = &table[ixp[i]]; + + F2DEBUG(("asgop: ixp %d\n", ixp[i])); + if (ttype(l->n_type, q->ltype) == 0 || + ttype(r->n_type, q->rtype) == 0) + continue; /* Types must be correct */ + + if ((cookie & q->visit) == 0) + continue; /* must get a result */ + + F2DEBUG(("asgop got types\n")); + if ((shl = tshape(l, q->lshape)) == SRNOPE) + continue; + + if (shl == SRREG) + continue; + + F2DEBUG(("asgop lshape %d\n", shl)); + F2WALK(l); + + if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT))== SRNOPE) + continue; + + F2DEBUG(("asgop rshape %d\n", shr)); + F2WALK(r); + if (q->needs & REWRITE) + break; /* Done here */ + + if (lvl <= (shl + shr)) + continue; + + lvl = shl + shr; + qq = q; + idx = ixp[i]; + gol = shl; + gor = shr; + } + + if (lvl == 10) { + F2DEBUG(("findasg failed\n")); + if (setasg(p, cookie)) + return FRETRY; + return FFAIL; + } + F2DEBUG(("findasg entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor])); + + sh = -1; + sh = shswitch(sh, p->n_left, qq->lshape, cookie, + qq->rewrite & RLEFT, gol); + + sh = shswitch(sh, p->n_right, qq->rshape, cookie, + qq->rewrite & RRIGHT, gor); + + if (sh == -1) { + if (cookie == FOREFF) + sh = 0; + else + sh = ffs(cookie & qq->visit & INREGS)-1; + } + F2DEBUG(("findasg: node %p class %d\n", p, sh)); + + p->n_su = MKIDX(idx, 0); + SCLASS(p->n_su, sh); + + return sh; +} + +/* + * Search for an UMUL table entry that can turn an indirect node into + * a move from an OREG. + */ +int +findumul(NODE *p, int cookie) +{ + extern int *qtable[]; + struct optab *q = NULL; /* XXX gcc */ + int i, shl = 0, shr = 0, sh; + int *ixp; + + F2DEBUG(("findumul p %p (%s)\n", p, prcook(cookie))); + F2WALK(p); + + ixp = qtable[p->n_op]; + for (i = 0; ixp[i] >= 0; i++) { + q = &table[ixp[i]]; + + F2DEBUG(("findumul: ixp %d\n", ixp[i])); + if ((q->visit & cookie) == 0) + continue; /* wrong registers */ + + if (ttype(p->n_type, q->rtype) == 0) + continue; /* Types must be correct */ + + + F2DEBUG(("findumul got types, rshape %s\n", prcook(q->rshape))); + /* + * Try to create an OREG of the node. + * Fake left even though it's right node, + * to be sure of conversion if going down left. + */ + if ((shl = chcheck(p, q->rshape, 0)) == SRNOPE) + continue; + + shr = 0; + + if (q->needs & REWRITE) + break; /* Done here */ + + F2DEBUG(("findumul got shape %s\n", srtyp[shl])); + + break; /* XXX search better matches */ + } + if (ixp[i] < 0) { + F2DEBUG(("findumul failed\n")); + if (setuni(p, cookie)) + return FRETRY; + return FFAIL; + } + F2DEBUG(("findumul entry %d(%s %s)\n", ixp[i], srtyp[shl], srtyp[shr])); + + sh = shswitch(-1, p, q->rshape, cookie, q->rewrite & RLEFT, shl); + if (sh == -1) + sh = ffs(cookie & q->visit & INREGS)-1; + + F2DEBUG(("findumul: node %p (%s)\n", p, prcook(1 << sh))); + p->n_su = MKIDX(ixp[i], 0); + SCLASS(p->n_su, sh); + return sh; +} + +/* + * Find a leaf type node that puts the value into a register. + */ +int +findleaf(NODE *p, int cookie) +{ + extern int *qtable[]; + struct optab *q = NULL; /* XXX gcc */ + int i, sh; + int *ixp; + + F2DEBUG(("findleaf p %p (%s)\n", p, prcook(cookie))); + F2WALK(p); + + ixp = qtable[p->n_op]; + for (i = 0; ixp[i] >= 0; i++) { + q = &table[ixp[i]]; + + F2DEBUG(("findleaf: ixp %d\n", ixp[i])); + if ((q->visit & cookie) == 0) + continue; /* wrong registers */ + + if (ttype(p->n_type, q->rtype) == 0 || + ttype(p->n_type, q->ltype) == 0) + continue; /* Types must be correct */ + + F2DEBUG(("findleaf got types, rshape %s\n", prcook(q->rshape))); + + if (chcheck(p, q->rshape, 0) != SRDIR) + continue; + + if (q->needs & REWRITE) + break; /* Done here */ + + break; + } + if (ixp[i] < 0) { + F2DEBUG(("findleaf failed\n")); + if (setuni(p, cookie)) + return FRETRY; + return FFAIL; + } + F2DEBUG(("findleaf entry %d\n", ixp[i])); + + sh = ffs(cookie & q->visit & INREGS)-1; + F2DEBUG(("findleaf: node %p (%s)\n", p, prcook(1 << sh))); + p->n_su = MKIDX(ixp[i], 0); + SCLASS(p->n_su, sh); + return sh; +} + +/* + * Find a UNARY op that satisfy the needs. + * For now, the destination is always a register. + * Both source and dest types must match, but only source (left) + * shape is of interest. + */ +int +finduni(NODE *p, int cookie) +{ + extern int *qtable[]; + struct optab *q; + NODE *l, *r; + int i, shl = 0, num = 4; + int *ixp, idx = 0; + int sh; + + F2DEBUG(("finduni tree: %s\n", prcook(cookie))); + F2WALK(p); + + l = getlr(p, 'L'); + if (p->n_op == CALL || p->n_op == FORTCALL || p->n_op == STCALL) + r = p; + else + r = getlr(p, 'R'); + ixp = qtable[p->n_op]; + for (i = 0; ixp[i] >= 0; i++) { + q = &table[ixp[i]]; + + F2DEBUG(("finduni: ixp %d\n", ixp[i])); + if (ttype(l->n_type, q->ltype) == 0) + continue; /* Type must be correct */ + + F2DEBUG(("finduni got left type\n")); + if (ttype(r->n_type, q->rtype) == 0) + continue; /* Type must be correct */ + + F2DEBUG(("finduni got types\n")); + if ((shl = chcheck(l, q->lshape, q->rewrite & RLEFT)) == SRNOPE) + continue; + + F2DEBUG(("finduni got shapes %d\n", shl)); + + if ((cookie & q->visit) == 0) /* check correct return value */ + continue; /* XXX - should check needs */ + + /* avoid clobbering of longlived regs */ + /* let register allocator coalesce */ + if ((q->rewrite & RLEFT) && (shl == SRDIR) /* && isreg(l) */) + shl = SRREG; + + F2DEBUG(("finduni got cookie\n")); + if (q->needs & REWRITE) + break; /* Done here */ + + if (shl >= num) + continue; + num = shl; + idx = ixp[i]; + + if (shl == SRDIR) + break; + } + + if (num == 4) { + F2DEBUG(("finduni failed\n")); + } else + F2DEBUG(("finduni entry %d(%s)\n", idx, srtyp[num])); + + if (num == 4) { + if (setuni(p, cookie)) + return FRETRY; + return FFAIL; + } + q = &table[idx]; + + sh = shswitch(-1, p->n_left, q->lshape, cookie, + q->rewrite & RLEFT, num); + if (sh == -1) + sh = ffs(cookie & q->visit & INREGS)-1; + if (sh == -1) + sh = 0; + + F2DEBUG(("finduni: node %p (%s)\n", p, prcook(1 << sh))); + p->n_su = MKIDX(idx, 0); + SCLASS(p->n_su, sh); + return sh; +} diff --git a/usr.bin/pcc/mip/mkext.c b/usr.bin/pcc/mip/mkext.c new file mode 100644 index 00000000000..347dd8ee43f --- /dev/null +++ b/usr.bin/pcc/mip/mkext.c @@ -0,0 +1,318 @@ + +/* + * Generate defines for the needed hardops. + */ +#include "pass2.h" + +#include <string.h> + +int chkop[MAXOP]; + +void mktables(void); + +char *cname = "external.c"; +char *hname = "external.h"; +FILE *fc, *fh; + +/* + * masks for matching dope with shapes + */ +int mamask[] = { + SIMPFLG, /* OPSIMP */ + SIMPFLG|ASGFLG, /* ASG OPSIMP */ + COMMFLG, /* OPCOMM */ + COMMFLG|ASGFLG, /* ASG OPCOMM */ + MULFLG, /* OPMUL */ + MULFLG|ASGFLG, /* ASG OPMUL */ + DIVFLG, /* OPDIV */ + DIVFLG|ASGFLG, /* ASG OPDIV */ + UTYPE, /* OPUNARY */ + TYFLG, /* ASG OPUNARY is senseless */ + LTYPE, /* OPLEAF */ + TYFLG, /* ASG OPLEAF is senseless */ + 0, /* OPANY */ + ASGOPFLG|ASGFLG, /* ASG OPANY */ + LOGFLG, /* OPLOG */ + TYFLG, /* ASG OPLOG is senseless */ + FLOFLG, /* OPFLOAT */ + FLOFLG|ASGFLG, /* ASG OPFLOAT */ + SHFFLG, /* OPSHFT */ + SHFFLG|ASGFLG, /* ASG OPSHIFT */ + SPFLG, /* OPLTYPE */ + TYFLG, /* ASG OPLTYPE is senseless */ + }; + + +struct checks { + int op, type; + char *name; +} checks[] = { + { MUL, TLONGLONG, "SMULLL", }, + { DIV, TLONGLONG, "SDIVLL", }, + { MOD, TLONGLONG, "SMODLL", }, + { PLUS, TLONGLONG, "SPLUSLL", }, + { MINUS, TLONGLONG, "SMINUSLL", }, + { MUL, TULONGLONG, "UMULLL", }, + { DIV, TULONGLONG, "UDIVLL", }, + { MOD, TULONGLONG, "UMODLL", }, + { PLUS, TULONGLONG, "UPLUSLL", }, + { MINUS, TULONGLONG, "UMINUSLL", }, + { 0, 0, 0, }, +}; + +int rstatus[] = { RSTATUS }; +int roverlay[MAXREGS][MAXREGS] = { ROVERLAP }; +int regclassmap[NUMCLASS][MAXREGS]; + +static void +compl(struct optab *q, char *str) +{ + printf("table entry %td, op %s: %s\n", q - table, opst[q->op], str); +} + +int +main(int argc, char *argv[]) +{ + struct optab *q; + struct checks *ch; + int i, j, areg, breg, creg, dreg, mx; + char *bitary; + int bitsz, rval, nelem; + + mkdope(); + + for (q = table; q->op != FREE; q++) { + if (q->op >= OPSIMP) + continue; + if ((q->ltype & TLONGLONG) && + (q->rtype & TLONGLONG)) + chkop[q->op] |= TLONGLONG; + if ((q->ltype & TULONGLONG) && + (q->rtype & TULONGLONG)) + chkop[q->op] |= TULONGLONG; + } + if ((fc = fopen(cname, "w")) == NULL) { + perror("open cfile"); + return(1); + } + if ((fh = fopen(hname, "w")) == NULL) { + perror("open hfile"); + return(1); + } + for (ch = checks; ch->op != 0; ch++) { + if ((chkop[ch->op] & ch->type) == 0) + fprintf(fh, "#define NEED_%s\n", ch->name); + } + + fprintf(fc, "#include \"pass2.h\"\n"); + /* create fast-lookup tables */ + mktables(); + + /* create efficient bitset sizes */ + if (sizeof(long) == 8) { /* 64-bit arch */ + bitary = "long"; + bitsz = 64; + } else { + bitary = "int"; + bitsz = sizeof(int) == 4 ? 32 : 16; + } + fprintf(fh, "#define NUMBITS %d\n", bitsz); + fprintf(fh, "#define BITSET(arr, bit) " + "(arr[bit/NUMBITS] |= (1 << (bit & (NUMBITS-1))))\n"); + fprintf(fh, "#define BITCLEAR(arr, bit) " + "(arr[bit/NUMBITS] &= ~(1 << (bit & (NUMBITS-1))))\n"); + fprintf(fh, "#define TESTBIT(arr, bit) " + "(arr[bit/NUMBITS] & (1 << (bit & (NUMBITS-1))))\n"); + fprintf(fh, "typedef %s bittype;\n", bitary); + + /* register class definitions, used by graph-coloring */ + /* TODO */ + + /* Sanity-check the table */ + rval = 0; + for (q = table; q->op != FREE; q++) { + if (q->op == ASSIGN) { +#define F(x) (q->visit & x && q->rewrite & (RLEFT|RRIGHT) && \ + q->lshape & ~x && q->rshape & ~x) + if (F(INAREG) || F(INBREG) || F(INCREG) || F(INDREG)) { + compl(q, "may match without result register"); + rval++; + } +#undef F + if ((q->visit & INREGS) && q->rewrite != RDEST) { + compl(q, "ASSIGN reclaim must be RDEST"); + rval++; + } + } + if (q->rewrite & (RESC1|RESC2|RESC1) && q->visit & FOREFF) + compl(q, "FOREFF may cause reclaim of wrong class"); + } + + /* print out list of scratched and permanent registers */ + fprintf(fh, "extern int tempregs[], permregs[];\n"); + fprintf(fc, "int tempregs[] = { "); + for (i = j = 0; i < MAXREGS; i++) + if (rstatus[i] & TEMPREG) + fprintf(fc, "%d, ", i), j++; + fprintf(fc, "-1 };\n"); + fprintf(fh, "#define NTEMPREG %d\n", j+1); + fprintf(fh, "#define FREGS %d\n", j); /* XXX - to die */ + fprintf(fc, "int permregs[] = { "); + for (i = j = 0; i < MAXREGS; i++) + if (rstatus[i] & PERMREG) + fprintf(fc, "%d, ", i), j++; + fprintf(fc, "-1 };\n"); + fprintf(fh, "#define NPERMREG %d\n", j+1); + + /* + * The register allocator uses bitmasks of registers for each class. + */ + areg = breg = creg = dreg = 0; + for (i = 0; i < MAXREGS; i++) { + regclassmap[0][i] = regclassmap[1][i] = regclassmap[2][i] = + regclassmap[3][i] = -1; + if (rstatus[i] & SAREG) regclassmap[0][i] = areg++; + if (rstatus[i] & SBREG) regclassmap[1][i] = breg++; + if (rstatus[i] & SCREG) regclassmap[2][i] = creg++; + if (rstatus[i] & SDREG) regclassmap[3][i] = dreg++; + } + fprintf(fh, "#define AREGCNT %d\n", areg); + fprintf(fh, "#define BREGCNT %d\n", breg); + fprintf(fh, "#define CREGCNT %d\n", creg); + fprintf(fh, "#define DREGCNT %d\n", dreg); + if (areg > bitsz) + printf("%d regs in class A (max %d)\n", areg, bitsz), rval++; + if (breg > bitsz) + printf("%d regs in class B (max %d)\n", breg, bitsz), rval++; + if (creg > bitsz) + printf("%d regs in class C (max %d)\n", creg, bitsz), rval++; + if (dreg > bitsz) + printf("%d regs in class D (max %d)\n", dreg, bitsz), rval++; + + fprintf(fc, "static int amap[MAXREGS][NUMCLASS] = {\n"); + for (i = 0; i < MAXREGS; i++) { + int ba, bb, bc, bd, r; + ba = bb = bc = bd = 0; + if (rstatus[i] & SAREG) ba = (1 << regclassmap[0][i]); + if (rstatus[i] & SBREG) bb = (1 << regclassmap[1][i]); + if (rstatus[i] & SCREG) bc = (1 << regclassmap[2][i]); + if (rstatus[i] & SDREG) bd = (1 << regclassmap[3][i]); + for (j = 0; roverlay[i][j] >= 0; j++) { + r = roverlay[i][j]; + if (rstatus[r] & SAREG) + ba |= (1 << regclassmap[0][r]); + if (rstatus[r] & SBREG) + bb |= (1 << regclassmap[1][r]); + if (rstatus[r] & SCREG) + bc |= (1 << regclassmap[2][r]); + if (rstatus[r] & SDREG) + bd |= (1 << regclassmap[3][r]); + } + fprintf(fc, "\t{ 0x%x,0x%x,0x%x,0x%x },\n", ba, bb, bc, bd); + } + fprintf(fc, "};\n"); + + fprintf(fh, "int aliasmap(int class, int regnum);\n"); + fprintf(fc, "int\naliasmap(int class, int regnum)\n{\n"); + fprintf(fc, " return amap[regnum][class-1];\n}\n"); + + /* routines to convert back from color to regnum */ + mx = areg; + if (breg > mx) mx = breg; + if (creg > mx) mx = creg; + if (dreg > mx) mx = dreg; + fprintf(fc, "static int rmap[NUMCLASS][%d] = {\n", mx); + for (j = 0; j < NUMCLASS; j++) { + int cl = (1 << (j+1)); + fprintf(fc, "\t{ "); + for (i = 0; i < MAXREGS; i++) + if (rstatus[i] & cl) fprintf(fc, "%d, ", i); + fprintf(fc, "},\n"); + } + fprintf(fc, "};\n\n"); + + fprintf(fh, "int color2reg(int color, int class);\n"); + fprintf(fc, "int\ncolor2reg(int color, int class)\n{\n"); + fprintf(fc, " return rmap[class-1][color];\n}\n"); + + /* used by register allocator */ + fprintf(fc, "int regK[] = { 0, %d, %d, %d, %d };\n", + areg, breg, creg, dreg); + fprintf(fc, "int\nclassmask(int class)\n{\n"); + fprintf(fc, "\tif(class == CLASSA) return 0x%x;\n", (1 << areg)-1); + fprintf(fc, "\tif(class == CLASSB) return 0x%x;\n", (1 << breg)-1); + fprintf(fc, "\tif(class == CLASSC) return 0x%x;\n", (1 << creg)-1); + fprintf(fc, "\treturn 0x%x;\n}\n", (1 << dreg)-1); + + fprintf(fh, "int interferes(int reg1, int reg2);\n"); + nelem = (MAXREGS+bitsz-1)/bitsz; + fprintf(fc, "static bittype ovlarr[MAXREGS][%d] = {\n", nelem); + for (i = 0; i < MAXREGS; i++) { + int el[10]; + memset(el, 0, sizeof(el)); + el[i/bitsz] = 1 << (i % bitsz); + for (j = 0; roverlay[i][j] >= 0; j++) { + int k = roverlay[i][j]; + el[k/bitsz] |= (1 << (k % bitsz)); + } + fprintf(fc, "{ "); + for (j = 0; j < MAXREGS; j += bitsz) + fprintf(fc, "0x%x, ", el[j/bitsz]); + fprintf(fc, " },\n"); + } + fprintf(fc, "};\n"); + + fprintf(fc, "int\ninterferes(int reg1, int reg2)\n{\n"); + fprintf(fc, "return TESTBIT(ovlarr[reg1], reg2);\n}\n"); + fclose(fc); + fclose(fh); + return rval; +} + +#define P(x) fprintf x + +void +mktables() +{ + struct optab *op; + int mxalen = 0, curalen; + int i; + +// P((fc, "#include \"pass2.h\"\n\n")); + for (i = 0; i <= MAXOP; i++) { + curalen = 0; + P((fc, "static int op%d[] = { ", i)); + if (dope[i] != 0) + for (op = table; op->op != FREE; op++) { + if (op->op < OPSIMP) { + if (op->op == i) { + P((fc, "%td, ", op - table)); + curalen++; + } + } else { + int opmtemp; + if ((opmtemp=mamask[op->op - OPSIMP])&SPFLG) { + if (i==NAME || i==ICON || i==TEMP || + i==OREG || i == REG) { + P((fc, "%td, ", op - table)); + curalen++; + } + } else if ((dope[i]&(opmtemp|ASGFLG))==opmtemp){ + P((fc, "%td, ", op - table)); + curalen++; + } + } + } + if (curalen > mxalen) + mxalen = curalen; + P((fc, "-1 };\n")); + } + P((fc, "\n")); + + P((fc, "int *qtable[] = { \n")); + for (i = 0; i <= MAXOP; i++) { + P((fc, " op%d,\n", i)); + } + P((fc, "};\n")); + P((fh, "#define MAXOPLEN %d\n", mxalen+1)); +} diff --git a/usr.bin/pcc/mip/node.h b/usr.bin/pcc/mip/node.h new file mode 100644 index 00000000000..3d42df7500c --- /dev/null +++ b/usr.bin/pcc/mip/node.h @@ -0,0 +1,194 @@ +/* $Id: node.h,v 1.1 2007/09/15 18:12:36 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. + */ + +/* + * The node structure is the basic element in the compiler. + * Depending on the operator, it may be one of several types. + * + * This is rewritten to be a struct instead of a union as it + * was in the old compiler. + */ +typedef unsigned int TWORD; +#define NIL (NODE *)0 + +struct symtab; +struct suedef; +struct regw; + +typedef struct node { + struct node *next; + int n_op; + union { + int _reg; + struct regw *_regw; + } n_3; +#define n_reg n_3._reg +#define n_regw n_3._regw + TWORD n_type; + TWORD n_qual; + int n_su; + union { + char * _name; + int _stsize; + union dimfun *_df; + } n_5; + union { + int _label; + int _stalign; + struct suedef *_sue; + } n_6; + union { + struct { + union { + struct node *_left; + CONSZ _lval; +#ifdef SPECIAL_INTEGERS + SPECLVAL _slval; +#endif + } n_l; + union { + struct node *_right; + int _rval; + struct symtab *_sp; + } n_r; + } n_u; + long double _dcon; + } n_f; +} NODE; + +#define n_name n_5._name +#define n_stsize n_5._stsize +#define n_df n_5._df + +#define n_label n_6._label +#define n_stalign n_6._stalign +#define n_sue n_6._sue + +#define n_left n_f.n_u.n_l._left +#define n_lval n_f.n_u.n_l._lval +#define n_slval n_f.n_u.n_l._slval +#define n_right n_f.n_u.n_r._right +#define n_rval n_f.n_u.n_r._rval +#define n_sp n_f.n_u.n_r._sp +#define n_dcon n_f._dcon + +/* + * Node types. + * + * MAXOP is the highest number used by the backend. + */ + +#define FREE 1 +/* + * Value nodes. + */ +#define NAME 2 +#define ICON 4 +#define FCON 5 +#define REG 6 +#define OREG 7 +#define TEMP 8 +#define MOVE 9 /* Special reg-reg move node */ + +/* + * Arithmetic nodes. + */ +#define PLUS 10 +#define MINUS 11 +#define DIV 12 +#define MOD 13 +#define MUL 14 + +/* + * Bitwise operations. + */ +#define AND 15 +#define OR 16 +#define ER 17 +#define LS 18 +#define RS 19 +#define COMPL 20 + +#define UMUL 23 +#define UMINUS 24 + +/* + * Logical compare nodes. + */ +#define EQ 25 +#define NE 26 +#define LE 27 +#define LT 28 +#define GE 29 +#define GT 30 +#define ULE 31 +#define ULT 32 +#define UGE 33 +#define UGT 34 + +/* + * Branch nodes. + */ +#define CBRANCH 35 + +/* + * Convert types. + */ +#define FLD 36 +#define SCONV 37 +#define PCONV 38 +#define PMCONV 39 +#define PVCONV 40 + +/* + * Function calls. + */ +#define CALL 41 +#define UCALL 42 +#define FORTCALL 43 +#define UFORTCALL 44 +#define STCALL 45 +#define USTCALL 46 + +/* + * Other used nodes. + */ +#define CCODES 47 +#define CM 48 +#define ASSIGN 49 +#define STASG 50 +#define STARG 51 +#define FORCE 52 +/* #define INIT 53 */ +#define GOTO 54 +#define RETURN 55 +#define STREF 56 +#define FUNARG 57 +#define ADDROF 58 + +#define MAXOP 58 diff --git a/usr.bin/pcc/mip/optim2.c b/usr.bin/pcc/mip/optim2.c new file mode 100644 index 00000000000..fcf367eb412 --- /dev/null +++ b/usr.bin/pcc/mip/optim2.c @@ -0,0 +1,882 @@ +/* $Id: optim2.c,v 1.1 2007/09/15 18:12:36 otto Exp $ */ +/* + * Copyright (c) 2004 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> +#include <stdlib.h> + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#define BDEBUG(x) if (b2debug) printf x + +static int dfsnum; + +void saveip(struct interpass *ip); +void deljumps(struct interpass *); +void optdump(struct interpass *ip); +void printip(struct interpass *pole); + +static struct varinfo defsites; +struct interpass *storesave; +static struct interpass_prolog *ipp, *epp; /* prolog/epilog */ + +void bblocks_build(struct interpass *, struct labelinfo *, struct bblockinfo *); +void cfg_build(struct labelinfo *labinfo); +void cfg_dfs(struct basicblock *bb, unsigned int parent, + struct bblockinfo *bbinfo); +void dominators(struct bblockinfo *bbinfo); +struct basicblock * +ancestorwithlowestsemi(struct basicblock *bblock, struct bblockinfo *bbinfo); +void link(struct basicblock *parent, struct basicblock *child); +void computeDF(struct basicblock *bblock, struct bblockinfo *bbinfo); +void findTemps(struct interpass *ip); +void placePhiFunctions(struct bblockinfo *bbinfo); +void remunreach(void); + +struct basicblock bblocks; +int nbblocks; +static struct interpass *cvpole; + +struct addrof { + struct addrof *next; + int tempnum; + int oregoff; +} *otlink; + +static int +getoff(int num) +{ + struct addrof *w; + + for (w = otlink; w; w = w->next) + if (w->tempnum == num) + return w->oregoff; + return 0; +} + +/* + * Use stack argument addresses instead of copying if & is used on a var. + */ +static int +setargs(int tval, struct addrof *w) +{ + struct interpass *ip; + NODE *p; + + ip = DLIST_NEXT(cvpole, qelem); /* PROLOG */ + ip = DLIST_NEXT(ip, qelem); /* first DEFLAB */ + ip = DLIST_NEXT(ip, qelem); /* first NODE */ + for (; ip->type != IP_DEFLAB; ip = DLIST_NEXT(ip, qelem)) { + p = ip->ip_node; +#ifdef PCC_DEBUG + if (p->n_op != ASSIGN || p->n_left->n_op != TEMP) + comperr("temparg"); +#endif + if (p->n_right->n_op != OREG) + continue; /* arg in register */ + if (tval != p->n_left->n_lval) + continue; /* wrong assign */ + w->oregoff = p->n_right->n_lval; + tfree(p); + DLIST_REMOVE(ip, qelem); + return 1; + } + return 0; +} + +/* + * Search for ADDROF elements and, if found, record them. + */ +static void +findaddrof(NODE *p) +{ + struct addrof *w; + + if (p->n_op != ADDROF) + return; + if (getoff(p->n_left->n_lval)) + return; + w = tmpalloc(sizeof(struct addrof)); + w->tempnum = p->n_left->n_lval; + if (setargs(p->n_left->n_lval, w) == 0) + w->oregoff = BITOOR(freetemp(szty(p->n_left->n_type))); + w->next = otlink; + otlink = w; +} + + +/* + * Convert address-taken temps to OREGs. + */ +static void +cvtaddrof(NODE *p) +{ + NODE *l; + int n; + + if (p->n_op != ADDROF && p->n_op != TEMP) + return; + if (p->n_op == TEMP) { + n = getoff(p->n_lval); + if (n == 0) + return; + p->n_op = OREG; + p->n_lval = n; + p->n_rval = FPREG; + } else { + l = p->n_left; + l->n_type = p->n_type; + p->n_right = mklnode(ICON, l->n_lval, 0, l->n_type); + p->n_op = PLUS; + l->n_op = REG; + l->n_lval = 0; + l->n_rval = FPREG; + + } +} + +void +optimize(struct interpass *ipole) +{ + struct interpass *ip; + struct labelinfo labinfo; + struct bblockinfo bbinfo; + + ipp = (struct interpass_prolog *)DLIST_NEXT(ipole, qelem); + epp = (struct interpass_prolog *)DLIST_PREV(ipole, qelem); + + if (b2debug) { + printf("initial links\n"); + printip(ipole); + } + + /* + * Convert ADDROF TEMP to OREGs. + */ + if (xtemps) { + otlink = NULL; + cvpole = ipole; + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + walkf(ip->ip_node, findaddrof); + } + if (otlink) { + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + walkf(ip->ip_node, cvtaddrof); + } + } + } + + if (xdeljumps) + deljumps(ipole); /* Delete redundant jumps and dead code */ + +#ifdef PCC_DEBUG + if (b2debug) { + printf("links after deljumps\n"); + printip(ipole); + } +#endif + if (xssaflag || xtemps) { + DLIST_INIT(&bblocks, bbelem); + bblocks_build(ipole, &labinfo, &bbinfo); + BDEBUG(("Calling cfg_build\n")); + cfg_build(&labinfo); + } + if (xssaflag) { + BDEBUG(("Calling dominators\n")); + dominators(&bbinfo); + BDEBUG(("Calling computeDF\n")); + computeDF(DLIST_NEXT(&bblocks, bbelem), &bbinfo); + BDEBUG(("Calling remunreach\n")); + remunreach(); +#if 0 + dfg = dfg_build(cfg); + ssa = ssa_build(cfg, dfg); +#endif + } + +#ifdef PCC_DEBUG + if (epp->ipp_regs != 0) + comperr("register error"); +#endif + +#ifdef MYOPTIM + myoptim((struct interpass *)ipp); +#endif +} + +/* + * Delete unused labels, excess of labels, gotos to gotos. + * This routine can be made much more efficient. + */ +void +deljumps(struct interpass *ipole) +{ + struct interpass *ip, *n, *ip2; + int gotone,low, high; + int *lblary, sz, o, i; + + low = ipp->ip_lblnum; + high = epp->ip_lblnum; + +#ifdef notyet + mark = tmpmark(); /* temporary used memory */ +#endif + + sz = (high-low) * sizeof(int); + lblary = tmpalloc(sz); + +again: gotone = 0; + memset(lblary, 0, sz); + + /* refcount and coalesce all labels */ + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type == IP_DEFLAB) { + n = DLIST_NEXT(ip, qelem); + while (n->type == IP_DEFLAB) { + if (n->type == IP_DEFLAB && + lblary[n->ip_lbl-low] >= 0) + lblary[n->ip_lbl-low] = -ip->ip_lbl; + n = DLIST_NEXT(n, qelem); + } + } + if (ip->type != IP_NODE) + continue; + o = ip->ip_node->n_op; + if (o == GOTO) + i = ip->ip_node->n_left->n_lval; + else if (o == CBRANCH) + i = ip->ip_node->n_right->n_lval; + else + continue; + lblary[i-low] |= 1; + } + + /* delete coalesced/unused labels and rename gotos */ + DLIST_FOREACH(ip, ipole, qelem) { + n = DLIST_NEXT(ip, qelem); + if (n->type == IP_DEFLAB) { + if (lblary[n->ip_lbl-low] <= 0) { + DLIST_REMOVE(n, qelem); + gotone = 1; + } + continue; + } + if (n->type != IP_NODE) + continue; + o = n->ip_node->n_op; + if (o == GOTO) + i = n->ip_node->n_left->n_lval; + else if (o == CBRANCH) + i = n->ip_node->n_right->n_lval; + else + continue; + if (lblary[i-low] < 0) { + if (o == GOTO) + n->ip_node->n_left->n_lval = -lblary[i-low]; + else + n->ip_node->n_right->n_lval = -lblary[i-low]; + } + } + + /* Delete gotos to the next statement */ + DLIST_FOREACH(ip, ipole, qelem) { + n = DLIST_NEXT(ip, qelem); + if (n->type != IP_NODE) + continue; + o = n->ip_node->n_op; + if (o == GOTO) + i = n->ip_node->n_left->n_lval; + else if (o == CBRANCH) + i = n->ip_node->n_right->n_lval; + else + continue; + + ip2 = n; + ip2 = DLIST_NEXT(ip2, qelem); + + if (ip2->type != IP_DEFLAB) + continue; + if (ip2->ip_lbl == i) { + tfree(n->ip_node); + DLIST_REMOVE(n, qelem); + gotone = 1; + } + } + + if (gotone) + goto again; + +#ifdef notyet + tmpfree(mark); +#endif +} + +void +optdump(struct interpass *ip) +{ + static char *nm[] = { "node", "prolog", "newblk", "epilog", "locctr", + "deflab", "defnam", "asm" }; + printf("type %s\n", nm[ip->type-1]); + switch (ip->type) { + case IP_NODE: + fwalk(ip->ip_node, e2print, 0); + break; + case IP_DEFLAB: + printf("label " LABFMT "\n", ip->ip_lbl); + break; + case IP_ASM: + printf(": %s\n", ip->ip_asm); + break; + } +} + +/* + * Build the basic blocks, algorithm 9.1, pp 529 in Compilers. + * + * Also fills the labelinfo struct with information about which bblocks + * that contain which label. + */ + +void +bblocks_build(struct interpass *ipole, struct labelinfo *labinfo, + struct bblockinfo *bbinfo) +{ + struct interpass *ip; + struct basicblock *bb = NULL; + int low, high; + int count = 0; + int i; + + BDEBUG(("bblocks_build (%p, %p)\n", labinfo, bbinfo)); + low = ipp->ip_lblnum; + high = epp->ip_lblnum; + + /* + * First statement is a leader. + * Any statement that is target of a jump is a leader. + * Any statement that immediately follows a jump is a leader. + */ + DLIST_FOREACH(ip, ipole, qelem) { + if (bb == NULL || (ip->type == IP_EPILOG) || + (ip->type == IP_DEFLAB) || (ip->type == IP_DEFNAM)) { + bb = tmpalloc(sizeof(struct basicblock)); + bb->first = ip; + SLIST_INIT(&bb->children); + SLIST_INIT(&bb->parents); + bb->dfnum = 0; + bb->dfparent = 0; + bb->semi = 0; + bb->ancestor = 0; + bb->idom = 0; + bb->samedom = 0; + bb->bucket = NULL; + bb->df = NULL; + bb->dfchildren = NULL; + bb->Aorig = NULL; + bb->Aphi = NULL; + bb->bbnum = count; + DLIST_INSERT_BEFORE(&bblocks, bb, bbelem); + count++; + } + bb->last = ip; + if ((ip->type == IP_NODE) && (ip->ip_node->n_op == GOTO || + ip->ip_node->n_op == CBRANCH)) + bb = NULL; + if (ip->type == IP_PROLOG) + bb = NULL; + } + nbblocks = count; + + if (b2debug) { + printf("Basic blocks in func: %d, low %d, high %d\n", + count, low, high); + DLIST_FOREACH(bb, &bblocks, bbelem) { + printf("bb %p: first %p last %p\n", bb, + bb->first, bb->last); + } + } + + labinfo->low = low; + labinfo->size = high - low + 1; + labinfo->arr = tmpalloc(labinfo->size * sizeof(struct basicblock *)); + for (i = 0; i < labinfo->size; i++) { + labinfo->arr[i] = NULL; + } + + bbinfo->size = count + 1; + bbinfo->arr = tmpalloc(bbinfo->size * sizeof(struct basicblock *)); + for (i = 0; i < bbinfo->size; i++) { + bbinfo->arr[i] = NULL; + } + + /* Build the label table */ + DLIST_FOREACH(bb, &bblocks, bbelem) { + if (bb->first->type == IP_DEFLAB) + labinfo->arr[bb->first->ip_lbl - low] = bb; + } + + if (b2debug) { + printf("Label table:\n"); + for (i = 0; i < labinfo->size; i++) + if (labinfo->arr[i]) + printf("Label %d bblock %p\n", i+low, + labinfo->arr[i]); + } +} + +/* + * Build the control flow graph. + */ + +void +cfg_build(struct labelinfo *labinfo) +{ + /* Child and parent nodes */ + struct cfgnode *cnode; + struct cfgnode *pnode; + struct basicblock *bb; + + DLIST_FOREACH(bb, &bblocks, bbelem) { + + if (bb->first->type == IP_EPILOG) { + break; + } + + cnode = tmpalloc(sizeof(struct cfgnode)); + pnode = tmpalloc(sizeof(struct cfgnode)); + pnode->bblock = bb; + + if ((bb->last->type == IP_NODE) && + (bb->last->ip_node->n_op == GOTO)) { + if (bb->last->ip_node->n_left->n_lval - labinfo->low > + labinfo->size) { + comperr("Label out of range: %d, base %d", + bb->last->ip_node->n_left->n_lval, + labinfo->low); + } + cnode->bblock = labinfo->arr[bb->last->ip_node->n_left->n_lval - labinfo->low]; + SLIST_INSERT_LAST(&cnode->bblock->parents, pnode, cfgelem); + SLIST_INSERT_LAST(&bb->children, cnode, cfgelem); + continue; + } + if ((bb->last->type == IP_NODE) && + (bb->last->ip_node->n_op == CBRANCH)) { + if (bb->last->ip_node->n_right->n_lval - labinfo->low > + labinfo->size) + comperr("Label out of range: %d", + bb->last->ip_node->n_left->n_lval); + + cnode->bblock = labinfo->arr[bb->last->ip_node->n_right->n_lval - labinfo->low]; + SLIST_INSERT_LAST(&cnode->bblock->parents, pnode, cfgelem); + SLIST_INSERT_LAST(&bb->children, cnode, cfgelem); + cnode = tmpalloc(sizeof(struct cfgnode)); + pnode = tmpalloc(sizeof(struct cfgnode)); + pnode->bblock = bb; + } + + cnode->bblock = DLIST_NEXT(bb, bbelem); + SLIST_INSERT_LAST(&cnode->bblock->parents, pnode, cfgelem); + SLIST_INSERT_LAST(&bb->children, cnode, cfgelem); + } +} + +void +cfg_dfs(struct basicblock *bb, unsigned int parent, struct bblockinfo *bbinfo) +{ + struct cfgnode *cnode; + + if (bb->dfnum != 0) + return; + + bb->dfnum = ++dfsnum; + bb->dfparent = parent; + bbinfo->arr[bb->dfnum] = bb; + SLIST_FOREACH(cnode, &bb->children, cfgelem) { + cfg_dfs(cnode->bblock, bb->dfnum, bbinfo); + } + /* Don't bring in unreachable nodes in the future */ + bbinfo->size = dfsnum + 1; +} + +static bittype * +setalloc(int nelem) +{ + bittype *b; + int sz = (nelem+NUMBITS-1)/NUMBITS; + + b = tmpalloc(sz * sizeof(bittype)); + memset(b, 0, sz * sizeof(bittype)); + return b; +} + +/* + * Algorithm 19.9, pp 414 from Appel. + */ + +void +dominators(struct bblockinfo *bbinfo) +{ + struct cfgnode *cnode; + struct basicblock *bb, *y, *v; + struct basicblock *s, *sprime, *p; + int h, i; + + DLIST_FOREACH(bb, &bblocks, bbelem) { + bb->bucket = setalloc(bbinfo->size); + bb->df = setalloc(bbinfo->size); + bb->dfchildren = setalloc(bbinfo->size); + } + + dfsnum = 0; + cfg_dfs(DLIST_NEXT(&bblocks, bbelem), 0, bbinfo); + + if (b2debug) { + struct basicblock *bbb; + struct cfgnode *ccnode; + + DLIST_FOREACH(bbb, &bblocks, bbelem) { + printf("Basic block %d, parents: ", bbb->dfnum); + SLIST_FOREACH(ccnode, &bbb->parents, cfgelem) { + printf("%d, ", ccnode->bblock->dfnum); + } + printf("\nChildren: "); + SLIST_FOREACH(ccnode, &bbb->children, cfgelem) { + printf("%d, ", ccnode->bblock->dfnum); + } + printf("\n"); + } + } + + for(h = bbinfo->size - 1; h > 1; h--) { + bb = bbinfo->arr[h]; + p = s = bbinfo->arr[bb->dfparent]; + SLIST_FOREACH(cnode, &bb->parents, cfgelem) { + if (cnode->bblock->dfnum <= bb->dfnum) + sprime = cnode->bblock; + else + sprime = bbinfo->arr[ancestorwithlowestsemi + (cnode->bblock, bbinfo)->semi]; + if (sprime->dfnum < s->dfnum) + s = sprime; + } + bb->semi = s->dfnum; + BITSET(s->bucket, bb->dfnum); + link(p, bb); + for (i = 1; i < bbinfo->size; i++) { + if(TESTBIT(p->bucket, i)) { + v = bbinfo->arr[i]; + y = ancestorwithlowestsemi(v, bbinfo); + if (y->semi == v->semi) + v->idom = p->dfnum; + else + v->samedom = y->dfnum; + } + } + memset(p->bucket, 0, (bbinfo->size + 7)/8); + } + + if (b2debug) { + printf("Num\tSemi\tAncest\tidom\n"); + DLIST_FOREACH(bb, &bblocks, bbelem) { + printf("%d\t%d\t%d\t%d\n", bb->dfnum, bb->semi, + bb->ancestor, bb->idom); + } + } + + for(h = 2; h < bbinfo->size; h++) { + bb = bbinfo->arr[h]; + if (bb->samedom != 0) { + bb->idom = bbinfo->arr[bb->samedom]->idom; + } + } + DLIST_FOREACH(bb, &bblocks, bbelem) { + if (bb->idom != 0 && bb->idom != bb->dfnum) { + BDEBUG(("Setting child %d of %d\n", + bb->dfnum, bbinfo->arr[bb->idom]->dfnum)); + BITSET(bbinfo->arr[bb->idom]->dfchildren, bb->dfnum); + } + } +} + + +struct basicblock * +ancestorwithlowestsemi(struct basicblock *bblock, struct bblockinfo *bbinfo) +{ + struct basicblock *u = bblock; + struct basicblock *v = bblock; + + while (v->ancestor != 0) { + if (bbinfo->arr[v->semi]->dfnum < + bbinfo->arr[u->semi]->dfnum) + u = v; + v = bbinfo->arr[v->ancestor]; + } + return u; +} + +void +link(struct basicblock *parent, struct basicblock *child) +{ + child->ancestor = parent->dfnum; +} + +void +computeDF(struct basicblock *bblock, struct bblockinfo *bbinfo) +{ + struct cfgnode *cnode; + int h, i; + + SLIST_FOREACH(cnode, &bblock->children, cfgelem) { + if (cnode->bblock->idom != bblock->dfnum) + BITSET(bblock->df, cnode->bblock->dfnum); + } + for (h = 1; h < bbinfo->size; h++) { + if (!TESTBIT(bblock->dfchildren, h)) + continue; + computeDF(bbinfo->arr[h], bbinfo); + for (i = 1; i < bbinfo->size; i++) { + if (TESTBIT(bbinfo->arr[h]->df, i) && + (bbinfo->arr[h] == bblock || + (bblock->idom != bbinfo->arr[h]->dfnum))) + BITSET(bblock->df, i); + } + } +} + +static struct basicblock *currbb; +static struct interpass *currip; + +/* Helper function for findTemps, Find assignment nodes. */ +static void +searchasg(NODE *p) +{ + struct pvarinfo *pv; + + if (p->n_op != ASSIGN) + return; + + if (p->n_left->n_op != TEMP) + return; + + pv = tmpcalloc(sizeof(struct pvarinfo)); + pv->next = defsites.arr[p->n_left->n_lval]; + pv->bb = currbb; + pv->top = currip->ip_node; + pv->n = p->n_left; + BITSET(currbb->Aorig, p->n_left->n_lval); + + defsites.arr[p->n_left->n_lval] = pv; +} + +/* Walk the interpass looking for assignment nodes. */ +void findTemps(struct interpass *ip) +{ + if (ip->type != IP_NODE) + return; + + currip = ip; + + walkf(ip->ip_node, searchasg); +} + +/* + * Algorithm 19.6 from Appel. + */ + +void +placePhiFunctions(struct bblockinfo *bbinfo) +{ + struct basicblock *bb; + struct interpass *ip; + int maxtmp, i, j, k, l; + struct pvarinfo *n; + struct cfgnode *cnode; + TWORD ntype; + NODE *p; + struct pvarinfo *pv; + + bb = DLIST_NEXT(&bblocks, bbelem); + defsites.low = ((struct interpass_prolog *)bb->first)->ip_tmpnum; + bb = DLIST_PREV(&bblocks, bbelem); + maxtmp = ((struct interpass_prolog *)bb->first)->ip_tmpnum; + defsites.size = maxtmp - defsites.low + 1; + defsites.arr = tmpcalloc(defsites.size*sizeof(struct pvarinfo *)); + + /* Find all defsites */ + DLIST_FOREACH(bb, &bblocks, bbelem) { + currbb = bb; + ip = bb->first; + bb->Aorig = setalloc(defsites.size); + bb->Aphi = setalloc(defsites.size); + + + while (ip != bb->last) { + findTemps(ip); + ip = DLIST_NEXT(ip, qelem); + } + /* Make sure we get the last statement in the bblock */ + findTemps(ip); + } + /* For each variable */ + for (i = defsites.low; i < defsites.size; i++) { + /* While W not empty */ + while (defsites.arr[i] != NULL) { + /* Remove some node n from W */ + n = defsites.arr[i]; + defsites.arr[i] = n->next; + /* For each y in n->bb->df */ + for (j = 0; j < bbinfo->size; j++) { + if (!TESTBIT(n->bb->df, j)) + continue; + + if (TESTBIT(bbinfo->arr[j]->Aphi, i)) + continue; + + ntype = n->n->n_type; + k = 0; + /* Amount of predecessors for y */ + SLIST_FOREACH(cnode, &n->bb->parents, cfgelem) + k++; + /* Construct phi(...) */ + p = mklnode(TEMP, i, 0, ntype); + for (l = 0; l < k-1; l++) + p = mkbinode(PHI, p, + mklnode(TEMP, i, 0, ntype), ntype); + ip = ipnode(mkbinode(ASSIGN, + mklnode(TEMP, i, 0, ntype), p, ntype)); + /* Insert phi at top of basic block */ + DLIST_INSERT_BEFORE(((struct interpass*)&n->bb->first), ip, qelem); + n->bb->first = ip; + BITSET(bbinfo->arr[j]->Aphi, i); + if (!TESTBIT(bbinfo->arr[j]->Aorig, i)) { + pv = tmpalloc(sizeof(struct pvarinfo)); + // XXXpj Ej fullständig information. + pv->bb = bbinfo->arr[j]; + pv->next = defsites.arr[i]->next; + defsites.arr[i] = pv; + } + + + } + } + } +} + +/* + * Remove unreachable nodes in the CFG. + */ + +void +remunreach(void) +{ + struct basicblock *bb, *nbb; + struct interpass *next, *ctree; + + bb = DLIST_NEXT(&bblocks, bbelem); + while (bb != &bblocks) { + nbb = DLIST_NEXT(bb, bbelem); + + /* Code with dfnum 0 is unreachable */ + if (bb->dfnum != 0) { + bb = nbb; + continue; + } + + /* Need the epilogue node for other parts of the + compiler, set its label to 0 and backend will + handle it. */ + if (bb->first->type == IP_EPILOG) { + bb->first->ip_lbl = 0; + bb = nbb; + continue; + } + + next = bb->first; + do { + ctree = next; + next = DLIST_NEXT(ctree, qelem); + + if (ctree->type == IP_NODE) + tfree(ctree->ip_node); + DLIST_REMOVE(ctree, qelem); + } while (ctree != bb->last); + + DLIST_REMOVE(bb, bbelem); + bb = nbb; + } +} + +void +printip(struct interpass *pole) +{ + static char *foo[] = { + 0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" }; + struct interpass *ip; + struct interpass_prolog *ipp, *epp; + + DLIST_FOREACH(ip, pole, qelem) { + if (ip->type > MAXIP) + printf("IP(%d) (%p): ", ip->type, ip); + else + printf("%s (%p): ", foo[ip->type], ip); + switch (ip->type) { + case IP_NODE: printf("\n"); + fwalk(ip->ip_node, e2print, 0); break; + case IP_PROLOG: + ipp = (struct interpass_prolog *)ip; + printf("%s %s regs %x autos %d mintemp %d minlbl %d\n", + ipp->ipp_name, ipp->ipp_vis ? "(local)" : "", + ipp->ipp_regs, ipp->ipp_autos, ipp->ip_tmpnum, + ipp->ip_lblnum); + break; + case IP_EPILOG: + epp = (struct interpass_prolog *)ip; + printf("%s %s regs %x autos %d mintemp %d minlbl %d\n", + epp->ipp_name, epp->ipp_vis ? "(local)" : "", + epp->ipp_regs, epp->ipp_autos, epp->ip_tmpnum, + epp->ip_lblnum); + break; + case IP_DEFLAB: printf(LABFMT "\n", ip->ip_lbl); break; + case IP_DEFNAM: printf("\n"); break; + case IP_ASM: printf("%s\n", ip->ip_asm); break; + default: + break; + } + } +} diff --git a/usr.bin/pcc/mip/pass2.h b/usr.bin/pcc/mip/pass2.h new file mode 100644 index 00000000000..35ccb7f4220 --- /dev/null +++ b/usr.bin/pcc/mip/pass2.h @@ -0,0 +1,418 @@ +/* $Id: pass2.h,v 1.1 2007/09/15 18:12:36 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 <sys/types.h> + +#include "manifest.h" +#include "protos.h" +#ifndef MKEXT +#include "external.h" +#else +typedef int bittype; /* XXX - for basicblock */ +#endif + +/* cookies, used as arguments to codgen */ +#define FOREFF 01 /* compute for effects only */ +#define INAREG 02 /* compute into a register */ +#define INBREG 04 /* compute into a register */ +#define INCREG 010 /* compute into a register */ +#define INDREG 020 /* compute into a register */ +#define INREGS (INAREG|INBREG|INCREG|INDREG) +#define FORCC 040 /* compute for condition codes only */ +#define INTEMP 010000 /* compute into a temporary location */ +#define FORREW 040000 /* search the table for a rewrite rule */ + +/* + * OP descriptors, + * the ASG operator may be used on some of these + */ +#define OPSIMP 010000 /* +, -, &, |, ^ */ +#define OPCOMM 010002 /* +, &, |, ^ */ +#define OPMUL 010004 /* *, / */ +#define OPDIV 010006 /* /, % */ +#define OPUNARY 010010 /* unary ops */ +#define OPLEAF 010012 /* leaves */ +#define OPANY 010014 /* any op... */ +#define OPLOG 010016 /* logical ops */ +#define OPFLOAT 010020 /* +, -, *, or / (for floats) */ +#define OPSHFT 010022 /* <<, >> */ +#define OPLTYPE 010024 /* leaf type nodes (e.g, NAME, ICON, etc.) */ + +/* shapes */ +#define SANY 01 /* same as FOREFF */ +#define SAREG 02 /* same as INAREG */ +#define SBREG 04 /* same as INBREG */ +#define SCREG 010 /* same as INCREG */ +#define SDREG 020 /* same as INDREG */ +#define SCC 040 /* same as FORCC */ +#define SNAME 0100 +#define SCON 0200 +#define SFLD 0400 +#define SOREG 01000 +#define STARNM 02000 +#define STARREG 04000 +#define SWADD 040000 +#define SPECIAL 0100000 +#define SZERO SPECIAL +#define SONE (SPECIAL|1) +#define SMONE (SPECIAL|2) +#define SCCON (SPECIAL|3) /* -256 <= constant < 256 */ +#define SSCON (SPECIAL|4) /* -32768 <= constant < 32768 */ +#define SSOREG (SPECIAL|5) /* non-indexed OREG */ +#define MAXSPECIAL (SPECIAL|5) + +/* These are used in rstatus[] in conjunction with SxREG */ +#define TEMPREG 0100 +#define PERMREG 0200 + +/* tshape() return values */ +#define SRNOPE 0 /* Cannot match any shape */ +#define SRDIR 1 /* Direct match */ +#define SROREG 2 /* Can convert into OREG */ +#define SRREG 3 /* Must put into REG */ + +/* find*() return values */ +#define FRETRY -2 +#define FFAIL -1 + +/* INTEMP is carefully not conflicting with shapes */ + +/* types */ +#define TCHAR 01 /* char */ +#define TSHORT 02 /* short */ +#define TINT 04 /* int */ +#define TLONG 010 /* long */ +#define TFLOAT 020 /* float */ +#define TDOUBLE 040 /* double */ +#define TPOINT 0100 /* pointer to something */ +#define TUCHAR 0200 /* unsigned char */ +#define TUSHORT 0400 /* unsigned short */ +#define TUNSIGNED 01000 /* unsigned int */ +#define TULONG 02000 /* unsigned long */ +#define TPTRTO 04000 /* pointer to one of the above */ +#define TANY 010000 /* matches anything within reason */ +#define TSTRUCT 020000 /* structure or union */ +#define TLONGLONG 040000 /* long long */ +#define TULONGLONG 0100000 /* unsigned long long */ +#define TLDOUBLE 0200000 /* long double; exceeds 16 bit */ +#define TFTN 0400000 /* function pointer; exceeds 16 bit */ + +/* reclamation cookies */ +#define RNULL 0 /* clobber result */ +#define RLEFT 01 +#define RRIGHT 02 +#define RESC1 04 +#define RESC2 010 +#define RESC3 020 +#define RDEST 040 +#define RESCC 04000 +#define RNOP 010000 /* DANGER: can cause loops.. */ + +/* needs */ +#define NAREG 0000001 +#define NACOUNT 0000003 +#define NAMASK 0000017 +#define NASL 0000004 /* may share left register */ +#define NASR 0000010 /* may share right register */ +#define NBREG 0000020 +#define NBCOUNT 0000060 +#define NBMASK 0000360 +#define NBSL 0000100 +#define NBSR 0000200 +#define NTEMP 0000400 +#define NTMASK 0001400 +#define NSPECIAL 0040000 /* need special register treatment */ +#define REWRITE 0100000 +#define NCSL 0x10000 /* Above 16 bit */ +#define NCSR 0x20000 /* Above 16 bit */ +#define NCREG 0x40000 /* Above 16 bit */ +#define NCCOUNT 0xc0000 +#define NDSL 0x100000 /* Above 16 bit */ +#define NDSR 0x200000 /* Above 16 bit */ +#define NDREG 0x400000 /* Above 16 bit */ +#define NDCOUNT 0xc00000 + +/* special treatment */ +#define NLEFT (0001) /* left leg register (moveadd) */ +#define NOLEFT (0002) /* avoid regs for left (addedge) */ +#define NRIGHT (0004) /* right leg register */ +#define NORIGHT (0010) /* avoid reg for right */ +#define NEVER (0020) /* registers trashed (addalledges) */ +#define NRES (0040) /* result register (moveadd) */ +#define NMOVTO (0100) /* move between classes */ + + +#define MUSTDO 010000 /* force register requirements */ +#define NOPREF 020000 /* no preference for register assignment */ + +#define isreg(p) (p->n_op == REG || p->n_op == TEMP) + +#define TBUSY 01000 + +#define SETSTO(x,y) (stotree = (x), stocook = (y)) +extern int stocook; + +extern NODE *stotree; +extern int callflag; + +extern int fregs; + +/* code tables */ +extern struct optab { + int op; + int visit; + int lshape; + int ltype; + int rshape; + int rtype; + int needs; + int rewrite; + char *cstring; +} table[]; + +/* Special needs for register allocations */ +struct rspecial { + int op, num; +#if 0 + int left; /* left leg register */ + int noleft; /* avoid regs for left */ + int right; /* right leg register */ + int noright; /* avoid right leg register */ + int *rmask; /* array of destroyed registers */ + int res; /* Result ends up here */ +// void (*rew)(struct optab *, NODE *); /* special rewrite */ +#endif +}; + +extern NODE resc[]; + +extern int p2autooff, p2maxautooff; + +extern NODE + *talloc(void), + *eread(void), + *tcopy(NODE *), + *mklnode(int, CONSZ, int, TWORD), + *mkbinode(int, NODE *, NODE *, TWORD), + *mkunode(int, NODE *, int, TWORD), + *getlr(NODE *p, int); + +void eoftn(struct interpass_prolog *); +void prologue(struct interpass_prolog *); +void setlocc(int locctr); +void e2print(NODE *p, int down, int *a, int *b); +void myoptim(struct interpass *); +void cbgen(int op, int label); +struct optab *nxtmatch(struct optab *); +int chkmatch(NODE *, int, int, int); +int match(NODE *p, int cookie); +int nmatch(NODE *p, int what); +#ifndef special +int special(NODE *, int); +#endif +int setasg(NODE *, int); +int setuni(NODE *, int); +int sucomp(NODE *); +int nsucomp(NODE *); +int setorder(NODE *); +int geninsn(NODE *, int cookie); +void adrput(FILE *, NODE *); +void comperr(char *str, ...); +void genregs(NODE *p); +void ngenregs(struct interpass *); +NODE *store(NODE *); +void gencall(NODE *, NODE *prev); +struct interpass *ipnode(NODE *); +void deflab(int); +void rmove(int, int, TWORD); +int rspecial(struct optab *, int); +struct rspecial *nspecial(struct optab *q); +void printip(struct interpass *pole); +int findops(NODE *p, int); +int findasg(NODE *p, int); +int finduni(NODE *p, int); +int findumul(NODE *p, int); +int findleaf(NODE *p, int); +int relops(NODE *p); +void offstar(NODE *p, int shape); +int gclass(TWORD); +void lastcall(NODE *); +void myreader(struct interpass *pole); +int oregok(NODE *p, int sharp); +void myormake(NODE *); + +char *prcook(int); + +void conput(FILE *, NODE *); + +extern char *rnames[]; +extern int rstatus[]; +extern int roverlap[MAXREGS][MAXREGS]; + +extern int classmask(int), tclassmask(int); +extern void cmapinit(void); +extern int aliasmap(int adjclass, int regnum); +extern int regK[]; +#define CLASSA 1 +#define CLASSB 2 +#define CLASSC 3 +#define CLASSD 4 +#define CLASSE 5 + +/* routines to handle double indirection */ +#ifdef R2REGS +void makeor2(NODE *p, NODE *q, int, int); +int base(NODE *); +int offset(NODE *p, int); +#endif + +extern int lineno; +extern int fldshf, fldsz; +extern int lflag, x2debug, udebug, e2debug, odebug, mdebug; +extern int rdebug, radebug, t2debug, s2debug, b2debug, c2debug; +extern int kflag; +#ifdef FORT +extern int Oflag; +#endif + +#ifndef callchk +#define callchk(x) allchk() +#endif + +#ifndef PUTCHAR +#define PUTCHAR(x) putchar(x) +#endif + +#define optype(o) (dope[o]&TYFLG) +#define asgop(o) (dope[o]&ASGFLG) +#define logop(o) (dope[o]&LOGFLG) +#define callop(o) (dope[o]&CALLFLG) +extern int dope[]; /* a vector containing operator information */ +extern char *opst[]; /* a vector containing names for ops */ + + /* macros for doing double indexing */ +#define R2PACK(x,y,z) (0200*((x)+1)+y+040000*z) +#define R2UPK1(x) ((((x)>>7)-1)&0177) +#define R2UPK2(x) ((x)&0177) +#define R2UPK3(x) (x>>14) +#define R2TEST(x) ((x)>=0200) + +/* + * Layout of findops() return value: + * bit 0-1 where to store left node. + * bit 2-3 where to store right node. + * bit 4 set if right leg should be evaluated first + * bit 5- table index + * + * LOREG means: walk down left node, after code emission call canon() to + * convert the tree to an OREG. + */ +#define LREG 001 +#define LOREG 002 +#define LTEMP 003 +#define LDIR 003 +#define LMASK 003 +#define RREG 004 +#define ROREG 010 +#define RTEMP 014 +#define RDIR 014 +#define RMASK 014 +#define DORIGHT 020 +#define SCLASS(v,x) ((v) |= ((x) << 5)) +#define TCLASS(x) (((x) >> 5) & 7) +#define TBSH 8 +#define TBLIDX(idx) ((idx) >> TBSH) +#define MKIDX(tbl,mod) (((tbl) << TBSH) | (mod)) + +#ifndef BREGS +#define BREGS 0 +#define TBREGS 0 +#endif +#define REGBIT(x) (1 << (x)) + +void emit(struct interpass *); +void optimize(struct interpass *); + +struct basicblock { + DLIST_ENTRY(basicblock) bbelem; + SLIST_HEAD(, cfgnode) children; /* CFG - children to this node */ + SLIST_HEAD(, cfgnode) parents; /* CFG - parents to this node */ + int bbnum; /* this basic block number */ + unsigned int dfnum; /* DFS-number */ + unsigned int dfparent; /* Parent in DFS */ + unsigned int semi; + unsigned int ancestor; + unsigned int idom; + unsigned int samedom; + bittype *bucket; + bittype *df; + bittype *dfchildren; + bittype *Aorig; + bittype *Aphi; + struct interpass *first; /* first element of basic block */ + struct interpass *last; /* last element of basic block */ +}; + +struct labelinfo { + struct basicblock **arr; + unsigned int size; + unsigned int low; +}; + +struct bblockinfo { + unsigned int size; + struct basicblock **arr; +}; + +struct varinfo { + struct pvarinfo **arr; + int size; + int low; +}; + +struct pvarinfo { + struct pvarinfo *next; + struct basicblock *bb; + NODE *top, *n; +}; + +struct cfgnode { + SLIST_ENTRY(cfgnode) cfgelem; + struct basicblock *bblock; +}; + +/* + * C compiler second pass extra defines. + */ +#define PHI (MAXOP + 1) /* Used in SSA trees */ diff --git a/usr.bin/pcc/mip/protos.h b/usr.bin/pcc/mip/protos.h new file mode 100644 index 00000000000..a0a436fdd45 --- /dev/null +++ b/usr.bin/pcc/mip/protos.h @@ -0,0 +1,83 @@ + +struct optab; +struct symtab; +struct sw; + +void cerror(char *s, ...); +void werror(char *s, ...); +void uerror(char *s, ...); +void reclaim(NODE *p, int, int); +void walkf(NODE *, void (*f)(NODE *)); +void allchk(void); +void tfree(NODE *); +int tshape(NODE *, int); +void prtdcon(NODE *p); +void tinit(void); +void tcheck(void); +void mkdope(void); +int tshape(NODE *p, int shape); +int shtemp(NODE *p); +int flshape(NODE *p); +int shumul(NODE *p); +int ttype(TWORD t, int tword); +void expand(NODE *, int, char *); +void hopcode(int, int); +void adrcon(CONSZ); +void zzzcode(NODE *, int); +void insput(NODE *); +void upput(NODE *, int); +void econvert(NODE *); +int andable(NODE *); +int conval(NODE *, int, NODE *); +int ispow2(CONSZ); +void defid(NODE *q, int class); +int getlab(void); +void ftnend(void); +void efcode(void); +void dclargs(void); +void fixarg(struct symtab *); +void cendarg(void); +void defalign(int); +int fldal(unsigned int); +void vfdzero(int); +void zecode(int); +void putbyte(int v); +void ecomp(NODE *p); +void cinit(NODE *, int); +void bccode(void); +int upoff(int size, int alignment, int *poff); +void fldty(struct symtab *p); +void nidcl(NODE *p, int class); +int noinit(void); +void eprint(NODE *, int, int *, int *); +int uclass(int class); +int fixclass(int, TWORD type); +void lineid(int, char *); +void mycanon(NODE *); +void delay(NODE *); +int delay1(NODE *); +void delay2(NODE *); +void setregs(void); +int autoincr(NODE *); +int deltest(NODE *); +void canon(NODE *); +void order(NODE *, int); +int tlen(NODE *p); +int setincr(NODE *); +int setbin(NODE *); +void stoarg(NODE *p, int); +void constore(NODE *); +void markcall(NODE *); +void oreg2(NODE *p); +int notoff(TWORD, int, CONSZ, char *); +void bycode(int, int); +void pstab(char *, int); +void psline(void); +int notlval(NODE *); +int icons(NODE *); +void ecode(NODE *p); +int yylex(void); +void yyerror(char *s); +void p2tree(NODE *p); +int rewfld(NODE *p); +int freetemp(int k); diff --git a/usr.bin/pcc/mip/reader.c b/usr.bin/pcc/mip/reader.c new file mode 100644 index 00000000000..01135685094 --- /dev/null +++ b/usr.bin/pcc/mip/reader.c @@ -0,0 +1,1098 @@ +/* $Id: reader.c,v 1.1 2007/09/15 18:12:37 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. + */ + +/* + * 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. + */ + +/* + * Everything is entered via pass2_compile(). Three functions are + * allowed to recurse into pass2_compile(), so be careful: + * - deluseless() + * - myreader() + * Especially in myreader note that trees may be rewritten twice if + * things are not carefully handled. + */ + +# include "pass2.h" + +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> + +/* some storage declarations */ +int nrecur; +int lflag; +int x2debug; +int udebug = 0; +int thisline; +int fregs; +int p2autooff, p2maxautooff; + +NODE *nodepole; +FILE *prfil; + +void saveip(struct interpass *ip); +void deljumps(void); +void deltemp(NODE *p); +void mkhardops(NODE *p); +void optdump(struct interpass *ip); +void cvtemps(struct interpass *epil); +NODE *store(NODE *); +void rcount(void); +void compile2(struct interpass *ip); +void compile3(struct interpass *ip); +void compile4(struct interpass *ip); + +static void gencode(NODE *p, int cookie); + +char *ltyp[] = { "", "LREG", "LOREG", "LTEMP" }; +char *rtyp[] = { "", "RREG", "ROREG", "RTEMP" }; + +/* used when removing nodes */ +struct tmpsave { + struct tmpsave *next; + CONSZ tempaddr; + int tempno; +} *tmpsave; + +#ifdef PCC_DEBUG +static void +cktree(NODE *p) +{ + if (p->n_op > MAXOP) + cerror("op %d slipped through", p->n_op); + if (BTYPE(p->n_type) > MAXTYPES) + cerror("type %x slipped through", p->n_type); + if (p->n_op == CBRANCH && !logop(p->n_left->n_op)) + cerror("not logop branch"); + if ((dope[p->n_op] & ASGOPFLG) && p->n_op != RETURN) + cerror("asgop %d slipped through", p->n_op); +} +#endif + +/* + * Check if a node has side effects. + */ +static int +isuseless(NODE *n) +{ + switch (n->n_op) { + case FUNARG: + case UCALL: + case UFORTCALL: + case FORCE: +/* case INIT: */ + case ASSIGN: + case CALL: + case FORTCALL: + case CBRANCH: + case RETURN: + case GOTO: + case STCALL: + case USTCALL: + case STASG: + case STARG: + return 0; + default: + return 1; + } +} + +/* + * Delete statements with no meaning (like a+b; or 513.4;) + */ +static NODE * +deluseless(NODE *p) +{ + struct interpass *ip; + NODE *l, *r; + + if (optype(p->n_op) == LTYPE) { + nfree(p); + return NULL; + } + if (isuseless(p) == 0) + return p; + + if (optype(p->n_op) == UTYPE) { + l = p->n_left; + nfree(p); + return deluseless(l); + } + + /* Be sure that both leaves may be valid */ + l = deluseless(p->n_left); + r = deluseless(p->n_right); + nfree(p); + if (l && r) { + /* Put left on queue first */ + ip = tmpalloc(sizeof(*ip)); + ip->type = IP_NODE; + ip->lineno = 0; /* XXX */ + ip->ip_node = l; + pass2_compile(ip); + return r; + } else if (l) + return l; + else if (r) + return r; + return NULL; +} + +static struct interpass ipole; +struct interpass_prolog *ipp, *epp; + +/* + * Receives interpass structs from pass1. + */ +void +pass2_compile(struct interpass *ip) +{ + if (ip->type == IP_PROLOG) { + tmpsave = NULL; + ipp = (struct interpass_prolog *)ip; + DLIST_INIT(&ipole, qelem); + } + DLIST_INSERT_BEFORE(&ipole, ip, qelem); + if (ip->type != IP_EPILOG) + return; + +#ifdef PCC_DEBUG + if (e2debug) { + printf("Entering pass2\n"); + printip(&ipole); + } +#endif + + epp = (struct interpass_prolog *)DLIST_PREV(&ipole, qelem); + p2maxautooff = p2autooff = epp->ipp_autos; + + myreader(&ipole); /* local massage of input */ + + DLIST_FOREACH(ip, &ipole, qelem) { + if (ip->type != IP_NODE) + continue; + if (xtemps == 0) + walkf(ip->ip_node, deltemp); + } + DLIST_FOREACH(ip, &ipole, qelem) { + if (ip->type != IP_NODE) + continue; + canon(ip->ip_node); + walkf(ip->ip_node, cktree); + if ((ip->ip_node = deluseless(ip->ip_node)) == NULL) + DLIST_REMOVE(ip, qelem); + } + + optimize(&ipole); + ngenregs(&ipole); + + DLIST_FOREACH(ip, &ipole, qelem) + emit(ip); +} + +void +emit(struct interpass *ip) +{ + NODE *p; + int o; + + switch (ip->type) { + case IP_NODE: + p = ip->ip_node; + + nodepole = p; +//printf("bu:\n"); +//fwalk(p, e2print, 0); + canon(p); /* may convert stuff after genregs */ +//fwalk(p, e2print, 0); + switch (p->n_op) { + case CBRANCH: + /* Only emit branch insn if RESCC */ + if (table[TBLIDX(p->n_left->n_su)].rewrite & RESCC) { + o = p->n_left->n_op; + gencode(p, FORCC); + cbgen(o, p->n_right->n_lval); + } else + gencode(p, FORCC); + break; + case FORCE: + gencode(p->n_left, INREGS); + break; + default: + if (p->n_op != REG || p->n_type != VOID) /* XXX */ + gencode(p, FOREFF); /* Emit instructions */ + } + + tfree(p); + break; + case IP_PROLOG: + prologue((struct interpass_prolog *)ip); + break; + case IP_EPILOG: + eoftn((struct interpass_prolog *)ip); + tmpsave = NULL; /* Always forget old nodes */ + p2maxautooff = p2autooff = AUTOINIT/SZCHAR; + break; + case IP_DEFLAB: + deflab(ip->ip_lbl); + break; + case IP_ASM: + printf("\t%s\n", ip->ip_asm); + break; + default: + cerror("compile4 %d", ip->type); + } +} + +#ifdef PCC_DEBUG +char *cnames[] = { + "SANY", + "SAREG", + "SBREG", + "SCREG", + "SDREG", + "SCC", + "SNAME", + "SCON", + "SFLD", + "SOREG", + "STARNM", + "STARREG", + "INTEMP", + "FORARG", + "SWADD", + 0, +}; + +/* + * print a nice-looking description of cookie + */ +char * +prcook(int cookie) +{ + static char buf[50]; + int i, flag; + + if (cookie & SPECIAL) { + switch (cookie) { + case SZERO: + return "SZERO"; + case SONE: + return "SONE"; + case SMONE: + return "SMONE"; + default: + snprintf(buf, sizeof(buf), "SPECIAL+%d", cookie & ~SPECIAL); + return buf; + } + } + + flag = 0; + buf[0] = 0; + for (i = 0; cnames[i]; ++i) { + if (cookie & (1<<i)) { + if (flag) + strlcat(buf, "|", sizeof(buf)); + ++flag; + strlcat(buf, cnames[i], sizeof(buf)); + } + } + return buf; +} + +#endif + +int odebug = 0; + +int +geninsn(NODE *p, int cookie) +{ + NODE *p1, *p2; + int o, rv = 0; + +#ifdef PCC_DEBUG + if (odebug) { + printf("geninsn(%p, %s)\n", p, prcook(cookie)); + fwalk(p, e2print, 0); + } +#endif + +again: switch (o = p->n_op) { + case EQ: + case NE: + case LE: + case LT: + case GE: + case GT: + case ULE: + case ULT: + case UGE: + case UGT: + rv = relops(p); + break; + + case PLUS: + case MINUS: + case MUL: + case DIV: + case MOD: + case AND: + case OR: + case ER: + case LS: + case RS: + rv = findops(p, cookie); + break; + + case ASSIGN: + case STASG: + rv = findasg(p, cookie); + break; + + case UMUL: /* May turn into an OREG */ + rv = findumul(p, cookie); + break; + + case REG: + case TEMP: + case NAME: + case ICON: + case OREG: + rv = findleaf(p, cookie); + break; + + case STCALL: + case CALL: + /* CALL arguments are handled special */ + for (p1 = p->n_right; p1->n_op == CM; p1 = p1->n_left) + geninsn(p1->n_right, FOREFF); + geninsn(p1, FOREFF); + /* FALLTHROUGH */ + case COMPL: + case UMINUS: + case PCONV: + case SCONV: +/* case INIT: */ + case GOTO: + case FUNARG: + case STARG: + case UCALL: + case USTCALL: + rv = finduni(p, cookie); + break; + + case CBRANCH: + p1 = p->n_left; + p2 = p->n_right; + p1->n_label = p2->n_lval; + o = p1->n_op; + geninsn(p1, FORCC); + p->n_su = 0; + break; + + case FORCE: /* XXX needed? */ + geninsn(p->n_left, INREGS); + p->n_su = 0; /* su calculations traverse left */ + break; + + default: + comperr("geninsn: bad op %s, node %p", opst[o], p); + } + if (rv == FFAIL) + comperr("Cannot generate code, node %p op %s", p,opst[p->n_op]); + if (rv == FRETRY) + goto again; + return rv; +} + +/* + * Store a given subtree in a temporary location. + * Return an OREG node where it is located. + */ +NODE * +store(NODE *p) +{ + extern struct interpass *storesave; + struct interpass *ip; + NODE *q, *r; + int s; + + s = BITOOR(freetemp(szty(p->n_type))); + q = mklnode(OREG, s, FPREG, p->n_type); + r = mklnode(OREG, s, FPREG, p->n_type); + ip = ipnode(mkbinode(ASSIGN, q, p, p->n_type)); + + storesave = ip; + return r; +} + +#ifdef PCC_DEBUG +#define CDEBUG(x) if (c2debug) printf x +#else +#define CDEBUG(x) +#endif + +/* + * Do a register-register move if necessary. + */ +static void +ckmove(NODE *p, NODE *q) +{ + if (q->n_op != REG || p->n_reg == -1) + return; /* no register */ + if (DECRA(p->n_reg, 0) == DECRA(q->n_reg, 0)) + return; /* no move necessary */ + CDEBUG(("rmove: node %p, %s -> %s\n", p, rnames[DECRA(q->n_reg, 0)], + rnames[DECRA(p->n_reg, 0)])); + rmove(DECRA(q->n_reg, 0), DECRA(p->n_reg, 0), p->n_type); + q->n_reg = q->n_rval = DECRA(p->n_reg, 0); +} + +/* + * Rewrite node to register after instruction emit. + */ +static void +rewrite(NODE *p, int rewrite, int cookie) +{ + NODE *l, *r; + int o; + + l = getlr(p, 'L'); + r = getlr(p, 'R'); + o = p->n_op; + p->n_op = REG; + p->n_lval = 0; + p->n_name = ""; + + if (o == ASSIGN) { + /* special rewrite care */ + int reg = DECRA(p->n_reg, 0); +#define TL(x) (TBLIDX(x->n_su) || x->n_op == REG) + if (p->n_reg == -1) + ; + else if (TL(l) && (DECRA(l->n_reg, 0) == reg)) + ; + else if (TL(r) && (DECRA(r->n_reg, 0) == reg)) + ; + else if (TL(l)) + rmove(DECRA(l->n_reg, 0), reg, p->n_type); + else if (TL(r)) + rmove(DECRA(r->n_reg, 0), reg, p->n_type); +#if 0 + else + comperr("rewrite"); +#endif +#undef TL + } + if (optype(o) != LTYPE) + tfree(l); + if (optype(o) == BITYPE) + tfree(r); + if (rewrite == 0) + return; + CDEBUG(("rewrite: %p, reg %s\n", p, rnames[DECRA(p->n_reg, 0)])); + p->n_rval = DECRA(p->n_reg, 0); +} + +void +gencode(NODE *p, int cookie) +{ + struct optab *q = &table[TBLIDX(p->n_su)]; + NODE *p1, *l, *r; + int o = optype(p->n_op); + + l = p->n_left; + r = p->n_right; + + if (TBLIDX(p->n_su) == 0) { + if (o == BITYPE && (p->n_su & DORIGHT)) + gencode(r, 0); + if (optype(p->n_op) != LTYPE) + gencode(l, 0); + if (o == BITYPE && !(p->n_su & DORIGHT)) + gencode(r, 0); + return; + } + + CDEBUG(("gencode: node %p\n", p)); + + if (p->n_op == REG && DECRA(p->n_reg, 0) == p->n_rval) + return; /* meaningless move to itself */ + + if (callop(p->n_op)) + lastcall(p); /* last chance before function args */ + if (p->n_op == CALL || p->n_op == FORTCALL || p->n_op == STCALL) { + /* Print out arguments first */ + for (p1 = r; p1->n_op == CM; p1 = p1->n_left) + gencode(p1->n_right, FOREFF); + gencode(p1, FOREFF); + o = UTYPE; /* avoid going down again */ + } + + if (o == BITYPE && (p->n_su & DORIGHT)) { + gencode(r, INREGS); + if (q->rewrite & RRIGHT) + ckmove(p, r); + } + if (o != LTYPE) { + gencode(l, INREGS); + if (q->rewrite & RLEFT) + ckmove(p, l); + } + if (o == BITYPE && !(p->n_su & DORIGHT)) { + gencode(r, INREGS); + if (q->rewrite & RRIGHT) + ckmove(p, r); + } + + canon(p); + + if (q->needs & NSPECIAL) { + int rr = rspecial(q, NRIGHT); + int lr = rspecial(q, NLEFT); + + if (rr >= 0) { + if (r->n_op != REG) + comperr("gencode: rop != REG"); + if (rr != r->n_rval) + rmove(r->n_rval, rr, r->n_type); + r->n_rval = r->n_reg = rr; + } + if (lr >= 0) { + if (l->n_op != REG) + comperr("gencode: %p lop != REG", p); + if (lr != l->n_rval) + rmove(l->n_rval, lr, l->n_type); + l->n_rval = l->n_reg = lr; + } + if (rr >= 0 && lr >= 0 && (l->n_reg == rr || r->n_reg == lr)) + comperr("gencode: cross-reg-move"); + } + + if (p->n_op == ASSIGN && + p->n_left->n_op == REG && p->n_right->n_op == REG && + p->n_left->n_rval == p->n_right->n_rval){ + /* do not emit anything */ + CDEBUG(("gencode(%p) assign nothing\n", p)); + rewrite(p, q->rewrite, cookie); + return; + } + + CDEBUG(("emitting node %p\n", p)); + if (TBLIDX(p->n_su) == 0) + return; + + expand(p, cookie, q->cstring); + if (callop(p->n_op) && cookie != FOREFF && + DECRA(p->n_reg, 0) != RETREG(p->n_type)) { + CDEBUG(("gencode(%p) retreg\n", p)); + rmove(RETREG(p->n_type), DECRA(p->n_reg, 0), p->n_type); + } else if (q->needs & NSPECIAL) { + int rr = rspecial(q, NRES); + + if (rr >= 0 && DECRA(p->n_reg, 0) != rr) { + CDEBUG(("gencode(%p) nspec retreg\n", p)); + rmove(rr, DECRA(p->n_reg, 0), p->n_type); + } + } else if ((q->rewrite & RESC1) && + (DECRA(p->n_reg, 1) != DECRA(p->n_reg, 0))) { + CDEBUG(("gencode(%p) RESC1 retreg\n", p)); + rmove(DECRA(p->n_reg, 1), DECRA(p->n_reg, 0), p->n_type); + } +#if 0 + /* XXX - kolla upp det här */ + else if (p->n_op == ASSIGN) { + /* may need move added if RLEFT/RRIGHT */ + /* XXX should be handled in sucomp() */ + if ((q->rewrite & RLEFT) && (p->n_left->n_op == REG) && + (p->n_left->n_rval != DECRA(p->n_reg, 0)) && + TCLASS(p->n_su)) { + rmove(p->n_left->n_rval, DECRA(p->n_reg, 0), p->n_type); + } else if ((q->rewrite & RRIGHT) && (p->n_right->n_op == REG) && + (p->n_right->n_rval != DECRA(p->n_reg, 0)) && + TCLASS(p->n_su)) { + rmove(p->n_right->n_rval, DECRA(p->n_reg, 0), p->n_type); + } + } +#endif + rewrite(p, q->rewrite, cookie); +} + +int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ; /* negatives of relationals */ + +#ifdef PCC_DEBUG +#undef PRTABLE +void +e2print(NODE *p, int down, int *a, int *b) +{ +#ifdef PRTABLE + extern int tablesize; +#endif + + prfil = stdout; + *a = *b = down+1; + while( down >= 2 ){ + fprintf(prfil, "\t"); + down -= 2; + } + if( down-- ) fprintf(prfil, " " ); + + + fprintf(prfil, "%p) %s", p, opst[p->n_op] ); + switch( p->n_op ) { /* special cases */ + + case REG: + fprintf(prfil, " %s", rnames[p->n_rval] ); + break; + + case TEMP: + fprintf(prfil, " " CONFMT, p->n_lval); + break; + + case ICON: + case NAME: + case OREG: + fprintf(prfil, " " ); + adrput(prfil, p ); + break; + + case STCALL: + case USTCALL: + case STARG: + case STASG: + fprintf(prfil, " size=%d", p->n_stsize ); + fprintf(prfil, " align=%d", p->n_stalign ); + break; + } + + fprintf(prfil, ", " ); + tprint(prfil, p->n_type, p->n_qual); + fprintf(prfil, ", " ); + { + int gregn(struct regw *); + if (p->n_reg == -1) + fprintf(prfil, "REG <undef>"); + else if (p->n_reg < 100000) /* XXX */ + fprintf(prfil, "REG %s", rnames[DECRA(p->n_reg, 0)]); + else + fprintf(prfil, "TEMP %d", gregn(p->n_regw)); + } + fprintf(prfil, ", SU= %d(%cREG,%s,%s,%s,%s)\n", + TBLIDX(p->n_su), + TCLASS(p->n_su)+'@', +#ifdef PRTABLE + TBLIDX(p->n_su) >= 0 && TBLIDX(p->n_su) <= tablesize ? + table[TBLIDX(p->n_su)].cstring : "", +#else + "", +#endif + ltyp[LMASK&p->n_su], + rtyp[(p->n_su&RMASK) >> 2], p->n_su & DORIGHT ? "DORIGHT" : ""); +} +#endif + +#ifndef FIELDOPS +/* + * do this if there is no special hardware support for fields + */ +static void +ffld(NODE *p, int down, int *down1, int *down2 ) +{ + /* + * look for fields that are not in an lvalue context, + * and rewrite them... + */ + NODE *shp; + int s, o, v, ty; + + *down1 = asgop( p->n_op ); + *down2 = 0; + + if( !down && p->n_op == FLD ){ /* rewrite the node */ + + if( !rewfld(p) ) return; + + ty = p->n_type; + v = p->n_rval; + s = UPKFSZ(v); +# ifdef RTOLBYTES + o = UPKFOFF(v); /* amount to shift */ +# else + o = szty(p->n_type)*SZINT - s - UPKFOFF(v); /* amount to shift */ +#endif + + /* make & mask part */ + + p->n_left->n_type = ty; + + p->n_op = AND; + p->n_right = mklnode(ICON, (1 << s)-1, 0, ty); + + /* now, if a shift is needed, do it */ + + if( o != 0 ){ + shp = mkbinode(RS, p->n_left, + mklnode(ICON, o, 0, INT), ty); + p->n_left = shp; + /* whew! */ + } + } +} +#endif + +/* + * change left TEMPs into OREGs + */ +void +deltemp(NODE *p) +{ + struct tmpsave *w; + NODE *l; + + if (p->n_op == TEMP) { + /* Check if already existing */ + for (w = tmpsave; w; w = w->next) + if (w->tempno == p->n_lval) + break; + if (w == NULL) { + /* new on stack */ + w = tmpalloc(sizeof(struct tmpsave)); + w->tempno = p->n_lval; + w->tempaddr = BITOOR(freetemp(szty(p->n_type))); + w->next = tmpsave; + tmpsave = w; + } + p->n_op = OREG; + p->n_rval = FPREG; + p->n_lval = w->tempaddr; + } else if (p->n_op == ADDROF) { + /* TEMPs are already converted to OREGs */ + if ((l = p->n_left)->n_op != OREG) + comperr("bad U&"); + p->n_op = PLUS; + l->n_op = REG; + l->n_type = INCREF(l->n_type); + p->n_right = mklnode(ICON, l->n_lval, 0, INT); + } +} + +/* + * for pointer/integer arithmetic, set pointer at left node + */ +static void +setleft(NODE *p) +{ + NODE *q; + + /* only additions for now */ + if (p->n_op != PLUS) + return; + if (ISPTR(p->n_right->n_type) && !ISPTR(p->n_left->n_type)) { + q = p->n_right; + p->n_right = p->n_left; + p->n_left = q; + } +} + +/* It is OK to have these as externals */ +static int oregr; +static CONSZ oregtemp; +static char *oregcp; +/* + * look for situations where we can turn * into OREG + * If sharp then do not allow temps. + */ +int +oregok(NODE *p, int sharp) +{ + + NODE *q; + NODE *ql, *qr; + int r; + CONSZ temp; + char *cp; + + q = p->n_left; +#if 0 + if ((q->n_op == REG || (q->n_op == TEMP && !sharp)) && + q->n_rval == DECRA(q->n_reg, 0)) { +#endif + if (q->n_op == REG || (q->n_op == TEMP && !sharp)) { + temp = q->n_lval; + r = q->n_rval; + cp = q->n_name; + goto ormake; + } + + if (q->n_op != PLUS && q->n_op != MINUS) + return 0; + ql = q->n_left; + qr = q->n_right; + +#ifdef R2REGS + + /* look for doubly indexed expressions */ + /* XXX - fix checks */ + + if( q->n_op == PLUS) { + int i; + if( (r=base(ql))>=0 && (i=offset(qr, tlen(p)))>=0) { + makeor2(p, ql, r, i); + return; + } else if((r=base(qr))>=0 && (i=offset(ql, tlen(p)))>=0) { + makeor2(p, qr, r, i); + return; + } + } + + +#endif + +#if 0 + if( (q->n_op==PLUS || q->n_op==MINUS) && qr->n_op == ICON && + (ql->n_op==REG || (ql->n_op==TEMP && !sharp)) && + szty(qr->n_type)==1 && + (ql->n_rval == DECRA(ql->n_reg, 0) || + /* XXX */ + ql->n_rval == FPREG || ql->n_rval == STKREG)) { +#endif + if ((q->n_op==PLUS || q->n_op==MINUS) && qr->n_op == ICON && + (ql->n_op==REG || (ql->n_op==TEMP && !sharp))) { + + temp = qr->n_lval; + if( q->n_op == MINUS ) temp = -temp; + r = ql->n_rval; + temp += ql->n_lval; + cp = qr->n_name; + if( *cp && ( q->n_op == MINUS || *ql->n_name ) ) + return 0; + if( !*cp ) cp = ql->n_name; + + ormake: + if( notoff( p->n_type, r, temp, cp )) + return 0; + oregtemp = temp; + oregr = r; + oregcp = cp; + return 1; + } + return 0; +} + +static void +ormake(NODE *p) +{ + NODE *q = p->n_left; + + p->n_op = OREG; + p->n_rval = oregr; + p->n_lval = oregtemp; + p->n_name = oregcp; + tfree(q); +} + +/* + * look for situations where we can turn * into OREG + */ +void +oreg2(NODE *p) +{ + if (p->n_op != UMUL) + return; + if (oregok(p, 1)) + ormake(p); + if (p->n_op == UMUL) + myormake(p); +} + +void +canon(p) NODE *p; { + /* put p in canonical form */ + + walkf(p, setleft); /* ptrs at left node for arithmetic */ + walkf(p, oreg2); /* look for and create OREG nodes */ +#ifndef FIELDOPS + fwalk(p, ffld, 0); /* look for field operators */ +# endif +#ifdef MYCANON + MYCANON(p); /* your own canonicalization routine(s) */ +#endif + +} + +void +comperr(char *str, ...) +{ + extern char *ftitle; + va_list ap; + + va_start(ap, str); + fprintf(stderr, "%s, line %d: compiler error: ", ftitle, thisline); + vfprintf(stderr, str, ap); + fprintf(stderr, "\n"); + va_end(ap); + prfil = stderr; + + if (nodepole && nodepole->n_op != FREE) + fwalk(nodepole, e2print, 0); + exit(1); +} + +/* + * allocate k integers worth of temp space + * we also make the convention that, if the number of words is + * more than 1, it must be aligned for storing doubles... + * Returns bits offset from base register. + * XXX - redo this. + */ +int +freetemp(int k) +{ +#ifndef BACKTEMP + int t; + + if (k > 1) + SETOFF(p2autooff, ALDOUBLE/ALCHAR); + + t = p2autooff; + p2autooff += k*(SZINT/SZCHAR); + if (p2autooff > p2maxautooff) + p2maxautooff = p2autooff; + return (t); + +#else + p2autooff += k*(SZINT/SZCHAR); + if (k > 1) + SETOFF(p2autooff, ALDOUBLE/ALCHAR); + + if (p2autooff > p2maxautooff) + p2maxautooff = p2autooff; + return( -p2autooff ); +#endif + } + +NODE * +mklnode(int op, CONSZ lval, int rval, TWORD type) +{ + NODE *p = talloc(); + + p->n_name = ""; + p->n_qual = 0; + p->n_op = op; + p->n_lval = lval; + p->n_rval = rval; + p->n_type = type; + p->n_regw = NULL; + p->n_su = 0; + return p; +} + +NODE * +mkbinode(int op, NODE *left, NODE *right, TWORD type) +{ + NODE *p = talloc(); + + p->n_name = ""; + p->n_qual = 0; + p->n_op = op; + p->n_left = left; + p->n_right = right; + p->n_type = type; + p->n_regw = NULL; + return p; +} + +NODE * +mkunode(int op, NODE *left, int rval, TWORD type) +{ + NODE *p = talloc(); + + p->n_name = ""; + p->n_qual = 0; + p->n_op = op; + p->n_left = left; + p->n_rval = rval; + p->n_type = type; + p->n_regw = NULL; + return p; +} + +struct interpass * +ipnode(NODE *p) +{ + struct interpass *ip = tmpalloc(sizeof(struct interpass)); + + ip->ip_node = p; + ip->type = IP_NODE; + ip->lineno = thisline; + return ip; +} + +int +rspecial(struct optab *q, int what) +{ + struct rspecial *r = nspecial(q); + while (r->op) { + if (r->op == what) + return r->num; + r++; + } + return -1; +} diff --git a/usr.bin/pcc/mip/regs.c b/usr.bin/pcc/mip/regs.c new file mode 100644 index 00000000000..3371b4bee79 --- /dev/null +++ b/usr.bin/pcc/mip/regs.c @@ -0,0 +1,2244 @@ +/* $Id: regs.c,v 1.1 2007/09/15 18:12:37 otto Exp $ */ +/* + * Copyright (c) 2005 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> +#include <stdlib.h> + +#define MAXLOOP 20 /* Max number of allocation loops XXX 3 should be enough */ + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +/* + * New-style register allocator using graph coloring. + * The design is based on the George and Appel paper + * "Iterated Register Coalescing", ACM Transactions, No 3, May 1996. + */ + +#define BIT2BYTE(bits) ((((bits)+NUMBITS-1)/NUMBITS)*(NUMBITS/8)) +#define BITALLOC(ptr,all,sz) { \ + int __s = BIT2BYTE(sz); ptr = all(__s); memset(ptr, 0, __s); } + +#undef COMPERR_PERM_MOVE +#define RDEBUG(x) if (rdebug) printf x +#define RRDEBUG(x) if (rdebug > 1) printf x +#define RPRINTIP(x) if (rdebug) printip(x) +#define RDX(x) x +#define UDEBUG(x) if (udebug) printf x + +/* + * Data structure overview for this implementation of graph coloring: + * + * Each temporary (called "node") is described by the type REGW. + * Space for all nodes is allocated initially as an array, so + * the nodes can be can be referenced both by the node number and + * by pointer. + * + * All moves are represented by the type REGM, allocated when needed. + * + * The "live" set used during graph building is represented by a bitset. + * + * Interference edges are represented by struct AdjSet, hashed and linked + * from index into the edgehash array. + * + * A mapping from each node to the moves it is assiciated with is + * maintained by an array moveList which for each node number has a linked + * list of MOVL types, each pointing to a REGM. + * + * Adjacency list is maintained by the adjList array, indexed by the + * node number. Each adjList entry points to an ADJL type, and is a + * single-linked list for all adjacent nodes. + * + * degree, alias and color are integer arrays indexed by node number. + */ + +/* + * linked list of adjacent nodes. + */ +typedef struct regw3 { + struct regw3 *r_next; + struct regw *a_temp; +} ADJL; + +/* + * Structure describing a move. + */ +typedef struct regm { + DLIST_ENTRY(regm) link; + struct regw *src, *dst; + int queue; +} REGM; + +typedef struct movlink { + struct movlink *next; + REGM *regm; +} MOVL; + +/* + * Structure describing a temporary. + */ +typedef struct regw { + DLIST_ENTRY(regw) link; + ADJL *r_adjList; /* linked list of adjacent nodes */ + int r_class; /* this nodes class */ + int r_nclass[NUMCLASS+1]; /* count of adjacent classes */ + struct regw *r_alias; /* aliased temporary */ + int r_color; /* final node color */ + struct regw *r_onlist; /* which work list this node belongs to */ + MOVL *r_moveList; /* moves associated with this node */ +#ifdef PCC_DEBUG + int nodnum; /* Debug number */ +#endif +} REGW; + +/* + * Worklists, a node is always on exactly one of these lists. + */ +static REGW precolored, simplifyWorklist, freezeWorklist, spillWorklist, + spilledNodes, coalescedNodes, coloredNodes, selectStack; +static REGW initial, *nblock; +static void insnwalk(NODE *p); +#ifdef PCC_DEBUG +int nodnum = 100; +#define SETNUM(x) (x)->nodnum = nodnum++ +#define ASGNUM(x) (x)->nodnum +#else +#define SETNUM(x) +#define ASGNUM(x) +#endif + +#define ALLNEEDS (NACOUNT|NBCOUNT|NCCOUNT|NDCOUNT) + +/* XXX */ +REGW *ablock; + +static int tempmin, tempmax, basetemp, xbits; +/* + * nsavregs is an array that matches the permregs array. + * Each entry in the array may have the values: + * 0 : register coalesced, just ignore. + * 1 : save register on stack + * If the entry is 0 but the resulting color differs from the + * corresponding permregs index, add moves. + * XXX - should be a bitfield! + */ +static int *nsavregs, *ndontregs; + +/* + * Return the REGW struct for a temporary. + * If first time touched, enter into list for existing vars. + * Only called from sucomp(). + */ +static REGW * +newblock(NODE *p) +{ + REGW *nb = &nblock[(int)p->n_lval]; + if (nb->link.q_forw == 0) { + DLIST_INSERT_AFTER(&initial, nb, link); + ASGNUM(nb) = p->n_lval; + RDEBUG(("Adding longtime %d for tmp %d\n", + nb->nodnum, (int)p->n_lval)); + } + if (nb->r_class == 0) + nb->r_class = gclass(p->n_type); + RDEBUG(("newblock: p %p, node %d class %d\n", + p, nb->nodnum, nb->r_class)); + return nb; +} + +/* + * Count the number of registers needed to evaluate a tree. + * This is only done to find the evaluation order of the tree. + * While here, assign temp numbers to the registers that will + * be needed when the tree is evaluated. + * + * While traversing the tree, assign REGW nodes to the registers + * used by all instructions: + * - n_regw[0] is always set to the outgoing node. If the + * instruction is 2-op (addl r0,r1) then an implicit move + * is inserted just before the left (clobbered) operand. + * - if the instruction has needs then REGW nodes are + * allocated as n_regw[1] etc. + */ +int +nsucomp(NODE *p) +{ + struct optab *q; + int left, right; + int nreg, need, i, nxreg, o; + int nareg, nbreg, ncreg, ndreg; + REGW *w; + + o = optype(p->n_op); + + UDEBUG(("entering nsucomp, node %p\n", p)); + + if (TBLIDX(p->n_su) == 0) { + int a = 0, b; + + p->n_regw = NULL; + if (o == LTYPE ) { + if (p->n_op == TEMP) + p->n_regw = newblock(p); + } else + a = nsucomp(p->n_left); + if (o == BITYPE) { + b = nsucomp(p->n_right); + if (b > a) + p->n_su |= DORIGHT; + a = MAX(a, b); + } + return a; + } + + q = &table[TBLIDX(p->n_su)]; + nareg = (q->needs & NACOUNT); + + for (i = (q->needs & NBCOUNT), nbreg = 0; i; i -= NBREG) + nbreg++; + for (i = (q->needs & NCCOUNT), ncreg = 0; i; i -= NCREG) + ncreg++; + for (i = (q->needs & NDCOUNT), ndreg = 0; i; i -= NDREG) + ndreg++; + + nxreg = nareg + nbreg + ncreg + ndreg; + nreg = nxreg; + if (callop(p->n_op)) + nreg = MAX(fregs, nreg); + + if (o == BITYPE) { + right = nsucomp(p->n_right); + } else + right = 0; + + if (o != LTYPE) + left = nsucomp(p->n_left); + else + left = 0; + + UDEBUG(("node %p left %d right %d\n", p, left, right)); + + if (o == BITYPE) { + /* Two children */ + if (right == left) { + need = left + MAX(nreg, 1); + } else { + need = MAX(right, left); + need = MAX(need, nreg); + } + if (setorder(p) == 0) { + /* XXX - should take care of overlapping needs */ + if (right > left) { + p->n_su |= DORIGHT; + } else if (right == left) { + /* A favor to 2-operand architectures */ + if ((q->rewrite & RRIGHT) == 0) + p->n_su |= DORIGHT; + } + } + } else if (o != LTYPE) { + /* One child */ + need = MAX(right, left) + nreg; + } else + need = nreg; + + if (p->n_op == TEMP) + (void)newblock(p); + + if (TCLASS(p->n_su) == 0 && nxreg == 0) { + UDEBUG(("node %p no class\n", p)); + p->n_regw = NULL; /* may be set earlier */ + return need; + } + +#define ADCL(n, cl) \ + for (i = 0; i < n; i++, w++) { w->r_class = cl; \ + DLIST_INSERT_BEFORE(&initial, w, link); SETNUM(w); \ + UDEBUG(("Adding " #n " %d\n", w->nodnum)); \ + } + + UDEBUG(("node %p numregs %d\n", p, nxreg+1)); + w = p->n_regw = tmpalloc(sizeof(REGW) * (nxreg+1)); + memset(w, 0, sizeof(REGW) * (nxreg+1)); + + w->r_class = TCLASS(p->n_su); + if (w->r_class == 0) + w->r_class = gclass(p->n_type); + SETNUM(w); + if (w->r_class) + DLIST_INSERT_BEFORE(&initial, w, link); + UDEBUG(("Adding short %d calss %d\n", w->nodnum, w->r_class)); + w++; + ADCL(nareg, CLASSA); + ADCL(nbreg, CLASSB); + ADCL(ncreg, CLASSC); + ADCL(ndreg, CLASSD); + + if (q->rewrite & RESC1) { + w = p->n_regw + 1; + w->r_class = -1; + DLIST_REMOVE(w,link); + } else if (q->rewrite & RESC2) { + w = p->n_regw + 2; + w->r_class = -1; + DLIST_REMOVE(w,link); + } else if (q->rewrite & RESC3) { + w = p->n_regw + 3; + w->r_class = -1; + DLIST_REMOVE(w,link); + } + + UDEBUG(("node %p return regs %d\n", p, need)); + + return need; +} + +#define CLASS(x) (x)->r_class +#define NCLASS(x,c) (x)->r_nclass[c] +#define ADJLIST(x) (x)->r_adjList +#define ALIAS(x) (x)->r_alias +#define ONLIST(x) (x)->r_onlist +#define MOVELIST(x) (x)->r_moveList +#define COLOR(x) (x)->r_color + +static bittype *live; + +#define PUSHWLIST(w, l) DLIST_INSERT_AFTER(&l, w, link); w->r_onlist = &l +#define POPWLIST(l) popwlist(&l); +#define DELWLIST(w) DLIST_REMOVE(w, link) +#define WLISTEMPTY(h) DLIST_ISEMPTY(&h,link) +#define PUSHMLIST(w, l, q) DLIST_INSERT_AFTER(&l, w, link); w->queue = q +#define POPMLIST(l) popmlist(&l); + +#define trivially_colorable(x) \ + trivially_colorable_p((x)->r_class, (x)->r_nclass) +/* + * Determine if a node is trivially colorable ("degree < K"). + * This implementation is a dumb one, without considering speed. + */ +static int +trivially_colorable_p(int c, int *n) +{ + int r[NUMCLASS+1]; + int i; + + for (i = 1; i < NUMCLASS+1; i++) + r[i] = n[i] < regK[i] ? n[i] : regK[i]; + +#if 0 + /* add the exclusion nodes. */ + /* XXX can we do someything smart here? */ + /* worst-case for exclusion nodes are better than the `worst-case' */ + for (; excl; excl >>= 1) + if (excl & 1) + r[c]++; +#endif + + i = COLORMAP(c, r); +if (i < 0 || i > 1) + comperr("trivially_colorable_p"); +//printf("trivially_colorable_p: n[1] %d n[2] %d n[3] %d n[4] %d class %d, triv %d\n", n[1], n[2], n[3], n[4], c, i); + return i; +} + +static int +ncnt(int needs) +{ + int i = 0; + + while (needs & NACOUNT) + needs -= NAREG, i++; + while (needs & NBCOUNT) + needs -= NBREG, i++; + while (needs & NCCOUNT) + needs -= NCREG, i++; + while (needs & NDCOUNT) + needs -= NDREG, i++; + return i; +} + +static inline REGW * +popwlist(REGW *l) +{ + REGW *w = DLIST_NEXT(l, link); + + DLIST_REMOVE(w, link); + w->r_onlist = NULL; + return w; +} + +/* + * Move lists, a move node is always on only one list. + */ +static REGM coalescedMoves, constrainedMoves, frozenMoves, + worklistMoves, activeMoves; +enum { COAL, CONSTR, FROZEN, WLIST, ACTIVE }; + +static inline REGM * +popmlist(REGM *l) +{ + REGM *w = DLIST_NEXT(l, link); + + DLIST_REMOVE(w, link); + return w; +} + +/* + * About data structures used in liveness analysis: + * + * The temporaries generated in pass1 are numbered between tempmin and + * tempmax. Temporaries generated in pass2 are numbered above tempmax, + * so they are sequentially numbered. + * + * Bitfields are used for liveness. Bit arrays are allocated on the + * heap for the "live" variable and on the stack for the in, out, gen + * and kill variables. Therefore, for a temp number, the bit number must + * be biased with tempmin. + * + * There may be an idea to use a different data structure to store + * pass2 allocated temporaries, because they are very sparse. + */ + +#ifdef PCC_DEBUG +static void +LIVEADD(int x) +{ + RDEBUG(("Liveadd: %d\n", x)); + if (x < tempmin || x >= tempmax) + comperr("LIVEADD: out of range"); + BITSET(live, (x-tempmin)); +} +static void +LIVEDEL(int x) +{ + RDEBUG(("Livedel: %d\n", x)); + if (x < tempmin || x >= tempmax) + comperr("LIVEDEL: out of range"); + BITCLEAR(live, (x-tempmin)); +} +#else +#define LIVEADD(x) BITSET(live, (x-tempmin)) +#define LIVEDEL(x) BITCLEAR(live, (x-tempmin)) +#endif + +static struct lives { + DLIST_ENTRY(lives) link; + REGW *var; +} lused, lunused; + +static void +LIVEADDR(REGW *x) +{ + struct lives *l; + +#ifdef PCC_DEBUG + RDEBUG(("LIVEADDR: %d\n", x->nodnum)); + DLIST_FOREACH(l, &lused, link) + if (l->var == x) + return; +// comperr("LIVEADDR: multiple %d", ASGNUM(x)); +#endif + if (!DLIST_ISEMPTY(&lunused, link)) { + l = DLIST_NEXT(&lunused, link); + DLIST_REMOVE(l, link); + } else + l = tmpalloc(sizeof(struct lives)); + + l->var = x; + DLIST_INSERT_AFTER(&lused, l, link); +} + +static void +LIVEDELR(REGW *x) +{ + struct lives *l; + + RDEBUG(("LIVEDELR: %d\n", x->nodnum)); + DLIST_FOREACH(l, &lused, link) { + if (l->var != x) + continue; + DLIST_REMOVE(l, link); + DLIST_INSERT_AFTER(&lunused, l, link); + return; + } +// comperr("LIVEDELR: %p not found", x); +} + +#define MOVELISTADD(t, p) movelistadd(t, p) +#define WORKLISTMOVEADD(s,d) worklistmoveadd(s,d) + +static void +movelistadd(REGW *t, REGM *p) +{ + MOVL *w = tmpalloc(sizeof(MOVL)); + + w->regm = p; + w->next = t->r_moveList; + t->r_moveList = w; +} + +static REGM * +worklistmoveadd(REGW *src, REGW *dst) +{ + REGM *w = tmpalloc(sizeof(REGM)); + + DLIST_INSERT_AFTER(&worklistMoves, w, link); + w->src = src; + w->dst = dst; + w->queue = WLIST; + return w; +} + +struct AdjSet { + struct AdjSet *next; + REGW *u, *v; +} *edgehash[256]; + +/* Check if a node pair is adjacent */ +static int +adjSet(REGW *u, REGW *v) +{ + struct AdjSet *w; + REGW *t; + + if (ONLIST(u) == &precolored) { + ADJL *a = ADJLIST(v); + /* + * Check if any of the registers that have edges against v + * alias to u. + */ + for (; a; a = a->r_next) { + if (ONLIST(a->a_temp) != &precolored) + continue; + t = a->a_temp; + if (interferes(t - ablock, u - ablock)) + return 1; + } + } + if (u > v) + t = v, v = u, u = t; + w = edgehash[((int)u+(int)v) & 255]; + for (; w; w = w->next) { + if (u == w->u && v == w->v) + return 1; + } + return 0; +} + +/* Add a pair to adjset. No check for dups */ +static void +adjSetadd(REGW *u, REGW *v) +{ + struct AdjSet *w; + int x; + REGW *t; + + if (u > v) + t = v, v = u, u = t; + x = ((int)u+(int)v) & 255; + w = tmpalloc(sizeof(struct AdjSet)); + w->u = u, w->v = v; + w->next = edgehash[x]; + edgehash[x] = w; +} + +/* + * Add an interference edge between two nodes. + */ +static void +AddEdge(REGW *u, REGW *v) +{ + ADJL *x; + + RRDEBUG(("AddEdge: u %d v %d\n", ASGNUM(u), ASGNUM(v))); + +#ifdef PCC_DEBUG +#if 0 + if (ASGNUM(u) == 0) + comperr("AddEdge 0"); +#endif + if (CLASS(u) == 0 || CLASS(v) == 0) + comperr("AddEdge class == 0 (%d=%d, %d=%d)", + CLASS(u), ASGNUM(u), CLASS(v), ASGNUM(v)); +#endif + + if (u == v) + return; + if (adjSet(u, v)) + return; + + adjSetadd(u, v); + +#if 0 + if (ONLIST(u) == &precolored || ONLIST(v) == &precolored) + comperr("precolored node in AddEdge"); +#endif + + if (ONLIST(u) != &precolored) { + x = tmpalloc(sizeof(ADJL)); + x->a_temp = v; + x->r_next = u->r_adjList; + u->r_adjList = x; + NCLASS(u, CLASS(v))++; + } + + if (ONLIST(v) != &precolored) { + x = tmpalloc(sizeof(ADJL)); + x->a_temp = u; + x->r_next = v->r_adjList; + v->r_adjList = x; + NCLASS(v, CLASS(u))++; + } + +#if 0 + RDEBUG(("AddEdge: u %d(d %d) v %d(d %d)\n", u, DEGREE(u), v, DEGREE(v))); +#endif +} + +static int +MoveRelated(REGW *n) +{ + MOVL *l; + REGM *w; + + for (l = MOVELIST(n); l; l = l->next) { + w = l->regm; + if (w->queue == ACTIVE || w->queue == WLIST) + return 1; + } + return 0; +} + +static void +MkWorklist(void) +{ + REGW *w; + + RDX(int s=0); + RDX(int f=0); + RDX(int d=0); + + DLIST_INIT(&precolored, link); + DLIST_INIT(&simplifyWorklist, link); + DLIST_INIT(&freezeWorklist, link); + DLIST_INIT(&spillWorklist, link); + DLIST_INIT(&spilledNodes, link); + DLIST_INIT(&coalescedNodes, link); + DLIST_INIT(&coloredNodes, link); + DLIST_INIT(&selectStack, link); + + /* + * Remove all nodes from the initial list and put them on + * one of the worklists. + */ + while (!DLIST_ISEMPTY(&initial, link)) { + w = DLIST_NEXT(&initial, link); + DLIST_REMOVE(w, link); + if (!trivially_colorable(w)) { + PUSHWLIST(w, spillWorklist); + RDX(s++); + } else if (MoveRelated(w)) { + PUSHWLIST(w, freezeWorklist); + RDX(f++); + } else { + PUSHWLIST(w, simplifyWorklist); + RDX(d++); + } + } + RDEBUG(("MkWorklist: spill %d freeze %d simplify %d\n", s,f,d)); +} + +static void +addalledges(REGW *e) +{ + int i, j, k; + int nbits = xbits; + struct lives *l; + + RDEBUG(("addalledges for %d\n", e->nodnum)); + + if (e->r_class == -1) + return; /* unused */ + + if (ONLIST(e) != &precolored) { + for (i = 0; ndontregs[i] >= 0; i++) + AddEdge(e, &ablock[ndontregs[i]]); + } + + /* First add to long-lived temps */ + RDEBUG(("addalledges longlived ")); + for (i = 0; i < nbits; i += NUMBITS) { + if ((k = live[i/NUMBITS]) == 0) + continue; + while (k) { + j = ffs(k)-1; + AddEdge(&nblock[i+j+tempmin], e); + RRDEBUG(("%d ", i+j+tempmin)); + k &= ~(1 << j); + } + } + RDEBUG(("done\n")); + /* short-lived temps */ + RDEBUG(("addalledges shortlived ")); + DLIST_FOREACH(l, &lused, link) { + RRDEBUG(("%d ", ASGNUM(l->var))); + AddEdge(l->var, e); + } + RDEBUG(("done\n")); +} + +/* + * Add a move edge between def and use. + */ +static void +moveadd(REGW *def, REGW *use) +{ + REGM *r; + + if (def == use) + return; /* no move to itself XXX - ``shouldn't happen'' */ + RDEBUG(("moveadd: def %d use %d\n", ASGNUM(def), ASGNUM(use))); + + r = WORKLISTMOVEADD(use, def); + MOVELISTADD(def, r); + MOVELISTADD(use, r); +} + +/* + * Traverse arguments backwards. + * XXX - can this be tricked in some other way? + */ +static void +argswalk(NODE *p) +{ + + if (p->n_op == CM) { + argswalk(p->n_left); + insnwalk(p->n_right); + } else + insnwalk(p); +} + +/* + * Add to (or remove from) live set variables that must not + * be clobbered when traversing down on the other leg for + * a BITYPE node. + */ +static void +setlive(NODE *p, int set, REGW *rv) +{ + if (rv != NULL) + return set ? LIVEADDR(rv) : LIVEDELR(rv); + + if (p->n_regw != NULL) + return set ? LIVEADDR(p->n_regw) : LIVEDELR(p->n_regw); + + switch (optype(p->n_op)) { + case LTYPE: + if (p->n_op == TEMP) + set ? LIVEADD((int)p->n_lval) : LIVEDEL((int)p->n_lval); +#ifdef notyet + else if (p->n_op == REG) + ... +#endif + break; + case BITYPE: + setlive(p->n_right, set, rv); + /* FALLTHROUGH */ + case UTYPE: + setlive(p->n_left, set, rv); + break; + } +} + +/* + * Add edges for temporary w against all temporaries that may be + * used simultaneously (like index registers). + */ +static void +addedge_r(NODE *p, REGW *w) +{ + if (p->n_regw != NULL) + return AddEdge(p->n_regw, w); + + if (optype(p->n_op) == BITYPE) + addedge_r(p->n_right, w); + if (optype(p->n_op) != LTYPE) + addedge_r(p->n_left, w); +} + +/* + * Do the in-tree part of liveness analysis. (the difficult part) + * + * Walk down the tree in reversed-evaluation order (backwards). + * The moves and edges inserted and evaluation order for + * instructions when code is emitted is described here, hence + * this code runs the same but backwards. + * + * 2-op reclaim LEFT: eval L, move to DEST, eval R. + * moveadd L,DEST; addedge DEST,R + * 2-op reclaim LEFT DORIGHT: eval R, eval L, move to DEST. + * moveadd L,DEST; addedge DEST,R; addedge L,R + * 2-op reclaim RIGHT; eval L, eval R, move to DEST. + * moveadd R,DEST; addedge DEST,L; addedge L,R + * 2-op reclaim RIGHT DORIGHT: eval R, move to DEST, eval L. + * moveadd R,DEST; addedge DEST,L + * 3-op: eval L, eval R + * addedge L,R + * 3-op DORIGHT: eval R, eval L + * addedge L,R + * + * Instructions with special needs are handled just like these variants, + * with the exception of extra added moves and edges. + * Moves to special regs are scheduled after the evaluation of both legs. + */ + +#define ASGLEFT(p) (p->n_op == ASSIGN && p->n_left->n_op == TEMP) + +static void +insnwalk(NODE *p) +{ + int o = p->n_op; + struct optab *q = &table[TBLIDX(p->n_su)]; + REGW *lr, *rr, *rv, *r, *rrv, *lrv; + int i, n; + + RDEBUG(("insnwalk %p\n", p)); + + rv = p->n_regw; + + rrv = lrv = NULL; + if (ASGLEFT(p)) { + int v = p->n_left->n_lval; + LIVEDEL(v); /* remove assigned temp from live set */ + addalledges(&nblock[v]); + } + + /* Add edges for the result of this node */ + if (rv && (q->visit & INREGS || o == TEMP)) + addalledges(rv); + + /* special handling of CALL operators */ + if (callop(o)) { + if (rv) + moveadd(rv, &ablock[RETREG(p->n_type)]); + for (i = 0; tempregs[i] >= 0; i++) + addalledges(&ablock[tempregs[i]]); + } + + /* for special return value registers add moves */ + if ((q->needs & NSPECIAL) && (n = rspecial(q, NRES)) >= 0) { + rv = &ablock[n]; + moveadd(p->n_regw, rv); + } + + /* Check leaves for results in registers */ + lr = optype(o) != LTYPE ? p->n_left->n_regw : NULL; + rr = optype(o) == BITYPE ? p->n_right->n_regw : NULL; + + /* simple needs */ + n = ncnt(q->needs); + for (i = 0; i < n; i++) { +#if 1 + static int ncl[] = { 0, NASL, NBSL, NCSL, NDSL }; + static int ncr[] = { 0, NASR, NBSR, NCSR, NDSR }; + + /* edges are already added */ + if ((r = &p->n_regw[1+i])->r_class == -1) + r = p->n_regw; + else + addalledges(r); + if (optype(o) != LTYPE && (q->needs & ncl[CLASS(r)]) == 0) + addedge_r(p->n_left, r); + if (optype(o) == BITYPE && (q->needs & ncr[CLASS(r)]) == 0) + addedge_r(p->n_right, r); +#else + if ((r = &p->n_regw[1+i])->r_class == -1) + continue; + addalledges(r); + if (optype(o) != LTYPE && (q->needs & NASL) == 0) + addedge_r(p->n_left, r); + if (optype(o) == BITYPE && (q->needs & NASR) == 0) + addedge_r(p->n_right, r); +#endif + } + + /* special needs */ + if (q->needs & NSPECIAL) { + struct rspecial *rc; + for (rc = nspecial(q); rc->op; rc++) { + switch (rc->op) { +#define ONLY(c,s) if (c) s(c, &ablock[rc->num]) + case NLEFT: + addalledges(&ablock[rc->num]); + ONLY(lr, moveadd); + break; + case NOLEFT: + addedge_r(p->n_left, &ablock[rc->num]); + break; + case NRIGHT: + addalledges(&ablock[rc->num]); + ONLY(rr, moveadd); + break; + case NORIGHT: + addedge_r(p->n_right, &ablock[rc->num]); + break; + case NEVER: + addalledges(&ablock[rc->num]); + break; +#undef ONLY + } + } + } + + if (o == ASSIGN) { + /* needs special treatment */ + if (lr && rr) + moveadd(lr, rr); + if (lr && rv) + moveadd(lr, rv); + if (rr && rv) + moveadd(rr, rv); + } else if (callop(o)) { +#ifdef notdef + /* calls needs special treatment */ + for (i = 0; tempregs[i] >= 0; i++) + addalledges(&ablock[i]); + if (rv) + moveadd(rv, &ablock[RETREG(p->n_type)]); +#endif + /* XXX - here must all live arg registers be added + * for archs with arguments in registers */ + } else if (q->rewrite & (RESC1|RESC2|RESC3)) { + if (lr && rr) + AddEdge(lr, rr); + } else if (q->rewrite & RLEFT) { + if (lr && rv) + moveadd(rv, lr), lrv = rv; + if (rr && rv) + AddEdge(rr, rv); + } else if (q->rewrite & RRIGHT) { + if (rr && rv) + moveadd(rv, rr), rrv = rv; + if (lr && rv) + AddEdge(lr, rv); + } + + switch (optype(o)) { + case BITYPE: + if (ASGLEFT(p)) { + /* only go down right node */ + insnwalk(p->n_right); + } else if (callop(o)) { + insnwalk(p->n_left); + /* Do liveness analysis on arguments (backwards) */ + argswalk(p->n_right); + } else if ((p->n_su & DORIGHT) == 0) { + setlive(p->n_left, 1, lrv); + insnwalk(p->n_right); + setlive(p->n_left, 0, lrv); + insnwalk(p->n_left); + } else { + setlive(p->n_right, 1, rrv); + insnwalk(p->n_left); + setlive(p->n_right, 0, rrv); + insnwalk(p->n_right); + } + break; + + case UTYPE: + insnwalk(p->n_left); + break; + + case LTYPE: + switch (o) { + case TEMP: + rr = &nblock[(int)p->n_lval]; + if (rv != rr) { + addalledges(rr); + moveadd(rv, rr); + } + LIVEADD((int)p->n_lval); + break; + case REG: + case OREG: + /* Liveness for regs??? */ + break; + default: + break; + } + break; + } +} + +static bittype **gen, **kill, **in, **out; + +static void +unionize(NODE *p, int bb) +{ + int i, o, ty; + + if ((o = p->n_op) == TEMP) { +#ifdef notyet + for (i = 0; i < szty(p->n_type); i++) { + BITSET(gen[bb], ((int)p->n_lval - tempmin+i)); + } +#else + i = 0; + BITSET(gen[bb], ((int)p->n_lval - tempmin+i)); +#endif + } + if (asgop(o) && p->n_left->n_op == TEMP) { + int b = p->n_left->n_lval - tempmin; +#ifdef notyet + for (i = 0; i < szty(p->n_type); i++) { + BITCLEAR(gen[bb], (b+i)); + BITSET(kill[bb], (b+i)); + } +#else + i = 0; + BITCLEAR(gen[bb], (b+i)); + BITSET(kill[bb], (b+i)); +#endif + unionize(p->n_right, bb); + return; + } + ty = optype(o); + if (ty != LTYPE) + unionize(p->n_left, bb); + if (ty == BITYPE) + unionize(p->n_right, bb); +} + +/* + * Do variable liveness analysis. Only analyze the long-lived + * variables, and save the live-on-exit temporaries in a bit-field + * at the end of each basic block. This bit-field is later used + * when doing short-range liveness analysis in Build(). + */ +static void +LivenessAnalysis(void) +{ + extern struct basicblock bblocks; + struct basicblock *bb; + struct interpass *ip; + int i, bbnum; + + /* + * generate the gen-kill sets for all basic blocks. + */ + DLIST_FOREACH(bb, &bblocks, bbelem) { + bbnum = bb->bbnum; + for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) { + /* gen/kill is 'p', this node is 'n' */ + if (ip->type == IP_NODE) + unionize(ip->ip_node, bbnum); + if (ip == bb->first) + break; + } + memcpy(in[bbnum], gen[bbnum], BIT2BYTE(tempmax-tempmin)); +#ifdef PCC_DEBUG + if (rdebug) { + printf("basic block %d\ngen: ", bbnum); + for (i = 0; i < tempmax-tempmin; i++) + if (TESTBIT(gen[bbnum], i)) + printf("%d ", i+tempmin); + printf("\nkill: "); + for (i = 0; i < tempmax-tempmin; i++) + if (TESTBIT(kill[bbnum], i)) + printf("%d ", i+tempmin); + printf("\n"); + } +#endif + } +} + +#define SETCOPY(t,f,i,n) for (i = 0; i < n/NUMBITS; i++) t[i] = f[i] +#define SETSET(t,f,i,n) for (i = 0; i < n/NUMBITS; i++) t[i] |= f[i] +#define SETCLEAR(t,f,i,n) for (i = 0; i < n/NUMBITS; i++) t[i] &= ~f[i] +#define SETCMP(v,t,f,i,n) for (i = 0; i < n/NUMBITS; i++) \ + if (t[i] != f[i]) v = 1 + +/* + * Build the set of interference edges and adjacency list. + */ +static void +Build(struct interpass *ipole) +{ + extern struct basicblock bblocks; + struct basicblock bbfake; + struct interpass *ip; + struct basicblock *bb; + struct cfgnode *cn; + extern int nbblocks; + bittype *saved; + int i, j, again, nbits; + + if (xtemps == 0) { + /* + * No basic block splitup is done if not optimizing, + * so fake one basic block to keep the liveness analysis + * happy. + */ + nbblocks = 1; + bbfake.bbnum = 0; + bbfake.last = DLIST_PREV(ipole, qelem); + bbfake.first = DLIST_NEXT(ipole, qelem); + DLIST_INIT(&bblocks, bbelem); + DLIST_INSERT_AFTER(&bblocks, &bbfake, bbelem); + SLIST_INIT(&bbfake.children); + } + + /* Just fetch space for the temporaries from stack */ + nbits = xbits+(NUMBITS-1); + gen = alloca(nbblocks*sizeof(bittype*)); + kill = alloca(nbblocks*sizeof(bittype*)); + in = alloca(nbblocks*sizeof(bittype*)); + out = alloca(nbblocks*sizeof(bittype*)); + for (i = 0; i < nbblocks; i++) { + BITALLOC(gen[i],alloca,nbits); + BITALLOC(kill[i],alloca,nbits); + BITALLOC(in[i],alloca,nbits); + BITALLOC(out[i],alloca,nbits); + } + BITALLOC(saved,alloca,nbits); + LivenessAnalysis(); + + /* register variable temporaries are live */ + for (i = 0; i < NPERMREG-1; i++) { + if (nsavregs[i]) + continue; + BITSET(out[nbblocks-1], i); + for (j = i+1; j < NPERMREG-1; j++) { + if (nsavregs[j]) + continue; + AddEdge(&nblock[i+tempmin], &nblock[j+tempmin]); + } + } + + /* do liveness analysis on basic block level */ + do { + again = 0; + /* XXX - loop should be in reversed execution-order */ + DLIST_FOREACH_REVERSE(bb, &bblocks, bbelem) { + int i = bb->bbnum; + SETCOPY(saved, out[i], j, nbits); + SLIST_FOREACH(cn, &bb->children, cfgelem) { + SETSET(out[i], in[cn->bblock->bbnum], + j, nbits); + } + SETCMP(again, saved, out[i], j, nbits); + SETCOPY(saved, in[i], j, nbits); + SETCOPY(in[i], out[i], j, nbits); + SETCLEAR(in[i], kill[i], j, nbits); + SETSET(in[i], gen[i], j, nbits); + SETCMP(again, saved, in[i], j, nbits); + } + } while (again); + +#ifdef PCC_DEBUG + if (rdebug) { + DLIST_FOREACH(bb, &bblocks, bbelem) { + printf("basic block %d\nin: ", bb->bbnum); + for (i = 0; i < tempmax-tempmin; i++) + if (TESTBIT(in[bb->bbnum], i)) + printf("%d ", i+tempmin); + printf("\nout: "); + for (i = 0; i < tempmax-tempmin; i++) + if (TESTBIT(out[bb->bbnum], i)) + printf("%d ", i+tempmin); + printf("\n"); + } + } +#endif + + DLIST_FOREACH(bb, &bblocks, bbelem) { + RDEBUG(("liveadd bb %d\n", bb->bbnum)); + i = bb->bbnum; + for (j = 0; j < (tempmax-tempmin); j += NUMBITS) + live[j/NUMBITS] = 0; + SETCOPY(live, out[i], j, nbits); + for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) { + if (ip->type == IP_NODE) + insnwalk(ip->ip_node); + if (ip == bb->first) + break; + } + } + +#ifdef PCC_DEBUG + if (rdebug) { + int i; + struct AdjSet *w; + ADJL *x; + REGW *y; + MOVL *m; + + printf("Interference edges\n"); + for (i = 0; i < 256; i++) { + if ((w = edgehash[i]) == NULL) + continue; + for (; w; w = w->next) + printf("%d <-> %d\n", ASGNUM(w->u), ASGNUM(w->v)); + } + printf("Degrees\n"); + DLIST_FOREACH(y, &initial, link) { + printf("%d (%c): trivial [%d] ", ASGNUM(y), + CLASS(y)+'@', trivially_colorable(y)); + for (x = ADJLIST(y); x; x = x->r_next) { + if (ONLIST(x->a_temp) != &selectStack && + ONLIST(x->a_temp) != &coalescedNodes) + printf("%d ", ASGNUM(x->a_temp)); + else + printf("(%d) ", ASGNUM(x->a_temp)); + } + printf("\n"); + } + printf("Move nodes\n"); + DLIST_FOREACH(y, &initial, link) { + if (MOVELIST(y) == NULL) + continue; + printf("%d: ", ASGNUM(y)); + for (m = MOVELIST(y); m; m = m->next) { + REGW *yy = m->regm->src == y ? + m->regm->dst : m->regm->src; + printf("%d ", ASGNUM(yy)); + } + printf("\n"); + } + } +#endif + +} + +static void +EnableMoves(REGW *n) +{ + MOVL *l; + REGM *m; + + for (l = MOVELIST(n); l; l = l->next) { + m = l->regm; + if (m->queue != ACTIVE) + continue; + DLIST_REMOVE(m, link); + PUSHMLIST(m, worklistMoves, WLIST); + } +} + +static void +EnableAdjMoves(REGW *nodes) +{ + ADJL *w; + REGW *n; + + EnableMoves(nodes); + for (w = ADJLIST(nodes); w; w = w->r_next) { + n = w->a_temp; + if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes) + continue; + EnableMoves(w->a_temp); + } +} + +/* + * Decrement the degree of node w for class c. + */ +static void +DecrementDegree(REGW *w, int c) +{ + int wast; + + RRDEBUG(("DecrementDegree: w %d, c %d\n", ASGNUM(w), c)); + + wast = trivially_colorable(w); + NCLASS(w, c)--; + if (wast == trivially_colorable(w)) + return; + + EnableAdjMoves(w); + DELWLIST(w); + ONLIST(w) = 0; + if (MoveRelated(w)) { + PUSHWLIST(w, freezeWorklist); + } else { + PUSHWLIST(w, simplifyWorklist); + } +} + +static void +Simplify(void) +{ + REGW *w; + ADJL *l; + + w = POPWLIST(simplifyWorklist); + PUSHWLIST(w, selectStack); + RDEBUG(("Simplify: node %d class %d\n", ASGNUM(w), w->r_class)); + + l = w->r_adjList; + for (; l; l = l->r_next) { + if (ONLIST(l->a_temp) == &selectStack || + ONLIST(l->a_temp) == &coalescedNodes) + continue; + DecrementDegree(l->a_temp, w->r_class); + } +} + +static REGW * +GetAlias(REGW *n) +{ + if (ONLIST(n) == &coalescedNodes) + return GetAlias(ALIAS(n)); + return n; +} + +static int +OK(REGW *t, REGW *r) +{ + RDEBUG(("OK: t %d CLASS(t) %d adjSet(%d,%d)=%d\n", + ASGNUM(t), CLASS(t), ASGNUM(t), ASGNUM(r), adjSet(t, r))); + +#ifdef PCC_DEBUG + if (rdebug > 1) { + ADJL *w; + int ndeg = 0; + printf("OK degree: "); + for (w = ADJLIST(t); w; w = w->r_next) { + if (ONLIST(w->a_temp) != &selectStack && + ONLIST(w->a_temp) != &coalescedNodes) + printf("%c%d ", CLASS(w->a_temp)+'@', + ASGNUM(w->a_temp)), ndeg++; + else + printf("(%d) ", ASGNUM(w->a_temp)); + } + printf("\n"); +#if 0 + if (ndeg != DEGREE(t) && DEGREE(t) >= 0) + printf("!!!ndeg %d != DEGREE(t) %d\n", ndeg, DEGREE(t)); +#endif + } +#endif + + if (trivially_colorable(t) || ONLIST(t) == &precolored || + (adjSet(t, r) || !aliasmap(CLASS(t), COLOR(r))))/* XXX - check aliasmap */ + return 1; + return 0; +} + +static int +adjok(REGW *v, REGW *u) +{ + ADJL *w; + REGW *t; + + RDEBUG(("adjok\n")); + for (w = ADJLIST(v); w; w = w->r_next) { + t = w->a_temp; + if (ONLIST(t) == &selectStack || ONLIST(t) == &coalescedNodes) + continue; + if (OK(t, u) == 0) + return 0; + } + RDEBUG(("adjok returns OK\n")); + return 1; +} + +#define oldcons /* check some more */ +/* + * Do a conservative estimation of whether two temporaries can + * be coalesced. This is "Briggs-style" check. + * Neither u nor v is precolored when called. + */ +static int +Conservative(REGW *u, REGW *v) +{ + ADJL *w, *ww; + REGW *n; +#ifdef oldcons + int i, ncl[NUMCLASS+1]; + + if (CLASS(u) != CLASS(v)) + comperr("Conservative: u(%d = %d), v(%d = %d)", + ASGNUM(u), CLASS(u), ASGNUM(v), CLASS(v)); + + for (i = 0; i < NUMCLASS+1; i++) + ncl[i] = 0; + + RDEBUG(("Conservative (%d,%d)\n", ASGNUM(u), ASGNUM(v))); + + for (w = ADJLIST(u); w; w = w->r_next) { + n = w->a_temp; + if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes) + continue; + for (ww = ADJLIST(v); ww; ww = ww->r_next) + if (ww->a_temp == n) + break; + if (ww) + continue; + if (!trivially_colorable(n)) + ncl[CLASS(n)]++; + } + for (w = ADJLIST(v); w; w = w->r_next) { + n = w->a_temp; + if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes) + continue; + if (!trivially_colorable(n)) + ncl[CLASS(n)]++; + } + i = trivially_colorable_p(CLASS(u), ncl); +#endif +{ + int xncl[NUMCLASS+1], mcl = 0, j; + for (j = 0; j < NUMCLASS+1; j++) + xncl[j] = 0; + /* + * Increment xncl[class] up to K for each class. + * If all classes has reached K then check colorability and return. + */ + for (w = ADJLIST(u); w; w = w->r_next) { + n = w->a_temp; + if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes) + continue; + if (xncl[CLASS(n)] == regK[CLASS(n)]) + continue; + if (!trivially_colorable(n)) + xncl[CLASS(n)]++; + if (xncl[CLASS(n)] < regK[CLASS(n)]) + continue; + if (++mcl == NUMCLASS) + goto out; /* cannot get more out of it */ + } + for (w = ADJLIST(v); w; w = w->r_next) { + n = w->a_temp; + if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes) + continue; + if (xncl[CLASS(n)] == regK[CLASS(n)]) + continue; + /* ugly: have we been here already? */ + for (ww = ADJLIST(u); ww; ww = ww->r_next) + if (ww->a_temp == n) + break; + if (ww) + continue; + if (!trivially_colorable(n)) + xncl[CLASS(n)]++; + if (xncl[CLASS(n)] < regK[CLASS(n)]) + continue; + if (++mcl == NUMCLASS) + break; + } +out: j = trivially_colorable_p(CLASS(u), xncl); +#ifdef oldcons + if (j != i) + comperr("Conservative: j %d i %d", j, i); +#else + return j; +#endif +} +#ifdef oldcons + RDEBUG(("Conservative i=%d\n", i)); + return i; +#endif +} + +static void +AddWorkList(REGW *w) +{ + + if (ONLIST(w) != &precolored && !MoveRelated(w) && + trivially_colorable(w)) { + DELWLIST(w); + PUSHWLIST(w, simplifyWorklist); + } +} + +static void +Combine(REGW *u, REGW *v) +{ + MOVL *m; + ADJL *l; + REGW *t; + + RDEBUG(("Combine (%d,%d)\n", ASGNUM(u), ASGNUM(v))); + + if (ONLIST(v) == &freezeWorklist) { + DELWLIST(v); + } else { + DELWLIST(v); + } + PUSHWLIST(v, coalescedNodes); + ALIAS(v) = u; + if (rdebug) { + printf("adjlist(%d): ", ASGNUM(v)); + for (l = ADJLIST(v); l; l = l->r_next) + printf("%d ", l->a_temp->nodnum); + printf("\n"); + } +#if 1 +{ + MOVL *m0 = MOVELIST(v); + + for (m0 = MOVELIST(v); m0; m0 = m0->next) { + for (m = MOVELIST(u); m; m = m->next) + if (m->regm == m0->regm) + break; /* Already on list */ + if (m) + continue; /* already on list */ + MOVELISTADD(u, m0->regm); + } +} +#else + + if ((m = MOVELIST(u))) { + while (m->next) + m = m->next; + m->next = MOVELIST(v); + } else + MOVELIST(u) = MOVELIST(v); +#endif + EnableMoves(v); + for (l = ADJLIST(v); l; l = l->r_next) { + t = l->a_temp; + if (ONLIST(t) == &selectStack || ONLIST(t) == &coalescedNodes) + continue; + /* Do not add edge if u cannot affect the colorability of t */ + /* XXX - check aliasmap */ + if (ONLIST(u) != &precolored || aliasmap(CLASS(t), COLOR(u))) + AddEdge(t, u); + DecrementDegree(t, CLASS(v)); + } + if (!trivially_colorable(u) && ONLIST(u) == &freezeWorklist) { + DELWLIST(u); + PUSHWLIST(u, spillWorklist); + } +if (rdebug) { + ADJL *w; + printf("Combine %d class (%d): ", ASGNUM(u), CLASS(u)); + for (w = ADJLIST(u); w; w = w->r_next) { + if (ONLIST(w->a_temp) != &selectStack && + ONLIST(w->a_temp) != &coalescedNodes) + printf("%d ", ASGNUM(w->a_temp)); + else + printf("(%d) ", ASGNUM(w->a_temp)); + } + printf("\n"); +} +} + +static void +Coalesce(void) +{ + REGM *m; + REGW *x, *y, *u, *v; + + m = POPMLIST(worklistMoves); + x = GetAlias(m->src); + y = GetAlias(m->dst); + + if (ONLIST(y) == &precolored) + u = y, v = x; + else + u = x, v = y; + + RDEBUG(("Coalesce: src %d dst %d u %d v %d x %d y %d\n", + ASGNUM(m->src), ASGNUM(m->dst), ASGNUM(u), ASGNUM(v), + ASGNUM(x), ASGNUM(y))); + + if (CLASS(m->src) != CLASS(m->dst)) + comperr("Coalesce: src class %d, dst class %d", + CLASS(m->src), CLASS(m->dst)); + + if (u == v) { + RDEBUG(("Coalesce: u == v\n")); + PUSHMLIST(m, coalescedMoves, COAL); + AddWorkList(u); + } else if (ONLIST(v) == &precolored || adjSet(u, v)) { + RDEBUG(("Coalesce: constrainedMoves\n")); + PUSHMLIST(m, constrainedMoves, CONSTR); + AddWorkList(u); + AddWorkList(v); + } else if ((ONLIST(u) == &precolored && adjok(v, u)) || + (ONLIST(u) != &precolored && Conservative(u, v))) { + RDEBUG(("Coalesce: Conservative\n")); + PUSHMLIST(m, coalescedMoves, COAL); + Combine(u, v); + AddWorkList(u); + } else { + RDEBUG(("Coalesce: activeMoves\n")); + PUSHMLIST(m, activeMoves, ACTIVE); + } +} + +static void +FreezeMoves(REGW *u) +{ + MOVL *w, *o; + REGM *m; + REGW *z; + REGW *x, *y, *v; + + for (w = MOVELIST(u); w; w = w->next) { + m = w->regm; + if (m->queue != WLIST && m->queue != ACTIVE) + continue; + x = m->src; + y = m->dst; + if (GetAlias(y) == GetAlias(u)) + v = GetAlias(x); + else + v = GetAlias(y); + RDEBUG(("FreezeMoves: u %d (%d,%d) v %d\n", + ASGNUM(u),ASGNUM(x),ASGNUM(y),ASGNUM(v))); + DLIST_REMOVE(m, link); + PUSHMLIST(m, frozenMoves, FROZEN); + if (ONLIST(v) != &freezeWorklist) + continue; + for (o = MOVELIST(v); o; o = o->next) + if (o->regm->queue == WLIST || o->regm->queue == ACTIVE) + break; + if (o == NULL) { + z = v; + DELWLIST(z); + PUSHWLIST(z, simplifyWorklist); + } + } +} + +static void +Freeze(void) +{ + REGW *u; + + /* XXX + * Should check if the moves to freeze have exactly the same + * interference edges. If they do, coalesce them instead, it + * may free up other nodes that they interfere with. + */ + u = POPWLIST(freezeWorklist); + PUSHWLIST(u, simplifyWorklist); + RDEBUG(("Freeze %d\n", ASGNUM(u))); + FreezeMoves(u); +} + +static void +SelectSpill(void) +{ + REGW *w; + + RDEBUG(("SelectSpill\n")); + if (rdebug) + DLIST_FOREACH(w, &spillWorklist, link) + printf("SelectSpill: %d\n", ASGNUM(w)); + + /* First check if we can spill register variables */ + DLIST_FOREACH(w, &spillWorklist, link) { + if (w >= &nblock[tempmin] && w < &nblock[basetemp]) + break; + } + + if (w == &spillWorklist) { + /* try to find another long-range variable */ + DLIST_FOREACH(w, &spillWorklist, link) { + if (w >= &nblock[tempmin] && w < &nblock[tempmax]) + break; + } + } + + if (w == &spillWorklist) { + /* no heuristics, just fetch first element */ + w = DLIST_NEXT(&spillWorklist, link); + } + + DLIST_REMOVE(w, link); + + PUSHWLIST(w, simplifyWorklist); + RDEBUG(("Freezing node %d\n", ASGNUM(w))); + FreezeMoves(w); +} + +int gregn(REGW *); + +int +gregn(REGW *w) +{ + return w->nodnum; +} + +/* + * Set class on long-lived temporaries based on its type. + */ +static void +traclass(NODE *p) +{ + REGW *nb; + + if (p->n_op != TEMP) + return; + + nb = &nblock[(int)p->n_lval]; + if (CLASS(nb) == 0) + CLASS(nb) = gclass(p->n_type); +} + +static void +paint(NODE *p) +{ + struct optab *q; + REGW *w, *ww; + int i; + + if (p->n_regw != NULL) { + /* Must color all allocated regs also */ + ww = w = p->n_regw; + q = &table[TBLIDX(p->n_su)]; + p->n_reg = COLOR(w); + w++; + if (q->needs & ALLNEEDS) + for (i = 0; i < ncnt(q->needs); i++) { + if (w->r_class == -1) + p->n_reg |= ENCRA(COLOR(ww), i); + else + p->n_reg |= ENCRA(COLOR(w), i); + w++; + } + } else + p->n_reg = -1; + if (p->n_op == TEMP) { + REGW *nb = &nblock[(int)p->n_lval]; + p->n_rval = COLOR(nb); + if (TCLASS(p->n_su) == 0) + SCLASS(p->n_su, CLASS(nb)); + p->n_op = REG; + p->n_lval = 0; + } +} + +static void +AssignColors(struct interpass *ip) +{ + int okColors, c; + REGW *o, *w; + ADJL *x; + + RDEBUG(("AssignColors\n")); + while (!WLISTEMPTY(selectStack)) { + w = POPWLIST(selectStack); + okColors = classmask(CLASS(w)); + RDEBUG(("classmask av %d, class %d: %x\n", + w->nodnum, CLASS(w), okColors)); + + for (x = ADJLIST(w); x; x = x->r_next) { + o = GetAlias(x->a_temp); + RRDEBUG(("Adj(%d): %d (%d)\n", + ASGNUM(w), ASGNUM(o), ASGNUM(x->a_temp))); + + if (ONLIST(o) == &coloredNodes || + ONLIST(o) == &precolored) { + c = aliasmap(CLASS(w), COLOR(o)); + RRDEBUG(("aliasmap in class %d by color %d: " + "%x, okColors %x\n", + CLASS(w), COLOR(o), c, okColors)); + + okColors &= ~c; + } + } + if (okColors == 0) { + PUSHWLIST(w, spilledNodes); + RDEBUG(("Spilling node %d\n", ASGNUM(w))); + } else { + PUSHWLIST(w, coloredNodes); + c = ffs(okColors)-1; + COLOR(w) = color2reg(c, CLASS(w)); + RDEBUG(("Coloring %d with %s, free %x\n", + ASGNUM(w), rnames[COLOR(w)], okColors)); + } + } + DLIST_FOREACH(w, &coalescedNodes, link) { + REGW *ww = GetAlias(w); + COLOR(w) = COLOR(ww); + if (ONLIST(ww) == &spilledNodes) { + RDEBUG(("coalesced node %d spilled\n", w->nodnum)); + ww = DLIST_PREV(w, link); + DLIST_REMOVE(w, link); + PUSHWLIST(w, spilledNodes); + w = ww; + } else + RDEBUG(("Giving coalesced node %d color %s\n", + w->nodnum, rnames[COLOR(w)])); + } + + if (rdebug) + DLIST_FOREACH(w, &coloredNodes, link) + printf("%d: color %s\n", ASGNUM(w), rnames[COLOR(w)]); + if (DLIST_ISEMPTY(&spilledNodes, link)) { + struct interpass *ip2; + DLIST_FOREACH(ip2, ip, qelem) + if (ip2->type == IP_NODE) + walkf(ip2->ip_node, paint); + } +} + +static REGW *spole; +/* + * Store all spilled nodes in memory by fetching a temporary on the stack. + * Will never end up here if not optimizing. + */ +static void +longtemp(NODE *p) +{ + REGW *w; + + if (p->n_op != TEMP) + return; + /* XXX - should have a bitmask to find temps to convert */ + DLIST_FOREACH(w, spole, link) { + if (w != &nblock[(int)p->n_lval]) + continue; + if (w->r_class == 0) { + w->r_color = BITOOR(freetemp(szty(p->n_type))); + w->r_class = 1; + } + p->n_op = OREG; + p->n_lval = w->r_color; + p->n_rval = FPREG; + p->n_regw = NULL; + break; + } +} + +static struct interpass *cip; +/* + * Rewrite a tree by storing a variable in memory. + * XXX - must check if basic block structure is destroyed! + */ +static void +shorttemp(NODE *p) +{ + struct interpass *nip; + REGW *w; + NODE *l, *r; + int off; + + /* XXX - optimize this somewhat */ + DLIST_FOREACH(w, spole, link) { + if (w != p->n_regw) + continue; + /* XXX - use canaddr() */ + if (p->n_op == OREG || p->n_op == NAME) { + DLIST_REMOVE(w, link); + RDEBUG(("Node %d already in memory\n", ASGNUM(w))); + break; + } + RDEBUG(("rewriting node %d\n", ASGNUM(w))); + off = BITOOR(freetemp(szty(p->n_type))); + l = mklnode(OREG, off, FPREG, p->n_type); + r = talloc(); + *r = *p; + nip = ipnode(mkbinode(ASSIGN, l, r, p->n_type)); + *p = *l; + DLIST_INSERT_BEFORE(cip, nip, qelem); + DLIST_REMOVE(w, link); + break; + } +} + +/* + * Change the TEMPs in the ipole list to stack variables. + */ +static void +treerewrite(struct interpass *ipole, REGW *rpole) +{ + struct interpass *ip; + + spole = rpole; + + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + cip = ip; + walkf(ip->ip_node, shorttemp); /* convert temps to oregs */ + } + if (!DLIST_ISEMPTY(spole, link)) + comperr("treerewrite not empty"); +} + +/* + * Change the TEMPs in the ipole list to stack variables. + */ +static void +leafrewrite(struct interpass *ipole, REGW *rpole) +{ + extern NODE *nodepole; + extern int thisline; + struct interpass *ip; + + spole = rpole; + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + nodepole = ip->ip_node; + thisline = ip->lineno; + walkf(ip->ip_node, longtemp); /* convert temps to oregs */ + } + nodepole = NIL; +} + +/* + * Avoid copying spilled argument to new position on stack. + */ +static int +temparg(struct interpass *ipole, REGW *w) +{ + struct interpass *ip; + NODE *p; + + ip = DLIST_NEXT(ipole, qelem); /* PROLOG */ + ip = DLIST_NEXT(ip, qelem); /* first DEFLAB */ + ip = DLIST_NEXT(ip, qelem); /* first NODE */ + for (; ip->type != IP_DEFLAB; ip = DLIST_NEXT(ip, qelem)) { + if (ip->type == IP_ASM) + continue; + p = ip->ip_node; +#ifdef PCC_DEBUG + if (p->n_op != ASSIGN || p->n_left->n_op != TEMP) + comperr("temparg"); +#endif + if (p->n_right->n_op != OREG) + continue; /* arg in register */ + if (w != &nblock[(int)p->n_left->n_lval]) + continue; + w->r_color = p->n_right->n_lval; + tfree(p); + /* Cannot DLIST_REMOVE here, would break basic blocks */ + /* Make it a nothing instead */ + ip->type = IP_ASM; + ip->ip_asm=""; + return 1; + } + return 0; +} + +#define ONLYPERM 1 +#define LEAVES 2 +#define SMALL 3 + +/* + * Scan the whole function and search for temporaries to be stored + * on-stack. + * + * Be careful to not destroy the basic block structure in the first scan. + */ +static int +RewriteProgram(struct interpass *ip) +{ + REGW shortregs, longregs, saveregs, *q; + REGW *w; + int rwtyp; + + RDEBUG(("RewriteProgram\n")); + DLIST_INIT(&shortregs, link); + DLIST_INIT(&longregs, link); + DLIST_INIT(&saveregs, link); + + /* sort the temporaries in three queues, short, long and perm */ + while (!DLIST_ISEMPTY(&spilledNodes, link)) { + w = DLIST_NEXT(&spilledNodes, link); + DLIST_REMOVE(w, link); + + if (w >= &nblock[tempmin] && w < &nblock[basetemp]) { + q = &saveregs; + } else if (w >= &nblock[basetemp] && w < &nblock[tempmax]) { + q = &longregs; + } else + q = &shortregs; + DLIST_INSERT_AFTER(q, w, link); + } +#ifdef PCC_DEBUG + if (rdebug) { + printf("permanent: "); + DLIST_FOREACH(w, &saveregs, link) + printf("%d ", ASGNUM(w)); + printf("\nlong-lived: "); + DLIST_FOREACH(w, &longregs, link) + printf("%d ", ASGNUM(w)); + printf("\nshort-lived: "); + DLIST_FOREACH(w, &shortregs, link) + printf("%d ", ASGNUM(w)); + printf("\n"); + } +#endif + rwtyp = 0; + + if (!DLIST_ISEMPTY(&saveregs, link)) { + rwtyp = ONLYPERM; + DLIST_FOREACH(w, &saveregs, link) { + int num = w - nblock - tempmin; + nsavregs[num] = 1; + } + } + if (!DLIST_ISEMPTY(&longregs, link)) { + rwtyp = LEAVES; + DLIST_FOREACH(w, &longregs, link) { + w->r_class = xtemps ? temparg(ip, w) : 0; + } + } + + if (rwtyp == LEAVES) { + leafrewrite(ip, &longregs); + rwtyp = ONLYPERM; + } + + if (rwtyp == 0 && !DLIST_ISEMPTY(&shortregs, link)) { + /* Must rewrite the trees */ + treerewrite(ip, &shortregs); +// if (xtemps) +// comperr("treerewrite"); + rwtyp = SMALL; + } + + RDEBUG(("savregs %x rwtyp %d\n", 0, rwtyp)); + + return rwtyp; +} + +#ifdef notyet +/* + * Assign instructions, calculate evaluation order and + * set temporary register numbers. + */ +static void +insgen() +{ + geninsn(); /* instruction assignment */ + sucomp(); /* set evaluation order */ + slong(); /* set long temp types */ + sshort(); /* set short temp numbers */ +} +#endif + +/* + * Do register allocation for trees by graph-coloring. + */ +void +ngenregs(struct interpass *ipole) +{ + extern NODE *nodepole; + struct interpass_prolog *ipp, *epp; + struct interpass *ip; + int i, j, nbits = 0; + int uu[NPERMREG] = { -1 }; + int xnsavregs[NPERMREG]; + int beenhere = 0; + + DLIST_INIT(&lunused, link); + DLIST_INIT(&lused, link); + + /* + * Do some setup before doing the real thing. + */ + ipp = (struct interpass_prolog *)DLIST_NEXT(ipole, qelem); + epp = (struct interpass_prolog *)DLIST_PREV(ipole, qelem); + + tempmin = ipp->ip_tmpnum; + tempmax = epp->ip_tmpnum; + + /* + * Allocate space for the permanent registers in the + * same block as the long-lived temporaries. + * These temporaries will be handled the same way as + * all other variables. + */ + basetemp = tempmin; + nsavregs = xnsavregs; + for (i = 0; i < NPERMREG; i++) + xnsavregs[i] = 0; + ndontregs = uu; /* currently never avoid any regs */ + + tempmin -= (NPERMREG-1); +#ifdef notyet + if (xavoidfp) + dontregs |= REGBIT(FPREG); +#endif + +#ifdef PCC_DEBUG + nodnum = tempmax; +#endif + nbits = xbits = tempmax - tempmin; + if (nbits) { + nblock = tmpalloc(nbits * sizeof(REGW)); + + nblock -= tempmin; + live = tmpalloc(BIT2BYTE(nbits)); + RDEBUG(("nblock %p num %d size %d\n", + nblock, nbits, (int)(nbits * sizeof(REGW)))); + } + + + /* Block for precolored nodes */ + ablock = tmpalloc(sizeof(REGW)*MAXREGS); + memset(ablock, 0, sizeof(REGW)*MAXREGS); + for (i = 0; i < MAXREGS; i++) { + ablock[i].r_onlist = &precolored; + ablock[i].r_class = GCLASS(i); /* XXX */ + ablock[i].r_color = i; +#ifdef PCC_DEBUG + ablock[i].nodnum = i; +#endif + } +#ifdef notyet + TMPMARK(); +#endif + + +recalc: +onlyperm: /* XXX - should not have to redo all */ + + if (nbits) { + memset(nblock+tempmin, 0, nbits * sizeof(REGW)); + memset(live, 0, BIT2BYTE(nbits)); + memset(edgehash, 0, sizeof(edgehash)); +#ifdef PCC_DEBUG + for (i = tempmin; i < tempmax; i++) + nblock[i].nodnum = i; +#endif + } + RPRINTIP(ipole); + DLIST_INIT(&initial, link); + DLIST_FOREACH(ip, ipole, qelem) { + extern int thisline; + if (ip->type != IP_NODE) + continue; + nodepole = ip->ip_node; + thisline = ip->lineno; + geninsn(ip->ip_node, FOREFF); + nsucomp(ip->ip_node); + walkf(ip->ip_node, traclass); + } + nodepole = NIL; + RDEBUG(("nsucomp allocated %d temps (%d,%d)\n", + tempmax-tempmin, tempmin, tempmax)); + + RPRINTIP(ipole); + RDEBUG(("ngenregs: numtemps %d (%d, %d)\n", tempmax-tempmin, + tempmin, tempmax)); + + DLIST_INIT(&coalescedMoves, link); + DLIST_INIT(&constrainedMoves, link); + DLIST_INIT(&frozenMoves, link); + DLIST_INIT(&worklistMoves, link); + DLIST_INIT(&activeMoves, link); + + /* Set class and move-related for perm regs */ + for (i = 0; i < (NPERMREG-1); i++) { + if (nsavregs[i]) + continue; + nblock[i+tempmin].r_class = GCLASS(permregs[i]); + DLIST_INSERT_AFTER(&initial, &nblock[i+tempmin], link); + moveadd(&nblock[i+tempmin], &ablock[permregs[i]]); + addalledges(&nblock[i+tempmin]); + } + + Build(ipole); + RDEBUG(("Build done\n")); + MkWorklist(); + RDEBUG(("MkWorklist done\n")); + do { + if (!WLISTEMPTY(simplifyWorklist)) + Simplify(); + else if (!WLISTEMPTY(worklistMoves)) + Coalesce(); + else if (!WLISTEMPTY(freezeWorklist)) + Freeze(); + else if (!WLISTEMPTY(spillWorklist)) + SelectSpill(); + } while (!WLISTEMPTY(simplifyWorklist) || !WLISTEMPTY(worklistMoves) || + !WLISTEMPTY(freezeWorklist) || !WLISTEMPTY(spillWorklist)); + AssignColors(ipole); + + RDEBUG(("After AssignColors\n")); + RPRINTIP(ipole); + + if (!WLISTEMPTY(spilledNodes)) { + switch (RewriteProgram(ipole)) { + case ONLYPERM: + goto onlyperm; + case SMALL: + optimize(ipole); + if (beenhere++ == MAXLOOP) + comperr("beenhere"); + goto recalc; + } + } + + /* fill in regs to save */ + ipp->ipp_regs = 0; + for (i = 0; i < NPERMREG-1; i++) { + NODE *p; + + if (nsavregs[i]) { + ipp->ipp_regs |= (1 << permregs[i]); + continue; /* Spilled */ + } + if (nblock[i+tempmin].r_color == permregs[i]) + continue; /* Coalesced */ + /* + * If the original color of this permreg is used for + * coloring another register, swap them to avoid + * unneccessary moves. + */ + for (j = i+1; j < NPERMREG-1; j++) { + if (nblock[j+tempmin].r_color != permregs[i]) + continue; + nblock[j+tempmin].r_color = nblock[i+tempmin].r_color; + break; + } + if (j != NPERMREG-1) + continue; + + /* Generate reg-reg move nodes for save */ + p = mkbinode(ASSIGN, + mklnode(REG, 0, nblock[i+tempmin].r_color, INT), + mklnode(REG, 0, permregs[i], INT), INT); + p->n_reg = p->n_left->n_reg = p->n_right->n_reg = -1; + p->n_left->n_su = p->n_right->n_su = 0; + geninsn(p, FOREFF); + ip = ipnode(p); + DLIST_INSERT_AFTER(ipole->qelem.q_forw, ip, qelem); + /* XXX not int */ + p = mkbinode(ASSIGN, mklnode(REG, 0, permregs[i], INT), + mklnode(REG, 0, nblock[i+tempmin].r_color, INT), INT); + p->n_reg = p->n_left->n_reg = p->n_right->n_reg = -1; + p->n_left->n_su = p->n_right->n_su = 0; + geninsn(p, FOREFF); + ip = ipnode(p); + DLIST_INSERT_BEFORE(ipole->qelem.q_back, ip, qelem); + } + epp->ipp_regs = ipp->ipp_regs; + /* Done! */ +} diff --git a/usr.bin/pcc/os/dragonfly/ccconfig.h b/usr.bin/pcc/os/dragonfly/ccconfig.h new file mode 100644 index 00000000000..08afb5fe161 --- /dev/null +++ b/usr.bin/pcc/os/dragonfly/ccconfig.h @@ -0,0 +1,47 @@ +/* $Id: ccconfig.h,v 1.1 2007/09/15 18:12:37 otto Exp $ */ + +/* + * Copyright (c) 2004 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. + */ + +/* + * Various settings that controls how the C compiler works. + */ + +/* common cpp predefines */ +#define CPPADD { "-D__DragonFly__", "-D__ELF__", NULL, } +#define DYNLINKER { "-dynamic-linker", "/usr/libexec/ld.elf_so.2", NULL } +#define CRT0FILE "/usr/lib/crt1.o" +#define STARTFILES { "/usr/lib/crti.o", "/usr/lib/crtbegin.o", NULL } +#define ENDFILES { "/usr/lib/crtend.o", "/usr/lib/crtn.o", NULL } + +#if defined(mach_x86) +#define CPPMDADD { "-D__i386__", NULL, } +#else +#error defines for arch missing +#endif + +#define STABS diff --git a/usr.bin/pcc/os/linux/ccconfig.h b/usr.bin/pcc/os/linux/ccconfig.h new file mode 100644 index 00000000000..41cb8b83455 --- /dev/null +++ b/usr.bin/pcc/os/linux/ccconfig.h @@ -0,0 +1,49 @@ +/* $Id: ccconfig.h,v 1.1 2007/09/15 18:12:37 otto Exp $ */ + +/* + * Copyright (c) 2004 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. + */ + +/* + * Various settings that controls how the C compiler works. + */ + +/* common cpp predefines */ +#define CPPADD { "-D__linux__", "-D__ELF__", "-I" INCLUDEDIR "/pcc", NULL, } +#define DYNLINKER { "-dynamic-linker", "/lib/ld-linux.so.2", NULL } +#define CRT0FILE "/usr/lib/crt1.o" +#define STARTFILES { "/usr/lib/crti.o", "/usr/lib/gcc/i586-suse-linux/4.1.0/crtbegin.o", NULL } +#define LIBCLIBS { "-lc", "-lgcc_s", NULL } +#define ENDFILES { "/usr/lib/gcc/i586-suse-linux/4.1.0/crtend.o", "/usr/lib/crtn.o", NULL } +#define STARTLABEL "_start" + +#if defined(mach_x86) +#define CPPMDADD { "-D__i386__", NULL, } +#else +#error defines for arch missing +#endif + +#define STABS diff --git a/usr.bin/pcc/os/netbsd/ccconfig.h b/usr.bin/pcc/os/netbsd/ccconfig.h new file mode 100644 index 00000000000..f0eecd3b704 --- /dev/null +++ b/usr.bin/pcc/os/netbsd/ccconfig.h @@ -0,0 +1,47 @@ +/* $Id: ccconfig.h,v 1.1 2007/09/15 18:12:37 otto Exp $ */ + +/* + * Copyright (c) 2004 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. + */ + +/* + * Various settings that controls how the C compiler works. + */ + +/* common cpp predefines */ +#define CPPADD { "-D__NetBSD__", "-D__ELF__", NULL, } +#define DYNLINKER { "-dynamic-linker", "/usr/libexec/ld.elf_so", NULL } +#define CRT0FILE "/usr/lib/crt0.o" +#define STARTFILES { "/usr/lib/crti.o", "/usr/lib/crtbegin.o", NULL } +#define ENDFILES { "/usr/lib/crtend.o", "/usr/lib/crtn.o", NULL } + +#if defined(mach_x86) +#define CPPMDADD { "-D__i386__", NULL, } +#else +#error defines for arch missing +#endif + +#define STABS diff --git a/usr.bin/pcc/os/netbsd/f77config.h b/usr.bin/pcc/os/netbsd/f77config.h new file mode 100644 index 00000000000..6bbc447b855 --- /dev/null +++ b/usr.bin/pcc/os/netbsd/f77config.h @@ -0,0 +1,54 @@ +/* $Id: f77config.h,v 1.1 2007/09/15 18:12:37 otto Exp $ */ + +/* + * Copyright (c) 2004 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. + */ + +/* + * Various settings that controls how the f77 compiler works. + */ + +#if 0 +/* common cpp predefines */ +#define CPPADD { "-D__NetBSD__", "-D__ELF__", NULL, } +#define DYNLINKER { "-dynamic-linker", "/usr/libexec/ld.elf_so", NULL } +#define CRT0FILE "/usr/lib/crt0.o" +#define STARTFILES { "/usr/lib/crti.o", "/usr/lib/crtbegin.o", NULL } +#define ENDFILES { "/usr/lib/crtend.o", "/usr/lib/crtn.o", NULL } +#endif +#define PASS1NAME "/usr/lib/f77pass1" +#define PASS2NAME "/lib/f1" +#define PASS2OPT "/lib/c2" +#define NOFLPASS2 "/lib/fc1" + +#define ASMNAME "/usr/bin/as" +#define LDNAME "/usr/bin/ld" +#define FOOTNAME "/usr/lib/crt0.o" +#define PROFFOOT "/usr/lib/mcrt0.o" +#define NOFLFOOT "/usr/lib/fcrt0.o" +#define NOFLPROFFOOT "/usr/lib/fmcrt0.o" +#define LIBLIST { "-lF77", "-lI77", "-lm", "-lc", "-l", NULL }; + diff --git a/usr.bin/pcc/os/none/ccconfig.h b/usr.bin/pcc/os/none/ccconfig.h new file mode 100644 index 00000000000..5bb3af33f42 --- /dev/null +++ b/usr.bin/pcc/os/none/ccconfig.h @@ -0,0 +1,50 @@ +/* $Id: ccconfig.h,v 1.1 2007/09/15 18:12:37 otto Exp $ */ + +/* + * Copyright (c) 2004 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. + */ + +/* + * Various settings that controls how the C compiler works. + */ + +/* + * This file is for targets where there is no OS + */ + +/* common cpp predefines */ +#define CPPADD { NULL, } +#define DYNLINKER { NULL } +#define CRT0FILE "" +#define STARTFILES { NULL } +#define ENDFILES { NULL } + +#if defined(mach_m16c) +#define CPPMDADD { "-D__m16c__", NULL, } +#elif defined(mach_nova) +#define CPPMDADD { "-D__nova__", NULL, } +#endif + diff --git a/usr.bin/pcc/os/openbsd/ccconfig.h b/usr.bin/pcc/os/openbsd/ccconfig.h new file mode 100644 index 00000000000..b0962add596 --- /dev/null +++ b/usr.bin/pcc/os/openbsd/ccconfig.h @@ -0,0 +1,47 @@ +/* $Id: ccconfig.h,v 1.1 2007/09/15 18:12:37 otto Exp $ */ + +/* + * Copyright (c) 2004 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. + */ + +/* + * Various settings that controls how the C compiler works. + */ + +/* common cpp predefines */ +#define CPPADD { "-D__OpenBSD__", "-D__ELF__", NULL, } +#define DYNLINKER { "-dynamic-linker", "/usr/libexec/ld.so", NULL } +#define CRT0FILE "/usr/lib/crt0.o" +#define STARTFILES { "/usr/lib/crtbegin.o", NULL } +#define ENDFILES { "/usr/lib/crtend.o", NULL } + +#if defined(mach_x86) +#define CPPMDADD { "-D__i386__", NULL, } +#else +#error defines for arch missing +#endif + +#define STABS diff --git a/usr.bin/pcc/os/openbsd/f77config.h b/usr.bin/pcc/os/openbsd/f77config.h new file mode 100644 index 00000000000..8ac985d8eab --- /dev/null +++ b/usr.bin/pcc/os/openbsd/f77config.h @@ -0,0 +1,46 @@ +/* $Id: f77config.h,v 1.1 2007/09/15 18:12:37 otto Exp $ */ + +/* + * Copyright (c) 2004 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. + */ + +/* + * Various settings that controls how the f77 compiler works. + */ + +#define PASS1NAME "/usr/lib/f77pass1" +#define PASS2NAME "/lib/f1" +#define PASS2OPT "/lib/c2" +#define NOFLPASS2 "/lib/fc1" + +#define ASMNAME "/usr/bin/as" +#define LDNAME "/usr/bin/ld" +#define FOOTNAME "/usr/lib/crt0.o" +#define PROFFOOT "/usr/lib/mcrt0.o" +#define NOFLFOOT "/usr/lib/fcrt0.o" +#define NOFLPROFFOOT "/usr/lib/fmcrt0.o" +#define LIBLIST { "-lF77", "-lI77", "-lm", "-lc", "-l", NULL }; + |