[Midnightbsd-cvs] src: usr.bin/pcc: WIP: Update to .99

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Tue Jan 20 16:09:44 EST 2009


Log Message:
-----------
WIP: Update to .99

Modified Files:
--------------
    src/usr.bin/pcc:
        ccconfig.h (r1.1 -> r1.2)
        config.h (r1.3 -> r1.4)
    src/usr.bin/pcc/cc:
        Makefile (r1.8 -> r1.9)
        cc.c (r1.2 -> r1.3)
    src/usr.bin/pcc/ccom:
        Makefile (r1.2 -> r1.3)
        ccom.1 (r1.1 -> r1.2)
        cgram.y (r1.1 -> r1.2)
        gcc_compat.c (r1.1 -> r1.2)
        init.c (r1.1 -> r1.2)
        inline.c (r1.1 -> r1.2)
        main.c (r1.2 -> r1.3)
        optim.c (r1.1 -> r1.2)
        pass1.h (r1.1 -> r1.2)
        pftn.c (r1.1 -> r1.2)
        scan.l (r1.1 -> r1.2)
        stabs.c (r1.1 -> r1.2)
        symtabs.c (r1.1 -> r1.2)
        trees.c (r1.1 -> r1.2)
    src/usr.bin/pcc/cpp:
        Makefile (r1.6 -> r1.7)
        cpp.c (r1.3 -> r1.4)
        cpp.h (r1.2 -> r1.3)
        cpy.y (r1.1 -> r1.2)
        scanner.l (r1.1 -> r1.2)
        token.c (r1.1 -> r1.2)
    src/usr.bin/pcc/i386:
        code.c (r1.1 -> r1.2)
        local.c (r1.1 -> r1.2)
        local2.c (r1.1 -> r1.2)
        macdefs.h (r1.1 -> r1.2)
        order.c (r1.1 -> r1.2)
        table.c (r1.1 -> r1.2)
    src/usr.bin/pcc/mip:
        common.c (r1.1 -> r1.2)
        compat.c (r1.1 -> r1.2)
        manifest.h (r1.1 -> r1.2)
        match.c (r1.1 -> r1.2)
        mkext.c (r1.1 -> r1.2)
        node.h (r1.1 -> r1.2)
        optim2.c (r1.1 -> r1.2)
        pass2.h (r1.1 -> r1.2)
        protos.h (r1.1 -> r1.2)
        reader.c (r1.1 -> r1.2)
        regs.c (r1.1 -> r1.2)

Added Files:
-----------
    src/usr.bin/pcc/amd64:
        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/cpp:
        pcpp.1 (r1.1)
    src/usr.bin/pcc/sparc64:
        code.c (r1.1)
        local.c (r1.1)
        local2.c (r1.1)
        macdefs.h (r1.1)
        order.c (r1.1)
        table.c (r1.1)

Removed Files:
-------------
    src/usr.bin/pcc/cpp:
        cpp.1

-------------- next part --------------
--- /dev/null
+++ usr.bin/pcc/amd64/order.c
@@ -0,0 +1,273 @@
+/*	$Id: order.c,v 1.1 2008/11/27 05:25:15 mickey Exp $	*/
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * 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, int shape)
+{
+
+	if (x2debug)
+		printf("shumul(%p)\n", p);
+
+	/* Turns currently anything into OREG on x86 */
+	if (shape & SOREG)
+		return SROREG;
+	return SRNOPE;
+}
+
+/*
+ * 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 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, RAX }, { NEVER, RDX },
+				{ NLEFT, RAX }, { NRES, RAX },
+				{ NORIGHT, RDX }, { NORIGHT, RAX }, { 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, RAX }, { 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, RAX }, { 0 } };
+			return s;
+		}
+		break;
+	case LS:
+	case RS:
+		static struct rspecial s[] = {
+			{ NRIGHT, CL }, { NOLEFT, RCX }, { 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 */
+}
+
+/*
+ * set registers in calling conventions live.
+ */
+int *
+livecall(NODE *p)
+{
+	static int r[] = { EAX, EBX, -1 };
+	int off = 1;
+
+#ifdef TLS
+	if (p->n_left->n_op == ICON &&
+	    strcmp(p->n_left->n_name, "___tls_get_addr at PLT") == 0)
+		off--;
+#endif
+
+	return kflag ? &r[off] : &r[2];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+	return 1;
+}
--- /dev/null
+++ usr.bin/pcc/amd64/macdefs.h
@@ -0,0 +1,337 @@
+/*	$Id: macdefs.h,v 1.2 2008/12/10 17:59:30 mickey Exp $	*/
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * 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 SZSHORT		16
+#define SZINT		32
+#define SZLONG		64
+#define SZPOINT(t)	64
+#define SZLONGLONG	64
+#define SZFLOAT		32
+#define SZDOUBLE	64
+#define SZLDOUBLE	128
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR		8
+#define ALBOOL		8
+#define ALSHORT		16
+#define ALINT		32
+#define ALLONG		64
+#define ALPOINT		64
+#define ALLONGLONG	64
+#define ALFLOAT		32
+#define ALDOUBLE	64
+#define ALLDOUBLE	128
+#define ALSTRUCT	128
+#define ALSTACK		64
+#define ALMAX		128 
+
+/*
+ * 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		(-0x7fffffff-1)
+#define	MAX_INT		0x7fffffff
+#define	MAX_UNSIGNED	0xffffffff
+#define	MIN_LONG	MIN_LONGLONG
+#define	MAX_LONG	MAX_LONGLONG
+#define	MAX_ULONG	MAX_ULONGLONG
+#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 */
+#if defined(os_mirbsd) || defined(os_win32)
+#define WCHAR_TYPE	USHORT	/* ISO 10646 16-bit Unicode */
+#else
+#define	WCHAR_TYPE	INT	/* what used to store wchar_t */
+#endif
+
+/*
+ * 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 LANG_F77
+#define BLANKCOMMON "_BLNK_"
+#define MSKIREG  (M(TYSHORT)|M(TYLONG))
+#define TYIREG TYLONG
+#define FSZLENG  FSZLONG
+#define	AUTOREG	EBP
+#define	ARGREG	EBP
+#define ARGOFFSET 8
+#endif
+
+#define BACKAUTO 		/* stack grows negatively for automatics */
+#define BACKTEMP 		/* stack grows negatively for temporaries */
+
+#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 */
+
+#define FINDMOPS	/* i386 has instructions that modifies memory */
+
+/* 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) == LONG || \
+	(t) == ULONG || (t) == LONGLONG || (t) == ULONGLONG) ? 2 : \
+	(t) == LDOUBLE ? 4 : 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	RAX	020
+#define	RDX	021
+#define	RCX	022
+#define	RBX	023
+#define	RSI	024
+#define	RDI	025
+#define	RBP	026
+#define	RSP	027
+#define	R08	030
+#define	R09	031
+#define	R10	032
+#define	R11	033
+#define	R12	034
+#define	R13	035
+#define	R14	036
+#define	R15	037
+
+/* The 8 math registers in class D lacks names */
+
+#define	MAXREGS	050	/* 40 registers */
+
+#define	RSTATUS	\
+	SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG,	\
+	SAREG|TEMPREG, SAREG|TEMPREG, 0, 0,	 			\
+	SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,		\
+	SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, 0, 0,			\
+	SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG,	\
+	SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, 	\
+	SDREG, SDREG, SDREG, SDREG,  SDREG, SDREG, SDREG, SDREG,
+
+#define	ROVERLAP \
+	/* 8 basic registers */\
+	{ AL, AH, RAX, -1 },\
+	{ DL, DH, RDX, -1 },\
+	{ CL, CH, RCX, -1 },\
+	{ BL, BH, RBX, -1 },\
+	{ RSI, -1 },\
+	{ RDI, -1 },\
+	{ RBP, -1 },\
+	{ RSP, -1 },\
+\
+	/* 8 char registers */\
+	{ EAX, RAX, -1 },\
+	{ EAX, RAX, -1 },\
+	{ EDX, RDX, -1 },\
+	{ EDX, RDX, -1 },\
+	{ ECX, RCX, -1 },\
+	{ ECX, RCX, -1 },\
+	{ EBX, RBX, -1 },\
+	{ EBX, RBX, -1 },\
+\
+	/* 16 long-long-emulating registers */\
+	{ EAX, AL, AH, -1 },\
+	{ EDX, DL, DH, -1 },\
+	{ ECX, CL, CH, -1 },\
+	{ EBX, BL, BH, -1 },\
+	{ ESI, -1 },\
+	{ EDI, -1 },\
+	{ EBP, -1 },\
+	{ ESP, -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -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 == LONG || p->n_type == ULONG || \
+		   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 < 32 ? CLASSC : CLASSD)
+#define DECRA(x,y)	(((x) >> (y*8)) & 255)	/* decode encoded regs */
+#define	ENCRD(x)	(x)		/* Encode dest reg in n_reg */
+#define ENCRA1(x)	((x) << 8)	/* A1 */
+#define ENCRA2(x)	((x) << 16)	/* A2 */
+#define ENCRA(x,y)	((x) << (8+y*8))	/* encode regs in int */
+/* XXX - return char in al? */
+#define	RETREG(x)	(x == CHAR || x == UCHAR ? AL : \
+			 x == LONG || x == ULONG || \
+			 x == LONGLONG || x == ULONGLONG ? RAX : \
+			 x == FLOAT || x == DOUBLE || x == LDOUBLE ? 32 : EAX)
+
+//#define R2REGS	1	/* permit double indexing */
+
+/* XXX - to die */
+#define FPREG	RBP	/* frame pointer */
+#define STKREG	RSP	/* stack pointer */
+
+#define	SHSTR		(MAXSPECIAL+1)	/* short struct */
+#define	SFUNCALL	(MAXSPECIAL+2)	/* struct assign after function call */
+#define	SPCON		(MAXSPECIAL+3)	/* positive nonnamed constant */
+
+/*
+ * Specials that indicate the applicability of machine idioms.
+ */
+#define SMIXOR		(MAXSPECIAL+4)
+#define SMILWXOR	(MAXSPECIAL+5)
+#define SMIHWXOR	(MAXSPECIAL+6)
+
+/*
+ * i386-specific symbol table flags.
+ */
+#define	SSECTION	SLOCAL1
+#define	STLS		SLOCAL2
+#define	SNOUNDERSCORE	SLOCAL3
+#define SSTDCALL	SLOCAL2	
+#define SDLLINDIRECT	SLOCAL3
+
+/*
+ * i386-specific node flags.
+ */
+#define FSTDCALL	0x01
+
+/*
+ * i386-specific interpass stuff.
+ */
+
+#define TARGET_IPP_MEMBERS			\
+	int ipp_argstacksize;
+
+/*
+ * Extended assembler macros.
+ */
+void targarg(char *w, void *arg);
+#define	XASM_TARGARG(w, ary)	\
+	(w[1] == 'b' || w[1] == 'h' || w[1] == 'w' || w[1] == 'k' ? \
+	w++, targarg(w, ary), 1 : 0)
+int numconv(void *ip, void *p, void *q);
+#define	XASM_NUMCONV(ip, p, q)	numconv(ip, p, q)
+
+/*
+ * builtins.
+ */
+#define TARGET_BUILTINS							\
+	{ "__builtin_frame_address", i386_builtin_frame_address },	\
+	{ "__builtin_return_address", i386_builtin_return_address },
+
+#define NODE struct node
+struct node;
+NODE *i386_builtin_frame_address(NODE *f, NODE *a);
+NODE *i386_builtin_return_address(NODE *f, NODE *a);
+#undef NODE
--- /dev/null
+++ usr.bin/pcc/amd64/table.c
@@ -0,0 +1,1568 @@
+/*	$Id: table.c,v 1.1 2008/11/27 05:25:15 mickey Exp $	*/
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * 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 TLONG|TULONG|TLONGLONG|TULONGLONG
+# define ANYSIGNED TINT|TSHORT|TCHAR
+# define ANYUSIGNED TUNSIGNED|TUSHORT|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TUWORD TUNSIGNED
+# define TSWORD TINT
+# 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 pointer to (u)longlong. */
+{ SCONV,	INLL,
+	SHLL,	TLL|TPOINT,
+	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 and ints. */
+{ SCONV,	ININT,
+	SHINT,	TPOINT|TWORD,
+	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,
+		NCREG|NCSL,	RESC1,
+		"	movsbq AL,A1\n", },
+
+/* convert unsigned char to (u)long long */
+{ SCONV,	INLL,
+	SHCH|SOREG|SNAME,	TUCHAR,
+	SANY,			TLL,
+		NCREG|NCSL,	RESC1,
+		"	movzbq AL,A1\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"	/* XXX fpconv */
+		"	fildl (%rsp)\n	addl $8,%rsp\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"	/* XXX fpconv */
+		"	fildl (%rsp)\n	addl $8,%rsp\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,
+		NCREG|NCSL,	RESC1,
+		"	movswq AL,A1\n", },
+
+/* convert unsigned short to (u)long long */
+{ SCONV,	INLL,
+	SAREG|SOREG|SNAME,	TUSHORT,
+	SHLL,			TLL,
+		NCREG|NCSL,	RESC1,
+		"	movzwq AL,A1\n", },
+
+/* convert short (in memory) to float/double */
+{ SCONV,	INFL,
+	SOREG|SNAME,	TSHORT,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NDREG,	RESC1,
+		"	fild AL\n", },	/* XXX fpconv */
+
+/* convert short (in register) to float/double */
+{ SCONV,	INFL,
+	SAREG,	TSHORT,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NTEMP|NDREG,	RESC1,	/* XXX fpconv */
+		"	pushw AL\n	fild (%rsp)\n	addl $8,%rsp\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"	/* XXX fpconv */
+		"	fildl (%rsp)\n	addl $8,%esp\n", },
+
+/* int to something */
+
+/* convert int to char. This is done when register is loaded */
+{ SCONV,	INCH,
+	SAREG,	TWORD|TPOINT,
+	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 signed int to (u)long long */
+{ SCONV,	INLL,
+	SHINT,	TSWORD,
+	SHLL,	TLL,
+		NSPECIAL|NCREG|NCSL,	RESC1,
+		"	cltd\n", },
+
+/* convert unsigned int to (u)long long */
+{ SCONV,	INLL,
+	SHINT|SOREG|SNAME,	TUWORD|TPOINT,
+	SHLL,	TLL,
+		NCSL|NCREG,	RESC1,
+		"	movzlq AL,A1\n\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,	/* XXX fpconv */
+		"	pushl AL\n	fildl (%esp)\n	addl $8,%esp\n", },
+
+/* long long to something */
+
+/* convert (u)long long to (u)char (mem->reg) */
+{ SCONV,	INCH,
+	SOREG|SNAME,	TLL,
+	SANY,	TCHAR|TUCHAR,
+		NBREG|NBSL,	RESC1,
+		"	movb AL,A1\n", },
+
+/* convert (u)long long to (u)char (reg->reg, hopefully nothing) */
+{ SCONV,	INCH,
+	SHLL,	TLL,
+	SANY,	TCHAR|TUCHAR,
+		NBREG|NBSL,	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,	/* XXX fpconv */
+		"	fildq AL\n", },
+
+/* convert long long (in register) to floating */
+{ SCONV,	INFL,
+	SHLL,	TLONGLONG,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NTEMP|NDREG,	RESC1,	/* XXX fpconv */
+		"	pushq AL\n\n"
+		"	fildq (%esp)\n	addl $8,%esp\n", },
+
+/* convert unsigned long long to floating */
+{ SCONV,	INFL,
+	SCREG,	TULONGLONG,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NDREG,	RESC1,	/* XXX fpconv */
+		"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,	/* XXX fpconv */
+		"	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,	/* XXX fpconv */
+		"	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,	/* XXX fpconv */
+#ifdef notdef	/* Must round down and nothing else */
+		"	subl $4,%esp\n	fistpl (%esp)\n	popl A1\n", },
+#else
+		"	subl $12,%esp\n"
+		"	fnstcw (%esp)\n"
+		"	fnstcw 4(%esp)\n"
+		"	movb $12,1(%esp)\n"
+		"	fldcw (%esp)\n"
+		"	fistpl 8(%esp)\n"
+		"	movl 8(%esp),A1\n"
+		"	fldcw 4(%esp)\n"
+		"	addl $12,%esp\n", },
+#endif
+
+/* 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,	/* XXX fpconv */
+#ifdef notdef	/* Must round down and nothing else */
+		"	subl $8,%esp\n	fistpq (%esp)\n"
+		"	popl A1\n	popl U1\n", },
+#else
+		"	subl $16,%esp\n"
+		"	fnstcw (%esp)\n"
+		"	fnstcw 4(%esp)\n"
+		"	movb $12,1(%esp)\n"
+		"	fldcw (%esp)\n"
+		"	fistpq 8(%esp)\n"
+		"	movl 8(%esp),A1\n"
+		"	movl 12(%esp),U1\n"
+		"	fldcw 4(%esp)\n"
+		"	addl $16,%esp\n", },
+#endif
+
+/* 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,	TSHORT|TUSHORT|TWORD|TPOINT,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	call CL\nZC", },
+
+{ UCALL,	INAREG,
+	SCON,	TANY,
+	SAREG,	TSHORT|TUSHORT|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,
+		"	call CL\nZC", },
+
+{ USTCALL,	INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	call CL\nZC", },
+
+{ USTCALL,	INAREG,
+	SNAME|SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ STCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	0,
+		"	call CL\nZC", },
+
+{ STCALL,	INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	call CL\nZC", },
+
+{ STCALL,	INAREG,
+	SNAME|SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+{ 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,		INLL|FOREFF,
+	SHLL|SNAME|SOREG,	TLL|TPOINT,
+	SONE,	TANY,
+		0,	RLEFT,
+		"	incq AL\n", },
+
+{ PLUS,		INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TWORD,
+	SONE,	TANY,
+		0,	RLEFT,
+		"	incl AL\n", },
+
+{ PLUS,		INLL,
+	SCREG,	TLL|TPOINT,
+	SCON,	TWORD,
+		NCREG|NCSL,	RESC1,
+		"	leaq CR(AL),A1\n", },
+
+{ PLUS,		INAREG,
+	SAREG,	TWORD,
+	SCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	leal CR(AL),A1\n", },
+
+{ PLUS,		INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SONE,	TANY,
+		0,	RLEFT,
+		"	incw AL\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,	INLL|FOREFF,
+	SCREG|SNAME|SOREG,	TLL|TPOINT,
+	SONE,			TANY,
+		0,	RLEFT,
+		"	decq AL\n", },
+
+{ MINUS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TWORD,
+	SONE,			TANY,
+		0,	RLEFT,
+		"	decl AL\n", },
+
+{ MINUS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SONE,			TANY,
+		0,	RLEFT,
+		"	decw 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,	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 */
+/* m/r |= r */
+{ OPSIMP,	INLL|FOREFF|FORCC,
+	SHLL|SNAME|SOREG,	TLL|TPOINT,
+	SHLL,			TLL|TPOINT,
+		0,	RLEFT|RESCC,
+		"	Oq AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,	INLL|FOREFF|FORCC,
+	SHLL,			TLL|TPOINT,
+	SHLL|SNAME|SOREG,	TLL|TPOINT,
+		0,	RLEFT|RESCC,
+		"	Oq AR,AL\n", },
+
+/* m/r |= r */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SAREG|SNAME|SOREG,	TWORD,
+	SAREG,			TWORD,
+		0,	RLEFT|RESCC,
+		"	Ol AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SAREG,			TWORD|TPOINT,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+		0,	RLEFT|RESCC,
+		"	Ol AR,AL\n", },
+
+/* m/r |= r */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SHINT|SNAME|SOREG,	TSHORT|TUSHORT,
+	SHINT,		TSHORT|TUSHORT,
+		0,	RLEFT|RESCC,
+		"	Ow AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SHINT,		TSHORT|TUSHORT,
+	SHINT|SNAME|SOREG,	TSHORT|TUSHORT,
+		0,	RLEFT|RESCC,
+		"	Ow AR,AL\n", },
+
+/* m/r |= r */
+{ OPSIMP,	INCH|FOREFF|FORCC,
+	SHCH,		TCHAR|TUCHAR,
+	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
+		0,	RLEFT|RESCC,
+		"	Ob AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,	INCH|FOREFF|FORCC,
+	SHCH,		TCHAR|TUCHAR,
+	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
+		0,	RLEFT|RESCC,
+		"	Ob AR,AL\n", },
+
+/* m/r |= const */
+{ OPSIMP,	INLL|FOREFF|FORCC,
+	SCREG|SNAME|SOREG,	TLL,
+	SCON,	TWORD,
+		0,	RLEFT|RESCC,
+		"	Oq AR,AL\n", },
+
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SAREG|SNAME|SOREG,	TWORD,
+	SCON,	TWORD,
+		0,	RLEFT|RESCC,
+		"	Ol AR,AL\n", },
+
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SHINT|SNAME|SOREG,	TSHORT|TUSHORT,
+	SCON,	TANY,
+		0,	RLEFT|RESCC,
+		"	Ow AR,AL\n", },
+
+{ OPSIMP,	INCH|FOREFF|FORCC,
+	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
+	SCON,	TANY,
+		0,	RLEFT|RESCC,
+		"	Ob AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,	INLL|FOREFF,
+	SHLL,	TLL|TPOINT,
+	SHLL|SNAME|SOREG,	TLL|TPOINT,
+		0,	RLEFT,
+		"	Oq AR,AL\n", },
+
+/*
+ * The next rules handle all shift operators.
+ */
+/* r/m <<= r */
+{ LS,	INLL|FOREFF,
+	SHLL|SNAME|SOREG,	TLL,
+	SHLL,		TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	salq AR,AL\n", },
+
+/* r/m <<= const */
+{ LS,	INLL|FOREFF,
+	SHLL|SNAME|SOREG,	TLL,
+	SCON,	TANY,
+		0,	RLEFT,
+		"	salq AR,AL\n", },
+
+/* r/m <<= r */
+{ LS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TWORD,
+	SHCH,		TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	sall AR,AL\n", },
+
+/* r/m <<= const */
+{ LS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TWORD,
+	SCON,	TANY,
+		0,	RLEFT,
+		"	sall AR,AL\n", },
+
+/* r/m <<= r */
+{ LS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	shlw AR,AL\n", },
+
+/* r/m <<= const */
+{ 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", },
+
+{ RS,	INLL|FOREFF,
+	SHLL|SNAME|SOREG,	TLONG|TLONGLONG,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	sarq AR,AL\n", },
+
+{ RS,	INLL|FOREFF,
+	SHLL|SNAME|SOREG,	TLONG|TLONGLONG,
+	SCON,			TANY,
+		0,		RLEFT,
+		"	sarq AR,AL\n", },
+
+{ RS,	INLL|FOREFF,
+	SHLL|SNAME|SOREG,	TULONG|TULONGLONG,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	shrq AR,AL\n", },
+
+{ RS,	INLL|FOREFF,
+	SHLL|SNAME|SOREG,	TULONG|TULONGLONG,
+	SCON,			TANY,
+		0,		RLEFT,
+		"	shrq AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSWORD,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	sarl AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSWORD,
+	SCON,			TANY,
+		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,			TANY,
+		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,	FORCC|FOREFF|INLL,
+	SHLL,		TLL|TPOINT,
+	SMIXOR,		TANY,
+		0,	RDEST,
+		"	xorq AL,AL\n\n", },
+
+{ ASSIGN,	FOREFF|INLL,
+	SHLL,		TLL|TPOINT,
+	SCON,		TANY,
+		0,	RDEST,
+		"	movabs AR,AL\n", },
+
+{ ASSIGN,	FORCC|FOREFF|INAREG,
+	SAREG,		TWORD,
+	SMIXOR,		TANY,
+		0,	RDEST,
+		"	xorl AL,AL\n", },
+
+{ ASSIGN,	FOREFF,
+	SAREG|SNAME|SOREG,	TWORD,
+	SCON,		TANY,
+		0,	0,
+		"	movl AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TWORD,
+	SCON,		TANY,
+		0,	RDEST,
+		"	movl AR,AL\n", },
+
+{ ASSIGN,	FORCC|FOREFF|INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SMIXOR,		TANY,
+		0,	RDEST,
+		"	xorw AL,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,
+		"	movq AR,AL\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,
+		NAREG|NBREG,	RDEST,
+		"	movb AR,A2\n"
+		"	movzbl A2,A1\n"
+		"	andl $N,AL\n"
+		"	sall $H,A1\n"
+		"	andl $M,A1\n"
+		"	orl A1,AL\n"
+		"F	movb AR,AD\n"
+		"FZE", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,		TSHORT|TUSHORT,
+	SAREG|SCON,	TSHORT|TUSHORT,
+		NAREG,	RDEST,
+		"	movw AR,A1\n"
+		"	movzwl A1,ZN\n"
+		"	andl $N,AL\n"
+		"	sall $H,ZN\n"
+		"	andl $M,ZN\n"
+		"	orl ZN,AL\n"
+		"F	movw AR,AD\n"
+		"FZE", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,		TWORD,
+	SAREG|SNAME|SOREG|SCON,	TWORD,
+		NAREG,	RDEST,
+		"	movl AR,A1\n"
+		"	andl $N,AL\n"
+		"	sall $H,A1\n"
+		"	andl $M,A1\n"
+		"	orl A1,AL\n"
+		"F	movl AR,AD\n"
+		"FZE", },
+
+{ 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,
+		"	fst 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 
+ */
+{ DIV,	INLL,
+	SCREG,			TLONG|TLONGLONG,
+	SCREG|SNAME|SOREG,	TLL,
+		NSPECIAL,	RDEST,
+		"	cltd\n	idivq AR\n", },
+
+{ DIV,	INAREG,
+	SAREG,			TULONG|TULONGLONG|TPOINT,
+	SAREG|SNAME|SOREG,	TULONG|TULONGLONG|TPOINT,
+		NSPECIAL,	RDEST,
+		"	xorq %rdx,%rdx\n	divq AR\n", },
+
+{ DIV,	INAREG,
+	SAREG,			TSWORD,
+	SAREG|SNAME|SOREG,	TWORD,
+		NSPECIAL,	RDEST,
+		"	cltd\n	idivl AR\n", },
+
+{ DIV,	INAREG,
+	SAREG,			TUWORD,
+	SAREG|SNAME|SOREG,	TUWORD,
+		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", },
+
+{ MOD,	INLL,
+	SCREG,			TLONG|TLONGLONG,
+	SCREG|SNAME|SOREG,	TLONG|TLONGLONG,
+		NCREG|NSPECIAL,	RESC1,
+		"	cltd\n	idivq AR\n", },
+
+{ MOD,	INLL,
+	SCREG,			TLL|TPOINT,
+	SCREG|SNAME|SOREG,	TULONG|TULONGLONG|TPOINT,
+		NCREG|NSPECIAL,	RESC1,
+		"	xorq %rdx,%rdx\n	divq AR\n", },
+
+{ MOD,	INAREG,
+	SAREG,			TSWORD,
+	SAREG|SNAME|SOREG,	TSWORD,
+		NAREG|NSPECIAL,	RESC1,
+		"	cltd\n	idivl AR\n", },
+
+{ MOD,	INAREG,
+	SAREG,			TWORD,
+	SAREG|SNAME|SOREG,	TUWORD,
+		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", },
+
+{ MUL,	INLL,
+	SCREG,				TLL|TPOINT,
+	SCREG|SNAME|SOREG|SCON,		TLL|TPOINT,
+		0,	RLEFT,
+		"	imulq AR,AL\n", },
+
+{ MUL,	INAREG,
+	SAREG,				TWORD,
+	SAREG|SNAME|SOREG|SCON,		TWORD,
+		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|TPOINT,
+		NCREG,	RESC1,
+		"	movq AL,A1\n", },
+
+{ UMUL,	INAREG,
+	SANY,	TWORD,
+	SOREG,	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,
+	SCON,	TWORD,
+	SHLL|SOREG|SNAME,	TLL|TPOINT,
+		0, 	RESCC,
+		"	cmpq AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SHLL,	TLL|TPOINT,
+	SHLL|SOREG|SNAME,	TLL|TPOINT,
+		0, 	RESCC,
+		"	cmpq AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SHLL|SOREG|SNAME,	TLL|TPOINT,
+	SHLL,			TLL|TPOINT,
+		0,	RESCC,
+		"	cmpq AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME,	TWORD,
+	SCON|SAREG,	TWORD,
+		0, 	RESCC,
+		"	cmpl AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SCON|SAREG,	TWORD,
+	SAREG|SOREG|SNAME,	TWORD,
+		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,
+	SCREG|SOREG|SNAME,	TLL,
+	SCON,			TWORD,
+		0,	RLEFT,
+		"	andq AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,
+	SCREG|SOREG|SNAME,	TLL,
+	SCREG,			TLL,
+		0,	RLEFT,
+		"	andq AR,AL\n", },
+
+{ AND,	INCREG|FOREFF,
+	SCREG,			TLL,
+	SCREG|SOREG|SNAME,	TLL,
+		0,	RLEFT,
+		"	andq AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,
+	SAREG|SOREG|SNAME,	TWORD,
+	SCON|SAREG,		TWORD,
+		0,	RLEFT,
+		"	andl AR,AL\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", },
+
+#if defined(GCC_COMPAT) || defined(LANG_F77)
+{ GOTO, 	FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	jmp *AL\n", },
+#endif
+
+/*
+ * Convert LTYPE to reg.
+ */
+{ OPLTYPE,	FORCC|INLL,
+	SCREG,	TLL|TPOINT,
+	SMIXOR,	TANY,
+		NCREG,	RESC1,
+		"	xorq A1,A1\n", },
+
+{ OPLTYPE,	INLL,
+	SANY,	TANY,
+	SCREG|SCON|SOREG|SNAME,	TLL|TPOINT,
+		NCREG,	RESC1,
+		"	movq AL,A1\n", },
+
+{ OPLTYPE,	FORCC|INAREG,
+	SAREG,	TWORD,
+	SMIXOR,	TANY,
+		NAREG|NASL,	RESC1,
+		"	xorl A1,A1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SAREG|SCON|SOREG|SNAME,	TWORD,
+		NAREG|NASL,	RESC1,
+		"	movl AL,A1\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SBREG|SOREG|SNAME|SCON,	TCHAR|TUCHAR,
+		NBREG,	RESC1,
+		"	movb AL,A1\n", },
+
+{ OPLTYPE,	FORCC|INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SMIXOR,	TANY,
+		NAREG,	RESC1,
+		"	xorw A1,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|TPOINT,
+	SCREG,	TLL|TPOINT,
+		0,	RLEFT,
+		"	negq AL\n", },
+
+{ UMINUS,	INAREG|FOREFF,
+	SAREG,	TWORD,
+	SAREG,	TWORD,
+		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,
+		"	notq AL\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", },
+
+# 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/amd64/local2.c
@@ -0,0 +1,1163 @@
+/*	$Id: local2.c,v 1.1 2008/11/27 05:25:15 mickey Exp $	*/
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * 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>
+
+static int stkpos;
+
+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)
+{
+	static int lwnr;
+	int i;
+
+	printf("	pushl %%ebp\n");
+	printf("	movl %%esp,%%ebp\n");
+	if (addto)
+		printf("	subl $%d,%%esp\n", addto);
+	for (i = 0; i < MAXREGS; i++)
+		if (TESTBIT(ipp->ipp_regs, i))
+			fprintf(stdout, "	movl %s,-%d(%s)\n",
+			    rnames[i], regoff[i], rnames[FPREG]);
+	if (kflag == 0)
+		return;
+
+	/* if ebx are not saved to stack, it must be moved into another reg */
+	/* check and emit the move before GOT stuff */
+	if (!TESTBIT(ipp->ipp_regs, EBX)) {
+		struct interpass *ip = (struct interpass *)ipp;
+
+		ip = DLIST_PREV(ip, qelem);
+		ip = DLIST_PREV(ip, qelem);
+		ip = DLIST_PREV(ip, qelem);
+		if (ip->type != IP_NODE || ip->ip_node->n_op != ASSIGN ||
+		    ip->ip_node->n_left->n_op != REG)
+			comperr("prtprolog pic error");
+		ip = (struct interpass *)ipp;
+		ip = DLIST_NEXT(ip, qelem);
+		if (ip->type != IP_NODE || ip->ip_node->n_op != ASSIGN ||
+		    ip->ip_node->n_left->n_op != REG)
+			comperr("prtprolog pic error2");
+		printf("	movl %s,%s\n",
+		    rnames[ip->ip_node->n_right->n_rval],
+		    rnames[ip->ip_node->n_left->n_rval]);
+		tfree(ip->ip_node);
+		DLIST_REMOVE(ip, qelem);
+	}
+	printf("	call .LW%d\n", ++lwnr);
+	printf(".LW%d:\n", lwnr);
+	printf("	popl %%ebx\n");
+	printf("	addl $_GLOBAL_OFFSET_TABLE_+[.-.LW%d], %%ebx\n", lwnr);
+}
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog *ipp)
+{
+	int i, addto;
+
+	addto = p2maxautooff;
+	if (addto >= AUTOINIT/SZCHAR)
+		addto -= AUTOINIT/SZCHAR;
+	for (i = 0; i < MAXREGS; i++)
+		if (TESTBIT(ipp->ipp_regs, i)) {
+			addto += SZINT/SZCHAR;
+			regoff[i] = addto;
+		}
+	return addto;
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+	int addto;
+
+	ftype = ipp->ipp_type;
+
+#ifdef LANG_F77
+	if (ipp->ipp_vis)
+		printf("	.globl %s\n", ipp->ipp_name);
+	printf("	.align 4\n");
+	printf("%s:\n", ipp->ipp_name);
+#endif
+	/*
+	 * 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;
+
+	if (ipp->ipp_ip.ip_lbl == 0)
+		return; /* no code needs to be generated */
+
+	/* return from function code */
+	for (i = 0; i < MAXREGS; i++)
+		if (TESTBIT(ipp->ipp_regs, i))
+			fprintf(stdout, "	movl -%d(%s),%s\n",
+			    regoff[i], rnames[FPREG], rnames[i]);
+
+	/* struct return needs special treatment */
+	if (ftype == STRTY || ftype == UNIONTY) {
+		printf("	movl 8(%%ebp),%%eax\n");
+		printf("	leave\n");
+		printf("	ret $%d\n", 4);
+	} else {
+		printf("	leave\n");
+	}
+	printf("\t.size %s,.-%s\n", ipp->ipp_name,
+	    ipp->ipp_name);
+}
+
+/*
+ * 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:
+			return(SZINT/SZCHAR);
+
+		case LONG:
+		case ULONG:
+		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);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+	CONSZ val;
+
+	if (p->n_op == ASSIGN)
+		p = p->n_left;
+	switch (**cp) {
+	case 'S':
+		printf("%d", UPKFSZ(p->n_rval));
+		break;
+	case 'H':
+		printf("%d", UPKFOFF(p->n_rval));
+		break;
+	case 'M':
+	case 'N':
+		val = (CONSZ)1 << UPKFSZ(p->n_rval);
+		--val;
+		val <<= UPKFOFF(p->n_rval);
+		printf("0x%llx", (**cp == 'M' ? val : ~val) & 0xffffffff);
+		break;
+	default:
+		comperr("fldexpand");
+	}
+	return 1;
+}
+
+static void
+bfext(NODE *p)
+{
+	int ch = 0, sz = 0;
+
+	if (ISUNSIGNED(p->n_right->n_type))
+		return;
+	switch (p->n_right->n_type) {
+	case CHAR:
+		ch = 'b';
+		sz = 8;
+		break;
+	case SHORT:
+		ch = 'w';
+		sz = 16;
+		break;
+	case INT:
+		ch = 'l';
+		sz = 32;
+		break;
+	case LONG:
+		ch = 'q';
+		sz = 64;
+		break;
+	default:
+		comperr("bfext");
+	}
+
+	sz -= UPKFSZ(p->n_left->n_rval);
+	printf("\tshl%c $%d,", ch, sz);
+	adrput(stdout, getlr(p, 'D'));
+	printf("\n\tsar%c $%d,", ch, sz);
+	adrput(stdout, getlr(p, 'D'));
+	printf("\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 < LONG || t == FLOAT || t > BTMASK)
+		return 4;
+	if (t == LONG || t == ULONG || t == LONGLONG || t == ULONGLONG ||
+	    t == DOUBLE)
+		return 8;
+	if (t == LDOUBLE)
+		return 16;
+	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 */
+		if (p->n_left->n_flags & FSTDCALL)
+			break;
+		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 'E': /* Perform bitfield sign-extension */
+		bfext(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 '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(%%rbp)\n", rnames[lr][1], s);
+			printf("\tmovb %d(%%rbp),%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);
+			comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]);
+			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]);
+			comperr("SCONV3 %s->%s", rnames[lr], rnames[pr]);
+			break;
+
+		default:
+			if (rnames[lr][1] == rnames[pr][2] &&
+			    rnames[lr][2] == rnames[pr][3])
+				break;
+			comperr("SCONV4 %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, SOREG)))
+		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, SOREG))
+		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_name[0])
+			printf("%s%s", p->n_name, p->n_lval ? "+" : "");
+		if (p->n_lval)
+			fprintf(io, "%d", (int)p->n_lval);
+		if (R2TEST(r)) {
+			fprintf(io, "(%s,%s,8)", rnames[R2UPK1(r)],
+			    rnames[R2UPK2(r)]);
+		} else
+			fprintf(io, "(%s)", rnames[p->n_rval]);
+		return;
+	case ICON:
+#ifdef PCC_DEBUG
+		/* Sanitycheck for PIC, to catch adressable constants */
+		if (kflag && p->n_name[0]) {
+			static int foo;
+
+			if (foo++ == 0) {
+				printf("\nfailing...\n");
+				fwalk(p, e2print, 0);
+				comperr("pass2 conput");
+			}
+		}
+#endif
+		/* addressable value of the constant */
+		fputc('$', io);
+		conput(io, p);
+		return;
+
+	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, void *arg)
+{
+	/* 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, 0);
+		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, void *arg)
+{
+	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, 0);
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+	int sl, sh, dl, dh;
+
+	switch (t) {
+	case LONG:
+	case ULONG:
+	case LONGLONG:
+	case ULONGLONG:
+		printf("	movq %s,%s\n", rnames[s], rnames[d]);
+		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",
+	"%rax", "%rdx", "%rcx", "%rbx", "%rsi", "%rdi", "%rbp", "%rsp",
+	"%r08", "%r09", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+	"%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 == LONG || t == ULONG || 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);
+	if (kflag)
+		size -= 4;
+	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;
+	case SMIXOR:
+		return tshape(p, SZERO);
+	case SMILWXOR:
+		if (o != ICON || p->n_name[0] ||
+		    p->n_lval == 0 || p->n_lval & 0xffffffff)
+			break;
+		return SRDIR;
+	case SMIHWXOR:
+		if (o != ICON || p->n_name[0] ||
+		     p->n_lval == 0 || (p->n_lval >> 32) != 0)
+			break;
+		return SRDIR;
+	}
+	return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+
+/*
+ * Do something target-dependent for xasm arguments.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+	struct interpass *ip2;
+	NODE *in = 0, *ut = 0;
+	TWORD t;
+	char *w;
+	int reg;
+	int cw;
+
+	cw = xasmcode(p->n_name);
+	if (cw & (XASMASG|XASMINOUT))
+		ut = p->n_left;
+	if ((cw & XASMASG) == 0)
+		in = p->n_left;
+
+	switch (XASMVAL(cw)) {
+	case 'D': reg = EDI; break;
+	case 'S': reg = ESI; break;
+	case 'a': reg = EAX; break;
+	case 'b': reg = EBX; break;
+	case 'c': reg = ECX; break;
+	case 'd': reg = EDX; break;
+	case 't': reg = 0; break;
+	case 'u': reg = 1; break;
+	case 'A': reg = EAXEDX; break;
+	case 'q': /* XXX let it be CLASSA as for now */
+		p->n_name = tmpstrdup(p->n_name);
+		w = strchr(p->n_name, 'q');
+		*w = 'r';
+		return 0;
+	default:
+		return 0;
+	}
+	p->n_name = tmpstrdup(p->n_name);
+	for (w = p->n_name; *w; w++)
+		;
+	w[-1] = 'r'; /* now reg */
+	t = p->n_left->n_type;
+	if (reg == EAXEDX) {
+		p->n_label = CLASSC;
+	} else {
+		p->n_label = CLASSA;
+		if (t == CHAR || t == UCHAR) {
+			p->n_label = CLASSB;
+			reg = reg * 2 + 8;
+		}
+	}
+	if (t == FLOAT || t == DOUBLE || t == LDOUBLE) {
+		p->n_label = CLASSD;
+		reg += 037;
+	}
+
+	if (in && ut)
+		in = tcopy(in);
+	p->n_left = mklnode(REG, 0, reg, t);
+	if (ut) {
+		ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
+		DLIST_INSERT_AFTER(ip, ip2, qelem);
+	}
+	if (in) {
+		ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
+		DLIST_INSERT_BEFORE(ip, ip2, qelem);
+	}
+	return 1;
+}
+
+void
+targarg(char *w, void *arg)
+{
+	NODE **ary = arg;
+	NODE *p, *q;
+
+	p = ary[(int)w[1]-'0']->n_left;
+	if (optype(p->n_op) != LTYPE)
+		comperr("bad xarg op %d", p->n_op);
+	q = tcopy(p);
+	if (q->n_op == REG) {
+		if (*w == 'k') {
+			q->n_type = INT;
+		} else if (*w != 'w') {
+			if (q->n_type > UCHAR) {
+				regno(q) = regno(q)*2+8;
+				if (*w == 'h')
+					regno(q)++;
+			}
+			q->n_type = INT;
+		} else
+			q->n_type = SHORT;
+	}
+	adrput(stdout, q);
+	tfree(q);
+}
+
+/*
+ * target-specific conversion of numeric arguments.
+ */
+int
+numconv(void *ip, void *p1, void *q1)
+{
+	NODE *p = p1, *q = q1;
+	int cw = xasmcode(q->n_name);
+
+	switch (XASMVAL(cw)) {
+	case 'a':
+	case 'b':
+	case 'c':
+	case 'd':
+		p->n_name = tmpcalloc(2);
+		p->n_name[0] = XASMVAL(cw);
+		return 1;
+	default:
+		return 0;
+	}
+}
--- /dev/null
+++ usr.bin/pcc/amd64/code.c
@@ -0,0 +1,290 @@
+/*	$Id: code.c,v 1.2 2008/12/10 17:59:30 mickey Exp $	*/
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * 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"
+
+NODE *funarg(NODE *, int *);
+int argreg(TWORD, int *);
+
+int lastloc = -1;
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+	extern char *nextsect;
+	static char *loctbl[] = { "text", "data", "section .rodata" };
+	TWORD t;
+	int s;
+
+	if (sp == NULL) {
+		lastloc = -1;
+		return;
+	}
+	t = sp->stype;
+	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+#ifdef TLS
+	if (sp->sflags & STLS) {
+		if (s != DATA)
+			cerror("non-data symbol in tls section");
+		nextsect = ".tdata";
+	}
+#endif
+	if (nextsect) {
+		printf("	.section %s\n", nextsect);
+		nextsect = NULL;
+		s = -1;
+	} else if (s != lastloc)
+		printf("	.%s\n", loctbl[s]);
+	lastloc = s;
+	while (ISARY(t))
+		t = DECREF(t);
+	if (sp->ssue->suealign > ALCHAR)
+		printf("	.align %d\n", sp->ssue->suealign/ALCHAR);
+	if (sp->sclass == EXTDEF)
+		printf("	.globl %s\n", exname(sp->soname));
+	if (ISFTN(t))
+		printf("\t.type %s, at function\n", exname(sp->soname));
+	if (sp->slevel == 0)
+		printf("%s:\n", exname(sp->soname));
+	else
+		printf(LABFMT ":\n", sp->soffset);
+}
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode()
+{
+	extern int gotnr;
+	NODE *p, *q;
+
+	gotnr = 0;	/* new number for next fun */
+	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+		return;
+	/* Create struct assignment */
+	q = block(OREG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
+	q->n_rval = EBP;
+	q->n_lval = 8; /* return buffer offset */
+	q = buildtree(UMUL, q, NIL);
+	p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
+	p = buildtree(UMUL, p, NIL);
+	p = buildtree(ASSIGN, q, p);
+	ecomp(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 cnt)
+{
+	struct symtab *sp2;
+	extern int gotnr;
+	NODE *n, *p;
+	int i;
+
+	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+		/* Function returns struct, adjust arg offset */
+		for (i = 0; i < cnt; i++) 
+			sp[i]->soffset += SZPOINT(LONG);
+	}
+
+	if (kflag) {
+		/* Put ebx in temporary */
+		n = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+		n->n_rval = EBX;
+		p = tempnode(0, INT, 0, MKSUE(INT));
+		gotnr = regno(p);
+		ecomp(buildtree(ASSIGN, p, n));
+	}
+
+	/* recalculate the arg offset and create TEMP moves */
+	for (n = 0, i = 0; i < cnt; i++) {
+		sp = a[i];
+
+		if (n < 6) {
+			p = tempnode(0, sp->stype, sp->sdf, sp->ssue);
+			q = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->ssue);
+			q->n_rval = argreg(sp->stype, &n);
+			p = buildtree(ASSIGN, p, q);
+			sp->soffset = regno(p->n_left);
+			sp->sflags |= STNODE;
+			ecomp(p);
+		} else {
+			sp->soffset += SZLONG * n;
+			if (xtemps) {
+				/* put stack args in temps if optimizing */
+				p = tempnode(0, sp->stype, sp->sdf, sp->ssue);
+				p = buildtree(ASSIGN, p, buildtree(NAME, 0, 0));
+				sp->soffset = regno(p->n_left);
+				sp->sflags |= STNODE;
+				ecomp(p);
+			}
+		}
+	}
+}
+
+
+/*
+ * 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 )
+{
+	if (errors)
+		return;
+
+#define _MKSTR(x) #x
+#define MKSTR(x) _MKSTR(x)
+#define OS MKSTR(TARGOS)
+        printf("\t.ident \"PCC: %s (%s)\"\n\t.end\n", PACKAGE_STRING, OS);
+}
+
+void
+bjobcode()
+{
+}
+
+static const int argregsi[] = { RDI, RSI, RDX, RCX, R09, R08 };
+
+int
+argreg(TWORD t, int *n)   
+{
+	switch (t) {
+	case FLOAT:
+	case DOUBLE:
+	case LDOUBLE:
+		return FR6 - *n - 2;
+	case LONGLONG:
+	case ULONGLONG:
+		/* TODO */;
+	default:
+		return argregsi[(*n)++];
+	}
+}
+
+NODE *
+funarg(NODE *p, int *n)
+{
+	NODE *r;
+	int sz;
+
+	if (p->n_op == CM) {
+		p->n_left = funarg(p->n_left, n);
+		p->n_right = funarg(p->n_right, n);
+		return p;
+	}
+
+	if (*n >= 6) {
+		*n++;
+		r = block(OREG, NIL, NIL, p->n_type|PTR, 0,
+		    MKSUE(p->n_type|PTR));
+		r->n_rval = RBP;
+		r->n_lval = 16 + (*n - 6) * 8;
+	} else {
+		r = block(REG, NIL, NIL, p->n_type, 0, 0);
+		r->n_lval = 0;
+		r->n_rval = argreg(p->n_type, n);
+	}
+	p = block(ASSIGN, r, p, p->n_type, 0, 0);
+	clocal(p);
+
+	return p;
+}  
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ * Returns p.
+ */
+NODE *
+funcode(NODE *p)
+{
+	extern int gotnr;
+	NODE *r, *l;
+	int n = 0;
+
+	p->n_right = funarg(p->n_right, &n);
+
+	if (kflag == 0)
+		return p;
+	/* Create an ASSIGN node for ebx */
+	l = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+	l->n_rval = EBX;
+	l = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, MKSUE(INT)));
+	if (p->n_right->n_op != CM) {
+		p->n_right = block(CM, l, p->n_right, INT, 0, MKSUE(INT));
+	} else {
+		for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
+			;
+		r->n_left = block(CM, l, r->n_left, INT, 0, MKSUE(INT));
+	}
+	return p;
+}
+
+/*
+ * 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)
+{
+}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+	return 0;
+}
--- /dev/null
+++ usr.bin/pcc/amd64/local.c
@@ -0,0 +1,1117 @@
+/*	$Id: local.c,v 1.2 2008/12/14 21:16:58 ragge Exp $	*/
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * 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 */
+
+/*
+ * Check if a constant is too large for a type.
+ */
+static int
+toolarge(TWORD t, CONSZ con)
+{
+	U_CONSZ ucon = con;
+
+	switch (t) {
+	case ULONG:
+	case LONG:
+	case ULONGLONG:
+	case LONGLONG:
+		break; /* cannot be too large */
+#define	SCHK(i)	case i: if (con > MAX_##i || con < MIN_##i) return 1; break
+#define	UCHK(i)	case i: if (ucon > MAX_##i) return 1; break
+	SCHK(INT);
+	SCHK(SHORT);
+	case BOOL:
+	SCHK(CHAR);
+	UCHK(UNSIGNED);
+	UCHK(USHORT);
+	UCHK(UCHAR);
+	default:
+		cerror("toolarge");
+	}
+	return 0;
+}
+
+#define	IALLOC(sz)	(isinlining ? permalloc(sz) : tmpalloc(sz))
+
+/*
+ * Make a symtab entry for PIC use.
+ */
+static struct symtab *
+picsymtab(char *p, char *s, char *s2)
+{
+	struct symtab *sp = IALLOC(sizeof(struct symtab));
+	size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
+	
+	sp->sname = sp->soname = IALLOC(len);
+	strlcpy(sp->soname, p, len);
+	strlcat(sp->soname, s, len);
+	strlcat(sp->soname, s2, len);
+	sp->sclass = EXTERN;
+	sp->sflags = sp->slevel = 0;
+	return sp;
+}
+
+int gotnr; /* tempnum for GOT register */
+int argstacksize;
+
+/*
+ * Create a reference for an extern variable.
+ */
+static NODE *
+picext(NODE *p)
+{
+	NODE *q, *r;
+	struct symtab *sp;
+
+	q = tempnode(gotnr, PTR|VOID, 0, MKSUE(VOID));
+	sp = picsymtab("", p->n_sp->soname, "@GOT");
+	r = xbcon(0, sp, INT);
+	q = buildtree(PLUS, q, r);
+	q = block(UMUL, q, 0, PTR|VOID, 0, MKSUE(VOID));
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_sue);
+	q->n_sp = p->n_sp; /* for init */
+	nfree(p);
+	return q;
+}
+
+/*
+ * Create a reference for a static variable.
+ */
+static NODE *
+picstatic(NODE *p)
+{
+	NODE *q, *r;
+	struct symtab *sp;
+
+	q = tempnode(gotnr, PTR|VOID, 0, MKSUE(VOID));
+	if (p->n_sp->slevel > 0) {
+		char buf[32];
+		snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset);
+		sp = picsymtab("", buf, "@GOTOFF");
+	} else
+		sp = picsymtab("", p->n_sp->soname, "@GOTOFF");
+	sp->sclass = STATIC;
+	sp->stype = p->n_sp->stype;
+	r = xbcon(0, sp, INT);
+	q = buildtree(PLUS, q, r);
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_sue);
+	q->n_sp = p->n_sp; /* for init */
+	nfree(p);
+	return q;
+}
+
+#ifdef TLS
+/*
+ * Create a reference for a TLS variable.
+ */
+static NODE *
+tlspic(NODE *p)
+{
+	NODE *q, *r;
+	struct symtab *sp, *sp2;
+
+	/*
+	 * creates:
+	 *   leal var at TLSGD(%ebx),%eax
+	 *   call ___tls_get_addr at PLT
+	 */
+
+	/* calc address of var at TLSGD */
+	q = tempnode(gotnr, PTR|VOID, 0, MKSUE(VOID));
+	sp = picsymtab("", p->n_sp->soname, "@TLSGD");
+	r = xbcon(0, sp, INT);
+	q = buildtree(PLUS, q, r);
+
+	/* assign to %eax */
+	r = block(REG, NIL, NIL, PTR|VOID, 0, MKSUE(VOID));
+	r->n_rval = EAX;
+	q = buildtree(ASSIGN, r, q);
+
+	/* call ___tls_get_addr */
+	sp2 = lookup("___tls_get_addr at PLT", 0);
+	sp2->stype = EXTERN|INT|FTN;
+	r = nametree(sp2);
+	r = buildtree(ADDROF, r, NIL);
+	r = block(UCALL, r, NIL, INT, 0, MKSUE(INT));
+
+	/* fusion both parts together */
+	q = buildtree(COMOP, q, r);
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_sue);
+	q->n_sp = p->n_sp; /* for init */
+
+	nfree(p);
+	return q;
+}
+
+static NODE *
+tlsnonpic(NODE *p)
+{
+	NODE *q, *r;
+	struct symtab *sp, *sp2;
+	int ext = p->n_sp->sclass;
+
+	sp = picsymtab("", p->n_sp->soname,
+	    ext == EXTERN ? "@INDNTPOFF" : "@NTPOFF");
+	q = xbcon(0, sp, INT);
+	if (ext == EXTERN)
+		q = block(UMUL, q, NIL, PTR|VOID, 0, MKSUE(VOID));
+
+	sp2 = lookup("%gs:0", 0);
+	sp2->stype = EXTERN|INT;
+	r = nametree(sp2);
+
+	q = buildtree(PLUS, q, r);
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_sue);
+	q->n_sp = p->n_sp; /* for init */
+
+	nfree(p);
+	return q;
+}
+
+static NODE *
+tlsref(NODE *p)
+{
+	if (kflag)
+		return (tlspic(p));
+	else
+		return (tlsnonpic(p));
+}
+#endif
+
+/* 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 USTATIC:
+			if (kflag == 0)
+				break;
+			/* FALLTHROUGH */
+		case STATIC:
+#ifdef TLS
+			if (q->sflags & STLS) {
+				p = tlsref(p);
+				break;
+			}
+#endif
+			if (kflag == 0) {
+				if (q->slevel == 0)
+					break;
+				p->n_lval = 0;
+			} else if (blevel > 0)
+				p = picstatic(p);
+			break;
+
+		case REGISTER:
+			p->n_op = REG;
+			p->n_lval = 0;
+			p->n_rval = q->soffset;
+			break;
+
+		case EXTERN:
+		case EXTDEF:
+#ifdef TLS
+			if (q->sflags & STLS) {
+				p = tlsref(p);
+				break;
+			}
+#endif
+			if (kflag == 0)
+				break;
+			if (blevel > 0)
+				p = picext(p);
+			break;
+		}
+		break;
+
+	case ADDROF:
+		if (kflag == 0 || blevel == 0)
+			break;
+		/* char arrays may end up here */
+		l = p->n_left;
+		if (l->n_op != NAME ||
+		    (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE))
+			break;
+		l = p;
+		p = picstatic(p->n_left);
+		nfree(l);
+		if (p->n_op != UMUL)
+			cerror("ADDROF error");
+		l = p;
+		p = p->n_left;
+		nfree(l);
+		break;
+
+	case UCALL:
+	case USTCALL:
+		if (kflag == 0)
+			break;
+		/* Change to CALL node with ebx as argument */
+		l = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+		l->n_rval = EBX;
+		p->n_right = buildtree(ASSIGN, l,
+		    tempnode(gotnr, INT, 0, MKSUE(INT)));
+		p->n_op -= (UCALL-CALL);
+		break;
+
+	case CBRANCH:
+		l = p->n_left;
+
+		/*
+		 * Remove unnecessary 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;
+				if (ISPTR(r->n_type))
+					break; /* no opt for pointers */
+				if (toolarge(r->n_type, l->n_right->n_lval))
+					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 UNSIGNED:
+				l->n_lval = val & 0xffffffff;
+				break;
+			case INT:
+				l->n_lval = (int)val;
+				break;
+			case LONG:
+			case LONGLONG:
+				l->n_lval = (long long)val;
+				break;
+			case ULONG:
+			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;
+		} else if (l->n_op == FCON) {
+			l->n_lval = l->n_dcon;
+			l->n_sp = NULL;
+			l->n_op = ICON;
+			l->n_type = m;
+			l->n_sue = MKSUE(m);
+			nfree(p);
+			return clocal(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:
+		r = p;
+		p = buildtree(o == PMCONV ? MUL : DIV, p->n_left, p->n_right);
+		nfree(r);
+		break;
+
+	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_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);
+}
+
+/*
+ * Change CALL references to either direct (static) or PLT.
+ */
+static void
+fixnames(NODE *p, void *arg)
+{
+	struct symtab *sp;
+	struct suedef *sue;
+	NODE *q;
+	char *c;
+	int isu;
+
+	if ((cdope(p->n_op) & CALLFLG) == 0)
+		return;
+	isu = 0;
+	q = p->n_left;
+	sue = q->n_sue;
+	if (q->n_op == UMUL)
+		q = q->n_left, isu = 1;
+
+	if (q->n_op == PLUS && q->n_left->n_op == TEMP &&
+	    q->n_right->n_op == ICON) {
+		sp = q->n_right->n_sp;
+
+		if (sp == NULL)
+			return;	/* nothing to do */
+		if (sp->sclass == STATIC && !ISFTN(sp->stype))
+			return; /* function pointer */
+
+		if (sp->sclass != STATIC && sp->sclass != EXTERN &&
+		    sp->sclass != EXTDEF)
+			cerror("fixnames");
+
+		if ((c = strstr(sp->soname, "@GOT")) == NULL)
+			cerror("fixnames2");
+		if (isu) {
+			memcpy(c, "@PLT", sizeof("@PLT"));
+		} else
+			*c = 0;
+
+		nfree(q->n_left);
+		q = q->n_right;
+		if (isu)
+			nfree(p->n_left->n_left);
+		nfree(p->n_left);
+		p->n_left = q;
+		q->n_sue = sue;
+	}
+}
+
+void
+myp2tree(NODE *p)
+{
+	struct symtab *sp;
+
+	if (kflag)
+		walkf(p, fixnames, 0); /* XXX walkf not needed */
+	if (p->n_op != FCON)
+		return;
+
+#if 0
+	/* put floating constants in memory */
+	setloc1(RDATA);
+	defalign(ALLDOUBLE);
+	deflab1(i = getlab());
+	ninval(0, btdims[p->n_type].suesize, p);
+#endif
+
+	sp = IALLOC(sizeof(struct symtab));
+	sp->sclass = STATIC;
+	sp->ssue = MKSUE(p->n_type);
+	sp->slevel = 1; /* fake numeric label */
+	sp->soffset = getlab();
+	sp->sflags = 0;
+	sp->stype = p->n_type;
+	sp->squal = (CON >> TSHIFT);
+
+	defloc(sp);
+	ninval(0, sp->ssue->suesize, p);
+
+	p->n_op = NAME;
+	p->n_lval = 0;
+	p->n_sp = sp;
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+	return(1);	/* all names can have & taken on them */
+}
+
+/*
+ * at the end of the arguments of a ftn, set the automatic offset
+ */
+void
+cendarg()
+{
+	autooff = AUTOINIT;
+}
+
+/*
+ * 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! */
+
+}
+
+/*
+ * Print out a string of characters.
+ * Assume that the assembler understands C-style escape
+ * sequences.
+ */
+void
+instring(struct symtab *sp)
+{
+	char *s, *str = sp->sname;
+
+	defloc(sp);
+
+	/* be kind to assemblers and avoid long strings */
+	printf("\t.ascii \"");
+	for (s = str; *s != 0; ) {
+		if (*s++ == '\\') {
+			(void)esccon(&s);
+		}
+		if (s - str > 60) {
+			fwrite(str, 1, s - str, stdout);
+			printf("\"\n\t.ascii \"");
+			str = s;
+		}
+	}
+	fwrite(str, 1, s - str, stdout);
+	printf("\\0\"\n");
+}
+
+/*
+ * Print out a wide string by calling ninval().
+ */
+void
+inwstring(struct symtab *sp)
+{
+	char *s = sp->sname;
+	NODE *p;
+
+	defloc(sp);
+	p = xbcon(0, NULL, WCHAR_TYPE);
+	do {
+		if (*s++ == '\\')
+			p->n_lval = esccon(&s);
+		else
+			p->n_lval = (unsigned char)s[-1];
+		ninval(0, (MKSUE(WCHAR_TYPE))->suesize, p);
+	} while (s[-1] != 0);
+	nfree(p);
+}
+
+
+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;
+	char *c;
+	TWORD t;
+	int i;
+
+	t = p->n_type;
+	if (t > BTMASK)
+		t = INT; /* pointer */
+
+	while (p->n_op == SCONV || p->n_op == PCONV) {
+		NODE *l = p->n_left;
+		l->n_type = p->n_type;
+		p = l;
+	}
+
+	if (kflag && (p->n_op == PLUS || p->n_op == UMUL)) {
+		if (p->n_op == UMUL)
+			p = p->n_left;
+		p = p->n_right;
+		q = p->n_sp;
+
+		if ((c = strstr(q->soname, "@GOT")) != NULL)
+			*c = 0; /* ignore GOT ref here */
+	}
+	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)) {
+				printf("+" LABFMT, q->soffset);
+			} else {
+				printf("+%s", exname(q->soname));
+			}
+		}
+		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;
+#if defined(HOST_BIG_ENDIAN)
+		/* XXX probably broken on most hosts */
+		printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[2], u.i[1], u.i[0]);
+#else
+		printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+#endif
+		break;
+	case DOUBLE:
+		u.d = (double)p->n_dcon;
+#if defined(HOST_BIG_ENDIAN)
+		printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]);
+#else
+		printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+#endif
+		break;
+	case FLOAT:
+		u.f = (float)p->n_dcon;
+		printf("\t.long\t0x%x\n", u.i[0]);
+		break;
+	default:
+		cerror("ninval");
+	}
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+	return (p == NULL ? "" : p);
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+	switch (BTYPE(type)) {
+	case LONG:
+		MODTYPE(type,LONG);
+		break;
+
+	case ULONG:
+		MODTYPE(type,ULONG);
+
+	}
+	return (type);
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+	int off;
+
+#ifdef TLS
+	if (sp->sflags & STLS) {
+		if (sp->sclass == EXTERN)
+			sp->sclass = EXTDEF;
+		simpleinit(sp, bcon(0));
+		return;
+	}
+#endif
+
+	off = tsize(sp->stype, sp->sdf, sp->ssue);
+	off = (off+(SZCHAR-1))/SZCHAR;
+	printf("	.%scomm ", sp->sclass == STATIC ? "l" : "");
+	if (sp->slevel == 0)
+		printf("%s,0%o\n", exname(sp->soname), off);
+	else
+		printf(LABFMT ",0%o\n", sp->soffset, off);
+}
+
+static char *
+section2string(char *name, int len)
+{
+	char *s;
+	int n;
+
+	if (strncmp(name, "link_set", 8) == 0) {
+		const char *postfix = ",\"aw\", at progbits";
+		n = len + strlen(postfix) + 1;
+		s = IALLOC(n);
+		strlcpy(s, name, n);
+		strlcat(s, postfix, n);
+		return s;
+	}
+
+	return newstring(name, len);
+}
+
+char *nextsect;
+#ifdef TLS
+static int gottls;
+#endif
+static char *alias;
+static int constructor;
+static int destructor;
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char **ary)
+{
+#ifdef TLS
+	if (strcmp(ary[1], "tls") == 0 && ary[2] == NULL) {
+		gottls = 1;
+		return 1;
+	}
+#endif
+	if (strcmp(ary[1], "constructor") == 0 || strcmp(ary[1], "init") == 0) {
+		constructor = 1;
+		return 1;
+	}
+	if (strcmp(ary[1], "destructor") == 0 || strcmp(ary[1], "fini") == 0) {
+		destructor = 1;
+		return 1;
+	}
+	if (strcmp(ary[1], "section") == 0 && ary[2] != NULL) {
+		nextsect = section2string(ary[2], strlen(ary[2]));
+		return 1;
+	}
+	if (strcmp(ary[1], "alias") == 0 && ary[2] != NULL) {
+		alias = tmpstrdup(ary[2]);
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Called when a identifier has been declared.
+ */
+void
+fixdef(struct symtab *sp)
+{
+#ifdef TLS
+	/* may have sanity checks here */
+	if (gottls)
+		sp->sflags |= STLS;
+	gottls = 0;
+#endif
+	if (alias != NULL && (sp->sclass != PARAM)) {
+		printf("\t.globl %s\n", exname(sp->soname));
+		printf("%s = ", exname(sp->soname));
+		printf("%s\n", exname(alias));
+		alias = NULL;
+	}
+	if ((constructor || destructor) && (sp->sclass != PARAM)) {
+		printf("\t.section .%ctors,\"aw\", at progbits\n",
+		    constructor ? 'c' : 'd');
+		printf("\t.p2align 2\n");
+		printf("\t.long %s\n", exname(sp->sname));
+		constructor = destructor = 0;
+	}
+}
+
+NODE *
+i386_builtin_return_address(NODE *f, NODE *a)
+{
+	int nframes;
+
+	if (a == NULL || a->n_op != ICON)
+		goto bad;
+
+	nframes = a->n_lval;
+
+	tfree(f);
+	tfree(a);
+
+	f = block(REG, NIL, NIL, PTR+VOID, 0, MKSUE(VOID));
+	regno(f) = FPREG;
+
+	while (nframes--)
+		f = block(UMUL, f, NIL, PTR+VOID, 0, MKSUE(VOID));
+
+	f = block(PLUS, f, bcon(4), INCREF(PTR+VOID), 0, MKSUE(VOID));
+	f = buildtree(UMUL, f, NIL);
+
+	return f;
+bad:
+        uerror("bad argument to __builtin_return_address");
+        return bcon(0);
+}
+
+NODE *
+i386_builtin_frame_address(NODE *f, NODE *a)
+{
+	int nframes;
+
+	if (a == NULL || a->n_op != ICON)
+		goto bad;
+
+	nframes = a->n_lval;
+
+	tfree(f);
+	tfree(a);
+
+	f = block(REG, NIL, NIL, PTR+VOID, 0, MKSUE(VOID));
+	regno(f) = FPREG;
+
+	while (nframes--)
+		f = block(UMUL, f, NIL, PTR+VOID, 0, MKSUE(VOID));
+
+	return f;
+bad:
+        uerror("bad argument to __builtin_frame_address");
+        return bcon(0);
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
Index: cc.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/cc/cc.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L usr.bin/pcc/cc/cc.c -L usr.bin/pcc/cc/cc.c -u -r1.2 -r1.3
--- usr.bin/pcc/cc/cc.c
+++ usr.bin/pcc/cc/cc.c
@@ -1,4 +1,4 @@
-/*	$Id: cc.c,v 1.61 2007/09/26 14:48:47 ragge Exp $	*/
+/*	$Id: cc.c,v 1.136 2008/12/22 02:04:11 gmcgarry Exp $	*/
 /*
  * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
  *
@@ -47,21 +47,35 @@
  *
  * This file should be rewritten readable.
  */
+#include "config.h"
+
 #include <sys/types.h>
+#ifdef HAVE_SYS_WAIT_H
 #include <sys/wait.h>
+#endif
 
-#include <stdio.h>
 #include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_LIBGEN_H
+#include <libgen.h>
+#endif
 #include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <libgen.h>
-#include <errno.h>
+#endif
+
+#ifdef WIN32
+#include <windows.h>
+#include <process.h>
+#include <io.h>
+#endif
 
-#include "../config.h"
+#include "compat.h"
 
 #include "ccconfig.h"
 /* C command */
@@ -72,34 +86,79 @@
 /*
  * Many specific definitions, should be declared elsewhere.
  */
-#define	STDINC	  "/usr/include/"
 
-#define SBSIZE 10000
-#define MAXINC 100
-#define MAXFIL 100
+#ifndef STDINC
+#define	STDINC	  	"/usr/include/"
+#endif
+
+#ifndef LIBDIR
+#define LIBDIR		"/usr/lib/"
+#endif
+
+#ifndef PREPROCESSOR
+#define PREPROCESSOR	"pcpp"
+#endif
+
+#ifndef COMPILER
+#define COMPILER	"pccom";
+#endif
+
+#ifndef ASSEMBLER
+#define ASSEMBLER	"as"
+#endif
+
+#ifndef LINKER
+#define LINKER		"ld"
+#endif
+
+#define OS MKS(TARGOS)
+#define MACH MKS(TARGMACH)
+#ifndef PCCINCDIR
+#define PCCINCDIR	LIBDIR "pcc/" MACH "-" OS "/" PACKAGE_VERSION "/include"
+#endif
+#ifndef PCCLIBDIR
+#define PCCLIBDIR	LIBDIR "pcc/" MACH "-" OS "/" PACKAGE_VERSION "/lib"
+#endif
+
+#define MAXFIL 10000
 #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 []);
+char	*outfile, *ermfile;
+char *Bprefix(char *);
+char *copy(char *, int),*setsuf(char *, char);
+int getsuf(char *);
 int main(int, char *[]);
 void error(char *, ...);
-void errorx(int eval, char *, ...);
-int nodup(char **, char *);
+void errorx(int, char *, ...);
 int callsys(char [], char *[]);
 int cunlink(char *);
-void dexit(int eval);
+void dexit(int);
 void idexit(int);
-char *gettmp();
+char *gettmp(void);
+void *ccmalloc(int size);
+#ifdef WIN32
+char *win32pathsubst(char *);
+#endif
 char	*av[MAXAV];
 char	*clist[MAXFIL];
 char	*llist[MAXLIB];
+char	*aslist[MAXAV];
 char	alist[20];
 char	*xlist[100];
 int	xnum;
+char	*mlist[100];
+char	*flist[100];
+char	*wlist[100];
+char	*idirafter;
+int	nm;
+int	nf;
+int	nw;
+int	sspflag;
+int	Cflag;
+int	Vflag;
 int	dflag;
 int	pflag;
 int	sflag;
@@ -117,205 +176,416 @@
 int	pgflag;
 int	exfail;
 int	Xflag;
-int	nostartfiles, Bstatic;
+int	Wallflag;
+int	Wflag;
+int	nostartfiles, Bstatic, shared;
 int	nostdinc, nostdlib;
 int	onlyas;
 int	pthreads;
+int	xcflag;
+int 	ascpp;
 
-char	*pass0 = LIBEXECDIR "/pccom";
-char	*passp = LIBEXECDIR "/pcpp";
+char	*passp = LIBEXECDIR PREPROCESSOR;
+char	*pass0 = LIBEXECDIR COMPILER;
+char	*as = ASSEMBLER;
+char	*ld = LINKER;
 char	*Bflag;
 char *cppadd[] = CPPADD;
+#ifdef DYNLINKER
 char *dynlinker[] = DYNLINKER;
+#endif
+#ifdef CRT0FILE
 char *crt0file = CRT0FILE;
+#endif
+#ifdef CRT0FILE_PROFILE
+char *crt0file_profile = CRT0FILE_PROFILE;
+#endif
+#ifdef STARTFILES
 char *startfiles[] = STARTFILES;
 char *endfiles[] = ENDFILES;
+#endif
+#ifdef STARTFILES_T
+char *startfiles_T[] = STARTFILES_T;
+char *endfiles_T[] = ENDFILES_T;
+#endif
+#ifdef STARTFILES_S
+char *startfiles_S[] = STARTFILES_S;
+char *endfiles_S[] = ENDFILES_S;
+#endif
+#ifdef MULTITARGET
+char *mach = DEFMACH;
+struct cppmd {
+	char *mach;
+	char *cppmdadd[MAXCPPMDARGS];
+};
+
+struct cppmd cppmds[] = CPPMDADDS;
+#else
 char *cppmdadd[] = CPPMDADD;
+#endif
 #ifdef LIBCLIBS
 char *libclibs[] = LIBCLIBS;
 #else
 char *libclibs[] = { "-lc", NULL };
 #endif
+#ifdef LIBCLIBS_PROFILE
+char *libclibs_profile[] = LIBCLIBS_PROFILE;
+#else
+char *libclibs_profile[] = { "-lc_p", NULL };
+#endif
 #ifndef STARTLABEL
 #define STARTLABEL "__start"
 #endif
+char *incdir = STDINC;
+char *libdir = LIBDIR;
+char *pccincdir = PCCINCDIR;
+char *pcclibdir = PCCLIBDIR;
+
+/* handle gcc warning emulations */
+struct Wflags {
+	char *name;
+	int flags;
+#define	INWALL		1
+#define	NEGATIVE	2
+} Wflags[] = {
+	{ "-Werror", 0 },
+	{ "-Wshadow", 0 },
+	{ "-Wno-shadow", NEGATIVE },
+	{ "-Wpointer-sign", INWALL },
+	{ "-Wno-pointer-sign", NEGATIVE },
+	{ "-Wsign-compare", 0 },
+	{ "-Wno-sign-compare", NEGATIVE },
+	{ "-Wunknown-pragmas", INWALL },
+	{ "-Wno-unknown-pragmas", NEGATIVE },
+	{ "-Wunreachable-code", 0 },
+	{ "-Wno-unreachable-code", NEGATIVE },
+	{ 0, 0 },
+};
+
+#define	SZWFL	(sizeof(Wflags)/sizeof(Wflags[0]))
 
 int
 main(int argc, char *argv[])
 {
+	struct Wflags *Wf;
 	char *t, *u;
 	char *assource;
 	char **pv, *ptemp[MAXOPT], **pvt;
-	int nc, nl, i, j, c, nxo, na;
+	int nc, nl, nas, i, j, c, nxo, na;
+#ifdef MULTITARGET
+	int k;
+#endif
 
-	i = nc = nl = nxo = 0;
+#ifdef WIN32
+	/* have to prefix path early.  -B may override */
+	incdir = win32pathsubst(incdir);
+	libdir = win32pathsubst(libdir);
+	pccincdir = win32pathsubst(pccincdir);
+	pcclibdir = win32pathsubst(pcclibdir);
+	passp = win32pathsubst(passp);
+	pass0 = win32pathsubst(pass0);
+#endif
+
+	i = nc = nl = nas = nxo = 0;
 	pv = ptemp;
 	while(++i < argc) {
-		if (argv[i][0] == '-')
-		switch (argv[i][1]) {
-		default:
-			goto passa;
+		if (argv[i][0] == '-') {
+			switch (argv[i][1]) {
+			default:
+				goto passa;
+#ifdef notyet
+	/* must add library options first (-L/-l/...) */
+				error("unrecognized option `-%c'", argv[i][1]);
+				break;
+#endif
 
-		case 'B': /* other search paths for binaries */
-			Bflag = &argv[i][2];
-			break;
+			case '-': /* double -'s */
+				if (strcmp(argv[i], "--version") == 0) {
+					printf("%s\n", VERSSTR);
+					return 0;
+				} else if (strcmp(argv[i], "--param") == 0)
+					/* NOTHING YET */;
+				else
+					error("unrecognized option %s", argv[i]);
+				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;
+			case 'B': /* other search paths for binaries */
+				Bflag = &argv[i][2];
+				break;
+
+#ifdef MULTITARGET
+			case 'b':
+				t = &argv[i][2];
+				if (*t == '\0' && i + 1 < argc) {
+					t = argv[i+1];
+					i++;
+				}
+				if (strncmp(t, "?", 1) == 0) {
+					/* show machine targets */
+					printf("Available machine targets:");
+					for (j=0; cppmds[j].mach; j++)
+						printf(" %s",cppmds[j].mach);
+					printf("\n");
+					exit(0);
+				}
+				for (j=0; cppmds[j].mach; j++)
+					if (strcmp(t, cppmds[j].mach) == 0) {
+						mach = cppmds[j].mach;
+						break;
+					}
+				if (cppmds[j].mach == NULL)
+					errorx(1, "unknown target arch %s", t);
+				break;
+#endif
+
+			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;
-					t = u;
+				} else if (strncmp(argv[i], "-Wa,", 4) == 0) {
+					/* options to the assembler */
+					t = &argv[i][4];
+					while ((u = strchr(t, ','))) {
+						*u++ = 0;
+						aslist[nas++] = t;
+						t = u;
+					}
+					aslist[nas++] = t;
+				} else if (strncmp(argv[i], "-Wp,", 4) == 0) {
+					/* preprocessor */
+					if (!strncmp(argv[i], "-Wp,-C", 6))
+						Cflag++;
+					else if (!strncmp(argv[i], "-Wp,-V", 6))
+						Vflag++;
+				} else if (strcmp(argv[i], "-Wall") == 0) {
+					Wallflag = 1;
+				} else if (strcmp(argv[i], "-WW") == 0) {
+					Wflag = 1;
+				} else {
+					/* check and set if available */
+					for (Wf = Wflags; Wf->name; Wf++) {
+						if (strcmp(argv[i], Wf->name))
+							continue;
+						wlist[nw++] = Wf->name;
+					}
 				}
-				llist[nl++] = t;
-			}
-			break;
+				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 'f': /* GCC compatibility flags */
+				if (strcmp(argv[i], "-fPIC") == 0)
+					kflag = F_PIC;
+				else if (strcmp(argv[i], "-fpic") == 0)
+					kflag = F_pic;
+				else if (strcmp(argv[i],
+				    "-fsigned-char") == 0)
+					flist[nf++] = argv[i];
+				else if (strcmp(argv[i],
+				    "-fno-signed-char") == 0)
+					flist[nf++] = argv[i];
+				else if (strcmp(argv[i],
+				    "-funsigned-char") == 0)
+					flist[nf++] = argv[i];
+				else if (strcmp(argv[i],
+				    "-fno-unsigned-char") == 0)
+					flist[nf++] = argv[i];
+				else if (strcmp(argv[i],
+				    "-fstack-protector") == 0) {
+					flist[nf++] = argv[i];
+					sspflag++;
+				} else if (strcmp(argv[i],
+				    "-fstack-protector-all") == 0) {
+					flist[nf++] = argv[i];
+					sspflag++;
+				} else if (strcmp(argv[i],
+				    "-fno-stack-protector") == 0) {
+					flist[nf++] = argv[i];
+					sspflag = 0;
+				} else if (strcmp(argv[i],
+				    "-fno-stack-protector-all") == 0) {
+					flist[nf++] = argv[i];
+					sspflag = 0;
+				}
+				/* silently ignore the rest */
+				break;
 
-		case 'g': /* create debug output */
-			gflag++;
-			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 '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 if (strcmp(argv[i], "-idirafter") == 0) {
+					idirafter = argv[++i];
+				} else
+					goto passa;
+				break;
 
-		case 'k': /* generate PIC code */
-			kflag = F_pic;
-			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 'm': /* target-dependent options */
+				mlist[nm++] = argv[i];
+				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 'n': /* handle -n flags */
+				if (strcmp(argv[i], "-nostdinc") == 0)
+					nostdinc++;
+				else if (strcmp(argv[i], "-nostdlib") == 0) {
+					nostdlib++;
+					nostartfiles++;
+				} else if (strcmp(argv[i], "-nostartfiles") == 0)
+					nostartfiles = 1;
+				else
+					goto passa;
+				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;
+			case 'p':
+				if (strcmp(argv[i], "-pg") == 0 ||
+				    strcmp(argv[i], "-p") == 0)
+					pgflag++;
+				else if (strcmp(argv[i], "-pthread") == 0)
+					pthreads++;
+				else if (strcmp(argv[i], "-pipe") == 0)
+					/* NOTHING YET */;
+				else
+					errorx(1, "unknown option %s", argv[i]);
+				break;
+
+			case 'x':
+				t = &argv[i][2];
+				if (*t == 0)
+					t = argv[++i];
+				if (strcmp(t, "c") == 0)
+					xcflag = 1; /* default */
+				else if (strcmp(t, "assembler-with-cpp") == 0)
+					ascpp = 1;
+#ifdef notyet
+				else if (strcmp(t, "c++") == 0)
+					cxxflag++;
+#endif
+				else
+					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':
+				if (argv[i][2] == '0')
+					Oflag = 0;
+				else
+					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;
+			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;
+			case 'C':
+				Cflag = 1;
+				break;
+			case 'D':
+			case 'I':
+			case 'U':
+				*pv++ = argv[i];
+				if (argv[i][2] == 0)
+					*pv++ = argv[++i];
+				if (pv >= ptemp+MAXOPT) {
+					error("Too many DIU options");
+					--pv;
 				}
-			break;
+				break;
 
-		case 'M':
-			Mflag++;
-			break;
+			case 'M':
+				Mflag++;
+				break;
 
-		case 'd':
-			dflag++;
-			strncpy(alist, argv[i], 19);
-			break;
-		case 'v':
-			printf("%s\n", VERSSTR);
-			vflag++;
-			break;
+			case 'd':
+				dflag++;
+				strlcpy(alist, argv[i], sizeof (alist));
+				break;
+			case 'v':
+				printf("%s\n", VERSSTR);
+				vflag++;
+				break;
 
-		case 's':
-			if (strcmp(argv[i], "-static") == 0)
-				Bstatic = 1;
-			else
-				goto passa;
-			break;
+			case 's':
+				if (strcmp(argv[i], "-static") == 0)
+					Bstatic = 1;
+				else if (strcmp(argv[i], "-shared") == 0) {
+					shared = 1;
+#ifndef os_win32
+					nostdlib = 1;
+#endif
+				} else if (strncmp(argv[i], "-std", 4) == 0) {
+					/* ignore gcc -std= */;
+				} 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) {
+			    c=='s'|| Eflag || xcflag) {
 				clist[nc++] = t;
-				if (nc>=MAXFIL)
-					{
+				if (nc>=MAXFIL) {
 					error("Too many source files");
 					exit(1);
-					}
+				}
 				t = setsuf(t, 'o');
 			}
-			if (nodup(llist, t)) {
+
+			/* Check for duplicate .o files. */
+			for (j = getsuf(t) == 'o' ? 0 : nl; j < nl; j++) {
+				if (strcmp(llist[j], t) == 0)
+					break;
+			}
+			if (j == nl) {
 				llist[nl++] = t;
-				if (nl >= MAXLIB)
-					{
+				if (nl >= MAXLIB) {
 					error("Too many object/library files");
 					exit(1);
-					}
+				}
 				if (getsuf(t)=='o')
 					nxo++;
 			}
@@ -329,31 +599,30 @@
 	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();
+		if (!sflag)
+			tmp3 = gettmp();
 		tmp4 = gettmp();
 	}
+	if (Bflag) {
+		incdir = Bflag;
+		libdir = Bflag;
+		pccincdir = Bflag;
+		pcclibdir = Bflag;
+	}
 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)	/* interrupt */
 		signal(SIGINT, idexit);
 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)	/* terminate */
 		signal(SIGTERM, idexit);
+#ifdef MULTITARGET
+	pass0 = copy(LIBEXECDIR "/pccom_", k = strlen(mach));
+	strlcat(pass0, mach, sizeof(LIBEXECDIR "/pccom_") + k);
+#endif
 	pvt = pv;
 	for (i=0; i<nc; i++) {
 		/*
@@ -363,17 +632,17 @@
 			printf("%s:\n", clist[i]);
 		onlyas = 0;
 		assource = tmp3;
+		if (getsuf(clist[i])=='S')
+			ascpp = 1;
 		if (getsuf(clist[i])=='i') {
 			if(Eflag)
 				continue;
 			goto com;
+		} else if (ascpp) {
+			onlyas = 1;
 		} 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');
@@ -384,36 +653,59 @@
 		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')
+		if (ascpp)
 			av[na++] = "-D__ASSEMBLER__";
+		if (sspflag)
+			av[na++] = "-D__SSP__=1";
 		if (pthreads)
 			av[na++] = "-D_PTHREADS";
+		if (Cflag)
+			av[na++] = "-C";
 		if (Mflag)
 			av[na++] = "-M";
+		if (Vflag)
+			av[na++] = "-V";
 		if (dflag)
 			av[na++] = alist;
 		for (j = 0; cppadd[j]; j++)
 			av[na++] = cppadd[j];
+#ifdef MULTITARGET
+		for (k = 0; cppmds[k].mach; k++) {
+			if (strcmp(cppmds[k].mach, mach) != 0)
+				continue;
+			for (j = 0; cppmds[k].cppmdadd[j]; j++)
+				av[na++] = cppmds[k].cppmdadd[j];
+			break;
+		}
+#else
 		for (j = 0; cppmdadd[j]; j++)
 			av[na++] = cppmdadd[j];
+#endif
 		if (tflag)
 			av[na++] = "-t";
 		for(pv=ptemp; pv <pvt; pv++)
 			av[na++] = *pv;
 		if (!nostdinc)
-			av[na++] = "-S", av[na++] = STDINC;
+			av[na++] = "-S", av[na++] = incdir;
+		av[na++] = "-I", av[na++] = pccincdir;
+		if (idirafter) {
+			av[na++] = "-I";
+			av[na++] = idirafter;
+		}
 		av[na++] = clist[i];
 		if (!Eflag && !Mflag)
 			av[na++] = tmp4;
 		if (Eflag && outfile)
-			 av[na++] = outfile;
+			 ermfile = av[na++] = outfile;
 		av[na++]=0;
 		if (callsys(passp, av))
 			{exfail++; eflag++;}
 		if (Eflag || Mflag)
 			continue;
-		if (onlyas)
+		if (onlyas) {
+			assource = tmp4;
 			goto assemble;
+		}
 
 		/*
 		 * C compiler
@@ -421,18 +713,53 @@
 	com:
 		na = 0;
 		av[na++]= "pccom";
+		if (Wallflag) {
+			/* Set only the same flags as gcc */
+			for (Wf = Wflags; Wf->name; Wf++) {
+				if (Wf->flags != INWALL)
+					continue;
+				av[na++] = Wf->name;
+			}
+		}
+		if (Wflag) {
+			/* set all positive flags */
+			for (Wf = Wflags; Wf->name; Wf++) {
+				if (Wf->flags == NEGATIVE)
+					continue;
+				av[na++] = Wf->name;
+			}
+		}
+		for (j = 0; j < nw; j++)
+			av[na++] = wlist[j];
+		for (j = 0; j < nf; j++)
+			av[na++] = flist[j];
 		if (vflag)
 			av[na++] = "-v";
+		if (pgflag)
+			av[na++] = "-p";
 		if (gflag)
 			av[na++] = "-g";
+#ifdef os_darwin
+		/* darwin always wants PIC compilation */
+		if (!Bstatic)
+			av[na++] = "-k";
+#else
 		if (kflag)
 			av[na++] = "-k";
+#endif
 		if (Oflag) {
 			av[na++] = "-xtemps";
+			av[na++] = "-xdeljumps";
+			av[na++] = "-xinline";
 		}
 		for (j = 0; j < xnum; j++)
 			av[na++] = xlist[j];
-		av[na++] = tmp4;
+		for (j = 0; j < nm; j++)
+			av[na++] = mlist[j];
+		if (getsuf(clist[i])=='i')
+			av[na++] = clist[i];
+		else
+			av[na++] = tmp4; /* created by cpp */
 		if (pflag || exfail)
 			{
 			cflag++;
@@ -440,11 +767,11 @@
 			}
 		if(sflag) {
 			if (outfile)
-				assource = tmp3 = outfile;
+				tmp3 = outfile;
 			else
-				assource = tmp3 = setsuf(clist[i], 's');
+				tmp3 = setsuf(clist[i], 's');
 		}
-		av[na++] = tmp3;
+		ermfile = av[na++] = tmp3;
 #if 0
 		if (proflag) {
 			av[3] = "-XP";
@@ -466,21 +793,30 @@
 		 */
 	assemble:
 		na = 0;
-		av[na++] = "as";
+		av[na++] = as;
+		for (j = 0; j < nas; j++)
+			av[na++] = aslist[j];
+#if defined(os_sunos) && defined(mach_sparc64)
+		av[na++] = "-m64";
+#endif
+#if defined(os_darwin)
+		if (Bstatic)
+			av[na++] = "-static";
+#endif
 		if (vflag)
 			av[na++] = "-v";
 		if (kflag)
 			av[na++] = "-k";
 		av[na++] = "-o";
 		if (outfile && cflag)
-			av[na++] = outfile;
+			ermfile = av[na++] = outfile;
 		else
-			av[na++] = setsuf(clist[i], 'o');
-		av[na++] = onlyas ? tmp4 : assource;
+			ermfile = av[na++] = setsuf(clist[i], 'o');
+		av[na++] = assource;
 		if (dflag)
 			av[na++] = alist;
 		av[na++] = 0;
-		if (callsys("/bin/as", av)) {
+		if (callsys(as, av)) {
 			cflag++;
 			eflag++;
 			cunlink(tmp4);
@@ -498,26 +834,86 @@
 nocom:
 	if (cflag==0 && nl!=0) {
 		j = 0;
-		av[j++] = "ld";
+		av[j++] = ld;
+#ifndef MSLINKER
 		if (vflag)
 			av[j++] = "-v";
+#endif
+#if !defined(os_sunos) && !defined(os_win32) && !defined(os_darwin)
 		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";
+#endif
+		if (shared) {
+			av[j++] = "-shared";
+#ifdef os_win32
+			av[j++] = "-Bdynamic";
+#endif
+#ifndef os_sunos
+		} else {
+#ifndef os_win32
+#ifndef os_darwin
+			av[j++] = "-d";
+#endif
+			av[j++] = "-e";
+			av[j++] = STARTLABEL;
+#endif
+#endif
+			if (Bstatic == 0) { /* Dynamic linkage */
+#ifdef DYNLINKER
+				for (i = 0; dynlinker[i]; i++)
+					av[j++] = dynlinker[i];
+#endif
+			} else {
+#ifdef os_darwin
+				av[j++] = "-static";
+#else
+				av[j++] = "-Bstatic";
+#endif
+			}
+		}
 		if (outfile) {
+#ifdef MSLINKER
+#define	OUTSTR	"/OUT:"
+			char *s = copy(OUTSTR, i = strlen(outfile));
+			strlcat(s, outfile, sizeof(OUTSTR) + i);
+			av[j++] = s;
+#else
 			av[j++] = "-o";
 			av[j++] = outfile;
+#endif
 		}
-		if (!nostartfiles) {
-			av[j++] = crt0file;
-			for (i = 0; startfiles[i]; i++)
-				av[j++] = startfiles[i];
+#ifdef STARTFILES_S
+		if (shared) {
+			if (!nostartfiles) {
+				for (i = 0; startfiles_S[i]; i++)
+					av[j++] = Bprefix(startfiles_S[i]);
+			}
+		} else
+#endif
+		{
+			if (!nostartfiles) {
+#ifdef CRT0FILE_PROFILE
+				if (pgflag) {
+					av[j++] = Bprefix(crt0file_profile);
+				} else
+#endif
+				{
+#ifdef CRT0FILE
+					av[j++] = Bprefix(crt0file);
+#endif
+				}
+#ifdef STARTFILES_T
+				if (Bstatic) {
+					for (i = 0; startfiles_T[i]; i++)
+						av[j++] = Bprefix(startfiles_T[i]);
+				} else
+#endif
+				{
+#ifdef STARTFILES
+					for (i = 0; startfiles[i]; i++)
+						av[j++] = Bprefix(startfiles[i]);
+#endif
+				}
+			}
 		}
 		i = 0;
 		while(i<nl) {
@@ -525,21 +921,63 @@
 			if (j >= MAXAV)
 				error("Too many ld options");
 		}
+#ifndef MACHOABI
+		/* darwin assembler doesn't want -g */
+		if (gflag)
+			av[j++] = "-g";
+#endif
 #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 (!nostdlib) {
+#ifdef MSLINKER
+#define	DL	"/LIBPATH:"
+#else
+#define	DL	"-L"
+#endif
+			char *s = copy(DL, i = strlen(pcclibdir));
+			strlcat(s, pcclibdir, sizeof(DL) + i);
+			av[j++] = s;
+#ifdef os_win32
+			s = copy(DL, i = strlen(libdir));
+			strlcat(s, libdir, sizeof(DL) + i);
+			av[j++] = s;
+#endif
+			if (pgflag) {
+				for (i = 0; libclibs_profile[i]; i++)
+					av[j++] = Bprefix(libclibs_profile[i]);
+			} else {
+				for (i = 0; libclibs[i]; i++)
+					av[j++] = Bprefix(libclibs[i]);
+			}
+		}
 		if (!nostartfiles) {
-			for (i = 0; endfiles[i]; i++)
-				av[j++] = endfiles[i];
+#ifdef STARTFILES_S
+			if (shared) {
+				for (i = 0; endfiles_S[i]; i++)
+					av[j++] = Bprefix(endfiles_S[i]);
+			} else 
+#endif
+			{
+#ifdef STARTFILES_T
+				if (Bstatic) {
+					for (i = 0; endfiles_T[i]; i++)
+						av[j++] = Bprefix(endfiles_T[i]);
+				} else
+#endif
+				{
+#ifdef STARTFILES
+					for (i = 0; endfiles[i]; i++)
+						av[j++] = Bprefix(endfiles[i]);
+#endif
+				}
+			}
 		}
 		av[j++] = 0;
-		eflag |= callsys("/bin/ld", av);
+		eflag |= callsys(ld, av);
 		if (nc==1 && nxo==1 && eflag==0)
 			cunlink(setsuf(clist[0], 'o'));
 		else if (nc > 0 && eflag == 0) {
@@ -572,6 +1010,10 @@
 			cunlink(tmp3);
 		cunlink(tmp4);
 	}
+	if (exfail || eflag)
+		cunlink(ermfile);
+	if (eval == 100)
+		_exit(eval);
 	exit(eval);
 }
 
@@ -612,14 +1054,47 @@
 	dexit(eval);
 }
 
+char *
+Bprefix(char *s)
+{
+	char *suffix;
+	char *str;
+	int i;
+
+#ifdef os_win32
+
+	/*  put here to save sprinkling it ~everywhere  */
+	s =  win32pathsubst(s);
+
+	if (Bflag == NULL)
+		return s;
+	suffix = strrchr(s, '/');
+	if (suffix == NULL)
+		suffix = strrchr(s, '\\');
+
+#else
+
+	if (Bflag == NULL || s[0] != '/')
+		return s;
+	suffix = strrchr(s, '/');
+
+#endif
+
+	if (suffix == NULL)
+		suffix = s;
+
+	str = copy(Bflag, i = strlen(suffix));
+	strlcat(str, suffix, strlen(Bflag) + i + 1);
+	return str;
+}
+
 int
-getsuf(as)
-char as[];
+getsuf(char *s)
 {
-	register char *s;
+	register char *p;
 
-	if ((s = strrchr(as, '.')) && s[1] != '\0' && s[2] == '\0')
-		return s[1];
+	if ((p = strrchr(s, '.')) && p[1] != '\0' && p[2] == '\0')
+		return p[1];
 	return(0);
 }
 
@@ -629,16 +1104,71 @@
 char *
 setsuf(char *s, char ch)
 {
-	s = copy(basename(s));
-	s[strlen(s) - 1] = ch;
+	char *p;
+
+	s = copy(basename(s), 2);
+	if ((p = strrchr(s, '.')) == NULL) {
+		p = s + strlen(s);
+		p[0] = '.';
+	}
+	p[1] = ch;
+	p[2] = '\0';
 	return(s);
 }
 
+#ifdef WIN32
 int
-callsys(char f[], char *v[])
+callsys(char *f, char *v[])
 {
-	int status;
-	pid_t t;
+	int t;
+	char cmd[MAX_PATH];
+	int len;
+	STARTUPINFO si;
+	PROCESS_INFORMATION pi;
+	DWORD exitCode;
+	BOOL ok;
+
+	len = strlcpy(cmd, f, MAX_PATH);
+	for (t = 1; v[t] && len < MAX_PATH; t++) {
+		len = strlcat(cmd, " ", MAX_PATH);
+		len = strlcat(cmd, v[t], MAX_PATH);
+	}
+
+	if (vflag)
+		printf("%s\n", cmd);
+
+	ZeroMemory(&si, sizeof(STARTUPINFO));
+	si.cb = sizeof(STARTUPINFO);
+	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
+
+	ok = CreateProcess(NULL,  // the executable program
+		cmd,   // the command line arguments
+		NULL,       // ignored
+		NULL,       // ignored
+		TRUE,       // inherit handles
+		HIGH_PRIORITY_CLASS,
+		NULL,       // ignored
+		NULL,       // ignored
+		&si,
+		&pi);
+
+	if (!ok) {
+		fprintf(stderr, "Can't find %s\n", f);
+		return 100;
+	}
+
+	WaitForSingleObject(pi.hProcess, INFINITE);
+	GetExitCodeProcess(pi.hProcess, &exitCode);
+	return (exitCode != 0);
+}
+
+#else
+
+int
+callsys(char *f, char *v[])
+{
+	int t, status = 0;
+	pid_t p;
 	char *s;
 
 	if (vflag) {
@@ -648,82 +1178,94 @@
 		fprintf(stderr, "\n");
 	}
 
-	if ((t=fork())==0) {
+	if ((p = fork()) == 0) {
 		if (Bflag) {
 			size_t len = strlen(Bflag) + 8;
 			char *a = malloc(len);
-			if (a == NULL)
-				errorx(1, "callsys: malloc failed\n");
+			if (a == NULL) {
+				error("callsys: malloc failed");
+				exit(1);
+			}
 			if ((s = strrchr(f, '/'))) {
 				strlcpy(a, Bflag, len);
 				strlcat(a, s, len);
 				execv(a, v);
 			}
 		}
-		execv(f, v);
+		execvp(f, v);
 		if ((s = strrchr(f, '/')))
 			execvp(s+1, v);
-		printf("Can't find %s\n", f);
-		exit(100);
-	} else
-		if (t == -1) {
+		fprintf(stderr, "Can't find %s\n", f);
+		_exit(100);
+	} else {
+		if (p == -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);
+	while (waitpid(p, &status, 0) == -1 && errno == EINTR)
+		;
+	if (WIFEXITED(status))
+		return (WEXITSTATUS(status));
+	if (WIFSIGNALED(status))
+		dexit(eflag ? eflag : 1);
+	errorx(8, "Fatal error in %s", f);
+
+	return 0;
 }
+#endif
 
+/*
+ * Make a copy of string as, mallocing extra bytes in the string.
+ */
 char *
-copy(char *as)
+copy(char *s, int extra)
 {
-	char *p;
-
-	if ((p = strdup(as)) == NULL)
-		errorx(8, "no space for file names");
+	int len = strlen(s)+1;
+	char *rv;
 
-	return p;
+	rv = ccmalloc(len+extra);
+	strlcpy(rv, s, len);
+	return rv;
 }
 
 int
-nodup(l, os)
-char **l, *os;
+cunlink(char *f)
 {
-	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);
+	if (f==0 || Xflag)
+		return(0);
+	return (unlink(f));
 }
 
-int
-cunlink(f)
-char *f;
+#ifdef WIN32
+char *
+gettmp(void)
 {
-	if (f==0 || Xflag)
-		return(0);
-	return(unlink(f));
+#define BUFFSIZE 1000
+	DWORD pathSize;
+	char pathBuffer[BUFFSIZE];
+	char tempFilename[MAX_PATH];
+	UINT uniqueNum;
+
+	pathSize = GetTempPath(BUFFSIZE, pathBuffer);
+	if (pathSize < BUFFSIZE)
+		pathBuffer[pathSize] = 0;
+	else
+		pathBuffer[0] = 0;
+	uniqueNum = GetTempFileName(pathBuffer, "ctm", 0, tempFilename);
+	if (uniqueNum == 0) {
+		fprintf(stderr, "%s:\n", pathBuffer);
+		exit(8);
+	}
+	return copy(tempFilename, 0);
 }
 
+#else
+
 char *
-gettmp()
+gettmp(void)
 {
-	char *sfn = strdup("/tmp/ctm.XXXXXX");
+	char *sfn = copy("/tmp/ctm.XXXXXX", 0);
 	int fd = -1;
 
 	if ((fd = mkstemp(sfn)) == -1) {
@@ -731,6 +1273,43 @@
 		exit(8);
 	}
 	close(fd);
-
 	return sfn;
 }
+#endif
+
+void *
+ccmalloc(int size)
+{
+	void *rv;
+
+	if ((rv = malloc(size)) == NULL)
+		error("malloc failed");
+	return rv;
+}
+
+#ifdef WIN32
+
+char *
+win32pathsubst(char *s)
+{
+	char env[1024];
+	char *rv;
+	int len;
+
+	len = ExpandEnvironmentStrings(s, env, sizeof(env));
+	if (len <= 0)
+		return s;
+
+	while (env[len-1] == '/' || env[len-1] == '\\' || env[len-1] == '\0')
+		env[--len] = 0;
+
+	len += 3;
+	rv = ccmalloc(len);
+	strlcpy(rv, "\"", len);
+	strlcat(rv, env, len);
+	strlcat(rv, "\"", len);
+
+	return rv;
+}
+
+#endif
Index: Makefile
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/cc/Makefile,v
retrieving revision 1.8
retrieving revision 1.9
diff -L usr.bin/pcc/cc/Makefile -L usr.bin/pcc/cc/Makefile -u -r1.8 -r1.9
--- usr.bin/pcc/cc/Makefile
+++ usr.bin/pcc/cc/Makefile
@@ -5,8 +5,8 @@
 TARGOS=	midnightbsd
 TARGMACH=	${MACHINE_ARCH}
 
-CFLAGS+=	-DLIBEXECDIR=\"/usr/libexec\"
-CFLAGS+=	-I${.CURDIR}/..
+CFLAGS+=	-DLIBEXECDIR=\"/usr/libexec/\"
+CFLAGS+=	-I${.CURDIR}/.. -I${.CURDIR}/../mip/
 CFLAGS+=	-Dmach_${TARGMACH} -Dos_${TARGOS}
 
 BINDIR=	/usr/bin
Index: inline.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/inline.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/ccom/inline.c -L usr.bin/pcc/ccom/inline.c -u -r1.1 -r1.2
--- usr.bin/pcc/ccom/inline.c
+++ usr.bin/pcc/ccom/inline.c
@@ -1,6 +1,6 @@
-/*	$Id: inline.c,v 1.17 2007/09/09 10:01:01 ragge Exp $	*/
+/*	$Id: inline.c,v 1.25 2008/11/28 15:23:57 ragge Exp $	*/
 /*
- * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
+ * Copyright (c) 2003, 2008 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,104 +32,135 @@
 #include <stdarg.h>
 
 /*
+ * Simple description of how the inlining works:
+ * A function found with the keyword "inline" is always saved.
+ * If it also has the keyword "extern" it is written out thereafter.
+ * If it has the keyword "static" it will be written out if it is referenced.
+ * inlining will only be done if -xinline is given, and only if it is 
+ * possible to inline the function.
+ */
+static void printip(struct interpass *pole);
+
+/*
  * 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 */
+	SLIST_ENTRY(istat) link;
+	struct symtab *sp;
+	int flags;
+#define	CANINL	1	/* function is possible to inline */
+#define	WRITTEN	2	/* function is written out */
+#define	REFD	4	/* Referenced but not yet written out */
+	int *args;	/* Array of arg temp numbers */
+	int nargs;	/* number of args in array */
+	int retval;	/* number of return temporary, if any */
 	struct interpass shead;
-} *ipole, *cifun;
+} *cifun;
+
+static SLIST_HEAD(, istat) ipole = { NULL, &ipole.q_forw };
+static int nlabs;
 
 #define	IP_REF	(MAXIP+1)
+#ifdef PCC_DEBUG
+#define	SDEBUG(x)	if (sdebug) printf x
+#else
+#define	SDEBUG(x)
+#endif
 
-int isinlining, recovernodes;
+int isinlining;
 int inlnodecnt, inlstatcnt;
 
-#define	ialloc() permalloc(sizeof(struct istat)); inlstatcnt++
-#define	nalloc() permalloc(sizeof(NODE))
+#define	SZSI	sizeof(struct istat)
+#define	ialloc() memset(permalloc(SZSI), 0, SZSI); inlstatcnt++
 
 static void
-tcnt(NODE *p)
+tcnt(NODE *p, void *arg)
 {
 	inlnodecnt++;
+	if (nlabs > 1 && (p->n_op == REG || p->n_op == OREG) &&
+	    regno(p) == FPREG)
+		SLIST_FIRST(&ipole)->flags &= ~CANINL; /* no stack refs */
+	if (nflag)
+		printf("locking node %p\n", p);
 }
 
 static struct istat *
-findfun(char *name)
+findfun(struct symtab *sp)
 {
-	struct istat *is = ipole;
-	while (is) {
-		if (is->name == name)
+	struct istat *is;
+
+	SLIST_FOREACH(is, &ipole, link)
+		if (is->sp == sp)
 			return is;
-		is = is->ilink;
-	}
 	return NULL;
 }
 
 static void
-refnode(char *str)
+refnode(struct symtab *sp)
 {
 	struct interpass *ip;
 
-	if (sdebug)
-		printf("refnode(%s)\n", str);
+	SDEBUG(("refnode(%s)\n", sp->sname));
 
 	ip = permalloc(sizeof(*ip));
 	ip->type = IP_REF;
-	ip->ip_name = str;
+	ip->ip_name = (char *)sp;
 	inline_addarg(ip);
 }
 
 void
 inline_addarg(struct interpass *ip)
 {
+	extern NODE *cftnod;
+
+//	SDEBUG(("inline_addarg(%p)\n", ip));
 	DLIST_INSERT_BEFORE(&cifun->shead, ip, qelem);
+	if (ip->type == IP_DEFLAB)
+		nlabs++;
 	if (ip->type == IP_NODE)
-		walkf(ip->ip_node, tcnt); /* Count as saved */
+		walkf(ip->ip_node, tcnt, 0); /* Count as saved */
+	if (cftnod)
+		cifun->retval = regno(cftnod);
 }
 
 /*
  * Called to setup for inlining of a new function.
  */
 void
-inline_start(char *name)
+inline_start(struct symtab *sp)
 {
 	struct istat *is;
 
-	if (sdebug)
-		printf("inline_start(\"%s\")\n", name);
+	SDEBUG(("inline_start(\"%s\")\n", sp->sname));
 
 	if (isinlining)
 		cerror("already inlining function");
 
-	if ((is = findfun(name)) == 0) {
-		is = ialloc();
-		is->ilink = ipole;
-		ipole = is;
-		is->name = name;
-		is->type = NOTYETR;
+	if ((is = findfun(sp)) != 0) {
+		if (!DLIST_ISEMPTY(&is->shead, qelem))
+			uerror("inline function already defined");
 	} else {
-		if (is->type != NOTYETD)
-			cerror("inline function already defined");
-		is->type = NOTYETW;
+		is = ialloc();
+		is->sp = sp;
+		SLIST_INSERT_FIRST(&ipole, is, link);
+		DLIST_INIT(&is->shead, qelem);
 	}
-	DLIST_INIT(&is->shead, qelem);
 	cifun = is;
+	nlabs = 0;
 	isinlining++;
 }
 
 void
 inline_end()
 {
-	if (sdebug)
-		printf("inline_end()\n");
+	SDEBUG(("inline_end()\n"));
 
+	if (sdebug)printip(&cifun->shead);
 	isinlining = 0;
+	if (cifun->sp->sclass == EXTDEF) {
+		cifun->flags |= REFD;
+		inline_prtout();
+	}
 }
 
 /*
@@ -138,49 +169,85 @@
  * The function may not be defined when inline_ref() is called.
  */
 void
-inline_ref(char *name)
+inline_ref(struct symtab *sp)
 {
-	struct istat *w = ipole;
+	struct istat *w;
 
-	if (sdebug)
-		printf("inline_ref(\"%s\")\n", name);
+	SDEBUG(("inline_ref(\"%s\")\n", sp->sname));
+	if (sp->sclass == SNULL)
+		return; /* only inline, no references */
 	if (isinlining) {
-		refnode(name);
+		refnode(sp);
 	} else {
-		while (w != NULL) {
-			if (w->name == name) {
-				if (w->type == NOTYETR)
-					w->type = NOTYETW;
-				return; /* setup for writeout */
-			}
-			w = w->ilink;
+		SLIST_FOREACH(w,&ipole, link) {
+			if (w->sp != sp)
+				continue;
+			w->flags |= REFD;
+			return;
 		}
 		/* function not yet defined, print out when found */
 		w = ialloc();
-		w->ilink = ipole;
-		ipole = w;
-		w->name = name;
-		w->type = NOTYETD;
+		w->sp = sp;
+		w->flags |= REFD;
+		SLIST_INSERT_FIRST(&ipole, w, link);
+		DLIST_INIT(&w->shead, qelem);
 	}
 }
 
 static void
 puto(struct istat *w)
 {
+	struct interpass_prolog *ipp, *epp, *pp;
 	struct interpass *ip, *nip;
+	extern int crslab;
+	int lbloff = 0;
 
-	/* 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;
+	/* Copy the saved function and print it out */
+	ipp = 0; /* XXX data flow analysis */
+	DLIST_FOREACH(ip, &w->shead, qelem) {
+		switch (ip->type) {
+		case IP_EPILOG:
+		case IP_PROLOG:
+			if (ip->type == IP_PROLOG) {
+				ipp = (struct interpass_prolog *)ip;
+				/* fix label offsets */
+				lbloff = crslab - ipp->ip_lblnum;
+			} else {
+				epp = (struct interpass_prolog *)ip;
+				crslab += (epp->ip_lblnum - ipp->ip_lblnum);
+			}
+			pp = tmpalloc(sizeof(struct interpass_prolog));
+			memcpy(pp, ip, sizeof(struct interpass_prolog));
+			pp->ip_lblnum += lbloff;
+#ifdef PCC_DEBUG
+			if (ip->type == IP_EPILOG && crslab != pp->ip_lblnum)
+				cerror("puto: %d != %d", crslab, pp->ip_lblnum);
+#endif
+			pass2_compile((struct interpass *)pp);
+			break;
+
+		case IP_REF:
+			inline_ref((struct symtab *)ip->ip_name);
+			break;
+
+		default:
+			nip = tmpalloc(sizeof(struct interpass));
+			*nip = *ip;
+			if (nip->type == IP_NODE) {
+				NODE *p;
+
+				p = nip->ip_node = tcopy(nip->ip_node);
+				if (p->n_op == GOTO)
+					p->n_left->n_lval += lbloff;
+				else if (p->n_op == CBRANCH)
+					p->n_right->n_lval += lbloff;
+			} else if (nip->type == IP_DEFLAB)
+				nip->ip_lbl += lbloff;
+			pass2_compile(nip);
+			break;
+		}
 	}
-	DLIST_INIT(&w->shead, qelem);
+	w->flags |= WRITTEN;
 }
 
 /*
@@ -189,21 +256,246 @@
 void
 inline_prtout()
 {
-	struct istat *w = ipole;
+	struct istat *w;
 	int gotone = 0;
 
-	if (w == NULL)
-		return;
-	recovernodes++;
-	while (w != NULL) {
-		if (w->type == NOTYETW) {
+	SLIST_FOREACH(w, &ipole, link) {
+		if ((w->flags & (REFD|WRITTEN)) == REFD &&
+		    !DLIST_ISEMPTY(&w->shead, qelem)) {
+			defloc(w->sp);
 			puto(w);
-			w->type = WRITTEN;
+			w->flags |= WRITTEN;
 			gotone++;
 		}
-		w = w->ilink;
 	}
 	if (gotone)
 		inline_prtout();
-	recovernodes--;
+}
+
+#if 1
+static void
+printip(struct interpass *pole)
+{
+	static char *foo[] = {
+	   0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" };
+	struct interpass *ip;
+	struct interpass_prolog *ipplg, *epplg;
+
+	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");
+#ifdef PCC_DEBUG
+			fwalk(ip->ip_node, eprint, 0); break;
+#endif
+		case IP_PROLOG:
+			ipplg = (struct interpass_prolog *)ip;
+			printf("%s %s regs %x autos %d mintemp %d minlbl %d\n",
+			    ipplg->ipp_name, ipplg->ipp_vis ? "(local)" : "",
+			    ipplg->ipp_regs[0], ipplg->ipp_autos, ipplg->ip_tmpnum,
+			    ipplg->ip_lblnum);
+			break;
+		case IP_EPILOG:
+			epplg = (struct interpass_prolog *)ip;
+			printf("%s %s regs %x autos %d mintemp %d minlbl %d\n",
+			    epplg->ipp_name, epplg->ipp_vis ? "(local)" : "",
+			    epplg->ipp_regs[0], epplg->ipp_autos, epplg->ip_tmpnum,
+			    epplg->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;
+		}
+	}
+}
+#endif
+
+static int toff;
+
+static NODE *
+mnode(int *n, NODE *p)
+{
+	NODE *q;
+	int num = *n + toff;
+
+	if (p->n_op == CM) {
+		q = p->n_right;
+		q = tempnode(num, q->n_type, q->n_df, q->n_sue);
+		n--;
+		p->n_right = buildtree(ASSIGN, q, p->n_right);
+		p->n_left = mnode(n, p->n_left);
+		p->n_op = COMOP;
+	} else {
+		p = pconvert(p);
+		q = tempnode(num, p->n_type, p->n_df, p->n_sue);
+		p = buildtree(ASSIGN, q, p);
+	}
+	return p;
+}
+
+static void
+rtmps(NODE *p, void *arg)
+{
+	if (p->n_op == TEMP)
+		regno(p) += toff;
+}
+
+/*
+ * Inline a function. Returns the return value.
+ * There are two major things that must be converted when 
+ * inlining a function:
+ * - Label numbers must be updated with an offset.
+ * - The stack block must be relocated (add to REG or OREG).
+ * - Temporaries should be updated (but no must)
+ */
+NODE *
+inlinetree(struct symtab *sp, NODE *f, NODE *ap)
+{
+	extern int crslab, tvaloff;
+	struct istat *is = findfun(sp);
+	struct interpass *ip, *ipf, *ipl;
+	int lmin, stksz, L0, L1, L2;
+	OFFSZ stkoff;
+	NODE *p, *rp;
+
+	if (is == NULL) {
+		inline_ref(sp); /* prototype of not yet declared inline ftn */
+		return NIL;
+	}
+
+	SDEBUG(("inlinetree(%p,%p) OK %d\n", f, ap, is->flags & CANINL));
+
+	if ((is->flags & CANINL) == 0 || xinline == 0) {
+		if (is->sp->sclass == STATIC || is->sp->sclass == USTATIC)
+			is->flags |= REFD; /* if static inline, emit */
+		return NIL;
+	}
+
+#ifdef mach_i386
+	if (kflag) {
+		is->flags |= REFD; /* if static inline, emit */
+		return NIL; /* XXX cannot handle hidden ebx arg */
+	}
+#endif
+
+	stksz = stkoff = 0;
+	/* emit jumps to surround inline function */
+	branch(L0 = getlab());
+	plabel(L1 = getlab());
+	L2 = getlab();
+	SDEBUG(("branch labels %d,%d,%d\n", L0, L1, L2));
+
+	ipf = DLIST_NEXT(&is->shead, qelem); /* prolog */
+	ipl = DLIST_PREV(&is->shead, qelem); /* epilog */
+
+	/* Fix label & temp offsets */
+#define	IPP(x) ((struct interpass_prolog *)x)
+	SDEBUG(("pre-offsets crslab %d tvaloff %d\n", crslab, tvaloff));
+	lmin = crslab - IPP(ipf)->ip_lblnum;
+	crslab += (IPP(ipl)->ip_lblnum - IPP(ipf)->ip_lblnum) + 1;
+	toff = tvaloff - IPP(ipf)->ip_tmpnum;
+	tvaloff += (IPP(ipl)->ip_tmpnum - IPP(ipf)->ip_tmpnum) + 1;
+	SDEBUG(("offsets crslab %d lmin %d tvaloff %d toff %d\n",
+	    crslab, lmin, tvaloff, toff));
+
+	/* traverse until first real label */
+	ipf = DLIST_NEXT(ipf, qelem);
+	do
+		ipf = DLIST_NEXT(ipf, qelem);
+	while (ipf->type != IP_DEFLAB);
+
+	/* traverse backwards to last label */
+	do
+		ipl = DLIST_PREV(ipl, qelem);
+	while (ipl->type != IP_DEFLAB);
+
+	/* So, walk over all statements and emit them */
+	for (ip = ipf; ip != ipl; ip = DLIST_NEXT(ip, qelem)) {
+		switch (ip->type) {
+		case IP_NODE:
+			p = tcopy(ip->ip_node);
+			if (p->n_op == GOTO)
+				p->n_left->n_lval += lmin;
+			else if (p->n_op == CBRANCH)
+				p->n_right->n_lval += lmin;
+			walkf(p, rtmps, 0);
+#ifdef PCC_DEBUG
+			if (sdebug) {
+				printf("converted node\n");
+				fwalk(ip->ip_node, eprint, 0);
+				fwalk(p, eprint, 0);
+			}
+#endif
+			send_passt(IP_NODE, p);
+			break;
+
+		case IP_DEFLAB:
+			SDEBUG(("converted label %d to %d\n",
+			    ip->ip_lbl, ip->ip_lbl + lmin));
+			send_passt(IP_DEFLAB, ip->ip_lbl + lmin);
+			break;
+
+		case IP_ASM:
+			send_passt(IP_ASM, ip->ip_asm);
+			break;
+
+		case IP_REF:
+			inline_ref((struct symtab *)ip->ip_name);
+			break;
+
+		default:
+			cerror("bad inline stmt %d", ip->type);
+		}
+	}
+	SDEBUG(("last label %d to %d\n", ip->ip_lbl, ip->ip_lbl + lmin));
+	send_passt(IP_DEFLAB, ip->ip_lbl + lmin);
+
+	branch(L2);
+	plabel(L0);
+
+	rp = block(GOTO, bcon(L1), NIL, INT, 0, MKSUE(INT));
+	if (is->retval)
+		p = tempnode(is->retval + toff, DECREF(sp->stype),
+		    sp->sdf, sp->ssue);
+	else
+		p = bcon(0);
+	rp = buildtree(COMOP, rp, p);
+
+	if (is->nargs) {
+		p = mnode(&is->args[is->nargs-1], ap);
+		rp = buildtree(COMOP, p, rp);
+	}
+
+	tfree(f);
+	return rp;
+}
+
+void
+inline_args(struct symtab **sp, int nargs)
+{
+	struct istat *cf;
+	int i;
+
+	SDEBUG(("inline_args\n"));
+	cf = cifun;
+	/*
+	 * First handle arguments.  We currently do not inline anything if:
+	 * - function has varargs
+	 * - function args are volatile, checked if no temp node is asg'd.
+	 */
+	if (nargs) {
+		for (i = 0; i < nargs; i++)
+			if ((sp[i]->sflags & STNODE) == 0)
+				return; /* not temporary */
+		cf->args = permalloc(sizeof(int)*nargs);
+		for (i = 0; i < nargs; i++)
+			cf->args[i] = sp[i]->soffset;
+	}
+	cf->nargs = nargs;
+	cf->flags |= CANINL;
 }
Index: scan.l
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/scan.l,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/ccom/scan.l -L usr.bin/pcc/ccom/scan.l -u -r1.1 -r1.2
--- usr.bin/pcc/ccom/scan.l
+++ usr.bin/pcc/ccom/scan.l
@@ -1,5 +1,5 @@
 %{
-/*	$Id: scan.l,v 1.61 2007/09/19 17:20:26 ragge Exp $	*/
+/*	$Id: scan.l,v 1.81 2008/12/20 14:15:27 ragge Exp $	*/
 
 /*
  * Copyright (c) 2002 Anders Magnusson. All rights reserved.
@@ -38,6 +38,7 @@
 IS			(u|U|l|L)*
 
 %{
+#include <stdlib.h>
 #include <errno.h>  
 #include <string.h>
 #include <stdarg.h>
@@ -48,30 +49,29 @@
 static NODE *cvtdig(int radix);
 static NODE *charcon(void);
 static void control(int);
-static NODE *floatcon(void);
-static NODE *fhexcon(void);
-int notype, parbal;
+static void pragma(void);
+int notype, parbal, inattr, parlvl;
+static int resw(TWORD, int);
 
-#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)
+#define	STABS_LINE(x) if (gflag && cftnsp) stabs_line(x)
 #else
 #define STABS_LINE(x)
 #endif
 #if defined(FLEX_SCANNER) && YY_FLEX_SUBMINOR_VERSION >= 31
-/* Hack to avoid unneccessary warnings */
+/* Hack to avoid unnecessary 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 );
+void yyset_in (FILE *);
+void yyset_out (FILE *);
 int yyget_debug  (void);
-void yyset_debug (int  bdebug );
+void yyset_debug (int);
 int yylex_destroy  (void);
 extern int yyget_lineno (void);
 extern void yyset_lineno (int);
@@ -95,9 +95,9 @@
 "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); }
+"_Complex"		{ yylval.nodep = mkty((TWORD)COMPLEX, 0, MKSUE(DOUBLE));
+			  notype=1; return(C_TYPE); }
+"const"			{ 	return resw(CON, C_QUALIFIER); }
 "continue"		{ return(C_CONTINUE); }
 "default"		{ return(C_DEFAULT); }
 "do"			{ return(C_DO); }
@@ -125,60 +125,48 @@
 			  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); }
+"struct"		{ yylval.intval = STNAME; 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); }
+"union"			{ yylval.intval = UNAME; 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); }
+"volatile"		{	return resw(VOL, C_QUALIFIER); }
 "while"			{ return(C_WHILE); }
 
-{L}({L}|{D})*		{ 	struct symtab *s;
-				int i;
+{L}({L}|{D})*	{ 	struct symtab *s;
+			int i = 0;
 
-				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);
+			yylval.strp = addname(yytext);
+#ifdef GCC_COMPAT
+			if ((i = gcc_keyword(yylval.strp, &yylval.nodep)) > 0)
+				return i;
+#endif
+			if (i == 0) {
+				if (notype)
+					return(C_NAME);
+				s = lookup(yylval.strp, SNOCREAT);
+				return s && s->sclass == TYPEDEF ?
+				    notype=1, C_TYPENAME : 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;
-			}
+{D}+{E}{FS}?		{ yylval.nodep = floatcon(yytext); return(C_FCON); }
+{D}*"."{D}+({E})?{FS}?	{ yylval.nodep = floatcon(yytext); return(C_FCON); }
+{D}+"."{D}*({E})?{FS}?	{ yylval.nodep = floatcon(yytext); return(C_FCON); }
+0[xX]{H}*"."{H}+{P}{FS}? { yylval.nodep = fhexcon(yytext); return(C_FCON); }
+0[xX]{H}+"."{P}{FS}?	{ yylval.nodep = fhexcon(yytext); return(C_FCON); }
+0[xX]{H}+{P}{FS}?	{ yylval.nodep = fhexcon(yytext); return(C_FCON); }
+
+L?\"(\\.|[^\\"])*\"	{ yylval.strp = yytext; return C_STRING; }
+
 "..."			{ return(C_ELLIPSIS); }
 ">>="			{ yylval.intval = RSEQ; return(C_ASOP); }
 "<<="			{ yylval.intval = LSEQ; return(C_ASOP); }
@@ -203,12 +191,16 @@
 "!="			{ yylval.intval = NE; return(C_EQUOP); }
 ";"			{ notype = 0; return(';'); }
 ("{"|"<%")		{ notype = 0; return('{'); }
-("}"|"%>")		{ return('}'); }
+("}"|"%>")		{ if (rpole) notype = 1; return('}'); }
 ","			{ if (parbal) notype = 0; return(','); }
 ":"			{ return(':'); }
 "="			{ return('='); }
 "("			{ parbal++; notype = 0; return('('); }
-")"			{ parbal--; if (parbal==0) { notype = 0; } return(')'); }
+")"			{	parbal--;
+				if (parbal==0) { notype = 0; }
+				if (inattr && parlvl == parbal)
+					inattr = 0;
+				return(')'); }
 ("["|"<:")		{ return('['); }
 ("]"|":>")		{ return(']'); }
 "."			{ yylval.intval = DOT; return(C_STROP); }
@@ -225,7 +217,7 @@
 "^"			{ return('^'); }
 "|"			{ return('|'); }
 "?"			{ return('?'); }
-^#pragma[ \t].*		{ control(CPP_PRAGMA); }
+^#pragma[ \t].*		{ pragma(); }
 ^#ident[ \t].*		{ control(CPP_IDENT); }
 ^#line[ \t].*		{ control(CPP_LINE); }
 ^#.*			{ control(CPP_HASH); }
@@ -246,6 +238,25 @@
 	return(1);
 }
 
+int
+resw(TWORD t, int rv)
+{
+	if (inattr) {
+		yylval.strp = addname(yytext);
+		return C_NAME;
+	}
+
+	switch (rv) {
+	case C_QUALIFIER:
+		yylval.nodep = block(QUALIFIER, NIL, NIL, t, 0, 0);
+		return C_QUALIFIER;
+	default:
+		cerror("resw");
+	}
+	return 0;
+}
+
+#ifndef SOFTFLOAT
 /*
  * XXX floatcon() and fhexcon() should be in support libraries for
  * the target floating point.
@@ -266,9 +277,9 @@
 }
 
 NODE *
-floatcon(void)
+floatcon(char *s)
 {
-	return f2(yytext);
+	return f2(s);
 }
 
 static int
@@ -283,10 +294,9 @@
 }
 
 NODE *
-fhexcon(void)
+fhexcon(char *c)
 {
 	char buf[500];
-	char *c = yytext;
 	unsigned long long num1, num2;
 
 	/* XXX - convert it to a decimal float number and use strtod */
@@ -307,6 +317,7 @@
 	snprintf(buf, sizeof(buf), "%llu.%lluE%s", num1, num2, c);
 	return f2(buf);
 }
+#endif
 
 unsigned int
 esccon(char **sptr)
@@ -325,9 +336,13 @@
 	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);
+	case '5': case '6': case '7':
+		val = wr[-1] - '0';
+		if (*wr >= '0' && *wr <= '7') {
+			val = (val << 3) + (*wr++ - '0');
+			if (*wr >= '0' && *wr <= '7')
+				val = (val << 3) + (*wr++ - '0');
+		}
 		break;
 	default: val = wr[-1];
 	}
@@ -387,8 +402,7 @@
 			ntype = UNSIGNED;
 	}
 	ntype = ctype(ntype);
-	p = block(ICON, NIL, NIL, ntype, 0, MKSUE(ntype));
-	p->n_lval = v;
+	p = xbcon(v, NULL, ntype);
 	ASGLVAL(p->n_slval, v);
 
 	return p;
@@ -432,7 +446,6 @@
 
 	wr++;	/* Skip initial '#' */
 	switch (t) {
-	case CPP_PRAGMA:
 	case CPP_IDENT:
 		return;	/* Just skip these for now. */
 
@@ -447,6 +460,8 @@
 		lineno = val - 1;
 		while (*wr && *wr != '\"')
 			wr++;
+		if (*wr == 0)
+			return;
 		if (*wr++ != '\"')
 			goto bad;
 		eptr = wr;
@@ -465,3 +480,62 @@
 bad:
 	werror("%s: illegal control", yytext);
 }
+
+/*
+ * split a pragma string in parts.
+ */
+static char **
+splitup(char *str)
+{
+	char *s, **ary;
+	int i;
+
+	/* count ws. at least needed array size, add 2 to terminate */
+	for (i = 2, s = str; *s; s++)
+		if (*s == ' ' || *s == '\t' ||
+		    *s == '(' || *s == ')' || *s == ',')
+			i++;
+	ary = tmpalloc(sizeof(char *)*i);
+	for (i = 0, s = strtok(str, " \t(,)"); s; s = strtok(NULL, " \t(,)"))
+		ary[i++] = s;
+	ary[i] = NULL;
+	return ary;
+}
+
+int pragma_allpacked;
+int pragma_packed, pragma_aligned;
+char *pragma_renamed;
+
+/*
+ * got a full pragma line.  Split it up here.
+ */
+static void
+pragma()
+{
+	char **ary;
+
+	ary = splitup(yytext);
+	if (ary[1] == NULL)
+		goto bad;
+	if (strcmp(ary[1], "pack") == 0) {
+		pragma_allpacked = ary[2] ? atoi(ary[2]) : 0;
+	} else if (strcmp(ary[1], "packed") == 0) {
+		pragma_packed = ary[2] ? atoi(ary[2]) : 1;
+	} else if (strcmp(ary[1], "aligned") == 0) {
+		pragma_aligned = ary[2] ? atoi(ary[2]) : 1;
+	} else if (strcmp(ary[1], "rename") == 0) {
+		pragma_renamed = newstring(ary[2], strlen(ary[2]));
+	} else if (mypragma(ary)) {
+		return;
+	} else {
+bad:
+		if (Wunknown_pragmas)
+			werror("unknown pragma");
+	}
+}
+
+void
+cunput(char c)
+{
+	unput(c);
+}
Index: pftn.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/pftn.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/ccom/pftn.c -L usr.bin/pcc/ccom/pftn.c -u -r1.1 -r1.2
--- usr.bin/pcc/ccom/pftn.c
+++ usr.bin/pcc/ccom/pftn.c
@@ -1,4 +1,4 @@
-/*	$Id: pftn.c,v 1.171 2007/09/23 20:00:22 ragge Exp $	*/
+/*	$Id: pftn.c,v 1.241 2008/12/14 17:19:50 ragge Exp $	*/
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -69,49 +69,41 @@
 
 #include <string.h> /* XXX - for strcmp */
 
-struct symtab *spname;
+#include "cgram.h"
+
 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 */
+    argoff;		/* the next unused argument offset */
 int retlab = NOLAB;	/* return label for subroutine */
 int brklab;
 int contlab;
 int flostat;
-int instruct, blevel;
+int blevel;
 int reached, prolab;
 
 struct params;
 
-#define ISSTR(ty) (ty == STRTY || ty == UNIONTY || ty == ENUMTY)
+#define ISSTR(ty) (ty == STRTY || ty == UNIONTY)
 #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;
+	int	rsou;
+	int	rstr;
 	struct	symtab *rsym;
-};
+	struct	symtab *rb;
+	struct	suedef *rsue;
+	int	flags;
+#define	LASTELM	1
+} *rpole;
 
 /*
  * Linked list for parameter (and struct elements) declaration.
@@ -127,6 +119,7 @@
 static NODE *arrstk[10];
 static int arrstkp;
 static int intcompare;
+static NODE *parlink;
 
 void fixtype(NODE *p, int class);
 int fixclass(int class, TWORD type);
@@ -135,9 +128,9 @@
 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);
+extern int fun_inline;
 
 int ddebug = 0;
 
@@ -161,6 +154,9 @@
 
 	p = q->n_sp;
 
+	if (p->sname == NULL)
+		cerror("defining null identifier");
+
 #ifdef PCC_DEBUG
 	if (ddebug) {
 		printf("defid(%s (%p), ", p->sname, p);
@@ -195,16 +191,13 @@
 	if (blevel == 1) {
 		switch (class) {
 		default:
-			if (!(class&FIELD))
+			if (!(class&FIELD) && !ISFTN(type))
 				uerror("declared argument %s missing",
 				    p->sname );
 		case MOS:
-		case STNAME:
 		case MOU:
-		case UNAME:
-		case MOE:
-		case ENAME:
 		case TYPEDEF:
+		case PARAM:
 			;
 		}
 	}
@@ -228,10 +221,11 @@
 	changed = 0;
 	for (temp = type; temp & TMASK; temp = DECREF(temp)) {
 		if (ISARY(temp)) {
-			if (dsym->ddim == 0) {
+			if (dsym->ddim == NOOFFSET) {
 				dsym->ddim = ddef->ddim;
 				changed = 1;
-			} else if (ddef->ddim != 0 && dsym->ddim!=ddef->ddim) {
+			} else if (ddef->ddim != NOOFFSET &&
+			    dsym->ddim!=ddef->ddim) {
 				goto mismatch;
 			}
 			++dsym;
@@ -252,9 +246,7 @@
 #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) {
+	if ((temp == STRTY || temp == UNIONTY) && p->ssue != q->n_sue) {
 		goto mismatch;
 	}
 
@@ -265,99 +257,87 @@
 		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) {
+	if (class & FIELD)
+		return;
+	switch(class) {
 
 	case EXTERN:
 		switch( scl ){
 		case STATIC:
 		case USTATIC:
-			if( slev==0 ) return;
+			if( slev==0 )
+				goto done;
 			break;
 		case EXTDEF:
 		case EXTERN:
 		case FORTRAN:
 		case UFORTRAN:
-			return;
+			goto done;
+		case SNULL:
+			if (p->sflags & SINLINE) {
+				p->sclass = EXTDEF;
+				inline_ref(p);
+				goto done;
 			}
+			break;
+		}
 		break;
 
 	case STATIC:
 		if (scl==USTATIC || (scl==EXTERN && blevel==0)) {
 			p->sclass = STATIC;
-			return;
+			goto done;
 		}
 		if (changed || (scl == STATIC && blevel == slev))
-			return; /* identical redeclaration */
+			goto done; /* identical redeclaration */
 		break;
 
 	case USTATIC:
 		if (scl==STATIC || scl==USTATIC)
-			return;
+			goto done;
 		break;
 
 	case TYPEDEF:
 		if (scl == class)
-			return;
+			goto done;
 		break;
 
 	case UFORTRAN:
 		if (scl == UFORTRAN || scl == FORTRAN)
-			return;
+			goto done;
 		break;
 
 	case FORTRAN:
 		if (scl == UFORTRAN) {
 			p->sclass = FORTRAN;
-			return;
+			goto done;
 		}
 		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;
+		goto done;
 
 	case EXTDEF:
 		switch (scl) {
 		case EXTERN:
 			p->sclass = EXTDEF;
-			return;
+			goto done;
 		case USTATIC:
 			p->sclass = STATIC;
-			return;
+			goto done;
 		}
 		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.. */
+		if (blevel == slev)
+			goto redec;
+		break;  /* mismatch.. */
+	case SNULL:
+		if (fun_inline && ISFTN(type))
+			goto done;
+		break;
 	}
 
 	mismatch:
@@ -368,12 +348,12 @@
 	if (blevel == slev || class == EXTERN || class == FORTRAN ||
 	    class == UFORTRAN) {
 		if (ISSTR(class) && !ISSTR(p->sclass)) {
-			uerror("redeclaration of %s", p->sname);
+redec:			uerror("redeclaration of %s", p->sname);
 			return;
 		}
 	}
 	if (blevel == 0)
-		uerror("redeclaration of %s", p->sname);
+		goto redec;
 	q->n_sp = p = hide(p);
 
 	enter:  /* make a new entry */
@@ -387,24 +367,9 @@
 	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));
-		}
-	}
+	if (q->n_sue == NULL)
+		cerror("q->n_sue == NULL");
+	p->ssue = q->n_sue;
 
 	/* copy dimensions */
 	p->sdf = q->n_df;
@@ -415,7 +380,6 @@
 	/* allocate offsets */
 	if (class&FIELD) {
 		(void) falloc(p, class&FLDSIZ, 0, NIL);  /* new entry */
-		ssave(p);
 	} else switch (class) {
 
 	case REGISTER:
@@ -427,47 +391,45 @@
 		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;
+	case PARAM:
+		if (ISARY(p->stype)) {
+			/* remove array type on parameters before oalloc */
+			p->stype += (PTR-ARY);
+			p->sdf++;
 		}
-#endif
+		if (arrstkp)
+			dynalloc(p, &argoff);
+		else
+			oalloc(p, &argoff);
 		break;
-
+		
+	case STATIC:
+	case EXTDEF:
 	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
+		if (pragma_renamed)
+			p->soname = pragma_renamed;
+		pragma_renamed = NULL;
 		break;
+
 	case MOU:
+		rpole->rstr = 0;
+		/* FALLTHROUGH */
 	case MOS:
-		oalloc(p, &strucoff);
+		oalloc(p, &rpole->rstr);
 		if (class == MOU)
-			strucoff = 0;
-		ssave(p);
+			rpole->rstr = 0;
 		break;
-
-	case MOE:
-		p->soffset = strucoff++;
-		ssave(p);
+	case SNULL:
+#ifdef notdef
+		if (fun_inline) {
+			p->slevel = 1;
+			p->soffset = getlab();
+		}
+#endif
 		break;
-
 	}
 
 #ifdef STABS
@@ -475,12 +437,13 @@
 		stabs_newsym(p);
 #endif
 
+done:
+	fixdef(p);	/* Leave last word to target */
 #ifdef PCC_DEBUG
 	if (ddebug)
 		printf( "	sdf, ssue, offset: %p, %p, %d\n",
 		    p->sdf, p->ssue, p->soffset);
 #endif
-
 }
 
 void
@@ -492,13 +455,10 @@
 	p->next = NULL;
 	p->sym = sym;
 
-	if (lparam == NULL) {
-		p->prev = (struct params *)&lpole;
+	if ((p->prev = lparam) == NULL)
 		lpole = p;
-	} else {
+	else
 		lparam->next = p;
-		p->prev = lparam;
-	}
 	lparam = p;
 }
 
@@ -508,22 +468,24 @@
 void
 ftnend()
 {
+	extern NODE *cftnod;
 	extern struct savbc *savbc;
 	extern struct swdef *swpole;
+	extern int tvaloff;
 	char *c;
 
 	if (retlab != NOLAB && nerrors == 0) { /* inside a real function */
 		plabel(retlab);
+		if (cftnod)
+			ecomp(buildtree(FORCE, cftnod, NIL));
 		efcode(); /* struct return handled here */
-		c = cftnsp->sname;
-#ifdef GCC_COMPAT
-		c = gcc_findname(cftnsp);
-#endif
+		c = cftnsp->soname;
 		SETOFF(maxautooff, ALCHAR);
-		send_passt(IP_EPILOG, 0, maxautooff/SZCHAR, c,
-		    cftnsp->stype, cftnsp->sclass == EXTDEF, retlab);
+		send_passt(IP_EPILOG, maxautooff/SZCHAR, c,
+		    cftnsp->stype, cftnsp->sclass == EXTDEF, retlab, tvaloff);
 	}
 
+	cftnod = NIL;
 	tcheck();
 	brklab = contlab = retlab = NOLAB;
 	flostat = 0;
@@ -537,6 +499,7 @@
 	}
 	savbc = NULL;
 	lparam = NULL;
+	cftnsp = NULL;
 	maxautooff = autooff = AUTOINIT;
 	reached = 1;
 
@@ -544,11 +507,13 @@
 		inline_end();
 	inline_prtout();
 
-	strprint();
-
 	tmpfree(); /* Release memory resources */
 }
 
+static struct symtab nulsym = {
+	NULL, 0, 0, 0, 0, "null", "null", INT, 0, NULL, NULL
+};
+
 void
 dclargs()
 {
@@ -556,15 +521,12 @@
 	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)
+	if (nparams == 1 && lparam->sym && lparam->sym->stype == VOID)
 		goto done;
 
 	/*
@@ -575,11 +537,13 @@
 		parr = tmpalloc(sizeof(struct symtab *) * nparams);
 
 	if (nparams)
-	    for (a = lparam, i = 0; a != NULL && a != (struct params *)&lpole;
-	    a = a->prev) {
-
+	    for (a = lparam, i = 0; a != NULL; a = a->prev) {
 		p = a->sym;
 		parr[i++] = p;
+		if (p == NULL) {
+			uerror("parameter %d name missing", i);
+			p = &nulsym; /* empty symtab */
+		}
 		if (p->stype == FARG) {
 			p->stype = INT;
 			p->ssue = MKSUE(INT);
@@ -591,8 +555,6 @@
 			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);
@@ -618,41 +580,66 @@
 		if (chkftn(al, alb))
 			uerror("function doesn't match prototype");
 		intcompare = 0;
+
 	}
+
+	if (oldstyle && nparams) {
+		/* Must recalculate offset for oldstyle args here */
+		argoff = ARGINIT;
+		for (i = 0; i < nparams; i++) {
+			parr[i]->soffset = NOOFFSET;
+			oalloc(parr[i], &argoff);
+		}
+	}
+
 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 */
-	}
+	if (fun_inline && xinline)
+		inline_args(parr, nparams);
+	plabel(getlab()); /* used when spilling */
+	if (parlink)
+		ecomp(parlink);
+	parlink = NIL;
 	lparam = NULL;
 	nparams = 0;
+	symclear(1);	/* In case of function pointer args */
+}
+
+/*
+ * Struct/union/enum symtab construction.
+ */
+static void
+defstr(struct symtab *sp, int class)
+{
+	sp->ssue = permalloc(sizeof(struct suedef));
+	memset(sp->ssue, 0, sizeof(struct suedef));
+	sp->sclass = class;
+	if (class == STNAME)
+		sp->stype = STRTY;
+	else if (class == UNAME)
+		sp->stype = UNIONTY;
+	else if (class == ENAME)
+		sp->stype = ENUMTY;
+}
+
+/*
+ * Declare a struct/union/enum tag.
+ * If not found, create a new tag with UNDEF type.
+ */
+static struct symtab *
+deftag(char *name, int class)
+{
+	struct symtab *sp;
+
+	if ((sp = lookup(name, STAGNAME))->ssue == NULL) {
+		/* New tag */
+		defstr(sp, class);
+	} else if (sp->sclass != class)
+		uerror("tag %s redeclared", name);
+	return sp;
 }
 
 /*
@@ -661,194 +648,246 @@
 NODE *
 rstruct(char *tag, int soru)
 {
-	struct symtab *p;
-	NODE *q;
+	struct symtab *sp;
 
-	p = (struct symtab *)lookup(tag, STAGNAME);
-	switch (p->stype) {
+	sp = deftag(tag, soru);
+	return mkty(sp->stype, 0, sp->ssue);
+}
 
-	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;
+static int enumlow, enumhigh;
+int enummer;
 
-	case STRTY:
-		if (soru & INSTRUCT)
-			break;
-		goto def;
+/*
+ * Declare a member of enum.
+ */
+void
+moedef(char *name)
+{
+	struct symtab *sp;
 
-	case UNIONTY:
-		if (soru & INUNION)
-			break;
-		goto def;
+	sp = lookup(name, SNORMAL);
+	if (sp->stype == UNDEF || (sp->slevel < blevel)) {
+		if (sp->stype != UNDEF)
+			sp = hide(sp);
+		sp->stype = INT; /* always */
+		sp->ssue = MKSUE(INT);
+		sp->sclass = MOE;
+		sp->soffset = enummer;
+	} else
+		uerror("%s redeclared", name);
+	if (enummer < enumlow)
+		enumlow = enummer;
+	if (enummer > enumhigh)
+		enumhigh = enummer;
+	enummer++;
+}
 
-	case ENUMTY:
-		if (!(soru&(INUNION|INSTRUCT)))
-			break;
-		goto def;
+/*
+ * Declare an enum tag.  Complain if already defined.
+ */
+struct symtab *
+enumhd(char *name)
+{
+	struct symtab *sp;
+
+	enummer = enumlow = enumhigh = 0;
+	if (name == NULL)
+		return NULL;
 
+	sp = deftag(name, ENAME);
+	if (sp->stype != ENUMTY) {
+		if (sp->slevel == blevel)
+			uerror("%s redeclared", name);
+		sp = hide(sp);
+		defstr(sp, ENAME);
 	}
-	q = mkty(p->stype, 0, p->ssue);
-	q->n_sue = p->ssue;
-	return q;
+	sp->ssue->sylnk = sp;	/* ourselves */
+	return sp;
 }
 
-void
-moedef(char *name)
+/*
+ * finish declaration of an enum
+ */
+NODE *
+enumdcl(struct symtab *sp)
 {
-	NODE *q;
+	NODE *p;
+	TWORD t;
 
-	q = block(NAME, NIL, NIL, MOETY, 0, 0);
-	q->n_sp = lookup(name, 0);
-	defid(q, MOE);
-	nfree(q);
+#ifdef ENUMSIZE
+	t = ENUMSIZE(enumhigh, enumlow);
+#else
+	if (enumhigh <= MAX_CHAR && enumlow >= MIN_CHAR)
+		t = ctype(CHAR);
+	else if (enumhigh <= MAX_SHORT && enumlow >= MIN_SHORT)
+		t = ctype(SHORT);
+	else
+		t = ctype(INT);
+#endif
+	if (sp) {
+		sp->stype = t;
+		sp->ssue = MKSUE(t);
+	}
+	p = mkty(t, 0, MKSUE(t));
+	p->n_sp = sp;
+	return p;
+}
+
+/*
+ * Handle reference to an enum
+ */
+NODE *
+enumref(char *name)
+{
+	struct symtab *sp;
+	NODE *p;
+
+	sp = lookup(name, STAGNAME);
+
+#ifdef notdef
+	/*
+	 * 6.7.2.3 Clause 2:
+	 * "A type specifier of the form 'enum identifier' without an
+	 *  enumerator list shall only appear after the type it specifies
+	 *  is complete."
+	 */
+	if (sp->sclass != ENAME)
+		uerror("enum %s undeclared", name);
+#endif
+	if (sp->sclass == SNULL) {
+		/* declare existence of enum */
+		sp = enumhd(name);
+		sp->stype = ENUMTY;
+	}
+
+	p = mkty(sp->stype, 0, sp->ssue);
+	p->n_sp = sp;
+	return p;
 }
 
 /*
  * begining of structure or union declaration
  */
 struct rstack *
-bstruct(char *name, int soru)
+bstruct(char *name, int soru, struct suedef *sue)
 {
 	struct rstack *r;
-	struct symtab *s;
-	NODE *q;
+	struct symtab *sp;
 
-	if (name != NULL)
-		s = lookup(name, STAGNAME);
-	else
-		s = NULL;
+	if (name != NULL) {
+		sp = deftag(name, soru);
+		if (sp->ssue->suealign != 0) {
+			if (sp->slevel < blevel) {
+				sp = hide(sp);
+				defstr(sp, soru);
+			} else
+				uerror("%s redeclared", name);
+		}
+	} else
+		sp = 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);
+	r = tmpcalloc(sizeof(struct rstack));
+	r->rsou = soru;
+	r->rsym = sp;
+	r->rb = NULL;
+	r->rsue = sue;
+	r->rnext = rpole;
+	rpole = r;
 
 	return r;
 }
 
 /*
  * Called after a struct is declared to restore the environment.
+ * Alignment and packing are handled here.
+ * - If ALSTRUCT is defined, this will be the struct alignment and the
+ *   struct size will be a multiple of ALSTRUCT, otherwise it will use
+ *   the alignment of the largest struct member.
+ * - If suep->suealigned is set, then it will specify the alignment.
+ * - If suep->suepacked is set, it will pack all struct members.
  */
 NODE *
-dclstruct(struct rstack *r)
+dclstruct(struct rstack *r, struct suedef *suep)
 {
 	NODE *n;
-	struct params *l, *m;
 	struct suedef *sue;
-	struct symtab *p;
-	int al, sa, sz;
-	TWORD temp;
-	int i, high, low;
+	struct symtab *sp;
+	int al, sa, sz, coff;
+	struct suedef sues;
+
+	if (suep && r->rsue) { /* merge */
+		if (suep->suealigned == 0)
+			suep->suealigned = r->rsue->suealigned;
+		if (suep->suepacked == 0)
+			suep->suepacked = r->rsue->suepacked;
+	} else if (suep == NULL)
+		suep = r->rsue;
+	if (suep == NULL)
+		suep = memset(&sues, 0, sizeof sues);
+
+	if (pragma_allpacked && !suep->suepacked)
+		suep->suepacked = pragma_allpacked;
 
 	if (r->rsym == NULL) {
 		sue = permalloc(sizeof(struct suedef));
+		memset(sue, 0, 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;
+#ifdef ALSTRUCT
 	al = ALSTRUCT;
+#else
+	al = ALCHAR;
+#endif
 
-	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);
+	/*
+	 * extract size and alignment, recalculate offsets
+	 * if struct should be packed.
+	 */
+	coff = 0;
+	sue->sylnk = r->rb;
+	for (sp = r->rb; sp; sp = sp->snext) {
+		sa = talign(sp->stype, sp->ssue);
+		if (sp->sclass & FIELD)
+			sz = sp->sclass&FLDSIZ;
+		else
+			sz = tsize(sp->stype, sp->sdf, sp->ssue);
+		if (suep->suepacked && r->rsou == STNAME) {
+			sp->soffset = coff;
+			coff += sz;
+			rpole->rstr = coff;
 		}
-		if (sz > strucoff)
-			strucoff = sz;  /* for use with unions */
+		if (sz > rpole->rstr)
+			rpole->rstr = sz;  /* for use with unions */
 		/*
 		 * set al, the alignment, to the lcm of the alignments
 		 * of the members.
 		 */
-		SETOFF(al, sa);
+		if (suep->suepacked == 0)
+			SETOFF(al, sa);
 	}
-	sue->suelem[i] = NULL;
-	SETOFF(strucoff, al);
 
-	if (temp == ENUMTY) {
-		TWORD ty;
+	/* If alignment given is larger that calculated, expand */
+	if (suep->suealigned)
+		SETOFF(al, suep->suealigned);
 
-#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));
-	}
+	SETOFF(rpole->rstr, al);
 
-	sue->suesize = strucoff;
+	sue->suesize = rpole->rstr;
 	sue->suealign = al;
+	sue->suealigned = suep->suealigned;
+	sue->suepacked = suep->suepacked;
+
+#ifdef PCC_DEBUG
+	if (ddebug) {
+		printf("dclstruct(%s): size=%d, align=%d\n",
+		    r->rsym ? r->rsym->sname : "??",
+		    sue->suesize, sue->suealign);
+	}
+#endif
+
+	pragma_packed = pragma_aligned = 0;
 
 #ifdef STABS
 	if (gflag)
@@ -857,25 +896,77 @@
 
 #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]);
+		printf("\tsize %d align %d link %p\n",
+		    sue->suesize, sue->suealign, sue->sylnk);
+		for (sp = sue->sylnk; sp != NULL; sp = sp->snext) {
+			printf("\tmember %s(%p)\n", sp->sname, sp);
 		}
 	}
 #endif
 
-	strucoff = r->rstrucoff;
-	if ((lparam = r->rlparam) != NULL)
-		lparam->next = NULL;
-	n = mkty(temp, 0, sue);
+	rpole = r->rnext;
+	n = mkty(r->rsou == STNAME ? STRTY : UNIONTY, 0, sue);
 	return n;
 }
 
 /*
+ * Add a new member to the current struct or union being declared.
+ */
+void
+soumemb(NODE *n, char *name, int class)
+{
+	struct symtab *sp, *lsp;
+	int incomp;
+ 
+	if (rpole == NULL)
+		cerror("soumemb");
+ 
+	/* check if tag name exists */
+	lsp = NULL;
+	for (sp = rpole->rb; sp != NULL; lsp = sp, sp = sp->snext)
+		if (*name != '*' && sp->sname == name)
+			uerror("redeclaration of %s", name);
+
+	sp = getsymtab(name, SMOSNAME);
+	if (rpole->rb == NULL)
+		rpole->rb = sp;
+	else
+		lsp->snext = sp;
+	n->n_sp = sp;
+	if ((class & FIELD) == 0)
+		class = rpole->rsou == STNAME ? MOS : MOU;
+	defid(n, class);
+
+	/*
+	 * 6.7.2.1 clause 16:
+	 * "...the last member of a structure with more than one
+	 *  named member may have incomplete array type;"
+	 */
+	if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET)
+		incomp = 1;
+	else
+		incomp = 0;
+	if ((rpole->flags & LASTELM) || (rpole->rb == sp && incomp == 1))
+		uerror("incomplete array in struct");
+	if (incomp == 1)
+		rpole->flags |= LASTELM;
+
+	/*
+	 * 6.7.2.1 clause 2:
+	 * "...such a structure shall not be a member of a structure
+	 *  or an element of an array."
+	 */
+	if (rpole->rsou == STNAME && sp->ssue->sylnk) {
+		struct symtab *lnk;
+
+		for (lnk = sp->ssue->sylnk; lnk->snext; lnk = lnk->snext)
+			;
+		if (ISARY(lnk->stype) && lnk->sdf->ddim == NOOFFSET)
+			uerror("incomplete struct in struct");
+	}
+}
+
+/*
  * error printing routine in parser
  */
 void yyerror(char *s);
@@ -900,74 +991,44 @@
 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.
+	 * Push argument symtab entries onto 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)
+		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);
+			ssave(q->n_sp);
 			nparams++;
 #ifdef PCC_DEBUG
 			if (ddebug > 2)
 				printf("	saving sym %s (%p) from (%p)\n",
-				    s->sname, s, q);
+				    q->n_sp->sname, q->n_sp, 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);
+	ssave(p->n_sp);
 	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);
+		    nparams ? p->n_sp->sname : "<noname>", p->n_sp, p);
 #endif
 }
 
@@ -1001,35 +1062,9 @@
 			}
 		}
 
-	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);
-	}
+	if (sue->suealign == 0)
+		uerror("no alignment");
+	return sue->suealign;
 }
 
 /* compute the size associated with type ty,
@@ -1052,6 +1087,8 @@
 		case PTR:
 			return( SZPOINT(ty) * mult );
 		case ARY:
+			if (d->ddim == NOOFFSET)
+				return 0;
 			mult *= d->ddim;
 			d++;
 			continue;
@@ -1074,7 +1111,7 @@
 			return(SZINT);
 		}
 	} else {
-		if (sue->suelem == NULL)
+		if (sue->suealign == 0)
 			uerror("unknown structure/union/enum");
 	}
 
@@ -1082,146 +1119,59 @@
 }
 
 /*
- * Write last part of wide string.
- * Do not bother to save wide strings.
+ * Save string (and print it out).  If wide then wide string.
  */
 NODE *
-wstrend(char *str)
+strend(int wide, 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;
+	struct symtab *sp;
 	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();
+	if (wide) {
+		/* Do not save wide strings, at least not now */
+		sp = getsymtab(str, SSTRING|STEMP);
+	} else {
+		str = addstring(str);	/* enter string in string table */
+		sp = lookup(str, SSTRING);	/* check for existance */
 	}
 
-	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);
-}
+	if (sp->soffset == 0) { /* No string */
+		char *wr;
+		int i;
 
-/*
- * 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);
+		sp->sclass = STATIC;
+		sp->slevel = 1;
+		sp->soffset = getlab();
+		sp->squal = (CON >> TSHIFT);
+		sp->sdf = permalloc(sizeof(union dimfun));
+		if (wide) {
+			sp->stype = WCHAR_TYPE+ARY;
+			sp->ssue = MKSUE(WCHAR_TYPE);
 		} else {
-			bycode(0, i++);
-			bycode(-1, i);
+			if (funsigned_char) {
+				sp->stype = UCHAR+ARY;
+				sp->ssue = MKSUE(UCHAR);
+			} else {
+				sp->stype = CHAR+ARY;
+				sp->ssue = MKSUE(CHAR);
+			}
 		}
-		strpole = strpole->next;
+		for (wr = sp->sname, i = 1; *wr; i++)
+			if (*wr++ == '\\')
+				(void)esccon(&wr);
+
+		sp->sdf->ddim = i;
+		if (wide)
+			inwstring(sp);
+		else
+			instring(sp);
 	}
-	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();
+	p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->ssue);
+	p->n_sp = sp;
+	return(clocal(p));
 }
-#endif
 
 /*
  * update the offset pointed to by poff; return the
@@ -1253,14 +1203,13 @@
 	/*
 	 * Only generate tempnodes if we are optimizing,
 	 * and only for integers, floats or pointers,
-	 * and not if the basic type is volatile.
+	 * and not if the type on this level 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)) {
+	    !(cqual(p->stype, p->squal) & VOL) && cisreg(p->stype)) {
 		NODE *tn = tempnode(0, p->stype, p->sdf, p->ssue);
-		p->soffset = tn->n_lval;
+		p->soffset = regno(tn);
 		p->sflags |= STNODE;
 		nfree(tn);
 		return 0;
@@ -1279,7 +1228,7 @@
 	} else
 #endif
 	if (p->sclass == PARAM && (p->stype == CHAR || p->stype == UCHAR ||
-	    p->stype == SHORT || p->stype == USHORT)) {
+	    p->stype == SHORT || p->stype == USHORT || p->stype == BOOL)) {
 		off = upoff(SZINT, ALINT, &noff);
 #ifndef RTOLBYTES
 		off = noff - tsz;
@@ -1301,7 +1250,24 @@
 }
 
 /*
- * Allocate space on the stack for dynamic arrays.
+ * Delay emission of code generated in argument headers.
+ */
+static void
+edelay(NODE *p)
+{
+	if (blevel == 1) {
+		/* Delay until after declarations */
+		if (parlink == NULL)
+			parlink = p;
+		else
+			parlink = block(COMOP, parlink, p, 0, 0, 0);
+	} else
+		ecomp(p);
+}
+
+/*
+ * Allocate space on the stack for dynamic arrays (or at least keep track
+ * of the index).
  * 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.
@@ -1316,41 +1282,68 @@
 	union dimfun *df;
 	NODE *n, *nn, *tn, *pol;
 	TWORD t;
-	int i, no;
+	int astkp, no;
 
 	/*
-	 * The pointer to the array is stored in a TEMP node, which number
-	 * is in the soffset field;
+	 * The pointer to the array is not necessarily stored in a
+	 * TEMP node, but if it is, its 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;
+	astkp = 0;
+	if (ISARY(t) && blevel == 1) {
+		/* must take care of side effects of dynamic arg arrays */
+		if (p->sdf->ddim < 0 && p->sdf->ddim != NOOFFSET) {
+			/* first-level array will be indexed correct */
+			edelay(arrstk[astkp++]);
+		}
+		p->sdf++;
+		p->stype += (PTR-ARY);
+		t = p->stype;
+	}
+	if (ISARY(t)) {
+		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 = regno(tn);
+	} else {
+		oalloc(p, poff);
+		tn = NIL;
+	}
 
 	df = p->sdf;
 
 	pol = NIL;
-	for (i = 0; ISARY(t); t = DECREF(t), df++) {
-		if (df->ddim >= 0)
+	for (; t > BTMASK; t = DECREF(t)) {
+		if (!ISARY(t))
 			continue;
-		n = arrstk[i++];
-		nn = tempnode(0, INT, 0, MKSUE(INT));
-		no = nn->n_lval;
-		ecomp(buildtree(ASSIGN, nn, n)); /* Save size */
+		if (df->ddim < 0) {
+			n = arrstk[astkp++];
+			do {
+				nn = tempnode(0, INT, 0, MKSUE(INT));
+				no = regno(nn);
+			} while (no == -NOOFFSET);
+			edelay(buildtree(ASSIGN, nn, n));
 
-		df->ddim = -no;
-		n = tempnode(no, INT, 0, MKSUE(INT));
-		if (pol == NIL)
-			pol = n;
-		else
-			pol = buildtree(MUL, pol, n);
+			df->ddim = -no;
+			n = tempnode(no, INT, 0, MKSUE(INT));
+		} else
+			n = bcon(df->ddim);
+
+		pol = (pol == NIL ? n : buildtree(MUL, pol, n));
+		df++;
 	}
 	/* Create stack gap */
-	if (pol == NIL)
-		uerror("aggregate dynamic array not allowed");
-	else
-		spalloc(tn, pol, tsize(t, 0, p->ssue));
+	if (blevel == 1) {
+		if (tn)
+			tfree(tn);
+		if (pol)
+			tfree(pol);
+	} else {
+		if (pol == NIL)
+			uerror("aggregate dynamic array not allowed");
+		if (tn)
+			spalloc(tn, pol, tsize(t, 0, p->ssue));
+	}
 	arrstkp = 0;
 }
 
@@ -1368,14 +1361,6 @@
 	/* 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;
@@ -1409,24 +1394,24 @@
 		}
 
 	if( w == 0 ){ /* align only */
-		SETOFF( strucoff, al );
+		SETOFF( rpole->rstr, al );
 		if( new >= 0 ) uerror( "zero size field");
 		return(0);
 		}
 
-	if( strucoff%al + w > sz ) SETOFF( strucoff, al );
+	if( rpole->rstr%al + w > sz ) SETOFF( rpole->rstr, al );
 	if( new < 0 ) {
-		strucoff += w;  /* we know it will fit */
+		rpole->rstr += 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);
+		if( p->soffset != rpole->rstr || p->sclass != (FIELD|w) ) return(1);
 		}
-	p->soffset = strucoff;
-	strucoff += w;
+	p->soffset = rpole->rstr;
+	rpole->rstr += w;
 	p->stype = type;
 	fldty( p );
 	return(0);
@@ -1448,7 +1433,7 @@
 	if (class == SNULL) {
 		if (blevel > 1)
 			class = AUTO;
-		else if (blevel != 0 || instruct)
+		else if (blevel != 0 || rpole)
 			cerror( "nidcl error" );
 		else /* blevel = 0 */
 			commflag = 1, class = EXTERN;
@@ -1458,7 +1443,7 @@
 
 	sp = p->n_sp;
 	/* check if forward decl */
-	if (ISARY(sp->stype) && sp->sdf->ddim == 0)
+	if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET)
 		return;
 
 	if (sp->sflags & SASG)
@@ -1479,7 +1464,7 @@
 		if (blevel == 0)
 			lcommadd(p->n_sp);
 		else
-			lcommdec(p->n_sp);
+			defzero(p->n_sp);
 		break;
 	}
 }
@@ -1539,173 +1524,161 @@
 	struct lcd *lc;
 
 	SLIST_FOREACH(lc, &lhead, next) {
-		if (lc->sp != NULL) {
-			if (lc->sp->sclass == STATIC)
-				lcommdec(lc->sp);
-			else
-				commdec(lc->sp);
-		}
+		if (lc->sp != NULL)
+			defzero(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?
+ * Merge given types to a single node.
+ * Any type can end up here.
+ * p is the old node, q is the old (if any).
+ * CLASS is AUTO, EXTERN, REGISTER, STATIC or TYPEDEF.
+ * QUALIFIER is VOL or CON
+ * TYPE is CHAR, SHORT, INT, LONG, SIGNED, UNSIGNED, VOID, BOOL, FLOAT,
+ * 	DOUBLE, STRTY, UNIONTY.
  */
 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");
+	NODE *q, *saved;
+	TWORD type;
+	int class, qual;
+	int sig, uns, cmplx;
+
+	cmplx = type = class = qual = sig = uns = 0;
+	saved = NIL;
+
+	for (q = p; p; p = p->n_left) {
+		switch (p->n_op) {
+		case CLASS:
+			if (class)
+				goto bad; /* max 1 class */
 			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;
+
+		case QUALIFIER:
+			qual |= p->n_type >> TSHIFT;
 			break;
-		case LONG:
-			if (adj == LONG) {
-				adj = LONGLONG;
+
+		case TYPE:
+			if (p->n_sp != NULL || ISSOU(p->n_type)) {
+				/* typedef, enum or struct/union */
+				if (saved || type)
+					goto bad;
+				saved = p;
 				break;
-			}
-			/* FALLTHROUGH */
-		case SHORT:
-			if (adj != INT)
+			} else if ((p->n_type == SIGNED && uns) ||
+			    (p->n_type == UNSIGNED && sig))
 				goto bad;
-			adj = p->n_type;
-			break;
-		case INT:
-		case CHAR:
+
+			switch (p->n_type) {
+			case BOOL:
+			case CHAR:
+			case FLOAT:
+			case VOID:
+				if (type)
+					goto bad;
+				type = p->n_type;
+				break;
+			case DOUBLE:
+				if (type == 0)
+					type = DOUBLE;
+				else if (type == LONG)
+					type = LDOUBLE;
+				else
+					goto bad;
+				break;
+			case SHORT:
+				if (type == 0 || type == INT)
+					type = SHORT;
+				else
+					goto bad;
+				break;
+			case INT:
+				if (type == SHORT || type == LONG ||
+				    type == LONGLONG)
+					break;
+				else if (type == 0)
+					type = INT;
+				else
+					goto bad;
+				break;
+			case LONG:
+				if (type == 0)
+					type = LONG;
+				else if (type == INT)
+					break;
+				else if (type == LONG)
+					type = LONGLONG;
+				else if (type == DOUBLE)
+					type = LDOUBLE;
+				else
+					goto bad;
+				break;
+			case SIGNED:
+				if (sig || uns)
+					goto bad;
+				sig = 1;
+				break;
+			case UNSIGNED:
+				if (sig || uns)
+					goto bad;
+				uns = 1;
+				break;
+			case COMPLEX:
+				cmplx = 1;
+				break;
+			default:
+				cerror("typenode");
+			}
+		}
+	}
+	if (cmplx) {
+		if (sig || uns)
+			goto bad;
+		switch (type) {
 		case FLOAT:
-		case DOUBLE:
-			if (noun != UNDEF)
-				goto bad;
-			noun = p->n_type;
+			type = FCOMPLEX;
 			break;
-		case VOID:
-			if (noun != UNDEF || adj != INT)
-				goto bad;
-			adj = noun = VOID;
+		case DOUBLE:
+			type = COMPLEX;
 			break;
-		case STRTY:
-		case UNIONTY:
+		case LDOUBLE:
+			type = LCOMPLEX;
 			break;
 		default:
 			goto bad;
 		}
-	next:
-		l = p->n_left;
-		nfree(p);
-		p = l;
 	}
 
-	if (sp) {
-		p = sp;
-		goto uni;
+	if (saved && type)
+		goto bad;
+	if (sig || uns) {
+		if (type == 0)
+			type = sig ? INT : UNSIGNED;
+		if (type > ULONGLONG)
+			goto bad;
+		if (uns)
+			type = ENUNSIGN(type);
 	}
 
-#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 (funsigned_char && type == CHAR && sig == 0)
+		type = UCHAR;
+
+	/* free the chain */
+	while (q) {
+		p = q->n_left;
+		if (q != saved)
+			nfree(q);
+		q = p;
+	}
 
-	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 = (saved ? saved : block(TYPE, NIL, NIL, type, 0, 0));
+	p->n_qual = qual;
 	p->n_lval = class;
+	if (BTYPE(p->n_type) == UNDEF)
+		MODTYPE(p->n_type, INT);
 	return p;
 
 bad:	uerror("illegal type combination");
@@ -1729,13 +1702,18 @@
 	(*ntdim)++;
 }
 
-/* merge type typ with identifier idp  */
+/*
+ * merge type typ with identifier idp.
+ * idp is returned as a NAME node with correct types.
+ * typ is untouched.
+ */
 NODE *
 tymerge(NODE *typ, NODE *idp)
 {
 	NODE *p;
 	union dimfun *j;
 	struct tylnk *base, tylnk, *tylkp;
+	struct suedef *sue;
 	unsigned int t;
 	int ntdim, i;
 
@@ -1750,8 +1728,10 @@
 	}
 #endif
 
+	sue = idp->n_sue;
+
 	idp->n_type = typ->n_type;
-	idp->n_qual = (typ->n_qual << TSHIFT) | idp->n_qual; /* XXX ??? */
+	idp->n_qual |= typ->n_qual;
 
 	tylkp = &tylnk;
 	tylkp->next = NULL;
@@ -1776,12 +1756,29 @@
 	/* 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 1
+	if (sue) {
+		struct suedef *s = permalloc(sizeof(struct suedef));
+		*s = *idp->n_sue;
+		idp->n_sue = s;
+		if (sue->suealigned > s->suealign)
+			s->suealign = sue->suealigned;
+		s->suepacked = sue->suepacked;
+		s->suesection = sue->suesection;
+	}
+#else
+	if (sue) {
+		if (sue->suealigned > idp->n_sue->suealign)
+			idp->n_sue->suealign = sue->suealigned;
+		idp->n_sue->suepacked = sue->suepacked;
+	}
+#endif
+
 	if (idp->n_op != NAME) {
 		for (p = idp->n_left; p->n_op != NAME; p = p->n_left)
 			nfree(p);
@@ -1818,8 +1815,7 @@
 		if (w->n_right->n_op == ELLIPSIS)
 			continue;
 		ty = w->n_right->n_type;
-		if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY ||
-		    BTYPE(ty) == ENUMTY)
+		if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY)
 			num++;
 		while (ISFTN(ty) == 0 && ISARY(ty) == 0 && ty > BTMASK)
 			ty = DECREF(ty);
@@ -1828,8 +1824,7 @@
 	}
 	cnt++;
 	ty = w->n_type;
-	if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY ||
-	    BTYPE(ty) == ENUMTY)
+	if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY)
 		num++;
 	while (ISFTN(ty) == 0 && ISARY(ty) == 0 && ty > BTMASK)
 		ty = DECREF(ty);
@@ -1863,8 +1858,7 @@
 			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)
+		if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY)
 			al[k++].sue = ap[j]->n_sue;
 		while (ISFTN(ty) == 0 && ISARY(ty) == 0 && ty > BTMASK)
 			ty = DECREF(ty);
@@ -1875,8 +1869,10 @@
 	if (k > num)
 		cerror("arglist: k%d > num%d", k, num);
 	tfree(n);
+#ifdef PCC_DEBUG
 	if (pdebug)
 		alprint(al, 0);
+#endif
 	return al;
 }
 
@@ -1894,8 +1890,10 @@
 	TWORD t, q;
 
 	o = p->n_op;
-	if (o == NAME)
+	if (o == NAME) {
+		p->n_qual = DECQAL(p->n_qual);
 		return;
+	}
 
 	t = INCREF(p->n_type);
 	q = p->n_qual;
@@ -1918,7 +1916,7 @@
 			nfree(p->n_right);
 #ifdef notdef
 	/* XXX - check dimensions at usage time */
-			if (dim.ddim == 0 && p->n_left->n_op == LB)
+			if (dim.ddim == NOOFFSET && p->n_left->n_op == LB)
 				uerror("null dimension");
 #endif
 		}
@@ -1975,25 +1973,153 @@
 	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;
+		return bcon(0);
 	}
 	t = tempnode(0, VOID|PTR, 0, MKSUE(INT) /* XXX */);
-	u = tempnode(t->n_lval, VOID|PTR, 0, MKSUE(INT) /* XXX */);
+	u = tempnode(regno(t), VOID|PTR, 0, MKSUE(INT) /* XXX */);
 	spalloc(t, a, SZCHAR);
 	tfree(f);
 	return u;
 }
+
+/*
+ * Determine if a value is known to be constant at compile-time and
+ * hence that PCC can perform constant-folding on expressions involving
+ * that value.
+ */
+static NODE *
+builtin_constant_p(NODE *f, NODE *a)
+{
+	int isconst = (a != NULL && a->n_op == ICON);
+
+	tfree(f);
+	tfree(a);
+
+	return bcon(isconst);
+}
+
+#ifndef TARGET_STDARGS
+static NODE *
+builtin_stdarg_start(NODE *f, NODE *a)
+{
+	NODE *p, *q;
+	int sz;
+
+	/* check num args and type */
+	if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+	    !ISPTR(a->n_left->n_type))
+		goto bad;
+
+	/* must first deal with argument size; use int size */
+	p = a->n_right;
+	if (p->n_type < INT) {
+		sz = SZINT/tsize(p->n_type, p->n_df, p->n_sue);
+	} else
+		sz = 1;
+
+	/* do the real job */
+	p = buildtree(ADDROF, p, NIL); /* address of last arg */
+#ifdef BACKAUTO
+	p = optim(buildtree(PLUS, p, bcon(sz))); /* add one to it (next arg) */
+#else
+	p = optim(buildtree(MINUS, p, bcon(sz))); /* add one to it (next arg) */
+#endif
+	q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); /* create cast node */
+	q = buildtree(CAST, q, p); /* cast to void * (for assignment) */
+	p = q->n_right;
+	nfree(q->n_left);
+	nfree(q);
+	p = buildtree(ASSIGN, a->n_left, p); /* assign to ap */
+	tfree(f);
+	nfree(a);
+	return p;
+bad:
+	uerror("bad argument to __builtin_stdarg_start");
+	return bcon(0);
+}
+
+static NODE *
+builtin_va_arg(NODE *f, NODE *a)
+{
+	NODE *p, *q, *r, *rv;
+	int sz, nodnum;
+
+	/* check num args and type */
+	if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+	    !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
+		goto bad;
+
+	/* create a copy to a temp node of current ap */
+	p = tcopy(a->n_left);
+	q = tempnode(0, p->n_type, p->n_df, p->n_sue);
+	nodnum = regno(q);
+	rv = buildtree(ASSIGN, q, p);
+
+	r = a->n_right;
+	sz = tsize(r->n_type, r->n_df, r->n_sue)/SZCHAR;
+	/* add one to ap */
+#ifdef BACKAUTO
+	rv = buildtree(COMOP, rv , buildtree(PLUSEQ, a->n_left, bcon(sz)));
+#else
+#error fix wrong eval order in builtin_va_arg
+	ecomp(buildtree(MINUSEQ, a->n_left, bcon(sz)));
+#endif
+
+	nfree(a->n_right);
+	nfree(a);
+	nfree(f);
+	r = tempnode(nodnum, INCREF(r->n_type), r->n_df, r->n_sue);
+	return buildtree(COMOP, rv, buildtree(UMUL, r, NIL));
+bad:
+	uerror("bad argument to __builtin_va_arg");
+	return bcon(0);
+
+}
+
+static NODE *
+builtin_va_end(NODE *f, NODE *a)
+{
+	tfree(f);
+	tfree(a);
+	return bcon(0); /* nothing */
+}
+
+static NODE *
+builtin_va_copy(NODE *f, NODE *a)
+{
+	if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
+		goto bad;
+	tfree(f);
+	f = buildtree(ASSIGN, a->n_left, a->n_right);
+	nfree(a);
+	return f;
+
+bad:
+	uerror("bad argument to __builtin_va_copy");
+	return bcon(0);
+}
+#endif /* TARGET_STDARGS */
+
+static struct bitable {
+	char *name;
+	NODE *(*fun)(NODE *f, NODE *a);
+} bitable[] = {
+	{ "__builtin_alloca", builtin_alloca },
+	{ "__builtin_constant_p", builtin_constant_p },
+#ifndef TARGET_STDARGS
+	{ "__builtin_stdarg_start", builtin_stdarg_start },
+	{ "__builtin_va_arg", builtin_va_arg },
+	{ "__builtin_va_end", builtin_va_end },
+	{ "__builtin_va_copy", builtin_va_copy },
+#endif
+#ifdef TARGET_BUILTINS
+	TARGET_BUILTINS
+#endif
+};
 #endif
 
 #ifdef PCC_DEBUG
@@ -2010,16 +2136,18 @@
 			printf("  ");
 		printf("arg %d: ", i++);
 		tprint(stdout, al->type, 0);
-		if (BTYPE(al->type) == STRTY ||
-		    BTYPE(al->type) == UNIONTY || BTYPE(al->type) == ENUMTY) {
+		if (ISARY(al->type)) {
+			printf(" dim %d\n", al->df->ddim);
+		} else if (BTYPE(al->type) == STRTY ||
+		    BTYPE(al->type) == UNIONTY) {
 			al++;
-			printf("dim %d\n", al->df->ddim);
-		}
-		printf("\n");
-		if (ISFTN(DECREF(al->type))) {
+			printf(" (size %d align %d)", al->sue->suesize,
+			    al->sue->suealign);
+		} else if (ISFTN(DECREF(al->type))) {
 			al++;
 			alprint(al->df->dfun, in+1);
 		}
+		printf("\n");
 	}
 	if (in == 0)
 		printf("end arglist\n");
@@ -2031,7 +2159,7 @@
  * Returns a merged node (via buildtree() of function and arguments.
  */
 NODE *
-doacall(NODE *f, NODE *a)
+doacall(struct symtab *sp, NODE *f, NODE *a)
 {
 	NODE *w, *r;
 	union arglist *al;
@@ -2054,7 +2182,7 @@
 	/* First let MD code do something */
 	calldec(f, a);
 /* XXX XXX hack */
-	if ((f->n_op == CALL || f->n_op == CALL) &&
+	if ((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)
@@ -2062,30 +2190,54 @@
 /* XXX XXX hack */
 
 #ifndef NO_C_BUILTINS
-	/* check for alloca */
-	if ((w = builtin_alloca(f, a)))
-		return w;
+	/* check for builtins. function pointers are not allowed */
+	if (f->n_op == NAME &&
+	    f->n_sp->sname[0] == '_' && f->n_sp->sname[1] == '_') {
+		int i;
+
+		for (i = 0; i < (int)(sizeof(bitable)/sizeof(bitable[0])); i++) {
+			if (strcmp(bitable[i].name, f->n_sp->sname) == 0)
+				return (*bitable[i].fun)(f, a);
+		}
+	}
 #endif
+
+	/* Check for undefined or late defined enums */
+	if (BTYPE(f->n_type) == ENUMTY) {
+		/* not-yet check if declared enum */
+		if (f->n_sue->sylnk->stype != ENUMTY)
+			MODTYPE(f->n_type, f->n_sue->sylnk->stype);
+		if (BTYPE(f->n_type) == ENUMTY)
+			uerror("enum %s not declared", f->n_sue->sylnk->sname);
+	}
+
 	/*
 	 * 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
+			if (f->n_sp != NULL) {
+				if (strncmp(f->n_sp->sname,
+				    "__builtin", 9) != 0)
+					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_op == TYPE)
+				uerror("type is not an argument");
 			if (w->n_right->n_type != FLOAT)
 				continue;
 			w->n_right = argcast(w->n_right, DOUBLE,
 			    NULL, MKSUE(DOUBLE));
 		}
+		if (a->n_op == TYPE)
+			uerror("type is not an argument");
 		if (a->n_type == FLOAT) {
 			MKTY(a, DOUBLE, 0, 0);
 		}
@@ -2103,7 +2255,7 @@
 	}
 #ifdef PCC_DEBUG
 	if (pdebug) {
-		printf("arglist for %p\n",
+		printf("arglist for %s\n",
 		    f->n_sp != NULL ? f->n_sp->sname : "function pointer");
 		alprint(al, 0);
 	}
@@ -2149,8 +2301,19 @@
 		if ((hasarray = ISARY(arrt)))
 			arrt += (PTR-ARY);
 #endif
-		if (ISARY(type))
-			type += (PTR-ARY);
+		/* Taking addresses of arrays are meaningless in expressions */
+		/* but people tend to do that and also use in prototypes */
+		/* this is mostly a problem with typedefs */
+		if (ISARY(type)) {
+			if (ISPTR(arrt) && ISARY(DECREF(arrt)))
+				type = INCREF(type);
+			else
+				type += (PTR-ARY);
+		} else if (ISPTR(type) && !ISARY(DECREF(type)) &&
+		    ISPTR(arrt) && ISARY(DECREF(arrt))) {
+			type += (ARY-PTR);
+			type = INCREF(type);
+		}
 
 		/* Check structs */
 		if (type <= BTMASK && arrt <= BTMASK) {
@@ -2162,12 +2325,17 @@
 					MKTY(apole->node, arrt, 0, 0)
 				}
 			} else if (ISSOU(BTYPE(type))) {
-				if (apole->node->n_sue != al[1].sue)
+				if (apole->node->n_sue->sylnk != al[1].sue->sylnk)
 					goto incomp;
 			}
 			goto out;
 		}
 
+		/* XXX should (recusively) check return type and arg list of
+		   func ptr arg XXX */
+		if (ISFTN(DECREF(arrt)) && ISFTN(type))
+			type = INCREF(type);
+
 		/* Hereafter its only pointers (or arrays) left */
 		/* Check for struct/union intermixing with other types */
 		if (((type <= BTMASK) && ISSOU(BTYPE(type))) ||
@@ -2177,14 +2345,11 @@
 		/* Check for struct/union compatibility */
 		if (type == arrt) {
 			if (ISSOU(BTYPE(type))) {
-				if (apole->node->n_sue == al[1].sue)
+				if (apole->node->n_sue->sylnk == al[1].sue->sylnk)
 					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)
@@ -2193,9 +2358,9 @@
 			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))
+			/* do not complain for pointers with signedness */
+			if (!Wpointer_sign &&
+			    DEUNSIGN(BTYPE(type)) == DEUNSIGN(BTYPE(arrt)))
 				goto skip;
 		}
 
@@ -2231,7 +2396,9 @@
 	if (apole != NULL)
 		uerror("too many arguments to function");
 
-build:	return buildtree(a == NIL ? UCALL : CALL, f, a);
+build:	if (sp != NULL && (sp->sflags & SINLINE) && (w = inlinetree(sp, f, a)))
+		return w;
+	return buildtree(a == NIL ? UCALL : CALL, f, a);
 }
 
 static int
@@ -2241,9 +2408,9 @@
 		switch (type & TMASK) {
 		case ARY:
 			/* may be declared without dimension */
-			if (dsym->ddim == 0)
+			if (dsym->ddim == NOOFFSET)
 				dsym->ddim = ddef->ddim;
-			if (ddef->ddim && dsym->ddim != ddef->ddim)
+			if (ddef->ddim != NOOFFSET && dsym->ddim != ddef->ddim)
 				return 1;
 			dsym++, ddef++;
 			break;
@@ -2303,7 +2470,7 @@
 		t2 = usym->type;
 		if (ISSTR(ty)) {
 			usym++, udef++;
-			if (usym->sue != udef->sue)
+			if (usym->sue->sylnk != udef->sue->sylnk)
 				return 1;
 		}
 
@@ -2345,7 +2512,7 @@
 		}
 
 	/* detect function arguments, watching out for structure declarations */
-	if (instruct && ISFTN(type)) {
+	if (rpole && ISFTN(type)) {
 		uerror("function illegal in structure or union");
 		type = INCREF(type);
 	}
@@ -2371,12 +2538,14 @@
 int
 fixclass(int class, TWORD type)
 {
+	extern int fun_inline;
+
 	/* first, fix null class */
 	if (class == SNULL) {
-		if (instruct&INSTRUCT)
-			class = MOS;
-		else if (instruct&INUNION)
-			class = MOU;
+		if (fun_inline && ISFTN(type))
+			return SNULL;
+		if (rpole)
+			class = rpole->rsou == STNAME ? MOS : MOU;
 		else if (blevel == 0)
 			class = EXTDEF;
 		else
@@ -2402,28 +2571,23 @@
 			}
 		}
 
-	if( class&FIELD ){
-		if( !(instruct&INSTRUCT) ) uerror( "illegal use of field" );
-		return( class );
-		}
-
-	switch( class ){
+	if (class & FIELD) {
+		if (rpole && rpole->rsou != STNAME && rpole->rsou != UNAME)
+			uerror("illegal use of field");
+		return(class);
+	}
 
-	case MOU:
-		if( !(instruct&INUNION) ) uerror( "illegal MOU class" );
-		return( class );
+	switch (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 MOU:
+		if (rpole == NULL)
+			uerror("illegal member class");
+		return(class);
 
 	case REGISTER:
 		if (blevel == 0)
-			uerror( "illegal register declaration" );
+			uerror("illegal register declaration");
 		if (blevel == 1)
 			return(PARAM);
 		else
@@ -2445,14 +2609,12 @@
 				uerror( "fortran function has wrong type" );
 				}
 			}
-	case STNAME:
-	case UNAME:
-	case ENAME:
 	case EXTERN:
 	case STATIC:
 	case EXTDEF:
 	case TYPEDEF:
 	case USTATIC:
+	case PARAM:
 		return( class );
 
 	default:
@@ -2504,7 +2666,7 @@
 		s = permalloc(sizeof(struct symtab));
 		symtabcnt++;
 	}
-	s->sname = name;
+	s->sname = s->soname = name;
 	s->snext = NULL;
 	s->stype = UNDEF;
 	s->squal = 0;
@@ -2512,9 +2674,23 @@
 	s->sflags = flags & SMASK;
 	s->soffset = 0;
 	s->slevel = blevel;
+	s->sdf = NULL;
+	s->ssue = NULL;
 	return s;
 }
 
+int
+fldchk(int sz)
+{
+	if (rpole->rsou != STNAME && rpole->rsou != UNAME)
+		uerror("field outside of structure");
+	if (sz < 0 || sz >= FIELD) {
+		uerror("illegal field size");
+		return 1;
+	}
+	return 0;
+}
+
 #ifdef PCC_DEBUG
 static char *
 ccnames[] = { /* names of storage classes */
@@ -2551,3 +2727,108 @@
 	return( ccnames[c] );
 	}
 #endif
+
+void
+sspinit()
+{
+	NODE *p;
+
+	p = block(NAME, NIL, NIL, FTN+VOID, 0, MKSUE(VOID));
+	p->n_sp = lookup("__stack_chk_fail", SNORMAL);
+	defid(p, EXTERN);
+	nfree(p);
+
+	p = block(NAME, NIL, NIL, INT, 0, MKSUE(INT));
+	p->n_sp = lookup("__stack_chk_guard", SNORMAL);
+	defid(p, EXTERN);
+	nfree(p);
+}
+
+void
+sspstart()
+{
+	NODE *p, *q;
+
+	q = block(NAME, NIL, NIL, INT, 0, MKSUE(INT));
+ 	q->n_sp = lookup("__stack_chk_guard", SNORMAL);
+	q = clocal(q);
+
+	p = block(REG, NIL, NIL, INT, 0, 0);
+	p->n_lval = 0;
+	p->n_rval = FPREG;
+	q = block(ER, p, q, INT, 0, MKSUE(INT));
+	q = clocal(q);
+
+	p = block(NAME, NIL, NIL, INT, 0, MKSUE(INT));
+	p->n_sp = lookup("__stack_chk_canary", SNORMAL);
+	defid(p, AUTO);
+	p = clocal(p);
+
+	ecomp(buildtree(ASSIGN, p, q));
+}
+
+void
+sspend()
+{
+	NODE *p, *q;
+	TWORD t;
+	int tmpnr = 0;
+	int lab;
+
+	if (retlab != NOLAB) {
+		plabel(retlab);
+		retlab = getlab();
+	}
+
+	t = DECREF(cftnsp->stype);
+	if (t == BOOL)
+		t = BOOL_TYPE;
+
+	if (t != VOID && !ISSOU(t)) {
+		p = tempnode(0, t, cftnsp->sdf, cftnsp->ssue);
+		tmpnr = regno(p);
+		q = block(REG, NIL, NIL, t, cftnsp->sdf, cftnsp->ssue);
+		q->n_rval = RETREG(t);
+		ecomp(buildtree(ASSIGN, p, q));
+	}
+
+	p = block(NAME, NIL, NIL, INT, 0, MKSUE(INT));
+	p->n_sp = lookup("__stack_chk_canary", SNORMAL);
+	p = clocal(p);
+
+	q = block(REG, NIL, NIL, INT, 0, 0);
+	q->n_lval = 0;
+	q->n_rval = FPREG;
+	q = block(ER, p, q, INT, 0, MKSUE(INT));
+
+	p = block(NAME, NIL, NIL, INT, 0, MKSUE(INT));
+	p->n_sp = lookup("__stack_chk_guard", SNORMAL);
+	p = clocal(p);
+
+	lab = getlab();
+	cbranch(buildtree(EQ, p, q), bcon(lab));
+
+	p = block(NAME, NIL, NIL, FTN+VOID, 0, MKSUE(VOID));
+	p->n_sp = lookup("__stack_chk_fail", SNORMAL);
+	p = clocal(p);
+
+	ecomp(buildtree(UCALL, p, NIL));
+
+	plabel(lab);
+
+	if (t != VOID && !ISSOU(t)) {
+		p = tempnode(tmpnr, t, cftnsp->sdf, cftnsp->ssue);
+		q = block(REG, NIL, NIL, t, cftnsp->sdf, cftnsp->ssue);
+		q->n_rval = RETREG(t);
+		ecomp(buildtree(ASSIGN, q, p));
+	}
+}
+
+/*
+ * Allocate on the permanent heap for inlines, otherwise temporary heap.
+ */
+void *
+inlalloc(int size)
+{
+	return isinlining ?  permalloc(size) : tmpalloc(size);
+}
Index: init.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/init.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/ccom/init.c -L usr.bin/pcc/ccom/init.c -u -r1.1 -r1.2
--- usr.bin/pcc/ccom/init.c
+++ usr.bin/pcc/ccom/init.c
@@ -1,4 +1,4 @@
-/*	$Id: init.c,v 1.30 2007/09/24 20:34:03 ragge Exp $	*/
+/*	$Id: init.c,v 1.47 2008/12/20 14:15:27 ragge Exp $	*/
 
 /*
  * Copyright (c) 2004, 2007 Anders Magnusson (ragge at ludd.ltu.se).
@@ -65,13 +65,13 @@
 #include <string.h>
 
 /*
- * Four machine-dependent routines may be called during initialization:
+ * The following 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 *)
+ * ninval(CONSZ off, int fsz, NODE *)
  *			- prints an integer constant which may have
  *			  a label associated with it, located at off and
  *			  size fsz.
@@ -118,8 +118,8 @@
  */
 static struct instk {
 	struct	instk *in_prev; /* linked list */
-	struct	symtab **in_xp;	/* member in structure initializations */
-	struct	symtab *in_sym; /* stab index */
+	struct	symtab *in_lnk;	/* member in structure initializations */
+	struct	symtab *in_sym; /* symtab index */
 	union	dimfun *in_df;	/* dimenston of array */
 	TWORD	in_t;		/* type for this level */
 	int	in_n;		/* number of arrays seen so far */
@@ -148,11 +148,20 @@
 	SLIST_ENTRY(llist) next;
 	CONSZ begsz;	/* bit offset of this entry */
 	struct ilist *il;
-} *curll;
-static SLIST_HEAD(, llist) lpole;
+};
+static SLIST_HEAD(llh, llist) lpole;
 static CONSZ basesz;
 static int numents; /* # of array entries allocated */
 
+static struct initctx {
+	struct initctx *prev;
+	struct instk *pstk;
+	struct symtab *psym;
+	struct llh lpole;
+	CONSZ basesz;
+	int numents;
+} *inilnk;
+
 static struct ilist *
 getil(struct ilist *next, CONSZ b, int sz, NODE *n)
 {
@@ -185,16 +194,19 @@
 /*
  * Return structure containing off bitnumber.
  * Allocate more entries, if needed.
- * This is not bright implemented.
  */
 static struct llist *
 setll(OFFSZ off)
 {
-	struct llist *ll;
+	struct llist *ll = NULL;
 
 	/* Ensure that we have enough entries */
 	while (off >= basesz * numents)
-		(void)getll();
+		 ll = getll();
+
+	if (ll != NULL && ll->begsz <= off && ll->begsz + basesz > off)
+		return ll;
+
 	SLIST_FOREACH(ll, &lpole, next)
 		if (ll->begsz <= off && ll->begsz + basesz > off)
 			break;
@@ -209,14 +221,30 @@
 void
 beginit(struct symtab *sp)
 {
+	struct initctx *ict;
 	struct instk *is = &pbase;
-	struct llist *ll;
 
 #ifdef PCC_DEBUG
 	if (idebug)
 		printf("beginit(), sclass %s\n", scnames(sp->sclass));
 #endif
 
+	if (pstk) {
+#ifdef PCC_DEBUG
+		if (idebug)
+			printf("beginit: saving ctx pstk %p\n", pstk);
+#endif
+		/* save old context */
+		ict = tmpalloc(sizeof(struct initctx));
+		ict->prev = inilnk;
+		inilnk = ict;
+		ict->pstk = pstk;
+		ict->psym = csym;
+		ict->lpole = lpole;
+		ict->basesz = basesz;
+		ict->numents = numents;
+		is = tmpalloc(sizeof(struct instk));
+	}
 	csym = sp;
 
 	numents = 0; /* no entries in array list */
@@ -225,10 +253,9 @@
 	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_lnk = ISSOU(sp->stype) ? sp->ssue->sylnk : NULL;
 	is->in_n = 0;
 	is->in_t = sp->stype;
 	is->in_sym = sp;
@@ -276,25 +303,26 @@
 	is->in_n = 0;
 	if (pstk == NULL) {
 		/* stack empty */
-		is->in_xp = ISSOU(sp->stype) ? sp->ssue->suelem : NULL;
+		is->in_lnk = ISSOU(sp->stype) ? sp->ssue->sylnk : NULL;
 		is->in_t = sp->stype;
 		is->in_sym = sp;
 		is->in_df = sp->sdf;
 	} else if (ISSOU(t)) {
-		sq = *pstk->in_xp;
+		sq = pstk->in_lnk;
 		if (sq == NULL) {
 			uerror("excess of initializing elements");
 		} else {
-			is->in_xp = ISSOU(sq->stype) ? sq->ssue->suelem : 0;
+			is->in_lnk = ISSOU(sq->stype) ? sq->ssue->sylnk : 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_lnk = ISSOU(DECREF(t)) ? pstk->in_sym->ssue->sylnk : 0;
 		is->in_t = DECREF(t);
 		is->in_sym = sp;
-		if (pstk->in_df->ddim && pstk->in_n >= pstk->in_df->ddim) {
+		if (pstk->in_df->ddim != NOOFFSET &&
+		    pstk->in_n >= pstk->in_df->ddim) {
 			werror("excess of initializing elements");
 			pstk->in_n--;
 		}
@@ -326,9 +354,9 @@
 		printf("stkpop\n");
 #endif
 	for (; pstk; pstk = pstk->in_prev) {
-		if (pstk->in_t == STRTY) {
-			pstk->in_xp++;
-			if (*pstk->in_xp != NULL)
+		if (pstk->in_t == STRTY && pstk->in_lnk != NULL) {
+			pstk->in_lnk = pstk->in_lnk->snext;
+			if (pstk->in_lnk != NULL)
 				break;
 		}
 		if (ISSOU(pstk->in_t) && pstk->in_fl)
@@ -337,7 +365,7 @@
 			pstk->in_n++;
 			if (pstk->in_fl)
 				break;
-			if (pstk->in_df->ddim == 0 ||
+			if (pstk->in_df->ddim == NOOFFSET ||
 			    pstk->in_n < pstk->in_df->ddim)
 				break; /* ger more elements */
 		}
@@ -398,10 +426,12 @@
 			}
 		}
 	}
+#ifdef PCC_DEBUG
 	if (idebug>1) {
 		printf("findoff: off %lld\n", off);
 		prtstk(pstk);
 	}
+#endif
 	return off;
 }
 
@@ -445,24 +475,6 @@
 }
 
 /*
- * 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
@@ -487,9 +499,11 @@
 
 	p = optim(p);
 
+#ifdef notdef /* leave to the target to decide if useable */
 	if (csym->sclass != AUTO && p->n_op != ICON &&
 	    p->n_op != FCON && p->n_op != NAME)
 		cerror("scalinit not leaf");
+#endif
 
 	/* Out of elements? */
 	if (pstk == NULL) {
@@ -552,17 +566,14 @@
 	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));
+	p = buildtree(ADDROF, nametree(csym), NIL);
 	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;
+	r = xbcon(0, &sym, typ);
 	p = block(STREF, p, r, INT, 0, MKSUE(INT));
 	ecode(buildtree(ASSIGN, stref(p), bcon(val)));
 }
@@ -609,10 +620,10 @@
 #endif
 
 	if (csym->sclass != AUTO)
-		setscl(csym);
+		defloc(csym);
 
 	/* Calculate total block size */
-	if (ISARY(csym->stype) && csym->sdf->ddim == 0) {
+	if (ISARY(csym->stype) && csym->sdf->ddim == NOOFFSET) {
 		tbit = numents*basesz; /* open-ended arrays */
 		csym->sdf->ddim = numents;
 		if (csym->sclass == AUTO) { /* Get stack space */
@@ -644,20 +655,17 @@
 					    (ll->begsz + il->off) - lastoff);
 
 				/* Fake a struct reference */
-				spname = csym;
-				p = buildtree(ADDROF,
-				    buildtree(NAME, NIL, NIL), NIL);
+				p = buildtree(ADDROF, nametree(csym), 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;
+				r = xbcon(0, &sym, INT);
 				p = block(STREF, p, r, INT, 0, MKSUE(INT));
-				ecode(buildtree(ASSIGN, stref(p), il->n));
+				ecomp(buildtree(ASSIGN, stref(p), il->n));
 				if (fsz < 0)
 					fsz = -fsz;
 
@@ -670,7 +678,7 @@
 					infld(il->off, fsz, il->n->n_lval);
 				} else
 					ninval(il->off, fsz, il->n);
-				nfree(il->n);
+				tfree(il->n);
 			}
 			lastoff = ll->begsz + il->off + fsz;
 		}
@@ -679,6 +687,19 @@
 		clearbf(lastoff, tbit-lastoff);
 	} else
 		zbits(lastoff, tbit-lastoff);
+	if (inilnk) {
+		struct initctx *ict = inilnk;
+		pstk = ict->pstk;
+		csym = ict->psym;
+		lpole = ict->lpole;
+		basesz = ict->basesz;
+		numents = ict->numents;
+		inilnk = inilnk->prev;
+#ifdef PCC_DEBUG
+		if (idebug)
+			printf("endinit: restoring ctx pstk %p\n", pstk);
+#endif
+	}
 }
 
 /*
@@ -731,8 +752,9 @@
 		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++;
+			while (pstk->in_lnk != NULL &&
+			    pstk->in_lnk->snext != NULL)
+				pstk->in_lnk = pstk->in_lnk->snext;
 		}
 		stkpop();
 		return;
@@ -766,11 +788,11 @@
 		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)
+		if (pstk->in_lnk) {
+			for (; pstk->in_lnk; pstk->in_lnk = pstk->in_lnk->snext)
+				if (pstk->in_lnk->sname == (char *)p->n_sp)
 					break;
-			if (pstk->in_xp[0] == NULL)
+			if (pstk->in_lnk == NULL)
 				uerror("member missing");
 		} else {
 			uerror("not a struct/union");
@@ -798,12 +820,12 @@
 		pstk = pstk->in_prev; /* Empty stack */
 
 	if (ISSOU(pstk->in_t))
-		pstk->in_xp = pstk->in_sym->ssue->suelem;
+		pstk->in_lnk = pstk->in_sym->ssue->sylnk;
 
 	mkstack(p);	/* Setup for assignment */
 
 	/* pop one step if SOU, ilbrace will push */
-	if (op == NAME)
+	if (op == NAME || op == LB)
 		pstk = pstk->in_prev;
 
 #ifdef PCC_DEBUG
@@ -830,7 +852,7 @@
 			i = (unsigned char)s[-1];
 		asginit(bcon(i));
 	} 
-	nfree(p);
+	tfree(p);
 }
 
 /*
@@ -904,8 +926,8 @@
 		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);
+			if (in->in_lnk)
+				printf("curel %s ", in->in_lnk->sname);
 			else
 				printf("END struct");
 		}
@@ -931,7 +953,7 @@
 		/* Handle "aaa" as { 'a', 'a', 'a' } */
 		beginit(sp);
 		strcvt(p);
-		if (csym->sdf->ddim == 0)
+		if (csym->sdf->ddim == NOOFFSET)
 			scalinit(bcon(0)); /* Null-term arrays */
 		endinit();
 		return;
@@ -940,9 +962,8 @@
 	switch (sp->sclass) {
 	case STATIC:
 	case EXTDEF:
-		spname = sp;
-		p = optim(buildtree(ASSIGN, buildtree(NAME, NIL, NIL), p));
-		setscl(sp);
+		p = optim(buildtree(ASSIGN, nametree(sp), p));
+		defloc(sp);
 		ninval(0, p->n_right->n_sue->suesize, p->n_right);
 		tfree(p);
 		break;
@@ -951,8 +972,7 @@
 	case REGISTER:
 		if (ISARY(sp->stype))
 			cerror("no array init");
-		spname = sp;
-		ecomp(buildtree(ASSIGN, buildtree(NAME, NIL, NIL), p));
+		ecomp(buildtree(ASSIGN, nametree(sp), p));
 		break;
 
 	default:
Index: gcc_compat.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/gcc_compat.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/ccom/gcc_compat.c -L usr.bin/pcc/ccom/gcc_compat.c -u -r1.1 -r1.2
--- usr.bin/pcc/ccom/gcc_compat.c
+++ usr.bin/pcc/ccom/gcc_compat.c
@@ -1,4 +1,4 @@
-/*      $Id: gcc_compat.c,v 1.7 2006/05/13 06:35:36 ragge Exp $     */
+/*      $Id: gcc_compat.c,v 1.22 2008/12/20 14:15:27 ragge Exp $     */
 /*
  * Copyright (c) 2004 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -36,15 +36,46 @@
 
 #include <string.h>
 
+/* Remove heading and trailing __ */
+static char *
+decap(char *s)
+{
+	if (s[0] == '_' && s[1] == '_') {
+		int len = strlen(s);
+
+		if (s[len-1] == '_' && s[len-2] == '_') {
+			s = tmpstrdup(s); /* will trash */
+			s[len-2] = 0;
+		}
+		s += 2;
+	}
+	return s;
+}
+
 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 },
+/*
+ * Do NOT change the order of these entries unless you know 
+ * what you're doing!
+ */
+/* 0 */	{ "__asm", NULL, C_ASM },
+/* 1 */	{ "__signed", NULL, 0 },
+/* 2 */	{ "__inline", NULL, C_FUNSPEC },
+/* 3 */	{ "__const", NULL, 0 },
+/* 4 */	{ "__asm__", NULL, C_ASM },
+/* 5 */	{ "__inline__", NULL, C_FUNSPEC },
+/* 6 */	{ "__thread", NULL, 0 },
+/* 7 */	{ "__FUNCTION__", NULL, 0 },
+/* 8 */	{ "__volatile", NULL, 0 },
+/* 9 */	{ "__volatile__", NULL, 0 },
+/* 10 */{ "__restrict", NULL, -1 },
+/* 11 */{ "__typeof__", NULL, C_TYPEOF },
+/* 12 */{ "typeof", NULL, C_TYPEOF },
+/* 13 */{ "__extension__", NULL, -1 },
+/* 14 */{ "__signed__", NULL, 0 },
+/* 15 */{ "__attribute__", NULL, 0 },
 	{ NULL, NULL, 0 },
 };
 
@@ -58,12 +89,16 @@
 
 }
 
+#define	TS	"\n#pragma tls\n# %d\n"
+#define	TLLEN	sizeof(TS)+10
 /*
  * See if a string matches a gcc keyword.
  */
 int
 gcc_keyword(char *str, NODE **n)
 {
+	extern int inattr, parlvl, parbal;
+	char tlbuf[TLLEN], *tw;
 	struct kw *kwp;
 	int i;
 
@@ -75,52 +110,174 @@
 	if (kwp->rv)
 		return kwp->rv;
 	switch (i) {
-	case 1: /* __signed */
+	case 1:  /* __signed */
+	case 14: /* __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;
+	case 6: /* __thread */
+		snprintf(tlbuf, TLLEN, TS, lineno);
+		tw = &tlbuf[strlen(tlbuf)];
+		while (tw > tlbuf)
+			cunput(*--tw);
+		return -1;
+	case 7: /* __FUNCTION__ */
+		if (cftnsp == NULL) {
+			uerror("__FUNCTION__ outside function");
+			yylval.strp = "";
+		} else
+			yylval.strp = cftnsp->sname; /* XXX - not C99 */
+		return C_STRING;
+	case 8: /* __volatile */
+	case 9: /* __volatile__ */
+		*n = block(QUALIFIER, NIL, NIL, VOL, 0, 0);
+		return C_QUALIFIER;
+	case 15: /* __attribute__ */
+		inattr = 1;
+		parlvl = parbal;
+		return C_ATTRIBUTE;
 	}
 	cerror("gcc_keyword");
 	return 0;
 }
 
-static struct ren {
-	struct ren *next;
-	char *old, *new;
-} *renp;
+#ifndef TARGET_TYPE_ATTR
+#define	TARGET_TYPE_ATTR(p, sue)	1
+#endif
+#ifndef TARGET_VAR_ATTR
+#define	TARGET_VAR_ATTR(p, sue)		1
+#endif
+#ifndef	ALMAX
+#define	ALMAX (ALLDOUBLE > ALLONGLONG ? ALLDOUBLE : ALLONGLONG)
+#endif
+
 /*
- * Save a name for later renaming of a variable.
+ * Get type attributes from an argument list.
  */
-void
-gcc_rename(struct symtab *sp, char *newname)
+static void
+gcc_ta(NODE *p, void *arg)
 {
-	struct ren *ren = permalloc(sizeof(struct ren));
+	struct suedef *sue = arg;
+	char *n2, *name = NULL;
 
-	sp->sflags |= SRENAME;
-	ren->old = sp->sname;
-	ren->new = newstring(newname, strlen(newname)+1);
-	ren->next = renp;
-	renp = ren;
+	if (p->n_op == NAME) {
+		name = (char *)p->n_sp;
+	} else if (p->n_op == CALL || p->n_op == UCALL) {
+		name = (char *)p->n_left->n_sp;
+	} else
+		cerror("bad type attribute");
+
+	n2 = name;
+	name = decap(name);
+	if (strcmp(name, "aligned") == 0) {
+		/* Align the type to a given max alignment */
+		if (p->n_op == CALL) {
+			sue->suealigned = icons(eve(p->n_right)) * SZCHAR;
+			p->n_op = UCALL;
+		} else
+			sue->suealigned = ALMAX;
+	} else if (strcmp(name, "packed") == 0) {
+		/* pack members of a struct */
+		if (p->n_op != NAME)
+			uerror("packed takes no args");
+		sue->suepacked = SZCHAR; /* specify pack size? */
+	} else if (TARGET_TYPE_ATTR(p, sue) == 0)
+		werror("unsupported attribute %s", n2);
 }
 
 /*
- * Get a renamed variable.
+ * Get variable attributes from an argument list.
  */
-char *
-gcc_findname(struct symtab *sp)
+static void
+gcc_va(NODE *p, void *arg)
 {
-	struct ren *w;
+	struct suedef *sue = arg;
+	char *n2, *name = NULL;
 
-	if ((sp->sflags & SRENAME) == 0)
-		return exname(sp->sname);
+	if (p->n_op == NAME) {
+		name = (char *)p->n_sp;
+	} else if (p->n_op == CALL || p->n_op == UCALL) {
+		name = (char *)p->n_left->n_sp;
+	} else
+		cerror("bad variable attribute");
+
+	n2 = name;
+	name = decap(name);
+	if (strcmp(name, "aligned") == 0) {
+		/* Align the variable to a given max alignment */
+		if (p->n_op == CALL) {
+			sue->suealigned = icons(eve(p->n_right)) * SZCHAR;
+			p->n_op = UCALL;
+		} else
+			sue->suealigned = ALMAX;
+	} else if (strcmp(name, "section") == 0) {
+		if (p->n_right->n_op != STRING)
+			uerror("bad section");
+		sue->suesection = p->n_right->n_name;
+#ifdef notyet
+	} else if (strcmp(name, "packed") == 0) {
+		/* pack members of a struct */
+		if (p->n_op != NAME)
+			uerror("packed takes no args");
+		sue->suepacked = SZCHAR; /* specify pack size? */
+#endif
+	} else if (TARGET_VAR_ATTR(p, sue) == 0)
+		werror("unsupported attribute %s", n2);
+}
 
-	for (w = renp; w; w = w->next) {
-		if (w->old == sp->sname)
-			return exname(w->new);
-	}
-	cerror("gcc_findname %s", sp->sname);
-	return NULL;
+/*
+ * Extract type attributes from a node tree and setup a suedef 
+ * struct based on its contents.
+ */
+struct suedef *
+gcc_type_attrib(NODE *p)
+{
+	struct suedef *sue = tmpcalloc(sizeof(struct suedef));
+
+	flist(p, gcc_ta, sue);
+	tfree(p);
+	return sue;
+}
+
+struct suedef *
+gcc_var_attrib(NODE *p)
+{
+	struct suedef *sue = permalloc(sizeof(struct suedef)); /* XXX ??? */
+
+	memset(sue, 0, sizeof(struct suedef));
+	flist(p, gcc_va, sue);
+	tfree(p);
+	return sue;
+}
+
+
+#ifdef notyet
+struct gcc_attrib {
+	int atype;
+	union {
+		int iarg; char *sarg;
+	} a1;
+	union {
+		int iarg; char *sarg;
+	} a2;
+	union {
+		int iarg; char *sarg;
+	} a3;
+};
+
+typedef struct gcc_attrib g_attr_t;
+
+/*
+ * Parse an attribute tree and create a attribute struct.
+ * If failed, return NULL>
+ */
+g_attr_t *
+gcc_attrib_parse(NODE *p)
+{
 }
+
+#endif
+
 #endif
Index: pass1.h
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/pass1.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/ccom/pass1.h -L usr.bin/pcc/ccom/pass1.h -u -r1.1 -r1.2
--- usr.bin/pcc/ccom/pass1.h
+++ usr.bin/pcc/ccom/pass1.h
@@ -1,4 +1,4 @@
-/*	$Id: pass1.h,v 1.125 2007/09/09 10:01:01 ragge Exp $	*/
+/*	$Id: pass1.h,v 1.166 2008/12/14 21:15:24 ragge Exp $	*/
 /*
  * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
  *
@@ -33,9 +33,20 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "config.h"
+
 #include <sys/types.h>
 #include <stdarg.h>
+#include <string.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
 
+#ifndef MKEXT
+#include "external.h"
+#else
+typedef unsigned int bittype; /* XXX - for basicblock */
+#endif
 #include "manifest.h"
 
 #include "protos.h"
@@ -63,7 +74,6 @@
 #define MOE		16
 #define UFORTRAN 	17
 #define USTATIC		18
-#define ILABEL		19
 
 	/* field size is ORed in */
 #define FIELD		0100
@@ -81,21 +91,17 @@
 #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
+/* #define SSET		00010 */
+/* #define SREF		00020 */
+#define SNOCREAT	00040	/* don't create a symbol in lookup() */
+#define STEMP		00100	/* Allocate symtab from temp or perm mem */
+#define	SDYNARRAY	00200	/* symbol is dynamic array on stack */
+#define	SINLINE		00400	/* function is of type inline */
+#define	STNODE		01000	/* symbol shall be a temporary node */
+#define	SASG		04000	/* symbol is assigned to already */
+#define	SLOCAL1		010000
+#define	SLOCAL2		020000
+#define	SLOCAL3		040000
 
 	/* alignment of initialized quantities */
 #ifndef AL_INIT
@@ -122,8 +128,11 @@
  */
 struct suedef {
 	int	suesize;	/* Size of the struct */
-	struct	symtab **suelem;/* points to the list of elements */
+	struct	symtab *sylnk;	/* the list of elements */
 	int	suealign;	/* Alignment of this struct */
+	int	suealigned;	/* Larger alignment requested */
+	int	suepacked;	/* Smaller alignment requested */
+	char *	suesection;	/* Section requested for this var/fun */
 };
 
 /*
@@ -134,38 +143,26 @@
 	union dimfun *df;
 	struct suedef *sue;
 };
-#define TNULL		INCREF(MOETY) /* pointer to MOETY -- impossible type */
-#define TELLIPSIS 	INCREF(INCREF(MOETY))
+#define TNULL		INCREF(FARG) /* pointer to FARG -- impossible type */
+#define TELLIPSIS 	INCREF(INCREF(FARG))
 
 /*
  * 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;
+	struct	symtab *snext;	/* link to other symbols in the same scope */
+	int	soffset;	/* offset or value */
+	char	sclass;		/* storage class */
+	char	slevel;		/* scope level */
+	short	sflags;		/* flags, see below */
+	char	*sname;		/* Symbol name */
+	char	*soname;	/* Written-out name */
 	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[];
 
@@ -177,7 +174,7 @@
 	CONSZ	sval;		/* case value */
 	int	slab;		/* associated label */
 };
-void genswitch(int, struct swents **, int);
+int mygenswitch(int, TWORD, struct swents **, int);
 
 extern	int blevel;
 extern	int instruct, got_type;
@@ -189,16 +186,12 @@
 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 xinline;
 
 extern	int sdebug, idebug, pdebug;
 
@@ -208,11 +201,9 @@
 extern	int flostat;
 extern	int retlab;
 
-/*
- * Flags used in structures/unions
- */
-#define INSTRUCT	02
-#define INUNION		04
+/* pragma globals */
+extern int pragma_allpacked, pragma_packed, pragma_aligned;
+extern char *pragma_renamed;
 
 /*
  * Flags used in the (elementary) flow analysis ...
@@ -228,16 +219,16 @@
 
 /* declarations of various functions */
 extern	NODE
-	*buildtree(int, NODE *l, NODE *r),
+	*buildtree(int, NODE *, NODE *r),
 	*mkty(unsigned, union dimfun *, struct suedef *),
 	*rstruct(char *, int),
-	*dclstruct(struct rstack *),
-	*strend(char *),
-	*wstrend(char *),
-	*tymerge(NODE *typ, NODE *idp),
+	*dclstruct(struct rstack *, struct suedef *),
+	*strend(int gtype, char *),
+	*tymerge(NODE *, NODE *),
 	*stref(NODE *),
 	*offcon(OFFSZ, TWORD, union dimfun *, struct suedef *),
 	*bcon(int),
+	*xbcon(CONSZ, struct symtab *, TWORD),
 	*bpsize(NODE *),
 	*convert(NODE *, int),
 	*pconvert(NODE *),
@@ -245,99 +236,150 @@
 	*ptmatch(NODE *),
 	*tymatch(NODE *),
 	*makety(NODE *, TWORD, TWORD, union dimfun *, struct suedef *),
-	*block(int, NODE *, NODE *r, TWORD, union dimfun *, struct suedef *),
+	*block(int, NODE *, NODE *, 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);
+	*tempnode(int, TWORD, union dimfun *, struct suedef *),
+	*eve(NODE *),
+	*doacall(struct symtab *, NODE *, NODE *);
+NODE	*intprom(NODE *);
 OFFSZ	tsize(TWORD, union dimfun *, struct suedef *),
 	psize(NODE *);
 NODE *	typenode(NODE *new);
 void	spalloc(NODE *, NODE *, OFFSZ);
 char	*exname(char *);
+NODE	*floatcon(char *);
+NODE	*fhexcon(char *);
+extern struct rstack *rpole;
 
-int oalloc(struct symtab *p, int *poff);
+int oalloc(struct symtab *, int *);
 void deflabel(char *);
-void deflab1(int);
-void setloc1(int);
 void gotolabel(char *);
-unsigned int esccon(char **sptr);
-void inline_start(char *name);
+unsigned int esccon(char **);
+void inline_start(struct symtab *);
 void inline_end(void);
 void inline_addarg(struct interpass *);
-void inline_ref(char *);
+void inline_ref(struct symtab *);
 void inline_prtout(void);
+void inline_args(struct symtab **, int);
+NODE *inlinetree(struct symtab *, NODE *, NODE *);
 void ftnarg(NODE *);
-struct rstack *bstruct(char *, int);
+struct rstack *bstruct(char *, int, struct suedef *);
 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);
+struct symtab *lookup(char *, int);
+struct symtab *getsymtab(char *, int);
 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);
+void symclear(int);
+struct symtab *hide(struct symtab *);
+void soumemb(NODE *, char *, int);
 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 cbranch(NODE *, NODE *);
 void extdec(struct symtab *);
-void commdec(struct symtab *);
-void lcommdec(struct symtab *);
-int falloc(struct symtab *p, int w, int new, NODE *pty);
+void defzero(struct symtab *);
+int falloc(struct symtab *, int, int, NODE *);
 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 ninval(CONSZ, int, NODE *);
+void infld(CONSZ, int, CONSZ);
+void zbits(CONSZ, int);
+void instring(struct symtab *);
+void inwstring(struct symtab *);
+void plabel(int);
 void bjobcode(void);
 void ejobcode(int);
 void calldec(NODE *, NODE *);
 int cisreg(TWORD);
-char *tmpsprintf(char *fmt, ...);
-char *tmpvsprintf(char *fmt, va_list ap);
+char *tmpsprintf(char *, ...);
+char *tmpvsprintf(char *, va_list);
 void asginit(NODE *);
 void desinit(NODE *);
 void endinit(void);
+void sspinit(void);
+void sspstart(void);
+void sspend(void);
 void ilbrace(void);
 void irbrace(void);
-void scalinit(NODE *p);
-int ftoint(NODE *, CONSZ **);
-void p1print(char *fmt, ...);
+void scalinit(NODE *);
+void p1print(char *, ...);
 char *copst(int);
 int cdope(int);
 void myp2tree(NODE *);
 void lcommprint(void);
 void lcommdel(struct symtab *);
+NODE *funcode(NODE *);
+struct symtab *enumhd(char *);
+NODE *enumdcl(struct symtab *);
+NODE *enumref(char *);
+CONSZ icons(NODE *);
+int mypragma(char **);
+void fixdef(struct symtab *);
+int cqual(TWORD, TWORD);
+void defloc(struct symtab *);
+int fldchk(int);
+int nncon(NODE *);
+void cunput(char);
+NODE *nametree(struct symtab *sp);
+void *inlalloc(int size);
+void pass1_lastchance(struct interpass *);
+void fldty(struct symtab *p);
+int getlab(void);
+
+#ifdef SOFTFLOAT
+typedef struct softfloat SF;
+SF soft_neg(SF);
+SF soft_cast(CONSZ v, TWORD);
+SF soft_plus(SF, SF);
+SF soft_minus(SF, SF);
+SF soft_mul(SF, SF);
+SF soft_div(SF, SF);
+int soft_isz(SF);
+CONSZ soft_val(SF);
+#define FLOAT_NEG(sf)		soft_neg(sf)
+#define	FLOAT_CAST(v,t)		soft_cast(v, t)
+#define	FLOAT_PLUS(x1,x2)	soft_plus(x1, x2)
+#define	FLOAT_MINUS(x1,x2)	soft_minus(x1, x2)
+#define	FLOAT_MUL(x1,x2)	soft_mul(x1, x2)
+#define	FLOAT_DIV(x1,x2)	soft_div(x1, x2)
+#define	FLOAT_ISZERO(sf)	soft_isz(sf)
+#define	FLOAT_VAL(sf)		soft_val(sf)
+#else
+#define	FLOAT_NEG(p)		-(p)
+#define	FLOAT_CAST(p,v)		(ISUNSIGNED(v) ? \
+		(long double)(U_CONSZ)(p) : (long double)(CONSZ)(p))
+#define	FLOAT_PLUS(x1,x2)	(x1) + (x2)
+#define	FLOAT_MINUS(x1,x2)	(x1) - (x2)
+#define	FLOAT_MUL(x1,x2)	(x1) * (x2)
+#define	FLOAT_DIV(x1,x2)	(x1) / (x2)
+#define	FLOAT_ISZERO(p)		(p) == 0.0
+#define FLOAT_VAL(p)		(CONSZ)(p)
+#endif
 
 #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);
+struct suedef *gcc_type_attrib(NODE *);
+struct suedef *gcc_var_attrib(NODE *);
 #endif
 
 #ifdef STABS
 void stabs_init(void);
 void stabs_file(char *);
+void stabs_efile(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);
+void stabs_struct(struct symtab *, struct suedef *);
 #endif
 
 #ifndef CHARCAST
@@ -363,7 +405,7 @@
 #define	OROR		(MAXOP+12)
 #define	NOT		(MAXOP+13)
 #define	CAST		(MAXOP+14)
-/* #define	STRING		(MAXOP+15) */
+#define	STRING		(MAXOP+15)
 
 /* The following must be in the same order as their NOASG counterparts */
 #define	PLUSEQ		(MAXOP+16)
@@ -381,12 +423,18 @@
 
 #define INCR		(MAXOP+26)
 #define DECR		(MAXOP+27)
+#define SZOF		(MAXOP+28)
+
+
 /*
  * The following types are only used in pass1.
  */
 #define SIGNED		(MAXTYPES+1)
 #define BOOL		(MAXTYPES+2)
-
+#define	FCOMPLEX	(MAXTYPES+3)
+#define	COMPLEX		(MAXTYPES+4)
+#define	LCOMPLEX	(MAXTYPES+5)
+#define	ENUMTY		(MAXTYPES+6)
 
 #define coptype(o)	(cdope(o)&TYFLG)
 #define clogop(o)	(cdope(o)&LOGFLG)
Index: main.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/main.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L usr.bin/pcc/ccom/main.c -L usr.bin/pcc/ccom/main.c -u -r1.2 -r1.3
--- usr.bin/pcc/ccom/main.c
+++ usr.bin/pcc/ccom/main.c
@@ -1,4 +1,4 @@
-/*	$Id: main.c,v 1.72 2007/09/25 06:43:06 ragge Exp $	*/
+/*	$Id: main.c,v 1.95 2008/12/17 15:59:24 ragge Exp $	*/
 
 /*
  * Copyright (c) 2002 Anders Magnusson. All rights reserved.
@@ -26,7 +26,11 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "config.h"
+
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #include <signal.h>
 #include <string.h>
 #include <stdlib.h>
@@ -34,19 +38,44 @@
 #include "pass1.h"
 #include "pass2.h"
 
-int sflag, nflag, oflag, kflag;
-int lflag, odebug, rdebug, radebug, vdebug, s2debug, udebug, x2debug;
+int sflag, nflag, oflag, kflag, pflag;
+int lflag, odebug, rdebug, s2debug, udebug, x2debug;
 #if !defined(MULTIPASS) || defined(PASST)
 int iTflag, oTflag;
 #endif
-int xdebug, mdebug, sdebug, gflag, c2debug, pdebug;
+int xdebug, sdebug, gflag, c2debug, pdebug;
 int Wstrict_prototypes, Wmissing_prototypes, Wimplicit_int,
-	Wimplicit_function_declaration;
-int xssaflag, xtailcallflag, xtemps, xdeljumps;
+	Wimplicit_function_declaration, Wpointer_sign, Wshadow,
+	Wsign_compare, Wunknown_pragmas, Wunreachable_code;
+#ifdef CHAR_UNSIGNED
+int funsigned_char = 1;
+#else
+int funsigned_char = 0;
+#endif
+int sspflag;
+int xssaflag, xtailcallflag, xtemps, xdeljumps, xdce, xinline;
 
 int e2debug, t2debug, f2debug, b2debug;
 
-struct suedef btdims[24];
+struct suedef btdims[32] = {
+	[BOOL] = { .suesize = SZBOOL, .suealign = ALBOOL },
+	[CHAR] = { .suesize = SZCHAR, .suealign = ALCHAR },
+	[INT] = { .suesize = SZINT, .suealign = ALINT },
+	[FLOAT] = { .suesize = SZFLOAT, .suealign = ALFLOAT },
+	[DOUBLE] = { .suesize = SZDOUBLE, .suealign = ALDOUBLE },
+	[LDOUBLE] = { .suesize = SZLDOUBLE, .suealign = ALLDOUBLE },
+	[LONG] = { .suesize = SZLONG, .suealign = ALLONG },
+	[LONGLONG] = { .suesize = SZLONGLONG, .suealign = ALLONGLONG },
+	[SHORT] = { .suesize = SZSHORT, .suealign = ALSHORT },
+	[UCHAR] = { .suesize = SZCHAR, .suealign = ALCHAR },
+	[USHORT] = { .suesize = SZSHORT, .suealign = ALSHORT },
+	[UNSIGNED] = { .suesize = SZINT, .suealign = ALINT },
+	[ULONG] = { .suesize = SZLONG, .suealign = ALLONG },
+	[ULONGLONG] = { .suesize = SZLONGLONG, .suealign = ALLONGLONG },
+	[FCOMPLEX] = { .suesize = SZFLOAT * 2, .suealign = ALFLOAT },
+	[COMPLEX] = { .suesize = SZDOUBLE * 2, .suealign = ALDOUBLE },
+	[LCOMPLEX] = { .suesize = SZLDOUBLE * 2, .suealign = ALLDOUBLE },
+};
 char *prgname;
 
 static void prtstats(void);
@@ -58,6 +87,11 @@
 	{ "missing-prototypes", &Wmissing_prototypes, },
 	{ "implicit-int", &Wimplicit_int, },
 	{ "implicit-function-declaration", &Wimplicit_function_declaration, },
+	{ "shadow", &Wshadow, },
+	{ "pointer-sign", &Wpointer_sign, },
+	{ "sign-compare", &Wsign_compare, },
+	{ "unknown-pragmas", &Wunknown_pragmas, },
+	{ "unreachable-code", &Wunreachable_code, },
 	{ NULL, NULL, },
 };
 
@@ -72,10 +106,12 @@
 static void
 segvcatch(int a)
 {
-	fprintf(stderr, "%sinternal compiler error: %s, line %d\n",
+	char buf[1024];
+
+	snprintf(buf, sizeof buf, "%sinternal compiler error: %s, line %d\n",
 	    nerrors ? "" : "major ", ftitle, lineno);
-	fflush(stderr);
-	exit(1);
+	write(STDERR_FILENO, buf, strlen(buf));
+	_exit(1);
 }
 
 /*
@@ -84,22 +120,60 @@
 static void
 Wflags(char *str)
 {
-	int i, found = 0, all;
+	int i, flagval = 1, found = 0, all;
+
+	if (strncmp("no-", str, 3) == 0) {
+		str += 3;
+		flagval = 0;
+	}
 
 	if (strcmp(str, "implicit") == 0) {
-		Wimplicit_int = Wimplicit_function_declaration = 1;
+		Wimplicit_int = Wimplicit_function_declaration = flagval;
+		return;
+	}
+	if (strcmp(str, "error") == 0) {
+		warniserr = flagval;
 		return;
 	}
+
 	all = strcmp(str, "W") == 0;
-	for (i = 0; flagstr[i].n; i++)
+	for (i = 0; flagstr[i].n; i++) {
 		if (all || strcmp(flagstr[i].n, str) == 0) {
-			*flagstr[i].f = 1;
+			*flagstr[i].f = flagval;
 			found++;
 		}
-	if (found == 0)
+	}
+	if (found == 0) {
+		fprintf(stderr, "unrecognised option '%s'\n", str);
 		usage();
+	}
 }
 
+static void
+fflags(char *str)
+{
+	int flagval = 1;
+
+	if (strncmp("no-", str, 3) == 0) {
+		str += 3;
+		flagval = 0;
+	}
+
+	if (strcmp(str, "signed-char") == 0)
+		funsigned_char = !flagval;
+	else if (strcmp(str, "unsigned-char") == 0)
+		funsigned_char = flagval;
+	else if (strcmp(str, "stack-protector") == 0)
+		sspflag = flagval;
+	else if (strcmp(str, "stack-protector-all") == 0)
+		sspflag = flagval;
+	else if (strncmp(str, "pack-struct", 11) == 0)
+		pragma_allpacked = (strlen(str) > 12 ? atoi(str+12) : 1);
+	else {
+		fprintf(stderr, "unrecognised option '%s'\n", str);
+		usage();
+	}
+}
 
 /* control multiple files */
 int
@@ -108,9 +182,15 @@
 
 	int ch;
 
+#ifdef TIMING
+	struct timeval t1, t2;
+
+	(void)gettimeofday(&t1, NULL);
+#endif
+
 	prgname = argv[0];
 
-	while ((ch = getopt(argc, argv, "VlwX:Z:W:sOT:gx:kv")) != -1)
+	while ((ch = getopt(argc, argv, "OT:VW:X:Z:f:gklm:psvwx:")) != -1)
 		switch (ch) {
 #if !defined(MULTIPASS) || defined(PASS1)
 		case 'X':
@@ -118,13 +198,13 @@
 				switch (*optarg++) {
 				case 'd': ++ddebug; break; /* declarations */
 				case 'i': ++idebug; break; /* initializations */
-				case 'b': ++bdebug; break;
-				case 't': ++tdebug; break;
+				case 'b': ++bdebug; break; /* buildtree */
+				case 't': ++tdebug; break; /* type match */
 				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 's': ++sdebug; break; /* inline */
+				case 'n': ++nflag; break;  /* node alloc */
+				case 'o': ++oflag; break;  /* optim */
 				case 'p': ++pdebug; break; /* prototype */
 				default:
 					fprintf(stderr, "unknown X flag '%c'\n",
@@ -161,15 +241,12 @@
 				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;
@@ -187,16 +264,28 @@
 #endif
 			break;
 
+		case 'f': /* Language */
+			fflags(optarg);
+			break;
+
+		case 'g': /* Debugging */
+			gflag = 1;
+			break;
+
 		case 'k': /* PIC code */
 			++kflag;
 			break;
 
-		case 'l': /* linenos */
+		case 'l': /* Linenos */
 			++lflag;
 			break;
 
-		case 'g': /* Debugging */
-			gflag = 1;
+		case 'm': /* Target-specific */
+			mflags(optarg);
+			break;
+
+		case 'p': /* Profiling */
+			pflag = 1;
 			break;
 
 		case 's': /* Statistics */
@@ -216,6 +305,10 @@
 				xtemps++;
 			else if (strcmp(optarg, "deljumps") == 0)
 				xdeljumps++;
+			else if (strcmp(optarg, "dce") == 0)
+				xdce++;
+			else if (strcmp(optarg, "inline") == 0)
+				xinline++;
 			else
 				usage();
 			break;
@@ -230,20 +323,21 @@
 		argc -= optind;
 		argv += optind;
 
-		if (argc != 0) {
+		if (argc > 0 && strcmp(argv[0], "-") != 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);
-				}
+		}
+		if (argc > 1 && strcmp(argv[1], "-") != 0) {
+			if (freopen(argv[1], "w", stdout) == NULL) {
+				fprintf(stderr, "open output file '%s':",
+				    argv[1]);
+				perror(NULL);
+				exit(1);
+			}
 		}
 
 	mkdope();
@@ -254,27 +348,18 @@
 	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();
+#ifndef TARGET_STDARGS
+	{
+		NODE *p = block(NAME, NIL, NIL, PTR|CHAR, NULL, MKSUE(CHAR));
+		struct symtab *sp = lookup(addname("__builtin_va_list"), 0);
+		p->n_sp = sp;
+		defid(p, TYPEDEF);
+		nfree(p);
+	}
+#endif
 
 #ifdef STABS
 	if (gflag) {
@@ -283,13 +368,34 @@
 	}
 #endif
 
+	if (sspflag)
+		sspinit();
+
 	(void) yyparse();
 	yyaccpt();
 
-	ejobcode( nerrors ? 1 : 0 );
 	if (!nerrors)
 		lcommprint();
 
+#ifdef STABS
+	if (gflag)
+		stabs_efile(argc ? argv[0] : "");
+#endif
+
+	ejobcode( nerrors ? 1 : 0 );
+
+#ifdef TIMING
+	(void)gettimeofday(&t2, NULL);
+	t2.tv_sec -= t1.tv_sec;
+	t2.tv_usec -= t1.tv_usec;
+	if (t2.tv_usec < 0) {
+		t2.tv_usec += 1000000;
+		t2.tv_sec -= 1;
+	}
+	fprintf(stderr, "pccom total time: %ld s %ld us\n",
+	    t2.tv_sec, t2.tv_usec);
+#endif
+
 	if (sflag)
 		prtstats();
 	return(nerrors?1:0);
Index: cgram.y
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/cgram.y,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/ccom/cgram.y -L usr.bin/pcc/ccom/cgram.y -u -r1.1 -r1.2
--- usr.bin/pcc/ccom/cgram.y
+++ usr.bin/pcc/ccom/cgram.y
@@ -1,4 +1,4 @@
-/*	$Id: cgram.y,v 1.170 2007/09/16 19:25:33 ragge Exp $	*/
+/*	$Id: cgram.y,v 1.241 2008/12/20 14:15:27 ragge Exp $	*/
 
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
@@ -79,7 +79,6 @@
 /*
  * 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 */
@@ -116,6 +115,9 @@
 %token	C_QUALIFIER
 %token	C_FUNSPEC
 %token	C_ASM
+%token	NOMATCH
+%token	C_TYPEOF	/* COMPAT_GCC */
+%token	C_ATTRIBUTE	/* COMPAT_GCC */
 
 /*
  * Precedence
@@ -142,14 +144,15 @@
 # include <string.h>
 # include <stdlib.h>
 
-static int fun_inline;	/* Reading an inline function */
+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
+extern int enummer, tvaloff;
+extern struct rstack *rpole;
+static int ctval, widestr;
+NODE *cftnod;
 
+#define	NORETYP	SNOCREAT /* no return type, save in unused field in symtab */
 
 static NODE *bdty(int op, ...);
 static void fend(void);
@@ -159,12 +162,29 @@
 static void resetbc(int mask);
 static void swend(void);
 static void addcase(NODE *p);
+#ifdef GCC_COMPAT
+static void gcccase(NODE *p, NODE *);
+#endif
 static void adddef(void);
 static void savebc(void);
-static void swstart(int);
-static NODE * structref(NODE *p, int f, char *name);
+static void swstart(int, TWORD);
+static void genswitch(int, TWORD, struct swents **, int);
+static NODE *structref(NODE *p, int f, char *name);
 static char *mkpstr(char *str);
 static struct symtab *clbrace(NODE *);
+static NODE *cmop(NODE *l, NODE *r);
+static NODE *xcmop(NODE *out, NODE *in, NODE *str);
+static void mkxasm(char *str, NODE *p);
+static NODE *xasmop(char *str, NODE *p);
+static int maxstlen(char *str);
+static char *stradd(char *old, char *new);
+static NODE *biop(int op, NODE *l, NODE *r);
+static void flend(void);
+static char * simname(char *s);
+#ifdef GCC_COMPAT
+static NODE *tyof(NODE *);	/* COMPAT_GCC */
+static NODE *voidcon(void);	/* COMPAT_GCC */
+#endif
 
 /*
  * State for saving current switch state (when nested switches).
@@ -184,6 +204,7 @@
 	NODE *nodep;
 	struct symtab *symp;
 	struct rstack *rp;
+	struct suedef *suep;
 	char *strp;
 }
 
@@ -191,60 +212,49 @@
 %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
+		type_qualifier_list xbegin
+%type <nodep> e .e term enum_dcl struct_dcl cast_type 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
+		identifier_list arg_param_list
+		designator_list designator xasm oplist oper cnstr funtype
+		typeof attribute attribute_specifier /* COMPAT_GCC */
+		attribute_list attr_spec_list /* COMPAT_GCC */
+%type <strp>	string C_STRING
+%type <rp>	str_head
+%type <symp>	xnfdeclarator clbrace enum_head
 
 %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
-
+%type <suep>	attr_var
 %%
 
 ext_def_list:	   ext_def_list external_def
 		| { ftnend(); }
 		;
 
-external_def:	   function_definition { blevel = 0; }
+external_def:	   funtype kr_args compoundstmt { fend(); }
 		|  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(); }
+funtype:	  /* no type given */ declarator {
+		    fundef(mkty(INT, 0, MKSUE(INT)), $1);
+		    cftnsp->sflags |= NORETYP;
+		}
+		| declaration_specifiers declarator { fundef($1,$2); }
+		;
+
+kr_args:	  /* empty */
+		| arg_dcl_list
 		;
 
 /*
@@ -264,14 +274,12 @@
 		|  C_QUALIFIER merge_attribs { $1->n_left = $2; $$ = $1; }
 		|  function_specifiers { $$ = NIL; }
 		|  function_specifiers merge_attribs { $$ = $2; }
+ /*COMPAT_GCC*/	|  typeof { $$ = $1; }
+ /*COMPAT_GCC*/	|  typeof merge_attribs { $1->n_left = $2; $$ = $1; }
 		;
 
 function_specifiers:
-		   C_FUNSPEC {
-			if (fun_inline)
-				uerror("too many inline");
-			fun_inline = 1;
-		}
+		   C_FUNSPEC { fun_inline = 1; }
 		;
 
 type_specifier:	   C_TYPE { $$ = $1; }
@@ -282,16 +290,40 @@
 		}
 		|  struct_dcl { $$ = $1; }
 		|  enum_dcl { $$ = $1; }
+		|  attribute_specifier { tfree($1); $$ = biop(FLD, 0, 0); }
+		;
+
+typeof:		   C_TYPEOF '(' term ')' { $$ = tyof($3); } /* COMPAT_GCC */
+ /*COMPAT_GCC*/	|  C_TYPEOF '(' cast_type ')' { $$ = tyof($3); }
+ /*COMPAT_GCC*/	;
+
+attribute_specifier :
+		   C_ATTRIBUTE '(' '(' attribute_list ')' ')' { $$ = $4; }
+ /*COMPAT_GCC*/	;
+
+attribute_list:	   attribute
+		|  attribute ',' attribute_list { $$ = cmop($3, $1); }
+		;
+
+attribute:	   { $$ = voidcon(); }
+		|  C_NAME { $$ = bdty(NAME, $1); }
+		|  C_NAME '(' elist ')' {
+			$$ = bdty($3 == NIL ? UCALL : CALL, bdty(NAME, $1), $3);
+		}
 		;
 
 /*
  * 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;
+declarator:	   pointer direct_declarator attr_var {
+			$$ = $1; $1->n_right->n_left = $2; $$->n_sue = 0;
 		}
-		|  direct_declarator { $$ = $1; }
+		|  pointer attr_spec_list direct_declarator attr_var {
+			$$ = $1; $1->n_right->n_left = $3; $$->n_sue = 0;
+			tfree($2);
+		}
+		|  direct_declarator attr_var { $$ = $1; $$->n_sue = 0; }
 		;
 
 /*
@@ -328,41 +360,58 @@
 direct_declarator: C_NAME { $$ = bdty(NAME, $1); }
 		|  '(' declarator ')' { $$ = $2; }
 		|  direct_declarator '[' nocon_e ']' { 
-			$$ = block(LB, $1, $3, INT, 0, MKSUE(INT));
+			$3 = optim($3);
+			if ((blevel == 0 || rpole != NULL) && !nncon($3))
+				uerror("array size not constant");
+			/*
+			 * Checks according to 6.7.5.2 clause 1:
+			 * "...the expression shall have an integer type."
+			 * "If the expression is a constant expression,
+			 * it shall have a value greater than zero."
+			 */
+			if (!ISINTEGER($3->n_type))
+				werror("array size is not an integer");
+			else if ($3->n_op == ICON) {
+				if ($3->n_lval < 0) {
+					uerror("array size cannot be negative");
+					$3->n_lval = 1;
+				}
+#ifdef notyet
+				if ($3->n_lval == 0 && Wgcc)
+					werror("gcc extension; zero size");
+#endif
+			}
+			$$ = biop(LB, $1, $3);
+		}
+		|  direct_declarator '[' ']' {
+			$$ = biop(LB, $1, bcon(NOOFFSET));
 		}
-		|  direct_declarator '[' ']' { $$ = bdty(LB, $1, 0); }
-		|  direct_declarator '(' notype parameter_type_list ')' {
-			$$ = bdty(CALL, $1, $4);
+		|  direct_declarator '(' parameter_type_list ')' {
+			$$ = bdty(CALL, $1, $3);
 		}
-		|  direct_declarator '(' notype identifier_list ')' { 
-			$$ = bdty(CALL, $1, $4);
+		|  direct_declarator '(' identifier_list ')' { 
+			$$ = bdty(CALL, $1, $3);
 			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"); */ }
+		|  direct_declarator '(' ')' {
+			ctval = tvaloff;
+			$$ = bdty(UCALL, $1);
+		}
 		;
 
-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);
-		}
+identifier_list:   C_NAME { $$ = bdty(NAME, $1); }
+		|  identifier_list ',' C_NAME { $$ = cmop($1, bdty(NAME, $3)); }
 		;
 
 /*
  * 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);
+			$$ = cmop($1, biop(ELLIPSIS, NIL, NIL));
 		}
 		;
 
@@ -373,7 +422,7 @@
  */
 parameter_list:	   parameter_declaration { $$ = $1; }
 		|  parameter_list ',' parameter_declaration {
-			$$ = block(CM, $1, $3, 0, 0, 0);
+			$$ = cmop($1, $3);
 		}
 		;
 
@@ -382,15 +431,22 @@
  */
 parameter_declaration:
 		   declaration_specifiers declarator {
+			if ($1->n_lval != SNULL && $1->n_lval != REGISTER)
+				uerror("illegal parameter class");
+			$2->n_sue = NULL; /* no attributes */
 			$$ = tymerge($1, $2);
 			nfree($1);
+		
 		}
 		|  declaration_specifiers abstract_declarator { 
+			$2->n_sue = NULL; /* no attributes */
 			$$ = tymerge($1, $2);
 			nfree($1);
 		}
 		|  declaration_specifiers {
-			$$ = tymerge($1, bdty(NAME, NULL));
+			$$ = bdty(NAME, NULL);
+			$$->n_sue = NULL; /* no attributes */
+			$$ = tymerge($1, $$);
 			nfree($1);
 		}
 		;
@@ -398,28 +454,30 @@
 abstract_declarator:
 		   pointer { $$ = $1; $1->n_right->n_left = bdty(NAME, NULL); }
 		|  direct_abstract_declarator { $$ = $1; }
-		|  pointer direct_abstract_declarator { 
+		|  pointer direct_abstract_declarator attr_var { 
 			$$ = $1; $1->n_right->n_left = $2;
 		}
 		;
 
 direct_abstract_declarator:
 		   '(' abstract_declarator ')' { $$ = $2; }
-		|  '[' ']' { $$ = bdty(LB, bdty(NAME, NULL), 0); }
+		|  '[' ']' { $$ = biop(LB, bdty(NAME, NULL), bcon(NOOFFSET)); }
 		|  '[' con_e ']' { $$ = bdty(LB, bdty(NAME, NULL), $2); }
-		|  direct_abstract_declarator '[' ']' { $$ = bdty(LB, $1, 0); }
+		|  direct_abstract_declarator '[' ']' {
+			$$ = biop(LB, $1, bcon(NOOFFSET));
+		}
 		|  direct_abstract_declarator '[' con_e ']' {
 			$$ = bdty(LB, $1, $3);
 		}
 		|  '(' ')' { $$ = bdty(UCALL, bdty(NAME, NULL)); }
-		|  '(' notype parameter_type_list ')' {
-			$$ = bdty(CALL, bdty(NAME, NULL), $3);
+		|  '(' parameter_type_list ')' {
+			$$ = bdty(CALL, bdty(NAME, NULL), $2);
 		}
 		|  direct_abstract_declarator '(' ')' {
 			$$ = bdty(UCALL, $1);
 		}
-		|  direct_abstract_declarator '(' notype parameter_type_list ')' {
-			$$ = bdty(CALL, $1, $4);
+		|  direct_abstract_declarator '(' parameter_type_list ')' {
+			$$ = bdty(CALL, $1, $3);
 		}
 		;
 
@@ -445,25 +503,24 @@
 /*
  * Declarations in beginning of blocks.
  */
-declaration_list:  declaration
-		|  declaration_list declaration
+block_item_list:   block_item
+		|  block_item_list block_item
+		;
+
+block_item:	   declaration
+		|  statement
 		;
 
 /*
  * 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:	   declaration_specifiers ';' { nfree($1); fun_inline = 0; }
 		|  declaration_specifiers init_declarator_list ';' {
 			nfree($1);
-			inl:
 			fun_inline = 0;
 		}
 		;
@@ -474,41 +531,51 @@
  */
 init_declarator_list:
 		   init_declarator
-		|  init_declarator_list ',' { $<nodep>$ = $<nodep>0; } init_declarator
+		|  init_declarator_list ',' attr_var { $<nodep>$ = $<nodep>0; } init_declarator attr_var
 		;
 
-enum_dcl:	   enum_head '{' moe_list optcomma '}' { $$ = dclstruct($1); }
-		|  C_ENUM C_NAME {  $$ = rstruct($2,0);  }
-		|  C_ENUM C_TYPENAME {  $$ = rstruct($2,0);  }
+enum_dcl:	   enum_head '{' moe_list optcomma '}' { $$ = enumdcl($1); }
+		|  C_ENUM C_NAME {  $$ = enumref($2); }
 		;
 
-enum_head:	   C_ENUM {  $$ = bstruct(NULL,0); }
-		|  C_ENUM C_NAME {  $$ = bstruct($2,0); }
-		|  C_ENUM C_TYPENAME {  $$ = bstruct($2,0); }
+enum_head:	   C_ENUM { $$ = enumhd(NULL); }
+		|  C_ENUM C_NAME {  $$ = enumhd($2); }
 		;
 
 moe_list:	   moe
 		|  moe_list ',' moe
 		;
 
-moe:		   C_NAME {  moedef( $1 ); }
-		|  C_NAME '=' con_e {  strucoff = $3;  moedef( $1 ); }
+moe:		   C_NAME {  moedef($1); }
+		|  C_TYPENAME {  moedef($1); }
+		|  C_NAME '=' con_e { enummer = $3; moedef($1); }
+		|  C_TYPENAME '=' con_e { enummer = $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); 
+struct_dcl:	   str_head '{' struct_dcl_list '}' {
+			$$ = dclstruct($1, NULL); 
 		}
+		|  C_STRUCT attr_var C_NAME {  $$ = rstruct($3,$1); }
+ /*COMPAT_GCC*/	|  str_head '{' '}' { $$ = dclstruct($1, NULL); }
 		;
 
-str_head:	   C_STRUCT {  $$ = bstruct(NULL, $1);  }
-		|  C_STRUCT C_NAME {  $$ = bstruct($2,$1);  }
-		|  C_STRUCT C_TYPENAME {  $$ = bstruct($2,$1);  }
+attr_var:	   {	
+			if (pragma_aligned || pragma_packed) {
+				$$ = tmpcalloc(sizeof(struct suedef));
+				$$->suealigned = pragma_aligned;
+				$$->suepacked = pragma_packed;
+			} else
+				$$ = NULL;
+		}
+ /*COMPAT_GCC*/	|  attr_spec_list { $$ = gcc_type_attrib($1); }
+		;
+
+attr_spec_list:	   attribute_specifier 
+		|  attr_spec_list attribute_specifier { tfree($2); /* XXX */ }
+		;
+
+str_head:	   C_STRUCT attr_var {  $$ = bstruct(NULL, $1, $2);  }
+		|  C_STRUCT attr_var C_NAME {  $$ = bstruct($3,$1, $2);  }
 		;
 
 struct_dcl_list:   struct_declaration
@@ -539,30 +606,33 @@
 
 struct_declarator: declarator {
 			tymerge($<nodep>0, $1);
-			$1->n_sp = getsymtab((char *)$1->n_sp, SMOSNAME); /* XXX */
-			defid($1, $<nodep>0->n_lval); 
+			soumemb($1, (char *)$1->n_sp, 0);
 			nfree($1);
 		}
 		|  ':' con_e {
-			if (!(instruct&INSTRUCT))
-				uerror( "field outside of structure" );
+			if (fldchk($2))
+				$2 = 1;
 			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" );
+			if (fldchk($3))
 				$3 = 1;
-			}
 			if ($1->n_op == NAME) {
 				tymerge($<nodep>0, $1);
-				$1->n_sp = getsymtab((char *)$1->n_sp,SMOSNAME);
-				defid($1, FIELD|$3);
+				soumemb($1, (char *)$1->n_sp, FIELD | $3);
 				nfree($1);
 			} else
 				uerror("illegal declarator");
 		}
+		| /* unnamed member */ {
+			NODE *p = $<nodep>0;
+			char *c = permalloc(10);
+
+			if (p->n_type != STRTY && p->n_type != UNIONTY)
+				uerror("bad unnamed member type");
+			snprintf(c, 10, "*%dFAKE", getlab());
+			soumemb(p, c, 0);
+		}
 		;
 
 		/* always preceeded by attributes */
@@ -576,27 +646,29 @@
 init_declarator:   declarator { init_declarator($<nodep>0, $1, 0); }
 		|  declarator C_ASM '(' string ')' {
 #ifdef GCC_COMPAT
-			renname = $4;
+			pragma_renamed = newstring($4, strlen($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 '=' e { simpleinit($1, eve($3)); xnf = NULL; }
 		|  xnfdeclarator '=' begbr init_list optcomma '}' {
 			endinit();
 			xnf = NULL;
 		}
+ /*COMPAT_GCC*/	|  xnfdeclarator '=' begbr '}' { endinit(); xnf = NULL; }
 		|  xnfdeclarator '=' addrlbl { simpleinit($1, $3); xnf = NULL; }
 		;
 
 begbr:		   '{' { beginit($<symp>-1); }
 		;
 
-initializer:	   e %prec ',' {  $$ = $1; }
+initializer:	   e %prec ',' {  $$ = eve($1); }
 		|  addrlbl {  $$ = $1; }
 		|  ibrace init_list optcomma '}' { $$ = NULL; }
+		|  ibrace '}' { asginit(bcon(0)); $$ = NULL; }
 		;
 
 init_list:	   designation initializer { asginit($2); }
@@ -611,8 +683,18 @@
 		|  designator_list designator { $$ = $2; $$->n_left = $1; }
 		;
 
-designator:	   '[' con_e ']' { $$ = bdty(LB, NULL, $2); }
-		|  C_STROP C_NAME { $$ = bdty(NAME, $2); }
+designator:	   '[' con_e ']' {
+			if ($2 < 0) {
+				uerror("designator must be non-negative");
+				$2 = 0;
+			}
+			$$ = biop(LB, NIL, bcon($2));
+		}
+		|  C_STROP C_NAME {
+			if ($1 != DOT)
+				uerror("invalid designator");
+			$$ = bdty(NAME, $2);
+		}
 		;
 
 optcomma	:	/* VOID */
@@ -624,34 +706,8 @@
 
 /*	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;
-		}
+compoundstmt:	   begin block_item_list '}' { flend(); }
+		|  begin '}' { flend(); }
 		;
 
 begin:		  '{' {
@@ -672,10 +728,13 @@
 			bc->contlab = autooff;
 			bc->next = savctx;
 			savctx = bc;
+			bccode();
+			if (sspflag && blevel == 2)
+				sspstart();
 		}
 		;
 
-statement:	   e ';' { ecomp( $1 ); }
+statement:	   e ';' { ecomp(eve($1)); symclear(blevel); }
 		|  compoundstmt
 		|  ifprefix statement { plabel($1); reached = 1; }
 		|  ifelprefix statement {
@@ -698,9 +757,9 @@
 			if (flostat & FCONT)
 				reached = 1;
 			if (reached)
-				cbranch($5, bcon($1));
+				cbranch(eve($5), bcon($1));
 			else
-				tfree($5);
+				tfree(eve($5));
 			plabel( brklab);
 			reached = 1;
 			resetbc(0);
@@ -741,35 +800,37 @@
 		}
 		|  C_RETURN  ';' {
 			branch(retlab);
-			if (cftnsp->stype != VOID && noretype &&
+			if (cftnsp->stype != VOID && 
+			    (cftnsp->sflags & NORETYP) == 0 &&
 			    cftnsp->stype != VOID+FTN)
 				uerror("return value required");
 			rch:
-			if (!reached)
+			if (!reached && Wunreachable_code)
 				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);
+			NODE *p;
 
-			if (temp->n_type == VOID)
-				ecomp(temp->n_right);
-			else
-				ecomp(buildtree(FORCE, temp->n_right, NIL));
-			nfree(temp->n_left);
-			nfree(temp);
+			p = nametree(cftnsp);
+			p->n_type = DECREF(p->n_type);
+			p = buildtree(RETURN, p, eve($2));
+			if (p->n_type == VOID) {
+				ecomp(p->n_right);
+			} else {
+				if (cftnod == NIL)
+					cftnod = tempnode(0, p->n_type,
+					    p->n_df, p->n_sue);
+				ecomp(buildtree(ASSIGN,
+				    tcopy(cftnod), p->n_right));
+			}
+			tfree(p->n_left);
+			nfree(p);
 			branch(retlab);
 			reached = 0;
 		}
 		|  C_GOTO C_NAME ';' { gotolabel($2); goto rch; }
-		|  C_GOTO '*' e ';' {
-			ecomp(block(GOTO, $3, NIL, INT, 0, 0));
-		}
+		|  C_GOTO '*' e ';' { ecomp(biop(GOTO, eve($3), NIL)); }
 		|  asmstatement ';'
 		|   ';'
 		|  error  ';'
@@ -777,18 +838,44 @@
 		|  label statement
 		;
 
-asmstatement:	   C_ASM '(' string ')' { send_passt(IP_ASM, mkpstr($3)); }
+asmstatement:	   C_ASM mvol '(' string ')' { send_passt(IP_ASM, mkpstr($4)); }
+		|  C_ASM mvol '(' string xasm ')' { mkxasm($4, $5); }
+		;
+
+mvol:		   /* empty */
+		|  C_QUALIFIER { nfree($1); }
+		;
+
+xasm:		   ':' oplist { $$ = xcmop($2, NIL, NIL); }
+		|  ':' oplist ':' oplist { $$ = xcmop($2, $4, NIL); }
+		|  ':' oplist ':' oplist ':' cnstr { $$ = xcmop($2, $4, $6); }
+		;
+
+oplist:		   /* nothing */ { $$ = NIL; }
+		|  oper { $$ = $1; }
 		;
 
+oper:		   string '(' e ')' { $$ = xasmop($1, eve($3)); }
+		|  oper ',' string '(' e ')' {
+			$$ = cmop($1, xasmop($3, eve($5)));
+		}
+		;
+
+cnstr:		   string { $$ = xasmop($1, bcon(0)); }
+		|  cnstr ',' string { $$ = cmop($1, xasmop($3, bcon(0))); }
+                ;
+
 label:		   C_NAME ':' { deflabel($1); reached = 1; }
-		|  C_CASE e ':' { addcase($2); reached = 1; }
+		|  C_TYPENAME ':' { deflabel($1); reached = 1; }
+		|  C_CASE e ':' { addcase(eve($2)); reached = 1; }
+/* COMPAT_GCC */|  C_CASE e C_ELLIPSIS e ':' {
+			gcccase(eve($2), eve($4)); 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());
@@ -796,7 +883,7 @@
 		}
 		;
 ifprefix:	C_IF '(' e ')' {
-			cbranch(buildtree(NOT, $3, NIL), bcon($$ = getlab()));
+			cbranch(buildtree(NOT, eve($3), NIL), bcon($$ = getlab()));
 			reached = 1;
 		}
 		;
@@ -812,8 +899,7 @@
 
 whprefix:	  C_WHILE  '('  e  ')' {
 			savebc();
-			if (!reached)
-				werror("loop not entered at top");
+			$3 = eve($3);
 			if ($3->n_op == ICON && $3->n_lval != 0)
 				flostat = FLOOP;
 			plabel( contlab = getlab());
@@ -828,8 +914,18 @@
 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;
+		}
+		|  C_FOR '(' incblev declaration .e ';' {
+			blevel--;
 			savebc();
 			contlab = getlab();
 			brklab = getlab();
@@ -841,182 +937,152 @@
 				flostat |= FLOOP;
 		}
 		;
-switchpart:	   C_SWITCH  '('  e  ')' {
+
+incblev:	   { blevel++; }
+		;
+
+switchpart:	   C_SWITCH  '('  e ')' {
 			NODE *p;
 			int num;
+			TWORD t;
 
 			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);
+			$3 = eve($3);
+			if (($3->n_type != BOOL && $3->n_type > ULONGLONG) ||
+			    $3->n_type < CHAR) {
+				uerror("switch expression must have integer "
+				       "type");
+				t = INT;
+			} else {
+				$3 = intprom($3);
+				t = $3->n_type;
 			}
-//			ecomp( buildtree( FORCE, $3, NIL ) );
-			p = tempnode(0, INT, 0, MKSUE(INT));
-			num = p->n_lval;
+			p = tempnode(0, t, 0, MKSUE(t));
+			num = regno(p);
 			ecomp(buildtree(ASSIGN, p, $3));
 			branch( $$ = getlab());
-			swstart(num);
+			swstart(num, t);
 			reached = 0;
 		}
 		;
 /*	EXPRESSIONS	*/
-con_e:		{ $<intval>$=instruct; instruct=0; } e %prec ',' {
-			$$ = icons( $2 );
-			instruct=$<intval>1;
+con_e:		{ $<rp>$ = rpole; rpole = NULL; } e %prec ',' {
+			$$ = icons(eve($2));
+			rpole = $<rp>1;
 		}
 		;
 
-nocon_e:	{ $<intval>$=instruct; instruct=0; } e %prec ',' {
-			instruct=$<intval>1;
-			$$ = $2;
+nocon_e:	{ $<rp>$ = rpole; rpole = NULL; } e %prec ',' {
+			rpole = $<rp>1;
+			$$ = eve($2);
 		}
 		;
 
-.e:		   e
+.e:		   e { $$ = eve($1); }
 		| 	{ $$=0; }
 		;
 
-elist:		   e %prec ','
-		|  elist  ','  e { $$ = buildtree(CM, $1, $3); }
+elist:		   { $$ = NIL; }
+		|  e %prec ','
+		|  elist  ','  e { $$ = biop(CM, $1, $3); }
+		|  elist  ','  cast_type { /* hack for stdarg */
+			$3->n_op = TYPE;
+			$$ = biop(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 { $$ = biop(COMOP, $1, $3); }
+		|  e '=' e {  $$ = biop(ASSIGN, $1, $3); }
+		|  e C_ASOP e {  $$ = biop($2, $1, $3); }
 		|  e '?' e ':' e {
-			$$=buildtree(QUEST, $1, buildtree(COLON, $3, $5));
+			$$=biop(QUEST, $1, biop(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); }
+		|  e C_OROR e { $$ = biop($2, $1, $3); }
+		|  e C_ANDAND e { $$ = biop($2, $1, $3); }
+		|  e '|' e { $$ = biop(OR, $1, $3); }
+		|  e '^' e { $$ = biop(ER, $1, $3); }
+		|  e '&' e { $$ = biop(AND, $1, $3); }
+		|  e C_EQUOP  e { $$ = biop($2, $1, $3); }
+		|  e C_RELOP e { $$ = biop($2, $1, $3); }
+		|  e C_SHIFTOP e { $$ = biop($2, $1, $3); }
+		|  e '+' e { $$ = biop(PLUS, $1, $3); }
+		|  e '-' e { $$ = biop(MINUS, $1, $3); }
+		|  e C_DIVOP e { $$ = biop($2, $1, $3); }
+		|  e '*' e { $$ = biop(MUL, $1, $3); }
+		|  e '=' addrlbl { $$ = biop(ASSIGN, $1, $3); }
 		|  term
 		;
 
+xbegin:		   begin {
+			$$ = getlab(); getlab(); getlab();
+			branch($$); plabel(($$)+1); }
+		;
+
 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);
+			$$ = buildtree(ADDROF, nametree(s), 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:		   term C_INCOP {  $$ = biop($2, $1, bcon(1)); }
+		|  '*' term { $$ = biop(UMUL, $2, NIL); }
+		|  '&' term { $$ = biop(ADDROF, $2, NIL); }
+		|  '-' term { $$ = biop(UMINUS, $2, NIL ); }
 		|  '+' term { $$ = $2; }
-		|  C_UNOP term { $$ = buildtree( $1, $2, NIL ); }
+		|  C_UNOP term { $$ = biop($1, $2, NIL); }
 		|  C_INCOP term {
-			$$ = buildtree($1 == INCR ? PLUSEQ : MINUSEQ,
-			    $2, bcon(1));
+			$$ = biop($1 == INCR ? PLUSEQ : MINUSEQ, $2, bcon(1));
 		}
-		|  C_SIZEOF term { $$ = doszof($2); }
+		|  C_SIZEOF term { $$ = biop(SZOF, $2, bcon(0)); }
 		|  '(' cast_type ')' term  %prec C_INCOP {
-			$$ = buildtree(CAST, $2, $4);
-			nfree($$->n_left);
-			nfree($$);
-			$$ = $$->n_right;
+			$$ = biop(CAST, $2, $4);
 		}
 		|  C_SIZEOF '(' cast_type ')'  %prec C_SIZEOF {
-			$$ = doszof($3);
+			$$ = biop(SZOF, $3, bcon(1));
 		}
-		| '(' cast_type ')' clbrace init_list '}' {
+		| '(' cast_type ')' clbrace init_list optcomma '}' {
+			uerror("compound literals");
 			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);
+			$$ = nametree($4);
 		}
+		|  term '[' e ']' { $$ = biop(LB, $1, $3); }
+		|  C_NAME  '(' elist ')' {
+			$$ = biop($3 ? CALL : UCALL, bdty(NAME, $1), $3);
+		}
+		|  term  '(' elist ')' { $$ = biop($3 ? CALL : UCALL, $1, $3); }
+		|  term C_STROP C_NAME { $$ = biop($2, $1, bdty(NAME, $3)); }
+		|  term C_STROP C_TYPENAME { $$ = biop($2, $1, bdty(NAME, $3));}
+		|  C_NAME %prec C_SIZEOF /* below ( */{ $$ = bdty(NAME, $1); }
 		|  C_ICON { $$ = $1; }
 		|  C_FCON { $$ = $1; }
-		|  string {  $$ = strend($1); /* get string contents */ }
-		|  wstring { $$ = wstrend($1); }
+		|  string { $$ = bdty(STRING, $1, widestr); }
 		|   '('  e  ')' { $$=$2; }
+		|  '(' xbegin block_item_list e ';' '}' ')' {
+			branch(($2)+2);
+			plabel($2);
+			$$ = biop(COMOP, biop(GOTO, bcon(($2)+1), NIL), $4);
+			$$->n_type = $4->n_type; /* XXX type checking ? */
+			$$->n_sue = $4->n_sue; /* XXX type checking ? */
+			$$->n_df = $4->n_df; /* XXX type checking ? */
+			flend();
+		}
 		;
 
 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);
-		}
+string:		   C_STRING { widestr = $1[0] == 'L'; $$ = stradd("", $1); }
+		|  string C_STRING { $$ = stradd($1, $2); }
 		;
 
 cast_type:	   specifier_qualifier_list {
@@ -1027,25 +1093,9 @@
 			$$ = tymerge($1, $2);
 			nfree($1);
 		}
+ /*COMPAT_GCC*/	|  typeof { $$ = $1; $$->n_op = NAME; }
 		;
 
-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 *
@@ -1058,10 +1108,11 @@
 bdty(int op, ...)
 {
 	va_list ap;
+	int val;
 	register NODE *q;
 
 	va_start(ap, op);
-	q = block(op, NIL, NIL, INT, 0, MKSUE(INT));
+	q = biop(op, NIL, NIL);
 
 	switch (op) {
 	case UMUL:
@@ -1077,13 +1128,22 @@
 
 	case LB:
 		q->n_left = va_arg(ap, NODE *);
-		q->n_right = bcon(va_arg(ap, int));
+		if ((val = va_arg(ap, int)) <= 0) {
+			uerror("array size must be positive");
+			val = 1;
+		}
+		q->n_right = bcon(val);
 		break;
 
 	case NAME:
 		q->n_sp = va_arg(ap, struct symtab *); /* XXX survive tymerge */
 		break;
 
+	case STRING:
+		q->n_name = va_arg(ap, char *);
+		q->n_lval = va_arg(ap, int);
+		break;
+
 	default:
 		cerror("bad bdty");
 	}
@@ -1093,6 +1153,25 @@
 }
 
 static void
+flend(void)
+{
+	if (sspflag && blevel == 2)
+		sspend();
+#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;
+}
+
+static void
 savebc(void)
 {
 	struct savbc *bc = tmpalloc(sizeof(struct savbc));
@@ -1120,6 +1199,7 @@
 	struct swents *ents;	/* Linked sorted list of case entries */
 	int nents;		/* # of entries in list */
 	int num;		/* Node value will end up in */
+	TWORD type;		/* Type of switch expression */
 } *swpole;
 
 /*
@@ -1128,7 +1208,8 @@
 static void
 addcase(NODE *p)
 {
-	struct swents *w, *sw = tmpalloc(sizeof(struct swents));
+	struct swents **put, *w, *sw = tmpalloc(sizeof(struct swents));
+	CONSZ val;
 
 	p = optim(p);  /* change enum to ints */
 	if (p->n_op != ICON || p->n_sp != NULL) {
@@ -1140,40 +1221,55 @@
 		return;
 	}
 
+	if (DEUNSIGN(swpole->type) != DEUNSIGN(p->n_type)) {
+		val = p->n_lval;
+		p = makety(p, swpole->type, 0, 0, MKSUE(swpole->type));
+		if (p->n_op != ICON)
+			cerror("could not cast case value to type of switch "
+			       "expression");
+		if (p->n_lval != val)
+			werror("case expression truncated");
+	}
 	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;
-		}
+	tfree(p);
+	put = &swpole->ents;
+	if (ISUNSIGNED(swpole->type)) {
+		for (w = swpole->ents;
+		     w != NULL && (U_CONSZ)w->sval < (U_CONSZ)sw->sval;
+		     w = w->next)
+			put = &w->next;
 	} 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;
-		}
+		for (w = swpole->ents; w != NULL && w->sval < sw->sval;
+		     w = w->next)
+			put = &w->next;
 	}
+	if (w != NULL && w->sval == sw->sval) {
+		uerror("duplicate case in switch");
+		return;
+	}
+	plabel(sw->slab = getlab());
+	*put = sw;
+	sw->next = w;
 	swpole->nents++;
-	tfree(p);
 }
 
+#ifdef GCC_COMPAT
+void
+gcccase(NODE *ln, NODE *hn)
+{
+	CONSZ i, l, h;
+
+	l = icons(optim(ln));
+	h = icons(optim(hn));
+
+	if (h < l)
+		i = l, l = h, h = i;
+
+	for (i = l; i <= h; i++)
+		addcase(xbcon(i, NULL, hn->n_type));
+}
+#endif
+
 /*
  * add default case to switch
  */
@@ -1189,7 +1285,7 @@
 }
 
 static void
-swstart(int num)
+swstart(int num, TWORD type)
 {
 	struct swdef *sw = tmpalloc(sizeof(struct swdef));
 
@@ -1197,6 +1293,7 @@
 	sw->ents = NULL;
 	sw->next = swpole;
 	sw->num = num;
+	sw->type = type;
 	swpole = sw;
 }
 
@@ -1219,12 +1316,44 @@
 		swp[i] = swpole->ents;
 		swpole->ents = swpole->ents->next;
 	}
-	genswitch(swpole->num, swp, swpole->nents);
+	genswitch(swpole->num, swpole->type, swp, swpole->nents);
 
 	swpole = swpole->next;
 }
 
 /*
+ * num: tempnode the value of the switch expression is in
+ * type: type of the switch expression
+ *
+ * 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
+ * n is the number of case statements (length of list)
+ */
+static void
+genswitch(int num, TWORD type, struct swents **p, int n)
+{
+	NODE *r, *q;
+	int i;
+
+	if (mygenswitch(num, type, p, n))
+		return;
+
+	/* simple switch code */
+	for (i = 1; i <= n; ++i) {
+		/* already in 1 */
+		r = tempnode(num, type, 0, MKSUE(type));
+		q = xbcon(p[i]->sval, NULL, type);
+		r = buildtree(NE, r, clocal(q));
+		cbranch(buildtree(NOT, r, NIL), bcon(p[i]->slab));
+	}
+	if (p[0]->slab > 0)
+		branch(p[0]->slab);
+}
+
+/*
  * Declare a variable or prototype.
  */
 static struct symtab *
@@ -1240,10 +1369,11 @@
 		typ->n_sp->sflags |= SINLINE;
 
 	if (ISFTN(typ->n_type) == 0) {
-		setloc1(DATA);
 		if (assign) {
 			defid(typ, class);
 			typ->n_sp->sflags |= SASG;
+			if (typ->n_sp->sflags & SDYNARRAY)
+				uerror("can't initialize dynamic arrays");
 			lcommdel(typ->n_sp);
 		} else {
 			nidcl(typ, class);
@@ -1258,6 +1388,24 @@
 }
 
 /*
+ * Declare function arguments.
+ */
+static void
+funargs(NODE *p)
+{
+	if (p->n_op == ELLIPSIS)
+		return;
+	if (oldstyle) {
+		p->n_op = TYPE;
+		p->n_type = FARG;
+	}
+	p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */
+	if (ISFTN(p->n_type))
+		p->n_type = INCREF(p->n_type);
+	defid(p, PARAM);
+}
+
+/*
  * Declare a function.
  */
 static void
@@ -1265,14 +1413,29 @@
 {
 	extern int prolab;
 	struct symtab *s;
+	NODE *q = p;
 	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);
+	for (q = p; coptype(q->n_op) != LTYPE && q->n_left->n_op != NAME;
+	    q = q->n_left)
+		;
+	if (q->n_op != CALL && q->n_op != UCALL) {
+		uerror("invalid function definition");
+		p = bdty(UCALL, p);
+	}
+
+	argoff = ARGINIT;
+	ctval = tvaloff;
+	blevel++;
+
+	if (q->n_op == CALL && q->n_right->n_type != VOID) {
+		/* declare function arguments */
+		listf(q->n_right, funargs);
+		ftnarg(q);
+	}
 
+	blevel--;
 	tymerge(tp, p);
 	s = p->n_sp = lookup((char *)p->n_sp, 0); /* XXX */
 
@@ -1280,26 +1443,22 @@
 	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 */
+	if (fun_inline) {
+		/* special syntax for inline functions */
 		s->sflags |= SINLINE;
-		inline_start(s->sname);
-	}
-	if (class == EXTERN)
+		inline_start(s);
+		if (class == EXTERN)
+			class = EXTDEF;
+	} else 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;
+	c = cftnsp->soname;
+	send_passt(IP_PROLOG, -1, c, cftnsp->stype,
+	    cftnsp->sclass == EXTDEF, prolab, ctval);
+	blevel++;
 #ifdef STABS
 	if (gflag)
 		stabs_func(s);
@@ -1326,9 +1485,10 @@
 
 	if (f == DOT)
 		p = buildtree(ADDROF, p, NIL);
-	r = block(NAME, NIL, NIL, INT, 0, MKSUE(INT));
+	r = biop(NAME, NIL, NIL);
 	r->n_name = name;
-	return buildtree(STREF, p, r);
+	r = buildtree(STREF, p, r);
+	return r;
 }
 
 static void
@@ -1351,7 +1511,7 @@
 branch(int lbl)
 {
 	int r = reached++;
-	ecomp(block(GOTO, bcon(lbl), NIL, INT, 0, 0));
+	ecomp(biop(GOTO, bcon(lbl), NIL));
 	reached = r;
 }
 
@@ -1362,9 +1522,10 @@
 mkpstr(char *str)
 {
 	char *s, *os;
-	int v, l = strlen(str)+1;
+	int v, l = strlen(str)+3; /* \t + \n + \0 */
 
-	os = s = isinlining ? permalloc(l) : tmpalloc(l);
+	os = s = inlalloc(l);
+	*s++ = '\t';
 	for (; *str; ) {
 		if (*str++ == '\\')
 			v = esccon(&str);
@@ -1372,29 +1533,365 @@
 			v = str[-1];
 		*s++ = v;
 	}
+	*s++ = '\n';
 	*s = 0;
 	return os;
 }
 
+/*
+ * Estimate the max length a string will have in its internal 
+ * representation based on number of \ characters.
+ */
+static int
+maxstlen(char *str)
+{
+	int i;
+
+	for (i = 0; *str; str++, i++)
+		if (*str == '\\' || *str < 32 || *str > 0176)
+			i += 3;
+	return i;
+}
+
+static char *
+voct(char *d, unsigned int v)
+{
+	v &= (1 << SZCHAR) - 1;
+	*d++ = '\\';
+	*d++ = v/64 + '0'; v &= 077;
+	*d++ = v/8 + '0'; v &= 7;
+	*d++ = v + '0';
+	return d;
+}
+	
+
+/*
+ * Convert a string to internal format.  The resulting string may be no
+ * more than len characters long.
+ */
+static void
+fixstr(char *d, char *s, int len)
+{
+	unsigned int v;
+
+	while (*s) {
+		if (len <= 0)
+			cerror("fixstr");
+		if (*s == '\\') {
+			s++;
+			v = esccon(&s);
+			d = voct(d, v);
+			len -= 4;
+		} else if (*s < ' ' || *s > 0176) {
+			d = voct(d, *s++);
+			len -= 4;
+		} else
+			*d++ = *s++, len--;
+	}
+	*d = 0;
+}
+
+/*
+ * Add "raw" string new to cleaned string old.
+ */
+static char *
+stradd(char *old, char *new)
+{
+	char *rv;
+	int len;
+
+	if (*new == 'L' && new[1] == '\"')
+		widestr = 1, new++;
+	if (*new == '\"') {
+		new++;			 /* remove first " */
+		new[strlen(new) - 1] = 0;/* remove last " */
+	}
+	len = strlen(old) + maxstlen(new) + 1;
+	rv = tmpalloc(len);
+	strlcpy(rv, old, len);
+	fixstr(rv + strlen(old), new, maxstlen(new) + 1);
+	return rv;
+}
+
 static struct symtab *
 clbrace(NODE *p)
 {
 	struct symtab *sp;
 
-	if (blevel == 0 && xnf != NULL)
-		cerror("no level0 compound literals");
-
-	sp = getsymtab("cl", STEMP);
+	sp = getsymtab(simname("cl"), STEMP);
+	if (blevel == 0 && xnf != NULL) {
+		sp->sclass = STATIC;
+		sp->slevel = 2;
+		sp->soffset = getlab();
+	} else {
+		sp->sclass = blevel ? AUTO : STATIC;
+		if (!ISARY(sp->stype) || sp->sdf->ddim != NOOFFSET) {
+			sp->soffset = NOOFFSET;
+			oalloc(sp, &autooff);
+		}
+	}
 	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;
 }
+
+char *
+simname(char *s)
+{
+	int len = strlen(s) + 10 + 1;
+	char *w = tmpalloc(len);
+
+	snprintf(w, len, "%s%d", s, getlab());
+	return w;
+}
+
+NODE *
+biop(int op, NODE *l, NODE *r)
+{
+	return block(op, l, r, INT, 0, MKSUE(INT));
+}
+
+static NODE *
+cmop(NODE *l, NODE *r)
+{
+	return biop(CM, l, r);
+}
+
+static NODE *
+voidcon(void)
+{
+	return block(ICON, NIL, NIL, STRTY, 0, MKSUE(VOID));
+}
+
+/* Support for extended assembler a' la' gcc style follows below */
+
+static NODE *
+xmrg(NODE *out, NODE *in)
+{
+	NODE *p = in;
+
+	if (p->n_op == XARG) {
+		in = cmop(out, p);
+	} else {
+		while (p->n_left->n_op == CM)
+			p = p->n_left;
+		p->n_left = cmop(out, p->n_left);
+	}
+	return in;
+}
+
+/*
+ * Put together in and out node lists in one list, and balance it with
+ * the constraints on the right side of a CM node.
+ */
+static NODE *
+xcmop(NODE *out, NODE *in, NODE *str)
+{
+	NODE *p, *q;
+
+	if (out) {
+		/* D out-list sanity check */
+		for (p = out; p->n_op == CM; p = p->n_left) {
+			q = p->n_right;
+			if (q->n_name[0] != '=' && q->n_name[0] != '+')
+				uerror("output missing =");
+		}
+		if (p->n_name[0] != '=' && p->n_name[0] != '+')
+			uerror("output missing =");
+		if (in == NIL)
+			p = out;
+		else
+			p = xmrg(out, in);
+	} else if (in) {
+		p = in;
+	} else
+		p = voidcon();
+
+	if (str == NIL)
+		str = voidcon();
+	return cmop(p, str);
+}
+
+/*
+ * Generate a XARG node based on a string and an expression.
+ */
+static NODE *
+xasmop(char *str, NODE *p)
+{
+
+	p = biop(XARG, p, NIL);
+	p->n_name = isinlining ? newstring(str, strlen(str)+1) : str;
+	return p;
+}
+
+/*
+ * Generate a XASM node based on a string and an expression.
+ */
+static void
+mkxasm(char *str, NODE *p)
+{
+	NODE *q;
+
+	q = biop(XASM, p->n_left, p->n_right);
+	q->n_name = isinlining ? newstring(str, strlen(str)+1) : str;
+	nfree(p);
+	ecomp(q);
+}
+
+#ifdef GCC_COMPAT
+static NODE *
+tyof(NODE *p)
+{
+	static struct symtab spp;
+	NODE *q = block(TYPE, NIL, NIL, p->n_type, 0, 0);
+	q->n_qual = p->n_qual;
+	q->n_sp = &spp; /* for typenode */
+	tfree(p);
+	return q;
+}
+#endif
+
+/*
+ * Traverse an unhandled expression tree bottom-up and call buildtree()
+ * or equivalent as needed.
+ */
+NODE *
+eve(NODE *p)
+{
+	struct symtab *sp;
+	NODE *r, *p1, *p2;
+	r = NULL;
+
+	p1 = p->n_left;
+	p2 = p->n_right;
+	switch (p->n_op) {
+	case NAME:
+		sp = lookup((char *)p->n_sp, 0);
+		if (sp->sflags & SINLINE)
+			inline_ref(sp);
+		r = nametree(sp);
+		if (sp->sflags & SDYNARRAY)
+			r = buildtree(UMUL, r, NIL);
+		break;
+
+	case DOT:
+	case STREF:
+		r = structref(eve(p1), p->n_op, (char *)p2->n_sp);
+		nfree(p2);
+		break;
+
+	case CAST:
+		p1 = buildtree(CAST, p1, eve(p2));
+		nfree(p1->n_left);
+		r = p1->n_right;
+		nfree(p1);
+		break;
+
+
+	case SZOF:
+		if (p2->n_lval == 0)
+			p1 = eve(p1);
+		nfree(p2);
+		r = doszof(p1);
+		break;
+
+	case LB:
+		p1 = eve(p->n_left);
+		r = buildtree(UMUL, buildtree(PLUS, p1, eve(p2)), NIL);
+		break;
+
+	case COMPL:
+	case UMINUS:
+	case NOT:
+	case UMUL:
+		r = buildtree(p->n_op, eve(p->n_left), NIL);
+		break;
+
+	case ADDROF:
+		r = eve(p1);
+		if (ISFTN(p->n_type)/* || ISARY(p->n_type) */){
+#ifdef notdef
+			werror( "& before array or function: ignored" );
+#endif
+		} else
+			r = buildtree(ADDROF, r, NIL);
+		break;
+
+	case CALL:
+		p2 = eve(p2);
+		/* FALLTHROUGH */
+	case UCALL:
+		if (p1->n_op == NAME) {
+			sp = lookup((char *)p1->n_sp, 0);
+			if (sp->stype == UNDEF) {
+				p1->n_type = FTN|INT;
+				p1->n_sp = sp;
+				defid(p1, EXTERN);
+			}
+			nfree(p1);
+			r = doacall(sp, nametree(sp), p2);
+		} else
+			r = doacall(NULL, eve(p1), p2);
+		break;
+
+	case INCR:
+	case DECR:
+	case CM:
+	case GT:
+	case GE:
+	case LT:
+	case LE:
+	case EQ:
+	case NE:
+	case RS:
+	case LS:
+	case RSEQ:
+	case LSEQ:
+	case AND:
+	case OR:
+	case ER:
+	case MUL:
+	case DIV:
+	case MOD:
+	case PLUS:
+	case MINUS:
+	case OROR:
+	case ANDAND:
+	case EREQ:
+	case OREQ:
+	case ANDEQ:
+	case MINUSEQ:
+	case PLUSEQ:
+	case MULEQ:
+	case DIVEQ:
+	case MODEQ:
+	case COMOP:
+	case QUEST:
+	case COLON:
+	case ASSIGN:
+		p1 = eve(p1);
+		r = buildtree(p->n_op, p1, eve(p2));
+		break;
+
+	case STRING:
+		r = strend(p->n_lval, p->n_name);
+		break;
+
+	case TYPE:
+	case ICON:
+	case FCON:
+		return p;
+
+	default:
+#ifdef PCC_DEBUG
+		fwalk(p, eprint, 0);
+#endif
+		cerror("eve");
+	}
+	nfree(p);
+	return r;
+}
Index: ccom.1
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/ccom.1,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/ccom/ccom.1 -L usr.bin/pcc/ccom/ccom.1 -u -r1.1 -r1.2
--- usr.bin/pcc/ccom/ccom.1
+++ usr.bin/pcc/ccom/ccom.1
@@ -1,39 +1,43 @@
-.\"	$Id: ccom.1,v 1.2 2007/09/26 14:48:49 ragge Exp $
 .\"	$NetBSD$
-.\"	$OpenBSD$
+.\"	$Id: ccom.1,v 1.8 2008/02/20 01:31:26 gmcgarry Exp $
 ."\
 .\" 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 
+.\" 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 
+.\"
+.\" 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
+.Dt CCOM 1
 .Os
 .Sh NAME
 .Nm ccom
 .Nd C compiler
 .Sh SYNOPSIS
 .Nm
+.Op Fl gs
+.Op Fl W Ar flags
 .Op Fl X Ar flags
+.Op Fl x Ar optimizations
+.Op Fl Z 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.
+It is
+.Em not
+intended to be run directly.
 .Pp
 .Nm
 reads the C source from
@@ -48,6 +52,8 @@
 .It Fl g
 Enable debugging.
 .\" built into binary, explain stabs?
+.It Fl k
+Generate PIC code.
 .It Fl s
 Print statistics to standard error when complete.
 This includes:
@@ -56,81 +62,112 @@
 dimension/function unions, struct/union/enum blocks, inline node count,
 inline control blocks, and permanent symtab entries.
 .\" TODO: explain units for above?
+.It Fl v
+Display version.
 .It Fl W Ar flags
 Report warnings.
 (Do some basic checks.)
-NOTE!  These are subject to change RSN!
-.Ar Flags
+.Em NOTE!
+.Em These are subject to change RSN!
+.Ar flags
 is one or more of the following:
 .Bl -tag -width Ds
+.It Sy error
+Report all warnings as errors.
 .It Sy implicit
 Implies
-.Sy implicit-int
+.Sy implicit-function-declaration
 and
-.Sy implicit-function-declaration .
+.Sy implicit-int .
+.It Sy implicit-function-declaration
+Report if no prototype was declared for a function.
 .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
+.It Sy W
+Enable all warnings.
+.El
+.\"
+.It Fl X Ar flags
+C specific debugging where
+.Ar flags
+is one or more of the following:
+.Bl -tag -width Ds
+.It Sy b
+Building of parse trees
+.It Sy d
+Declarations (using multiple
+.Sy d
+flags gives more output)
+.It Sy e
+Pass1 trees at exit
+.It Sy i
+Initializations
+.It Sy n
+Memory allocations
+.It Sy o
+Turn off optimisations
+.It Sy p
+Prototypes
+.It Sy s
+Inlining
+.It Sy t
+Type conversions
+.It Sy x
+Target-specific flag, used in machine-dependent code
 .El
 .\"
 .It Fl x Ar optimizations
 .Ar optimizations
-is one or more of the following:
+is one of the following:
+.\" TODO: reword this, since multiple terms don't go with one -x switch??
 .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.
+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 
+Setting this flag allows variables to be put into registers, for further
 optimization by the register allocator.
 .El
+The
+.Fl x
+flag can be passed multiple times to set different options.
 .\"
-.It Fl X Ar C specific debugging flags
-.Ar Flags
+.It Fl Z Ar flags
+Code generator (pass2) specific debugging where
+.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
+Basic block and SSA building
+.It Sy c
+Code printout
 .It Sy e
 Trees when entering pass2
-.It Sy o
-Instruction generator
 .It Sy f
 Instruction matcher, may provide much output
+.It Sy n
+Memory allocation
+.It Sy o
+Instruction generator
 .It Sy r
 Register allocator
-.It Sy t
-Type matching in instruction generator
 .It Sy s
 Shape matching in instruction generator
+.It Sy t
+Type matching in instruction generator
 .It Sy u
 Sethi-Ullman computations
 .It Sy x
-Target-specific flag, used in machine-dependent code 
+Target-specific flag, used in machine-dependent code
+.El
 .El
 .Sh SEE ALSO
 .Xr as 1 ,
@@ -139,8 +176,8 @@
 .Sh HISTORY
 The
 .Nm
-compiler is based on the original Portable C Compiler by S. C.
-Johnson, written in the late 70's.
+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
@@ -148,5 +185,8 @@
 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 
+part of a project by undergraduate students at Lulea University of
 Technology.
+.Pp
+This product includes software developed or owned by Caldera
+International, Inc.
Index: trees.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/trees.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/ccom/trees.c -L usr.bin/pcc/ccom/trees.c -u -r1.1 -r1.2
--- usr.bin/pcc/ccom/trees.c
+++ usr.bin/pcc/ccom/trees.c
@@ -1,4 +1,4 @@
-/*	$Id: trees.c,v 1.163 2007/09/16 08:26:39 ragge Exp $	*/
+/*	$Id: trees.c,v 1.223 2008/12/14 21:15:24 ragge Exp $	*/
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -70,14 +70,16 @@
 # include "pass2.h"
 
 # include <stdarg.h>
+# include <string.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;
+static void putjops(NODE *, void *);
+static struct symtab *findmember(struct symtab *, char *);
+int inftn; /* currently between epilog/prolog */
 
 /*	some special actions, used in finding the type of nodes */
 # define NCVT 01
@@ -107,6 +109,8 @@
 	*/
 
 int bdebug = 0;
+extern int negrel[];
+
 
 NODE *
 buildtree(int o, NODE *l, NODE *r)
@@ -116,8 +120,6 @@
 	int opty;
 	struct symtab *sp = NULL; /* XXX gcc */
 	NODE *lr, *ll;
-	char *name;
-	struct symtab **elem;
 
 #ifdef PCC_DEBUG
 	if (bdebug) {
@@ -143,23 +145,23 @@
 	} 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;
+			l->n_dcon = FLOAT_NEG(l->n_dcon);
 			return(l);
 
 	} else if( o==QUEST && l->n_op==ICON ) {
 		CONSZ c = l->n_lval;
 		nfree(l);
 		if (c) {
+			walkf(r->n_right, putjops, 0);
 			tfree(r->n_right);
 			l = r->n_left;
-			nfree(r);
-			return(l);
 		} else {
+			walkf(r->n_left, putjops, 0);
 			tfree(r->n_left);
 			l = r->n_right;
-			nfree(r);
-			return(l);
 		}
+		nfree(r);
+		return(l);
 	} else if( opty == BITYPE && l->n_op == ICON && r->n_op == ICON ){
 
 		switch( o ){
@@ -199,9 +201,11 @@
 		case ER:
 		case LS:
 		case RS:
-			if( conval( l, o, r ) ) {
-				nfree(r);
-				return(l);
+			if (!ISPTR(l->n_type) && !ISPTR(r->n_type)) {
+				if( conval( l, o, r ) ) {
+					nfree(r);
+					return(l);
+				}
 			}
 			break;
 		}
@@ -214,21 +218,24 @@
 		case MUL:
 		case DIV:
 			if (l->n_op == ICON)
-				l->n_dcon = l->n_lval;
+				l->n_dcon = FLOAT_CAST(l->n_lval, l->n_type);
 			if (r->n_op == ICON)
-				r->n_dcon = r->n_lval;
+				r->n_dcon = FLOAT_CAST(r->n_lval, r->n_type);
 			switch (o) {
 			case PLUS:
-				l->n_dcon += r->n_dcon; break;
+				l->n_dcon = FLOAT_PLUS(l->n_dcon, r->n_dcon);
+				break;
 			case MINUS:
-				l->n_dcon -= r->n_dcon; break;
+				l->n_dcon = FLOAT_MINUS(l->n_dcon, r->n_dcon);
+				break;
 			case MUL:
-				l->n_dcon *= r->n_dcon; break;
+				l->n_dcon = FLOAT_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;
+				if (FLOAT_ISZERO(r->n_dcon))
+					goto runtime;
+				l->n_dcon = FLOAT_DIV(l->n_dcon, r->n_dcon);
+				break;
 			}
 			l->n_op = FCON;
 			l->n_type = DOUBLE;
@@ -237,7 +244,7 @@
 			return(l);
 		}
 	}
-
+runtime:
 	/* its real; we must make a new node */
 
 	p = block(o, l, r, INT, 0, MKSUE(INT));
@@ -247,6 +254,8 @@
 	if (actions & LVAL) { /* check left descendent */
 		if (notlval(p->n_left)) {
 			uerror("lvalue required");
+			nfree(p);
+			return l;
 #ifdef notyet
 		} else {
 			if ((l->n_type > BTMASK && ISCON(l->n_qual)) ||
@@ -296,53 +305,7 @@
 		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;
+			cerror("buildtree NAME");
 
 		case STREF:
 			/* p->x turned into *(p+offset) */
@@ -354,17 +317,23 @@
 				break;
 			}
 
-			if ((elem = l->n_sue->suelem) == NULL)
+			if ((sp = l->n_sue->sylnk) == NULL) {
 				uerror("undefined struct or union");
+				break;
+			}
 
+			sp = findmember(sp, r->n_name);
+#ifdef notdef
 			name = r->n_name;
-			for (; *elem != NULL; elem++) {
-				sp = *elem;
+			for (; sp != NULL; sp = sp->snext) {
 				if (sp->sname == name)
 					break;
 			}
-			if (*elem == NULL)
-				uerror("member '%s' not declared", name);
+#endif
+			if (sp == NULL) {
+				uerror("member '%s' not declared", r->n_name);
+				break;
+			}
 
 			r->n_sp = sp;
 			p = stref(p);
@@ -453,7 +422,7 @@
 				TWORD t;
 				union dimfun *d;
 
-				if (l->n_sue != r->n_sue)
+				if (l->n_sue->sylnk != r->n_sue->sylnk)
 					uerror("assignment of different structures");
 
 				r = buildtree(ADDROF, r, NIL);
@@ -462,6 +431,7 @@
 				sue = r->n_sue;
 
 				l = block(STASG, l, r, t, d, sue);
+				l = clocal(l);
 
 				if( o == RETURN ){
 					nfree(p);
@@ -483,6 +453,8 @@
 
 		case CALL:
 			p->n_right = r = strargs(p->n_right);
+			p = funcode(p);
+			/* FALLTHROUGH */
 		case UCALL:
 			if (!ISPTR(l->n_type))
 				uerror("illegal function");
@@ -540,6 +512,88 @@
 
 	}
 
+/* Find a member in a struct or union.  May be an unnamed member */
+static struct symtab *
+findmember(struct symtab *sp, char *s)
+{
+	struct symtab *sp2, *sp3;
+
+	for (; sp != NULL; sp = sp->snext) {
+		if (sp->sname[0] == '*') {
+			/* unnamed member, recurse down */
+			if ((sp2 = findmember(sp->ssue->sylnk, s))) {
+				sp3 = tmpalloc(sizeof (struct symtab));
+				*sp3 = *sp2;
+				sp3->soffset += sp->soffset;
+				return sp3;
+			}
+		} else if (sp->sname == s)
+			return sp;
+	}
+	return NULL;
+}
+
+
+/*
+ * Check if there will be a lost label destination inside of a ?:
+ * It cannot be reached so just print it out.
+ */
+static void
+putjops(NODE *p, void *arg)
+{
+	if (p->n_op == COMOP && p->n_left->n_op == GOTO)
+		plabel(p->n_left->n_left->n_lval+1);
+}
+
+/*
+ * Build a name node based on a symtab entry.
+ * broken out from buildtree().
+ */
+NODE *
+nametree(struct symtab *sp)
+{
+	NODE *p;
+
+	p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->ssue);
+	p->n_qual = sp->squal;
+	p->n_sp = sp;
+
+#ifndef NO_C_BUILTINS
+	if (sp->sname[0] == '_' && strncmp(sp->sname, "__builtin_", 10) == 0)
+		return p;  /* do not touch builtins here */
+	
+#endif
+
+	if (sp->sflags & STNODE) {
+		/* Generated for optimizer */
+		p->n_op = TEMP;
+		p->n_rval = sp->soffset;
+	}
+
+#ifdef GCC_COMPAT
+	/* Get a label name */
+	if (sp->sflags == SLBLNAME) {
+		p->n_type = VOID;
+		p->n_sue = MKSUE(VOID);
+	}
+#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;
+		defid(p, SNULL);
+	}
+	if (sp->sclass == MOE) {
+		p->n_op = ICON;
+		p->n_lval = sp->soffset;
+		p->n_df = NULL;
+		p->n_sp = NULL;
+	}
+	return clocal(p);
+}
+
 /*
  * Do a conditional branch.
  */
@@ -548,8 +602,10 @@
 {
 	p = buildtree(CBRANCH, p, q);
 	if (p->n_left->n_op == ICON) {
-		if (p->n_left->n_lval != 0)
+		if (p->n_left->n_lval != 0) {
 			branch(q->n_lval); /* branch always */
+			reached = 0;
+		}
 		tfree(p);
 		tfree(q);
 		return;
@@ -714,6 +770,7 @@
  * 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.
+ * XXX - check for COMOPs in assignment RHS?
  */
 void
 chkpun(NODE *p)
@@ -743,8 +800,10 @@
 			return;
 		break;
 	default:
-		if ((t1 == VOID && t2 != VOID) || (t1 != VOID && t2 == VOID))
-			return uerror("value of void expression used");
+		if ((t1 == VOID && t2 != VOID) || (t1 != VOID && t2 == VOID)) {
+			uerror("value of void expression used");
+			return;
+		}
 		break;
 	}
 
@@ -754,26 +813,6 @@
 	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
@@ -786,7 +825,7 @@
 		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)
+			if (p->n_left->n_sue->sylnk != p->n_right->n_sue->sylnk)
 				werror("illegal structure pointer combination");
 			return;
 		}
@@ -815,7 +854,8 @@
 			t1 = DECREF(t1);
 			t2 = DECREF(t2);
 		}
-		werror("illegal pointer combination");
+		if (Wpointer_sign)
+			werror("illegal pointer combination");
 	}
 }
 
@@ -856,6 +896,21 @@
 	off = s->soffset;
 	dsc = s->sclass;
 
+#ifndef CAN_UNALIGN
+	/*
+	 * If its a packed struct, and the target cannot do unaligned
+	 * accesses, then split it up in two bitfield operations.
+	 * LHS and RHS accesses are different, so must delay
+	 * it until we know.  Do the bitfield construct here though.
+	 */
+	if ((dsc & FIELD) == 0 && (off % talign(s->stype, s->ssue))) {
+//		int sz = tsize(s->stype, s->sdf, s->ssue);
+//		int al = talign(s->stype, s->ssue);
+//		int sz1 = al - (off % al);
+		
+	}
+#endif
+
 	if (dsc & FIELD) {  /* make fields look like ints */
 		off = (off/ALINT)*ALINT;
 		sue = MKSUE(INT);
@@ -911,12 +966,18 @@
 NODE *
 bcon(int i)
 {
-	register NODE *p;
+	return xbcon(i, NULL, INT);
+}
 
-	p = block(ICON, NIL, NIL, INT, 0, MKSUE(INT));
-	p->n_lval = i;
-	p->n_sp = NULL;
-	return(clocal(p));
+NODE *
+xbcon(CONSZ val, struct symtab *sp, TWORD type)
+{
+	NODE *p;
+
+	p = block(ICON, NIL, NIL, type, 0, MKSUE(type));
+	p->n_lval = val;
+	p->n_sp = sp;
+	return clocal(p);
 }
 
 NODE *
@@ -995,34 +1056,6 @@
 	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; {
 
@@ -1049,7 +1082,12 @@
 	case LT:
 	case GE:
 	case GT:
-		if( ISUNSIGNED(p->n_left->n_type) || ISUNSIGNED(p->n_right->n_type) )  p->n_op += (ULE-LE);
+		if(ISUNSIGNED(p->n_left->n_type) ||
+		    ISUNSIGNED(p->n_right->n_type) ||
+		    ISPTR(p->n_left->n_type) ||
+		    ISPTR(p->n_right->n_type))
+			 p->n_op += (ULE-LE);
+		/* FALLTHROUGH */
 	case EQ:
 	case NE:
 		return( p );
@@ -1184,10 +1222,10 @@
 		t2 = DEUNSIGN(t2);
 		}
 
-	if (t1 == ENUMTY || t1 == MOETY)
-		t1 = INT; /* XXX */
-	if (t2 == ENUMTY || t2 == MOETY)
-		t2 = INT; /* XXX */
+	if (Wsign_compare && clogop(o) && t1 == t2 && lu != ru &&
+	    p->n_left->n_op != ICON && p->n_right->n_op != ICON)
+		werror("comparison between signed and unsigned");
+
 #if 0
 	if ((t1 == CHAR || t1 == SHORT) && o!= RETURN)
 		t1 = INT;
@@ -1266,8 +1304,6 @@
 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;
@@ -1294,10 +1330,7 @@
 	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_dcon = FLOAT_CAST(p->n_lval, p->n_type);
 			p->n_type = t;
 			p->n_qual = q;
 			p->n_sue = MKSUE(t);
@@ -1332,20 +1365,21 @@
 	return(p);
 	}
 
-int
-icons(p) register NODE *p; {
+/*
+ * Return the constant value from an ICON.
+ */
+CONSZ
+icons(NODE *p)
+{
 	/* if p is an integer constant, return its value */
-	int val;
+	CONSZ val;
 
-	if( p->n_op != ICON ){
+	if (p->n_op != ICON || p->n_sp != NULL) {
 		uerror( "constant expected");
 		val = 1;
-		}
-	else {
+	} else
 		val = p->n_lval;
-		if( val != p->n_lval ) uerror( "constant too big for cross-compiler" );
-		}
-	tfree( p );
+	tfree(p);
 	return(val);
 }
 
@@ -1382,7 +1416,6 @@
 # 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)
@@ -1428,8 +1461,6 @@
 
 	case MUL:
 	case DIV:
-		if ((mt1&MDBI) && (mt2&MENU)) return( TYMATCH );
-		if ((mt2&MDBI) && (mt1&MENU)) return( TYMATCH );
 		if( mt12 & MDBI ) return( TYMATCH );
 		break;
 
@@ -1452,13 +1483,12 @@
 	case GT:
 	case GE:
 		if( mt12 & MDBI ) return( TYMATCH+CVTO );
-		else if( mt12 & MPTR ) return( PTMATCH+PUN );
+		else if( mt12 & MPTR ) return( PTMATCH+PUN+CVTO );
 		else if( mt12 & MPTI ) return( PTMATCH+PUN );
 		else break;
 
 	case QUEST:
 	case COMOP:
-		if( mt2&MENU ) return( TYPR+NCVTR );
 		return( TYPR );
 
 	case STREF:
@@ -1480,12 +1510,6 @@
 		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;
@@ -1542,10 +1566,6 @@
 {
 	switch (ty) {
 
-	case ENUMTY:
-	case MOETY:
-		return( MENU|MINT|MDBI|MPTI );
-
 	case STRTY:
 	case UNIONTY:
 		return( MSTR );
@@ -1572,7 +1592,7 @@
 	}
 }
 
-int tvaloff = 100;
+int tvaloff = MAXREGS+NPERMREG > 100 ? MAXREGS+NPERMREG + 100 : 100;
 
 /*
  * Returns a TEMP node with temp number nr.
@@ -1584,7 +1604,7 @@
 	NODE *r;
 
 	r = block(TEMP, NIL, NIL, type, df, sue);
-	r->n_lval = nr ? nr : tvaloff;
+	regno(r) = nr ? nr : tvaloff;
 	tvaloff += szty(type);
 	return r;
 }
@@ -1599,6 +1619,9 @@
 	TWORD ty;
 	NODE *rv;
 
+	if (p->n_op == FLD)
+		uerror("can't apply sizeof to bit-field");
+
 	/*
 	 * Arrays may be dynamic, may need to make computations.
 	 */
@@ -1607,6 +1630,8 @@
 	df = p->n_df;
 	ty = p->n_type;
 	while (ISARY(ty)) {
+		if (df->ddim == NOOFFSET)
+			uerror("sizeof of incomplete type");
 		rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) :
 		    tempnode(-df->ddim, INT, 0, MKSUE(INT)));
 		df++;
@@ -1633,40 +1658,51 @@
 	ty = coptype( p->n_op );
 
 	printf("%p) %s, ", p, copst(p->n_op));
+	if (p->n_op == XARG || p->n_op == XASM)
+		printf("id '%s', ", p->n_name);
 	if (ty == LTYPE) {
 		printf(CONFMT, p->n_lval);
-		printf(", %d, ", p->n_rval);
+		printf(", %d, ", (p->n_op != NAME && p->n_op != ICON) ?
+		    p->n_rval : 0);
 	}
 	tprint(stdout, p->n_type, p->n_qual);
 	printf( ", %p, %p\n", p->n_df, p->n_sue );
 }
 # endif
 
-void
-prtdcon(NODE *p)
+/*
+ * Emit everything that should be emitted on the left side 
+ * of a comma operator, and remove the operator.
+ * Do not traverse through QUEST, ANDAND and OROR.
+ * Enable this for all targets when stable enough.
+ */
+static void
+comops(NODE *p)
 {
-	int o = p->n_op, i;
-
-	if (o != FCON)
-		return;
-
-	/* Write float constants to memory */
-	/* Should be volontary per architecture */
+	int o;
+	NODE *q;
 
-	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;
+	while (p->n_op == COMOP) {
+		/* XXX hack for GCC ({ }) ops */
+		if (p->n_left->n_op == GOTO) {
+			int v = p->n_left->n_left->n_lval;
+			ecomp(p->n_left);
+			plabel(v+1);
+		} else
+			ecomp(p->n_left); /* will recurse if more COMOPs */
+		q = p->n_right;
+		*p = *q;
+		nfree(q);
+	}
+	o = coptype(p->n_op);
+	if (p->n_op == QUEST || p->n_op == ANDAND || p->n_op == OROR)
+		o = UTYPE;
+	if (o != LTYPE)
+		comops(p->n_left);
+	if (o == BITYPE)
+		comops(p->n_right);
 }
 
-extern int negrel[];
-
 /*
  * Walk up through the tree from the leaves,
  * removing constant operators.
@@ -1815,6 +1851,7 @@
 	case ANDAND:
 		lab = false<0 ? getlab() : false ;
 		andorbr(p->n_left, -1, lab);
+		comops(p->n_right);
 		andorbr(p->n_right, true, false);
 		if (false < 0)
 			plabel( lab);
@@ -1824,6 +1861,7 @@
 	case OROR:
 		lab = true<0 ? getlab() : true;
 		andorbr(p->n_left, lab, -1);
+		comops(p->n_right);
 		andorbr(p->n_right, true, false);
 		if (true < 0)
 			plabel( lab);
@@ -1862,9 +1900,18 @@
 	NODE *q, *r;
 	int o, ty, lbl, lbl2, tval = 0;
 
-again:
 	o = p->n_op;
 	ty = coptype(o);
+	if (BTYPE(p->n_type) == ENUMTY) { /* fixup enum */
+		MODTYPE(p->n_type, p->n_sue->sylnk->stype);
+		/*
+		 * XXX may fail if these are true:
+		 * - variable-sized enums
+		 * - non-byte-addressed targets.
+		 */
+		if (BTYPE(p->n_type) == ENUMTY && ISPTR(p->n_type))
+			MODTYPE(p->n_type, INT); /* INT ok? */
+	}
 	switch (o) {
 	case QUEST:
 
@@ -1878,9 +1925,10 @@
 		/* Make ASSIGN node */
 		/* Only if type is not void */
 		q = p->n_right->n_left;
+		comops(q);
 		if (type != VOID) {
 			r = tempnode(0, q->n_type, q->n_df, q->n_sue);
-			tval = r->n_lval;
+			tval = regno(r);
 			q = buildtree(ASSIGN, r, q);
 		}
 		rmcops(q);
@@ -1889,6 +1937,7 @@
 		plabel( lbl);
 
 		q = p->n_right->n_right;
+		comops(q);
 		if (type != VOID) {
 			r = tempnode(tval, q->n_type, q->n_df, q->n_sue);
 			q = buildtree(ASSIGN, r, q);
@@ -1927,7 +1976,7 @@
 		*r = *p;
 		andorbr(r, -1, lbl = getlab());
 		q = tempnode(0, p->n_type, p->n_df, p->n_sue);
-		tval = q->n_lval;
+		tval = regno(q);
 		r = tempnode(tval, p->n_type, p->n_df, p->n_sue);
 		ecode(buildtree(ASSIGN, q, bcon(1)));
 		branch(lbl2 = getlab());
@@ -1945,13 +1994,7 @@
 		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;
+		cerror("COMOP error");
 
 	default:
 		if (ty == LTYPE)
@@ -1994,7 +2037,7 @@
 	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.
+		 * Pass2 will remove -1 if unnecessary.
 		 */
 		q = ccopy(p);
 		tfree(p->n_left);
@@ -2009,7 +2052,7 @@
 
 		if (has_se(l)) {
 			q = tempnode(0, ll->n_type, ll->n_df, ll->n_sue);
-			tval = q->n_lval;
+			tval = regno(q);
 			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. */
@@ -2052,19 +2095,21 @@
 		fwalk(p, eprint, 0);
 #endif
 	if (!reached) {
-		werror("statement not reached");
+		if (Wunreachable_code)
+			werror("statement not reached");
 		reached = 1;
 	}
 	p = optim(p);
+	comops(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)
@@ -2072,9 +2117,7 @@
 	struct symtab *q;
 	int ty;
 
-# ifdef MYP2TREE
-	MYP2TREE(p);  /* local action can be taken here; then return... */
-# endif
+	myp2tree(p);  /* local action can be taken here */
 
 	ty = coptype(p->n_op);
 
@@ -2101,11 +2144,10 @@
 	case ICON:
 		/* print external name */
 		if ((q = p->n_sp) != NULL) {
-			if ((q->sclass == STATIC && q->slevel > 0) ||
-			    q->sclass == ILABEL) {
+			if ((q->sclass == STATIC && q->slevel > 0)) {
 				printf(LABFMT, q->soffset);
 			} else
-				printf("%s\n", exname(q->sname));
+				printf("%s\n", exname(q->soname));
 		} else
 			printf("\n");
 		break;
@@ -2125,6 +2167,10 @@
 		printf("\t%d\t\n", talign(STRTY, p->n_left->n_sue));
 		break;
 
+	case XARG:
+	case XASM:
+		break;
+
 	default:
 		printf(	 "\n" );
 	}
@@ -2135,15 +2181,24 @@
 		p2tree(p->n_right);
 }
 #else
+static char *
+sptostr(struct symtab *sp)
+{
+	char *cp = inlalloc(32);
+	int n = sp->soffset;
+	if (n < 0)
+		n = -n;
+	snprintf(cp, 32, LABFMT, n);
+	return cp;
+}
+
 void
 p2tree(NODE *p)
 {
 	struct symtab *q;
 	int ty;
 
-# ifdef MYP2TREE
-	MYP2TREE(p);  /* local action can be taken here; then return... */
-# endif
+	myp2tree(p);  /* local action can be taken here */
 
 	ty = coptype(p->n_op);
 
@@ -2154,23 +2209,19 @@
 		if ((q = p->n_sp) != NULL) {
 			if ((q->sclass == STATIC && q->slevel > 0) ||
 #ifdef GCC_COMPAT
-			    q->sflags == SLBLNAME ||
+			    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 = sptostr(q);
+			} else if (!kflag) {
+				char *name = exname(q->soname);
+				int n = strlen(name) + 1;
+				char *cp = inlalloc(n);
+
+				strlcpy(cp, name, 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 = q->soname;
 		} else
 			p->n_name = "";
 		break;
@@ -2198,6 +2249,10 @@
 		p->n_stalign = talign(STRTY,p->n_left->n_sue)/SZCHAR;
 		break;
 
+	case XARG:
+	case XASM:
+		break;
+
 	default:
 		p->n_name = "";
 		}
@@ -2212,7 +2267,7 @@
  * Change void data types into char.
  */
 static void
-delvoid(NODE *p)
+delvoid(NODE *p, void *arg)
 {
 	/* Convert "PTR undef" (void *) to "PTR uchar" */
 	if (BTYPE(p->n_type) == VOID)
@@ -2227,7 +2282,7 @@
 			*q = *p;
 			q->n_type = BOOL_TYPE;
 			r = tempnode(0, BOOL_TYPE, NULL, MKSUE(BOOL_TYPE));
-			val = r->n_lval;
+			val = regno(r);
 			s = tempnode(val, BOOL_TYPE, NULL, MKSUE(BOOL_TYPE));
 			*p = *s;
 			q = buildtree(ASSIGN, r, q);
@@ -2250,8 +2305,7 @@
 
 	p = optim(p);
 	p = delasgop(p);
-	walkf(p, prtdcon);
-	walkf(p, delvoid);
+	walkf(p, delvoid, 0);
 #ifdef PCC_DEBUG
 	if (xdebug) {
 		printf("Fulltree:\n"); 
@@ -2282,26 +2336,28 @@
 	else
 		sz = sizeof(struct interpass);
 
-	ip = isinlining ? permalloc(sz) : tmpalloc(sz);
+	ip = inlalloc(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:
+		if (!isinlining)
+			defloc(cftnsp);
+		/* FALLTHROUGH */
 	case IP_PROLOG:
-		setloc1(PROG);
+		inftn = type == IP_PROLOG ? 1 : 0;
 		ipp = (struct interpass_prolog *)ip;
-		ipp->ipp_regs = va_arg(ap, int);
+		memset(ipp->ipp_regs, (type == IP_PROLOG)? -1 : 0,
+		    sizeof(ipp->ipp_regs));
 		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_tmpnum = va_arg(ap, int);
 		ipp->ip_lblnum = crslab;
 		if (type == IP_PROLOG)
 			ipp->ip_lblnum--;
@@ -2311,9 +2367,11 @@
 		break;
 	case IP_ASM:
 		if (blevel == 0) { /* outside function */
-			printf("\t%s\n", va_arg(ap, char *));
+			printf("\t");
+			printf("%s", va_arg(ap, char *));
+			printf("\n");
 			va_end(ap);
-			lastloc = -1;
+			defloc(NULL);
 			return;
 		}
 		ip->ip_asm = va_arg(ap, char *);
@@ -2322,12 +2380,11 @@
 		cerror("bad send_passt type %d", type);
 	}
 	va_end(ap);
+	pass1_lastchance(ip); /* target-specific info */
 	if (isinlining)
 		inline_addarg(ip);
 	else
 		pass2_compile(ip);
-	if (type == IP_EPILOG)
-		lastloc = PROG;
 }
 
 char *
@@ -2363,6 +2420,8 @@
 	SNAM(RSEQ,>>=)
 	SNAM(INCR,++)
 	SNAM(DECR,--)
+	SNAM(STRING,STRING)
+	SNAM(SZOF,SIZEOF)
 	default:
 		cerror("bad copst %d", op);
 	}
@@ -2375,6 +2434,7 @@
 	if (op <= MAXOP)
 		return dope[op];
 	switch (op) {
+	case STRING:
 	case QUALIFIER:
 	case CLASS:
 	case RB:
@@ -2415,6 +2475,7 @@
 	case DECR:
 		return BITYPE|ASGFLG;
 	}
+	cerror("cdope missing op %d", op);
 	return 0; /* XXX gcc */
 }
 
@@ -2445,7 +2506,45 @@
 void
 plabel(int label)
 {
-	setloc1(PROG);
 	reached = 1; /* Will this always be correct? */
 	send_passt(IP_DEFLAB, label);
 }
+
+/*
+ * Perform integer promotion on node n.
+ */
+NODE *
+intprom(NODE *n)
+{
+	if ((n->n_type >= CHAR && n->n_type < INT) || n->n_type == BOOL) {
+		if ((n->n_type == UCHAR && MAX_UCHAR > MAX_INT) ||
+		    (n->n_type == USHORT && MAX_USHORT > MAX_INT))
+			return makety(n, UNSIGNED, 0, 0, MKSUE(UNSIGNED));
+		return makety(n, INT, 0, 0, MKSUE(INT));
+	}
+	return n;
+}
+
+/*
+ * Return CON/VOL/0, whichever are active for the current type.
+ */
+int
+cqual(TWORD t, TWORD q)
+{
+	while (ISARY(t))
+		t = DECREF(t), q = DECQAL(q);
+	if (t <= BTMASK)
+		q <<= TSHIFT;
+	return q & (CON|VOL);
+}
+
+int crslab = 10;
+/*
+ * Return a number for internal labels.
+ */
+int
+getlab(void)
+{
+	return crslab++;
+}
+
Index: stabs.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/stabs.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/ccom/stabs.c -L usr.bin/pcc/ccom/stabs.c -u -r1.1 -r1.2
--- usr.bin/pcc/ccom/stabs.c
+++ usr.bin/pcc/ccom/stabs.c
@@ -1,4 +1,4 @@
-/*	$Id: stabs.c,v 1.15 2007/09/15 07:37:44 ragge Exp $	*/
+/*	$Id: stabs.c,v 1.27 2008/12/08 21:39:50 gmcgarry Exp $	*/
 
 /*
  * Copyright (c) 2004 Anders Magnusson (ragge at ludd.luth.se).
@@ -39,18 +39,31 @@
 #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" */
+#undef BIT2BYTE /* from external.h */
 #define	BIT2BYTE(x)	((x)/SZCHAR)
 
 #ifndef STABLBL
 #error macdefs.h must define STABLBL
 #endif
 
+/* defines taken from BSD <stab.h> */
+#define N_GSYM          0x20    /* global symbol */
+#define N_FUN           0x24    /* procedure name */
+#define N_LCSYM         0x28    /* bss segment variable */
+#define N_RSYM          0x40    /* register variable */
+#define N_SLINE         0x44    /* text segment line number */
+#define N_SO            0x64    /* main source file name */
+#define N_LSYM          0x80    /* stack variable */
+#define N_SOL           0x84    /* included source file name */
+#define N_PSYM          0xa0    /* parameter variable */
+#define N_LBRAC         0xc0    /* left bracket */
+#define N_RBRAC         0xe0    /* right bracket */
+
 /*
  * Local type mapping
  * Types are defined as a typeword, a dimension pointer (in the case
@@ -67,6 +80,7 @@
 static int ntypes;
 static char *curfun;
 static int stablbl = 10;
+extern int inftn;
 
 void ptype(char *name, int num, int inhnum, long long min, long long max);
 struct stabtype *addtype(TWORD, union dimfun *, struct suedef *);
@@ -77,7 +91,6 @@
 #define	MAXPSTR	100
 
 extern int isinlining;
-#define savestabs isinlining
 
 /*
  * Output type definitions for the stab debugging format.
@@ -109,7 +122,7 @@
 	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",
+	cprint(0, "\t.stabs \"void:t%d=r%d\",%d,0,0,0\n",
 	    st->num, st->num, N_LSYM);
 
 }
@@ -120,7 +133,7 @@
 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",
+	cprint(0, "\t.stabs \"%s:t%d=r%d;%lld;%lld;\",%d,0,0,0\n",
 	    name, num, inhnum, min, max, N_LSYM);
 }
 
@@ -183,8 +196,16 @@
 void
 stabs_line(int line)
 {
-	cprint(savestabs, ".stabn %d,0,%d," STABLBL "-%s", N_SLINE, line, stablbl, curfun);
-	cprint(1, STABLBL ":", stablbl++);
+	if (inftn == 0)
+		return; /* ignore */
+#ifdef STAB_LINE_ABSOLUTE
+	cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
+	    N_SLINE, line, stablbl, stablbl);
+#else
+	cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
+	    N_SLINE, line, stablbl, exname(curfun), stablbl);
+#endif
+	stablbl++;
 }
 
 /*
@@ -193,9 +214,14 @@
 void
 stabs_lbrac(int blklvl)
 {
-	cprint(savestabs, ".stabn %d,0,%d," STABLBL "-%s",
-	    N_LBRAC, blklvl, stablbl, curfun);
-	cprint(1, STABLBL ":", stablbl++);
+#ifdef STAB_LINE_ABSOLUTE
+	cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
+	    N_LBRAC, blklvl, stablbl, stablbl);
+#else
+	cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
+	    N_LBRAC, blklvl, stablbl, exname(curfun), stablbl);
+#endif
+	stablbl++;
 }
 
 /*
@@ -204,24 +230,40 @@
 void
 stabs_rbrac(int blklvl)
 {
-	cprint(savestabs, ".stabn %d,0,%d," STABLBL "-%s\n",
-	    N_RBRAC, blklvl, stablbl, curfun);
-	cprint(1, STABLBL ":", stablbl++);
+#ifdef STAB_LINE_ABSOLUTE
+	cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
+	    N_RBRAC, blklvl, stablbl, stablbl);
+#else
+	cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
+	    N_RBRAC, blklvl, stablbl, exname(curfun), stablbl);
+#endif
+	stablbl++;
 }
 
+static char *mainfile;
+
 /*
  * 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++);
+	cprint(inftn, "\t.stabs	\"%s\",%d,0,0," STABLBL "\n" STABLBL ":\n",
+	    fname, fname == mainfile ? N_SO : N_SOL, stablbl, stablbl);
+	stablbl++;
+}
+
+/*
+ * Print end mark
+ */
+void
+stabs_efile(char *fname)
+{
+	cprint(inftn, "\t.stabs	\"\",%d,0,0," STABLBL "\n" STABLBL ":\n",
+	    fname == mainfile ? N_SO : N_SOL, stablbl, stablbl);
+	stablbl++;
 }
 
 /*
@@ -232,12 +274,9 @@
 {
 	char str[MAXPSTR];
 
-	curfun = s->sname;
-#ifdef GCC_COMPAT
-	curfun = gcc_findname(cftnsp);
-#endif
+	curfun = s->soname;
 	printtype(s, str, sizeof(str));
-	cprint(savestabs, ".stabs	\"%s:%c%s\",%d,0,%d,%s",
+	cprint(1, "\t.stabs	\"%s:%c%s\",%d,0,%d,%s\n",
 	    curfun, s->sclass == STATIC ? 'f' : 'F', str,
 	    N_FUN, BIT2BYTE(s->ssue->suesize), exname(curfun));
 }
@@ -286,8 +325,10 @@
 void
 stabs_newsym(struct symtab *s)
 {
+	extern int fun_inline;
 	char *sname;
 	char ostr[MAXPSTR];
+	int suesize;
 
 	if (ISFTN(s->stype))
 		return; /* functions are handled separate */
@@ -297,43 +338,48 @@
 	    s->sclass == TYPEDEF || (s->sclass & FIELD))
 		return; /* XXX - fix structs */
 
-	sname = s->sname;
-#ifdef GCC_COMPAT
-	sname = gcc_findname(s);
-#endif
+	sname = s->soname;
+	suesize = BIT2BYTE(s->ssue->suesize);
+	if (suesize > 32767)
+		suesize = 32767;
+	else if (suesize < -32768)
+		suesize = -32768;
 
 	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));
+		cprint(0, "\t.stabs \"%s:p%s\",%d,0,%d,%d\n", sname, ostr,
+		    N_PSYM, 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));
+		cprint(0, "\t.stabs \"%s:%s\",%d,0,%d,%d\n", sname, ostr,
+		    N_LSYM, 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);
+			cprint(0, "\t.stabs \"%s:V%s\",%d,0,%d," LABFMT "\n", sname, ostr,
+			    N_LCSYM, suesize, s->soffset);
 		else
-			cprint(savestabs, ".stabs \"%s:S%s\",%d,0,%d,%s", sname, ostr,
-			    N_LCSYM, BIT2BYTE(s->ssue->suesize), exname(sname));
+			cprint(0, "\t.stabs \"%s:S%s\",%d,0,%d,%s\n", sname, ostr,
+			    N_LCSYM, 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));
+		cprint(0, "\t.stabs \"%s:G%s\",%d,0,%d,0\n", sname, ostr,
+		    N_GSYM, suesize);
 		break;
 
 	case REGISTER:
-		cprint(savestabs, ".stabs \"%s:r%s\",%d,0,%d,%d", sname, ostr,
+		cprint(0, "\t.stabs \"%s:r%s\",%d,0,%d,%d\n", sname, ostr,
 		    N_RSYM, 1, s->soffset);
 		break;
-
+	case SNULL:
+		if (fun_inline)
+			break;
+		/* FALLTHROUGH */
 	default:
 		cerror("fix stab_newsym; class %d", s->sclass);
 	}
@@ -352,22 +398,54 @@
 {
 }
 
-void    
+struct stabsv {
+	SLIST_ENTRY(stabsv) next;
+	char *str;
+} ;
+static SLIST_HEAD(, stabsv) stpole = { NULL, &stpole.q_forw };
+
+/*
+ * Global variable debug info is printed out directly.
+ * For functions and their declarations, both the labels and 
+ * the debug info is put into ASM nodes and follows their statements
+ * into pass2.  
+ * Due to the possible unsync between pass1 and 2 and where the 
+ * stabs info for text is sent over the following syncing is used:
+ * curfun == 0
+ *	print out everything; only data will be.
+ * curfun != 0 && inftn == 0
+ *	save in linked list
+ * curfun != 0 && inftn != 0
+ *	print linked list first, empty it, then arg.
+ */
+void
 cprint(int p2, char *fmt, ...)
 {
-	va_list ap;  
+	struct stabsv *w;
+	va_list ap;
 	char *str;
 
+	if (isinlining)
+		return; /* XXX do not save any inline functions currently */
+
 	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');
+		if (inftn == 0) {
+			w = tmpalloc(sizeof(struct stabsv));
+			w->str = str;
+			SLIST_INSERT_LAST(&stpole, w, next);
+		} else {
+			if (stpole.q_last != &stpole.q_forw) {
+				SLIST_FOREACH(w, &stpole, next) {
+					send_passt(IP_ASM, w->str);
+				}
+				SLIST_INIT(&stpole);
+			}
+			send_passt(IP_ASM, str);
+		}
+	} else
 		vprintf(fmt, ap);
-		putchar('\n');
-	}
 	va_end(ap);
 }
 
Index: symtabs.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/symtabs.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/ccom/symtabs.c -L usr.bin/pcc/ccom/symtabs.c -u -r1.1 -r1.2
--- usr.bin/pcc/ccom/symtabs.c
+++ usr.bin/pcc/ccom/symtabs.c
@@ -1,4 +1,4 @@
-/*	$Id: symtabs.c,v 1.14 2006/06/16 09:30:32 ragge Exp $	*/
+/*	$Id: symtabs.c,v 1.18 2008/06/19 08:05:00 gmcgarry Exp $	*/
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -175,15 +175,15 @@
  * Returns a struct symtab.
  */
 struct symtab *
-lookup(char *key, int ttype)
+lookup(char *key, int stype)
 {
 	struct symtab *sym;
 	struct tree *w, *new, *last;
-	int cix, bit, fbit, svbit, ix, bitno, match;
+	int cix, bit, fbit, svbit, bitno;
 	int type, uselvl;
+	intptr_t ix, match, code = (intptr_t)key;
 
-	long code = (long)key;
-	type = ttype & SMASK;
+	type = stype & SMASK;
 	uselvl = (blevel > 0 && type != SSTRING);
 
 	/*
@@ -197,15 +197,15 @@
 
 	switch (numsyms[type]) {
 	case 0:
-		if (ttype & SNOCREAT)
+		if (stype & SNOCREAT)
 			return NULL;
 		if (uselvl) {
-			sym = getsymtab(key, ttype|STEMP);
+			sym = getsymtab(key, stype|STEMP);
 			sym->snext = tmpsyms[type];
 			tmpsyms[type] = sym;
 			return sym;
 		}
-		sympole[type] = (struct tree *)getsymtab(key, ttype);
+		sympole[type] = (struct tree *)getsymtab(key, stype);
 		numsyms[type]++;
 		return (struct symtab *)sympole[type];
 
@@ -228,12 +228,12 @@
 	}
 
 	sym = (struct symtab *)w;
-	match = (long)sym->sname;
+	match = (intptr_t)sym->sname;
 
 	ix = code ^ match;
 	if (ix == 0)
 		return sym;
-	else if (ttype & SNOCREAT)
+	else if (stype & SNOCREAT)
 		return NULL;
 
 #ifdef PCC_DEBUG
@@ -246,7 +246,7 @@
 	 * Insert into the linked list, if feasible.
 	 */
 	if (uselvl) {
-		sym = getsymtab(key, ttype|STEMP);
+		sym = getsymtab(key, stype|STEMP);
 		sym->snext = tmpsyms[type];
 		tmpsyms[type] = sym;
 		return sym;
@@ -258,17 +258,17 @@
 	 * 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;
+	if (stype == (STEMP|SNORMAL))
+		stype = SNORMAL;
 
 	for (cix = 0; (ix & 1) == 0; ix >>= 1, cix++)
 		;
 
-	new = ttype & STEMP ? tmpalloc(sizeof(struct tree)) :
+	new = stype & 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);
+	new->lr[bit] = (struct tree *)getsymtab(key, stype);
 	if (numsyms[type]++ == 1) {
 		new->lr[!bit] = sympole[type];
 		new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
@@ -343,10 +343,15 @@
 hide(struct symtab *sym)
 {
 	struct symtab *new;
+	int typ = sym->sflags & SMASK;
+
+	new = getsymtab(sym->sname, typ|STEMP);
+	new->snext = tmpsyms[typ];
+	tmpsyms[typ] = new;
+
+	if (Wshadow)
+		werror("declaration of '%s' shadows previous", sym->sname);
 
-	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",
Index: optim.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/optim.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/ccom/optim.c -L usr.bin/pcc/ccom/optim.c -u -r1.1 -r1.2
--- usr.bin/pcc/ccom/optim.c
+++ usr.bin/pcc/ccom/optim.c
@@ -1,4 +1,4 @@
-/*	$Id: optim.c,v 1.28 2006/07/11 07:54:29 ragge Exp $	*/
+/*	$Id: optim.c,v 1.32 2008/10/27 21:13:20 ragge Exp $	*/
 /*
  * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
  *
@@ -43,8 +43,6 @@
 # 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 */
@@ -92,7 +90,7 @@
 	int i;
 	TWORD t;
 
-	if( (t=BTYPE(p->n_type))==ENUMTY || t==MOETY ) econvert(p);
+	t = BTYPE(p->n_type);
 	if( oflag ) return(p);
 
 	ty = coptype(p->n_op);
@@ -137,7 +135,8 @@
 		goto setuleft;
 
 	case RS:
-		if (LO(p) == RS && RCON(p->n_left) && RCON(p)) {
+		if (LO(p) == RS && RCON(p->n_left) && RCON(p) &&
+		    (RV(p) + RV(p->n_left)) < p->n_sue->suesize) {
 			/* two right-shift  by constants */
 			RV(p) += RV(p->n_left);
 			p->n_left = zapleft(p->n_left);
@@ -334,7 +333,21 @@
 		p->n_op = revrel[p->n_op - EQ ];
 		break;
 
+#ifdef notyet
+	case ASSIGN:
+		/* Simple test to avoid two branches */
+		if (RO(p) != NE)
+			break;
+		q = p->n_right;
+		if (RCON(q) && RV(q) == 0 && LO(q) == AND &&
+		    RCON(q->n_left) && (i = ispow2(RV(q->n_left))) &&
+		    q->n_left->n_type == INT) {
+			q->n_op = RS;
+			RV(q) = i;
 		}
+		break;
+#endif
+	}
 
 	return(p);
 	}
Index: Makefile
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccom/Makefile,v
retrieving revision 1.2
retrieving revision 1.3
diff -L usr.bin/pcc/ccom/Makefile -L usr.bin/pcc/ccom/Makefile -u -r1.2 -r1.3
--- usr.bin/pcc/ccom/Makefile
+++ usr.bin/pcc/ccom/Makefile
@@ -14,8 +14,8 @@
 CFLAGS+=        -Dmach_${TARGMACH}
 CFLAGS+=	-DPCC_DEBUG -DGCC_COMPAT
 CFLAGS+=	-Wall -Wmissing-prototypes -Wstrict-prototypes -Werror
-CFLAGS+=	-I. -I${.CURDIR}/.. -I${.CURDIR} -I${.CURDIR}/../mip
-CFLAGS+=	-I${.CURDIR}/../${TARGMACH}
+CFLAGS+=	-I. -I${.CURDIR}/.. -I${.CURDIR} 
+CFLAGS+=	-I${.CURDIR}/../${TARGMACH} -I${.CURDIR}/../mip
 
 .PATH:	${.CURDIR}/../${TARGMACH}
 .PATH:	${.CURDIR}/../mip
Index: scanner.l
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/cpp/scanner.l,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/cpp/scanner.l -L usr.bin/pcc/cpp/scanner.l -u -r1.1 -r1.2
--- usr.bin/pcc/cpp/scanner.l
+++ usr.bin/pcc/cpp/scanner.l
@@ -1,5 +1,5 @@
 %{
-/*	$Id: scanner.l,v 1.20 2007/09/25 20:41:07 ragge Exp $	*/
+/*	$Id: scanner.l,v 1.48 2008/08/21 16:32:40 ragge Exp $   */
 
 /*
  * Copyright (c) 2004 Anders Magnusson. All rights reserved.
@@ -27,19 +27,25 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "config.h"
+
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #include <fcntl.h>
+#include <errno.h>
 
+#include "compat.h"
 #include "cpp.h"
 #include "y.tab.h"
 %}
 
 %{
-static long long cvtdig(int rad);
-static int charcon(void);
+static void cvtdig(int rad);
+static int charcon(usch *);
 static void elsestmt(void);
 static void ifdefstmt(void);
 static void ifndefstmt(void);
@@ -50,8 +56,8 @@
 static void undefstmt(void);
 static void cpperror(void);
 static void elifstmt(void);
-//static void linestmt(void);
 static void storepb(void);
+static void badop(const char *);
 void  include(void);
 void  define(void);
 
@@ -82,15 +88,17 @@
 }
 #undef YY_INPUT
 #undef YY_BUF_SIZE
-#define	YY_BUF_SIZE 32768
+#define	YY_BUF_SIZE (8*65536)
 #define YY_INPUT(b,r,m) (r = yyinput(b, m))
+#ifdef HAVE_CPP_VARARG_MACRO_GCC
 #define fprintf(x, ...) error(__VA_ARGS__)
+#endif
 #define	ECHO putstr((usch *)yytext)
 #undef fileno
 #define fileno(x) 0
 
 #if YY_FLEX_SUBMINOR_VERSION >= 31
-/* Hack to avoid unneccessary warnings */
+/* Hack to avoid unnecessary warnings */
 FILE *yyget_in	(void);
 FILE *yyget_out  (void);
 int yyget_leng	(void);
@@ -108,6 +116,9 @@
 #define unput(ch) unch(ch)
 #endif
 #define PRTOUT(x) if (YYSTATE || slow) return x; if (!flslvl) putstr((usch *)yytext);
+/* protection against recursion in #include */
+#define MAX_INCLEVEL	100
+static int inclevel;
 %}
 
 D	[0-9]
@@ -118,7 +129,7 @@
 IS	(u|U|l|L)*
 WS	[\t ]
 
-%s IFR CONTR DEF
+%s IFR CONTR DEF COMMENT
 
 %%
 
@@ -139,6 +150,8 @@
 
 "\r"			{ ; /* Ignore CR's */ }
 
+<IFR>"++"		{ badop("++"); }
+<IFR>"--"		{ badop("--"); }
 <IFR>"=="		{ return EQ; }
 <IFR>"!="		{ return NE; }
 <IFR>"<="		{ return LE; }
@@ -160,28 +173,41 @@
 
 <IFR>{WS}+		{ ; }
 <IFR>{L}({L}|{D})*	{
+				yylval.node.op = NUMBER;
 				if (gotdef) {
-					yylval.val =
-					    lookup((usch *)yytext, FIND) != 0;
+					yylval.node.nd_val
+					    = lookup((usch *)yytext, FIND) != 0;
 					gotdef = 0;
 					return IDENT;
 				}
-				yylval.val = 0;
+				yylval.node.nd_val = 0;
 				return NUMBER;
 			}
 
-[1-9][0-9]*		{ if (slow && !YYSTATE) return IDENT; scale = 10; goto num; }
+[0-9][0-9]*		{
+				if (slow && !YYSTATE)
+					return IDENT;
+				scale = yytext[0] == '0' ? 8 : 10;
+				goto num;
+			}
 
 0[xX]{H}+{IS}?		{	scale = 16;
-			num:	if (YYSTATE)
-					yylval.val = cvtdig(scale);
+			num:	if (YYSTATE == IFR) 
+					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);
+'(\\.|[^\\'])+'		{
+				if (YYSTATE || slow) {
+					yylval.node.op = NUMBER;
+					yylval.node.nd_val = charcon((usch *)yytext);
+					return (NUMBER);
+				}
+				if (tflag)
+					yyless(1);
+				if (!flslvl)
+					putstr((usch *)yytext);
 			}
 
 <IFR>.			{ return yytext[0]; }
@@ -190,7 +216,14 @@
 {D}*"."{D}+({E})?{FS}?	{ PRTOUT(FPOINT); }
 {D}+"."{D}*({E})?{FS}?	{ PRTOUT(FPOINT); }
 
-^{WS}*#{WS}*		{ contr = 1; BEGIN CONTR; }
+^{WS}*#{WS}*		{	extern int inmac;
+
+				if (inmac)
+					error("preprocessor directive found "
+					    "while expanding macro");
+				contr = 1;
+				BEGIN CONTR;
+			}
 {WS}+			{ PRTOUT(WSPACE); }
 
 <CONTR>"ifndef"		{ contr = 0; ifndefstmt(); }
@@ -203,19 +236,25 @@
 <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>"pragma"		{ contr = 0; pragmastmt(); BEGIN 0; }
 <CONTR>"elif"		{ contr = 0; storepb(); BEGIN IFR; elifstmt(); BEGIN 0; }
 
 
 
 "//".*$			{ /* if (tflag) yyless(..) */
-				if (Cflag)
+				if (Cflag && !flslvl && !slow)
 					putstr((usch *)yytext);
 				else if (!flslvl)
 					putch(' ');
 			}
 "/*"			{	int c, wrn;
-				if (Cflag)
+				int prtcm = Cflag && !flslvl && !slow;
+				extern int readmac;
+
+				if (Cflag && !flslvl && readmac)
+					return CMNT;
+
+				if (prtcm)
 					putstr((usch *)yytext);
 				wrn = 0;
 			more:	while ((c = input()) && c != '*') {
@@ -223,20 +262,18 @@
 						putch(c), ifiles->lineno++;
 					else if (c == 1) /* WARN */
 						wrn = 1;
-					else if (Cflag)
+					else if (prtcm)
 						putch(c);
 				}
 				if (c == 0)
 					return 0;
-				if (Cflag)
+				if (prtcm)
 					putch(c);
 				if ((c = input()) && c != '/') {
-					if (Cflag)
-						putch('*');
 					unput(c);
 					goto more;
 				}
-				if (Cflag)
+				if (prtcm)
 					putch(c);
 				if (c == 0)
 					return 0;
@@ -280,7 +317,31 @@
 				xx: ;
 			}
 
-.			{ PRTOUT(yytext[0]); }
+.			{
+				if (contr) {
+					while (input() != '\n')
+						;
+					unput('\n');
+					BEGIN 0;
+					contr = 0;
+					goto yy;
+				}
+				if (YYSTATE || slow)
+					return yytext[0];
+				if (yytext[0] == 6) { /* PRAGS */
+					usch *obp = stringbuf;
+					extern usch *prtprag(usch *);
+					*stringbuf++ = yytext[0];
+					do {
+						*stringbuf = input();
+					} while (*stringbuf++ != 14);
+					prtprag(obp);
+					stringbuf = obp;
+				} else {
+					PRTOUT(yytext[0]);
+				}
+				yy:;
+			}
 
 %%
 
@@ -393,25 +454,26 @@
 /*
  * 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.
+ * Return 0 on success, -1 if file to be included is not found.
  */
 int
 pushfile(usch *file)
 {
 	extern struct initar *initar;
 	struct includ ibuf;
-	struct includ *old;
 	struct includ *ic;
 	int c, otrulvl;
 
 	ic = &ibuf;
-	old = ifiles;
+	ic->next = ifiles;
 
 	slow = 0;
 	if (file != NULL) {
 		if ((ic->infil = open((char *)file, O_RDONLY)) < 0)
 			return -1;
 		ic->orgfn = ic->fname = file;
+		if (++inclevel > MAX_INCLEVEL)
+			error("Limit for nested includes exceeded");
 	} else {
 		ic->infil = 0;
 		ic->orgfn = ic->fname = (usch *)"<stdin>";
@@ -438,8 +500,9 @@
 	if (otrulvl != trulvl || flslvl)
 		error("unterminated conditional");
 
-	ifiles = old;
+	ifiles = ic->next;
 	close(ic->infil);
+	inclevel--;
 	return 0;
 }
 
@@ -458,7 +521,7 @@
 			s = sheap("%s: %s\n", Mfile, ifiles->fname);
 			write(ofd, s, strlen((char *)s));
 		}
-	} else
+	} else if (!Pflag)
 		putstr(sheap("# %d \"%s\"\n", ifiles->lineno, ifiles->fname));
 	stringbuf = os;
 }
@@ -468,7 +531,7 @@
 {
 #ifdef CPP_DEBUG
 	extern int dflag;
-	if (dflag)printf(": '%c'(%d)", c, c);
+	if (dflag)printf(": '%c'(%d)", c > 31 ? c : ' ', c);
 #endif
 	unput(c);
 }
@@ -488,13 +551,13 @@
 }
 
 /*
- * Convert some string numbers to long long.
- * Do not care about UL trailers, should we?
+ * Convert string numbers to unsigned long long and check overflow.
  */
-static long long
+static void
 cvtdig(int rad)
 {
-	long long rv = 0;
+	unsigned long long rv = 0;
+	unsigned long long rv2 = 0;
 	char *y = yytext;
 	int c;
 
@@ -503,20 +566,30 @@
 		y++;
 	while (isxdigit(c)) {
 		rv = rv * rad + dig2num(c);
+		/* check overflow */
+		if (rv / rad < rv2)
+			error("Constant \"%s\" is out of range", yytext);
+		rv2 = rv;
 		c = *y++;
 	}
-	return rv;
+	y--;
+	while (*y == 'l' || *y == 'L')
+		y++;
+	yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER;
+	yylval.node.nd_uval = rv;
+	if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0)
+		yylval.node.op = UNUMBER;
+	if (yylval.node.op == NUMBER && yylval.node.nd_val < 0)
+		/* too large for signed */
+		error("Constant \"%s\" is out of range", yytext);
 }
 
 static int
-charcon(void)
+charcon(usch *p)
 {
-	usch *p = (usch *)yytext;
 	int val, c;
 
-	if (*p == 'L')
-		p++;
-	p++; /* first ' */
+	p++; /* skip first ' */
 	val = 0;
 	if (*p++ == '\\') {
 		switch (*p++) {
@@ -553,14 +626,24 @@
 }
 
 static void
-chknl(void)
+chknl(int ignore)
 {
 	int t;
 
+	slow = 1;
 	while ((t = yylex()) == WSPACE)
 		;
-	if (t != '\n')
-		error("newline expected, got %d", t);
+	if (t != '\n') {
+		if (ignore) {
+			warning("newline expected, got \"%s\"", yytext);
+			/* ignore rest of line */
+			while ((t = yylex()) && t != '\n')
+				;
+		}
+		else
+			error("newline expected, got \"%s\"", yytext);
+	}
+	slow = 0;
 }
 
 static void
@@ -583,12 +666,14 @@
 	if (elslvl==trulvl+flslvl)
 		error("Too many else");
 	elslvl=trulvl+flslvl;
-	chknl();
+	chknl(1);
 }
 
 static void
 ifdefstmt(void)		 
 { 
+	int t;
+
 	if (flslvl) {
 		/* just ignore the rest of the line */
 		while (input() != '\n')
@@ -599,28 +684,36 @@
 		return;
 	}
 	slow = 1;
-	if (yylex() != WSPACE || yylex() != IDENT)
+	do
+		t = yylex();
+	while (t == WSPACE);
+	if (t != IDENT)
 		error("bad ifdef");
 	slow = 0;
 	if (flslvl == 0 && lookup((usch *)yytext, FIND) != 0)
 		trulvl++;
 	else
 		flslvl++;
-	chknl();
+	chknl(0);
 }
 
 static void
 ifndefstmt(void)	  
 { 
+	int t;
+
 	slow = 1;
-	if (yylex() != WSPACE || yylex() != IDENT)
+	do
+		t = yylex();
+	while (t == WSPACE);
+	if (t != IDENT)
 		error("bad ifndef");
 	slow = 0;
 	if (flslvl == 0 && lookup((usch *)yytext, FIND) == 0)
 		trulvl++;
 	else
 		flslvl++;
-	chknl();
+	chknl(0);
 }
 
 static void
@@ -637,7 +730,7 @@
 	if (flslvl == 0)
 		elflvl = 0;
 	elslvl = 0;
-	chknl();
+	chknl(1);
 }
 
 /*
@@ -694,8 +787,24 @@
 	usch *opb = stringbuf;
 	int c;
 
-	while ((c = input()) != '\n')
+	while ((c = input()) != '\n') {
+		if (c == '/') {
+			 if ((c = input()) == '*') {
+				/* ignore comments here whatsoever */
+				usch *g = stringbuf;
+				getcmnt();
+				stringbuf = g;
+				continue;
+			} else if (c == '/') {
+				while ((c = input()) && c != '\n')
+					;
+				break;
+			}
+			unput(c);
+			c = '/';
+		}
 		savch(c);
+	}
 	cunput('\n');
 	savch(0);
 	fixdefined(opb); /* XXX can fail if #line? */
@@ -779,7 +888,7 @@
 	if (flslvl)
 		stringbuf = cp;
 	else
-		error("error: %s", cp);
+		error("%s", cp);
 }
 
 static void
@@ -793,7 +902,7 @@
 	if (flslvl == 0 && (np = lookup((usch *)yytext, FIND)))
 		np->value = 0;
 	slow = 0;
-	chknl();
+	chknl(0);
 }
 
 static void
@@ -804,11 +913,26 @@
 	slow = 1;
 	if (yylex() != WSPACE)
 		error("bad pragma");
-	putstr((usch *)"#pragma ");
+	if (!flslvl)
+		putstr((usch *)"#pragma ");
 	do {
-		putch(c = input());	/* Do arg expansion instead? */
+		c = input();
+		if (!flslvl)
+			putch(c);	/* Do arg expansion instead? */
 	} while (c && c != '\n');
 	ifiles->lineno++;
 	prtline();
 	slow = 0;
 }
+
+static void
+badop(const char *op)
+{
+	error("invalid operator in preprocessor expression: %s", op);
+}
+
+int
+cinput()
+{
+	return input();
+}
Index: token.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/cpp/token.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/cpp/token.c -L usr.bin/pcc/cpp/token.c -u -r1.1 -r1.2
--- usr.bin/pcc/cpp/token.c
+++ usr.bin/pcc/cpp/token.c
@@ -1,4 +1,4 @@
-/*	$Id: token.c,v 1.11 2006/09/28 11:10:08 ragge Exp $	*/
+/*	$Id: token.c,v 1.12 2008/04/15 09:54:23 gmcgarry Exp $	*/
 
 /*
  * Copyright (c) 2004 Anders Magnusson. All rights reserved.
@@ -35,17 +35,7 @@
 #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;
+struct includ *ifiles;
 
 usch *yyp, *yystr, yybuf[CPPBUF];
 
Index: cpp.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/cpp/cpp.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -L usr.bin/pcc/cpp/cpp.c -L usr.bin/pcc/cpp/cpp.c -u -r1.3 -r1.4
--- usr.bin/pcc/cpp/cpp.c
+++ usr.bin/pcc/cpp/cpp.c
@@ -1,4 +1,4 @@
-/*	$Id: cpp.c,v 1.65 2007/09/25 20:41:08 ragge Exp $	*/
+/*	$Id: cpp.c,v 1.95 2008/12/07 20:12:05 gmcgarry Exp $	*/
 
 /*
  * Copyright (c) 2004 Anders Magnusson (ragge at ludd.luth.se).
@@ -66,24 +66,24 @@
  * from V7 cpp, and at last ansi/c99 support.
  */
 
-#include "../config.h"
+#include "config.h"
 
+#ifdef HAVE_SYS_WAIT_H
 #include <sys/wait.h>
+#endif
 
 #include <fcntl.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #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 "compat.h"
 #include "cpp.h"
 #include "y.tab.h"
 
@@ -103,12 +103,15 @@
 #define DDPRINT(x)
 #endif
 
+#define	GCC_VARI
+
 int ofd;
 usch outbuf[CPPBUF];
-int obufp, istty;
-int Cflag, Mflag, dMflag;
+int obufp, istty, inmac;
+int Cflag, Mflag, dMflag, Pflag;
 usch *Mfile;
 struct initar *initar;
+int readmac;
 
 /* avoid recursion */
 struct recur {
@@ -149,6 +152,7 @@
  *   1->   - number of args.
  */
 
+#define	GCCARG	0xfd	/* has gcc varargs that may be replaced with 0 */
 #define	VARG	0xfe	/* has varargs */
 #define	OBJCT	0xff
 #define	WARN	1	/* SOH, not legal char */
@@ -156,6 +160,8 @@
 #define	SNUFF	3	/* ETX, not legal char */
 #define	NOEXP	4	/* EOT, not legal char */
 #define	EXPAND	5	/* ENQ, not legal char */
+#define	PRAGS	6	/* start of converted pragma */
+#define	PRAGE	14	/* end of converted pragma */
 
 /* args for lookup() */
 #define	FIND	0
@@ -168,6 +174,9 @@
 void line(void);
 void flbuf(void);
 void usage(void);
+usch *xstrdup(char *str);
+usch *prtprag(usch *opb);
+
 
 int
 main(int argc, char **argv)
@@ -177,7 +186,13 @@
 	struct symtab *nl;
 	register int ch;
 
-	while ((ch = getopt(argc, argv, "CD:I:MS:U:d:i:tvV?")) != -1)
+#ifdef TIMING
+	struct timeval t1, t2;
+
+	(void)gettimeofday(&t1, NULL);
+#endif
+
+	while ((ch = getopt(argc, argv, "CD:I:MPS:U:d:i:tvV?")) != -1)
 		switch (ch) {
 		case 'C': /* Do not discard comments */
 			Cflag++;
@@ -199,6 +214,10 @@
 			Mflag++;
 			break;
 
+		case 'P': /* Inhibit generation of line numbers */
+			Pflag++;
+			break;
+
 		case 'S':
 		case 'I':
 			if ((w = calloc(sizeof(struct incs), 1)) == NULL)
@@ -219,7 +238,7 @@
 			break;
 #endif
 		case 'v':
-			printf("pcpp: %s\n", VERSSTR);
+			printf("cpp: %s\n", VERSSTR);
 			break;
 		case 'd':
 			if (optarg[0] == 'M') {
@@ -267,6 +286,10 @@
 		nl = lookup((usch *)"__STDC__", ENTER);
 		savch(0); savch('1'); savch(OBJCT);
 		nl->value = stringbuf-1;
+
+		nl = lookup((usch *)"__STDC_VERSION__", ENTER);
+		savch(0); savstr((usch *)"199901L"); savch(OBJCT);
+		nl->value = stringbuf-1;
 	}
 
 	if (Mflag && !dMflag) {
@@ -298,6 +321,17 @@
 
 	flbuf();
 	close(ofd);
+#ifdef TIMING
+	(void)gettimeofday(&t2, NULL);
+	t2.tv_sec -= t1.tv_sec;
+	t2.tv_usec -= t1.tv_usec;
+	if (t2.tv_usec < 0) {
+		t2.tv_usec += 1000000;
+		t2.tv_sec -= 1;
+	}
+	fprintf(stderr, "cpp total time: %ld s %ld us\n",
+	     t2.tv_sec, t2.tv_usec);
+#endif
 	return 0;
 }
 
@@ -315,6 +349,7 @@
 
 	thisnl = NULL;
 	slow = 1;
+	readmac++;
 	base = osp = stringbuf;
 	goto found;
 
@@ -377,6 +412,10 @@
 			thisnl = NULL;
 			break;
 
+		case CMNT:
+			getcmnt();
+			break;
+
 		case STRING:
 		case '\n':
 		case NUMBER:
@@ -394,11 +433,12 @@
 		}
 		if (thisnl == NULL) {
 			slow = 0;
+			readmac--;
 			savch(0);
 			return base;
 		}
 	}
-	error("preamture EOF");
+	error("premature EOF");
 	/* NOTREACHED */
 	return NULL; /* XXX gcc */
 }
@@ -423,7 +463,7 @@
 		slow = 0;
 		return;
 	}
-	if (yylex() != STRING)
+	if (yylex() != STRING || yytext[0] == 'L')
 		goto bad;
 	c = strlen((char *)yytext);
 	if (llen < c) {
@@ -550,6 +590,55 @@
 }
 
 void
+getcmnt(void)
+{
+	int c;
+
+	savstr((usch *)yytext);
+	for (;;) {
+		c = cinput();
+		if (c == '*') {
+			c = cinput();
+			if (c == '/') {
+				savstr((usch *)"*/");
+				return;
+			}
+			cunput(c);
+			c = '*';
+		}
+		savch(c);
+	}
+}
+
+/*
+ * Compare two replacement lists, taking in account comments etc.
+ */
+static int
+cmprepl(usch *o, usch *n)
+{
+	for (; *o; o--, n--) {
+		/* comment skip */
+		if (*o == '/' && o[-1] == '*') {
+			while (*o != '*' || o[-1] != '/')
+				o--;
+			o -= 2;
+		}
+		if (*n == '/' && n[-1] == '*') {
+			while (*n != '*' || n[-1] != '/')
+				n--;
+			n -= 2;
+		}
+		while (*o == ' ' || *o == '\t')
+			o--;
+		while (*n == ' ' || *n == '\t')
+			n--;
+		if (*o != *n)
+			return 1;
+	}
+	return 0;
+}
+
+void
 define()
 {
 	struct symtab *np;
@@ -557,7 +646,10 @@
 	int c, i, redef;
 	int mkstr = 0, narg = -1;
 	int ellips = 0;
-	int len;
+#ifdef GCC_VARI
+	usch *gccvari = NULL;
+	int wascon;
+#endif
 
 	if (flslvl)
 		return;
@@ -571,12 +663,13 @@
 	np = lookup((usch *)yytext, ENTER);
 	redef = np->value != NULL;
 
+	readmac = 1;
 	sbeg = stringbuf;
 	if ((c = yylex()) == '(') {
 		narg = 0;
 		/* function-like macros, deal with identifiers */
+		c = definp();
 		for (;;) {
-			c = definp();
 			if (c == ')')
 				break;
 			if (c == ELLIPS) {
@@ -586,15 +679,27 @@
 				break;
 			}
 			if (c == IDENT) {
-				len = strlen(yytext);
-				args[narg] = alloca(len+1);
-				strlcpy((char *)args[narg], yytext, len+1);
-				narg++;
-				if ((c = definp()) == ',')
+				/* make sure there is no arg of same name */
+				for (i = 0; i < narg; i++)
+					if (!strcmp((char *) args[i], yytext))
+						error("Duplicate macro "
+						  "parameter \"%s\"", yytext);
+				args[narg++] = xstrdup(yytext);
+				if ((c = definp()) == ',') {
+					if ((c = definp()) == ')')
+						goto bad;
 					continue;
+				}
+#ifdef GCC_VARI
+				if (c == ELLIPS) {
+					if (definp() != ')')
+						goto bad;
+					gccvari = args[--narg];
+					break;
+				}
+#endif
 				if (c == ')')
 					break;
-				goto bad;
 			}
 			goto bad;
 		}
@@ -608,9 +713,17 @@
 	while (c == WSPACE)
 		c = yylex();
 
+	/* replacement list cannot start with ## operator */
+	if (c == CONCAT)
+		goto bad;
+
 	/* parse replacement-list, substituting arguments */
 	savch('\0');
 	while (c != '\n') {
+#ifdef GCC_VARI
+		wascon = 0;
+loop:
+#endif
 		switch (c) {
 		case WSPACE:
 			/* remove spaces if it surrounds a ## directive */
@@ -622,6 +735,12 @@
 				savch(CONC);
 				if ((c = yylex()) == WSPACE)
 					c = yylex();
+#ifdef GCC_VARI
+				if (c == '\n')
+					break;
+				wascon = 1;
+				goto loop;
+#endif
 			}
 			continue;
 
@@ -630,7 +749,14 @@
 			savch(CONC);
 			if ((c = yylex()) == WSPACE)
 				c = yylex();
+#ifdef GCC_VARI
+			if (c == '\n')
+				break;
+			wascon = 1;
+			goto loop;
+#else
 			continue;
+#endif
 
 		case MKSTR:
 			if (narg < 0) {
@@ -655,6 +781,16 @@
 				if (strcmp(yytext, (char *)args[i]) == 0)
 					break;
 			if (i == narg) {
+#ifdef GCC_VARI
+				if (gccvari &&
+				    strcmp(yytext, (char *)gccvari) == 0) {
+					savch(wascon ? GCCARG : VARG);
+					savch(WARN);
+					if (mkstr)
+						savch(SNUFF), mkstr = 0;
+					break;
+				}
+#endif
 				if (mkstr)
 					error("not argument");
 				goto id;
@@ -674,31 +810,40 @@
 				savch(SNUFF), mkstr = 0;
 			break;
 
+		case CMNT: /* save comments */
+			getcmnt();
+			break;
+
 		default:
 id:			savstr((usch *)yytext);
 			break;
 		}
 		c = yylex();
 	}
+	readmac = 0;
 	/* remove trailing whitespace */
 	while (stringbuf > sbeg) {
 		if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')
 			stringbuf--;
+		/* replacement list cannot end with ## operator */
+		else if (stringbuf[-1] == CONC)
+			goto bad;
 		else
 			break;
 	}
+#ifdef GCC_VARI
+	if (gccvari) {
+		savch(narg);
+		savch(VARG);
+	} else
+#endif
 	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)
+		if (cmprepl(np->value, stringbuf-1))
 			error("%s redefined\nprevious define: %s:%d",
 			    np->namep, np->file, np->line);
 		stringbuf = sbeg;  /* forget this space */
@@ -726,12 +871,31 @@
 	}
 #endif
 	slow = 0;
+	for (i = 0; i < narg; i++)
+		free(args[i]);
 	return;
 
 bad:	error("bad define");
 }
 
 void
+xwarning(usch *s)
+{
+	usch *t;
+	usch *sb = stringbuf;
+
+	flbuf();
+	savch(0);
+	if (ifiles != NULL) {
+		t = sheap("%s:%d: warning: ", ifiles->fname, ifiles->lineno);
+		write (2, t, strlen((char *)t));
+	}
+	write (2, s, strlen((char *)s));
+	write (2, "\n", 1);
+	stringbuf = sb;
+}
+
+void
 xerror(usch *s)
 {
 	usch *t;
@@ -739,7 +903,7 @@
 	flbuf();
 	savch(0);
 	if (ifiles != NULL) {
-		t = sheap("%s:%d: ", ifiles->fname, ifiles->lineno);
+		t = sheap("%s:%d: error: ", ifiles->fname, ifiles->lineno);
 		write (2, t, strlen((char *)t));
 	}
 	write (2, s, strlen((char *)s));
@@ -751,7 +915,7 @@
  * store a character into the "define" buffer.
  */
 void
-savch(c)
+savch(int c)
 {
 	if (stringbuf-sbf < SBSIZE) {
 		*stringbuf++ = c;
@@ -768,10 +932,9 @@
 pragoper(void)
 {
 	usch *opb;
-	int t;
+	int t, plev;
 
-	slow = 1;
-	putstr((usch *)"\n#pragma ");
+	slow++;
 	if ((t = yylex()) == WSPACE)
 		t = yylex();
 	if (t != '(')
@@ -779,29 +942,37 @@
 	if ((t = yylex()) == WSPACE)
 		t = yylex();
 	opb = stringbuf;
-	while (t != ')') {
+	for (plev = 0; ; t = yylex()) {
+		if (t == '(')
+			plev++;
+		if (t == ')')
+			plev--;
+		if (plev < 0)
+			break;
 		savstr((usch *)yytext);
-		t = yylex();
 	}
+
 	savch(0);
 	cunput(WARN);
 	unpstr(opb);
 	stringbuf = opb;
 	expmac(NULL);
+	cunput('\n');
 	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);
+	savch(PRAGS);
+	while ((t = yylex()) != '\n') {
+		if (t == WSPACE)
+			continue;
+		if (t != STRING)
+			goto bad;
+		savstr((usch *)yytext);
 	}
-	putch('\n');
-	prtline();
+
+	savch(PRAGE);
+	while (stringbuf > opb)
+		cunput(*--stringbuf);
+	slow--;
 	return;
 bad:	error("bad pragma operator");
 }
@@ -815,8 +986,8 @@
 struct recur *rp;
 {
 	struct recur rp2;
-	register usch *vp, *cp;
-	int c, rv = 0, ws;
+	register usch *vp, *cp, *obp;
+	int c, nl;
 
 	DPRINT(("subst: %s\n", sp->namep));
 	/*
@@ -842,40 +1013,36 @@
 
 		/* should we be here at all? */
 		/* check if identifier is followed by parentheses */
-		rv = 1;
-		ws = 0;
+
+		obp = stringbuf;
+		nl = 0;
 		do {
-			c = yylex();
+			c = cinput();
+			*stringbuf++ = c;
 			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);
+					break;
+			}
+			if (c == '\n')
+				nl++;
+		} while (c == ' ' || c == '\t' || c == '\n' || 
+			    c == '\r' || c == WARN);
+
 		DPRINT(("c %d\n", c));
 		if (c == '(' ) {
+			cunput(c);
+			stringbuf = obp;
+			ifiles->lineno += nl;
 			expdef(vp, &rp2, gotwarn);
-			return rv;
+			return 1;
 		} else {
-			/* restore identifier */
-noid:			while (gotwarn--)
-				cunput(WARN);
-			if (ws)
-				cunput(' ');
-			cp = sp->namep;
-			while (*cp)
-				cp++;
-			while (cp > sp->namep)
-				cunput(*--cp);
+	 		*stringbuf = 0;
+			unpstr(obp);
+			unpstr(sp->namep);
 			if ((c = yylex()) != IDENT)
 				error("internal sync error");
+			stringbuf = obp;
 			return 0;
 		}
 	} else {
@@ -903,18 +1070,18 @@
 	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);
+			printf("do not expand %s\n", rp2->sp->namep);
 			rp2 = rp2->next;
 		}
 	}
 #endif
+	readmac++;
 	while ((c = yylex()) != WARN) {
 		switch (c) {
 		case NOEXP: noexp++; break;
@@ -940,7 +1107,8 @@
 				else
 					orgexp++;
 
-			DDPRINT(("id1: noexp %d orgexp %d\n", noexp, orgexp));
+			DDPRINT(("id1: typ %d noexp %d orgexp %d\n",
+			    c, noexp, orgexp));
 			if (c == IDENT) { /* XXX numbers? */
 				DDPRINT(("id2: str %s\n", yytext));
 				/* OK to always expand here? */
@@ -974,6 +1142,8 @@
 			unpstr((usch *)yytext);
 			if (orgexp == -1)
 				cunput(EXPAND);
+			else if (orgexp == -2)
+				cunput(EXPAND), cunput(EXPAND);
 			else if (orgexp == 1)
 				cunput(NOEXP);
 			unpstr(och);
@@ -1004,8 +1174,7 @@
 				error("bad noexp %d", noexp);
 			stksv = NULL;
 			if ((c = yylex()) == WSPACE) {
-				stksv = alloca(yyleng+1);
-				strlcpy((char *)stksv, yytext, yyleng+1);
+				stksv = xstrdup(yytext);
 				c = yylex();
 			}
 			/* only valid for expansion if fun macro */
@@ -1022,6 +1191,12 @@
 					unpstr(stksv);
 				savstr(nl->namep);
 			}
+			if (stksv)
+				free(stksv);
+			break;
+
+		case CMNT:
+			getcmnt();
 			break;
 
 		case STRING:
@@ -1043,6 +1218,7 @@
 	}
 	if (noexp)
 		error("expmac noexp=%d", noexp);
+	readmac--;
 	DPRINT(("return from expmac\n"));
 }
 
@@ -1053,34 +1229,40 @@
  * result is written on top of heap
  */
 void
-expdef(vp, rp, gotwarn)
-	usch *vp;
-	struct recur *rp;
+expdef(usch *vp, struct recur *rp, int gotwarn)
 {
 	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 : "")));
+	DPRINT(("expdef rp %s\n", (rp ? (char *)rp->sp->namep : "")));
 	if ((c = yylex()) != '(')
-		error("got %c, expected )", c);
+		error("got %c, expected (", c);
 	if (vp[1] == VARG) {
 		narg = *vp--;
 		ellips = 1;
 	} else
 		narg = vp[1];
-	args = alloca(sizeof(usch *) * (narg+ellips));
+	if ((args = malloc(sizeof(usch *) * (narg+ellips))) == NULL)
+		error("expdef: out of mem");
 
 	/*
 	 * read arguments and store them on heap.
 	 * will be removed just before return from this function.
 	 */
+	inmac = 1;
 	sptr = stringbuf;
+	instr = 0;
 	for (i = 0; i < narg && c != ')'; i++) {
 		args[i] = stringbuf;
 		plev = 0;
 		while ((c = yylex()) == WSPACE || c == '\n')
 			;
+		DDPRINT((":AAA (%d)", c));
+		if (instr == -1)
+			savch(NOEXP), instr = 1;
+		if (c == NOEXP)
+			instr = 1;
 		for (;;) {
 			if (plev == 0 && (c == ')' || c == ','))
 				break;
@@ -1091,10 +1273,20 @@
 			savstr((usch *)yytext);
 			while ((c = yylex()) == '\n')
 				savch('\n');
+			while (c == CMNT) {
+				getcmnt();
+				c = yylex();
+			}
+			if (c == EXPAND)
+				instr = 0;
+			if (c == 0)
+				error("eof in macro");
 		}
 		while (args[i] < stringbuf &&
 		    (stringbuf[-1] == ' ' || stringbuf[-1] == '\t'))
 			stringbuf--;
+		if (instr == 1)
+			savch(EXPAND), instr = -1;
 		savch('\0');
 	}
 	if (ellips)
@@ -1102,8 +1294,12 @@
 	if (ellips && c != ')') {
 		args[i] = stringbuf;
 		plev = 0;
+		instr = 0;
 		while ((c = yylex()) == WSPACE)
 			;
+		if (c == NOEXP)
+			instr++;
+		DDPRINT((":AAY (%d)", c));
 		for (;;) {
 			if (plev == 0 && c == ')')
 				break;
@@ -1111,9 +1307,16 @@
 				plev++;
 			if (c == ')')
 				plev--;
-			savstr((usch *)yytext);
+			if (plev == 0 && c == ',' && instr) {
+				savch(EXPAND);
+				savch(',');
+				savch(NOEXP);
+			} else
+				savstr((usch *)yytext);
 			while ((c = yylex()) == '\n')
 				savch('\n');
+			if (c == EXPAND)
+				instr--;
 		}
 		while (args[i] < stringbuf &&
 		    (stringbuf[-1] == ' ' || stringbuf[-1] == '\t'))
@@ -1122,10 +1325,13 @@
 		
 	}
 	if (narg == 0 && ellips == 0)
-		c = yylex();
+		while ((c = yylex()) == WSPACE || c == '\n')
+			;
+
 	if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
 		error("wrong arg count");
 
+	inmac = 0;
 	while (gotwarn--)
 		cunput(WARN);
 
@@ -1147,6 +1353,14 @@
 			if (sp[-1] == VARG) {
 				bp = ap = args[narg];
 				sp--;
+#ifdef GCC_VARI
+			} else if (sp[-1] == GCCARG) {
+				ap = args[narg];
+				if (ap[0] == 0)
+					ap = (usch *)"0";
+				bp = ap;
+				sp--;
+#endif
 			} else
 				bp = ap = args[(int)*--sp];
 			if (sp[2] != CONC && !snuff && sp[-1] != CONC) {
@@ -1192,6 +1406,7 @@
 
 	/* scan the input buffer (until WARN) and save result on heap */
 	expmac(rp);
+	free(args);
 }
 
 usch *
@@ -1255,6 +1470,10 @@
 putstr(usch *s)
 {
 	for (; *s; s++) {
+		if (*s == PRAGS) {
+			s = prtprag(s);
+			continue;
+		}
 		outbuf[obufp++] = *s;
 		if (obufp == CPPBUF || (istty && *s == '\n'))
 			flbuf();
@@ -1480,3 +1699,41 @@
 	return (struct symtab *)new->lr[bit];
 }
 
+usch *
+xstrdup(char *str)
+{
+	size_t len = strlen(str)+1;
+	usch *rv;
+
+	if ((rv = malloc(len)) == NULL)
+		error("xstrdup: out of mem");
+	strlcpy((char *)rv, str, len);
+	return rv;
+}
+
+usch *
+prtprag(usch *s)
+{
+	int ch;
+
+	s++;
+	putstr((usch *)"\n#pragma ");
+	while (*s != PRAGE) {
+		if (*s == 'L')
+			s++;
+		if (*s == '\"') {
+			s++;
+			while ((ch = *s++) != '\"') {
+				if (ch == '\\' && (*s == '\"' || *s == '\\'))
+					ch = *s++;
+				putch(ch);
+			}
+		} else {
+			s++;
+			putch(*s);
+		}
+	}
+	putstr((usch *)"\n");
+	prtline();
+	return ++s;
+}
Index: cpy.y
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/cpp/cpy.y,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/cpp/cpy.y -L usr.bin/pcc/cpp/cpy.y -u -r1.1 -r1.2
--- usr.bin/pcc/cpp/cpy.y
+++ usr.bin/pcc/cpp/cpy.y
@@ -1,4 +1,4 @@
-/*	$Id: cpy.y,v 1.12 2006/10/08 13:41:39 ragge Exp $	*/
+/*	$Id: cpy.y,v 1.16 2008/04/12 17:14:27 ragge Exp $	*/
 
 /*
  * Copyright (c) 2004 Anders Magnusson (ragge at ludd.luth.se).
@@ -62,23 +62,34 @@
  */
 
 %{
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
+
+#include "cpp.h"
+
 void yyerror(char *);
 int yylex(void);
+int setd(int l, int r);
+
+#define	EVALUNARY(tok, l, r) l.nd_val = tok r.nd_val; l.op = r.op
+#define	EVALBIN(tok, d, l, r)	\
+	d.op = setd(l.op, r.op); d.nd_val = l.nd_val tok r.nd_val
+#define	EVALUBIN(tok, d, l, r, t)				\
+	d.op = setd(l.op, r.op);				\
+	if (d.op == NUMBER) d.nd_val = l.nd_val tok r.nd_val;	\
+	else d.nd_uval = l.nd_uval tok r.nd_uval;		\
+	if (t && d.op) d.op = NUMBER
+#define	XEVALUBIN(tok, d, l, r)					\
+	if (r.nd_val) { EVALUBIN(tok, d, l, r, 0); } else d.op = 0
 %}
 
 %term stop
 %term EQ NE LE GE LS RS
-%term ANDAND OROR IDENT NUMBER
+%term ANDAND OROR IDENT NUMBER UNUMBER
 /*
  * The following terminals are not used in the yacc code.
  */
-%term STRING FPOINT WSPACE VA_ARGS CONCAT MKSTR ELLIPS
+%term STRING FPOINT WSPACE VA_ARGS CONCAT MKSTR ELLIPS CMNT
 
 %left ','
-%right '='
 %right '?' ':'
 %left OROR
 %left ANDAND
@@ -90,77 +101,117 @@
 %left '+' '-'
 %left '*' '/' '%'
 %right '!' '~' UMINUS
-%left '(' '.'
+%left '('
 
 %union {
-	long long val;
+	struct nd node;
 }
 
-%type <val> term NUMBER e
+%type <node>	term e NUMBER UNUMBER
 
 %%
-S:	e '\n'	{ return($1 != 0);}
-
+S:	e '\n'	{ 
+		if ($1.op == 0)
+			error("division by zero");
+		return $1.nd_val;
+	}
 
 e:	  e '*' e
-		{$$ = $1 * $3;}
+		{ EVALUBIN(*, $$, $1, $3, 0); }
 	| e '/' e
-		{$$ = $1 / $3;}
+		{ XEVALUBIN(/, $$, $1, $3); }
 	| e '%' e
-		{$$ = $1 % $3;}
+		{ XEVALUBIN(%, $$, $1, $3); }
 	| e '+' e
-		{$$ = $1 + $3;}
+		{ EVALBIN(+, $$, $1, $3); }
 	| e '-' e
-		{$$ = $1 - $3;}
+		{ EVALBIN(-, $$, $1, $3); }
 	| e LS e
-		{$$ = $1 << $3;}
+		{ EVALBIN(<<, $$, $1, $3); }
 	| e RS e
-		{$$ = $1 >> $3;}
+		{ EVALUBIN(>>, $$, $1, $3, 0); }
 	| e '<' e
-		{$$ = $1 < $3;}
+		{ EVALUBIN(<, $$, $1, $3, 1); }
 	| e '>' e
-		{$$ = $1 > $3;}
+		{ EVALUBIN(>, $$, $1, $3, 1); }
 	| e LE e
-		{$$ = $1 <= $3;}
+		{ EVALUBIN(<=, $$, $1, $3, 1); }
 	| e GE e
-		{$$ = $1 >= $3;}
+		{ EVALUBIN(>=, $$, $1, $3, 1); }
 	| e EQ e
-		{$$ = $1 == $3;}
+		{ EVALUBIN(==, $$, $1, $3, 1); }
 	| e NE e
-		{$$ = $1 != $3;}
+		{ EVALUBIN(!=, $$, $1, $3, 1); }
 	| e '&' e
-		{$$ = $1 & $3;}
+		{ EVALBIN(&, $$, $1, $3); }
 	| e '^' e
-		{$$ = $1 ^ $3;}
+		{ EVALBIN(^, $$, $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;}
+		{ EVALBIN(|, $$, $1, $3); }
+	| e ANDAND e {
+		$$ = $1;
+		if ($1.nd_val) {
+			$$.op = setd($1.op, $3.op);
+			$$.nd_val = ($3.nd_val != 0);
+		}
+		if ($$.op == UNUMBER) $$.op = NUMBER;
+	}
+	| e OROR e {
+		if ($1.nd_val != 0) {
+			$$.nd_val = ($1.nd_val != 0);
+			$$.op = $1.op;
+		} else {
+			$$.nd_val = ($3.nd_val != 0);
+			$$.op = setd($1.op, $3.op);
+		}
+		if ($$.op == UNUMBER) $$.op = NUMBER;
+	}
+	| e '?' e ':' e {
+		if ($1.op == 0)
+			$$ = $1;
+		else if ($1.nd_val)
+			$$ = $3;
+		else
+			$$ = $5;
+	}
+	| e ',' e {
+		$$.op = setd($1.op, $3.op);
+		$$.nd_val = $3.nd_val;
+		if ($$.op) $$.op =  $3.op;
+	}
 	| term
 		{$$ = $1;}
 term:
 	  '-' term %prec UMINUS
-		{$$ = -$2;}
+		{ EVALUNARY(-, $$, $2); }
+	| '+' term %prec UMINUS
+		{$$ = $2;}
 	| '!' term
-		{$$ = !$2;}
+		{ $$.nd_val = ! $2.nd_val; $$.op = $2.op ? NUMBER : 0; }
 	| '~' term
-		{$$ = ~$2;}
+		{ EVALUNARY(~, $$, $2); }
 	| '(' e ')'
 		{$$ = $2;}
 	| NUMBER
-		{$$= $1;}
+		{$$ = $1;}
 %%
 
-#include "cpp.h"
-
 void
 yyerror(char *err)
 {
 	error(err);
 }
+
+/*
+ * Set return type of an expression.
+ */
+int
+setd(int l, int r)
+{
+	if (!l || !r)
+		return 0; /* div by zero involved */
+	if (l == UNUMBER || r == UNUMBER)
+		return UNUMBER;
+	return NUMBER;
+}
+
Index: cpp.h
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/cpp/cpp.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L usr.bin/pcc/cpp/cpp.h -L usr.bin/pcc/cpp/cpp.h -u -r1.2 -r1.3
--- usr.bin/pcc/cpp/cpp.h
+++ usr.bin/pcc/cpp/cpp.h
@@ -1,4 +1,4 @@
-/*	$Id: cpp.h,v 1.27 2007/09/17 18:16:14 ragge Exp $	*/
+/*	$Id: cpp.h,v 1.37 2008/07/02 01:12:41 gmcgarry Exp $	*/
 
 /*
  * Copyright (c) 2004 Anders Magnusson (ragge at ludd.luth.se).
@@ -28,8 +28,9 @@
  */
 
 #include <stdio.h> /* for obuf */
+#include <stdlib.h>
 
-#include "../config.h"
+#include "config.h"
 
 typedef unsigned char usch;
 #ifdef YYTEXT_POINTER
@@ -43,7 +44,7 @@
 extern	int	flslvl;
 extern	int	elflvl;
 extern	int	elslvl;
-extern	int	tflag, Cflag;
+extern	int	tflag, Cflag, Pflag;
 extern	int	Mflag, dMflag;
 extern	usch	*Mfile;
 extern	int	ofd;
@@ -72,6 +73,7 @@
 	int infil;
 	usch *curptr;
 	usch *maxread;
+	usch *ostr;
 	usch *buffer;
 	usch bbuf[NAMEMAX+CPPBUF+1];
 } *ifiles;
@@ -90,6 +92,23 @@
 	char *str;
 };
 
+/*
+ * Struct used in parse tree evaluation.
+ * op is one of:
+ *	- number type (NUMBER, UNUMBER)
+ *	- zero (0) if divided by zero.
+ */
+struct nd {
+	int op;
+	union {
+		long long val;
+		unsigned long long uval;
+	} n;
+};
+
+#define nd_val n.val
+#define nd_uval n.uval
+
 struct recur;	/* not used outside cpp.c */
 int subst(struct symtab *, struct recur *);
 struct symtab *lookup(usch *namep, int enterf);
@@ -115,6 +134,15 @@
 void putstr(usch *s);
 void line(void);
 usch *sheap(char *fmt, ...);
+void xwarning(usch *);
 void xerror(usch *);
+#ifdef HAVE_CPP_VARARG_MACRO_GCC
+#define warning(...) xwarning(sheap(__VA_ARGS__))
 #define error(...) xerror(sheap(__VA_ARGS__))
+#else
+#define warning printf
+#define error printf
+#endif
 void expmac(struct recur *);
+int cinput(void);
+void getcmnt(void);
--- /dev/null
+++ usr.bin/pcc/cpp/pcpp.1
@@ -0,0 +1,210 @@
+.\"	$Id: cpp.1,v 1.10 2008/07/02 01:12:41 gmcgarry 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 CdMtVv
+.Op Fl D Ar macro[=value]
+.Op Fl I Ar path
+.Op Fl i Ar file
+.Op Fl S Ar path
+.Op Fl U Ar macro
+.Op Ar infile | -
+.Op Ar outfile
+.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 ?
+Show command line usage for
+.Nm .
+.It Fl C
+Do not discard comments.
+.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 define it as 1.
+.\" TODO: show example
+.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 output.
+.\" TODO this doesn't show predefined macros
+.\" other -d options are ignored
+.It Fl I Ar path
+Add
+.Ar path
+to the list of 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 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 M
+Generate dependencies for
+.Xr make 1 .
+.\" TODO: explain and show example?
+.It Fl P
+Inhibit generation of line markers.  This is sometimes useful when
+running the preprocessor on something other than C code.
+.It Fl S Ar path
+Add
+.Ar path
+to the list of system directories containing needed header files.
+The
+.Fl S
+option 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__ ,
+.Dv __STDC__ ,
+and
+.Dv __STDC_VERSION__
+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 v
+Display version.
+.El
+.Ss 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 Aq stdin .
+.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
+.St -isoC
+.Po also known as
+.Do C90 Dc Pc .
+.It __STDC_VERSION__
+Expands to
+.Dq 199901L
+which indicates that
+.Nm
+supports
+.St -isoC-99
+.Po commonly referred to as
+.Do C99 Dc Pc .
+.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.
Index: Makefile
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/cpp/Makefile,v
retrieving revision 1.6
retrieving revision 1.7
diff -L usr.bin/pcc/cpp/Makefile -L usr.bin/pcc/cpp/Makefile -u -r1.6 -r1.7
--- usr.bin/pcc/cpp/Makefile
+++ usr.bin/pcc/cpp/Makefile
@@ -5,13 +5,11 @@
 PROG=	pcpp
 TARGOS=	midnightbsd
 BINDIR=	${libexecdir}
-NO_MAN=
-#MAN=	cpp.1
-#MANDIR=	/usr/local/man/man
+MAN=	pcpp.1
 
 CFLAGS+=	-DCPP_DEBUG -Wall -Wmissing-prototypes -Wstrict-prototypes -Werror
 CFLAGS+=	-DLIBEXECDIR=\"${libexecdir}\"
-CFLAGS+=	-I. -I${.CURDIR}
+CFLAGS+=	-I. -I${.CURDIR} -I${.CURDIR}/.. -I${.CURDIR}/../mip/
 SRCS=	cpy.y scanner.l cpp.c
 
 CLEANFILES+=	y.tab.c y.tab.h 
--- usr.bin/pcc/cpp/cpp.1
+++ /dev/null
@@ -1,191 +0,0 @@
-.\"	$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.
Index: order.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/i386/order.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/i386/order.c -L usr.bin/pcc/i386/order.c -u -r1.1 -r1.2
--- usr.bin/pcc/i386/order.c
+++ usr.bin/pcc/i386/order.c
@@ -1,4 +1,4 @@
-/*	$Id: order.c,v 1.49 2007/08/01 04:53:58 ragge Exp $	*/
+/*	$Id: order.c,v 1.54 2008/09/27 07:35:22 ragge Exp $	*/
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -103,26 +103,16 @@
  * Shape matches for UMUL.  Cooperates with offstar().
  */
 int
-shumul(NODE *p)
+shumul(NODE *p, int shape)
 {
 
 	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);
+	if (shape & SOREG)
+		return SROREG;
+	return SRNOPE;
 }
 
 /*
@@ -183,8 +173,8 @@
 			static struct rspecial s[] = { 
 				{ NOLEFT, ESI }, { NOLEFT, EDI }, { 0 } };
 			return s;
-		} else if ((q->ltype & (TINT|TUNSIGNED)) &&
-		    q->rtype == TLONGLONG) {
+		} else if ((q->ltype & TINT) &&
+		    q->rtype == (TLONGLONG|TULONGLONG)) {
 			static struct rspecial s[] = {
 				{ NLEFT, EAX }, { NRES, EAXEDX },
 				{ NEVER, EAX }, { NEVER, EDX }, { 0 } };
@@ -285,3 +275,30 @@
 {
 	return 0; /* nothing differs on x86 */
 }
+
+/*
+ * set registers in calling conventions live.
+ */
+int *
+livecall(NODE *p)
+{
+	static int r[] = { EAX, EBX, -1 };
+	int off = 1;
+
+#ifdef TLS
+	if (p->n_left->n_op == ICON &&
+	    strcmp(p->n_left->n_name, "___tls_get_addr at PLT") == 0)
+		off--;
+#endif
+
+	return kflag ? &r[off] : &r[2];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+	return 1;
+}
Index: macdefs.h
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/i386/macdefs.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/i386/macdefs.h -L usr.bin/pcc/i386/macdefs.h -u -r1.1 -r1.2
--- usr.bin/pcc/i386/macdefs.h
+++ usr.bin/pcc/i386/macdefs.h
@@ -1,4 +1,4 @@
-/*	$Id: macdefs.h,v 1.46 2007/08/19 19:25:22 ragge Exp $	*/
+/*	$Id: macdefs.h,v 1.67 2008/12/14 18:26:43 ragge Exp $	*/
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -65,8 +65,9 @@
 #define ALLONGLONG	32
 #define ALSHORT		16
 #define ALPOINT		32
-#define ALSTRUCT	32
+#undef ALSTRUCT		/* Not defined if ELF ABI */
 #define ALSTACK		32 
+#define	ALMAX		128	/* not yet supported type */
 
 /*
  * Min/max values.
@@ -77,7 +78,7 @@
 #define	MIN_SHORT	-32768
 #define	MAX_SHORT	32767
 #define	MAX_USHORT	65535
-#define	MIN_INT		-1
+#define	MIN_INT		(-0x7fffffff-1)
 #define	MAX_INT		0x7fffffff
 #define	MAX_UNSIGNED	0xffffffff
 #define	MIN_LONG	MIN_INT
@@ -90,7 +91,11 @@
 /* Default char is signed */
 #undef	CHAR_UNSIGNED
 #define	BOOL_TYPE	CHAR	/* what used to store _Bool */
+#if defined(os_mirbsd) || defined(os_win32)
+#define WCHAR_TYPE	USHORT	/* ISO 10646 16-bit Unicode */
+#else
 #define	WCHAR_TYPE	INT	/* what used to store wchar_t */
+#endif
 
 /*
  * Use large-enough types.
@@ -100,36 +105,37 @@
 typedef long long OFFSZ;
 
 #define CONFMT	"%lld"		/* format for printing constants */
+#if defined(ELFABI)
 #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 */
+#else
+#define LABFMT	"L%d"		/* format for printing labels */
+#define	STABLBL	"LL%d"		/* format for stab (debugging) labels */
+#endif
+#ifdef LANG_F77
 #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
+#define ARGOFFSET 8
+#endif
+
+#ifdef MACHOABI
+#define STAB_LINE_ABSOLUTE	/* S_LINE fields use absolute addresses */
 #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 */
 
+#define FINDMOPS	/* i386 has instructions that modifies memory */
+
 /* Definitions mostly used in pass2 */
 
 #define BYTEOFF(x)	((x)&03)
@@ -292,10 +298,69 @@
 #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 */
+
+/*
+ * Specials that indicate the applicability of machine idioms.
+ */
+#define SMIXOR		(MAXSPECIAL+4)
+#define SMILWXOR	(MAXSPECIAL+5)
+#define SMIHWXOR	(MAXSPECIAL+6)
+
+/*
+ * i386-specific symbol table flags.
+ */
+#define	SSECTION	SLOCAL1
+#define	STLS		SLOCAL2
+#define	SNOUNDERSCORE	SLOCAL3
+#define SSTDCALL	SLOCAL2	
+#define SDLLINDIRECT	SLOCAL3
+
+/*
+ * i386-specific node flags.
+ */
+#define FSTDCALL	0x01
+
+/*
+ * i386-specific interpass stuff.
+ */
+
+#define TARGET_IPP_MEMBERS			\
+	int ipp_argstacksize;
+
+/*
+ * Extended assembler macros.
+ */
+void targarg(char *w, void *arg);
+#define	XASM_TARGARG(w, ary)	\
+	(w[1] == 'b' || w[1] == 'h' || w[1] == 'w' || w[1] == 'k' ? \
+	w++, targarg(w, ary), 1 : 0)
+int numconv(void *ip, void *p, void *q);
+#define	XASM_NUMCONV(ip, p, q)	numconv(ip, p, q)
+int xasmconstregs(char *);
+#define	XASMCONSTREGS(x) xasmconstregs(x)
+
+/*
+ * builtins.
+ */
+#define TARGET_BUILTINS							\
+	{ "__builtin_frame_address", i386_builtin_frame_address },	\
+	{ "__builtin_return_address", i386_builtin_return_address },
+
+#define NODE struct node
+struct node;
+NODE *i386_builtin_frame_address(NODE *f, NODE *a);
+NODE *i386_builtin_return_address(NODE *f, NODE *a);
+#undef NODE
+
+#if defined(MACHOABI)
+struct stub {
+	struct { struct stub *q_forw, *q_back; } link;
+	char *name;
+};    
+extern struct stub stublist;
+extern struct stub nlplist;
+void addstub(struct stub *list, char *name);
+#endif
Index: table.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/i386/table.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/i386/table.c -L usr.bin/pcc/i386/table.c -u -r1.1 -r1.2
--- usr.bin/pcc/i386/table.c
+++ usr.bin/pcc/i386/table.c
@@ -1,4 +1,4 @@
-/*	$Id: table.c,v 1.96 2007/09/20 14:52:13 ragge Exp $	*/
+/*	$Id: table.c,v 1.110 2008/11/24 14:52:02 mickey Exp $	*/
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -133,7 +133,7 @@
 { SCONV,	INLL,
 	SHCH|SOREG|SNAME,	TCHAR,
 	SANY,	TLL,
-		NSPECIAL|NAREG|NASL,	RESC1,
+		NSPECIAL|NCREG|NCSL,	RESC1,
 		"	movsbl AL,%eax\n	cltd\n", },
 
 /* convert unsigned char to (u)long long */
@@ -229,7 +229,7 @@
 
 /* convert int to char. This is done when register is loaded */
 { SCONV,	INCH,
-	SAREG,	TWORD,
+	SAREG,	TWORD|TPOINT,
 	SANY,	TCHAR|TUCHAR,
 		NSPECIAL|NBREG|NBSL,	RESC1,
 		"ZM", },
@@ -241,17 +241,17 @@
 		0,	RLEFT,
 		"", },
 
-/* convert int to long long */
+/* convert signed int to (u)long long */
 { SCONV,	INLL,
-	SAREG,	TWORD|TPOINT,
-	SCREG,	TLONGLONG,
+	SHINT,	TSWORD,
+	SHLL,	TLL,
 		NSPECIAL|NCREG|NCSL,	RESC1,
 		"	cltd\n", },
 
-/* convert int to unsigned long long */
+/* convert unsigned int to (u)long long */
 { SCONV,	INLL,
-	SAREG|SOREG|SNAME,	TWORD|TPOINT,
-	SHLL,	TULONGLONG,
+	SHINT|SOREG|SNAME,	TUWORD|TPOINT,
+	SHLL,	TLL,
 		NCSL|NCREG,	RESC1,
 		"	movl AL,A1\n	xorl U1,U1\n", },
 
@@ -275,14 +275,14 @@
 { SCONV,	INCH,
 	SOREG|SNAME,	TLL,
 	SANY,	TCHAR|TUCHAR,
-		NAREG|NASL,	RESC1,
+		NBREG|NBSL,	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,
+		NBREG|NBSL,	RESC1,
 		"ZS", },
 
 /* convert (u)long long to (u)short (mem->reg) */
@@ -358,7 +358,19 @@
 	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
 	SAREG,	TWORD,
 		NAREG,	RESC1,
+#ifdef notdef	/* Must round down and nothing else */
 		"	subl $4,%esp\n	fistpl (%esp)\n	popl A1\n", },
+#else
+		"	subl $12,%esp\n"
+		"	fnstcw (%esp)\n"
+		"	fnstcw 4(%esp)\n"
+		"	movb $12,1(%esp)\n"
+		"	fldcw (%esp)\n"
+		"	fistpl 8(%esp)\n"
+		"	movl 8(%esp),A1\n"
+		"	fldcw 4(%esp)\n"
+		"	addl $12,%esp\n", },
+#endif
 
 /* convert float/double (in register) to (unsigned) long long */
 /* XXX - unsigned is not handled correct */
@@ -366,8 +378,21 @@
 	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
 	SHLL,	TLONGLONG|TULONGLONG,
 		NCREG,	RESC1,
+#ifdef notdef	/* Must round down and nothing else */
 		"	subl $8,%esp\n	fistpq (%esp)\n"
 		"	popl A1\n	popl U1\n", },
+#else
+		"	subl $16,%esp\n"
+		"	fnstcw (%esp)\n"
+		"	fnstcw 4(%esp)\n"
+		"	movb $12,1(%esp)\n"
+		"	fldcw (%esp)\n"
+		"	fistpq 8(%esp)\n"
+		"	movl 8(%esp),A1\n"
+		"	movl 12(%esp),U1\n"
+		"	fldcw 4(%esp)\n"
+		"	addl $16,%esp\n", },
+#endif
 
 /* slut sconv */
 
@@ -389,13 +414,13 @@
 
 { CALL,	INAREG,
 	SCON,	TANY,
-	SAREG,	TWORD|TPOINT,
+	SAREG,	TSHORT|TUSHORT|TWORD|TPOINT,
 		NAREG|NASL,	RESC1,	/* should be 0 */
 		"	call CL\nZC", },
 
 { UCALL,	INAREG,
 	SCON,	TANY,
-	SAREG,	TWORD|TPOINT,
+	SAREG,	TSHORT|TUSHORT|TWORD|TPOINT,
 		NAREG|NASL,	RESC1,	/* should be 0 */
 		"	call CL\n", },
 
@@ -573,6 +598,12 @@
 		NAREG|NASL,	RESC1,
 		"	leal CR(AL),A1\n", },
 
+{ PLUS,		INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SONE,	TANY,
+		0,	RLEFT,
+		"	incw AL\n", },
+
 { PLUS,		INCH|FOREFF,
 	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
 	SONE,	TANY,
@@ -591,6 +622,12 @@
 		0,	RLEFT,
 		"	decl AL\n", },
 
+{ MINUS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SONE,			TANY,
+		0,	RLEFT,
+		"	decw AL\n", },
+
 { MINUS,	INCH|FOREFF,
 	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
 	SONE,	TANY,
@@ -623,48 +660,81 @@
 		"	fsubZAp\n", },
 
 /* Simple r/m->reg ops */
-{ OPSIMP,	INAREG|FOREFF,
+/* m/r |= r */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SAREG,			TWORD|TPOINT,
+		0,	RLEFT|RESCC,
+		"	Ol AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
 	SAREG,			TWORD|TPOINT,
 	SAREG|SNAME|SOREG,	TWORD|TPOINT,
-		0,	RLEFT,
+		0,	RLEFT|RESCC,
 		"	Ol AR,AL\n", },
 
-{ OPSIMP,	INAREG|FOREFF,
+/* m/r |= r */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SHINT|SNAME|SOREG,	TSHORT|TUSHORT,
+	SHINT,		TSHORT|TUSHORT,
+		0,	RLEFT|RESCC,
+		"	Ow AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
 	SHINT,		TSHORT|TUSHORT,
 	SHINT|SNAME|SOREG,	TSHORT|TUSHORT,
-		0,	RLEFT,
+		0,	RLEFT|RESCC,
 		"	Ow AR,AL\n", },
 
-{ OPSIMP,	INCH|FOREFF,
+/* m/r |= r */
+{ OPSIMP,	INCH|FOREFF|FORCC,
 	SHCH,		TCHAR|TUCHAR,
 	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
-		0,	RLEFT,
+		0,	RLEFT|RESCC,
 		"	Ob AR,AL\n", },
 
-{ OPSIMP,	INAREG|FOREFF,
-	SAREG,	TWORD|TPOINT,
+/* r |= r/m */
+{ OPSIMP,	INCH|FOREFF|FORCC,
+	SHCH,		TCHAR|TUCHAR,
+	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
+		0,	RLEFT|RESCC,
+		"	Ob AR,AL\n", },
+
+/* m/r |= const */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
 	SCON,	TWORD|TPOINT,
-		0,	RLEFT,
+		0,	RLEFT|RESCC,
 		"	Ol AR,AL\n", },
 
-{ OPSIMP,	INAREG|FOREFF,
+{ OPSIMP,	INAREG|FOREFF|FORCC,
 	SHINT|SNAME|SOREG,	TSHORT|TUSHORT,
 	SCON,	TANY,
-		0,	RLEFT,
+		0,	RLEFT|RESCC,
 		"	Ow AR,AL\n", },
 
-{ OPSIMP,	INCH|FOREFF,
+{ OPSIMP,	INCH|FOREFF|FORCC,
 	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
 	SCON,	TANY,
-		0,	RLEFT,
+		0,	RLEFT|RESCC,
 		"	Ob AR,AL\n", },
 
+/* r |= r/m */
 { OPSIMP,	INLL|FOREFF,
 	SHLL,	TLL,
 	SHLL|SNAME|SOREG,	TLL,
 		0,	RLEFT,
 		"	Ol AR,AL\n	Ol UR,UL\n", },
 
+/* m/r |= r/const */
+{ OPSIMP,	INLL|FOREFF,
+	SHLL|SNAME|SOREG,	TLL,
+	SHLL|SCON,	TLL,
+		0,	RLEFT,
+		"	Ol AR,AL\n	Ol UR,UL\n", },
+
 
 /*
  * The next rules handle all shift operators.
@@ -676,24 +746,28 @@
 		NSPECIAL|NCREG|NCSL|NCSR,	RESC1,
 		"ZO", },
 
+/* r/m <<= r */
 { LS,	INAREG|FOREFF,
 	SAREG|SNAME|SOREG,	TWORD,
 	SHCH,		TCHAR|TUCHAR,
 		NSPECIAL,	RLEFT,
 		"	sall AR,AL\n", },
 
+/* r/m <<= const */
 { LS,	INAREG|FOREFF,
-	SAREG,	TWORD,
+	SAREG|SNAME|SOREG,	TWORD,
 	SCON,	TANY,
 		0,	RLEFT,
 		"	sall AR,AL\n", },
 
+/* r/m <<= r */
 { LS,	INAREG|FOREFF,
 	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
 	SHCH,			TCHAR|TUCHAR,
 		NSPECIAL,	RLEFT,
 		"	shlw AR,AL\n", },
 
+/* r/m <<= const */
 { LS,	INAREG|FOREFF,
 	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
 	SCON,	TANY,
@@ -727,7 +801,7 @@
 
 { RS,	INAREG|FOREFF,
 	SAREG|SNAME|SOREG,	TSWORD,
-	SCON,			TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SCON,			TANY,
 		0,		RLEFT,
 		"	sarl AR,AL\n", },
 
@@ -739,7 +813,7 @@
 
 { RS,	INAREG|FOREFF,
 	SAREG|SNAME|SOREG,	TUWORD,
-	SCON,			TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SCON,			TANY,
 		0,		RLEFT,
 		"	shrl AR,AL\n", },
 
@@ -794,17 +868,41 @@
 /*
  * The next rules takes care of assignments. "=".
  */
+{ ASSIGN,	FORCC|FOREFF|INLL,
+	SHLL,		TLL,
+	SMIXOR,		TANY,
+		0,	RDEST,
+		"	xorl AL,AL\n	xorl UL,UL\n", },
+
+{ ASSIGN,	FORCC|FOREFF|INLL,
+	SHLL,		TLL,
+	SMILWXOR,	TANY,
+		0,	RDEST,
+		"	xorl AL,AL\n	movl UR,UL\n", },
+
+{ ASSIGN,	FORCC|FOREFF|INLL,
+	SHLL,		TLL,
+	SMIHWXOR,	TANY,
+		0,	RDEST,
+		"	movl AR,AL\n	xorl UL,UL\n", },
+
+{ ASSIGN,	FOREFF|INLL,
+	SHLL,		TLL,
+	SCON,		TANY,
+		0,	RDEST,
+		"	movl AR,AL\n	movl UR,UL\n", },
+
 { 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,
+{ ASSIGN,	FORCC|FOREFF|INAREG,
+	SAREG,	TWORD|TPOINT,
+	SMIXOR,		TANY,
 		0,	RDEST,
-		"	movl AR,AL\n	movl UR,UL\n", },
+		"	xorl AL,AL\n", },
 
 { ASSIGN,	FOREFF,
 	SAREG|SNAME|SOREG,	TWORD|TPOINT,
@@ -818,6 +916,12 @@
 		0,	RDEST,
 		"	movl AR,AL\n", },
 
+{ ASSIGN,	FORCC|FOREFF|INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SMIXOR,		TANY,
+		0,	RDEST,
+		"	xorw AL,AL\n", },
+
 { ASSIGN,	FOREFF,
 	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
 	SCON,		TANY,
@@ -875,20 +979,40 @@
 { ASSIGN,	FOREFF|INBREG,
 	SFLD,		TCHAR|TUCHAR,
 	SBREG|SCON,	TCHAR|TUCHAR,
-		NBREG,	RDEST,
-		"ZE", },
+		NAREG|NBREG,	RDEST,
+		"	movb AR,A2\n"
+		"	movzbl A2,A1\n"
+		"	andl $N,AL\n"
+		"	sall $H,A1\n"
+		"	andl $M,A1\n"
+		"	orl A1,AL\n"
+		"F	movb AR,AD\n"
+		"FZE", },
 
 { ASSIGN,	FOREFF|INAREG,
-	SFLD,		TANY,
-	SAREG,	TANY,
+	SFLD,		TSHORT|TUSHORT,
+	SAREG|SCON,	TSHORT|TUSHORT,
 		NAREG,	RDEST,
-		"ZE", },
+		"	movw AR,A1\n"
+		"	movzwl A1,ZN\n"
+		"	andl $N,AL\n"
+		"	sall $H,ZN\n"
+		"	andl $M,ZN\n"
+		"	orl ZN,AL\n"
+		"F	movw AR,AD\n"
+		"FZE", },
 
-{ ASSIGN,	FOREFF,
-	SFLD,		TANY,
-	SAREG|SNAME|SOREG|SCON,	TANY,
-		NAREG,	0,
-		"ZE", },
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,		TWORD,
+	SAREG|SNAME|SOREG|SCON,	TWORD,
+		NAREG,	RDEST,
+		"	movl AR,A1\n"
+		"	andl $N,AL\n"
+		"	sall $H,A1\n"
+		"	andl $M,A1\n"
+		"	orl A1,AL\n"
+		"F	movl AR,AD\n"
+		"FZE", },
 
 { ASSIGN,	INDREG|FOREFF,
 	SHFL,	TFLOAT|TDOUBLE|TLDOUBLE,
@@ -901,7 +1025,7 @@
 	SNAME|SOREG,	TLDOUBLE,
 	SHFL,	TFLOAT|TDOUBLE|TLDOUBLE,
 		0,	RDEST,
-		"	fstt AL\n", },
+		"	fst AL\n", },
 
 { ASSIGN,	FOREFF,
 	SNAME|SOREG,	TLDOUBLE,
@@ -1087,7 +1211,7 @@
 { UMUL,	INLL,
 	SANY,	TANY,
 	SOREG,	TLL,
-		NCREG|NCSL,	RESC1,
+		NCREG,	RESC1,
 		"	movl UL,U1\n	movl AL,A1\n", },
 
 { UMUL,	INAREG,
@@ -1241,7 +1365,7 @@
 		0,	RNOP,
 		"	jmp LL\n", },
 
-#ifdef GCC_COMPAT
+#if defined(GCC_COMPAT) || defined(LANG_F77)
 { GOTO, 	FOREFF,
 	SAREG,	TANY,
 	SANY,	TANY,
@@ -1252,12 +1376,36 @@
 /*
  * Convert LTYPE to reg.
  */
+{ OPLTYPE,	FORCC|INLL,
+	SCREG,	TLL,
+	SMIXOR,	TANY,
+		NCREG,	RESC1,
+		"	xorl U1,U1\n	xorl A1,A1\n", },
+
+{ OPLTYPE,	FORCC|INLL,
+	SCREG,	TLL,
+	SMILWXOR,	TANY,
+		NCREG,	RESC1,
+		"	movl UL,U1\n	xorl A1,A1\n", },
+
+{ OPLTYPE,	FORCC|INLL,
+	SCREG,	TLL,
+	SMIHWXOR,	TANY,
+		NCREG,	RESC1,
+		"	xorl U1,U1\n	movl AL,A1\n", },
+
 { OPLTYPE,	INLL,
 	SANY,	TANY,
 	SCREG|SCON|SOREG|SNAME,	TLL,
 		NCREG,	RESC1,
 		"	movl UL,U1\n	movl AL,A1\n", },
 
+{ OPLTYPE,	FORCC|INAREG,
+	SAREG,	TWORD|TPOINT,
+	SMIXOR,	TANY,
+		NAREG|NASL,	RESC1,
+		"	xorl A1,A1\n", },
+
 { OPLTYPE,	INAREG,
 	SANY,	TANY,
 	SAREG|SCON|SOREG|SNAME,	TWORD|TPOINT,
@@ -1270,6 +1418,12 @@
 		NBREG,	RESC1,
 		"	movb AL,A1\n", },
 
+{ OPLTYPE,	FORCC|INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SMIXOR,	TANY,
+		NAREG,	RESC1,
+		"	xorw A1,A1\n", },
+
 { OPLTYPE,	INAREG,
 	SANY,	TANY,
 	SAREG|SOREG|SNAME|SCON,	TSHORT|TUSHORT,
Index: local2.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/i386/local2.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/i386/local2.c -L usr.bin/pcc/i386/local2.c -u -r1.1 -r1.2
--- usr.bin/pcc/i386/local2.c
+++ usr.bin/pcc/i386/local2.c
@@ -1,4 +1,4 @@
-/*	$Id: local2.c,v 1.89 2007/09/16 19:08:16 ragge Exp $	*/
+/*	$Id: local2.c,v 1.120 2008/12/14 18:26:43 ragge Exp $	*/
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -26,22 +26,18 @@
  * 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);
+#if defined(PECOFFABI) || defined(MACHOABI)
+#define EXPREFIX	"_"
+#else
+#define EXPREFIX	""
+#endif
 
-static int stkpos;
 
-void
-lineid(int l, char *fn)
-{
-	/* identify line l and file fn */
-	printf("#	line %d, file %s\n", l, fn);
-}
+static int stkpos;
 
 void
 deflab(int label)
@@ -59,16 +55,19 @@
 static void
 prtprolog(struct interpass_prolog *ipp, int addto)
 {
-	int i, j;
+	int i;
 
 	printf("	pushl %%ebp\n");
 	printf("	movl %%esp,%%ebp\n");
+#if defined(MACHOABI)
+	printf("	subl $8,%%esp\n");	/* 16-byte stack alignment */
+#endif
 	if (addto)
 		printf("	subl $%d,%%esp\n", addto);
-	for (i = ipp->ipp_regs, j = 0; i; i >>= 1, j++)
-		if (i & 1)
+	for (i = 0; i < MAXREGS; i++)
+		if (TESTBIT(ipp->ipp_regs, i))
 			fprintf(stdout, "	movl %s,-%d(%s)\n",
-			    rnames[j], regoff[j], rnames[FPREG]);
+			    rnames[i], regoff[i], rnames[FPREG]);
 }
 
 /*
@@ -77,17 +76,16 @@
 static int
 offcalc(struct interpass_prolog *ipp)
 {
-	int i, j, addto;
+	int i, addto;
 
 	addto = p2maxautooff;
 	if (addto >= AUTOINIT/SZCHAR)
 		addto -= AUTOINIT/SZCHAR;
-	for (i = ipp->ipp_regs, j = 0; i ; i >>= 1, j++) {
-		if (i & 1) {
+	for (i = 0; i < MAXREGS; i++)
+		if (TESTBIT(ipp->ipp_regs, i)) {
 			addto += SZINT/SZCHAR;
-			regoff[j] = addto;
+			regoff[i] = addto;
 		}
-	}
 	return addto;
 }
 
@@ -97,43 +95,61 @@
 	int addto;
 
 	ftype = ipp->ipp_type;
+
+#ifdef LANG_F77
 	if (ipp->ipp_vis)
 		printf("	.globl %s\n", ipp->ipp_name);
 	printf("	.align 4\n");
 	printf("%s:\n", ipp->ipp_name);
+#endif
 	/*
 	 * We here know what register to save and how much to 
 	 * add to the stack.
 	 */
 	addto = offcalc(ipp);
+#if defined(MACHOABI)
+	addto = (addto + 15) & ~15;	/* stack alignment */
+#endif
 	prtprolog(ipp, addto);
 }
 
 void
 eoftn(struct interpass_prolog *ipp)
 {
-	int i, j;
+	int i;
 
 	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)
+	for (i = 0; i < MAXREGS; i++)
+		if (TESTBIT(ipp->ipp_regs, i))
 			fprintf(stdout, "	movl -%d(%s),%s\n",
-			    regoff[j], rnames[FPREG], rnames[j]);
-			
-	}
+			    regoff[i], rnames[FPREG], rnames[i]);
 
 	/* struct return needs special treatment */
 	if (ftype == STRTY || ftype == UNIONTY) {
 		printf("	movl 8(%%ebp),%%eax\n");
 		printf("	leave\n");
-		printf("	ret $4\n");
+#ifdef os_win32
+		printf("	ret $%d\n", 4 + ipp->ipp_argstacksize);
+#else
+		printf("	ret $%d\n", 4);
+#endif
 	} else {
 		printf("	leave\n");
-		printf("	ret\n");
+#ifdef os_win32
+		if (ipp->ipp_argstacksize)
+			printf("	ret $%d\n", ipp->ipp_argstacksize);
+		else
+#endif
+			printf("	ret\n");
 	}
+
+#if defined(ELFABI)
+	printf("\t.size " EXPREFIX "%s,.-" EXPREFIX "%s\n", ipp->ipp_name,
+	    ipp->ipp_name);
+#endif
 }
 
 /*
@@ -211,7 +227,7 @@
 twollcomp(NODE *p)
 {
 	int o = p->n_op;
-	int s = getlab();
+	int s = getlab2();
 	int e = p->n_label;
 	int cb1, cb2;
 
@@ -250,58 +266,64 @@
 	deflab(s);
 }
 
-/*
- * Assign to a bitfield.
- * Clumsy at least, but what to do?
- */
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+	CONSZ val;
+
+	if (p->n_op == ASSIGN)
+		p = p->n_left;
+	switch (**cp) {
+	case 'S':
+		printf("%d", UPKFSZ(p->n_rval));
+		break;
+	case 'H':
+		printf("%d", UPKFOFF(p->n_rval));
+		break;
+	case 'M':
+	case 'N':
+		val = (CONSZ)1 << UPKFSZ(p->n_rval);
+		--val;
+		val <<= UPKFOFF(p->n_rval);
+		printf("0x%llx", (**cp == 'M' ? val : ~val) & 0xffffffff);
+		break;
+	default:
+		comperr("fldexpand");
+	}
+	return 1;
+}
+
 static void
-bfasg(NODE *p)
+bfext(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");
+	int ch = 0, sz = 0;
+
+	if (ISUNSIGNED(p->n_right->n_type))
+		return;
+	switch (p->n_right->n_type) {
+	case CHAR:
+		ch = 'b';
+		sz = 8;
+		break;
+	case SHORT:
+		ch = 'w';
+		sz = 16;
+		break;
+	case INT:
+	case LONG:
+		ch = 'l';
+		sz = 32;
+		break;
+	default:
+		comperr("bfext");
 	}
 
-	/* 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");
+	sz -= UPKFSZ(p->n_left->n_rval);
+	printf("\tshl%c $%d,", ch, sz);
+	adrput(stdout, getlr(p, 'D'));
+	printf("\n\tsar%c $%d,", ch, sz);
+	adrput(stdout, getlr(p, 'D'));
+	printf("\n");
 }
 
 /*
@@ -318,7 +340,12 @@
 	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");
+#if defined(MACHOABI)
+	fprintf(fp, "	call L%s$stub\n", EXPREFIX "memcpy");
+	addstub(&stublist, "memcpy");
+#else
+	fprintf(fp, "	call %s\n", EXPREFIX "memcpy");
+#endif
 	fprintf(fp, "	addl $12,%%esp\n");
 }
 
@@ -375,12 +402,12 @@
 	int jmplab;
 
 	if (loadlab == 0) {
-		loadlab = getlab();
+		loadlab = getlab2();
 		expand(p, 0, "	.data\n");
 		printf(LABFMT ":	.long 0,0x80000000,0x403f\n", loadlab);
 		expand(p, 0, "	.text\n");
 	}
-	jmplab = getlab();
+	jmplab = getlab2();
 	expand(p, 0, "	pushl UL\n	pushl AL\n");
 	expand(p, 0, "	fildq (%esp)\n");
 	expand(p, 0, "	addl $8,%esp\n");
@@ -426,6 +453,8 @@
 		break;
 
 	case 'C':  /* remove from stack after subroutine call */
+		if (p->n_left->n_flags & FSTDCALL)
+			break;
 		pr = p->n_qual;
 		if (p->n_op == STCALL || p->n_op == USTCALL)
 			pr += 4;
@@ -439,8 +468,8 @@
 		twollcomp(p);
 		break;
 
-	case 'E': /* Assign to bitfield */
-		bfasg(p);
+	case 'E': /* Perform bitfield sign-extension */
+		bfext(p);
 		break;
 
 	case 'F': /* Structure argument */
@@ -491,7 +520,8 @@
 		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]);
+		printf("\tcall " EXPREFIX "__%sdi3\n\taddl $%d,%s\n",
+			ch, pr, rnames[ESP]);
                 break;
 
 	case 'P': /* push hidden argument on stack */
@@ -508,7 +538,12 @@
 		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");
+#if defined(MACHOABI)
+		printf("\tcall L%s$stub\n", EXPREFIX "memcpy");
+		addstub(&stublist, "memcpy");
+#else
+		printf("\tcall %s\n", EXPREFIX "memcpy");
+#endif
 		printf("\taddl $12,%%esp\n");
 		break;
 
@@ -578,7 +613,7 @@
 	int o = p->n_op;
 
 	if (o==NAME || o==REG || o==ICON || o==OREG ||
-	    (o==UMUL && shumul(p->n_left)))
+	    (o==UMUL && shumul(p->n_left, SOREG)))
 		return(1);
 	return(0);
 }
@@ -593,7 +628,7 @@
 
 	if (o == OREG || o == REG || o == NAME)
 		return SRDIR; /* Direct match */
-	if (o == UMUL && shumul(p->n_left))
+	if (o == UMUL && shumul(p->n_left, SOREG))
 		return SROREG; /* Convert into oreg */
 	return SRREG; /* put it into a register */
 }
@@ -717,6 +752,8 @@
 
 	case OREG:
 		r = p->n_rval;
+		if (p->n_name[0])
+			printf("%s%s", p->n_name, p->n_lval ? "+" : "");
 		if (p->n_lval)
 			fprintf(io, "%d", (int)p->n_lval);
 		if (R2TEST(r)) {
@@ -726,12 +763,23 @@
 			fprintf(io, "(%s)", rnames[p->n_rval]);
 		return;
 	case ICON:
+#ifdef PCC_DEBUG
+		/* Sanitycheck for PIC, to catch adressable constants */
+		if (kflag && p->n_name[0] && 0) {
+			static int foo;
+
+			if (foo++ == 0) {
+				printf("\nfailing...\n");
+				fwalk(p, e2print, 0);
+				comperr("pass2 conput");
+			}
+		}
+#endif
 		/* addressable value of the constant */
 		fputc('$', io);
 		conput(io, p);
 		return;
 
-	case MOVE:
 	case REG:
 		switch (p->n_type) {
 		case LONGLONG:
@@ -780,7 +828,7 @@
 }
 
 static void
-fixcalls(NODE *p)
+fixcalls(NODE *p, void *arg)
 {
 	/* Prepare for struct return by allocating bounce space on stack */
 	switch (p->n_op) {
@@ -844,7 +892,7 @@
 	DLIST_FOREACH(ip, ipole, qelem) {
 		if (ip->type != IP_NODE)
 			continue;
-		walkf(ip->ip_node, fixcalls);
+		walkf(ip->ip_node, fixcalls, 0);
 		storefloat(ip, ip->ip_node);
 	}
 	if (stkpos > p2autooff)
@@ -859,7 +907,7 @@
  * Remove some PCONVs after OREGs are created.
  */
 static void
-pconv2(NODE *p)
+pconv2(NODE *p, void *arg)
 {
 	NODE *q;
 
@@ -884,7 +932,7 @@
 void
 mycanon(NODE *p)
 {
-	walkf(p, pconv2);
+	walkf(p, pconv2, 0);
 }
 
 void
@@ -1026,6 +1074,22 @@
 	for (p = p->n_right; p->n_op == CM; p = p->n_left)
 		size += argsiz(p->n_right);
 	size += argsiz(p);
+#if defined(ELFABI)
+	if (kflag)
+		size -= 4;
+#endif
+
+	
+#if defined(MACHOABI)
+	int newsize = (size + 15) & ~15;	/* stack alignment */
+	int align = newsize-size;
+
+	if (align != 0)
+		printf("	subl $%d,%%esp\n", align);
+
+	size=newsize;
+#endif
+	
 	op->n_qual = size; /* XXX */
 }
 
@@ -1047,6 +1111,177 @@
 		    p->n_lval < 0 || p->n_lval > 0x7fffffff)
 			break;
 		return SRDIR;
+	case SMIXOR:
+		return tshape(p, SZERO);
+	case SMILWXOR:
+		if (o != ICON || p->n_name[0] ||
+		    p->n_lval == 0 || p->n_lval & 0xffffffff)
+			break;
+		return SRDIR;
+	case SMIHWXOR:
+		if (o != ICON || p->n_name[0] ||
+		     p->n_lval == 0 || (p->n_lval >> 32) != 0)
+			break;
+		return SRDIR;
 	}
 	return SRNOPE;
 }
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+
+/*
+ * Do something target-dependent for xasm arguments.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+	struct interpass *ip2;
+	NODE *in = 0, *ut = 0;
+	TWORD t;
+	char *w;
+	int reg;
+	int cw;
+
+	cw = xasmcode(p->n_name);
+	if (cw & (XASMASG|XASMINOUT))
+		ut = p->n_left;
+	if ((cw & XASMASG) == 0)
+		in = p->n_left;
+
+	switch (XASMVAL(cw)) {
+	case 'D': reg = EDI; break;
+	case 'S': reg = ESI; break;
+	case 'a': reg = EAX; break;
+	case 'b': reg = EBX; break;
+	case 'c': reg = ECX; break;
+	case 'd': reg = EDX; break;
+	case 't': reg = 0; break;
+	case 'u': reg = 1; break;
+	case 'A': reg = EAXEDX; break;
+	case 'q': /* XXX let it be CLASSA as for now */
+		p->n_name = tmpstrdup(p->n_name);
+		w = strchr(p->n_name, 'q');
+		*w = 'r';
+		return 0;
+	default:
+		return 0;
+	}
+	p->n_name = tmpstrdup(p->n_name);
+	for (w = p->n_name; *w; w++)
+		;
+	w[-1] = 'r'; /* now reg */
+	t = p->n_left->n_type;
+	if (reg == EAXEDX) {
+		p->n_label = CLASSC;
+	} else {
+		p->n_label = CLASSA;
+		if (t == CHAR || t == UCHAR) {
+			p->n_label = CLASSB;
+			reg = reg * 2 + 8;
+		}
+	}
+	if (t == FLOAT || t == DOUBLE || t == LDOUBLE) {
+		p->n_label = CLASSD;
+		reg += 037;
+	}
+
+	if (in && ut)
+		in = tcopy(in);
+	p->n_left = mklnode(REG, 0, reg, t);
+	if (ut) {
+		ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
+		DLIST_INSERT_AFTER(ip, ip2, qelem);
+	}
+	if (in) {
+		ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
+		DLIST_INSERT_BEFORE(ip, ip2, qelem);
+	}
+	return 1;
+}
+
+void
+targarg(char *w, void *arg)
+{
+	NODE **ary = arg;
+	NODE *p, *q;
+
+	p = ary[(int)w[1]-'0']->n_left;
+	if (optype(p->n_op) != LTYPE)
+		comperr("bad xarg op %d", p->n_op);
+	q = tcopy(p);
+	if (q->n_op == REG) {
+		if (*w == 'k') {
+			q->n_type = INT;
+		} else if (*w != 'w') {
+			if (q->n_type > UCHAR) {
+				regno(q) = regno(q)*2+8;
+				if (*w == 'h')
+					regno(q)++;
+			}
+			q->n_type = INT;
+		} else
+			q->n_type = SHORT;
+	}
+	adrput(stdout, q);
+	tfree(q);
+}
+
+/*
+ * target-specific conversion of numeric arguments.
+ */
+int
+numconv(void *ip, void *p1, void *q1)
+{
+	NODE *p = p1, *q = q1;
+	int cw = xasmcode(q->n_name);
+
+	switch (XASMVAL(cw)) {
+	case 'a':
+	case 'b':
+	case 'c':
+	case 'd':
+		p->n_name = tmpcalloc(2);
+		p->n_name[0] = XASMVAL(cw);
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static struct {
+	char *name; int num;
+} xcr[] = {
+	{ "eax", EAX },
+	{ "ebx", EBX },
+	{ "ecx", ECX },
+	{ "edx", EDX },
+	{ "ax", EAX },
+	{ "bx", EBX },
+	{ "cx", ECX },
+	{ "dx", EDX },
+	{ NULL, 0 },
+};
+
+/*
+ * Check for other names of the xasm constraints registers.
+ */
+
+/*
+ * Check for other names of the xasm constraints registers.
+ */
+int xasmconstregs(char *s)
+{
+	int i;
+
+	for (i = 0; xcr[i].name; i++)
+		if (strcmp(xcr[i].name, s) == 0)
+			return xcr[i].num;
+	return -1;
+}
+
Index: code.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/i386/code.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/i386/code.c -L usr.bin/pcc/i386/code.c -u -r1.1 -r1.2
--- usr.bin/pcc/i386/code.c
+++ usr.bin/pcc/i386/code.c
@@ -1,4 +1,4 @@
-/*	$Id: code.c,v 1.15 2007/07/06 17:02:27 ragge Exp $	*/
+/*	$Id: code.c,v 1.38 2008/12/14 17:20:58 ragge Exp $	*/
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -29,37 +29,62 @@
 
 # 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);
-}
+int lastloc = -1;
 
 /*
- * define the current location as the name p->sname
- * never called for text segment.
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
  */
 void
-defnam(struct symtab *p)
+defloc(struct symtab *sp)
 {
-	char *c = p->sname;
+	extern char *nextsect;
+#if defined(ELFABI) || defined(PECOFFABI)
+	static char *loctbl[] = { "text", "data", "section .rodata" };
+#elif defined(MACHOABI)
+	static char *loctbl[] = { "text", "data", "const_data" };
+#endif
+	TWORD t;
+	int s;
 
-#ifdef GCC_COMPAT
-	c = gcc_findname(p);
+	if (sp == NULL) {
+		lastloc = -1;
+		return;
+	}
+	t = sp->stype;
+	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+#ifdef TLS
+	if (sp->sflags & STLS) {
+		if (s != DATA)
+			cerror("non-data symbol in tls section");
+		nextsect = ".tdata";
+	}
+#endif
+	if (sp->ssue->suesection)
+		nextsect = sp->ssue->suesection;
+	if (nextsect) {
+		printf("	.section %s\n", nextsect);
+		nextsect = NULL;
+		s = -1;
+	} else if (s != lastloc)
+		printf("	.%s\n", loctbl[s]);
+	lastloc = s;
+	while (ISARY(t))
+		t = DECREF(t);
+	if (sp->ssue->suealign > ALCHAR)
+		printf("	.align %d\n", sp->ssue->suealign/ALCHAR);
+	if (sp->sclass == EXTDEF)
+		printf("	.globl %s\n", exname(sp->soname));
+#if defined(ELFABI)
+	if (ISFTN(t))
+		printf("\t.type %s, at function\n", exname(sp->soname));
 #endif
-	if (p->sclass == EXTDEF)
-		printf("	.globl %s\n", c);
-	printf("%s:\n", c);
+	if (sp->slevel == 0)
+		printf("%s:\n", exname(sp->soname));
+	else
+		printf(LABFMT ":\n", sp->soffset);
 }
 
-
 /*
  * code for the end of a function
  * deals with struct return here
@@ -67,27 +92,21 @@
 void
 efcode()
 {
+	extern int gotnr;
 	NODE *p, *q;
-	int sz;
 
+	gotnr = 0;	/* new number for next fun */
 	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));
+	/* Create struct assignment */
+	q = block(OREG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
 	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);
+	q = buildtree(UMUL, q, NIL);
+	p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
+	p = buildtree(UMUL, p, NIL);
+	p = buildtree(ASSIGN, q, p);
+	ecomp(p);
 }
 
 /*
@@ -95,15 +114,86 @@
  * indices in symtab for the arguments; n is the number
  */
 void
-bfcode(struct symtab **a, int n)
+bfcode(struct symtab **sp, int cnt)
 {
+#ifdef os_win32
+	extern int argstacksize;
+#endif
+	struct symtab *sp2;
+	extern int gotnr;
+	NODE *n, *p;
 	int i;
 
-	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+		/* Function returns struct, adjust arg offset */
+		for (i = 0; i < cnt; i++) 
+			sp[i]->soffset += SZPOINT(INT);
+	}
+
+#ifdef os_win32
+	/*
+	 * Count the arguments and mangle name in symbol table as a callee.
+	 */
+	argstacksize = 0;
+	if (cftnsp->sflags & SSTDCALL) {
+		char buf[64];
+		for (i = 0; i < cnt; i++) {
+			TWORD t = sp[i]->stype;
+			if (t == STRTY || t == UNIONTY)
+				argstacksize += sp[i]->ssue->suesize;
+			else
+				argstacksize += szty(t) * SZINT / SZCHAR;
+		}
+		snprintf(buf, 64, "%s@%d", cftnsp->soname, argstacksize);
+		cftnsp->soname = newstring(buf, strlen(buf));
+	}
+#endif
+
+	if (kflag) {
+#define	STL	100
+		char *str = inlalloc(STL);
+#if !defined(MACHOABI)
+		int l = getlab();
+#endif
+
+		/* Generate extended assembler for PIC prolog */
+		p = tempnode(0, INT, 0, MKSUE(INT));
+		gotnr = regno(p);
+		p = block(XARG, p, NIL, INT, 0, MKSUE(INT));
+		p->n_name = "=g";
+		p = block(XASM, p, bcon(0), INT, 0, MKSUE(INT));
+#if defined(MACHOABI)
+		if (snprintf(str, STL, "call L%s$pb\nL%s$pb:\n\tpopl %%0\n",
+		    cftnsp->sname, cftnsp->sname) >= STL)
+			cerror("bfcode");
+#else
+		if (snprintf(str, STL,
+		    "call " LABFMT "\n" LABFMT ":\n	popl %%0\n"
+		    "	addl $_GLOBAL_OFFSET_TABLE_+[.-" LABFMT "], %%0\n",
+		    l, l, l) >= STL)
+			cerror("bfcode");
+#endif
+		p->n_name = str;
+		p->n_right->n_type = STRTY;
+		ecomp(p);
+	}
+	if (xtemps == 0)
 		return;
-	/* Function returns struct, adjust arg offset */
-	for (i = 0; i < n; i++)
-		a[i]->soffset += SZPOINT(INT);
+
+	/* put arguments in temporaries */
+	for (i = 0; i < cnt; i++) {
+		if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY ||
+		    cisreg(sp[i]->stype) == 0)
+			continue;
+		if (cqual(sp[i]->stype, sp[i]->squal) & VOL)
+			continue;
+		sp2 = sp[i];
+		n = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->ssue);
+		n = buildtree(ASSIGN, n, nametree(sp2));
+		sp[i]->soffset = regno(n->n_left);
+		sp[i]->sflags |= STNODE;
+		ecomp(n);
+	}
 }
 
 
@@ -116,60 +206,97 @@
 	SETOFF(autooff, SZINT);
 }
 
+#if defined(MACHOABI)
+struct stub stublist;
+struct stub nlplist;
+#endif
+
 /* called just before final exit */
 /* flag is 1 if errors, 0 if none */
 void
 ejobcode(int flag )
 {
+#if defined(MACHOABI)
+	/*
+	 * iterate over the stublist and output the PIC stubs
+`	 */
+	if (kflag) {
+		struct stub *p;
+
+		DLIST_FOREACH(p, &stublist, link) {
+			printf("\t.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5\n");
+			printf("L%s$stub:\n", p->name);
+			printf("\t.indirect_symbol %s\n", exname(p->name));
+			printf("\thlt ; hlt ; hlt ; hlt ; hlt\n");
+			printf("\t.subsections_via_symbols\n");
+		}
+
+		printf("\t.section __IMPORT,__pointers,non_lazy_symbol_pointers\n");
+		DLIST_FOREACH(p, &nlplist, link) {
+			printf("L%s$non_lazy_ptr:\n", p->name);
+			printf("\t.indirect_symbol %s\n", exname(p->name));
+			printf("\t.long 0\n");
+	        }
+
+	}
+#endif
+
+#define _MKSTR(x) #x
+#define MKSTR(x) _MKSTR(x)
+#define OS MKSTR(TARGOS)
+        printf("\t.ident \"PCC: %s (%s)\"\n", PACKAGE_STRING, OS);
 }
 
 void
 bjobcode()
 {
+#if defined(MACHOABI)
+	DLIST_INIT(&stublist, link);
+	DLIST_INIT(&nlplist, link);
+#endif
 }
 
 /*
- * Print character t at position i in one string, until t == -1.
- * Locctr & label is already defined.
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ * Returns p.
  */
-void
-bycode(int t, int i)
+NODE *
+funcode(NODE *p)
 {
-	static	int	lastoctal = 0;
-
-	/* put byte i+1 in a string */
+	extern int gotnr;
+	NODE *r, *l;
 
-	if (t < 0) {
-		if (i != 0)
-			puts("\"");
+	/* 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 = 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) {
+		l = talloc();
+		*l = *r;
+		r->n_op = FUNARG;
+		r->n_left = l;
+		r->n_type = l->n_type;
+	}
+	if (kflag == 0)
+		return p;
+#if defined(ELFABI)
+	/* Create an ASSIGN node for ebx */
+	l = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+	l->n_rval = EBX;
+	l = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, MKSUE(INT)));
+	if (p->n_right->n_op != CM) {
+		p->n_right = block(CM, l, p->n_right, INT, 0, MKSUE(INT));
 	} 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);
-		}
+		for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
+			;
+		r->n_left = block(CM, l, r->n_left, INT, 0, MKSUE(INT));
 	}
-}
-
-/*
- * n integer words of zeros
- */
-void
-zecode(int n)
-{
-	printf("	.zero %d\n", n * (SZINT/SZCHAR));
-//	inoff += n * SZINT;
+#endif
+	return p;
 }
 
 /*
@@ -188,26 +315,11 @@
 {
 }
 
-/* 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)
+int
+mygenswitch(int num, TWORD type, 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);
+	return 0;
 }
Index: local.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/i386/local.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/i386/local.c -L usr.bin/pcc/i386/local.c -u -r1.1 -r1.2
--- usr.bin/pcc/i386/local.c
+++ usr.bin/pcc/i386/local.c
@@ -1,4 +1,4 @@
-/*	$Id: local.c,v 1.56 2007/09/24 16:23:36 ragge Exp $	*/
+/*	$Id: local.c,v 1.95 2008/12/23 06:51:21 gmcgarry Exp $	*/
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -31,6 +31,277 @@
 
 /*	this file contains code which is dependent on the target machine */
 
+/*
+ * Check if a constant is too large for a type.
+ */
+static int
+toolarge(TWORD t, CONSZ con)
+{
+	U_CONSZ ucon = con;
+
+	switch (t) {
+	case ULONGLONG:
+	case LONGLONG:
+		break; /* cannot be too large */
+#define	SCHK(i)	case i: if (con > MAX_##i || con < MIN_##i) return 1; break
+#define	UCHK(i)	case i: if (ucon > MAX_##i) return 1; break
+	SCHK(INT);
+	SCHK(SHORT);
+	case BOOL:
+	SCHK(CHAR);
+	UCHK(UNSIGNED);
+	UCHK(USHORT);
+	UCHK(UCHAR);
+	default:
+		cerror("toolarge");
+	}
+	return 0;
+}
+
+#if defined(MACHOABI)
+
+/*
+ *  Keep track of PIC stubs.
+ */
+
+void
+addstub(struct stub *list, char *name)
+{
+        struct stub *s;
+
+        DLIST_FOREACH(s, list, link) {
+                if (strcmp(s->name, name) == 0)
+                        return;
+        }
+
+        s = permalloc(sizeof(struct stub));
+        s->name = permalloc(strlen(name) + 1);
+        strcpy(s->name, name);
+        DLIST_INSERT_BEFORE(list, s, link);
+}
+
+#endif
+
+#define	IALLOC(sz)	(isinlining ? permalloc(sz) : tmpalloc(sz))
+
+#ifndef os_win32
+/*
+ * Make a symtab entry for PIC use.
+ */
+static struct symtab *
+picsymtab(char *p, char *s, char *s2)
+{
+	struct symtab *sp = IALLOC(sizeof(struct symtab));
+	size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
+	
+	sp->sname = sp->soname = IALLOC(len);
+	strlcpy(sp->soname, p, len);
+	strlcat(sp->soname, s, len);
+	strlcat(sp->soname, s2, len);
+	sp->sclass = EXTERN;
+	sp->sflags = sp->slevel = 0;
+	return sp;
+}
+#endif
+
+int gotnr; /* tempnum for GOT register */
+int argstacksize;
+
+/*
+ * Create a reference for an extern variable.
+ */
+static NODE *
+picext(NODE *p)
+{
+
+#if defined(ELFABI)
+
+	NODE *q, *r;
+	struct symtab *sp;
+
+	q = tempnode(gotnr, PTR|VOID, 0, MKSUE(VOID));
+	sp = picsymtab("", p->n_sp->soname, "@GOT");
+	r = xbcon(0, sp, INT);
+	q = buildtree(PLUS, q, r);
+	q = block(UMUL, q, 0, PTR|VOID, 0, MKSUE(VOID));
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_sue);
+	q->n_sp = p->n_sp; /* for init */
+	nfree(p);
+	return q;
+
+#elif defined(MACHOABI)
+
+	NODE *q, *r;
+	struct symtab *sp;
+	char buf2[64];
+
+	if (p->n_sp->sclass == EXTDEF) {
+		snprintf(buf2, 64, "-L%s$pb", cftnsp->soname);
+		sp = picsymtab("", exname(p->n_sp->soname), buf2);
+	} else {
+		snprintf(buf2, 64, "$non_lazy_ptr-L%s$pb", cftnsp->soname);
+		sp = picsymtab("L", p->n_sp->soname, buf2);
+		addstub(&nlplist, p->n_sp->soname);
+	}
+	q = tempnode(gotnr, PTR+VOID, 0, MKSUE(VOID));
+	r = xbcon(0, sp, INT);
+	q = buildtree(PLUS, q, r);
+
+	if (p->n_sp->sclass != EXTDEF)
+		q = block(UMUL, q, 0, PTR+VOID, 0, MKSUE(VOID));
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_sue);
+	q->n_sp = p->n_sp; /* for init */
+	nfree(p);
+	return q;
+
+#elif defined(PECOFFABI)
+
+	return p;
+
+#endif
+
+}
+
+/*
+ * Create a reference for a static variable.
+ */
+static NODE *
+picstatic(NODE *p)
+{
+
+#if defined(ELFABI)
+
+	NODE *q, *r;
+	struct symtab *sp;
+
+	q = tempnode(gotnr, PTR|VOID, 0, MKSUE(VOID));
+	if (p->n_sp->slevel > 0) {
+		char buf[32];
+		snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset);
+		sp = picsymtab("", buf, "@GOTOFF");
+	} else
+		sp = picsymtab("", p->n_sp->soname, "@GOTOFF");
+	sp->sclass = STATIC;
+	sp->stype = p->n_sp->stype;
+	r = xbcon(0, sp, INT);
+	q = buildtree(PLUS, q, r);
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_sue);
+	q->n_sp = p->n_sp; /* for init */
+	nfree(p);
+	return q;
+
+#elif defined(MACHOABI)
+
+	NODE *q, *r;
+	struct symtab *sp;
+	char buf2[64];
+
+	snprintf(buf2, 64, "-L%s$pb", cftnsp->soname);
+
+	if (p->n_sp->slevel > 0) {
+		char buf1[64];
+		snprintf(buf1, 64, LABFMT, (int)p->n_sp->soffset);
+		sp = picsymtab("", buf1, buf2);
+		sp->sflags |= SNOUNDERSCORE;
+	} else  {
+		sp = picsymtab("", exname(p->n_sp->soname), buf2);
+	}
+	sp->sclass = STATIC;
+	sp->stype = p->n_sp->stype;
+	q = tempnode(gotnr, PTR+VOID, 0, MKSUE(VOID));
+	r = xbcon(0, sp, INT);
+	q = buildtree(PLUS, q, r);
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_sue);
+	q->n_sp = p->n_sp;
+	nfree(p);
+	return q;
+
+#elif defined(PECOFFABI)
+
+	return p;
+
+#endif
+
+}
+
+#ifdef TLS
+/*
+ * Create a reference for a TLS variable.
+ */
+static NODE *
+tlspic(NODE *p)
+{
+	NODE *q, *r;
+	struct symtab *sp, *sp2;
+
+	/*
+	 * creates:
+	 *   leal var at TLSGD(%ebx),%eax
+	 *   call ___tls_get_addr at PLT
+	 */
+
+	/* calc address of var at TLSGD */
+	q = tempnode(gotnr, PTR|VOID, 0, MKSUE(VOID));
+	sp = picsymtab("", p->n_sp->soname, "@TLSGD");
+	r = xbcon(0, sp, INT);
+	q = buildtree(PLUS, q, r);
+
+	/* assign to %eax */
+	r = block(REG, NIL, NIL, PTR|VOID, 0, MKSUE(VOID));
+	r->n_rval = EAX;
+	q = buildtree(ASSIGN, r, q);
+
+	/* call ___tls_get_addr */
+	sp2 = lookup("___tls_get_addr at PLT", 0);
+	sp2->stype = EXTERN|INT|FTN;
+	r = nametree(sp2);
+	r = buildtree(ADDROF, r, NIL);
+	r = block(UCALL, r, NIL, INT, 0, MKSUE(INT));
+
+	/* fusion both parts together */
+	q = buildtree(COMOP, q, r);
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_sue);
+	q->n_sp = p->n_sp; /* for init */
+
+	nfree(p);
+	return q;
+}
+
+static NODE *
+tlsnonpic(NODE *p)
+{
+	NODE *q, *r;
+	struct symtab *sp, *sp2;
+	int ext = p->n_sp->sclass;
+
+	sp = picsymtab("", p->n_sp->soname,
+	    ext == EXTERN ? "@INDNTPOFF" : "@NTPOFF");
+	q = xbcon(0, sp, INT);
+	if (ext == EXTERN)
+		q = block(UMUL, q, NIL, PTR|VOID, 0, MKSUE(VOID));
+
+	sp2 = lookup("%gs:0", 0);
+	sp2->stype = EXTERN|INT;
+	r = nametree(sp2);
+
+	q = buildtree(PLUS, q, r);
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_sue);
+	q->n_sp = p->n_sp; /* for init */
+
+	nfree(p);
+	return q;
+}
+
+static NODE *
+tlsref(NODE *p)
+{
+	if (kflag)
+		return (tlspic(p));
+	else
+		return (tlsnonpic(p));
+}
+#endif
+
 /* clocal() is called to do local transformations on
  * an expression tree preparitory to its being
  * written out in intermediate code.
@@ -75,11 +346,23 @@
 			p = stref(block(STREF, r, p, 0, 0, 0));
 			break;
 
+		case USTATIC:
+			if (kflag == 0)
+				break;
+			/* FALLTHROUGH */
 		case STATIC:
-			if (q->slevel == 0)
+#ifdef TLS
+			if (q->sflags & STLS) {
+				p = tlsref(p);
 				break;
-			p->n_lval = 0;
-			p->n_sp = q;
+			}
+#endif
+			if (kflag == 0) {
+				if (q->slevel == 0)
+					break;
+				p->n_lval = 0;
+			} else if (blevel > 0)
+				p = picstatic(p);
 			break;
 
 		case REGISTER:
@@ -88,31 +371,72 @@
 			p->n_rval = q->soffset;
 			break;
 
+		case EXTERN:
+		case EXTDEF:
+#ifdef TLS
+			if (q->sflags & STLS) {
+				p = tlsref(p);
+				break;
 			}
+#endif
+			if (kflag == 0)
+				break;
+			if (blevel > 0)
+				p = picext(p);
+			break;
+		}
 		break;
 
-	case STCALL:
+	case ADDROF:
+		if (kflag == 0 || blevel == 0)
+			break;
+		/* char arrays may end up here */
+		l = p->n_left;
+		if (l->n_op != NAME ||
+		    (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE))
+			break;
+		l = p;
+		p = picstatic(p->n_left);
+		nfree(l);
+		if (p->n_op != UMUL)
+			cerror("ADDROF error");
+		l = p;
+		p = p->n_left;
+		nfree(l);
+		break;
+
+	case UCALL:
+	case USTCALL:
+		if (kflag == 0)
+			break;
+#if defined(ELFABI)
+		/* Change to CALL node with ebx as argument */
+		l = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+		l->n_rval = EBX;
+		p->n_right = buildtree(ASSIGN, l,
+		    tempnode(gotnr, INT, 0, MKSUE(INT)));
+		p->n_op -= (UCALL-CALL);
+#endif
+	
+	/* FALLTHROUGH */
+#if defined(MACHOABI)
 	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;
-		}
+	case STCALL:
+		if (p->n_type == VOID)
+			break;
+
+		r = tempnode(0, p->n_type, p->n_df, p->n_sue);
+		l = tcopy(r);
+		p = buildtree(COMOP, buildtree(ASSIGN, r, p), l);
+#endif
+			
 		break;
-		
+
 	case CBRANCH:
 		l = p->n_left;
 
 		/*
-		 * Remove unneccessary conversion ops.
+		 * Remove unnecessary conversion ops.
 		 */
 		if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
 			if (coptype(l->n_op) != BITYPE)
@@ -121,6 +445,10 @@
 				r = l->n_left->n_left;
 				if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
 					break;
+				if (ISPTR(r->n_type))
+					break; /* no opt for pointers */
+				if (toolarge(r->n_type, l->n_right->n_lval))
+					break;
 				/* Type must be correct */
 				t = r->n_type;
 				nfree(l->n_left);
@@ -222,8 +550,6 @@
 			case UNSIGNED:
 				l->n_lval = val & 0xffffffff;
 				break;
-			case ENUMTY:
-			case MOETY:
 			case LONG:
 			case INT:
 				l->n_lval = (int)val;
@@ -249,6 +575,14 @@
 			l->n_sue = MKSUE(m);
 			nfree(p);
 			return l;
+		} else if (l->n_op == FCON) {
+			l->n_lval = l->n_dcon;
+			l->n_sp = NULL;
+			l->n_op = ICON;
+			l->n_type = m;
+			l->n_sue = MKSUE(m);
+			nfree(p);
+			return clocal(l);
 		}
 		if (DEUNSIGN(p->n_type) == SHORT &&
 		    DEUNSIGN(l->n_type) == SHORT) {
@@ -280,9 +614,10 @@
 
 	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));
+		r = p;
+		p = buildtree(o == PMCONV ? MUL : DIV, p->n_left, p->n_right);
+		nfree(r);
+		break;
 
 	case FORCE:
 		/* put return value in return reg */
@@ -297,8 +632,6 @@
 	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,
@@ -320,16 +653,115 @@
 	return(p);
 }
 
+/*
+ * Change CALL references to either direct (static) or PLT.
+ */
+static void
+fixnames(NODE *p, void *arg)
+{
+#if !defined(PECOFFABI)
+
+	struct symtab *sp;
+	struct suedef *sue;
+	NODE *q;
+	char *c;
+	int isu;
+
+	if ((cdope(p->n_op) & CALLFLG) == 0)
+		return;
+	isu = 0;
+	q = p->n_left;
+	sue = q->n_sue;
+	if (q->n_op == UMUL)
+		q = q->n_left, isu = 1;
+
+	if (q->n_op == PLUS && q->n_left->n_op == TEMP &&
+	    q->n_right->n_op == ICON) {
+		sp = q->n_right->n_sp;
+
+		if (sp == NULL)
+			return;	/* nothing to do */
+		if (sp->sclass == STATIC && !ISFTN(sp->stype))
+			return; /* function pointer */
+
+		if (sp->sclass != STATIC && sp->sclass != EXTERN &&
+		    sp->sclass != EXTDEF)
+			cerror("fixnames");
+
+#if defined(ELFABI)
+
+		if ((c = strstr(sp->soname, "@GOT")) == NULL)
+			cerror("fixnames2");
+		if (isu) {
+			memcpy(c, "@PLT", sizeof("@PLT"));
+		} else
+			*c = 0;
+
+#elif defined(MACHOABI)
+
+		if ((c = strstr(sp->soname, "$non_lazy_ptr")) == NULL &&
+		    (c = strstr(sp->soname, "-L")) == NULL)
+				cerror("fixnames2");
+		if (isu) {
+			*c = 0;
+			addstub(&stublist, sp->soname+1);
+			strcpy(c, "$stub");
+		} else 
+			*c = 0;
+
+#endif
+
+		nfree(q->n_left);
+		q = q->n_right;
+		if (isu)
+			nfree(p->n_left->n_left);
+		nfree(p->n_left);
+		p->n_left = q;
+		q->n_sue = sue;
+	}
+#endif
+}
+
 void
 myp2tree(NODE *p)
 {
+	struct symtab *sp;
+
+	if (kflag)
+		walkf(p, fixnames, 0); /* XXX walkf not needed */
+	if (p->n_op != FCON)
+		return;
+
+#if 0
+	/* put floating constants in memory */
+	setloc1(RDATA);
+	defalign(ALLDOUBLE);
+	deflab1(i = getlab());
+	ninval(0, btdims[p->n_type].suesize, p);
+#endif
+
+	sp = IALLOC(sizeof(struct symtab));
+	sp->sclass = STATIC;
+	sp->ssue = MKSUE(p->n_type);
+	sp->slevel = 1; /* fake numeric label */
+	sp->soffset = getlab();
+	sp->sflags = 0;
+	sp->stype = p->n_type;
+	sp->squal = (CON >> TSHIFT);
+
+	defloc(sp);
+	ninval(0, sp->ssue->suesize, p);
+
+	p->n_op = NAME;
+	p->n_lval = 0;
+	p->n_sp = sp;
 }
 
 /*ARGSUSED*/
 int
 andable(NODE *p)
 {
-	return(1);  /* all names can have & taken on them */
+	return(1);	/* all names can have & taken on them */
 }
 
 /*
@@ -403,47 +835,38 @@
 
 }
 
-#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.
+ * sequences.
  */
 void
-instring(char *str)
+instring(struct symtab *sp)
 {
-	char *s;
+	char *s, *str = sp->sname;
+
+#if defined(ELFABI) || defined(PECOFFABI)
+
+	defloc(sp);
+
+#elif defined(MACHOABI)
+
+	extern int lastloc;
+	if (lastloc != STRNG)
+		printf("	.cstring\n");
+	lastloc = STRNG;
+	printf("\t.p2align 2\n");
+	printf(LABFMT ":\n", sp->soffset);
 
-	/* be kind to assemblers and avoid long strings */
+#endif
+
+	/* 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) {
+		if (s - str > 60) {
 			fwrite(str, 1, s - str, stdout);
 			printf("\"\n\t.ascii \"");
 			str = s;
@@ -453,6 +876,28 @@
 	printf("\\0\"\n");
 }
 
+/*
+ * Print out a wide string by calling ninval().
+ */
+void
+inwstring(struct symtab *sp)
+{
+	char *s = sp->sname;
+	NODE *p;
+
+	defloc(sp);
+	p = xbcon(0, NULL, WCHAR_TYPE);
+	do {
+		if (*s++ == '\\')
+			p->n_lval = esccon(&s);
+		else
+			p->n_lval = (unsigned char)s[-1];
+		ninval(0, (MKSUE(WCHAR_TYPE))->suesize, p);
+	} while (s[-1] != 0);
+	nfree(p);
+}
+
+
 static int inbits, inval;
 
 /*
@@ -520,6 +965,9 @@
 {
 	union { float f; double d; long double l; int i[3]; } u;
 	struct symtab *q;
+#if defined(ELFABI) || defined(MACHOABI)
+	char *c;
+#endif
 	TWORD t;
 	int i;
 
@@ -527,6 +975,34 @@
 	if (t > BTMASK)
 		t = INT; /* pointer */
 
+	while (p->n_op == SCONV || p->n_op == PCONV) {
+		NODE *l = p->n_left;
+		l->n_type = p->n_type;
+		p = l;
+	}
+
+	if (kflag && (p->n_op == PLUS || p->n_op == UMUL)) {
+		if (p->n_op == UMUL)
+			p = p->n_left;
+		p = p->n_right;
+		q = p->n_sp;
+
+#if defined(ELFABI)
+
+		if ((c = strstr(q->soname, "@GOT")) != NULL)
+			*c = 0; /* ignore GOT ref here */
+
+#elif defined(MACHOABI)
+
+		if  ((c = strstr(q->soname, "$non_lazy_ptr")) != NULL) {
+			q->soname++;	/* skip "L" */
+			*c = 0; /* ignore GOT ref here */
+		}
+		else if ((c = strstr(q->soname, "-L")) != NULL)
+			*c = 0; /* ignore GOT ref here */
+
+#endif
+	}
 	if (p->n_op != ICON && p->n_op != FCON)
 		cerror("ninval: init node not constant");
 
@@ -547,17 +1023,26 @@
 	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) {
+			if ((q->sclass == STATIC && q->slevel > 0)) {
 				printf("+" LABFMT, q->soffset);
-			} else
-				printf("+%s", exname(q->sname));
+			} else {
+#if defined(MACHOABI)
+				if ((q->sflags & SNOUNDERSCORE) != 0)
+					printf("+%s", q->soname);
+				else
+#endif
+					printf("+%s", exname(q->soname));
+			}
 		}
 		printf("\n");
 		break;
 	case SHORT:
 	case USHORT:
+#ifdef os_sunos
+		printf("\t.2byte 0x%x\n", (int)p->n_lval & 0xffff);
+#else
 		printf("\t.short 0x%x\n", (int)p->n_lval & 0xffff);
+#endif
 		break;
 	case BOOL:
 		if (p->n_lval > 1)
@@ -570,11 +1055,20 @@
 	case LDOUBLE:
 		u.i[2] = 0;
 		u.l = (long double)p->n_dcon;
+#if defined(HOST_BIG_ENDIAN)
+		/* XXX probably broken on most hosts */
+		printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[2], u.i[1], u.i[0]);
+#else
 		printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+#endif
 		break;
 	case DOUBLE:
 		u.d = (double)p->n_dcon;
+#if defined(HOST_BIG_ENDIAN)
+		printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]);
+#else
 		printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+#endif
 		break;
 	case FLOAT:
 		u.f = (float)p->n_dcon;
@@ -585,49 +1079,33 @@
 	}
 }
 
-#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 defined(PECOFFABI) || defined(MACHOABI)
+
+#define NCHNAM  256
+	static char text[NCHNAM+1];
+	int i;
+
 	if (p == NULL)
 		return "";
-	return p;
+
+	text[0] = '_';
+	for (i=1; *p && i<NCHNAM; ++i)
+		text[i] = *p++;
+
+	text[i] = '\0';
+	text[NCHNAM] = '\0';  /* truncate */
+
+	return (text);
+
+#else
+
+	return (p == NULL ? "" : p);
+
+#endif
 }
 
 /*
@@ -660,84 +1138,294 @@
 
 /* make a common declaration for id, if reasonable */
 void
-commdec(struct symtab *q)
+defzero(struct symtab *sp)
 {
 	int off;
+	int al;
 
-	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);
+#ifdef TLS
+	if (sp->sflags & STLS) {
+		if (sp->sclass == EXTERN)
+			sp->sclass = EXTDEF;
+		simpleinit(sp, bcon(0));
+		return;
+	}
 #endif
+
+	al = talign(sp->stype, sp->ssue)/SZCHAR;
+	off = tsize(sp->stype, sp->sdf, sp->ssue);
+	off = (off+(SZCHAR-1))/SZCHAR;
+	printf("	.%scomm ", sp->sclass == STATIC ? "l" : "");
+	if (sp->slevel == 0)
+		printf("%s,0%o", exname(sp->soname), off);
+	else
+		printf(LABFMT ",0%o", sp->soffset, off);
+	if (sp->sclass != STATIC)
+		printf(",%d", al);
+	printf("\n");
 }
 
-/* make a local common declaration for id, if reasonable */
-void
-lcommdec(struct symtab *q)
+static char *
+section2string(char *name, int len)
 {
-	int off;
+#if defined(ELFABI)
+	char *s;
+	int n;
 
-	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);
+	if (strncmp(name, "link_set", 8) == 0) {
+		const char *postfix = ",\"aw\", at progbits";
+		n = len + strlen(postfix) + 1;
+		s = IALLOC(n);
+		strlcpy(s, name, n);
+		strlcat(s, postfix, n);
+		return s;
+	}
 #endif
-	else
-		printf("	.lcomm " LABFMT ",0%o\n", q->soffset, off);
+
+	return newstring(name, len);
 }
 
+char *nextsect;
+#ifdef TLS
+static int gottls;
+#endif
+#ifdef os_win32
+static int stdcall;
+static int dllindirect;
+#endif
+static char *alias;
+static int constructor;
+static int destructor;
+
 /*
- * print a (non-prog) label.
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char **ary)
+{
+#ifdef TLS
+	if (strcmp(ary[1], "tls") == 0 && ary[2] == NULL) {
+		gottls = 1;
+		return 1;
+	}
+#endif
+#ifdef os_win32
+	if (strcmp(ary[1], "stdcall") == 0) {
+		stdcall = 1;
+		return 1;
+	}
+	if (strcmp(ary[1], "cdecl") == 0) {
+		stdcall = 0;
+		return 1;
+	}
+	if (strcmp(ary[1], "fastcall") == 0) {
+		stdcall = 2;
+		return 1;
+	}
+	if (strcmp(ary[1], "dllimport") == 0) {
+		dllindirect = 1;
+		return 1;
+	}
+	if (strcmp(ary[1], "dllexport") == 0) {
+		dllindirect = 1;
+		return 1;
+	}
+#endif
+	if (strcmp(ary[1], "constructor") == 0 || strcmp(ary[1], "init") == 0) {
+		constructor = 1;
+		return 1;
+	}
+	if (strcmp(ary[1], "destructor") == 0 || strcmp(ary[1], "fini") == 0) {
+		destructor = 1;
+		return 1;
+	}
+	if (strcmp(ary[1], "section") == 0 && ary[2] != NULL) {
+		nextsect = section2string(ary[2], strlen(ary[2]));
+		return 1;
+	}
+	if (strcmp(ary[1], "alias") == 0 && ary[2] != NULL) {
+		alias = tmpstrdup(ary[2]);
+		return 1;
+	}
+	if (strcmp(ary[1], "ident") == 0)
+		return 1; /* Just ignore */
+
+	return 0;
+}
+
+/*
+ * Called when a identifier has been declared.
  */
 void
-deflab1(int label)
+fixdef(struct symtab *sp)
 {
-	printf(LABFMT ":\n", label);
+#ifdef TLS
+	/* may have sanity checks here */
+	if (gottls)
+		sp->sflags |= STLS;
+	gottls = 0;
+#endif
+	if (alias != NULL && (sp->sclass != PARAM)) {
+		printf("\t.globl %s\n", exname(sp->soname));
+		printf("%s = ", exname(sp->soname));
+		printf("%s\n", exname(alias));
+		alias = NULL;
+	}
+	if ((constructor || destructor) && (sp->sclass != PARAM)) {
+#if defined(ELFABI)
+		printf("\t.section .%ctors,\"aw\", at progbits\n",
+		    constructor ? 'c' : 'd');
+#elif defined(PECOFFABI)
+		printf("\t.section .%ctors,\"w\"\n",
+		    constructor ? 'c' : 'd');
+#elif defined(MACHOABI)
+		if (kflag) {
+			if (constructor)
+				printf("\t.mod_init_func\n");
+			else
+				printf("\t.mod_term_func\n");
+		} else {
+			if (constructor)
+				printf("\t.constructor\n");
+			else
+				printf("\t.destructor\n");
+		}
+#endif
+		printf("\t.p2align 2\n");
+		printf("\t.long %s\n", exname(sp->sname));
+		constructor = destructor = 0;
+	}
+#ifdef os_win32
+	if (stdcall && (sp->sclass != PARAM)) {
+		sp->sflags |= SSTDCALL;
+		stdcall = 0;
+	}
+	if (dllindirect && (sp->sclass != PARAM)) {
+		sp->sflags |= SDLLINDIRECT;
+		dllindirect = 0;
+	}
+#endif
 }
 
-static char *loctbl[] = { "text", "data", "section .rodata", "section .rodata" };
+NODE *
+i386_builtin_return_address(NODE *f, NODE *a)
+{
+	int nframes;
+
+	if (a == NULL || a->n_op != ICON)
+		goto bad;
 
-void
-setloc1(int locc)
+	nframes = a->n_lval;
+
+	tfree(f);
+	tfree(a);
+
+	f = block(REG, NIL, NIL, PTR+VOID, 0, MKSUE(VOID));
+	regno(f) = FPREG;
+
+	while (nframes--)
+		f = block(UMUL, f, NIL, PTR+VOID, 0, MKSUE(VOID));
+
+	f = block(PLUS, f, bcon(4), INCREF(PTR+VOID), 0, MKSUE(VOID));
+	f = buildtree(UMUL, f, NIL);
+
+	return f;
+bad:
+        uerror("bad argument to __builtin_return_address");
+        return bcon(0);
+}
+
+NODE *
+i386_builtin_frame_address(NODE *f, NODE *a)
 {
-	if (locc == lastloc)
-		return;
-	lastloc = locc;
-	printf("	.%s\n", loctbl[locc]);
+	int nframes;
+
+	if (a == NULL || a->n_op != ICON)
+		goto bad;
+
+	nframes = a->n_lval;
+
+	tfree(f);
+	tfree(a);
+
+	f = block(REG, NIL, NIL, PTR+VOID, 0, MKSUE(VOID));
+	regno(f) = FPREG;
+
+	while (nframes--)
+		f = block(UMUL, f, NIL, PTR+VOID, 0, MKSUE(VOID));
+
+	return f;
+bad:
+        uerror("bad argument to __builtin_frame_address");
+        return bcon(0);
 }
 
-#if 0
-int
-ftoint(NODE *p, CONSZ **c)
+#ifdef os_win32
+/*
+ *  Postfix external functions with the arguments size.
+ */
+static void
+mangle(NODE *p, void *arg)
 {
-	static CONSZ cc[3];
-	union { float f; double d; long double l; int i[3]; } u;
-	int n;
+	NODE *l, *r;
+	TWORD t;
+	int size = 0;
+	char buf[64];
 
-	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;
+	if ((p->n_op == NAME || p->n_op == ICON) && 
+	    p->n_sp && (p->n_sp->sflags & SDLLINDIRECT) && p->n_name) {
+		snprintf(buf, 64, "__imp_%s", p->n_name);
+	        p->n_name = IALLOC(strlen(buf) + 1);
+		strcpy(p->n_name, buf);
+		return;
+	}
+
+	if (p->n_op != CALL && p->n_op != STCALL &&
+	    p->n_op != UCALL && p->n_op != USTCALL)
+		return;
+
+	l = p->n_left;
+	if (l->n_op == ADDROF)
+		l = l->n_left;
+	if (l->n_sp == NULL)
+		return;
+	if (l->n_sp->sflags & SSTDCALL) {
+		if (strchr(l->n_name, '@') == NULL) {
+			if (p->n_op == CALL || p->n_op == STCALL) {
+				for (r = p->n_right;	
+				    r->n_op == CM; r = r->n_left) {
+					t = r->n_type;
+					if (t == STRTY || t == UNIONTY)
+						size += r->n_sue->suesize;
+					else
+						size += szty(t) * SZINT / SZCHAR;
+				}
+				t = r->n_type;
+				if (t == STRTY || t == UNIONTY)
+					size += r->n_sue->suesize;
+				else
+					size += szty(t) * SZINT / SZCHAR;
+			}
+			snprintf(buf, 64, "%s@%d", l->n_name, size);
+	        	l->n_name = IALLOC(strlen(buf) + 1);
+			strcpy(l->n_name, buf);
+		}
+
+		l->n_flags = FSTDCALL;
 	}
-	cc[0] = u.i[0];
-	cc[1] = u.i[1];
-	cc[2] = u.i[2];
-	*c = cc;
-	return n;
 }
 #endif
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+#ifdef os_win32
+	if (ip->type == IP_EPILOG) {
+		struct interpass_prolog *ipp = (struct interpass_prolog *)ip;
+		ipp->ipp_argstacksize = argstacksize;
+	}
+
+	if (ip->type == IP_NODE)
+                walkf(ip->ip_node, mangle, 0);
+#endif
+}
Index: reader.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/mip/reader.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/mip/reader.c -L usr.bin/pcc/mip/reader.c -u -r1.1 -r1.2
--- usr.bin/pcc/mip/reader.c
+++ usr.bin/pcc/mip/reader.c
@@ -1,4 +1,4 @@
-/*	$Id: reader.c,v 1.203 2007/09/24 17:49:54 ragge Exp $	*/
+/*	$Id: reader.c,v 1.248 2008/12/03 07:08:40 ragge Exp $	*/
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -61,12 +61,8 @@
  */
 
 /*
- * 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.
+ * Everything is entered via pass2_compile().  No functions are 
+ * allowed to recurse back into pass2_compile().
  */
 
 # include "pass2.h"
@@ -86,59 +82,185 @@
 
 NODE *nodepole;
 FILE *prfil;
-static struct interpass prepole;
+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);
+void deltemp(NODE *p, void *);
+static void cvtemps(struct interpass *ipole, int op, int off);
 NODE *store(NODE *);
-void rcount(void);
-void compile2(struct interpass *ip);
-void compile3(struct interpass *ip);
-void compile4(struct interpass *ip);
+static void fixxasm(struct p2env *);
 
 static void gencode(NODE *p, int cookie);
+static void genxasm(NODE *p);
 
-char *ltyp[] = { "", "LREG", "LOREG", "LTEMP" };
-char *rtyp[] = { "", "RREG", "ROREG", "RTEMP" };
+struct p2env p2env;
 
-/* used when removing nodes */
-struct tmpsave {
-	struct tmpsave *next;
-	CONSZ tempaddr;
-	int tempno;
-} *tmpsave;
+int
+getlab2(void)
+{
+	extern int getlab(void);
+	int rv = getlab();
+#ifdef PCC_DEBUG
+	if (p2env.epp->ip_lblnum != rv)
+		comperr("getlab2 error: %d != %d", p2env.epp->ip_lblnum, rv);
+#endif
+	p2env.epp->ip_lblnum++;
+	return rv;
+}
 
 #ifdef PCC_DEBUG
+static int *lbldef, *lbluse;
 static void
-cktree(NODE *p)
+cktree(NODE *p, void *arg)
 {
+	int i;
+
 	if (p->n_op > MAXOP)
-		cerror("op %d slipped through", p->n_op);
+		cerror("%p) op %d slipped through", p, 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");
+		cerror("%p) type %x slipped through", p, p->n_type);
+	if (p->n_op == CBRANCH) {
+		 if (!logop(p->n_left->n_op))
+			cerror("%p) not logop branch", p);
+		i = p->n_right->n_lval;
+		if (i < p2env.ipp->ip_lblnum || i >= p2env.epp->ip_lblnum)
+			cerror("%p) label %d outside boundaries %d-%d",
+			    p, i, p2env.ipp->ip_lblnum, p2env.epp->ip_lblnum);
+		lbluse[i-p2env.ipp->ip_lblnum] = 1;
+	}
 	if ((dope[p->n_op] & ASGOPFLG) && p->n_op != RETURN)
-		cerror("asgop %d slipped through", p->n_op);
+		cerror("%p) asgop %d slipped through", p, p->n_op);
+	if (p->n_op == TEMP &&
+	    (regno(p) < p2env.ipp->ip_tmpnum || regno(p) >= p2env.epp->ip_tmpnum))
+		cerror("%p) temporary %d outside boundaries %d-%d",
+		    p, regno(p), p2env.ipp->ip_tmpnum, p2env.epp->ip_tmpnum);
+	if (p->n_op == GOTO) {
+		i = p->n_left->n_lval;
+		if (i < p2env.ipp->ip_lblnum || i >= p2env.epp->ip_lblnum)
+			cerror("%p) label %d outside boundaries %d-%d",
+			    p, i, p2env.ipp->ip_lblnum, p2env.epp->ip_lblnum);
+		lbluse[i-p2env.ipp->ip_lblnum] = 1;
+	}
+}
+
+/*
+ * Check that the trees are in a suitable state for pass2.
+ */
+static void
+sanitychecks(struct p2env *p2e)
+{
+	struct interpass *ip;
+	int i;
+#ifdef notyet
+	TMPMARK();
+#endif
+	lbldef = tmpcalloc(sizeof(int) * (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum));
+	lbluse = tmpcalloc(sizeof(int) * (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum));
+
+	DLIST_FOREACH(ip, &p2env.ipole, qelem) {
+		if (ip->type == IP_DEFLAB) {
+			i = ip->ip_lbl;
+			if (i < p2e->ipp->ip_lblnum || i >= p2e->epp->ip_lblnum)
+				cerror("label %d outside boundaries %d-%d",
+				    i, p2e->ipp->ip_lblnum, p2e->epp->ip_lblnum);
+			lbldef[i-p2e->ipp->ip_lblnum] = 1;
+		}
+		if (ip->type == IP_NODE)
+			walkf(ip->ip_node, cktree, 0);
+	}
+	for (i = 0; i < (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum); i++)
+		if (lbluse[i] != 0 && lbldef[i] == 0)
+			cerror("internal label %d not defined",
+			    i + p2e->ipp->ip_lblnum);
+
+#ifdef notyet
+	TMPFREE();
+#endif
 }
 #endif
 
 /*
+ * Look if a temporary comes from a on-stack argument, in that case
+ * use the already existing stack position instead of moving it to
+ * a new place, and remove the move-to-temp statement.
+ */
+static int
+stkarg(int tnr, int *soff)
+{
+	struct p2env *p2e = &p2env;
+	struct interpass *ip;
+	NODE *p;
+
+	ip = DLIST_NEXT((struct interpass *)p2e->ipp, qelem);
+	while (ip->type != IP_DEFLAB) /* search for first DEFLAB */
+		ip = DLIST_NEXT(ip, qelem);
+
+	ip = DLIST_NEXT(ip, qelem); /* first NODE */
+
+	for (; ip->type != IP_DEFLAB; ip = DLIST_NEXT(ip, qelem)) {
+		if (ip->type != IP_NODE)
+			continue;
+
+		p = ip->ip_node;
+		if (p->n_op == XASM)
+			continue; /* XXX - hack for x86 PIC */
+#ifdef PCC_DEBUG
+		if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
+			comperr("temparg");
+#endif
+		if (p->n_right->n_op != OREG && p->n_right->n_op != UMUL)
+			continue; /* arg in register */
+		if (tnr != regno(p->n_left))
+			continue; /* wrong assign */
+		p = p->n_right;
+		if (p->n_op == UMUL &&
+		    p->n_left->n_op == PLUS &&
+		    p->n_left->n_left->n_op == REG &&
+		    p->n_left->n_right->n_op == ICON)
+			*soff = p->n_left->n_right->n_lval;
+		else if (p->n_op == OREG)
+			*soff = p->n_lval;
+		else
+			comperr("stkarg: bad arg");
+		tfree(ip->ip_node);
+		DLIST_REMOVE(ip, qelem);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * See if an ADDROF is somewhere inside the expression tree.
+ * If so, fill in the offset table.
+ */
+static void
+findaof(NODE *p, void *arg)
+{
+	int *aof = arg;
+	int tnr;
+
+	if (p->n_op != ADDROF)
+		return;
+	tnr = regno(p->n_left);
+	if (aof[tnr])
+		return; /* already gotten stack address */
+	if (stkarg(tnr, &aof[tnr]))
+		return;	/* argument was on stack */
+	aof[tnr] = BITOOR(freetemp(szty(p->n_left->n_type)));
+}
+
+/*
  * Check if a node has side effects.
  */
 static int
 isuseless(NODE *n)
 {
 	switch (n->n_op) {
+	case XASM:
 	case FUNARG:
 	case UCALL:
 	case UFORTCALL:
 	case FORCE:
-/*	case INIT: */
 	case ASSIGN:
 	case CALL:
 	case FORTCALL:
@@ -158,7 +280,7 @@
 /*
  * Delete statements with no meaning (like a+b; or 513.4;)
  */
-static NODE *
+NODE *
 deluseless(NODE *p)
 {
 	struct interpass *ip;
@@ -192,70 +314,111 @@
 	return NULL;
 }
 
-static struct interpass ipole;
-struct interpass_prolog *ipp, *epp;
-
 /*
  * Receives interpass structs from pass1.
  */
 void
 pass2_compile(struct interpass *ip)
 {
+	struct p2env *p2e = &p2env;
+	int *addrp;
+	MARK mark;
+
 	if (ip->type == IP_PROLOG) {
-		tmpsave = NULL;
-		ipp = (struct interpass_prolog *)ip;
-		DLIST_INIT(&ipole, qelem);
+		memset(p2e, 0, sizeof(struct p2env));
+		p2e->ipp = (struct interpass_prolog *)ip;
+		DLIST_INIT(&p2e->ipole, qelem);
 	}
-	DLIST_INSERT_BEFORE(&ipole, ip, qelem);
+	DLIST_INSERT_BEFORE(&p2e->ipole, ip, qelem);
 	if (ip->type != IP_EPILOG)
 		return;
 
 #ifdef PCC_DEBUG
 	if (e2debug) {
 		printf("Entering pass2\n");
-		printip(&ipole);
+		printip(&p2e->ipole);
 	}
 #endif
 
-	epp = (struct interpass_prolog *)DLIST_PREV(&ipole, qelem);
-	p2maxautooff = p2autooff = epp->ipp_autos;
+	p2e->epp = (struct interpass_prolog *)DLIST_PREV(&p2e->ipole, qelem);
+	p2maxautooff = p2autooff = p2e->epp->ipp_autos;
 
-	myreader(&ipole); /* local massage of input */
+#ifdef PCC_DEBUG
+	sanitychecks(p2e);
+#endif
+	myreader(&p2e->ipole); /* local massage of input */
+
+	/*
+	 * Do initial modification of the trees.  Two loops;
+	 * - first, search for ADDROF of TEMPs, these must be
+	 *   converterd to OREGs on stack.
+	 * - second, do the actual conversions, in case of not xtemps
+	 *   convert all temporaries to stack references.
+	 */
+	markset(&mark);
+	if (p2e->epp->ip_tmpnum != p2e->ipp->ip_tmpnum) {
+		addrp = tmpcalloc(sizeof(int) *
+		    (p2e->epp->ip_tmpnum - p2e->ipp->ip_tmpnum));
+		addrp -= p2e->ipp->ip_tmpnum;
+	} else
+		addrp = NULL;
+	if (xtemps) {
+		DLIST_FOREACH(ip, &p2e->ipole, qelem) {
+			if (ip->type == IP_NODE)
+				walkf(ip->ip_node, findaof, addrp);
+		}
+	}
+	DLIST_FOREACH(ip, &p2e->ipole, qelem)
+		if (ip->type == IP_NODE)
+			walkf(ip->ip_node, deltemp, addrp);
+	markfree(&mark);
+
+#ifdef PCC_DEBUG
+	if (e2debug) {
+		printf("Efter ADDROF/TEMP\n");
+		printip(&p2e->ipole);
+	}
+#endif
 
-	DLIST_FOREACH(ip, &ipole, qelem) {
+#if 0
+	DLIST_FOREACH(ip, &p2e->ipole, qelem) {
 		if (ip->type != IP_NODE)
 			continue;
 		if (xtemps == 0)
-			walkf(ip->ip_node, deltemp);
+			walkf(ip->ip_node, deltemp, 0);
 	}
+#endif
+
 	DLIST_INIT(&prepole, qelem);
-	DLIST_FOREACH(ip, &ipole, qelem) {
+	DLIST_FOREACH(ip, &p2e->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;
+			struct interpass *tipp;
 
-			ipp = DLIST_NEXT(&prepole, qelem);
-			DLIST_REMOVE(ipp, qelem);
-			DLIST_INSERT_BEFORE(ip, ipp, qelem);
+			tipp = DLIST_NEXT(&prepole, qelem);
+			DLIST_REMOVE(tipp, qelem);
+			DLIST_INSERT_BEFORE(ip, tipp, qelem);
 		}
 	}
 
-	optimize(&ipole);
-	ngenregs(&ipole);
+	fixxasm(p2e); /* setup for extended asm */
 
-	DLIST_FOREACH(ip, &ipole, qelem)
+	optimize(p2e);
+	ngenregs(p2e);
+
+	DLIST_FOREACH(ip, &p2e->ipole, qelem)
 		emit(ip);
 }
 
 void
 emit(struct interpass *ip)
 {
-	NODE *p;
+	NODE *p, *r;
+	struct optab *op;
 	int o;
 
 	switch (ip->type) {
@@ -263,23 +426,36 @@
 		p = ip->ip_node;
 
 		nodepole = p;
-//printf("bu:\n");
-//fwalk(p, e2print, 0);
 		canon(p); /* may convert stuff after genregs */
-//fwalk(p, e2print, 0);
+		if (c2debug > 1) {
+			printf("emit IP_NODE:\n");
+			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) {
+			/* careful when an OPLOG has been elided */
+			if (p->n_left->n_su == 0 && p->n_left->n_left != NULL) {
+				op = &table[TBLIDX(p->n_left->n_left->n_su)];
+				r = p->n_left;
+			} else {
+				op = &table[TBLIDX(p->n_left->n_su)];
+				r = p;
+			}
+			if (op->rewrite & RESCC) {
 				o = p->n_left->n_op;
-				gencode(p, FORCC);
+				gencode(r, FORCC);
 				cbgen(o, p->n_right->n_lval);
-			} else
-				gencode(p, FORCC);
+			} else {
+				gencode(r, FORCC);
+			}
 			break;
 		case FORCE:
 			gencode(p->n_left, INREGS);
 			break;
+		case XASM:
+			genxasm(p);
+			break;
 		default:
 			if (p->n_op != REG || p->n_type != VOID) /* XXX */
 				gencode(p, FOREFF); /* Emit instructions */
@@ -292,17 +468,16 @@
 		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);
+		printf("%s", ip->ip_asm);
 		break;
 	default:
-		cerror("compile4 %d", ip->type);
+		cerror("emit %d", ip->type);
 	}
 }
 
@@ -370,7 +545,7 @@
 geninsn(NODE *p, int cookie)
 {
 	NODE *p1, *p2;
-	int o, rv = 0;
+	int q, o, rv = 0;
 
 #ifdef PCC_DEBUG
 	if (odebug) {
@@ -379,6 +554,9 @@
 	}
 #endif
 
+	q = cookie & QUIET;
+	cookie &= ~QUIET; /* XXX - should not be necessary */
+
 again:	switch (o = p->n_op) {
 	case EQ:
 	case NE:
@@ -390,6 +568,18 @@
 	case ULT:
 	case UGE:
 	case UGT:
+		p1 = p->n_left;
+		p2 = p->n_right;
+		if (p2->n_op == ICON && p2->n_lval == 0 &&
+		    optype(p1->n_op) == BITYPE) {
+#ifdef mach_pdp11 /* XXX all targets? */
+			if ((rv = geninsn(p1, FORCC|QUIET)) != FFAIL)
+				break;
+#else
+			if (findops(p1, FORCC) > 0)
+				break;
+#endif
+		}
 		rv = relops(p);
 		break;
 
@@ -407,6 +597,11 @@
 		break;
 
 	case ASSIGN:
+#ifdef FINDMOPS
+		if ((rv = findmops(p, cookie)) != FFAIL)
+			break;
+		/* FALLTHROUGH */
+#endif
 	case STASG:
 		rv = findasg(p, cookie);
 		break;
@@ -419,6 +614,7 @@
 	case TEMP:
 	case NAME:
 	case ICON:
+	case FCON:
 	case OREG:
 		rv = findleaf(p, cookie);
 		break;
@@ -427,9 +623,10 @@
 	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);
+			(void)geninsn(p1->n_right, FOREFF);
+		(void)geninsn(p1, FOREFF);
 		/* FALLTHROUGH */
+	case FLD:
 	case COMPL:
 	case UMINUS:
 	case PCONV:
@@ -440,6 +637,7 @@
 	case STARG:
 	case UCALL:
 	case USTCALL:
+	case ADDROF:
 		rv = finduni(p, cookie);
 		break;
 
@@ -447,23 +645,39 @@
 		p1 = p->n_left;
 		p2 = p->n_right;
 		p1->n_label = p2->n_lval;
-		o = p1->n_op;
-		geninsn(p1, FORCC);
+		(void)geninsn(p1, FORCC);
 		p->n_su = 0;
 		break;
 
 	case FORCE: /* XXX needed? */
-		geninsn(p->n_left, INREGS);
+		(void)geninsn(p->n_left, INREGS);
 		p->n_su = 0; /* su calculations traverse left */
 		break;
 
+	case XASM:
+		for (p1 = p->n_left; p1->n_op == CM; p1 = p1->n_left)
+			(void)geninsn(p1->n_right, FOREFF);
+		(void)geninsn(p1, FOREFF);
+		break;	/* all stuff already done? */
+
+	case XARG:
+		/* generate code for correct class here */
+//		geninsn(p->n_left, 1 << p->n_label);
+		break;
+
 	default:
 		comperr("geninsn: bad op %s, node %p", opst[o], p);
 	}
-	if (rv == FFAIL)
+	if (rv == FFAIL && !q)
 		comperr("Cannot generate code, node %p op %s", p,opst[p->n_op]);
 	if (rv == FRETRY)
 		goto again;
+#ifdef PCC_DEBUG
+	if (odebug) {
+		printf("geninsn(%p, %s) rv %d\n", p, prcook(cookie), rv);
+		fwalk(p, e2print, 0);
+	}
+#endif
 	return rv;
 }
 
@@ -514,7 +728,7 @@
  * Rewrite node to register after instruction emit.
  */
 static void
-rewrite(NODE *p, int rewrite, int cookie)
+rewrite(NODE *p, int dorewrite, int cookie)
 {
 	NODE *l, *r;
 	int o;
@@ -550,18 +764,75 @@
 		tfree(l);
 	if (optype(o) == BITYPE)
 		tfree(r);
-	if (rewrite == 0)
+	if (dorewrite == 0)
 		return;
-	CDEBUG(("rewrite: %p, reg %s\n", p, rnames[DECRA(p->n_reg, 0)]));
+	CDEBUG(("rewrite: %p, reg %s\n", p,
+	    p->n_reg == -1? "<none>" : rnames[DECRA(p->n_reg, 0)]));
 	p->n_rval = DECRA(p->n_reg, 0);
 }
 
+#ifndef XASM_TARGARG
+#define	XASM_TARGARG(x,y) 0
+#endif
+
+/*
+ * printout extended assembler.
+ */
+void
+genxasm(NODE *p)
+{
+	NODE *q, **nary;
+	int n = 1, o = 0;
+	char *w;
+
+	if (p->n_left->n_op != ICON || p->n_left->n_type != STRTY) {
+		for (q = p->n_left; q->n_op == CM; q = q->n_left)
+			n++;
+		nary = tmpalloc(sizeof(NODE *)*n);
+		o = n;
+		for (q = p->n_left; q->n_op == CM; q = q->n_left) {
+			gencode(q->n_right->n_left, INREGS);
+			nary[--o] = q->n_right;
+		}
+		gencode(q->n_left, INREGS);
+		nary[--o] = q;
+	} else
+		nary = 0;
+
+	w = p->n_name;
+	putchar('\t');
+	while (*w != 0) {
+		if (*w == '%') {
+			if (w[1] == '%')
+				putchar('%');
+			else if (XASM_TARGARG(w, nary))
+				; /* handled by target */
+			else if (w[1] < '0' || w[1] > (n + '0'))
+				uerror("bad xasm arg number %c", w[1]);
+			else
+				adrput(stdout, nary[(int)w[1]-'0']->n_left);
+			w++;
+		} else if (*w == '\\') { /* Always 3-digit octal */
+			int num = *++w - '0';
+			num = (num << 3) + *++w - '0';
+			num = (num << 3) + *++w - '0';
+			putchar(num);
+		} else
+			putchar(*w);
+		w++;
+	}
+	putchar('\n');
+}
+
 void
 gencode(NODE *p, int cookie)
 {
 	struct optab *q = &table[TBLIDX(p->n_su)];
 	NODE *p1, *l, *r;
 	int o = optype(p->n_op);
+#ifdef FINDMOPS
+	int ismops = (p->n_op == ASSIGN && (p->n_flags & 1));
+#endif
 
 	l = p->n_left;
 	r = p->n_right;
@@ -598,7 +869,12 @@
 	}
 	if (o != LTYPE) {
 		gencode(l, INREGS);
-		if (q->rewrite & RLEFT)
+#ifdef FINDMOPS
+		if (ismops)
+			;
+		else
+#endif
+		     if (q->rewrite & RLEFT)
 			ckmove(p, l);
 	}
 	if (o == BITYPE && !(p->n_su & DORIGHT)) {
@@ -607,6 +883,18 @@
 			ckmove(p, r);
 	}
 
+#ifdef FINDMOPS
+	if (ismops) {
+		/* reduce right tree to make expand() work */
+		if (optype(r->n_op) != LTYPE) {
+			p->n_op = r->n_op;
+			r = tcopy(r->n_right);
+			tfree(p->n_right);
+			p->n_right = r;
+		}
+	}
+#endif
+
 	canon(p);
 
 	if (q->needs & NSPECIAL) {
@@ -614,6 +902,10 @@
 		int lr = rspecial(q, NLEFT);
 
 		if (rr >= 0) {
+#ifdef PCC_DEBUG
+			if (optype(p->n_op) != BITYPE)
+				comperr("gencode: rspecial borked");
+#endif
 			if (r->n_op != REG)
 				comperr("gencode: rop != REG");
 			if (rr != r->n_rval)
@@ -633,7 +925,8 @@
 
 	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){
+	    p->n_left->n_rval == p->n_right->n_rval &&
+	    (p->n_su & RVCC) == 0) { /* XXX should check if necessary */
 		/* do not emit anything */
 		CDEBUG(("gencode(%p) assign nothing\n", p));
 		rewrite(p, q->rewrite, cookie);
@@ -645,6 +938,12 @@
 		return;
 
 	expand(p, cookie, q->cstring);
+#ifdef FINDMOPS
+	if (ismops && DECRA(p->n_reg, 0) != regno(l) && cookie != FOREFF) {
+		CDEBUG(("gencode(%p) rmove\n", p));
+		rmove(regno(l), DECRA(p->n_reg, 0), p->n_type);
+	} else
+#endif
 	if (callop(p->n_op) && cookie != FOREFF &&
 	    DECRA(p->n_reg, 0) != RETREG(p->n_type)) {
 		CDEBUG(("gencode(%p) retreg\n", p));
@@ -681,6 +980,7 @@
 }
 
 int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ;  /* negatives of relationals */
+size_t negrelsize = sizeof negrel / sizeof negrel[0];
 
 #ifdef PCC_DEBUG
 #undef	PRTABLE
@@ -708,7 +1008,12 @@
 		break;
 
 	case TEMP:
-		fprintf(prfil, " " CONFMT, p->n_lval);
+		fprintf(prfil, " %d", regno(p));
+		break;
+
+	case XASM:
+	case XARG:
+		fprintf(prfil, " '%s'", p->n_name);
 		break;
 
 	case ICON:
@@ -730,16 +1035,9 @@
 	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",
+
+	prtreg(prfil, p);
+	fprintf(prfil, ", SU= %d(%cREG,%s,%s,%s,%s,%s,%s)\n",
 	    TBLIDX(p->n_su), 
 	    TCLASS(p->n_su)+'@',
 #ifdef PRTABLE
@@ -748,8 +1046,9 @@
 #else
 	    "",
 #endif
-	    ltyp[LMASK&p->n_su],
-	    rtyp[(p->n_su&RMASK) >> 2], p->n_su & DORIGHT ? "DORIGHT" : "");
+	    p->n_su & LREG ? "LREG" : "", p->n_su & RREG ? "RREG" : "",
+	    p->n_su & RVEFF ? "RVEFF" : "", p->n_su & RVCC ? "RVCC" : "",
+	    p->n_su & DORIGHT ? "DORIGHT" : "");
 }
 #endif
 
@@ -815,35 +1114,32 @@
  * change left TEMPs into OREGs
  */
 void
-deltemp(NODE *p)
+deltemp(NODE *p, void *arg)
 {
-	struct tmpsave *w;
-	NODE *l;
+	int *aor = arg;
+	NODE *l, *r;
 
 	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&");
+		if (aor[regno(p)] == 0) {
+			if (xtemps)
+				return;
+			aor[regno(p)] = BITOOR(freetemp(szty(p->n_type)));
+		}
+		l = mklnode(REG, 0, FPREG, INCREF(p->n_type));
+		r = mklnode(ICON, aor[regno(p)], 0, INT);
+		p->n_left = mkbinode(PLUS, l, r, INCREF(p->n_type));
+		p->n_op = UMUL;
+	} else if (p->n_op == ADDROF && p->n_left->n_op == OREG) {
 		p->n_op = PLUS;
+		l = p->n_left;
 		l->n_op = REG;
 		l->n_type = INCREF(l->n_type);
 		p->n_right = mklnode(ICON, l->n_lval, 0, INT);
+	} else if (p->n_op == ADDROF && p->n_left->n_op == UMUL) {
+		l = p->n_left;
+		*p = *p->n_left->n_left;
+		nfree(l->n_left);
+		nfree(l);
 	}
 }
 
@@ -851,7 +1147,7 @@
  * for pointer/integer arithmetic, set pointer at left node
  */
 static void
-setleft(NODE *p)          
+setleft(NODE *p, void *arg)
 {        
 	NODE *q;
 
@@ -909,10 +1205,10 @@
 		int i;
 		if( (r=base(ql))>=0 && (i=offset(qr, tlen(p)))>=0) {
 			makeor2(p, ql, r, i);
-			return;
+			return 1;
 		} else if((r=base(qr))>=0 && (i=offset(ql, tlen(p)))>=0) {
 			makeor2(p, qr, r, i);
-			return;
+			return 1;
 		}
 	}
 
@@ -966,7 +1262,7 @@
  * look for situations where we can turn * into OREG
  */
 void
-oreg2(NODE *p)
+oreg2(NODE *p, void *arg)
 {
 	if (p->n_op != UMUL)
 		return;
@@ -980,14 +1276,12 @@
 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 */
+	walkf(p, setleft, 0);	/* ptrs at left node for arithmetic */
+	walkf(p, oreg2, 0);	/* 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
+	mycanon(p);		/* your own canonicalization routine(s) */
 
 }
 
@@ -997,6 +1291,12 @@
 	extern char *ftitle;
 	va_list ap;
 
+	if (nerrors) {
+		fprintf(stderr,
+		    "cannot recover from earlier errors: goodbye!\n");
+		exit(1);
+	}
+
 	va_start(ap, str);
 	fprintf(stderr, "%s, line %d: compiler error: ", ftitle, thisline);
 	vfprintf(stderr, str, ap);
@@ -1004,8 +1304,10 @@
 	va_end(ap);
 	prfil = stderr;
 
+#ifdef PCC_DEBUG
 	if (nodepole && nodepole->n_op != FREE)
 		fwalk(nodepole, e2print, 0);
+#endif
 	exit(1);
 }
 
@@ -1050,6 +1352,7 @@
 	p->n_name = "";
 	p->n_qual = 0;
 	p->n_op = op;
+	p->n_label = 0;
 	p->n_lval = lval;
 	p->n_rval = rval;
 	p->n_type = type;
@@ -1066,10 +1369,12 @@
 	p->n_name = "";
 	p->n_qual = 0;
 	p->n_op = op;
+	p->n_label = 0;
 	p->n_left = left;
 	p->n_right = right;
 	p->n_type = type;
 	p->n_regw = NULL;
+	p->n_su = 0;
 	return p;
 }
 
@@ -1081,10 +1386,12 @@
 	p->n_name = "";
 	p->n_qual = 0;
 	p->n_op = op;
+	p->n_label = 0;
 	p->n_left = left;
 	p->n_rval = rval;
 	p->n_type = type;
 	p->n_regw = NULL;
+	p->n_su = 0;
 	return p;
 }
 
@@ -1110,3 +1417,222 @@
 	}
 	return -1;
 }
+
+#ifndef XASM_NUMCONV
+#define	XASM_NUMCONV(x,y,z)	0
+#endif
+
+/*
+ * change numeric argument redirections to the correct node type after 
+ * cleaning up the other nodes.
+ * be careful about input operands that may have different value than output.
+ */
+static void
+delnums(NODE *p, void *arg)
+{
+	struct interpass *ip = arg, *ip2;
+	NODE *r = ip->ip_node->n_left;
+	NODE *q;
+	TWORD t;
+	int cnt;
+
+	if (p->n_name[0] < '0' || p->n_name[0] > '9')
+		return; /* not numeric */
+	if ((q = listarg(r, p->n_name[0] - '0', &cnt)) == NIL)
+		comperr("bad delnums");
+
+	/* target may have opinions whether to do this conversion */
+	if (XASM_NUMCONV(ip, p, q))
+		return;
+
+	/* Delete number by adding move-to/from-temp.  Later on */
+	/* the temps may be rewritten to other LTYPEs */
+	t = p->n_left->n_type;
+	r = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t);
+
+	/* pre node */
+	ip2 = ipnode(mkbinode(ASSIGN, tcopy(r), p->n_left, t));
+	DLIST_INSERT_BEFORE(ip, ip2, qelem);
+
+	/* post node */
+	ip2 = ipnode(mkbinode(ASSIGN, q->n_left, tcopy(r), t));
+	DLIST_INSERT_AFTER(ip, ip2, qelem);
+
+	p->n_left = tcopy(r);
+	q->n_left = r;
+
+	p->n_name = tmpstrdup(q->n_name);
+	if (*p->n_name == '=')
+		p->n_name++;
+}
+
+/*
+ * Ensure that a node is correct for the destination.
+ */
+static void
+ltypify(NODE *p, void *arg)
+{
+	struct interpass *ip = arg;
+	struct interpass *ip2;
+	TWORD t = p->n_left->n_type;
+	NODE *q, *r;
+	int cw, ooff;
+	char *c;
+
+again:
+	if (myxasm(ip, p))
+		return;	/* handled by target-specific code */
+
+	cw = xasmcode(p->n_name);
+	switch (XASMVAL(cw)) {
+	case 'p':
+		/* pointer */
+		/* just make register of it */
+		p->n_name = tmpstrdup(p->n_name);
+		c = strchr(p->n_name, XASMVAL(cw)); /* cannot fail */
+		*c = 'r';
+		/* FALLTHROUGH */
+	case 'g':  /* general; any operand */
+	case 'r': /* general reg */
+		/* set register class */
+		p->n_label = gclass(p->n_left->n_type);
+		if (p->n_left->n_op == REG || p->n_left->n_op == TEMP)
+			break;
+		q = p->n_left;
+		r = (cw & XASMINOUT ? tcopy(q) : q);
+		p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t);
+		if ((cw & XASMASG) == 0) {
+			ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), r, t));
+			DLIST_INSERT_BEFORE(ip, ip2, qelem);
+		}
+		if (cw & (XASMASG|XASMINOUT)) {
+			/* output parameter */
+			ip2 = ipnode(mkbinode(ASSIGN, q, tcopy(p->n_left), t));
+			DLIST_INSERT_AFTER(ip, ip2, qelem);
+		}
+		break;
+
+	case '0': case '1': case '2': case '3': case '4':
+	case '5': case '6': case '7': case '8': case '9':
+		break;
+
+	case 'm': /* memory operand */
+		/* store and reload value */
+		q = p->n_left;
+		if (optype(q->n_op) == LTYPE) {
+			if (q->n_op == TEMP) {
+				ooff = BITOOR(freetemp(szty(t)));
+				cvtemps(ip, q->n_rval, ooff);
+			} else if (q->n_op == REG)
+				comperr("xasm m and reg");
+		} else if (q->n_op == UMUL && 
+		    (q->n_left->n_op != TEMP && q->n_left->n_op != REG)) {
+			t = q->n_left->n_type;
+			ooff = p2env.epp->ip_tmpnum++;
+			ip2 = ipnode(mkbinode(ASSIGN,
+			    mklnode(TEMP, 0, ooff, t), q->n_left, t));
+			q->n_left = mklnode(TEMP, 0, ooff, t);
+			DLIST_INSERT_BEFORE(ip, ip2, qelem);
+		}
+		break;
+
+	case 'i': /* immediate constant */
+	case 'n': /* numeric constant */
+		if (p->n_left->n_op == ICON)
+			break;
+		p->n_name = tmpstrdup(p->n_name);
+		c = strchr(p->n_name, XASMVAL(cw)); /* cannot fail */
+		if (c[1]) {
+			c[0] = c[1], c[1] = 0;
+			goto again;
+		} else
+			uerror("constant required");
+		break;
+
+	default:
+		uerror("unsupported xasm option string '%s'", p->n_name);
+	}
+}
+
+/* Extended assembler hacks */
+static void
+fixxasm(struct p2env *p2e)
+{
+	struct interpass *pole = &p2e->ipole;
+	struct interpass *ip;
+	NODE *p;
+
+	DLIST_FOREACH(ip, pole, qelem) {
+		if (ip->type != IP_NODE || ip->ip_node->n_op != XASM)
+			continue;
+		thisline = ip->lineno;
+		p = ip->ip_node->n_left;
+
+		if (p->n_op == ICON && p->n_type == STRTY)
+			continue;
+
+		/* replace numeric redirections with its underlying type */
+		flist(p, delnums, ip);
+
+		/*
+		 * Ensure that the arg nodes can be directly addressable
+		 * We decide that everything shall be LTYPE here.
+		 */
+		flist(p, ltypify, ip);
+	}
+}
+
+/*
+ * Extract codeword from xasm string */
+int
+xasmcode(char *s)
+{
+	int cw = 0;
+
+	while (*s) {
+		switch ((int)*s) {
+		case '=': cw |= XASMASG; break;
+		case '&': cw |= XASMCONSTR; break;
+		case '+': cw |= XASMINOUT; break;
+		default:
+			if ((*s >= 'a' && *s <= 'z') ||
+			    (*s >= 'A' && *s <= 'Z') ||
+			    (*s >= '0' && *s <= '9')) {
+				cw |= *s;
+				return cw;
+			}
+			uerror("bad xasm constraint %c", *s);
+		}
+		s++;
+	}
+	return cw;
+}
+
+static int xasnum, xoffnum;
+
+static void
+xconv(NODE *p, void *arg)
+{
+	if (p->n_op != TEMP || p->n_rval != xasnum)
+		return;
+	p->n_op = OREG;
+	p->n_rval = FPREG;
+	p->n_lval = xoffnum;
+}
+
+/*
+ * Convert nodes of type TEMP to op with lval off.
+ */
+static void
+cvtemps(struct interpass *ipl, int tnum, int off)
+{
+	struct interpass *ip;
+
+	xasnum = tnum;
+	xoffnum = off;
+
+	DLIST_FOREACH(ip, ipl, qelem)
+		if (ip->type == IP_NODE)
+			walkf(ip->ip_node, xconv, 0);
+	walkf(ipl->ip_node, xconv, 0);
+}
Index: node.h
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/mip/node.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/mip/node.h -L usr.bin/pcc/mip/node.h -u -r1.1 -r1.2
--- usr.bin/pcc/mip/node.h
+++ usr.bin/pcc/mip/node.h
@@ -1,4 +1,4 @@
-/*	$Id: node.h,v 1.31 2007/07/22 12:50:56 ragge Exp $	*/
+/*	$Id: node.h,v 1.35 2008/09/04 08:00:11 ragge Exp $	*/
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -26,6 +26,9 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifndef NODE_H
+#define NODE_H
+
 /*
  * The node structure is the basic element in the compiler.
  * Depending on the operator, it may be one of several types.
@@ -60,6 +63,7 @@
 	union {
 		int	_label;
 		int	_stalign;
+		int	_flags;
 		struct	suedef *_sue;
 	} n_6;
 	union {
@@ -77,7 +81,18 @@
 				struct symtab *_sp;
 			} n_r;
 		} n_u;
+#ifdef SOFTFLOAT
+#ifdef FDFLOAT
+		/* To store F- or D-floats */
+		struct softfloat {
+			unsigned short fd1, fd2, fd3, fd4;
+		} _dcon;
+#else
+#error missing softfloat structure definition
+#endif
+#else
 		long double	_dcon;
+#endif
 	} n_f;
 } NODE;
 
@@ -87,6 +102,7 @@
 
 #define	n_label	n_6._label
 #define	n_stalign n_6._stalign
+#define	n_flags n_6._flags
 #define	n_sue	n_6._sue
 
 #define	n_left	n_f.n_u.n_l._left
@@ -97,6 +113,9 @@
 #define	n_sp	n_f.n_u.n_r._sp
 #define	n_dcon	n_f._dcon
 
+#define	NLOCAL1	010000
+#define	NLOCAL2	020000
+#define	NLOCAL3	040000
 /*
  * Node types.
  *
@@ -113,7 +132,7 @@
 #define REG	6
 #define OREG	7
 #define TEMP	8
-#define	MOVE	9	/* Special reg-reg move node */
+#define XARG	9
 
 /*
  * Arithmetic nodes.
@@ -184,7 +203,7 @@
 #define STASG	50
 #define STARG	51
 #define FORCE	52
-/* #define INIT	53 */
+#define XASM	53
 #define	GOTO	54
 #define	RETURN	55
 #define STREF	56
@@ -192,3 +211,5 @@
 #define	ADDROF	58
 
 #define	MAXOP	58
+
+#endif
Index: match.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/mip/match.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/mip/match.c -L usr.bin/pcc/mip/match.c -u -r1.1 -r1.2
--- usr.bin/pcc/mip/match.c
+++ usr.bin/pcc/mip/match.c
@@ -1,4 +1,4 @@
-/*      $Id: match.c,v 1.72 2006/07/30 09:32:15 ragge Exp $   */
+/*      $Id: match.c,v 1.89 2008/11/26 17:31:40 ragge Exp $   */
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -60,16 +60,15 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-# include "pass2.h"
+#include "pass2.h"
 
+#ifdef HAVE_STRINGS_H
 #include <strings.h>
+#endif
 
-void prttype(int t);
 void setclass(int tmp, int class);
 int getclass(int tmp);
 
-int fldsz, fldshf;
-
 int s2debug = 0;
 
 extern char *ltyp[], *rtyp[];
@@ -149,27 +148,14 @@
 		break;
 
 	case ICON:
+	case FCON:
 		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;
-		}
+		if (shape & SFLD)
+			return flshape(p->n_left);
 		break;
 
 	case CCODES:
@@ -190,9 +176,13 @@
 		break;
 
 	case UMUL:
+#if 0
 		if (shumul(p->n_left) & shape)
 			return SROREG;	/* Calls offstar to traverse down */
 		break;
+#else
+		return shumul(p->n_left, shape);
+#endif
 
 	}
 	return SRNOPE;
@@ -264,6 +254,13 @@
 	return(0);
 }
 
+#define FLDSZ(x)	UPKFSZ(x)
+#ifdef RTOLBYTES
+#define	FLDSHF(x)	UPKFOFF(x)
+#else
+#define	FLDSHF(x)	(SZINT - FLDSZ(x) - UPKFOFF(x))
+#endif
+
 /*
  * generate code by interpreting table entry
  */
@@ -272,6 +269,9 @@
 {
 	CONSZ val;
 
+//printf("expand\n");
+//fwalk(p, e2print, 0);
+
 	for( ; *cp; ++cp ){
 		switch( *cp ){
 
@@ -284,23 +284,34 @@
 			continue;
 
 		case 'F':  /* this line deleted if FOREFF is active */
-			if( cookie & FOREFF ) while( *++cp != '\n' ) ; /* VOID */
+			if (cookie & FOREFF) {
+				while (*cp && *cp != '\n')
+					cp++;
+				if (*cp == 0)
+					return;
+			}
 			continue;
 
 		case 'S':  /* field size */
-			printf( "%d", fldsz );
+			if (fldexpand(p, cookie, &cp))
+				continue;
+			printf("%d", FLDSZ(p->n_rval));
 			continue;
 
 		case 'H':  /* field shift */
-			printf( "%d", fldshf );
+			if (fldexpand(p, cookie, &cp))
+				continue;
+			printf("%d", FLDSHF(p->n_rval));
 			continue;
 
 		case 'M':  /* field mask */
 		case 'N':  /* complement of field mask */
+			if (fldexpand(p, cookie, &cp))
+				continue;
 			val = 1;
-			val <<= fldsz;
+			val <<= FLDSZ(p->n_rval);
 			--val;
-			val <<= fldshf;
+			val <<= FLDSHF(p->n_rval);
 			adrcon( *cp=='M' ? val : ~val );
 			continue;
 
@@ -312,6 +323,11 @@
 			continue;
 
 		case 'O':  /* opcode string */
+#ifdef FINDMOPS
+			if (p->n_op == ASSIGN)
+				hopcode(*++cp, p->n_right->n_op);
+			else
+#endif
 			hopcode( *++cp, p->n_op );
 			continue;
 
@@ -382,26 +398,6 @@
 	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)
@@ -415,8 +411,8 @@
  * 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().
+ *	- SRREG - result in register, call geninsn().
+ *	- SROREG - create OREG; call offstar().
  *	- 0 - clear su, walk down.
  */
 static int
@@ -424,12 +420,14 @@
 {
 	int rv = 0;
 
+	F2DEBUG(("swmatch: p=%p, shape=%s, w=%s\n", p, prcook(shape), srtyp[w]));
+
 	switch (w) {
-	case LREG:
+	case SRREG:
 		rv = geninsn(p, shape);
 		break;
 
-	case LOREG:
+	case SROREG:
 		/* should be here only if op == UMUL */
 		if (p->n_op != UMUL && p->n_op != FLD)
 			comperr("swmatch %p", p);
@@ -493,7 +491,8 @@
  *	p - node (for this leg)
  *	shape - given shape for this leg
  *	cookie - cookie given for parent node
- *	rv - switch key for traversing down
+ *	rew - 
+ *	go - switch key for traversing down
  *	returns register class.
  */
 static int
@@ -501,20 +500,23 @@
 {
 	int lsh;
 
+	F2DEBUG(("shswitch: p=%p, shape=%s, ", p, prcook(shape)));
+	F2DEBUG(("cookie=%s, rew=0x%x, go=%s\n", prcook(cookie), rew, srtyp[go]));
+
 	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);
+		(void)swmatch(p, shape, SROREG);
 		break;
 
 	case SRREG: /* call geninsn() to get value into register */
-		lsh = shape & INREGS;
+		lsh = shape & (FORCC | INREGS);
 		if (rew && cookie != FOREFF)
-			lsh &= (cookie & INREGS);
-		lsh = swmatch(p, lsh, LREG);
+			lsh &= (cookie & (FORCC | INREGS));
+		lsh = swmatch(p, lsh, SRREG);
 		if (rew)
 			sh = lsh;
 		break;
@@ -549,7 +551,10 @@
 	for (i = 0; ixp[i] >= 0; i++) {
 		q = &table[ixp[i]];
 
-		F2DEBUG(("findop: ixp %d\n", ixp[i]));
+		F2DEBUG(("findop: ixp %d str %s\n", ixp[i], q->cstring));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
+
 		if (ttype(l->n_type, q->ltype) == 0 ||
 		    ttype(r->n_type, q->rtype) == 0)
 			continue; /* Types must be correct */
@@ -565,7 +570,8 @@
 		F2DEBUG(("findop lshape %d\n", shl));
 		F2WALK(l);
 
-		if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT))== SRNOPE)			continue;
+		if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT)) == SRNOPE)
+			continue;
 
 		F2DEBUG(("findop rshape %d\n", shr));
 		F2WALK(r);
@@ -592,18 +598,26 @@
 
 	sh = -1;
 
+#ifdef mach_pdp11
+	if (cookie == FORCC && p->n_op != AND)	/* XXX - fix */
+		cookie = INREGS;
+#else
+	if (cookie == FORCC)
+		cookie = INREGS;
+#endif
+
 	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)
+		if (cookie == FOREFF || cookie == FORCC)
 			sh = 0;
 		else
 			sh = ffs(cookie & qq->visit & INREGS)-1;
 	}
-	F2DEBUG(("findops: node %p (%s)\n", p, prcook(1 << sh)));
+	F2DEBUG(("findops: node %p sh %d (%s)\n", p, sh, prcook(1 << sh)));
 	p->n_su = MKIDX(idx, 0);
 	SCLASS(p->n_su, sh);
 	return sh;
@@ -647,6 +661,9 @@
 		q = &table[ixp[i]];
 
 		F2DEBUG(("relops: ixp %d\n", ixp[i]));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
+
 		if (ttype(l->n_type, q->ltype) == 0 ||
 		    ttype(r->n_type, q->rtype) == 0)
 			continue; /* Types must be correct */
@@ -686,7 +703,7 @@
 	(void)shswitch(-1, p->n_right, q->rshape, FORCC,
 	    q->rewrite & RRIGHT, gor);
 	
-	F2DEBUG(("findops: node %p\n", p));
+	F2DEBUG(("relops: node %p\n", p));
 	p->n_su = MKIDX(idx, 0);
 	SCLASS(p->n_su, CLASSA); /* XXX */
 	return 0;
@@ -727,7 +744,10 @@
 	for (i = 0; ixp[i] >= 0; i++) {
 		q = &table[ixp[i]];
 
-		F2DEBUG(("asgop: ixp %d\n", ixp[i]));
+		F2DEBUG(("findasg: ixp %d\n", ixp[i]));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
+
 		if (ttype(l->n_type, q->ltype) == 0 ||
 		    ttype(r->n_type, q->rtype) == 0)
 			continue; /* Types must be correct */
@@ -735,20 +755,30 @@
 		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(("findasg got types\n"));
+#ifdef mach_pdp11 /* XXX - check for other targets too */
+		if (p->n_op == STASG && ISPTR(l->n_type)) {
+			/* Accept lvalue to be in register */
+			/* if struct assignment is given a pointer */
+			if ((shl = chcheck(l, q->lshape,
+			    q->rewrite & RLEFT)) == SRNOPE)
+				continue;
+		} else
+#endif
+		{
+			if ((shl = tshape(l, q->lshape)) == SRNOPE)
+				continue;
+			if (shl == SRREG)
+				continue;
+		}
 
-		F2DEBUG(("asgop lshape %d\n", shl));
+		F2DEBUG(("findasg lshape %d\n", shl));
 		F2WALK(l);
 
-		if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT))== SRNOPE)
+		if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT)) == SRNOPE)
 			continue;
 
-		F2DEBUG(("asgop rshape %d\n", shr));
+		F2DEBUG(("findasg rshape %d\n", shr));
 		F2WALK(r);
 		if (q->needs & REWRITE)
 			break;	/* Done here */
@@ -778,6 +808,23 @@
 	sh = shswitch(sh, p->n_right, qq->rshape, cookie,
 	    qq->rewrite & RRIGHT, gor);
 
+#ifdef mach_pdp11 /* XXX all targets? */
+	lvl = 0;
+	if (cookie == FOREFF)
+		lvl = RVEFF, sh = 0;
+	else if (cookie == FORCC)
+		lvl = RVCC, sh = 0;
+	else if (sh == -1) {
+		sh = ffs(cookie & qq->visit & INREGS)-1;
+#ifdef PCC_DEBUG
+		if (sh == -1)
+			comperr("findasg bad shape");
+#endif
+		SCLASS(lvl,sh);
+	} else
+		SCLASS(lvl,sh);
+	p->n_su = MKIDX(idx, lvl);
+#else
 	if (sh == -1) {
 		if (cookie == FOREFF)
 			sh = 0;
@@ -788,7 +835,10 @@
 
 	p->n_su = MKIDX(idx, 0);
 	SCLASS(p->n_su, sh);
-
+#endif /* mach_pdp11 */
+#ifdef FINDMOPS
+	p->n_flags &= ~1;
+#endif
 	return sh;
 }
 
@@ -812,6 +862,9 @@
 		q = &table[ixp[i]];
 
 		F2DEBUG(("findumul: ixp %d\n", ixp[i]));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
+
 		if ((q->visit & cookie) == 0)
 			continue; /* wrong registers */
 
@@ -874,6 +927,8 @@
 		q = &table[ixp[i]];
 
 		F2DEBUG(("findleaf: ixp %d\n", ixp[i]));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
 		if ((q->visit & cookie) == 0)
 			continue; /* wrong registers */
 
@@ -935,6 +990,9 @@
 		q = &table[ixp[i]];
 
 		F2DEBUG(("finduni: ixp %d\n", ixp[i]));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
+
 		if (ttype(l->n_type, q->ltype) == 0)
 			continue; /* Type must be correct */
 
@@ -993,3 +1051,192 @@
 	SCLASS(p->n_su, sh);
 	return sh;
 }
+
+#ifdef FINDMOPS
+/*
+ * Try to find constructs like "a = a + 1;" and match them together
+ * with instructions like "incl a" or "addl $1,a".
+ *
+ * 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
+findmops(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(("findmops tree: %s\n", prcook(cookie)));
+	F2WALK(p);
+
+	l = getlr(p, 'L');
+	r = getlr(p, 'R');
+	/* See if this is a usable tree to work with */
+	/* Currently only check for leaves */
+	if (optype(r->n_op) != BITYPE || treecmp(l, r->n_left) == 0)
+		return FFAIL;
+
+	F2DEBUG(("findmops is useable\n"));
+
+	/* We can try to find a match.  Use right op */
+	ixp = qtable[r->n_op];
+	l = getlr(r, 'L');
+	r = getlr(r, 'R');
+
+	for (i = 0; ixp[i] >= 0; i++) {
+		q = &table[ixp[i]];
+
+		F2DEBUG(("findmops: ixp %d\n", ixp[i]));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
+
+		if (ttype(l->n_type, q->ltype) == 0 ||
+		    ttype(r->n_type, q->rtype) == 0)
+			continue; /* Types must be correct */
+
+		F2DEBUG(("findmops got types\n"));
+
+		switch (cookie) {
+		case FOREFF:
+			if ((q->visit & FOREFF) == 0)
+				continue; /* Not only for side effects */
+			break;
+		case FORCC:
+			if ((q->visit & FORCC) == 0)
+				continue; /* Not only for side effects */
+			break;
+		default:
+			if ((cookie & q->visit) == 0)
+				continue; /* Won't match requested shape */
+			if (((cookie & INREGS & q->lshape) == 0) || !isreg(l))
+				continue; /* Bad return register */
+			break;
+		}
+		F2DEBUG(("findmops cookie\n"));
+
+		/*
+		 * left shape must match left node.
+		 */
+		if ((shl = tshape(l, q->lshape)) != SRDIR && (shl != SROREG))
+			continue;
+
+		F2DEBUG(("findmops lshape %d\n", shl));
+		F2WALK(l);
+
+		if ((shr = chcheck(r, q->rshape, 0)) == SRNOPE)
+			continue;
+
+		F2DEBUG(("findmops rshape %d\n", shr));
+
+		/*
+		 * Only allow RLEFT. XXX
+		 */
+		if ((q->rewrite & (RLEFT|RRIGHT)) != RLEFT)
+			continue;
+
+		F2DEBUG(("rewrite OK\n"));
+
+		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)
+		return FFAIL;
+	F2DEBUG(("findmops entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor]));
+
+	/*
+	 * Now we're here and have a match. left is semi-direct and 
+	 * right may be anything.
+	 */
+
+	sh = -1;
+	sh = shswitch(sh, p->n_left, qq->lshape, cookie,
+	    qq->rewrite & RLEFT, gol);
+	sh = shswitch(sh, r, qq->rshape, cookie, 0, gor);
+
+	if (sh == -1) {
+		if (cookie & (FOREFF|FORCC))
+			sh = 0;
+		else
+			sh = ffs(cookie & qq->visit & INREGS)-1;
+	}
+	F2DEBUG(("findmops done: node %p class %d\n", p, sh));
+
+	/* Trickery:  Set table index on assign to op instead */
+	/* gencode() will remove useless nodes */
+	p->n_su = MKIDX(idx, 0);
+	p->n_flags |= 1; /* XXX tell gencode to reduce the right tree */
+	SCLASS(p->n_su, sh);
+
+	return sh;
+}
+
+/*
+ * Compare two trees; return 1 if equal and 0 if not.
+ */
+int
+treecmp(NODE *p1, NODE *p2)
+{
+	if (p1->n_op != p2->n_op)
+		return 0;
+
+	switch (p1->n_op) {
+	case UMUL:
+		return treecmp(p1->n_left, p2->n_left);
+
+	case OREG:
+		if (p1->n_lval != p2->n_lval || p1->n_rval != p2->n_rval)
+			return 0;
+		break;
+
+	case NAME:
+	case ICON:
+		if (strcmp(p1->n_name, p2->n_name))
+			return 0;
+		/* FALLTHROUGH */
+		if (p1->n_lval != p2->n_lval)
+			return 0;
+		break;
+
+	case REG:
+	case TEMP:
+		if (p1->n_rval != p2->n_rval)
+			return 0;
+		break;
+	case PLUS:
+	case MINUS:
+		if (treecmp(p1->n_left, p2->n_left) == 0 ||
+		    treecmp(p1->n_right, p2->n_right) == 0)
+			return 0;
+		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+#endif
Index: pass2.h
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/mip/pass2.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/mip/pass2.h -L usr.bin/pcc/mip/pass2.h -u -r1.1 -r1.2
--- usr.bin/pcc/mip/pass2.h
+++ usr.bin/pcc/mip/pass2.h
@@ -1,4 +1,4 @@
-/*	$Id: pass2.h,v 1.98 2006/12/22 06:23:09 ragge Exp $	*/
+/*	$Id: pass2.h,v 1.119 2008/11/22 20:13:50 pantzer Exp $	*/
 /*
  * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
  *
@@ -34,13 +34,14 @@
  */
 #include <sys/types.h>
 
-#include "manifest.h"
-#include "protos.h"
 #ifndef MKEXT
 #include "external.h"
 #else
-typedef int bittype; /* XXX - for basicblock */
+typedef unsigned int bittype; /* XXX - for basicblock */
+#define	BIT2BYTE(a)	(((a) + 31) / 32)
 #endif
+#include "manifest.h"
+#include "protos.h"
 
 /* cookies, used as arguments to codgen */
 #define FOREFF	01		/* compute for effects only */
@@ -50,8 +51,12 @@
 #define INDREG	020		/* compute into a register */
 #define	INREGS	(INAREG|INBREG|INCREG|INDREG)
 #define FORCC	040		/* compute for condition codes only */
+#define QUIET	0100		/* tell geninsn() to not complain if fail */
 #define INTEMP	010000		/* compute into a temporary location */
 #define FORREW	040000		/* search the table for a rewrite rule */
+#define INEREG	0x10000		/* compute into a register, > 16 bits */
+#define INFREG	0x20000		/* compute into a register, > 16 bits */
+#define INGREG	0x40000		/* compute into a register, > 16 bits */
 
 /*
  * OP descriptors,
@@ -91,10 +96,13 @@
 #define SSCON	(SPECIAL|4)	/* -32768 <= constant < 32768 */
 #define SSOREG	(SPECIAL|5)	/* non-indexed OREG */
 #define	MAXSPECIAL	(SPECIAL|5)
+#define SEREG	0x10000		/* same as INEREG */
+#define SFREG	0x20000		/* same as INFREG */
+#define SGREG	0x40000		/* same as INGREG */
 
 /* These are used in rstatus[] in conjunction with SxREG */
-#define	TEMPREG	0100
-#define	PERMREG	0200
+#define	TEMPREG	01000
+#define	PERMREG	02000
 
 /* tshape() return values */
 #define	SRNOPE	0		/* Cannot match any shape */
@@ -140,28 +148,38 @@
 #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
+#define NASL		0x0001	/* may share left register */
+#define NASR		0x0002	/* may share right register */
+#define NAREG		0x0004
+#define NACOUNT		0x000c
+#define NBSL		0x0010
+#define NBSR		0x0020
+#define NBREG		0x0040
+#define NBCOUNT		0x00c0
+#define	NCSL		0x0100
+#define	NCSR		0x0200
+#define	NCREG		0x0400
+#define	NCCOUNT		0x0c00
+#define NTEMP		0x1000
+#define NTMASK		0x3000
+#define NSPECIAL	0x4000	/* need special register treatment */
+#define REWRITE		0x8000
+#define	NDSL		0x00010000	/* Above 16 bit */
+#define	NDSR		0x00020000	/* Above 16 bit */
+#define	NDREG		0x00040000	/* Above 16 bit */
+#define	NDCOUNT		0x000c0000
+#define	NESL		0x00100000	/* Above 16 bit */
+#define	NESR		0x00200000	/* Above 16 bit */
+#define	NEREG		0x00400000	/* Above 16 bit */
+#define	NECOUNT		0x00c00000
+#define	NFSL		0x01000000	/* Above 16 bit */
+#define	NFSR		0x02000000	/* Above 16 bit */
+#define	NFREG		0x04000000	/* Above 16 bit */
+#define	NFCOUNT		0x0c000000
+#define	NGSL		0x10000000	/* Above 16 bit */
+#define	NGSR		0x20000000	/* Above 16 bit */
+#define	NGREG		0x40000000	/* Above 16 bit */
+#define	NGCOUNT		0xc0000000
 
 /* special treatment */
 #define	NLEFT		(0001)	/* left leg register (moveadd) */
@@ -178,14 +196,6 @@
 
 #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 */
@@ -215,14 +225,13 @@
 #endif
 };
 
+struct p2env;
 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),
@@ -230,17 +239,12 @@
 
 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 acceptable(struct optab *);
 int special(NODE *, int);
-#endif
 int setasg(NODE *, int);
 int setuni(NODE *, int);
 int sucomp(NODE *);
@@ -250,9 +254,8 @@
 void adrput(FILE *, NODE *);
 void comperr(char *str, ...);
 void genregs(NODE *p);
-void ngenregs(struct interpass *);
+void ngenregs(struct p2env *);
 NODE *store(NODE *);
-void gencall(NODE *, NODE *prev);
 struct interpass *ipnode(NODE *);
 void deflab(int);
 void rmove(int, int, TWORD);
@@ -265,14 +268,29 @@
 int findumul(NODE *p, int);
 int findleaf(NODE *p, int);
 int relops(NODE *p);
+#ifdef FINDMOPS
+int findmops(NODE *p, int);
+int treecmp(NODE *p1, NODE *p2);
+#endif
 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 *);
-
+int *livecall(NODE *);
+void prtreg(FILE *, NODE *);
 char *prcook(int);
+int myxasm(struct interpass *ip, NODE *p);
+int xasmcode(char *s);
+int freetemp(int k);
+int rewfld(NODE *p);
+void canon(NODE *);
+void mycanon(NODE *);
+void oreg2(NODE *p, void *);
+int shumul(NODE *p, int);
+NODE *deluseless(NODE *p);
+int getlab2(void);
 
 void conput(FILE *, NODE *);
 
@@ -289,6 +307,17 @@
 #define	CLASSC	3
 #define	CLASSD	4
 #define	CLASSE	5
+#define	CLASSF	6
+#define	CLASSG	7
+
+/* used when parsing xasm codes */
+#define	XASMVAL(x)	((x) & 0377)	/* get val from codeword */
+#define	XASMASG		0x100	/* = */
+#define	XASMCONSTR	0x200	/* & */
+#define	XASMINOUT	0x400	/* + */
+#define XASMALL		(XASMASG|XASMCONSTR|XASMINOUT)
+#define	XASMISINP(cw)	(((cw) & XASMASG) == 0)		/* input operand */
+#define	XASMISOUT(cw)	((cw) & (XASMASG|XASMINOUT))	/* output operand */
 
 /* routines to handle double indirection */
 #ifdef R2REGS
@@ -299,8 +328,8 @@
 
 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 lflag, x2debug, udebug, e2debug, odebug;
+extern	int rdebug, t2debug, s2debug, b2debug, c2debug;
 extern	int kflag;
 #ifdef FORT
 extern	int Oflag;
@@ -330,24 +359,17 @@
 
 /*
  * 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
+ *      bit 0 whether left shall go into a register.
+ *      bit 1 whether right shall go into a register.
+ *      bit 2 entry is only used for side effects.
+ *      bit 3 if condition codes are used.
  *
- * LOREG means: walk down left node, after code emission call canon() to
- *  convert the tree to an OREG.
+ * These values should be synced with FOREFF/FORCC.
  */
 #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 RREG		002
+#define	RVEFF		004
+#define	RVCC		010
 #define DORIGHT		020
 #define	SCLASS(v,x)	((v) |= ((x) << 5))
 #define	TCLASS(x)	(((x) >> 5) & 7)
@@ -360,9 +382,12 @@
 #define	TBREGS	0
 #endif
 #define	REGBIT(x) (1 << (x))
+#ifndef PERMTYPE
+#define	PERMTYPE(a)	(INT)
+#endif
 
 void emit(struct interpass *);
-void optimize(struct interpass *);
+void optimize(struct p2env *);
 
 struct basicblock {
 	DLIST_ENTRY(basicblock) bbelem;
@@ -380,23 +405,25 @@
 	bittype *dfchildren;
 	bittype *Aorig;
 	bittype *Aphi;
+	SLIST_HEAD(, phiinfo) phi;
 	struct interpass *first; /* first element of basic block */
 	struct interpass *last;  /* last element of basic block */
 };
 
 struct labelinfo {
 	struct basicblock **arr;
-	unsigned int size;
+	int size;
 	unsigned int low;
 };
 
 struct bblockinfo {
-	unsigned int size;
+	int size;
 	struct basicblock **arr;
 };
 
 struct varinfo {
 	struct pvarinfo **arr;
+	SLIST_HEAD(, varstack) *stack;
 	int size;
 	int low;
 };
@@ -404,14 +431,44 @@
 struct pvarinfo {
 	struct pvarinfo *next;
 	struct basicblock *bb;
-	NODE *top, *n;
+	TWORD n_type;
+};
+
+struct varstack {
+	SLIST_ENTRY(varstack) varstackelem;
+	int tmpregno;
 };
 
+
 struct cfgnode {
 	SLIST_ENTRY(cfgnode) cfgelem;
 	struct basicblock *bblock;
 };
 
+struct phiinfo {
+	SLIST_ENTRY(phiinfo) phielem;
+	int tmpregno;
+	int newtmpregno;
+	TWORD n_type;
+	int size;
+	int *intmpregno;
+};
+
+/*
+ * Description of the pass2 environment.
+ * There will be only one of these structs.  It is used to keep
+ * all state descriptions during the compilation of a function
+ * in one place.
+ */
+struct p2env {
+	struct interpass ipole;			/* all statements */
+	struct interpass_prolog *ipp, *epp;	/* quick references */
+	struct basicblock bblocks;
+	int nbblocks;
+};
+
+extern struct p2env p2env;
+
 /*
  * C compiler second pass extra defines.
  */
Index: regs.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/mip/regs.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/mip/regs.c -L usr.bin/pcc/mip/regs.c -u -r1.1 -r1.2
--- usr.bin/pcc/mip/regs.c
+++ usr.bin/pcc/mip/regs.c
@@ -1,4 +1,4 @@
-/*	$Id: regs.c,v 1.155 2007/09/22 17:15:00 ragge Exp $	*/
+/*	$Id: regs.c,v 1.198 2008/12/14 18:26:02 ragge Exp $	*/
 /*
  * Copyright (c) 2005 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -28,11 +28,22 @@
 
 #include "pass2.h"
 #include <string.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
 #include <stdlib.h>
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
 
 #define	MAXLOOP	20 /* Max number of allocation loops XXX 3 should be enough */
 
+#ifndef MAX
 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
  
 /*
  * New-style register allocator using graph coloring.
@@ -40,9 +51,8 @@
  * "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); }
+	int sz__s = BIT2BYTE(sz); ptr = all(sz__s); memset(ptr, 0, sz__s); }
 
 #undef COMPERR_PERM_MOVE
 #define	RDEBUG(x)	if (rdebug) printf x
@@ -50,6 +60,9 @@
 #define	RPRINTIP(x)	if (rdebug) printip(x)
 #define	RDX(x)		x
 #define UDEBUG(x)	if (udebug) printf x
+#define BDEBUG(x)	if (b2debug) printf x
+
+#define	VALIDREG(p)	(p->n_op == REG && TESTBIT(validregs, regno(p)))
 
 /*
  * Data structure overview for this implementation of graph coloring:
@@ -124,6 +137,7 @@
 static REGW initial, *nblock;
 static void insnwalk(NODE *p);
 #ifdef PCC_DEBUG
+int use_regw;
 int nodnum = 100;
 #define	SETNUM(x)	(x)->nodnum = nodnum++
 #define	ASGNUM(x)	(x)->nodnum
@@ -132,7 +146,7 @@
 #define ASGNUM(x)
 #endif
 
-#define	ALLNEEDS (NACOUNT|NBCOUNT|NCCOUNT|NDCOUNT)
+#define	ALLNEEDS (NACOUNT|NBCOUNT|NCCOUNT|NDCOUNT|NECOUNT|NFCOUNT|NGCOUNT)
 
 /* XXX */
 REGW *ablock;
@@ -157,17 +171,21 @@
 static REGW *
 newblock(NODE *p)
 {
-	REGW *nb = &nblock[(int)p->n_lval];
+	REGW *nb = &nblock[regno(p)];
 	if (nb->link.q_forw == 0) {
 		DLIST_INSERT_AFTER(&initial, nb, link);
-		ASGNUM(nb) = p->n_lval;
+#ifdef PCC_DEBUG
+		ASGNUM(nb) = regno(p);
 		RDEBUG(("Adding longtime %d for tmp %d\n",
-		    nb->nodnum, (int)p->n_lval));
+		    nb->nodnum, regno(p)));
+#endif
 	}
 	if (nb->r_class == 0)
 		nb->r_class = gclass(p->n_type);
+#ifdef PCC_DEBUG
 	RDEBUG(("newblock: p %p, node %d class %d\n",
 	    p, nb->nodnum, nb->r_class));
+#endif
 	return nb;
 }
 
@@ -191,7 +209,7 @@
 	struct optab *q;
 	int left, right;
 	int nreg, need, i, nxreg, o;
-	int nareg, nbreg, ncreg, ndreg;
+	int nareg, nbreg, ncreg, ndreg, nereg, nfreg, ngreg;
 	REGW *w;
 
 	o = optype(p->n_op);
@@ -205,6 +223,8 @@
 		if (o == LTYPE ) {
 			if (p->n_op == TEMP)
 				p->n_regw = newblock(p);
+			else if (p->n_op == REG)
+				p->n_regw = &ablock[regno(p)];
 		} else
 			a = nsucomp(p->n_left);
 		if (o == BITYPE) {
@@ -217,16 +237,23 @@
 	}
 
 	q = &table[TBLIDX(p->n_su)];
-	nareg = (q->needs & NACOUNT);
 
+	for (i = (q->needs & NACOUNT), nareg = 0; i; i -= NAREG)
+		nareg++;
 	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++;
+	for (i = (q->needs & NECOUNT), nereg = 0; i; i -= NEREG)
+		nereg++;
+	for (i = (q->needs & NFCOUNT), nfreg = 0; i; i -= NFREG)
+		nfreg++;
+	for (i = (q->needs & NGCOUNT), ngreg = 0; i; i -= NGREG)
+		ngreg++;
 
-	nxreg = nareg + nbreg + ncreg + ndreg;
+	nxreg = nareg + nbreg + ncreg + ndreg + nereg + nfreg + ngreg;
 	nreg = nxreg;
 	if (callop(p->n_op))
 		nreg = MAX(fregs, nreg);
@@ -276,11 +303,18 @@
 		return need;
 	}
 
+#ifdef PCC_DEBUG
 #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)); \
 	}
+#else
+#define	ADCL(n, cl)	\
+	for (i = 0; i < n; i++, w++) {	w->r_class = cl; \
+		DLIST_INSERT_BEFORE(&initial, w, link);  SETNUM(w); \
+	}
+#endif
 
 	UDEBUG(("node %p numregs %d\n", p, nxreg+1));
 	w = p->n_regw = tmpalloc(sizeof(REGW) * (nxreg+1));
@@ -293,12 +327,17 @@
 	SETNUM(w);
 	if (w->r_class)
 		DLIST_INSERT_BEFORE(&initial, w, link);
-	UDEBUG(("Adding short %d calss %d\n", w->nodnum, w->r_class));
+#ifdef PCC_DEBUG
+	UDEBUG(("Adding short %d class %d\n", w->nodnum, w->r_class));
+#endif
 	w++;
 	ADCL(nareg, CLASSA);
 	ADCL(nbreg, CLASSB);
 	ADCL(ncreg, CLASSC);
 	ADCL(ndreg, CLASSD);
+	ADCL(nereg, CLASSE);
+	ADCL(nfreg, CLASSF);
+	ADCL(ngreg, CLASSG);
 
 	if (q->rewrite & RESC1) {
 		w = p->n_regw + 1;
@@ -361,9 +400,13 @@
 #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);
+	if (i < 0 || i > 1)
+		comperr("trivially_colorable_p");
+#ifdef PCC_DEBUG
+	if (rdebug > 1)
+		printf("trivially_colorable_p: n[1] %d n[2] %d n[3] %d n[4] "
+		    "%d for class %d, triv %d\n", n[1], n[2], n[3], n[4], c, i);
+#endif
 	return i;
 }
 
@@ -380,10 +423,16 @@
 		needs -= NCREG, i++;
 	while (needs & NDCOUNT)
 		needs -= NDREG, i++;
+	while (needs & NECOUNT)
+		needs -= NEREG, i++;
+	while (needs & NFCOUNT)
+		needs -= NFREG, i++;
+	while (needs & NGCOUNT)
+		needs -= NGREG, i++;
 	return i;
 }
 
-static inline REGW *
+static REGW *
 popwlist(REGW *l)
 {
 	REGW *w = DLIST_NEXT(l, link);
@@ -400,7 +449,7 @@
 	worklistMoves, activeMoves;
 enum { COAL, CONSTR, FROZEN, WLIST, ACTIVE };
 
-static inline REGM *
+static REGM *
 popmlist(REGM *l)
 {
 	REGM *w = DLIST_NEXT(l, link);
@@ -418,7 +467,7 @@
  *
  * 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
+ * and killed 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 
@@ -430,21 +479,31 @@
 LIVEADD(int x)
 {
 	RDEBUG(("Liveadd: %d\n", x));
-	if (x < tempmin || x >= tempmax)
+	if (x >= MAXREGS && (x < tempmin || x >= tempmax))
 		comperr("LIVEADD: out of range");
-	BITSET(live, (x-tempmin));
+	if (x < MAXREGS) {
+		BITSET(live, x);
+	} else
+		BITSET(live, (x-tempmin+MAXREGS));
 }
+
 static void
 LIVEDEL(int x)
 {
 	RDEBUG(("Livedel: %d\n", x));
-	if (x < tempmin || x >= tempmax)
+
+	if (x >= MAXREGS && (x < tempmin || x >= tempmax))
 		comperr("LIVEDEL: out of range");
-	BITCLEAR(live, (x-tempmin));
+	if (x < MAXREGS) {
+		BITCLEAR(live, x);
+	} else
+		BITCLEAR(live, (x-tempmin+MAXREGS));
 }
 #else
-#define LIVEADD(x) BITSET(live, (x-tempmin))
-#define LIVEDEL(x) BITCLEAR(live, (x-tempmin))
+#define LIVEADD(x) \
+	(x >= MAXREGS ? BITSET(live, (x-tempmin+MAXREGS)) : BITSET(live, x))
+#define LIVEDEL(x) \
+	(x >= MAXREGS ? BITCLEAR(live, (x-tempmin+MAXREGS)) : BITCLEAR(live, x))
 #endif
 
 static struct lives {
@@ -479,7 +538,9 @@
 {
 	struct lives *l;
 
+#ifdef PCC_DEBUG
 	RDEBUG(("LIVEDELR: %d\n", x->nodnum));
+#endif
 	DLIST_FOREACH(l, &lused, link) {
 		if (l->var != x)
 			continue;
@@ -515,10 +576,11 @@
 	return w;
 }
 
+#define	HASHSZ	16384
 struct AdjSet {
 	struct AdjSet *next;
 	REGW *u, *v;
-} *edgehash[256];
+} *edgehash[HASHSZ];
 
 /* Check if a node pair is adjacent */
 static int
@@ -543,7 +605,7 @@
 	}
 	if (u > v)
 		t = v, v = u, u = t;
-	w = edgehash[((long)u+(long)v) & 255];
+	w = edgehash[((intptr_t)u+(intptr_t)v) & (HASHSZ-1)];
 	for (; w; w = w->next) {
 		if (u == w->u && v == w->v)
 			return 1;
@@ -561,7 +623,7 @@
 
 	if (u > v)
 		t = v, v = u, u = t;
-	x = ((long)u+(long)v) & 255;
+	x = ((intptr_t)u+(intptr_t)v) & (HASHSZ-1);
 	w = tmpalloc(sizeof(struct AdjSet));
 	w->u = u, w->v = v;
 	w->next = edgehash[x];
@@ -576,9 +638,9 @@
 {
 	ADJL *x;
 
+#ifdef PCC_DEBUG
 	RRDEBUG(("AddEdge: u %d v %d\n", ASGNUM(u), ASGNUM(v)));
 
-#ifdef PCC_DEBUG
 #if 0
 	if (ASGNUM(u) == 0)
 		comperr("AddEdge 0");
@@ -678,10 +740,11 @@
 addalledges(REGW *e)
 {
 	int i, j, k;
-	int nbits = xbits;
 	struct lives *l;
 
+#ifdef PCC_DEBUG
 	RDEBUG(("addalledges for %d\n", e->nodnum));
+#endif
 
 	if (e->r_class == -1)
 		return; /* unused */
@@ -691,14 +754,17 @@
 			AddEdge(e, &ablock[ndontregs[i]]);
 	}
 
-	/* First add to long-lived temps */
+	/* First add to long-lived temps and hard regs */
 	RDEBUG(("addalledges longlived "));
-	for (i = 0; i < nbits; i += NUMBITS) {
+	for (i = 0; i < xbits; i += NUMBITS) {
 		if ((k = live[i/NUMBITS]) == 0)
 			continue;
 		while (k) {
 			j = ffs(k)-1;
-			AddEdge(&nblock[i+j+tempmin], e);
+			if (i+j < MAXREGS)
+				AddEdge(&ablock[i+j], e);
+			else
+				AddEdge(&nblock[i+j+tempmin-MAXREGS], e);
 			RRDEBUG(("%d ", i+j+tempmin));
 			k &= ~(1 << j);
 		}
@@ -707,7 +773,9 @@
 	/* short-lived temps */
 	RDEBUG(("addalledges shortlived "));
 	DLIST_FOREACH(l, &lused, link) {
+#ifdef PCC_DEBUG
 		RRDEBUG(("%d ", ASGNUM(l->var)));
+#endif
 		AddEdge(l->var, e);
 	}
 	RDEBUG(("done\n"));
@@ -723,7 +791,9 @@
 
 	if (def == use)
 		return; /* no move to itself XXX - ``shouldn't happen'' */
+#ifdef PCC_DEBUG
 	RDEBUG(("moveadd: def %d use %d\n", ASGNUM(def), ASGNUM(use)));
+#endif
 
 	r = WORKLISTMOVEADD(use, def);
 	MOVELISTADD(def, r);
@@ -754,23 +824,25 @@
 setlive(NODE *p, int set, REGW *rv)
 {
 	if (rv != NULL) {
+		if (rv->nodnum < MAXREGS &&
+		    TESTBIT(validregs, rv->nodnum) == 0)
+			return;
 		set ? LIVEADDR(rv) : LIVEDELR(rv);
 		return;
 	}
 
 	if (p->n_regw != NULL) {
+		if (p->n_regw->nodnum < MAXREGS &&
+		    TESTBIT(validregs, p->n_regw->nodnum) == 0)
+			return;
 		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
+		if (p->n_op == TEMP || VALIDREG(p))
+			set ? LIVEADD(regno(p)) : LIVEDEL(regno(p));
 		break;
 	case BITYPE:
 		setlive(p->n_right, set, rv);
@@ -788,7 +860,12 @@
 static void
 addedge_r(NODE *p, REGW *w)
 {
+	RRDEBUG(("addedge_r: node %p regw %p\n", p, w));
+
 	if (p->n_regw != NULL) {
+		if (p->n_regw->nodnum < MAXREGS &&
+		    TESTBIT(validregs, p->n_regw->nodnum) == 0)
+			return;
 		AddEdge(p->n_regw, w);
 		return;
 	}
@@ -800,6 +877,50 @@
 }
 
 /*
+ * add/del parameter from live set.
+ */
+static void
+setxarg(NODE *p)
+{
+	int i, ut = 0, in = 0;
+	int cw;
+
+	if (p->n_op == ICON && p->n_type == STRTY)
+		return;
+
+	RDEBUG(("setxarg %p %s\n", p, p->n_name));
+	cw = xasmcode(p->n_name);
+	if (XASMISINP(cw))
+		in = 1;
+	if (XASMISOUT(cw))
+		ut = 1;
+
+	switch (XASMVAL(cw)) {
+	case 'g':
+		if (p->n_left->n_op != REG && p->n_left->n_op != TEMP)
+			break;
+		/* FALLTHROUGH */
+	case 'r':
+		i = regno(p->n_left);
+		if (ut) {
+			REGW *rw = p->n_left->n_op == REG ? ablock : nblock;
+			LIVEDEL(i);
+			addalledges(&rw[i]);
+		}
+		if (in) {
+			LIVEADD(i);
+		}
+		break;
+	case 'i':
+	case 'm':
+	case 'n':
+		break;
+	default:
+		comperr("bad ixarg %s", p->n_name);
+	}
+}
+
+/*
  * Do the in-tree part of liveness analysis. (the difficult part)
  *
  * Walk down the tree in reversed-evaluation order (backwards).
@@ -825,14 +946,13 @@
  * 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;
+	NODE *lp, *rp;
 	int i, n;
 
 	RDEBUG(("insnwalk %p\n", p));
@@ -840,14 +960,16 @@
 	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]);
+	if (p->n_op == ASSIGN &&
+	    (p->n_left->n_op == TEMP || VALIDREG(p->n_left))) {
+		lr = p->n_left->n_op == TEMP ? nblock : ablock;
+		i = regno(p->n_left);
+		LIVEDEL(i);	/* remove assigned temp from live set */
+		addalledges(&lr[i]);
 	}
 
 	/* Add edges for the result of this node */
-	if (rv && (q->visit & INREGS || o == TEMP))	
+	if (rv && (q->visit & INREGS || o == TEMP || VALIDREG(p)))	
 		addalledges(rv);
 
 	/* special handling of CALL operators */
@@ -866,24 +988,36 @@
 
 	/* Check leaves for results in registers */
 	lr = optype(o) != LTYPE ? p->n_left->n_regw : NULL;
+	lp = optype(o) != LTYPE ? p->n_left : NULL;
 	rr = optype(o) == BITYPE ? p->n_right->n_regw : NULL;
+	rp = optype(o) == BITYPE ? p->n_right : 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 };
-		
+		static int ncl[] =
+		    { 0, NASL, NBSL, NCSL, NDSL, NESL, NFSL, NGSL };
+		static int ncr[] =
+		    { 0, NASR, NBSR, NCSR, NDSR, NESR, NFSR, NGSR };
+		int j;
+
 		/* edges are already added */
-		if ((r = &p->n_regw[1+i])->r_class == -1)
+		if ((r = &p->n_regw[1+i])->r_class == -1) {
 			r = p->n_regw;
-		else
+		} else {
+			AddEdge(r, p->n_regw);
 			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);
+		for (j = i + 1; j < n; j++) {
+			if (p->n_regw[j+1].r_class == -1)
+				continue;
+			AddEdge(r, &p->n_regw[j+1]);
+		}
 #else
 		if ((r = &p->n_regw[1+i])->r_class == -1)
 			continue;
@@ -924,6 +1058,13 @@
 	}
 
 	if (o == ASSIGN) {
+		/* avoid use of unhandled registers */
+		if (p->n_left->n_op == REG &&
+		    !TESTBIT(validregs, regno(p->n_left)))
+			lr = NULL;
+		if (p->n_right->n_op == REG &&
+		    !TESTBIT(validregs, regno(p->n_right)))
+			rr = NULL;
 		/* needs special treatment */
 		if (lr && rr)
 			moveadd(lr, rr);
@@ -932,33 +1073,31 @@
 		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 */
+		int *c;
+
+		for (c = livecall(p); *c != -1; c++) {
+			addalledges(ablock + *c);
+			LIVEADD(*c);
+		}
 	} 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);
+		if (rv && rp)
+			addedge_r(rp, rv);
 	} else if (q->rewrite & RRIGHT) {
 		if (rr && rv)
 			moveadd(rv, rr), rrv = rv;
-		if (lr && rv)
-			AddEdge(lr, rv);
+		if (rv && lp)
+			addedge_r(lp, rv);
 	}
 
 	switch (optype(o)) {
 	case BITYPE:
-		if (ASGLEFT(p)) {
+		if (p->n_op == ASSIGN &&
+		    (p->n_left->n_op == TEMP || p->n_left->n_op == REG)) {
 			/* only go down right node */
 			insnwalk(p->n_right);
 		} else if (callop(o)) {
@@ -984,18 +1123,23 @@
 
 	case LTYPE:
 		switch (o) {
+		case REG:
+			if (!TESTBIT(validregs, regno(p)))
+				break; /* never add moves */
+			/* FALLTHROUGH */
 		case TEMP:
-			rr = &nblock[(int)p->n_lval];
+			i = regno(p);
+			rr = (o == TEMP ? &nblock[i] :  &ablock[i]);
 			if (rv != rr) {
 				addalledges(rr);
 				moveadd(rv, rr);
 			}
-			LIVEADD((int)p->n_lval);
-			break;
-		case REG:
-		case OREG:
-			/* Liveness for regs??? */
+			LIVEADD(i);
 			break;
+
+		case OREG: /* XXX - not yet */
+			break; 
+
 		default:
 			break;
 		}
@@ -1003,8 +1147,218 @@
 	}
 }
 
-static bittype **gen, **kill, **in, **out;
+static bittype **gen, **killed, **in, **out;
+
+#define	MAXNSPILL	100
+static int notspill[MAXNSPILL], nspill;
+
+static int
+innotspill(int n)
+{
+	int i;
+	for (i = 0; i < nspill; i++)
+		if (notspill[i] == n)
+			return 1;
+	return 0;
+}
+
+/*
+ * Found an extended assembler node, so growel out gen/killed nodes.
+ */
+static void
+xasmionize(NODE *p, void *arg)
+{
+	int bb = *(int *)arg;
+	int cw, b;
+
+	if (p->n_op == ICON && p->n_type == STRTY)
+		return; /* dummy end marker */
+
+	cw = xasmcode(p->n_name);
+	if (XASMVAL(cw) == 'n' || XASMVAL(cw) == 'm')
+		return; /* no flow analysis */
+	p = p->n_left;
+
+	if (XASMVAL(cw) == 'g' && p->n_op != TEMP && p->n_op != REG)
+		return; /* no flow analysis */
+
+	b = regno(p);
+	if (XASMVAL(cw) == 'r' && p->n_op == TEMP) {
+		if (!innotspill(b)) {
+			if (nspill < MAXNSPILL)
+				notspill[nspill++] = b;
+			else
+				werror("MAXNSPILL overbooked");
+		}
+	}
+	if (XASMISOUT(cw)) {
+		if (p->n_op == TEMP) {
+			b -= tempmin+MAXREGS;
+			BITCLEAR(gen[bb], b);
+			BITSET(killed[bb], b);
+		} else if (p->n_op == REG) {
+			BITCLEAR(gen[bb], b);
+			BITSET(killed[bb], b);
+		} else
+			uerror("bad xasm node type");
+	}
+	if (XASMISINP(cw)) {
+		if (p->n_op == TEMP) {
+			BITSET(gen[bb], (b - tempmin+MAXREGS));
+		} else if (p->n_op == REG) {
+			BITSET(gen[bb], b);
+		} else if (optype(p->n_op) != LTYPE) {
+			if (XASMVAL(cw) == 'r')
+				uerror("couldn't find available register");
+			else
+				uerror("bad xasm node type2");
+		}
+	}
+}
+
+#ifndef XASMCONSTREGS
+#define	XASMCONSTREGS(x) (-1)
+#endif
+
+/*
+ * Check that given constraints are valid.
+ */
+static void
+xasmconstr(NODE *p, void *arg)
+{
+	int i;
+
+	if (p->n_op == ICON && p->n_type == STRTY)
+		return; /* no constraints */
+
+	if (strcmp(p->n_name, "cc") == 0 || strcmp(p->n_name, "memory") == 0)
+		return;
+
+	for (i = 0; i < MAXREGS; i++)
+		if (strcmp(rnames[i], p->n_name) == 0) {
+			addalledges(&ablock[i]);
+			return;
+		}
+	if ((i = XASMCONSTREGS(p->n_name)) < 0)
+		comperr("unsupported xasm constraint %s", p->n_name);
+	addalledges(&ablock[i]);
+}
+
+#define	RUP(x) (((x)+NUMBITS-1)/NUMBITS)
+#define	SETCOPY(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] = f[i]
+#define	SETSET(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] |= f[i]
+#define	SETCLEAR(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] &= ~f[i]
+#define	SETCMP(v,t,f,i,n) for (i = 0; i < RUP(n); i++) \
+	if (t[i] != f[i]) v = 1
+#define	SETEMPTY(t,sz)	memset(t, 0, BIT2BYTE(sz))
+
+static int
+deldead(NODE *p, bittype *lvar)
+{
+	NODE *q;
+	int ty, rv = 0;
+
+#define	BNO(p) (regno(p) - tempmin+MAXREGS)
+	if (p->n_op == TEMP)
+		BITSET(lvar, BNO(p));
+	if (asgop(p->n_op) && p->n_left->n_op == TEMP &&
+	    TESTBIT(lvar, BNO(p->n_left)) == 0) {
+		/*
+		 * Not live, must delete the right tree at least 
+		 * down to next statement with side effects.
+		 */
+		BDEBUG(("DCE deleting temp %d\n", regno(p->n_left)));
+		nfree(p->n_left);
+		q = p->n_right;
+		*p = *q;
+		nfree(q);
+		rv = 1;
+	}
+	ty = optype(p->n_op);
+	if (ty != LTYPE)
+		rv |= deldead(p->n_left, lvar);
+	if (ty == BITYPE)
+		rv |= deldead(p->n_right, lvar);
+	return rv;
+}
+
+/*
+ * Do dead code elimination.
+ */
+static int
+dce(struct p2env *p2e)
+{
+	extern struct interpass prepole;
+	struct basicblock *bb;
+	struct interpass *ip;
+	NODE *p;
+	bittype *lvar;
+	int i, bbnum, fix = 0;
+
+	BDEBUG(("Entering DCE\n"));
+	/*
+	 * Traverse over the basic blocks.
+	 * if an assignment is found that writes to a temporary
+	 * that is not live out, remove that assignment and its legs.
+	 */
+	DLIST_INIT(&prepole, qelem);
+	BITALLOC(lvar, alloca, xbits);
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		bbnum = bb->bbnum;
+		BDEBUG(("DCE bblock %d, start %p last %p\n",
+		    bbnum, bb->first, bb->last));
+		SETCOPY(lvar, out[bbnum], i, xbits);
+		for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) {
+			if (ip->type == IP_NODE && deldead(ip->ip_node, lvar)) {
+				if ((p = deluseless(ip->ip_node)) == NULL) {
+#ifdef notyet
+					if (ip == bb->last) {
+						bb->last =
+						    DLIST_PREV(ip, qelem);
+					} else if (ip == bb->first) {
+						bb->first =
+						    DLIST_NEXT(ip, qelem);
+					}
+					DLIST_REMOVE(ip, qelem);
+#else
+					ip->type = IP_ASM;
+					ip->ip_asm = "";
+#endif
+					fix++;
+					BDEBUG(("DCE ip %p deleted\n", ip));
+				} else while (!DLIST_ISEMPTY(&prepole, qelem)) {
 
+					BDEBUG(("DCE doing ip prepend\n"));
+#ifdef notyet
+					struct interpass *tipp;
+					tipp = DLIST_NEXT(&prepole, qelem);
+					DLIST_REMOVE(tipp, qelem);
+					DLIST_INSERT_BEFORE(ip, tipp, qelem);
+					if (ip == bb->first)
+						bb->first = tipp;
+					fix++;
+#else
+					comperr("dce needs bb fixup");
+#endif
+					BDEBUG(("DCE ip prepended\n"));
+				}
+				if (ip->type == IP_NODE) {
+					geninsn(p, FOREFF);
+					nsucomp(p);
+					ip->ip_node = p;
+				}
+			}
+			if (ip == bb->first)
+				break;
+		}
+	}
+	BDEBUG(("DCE fix %d\n", fix));
+	return fix;
+}
+
+/*
+ * Set/clear long term liveness for regs and temps.
+ */
 static void
 unionize(NODE *p, int bb)
 {
@@ -1013,27 +1367,37 @@
 	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));
+			BITSET(gen[bb], (regno(p) - tempmin+i+MAXREGS));
 		}
 #else
 		i = 0;
-		BITSET(gen[bb], ((int)p->n_lval - tempmin+i));
+		BITSET(gen[bb], (regno(p) - tempmin+i+MAXREGS));
 #endif
+	} else if (VALIDREG(p)) {
+		BITSET(gen[bb], regno(p));
 	}
-	if (asgop(o) && p->n_left->n_op == TEMP) {
-		int b = p->n_left->n_lval - tempmin;
+	if (asgop(o)) {
+		if (p->n_left->n_op == TEMP) {
+			int b = regno(p->n_left) - tempmin+MAXREGS;
 #ifdef notyet
-		for (i = 0; i < szty(p->n_type); i++) {
-			BITCLEAR(gen[bb], (b+i));
-			BITSET(kill[bb], (b+i));
-		}
+			for (i = 0; i < szty(p->n_type); i++) {
+				BITCLEAR(gen[bb], (b+i));
+				BITSET(killed[bb], (b+i));
+			}
 #else
-		i = 0;
-		BITCLEAR(gen[bb], (b+i));
-		BITSET(kill[bb], (b+i));
+			i = 0;
+			BITCLEAR(gen[bb], (b+i));
+			BITSET(killed[bb], (b+i));
 #endif
-		unionize(p->n_right, bb);
-		return;
+			unionize(p->n_right, bb);
+			return;
+		} else if (VALIDREG(p->n_left)) {
+			int b = regno(p->n_left);
+			BITCLEAR(gen[bb], b);
+			BITSET(killed[bb], b);
+			unionize(p->n_right, bb);
+			return;
+		}
 	}
 	ty = optype(o);
 	if (ty != LTYPE)
@@ -1049,62 +1413,60 @@
  * when doing short-range liveness analysis in Build().
  */
 static void
-LivenessAnalysis(void)
+LivenessAnalysis(struct p2env *p2e)
 {
-	extern struct basicblock bblocks;
 	struct basicblock *bb;
 	struct interpass *ip;
 	int i, bbnum;
 
 	/*
-	 * generate the gen-kill sets for all basic blocks.
+	 * generate the gen-killed sets for all basic blocks.
 	 */
-	DLIST_FOREACH(bb, &bblocks, bbelem) {
+	DLIST_FOREACH(bb, &p2e->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);
+			/* gen/killed is 'p', this node is 'n' */
+			if (ip->type == IP_NODE) {
+				if (ip->ip_node->n_op == XASM)
+					flist(ip->ip_node->n_left,
+					    xasmionize, &bbnum);
+				else
+					unionize(ip->ip_node, bbnum);
+			}
 			if (ip == bb->first)
 				break;
 		}
-		memcpy(in[bbnum], gen[bbnum], BIT2BYTE(tempmax-tempmin));
+		memcpy(in[bbnum], gen[bbnum], BIT2BYTE(xbits));
 #ifdef PCC_DEBUG
+#define	PRTRG(x) printf("%d ", i < MAXREGS ? i : i + tempmin-MAXREGS)
 		if (rdebug) {
 			printf("basic block %d\ngen: ", bbnum);
-			for (i = 0; i < tempmax-tempmin; i++)
+			for (i = 0; i < xbits; 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);
+					PRTRG(i);
+			printf("\nkilled: ");
+			for (i = 0; i < xbits; i++)
+				if (TESTBIT(killed[bbnum], i))
+					PRTRG(i);
 			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)
+Build(struct p2env *p2e)
 {
-	extern struct basicblock bblocks;
+	struct interpass *ipole = &p2e->ipole;
 	struct basicblock bbfake;
 	struct interpass *ip;
 	struct basicblock *bb;
 	struct cfgnode *cn;
-	extern int nbblocks;
 	bittype *saved;
-	int i, j, again, nbits;
+	int i, j, again;
 
 	if (xtemps == 0) {
 		/*
@@ -1112,35 +1474,37 @@
 		 * so fake one basic block to keep the liveness analysis 
 		 * happy.
 		 */
-		nbblocks = 1;
+		p2e->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);
+		DLIST_INIT(&p2e->bblocks, bbelem);
+		DLIST_INSERT_AFTER(&p2e->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();
+	gen = alloca(p2e->nbblocks*sizeof(bittype*));
+	killed = alloca(p2e->nbblocks*sizeof(bittype*));
+	in = alloca(p2e->nbblocks*sizeof(bittype*));
+	out = alloca(p2e->nbblocks*sizeof(bittype*));
+	for (i = 0; i < p2e->nbblocks; i++) {
+		BITALLOC(gen[i],alloca,xbits);
+		BITALLOC(killed[i],alloca,xbits);
+		BITALLOC(in[i],alloca,xbits);
+		BITALLOC(out[i],alloca,xbits);
+	}
+	BITALLOC(saved,alloca,xbits);
+
+	nspill = 0;
+livagain:
+	LivenessAnalysis(p2e);
 
 	/* register variable temporaries are live */
 	for (i = 0; i < NPERMREG-1; i++) {
 		if (nsavregs[i])
 			continue;
-		BITSET(out[nbblocks-1], i);
+		BITSET(out[p2e->nbblocks-1], (i+MAXREGS));
 		for (j = i+1; j < NPERMREG-1; j++) {
 			if (nsavregs[j])
 				continue;
@@ -1152,47 +1516,73 @@
 	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);
+		DLIST_FOREACH_REVERSE(bb, &p2e->bblocks, bbelem) {
+			i = bb->bbnum;
+			SETCOPY(saved, out[i], j, xbits);
 			SLIST_FOREACH(cn, &bb->children, cfgelem) {
-				SETSET(out[i], in[cn->bblock->bbnum],
-				    j, nbits);
+				SETSET(out[i], in[cn->bblock->bbnum], j, xbits);
 			}
-			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);
+			SETCMP(again, saved, out[i], j, xbits);
+			SETCOPY(saved, in[i], j, xbits);
+			SETCOPY(in[i], out[i], j, xbits);
+			SETCLEAR(in[i], killed[i], j, xbits);
+			SETSET(in[i], gen[i], j, xbits);
+			SETCMP(again, saved, in[i], j, xbits);
 		}
 	} while (again);
 
 #ifdef PCC_DEBUG
 	if (rdebug) {
-		DLIST_FOREACH(bb, &bblocks, bbelem) {
+		DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
 			printf("basic block %d\nin: ", bb->bbnum);
-			for (i = 0; i < tempmax-tempmin; i++)
+			for (i = 0; i < xbits; i++)
 				if (TESTBIT(in[bb->bbnum], i))
-					printf("%d ", i+tempmin);
+					PRTRG(i);
 			printf("\nout: ");
-			for (i = 0; i < tempmax-tempmin; i++)
+			for (i = 0; i < xbits; i++)
 				if (TESTBIT(out[bb->bbnum], i))
-					printf("%d ", i+tempmin);
+					PRTRG(i);
 			printf("\n");
 		}
 	}
 #endif
+	if (xtemps && xdce) {
+		/*
+		 * Do dead code elimination by using live out.
+		 * Ignores if any variable read from is marked volatile,
+		 * but what it should do is unspecified anyway.
+		 * Liveness Analysis should be done in optim2 instead.
+		 *
+		 * This should recalculate the basic block structure.
+		 */
+		if (dce(p2e)) {
+			/* Clear bitfields */
+			for (i = 0; i < p2e->nbblocks; i++) {
+				SETEMPTY(gen[i],xbits);
+				SETEMPTY(killed[i],xbits);
+				SETEMPTY(in[i],xbits);
+				SETEMPTY(out[i],xbits);
+			}
+			SETEMPTY(saved,xbits);
+			goto livagain;
+		}
+	}
 
-	DLIST_FOREACH(bb, &bblocks, bbelem) {
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
 		RDEBUG(("liveadd bb %d\n", bb->bbnum));
 		i = bb->bbnum;
-		for (j = 0; j < (tempmax-tempmin); j += NUMBITS)
+		for (j = 0; j < xbits; j += NUMBITS)
 			live[j/NUMBITS] = 0;
-		SETCOPY(live, out[i], j, nbits);
+		SETCOPY(live, out[i], j, xbits);
 		for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) {
-			if (ip->type == IP_NODE)
-				insnwalk(ip->ip_node);
+			if (ip->type == IP_NODE) {
+				if (ip->ip_node->n_op == XASM) {
+					flist(ip->ip_node->n_right,
+					    xasmconstr, 0);
+					listf(ip->ip_node->n_left, setxarg);
+				} else
+					insnwalk(ip->ip_node);
+			}
 			if (ip == bb->first)
 				break;
 		}
@@ -1200,14 +1590,13 @@
 
 #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++) {
+		for (i = 0; i < HASHSZ; i++) {
 			if ((w = edgehash[i]) == NULL)
 				continue;
 			for (; w; w = w->next)
@@ -1217,14 +1606,16 @@
 		DLIST_FOREACH(y, &initial, link) {
 			printf("%d (%c): trivial [%d] ", ASGNUM(y),
 			    CLASS(y)+'@', trivially_colorable(y));
+			i = 0;
 			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));
+				i++;
 			}
-			printf("\n");
+			printf(": n=%d\n", i);
 		}
 		printf("Move nodes\n");
 		DLIST_FOREACH(y, &initial, link) {
@@ -1281,7 +1672,9 @@
 {
 	int wast;
 
+#ifdef PCC_DEBUG
 	RRDEBUG(("DecrementDegree: w %d, c %d\n", ASGNUM(w), c));
+#endif
 
 	wast = trivially_colorable(w);
 	NCLASS(w, c)--;
@@ -1306,7 +1699,9 @@
 
 	w = POPWLIST(simplifyWorklist);
 	PUSHWLIST(w, selectStack);
+#ifdef PCC_DEBUG
 	RDEBUG(("Simplify: node %d class %d\n", ASGNUM(w), w->r_class));
+#endif
 
 	l = w->r_adjList;
 	for (; l; l = l->r_next) {
@@ -1328,10 +1723,10 @@
 static int
 OK(REGW *t, REGW *r)
 {
+#ifdef PCC_DEBUG
 	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;
@@ -1376,7 +1771,6 @@
 	return 1;
 }
 
-#define oldcons /* check some more */
 /*
  * Do a conservative estimation of whether two temporaries can 
  * be coalesced.  This is "Briggs-style" check.
@@ -1387,41 +1781,8 @@
 {
 	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;
 	/*
@@ -1461,17 +1822,7 @@
 			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
@@ -1492,7 +1843,9 @@
 	ADJL *l;
 	REGW *t;
 
+#ifdef PCC_DEBUG
 	RDEBUG(("Combine (%d,%d)\n", ASGNUM(u), ASGNUM(v)));
+#endif
 
 	if (ONLIST(v) == &freezeWorklist) {
 		DELWLIST(v);
@@ -1501,12 +1854,14 @@
 	}
 	PUSHWLIST(v, coalescedNodes);
 	ALIAS(v) = u;
+#ifdef PCC_DEBUG
 	if (rdebug) { 
 		printf("adjlist(%d): ", ASGNUM(v));
 		for (l = ADJLIST(v); l; l = l->r_next)
 			printf("%d ", l->a_temp->nodnum);
 		printf("\n");
 	}
+#endif
 #if 1
 {
 	MOVL *m0 = MOVELIST(v);
@@ -1544,6 +1899,7 @@
 		DELWLIST(u);
 		PUSHWLIST(u, spillWorklist);
 	}
+#ifdef PCC_DEBUG
 if (rdebug) {
 	ADJL *w;
 	printf("Combine %d class (%d): ", ASGNUM(u), CLASS(u));
@@ -1556,6 +1912,7 @@
 	}
 	printf("\n");
 }
+#endif
 }
 
 static void
@@ -1573,9 +1930,11 @@
 	else
 		u = x, v = y;
 
+#ifdef PCC_DEBUG
 	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)));
+#endif
 
 	if (CLASS(m->src) != CLASS(m->dst))
 		comperr("Coalesce: src class %d, dst class %d",
@@ -1620,8 +1979,10 @@
 			v = GetAlias(x);
 		else
 			v = GetAlias(y);
+#ifdef PCC_DEBUG
 		RDEBUG(("FreezeMoves: u %d (%d,%d) v %d\n",
 		    ASGNUM(u),ASGNUM(x),ASGNUM(y),ASGNUM(v)));
+#endif
 		DLIST_REMOVE(m, link);
 		PUSHMLIST(m, frozenMoves, FROZEN);
 		if (ONLIST(v) != &freezeWorklist)
@@ -1649,7 +2010,9 @@
 	 */
 	u = POPWLIST(freezeWorklist);
 	PUSHWLIST(u, simplifyWorklist);
+#ifdef PCC_DEBUG
 	RDEBUG(("Freeze %d\n", ASGNUM(u)));
+#endif
 	FreezeMoves(u);
 }
 
@@ -1659,9 +2022,11 @@
 	REGW *w;
 
 	RDEBUG(("SelectSpill\n"));
+#ifdef PCC_DEBUG
 	if (rdebug)
 		DLIST_FOREACH(w, &spillWorklist, link)
 			printf("SelectSpill: %d\n", ASGNUM(w));
+#endif
 
 	/* First check if we can spill register variables */
 	DLIST_FOREACH(w, &spillWorklist, link) {
@@ -1672,6 +2037,8 @@
 	if (w == &spillWorklist) {
 		/* try to find another long-range variable */
 		DLIST_FOREACH(w, &spillWorklist, link) {
+			if (innotspill(w - nblock))
+				continue;
 			if (w >= &nblock[tempmin] && w < &nblock[tempmax])
 				break;
 		}
@@ -1695,41 +2062,42 @@
         DLIST_REMOVE(w, link);
 
 	PUSHWLIST(w, simplifyWorklist);
+#ifdef PCC_DEBUG
 	RDEBUG(("Freezing node %d\n", ASGNUM(w)));
+#endif
 	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)
+traclass(NODE *p, void *arg)
 {
 	REGW *nb;
 
 	if (p->n_op != TEMP)
 		return;
 
-	nb = &nblock[(int)p->n_lval];
+	nb = &nblock[regno(p)];
 	if (CLASS(nb) == 0)
 		CLASS(nb) = gclass(p->n_type);
 }
 
 static void
-paint(NODE *p)
+paint(NODE *p, void *arg)
 {
 	struct optab *q;
 	REGW *w, *ww;
 	int i;
 
+#ifdef notyet
+	/* XXX - trashes rewrite of trees (short) */
+	if (!DLIST_ISEMPTY(&spilledNodes, link)) {
+		p->n_reg = 0;
+		return;
+	}
+#endif
 	if (p->n_regw != NULL) {
 		/* Must color all allocated regs also */
 		ww = w = p->n_regw;
@@ -1747,8 +2115,8 @@
 	} else
 		p->n_reg = -1;
 	if (p->n_op == TEMP) {
-		REGW *nb = &nblock[(int)p->n_lval];
-		p->n_rval = COLOR(nb);
+		REGW *nb = &nblock[regno(p)];
+		regno(p) = COLOR(nb);
 		if (TCLASS(p->n_su) == 0)
 			SCLASS(p->n_su, CLASS(nb));
 		p->n_op = REG;
@@ -1759,6 +2127,7 @@
 static void
 AssignColors(struct interpass *ip)
 {
+	struct interpass *ip2;
 	int okColors, c;
 	REGW *o, *w;
 	ADJL *x;
@@ -1767,13 +2136,17 @@
 	while (!WLISTEMPTY(selectStack)) {
 		w = POPWLIST(selectStack);
 		okColors = classmask(CLASS(w));
+#ifdef PCC_DEBUG
 		RDEBUG(("classmask av %d, class %d: %x\n",
 		    w->nodnum, CLASS(w), okColors));
+#endif
 
 		for (x = ADJLIST(w); x; x = x->r_next) {
 			o = GetAlias(x->a_temp);
+#ifdef PCC_DEBUG
 			RRDEBUG(("Adj(%d): %d (%d)\n",
 			    ASGNUM(w), ASGNUM(o), ASGNUM(x->a_temp)));
+#endif
 
 			if (ONLIST(o) == &coloredNodes ||
 			    ONLIST(o) == &precolored) {
@@ -1787,37 +2160,47 @@
 		}
 		if (okColors == 0) {
 			PUSHWLIST(w, spilledNodes);
+#ifdef PCC_DEBUG
 			RDEBUG(("Spilling node %d\n", ASGNUM(w)));
+#endif
 		} else {
 			PUSHWLIST(w, coloredNodes);
 			c = ffs(okColors)-1;
 			COLOR(w) = color2reg(c, CLASS(w));
+#ifdef PCC_DEBUG
 			RDEBUG(("Coloring %d with %s, free %x\n",
 			    ASGNUM(w), rnames[COLOR(w)], okColors));
+#endif
 		}
 	}
 	DLIST_FOREACH(w, &coalescedNodes, link) {
 		REGW *ww = GetAlias(w);
 		COLOR(w) = COLOR(ww);
 		if (ONLIST(ww) == &spilledNodes) {
+#ifdef PCC_DEBUG
 			RDEBUG(("coalesced node %d spilled\n", w->nodnum));
+#endif
 			ww = DLIST_PREV(w, link);
 			DLIST_REMOVE(w, link);
 			PUSHWLIST(w, spilledNodes);
 			w = ww;
-		} else
+		} else {
+#ifdef PCC_DEBUG
 			RDEBUG(("Giving coalesced node %d color %s\n",
 			    w->nodnum, rnames[COLOR(w)]));
+#endif
+		}
 	}
 
+#ifdef PCC_DEBUG
 	if (rdebug)
 		DLIST_FOREACH(w, &coloredNodes, link)
 			printf("%d: color %s\n", ASGNUM(w), rnames[COLOR(w)]);
+#endif
 	if (DLIST_ISEMPTY(&spilledNodes, link)) {
-		struct interpass *ip2;
 		DLIST_FOREACH(ip2, ip, qelem)
 			if (ip2->type == IP_NODE)
-				walkf(ip2->ip_node, paint);
+				walkf(ip2->ip_node, paint, 0);
 	}
 }
 
@@ -1827,23 +2210,25 @@
  * Will never end up here if not optimizing.
  */
 static void
-longtemp(NODE *p)
+longtemp(NODE *p, void *arg)
 {
+	NODE *l, *r;
 	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])
+		if (w != &nblock[regno(p)])
 			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;
+		l = mklnode(REG, 0, FPREG, INCREF(p->n_type));
+		r = mklnode(ICON, w->r_color, 0, INT);
+		p->n_left = mkbinode(PLUS, l, r, INCREF(p->n_type));
+		p->n_op = UMUL;
 		p->n_regw = NULL;
 		break;
 	}
@@ -1855,7 +2240,7 @@
  * XXX - must check if basic block structure is destroyed!
  */
 static void
-shorttemp(NODE *p)
+shorttemp(NODE *p, void *arg)
 {
 	struct interpass *nip;
 	struct optab *q;
@@ -1870,10 +2255,14 @@
 		/* XXX - use canaddr() */
 		if (p->n_op == OREG || p->n_op == NAME) {
 			DLIST_REMOVE(w, link);
+#ifdef PCC_DEBUG
 			RDEBUG(("Node %d already in memory\n", ASGNUM(w)));
+#endif
 			break;
 		}
+#ifdef PCC_DEBUG
 		RDEBUG(("rewriting node %d\n", ASGNUM(w)));
+#endif
 
 		off = BITOOR(freetemp(szty(p->n_type)));
 		l = mklnode(OREG, off, FPREG, p->n_type);
@@ -1923,7 +2312,7 @@
 		if (ip->type != IP_NODE)
 			continue;
 		cip = ip;
-		walkf(ip->ip_node, shorttemp);	/* convert temps to oregs */
+		walkf(ip->ip_node, shorttemp, 0); /* convert temps to oregs */
 	}
 	if (!DLIST_ISEMPTY(spole, link))
 		comperr("treerewrite not empty");
@@ -1945,7 +2334,7 @@
 			continue;
 		nodepole = ip->ip_node;
 		thisline = ip->lineno;
-		walkf(ip->ip_node, longtemp);	/* convert temps to oregs */
+		walkf(ip->ip_node, longtemp, 0); /* convert temps to oregs */
 	}
 	nodepole = NIL;
 }
@@ -1960,19 +2349,21 @@
 	NODE *p;
 
 	ip = DLIST_NEXT(ipole, qelem); /* PROLOG */
-	ip = DLIST_NEXT(ip, qelem); /* first DEFLAB */
+	while (ip->type != IP_DEFLAB)
+		ip = DLIST_NEXT(ip, qelem);
 	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
+#ifdef notdef
+		/* register args may already have been put on stack */
 		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])
+		if (w != &nblock[regno(p->n_left)])
 			continue;
 		w->r_color = p->n_right->n_lval;
 		tfree(p);
@@ -2068,6 +2459,33 @@
 	return rwtyp;
 }
 
+#ifdef PCC_DEBUG
+/*
+ * Print TEMP/REG contents in a node.
+ */
+void
+prtreg(FILE *fp, NODE *p)
+{
+	int i, n = p->n_su == -1 ? 0 : ncnt(table[TBLIDX(p->n_su)].needs);
+if (p->n_reg == -1) goto foo;
+	if (use_regw || p->n_reg > 0x40000000 || p->n_reg < 0) {
+		fprintf(fp, "TEMP ");
+		if (p->n_regw != NULL) {
+			for (i = 0; i < n+1; i++)
+				fprintf(fp, "%d ", p->n_regw[i].nodnum);
+		} else
+			fprintf(fp, "<undef>");
+	} else {
+foo:		fprintf(fp, "REG ");
+		if (p->n_reg != -1) {
+			for (i = 0; i < n+1; i++)
+				fprintf(fp, "%s ", rnames[DECRA(p->n_reg, i)]);
+		} else
+			fprintf(fp, "<undef>");
+	}
+}
+#endif
+
 #ifdef notyet
 /*
  * Assign instructions, calculate evaluation order and
@@ -2087,15 +2505,16 @@
  * Do register allocation for trees by graph-coloring.
  */
 void
-ngenregs(struct interpass *ipole)
+ngenregs(struct p2env *p2e)
 {
+	struct interpass *ipole = &p2e->ipole;
 	extern NODE *nodepole;
-	struct interpass_prolog *ipp, *epp;
 	struct interpass *ip;
-	int i, j, nbits = 0;
+	int i, j, tbits;
 	int uu[NPERMREG] = { -1 };
 	int xnsavregs[NPERMREG];
 	int beenhere = 0;
+	TWORD type;
 
 	DLIST_INIT(&lunused, link);
 	DLIST_INIT(&lused, link);
@@ -2103,11 +2522,8 @@
 	/*
 	 * 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;
+	tempmin = p2e->ipp->ip_tmpnum;
+	tempmax = p2e->epp->ip_tmpnum;
 
 	/*
 	 * Allocate space for the permanent registers in the
@@ -2130,16 +2546,16 @@
 #ifdef PCC_DEBUG
 	nodnum = tempmax;
 #endif
-	nbits = xbits = tempmax - tempmin;
-	if (nbits) {
-		nblock = tmpalloc(nbits * sizeof(REGW));
+	tbits = tempmax - tempmin;	/* # of temporaries */
+	xbits = tbits + MAXREGS;	/* total size of live array */
+	if (tbits) {
+		nblock = tmpalloc(tbits * sizeof(REGW));
 
 		nblock -= tempmin;
-		live = tmpalloc(BIT2BYTE(nbits));
-		RDEBUG(("nblock %p num %d size %zd\n",
-		    nblock, nbits, (int)(nbits * sizeof(REGW))));
+		RDEBUG(("nblock %p num %d size %zu\n",
+		    nblock, tbits, (size_t)(tbits * sizeof(REGW))));
 	}
-
+	live = tmpalloc(BIT2BYTE(xbits));
 
 	/* Block for precolored nodes */
 	ablock = tmpalloc(sizeof(REGW)*MAXREGS);
@@ -2159,16 +2575,16 @@
 
 recalc:
 onlyperm: /* XXX - should not have to redo all */
+	memset(edgehash, 0, sizeof(edgehash));
 
-	if (nbits) {
-		memset(nblock+tempmin, 0, nbits * sizeof(REGW));
-		memset(live, 0, BIT2BYTE(nbits));
-		memset(edgehash, 0, sizeof(edgehash));
+	if (tbits) {
+		memset(nblock+tempmin, 0, tbits * sizeof(REGW));
 #ifdef PCC_DEBUG
 		for (i = tempmin; i < tempmax; i++)
 			nblock[i].nodnum = i;
 #endif
 	}
+	memset(live, 0, BIT2BYTE(xbits));
 	RPRINTIP(ipole);
 	DLIST_INIT(&initial, link);
 	DLIST_FOREACH(ip, ipole, qelem) {
@@ -2177,15 +2593,20 @@
 			continue;
 		nodepole = ip->ip_node;
 		thisline = ip->lineno;
-		geninsn(ip->ip_node, FOREFF);
+		if (ip->ip_node->n_op != XASM)
+			geninsn(ip->ip_node, FOREFF);
 		nsucomp(ip->ip_node);
-		walkf(ip->ip_node, traclass);
+		walkf(ip->ip_node, traclass, 0);
 	}
 	nodepole = NIL;
 	RDEBUG(("nsucomp allocated %d temps (%d,%d)\n", 
 	    tempmax-tempmin, tempmin, tempmax));
 
+#ifdef PCC_DEBUG
+	use_regw = 1;
 	RPRINTIP(ipole);
+	use_regw = 0;
+#endif
 	RDEBUG(("ngenregs: numtemps %d (%d, %d)\n", tempmax-tempmin,
 		    tempmin, tempmax));
 
@@ -2205,7 +2626,7 @@
 		addalledges(&nblock[i+tempmin]);
 	}
 
-	Build(ipole);
+	Build(p2e);
 	RDEBUG(("Build done\n"));
 	MkWorklist();
 	RDEBUG(("MkWorklist done\n"));
@@ -2230,20 +2651,20 @@
 		case ONLYPERM:
 			goto onlyperm;
 		case SMALL:
-			optimize(ipole);
+			optimize(p2e);
 			if (beenhere++ == MAXLOOP)
-				comperr("beenhere");
+				comperr("cannot color graph - COLORMAP() bug?");
 			goto recalc;
 		}
 	}
 
-		/* fill in regs to save */
-	ipp->ipp_regs = 0;
+	/* fill in regs to save */
+	memset(p2e->ipp->ipp_regs, 0, sizeof(p2e->ipp->ipp_regs));
 	for (i = 0; i < NPERMREG-1; i++) {
 		NODE *p;
 
 		if (nsavregs[i]) {
-			ipp->ipp_regs |= (1 << permregs[i]);
+			BITSET(p2e->ipp->ipp_regs, permregs[i]);
 			continue; /* Spilled */
 		}
 		if (nblock[i+tempmin].r_color == permregs[i])
@@ -2251,7 +2672,7 @@
 		/*
 		 * If the original color of this permreg is used for
 		 * coloring another register, swap them to avoid
-		 * unneccessary moves.
+		 * unnecessary moves.
 		 */
 		for (j = i+1; j < NPERMREG-1; j++) {
 			if (nblock[j+tempmin].r_color != permregs[i])
@@ -2263,23 +2684,27 @@
 			continue;
 
 		/* Generate reg-reg move nodes for save */
+		type = PERMTYPE(permregs[i]);
+#ifdef PCC_DEBUG
+		if (PERMTYPE(nblock[i+tempmin].r_color) != type)
+			comperr("permreg botch");
+#endif
 		p = mkbinode(ASSIGN,
-		    mklnode(REG, 0, nblock[i+tempmin].r_color, INT),
-		    mklnode(REG, 0, permregs[i], INT), INT);
+		    mklnode(REG, 0, nblock[i+tempmin].r_color, type),
+		    mklnode(REG, 0, permregs[i], type), type);
 		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 = mkbinode(ASSIGN, mklnode(REG, 0, permregs[i], type),
+		    mklnode(REG, 0, nblock[i+tempmin].r_color, type), type);
 		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! */
+	memcpy(p2e->epp->ipp_regs, p2e->ipp->ipp_regs, sizeof(p2e->epp->ipp_regs));
+	/* Done! */
 }
Index: common.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/mip/common.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/mip/common.c -L usr.bin/pcc/mip/common.c -u -r1.1 -r1.2
--- usr.bin/pcc/mip/common.c
+++ usr.bin/pcc/mip/common.c
@@ -1,4 +1,4 @@
-/*	$Id: common.c,v 1.73 2007/09/22 17:15:00 ragge Exp $	*/
+/*	$Id: common.c,v 1.87 2008/12/03 07:10:04 ragge Exp $	*/
 /*
  * Copyright (c) 2003 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -11,8 +11,6 @@
  * 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
@@ -75,10 +73,19 @@
 char *ftitle;
 int lineno;
 
+int warniserr = 0;
+
 #ifndef WHERE
 #define	WHERE(ch) fprintf(stderr, "%s, line %d: ", ftitle, lineno);
 #endif
 
+static void
+incerr(void)
+{
+	if (++nerrors > 30)
+		cerror("too many errors");
+}
+
 /*
  * nonfatal error message
  * the routine where is different for pass 1 and pass 2;
@@ -90,13 +97,11 @@
 	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);
+	incerr();
 }
 
 /*
@@ -137,22 +142,22 @@
 	vfprintf(stderr, s, ap);
 	fprintf(stderr, "\n");
 	va_end(ap);
+	if (warniserr)
+		incerr();
 }
 
 #ifndef MKEXT
 static NODE *freelink;
 static int usednodes;
 
+#ifndef LANG_F77
 NODE *
 talloc()
 {
-	extern int inlnodecnt, recovernodes;
 	register NODE *p;
 
 	usednodes++;
 
-	if (recovernodes)
-		inlnodecnt++;
 	if (freelink != NULL) {
 		p = freelink;
 		freelink = p->next;
@@ -169,6 +174,7 @@
 		printf("alloc node %p from memory\n", p);
 	return p;
 }
+#endif
 
 /*
  * make a fresh copy of p
@@ -191,7 +197,7 @@
 	return(q);
 }
 
-
+#ifndef LANG_F77
 /*
  * ensure that all nodes have been freed
  */
@@ -206,6 +212,7 @@
 	if ((usednodes - inlnodecnt) != 0)
 		cerror("usednodes == %d, inlnodecnt %d", usednodes, inlnodecnt);
 }
+#endif
 
 /*
  * free the tree p
@@ -214,7 +221,7 @@
 tfree(NODE *p)
 {
 	if (p->n_op != FREE)
-		walkf(p, (void (*)(NODE *))nfree);
+		walkf(p, (void (*)(NODE *, void *))nfree, 0);
 }
 
 /*
@@ -224,7 +231,6 @@
 NODE *
 nfree(NODE *p)
 {
-	extern int inlnodecnt, recovernodes;
 	NODE *l;
 #ifdef PCC_DEBUG_NODES
 	NODE *q;
@@ -251,12 +257,16 @@
 	p->next = freelink;
 	freelink = p;
 	usednodes--;
-	if (recovernodes)
-		inlnodecnt--;
 	return l;
 }
 #endif
 
+#ifdef LANG_F77
+#define OPTYPE(x) optype(x)
+#else
+#define OPTYPE(x) coptype(x)
+#endif
+
 #ifdef MKEXT
 #define coptype(o)	(dope[o]&TYFLG)
 #else
@@ -275,7 +285,7 @@
 
 	(*f)(t, down, &down1, &down2);
 
-	switch (coptype( t->n_op )) {
+	switch (OPTYPE( t->n_op )) {
 
 	case BITYPE:
 		fwalk( t->n_left, f, down1 );
@@ -292,17 +302,18 @@
 }
 
 void
-walkf(NODE *t, void (*f)(NODE *))
+walkf(NODE *t, void (*f)(NODE *, void *), void *arg)
 {
 	int opty;
 
-	opty = coptype(t->n_op);
+
+	opty = OPTYPE(t->n_op);
 
 	if (opty != LTYPE)
-		walkf( t->n_left, f );
+		walkf( t->n_left, f, arg );
 	if (opty == BITYPE)
-		walkf( t->n_right, f );
-	(*f)(t);
+		walkf( t->n_right, f, arg );
+	(*f)(t, arg);
 }
 
 int dope[DSIZE];
@@ -317,7 +328,6 @@
 	{ REG, "REG", LTYPE, },
 	{ OREG, "OREG", LTYPE, },
 	{ TEMP, "TEMP", LTYPE, },
-	{ MOVE, "MOVE", UTYPE, },
 	{ ICON, "ICON", LTYPE, },
 	{ FCON, "FCON", LTYPE, },
 	{ CCODES, "CCODES", LTYPE, },
@@ -328,7 +338,8 @@
 	{ UFORTCALL, "UFCALL", UTYPE|CALLFLG, },
 	{ COMPL, "~", UTYPE, },
 	{ FORCE, "FORCE", UTYPE, },
-/*	{ INIT, "INIT", UTYPE, }, */
+	{ XARG, "XARG", UTYPE, },
+	{ XASM, "XASM", BITYPE, },
 	{ SCONV, "SCONV", UTYPE, },
 	{ PCONV, "PCONV", UTYPE, },
 	{ PLUS, "+", BITYPE|FLOFLG|SIMPFLG|COMMFLG, },
@@ -411,6 +422,9 @@
 		"void",
 		"signed", /* pass1 */
 		"bool", /* pass1 */
+		"fcomplex", /* pass1 */
+		"dcomplex", /* pass1 */
+		"lcomplex", /* pass1 */
 		"?", "?"
 		};
 
@@ -434,16 +448,6 @@
 	}
 }
 
-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.
@@ -453,7 +457,7 @@
  */
 
 #define	MEMCHUNKSZ 8192	/* 8k per allocation */
-struct b {
+struct balloc {
 	char a1;
 	union {
 		long long l;
@@ -461,13 +465,11 @@
 	} a2;
 };
 
-#define ALIGNMENT ((long)&((struct b *)0)->a2)
+#define ALIGNMENT ((long)&((struct balloc *)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 *
@@ -475,29 +477,27 @@
 {
 	void *rv;
 
-//printf("permalloc: allocpole %p allocleft %d size %d ", allocpole, allocleft, size);
-	if (size > MEMCHUNKSZ)
-		cerror("permalloc");
+	if (size > MEMCHUNKSZ) {
+		if ((rv = malloc(size)) == NULL)
+			cerror("permalloc: missing %d bytes", size);
+		return rv;
+	}
 	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)
 {
@@ -508,66 +508,96 @@
 	return rv;
 }
 
-#define	TMPOLE	&tmppole[MEMCHUNKSZ-tmpleft]
+/*
+ * Duplicate a string onto the temporary heap.
+ */
+char *
+tmpstrdup(char *str)
+{
+	int len;
+
+	len = strlen(str) + 1;
+	return memcpy(tmpalloc(len), str, len);
+}
+
+/*
+ * Allocation routines for temporary memory.
+ */
+#if 0
+#define	ALLDEBUG(x)	printf x
+#else
+#define	ALLDEBUG(x)
+#endif
+
+#define	NELEM	((MEMCHUNKSZ-ROUNDUP(sizeof(struct xalloc *)))/ALIGNMENT)
+#define	ELEMSZ	(ALIGNMENT)
+#define	MAXSZ	(NELEM*ELEMSZ)
+struct xalloc {
+	struct xalloc *next;
+	union {
+		struct balloc b; /* for initial alignment */
+		char elm[MAXSZ];
+	} u;
+} *tapole, *tmpole;
+int uselem = NELEM; /* next unused element */
+
 void *
 tmpalloc(int size)
 {
+	struct xalloc *xp;
 	void *rv;
+	size_t nelem;
 
-	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;
+	nelem = ROUNDUP(size)/ELEMSZ;
+	ALLDEBUG(("tmpalloc(%ld,%ld) %d (%zd) ", ELEMSZ, NELEM, size, nelem));
+	if (nelem > NELEM/2) {
+		xp = malloc(size + ROUNDUP(sizeof(struct xalloc *)));
+		if (xp == NULL)
+			cerror("out of memory");
+		ALLDEBUG(("XMEM! (%ld,%p) ",
+		    size + ROUNDUP(sizeof(struct xalloc *)), xp));
+		xp->next = tmpole;
+		tmpole = xp;
+		ALLDEBUG(("rv %p\n", &xp->u.elm[0]));
+		return &xp->u.elm[0];
+	}
+	if (nelem + uselem >= NELEM) {
+		ALLDEBUG(("MOREMEM! "));
+		/* alloc more */
+		if ((xp = malloc(sizeof(struct xalloc))) == NULL)
+			cerror("out of memory");
+		xp->next = tapole;
+		tapole = xp;
+		uselem = 0;
+	} else
+		xp = tapole;
+	rv = &xp->u.elm[uselem * ELEMSZ];
+	ALLDEBUG(("elemno %d ", uselem));
+	uselem += nelem;
+	ALLDEBUG(("new %d rv %p\n", uselem, rv));
 	return rv;
 }
 
-#if 0
-/*
- * Print and pack strings on heap.
- */
-char *tmpsprintf(char *fmt, ...);
-char *
-tmpsprintf(char *fmt, ...)
+void
+tmpfree()
 {
-	va_list ap;
-	int len;
-	char *tmp;
+	struct xalloc *x1;
 
-	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");
+	while (tmpole) {
+		x1 = tmpole;
+		tmpole = tmpole->next;
+		ALLDEBUG(("XMEM! free %p\n", x1));
+		free(x1);
+	}
+	while (tapole && tapole->next) {
+		x1 = tapole;
+		tapole = tapole->next;
+		ALLDEBUG(("MOREMEM! free %p\n", x1));
+		free(x1);
 	}
-	va_end(ap);
-	tmpleft += len;
-	return tmp;
+	if (tapole)
+		uselem = 0;
 }
-#endif
 
 /*
  * Print and pack vararg string on heap.
@@ -576,43 +606,58 @@
 char *
 tmpvsprintf(char *fmt, va_list ap)
 {
-	int len;
+	int len, asz;
 	char *tmp;
 
-	if (tmpleft == 0)
+	if (uselem == NELEM)
 		(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)
+	tmp = &tapole->u.elm[uselem * ELEMSZ];
+	asz = (NELEM-uselem) * ELEMSZ;
+//printf("tmpvsprintf: uselem %d asz %d ", uselem, asz);
+	if ((len = vsnprintf(tmp, asz, fmt, ap)) >= asz) {
+		(void)tmpalloc(asz+1); /* ugly */
+		tmp = &tapole->u.elm[uselem * ELEMSZ];
+		asz = (NELEM-uselem) * ELEMSZ;
+//printf("len %d uselem %d \n", len, uselem);
+		if ((len = vsnprintf(tmp, asz, fmt, ap)) >= asz)
 			cerror("bad tmpsprintf len");
 	}
-	tmpleft -= len+1;
+//else printf("\n");
+	uselem += (ROUNDUP(len+1)/ELEMSZ);
+//printf("len %d asz %d strlen(tmp) %ld\n", len, asz, strlen(tmp));
 	return tmp;
 }
 
+/*
+ * Set a mark for later removal from the temp heap.
+ */
 void
-tmpfree()
+markset(struct mark *m)
 {
-	char *f, *of;
+	m->tmsav = tmpole;
+	m->tasav = tapole;
+	m->elem = uselem;
+}
 
-	f = tmplink;
-	if (f == NULL)
-		return;
-	if (*(char **)f == NULL) {
-		tmpleft = MEMCHUNKSZ - ROUNDUP(sizeof(char *));
-		return;
+/*
+ * Remove everything on tmp heap from a mark.
+ */
+void
+markfree(struct mark *m)
+{
+	struct xalloc *x1;
+
+	while (tmpole != m->tmsav) {
+		x1 = tmpole;
+		tmpole = tmpole->next;
+		free(x1);
 	}
-	while (f != NULL) {
-		of = f;
-		f = *(char **)f;
-		free(of);
-	}
-	tmplink = tmppole = NULL;
-	tmpleft = 0;
-//fprintf(stderr, "freeing tmp\n");
-	/* XXX - nothing right now */
+	while (tapole != m->tasav) {
+		x1 = tapole;
+		tapole = tapole->next;
+		free(x1);
+	}
+	uselem = m->elem;
 }
 
 /*
@@ -636,3 +681,48 @@
 		*c++ = *s++;
 	return u;
 }
+
+/*
+ * Do a preorder walk of the CM list p and apply function f on each element.
+ */
+void
+flist(NODE *p, void (*f)(NODE *, void *), void *arg)
+{
+	if (p->n_op == CM) {
+		(*f)(p->n_right, arg);
+		flist(p->n_left, f, arg);
+	} else
+		(*f)(p, arg);
+}
+
+/*
+ * The same as flist but postorder.
+ */
+void
+listf(NODE *p, void (*f)(NODE *))
+{
+	if (p->n_op == CM) {
+		listf(p->n_left, f);
+		(*f)(p->n_right);
+	} else
+		(*f)(p);
+}
+
+/*
+ * Get list argument number n from list, or NIL if out of list.
+ */
+NODE *
+listarg(NODE *p, int n, int *cnt)
+{
+	NODE *r;
+
+	if (p->n_op == CM) {
+		r = listarg(p->n_left, n, cnt);
+		if (n == ++(*cnt))
+			r = p->n_right;
+	} else {
+		*cnt = 0;
+		r = n == 0 ? p : NIL;
+	}
+	return r;
+}
Index: compat.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/mip/compat.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/mip/compat.c -L usr.bin/pcc/mip/compat.c -u -r1.1 -r1.2
--- usr.bin/pcc/mip/compat.c
+++ usr.bin/pcc/mip/compat.c
@@ -24,12 +24,83 @@
  * 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 $
+ * $Id: compat.c,v 1.8 2008/11/01 08:29:38 mickey Exp $
+ */
+
+/*-
+ * Copyright (c) 1997, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Klaus Klein and Jason R. Thorpe.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, 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 THE FOUNDATION 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.
+ *
+ *	$NetBSD: basename.c,v 1.5 2002/10/17 02:06:04 thorpej Exp $
+ */
+
+/*
+ * Copyright (c) 1987, 1993
+ *	The Regents of the University of California.  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. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	$NetBSD: gettemp.c,v 1.13 2003/12/05 00:57:36 uebayasi Exp $
  */
 
 #include <string.h>
+#include <fcntl.h>
 
-#include "../config.h"
+#include "config.h"
+#define MKEXT	/* XXX */
 #include "manifest.h"
 
 #ifndef HAVE_STRLCAT
@@ -102,3 +173,754 @@
 	return(s - src - 1);	/* count does not include NUL */
 }
 #endif
+
+#ifndef HAVE_GETOPT
+char *optarg;
+int optind = 1;
+int
+getopt(int argc, char **argv, char *args)
+{
+        int n;
+	int nlen = strlen(args);
+        char cmd;
+        char rv;
+
+        if (argv[optind] && *argv[optind] == '-') {
+                cmd = *(argv[optind] + 1);
+
+                for (n = 0; n < nlen; n++) {
+                        if (args[n] == ':')
+				continue;
+                        if (args[n] == cmd) {
+                                rv = *(argv[optind] + 1);
+                                if (args[n+1] == ':') {
+					if (*(argv[optind] + 2) != '\0') {
+	                                        optarg = argv[optind] + 2;
+						optind += 1;
+					} else {
+	                                        optarg = argv[optind + 1];
+                                        	optind += 2;
+					}
+                                        if (!optarg)
+						 optarg="";
+                                        return rv;
+                                } else {
+                                        optarg = NULL;
+                                        optind += 1;
+                                        return rv;
+                                }
+                        }
+                }       
+        }
+
+        return -1;
+}
+#endif
+
+#ifdef WIN32
+#define ISPATHSEPARATOR(x) ((x == '/') || (x == '\\'))
+#else
+#define ISPATHSEPARATOR(x) (x == '/')
+#endif
+
+#ifndef HAVE_BASENAME
+#ifndef PATH_MAX
+#define PATH_MAX 5000
+#endif
+
+char *
+basename(char *path)
+{
+	static char singledot[] = ".";
+	static char result[PATH_MAX];
+	char *p, *lastp;
+	size_t len;
+
+	/*
+	 * If `path' is a null pointer or points to an empty string,
+	 * return a pointer to the string ".".
+	 */
+	if ((path == NULL) || (*path == '\0'))
+		return (singledot);
+
+	/* Strip trailing slashes, if any. */
+	lastp = path + strlen(path) - 1;
+	while (lastp != path && ISPATHSEPARATOR(*lastp))
+		lastp--;
+
+	/* Now find the beginning of this (final) component. */
+	p = lastp;
+	while (p != path && !ISPATHSEPARATOR(*(p - 1)))
+		p--;
+
+	/* ...and copy the result into the result buffer. */
+	len = (lastp - p) + 1 /* last char */;
+	if (len > (PATH_MAX - 1))
+		len = PATH_MAX - 1;
+
+	memcpy(result, p, len);
+	result[len] = '\0';
+
+	return (result);
+}
+#endif
+
+#if !defined(HAVE_MKSTEMP) && !defined(WIN32)
+int
+mkstemp(char *path)
+{
+	char *start, *trv;
+	unsigned int pid;
+
+	/* To guarantee multiple calls generate unique names even if
+	   the file is not created. 676 different possibilities with 7
+	   or more X's, 26 with 6 or less. */
+	static char xtra[2] = "aa";
+	int xcnt = 0;
+
+	pid = getpid();
+
+	/* Move to end of path and count trailing X's. */
+	for (trv = path; *trv; ++trv)
+		if (*trv == 'X')
+			xcnt++;
+		else
+			xcnt = 0;
+
+	/* Use at least one from xtra.  Use 2 if more than 6 X's. */
+	if (*(trv - 1) == 'X')
+		*--trv = xtra[0];
+	if (xcnt > 6 && *(trv - 1) == 'X')
+		*--trv = xtra[1];
+
+	/* Set remaining X's to pid digits with 0's to the left. */
+	while (*--trv == 'X') {
+		*trv = (pid % 10) + '0';
+		pid /= 10;
+	}
+
+	/* update xtra for next call. */
+	if (xtra[0] != 'z')
+		xtra[0]++;
+	else {
+		xtra[0] = 'a';
+		if (xtra[1] != 'z')
+			xtra[1]++;
+		else
+			xtra[1] = 'a';
+	}
+
+	return open(path, O_CREAT | O_EXCL | O_RDWR, 0600);
+}
+#endif
+
+#ifndef HAVE_FFS
+int
+ffs(int x) 
+{ 
+	int r = 1;
+	if (!x) return 0; 
+	if (!(x & 0xffff)) { x >>= 16; r += 16; }
+	if (!(x &   0xff)) { x >>= 8;  r += 8;  }
+	if (!(x &    0xf)) { x >>= 4;  r += 4;  }
+	if (!(x &      3)) { x >>= 2;  r += 2;  }
+	if (!(x &      1)) { x >>= 1;  r += 1;  }
+
+	return r; 
+}
+#endif
+
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell at astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
+
+static void 
+dopr(char *buffer, size_t maxlen, const char *format, va_list args);
+
+static void 
+fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, 
+    int min, int max);
+
+static void 
+fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, 
+    int min, int max, int flags);
+
+static void 
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
+    int min, int max, int flags);
+
+static void
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS   1
+#define DP_S_MIN     2
+#define DP_S_DOT     3
+#define DP_S_MAX     4
+#define DP_S_MOD     5
+#define DP_S_CONV    6
+#define DP_S_DONE    7
+
+/* format flags - Bits */
+#define DP_F_MINUS 	(1 << 0)
+#define DP_F_PLUS  	(1 << 1)
+#define DP_F_SPACE 	(1 << 2)
+#define DP_F_NUM   	(1 << 3)
+#define DP_F_ZERO  	(1 << 4)
+#define DP_F_UP    	(1 << 5)
+#define DP_F_UNSIGNED 	(1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT     1
+#define DP_C_LONG      2
+#define DP_C_LDOUBLE   3
+#define DP_C_LONG_LONG 4
+
+#define char_to_int(p) (p - '0')
+#define abs_val(p) (p < 0 ? -p : p)
+
+
+static void 
+dopr(char *buffer, size_t maxlen, const char *format, va_list args)
+{
+	char *strvalue, ch;
+	long value;
+	long double fvalue;
+	int min = 0, max = -1, state = DP_S_DEFAULT, flags = 0, cflags = 0;
+	size_t currlen = 0;
+  
+	ch = *format++;
+
+	while (state != DP_S_DONE) {
+		if ((ch == '\0') || (currlen >= maxlen)) 
+			state = DP_S_DONE;
+
+		switch(state) {
+		case DP_S_DEFAULT:
+			if (ch == '%') 
+				state = DP_S_FLAGS;
+			else 
+				dopr_outch(buffer, &currlen, maxlen, ch);
+			ch = *format++;
+			break;
+		case DP_S_FLAGS:
+			switch (ch) {
+			case '-':
+				flags |= DP_F_MINUS;
+				ch = *format++;
+				break;
+			case '+':
+				flags |= DP_F_PLUS;
+				ch = *format++;
+				break;
+			case ' ':
+				flags |= DP_F_SPACE;
+				ch = *format++;
+				break;
+			case '#':
+				flags |= DP_F_NUM;
+				ch = *format++;
+				break;
+			case '0':
+				flags |= DP_F_ZERO;
+				ch = *format++;
+				break;
+			default:
+				state = DP_S_MIN;
+				break;
+			}
+			break;
+		case DP_S_MIN:
+			if (isdigit((unsigned char)ch)) {
+				min = 10 * min + char_to_int (ch);
+				ch = *format++;
+			} else if (ch == '*') {
+				min = va_arg (args, int);
+				ch = *format++;
+				state = DP_S_DOT;
+			} else 
+				state = DP_S_DOT;
+			break;
+		case DP_S_DOT:
+			if (ch == '.') {
+				state = DP_S_MAX;
+				ch = *format++;
+			} else 
+				state = DP_S_MOD;
+			break;
+		case DP_S_MAX:
+			if (isdigit((unsigned char)ch)) {
+				if (max < 0)
+					max = 0;
+				max = 10 * max + char_to_int(ch);
+				ch = *format++;
+			} else if (ch == '*') {
+				max = va_arg (args, int);
+				ch = *format++;
+				state = DP_S_MOD;
+			} else 
+				state = DP_S_MOD;
+			break;
+		case DP_S_MOD:
+			switch (ch) {
+			case 'h':
+				cflags = DP_C_SHORT;
+				ch = *format++;
+				break;
+			case 'l':
+				cflags = DP_C_LONG;
+				ch = *format++;
+				if (ch == 'l') {
+					cflags = DP_C_LONG_LONG;
+					ch = *format++;
+				}
+				break;
+			case 'q':
+				cflags = DP_C_LONG_LONG;
+				ch = *format++;
+				break;
+			case 'L':
+				cflags = DP_C_LDOUBLE;
+				ch = *format++;
+				break;
+			default:
+				break;
+			}
+			state = DP_S_CONV;
+			break;
+		case DP_S_CONV:
+			switch (ch) {
+			case 'd':
+			case 'i':
+				if (cflags == DP_C_SHORT) 
+					value = va_arg(args, int);
+				else if (cflags == DP_C_LONG)
+					value = va_arg(args, long int);
+				else if (cflags == DP_C_LONG_LONG)
+					value = va_arg (args, long long);
+				else
+					value = va_arg (args, int);
+				fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
+				break;
+			case 'o':
+				flags |= DP_F_UNSIGNED;
+				if (cflags == DP_C_SHORT)
+					value = va_arg(args, unsigned int);
+				else if (cflags == DP_C_LONG)
+					value = va_arg(args, unsigned long int);
+				else if (cflags == DP_C_LONG_LONG)
+					value = va_arg(args, unsigned long long);
+				else
+					value = va_arg(args, unsigned int);
+				fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
+				break;
+			case 'u':
+				flags |= DP_F_UNSIGNED;
+				if (cflags == DP_C_SHORT)
+					value = va_arg(args, unsigned int);
+				else if (cflags == DP_C_LONG)
+					value = va_arg(args, unsigned long int);
+				else if (cflags == DP_C_LONG_LONG)
+					value = va_arg(args, unsigned long long);
+				else
+					value = va_arg(args, unsigned int);
+				fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+				break;
+			case 'X':
+				flags |= DP_F_UP;
+			case 'x':
+				flags |= DP_F_UNSIGNED;
+				if (cflags == DP_C_SHORT)
+					value = va_arg(args, unsigned int);
+				else if (cflags == DP_C_LONG)
+					value = va_arg(args, unsigned long int);
+				else if (cflags == DP_C_LONG_LONG)
+					value = va_arg(args, unsigned long long);
+				else
+					value = va_arg(args, unsigned int);
+				fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
+				break;
+			case 'f':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, long double);
+				else
+					fvalue = va_arg(args, double);
+				/* um, floating point? */
+				fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
+				break;
+			case 'E':
+				flags |= DP_F_UP;
+			case 'e':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, long double);
+				else
+					fvalue = va_arg(args, double);
+				break;
+			case 'G':
+				flags |= DP_F_UP;
+			case 'g':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, long double);
+				else
+					fvalue = va_arg(args, double);
+				break;
+			case 'c':
+				dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
+				break;
+			case 's':
+				strvalue = va_arg(args, char *);
+				if (max < 0) 
+					max = maxlen; /* ie, no max */
+				fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
+				break;
+			case 'p':
+				strvalue = va_arg(args, void *);
+				fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
+				break;
+			case 'n':
+				if (cflags == DP_C_SHORT) {
+					short int *num;
+					num = va_arg(args, short int *);
+					*num = currlen;
+				} else if (cflags == DP_C_LONG) {
+					long int *num;
+					num = va_arg(args, long int *);
+					*num = currlen;
+				} else if (cflags == DP_C_LONG_LONG) {
+					long long *num;
+					num = va_arg(args, long long *);
+					*num = currlen;
+				} else {
+					int *num;
+					num = va_arg(args, int *);
+					*num = currlen;
+				}
+				break;
+			case '%':
+				dopr_outch(buffer, &currlen, maxlen, ch);
+				break;
+			case 'w': /* not supported yet, treat as next char */
+				ch = *format++;
+				break;
+			default: /* Unknown, skip */
+			break;
+			}
+			ch = *format++;
+			state = DP_S_DEFAULT;
+			flags = cflags = min = 0;
+			max = -1;
+			break;
+		case DP_S_DONE:
+			break;
+		default: /* hmm? */
+			break; /* some picky compilers need this */
+		}
+	}
+	if (currlen < maxlen - 1) 
+		buffer[currlen] = '\0';
+	else 
+		buffer[maxlen - 1] = '\0';
+}
+
+static void
+fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+    char *value, int flags, int min, int max)
+{
+	int cnt = 0, padlen, strln;     /* amount to pad */
+  
+	if (value == 0) 
+		value = "<NULL>";
+
+	for (strln = 0; value[strln]; ++strln); /* strlen */
+	padlen = min - strln;
+	if (padlen < 0) 
+		padlen = 0;
+	if (flags & DP_F_MINUS) 
+		padlen = -padlen; /* Left Justify */
+
+	while ((padlen > 0) && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--padlen;
+		++cnt;
+	}
+	while (*value && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, *value++);
+		++cnt;
+	}
+	while ((padlen < 0) && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		++padlen;
+		++cnt;
+	}
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void 
+fmtint(char *buffer, size_t *currlen, size_t maxlen,
+    long value, int base, int min, int max, int flags)
+{
+	unsigned long uvalue;
+	char convert[20];
+	int signvalue = 0, place = 0, caps = 0;
+	int spadlen = 0; /* amount to space pad */
+	int zpadlen = 0; /* amount to zero pad */
+
+#define PADMAX(x,y)	((x) > (y) ? (x) : (y))
+
+	if (max < 0)
+		max = 0;
+
+	uvalue = value;
+
+	if (!(flags & DP_F_UNSIGNED)) {
+		if (value < 0) {
+			signvalue = '-';
+			uvalue = -value;
+		} else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+			signvalue = '+';
+		else if (flags & DP_F_SPACE)
+			signvalue = ' ';
+	}
+  
+	if (flags & DP_F_UP) 
+		caps = 1; /* Should characters be upper case? */
+	do {
+		convert[place++] =
+		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+		    [uvalue % (unsigned)base];
+		uvalue = (uvalue / (unsigned)base );
+	} while (uvalue && (place < 20));
+	if (place == 20) 
+		place--;
+	convert[place] = 0;
+
+	zpadlen = max - place;
+	spadlen = min - PADMAX(max, place) - (signvalue ? 1 : 0);
+	if (zpadlen < 0)
+		zpadlen = 0;
+	if (spadlen < 0)
+		spadlen = 0;
+	if (flags & DP_F_ZERO) {
+		zpadlen = PADMAX(zpadlen, spadlen);
+		spadlen = 0;
+	}
+	if (flags & DP_F_MINUS) 
+		spadlen = -spadlen; /* Left Justifty */
+
+	/* Spaces */
+	while (spadlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--spadlen;
+	}
+
+	/* Sign */
+	if (signvalue) 
+		dopr_outch(buffer, currlen, maxlen, signvalue);
+
+	/* Zeros */
+	if (zpadlen > 0) {
+		while (zpadlen > 0) {
+			dopr_outch(buffer, currlen, maxlen, '0');
+			--zpadlen;
+		}
+	}
+
+	/* Digits */
+	while (place > 0) 
+		dopr_outch(buffer, currlen, maxlen, convert[--place]);
+  
+	/* Left Justified spaces */
+	while (spadlen < 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		++spadlen;
+	}
+}
+
+static long double 
+pow10(int exp)
+{
+	long double result = 1;
+
+	while (exp) {
+		result *= 10;
+		exp--;
+	}
+  
+	return result;
+}
+
+static long 
+round(long double value)
+{
+	long intpart = value;
+
+	value -= intpart;
+	if (value >= 0.5)
+		intpart++;
+
+	return intpart;
+}
+
+static void 
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
+      int min, int max, int flags)
+{
+	char iconvert[20], fconvert[20];
+	int signvalue = 0, iplace = 0, fplace = 0;
+	int padlen = 0; /* amount to pad */
+	int zpadlen = 0, caps = 0;
+	long intpart, fracpart;
+	long double ufvalue;
+  
+	/* 
+	 * AIX manpage says the default is 0, but Solaris says the default
+	 * is 6, and sprintf on AIX defaults to 6
+	 */
+	if (max < 0)
+		max = 6;
+
+	ufvalue = abs_val(fvalue);
+
+	if (fvalue < 0)
+		signvalue = '-';
+	else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+		signvalue = '+';
+	else if (flags & DP_F_SPACE)
+		signvalue = ' ';
+
+	intpart = ufvalue;
+
+	/* 
+	 * Sorry, we only support 9 digits past the decimal because of our 
+	 * conversion method
+	 */
+	if (max > 9)
+		max = 9;
+
+	/* We "cheat" by converting the fractional part to integer by
+	 * multiplying by a factor of 10
+	 */
+	fracpart = round((pow10 (max)) * (ufvalue - intpart));
+
+	if (fracpart >= pow10 (max)) {
+		intpart++;
+		fracpart -= pow10 (max);
+	}
+
+	/* Convert integer part */
+	do {
+		iconvert[iplace++] =
+		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+		    [intpart % 10];
+		intpart = (intpart / 10);
+	} while(intpart && (iplace < 20));
+	if (iplace == 20) 
+		iplace--;
+	iconvert[iplace] = 0;
+
+	/* Convert fractional part */
+	do {
+		fconvert[fplace++] =
+		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+		    [fracpart % 10];
+		fracpart = (fracpart / 10);
+	} while(fracpart && (fplace < 20));
+	if (fplace == 20) 
+		fplace--;
+	fconvert[fplace] = 0;
+
+	/* -1 for decimal point, another -1 if we are printing a sign */
+	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
+	zpadlen = max - fplace;
+	if (zpadlen < 0)
+		zpadlen = 0;
+	if (padlen < 0) 
+		padlen = 0;
+	if (flags & DP_F_MINUS) 
+		padlen = -padlen; /* Left Justifty */
+
+	if ((flags & DP_F_ZERO) && (padlen > 0)) {
+		if (signvalue) {
+			dopr_outch(buffer, currlen, maxlen, signvalue);
+			--padlen;
+			signvalue = 0;
+		}
+		while (padlen > 0) {
+			dopr_outch(buffer, currlen, maxlen, '0');
+			--padlen;
+		}
+	}
+	while (padlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--padlen;
+	}
+	if (signvalue) 
+		dopr_outch(buffer, currlen, maxlen, signvalue);
+
+	while (iplace > 0) 
+		dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
+
+	/*
+	 * Decimal point.  This should probably use locale to find the 
+	 * correct char to print out.
+	 */
+	dopr_outch(buffer, currlen, maxlen, '.');
+
+	while (fplace > 0) 
+		dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
+
+	while (zpadlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, '0');
+		--zpadlen;
+	}
+
+	while (padlen < 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		++padlen;
+	}
+}
+
+static void 
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+	if (*currlen < maxlen)
+		buffer[(*currlen)++] = c;
+}
+#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
+
+#ifndef HAVE_VSNPRINTF
+int 
+vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+{
+	str[0] = 0;
+	dopr(str, count, fmt, args);
+
+	return(strlen(str));
+}
+#endif /* !HAVE_VSNPRINTF */
+
+#ifndef HAVE_SNPRINTF
+int 
+snprintf(char *str,size_t count,const char *fmt,...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	(void) vsnprintf(str, count, fmt, ap);
+	va_end(ap);
+
+	return(strlen(str));
+}
+
+#endif /* !HAVE_SNPRINTF */
Index: manifest.h
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/mip/manifest.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/mip/manifest.h -L usr.bin/pcc/mip/manifest.h -u -r1.1 -r1.2
--- usr.bin/pcc/mip/manifest.h
+++ usr.bin/pcc/mip/manifest.h
@@ -1,4 +1,4 @@
-/*	$Id: manifest.h,v 1.59 2007/09/20 12:02:54 ragge Exp $	*/
+/*	$Id: manifest.h,v 1.87 2008/12/04 07:28:55 ragge Exp $	*/
 /*
  * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
  *
@@ -37,9 +37,11 @@
 #define	MANIFEST
 
 #include <stdio.h>
-#include "../config.h"
+#include <string.h>
+#include "config.h"
 #include "macdefs.h"
 #include "node.h"
+#include "compat.h"
 
 /*
  * Node types
@@ -75,8 +77,8 @@
 #define	LDOUBLE		14
 #define	STRTY		15
 #define	UNIONTY		16
-#define	ENUMTY		17
-#define	MOETY		18	/* member of enum */
+/* #define	ENUMTY		17 */
+/* #define	MOETY		18 */	/* member of enum */
 #define	VOID		19
 
 #define	MAXTYPES	19	/* highest type+1 to be used by lang code */
@@ -114,6 +116,7 @@
 #define UNSIGNABLE(x)	(((x)<=ULONGLONG&&(x)>=CHAR) && !ISUNSIGNED(x))
 #define ENUNSIGN(x)	((x)|1)
 #define DEUNSIGN(x)	((x)&~1)
+#define ISINTEGER(x)	(((x) >= CHAR && (x) <= ULONGLONG) || (x) == BOOL)
 #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? */
@@ -165,18 +168,24 @@
 #define DATA		1		/* (rw) data segment */
 #define RDATA		2		/* (ro) data segment */
 #define STRNG		3		/* (ro) string segment */
+#define	UDATA		4		/* (rw) uninitialized data */
 
 
+#define	regno(p)	((p)->n_rval)	/* register number */
+
 /*
  * 
  */
 extern int bdebug, tdebug, edebug;
 extern int ddebug, xdebug, f2debug;
-extern int iTflag, oTflag;
-extern int vdebug, sflag, nflag, gflag;
+extern int iTflag, oTflag, kflag;
+extern int sflag, nflag, gflag, pflag;
 extern int Wstrict_prototypes, Wmissing_prototypes, Wimplicit_int,
-	Wimplicit_function_declaration;
-extern int xssaflag, xtailcallflag, xtemps, xdeljumps;
+	Wimplicit_function_declaration, Wpointer_sign, Wshadow,
+	Wsign_compare, Wunknown_pragmas, Wunreachable_code;
+extern int funsigned_char;
+extern int sspflag;
+extern int xssaflag, xtailcallflag, xtemps, xdeljumps, xdce;
 
 int yyparse(void);
 void yyaccpt(void);
@@ -191,6 +200,7 @@
 #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_ENDMARK(h)	(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) \
@@ -215,17 +225,26 @@
 /* Single-linked list */
 #define	SLIST_INIT(h)	\
 	{ (h)->q_forw = NULL; (h)->q_last = &(h)->q_forw; }
+#define	SLIST_SETUP(h) { NULL, &(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_ISEMPTY(h) ((h)->q_last == &(h)->q_forw)
 #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_FIRST(h,e,f) {		\
+	if ((h)->q_last == &(h)->q_forw)	\
+		(h)->q_last = &(e)->f.q_forw;	\
+	(e)->f.q_forw = (h)->q_forw;		\
+	(h)->q_forw = (e);			\
+}
 #define	SLIST_INSERT_LAST(h,e,f) {	\
 	(e)->f.q_forw = NULL;		\
 	*(h)->q_last = (e);		\
 	(h)->q_last = &(e)->f.q_forw;	\
 }
 
+#ifndef	MKEXT
 /*
  * Functions for inter-pass communication.
  *
@@ -253,11 +272,20 @@
 	char *ipp_name;		/* Function name */
 	int ipp_vis;		/* Function visibility */
 	TWORD ipp_type;		/* Function type */
-	int ipp_regs;		/* Bitmask of registers to save */
+#define	NIPPREGS	BIT2BYTE(MAXREGS)/sizeof(bittype)
+	bittype ipp_regs[NIPPREGS];
+				/* 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 */
+#ifdef TARGET_IPP_MEMBERS
+	TARGET_IPP_MEMBERS
+#endif
 };
+#else
+struct interpass { int dummy; };
+struct interpass_prolog;
+#endif /* !MKEXT */
 
 /*
  * Epilog/prolog takes following arguments (in order):
@@ -289,17 +317,13 @@
 /*
  * 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
+/* used for memory allocation */
+typedef struct mark {
+	void *tmsav;
+	void *tasav;
+	int elem;
+} MARK;
 
 /* memory management stuff */
 void *permalloc(int size);
@@ -307,6 +331,12 @@
 void *tmpalloc(int size);
 void tmpfree(void);
 char *newstring(char *, int len);
+char *tmpstrdup(char *str);
+void markset(struct mark *m);
+void markfree(struct mark *m);
+
+/* command-line processing */
+void mflags(char *);
 
 void tprint(FILE *, TWORD, TWORD);
 
@@ -318,7 +348,18 @@
 
 /* node routines */
 NODE *nfree(NODE *);
+void tfree(NODE *);
+NODE *tcopy(NODE *);
+void walkf(NODE *, void (*f)(NODE *, void *), void *);
 void fwalk(NODE *t, void (*f)(NODE *, int, int *, int *), int down);
+void flist(NODE *p, void (*f)(NODE *, void *), void *);
+void listf(NODE *p, void (*f)(NODE *));
+NODE *listarg(NODE *p, int n, int *cnt);
+void cerror(char *s, ...);
+void werror(char *s, ...);
+void uerror(char *s, ...);
+
 
 extern	int nerrors;		/* number of errors seen so far */
+extern	int warniserr;		/* treat warnings as errors */
 #endif
Index: mkext.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/mip/mkext.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/mip/mkext.c -L usr.bin/pcc/mip/mkext.c -u -r1.1 -r1.2
--- usr.bin/pcc/mip/mkext.c
+++ usr.bin/pcc/mip/mkext.c
@@ -3,8 +3,21 @@
  * Generate defines for the needed hardops.
  */
 #include "pass2.h"
+#include <stdlib.h>
 
+#ifdef HAVE_STRING_H
 #include <string.h>
+#endif
+
+#ifdef HAVE_C99_FORMAT
+#define FMTdPTR "%td"
+#else
+#if defined(_WIN64) || defined(LP64)
+#define FMTdPTR "%ld"
+#else
+#define FMTdPTR "%d"
+#endif
+#endif
 
 int chkop[DSIZE];
 
@@ -62,12 +75,53 @@
 
 int rstatus[] = { RSTATUS };
 int roverlay[MAXREGS][MAXREGS] = { ROVERLAP };
-int regclassmap[NUMCLASS][MAXREGS];
+int regclassmap[CLASSG][MAXREGS]; /* CLASSG is highest class */
 
 static void
 compl(struct optab *q, char *str)
 {
-	printf("table entry %td, op %s: %s\n", q - table, opst[q->op], str);
+	int op = q->op;
+	char *s;
+
+	if (op < OPSIMP) {
+		s = opst[op];
+	} else
+		switch (op) {
+		default:	s = "Special op";	break;
+		case OPSIMP:	s = "OPLSIMP";	break;
+		case OPCOMM:	s = "OPCOMM";	break;
+		case OPMUL:	s = "OPMUL";	break;
+		case OPDIV:	s = "OPDIV";	break;
+		case OPUNARY:	s = "OPUNARY";	break;
+		case OPLEAF:	s = "OPLEAF";	break;
+		case OPANY:	s = "OPANY";	break;
+		case OPLOG:	s = "OPLOG";	break;
+		case OPFLOAT:	s = "OPFLOAT";	break;
+		case OPSHFT:	s = "OPSHFT";	break;
+		case OPLTYPE:	s = "OPLTYPE";	break;
+		}
+
+	printf("table entry " FMTdPTR ", op %s: %s\n", q - table, s, str);
+}
+
+static int
+getrcl(struct optab *q)
+{
+	int v = q->needs &
+	    (NACOUNT|NBCOUNT|NCCOUNT|NDCOUNT|NECOUNT|NFCOUNT|NGCOUNT);
+	int r = q->rewrite & RESC1 ? 1 : q->rewrite & RESC2 ? 2 : 3;
+	int i = 0;
+
+#define INCK(c) while (v & c##COUNT) { \
+	v -= c##REG, i++; if (i == r) return I##c##REG; }
+	INCK(NA)
+	INCK(NB)
+	INCK(NC)
+	INCK(ND)
+	INCK(NE)
+	INCK(NF)
+	INCK(NG)
+	return 0;
 }
 
 int
@@ -75,10 +129,16 @@
 {
 	struct optab *q;
 	struct checks *ch;
-	int i, j, areg, breg, creg, dreg, mx;
+	int i, j, areg, breg, creg, dreg, mx, ereg, freg, greg;
 	char *bitary;
 	int bitsz, rval, nelem;
 
+	if (argc == 2) {
+		i = atoi(argv[1]);
+		printf("Entry %d:\n%s\n", i, table[i].cstring);
+		return 0;
+	}
+
 	mkdope();
 
 	for (q = table; q->op != FREE; q++) {
@@ -99,6 +159,8 @@
 		perror("open hfile");
 		return(1);
 	}
+	fprintf(fh, "#ifndef _EXTERNAL_H_\n#define _EXTERNAL_H_\n");
+
 	for (ch = checks; ch->op != 0; ch++) {
 		if ((chkop[ch->op] & ch->type) == 0)
 			fprintf(fh, "#define NEED_%s\n", ch->name);
@@ -117,12 +179,17 @@
 		bitsz = sizeof(int) == 4 ? 32 : 16;
 	}
 	fprintf(fh, "#define NUMBITS %d\n", bitsz);
+	fprintf(fh, "#define BIT2BYTE(bits) "
+	     "((((bits)+NUMBITS-1)/NUMBITS)*(NUMBITS/8))\n");
 	fprintf(fh, "#define BITSET(arr, bit) "
-	     "(arr[bit/NUMBITS] |= (1 << (bit & (NUMBITS-1))))\n");
+	     "(arr[bit/NUMBITS] |= ((%s)1 << (bit & (NUMBITS-1))))\n",
+	     bitary);
 	fprintf(fh, "#define BITCLEAR(arr, bit) "
-	     "(arr[bit/NUMBITS] &= ~(1 << (bit & (NUMBITS-1))))\n");
+	     "(arr[bit/NUMBITS] &= ~((%s)1 << (bit & (NUMBITS-1))))\n",
+	     bitary);
 	fprintf(fh, "#define TESTBIT(arr, bit) "
-	     "(arr[bit/NUMBITS] & (1 << (bit & (NUMBITS-1))))\n");
+	     "(arr[bit/NUMBITS] & ((%s)1 << (bit & (NUMBITS-1))))\n",
+	     bitary);
 	fprintf(fh, "typedef %s bittype;\n", bitary);
 
 	/* register class definitions, used by graph-coloring */
@@ -134,16 +201,25 @@
 		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)) {
+			if (F(INAREG) || F(INBREG) || F(INCREG) || F(INDREG) ||
+			    F(INEREG) || F(INFREG) || F(INGREG)) {
 				compl(q, "may match without result register");
 				rval++;
 			}
 #undef F
-			if ((q->visit & INREGS) && q->rewrite != RDEST) {
+			if ((q->visit & INREGS) && !(q->rewrite & RDEST)) {
 				compl(q, "ASSIGN reclaim must be RDEST");
 				rval++;
 			}
 		}
+		/* check that reclaim is not the wrong class */
+		if ((q->rewrite & (RESC1|RESC2|RESC3)) && 
+		    !(q->needs & REWRITE)) {
+			if ((q->visit & getrcl(q)) == 0) {
+				compl(q, "wrong RESCx class");
+				rval++;
+			}
+		}
 		if (q->rewrite & (RESC1|RESC2|RESC3) && q->visit & FOREFF)
 			compl(q, "FOREFF may cause reclaim of wrong class");
 	}
@@ -163,23 +239,42 @@
 			fprintf(fc, "%d, ", i), j++;
 	fprintf(fc, "-1 };\n");
 	fprintf(fh, "#define NPERMREG %d\n", j+1);
+	fprintf(fc, "bittype validregs[] = {\n");
+	for (j = 0; j < MAXREGS; j += bitsz) {
+		int cbit = 0;
+		for (i = 0; i < bitsz; i++) {
+			if (i+j == MAXREGS)
+				break;
+			if (rstatus[i+j] & INREGS)
+				cbit |= (1 << i);
+		}
+		fprintf(fc, "\t0x%08x,\n", cbit);
+	}
+	fprintf(fc, "};\n");
+	fprintf(fh, "extern bittype validregs[];\n");
 
 	/*
 	 * The register allocator uses bitmasks of registers for each class.
 	 */
-	areg = breg = creg = dreg = 0;
+	areg = breg = creg = dreg = ereg = freg = greg = 0;
 	for (i = 0; i < MAXREGS; i++) {
-		regclassmap[0][i] = regclassmap[1][i] = regclassmap[2][i] = 
-		    regclassmap[3][i] = -1;
+		for (j = 0; j < NUMCLASS; j++)
+			regclassmap[j][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++;
+		if (rstatus[i] & SEREG) regclassmap[4][i] = ereg++;
+		if (rstatus[i] & SFREG) regclassmap[5][i] = freg++;
+		if (rstatus[i] & SGREG) regclassmap[6][i] = greg++;
 	}
 	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);
+	fprintf(fh, "#define EREGCNT %d\n", ereg);
+	fprintf(fh, "#define FREGCNT %d\n", freg);
+	fprintf(fh, "#define GREGCNT %d\n", greg);
 	if (areg > bitsz)
 		printf("%d regs in class A (max %d)\n", areg, bitsz), rval++;
 	if (breg > bitsz)
@@ -188,15 +283,24 @@
 		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++;
+	if (ereg > bitsz)
+		printf("%d regs in class E (max %d)\n", ereg, bitsz), rval++;
+	if (freg > bitsz)
+		printf("%d regs in class F (max %d)\n", freg, bitsz), rval++;
+	if (greg > bitsz)
+		printf("%d regs in class G (max %d)\n", greg, 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;
+		int ba, bb, bc, bd, r, be, bf, bg;
+		ba = bb = bc = bd = be = bf = bg = 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]);
+		if (rstatus[i] & SEREG) be = (1 << regclassmap[4][i]);
+		if (rstatus[i] & SFREG) bf = (1 << regclassmap[5][i]);
+		if (rstatus[i] & SGREG) bg = (1 << regclassmap[6][i]);
 		for (j = 0; roverlay[i][j] >= 0; j++) {
 			r = roverlay[i][j];
 			if (rstatus[r] & SAREG)
@@ -207,8 +311,21 @@
 				bc |= (1 << regclassmap[2][r]);
 			if (rstatus[r] & SDREG)
 				bd |= (1 << regclassmap[3][r]);
+			if (rstatus[r] & SEREG)
+				be |= (1 << regclassmap[4][r]);
+			if (rstatus[r] & SFREG)
+				bf |= (1 << regclassmap[5][r]);
+			if (rstatus[r] & SGREG)
+				bg |= (1 << regclassmap[6][r]);
 		}
-		fprintf(fc, "\t{ 0x%x,0x%x,0x%x,0x%x },\n", ba, bb, bc, bd);
+		fprintf(fc, "\t/* %d */{ 0x%x", i, ba);
+		if (NUMCLASS > 1) fprintf(fc, ",0x%x", bb);
+		if (NUMCLASS > 2) fprintf(fc, ",0x%x", bc);
+		if (NUMCLASS > 3) fprintf(fc, ",0x%x", bd);
+		if (NUMCLASS > 4) fprintf(fc, ",0x%x", be);
+		if (NUMCLASS > 5) fprintf(fc, ",0x%x", bf);
+		if (NUMCLASS > 6) fprintf(fc, ",0x%x", bg);
+		fprintf(fc, " },\n");
 	}
 	fprintf(fc, "};\n");
 
@@ -221,9 +338,12 @@
 	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);
+	if (ereg > mx) mx = ereg;
+	if (freg > mx) mx = freg;
+	if (greg > mx) mx = greg;
+	if (mx > (int)(sizeof(int)*8)-1) {
+		printf("too many regs in a class, use two classes instead\n");
+		printf("%d > %zu\n", mx, (sizeof(int)*8)-1);
 		rval++;
 	}
 	fprintf(fc, "static int rmap[NUMCLASS][%d] = {\n", mx);
@@ -241,13 +361,16 @@
 	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 regK[] = { 0, %d, %d, %d, %d, %d, %d, %d };\n",
+	    areg, breg, creg, dreg, ereg, freg, greg);
 	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(fc, "\tif(class == CLASSD) return 0x%x;\n", (1 << dreg)-1);
+	fprintf(fc, "\tif(class == CLASSE) return 0x%x;\n", (1 << ereg)-1);
+	fprintf(fc, "\tif(class == CLASSF) return 0x%x;\n", (1 << freg)-1);
+	fprintf(fc, "\treturn 0x%x;\n}\n", (1 << greg)-1);
 
 	fprintf(fh, "int interferes(int reg1, int reg2);\n");
 	nelem = (MAXREGS+bitsz-1)/bitsz;
@@ -270,6 +393,7 @@
 	fprintf(fc, "int\ninterferes(int reg1, int reg2)\n{\n");
 	fprintf(fc, "return TESTBIT(ovlarr[reg1], reg2);\n}\n");
 	fclose(fc);
+	fprintf(fh, "#endif /* _EXTERNAL_H_ */\n");
 	fclose(fh);
 	return rval;
 }
@@ -291,19 +415,20 @@
 		for (op = table; op->op != FREE; op++) {
 			if (op->op < OPSIMP) {
 				if (op->op == i) {
-					P((fc, "%td, ", op - table));
+					P((fc, FMTdPTR ", ", 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));
+					    i==OREG || i == REG || i == FCON) {
+						P((fc, FMTdPTR ", ",
+						    op - table));
 						curalen++;
 					}
 				} else if ((dope[i]&(opmtemp|ASGFLG))==opmtemp){
-					P((fc, "%td, ", op - table));
+					P((fc, FMTdPTR ", ", op - table));
 					curalen++;
 				}
 			}
Index: optim2.c
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/mip/optim2.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/mip/optim2.c -L usr.bin/pcc/mip/optim2.c -u -r1.1 -r1.2
--- usr.bin/pcc/mip/optim2.c
+++ usr.bin/pcc/mip/optim2.c
@@ -1,4 +1,4 @@
-/*	$Id: optim2.c,v 1.44 2006/06/20 06:02:44 ragge Exp $	*/
+/*	$Id: optim2.c,v 1.62 2008/12/11 21:23:28 pantzer Exp $	*/
 /*
  * Copyright (c) 2004 Anders Magnusson (ragge at ludd.luth.se).
  * All rights reserved.
@@ -41,169 +41,48 @@
 
 #define	BDEBUG(x)	if (b2debug) printf x
 
+#define	mktemp(n, t)	mklnode(TEMP, 0, n, t)
+
 static int dfsnum;
 
 void saveip(struct interpass *ip);
-void deljumps(struct interpass *);
+void deljumps(struct p2env *);
 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 bblocks_build(struct p2env *, struct labelinfo *, struct bblockinfo *);
+void cfg_build(struct p2env *, struct labelinfo *labinfo);
 void cfg_dfs(struct basicblock *bb, unsigned int parent, 
 	     struct bblockinfo *bbinfo);
-void dominators(struct bblockinfo *bbinfo);
+void dominators(struct p2env *, 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 printDF(struct p2env *p2e, 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 placePhiFunctions(struct p2env *, struct bblockinfo *bbinfo);
+void renamevar(struct p2env *p2e,struct basicblock *bblock, struct bblockinfo *bbinfo);
+void removephi(struct p2env *p2e, struct labelinfo *,struct bblockinfo *bbinfo);
+void remunreach(struct p2env *);
 
 void
-optimize(struct interpass *ipole)
+optimize(struct p2env *p2e)
 {
-	struct interpass *ip;
+	struct interpass *ipole = &p2e->ipole;
 	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 */
+		deljumps(p2e); /* Delete redundant jumps and dead code */
 
 #ifdef PCC_DEBUG
 	if (b2debug) {
@@ -212,32 +91,64 @@
 	}
 #endif
 	if (xssaflag || xtemps) {
-		DLIST_INIT(&bblocks, bbelem);
-		bblocks_build(ipole, &labinfo, &bbinfo);
+		DLIST_INIT(&p2e->bblocks, bbelem);
+		bblocks_build(p2e, &labinfo, &bbinfo);
 		BDEBUG(("Calling cfg_build\n"));
-		cfg_build(&labinfo);
+		cfg_build(p2e, &labinfo);
 	}
 	if (xssaflag) {
 		BDEBUG(("Calling dominators\n"));
-		dominators(&bbinfo);
+		dominators(p2e, &bbinfo);
 		BDEBUG(("Calling computeDF\n"));
-		computeDF(DLIST_NEXT(&bblocks, bbelem), &bbinfo);
+		computeDF(DLIST_NEXT(&p2e->bblocks, bbelem), &bbinfo);
+
+		if (b2debug) {
+			printDF(p2e,&bbinfo);
+		}
+
+		BDEBUG(("Calling placePhiFunctions\n"));
+
+		placePhiFunctions(p2e, &bbinfo);
+
+		BDEBUG(("Calling renamevar\n"));
+
+		renamevar(p2e,DLIST_NEXT(&p2e->bblocks, bbelem), &bbinfo);
+
+		BDEBUG(("Calling removephi\n"));
+
+		removephi(p2e,&labinfo,&bbinfo);
+
 		BDEBUG(("Calling remunreach\n"));
-		remunreach();
-#if 0
-		dfg = dfg_build(cfg);
-		ssa = ssa_build(cfg, dfg);
+		remunreach(p2e);
+		
+		/*
+		 Recalculate basic blocks and cfg that was destroyed
+		 by removephi
+		 */
+
+		DLIST_INIT(&p2e->bblocks, bbelem);
+		bblocks_build(p2e, &labinfo, &bbinfo);
+		BDEBUG(("Calling cfg_build\n"));
+		cfg_build(p2e, &labinfo);
+
+#ifdef PCC_DEBUG
+		if (b2debug) {
+			printf("new tree\n");
+			printip(ipole);
+		}
 #endif
 	}
 
 #ifdef PCC_DEBUG
-	if (epp->ipp_regs != 0)
-		comperr("register error");
+	{
+		int i;
+		for (i = NIPPREGS; i--; )
+			if (p2e->epp->ipp_regs[i] != 0)
+				comperr("register error");
+	}
 #endif
 
-#ifdef MYOPTIM
-	myoptim((struct interpass *)ipp);
-#endif
+	myoptim(ipole);
 }
 
 /*
@@ -245,14 +156,18 @@
  * This routine can be made much more efficient.
  */
 void
-deljumps(struct interpass *ipole)
+deljumps(struct p2env *p2e)
 {
-	struct interpass *ip, *n, *ip2;
+	struct interpass *ipole = &p2e->ipole;
+	struct interpass *ip, *n, *ip2, *start;
 	int gotone,low, high;
-	int *lblary, sz, o, i;
+	int *lblary, *jmpary, sz, o, i, j, lab1, lab2;
+	int del;
+	extern int negrel[];
+	extern size_t negrelsize;
 
-	low = ipp->ip_lblnum;
-	high = epp->ip_lblnum;
+	low = p2e->ipp->ip_lblnum;
+	high = p2e->epp->ip_lblnum;
 
 #ifdef notyet
 	mark = tmpmark(); /* temporary used memory */
@@ -260,18 +175,64 @@
 
 	sz = (high-low) * sizeof(int);
 	lblary = tmpalloc(sz);
+	jmpary = tmpalloc(sz);
+
+	/*
+	 * XXX: Find the first two labels. They may not be deleted,
+	 * because the register allocator expects them to be there.
+	 * These will not be coalesced with any other label.
+	 */
+	lab1 = lab2 = -1;
+	start = NULL;
+	DLIST_FOREACH(ip, ipole, qelem) {
+		if (ip->type != IP_DEFLAB)
+			continue;
+		if (lab1 < 0)
+			lab1 = ip->ip_lbl;
+		else if (lab2 < 0) {
+			lab2 = ip->ip_lbl;
+			start = ip;
+		} else	/* lab1 >= 0 && lab2 >= 0, we're done. */
+			break;
+	}
+	if (lab1 < 0 || lab2 < 0)
+		comperr("deljumps");
 
 again:	gotone = 0;
 	memset(lblary, 0, sz);
+	lblary[lab1 - low] = lblary[lab2 - low] = 1;
+	memset(jmpary, 0, sz);
 
 	/* refcount and coalesce all labels */
 	DLIST_FOREACH(ip, ipole, qelem) {
-		if (ip->type == IP_DEFLAB) {
+		if (ip->type == IP_DEFLAB && ip->ip_lbl != lab1 &&
+		    ip->ip_lbl != lab2) {
 			n = DLIST_NEXT(ip, qelem);
+
+			/*
+			 * Find unconditional jumps directly following a
+			 * label. Jumps jumping to themselves are not
+			 * taken into account.
+			 */
+			if (n->type == IP_NODE && n->ip_node->n_op == GOTO) {
+				i = n->ip_node->n_left->n_lval;
+				if (i != ip->ip_lbl)
+					jmpary[ip->ip_lbl - low] = i;
+			}
+
 			while (n->type == IP_DEFLAB) {
-				if (n->type == IP_DEFLAB &&
-				    lblary[n->ip_lbl-low] >= 0)
-					lblary[n->ip_lbl-low] = -ip->ip_lbl;
+				if (n->ip_lbl != lab1 && n->ip_lbl != lab2 &&
+				    lblary[n->ip_lbl-low] >= 0) {
+					/*
+					 * If the label is used, mark the
+					 * label to be coalesced with as
+					 * used, too.
+					 */
+					if (lblary[n->ip_lbl - low] > 0 &&
+					    lblary[ip->ip_lbl - low] == 0)
+						lblary[ip->ip_lbl - low] = 1;
+					lblary[n->ip_lbl - low] = -ip->ip_lbl;
+				}
 				n = DLIST_NEXT(n, qelem);
 			}
 		}
@@ -284,7 +245,15 @@
 			i = ip->ip_node->n_right->n_lval;
 		else
 			continue;
-		lblary[i-low] |= 1;
+
+		/*
+		 * Mark destination label i as used, if it is not already.
+		 * If i is to be merged with label j, mark j as used, too.
+		 */
+		if (lblary[i - low] == 0)
+			lblary[i-low] = 1;
+		else if ((j = lblary[i - low]) < 0 && lblary[-j - low] == 0)
+			lblary[-j - low] = 1;
 	}
 
 	/* delete coalesced/unused labels and rename gotos */
@@ -295,22 +264,33 @@
 				DLIST_REMOVE(n, qelem);
 				gotone = 1;
 			}
-			continue;
 		}
-		if (n->type != IP_NODE)
+		if (ip->type != IP_NODE)
 			continue;
-		o = n->ip_node->n_op;
+		o = ip->ip_node->n_op;
 		if (o == GOTO)
-			i = n->ip_node->n_left->n_lval;
+			i = ip->ip_node->n_left->n_lval;
 		else if (o == CBRANCH)
-			i = n->ip_node->n_right->n_lval;
+			i = ip->ip_node->n_right->n_lval;
 		else
 			continue;
+
+		/* Simplify (un-)conditional jumps to unconditional jumps. */
+		if (jmpary[i - low] > 0) {
+			gotone = 1;
+			i = jmpary[i - low];
+			if (o == GOTO)
+				ip->ip_node->n_left->n_lval = i;
+			else
+				ip->ip_node->n_right->n_lval = i;
+		}
+
+		/* Fixup for coalesced labels. */
 		if (lblary[i-low] < 0) {
 			if (o == GOTO)
-				n->ip_node->n_left->n_lval = -lblary[i-low];
+				ip->ip_node->n_left->n_lval = -lblary[i-low];
 			else
-				n->ip_node->n_right->n_lval = -lblary[i-low];
+				ip->ip_node->n_right->n_lval = -lblary[i-low];
 		}
 	}
 
@@ -332,13 +312,61 @@
 
 		if (ip2->type != IP_DEFLAB)
 			continue;
-		if (ip2->ip_lbl == i) {
+		if (ip2->ip_lbl == i && i != lab1 && i != lab2) {
 			tfree(n->ip_node);
 			DLIST_REMOVE(n, qelem);
 			gotone = 1;
 		}
 	}
 
+	/*
+	 * Transform cbranch cond, 1; goto 2; 1: ... into
+	 * cbranch !cond, 2; 1: ...
+	 */
+	DLIST_FOREACH(ip, ipole, qelem) {
+		n = DLIST_NEXT(ip, qelem);
+		ip2 = DLIST_NEXT(n, qelem);
+		if (ip->type != IP_NODE || ip->ip_node->n_op != CBRANCH)
+			continue;
+		if (n->type != IP_NODE || n->ip_node->n_op != GOTO)
+			continue;
+		if (ip2->type != IP_DEFLAB)
+			continue;
+		i = ip->ip_node->n_right->n_lval;
+		j = n->ip_node->n_left->n_lval;
+		if (j == lab1 || j == lab2)
+			continue;
+		if (i != ip2->ip_lbl || i == lab1 || i == lab2)
+			continue;
+		ip->ip_node->n_right->n_lval = j;
+		i = ip->ip_node->n_left->n_op;
+		if (i < EQ || i - EQ >= (int)negrelsize)
+			comperr("deljumps: unexpected op");
+		ip->ip_node->n_left->n_op = negrel[i - EQ];
+		tfree(n->ip_node);
+		DLIST_REMOVE(n, qelem);
+		gotone = 1;
+	}
+
+	/* Delete everything after a goto up to the next label. */
+	for (ip = start, del = 0; ip != DLIST_ENDMARK(ipole);
+	     ip = DLIST_NEXT(ip, qelem)) {
+loop:
+		if ((n = DLIST_NEXT(ip, qelem)) == DLIST_ENDMARK(ipole))
+			break;
+		if (n->type != IP_NODE) {
+			del = 0;
+			continue;
+		}
+		if (del) {
+			tfree(n->ip_node);
+			DLIST_REMOVE(n, qelem);
+			gotone = 1;
+			goto loop;
+		} else if (n->ip_node->n_op == GOTO)
+			del = 1;
+	}
+
 	if (gotone)
 		goto again;
 
@@ -355,7 +383,9 @@
 	printf("type %s\n", nm[ip->type-1]);
 	switch (ip->type) {
 	case IP_NODE:
+#ifdef PCC_DEBUG
 		fwalk(ip->ip_node, e2print, 0);
+#endif
 		break;
 	case IP_DEFLAB:
 		printf("label " LABFMT "\n", ip->ip_lbl);
@@ -374,9 +404,10 @@
  */
 
 void
-bblocks_build(struct interpass *ipole, struct labelinfo *labinfo,
+bblocks_build(struct p2env *p2e, struct labelinfo *labinfo,
     struct bblockinfo *bbinfo)
 {
+	struct interpass *ipole = &p2e->ipole;
 	struct interpass *ip;
 	struct basicblock *bb = NULL;
 	int low, high;
@@ -384,8 +415,8 @@
 	int i;
 
 	BDEBUG(("bblocks_build (%p, %p)\n", labinfo, bbinfo));
-	low = ipp->ip_lblnum;
-	high = epp->ip_lblnum;
+	low = p2e->ipp->ip_lblnum;
+	high = p2e->epp->ip_lblnum;
 
 	/* 
 	 * First statement is a leader.
@@ -410,8 +441,9 @@
 			bb->dfchildren = NULL;
 			bb->Aorig = NULL;
 			bb->Aphi = NULL;
+			SLIST_INIT(&bb->phi);
 			bb->bbnum = count;
-			DLIST_INSERT_BEFORE(&bblocks, bb, bbelem);
+			DLIST_INSERT_BEFORE(&p2e->bblocks, bb, bbelem);
 			count++;
 		}
 		bb->last = ip;
@@ -421,12 +453,12 @@
 		if (ip->type == IP_PROLOG)
 			bb = NULL;
 	}
-	nbblocks = count;
+	p2e->nbblocks = count;
 
 	if (b2debug) {
 		printf("Basic blocks in func: %d, low %d, high %d\n",
 		    count, low, high);
-		DLIST_FOREACH(bb, &bblocks, bbelem) {
+		DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
 			printf("bb %p: first %p last %p\n", bb,
 			    bb->first, bb->last);
 		}
@@ -446,7 +478,7 @@
 	}
 
 	/* Build the label table */
-	DLIST_FOREACH(bb, &bblocks, bbelem) {
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
 		if (bb->first->type == IP_DEFLAB)
 			labinfo->arr[bb->first->ip_lbl - low] = bb;
 	}
@@ -465,14 +497,14 @@
  */
 
 void
-cfg_build(struct labelinfo *labinfo)
+cfg_build(struct p2env *p2e, struct labelinfo *labinfo)
 {
 	/* Child and parent nodes */
 	struct cfgnode *cnode; 
 	struct cfgnode *pnode;
 	struct basicblock *bb;
 	
-	DLIST_FOREACH(bb, &bblocks, bbelem) {
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
 
 		if (bb->first->type == IP_EPILOG) {
 			break;
@@ -483,7 +515,8 @@
 		pnode->bblock = bb;
 
 		if ((bb->last->type == IP_NODE) && 
-		    (bb->last->ip_node->n_op == GOTO)) {
+		    (bb->last->ip_node->n_op == GOTO) &&
+		    (bb->last->ip_node->n_left->n_op == ICON))  {
 			if (bb->last->ip_node->n_left->n_lval - labinfo->low > 
 			    labinfo->size) {
 				comperr("Label out of range: %d, base %d", 
@@ -550,27 +583,27 @@
  */
 
 void
-dominators(struct bblockinfo *bbinfo)
+dominators(struct p2env *p2e, struct bblockinfo *bbinfo)
 {
 	struct cfgnode *cnode;
 	struct basicblock *bb, *y, *v;
 	struct basicblock *s, *sprime, *p;
 	int h, i;
 
-	DLIST_FOREACH(bb, &bblocks, bbelem) {
+	DLIST_FOREACH(bb, &p2e->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);
+	cfg_dfs(DLIST_NEXT(&p2e->bblocks, bbelem), 0, bbinfo);
 
 	if (b2debug) {
 		struct basicblock *bbb;
 		struct cfgnode *ccnode;
 
-		DLIST_FOREACH(bbb, &bblocks, bbelem) {
+		DLIST_FOREACH(bbb, &p2e->bblocks, bbelem) {
 			printf("Basic block %d, parents: ", bbb->dfnum);
 			SLIST_FOREACH(ccnode, &bbb->parents, cfgelem) {
 				printf("%d, ", ccnode->bblock->dfnum);
@@ -587,6 +620,9 @@
 		bb = bbinfo->arr[h];
 		p = s = bbinfo->arr[bb->dfparent];
 		SLIST_FOREACH(cnode, &bb->parents, cfgelem) {
+			if (cnode->bblock->dfnum ==0)
+				continue; /* Ignore unreachable code */
+
 			if (cnode->bblock->dfnum <= bb->dfnum) 
 				sprime = cnode->bblock;
 			else 
@@ -613,7 +649,7 @@
 
 	if (b2debug) {
 		printf("Num\tSemi\tAncest\tidom\n");
-		DLIST_FOREACH(bb, &bblocks, bbelem) {
+		DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
 			printf("%d\t%d\t%d\t%d\n", bb->dfnum, bb->semi,
 			    bb->ancestor, bb->idom);
 		}
@@ -625,7 +661,7 @@
 			bb->idom = bbinfo->arr[bb->samedom]->idom;
 		}
 	}
-	DLIST_FOREACH(bb, &bblocks, bbelem) {
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
 		if (bb->idom != 0 && bb->idom != bb->dfnum) {
 			BDEBUG(("Setting child %d of %d\n",
 			    bb->dfnum, bbinfo->arr[bb->idom]->dfnum));
@@ -672,36 +708,70 @@
 		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))) 
+			    (bbinfo->arr[i] == bblock ||
+			     (bblock->dfnum != bbinfo->arr[i]->idom))) 
 			    BITSET(bblock->df, i);
 		}
 	}
 }
 
+void printDF(struct p2env *p2e, struct bblockinfo *bbinfo)
+{
+	struct basicblock *bb;
+	int i;
+
+	printf("Dominance frontiers:\n");
+    
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		printf("bb %d : ", bb->dfnum);
+	
+		for (i=1; i < bbinfo->size;i++) {
+			if (TESTBIT(bb->df,i)) {
+				printf("%d ",i);
+			}
+		}
+	    
+		printf("\n");
+	}
+    
+}
+
+
+
 static struct basicblock *currbb;
 static struct interpass *currip;
 
 /* Helper function for findTemps, Find assignment nodes. */
 static void
-searchasg(NODE *p)
+searchasg(NODE *p, void *arg)
 {
 	struct pvarinfo *pv;
-
+	int tempnr;
+	struct varstack *stacke;
+    
 	if (p->n_op != ASSIGN)
 		return;
 
 	if (p->n_left->n_op != TEMP)
 		return;
 
+	tempnr=regno(p->n_left)-defsites.low;
+    
+	BITSET(currbb->Aorig, tempnr);
+	
 	pv = tmpcalloc(sizeof(struct pvarinfo));
-	pv->next = defsites.arr[p->n_left->n_lval];
+	pv->next = defsites.arr[tempnr];
 	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;
+	pv->n_type = p->n_left->n_type;
+	
+	defsites.arr[tempnr] = pv;
+	
+	
+	if (SLIST_FIRST(&defsites.stack[tempnr])==NULL) {
+		stacke=tmpcalloc(sizeof (struct varstack));
+		stacke->tmpregno=0;
+		SLIST_INSERT_FIRST(&defsites.stack[tempnr],stacke,varstackelem);
+	}
 }
 
 /* Walk the interpass looking for assignment nodes. */
@@ -712,7 +782,7 @@
 
 	currip = ip;
 
-	walkf(ip->ip_node, searchasg);
+	walkf(ip->ip_node, searchasg, 0);
 }
 
 /*
@@ -720,32 +790,37 @@
  */
 
 void
-placePhiFunctions(struct bblockinfo *bbinfo)
+placePhiFunctions(struct p2env *p2e, struct bblockinfo *bbinfo)
 {
 	struct basicblock *bb;
+	struct basicblock *y;
 	struct interpass *ip;
-	int maxtmp, i, j, k, l;
+	int maxtmp, i, j, k;
 	struct pvarinfo *n;
 	struct cfgnode *cnode;
 	TWORD ntype;
-	NODE *p;
 	struct pvarinfo *pv;
+	struct phiinfo *phi;
+	int phifound;
 
-	bb = DLIST_NEXT(&bblocks, bbelem);
+	bb = DLIST_NEXT(&p2e->bblocks, bbelem);
 	defsites.low = ((struct interpass_prolog *)bb->first)->ip_tmpnum;
-	bb = DLIST_PREV(&bblocks, bbelem);
+	bb = DLIST_PREV(&p2e->bblocks, bbelem);
 	maxtmp = ((struct interpass_prolog *)bb->first)->ip_tmpnum;
 	defsites.size = maxtmp - defsites.low + 1;
 	defsites.arr = tmpcalloc(defsites.size*sizeof(struct pvarinfo *));
-
+	defsites.stack = tmpcalloc(defsites.size*sizeof(SLIST_HEAD(, varstack)));
+	
+	for (i=0;i<defsites.size;i++)
+		SLIST_INIT(&defsites.stack[i]);	
+	
 	/* Find all defsites */
-	DLIST_FOREACH(bb, &bblocks, bbelem) {
+	DLIST_FOREACH(bb, &p2e->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);
@@ -753,8 +828,9 @@
 		/* Make sure we get the last statement in the bblock */
 		findTemps(ip);
 	}
+    
 	/* For each variable */
-	for (i = defsites.low; i < defsites.size; i++) {
+	for (i = 0; i < defsites.size; i++) {
 		/* While W not empty */
 		while (defsites.arr[i] != NULL) {
 			/* Remove some node n from W */
@@ -768,27 +844,45 @@
 				if (TESTBIT(bbinfo->arr[j]->Aphi, i))
 					continue;
 
-				ntype = n->n->n_type;
+				y=bbinfo->arr[j];
+				ntype = n->n_type;
 				k = 0;
 				/* Amount of predecessors for y */
-				SLIST_FOREACH(cnode, &n->bb->parents, cfgelem) 
+				SLIST_FOREACH(cnode, &y->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;
+				/* Construct phi(...) 
+				*/
+			    
+				phifound=0;
+			    
+				SLIST_FOREACH(phi, &y->phi, phielem) {
+				    if (phi->tmpregno==i+defsites.low)
+					phifound++;
+				}
+			    
+				if (phifound==0) {
+					if (b2debug)
+					    printf("Phi in %d (%p) for %d\n",y->dfnum,y,i+defsites.low);
+
+					phi = tmpcalloc(sizeof(struct phiinfo));
+			    
+					phi->tmpregno=i+defsites.low;
+					phi->size=k;
+					phi->n_type=ntype;
+					phi->intmpregno=tmpcalloc(k*sizeof(int));
+			    
+					SLIST_INSERT_LAST(&y->phi,phi,phielem);
+				} else {
+				    if (b2debug)
+					printf("Phi already in %d for %d\n",y->dfnum,i+defsites.low);
+				}
+
 				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;
+					pv->bb = y;
+				        pv->n_type=ntype;
+					pv->next = defsites.arr[i];
 					defsites.arr[i] = pv;
 				}
 					
@@ -798,18 +892,232 @@
 	}
 }
 
+/* Helper function for renamevar. */
+static void
+renamevarhelper(struct p2env *p2e,NODE *t,void *poplistarg)
+{	
+	SLIST_HEAD(, varstack) *poplist=poplistarg;
+	int opty;
+	int tempnr;
+	int newtempnr;
+	int x;
+	struct varstack *stacke;
+	
+	if (t->n_op == ASSIGN && t->n_left->n_op == TEMP) {
+		renamevarhelper(p2e,t->n_right,poplist);
+				
+		tempnr=regno(t->n_left)-defsites.low;
+		
+		newtempnr=p2e->epp->ip_tmpnum++;
+		regno(t->n_left)=newtempnr;
+		
+		stacke=tmpcalloc(sizeof (struct varstack));
+		stacke->tmpregno=newtempnr;
+		SLIST_INSERT_FIRST(&defsites.stack[tempnr],stacke,varstackelem);
+		
+		stacke=tmpcalloc(sizeof (struct varstack));
+		stacke->tmpregno=tempnr;
+		SLIST_INSERT_FIRST(poplist,stacke,varstackelem);
+	} else {
+		if (t->n_op == TEMP) {
+			tempnr=regno(t)-defsites.low;
+			
+			x=SLIST_FIRST(&defsites.stack[tempnr])->tmpregno;
+			regno(t)=x;
+		}
+		
+		opty = optype(t->n_op);
+		
+		if (opty != LTYPE)
+			renamevarhelper(p2e, t->n_left,poplist);
+		if (opty == BITYPE)
+			renamevarhelper(p2e, t->n_right,poplist);
+	}
+}
+
+
+void
+renamevar(struct p2env *p2e,struct basicblock *bb, struct bblockinfo *bbinfo)
+{
+    	struct interpass *ip;
+	int h,j;
+	SLIST_HEAD(, varstack) poplist;
+	struct varstack *stacke;
+	struct cfgnode *cfgn;
+	struct cfgnode *cfgn2;
+	int tmpregno,newtmpregno;
+	struct phiinfo *phi;
+	
+	SLIST_INIT(&poplist);
+	
+	SLIST_FOREACH(phi,&bb->phi,phielem) {
+		tmpregno=phi->tmpregno-defsites.low;
+		
+		newtmpregno=p2e->epp->ip_tmpnum++;
+		phi->newtmpregno=newtmpregno;
+		
+		stacke=tmpcalloc(sizeof (struct varstack));
+		stacke->tmpregno=newtmpregno;
+		SLIST_INSERT_FIRST(&defsites.stack[tmpregno],stacke,varstackelem);
+		
+		stacke=tmpcalloc(sizeof (struct varstack));
+		stacke->tmpregno=tmpregno;
+		SLIST_INSERT_FIRST(&poplist,stacke,varstackelem);		
+	}
+	
+	
+	ip=bb->first;
+	
+	while (1) {		
+		if ( ip->type == IP_NODE) {
+			renamevarhelper(p2e,ip->ip_node,&poplist);
+		}
+		
+		if (ip==bb->last)
+			break;
+		
+		ip = DLIST_NEXT(ip, qelem);
+	}
+	
+	SLIST_FOREACH(cfgn,&bb->children,cfgelem) {
+		j=0;
+		
+		SLIST_FOREACH(cfgn2, &cfgn->bblock->parents, cfgelem) { 
+			if (cfgn2->bblock->dfnum==bb->dfnum)
+				break;
+			
+			j++;
+		}
+
+		SLIST_FOREACH(phi,&cfgn->bblock->phi,phielem) {
+			phi->intmpregno[j]=SLIST_FIRST(&defsites.stack[phi->tmpregno-defsites.low])->tmpregno;
+		}
+		
+	}
+	
+	for (h = 1; h < bbinfo->size; h++) {
+		if (!TESTBIT(bb->dfchildren, h))
+			continue;
+		
+		renamevar(p2e,bbinfo->arr[h], bbinfo);
+	}
+	
+	SLIST_FOREACH(stacke,&poplist,varstackelem) {
+		tmpregno=stacke->tmpregno;
+		
+		defsites.stack[tmpregno].q_forw=defsites.stack[tmpregno].q_forw->varstackelem.q_forw;
+	}
+}
+
+void
+removephi(struct p2env *p2e, struct labelinfo *labinfo,struct bblockinfo *bbinfo)
+{
+	struct basicblock *bb,*bbparent;
+	struct cfgnode *cfgn;
+	struct phiinfo *phi;
+	int i;
+	struct interpass *ip;
+	struct interpass *pip;
+	TWORD n_type;
+	int complex;
+	int label=0;
+	int newlabel;
+	
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {		
+		SLIST_FOREACH(phi,&bb->phi,phielem) { // Look at only one, notice break at end
+			i=0;
+			
+			SLIST_FOREACH(cfgn, &bb->parents, cfgelem) { 
+				bbparent=cfgn->bblock;
+				
+				pip=bbparent->last;
+				
+				complex = 0;
+				
+				BDEBUG(("removephi: %p in %d",pip,bb->dfnum));
+				if (pip->type == IP_NODE && pip->ip_node->n_op == GOTO) {
+					BDEBUG((" GOTO "));
+					label=pip->ip_node->n_left->n_lval;
+					complex=1;
+				} else if (pip->type == IP_NODE && pip->ip_node->n_op == CBRANCH) {
+					BDEBUG((" CBRANCH "));
+					label=pip->ip_node->n_right->n_lval;
+					
+					if (bb==labinfo->arr[label - p2e->ipp->ip_lblnum])
+						complex=2;
+				}	
+       
+				BDEBUG((" Complex: %d\n",complex));
+
+				if (complex > 0) {
+					/*
+					 This destroys basic block calculations.
+					 Maybe it shoud not
+					*/
+					ip = ipnode(mkunode(GOTO, mklnode(ICON, label, 0, INT), 0, INT));
+					DLIST_INSERT_BEFORE((bb->first), ip, qelem);
+					
+					newlabel=getlab2();
+					
+					ip = tmpalloc(sizeof(struct interpass));
+					ip->type = IP_DEFLAB;
+					// Line number?? ip->lineno;
+					ip->ip_lbl = newlabel;
+					DLIST_INSERT_BEFORE((bb->first), ip, qelem);
+					
+					SLIST_FOREACH(phi,&bb->phi,phielem) {
+						if (phi->intmpregno[i]>0) {
+							n_type=phi->n_type;
+							ip = ipnode(mkbinode(ASSIGN,
+								     mktemp(phi->newtmpregno, n_type),
+								     mktemp(phi->intmpregno[i],n_type),
+								     n_type));
+					
+							DLIST_INSERT_BEFORE((bb->first), ip, qelem);
+						}
+					}
+					
+					if (complex==1)
+						pip->ip_node->n_left->n_lval=newlabel;
+					
+					if (complex==2)
+						pip->ip_node->n_right->n_lval=newlabel;
+					
+				} else {
+					/* Construct move */
+					SLIST_FOREACH(phi,&bb->phi,phielem) {
+						if (phi->intmpregno[i]>0) {
+							n_type=phi->n_type;
+							ip = ipnode(mkbinode(ASSIGN,
+							     mktemp(phi->newtmpregno, n_type),
+							     mktemp(phi->intmpregno[i],n_type),
+							     n_type));
+				
+							/* Insert move at bottom of parent basic block */
+							DLIST_INSERT_AFTER((bbparent->last), ip, qelem);
+						}
+					}
+				}
+				i++;
+			}
+			break;
+		}
+	}
+}
+
+    
 /*
  * Remove unreachable nodes in the CFG.
  */ 
 
 void
-remunreach(void)
+remunreach(struct p2env *p2e)
 {
 	struct basicblock *bb, *nbb;
 	struct interpass *next, *ctree;
 
-	bb = DLIST_NEXT(&bblocks, bbelem);
-	while (bb != &bblocks) {
+	bb = DLIST_NEXT(&p2e->bblocks, bbelem);
+	while (bb != &p2e->bblocks) {
 		nbb = DLIST_NEXT(bb, bbelem);
 
 		/* Code with dfnum 0 is unreachable */
@@ -848,7 +1156,8 @@
 	static char *foo[] = {
 	   0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" };
 	struct interpass *ip;
-	struct interpass_prolog *ipp, *epp;
+	struct interpass_prolog *ipplg, *epplg;
+	unsigned i;
 
 	DLIST_FOREACH(ip, pole, qelem) {
 		if (ip->type > MAXIP)
@@ -857,20 +1166,28 @@
 			printf("%s (%p): ", foo[ip->type], ip);
 		switch (ip->type) {
 		case IP_NODE: printf("\n");
+#ifdef PCC_DEBUG
 			fwalk(ip->ip_node, e2print, 0); break;
+#endif
 		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);
+			ipplg = (struct interpass_prolog *)ip;
+			printf("%s %s regs",
+			    ipplg->ipp_name, ipplg->ipp_vis ? "(local)" : "");
+			for (i = 0; i < NIPPREGS; i++)
+				printf("%s0x%x", i? ":" : " ",
+				    ipplg->ipp_regs[i]);
+			printf(" autos %d mintemp %d minlbl %d\n",
+			    ipplg->ipp_autos, ipplg->ip_tmpnum, ipplg->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);
+			epplg = (struct interpass_prolog *)ip;
+			printf("%s %s regs",
+			    epplg->ipp_name, epplg->ipp_vis ? "(local)" : "");
+			for (i = 0; i < NIPPREGS; i++)
+				printf("%s0x%x", i? ":" : " ",
+				    epplg->ipp_regs[i]);
+			printf(" autos %d mintemp %d minlbl %d\n",
+			    epplg->ipp_autos, epplg->ip_tmpnum, epplg->ip_lblnum);
 			break;
 		case IP_DEFLAB: printf(LABFMT "\n", ip->ip_lbl); break;
 		case IP_DEFNAM: printf("\n"); break;
Index: protos.h
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/mip/protos.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/mip/protos.h -L usr.bin/pcc/mip/protos.h -u -r1.1 -r1.2
--- usr.bin/pcc/mip/protos.h
+++ usr.bin/pcc/mip/protos.h
@@ -1,24 +1,9 @@
 
-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);
@@ -26,58 +11,29 @@
 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);
+int fldexpand(NODE *, int, char **);
 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);
Index: ccconfig.h
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/ccconfig.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L usr.bin/pcc/ccconfig.h -L usr.bin/pcc/ccconfig.h -u -r1.1 -r1.2
--- usr.bin/pcc/ccconfig.h
+++ usr.bin/pcc/ccconfig.h
@@ -1,43 +1,129 @@
+/* $Id: ccconfig.h,v 1.4 2008/07/18 06:53:48 gmcgarry Exp $ */
 /*-
- * 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.
+ * Copyright (c) 2007, 2008
+ *	Thorsten Glaser <tg at mirbsd.de>
  *
- * 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.
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
  *
- * 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.
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
  */
 
-#define CPPADD { "-D__MidnightBSD__", "-D__ELF__", "-D__unix__=1", "-D__unix=1", "-D__STDC__=1", NULL, }
-#define DYNLINKER { "-dynamic-linker", "/libexec/ld-elf.so.1", 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"
+/**
+ * Configuration for pcc on a MidnightBSD (amd64, i386 or sparc64) target
+ */
 
-#if defined(mach_i386) || defined(mach_x86)
-#define CPPMDADD { "-D__i386__", "-D__i386", NULL, }
-#else
-#error defines for arch missing
+/* === mi part === */
+
+#ifndef LIBDIR
+#define LIBDIR			"/usr/lib/"
 #endif
 
+/* cpp MI defines */
+#define CPPADD			{		\
+	"-D__MidnightBSD__",			\
+	"-D__FreeBSD__",			\
+	"-D__unix__",				\
+	"-D__unix",				\
+	"-Dunix",				\
+	"-D__ELF__",				\
+	"-D_LONGLONG",				\
+	NULL					\
+}
+
+/* for dynamically linked binaries */
+#define DYNLINKER		{		\
+	"-dynamic-linker",			\
+	"/libexec/ld-elf.so.1",			\
+	NULL					\
+}
+#define STARTFILES		{		\
+	LIBDIR "crti.o",			\
+	LIBDIR "crtbegin.o",			\
+	NULL					\
+}
+#define ENDFILES		{		\
+	LIBDIR "crtend.o",			\
+	LIBDIR "crtn.o",			\
+	NULL					\
+}
+
+/* for shared libraries */
+#define STARTFILES_S		{		\
+	LIBDIR "crti.o",			\
+	LIBDIR "crtbeginS.o",			\
+	NULL					\
+}
+#define ENDFILES_S		{		\
+	LIBDIR "crtendS.o",			\
+	LIBDIR "crtn.o",			\
+	NULL					\
+}
+
+/* for statically linked binaries */
+#define STARTFILES_T		{		\
+	LIBDIR "crti.o",			\
+	LIBDIR "crtbeginT.o",			\
+	NULL					\
+}
+#define ENDFILES_T		{		\
+	LIBDIR "crtend.o",			\
+	LIBDIR "crtn.o",			\
+	NULL					\
+}
+
+#define LIBCLIBS		{		\
+	"-lc",					\
+	NULL					\
+}
+#define LIBCLIBS_PROFILE	{		\
+	"-lc_p",				\
+	NULL					\
+}
+
+
+/* C run-time startup */
+#define CRT0FILE		LIBDIR "crt1.o"
+#define CRT0FILE_PROFILE	LIBDIR "gcrt1.o"
+#define STARTLABEL		"_start"
+
+/* debugging info */
 #define STABS
 
+/* === md part === */
+
+#if defined(mach_i386)
+#define CPPMDADD		{		\
+	"-D__i386__",				\
+	"-D__i386",				\
+	"-Di386",				\
+	NULL,					\
+}
+#elif defined(mach_sparc64)
+#define CPPMDADD		{		\
+	"-D__sparc64__",			\
+	"-D__sparc_v9__",			\
+	"-D__sparcv9",				\
+	"-D__sparc__",				\
+	"-D__sparc",				\
+	"-Dsparc",				\
+	"-D__arch64__",				\
+	"-D__LP64__",				\
+	"-D_LP64",				\
+	NULL,					\
+}
+#elif defined(mach_amd64)
+#error pcc does not support amd64 yet
+#else
+#error this architecture is not supported by MidnightBSD
+#endif
Index: config.h
===================================================================
RCS file: /home/cvs/src/usr.bin/pcc/config.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -L usr.bin/pcc/config.h -L usr.bin/pcc/config.h -u -r1.3 -r1.4
--- usr.bin/pcc/config.h
+++ usr.bin/pcc/config.h
@@ -1,6 +1,21 @@
 /* config.h.  Generated from config.h.in by configure.  */
 /* config.h.in.  Generated from configure.ac by autoheader.  */
 
+/* Using a.out ABI */
+/* #undef AOUTABI */
+
+/* Define path to alternate assembler */
+/* #undef ASSEMBLER */
+
+/* Using Classic 68k ABI */
+/* #undef CLASSIC68K */
+
+/* Using COFF ABI */
+/* #undef COFFABI */
+
+/* Define path to alternate preprocessor */
+/* #undef COMPILER */
+
 /* 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.
    */
@@ -9,6 +24,12 @@
 /* Define to 1 if using `alloca.c'. */
 /* #undef C_ALLOCA */
 
+/* Using ECOFF ABI */
+/* #undef ECOFFABI */
+
+/* Using ELF ABI */
+#define ELFABI 
+
 /* Define to 1 if you have `alloca', as a function or macro. */
 #define HAVE_ALLOCA 1
 
@@ -16,30 +37,38 @@
    */
 /* #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 `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if printf supports C99 size specifiers */
+#define HAVE_C99_FORMAT 1
+
+/* Define to 1 if your compiler supports C99 variadic macros */
+#define HAVE_CPP_VARARG_MACRO_GCC 1
 
-/* Define to 1 if you have the <fcntl.h> header file. */
-/* #undef HAVE_FCNTL_H */
+/* Define to 1 if you have the `ffs' function. */
+#define HAVE_FFS 1
 
-/* Define to 1 if you have the `fork' function. */
-/* #undef HAVE_FORK */
+/* Define to 1 if you have the `getopt' function. */
+#define HAVE_GETOPT 1
 
 /* 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 <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the <malloc.h> header file. */
+/* #undef HAVE_MALLOC_H */
 
 /* 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 you have the `mkstemp' function. */
+#define HAVE_MKSTEMP 1
 
-/* Define to 1 if stdbool.h conforms to C99. */
-/* #undef HAVE_STDBOOL_H */
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
 
 /* Define to 1 if you have the <stdint.h> header file. */
 #define HAVE_STDINT_H 1
@@ -47,27 +76,17 @@
 /* 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 HAVE_STRCHR 1
-
-/* Define to 1 if you have the `strdup' function. */
-/* #undef HAVE_STRDUP */
-#define HAVE_STRDUP 1
-
 /* 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 HAVE_STRRCHR 1
-
-/* Define to 1 if you have the `strtol' function. */
-/* #undef HAVE_STRTOL */
-#define HAVE_STRTOL 1
+/* Define to 1 if you have the `strlcat' function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
 
 /* Define to 1 if you have the <sys/stat.h> header file. */
 #define HAVE_SYS_STAT_H 1
@@ -76,51 +95,61 @@
 #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 HAVE_SYS_WAIT_H 1
 
 /* 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 HAVE_VFORK 1
+/* Define to 1 if you have the `vsnprintf' function. */
+#define HAVE_VSNPRINTF 1
 
-/* Define to 1 if you have the <vfork.h> header file. */
-/* #undef HAVE_VFORK_H */
+/* Define if host is BIG endian */
+/* #undef HOST_BIG_ENDIAN */
 
-/* Define to 1 if you have the `vprintf' function. */
-/* #undef HAVE_VPRINTF */
-#define HAVE_VPRINTF 1
+/* Define if host is LITTLE endian */
+#define HOST_LITTLE_ENDIAN 
 
-/* Define to 1 if `fork' works. */
-/* #undef HAVE_WORKING_FORK */
+/* lex is flex */
+#define ISFLEX 1
 
-/* Define to 1 if `vfork' works. */
-/* #undef HAVE_WORKING_VFORK */
+/* Define alternate standard lib directory */
+/* #undef LIBDIR */
 
-/* Define to 1 if the system has the type `_Bool'. */
-/* #undef HAVE__BOOL */
+/* Define path to alternate linker */
+/* #undef LINKER */
 
-/* Name of package */
-/* #undef PACKAGE */
+/* Using Mach-O ABI */
+/* #undef MACHOABI */
 
 /* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "BUG-REPORT-ADDRESS"
+#define PACKAGE_BUGREPORT "<pcc-list at ludd.ltu.se>"
 
 /* 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 PACKAGE_STRING "pcc 0.9.9"
 
 /* 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 PACKAGE_VERSION "0.9.9"
+
+/* Major version no */
+#define PCC_MAJOR 0
 
-/* Define as the return type of signal handlers (`int' or `void'). */
-/* #undef RETSIGTYPE */
+/* Minor version no */
+#define PCC_MINOR 9
+
+/* Minor minor version no */
+#define PCC_MINORMINOR 9
+
+/* Using PE/COFF ABI */
+/* #undef PECOFFABI */
+
+/* Define path to alternate preprocessor */
+/* #undef PREPROCESSOR */
 
 /* If using the C implementation of alloca, define if you know the
    direction of stack growth for your system; otherwise it will be
@@ -133,30 +162,24 @@
 /* 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.2, 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 alternate standard include directory */
+/* #undef STDINC */
 
-/* Define to `int' if <sys/types.h> does not define. */
-/* #undef pid_t */
+/* Define if target defaults to BIG endian */
+/* #undef TARGET_BIG_ENDIAN */
 
-/* Define as `fork' if `vfork' does not work. */
-/* #undef vfork */
+/* Define if target defaults to LITTLE endian */
+#define TARGET_LITTLE_ENDIAN 1
 
-/* target operating system */
+/* Target OS */
 #define TARGOS midnightbsd
 
-/* mkstemp() */
-#define HAVE_MKSTEMP 1
+/* Enable thread-local storage (TLS). */
+/* #undef TLS */
 
-/* which lex is used */
-#define ISFLEX 1
+/* Version string */
+#define VERSSTR "pcc 0.9.9 for i386-unknown-midnightbsd0.3, root at defiant.midnightbsd.org Tue Jan 20 15:33:42 EST 2009"
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#define YYTEXT_POINTER 1
--- /dev/null
+++ usr.bin/pcc/sparc64/order.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2008 David Crawshaw <david at zentus.com>
+ * 
+ * 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 DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+#include "pass2.h"
+
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+	return 0;
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ */
+void
+offstar(NODE *p, int shape)
+{
+	if (x2debug)
+		printf("offstar(%p)\n", p);
+
+	if (p->n_op == PLUS || p->n_op == MINUS) {
+		if (p->n_right->n_op == ICON) {
+			if (isreg(p->n_left) == 0)
+				(void)geninsn(p->n_left, INAREG);
+			/* Converted in ormake() */
+			return;
+		}
+	}
+	(void)geninsn(p, INAREG);
+}
+
+void
+myormake(NODE *q)
+{
+}
+
+int
+shumul(NODE *p, int shape)
+{
+	if (shape & SOREG)
+		return SROREG;
+	return SRNOPE;
+}
+
+int
+setbin(NODE *p)
+{
+	return 0;
+}
+
+int
+setasg(NODE *p, int cookie)
+{
+	return 0;
+}
+
+int
+setuni(NODE *p, int cookie)
+{
+	return 0;
+}
+
+struct rspecial *
+nspecial(struct optab *q)
+{
+	switch (q->op) {
+	case STASG: {
+		static struct rspecial s[] = {
+			{ NEVER, O0 },
+			{ NRIGHT, O1 },
+			{ NEVER, O2 },
+			{ 0 }
+		};
+		return s;
+	}
+	}
+
+	comperr("unknown nspecial %d: %s", q - table, q->cstring);
+	return 0; /* XXX */
+}
+
+int
+setorder(NODE *p)
+{
+	return 0;
+}
+
+int *
+livecall(NODE *p)
+{
+	static int ret[] = { O0, O1, O2, O3, O4, O5, O6, O7, -1 };
+	return ret;
+}
+
+int
+acceptable(struct optab *op)
+{
+	return 1;
+}
--- /dev/null
+++ usr.bin/pcc/sparc64/macdefs.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2008 David Crawshaw <david at zentus.com>
+ * 
+ * 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 DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+
+/*
+ * Many arithmetic instructions take 'reg_or_imm' in SPARCv9, where imm
+ * means we can use a signed 13-bit constant (simm13). This gives us a
+ * shortcut for small constants, instead of loading them into a register.
+ * Special handling is required because 13 bits lies between SSCON and SCON.
+ */
+#define SIMM13(val) (val < 4096 && val > -4097)
+
+/*
+ * The SPARCv9 ABI specifies a stack bias of 2047 bits. This means that the
+ * end of our call space is %fp+V9BIAS, working back towards %sp+V9BIAS+176.
+ */
+#define V9BIAS 2047
+
+/*
+ * The ABI requires that every frame reserve 176 bits for saving registers
+ * in the case of a spill. The stack size must be 16-bit aligned.
+ */
+#define V9RESERVE 176
+#define V9STEP(x) ALIGN(x, 0xf)
+#define ALIGN(x, y) ((x & y) ? (x + y) & ~y : x)
+
+
+#define makecc(val,i)	lastcon = (lastcon<<8)|((val<<24)>>24);
+
+#define ARGINIT		(7*8) /* XXX */
+#define AUTOINIT	(0)
+
+/* Type sizes */
+#define SZCHAR		8
+#define SZBOOL		32
+#define SZINT		32
+#define SZFLOAT		32
+#define SZDOUBLE	64
+#define SZLDOUBLE	64
+#define SZLONG		64
+#define SZSHORT		16
+#define SZLONGLONG	64
+#define SZPOINT(t)	64
+
+/* Type alignments */
+#define ALCHAR		8
+#define ALBOOL		32
+#define ALINT		32
+#define ALFLOAT		32
+#define ALDOUBLE	64
+#define ALLDOUBLE	64
+#define ALLONG		64
+#define ALLONGLONG	64
+#define ALSHORT		16
+#define ALPOINT		64
+#define ALSTRUCT	32
+#define ALSTACK		64
+
+/* 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_LONGLONG	0x8000000000000000LL
+#define	MAX_LONGLONG	0x7fffffffffffffffLL
+#define	MAX_ULONGLONG	0xffffffffffffffffULL
+#define	MIN_LONG	MIN_LONGLONG
+#define	MAX_LONG	MAX_LONGLONG
+#define	MAX_ULONG	MAX_ULONGLONG
+
+#define BOOL_TYPE	INT
+#define WCHAR_TYPE	INT
+
+typedef	long long CONSZ;
+typedef	unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT	"%lld"
+#define LABFMT  "L%d"
+#define STABLBL "LL%d"
+
+#define BACKAUTO 		/* Stack grows negatively for automatics. */
+#define BACKTEMP 		/* Stack grows negatively for temporaries. */
+
+#undef	FIELDOPS
+#define RTOLBYTES
+
+#define ENUMSIZE(high,low) INT
+#define BYTEOFF(x) 	((x)&03)
+#define BITOOR(x)	(x)
+
+#define	szty(t)	((ISPTR(t) || (t) == DOUBLE || \
+	         (t) == LONG || (t) == ULONG || \
+	         (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1)
+
+
+/* Register names. */
+
+#define MAXREGS (31 + 31 + 16 + 2)
+#define NUMCLASS 4
+
+//define G0 	-1
+#define G1 	0
+#define G2 	1
+#define G3 	2
+#define G4 	3
+#define G5 	4
+#define G6 	5
+#define G7 	6
+#define O0 	7
+#define O1 	8
+#define O2 	9
+#define O3 	10
+#define O4 	11
+#define O5 	12
+#define O6 	13
+#define O7 	14
+#define L0 	15
+#define L1 	16
+#define L2 	17
+#define L3 	18
+#define L4 	19
+#define L5 	20
+#define L6 	21
+#define L7 	22
+#define I0 	23
+#define I1 	24
+#define I2 	25
+#define I3 	26
+#define I4 	27
+#define I5 	28
+#define I6 	29
+#define I7 	30
+
+#define F0 	31
+#define F1 	32
+#define F2 	33
+#define F3 	34
+#define F4 	35
+#define F5 	36
+#define F6 	37
+#define F7 	38
+#define F8 	39
+#define F9 	40
+#define F10	41
+#define F11	42
+#define F12	43
+#define F13	44
+#define F14	45
+#define F15	46
+#define F16	47
+#define F17	48
+#define F18	49
+#define F19	50
+#define F20	51
+#define F21	52
+#define F22	53
+#define F23	54
+#define F24	55
+#define F25	56
+#define F26	57
+#define F27	58
+#define F28	59
+#define F29	60
+#define F30	61
+//define F31    XXX
+#define D0	62
+#define D1	63
+#define D2	64
+#define D3	65
+#define D4	66
+#define D5	67
+#define D6	68
+#define D7	69
+#define D8	70
+#define D9	71
+#define D10	72
+#define D11	73
+#define D12	74
+#define D13	75
+#define D14	76
+#define D15	77
+
+#define SP 	78
+#define FP 	79
+
+#define FPREG 	FP
+
+#define RETREG(x)	((x)==DOUBLE ? D0 : (x)==FLOAT ? F1 : O0)
+#define RETREG_PRE(x)	((x)==DOUBLE ? D0 : (x)==FLOAT ? F1 : I0)
+
+#define RSTATUS \
+	/* global */ \
+		               SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \
+		SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \
+	/* out */ \
+		SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+		SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+	/* local */ \
+		SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+		SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+	/* in */ \
+		SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+		SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+	/* 32-bit floating point */ \
+		SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \
+		SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \
+		SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \
+		SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, /*, SBREG */ \
+	/* 64-bit floating point */ \
+		SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \
+		SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \
+	/* sp */ SDREG, \
+	/* fp */ SDREG
+
+#define ROVERLAP \
+	        { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+/* 32-bit floating point */ \
+	{  D0, -1 }, {  D0, -1 }, {  D1, -1 }, {  D1, -1 }, \
+	{  D2, -1 }, {  D2, -1 }, {  D3, -1 }, {  D3, -1 }, \
+	{  D4, -1 }, {  D4, -1 }, {  D5, -1 }, {  D5, -1 }, \
+	{  D6, -1 }, {  D6, -1 }, {  D7, -1 }, {  D7, -1 }, \
+	{  D8, -1 }, {  D8, -1 }, {  D9, -1 }, {  D9, -1 }, \
+	{ D10, -1 }, { D10, -1 }, { D11, -1 }, { D11, -1 }, \
+	{ D12, -1 }, { D12, -1 }, { D13, -1 }, { D13, -1 }, \
+	{ D14, -1 }, { D14, -1 }, { D15, -1 }, /* { D15, -1 }, */ \
+/* 64-bit floating point */ \
+	{  F0,  F1, -1 }, {  F2,  F3, -1 }, {  F4,  F5, -1 }, \
+	{  F6,  F7, -1 }, {  F8,  F9, -1 }, { F10, F11, -1 }, \
+	{ F12, F13, -1 }, { F14, F15, -1 }, { F16, F17, -1 }, \
+	{ F18, F19, -1 }, { F20, F21, -1 }, { F22, F23, -1 }, \
+	{ F24, F25, -1 }, { F26, F27, -1 }, { F28, F29, -1 }, \
+	{ F30, /* F31, */ -1 }, \
+	{ -1 }, \
+	{ -1 }
+
+#define GCLASS(x) 	(x <= I7                ? CLASSA : \
+			(x <= F30               ? CLASSB : \
+			(x <= D15               ? CLASSC : \
+			(x == SP || x == FP     ? CLASSD : 0))))
+#define PCLASS(p)	(1 << gclass((p)->n_type))
+#define DECRA(x,y)	(((x) >> (y*7)) & 127)
+#define ENCRA(x,y)	((x) << (7+y*7))
+#define ENCRD(x)	(x)
+
+int COLORMAP(int c, int *r);
--- /dev/null
+++ usr.bin/pcc/sparc64/table.c
@@ -0,0 +1,963 @@
+/*
+ * Copyright (c) 2008 David Crawshaw <david at zentus.com>
+ * 
+ * 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 DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+#include "pass2.h"
+
+#define TS64   TLONG|TLONGLONG
+#define TU64   TULONG|TULONGLONG|TPOINT
+#define T64    TS64|TU64
+
+struct optab table[] = {
+
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },      /* empty */
+
+{ PCONV,	INAREG,
+	SAREG,	T64|TINT,
+	SAREG,	T64,
+		0,	RLEFT,
+		"	! convert between word and pointer\n", },
+
+/* Conversions. */
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TUNSIGNED,
+	SAREG,	TINT,
+		NAREG|NASL,	RESC1,
+		"	sra AL,0,A1	\t\t! (u)int64/32 -> (u)int32\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TINT|TUNSIGNED,
+	SAREG,	TSHORT,
+		NAREG|NASL,	RESC1,
+		"	sll AL,16,A1	\t\t! (u)int64/32 -> int16\n"
+		"	sra AL,16,A1\n"
+		"	sra AL, 0,A1\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TINT|TUNSIGNED,
+	SAREG,	TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	sll AL,16,A1	\t\t! (u)int64/32 -> uint16\n"
+		"	srl AL,16,A1\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TINT|TUNSIGNED|TSHORT|TUSHORT,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	sll AL,24,A1	\t\t! (u)int64/32/16 -> int8\n"
+		"	sra AL,24,A1\n"
+		"	sra AL, 0,A1\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TINT|TUNSIGNED|TSHORT|TUSHORT,
+	SAREG,	TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	and AL,0xff,A1	\t\t! (u)int64/32/16 -> uint8\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TINT|TUNSIGNED|TSHORT|TUSHORT,
+	SAREG,	T64,
+		0,	RLEFT,
+		"	              	\t\t! (u)int64...8 -> (u)int64\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TINT,
+		0,	RLEFT,
+		"	              	\t\t! (u)int16/8 -> int32\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TINT|TSHORT|TCHAR,
+	SAREG,	TUNSIGNED,
+		0,	RLEFT,
+		"	srl AL, 0,A1	\t\t! int32/16/8 -> uint32\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUSHORT|TUCHAR,
+	SAREG,	TUNSIGNED,
+		0,	RLEFT,
+		"	              	\t\t! uint16/8 -> uint32\n", },
+
+{ SCONV,	INBREG,
+	SBREG,	TINT|TUNSIGNED,
+	SBREG,	TFLOAT,
+		NBREG|NASL,	RESC1,
+		"	fitos AL,A1         \t\t! (u)int32 -> float\n", },
+
+{ SCONV,	INBREG,
+	SBREG,	T64,
+	SBREG,	TFLOAT,
+		NBREG|NASL,	RESC1,
+		"	fxtos AL,A1         \t\t! (u)int64 -> float\n", },
+
+{ SCONV,	INCREG,
+	SCREG,	TINT|TUNSIGNED,
+	SCREG,	TDOUBLE,
+		NCREG|NASL,	RESC1,
+		"	fitod AL,A1         \t\t! (u)int32 -> double\n", },
+
+{ SCONV,	INCREG,
+	SCREG,	T64,
+	SCREG,	TDOUBLE,
+		NCREG|NASL,	RESC1,
+		"	fxtod AL,A1         \t\t! (u)int64 -> double\n", },
+
+
+/* Floating-point conversions must be stored and loaded. */
+
+{ SCONV, 	INAREG,
+	SOREG, 	TFLOAT,
+	SAREG,	TINT,
+		NAREG|(2*NBREG),	RESC1,
+		" 	ld [AL],A2    \t\t! float -> int32\n"
+		"	nop\n"
+		"	fmovs A2,A3\n"
+		"	fstoi A2,A2\n"
+		"	st A2,[AL]\n"
+		"	nop\n"
+		"	ld [AL],A1\n"
+		"	nop\n"
+		"	st A3,[AL]\n"
+		"	nop\n", },
+
+{ SCONV, 	INAREG,
+	SOREG, 	TDOUBLE,
+	SAREG,	TINT,
+		NAREG|(2*NCREG),	RESC1,
+		" 	ld [AL],A2    \t\t! double -> int32\n"
+		"	nop\n"
+		"	fmovd A2,A3\n"
+		"	fdtoi A2,A2\n"
+		"	std A2,[AL]\n"
+		"	nop\n"
+		"	ldd [AL],A1\n"
+		"	nop\n"
+		"	std A3,[AL]\n"
+		"	nop\n", },
+
+{ SCONV,	INBREG,
+	SOREG,	T64|TUNSIGNED,
+	SBREG,	TFLOAT,
+		NBREG,	RESC1,
+		"	ld [AL],A1	\t\t! int64 -> float\n"
+		"	fxtos A1,A1\n", },
+
+{ SCONV,	INBREG,
+	SOREG,	TINT|TSHORT|TCHAR,
+	SBREG,	TFLOAT,
+		NBREG,	RESC1,
+		"	ld [AL],A1	\t\t! int32/16/8 -> float\n"
+		"	fitos A1,A1\n", }, // XXX need 'lds', 'ldh', etc
+
+{ SCONV,	INCREG,
+	SOREG,	T64|TUNSIGNED,
+	SCREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	ldd [AL],A1	\t\t! (u)int64 -> double\n"
+		"	fxtod A1,A1\n", },
+
+{ SCONV,	INCREG,
+	SOREG,	TINT|TSHORT|TCHAR,
+	SCREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	ld [AL],A1	\t\t! int32/16/8 -> double\n"
+		"	fitod A1,A1\n", }, // XXX need 'lds' 'ldh' 'ld', etc.
+
+{ SCONV,	INBREG,
+	SCREG,	TDOUBLE,
+	SBREG,	TFLOAT,
+		NBREG,	RESC1,
+		"	fdtos AL,A1 	\t\t! double -> float\n",},
+
+{ SCONV,	INCREG,
+	SBREG,	TFLOAT,
+	SCREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	fstod AL,A1 	\t\t! float -> double\n",},
+
+{ SCONV,    INAREG,
+	SBREG,  TFLOAT,
+	SAREG,  TINT,
+		NAREG|NBREG,    RESC1,
+		"	fstoi AL,A2     \t\t! float -> int\n"
+		"	st A2,[%fp+2047]\n"
+		"	nop\n"
+		"	ld [%fp+2047],A1\n"
+		"	nop\n",},
+
+{ SCONV,    INAREG,
+	SCREG,  TDOUBLE,
+	SAREG,  TINT,
+		NAREG|NCREG,    RESC1,
+		"	fdtoi AL,A2     \t\t! double -> int\n"
+		"	st A2,[%fp+2047]\n"
+		"	nop\n"
+		"	ld [%fp+2047],A1\n"
+        "	nop\n",},
+
+
+/* Multiplication and division */
+
+{ MUL,	INAREG,
+	SAREG,	TANY,
+	SAREG,	TANY,
+		NAREG|NASR|NASL,	RESC1,
+		"	mulx AL,AR,A1		! multiply\n", },
+
+{ MUL,	INBREG,
+	SBREG,	TFLOAT,
+	SBREG,	TFLOAT,
+		NBREG|NBSR|NBSL,	RESC1,
+		"	fmuls AL,AR,A1		! multiply float\n", },
+
+{ MUL,	INCREG,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG|NCSR|NCSL,	RESC1,
+		"	fmuld AL,AR,A1		! multiply double\n", },
+
+{ DIV,	INAREG,
+	SAREG,	TUNSIGNED|TUSHORT|TUCHAR|TU64,
+	SAREG,	TUNSIGNED|TUSHORT|TUCHAR|TU64,
+		NAREG|NASR|NASL,	RESC1,
+		"	udivx AL,AR,A1		! unsigned division\n", },
+
+{ DIV,	INAREG,
+	SAREG,	TINT|TSHORT|TCHAR|TS64,
+	SAREG,	TINT|TSHORT|TCHAR|TS64,
+		NAREG|NASR|NASL,	RESC1,
+		"	sdivx AL,AR,A1		! signed division\n", },
+
+{ DIV,	INBREG,
+	SBREG,	TFLOAT,
+	SBREG,	TFLOAT,
+		NBREG|NBSR|NBSL,	RESC1,
+		"	fdivs AL,AR,A1		! divide float\n", },
+
+{ DIV,	INCREG,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG|NCSR|NCSL,	RESC1,
+		"	fdivd AL,AR,A1		! divide double\n", },
+
+{ MOD,	INAREG,
+	SAREG,	TUNSIGNED|TUSHORT|TUCHAR|TU64,
+	SAREG,	TUNSIGNED|TUSHORT|TUCHAR|TU64,
+		NAREG, RESC1,
+		"	udivx AL,AR,A1		! unsigned modulo\n"
+		"	mulx A1,AR,A1\n"
+		"	sub AL,A1,A1\n", },
+
+{ MOD,	INAREG,
+	SAREG,	TINT|TSHORT|TCHAR|TS64,
+	SAREG,	TINT|TSHORT|TCHAR|TS64,
+		NAREG, RESC1,
+		"	sdivx AL,AR,A1		! signed modulo\n"
+		"	mulx A1,AR,A1\n"
+		"	sub AL,A1,A1\n", },
+
+{ PLUS,	INAREG,
+	SAREG,	TANY,
+	SAREG,	TANY,
+		NAREG|NASL,	RESC1,
+      		"	add AL,AR,A1\n", },
+
+{ PLUS,	INBREG,
+	SBREG,	TFLOAT,
+	SBREG,	TFLOAT,
+		NBREG|NBSL,	RESC1,
+      		"	fadds AL,AR,A1\n", },
+
+{ PLUS,	INCREG,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG|NCSL,	RESC1,
+      		"	faddd AL,AR,A1\n", },
+
+{ PLUS,	INAREG,
+	SAREG,	TANY,
+	SCON,	TANY,
+		(3*NAREG)|NASL,	RESC1,
+		"ZA", },
+
+{ MINUS,	INAREG,
+	SAREG,	TANY,
+	SAREG,	TANY,
+		NAREG|NASL,	RESC1,
+		"	sub AL,AR,A1\n", },
+
+{ MINUS,	INBREG,
+	SBREG,	TANY,
+	SBREG,	TANY,
+		NBREG|NBSL|NBSR,	RESC1,
+      		"	fsubs AL,AR,A1\n", },
+
+{ MINUS,	INCREG,
+	SCREG,	TANY,
+	SCREG,	TANY,
+		NCREG|NCSL|NBSR,	RESC1,
+      		"	fsubd AL,AR,A1\n", },
+
+{ MINUS,	INAREG,
+	SAREG,	TANY,
+	SCON,	TANY,
+		(3*NAREG)|NASL,	RESC1,
+		"ZB", },
+
+{ UMINUS,	INAREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,
+		"	sub %g0,AL,A1\n", },
+
+{ UMINUS,	INBREG,
+	SBREG,	TANY,
+	SANY,	TANY,
+		NBREG|NBSL,	RESC1,
+		"	fsubs %g0,AL,A1\n", },
+
+{ UMINUS,	INCREG,
+	SCREG,	TANY,
+	SANY,	TANY,
+		NCREG|NCSL,	RESC1,
+		"	fsubd %g0,AL,A1\n", },
+
+/* Shifts */
+
+{ RS,	INAREG,
+	SAREG,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG|SCON,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	sra AL,AR,A1			! shift right\n", },
+
+{ RS,	INAREG,
+	SAREG,	T64,
+	SAREG|SCON,	T64|TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	srax AL,AR,A1			! shift right\n", },
+
+{ LS,	INAREG,
+	SAREG,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG|SCON,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	sll AL,AR,A1			! shift left\n", },
+
+{ LS,	INAREG,
+	SAREG,	T64,
+	SAREG|SCON,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	sllx AL,AR,A1			! shift left\n", },
+
+{ COMPL,	INAREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,
+		"	orn AL,%g0,A1			! complement\n", },
+
+/* Assignments */
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,	TINT|TUNSIGNED,
+	SAREG,	TINT|TUNSIGNED,
+		0,	RDEST,
+		"	stw AR,[AL]		! store (u)int32\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,	TSHORT|TUSHORT,
+	SAREG,	TSHORT|TUSHORT,
+		0,	RDEST,
+        	"	sth AR,[AL]		! store (u)int16\n"
+		"	nop\n", },	
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,	TCHAR|TUCHAR,
+	SAREG,	TCHAR|TUCHAR,
+		0,	RDEST,
+        	"	stb AR,[AL]		! store (u)int8\n"
+		"	nop\n", },	
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,	T64,
+	SAREG,	T64,
+		0,	RDEST,
+		"	stx AR,[AL] 		! store (u)int64\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SOREG,	TFLOAT,
+	SBREG,	TFLOAT,
+		0,	RDEST,
+		"	st AR,[AL] 		! store float\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SOREG,	TINT,
+	SBREG,	TINT,
+		0,	RDEST,
+		"	st AR,[AL] 		! store int from fp address\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SOREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		0,	RDEST,
+		"	std AR,[AL] 		! store double\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SOREG,	TINT,
+	SCREG,	TINT,
+		0,	RDEST,
+		"	st AR,[AL] 		! store int from fp address\n"
+		"	nop\n", },
+
+
+{ ASSIGN,	FOREFF|INAREG,
+	SNAME,	TINT|TUNSIGNED,
+	SAREG,	TINT|TUNSIGNED,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store (u)int32 into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	stw AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SNAME,	TSHORT|TUSHORT,
+	SAREG,	TSHORT|TUSHORT,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store (u)int16 into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	sth AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SNAME,	TCHAR|TUCHAR,
+	SAREG,	TCHAR|TUCHAR,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store (u)int8 into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	stb AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SNAME,	T64,
+	SAREG,	T64,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store (u)int64 into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	stx AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SNAME,	TFLOAT|TINT,
+	SBREG,	TFLOAT|TINT,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store float into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	st AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SNAME,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store double into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	std AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SNAME,	TINT,
+	SCREG,	TINT,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store int into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	st AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TANY,
+	SAREG,	TANY,
+		0,	RDEST,
+		"	mov AR,AL			! register move\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,	TANY,
+	SBREG,	TANY,
+		0,	RDEST,
+		"	fmovs AR,AL			! move float\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SCREG,	TANY,
+	SCREG,	TANY,
+		0,	RDEST,
+		"	fmovd AR,AL			! move double\n", },
+
+/* Structure assignment. */
+
+{ STASG,	INAREG|FOREFF,
+	SOREG|SNAME,	TANY,
+	SAREG,		TPTRTO|TANY,
+		NSPECIAL,	RRIGHT,
+		"ZQ", },
+
+/* Comparisons. */
+
+{ EQ,	FORCC,
+        SAREG,	TANY,
+        SAREG,	TANY,
+                0,      RESCC,
+		"	cmp AL,AR\n"
+		"	be LC\n"
+		"	nop\n", },
+
+{ NE,	FORCC,
+        SAREG,	TANY,
+        SAREG,	TANY,
+                0,      RESCC,
+		"	cmp AL,AR\n"
+                "	bne LC\n"
+		"	nop\n", },
+
+{ OPLOG,	FORCC,
+	SAREG,	TANY,
+	SZERO,	TANY,
+		0,	RESCC,
+		"	O AL,LC\n"
+		"	nop\n", },
+
+{ OPLOG,	FORCC,
+	SAREG,	TANY,
+	SAREG,	TANY,
+		NAREG|NASL,	RESCC,
+		"	sub AL,AR,A1			! oplog\n"
+		"	O A1,LC\n"
+		"	nop\n", },
+
+{ OPLOG,	FORCC,
+	SAREG,	TANY,
+	SCCON,	TANY,
+		NAREG|NASL,	RESCC,
+		"	sub AL,AR,A1			! oplog sccon\n"
+		"	O A1,LC\n"
+		"	nop\n", },
+
+{ OPLOG,	FORCC,
+	SBREG,	TFLOAT,
+	SBREG,	TFLOAT,
+		NBREG, RESCC,
+		"	fcmps AL,AR			! oplog float\n"
+		"	ZF LC\n", },
+
+{ OPLOG,	FORCC,
+	SOREG,	TFLOAT,
+	SBREG,	TFLOAT,
+		NBREG, RESCC,
+		"	ld [AL], A1    			! oplog float oreg\n"
+		"	nop\n"
+		"	fcmps A1,AR\n"
+		"	ZF LC\n", },
+
+{ OPLOG,	FORCC,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG, RESCC,
+		"	fcmpd AL,AR			! oplog double\n"
+		"	ZF LC\n", },
+
+{ OPLOG,	FORCC,
+	SOREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG, RESCC,
+		"	ldd [AL], A1   			! oplog double oreg\n"
+		"	nop\n"
+		"	fcmpd A1,AR\n"
+		"	ZF LC\n", },
+
+
+/* Load constants to register. */
+
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		T64,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t	! load const (u)int64 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ldx [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		TINT,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t	! load const int32 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ldsw [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		TUNSIGNED,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t! load const uint32 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	lduw [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		TSHORT,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t! load const int16 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ldsh [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		TUSHORT,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t	! load const uint16 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	lduh [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		TCHAR,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t\t! load const int8 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ldsb [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		TUCHAR,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t! load const uint8 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ldub [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INBREG,
+	SBREG,	TANY,
+	SNAME,	TANY,
+		NAREG|NBREG,	RESC2,
+		"	sethi %h44(AL),A1\t\t! load const to fp reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ld [A1+%l44(AL)],A2\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INCREG,
+	SCREG,	TANY,
+	SNAME,	TANY,
+		NAREG|NCREG,	RESC2,
+		"	sethi %h44(AL),A1\t\t! load const to fp reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ldd [A1+%l44(AL)],A2\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SCON,	TANY,
+		(2*NAREG),	RESC1,
+		"ZC" },
+
+/* Convert LTYPE to reg. */
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	TCHAR,
+		NAREG,	RESC1,
+		"	ldsb [AL],A1		! load int8 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	TUCHAR,
+		NAREG,	RESC1,
+		"	ldub [AL],A1		! load uint8 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	TSHORT,
+		NAREG,	RESC1,
+		"	ldsh [AL],A1		! load int16 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	TUSHORT,
+		NAREG,	RESC1,
+		"	lduh [AL],A1		! load uint16 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	TINT,
+		NAREG,	RESC1,
+		"	ldsw [AL],A1		! load int32 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	TUNSIGNED,
+		NAREG,	RESC1,
+		"	lduw [AL],A1		! load uint32 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	T64,
+		NAREG,	RESC1,
+		"	ldx [AL],A1		! load (u)int64 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SZERO,	TANY,
+		NAREG,	RESC1,
+		"	mov \%g0,A1\t		! load 0 to reg\n", },
+
+{ OPLTYPE,	INBREG,
+	SBREG,	TFLOAT,
+	SOREG,	TFLOAT,
+		NBREG,	RESC1,
+		"	ld [AL],A1  		! load float to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INCREG,
+	SCREG,	TDOUBLE,
+	SOREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	ldd [AL],A1  		! load double to reg\n"
+		"	nop\n", },
+
+/* Jumps. */
+
+{ GOTO, 	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	call LL		 	! goto LL\n"
+		"	nop\n", },
+
+{ UCALL,	FOREFF,
+	SCON,		TANY,
+	SANY,		TANY,
+		0,	0,
+		"	call CL			! void CL()\n"
+		"	nop\n", },
+
+{ UCALL,         INAREG,
+        SCON,		TANY,
+        SAREG,          TANY,
+                NAREG,     RESC1,
+		"	call CL			! = CL()\n"
+		" 	nop\n", },
+
+{ CALL,		FOREFF,
+	SCON,		TANY,
+	SANY,		TANY,
+		0,	0,
+		"	call CL			! void CL(constant)\n"
+		"	nop\n", },
+
+{ CALL,		INAREG,
+	SCON,		TANY,
+	SAREG,		TANY,
+		NAREG,		RESC1,
+		"	call CL			! = CL(constant)\n"
+		"	nop\n", },
+
+{ CALL,		INBREG,
+	SCON,		TANY,
+	SBREG,		TFLOAT,
+		NBREG,		RESC1,
+		"	call CL			! = CL(constant)\n"
+		"	nop\n", },
+
+{ CALL,		INCREG,
+	SCON,		TANY,
+	SCREG,		TDOUBLE,
+		NCREG,		RESC1,
+		"	call CL			! = CL(constant)\n"
+		"	nop\n", },
+
+{ CALL,         INAREG,
+        SAREG,		TANY,
+        SAREG,		TANY,
+                NAREG,     RESC1,
+		"	call AL			! = AL(args)\n"
+		"	nop\n", },
+
+{ CALL,		FOREFF,
+	SAREG,		TANY,
+	SANY,		TANY,
+		0,		0,
+		"	call AL			! void AL(args)\n"
+		"	nop\n", },
+
+{ UCALL,	FOREFF,
+	SAREG,		TANY,
+	SANY,		TANY,
+		0,	0,
+		"	call AL			! (*AL)()\n"
+		"	nop\n", },
+
+{ UCALL,	INAREG,
+	SAREG,		TANY,
+	SAREG,		TANY,
+		NAREG,		RESC1,
+		"	call AL			! = (*AL)()\n"
+		"	nop\n", },
+
+{ CALL,		INAREG,
+	SAREG,		TANY,
+	SAREG,		TANY,
+		NAREG,		RESC1,
+		"	call AL			! = (*AL)(args)\n"
+		"	nop\n", },
+
+/* Function arguments. */
+
+{ FUNARG,       FOREFF,
+        SAREG,  T64,
+        SANY,   TANY,
+                0,      0,
+                "	stx AL,[%sp+AR]   	\t! save func arg to stack\n"
+		"	nop\n", },
+
+{ FUNARG,       FOREFF,
+        SAREG,  TINT|TUNSIGNED,
+        SANY,   TANY,
+                0,      0,
+                "	stw AL,[%sp+AR]   	\t! save func arg to stack\n"
+		"	nop\n", },
+
+{ FUNARG,       FOREFF,
+        SAREG,  TSHORT|TUSHORT,
+        SANY,   TANY,
+                0,      0,
+                "	sth AL,[%sp+AR]   	\t! save func arg to stack\n"
+		"	nop\n", },
+
+{ FUNARG,       FOREFF,
+        SAREG,  TCHAR|TUCHAR,
+        SANY,   TANY,
+                0,      0,
+                "	stb AL,[%sp+AR]  	\t! save func arg to stack\n"
+		"	nop\n", },
+
+{ FUNARG,       FOREFF,
+        SBREG,  TFLOAT,
+        SANY,   TANY,
+                0,      0,
+                "	st AL,[%sp+AR]  	\t! save func arg to stack\n"
+		"	nop\n", },
+
+{ FUNARG,       FOREFF,
+        SCREG,  TDOUBLE,
+        SANY,   TANY,
+                0,      0,
+                "	std AL,[%sp+AR]  	\t! save func arg to stack\n"
+		"	nop\n", },
+
+
+/* Indirection. */
+
+{ OPSIMP,	INAREG,
+	SAREG,	TANY,
+	SAREG,	TANY,
+		NAREG|NASR|NASL,	RESC1,
+		"	O AL,AR,A1\n", },
+
+{ UMUL, INAREG,
+	SANY,	T64,
+	SOREG,	T64,
+		NAREG,		RESC1,
+		"	ldx [AL],A1		! (u)int64 load\n"
+		"	nop\n", },
+{ UMUL, INAREG,
+	SANY,	TINT,
+	SOREG,	TINT,
+		NAREG,		RESC1,
+		"	ldsw [AL],A1		! int32 load\n"
+		"	nop\n", },
+{ UMUL, INAREG,
+	SANY,	TUNSIGNED,
+	SOREG,	TUNSIGNED,
+		NAREG,		RESC1,
+		"	lduw [AL],A1		! uint32 load\n"
+		"	nop\n", },
+{ UMUL, INAREG,
+	SANY,	TCHAR,
+	SOREG,	TCHAR,
+		NAREG,		RESC1,
+		"	ldsb [AL],A1		! int8 load\n"
+		"	nop\n", },
+{ UMUL, INAREG,
+	SANY,	TUCHAR,
+	SOREG,	TUCHAR,
+		NAREG,		RESC1,
+		"	ldub [AL],A1		! uint8 load\n"
+		"	nop\n", },
+{ UMUL, INAREG,
+	SANY,	TSHORT,
+	SOREG,	TSHORT,
+		NAREG,		RESC1,
+		"	ldsh [AL],A1		! int16 load\n"
+		"	nop\n", },
+{ UMUL, INAREG,
+	SANY,	TUSHORT,
+	SOREG,	TUSHORT,
+		NAREG,		RESC1,
+		"	lduh [AL],A1		! uint16 load\n"
+		"	nop\n", },
+
+{ UMUL, INBREG,
+	SANY,	TFLOAT,
+	SOREG,	TFLOAT,
+		NBREG,		RESC1,
+		"	ld [AL],A1		! load float\n"
+		"	nop\n", },
+
+{ UMUL, INCREG,
+	SANY,	TDOUBLE,
+	SOREG,	TDOUBLE,
+		NCREG,		RESC1,
+		"	ldd [AL],A1		! load double\n"
+		"	nop\n", },
+
+{ FREE,FREE,FREE,FREE,FREE,FREE,FREE,FREE, "ERR: printing free op\n" },
+
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
--- /dev/null
+++ usr.bin/pcc/sparc64/local2.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2008 David Crawshaw <david at zentus.com>
+ * 
+ * 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 DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+#include "pass1.h"
+#include "pass2.h"
+
+
+char *
+rnames[] = {
+	/* "\%g0", always zero, removed due to 31-element class limit */
+	        "\%g1", "\%g2", "\%g3", "\%g4", "\%g5", "\%g6", "\%g7",
+	"\%o0", "\%o1", "\%o2", "\%o3", "\%o4", "\%o5", "\%o6", "\%o7",
+	"\%l0", "\%l1", "\%l2", "\%l3", "\%l4", "\%l5", "\%l6", "\%l7",
+	"\%i0", "\%i1", "\%i2", "\%i3", "\%i4", "\%i5", "\%i6", "\%i7",
+
+	"\%f0",  "\%f1",  "\%f2",  "\%f3",  "\%f4",  "\%f5",  "\%f6",  "\%f7",
+	"\%f8",  "\%f9",  "\%f10", "\%f11", "\%f12", "\%f13", "\%f14", "\%f15",
+	"\%f16", "\%f17", "\%f18", "\%f19", "\%f20", "\%f21", "\%f22", "\%f23",
+	"\%f24", "\%f25", "\%f26", "\%f27", "\%f28", "\%f29", "\%f30",
+	/*, "\%f31" XXX removed due to 31-element class limit */
+
+	"\%f0",  "\%f2",  "\%f4",  "\%f6",  "\%f8",  "\%f10", "\%f12", "\%f14",
+	"\%f16", "\%f18", "\%f20", "\%f22", "\%f24", "\%f26", "\%f28", "\%f30",
+
+	"\%sp", "\%fp",
+};
+
+void
+deflab(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+	int i, stack;
+
+	stack = V9RESERVE + V9STEP(p2maxautooff);
+
+	for (i = ipp->ipp_regs[0]; i; i >>= 1)
+		if (i & 1)
+			stack += 16;
+
+	/* TODO printf("\t.proc %d\n"); */
+	printf("\t.global %s\n", ipp->ipp_name);
+	printf("\t.align 4\n");
+	printf("%s:\n", ipp->ipp_name);
+	if (SIMM13(stack))
+		printf("\tsave %%sp,-%d,%%sp\n", stack);
+	else {
+		printf("\tsetx -%d,%%g4,%%g1\n", stack);
+		printf("\tsave %%sp,%%g1,%%sp\n");
+	}
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+	printf("\tret\n");
+	printf("\trestore\n");
+	printf("\t.type %s,#function\n", ipp->ipp_name);
+	printf("\t.size %s,(.-%s)\n", ipp->ipp_name, ipp->ipp_name);
+}
+
+void
+hopcode(int f, int o)
+{
+	char *str;
+
+	switch (o) {
+		case EQ:        str = "brz"; break;
+		case NE:        str = "brnz"; break;
+		case ULE:
+		case LE:        str = "brlez"; break;
+		case ULT:
+		case LT:        str = "brlz";  break;
+		case UGE:
+		case GE:        str = "brgez"; break;
+		case UGT:
+		case GT:        str = "brgz";  break;
+		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("unknown hopcode: %d (with %c)", o, f);
+			return;
+	}
+
+	printf("%s%c", str, f);
+}
+
+int
+tlen(NODE *p)
+{
+	switch (p->n_type) {
+		case CHAR:
+		case UCHAR:
+			return 1;
+		case SHORT:
+		case USHORT:
+			return (SZSHORT / SZCHAR);
+		case FLOAT:
+			return (SZFLOAT / SZCHAR);
+		case DOUBLE:
+			return (SZDOUBLE / SZCHAR);
+		case INT:
+		case UNSIGNED:
+			return (SZINT / SZCHAR);
+		case LONG:
+		case ULONG:
+		case LONGLONG:
+		case ULONGLONG:
+			return SZLONGLONG / SZCHAR;
+		default:
+			if (!ISPTR(p->n_type))
+				comperr("tlen type unknown: %d");
+			return SZPOINT(p->n_type) / SZCHAR;
+	}
+}
+
+void
+zzzcode(NODE * p, int c)
+{
+	char *str;
+	NODE *l, *r;
+	l = p->n_left;
+	r = p->n_right;
+
+	switch (c) {
+
+	case 'A':	/* Add const. */
+		if (ISPTR(l->n_type) && l->n_rval == FP)
+			r->n_lval += V9BIAS;
+
+		if (SIMM13(r->n_lval))
+			expand(p, 0, "\tadd AL,AR,A1\t\t! add const\n");
+		else
+			expand(p, 0, "\tsetx AR,A3,A2\t\t! add const\n"
+			             "\tadd AL,A2,A1\n");
+		break;
+	case 'B':	/* Subtract const. */
+		if (ISPTR(l->n_type) && l->n_rval == FP)
+			r->n_lval -= V9BIAS;
+
+		if (SIMM13(r->n_lval))
+			expand(p, 0, "\tsub AL,AR,A1\t\t! subtract const\n");
+		else
+			expand(p, 0, "\tsetx AR,A3,A2\t\t! subtract const\n"
+			             "\tsub AL,A2,A1\n");
+		break;
+	case 'C':	/* Load constant to register. */
+		if (ISPTR(p->n_type))
+			expand(p, 0,
+				"\tsethi %h44(AL),A1\t\t! load label\n"
+				"\tor A1,%m44(AL),A1\n"
+				"\tsllx A1,12,A1\n"
+				"\tor A1,%l44(AL),A1\n");
+		else if (SIMM13(p->n_lval))
+			expand(p, 0, "\tor %g0,AL,A1\t\t\t! load const\n");
+		else
+			expand(p, 0, "\tsetx AL,A2,A1\t\t! load const\n");
+		break;
+	case 'F':	/* Floating-point comparison, cf. hopcode(). */
+		switch (p->n_op) {
+			case EQ:        str = "fbe"; break;
+			case NE:        str = "fbne"; break;
+			case ULE:
+			case LE:        str = "fbule"; break;
+			case ULT:
+			case LT:        str = "fbul";  break;
+			case UGE:
+			case GE:        str = "fbuge"; break;
+			case UGT:
+			case GT:        str = "fbug";  break;
+			/* XXX
+			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("unknown float code: %d", p->n_op);
+				return;
+		}
+		printf(str);
+		break;
+
+	case 'Q':	/* Structure assignment. */
+		/* TODO Check if p->n_stsize is small and use a few ldx's
+		        to move the struct instead of memcpy. The equiv.
+			could be done on all the architectures. */
+		if (l->n_rval != O0)
+			printf("\tmov %s,%s\n", rnames[l->n_rval], rnames[O0]);
+		if (SIMM13(p->n_stsize))
+			printf("\tor %%g0,%d,%%o2\n", p->n_stsize);
+		else
+			printf("\tsetx %d,%%g1,%%o2\n", p->n_stsize);
+		printf("\tcall memcpy\t\t\t! struct assign (dest, src, len)\n");
+		printf("\tnop\n");
+		break;
+	default:
+		cerror("unknown zzzcode call: %c", c);
+	}
+}
+
+int
+rewfld(NODE * p)
+{
+	return (1);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+	printf("XXX fldexpand called\n"); /* XXX */
+	return 1;
+}
+
+int
+flshape(NODE * p)
+{
+	return SRREG;
+}
+
+int
+shtemp(NODE * p)
+{
+	return 0;
+}
+
+
+void
+adrcon(CONSZ val)
+{
+}
+
+void
+conput(FILE * fp, NODE * p)
+{
+	if (p->n_op != ICON) {
+		comperr("conput got bad op: %s", copst(p->n_op));
+		return;
+	}
+
+	if (p->n_name[0] != '\0') {
+		fprintf(fp, "%s", p->n_name);
+		if (p->n_lval > 0)
+			fprintf(fp, "+");
+		if (p->n_lval)
+			fprintf(fp, "%lld", p->n_lval);
+	} else
+		fprintf(fp, CONFMT, p->n_lval);
+}
+
+void
+insput(NODE * p)
+{
+	comperr("insput");
+}
+
+void
+upput(NODE *p, int size)
+{
+	comperr("upput");
+}
+
+void
+adrput(FILE * io, NODE * p)
+{
+	int64_t off;
+
+	if (p->n_op == FLD) {
+		printf("adrput a FLD\n");
+		p = p->n_left;
+	}
+
+	if (p->n_op == UMUL && p->n_right == 0)
+		p = p->n_left;
+
+	off = p->n_lval;
+
+	switch (p->n_op) {
+	case NAME:
+		if (p->n_name[0] != '\0')
+			fputs(p->n_name, io);
+		if (off > 0)
+			fprintf(io, "+");
+		if (off != 0)
+			fprintf(io, CONFMT, off);
+		return;
+	case OREG:
+		fprintf(io, "%s", rnames[p->n_rval]);
+		if (p->n_rval == FP)
+			off += V9BIAS;
+		if (p->n_rval == SP)
+			off += V9BIAS + V9RESERVE;
+		if (off > 0)
+			fprintf(io, "+");
+		if (off)
+			fprintf(io, "%lld", off);
+		return;
+	case ICON:
+		/* addressable value of the constant */
+		conput(io, p);
+		return;
+	case REG:
+		fputs(rnames[p->n_rval], io);
+		return;
+	case FUNARG:
+		/* We do something odd and store the stack offset in n_rval. */
+		fprintf(io, "%d", V9BIAS + V9RESERVE + p->n_rval);
+		return;
+	default:
+		comperr("bad address, %s, node %p", copst(p->n_op), p);
+		return;
+	}
+}
+
+void
+cbgen(int o, int lab)
+{
+}
+
+void
+myreader(struct interpass * ipole)
+{
+}
+
+void
+mycanon(NODE * p)
+{
+}
+
+void
+myoptim(struct interpass * ipole)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+	printf("\t");
+
+	if (t == FLOAT)	      printf("fmovs");
+	else if (t == DOUBLE) printf("fmovd");
+	else                  printf("mov");
+
+	printf(" %s,%s\t\t\t! rmove()\n", rnames[s], rnames[d]);
+}
+
+int
+gclass(TWORD t)
+{
+	if (t == FLOAT)
+		return CLASSB;
+	if (t == DOUBLE)
+		return CLASSC;
+	return CLASSA;
+}
+
+void
+lastcall(NODE *p)
+{
+}
+
+int
+special(NODE *p, int shape)
+{
+	return SRNOPE;
+}
+
+void mflags(char *str)
+{
+}
+
+int
+COLORMAP(int c, int *r)
+{
+	int num=0;
+
+	switch (c) {
+		case CLASSA:
+			num += r[CLASSA];
+			return num < 32;
+		case CLASSB:
+			num += r[CLASSB];
+			num += 2*r[CLASSC];
+			return num < 32;;
+		case CLASSC:
+			num += r[CLASSC];
+			num += 2*r[CLASSB];
+			return num < 17;
+		case CLASSD:
+			return 0;
+		default:
+			comperr("COLORMAP: unknown class: %d", c);
+			return 0;
+	}
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+	return 0;
+}
--- /dev/null
+++ usr.bin/pcc/sparc64/code.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2008 David Crawshaw <david at zentus.com>
+ * 
+ * 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 DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+#include "pass1.h"
+
+void
+defloc(struct symtab *sp)
+{
+	static char *loctbl[] = { "text", "data", "rodata" };
+	static int lastloc = -1;
+	TWORD t;
+	int s;
+
+	t = sp->stype;
+	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+	if (s != lastloc)
+		printf("\n\t.section \".%s\"\n", loctbl[s]);
+	lastloc = s;
+	if (s == PROG)
+		return;
+
+	switch (DEUNSIGN(sp->stype)) {
+		case CHAR:	s = 1;
+		case SHORT:	s = 2;
+		case INT:
+		case UNSIGNED:	s = 4;
+		default:	s = 8;
+	}
+	printf("\t.align %d\n", s);
+
+	if (sp->sclass == EXTDEF)
+		printf("\t.global %s\n", sp->soname);
+	if (sp->slevel == 0) {
+		printf("\t.type %s,#object\n", sp->soname);
+		printf("\t.size %s," CONFMT "\n", sp->soname,
+			tsize(sp->stype, sp->sdf, sp->ssue) / SZCHAR);
+		printf("%s:\n", sp->soname);
+	} else
+		printf(LABFMT ":\n", sp->soffset);
+}
+
+void
+efcode()
+{
+	/* XXX */
+}
+
+void
+bfcode(struct symtab **sp, int cnt)
+{
+	int i, off;
+	NODE *p, *q;
+	struct symtab *sym;
+
+	/* Process the first six arguments. */
+	for (i=0; i < cnt && i < 6; i++) {
+		sym = sp[i];
+		q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->ssue);
+		q->n_rval = RETREG_PRE(sym->stype) + i;
+		p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
+		sym->soffset = regno(p);
+		sym->sflags |= STNODE;
+		p = buildtree(ASSIGN, p, q);
+		ecomp(p);
+	}
+
+	/* Process the remaining arguments. */
+	for (off = V9RESERVE; i < cnt; i++) {
+		sym = sp[i];
+		p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
+		off = ALIGN(off, (tlen(p) - 1));
+		sym->soffset = off * SZCHAR;
+		off += tlen(p);
+		p = buildtree(ASSIGN, p, nametree(sym));
+		sym->soffset = regno(p->n_left);
+		sym->sflags |= STNODE;
+		ecomp(p);
+	}
+}
+
+void
+bccode()
+{
+	SETOFF(autooff, SZINT);
+}
+
+void
+ejobcode(int flag)
+{
+}
+
+void
+bjobcode()
+{
+}
+
+/*
+ * The first six 64-bit arguments are saved in the registers O0 to O5,
+ * which become I0 to I5 after the "save" instruction moves the register
+ * window. Arguments 7 and up must be saved on the stack to %sp+BIAS+176.
+ *
+ * For a pretty picture, see Figure 3-16 in the SPARC Compliance Def 2.4.
+ */
+static NODE *
+moveargs(NODE *p, int *regp, int *stacksize)
+{
+	NODE *r, *q;
+
+	if (p->n_op == CM) {
+		p->n_left = moveargs(p->n_left, regp, stacksize);
+		r = p->n_right;
+	} else {
+		r = p;
+	}
+
+	/* XXX more than six FP args can and should be passed in registers. */
+	if (*regp > 5 && r->n_op != STARG) {
+		/* We are storing the stack offset in n_rval. */
+		r = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_sue);
+		/* Make sure we are appropriately aligned. */
+		*stacksize = ALIGN(*stacksize, (tlen(r) - 1));
+		r->n_rval = *stacksize;
+		*stacksize += tlen(r);
+	} else if (r->n_op == STARG)
+		cerror("op STARG in moveargs");
+	else {
+		q = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_sue);
+
+		/*
+		 * The first six non-FP arguments go in the registers O0 - O5.
+		 * Float arguments are stored in %fp1, %fp3, ..., %fp29, %fp31.
+		 * Double arguments are stored in %fp0, %fp2, ..., %fp28, %fp30.
+		 * A non-fp argument still increments register, eg.
+		 *     test(int a, int b, float b)
+		 * takes %o0, %o1, %fp5.
+		 */
+		if (q->n_type == FLOAT)
+			q->n_rval = F0 + (*regp++ * 2) + 1;
+		else if (q->n_type == DOUBLE)
+			q->n_rval = D0 + *regp++;
+		else if (q->n_type == LDOUBLE)
+			cerror("long double support incomplete");
+		else
+			q->n_rval = O0 + (*regp)++;
+
+		r = buildtree(ASSIGN, q, r);
+	}
+
+	if (p->n_op == CM) {
+		p->n_right = r;
+		return p;
+	}
+
+	return r;
+}
+
+NODE *
+funcode(NODE *p)
+{
+	NODE *r, *l;
+	int reg = 0, stacksize = 0;
+
+	r = l = 0;
+
+	p->n_right = moveargs(p->n_right, &reg, &stacksize);
+
+	/*
+	 * This is a particularly gross and inefficient way to handle
+	 * argument overflows. First, we calculate how much stack space
+	 * we need in moveargs(). Then we assign it by moving %sp, make
+	 * the function call, and then move %sp back.
+	 *
+	 * What we should be doing is getting the maximum of all the needed
+	 * stacksize values to the prologue and doing it all in the "save"
+	 * instruction.
+	 */
+	if (stacksize != 0) {
+		stacksize = V9STEP(stacksize); /* 16-bit alignment. */
+
+		r = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+		r->n_lval = 0;
+		r->n_rval = SP;
+		r = block(MINUS, r, bcon(stacksize), INT, 0, MKSUE(INT));
+
+		l = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+		l->n_lval = 0;
+		l->n_rval = SP;
+		r = buildtree(ASSIGN, l, r);
+
+		p = buildtree(COMOP, r, p);
+
+		r = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+		r->n_lval = 0;
+		r->n_rval = SP;
+		r = block(PLUS, r, bcon(stacksize), INT, 0, MKSUE(INT));
+
+		l = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+		l->n_lval = 0;
+		l->n_rval = SP;
+		r = buildtree(ASSIGN, l, r);
+
+		p = buildtree(COMOP, p, r);
+
+	}
+	return p;
+}
+
+int
+fldal(unsigned int t)
+{
+	uerror("illegal field type");
+	return ALINT;
+}
+
+void
+fldty(struct symtab *p)
+{
+}
+
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+	return 0;
+}
--- /dev/null
+++ usr.bin/pcc/sparc64/local.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2008 David Crawshaw <david at zentus.com>
+ * 
+ * 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 DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+#include "pass1.h"
+
+NODE *
+clocal(NODE *p)
+{
+	struct symtab *sp;
+	int op;
+	NODE *r, *l;
+
+	op = p->n_op;
+	sp = p->n_sp;
+	l  = p->n_left;
+	r  = p->n_right;
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal in: %p, %s\n", p, copst(op));
+		fwalk(p, eprint, 0);
+	}
+#endif
+
+	switch (op) {
+
+	case NAME:
+		if (sp->sclass == PARAM || sp->sclass == AUTO) {
+			/*
+			 * Use a fake structure reference to
+			 * write out frame pointer offsets.
+			 */
+			l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+			l->n_lval = 0;
+			l->n_rval = FP;
+			r = p;
+			p = stref(block(STREF, l, r, 0, 0, 0));
+		}
+		break;
+	case PCONV: /* Remove what PCONVs we can. */
+		if (l->n_op == SCONV)
+			break;
+
+		if (l->n_op == ICON || (ISPTR(p->n_type) && ISPTR(l->n_type))) {
+			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:
+        /* Remove redundant conversions. */
+		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+		    btdims[p->n_type].suesize == btdims[l->n_type].suesize &&
+		    p->n_type != FLOAT && p->n_type != DOUBLE &&
+		    l->n_type != FLOAT && l->n_type != DOUBLE &&
+		    l->n_type != DOUBLE && 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);
+				p = l;
+				break;
+			}
+		}
+
+        /* Convert floating point to int before to char or short. */
+        if ((l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE)
+            && (DEUNSIGN(p->n_type) == CHAR || DEUNSIGN(p->n_type) == SHORT)) {
+            p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
+            p->n_left->n_type = INT;
+            break;
+        }
+
+        /* Transform constants now. */
+		if (l->n_op != ICON)
+			break;
+
+		if (ISPTR(p->n_type)) {
+			l->n_type = p->n_type;
+			nfree(p);
+			p = l;
+			break;
+		}
+
+		switch (p->n_type) {
+		case BOOL:      l->n_lval = (l->n_lval != 0); break;
+		case CHAR:      l->n_lval = (char)l->n_lval; break;
+		case UCHAR:     l->n_lval = l->n_lval & 0377; break;
+		case SHORT:     l->n_lval = (short)l->n_lval; break;
+		case USHORT:    l->n_lval = l->n_lval & 0177777; break;
+		case UNSIGNED:  l->n_lval = l->n_lval & 0xffffffff; break;
+		case INT:       l->n_lval = (int)l->n_lval; break;
+		case ULONG:
+		case ULONGLONG: l->n_lval = l->n_lval; break;
+		case LONG:
+		case LONGLONG:	l->n_lval = (long long)l->n_lval; break;
+		case FLOAT:
+		case DOUBLE:
+		case LDOUBLE:
+			l->n_op = FCON;
+			l->n_dcon = l->n_lval;
+			break;
+		case VOID:
+			break;
+		default:
+			cerror("sconv type unknown %d", p->n_type);
+		}
+
+		l->n_type = p->n_type;
+		nfree(p);
+		p = l;
+		break;
+
+	case PMCONV:
+	case PVCONV:
+		if (r->n_op != ICON)
+			cerror("converting bad type");
+		nfree(p);
+		p = buildtree(op == PMCONV ? MUL : DIV, l, r);
+		break;
+
+	case FORCE:
+		/* Put attached value into the return register. */
+		p->n_op = ASSIGN;
+		p->n_right = p->n_left;
+		p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
+		p->n_left->n_rval = RETREG_PRE(p->n_type);
+		break;
+	}
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal out: %p, %s\n", p, copst(op));
+		fwalk(p, eprint, 0);
+	}
+#endif
+
+	return p;
+}
+
+void
+myp2tree(NODE *p)
+{
+	struct symtab *sp;
+
+	if (p->n_op != FCON)
+		return;
+
+	sp = tmpalloc(sizeof(struct symtab));
+	sp->sclass = STATIC;
+	sp->slevel = 1;
+	sp->soffset = getlab();
+	sp->sflags = 0;
+	sp->stype = p->n_type;
+	sp->squal = (CON >> TSHIFT);
+
+	defloc(sp);
+	ninval(0, btdims[p->n_type].suesize, p);
+
+	p->n_op = NAME;
+	p->n_lval = 0;
+	p->n_sp = sp;
+}
+
+int
+andable(NODE *p)
+{
+	return 1;
+}
+
+void
+cendarg()
+{
+	autooff = AUTOINIT;
+}
+
+int
+cisreg(TWORD t)
+{
+	/* SPARCv9 registers are all 64-bits wide. */
+	return 1;
+}
+
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
+{
+	return bcon(off / SZCHAR);
+}
+
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+}
+
+void
+inwstring(struct symtab *sp)
+{
+}
+
+void
+instring(struct symtab *sp)
+{
+	char *s, *str;
+
+	defloc(sp);
+	str = sp->sname;
+
+	printf("\t.ascii \"");
+	for (s = str; *s != 0; *s++) {
+		if (*s++ == '\\')
+			esccon(&s);
+		if (s - str > 60) {
+			fwrite(str, 1, s - str, stdout);
+			printf("\"\n\t.ascii \"");
+			str = s;
+		}
+	}
+	fwrite(str, 1, s - str, stdout);
+	printf("\\0\"\n");
+}
+
+void
+zbits(OFFSZ off, int fsz)
+{
+}
+
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+}
+
+void
+ninval(CONSZ off, int fsz, NODE *p)
+{
+	TWORD t;
+	struct symtab *sp;
+	union { float f; double d; int i; long long l; } u;
+
+	t = p->n_type;
+	sp = p->n_sp;
+
+	if (ISPTR(t))
+		t = LONGLONG;
+
+	if (p->n_op != ICON && p->n_op != FCON)
+		cerror("ninval: not a constant");
+	if (p->n_op == ICON && sp != NULL && DEUNSIGN(t) != LONGLONG)
+		cerror("ninval: not constant");
+
+	switch (t) {
+		case CHAR:
+		case UCHAR:
+			printf("\t.byte %d\n", (int)p->n_lval & 0xff);
+			break;
+		case SHORT:
+		case USHORT:
+			printf("\t.half %d\n", (int)p->n_lval &0xffff);
+			break;
+		case BOOL:
+			p->n_lval = (p->n_lval != 0); /* FALLTHROUGH */
+		case INT:
+		case UNSIGNED:
+			printf("\t.long " CONFMT "\n", p->n_lval);
+			break;
+		case LONG:
+		case ULONG:
+		case LONGLONG:
+		case ULONGLONG:
+			printf("\t.xword %lld", p->n_lval);
+			if (sp != 0) {
+				if (sp->sclass == STATIC && sp->slevel > 0)
+					printf("+" LABFMT, sp->soffset);
+				else
+					printf("+%s", exname(sp->soname));
+			}
+			printf("\n");
+			break;
+		case FLOAT:
+			u.f = (float)p->n_dcon;
+			printf("\t.long %d\n", u.i);
+			break;
+		case DOUBLE:
+			u.d = (double)p->n_dcon;
+			printf("\t.xword %lld\n", u.l);
+			break;
+	}
+}
+
+char *
+exname(char *p)
+{
+	return p ? p : "";
+}
+
+TWORD
+ctype(TWORD type)
+{
+	return type;
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+void
+defzero(struct symtab *sp)
+{
+	int off = (tsize(sp->stype, sp->sdf, sp->ssue) + SZCHAR - 1) / SZCHAR;
+	printf("\t.comm ");
+	if (sp->slevel == 0)
+		printf("%s,%d\n", exname(sp->soname), off);
+	else
+		printf(LABFMT ",%d\n", sp->soffset, off);
+}
+
+int
+mypragma(char **ary)
+{
+	return 0;
+}
+
+void
+fixdef(struct symtab *sp)
+{
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
+


More information about the Midnightbsd-cvs mailing list