[Midnightbsd-cvs] src: usr.bin/pcc: Initial revision of pcc.
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Fri Sep 28 09:47:23 EDT 2007
Log Message:
-----------
Initial revision of pcc.
This is not connected to the build. The Makefiles need more work first.
Added Files:
-----------
src/usr.bin/pcc:
Makefile (r1.1)
config.h (r1.1)
src/usr.bin/pcc/arch/x86:
code.c (r1.1)
local.c (r1.1)
local2.c (r1.1)
macdefs.h (r1.1)
order.c (r1.1)
table.c (r1.1)
src/usr.bin/pcc/cc:
Makefile (r1.1)
src/usr.bin/pcc/cc/cc:
Makefile (r1.1)
cc.1 (r1.1)
cc.c (r1.1)
src/usr.bin/pcc/cc/ccom:
Makefile (r1.1)
ccom.1 (r1.1)
cgram.y (r1.1)
gcc_compat.c (r1.1)
init.c (r1.1)
inline.c (r1.1)
main.c (r1.1)
optim.c (r1.1)
pass1.h (r1.1)
pftn.c (r1.1)
scan.l (r1.1)
stabs.c (r1.1)
symtabs.c (r1.1)
trees.c (r1.1)
src/usr.bin/pcc/cc/cpp:
Makefile (r1.1)
cpp.1 (r1.1)
cpp.c (r1.1)
cpp.h (r1.1)
cpy.y (r1.1)
scanner.l (r1.1)
token.c (r1.1)
src/usr.bin/pcc/cc/cpp/tests:
res1 (r1.1)
res2 (r1.1)
res3 (r1.1)
res4 (r1.1)
res5 (r1.1)
res6 (r1.1)
res7 (r1.1)
res8 (r1.1)
res9 (r1.1)
test1 (r1.1)
test2 (r1.1)
test3 (r1.1)
test4 (r1.1)
test5 (r1.1)
test6 (r1.1)
test7 (r1.1)
test8 (r1.1)
test9 (r1.1)
src/usr.bin/pcc/f77:
Makefile (r1.1)
src/usr.bin/pcc/f77/f77:
Makefile (r1.1)
src/usr.bin/pcc/f77/fcom:
Makefile (r1.1)
src/usr.bin/pcc/mip:
common.c (r1.1)
compat.c (r1.1)
manifest.h (r1.1)
match.c (r1.1)
mkext.c (r1.1)
node.h (r1.1)
optim2.c (r1.1)
pass2.h (r1.1)
protos.h (r1.1)
reader.c (r1.1)
regs.c (r1.1)
src/usr.bin/pcc/os/midnightbsd:
ccconfig.h (r1.1)
src/usr.bin/pcc/os/none:
ccconfig.h (r1.1)
-------------- next part --------------
--- /dev/null
+++ usr.bin/pcc/arch/x86/order.c
@@ -0,0 +1,287 @@
+/* $Id: order.c,v 1.49 2007/08/01 04:53:58 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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 */
+}
--- /dev/null
+++ usr.bin/pcc/arch/x86/macdefs.h
@@ -0,0 +1,301 @@
+/* $Id: macdefs.h,v 1.46 2007/08/19 19:25:22 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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 */
--- /dev/null
+++ usr.bin/pcc/arch/x86/table.c
@@ -0,0 +1,1464 @@
+/* $Id: table.c,v 1.96 2007/09/20 14:52:13 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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|FOREFF,
+ 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|FOREFF,
+ 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", },
+
+{ MINUS, INAREG|FOREFF,
+ SAREG|SNAME|SOREG, TWORD|TPOINT,
+ SONE, TANY,
+ 0, RLEFT,
+ " decl AL\n", },
+
+{ MINUS, INCH|FOREFF,
+ SHCH|SNAME|SOREG, TCHAR|TUCHAR,
+ SONE, TANY,
+ 0, RLEFT,
+ " decb AL\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]);
--- /dev/null
+++ usr.bin/pcc/arch/x86/local2.c
@@ -0,0 +1,1052 @@
+/* $Id: local2.c,v 1.89 2007/09/16 19:08:16 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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 || p->n_lval > 0x7fffffff)
+ break;
+ return SRDIR;
+ }
+ return SRNOPE;
+}
--- /dev/null
+++ usr.bin/pcc/arch/x86/code.c
@@ -0,0 +1,213 @@
+/* $Id: code.c,v 1.15 2007/07/06 17:02:27 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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);
+}
--- /dev/null
+++ usr.bin/pcc/arch/x86/local.c
@@ -0,0 +1,743 @@
+/* $Id: local.c,v 1.56 2007/09/24 16:23:36 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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 &= ((CONSZ)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
--- /dev/null
+++ usr.bin/pcc/cc/Makefile
@@ -0,0 +1,38 @@
+# $Id: Makefile.in,v 1.2 2005/05/14 13:28:21 ragge Exp $
+#
+# Makefile.in for top-level of pcc.
+#
+
+
+CC=gcc
+CFLAGS=-g
+LDFLAGS=
+CPPFLAGS=
+YACC=yacc
+LEX=flex
+
+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:
--- /dev/null
+++ usr.bin/pcc/cc/cc/cc.c
@@ -0,0 +1,736 @@
+/* $Id: cc.c,v 1.61 2007/09/26 14:48:47 ragge 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 .i are passed via 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/pic code */
+#define F_PIC 1
+#define F_pic 2
+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 = F_PIC;
+ if (strcmp(argv[i], "-fpic") == 0)
+ kflag = F_pic;
+ /* 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 = F_pic;
+ 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=='i' ||
+ 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 || Eflag) && nc > 1)
+ errorx(8, "-o given with -c || -E || -S and more than one file");
+ if (outfile && clist[0] && strcmp(outfile, clist[0]) == 0)
+ errorx(8, "output file will be clobbered");
+#if 0
+ for(i=0, j=0; i<nc; i++) {
+ if((c=getsuf(clist[i]))=='c' || c=='S') {
+ j++;
+ break;
+ }
+ }
+ if (j==0 && Eflag)
+ errorx(8, "no file to be preprocessed");
+#endif
+
+ 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])=='i') {
+ if(Eflag)
+ continue;
+ goto com;
+ } else 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";
+ if (vflag)
+ av[na++] = "-v";
+ 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";
+ if (dflag)
+ av[na++] = alist;
+ 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;
+ if (Eflag && outfile)
+ av[na++] = outfile;
+ av[na++]=0;
+ if (callsys(passp, av))
+ {exfail++; eflag++;}
+ if (Eflag || Mflag)
+ continue;
+ if (onlyas)
+ goto assemble;
+
+ /*
+ * C compiler
+ */
+ com:
+ na = 0;
+ av[na++]= "ccom";
+ if (vflag)
+ av[na++] = "-v";
+ 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 (vflag)
+ av[na++] = "-v";
+ 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";
+ if (vflag)
+ av[j++] = "-v";
+ 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(char f[], char *v[])
+{
+ int status;
+ pid_t t;
+ 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) {
+ size_t len = strlen(Bflag) + 8;
+ char *a = malloc(len);
+ if (a == NULL)
+ errorx(1, "callsys: malloc failed\n");
+ 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;
+}
--- /dev/null
+++ usr.bin/pcc/cc/cc/cc.1
@@ -0,0 +1,275 @@
+.\" $Id: cc.1,v 1.4 2007/09/26 14:48:47 ragge Exp $
+.\" $NetBSD$
+.\" $OpenBSD$
+."\
+.\" Copyright (c) 2007 Jeremy C. Reed <reed at 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 cdEgkLMPOStvxX
+.Op Fl B Ar prefix
+.Op Fl fPIC
+.Op Fl include Ar path
+.Op Fl isystem Ar path
+.Op Fl nostdinc
+.Op Fl nostdlib
+.Op Fl nostartfiles
+.Op Fl o Ar outfile
+.Op Fl pg
+.Op Fl pthread
+.Op Fl static
+.Op Fl Wl Ar flags
+.Op Ar infile ...
+.Pp
+.Sh DESCRIPTION
+The
+.Nm
+utility provides a front-end to the
+.Dq portable 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 .i
+are passed via
+.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
+.\"
+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.
+The resulting object output is saved
+as a filename with a
+.Dq .o
+suffix unless
+.Fl o
+option is used.
+Note: cannot be combined with
+.Fl o
+if multiple files are given.
+.It Fl d Ar option
+Passed to the
+.Xr as 1
+assembler.
+.\" TODO: what is as -dfoo for?
+.It Fl D Ar macro[=value]
+Passed to the
+.Xr cpp 1
+preprocessor to define
+.Ar macro .
+.It Fl E
+Stop after preprocessing with
+.Xr cpp 1 .
+Do not compile, assemble, or link.
+.It Fl fpic
+Tells C compiler to generate PIC code
+and tells assembler that PIC code has been generated.
+.\" TODO: document difference between PIC and pic
+.It Fl fPIC
+Generate PIC code.
+.\" TODO: document about avoiding machine-specific maximum size?
+.\" other -f GCC compatibility flags are ignored for now
+.It Fl g
+Send
+.Fl g
+flag to
+.Xr ccom 1
+to create debug output.
+This unsets the
+.Fl O
+option.
+.It Fl include Ar path
+.\" TODO
+.It Fl isystem Ar path
+.\" TODO
+.It Fl k
+Generate PIC code.
+See
+.Fl fpic
+option.
+.It Fl I Ar path
+Passed to the
+.Xr cpp 1
+preprocessor to add header search directory to override system defaults.
+.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?
+.\" TODO: Looks like it does cpp only, but I couldn't get it to work for me.
+.It Fl pg
+Not implemented.
+.It Fl O
+Enable optimizations.
+Currently passes
+.Fl xtemps
+to
+.Xr ccom 1 .
+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.
+The resulting assembler-language output is saved
+as a filename with a
+.Dq .s
+suffix unless the
+.Fl o
+option is used.
+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 U Ar macro
+Passed to the
+.Xr cpp 1
+preprocessor to remove the initial macro definition.
+.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?
+.El
+.Sh Predefined Macros
+A few
+macros are predefined by
+.Nm
+went sent to
+.Xr cpp 1 .
+.Bl -diag
+.\" TODO:
+.\" .It __ASSEMBLER__
+.\" Defined if suffix is .S -- why not with .s? what does this mean?
+.It __PCC__
+Set to the major version of
+.Xr pcc 1 .
+These macros can be used to select code based on
+.Xr pcc 1
+compatibility.
+See
+.Fl v
+option.
+.It __PCC_MINOR__
+Set to the minor version.
+.It __PCC_MINORMINOR__
+Set to the minor-minor version -- the number after the minor version.
+.It _PTHREADS
+Defined when
+.Fl pthread
+switch is used.
+.El
+.Pp
+Also system- and/or machine-dependent macros may also be predefined;
+for example:
+.Dv __NetBSD__ ,
+.Dv __ELF__ ,
+and
+.Dv __i386__ .
+.Sh SEE ALSO
+.Xr as 1 ,
+.Xr ccom 1 ,
+.Xr cpp 1 ,
+.Xr ld 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.
--- /dev/null
+++ usr.bin/pcc/cc/cc/Makefile
@@ -0,0 +1,53 @@
+# $Id: Makefile.in,v 1.9 2007/09/26 14:48:47 ragge Exp $
+#
+# Makefile.in for the cc part of pcc.
+#
+prefix = /usr/local
+exec_prefix = ${prefix}
+bindir = ${exec_prefix}/bin
+libexecdir = ${exec_prefix}/libexec
+datarootdir = ${prefix}/share
+mandir = ${datarootdir}/man
+#strip = yes
+CC = gcc
+TARGOS = midnightbsd
+TARGMACH = x86
+CFLAGS = -g -DLIBEXECDIR=\"${libexecdir}\" -DINCLUDEDIR=\"${includedir}\" -static-libgcc
+CPPFLAGS = -I../../os/${TARGOS} -I${MDIR} -Dmach_${TARGMACH} -Dos_${TARGOS}
+LIBS =
+LDFLAGS =
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+
+OBJS=cc.o compat.o
+DEST=pcc
+
+MIPDIR=../../mip
+MDIR=../../arch/$(TARGMACH)
+
+all: ${DEST}
+
+${DEST}: $(OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@
+
+.c.o:
+ $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $<
+
+compat.o: $(MIPDIR)/compat.c
+ $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/compat.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
+ test -z "${DESTDIR}$(mandir)/man1" || mkdir -p "${DESTDIR}$(mandir)/man1"
+ ${INSTALL} cc.1 ${DESTDIR}${mandir}/man1/${DEST}.1
+
+clean:
+ /bin/rm -f $(OBJS) ${DEST}
+
+distclean: clean
+ /bin/rm -f Makefile
--- /dev/null
+++ usr.bin/pcc/cc/ccom/inline.c
@@ -0,0 +1,209 @@
+/* $Id: inline.c,v 1.17 2007/09/09 10:01:01 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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--;
+}
--- /dev/null
+++ usr.bin/pcc/cc/ccom/scan.l
@@ -0,0 +1,467 @@
+%{
+/* $Id: scan.l,v 1.61 2007/09/19 17:20:26 ragge 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);
+extern int yyget_lineno (void);
+extern void yyset_lineno (int);
+#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('+'); }
+"*" { if (parbal && notype == 0) notype = 1; 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);
+}
--- /dev/null
+++ usr.bin/pcc/cc/ccom/pftn.c
@@ -0,0 +1,2553 @@
+/* $Id: pftn.c,v 1.171 2007/09/23 20:00:22 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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 */
+ if (pol == NIL)
+ uerror("aggregate dynamic array not allowed");
+ else
+ 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);
+ if (a)
+ 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
--- /dev/null
+++ usr.bin/pcc/cc/ccom/init.c
@@ -0,0 +1,961 @@
+/* $Id: init.c,v 1.30 2007/09/24 20:34:03 ragge Exp $ */
+
+/*
+ * Copyright (c) 2004, 2007 Anders Magnusson (ragge at 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;
+ if (sq == NULL) {
+ uerror("excess of initializing elements");
+ } else {
+ 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
+ uerror("too many left braces");
+ 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)) {
+ if (is->in_prev->in_prev &&
+ is->in_prev->in_prev->in_t == STRTY)
+ off += is->in_sym->soffset;
+ 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;
+
+ if (pstk == NULL)
+ stkpush();
+ 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");
+ }
+}
--- /dev/null
+++ usr.bin/pcc/cc/ccom/gcc_compat.c
@@ -0,0 +1,126 @@
+/* $Id: gcc_compat.c,v 1.7 2006/05/13 06:35:36 ragge Exp $ */
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge at 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
--- /dev/null
+++ usr.bin/pcc/cc/ccom/pass1.h
@@ -0,0 +1,394 @@
+/* $Id: pass1.h,v 1.125 2007/09/09 10:01:01 ragge 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)
+
--- /dev/null
+++ usr.bin/pcc/cc/ccom/main.c
@@ -0,0 +1,317 @@
+/* $Id: main.c,v 1.72 2007/09/25 06:43:06 ragge 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:kv")) != -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 'v':
+ printf("ccom: %s\n", VERSSTR);
+ 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 );
+ if (!nerrors)
+ 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);
+}
--- /dev/null
+++ usr.bin/pcc/cc/ccom/cgram.y
@@ -0,0 +1,1400 @@
+/* $Id: cgram.y,v 1.170 2007/09/16 19:25:33 ragge Exp $ */
+
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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>
+# include <stdlib.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;
+}
--- /dev/null
+++ usr.bin/pcc/cc/ccom/ccom.1
@@ -0,0 +1,152 @@
+.\" $Id: ccom.1,v 1.2 2007/09/26 14:48:49 ragge Exp $
+.\" $NetBSD$
+.\" $OpenBSD$
+."\
+.\" Copyright (c) 2007 Jeremy C. Reed <reed at 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.
--- /dev/null
+++ usr.bin/pcc/cc/ccom/trees.c
@@ -0,0 +1,2451 @@
+/* $Id: trees.c,v 1.163 2007/09/16 08:26:39 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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) {
+ werror("returning value from void function");
+ return;
+ }
+ if (t2 == VOID) {
+ uerror("using void value");
+ return;
+ }
+ 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);
+}
--- /dev/null
+++ usr.bin/pcc/cc/ccom/stabs.c
@@ -0,0 +1,374 @@
+/* $Id: stabs.c,v 1.15 2007/09/15 07:37:44 ragge Exp $ */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge at 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
--- /dev/null
+++ usr.bin/pcc/cc/ccom/symtabs.c
@@ -0,0 +1,356 @@
+/* $Id: symtabs.c,v 1.14 2006/06/16 09:30:32 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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;
+}
--- /dev/null
+++ usr.bin/pcc/cc/ccom/optim.c
@@ -0,0 +1,355 @@
+/* $Id: optim.c,v 1.28 2006/07/11 07:54:29 ragge 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 );
+ }
--- /dev/null
+++ usr.bin/pcc/cc/ccom/Makefile
@@ -0,0 +1,114 @@
+# $Id: Makefile.in,v 1.11 2007/09/26 14:48:49 ragge Exp $
+#
+# Makefile.in for ccom
+#
+XFL=-DPCC_DEBUG -DGCC_COMPAT \
+ -Wall -Wmissing-prototypes -Wstrict-prototypes -Werror
+
+CC = gcc
+CFLAGS = -g $(XFL) -I. -I${MIPDIR} -I$(MDIR) -Dmach_${TARGMACH} \
+ -I../../os/${TARGOS}
+CPPFLAGS =
+LIBS =
+LDFLAGS =
+LEX = flex
+YACC = yacc
+TARGOS = midnightbsd
+TARGMACH = x86
+prefix = /usr/local
+exec_prefix = ${prefix}
+libexecdir = ${exec_prefix}/libexec
+datarootdir = ${prefix}/share
+mandir = ${datarootdir}/man
+strip = yes
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+
+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) compat.o 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
+
+compat.o: $(MIPDIR)/compat.c
+ $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/compat.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
+ test -z "${DESTDIR}$(mandir)/man1" || mkdir -p "${DESTDIR}$(mandir)/man1"
+ ${INSTALL} ${DEST}.1 ${DESTDIR}${mandir}/man1/
+
+clean:
+ /bin/rm -f $(OBJS) ccom scan.c cgram.[ch] mkext external.[ch]
+
+distclean: clean
+ /bin/rm -f Makefile
--- /dev/null
+++ usr.bin/pcc/cc/cpp/tests/res9
@@ -0,0 +1,5 @@
+# 1 "<stdin>"
+
+
+
+ao
--- /dev/null
+++ usr.bin/pcc/cc/cpp/tests/res7
@@ -0,0 +1,5 @@
+# 1 "<stdin>"
+
+
+
+a YES
--- /dev/null
+++ 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";
--- /dev/null
+++ usr.bin/pcc/cc/cpp/tests/res6
@@ -0,0 +1,6 @@
+# 1 "<stdin>"
+
+
+
+
+foo
--- /dev/null
+++ 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", "" };
+ */
--- /dev/null
+++ 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)
+
--- /dev/null
+++ 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(,,) };
--- /dev/null
+++ usr.bin/pcc/cc/cpp/tests/test7
@@ -0,0 +1,4 @@
+#define a() YES
+#define b() a
+b()
+b()()
--- /dev/null
+++ usr.bin/pcc/cc/cpp/tests/res4
@@ -0,0 +1,5 @@
+# 1 "<stdin>"
+
+
+
+(1)
--- /dev/null
+++ 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"
--- /dev/null
+++ usr.bin/pcc/cc/cpp/tests/test6
@@ -0,0 +1,5 @@
+#define X(a,b, \
+ c,d) \
+ foo
+
+X(1,2,3,4)
--- /dev/null
+++ usr.bin/pcc/cc/cpp/tests/res8
@@ -0,0 +1,8 @@
+# 1 "<stdin>"
+
+
+
+
+
+(hej.s_s.s_pos)
+
--- /dev/null
+++ usr.bin/pcc/cc/cpp/tests/res5
@@ -0,0 +1,4 @@
+# 1 "<stdin>"
+
+int j[] = { 123, 45, 67, 89,
+ 10, 11, 12, };
--- /dev/null
+++ usr.bin/pcc/cc/cpp/tests/res1
@@ -0,0 +1,7 @@
+# 1 "<stdin>"
+
+
+
+
+char p[] = "x ## y";
+
--- /dev/null
+++ 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", "" };
+
+
+
+
+
+
--- /dev/null
+++ 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)
--- /dev/null
+++ 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)
--- /dev/null
+++ 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)
--- /dev/null
+++ usr.bin/pcc/f77/Makefile
@@ -0,0 +1,36 @@
+# $Id: Makefile.in,v 1.1 2005/05/14 11:22:00 ragge Exp $
+#
+# Makefile.in for top-level of pcc.
+#
+
+
+CC=gcc
+CFLAGS=-g -O2
+LDFLAGS=
+CPPFLAGS=
+YACC=yacc
+LEX=flex
+
+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)
--- /dev/null
+++ usr.bin/pcc/f77/f77/Makefile
@@ -0,0 +1,41 @@
+# $Id: Makefile.in,v 1.3 2004/12/30 15:23:13 ragge Exp $
+#
+# Makefile.in for the cc part of pcc.
+#
+prefix = /usr/local
+exec_prefix = ${prefix}
+bindir = ${exec_prefix}/bin
+libexecdir = ${exec_prefix}/libexec
+CC = gcc
+TARGOS = midnightbsd
+TARGMACH = x86
+CFLAGS = -g -DLIBEXECDIR=\"${libexecdir}\"
+CPPFLAGS = -I../os/${TARGOS} -Dmach_${TARGMACH} -Dos_${TARGOS}
+LIBS =
+LDFLAGS =
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+
+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
--- /dev/null
+++ usr.bin/pcc/f77/fcom/Makefile
@@ -0,0 +1,95 @@
+# $Id: Makefile.in,v 1.2 2005/05/11 19:31:05 ragge Exp $
+#
+# Makefile for the Fortran 77 command
+# Running on the x86
+# Generating code for the x86
+# Using the Johnson C compiler's second pass (binary version)
+
+TARGOS = midnightbsd
+TARGMACH = x86
+MDIR=../arch/$(TARGMACH)
+YFLAGS=-d
+
+COMPFLGS = -O -DFORTRAN -DTARGET=x86 -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
--- /dev/null
+++ usr.bin/pcc/mip/reader.c
@@ -0,0 +1,1112 @@
+/* $Id: reader.c,v 1.203 2007/09/24 17:49:54 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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;
+static struct interpass prepole;
+
+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) {
+ ip = ipnode(l);
+ DLIST_INSERT_AFTER(&prepole, ip, qelem);
+ 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_INIT(&prepole, qelem);
+ 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);
+ } else while (!DLIST_ISEMPTY(&prepole, qelem)) {
+ struct interpass *ipp;
+
+ ipp = DLIST_NEXT(&prepole, qelem);
+ DLIST_REMOVE(ipp, qelem);
+ DLIST_INSERT_BEFORE(ip, ipp, 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 */
+
+ if (ISUNSIGNED(ty)) {
+
+ p->n_left->n_type = ty;
+ p->n_op = AND;
+ p->n_right = mklnode(ICON, ((CONSZ)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! */
+ }
+ } else {
+ /* must sign-extend, assume RS will do */
+ /* if not, arch must use rewfld() */
+ p->n_left->n_type = INT; /* Ok? */
+ p->n_op = RS;
+ p->n_right = mklnode(ICON, SZINT-s, 0, INT);
+ p->n_left = mkbinode(LS, p->n_left,
+ mklnode(ICON, SZINT-s-o, 0, INT), INT);
+ }
+ }
+}
+#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;
+}
--- /dev/null
+++ usr.bin/pcc/mip/node.h
@@ -0,0 +1,194 @@
+/* $Id: node.h,v 1.31 2007/07/22 12:50:56 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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
--- /dev/null
+++ usr.bin/pcc/mip/match.c
@@ -0,0 +1,995 @@
+/* $Id: match.c,v 1.72 2006/07/30 09:32:15 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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;
+}
--- /dev/null
+++ usr.bin/pcc/mip/pass2.h
@@ -0,0 +1,418 @@
+/* $Id: pass2.h,v 1.98 2006/12/22 06:23:09 ragge 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 */
--- /dev/null
+++ usr.bin/pcc/mip/regs.c
@@ -0,0 +1,2285 @@
+/* $Id: regs.c,v 1.155 2007/09/22 17:15:00 ragge Exp $ */
+/*
+ * Copyright (c) 2005 Anders Magnusson (ragge at 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);
+ w->r_nclass[0] = o == LTYPE; /* XXX store leaf info here */
+ 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[((long)u+(long)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 = ((long)u+(long)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) {
+ set ? LIVEADDR(rv) : LIVEDELR(rv);
+ return;
+ }
+
+ if (p->n_regw != NULL) {
+ set ? LIVEADDR(p->n_regw) : LIVEDELR(p->n_regw);
+ return;
+ }
+
+ 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) {
+ AddEdge(p->n_regw, w);
+ return;
+ }
+
+ 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 */
+ /* but not if leaf */
+ DLIST_FOREACH(w, &spillWorklist, link) {
+ if (w->r_nclass[0] == 0)
+ break;
+ }
+ }
+
+ if (w == &spillWorklist) {
+ /* Eh, only leaves :-/ Try anyway */
+ /* May not be useable */
+ 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;
+ struct optab *q;
+ 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();
+ /*
+ * If this is a binode which reclaim a leg, and it had
+ * to walk down the other leg first, then it must be
+ * split below this node instead.
+ */
+ q = &table[TBLIDX(p->n_su)];
+ if (optype(p->n_op) == BITYPE &&
+ (q->rewrite & RLEFT && (p->n_su & DORIGHT) == 0) &&
+ (TBLIDX(p->n_right->n_su) != 0)) {
+ *r = *l;
+ nip = ipnode(mkbinode(ASSIGN, l,
+ p->n_left, p->n_type));
+ p->n_left = r;
+ } else if (optype(p->n_op) == BITYPE &&
+ (q->rewrite & RRIGHT && (p->n_su & DORIGHT) != 0) &&
+ (TBLIDX(p->n_left->n_su) != 0)) {
+ *r = *l;
+ nip = ipnode(mkbinode(ASSIGN, l,
+ p->n_right, p->n_type));
+ p->n_right = r;
+ } else {
+ *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 %zd\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! */
+}
--- /dev/null
+++ usr.bin/pcc/mip/common.c
@@ -0,0 +1,638 @@
+/* $Id: common.c,v 1.73 2007/09/22 17:15:00 ragge Exp $ */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge at 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");
+ va_end(ap);
+}
+
+#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 ((long)&((struct b *)0)->a2)
+#define ROUNDUP(x) (((x) + ((ALIGNMENT)-1)) & ~((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/2) {
+ size += ROUNDUP(sizeof(char *));
+ if ((rv = malloc(size)) == NULL)
+ cerror("tmpalloc: out of memory");
+ /* link in before current chunk XXX */
+ *(char **)rv = *(char **)tmppole;
+ *(char **)tmppole = rv;
+ tmpallocsize += size;
+ return (char *)rv + ROUNDUP(sizeof(char *));
+ }
+ 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;
+}
--- /dev/null
+++ usr.bin/pcc/mip/compat.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller at courtesan.com>
+ * 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 ``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.
+ *
+ * $Id: compat.c,v 1.1 2007/09/20 12:52:15 ragge Exp $
+ */
+
+#include <string.h>
+
+#include "../config.h"
+#include "manifest.h"
+
+#ifndef HAVE_STRLCAT
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(initial dst) + strlen(src); if retval >= siz,
+ * truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+#endif
+
+
+#ifndef HAVE_STRLCPY
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+#endif
--- /dev/null
+++ usr.bin/pcc/mip/manifest.h
@@ -0,0 +1,324 @@
+/* $Id: manifest.h,v 1.59 2007/09/20 12:02:54 ragge 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);
+
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *dst, const char *src, size_t siz);
+#endif
+
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *dst, const char *src, size_t siz);
+#endif
+
+/* 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
--- /dev/null
+++ usr.bin/pcc/mip/mkext.c
@@ -0,0 +1,323 @@
+
+/*
+ * Generate defines for the needed hardops.
+ */
+#include "pass2.h"
+
+#include <string.h>
+
+int chkop[DSIZE];
+
+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|RESC3) && 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;
+ if (mx > (sizeof(int)*8)-1) {
+ printf("too many regs in a calss, use two classes instead\n");
+ printf("%d > %d\n", mx, (sizeof(int)*8)-1);
+ rval++;
+ }
+ 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));
+}
--- /dev/null
+++ usr.bin/pcc/mip/optim2.c
@@ -0,0 +1,882 @@
+/* $Id: optim2.c,v 1.44 2006/06/20 06:02:44 ragge Exp $ */
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge at 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;
+ }
+ }
+}
--- /dev/null
+++ 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);
--- /dev/null
+++ usr.bin/pcc/os/midnightbsd/ccconfig.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2007 Lucas Holt <luke at midnightbsd.org>
+ * Copyright (c) 2007 David O'Brien <obrien at FreeBSD.org>
+ * Copyright (c) 2007 Ed Schouten <ed at fxq.nl>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 THE AUTHOR OR CONTRIBUTORS 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.
+ */
+
+#define CPPADD { "-D__MidnightBSD__", "-D__ELF__", "-D__unix__=1", "-D__unix=1", NULL, }
+#define DYNLINKER { "-dynamic-linker", "/libexec/ld-elf.so.1", "-lgcc_s", 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 }
+#define STARTLABEL "_start"
+
+#if defined(mach_x86)
+#define CPPMDADD { "-D__i386__", "-D__i386", NULL, }
+#else
+#error defines for arch missing
+#endif
+
+#define STABS
+
--- /dev/null
+++ usr.bin/pcc/config.h
@@ -0,0 +1,156 @@
+/* config.h. Generated from config.h.in by configure. */
+/* 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. */
+#define HAVE_ALLOCA 1
+
+/* 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. */
+#define HAVE_INTTYPES_H 1
+
+/* 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. */
+#define HAVE_MEMORY_H 1
+
+/* 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. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* 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. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* 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. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* 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. */
+#define HAVE_UNISTD_H 1
+
+/* 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. */
+#define PACKAGE_BUGREPORT "BUG-REPORT-ADDRESS"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "pcc"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "pcc 0.9.8"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "pcc"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.9.8"
+
+/* 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. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define PCC_MAJOR 0
+#define PCC_MINOR 9
+#define PCC_MINORMINOR 8
+#define VERSSTR "pcc 0.9.8 for i386-unknown-midnightbsd0.1, laffer1 at m5.midnightbsd.org Wed Sep 26 15:13:33 EDT 2007"
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+ `char[]'. */
+#define YYTEXT_POINTER 1
+
+/* 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 */
+#define TARGOS midnightbsd
+
+/* mkstemp() */
+#define HAVE_MKSTEMP 1
+
+/* which lex is used */
+#define ISFLEX 1
--- /dev/null
+++ usr.bin/pcc/Makefile
@@ -0,0 +1,31 @@
+# $Id: Makefile.in,v 1.3 2005/05/14 13:28:13 ragge Exp $
+#
+# Makefile.in for top-level of pcc.
+#
+
+CC=gcc
+CFLAGS=-g
+LDFLAGS=
+CPPFLAGS=
+YACC=yacc
+LEX=flex
+
+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:
--- /dev/null
+++ usr.bin/pcc/cc/cpp/scanner.l
@@ -0,0 +1,814 @@
+%{
+/* $Id: scanner.l,v 1.20 2007/09/25 20:41:07 ragge 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);
+
+extern int yyget_lineno (void);
+extern void yyset_lineno (int);
+
+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" { 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" { 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;
+ default:
+ error("prinit");
+ }
+ strlcat((char *)ic->buffer, pre, CPPBUF+1);
+ strlcat((char *)ic->buffer, it->str, CPPBUF+1);
+ if (strlcat((char *)ic->buffer, post, CPPBUF+1) >= CPPBUF+1)
+ error("line exceeds buffer size");
+
+ 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);
+ if (dMflag)
+ write(ofd, ic->buffer, strlen((char *)ic->buffer));
+ initar = NULL;
+ }
+
+ 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 (dMflag)
+ return; /* no output */
+ 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)
+{
+ int c;
+
+ slow = 1;
+ if (yylex() != WSPACE)
+ error("bad pragma");
+ putstr((usch *)"#pragma ");
+ do {
+ putch(c = input()); /* Do arg expansion instead? */
+ } while (c && c != '\n');
+ ifiles->lineno++;
+ prtline();
+ slow = 0;
+}
--- /dev/null
+++ usr.bin/pcc/cc/cpp/token.c
@@ -0,0 +1,495 @@
+/* $Id: token.c,v 1.11 2006/09/28 11:10:08 ragge 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 : "";
+}
--- /dev/null
+++ usr.bin/pcc/cc/cpp/cpp.c
@@ -0,0 +1,1482 @@
+/* $Id: cpp.c,v 1.65 2007/09/25 20:41:08 ragge Exp $ */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge at 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;
+usch outbuf[CPPBUF];
+int obufp, istty;
+int Cflag, Mflag, dMflag;
+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;
+static struct symtab *pragloc;
+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;
+
+ while ((ch = getopt(argc, argv, "CD:I:MS:U:d:i:tvV?")) != -1)
+ switch (ch) {
+ case 'C': /* Do not discard comments */
+ Cflag++;
+ break;
+
+ case 'i': /* include */
+ case 'U': /* undef */
+ case 'D': /* define something */
+ /* XXX should not need malloc() here */
+ if ((it = malloc(sizeof(struct initar))) == NULL)
+ error("couldn't apply -%c %s", ch, optarg);
+ it->type = ch;
+ it->str = optarg;
+ it->next = initar;
+ initar = it;
+ break;
+
+ case 'M': /* Generate dependencies for make */
+ Mflag++;
+ break;
+
+ case 'S':
+ case 'I':
+ if ((w = calloc(sizeof(struct incs), 1)) == NULL)
+ error("couldn't apply -%c %s", ch, optarg);
+ 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;
+
+#ifdef CPP_DEBUG
+ case 'V':
+ dflag++;
+ break;
+#endif
+ case 'v':
+ printf("cpp: %s\n", VERSSTR);
+ break;
+ case 'd':
+ if (optarg[0] == 'M') {
+ dMflag = 1;
+ Mflag = 1;
+ }
+ /* ignore others */
+ break;
+
+ case 't':
+ tflag = 1;
+ break;
+
+ case '?':
+ usage();
+ default:
+ error("bad arg %c\n", ch);
+ }
+ argc -= optind;
+ argv += optind;
+
+ filloc = lookup((usch *)"__FILE__", ENTER);
+ linloc = lookup((usch *)"__LINE__", ENTER);
+ pragloc = lookup((usch *)"_Pragma", ENTER);
+ filloc->value = linloc->value = (usch *)""; /* Just something */
+ pragloc->value = (usch *)"";
+
+ 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 && !dMflag) {
+ 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;
+ if (strlcpy((char *)lbuf, &yytext[1], SBSIZE) >= SBSIZE)
+ error("line exceeded buffer size");
+
+ 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, *safefn;
+ int i, c, it;
+
+ if (flslvl)
+ return;
+ osp = stringbuf;
+ slow = 1;
+again:
+ if ((c = yylex()) == WSPACE)
+ c = yylex();
+ if (c != 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;
+ safefn = fn;
+ } 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++;
+ }
+ safefn = stringbuf;
+ savstr(fn); savch(0);
+ while ((c = yylex()) == WSPACE)
+ ;
+ if (c != '\n')
+ goto bad;
+ slow = 0;
+ if (pushfile(nm) == 0)
+ return;
+ /* XXX may loose stringbuf space */
+ }
+
+ /* 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(safefn); savch(0);
+ if (pushfile(nm) == 0)
+ return;
+ stringbuf = nm;
+ }
+ }
+ error("cannot find '%s'", safefn);
+ /* 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;
+ int len;
+
+ 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) {
+ len = strlen(yytext);
+ args[narg] = alloca(len+1);
+ strlcpy((char *)args[narg], yytext, len+1);
+ 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");
+ }
+}
+
+/*
+ * convert _Pragma to #pragma for output.
+ */
+static void
+pragoper(void)
+{
+ usch *opb;
+ int t;
+
+ slow = 1;
+ putstr((usch *)"\n#pragma ");
+ if ((t = yylex()) == WSPACE)
+ t = yylex();
+ if (t != '(')
+ goto bad;
+ if ((t = yylex()) == WSPACE)
+ t = yylex();
+ opb = stringbuf;
+ while (t != ')') {
+ savstr((usch *)yytext);
+ t = yylex();
+ }
+ savch(0);
+ cunput(WARN);
+ unpstr(opb);
+ stringbuf = opb;
+ expmac(NULL);
+ while (stringbuf > opb)
+ cunput(*--stringbuf);
+ if ((t = yylex()) != STRING)
+ goto bad;
+ opb = (usch *)yytext;
+ if (*opb++ == 'L')
+ opb++;
+ while ((t = *opb++) != '\"') {
+ if (t == '\\' && (*opb == '\"' || *opb == '\\'))
+ t = *opb++;
+ putch(t);
+ }
+ putch('\n');
+ prtline();
+ return;
+bad: error("bad pragma operator");
+}
+
+/*
+ * 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;
+ } else if (sp == pragloc) {
+ pragoper();
+ 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 || c == '\n')
+ 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);
+ strlcpy((char *)stksv, yytext, yyleng+1);
+ 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;
+
+/*
+ * Allocate a symtab struct and store the string.
+ */
+static struct symtab *
+getsymtab(usch *str)
+{
+ struct symtab *sp = malloc(sizeof(struct symtab));
+
+ if (sp == NULL)
+ error("getsymtab: couldn't allocate 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 */
+ if ((new = malloc(sizeof *new)) == NULL)
+ error("getree: couldn't allocate tree");
+ 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];
+}
+
--- /dev/null
+++ usr.bin/pcc/cc/cpp/cpy.y
@@ -0,0 +1,166 @@
+/* $Id: cpy.y,v 1.12 2006/10/08 13:41:39 ragge Exp $ */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge at 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);
+}
--- /dev/null
+++ usr.bin/pcc/cc/cpp/cpp.h
@@ -0,0 +1,120 @@
+/* $Id: cpp.h,v 1.27 2007/09/17 18:16:14 ragge Exp $ */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge at 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, dMflag;
+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 *);
--- /dev/null
+++ usr.bin/pcc/cc/cpp/Makefile
@@ -0,0 +1,89 @@
+# $Id: Makefile.in,v 1.14 2007/09/26 14:48:51 ragge Exp $
+#
+# Makefile.in for cpp
+#
+XFL=-DCPP_DEBUG -Wall -Wmissing-prototypes -Wstrict-prototypes -Werror
+
+prefix = /usr/local
+exec_prefix = ${prefix}
+bindir = ${exec_prefix}/bin
+libexecdir = ${exec_prefix}/libexec
+datarootdir = ${prefix}/share
+mandir = ${datarootdir}/man
+CC = gcc
+CFLAGS = -g $(XFL)
+CPPFLAGS = -I${MDIR}
+LIBS =
+LDFLAGS =
+LEX = flex
+YACC=yacc
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+TARGMACH = x86
+
+OBJS=cpp.o cpy.o scanner.o compat.o
+HEADERS=cpp.h
+DEST=cpp
+
+MIPDIR=../../mip
+MDIR=../../arch/$(TARGMACH)
+
+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
+
+compat.o: $(MIPDIR)/compat.c
+ $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/compat.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
+ test -z "${DESTDIR}$(mandir)/man1" || mkdir -p "${DESTDIR}$(mandir)/man1"
+ ${INSTALL} ${DEST}.1 ${DESTDIR}${mandir}/man1/
+
+clean:
+ /bin/rm -f $(OBJS) cpp lex.yy.c y.tab.[ch] tests/run*
+
+distclean: clean
+ /bin/rm -f Makefile
--- /dev/null
+++ usr.bin/pcc/cc/cpp/cpp.1
@@ -0,0 +1,191 @@
+.\" $Id: cpp.1,v 1.4 2007/09/26 14:48:51 ragge Exp $
+.\" $NetBSD$
+.\" $OpenBSD$
+."\
+.\" Copyright (c) 2007 Jeremy C. Reed <reed at 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 17, 2007
+.Dt cpp 1
+.Os
+.Sh NAME
+.Nm cpp
+.Nd C preprocessor
+.Sh SYNOPSIS
+.Nm
+.\" TODO also document -Dvar and below without spaces?
+.Op Fl Cdt
+.Op Fl D Ar var=val
+.Op Fl U Ar var
+.Op Fl I Ar path
+.Op Fl S Ar path
+.Op Ar infile | -
+.Op Ar outfile
+.Pp
+.Sh DESCRIPTION
+The
+.Nm
+utility is a macro preprocessor used by the
+.Xr pcc 1
+compiler.
+It is used to include header files,
+expand macro definitions,
+and perform conditional compilation.
+.Pp
+The
+.Ar infile
+input file is optional.
+If not provided or the file name is
+.Qq -
+(dash),
+.Nm
+reads its initial file from standard input.
+The
+.Ar outfile
+output file is also optional.
+It writes by default to standard output.
+.Pp
+.\" TODO: document MAXARG 250 args to a macro, limited by char value
+.\" TODO: Include order:
+.\" For "..." files, first search "current" dir, then as <...> files.
+.\" For <...> files, first search -I directories, then system directories.
+.\"
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl C
+Do not discard comments.
+.It Fl dM
+Print list of
+.Dq #define
+statements to standard output for all defined macros other than
+builtin macros (see below).
+The normal results of preprocessing are not outputted.
+.\" TODO this doesn't show predefined macros
+.\" other -d options are ignored
+.It Fl D Ar macro[=value]
+Fake a definition at the beginning by using
+.Do #define
+.Ar macro=value Dc .
+If
+.Ar value
+is not set on command-line, then defines as 1.
+.\" TODO: show example
+.It Fl i Ar file
+Include a file at the beginning by using
+.Do #include
+.Ar file Dc .
+.\" Note: I did not use the .In macro above
+.It Fl I Ar directory
+Add
+.Ar directory
+to the list of system directories containing needed header files.
+This may be used to override system include directories
+(see
+.Fl S
+option).
+.Fl I
+may be specified multiple times.
+.It Fl M
+Generate dependencies for
+.Xr make 1 .
+.\" TODO: explain and show example?
+.It Fl S Ar directory
+Add
+.Ar directory
+to the list of system directories containing needed header files.
+.Fl S
+may be specified multiple times.
+Note:
+.Nm
+does not have a default include directory defined.
+.\" TODO: explain difference between -I and -S
+.\" The directories listed by -I are searched first?
+.It Fl t
+Traditional cpp syntax.
+Do not define the
+.Dv __TIME__ ,
+.Dv __DATE__ ,
+and
+.Dv __STDC__
+macros.
+.\"
+.It Fl U Ar macro
+Undefine a macro at the beginning by using
+.Do #undef
+.Ar macro Dc .
+.It Fl v
+Verbose debugging output.
+.Fl v
+can be repeated for further details.
+.\" -v only available if cpp source built with CPP_DEBUG, which is the default.
+.It Fl ?
+Show command line usage for
+.Nm .
+.El
+.Sh Builtin Macros
+A few macros are interpreted inside the
+.Nm cpp
+program:
+.Bl -diag
+.It __DATE__
+Expands to the date in abbreviated month, day, and year format from
+.Xr ctime 3
+in quotes.
+.\" TODO: is that ctime(3) format output change according to locale?
+.It __FILE__
+Expands to the name of the current input file in quotes.
+When read from standard input, it expands to
+.Qq Ao stdin Ac .
+.It __LINE__
+Expands to the line number of the current line containing the macro.
+.It __STDC__
+Expands to the constant 1.
+This means the compiler conforms to ISO Standard C.
+.It __TIME__
+Expands to the time in hour, minutes, and seconds from
+.Xr ctime 3
+in quotes.
+.El
+.Pp
+Also see the
+.Fl t
+option.
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width Ds
+.It 0
+Successfully finished.
+.It 1
+An error occurred.
+.El
+.Sh SEE ALSO
+.Xr as 1 ,
+.Xr ccom 1 ,
+.Xr pcc 1
+.\"
+.Sh HISTORY
+The
+.Nm
+command comes from the original Portable C Compiler by S. C.
+Johnson, written in the late 70's.
+The code originates from the V6 preprocessor with some additions
+from V7 cpp and ansi/c99 support.
+.Pp
+A lot of the PCC code was rewritten by Anders Magnusson.
+.Pp
+This product includes software developed or owned by Caldera
+International, Inc.
--- /dev/null
+++ usr.bin/pcc/os/none/ccconfig.h
@@ -0,0 +1,50 @@
+/* $Id: ccconfig.h,v 1.2 2006/07/30 09:29:27 ragge Exp $ */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge at 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
+
More information about the Midnightbsd-cvs
mailing list