Index: uspace/app/pcc/arch/i386/CVS/Entries
===================================================================
--- uspace/app/pcc/arch/i386/CVS/Entries	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
+++ uspace/app/pcc/arch/i386/CVS/Entries	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
@@ -0,0 +1,8 @@
+/code.c/1.56.2.1/Tue Mar  1 17:33:24 2011//Tr-1-0-0-RELEASE
+/flocal.c/1.16/Fri Dec 19 20:26:50 2008//Tr-1-0-0-RELEASE
+/local.c/1.130.2.3/Wed Mar 30 16:35:36 2011//Tr-1-0-0-RELEASE
+/local2.c/1.154.2.2/Sat Feb 26 07:17:34 2011//Tr-1-0-0-RELEASE
+/macdefs.h/1.77/Fri Feb  4 15:08:58 2011//Tr-1-0-0-RELEASE
+/order.c/1.59/Sat Jan 29 09:55:29 2011//Tr-1-0-0-RELEASE
+/table.c/1.128/Sat Jan 29 09:55:29 2011//Tr-1-0-0-RELEASE
+D
Index: uspace/app/pcc/arch/i386/CVS/Repository
===================================================================
--- uspace/app/pcc/arch/i386/CVS/Repository	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
+++ uspace/app/pcc/arch/i386/CVS/Repository	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
@@ -0,0 +1,1 @@
+pcc/arch/i386
Index: uspace/app/pcc/arch/i386/CVS/Root
===================================================================
--- uspace/app/pcc/arch/i386/CVS/Root	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
+++ uspace/app/pcc/arch/i386/CVS/Root	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
@@ -0,0 +1,1 @@
+/cvsroot
Index: uspace/app/pcc/arch/i386/CVS/Tag
===================================================================
--- uspace/app/pcc/arch/i386/CVS/Tag	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
+++ uspace/app/pcc/arch/i386/CVS/Tag	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
@@ -0,0 +1,1 @@
+Nr-1-0-0-RELEASE
Index: uspace/app/pcc/arch/i386/code.c
===================================================================
--- uspace/app/pcc/arch/i386/code.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
+++ uspace/app/pcc/arch/i386/code.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
@@ -0,0 +1,431 @@
+/*	$Id: code.c,v 1.56.2.1 2011/03/01 17:33:24 ragge Exp $	*/
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+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;
+	struct attr *ap;
+	int weak = 0;
+	char *name = NULL;
+#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, al;
+
+	if (sp == NULL) {
+		lastloc = -1;
+		return;
+	}
+	t = sp->stype;
+	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+	if ((name = sp->soname) == NULL)
+		name = exname(sp->sname);
+#ifdef TLS
+	if (sp->sflags & STLS) {
+		if (s != DATA)
+			cerror("non-data symbol in tls section");
+		nextsect = ".tdata";
+	}
+#endif
+#ifdef GCC_COMPAT
+	{
+		if ((ap = attr_find(sp->sap, GCC_ATYP_SECTION)) != NULL)
+			nextsect = ap->sarg(0);
+		if (attr_find(sp->sap, GCC_ATYP_WEAK) != NULL)
+			weak = 1;
+		if (attr_find(sp->sap, GCC_ATYP_DESTRUCTOR)) {
+			printf("\t.section\t.dtors,\"aw\",@progbits\n");
+			printf("\t.align 4\n\t.long\t%s\n", name);
+			lastloc = -1;
+		}
+		if (attr_find(sp->sap, GCC_ATYP_CONSTRUCTOR)) {
+			printf("\t.section\t.ctors,\"aw\",@progbits\n");
+			printf("\t.align 4\n\t.long\t%s\n", name);
+			lastloc = -1;
+		}
+		if ((ap = attr_find(sp->sap, GCC_ATYP_VISIBILITY)) &&
+		    strcmp(ap->sarg(0), "default"))
+			printf("\t.%s %s\n", ap->sarg(0), name);
+	}
+#endif
+#ifdef ELFABI
+	if (kflag && !ISFTN(t)) {
+		/* Must place aggregates with pointers in relocatable memory */
+		TWORD t2 = t;
+
+		while (ISARY(t2))
+			t2 = DECREF(t2);
+		if (t2 > LDOUBLE) {
+			/* put in reloc memory */
+			printf("\t.section .data.rel.local,\"aw\",@progbits\n");
+			s = lastloc = -1;
+		}
+	}
+#endif
+	if (nextsect) {
+		printf("	.section %s,\"wa\",@progbits\n", nextsect);
+		nextsect = NULL;
+		s = -1;
+	} else if (s != lastloc)
+		printf("	.%s\n", loctbl[s]);
+	lastloc = s;
+	while (ISARY(t))
+		t = DECREF(t);
+	al = ISFTN(t) ? ALINT : talign(t, sp->sap);
+	if (al > ALCHAR)
+		printf("	.align %d\n", al/ALCHAR);
+	if (weak)
+		printf("	.weak %s\n", name);
+	else if (sp->sclass == EXTDEF) {
+		printf("	.globl %s\n", name);
+#if defined(ELFABI)
+		printf("\t.type %s,@%s\n", name,
+		    ISFTN(t)? "function" : "object");
+#endif
+	}
+#if defined(ELFABI)
+	if (!ISFTN(t)) {
+		if (sp->slevel == 0)
+			printf("\t.size %s,%d\n", name,
+			    (int)tsize(t, sp->sdf, sp->sap)/SZCHAR);
+		else
+			printf("\t.size " LABFMT ",%d\n", sp->soffset,
+			    (int)tsize(t, sp->sdf, sp->sap)/SZCHAR);
+	}
+#endif
+	if (sp->slevel == 0)
+		printf("%s:\n", name);
+	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;
+#if defined(os_openbsd)
+	/* struct return for small structs */
+	int sz = tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->sap);
+	if (sz == SZCHAR || sz == SZSHORT || sz == SZINT || sz == SZLONGLONG) {
+		/* Pointer to struct in eax */
+		if (sz == SZLONGLONG) {
+			q = block(OREG, NIL, NIL, INT, 0, MKAP(INT));
+			q->n_lval = 4;
+			p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+			p->n_rval = EDX;
+			ecomp(buildtree(ASSIGN, p, q));
+		}
+		if (sz < SZSHORT) sz = CHAR;
+		else if (sz > SZSHORT) sz = INT;
+		else sz = SHORT;
+		q = block(OREG, NIL, NIL, sz, 0, MKAP(sz));
+		p = block(REG, NIL, NIL, sz, 0, MKAP(sz));
+		ecomp(buildtree(ASSIGN, p, q));
+		return;
+	}
+#endif
+	/* Create struct assignment */
+	q = block(OREG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
+	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->sap);
+	p = buildtree(UMUL, p, NIL);
+	p = buildtree(ASSIGN, q, p);
+	ecomp(p);
+
+	/* put hidden arg in eax on return */
+	q = block(OREG, NIL, NIL, INT, 0, MKAP(INT));
+	regno(q) = FPREG;
+	q->n_lval = 8;
+	p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+	regno(p) = EAX;
+	ecomp(buildtree(ASSIGN, p, q));
+}
+
+/*
+ * 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 **sp, int cnt)
+{
+	extern int argstacksize;
+	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 */
+#if defined(os_openbsd)
+		/* OpenBSD uses non-standard return for small structs */
+		int sz = tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->sap);
+		if (sz != SZCHAR && sz != SZSHORT &&
+		    sz != SZINT && sz != SZLONGLONG)
+#endif
+			for (i = 0; i < cnt; i++) 
+				sp[i]->soffset += SZPOINT(INT);
+	}
+
+#ifdef GCC_COMPAT
+	if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL) != NULL)
+		cftnsp->sflags |= SSTDCALL;
+#endif
+
+	/*
+	 * Count the arguments
+	 */
+	argstacksize = 0;
+	if (cftnsp->sflags & SSTDCALL) {
+#ifdef os_win32
+
+		char buf[256];
+		char *name;
+#endif
+
+		for (i = 0; i < cnt; i++) {
+			TWORD t = sp[i]->stype;
+			if (t == STRTY || t == UNIONTY)
+				argstacksize +=
+				    tsize(t, sp[i]->sdf, sp[i]->sap);
+			else
+				argstacksize += szty(t) * SZINT / SZCHAR;
+		}
+#ifdef os_win32
+		/*
+		 * mangle name in symbol table as a callee.
+		 */
+		if ((name = cftnsp->soname) == NULL)
+			name = exname(cftnsp->sname);
+		snprintf(buf, 256, "%s@%d", name, argstacksize);
+		cftnsp->soname = addname(buf);
+#endif
+	}
+
+	if (kflag) {
+#define	STL	200
+		char *str = inlalloc(STL);
+#if !defined(MACHOABI)
+		int l = getlab();
+#else
+		char *name;
+#endif
+
+		/* Generate extended assembler for PIC prolog */
+		p = tempnode(0, INT, 0, MKAP(INT));
+		gotnr = regno(p);
+		p = block(XARG, p, NIL, INT, 0, MKAP(INT));
+		p->n_name = "=g";
+		p = block(XASM, p, bcon(0), INT, 0, MKAP(INT));
+
+#if defined(MACHOABI)
+		if ((name = cftnsp->soname) == NULL)
+			name = cftnsp->sname;
+		if (snprintf(str, STL, "call L%s$pb\nL%s$pb:\n\tpopl %%0\n",
+		    name, name) >= 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;
+
+	/* 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]->sap);
+		n = buildtree(ASSIGN, n, nametree(sp2));
+		sp[i]->soffset = regno(n->n_left);
+		sp[i]->sflags |= STNODE;
+		ecomp(n);
+	}
+}
+
+
+/*
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+	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", 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", 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
+}
+
+/*
+ * 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;
+
+	/* 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_ap);
+	}
+	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, MKAP(INT));
+	l->n_rval = EBX;
+	l = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, MKAP(INT)));
+	if (p->n_right->n_op != CM) {
+		p->n_right = block(CM, l, p->n_right, INT, 0, MKAP(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, MKAP(INT));
+	}
+#endif
+	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;
+}
Index: uspace/app/pcc/arch/i386/flocal.c
===================================================================
--- uspace/app/pcc/arch/i386/flocal.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
+++ uspace/app/pcc/arch/i386/flocal.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
@@ -0,0 +1,234 @@
+/*	$Id: flocal.c,v 1.16 2008/12/19 20:26:50 ragge Exp $	*/
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+
+#include "defines.h"
+#include "defs.h"
+
+void
+prchars(int *s)
+{
+	printf("\t.byte 0%o,0%o\n", s[0], s[1]);
+}
+
+
+void
+setloc(int l)
+{
+	static int lastloc = -1;
+	static char *loctbl[] =
+	    { "text", "data", "section .rodata", "section .rodata", "bss" };
+	if (l == lastloc)
+		return;
+	printf("\t.%s\n", loctbl[l]);
+	lastloc = l;
+}
+
+#ifdef FCOM
+
+
+/*
+	PDP11-780/VAX - SPECIFIC PRINTING ROUTINES
+*/
+
+/*
+ * Called just before return from a subroutine.
+ */
+void
+goret(int type)
+{
+}
+
+/*
+ * Print out a label.
+ */
+void
+prlabel(int k)
+{
+	printf(LABFMT ":\n", k);
+}
+
+/*
+ * Print naming for location.
+ * name[0] is location type.
+ */
+void
+prnloc(char *name)
+{
+	if (*name == '0')
+		setloc(DATA);
+	else
+		fatal("unhandled prnloc %c", *name);
+	printf("%s:\n", name+1);
+}
+
+/*
+ * Print integer constant.
+ */
+void
+prconi(FILE *fp, int type, ftnint n)
+{
+	fprintf(fp, "\t%s\t%ld\n", (type==TYSHORT ? ".word" : ".long"), n);
+}
+
+/*
+ * Print address constant, given as a label number.
+ */
+void
+prcona(ftnint a)
+{
+	printf("\t.long\t" LABFMT "\n", (int)a);
+}
+
+/*
+ * Print out a floating constant.
+ */
+void
+prconr(FILE *fp, int type, double x)
+{
+	fprintf(fp, "\t%s\t0f%e\n", (type==TYREAL ? ".float" : ".double"), x);
+}
+
+void
+preven(int k)
+{
+	if (k > 1)
+		printf("\t.align\t%d\n", k);
+}
+
+/*
+ * Convert a tag and offset into the symtab table to a string.
+ * An external string is never longer than XL bytes.
+ */
+char *
+memname(int stg, int mem)
+{
+#define	MLEN	(XL + 10)
+	char *s = malloc(MLEN);
+
+	switch(stg) {
+	case STGCOMMON:
+	case STGEXT:
+		snprintf(s, MLEN, "%s", varstr(XL, extsymtab[mem].extname));
+		break;
+
+	case STGBSS:
+	case STGINIT:
+		snprintf(s, MLEN, "v.%d", mem);
+		break;
+
+	case STGCONST:
+		snprintf(s, MLEN, ".L%d", mem);
+		break;
+
+	case STGEQUIV:
+		snprintf(s, MLEN, "q.%d", mem);
+		break;
+
+	default:
+		fatal1("memname: invalid vstg %d", stg);
+	}
+	return(s);
+}
+
+void
+prlocvar(char *s, ftnint len)
+{
+	printf("\t.lcomm\t%s,%ld\n", s, len);
+}
+
+
+void
+prext(char *name, ftnint leng, int init)
+{
+	if(leng == 0)
+		printf("\t.globl\t%s\n", name);
+	else
+		printf("\t.comm\t%s,%ld\n", name, leng);
+}
+
+void
+prendproc()
+{
+}
+
+void
+prtail()
+{
+}
+
+void
+prolog(struct entrypoint *ep, struct bigblock *argvec)
+{
+	/* Ignore for now.  ENTRY is not supported */
+}
+
+
+
+void
+prdbginfo()
+{
+}
+
+static void
+fcheck(NODE *p, void *arg)
+{
+	NODE *r, *l;
+
+	switch (p->n_op) {
+	case CALL: /* fix arguments */
+		for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+			r->n_right = mkunode(FUNARG, r->n_right, 0,
+			    r->n_right->n_type);
+		}
+		l = talloc();
+		*l = *r;
+		r->n_op = FUNARG;
+		r->n_left = l;
+		r->n_type = l->n_type;
+		break;
+	}
+}
+
+/*
+ * Called just before the tree is written out to pass2.
+ */
+void p2tree(NODE *p);
+void
+p2tree(NODE *p)
+{
+	walkf(p, fcheck, 0);
+}
+#endif /* FCOM */
Index: uspace/app/pcc/arch/i386/local.c
===================================================================
--- uspace/app/pcc/arch/i386/local.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
+++ uspace/app/pcc/arch/i386/local.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
@@ -0,0 +1,1574 @@
+/*	$Id: local.c,v 1.130.2.3 2011/03/30 16:35:36 ragge Exp $	*/
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+
+/*	this file contains code which is dependent on the target machine */
+
+#ifdef notyet
+/*
+ * 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;
+}
+#endif
+
+#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))
+
+/*
+ * 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->sap = NULL;
+	sp->sclass = EXTERN;
+	sp->sflags = sp->slevel = 0;
+	return sp;
+}
+
+#ifdef os_win32
+static NODE *
+import(NODE *p)
+{
+	NODE *q;
+	char *name;
+	struct symtab *sp;
+
+	if ((name = p->n_sp->soname) == NULL)
+		name = exname(p->n_sp->sname);
+
+	sp = picsymtab("__imp_", name, "");
+	q = xbcon(0, sp, PTR+VOID);
+	q = block(UMUL, q, 0, PTR|VOID, 0, MKAP(VOID));
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+	q->n_sp = p->n_sp; /* for init */
+	nfree(p);
+
+	return q;
+}
+#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;
+	char *name;
+
+	q = tempnode(gotnr, PTR|VOID, 0, MKAP(VOID));
+	if ((name = p->n_sp->soname) == NULL)
+		name = p->n_sp->sname;
+	sp = picsymtab("", name, "@GOT");
+#ifdef GCC_COMPAT
+	if (attr_find(p->n_sp->sap, GCC_ATYP_STDCALL) != NULL)
+		p->n_sp->sflags |= SSTDCALL;
+#endif
+	sp->sflags = p->n_sp->sflags & SSTDCALL;
+	r = xbcon(0, sp, INT);
+	q = buildtree(PLUS, q, r);
+	q = block(UMUL, q, 0, PTR|VOID, 0, MKAP(VOID));
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+	q->n_sp = p->n_sp; /* for init */
+	nfree(p);
+	return q;
+
+#elif defined(MACHOABI)
+
+	NODE *q, *r;
+	struct symtab *sp;
+	char buf2[256], *name, *pspn;
+
+	if ((name = cftnsp->soname) == NULL)
+		name = cftnsp->sname;
+	if ((pspn = p->n_sp->soname) == NULL)
+		pspn = exname(p->n_sp->sname);
+	if (p->n_sp->sclass == EXTDEF) {
+		snprintf(buf2, 256, "-L%s$pb", name);
+		sp = picsymtab("", pspn, buf2);
+	} else {
+		snprintf(buf2, 256, "$non_lazy_ptr-L%s$pb", name);
+		sp = picsymtab("L", pspn, buf2);
+		addstub(&nlplist, pspn);
+	}
+	q = tempnode(gotnr, PTR+VOID, 0, MKAP(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, MKAP(VOID));
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+	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, MKAP(VOID));
+	if (p->n_sp->slevel > 0) {
+		char buf[32];
+		snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset);
+		sp = picsymtab("", buf, "@GOTOFF");
+	} else {
+		char *name;
+		if ((name = p->n_sp->soname) == NULL)
+			name = p->n_sp->sname;
+		sp = picsymtab("", name, "@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_ap);
+	q->n_sp = p->n_sp; /* for init */
+	nfree(p);
+	return q;
+
+#elif defined(MACHOABI)
+
+	NODE *q, *r;
+	struct symtab *sp;
+	char buf2[256];
+
+	snprintf(buf2, 256, "-L%s$pb",
+	    cftnsp->soname ? cftnsp->soname : cftnsp->sname);
+
+	if (p->n_sp->slevel > 0) {
+		char buf1[32];
+		snprintf(buf1, 32, LABFMT, (int)p->n_sp->soffset);
+		sp = picsymtab("", buf1, buf2);
+	} else  {
+		char *name;
+		if ((name = p->n_sp->soname) == NULL)
+			name = p->n_sp->sname;
+		sp = picsymtab("", exname(name), buf2);
+	}
+	sp->sclass = STATIC;
+	sp->stype = p->n_sp->stype;
+	q = tempnode(gotnr, PTR+VOID, 0, MKAP(VOID));
+	r = xbcon(0, sp, INT);
+	q = buildtree(PLUS, q, r);
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+	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;
+	char *name;
+
+	/*
+	 * creates:
+	 *   leal var@TLSGD(%ebx),%eax
+	 *   call ___tls_get_addr@PLT
+	 */
+
+	/* calc address of var@TLSGD */
+	q = tempnode(gotnr, PTR|VOID, 0, MKAP(VOID));
+	if ((name = p->n_sp->soname) == NULL)
+		name = p->n_sp->sname;
+	sp = picsymtab("", name, "@TLSGD");
+	r = xbcon(0, sp, INT);
+	q = buildtree(PLUS, q, r);
+
+	/* assign to %eax */
+	r = block(REG, NIL, NIL, PTR|VOID, 0, MKAP(VOID));
+	r->n_rval = EAX;
+	q = buildtree(ASSIGN, r, q);
+
+	/* call ___tls_get_addr */
+	sp2 = lookup("___tls_get_addr@PLT", 0);
+	sp2->stype = EXTERN|INT|FTN;
+	r = nametree(sp2);
+	r = buildtree(ADDROF, r, NIL);
+	r = block(UCALL, r, NIL, INT, 0, MKAP(INT));
+
+	/* fusion both parts together */
+	q = buildtree(COMOP, q, r);
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+	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;
+	char *name;
+
+	if ((name = p->n_sp->soname) == NULL)
+		name = p->n_sp->sname;
+	sp = picsymtab("", name,
+	    ext == EXTERN ? "@INDNTPOFF" : "@NTPOFF");
+	q = xbcon(0, sp, INT);
+	if (ext == EXTERN)
+		q = block(UMUL, q, NIL, PTR|VOID, 0, MKAP(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_ap);
+	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;
+#if defined(os_openbsd)
+	register NODE *s, *n;
+#endif
+	register int o;
+	register int m;
+
+#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
+
+#ifdef os_win32
+			if (q->sflags & SDLLINDIRECT)
+				p = import(p);
+#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;
+#if defined(ELFABI)
+		/* Change to CALL node with ebx as argument */
+		l = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		l->n_rval = EBX;
+		p->n_right = buildtree(ASSIGN, l,
+		    tempnode(gotnr, INT, 0, MKAP(INT)));
+		p->n_op -= (UCALL-CALL);
+#endif
+	
+	/* FALLTHROUGH */
+#if defined(MACHOABI)
+	case CALL:
+	case STCALL:
+		if (p->n_type == VOID)
+			break;
+
+		r = tempnode(0, p->n_type, p->n_df, p->n_ap);
+		l = tcopy(r);
+		p = buildtree(COMOP, buildtree(ASSIGN, r, p), l);
+#endif
+			
+		break;
+
+#ifdef notyet
+	/* XXX breaks sometimes */
+	case CBRANCH:
+		l = p->n_left;
+
+		/*
+		 * Remove unnecessary conversion ops.
+		 */
+		if (!clogop(l->n_op) || l->n_left->n_op != SCONV)
+			break;
+		if (coptype(l->n_op) != BITYPE)
+			break;
+		if (l->n_right->n_op != ICON)
+			break;
+		r = l->n_left->n_left;
+		if (r->n_type >= FLOAT)
+			break;
+		if (toolarge(r->n_type, l->n_right->n_lval))
+			break;
+		l->n_right->n_type = r->n_type;
+		if (l->n_op >= ULE && l->n_op <= UGT)
+			l->n_op -= (UGT-ULE);
+		p->n_left = buildtree(l->n_op, r, l->n_right);
+		nfree(l->n_left);
+		nfree(l);
+		break;
+#endif
+
+	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, MKAP(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_ap = p->n_ap;
+		nfree(p);
+		p = l;
+		break;
+		
+	case SCONV:
+		if (p->n_left->n_op == COMOP)
+			break;  /* may propagate wrong type later */
+		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 &&
+		    btattr[p->n_type].atypsz == btattr[l->n_type].atypsz) {
+			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_op != COMOP &&
+		    l->n_op != QUEST) {
+			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 = nncon(l) ? (l->n_lval != 0) : 1;
+				l->n_sp = NULL;
+				break;
+			case CHAR:
+				l->n_lval = (char)val;
+				break;
+			case UCHAR:
+				l->n_lval = val & 0377;
+				break;
+			case SHORT:
+				l->n_lval = (short)val;
+				break;
+			case USHORT:
+				l->n_lval = val & 0177777;
+				break;
+			case ULONG:
+			case UNSIGNED:
+				l->n_lval = val & 0xffffffff;
+				break;
+			case LONG:
+			case INT:
+				l->n_lval = (int)val;
+				break;
+			case LONGLONG:
+				l->n_lval = (long long)val;
+				break;
+			case ULONGLONG:
+				l->n_lval = val;
+				break;
+			case VOID:
+				break;
+			case LDOUBLE:
+			case DOUBLE:
+			case FLOAT:
+				l->n_op = FCON;
+				l->n_dcon = val;
+				break;
+			default:
+				cerror("unknown type %d", m);
+			}
+			l->n_type = m;
+			l->n_ap = MKAP(m);
+			nfree(p);
+			return l;
+		} else if (l->n_op == FCON) {
+			l->n_lval = (CONSZ)l->n_dcon;
+			l->n_sp = NULL;
+			l->n_op = ICON;
+			l->n_type = m;
+			l->n_ap = MKAP(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_ap);
+			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, MKAP(INT));
+		p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKAP(INT));
+		p = block(SCONV, p, NIL, p->n_type, 0, MKAP(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, MKAP(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 */
+		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, MKAP(CHAR));
+		break;
+#if defined(os_openbsd)
+		/* If not using pcc struct return */
+	case STASG:
+		r = p->n_right;
+		if (r->n_op != STCALL && r->n_op != USTCALL)
+			break;
+		m = tsize(BTYPE(r->n_type), r->n_df, r->n_ap);
+		if (m == SZCHAR)
+			m = CHAR;
+		else if (m == SZSHORT)
+			m = SHORT;
+		else if (m == SZINT)
+			m = INT;
+		else if (m == SZLONGLONG)
+			m = LONGLONG;
+		else
+			break;
+
+		l = buildtree(ADDROF, p->n_left, NIL);
+		nfree(p);
+
+		r->n_op -= (STCALL-CALL);
+		r->n_type = m;
+
+		/* r = long, l = &struct */
+
+		n = tempnode(0, m, r->n_df, r->n_ap);
+		r = buildtree(ASSIGN, ccopy(n), r);
+
+		s = tempnode(0, l->n_type, l->n_df, l->n_ap);
+		l = buildtree(ASSIGN, ccopy(s), l);
+
+		p = buildtree(COMOP, r, l);
+
+		l = buildtree(CAST,
+		    block(NAME, NIL, NIL, m|PTR, 0, MKAP(m)), ccopy(s));
+		r = l->n_right;
+		nfree(l->n_left);
+		nfree(l);
+
+		r = buildtree(ASSIGN, buildtree(UMUL, r, NIL), n);
+		p = buildtree(COMOP, p, r);
+		p = buildtree(COMOP, p, s);
+		break;
+#endif
+	}
+#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)
+{
+#if !defined(PECOFFABI)
+
+	struct symtab *sp;
+	struct attr *ap;
+	NODE *q;
+	char *c;
+	int isu;
+
+	if ((cdope(p->n_op) & CALLFLG) == 0)
+		return;
+	isu = 0;
+	q = p->n_left;
+	ap = q->n_ap;
+	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");
+		c = NULL;
+#if defined(ELFABI)
+
+		if (sp->soname == NULL ||
+		    (c = strstr(sp->soname, "@GOT")) == NULL)
+			cerror("fixnames2");
+		if (isu) {
+			memcpy(c, "@PLT", sizeof("@PLT"));
+		} else
+			*c = 0;
+
+#elif defined(MACHOABI)
+
+		if (sp->soname == NULL ||
+		    ((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_ap = ap;
+	}
+#endif
+}
+
+static void mangle(NODE *p);
+
+void
+myp2tree(NODE *p)
+{
+	struct symtab *sp;
+
+	if (kflag)
+		fixnames(p, 0);
+
+	mangle(p);
+
+	if (p->n_op != FCON)
+		return;
+
+	sp = IALLOC(sizeof(struct symtab));
+	sp->sclass = STATIC;
+	sp->sap = MKAP(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->sap->atypsz, 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 attr *ap)
+{
+	register NODE *p;
+
+	if (xdebug)
+		printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
+		    off, t, d, 0);
+
+	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, MKAP(INT));
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	ecomp(buildtree(MINUSEQ, sp, p));
+
+#ifdef MACHOABI	
+	/* align to 16 bytes */
+	sp = block(REG, NIL, NIL, p->n_type, 0, MKAP(INT));
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	ecomp(buildtree(PLUSEQ, sp, bcon(15)));
+	
+	sp = block(REG, NIL, NIL, p->n_type, 0, MKAP(INT));
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	ecomp(buildtree(RSEQ, sp, bcon(4)));
+	
+	sp = block(REG, NIL, NIL, p->n_type, 0, MKAP(INT));
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	ecomp(buildtree(LSEQ, sp, bcon(4)));
+#endif
+	
+
+	/* save the address of sp */
+	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
+	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;
+
+#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);
+
+#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 > 60) {
+			fwrite(str, 1, s - str, stdout);
+			printf("\"\n\t.ascii \"");
+			str = s;
+		}
+	}
+	fwrite(str, 1, s - str, stdout);
+	printf("\\0\"\n");
+}
+
+static int inbits, inval;
+
+/*
+ * set fsz bits in sequence to zero.
+ */
+void
+zbits(OFFSZ off, int fsz)
+{
+	int m;
+
+	if (idebug)
+		printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
+	if ((m = (inbits % SZCHAR))) {
+		m = SZCHAR - m;
+		if (fsz < m) {
+			inbits += fsz;
+			return;
+		} else {
+			fsz -= m;
+			printf("\t.byte %d\n", inval);
+			inval = inbits = 0;
+		}
+	}
+	if (fsz >= SZCHAR) {
+#ifdef os_darwin
+		printf("\t.space %d\n", fsz/SZCHAR);
+#else
+ 		printf("\t.zero %d\n", fsz/SZCHAR);
+#endif
+		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 |= (int)(val << inbits);
+		printf("\t.byte %d\n", inval & 255);
+		fsz -= (SZCHAR - inbits);
+		val >>= (SZCHAR - inbits);
+		inval = inbits = 0;
+	}
+	if (fsz) {
+		inval |= (int)(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;
+#if defined(ELFABI) || defined(MACHOABI)
+	char *c;
+#endif
+	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 (q->soname != NULL) {
+#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");
+
+	if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
+		uerror("element not constant");
+
+	switch (t) {
+	case LONGLONG:
+	case ULONGLONG:
+		i = (int)(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 %d", (int)p->n_lval);
+		if ((q = p->n_sp) != NULL) {
+			if ((q->sclass == STATIC && q->slevel > 0)) {
+				printf("+" LABFMT, q->soffset);
+			} else {
+				char *name;
+				if ((name = q->soname) == NULL)
+					name = exname(q->sname);
+				printf("+%s", name);
+			}
+		}
+		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)
+			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\t%d,%d,%d\n", u.i[0], u.i[1], u.i[2] & 0177777);
+#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\t%d,%d\n", u.i[0], u.i[1]);
+#endif
+		break;
+	case FLOAT:
+		u.f = (float)p->n_dcon;
+		printf("\t.long\t%d\n", u.i[0]);
+		break;
+	default:
+		cerror("ninval");
+	}
+}
+
+/* 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 "";
+
+	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
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+	switch (BTYPE(type)) {
+	case LONG:
+		MODTYPE(type,INT);
+		break;
+
+	case ULONG:
+		MODTYPE(type,UNSIGNED);
+
+	}
+	return (type);
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+	int off;
+	int al;
+	char *name;
+
+#ifdef TLS
+	if (sp->sflags & STLS) {
+		if (sp->sclass == EXTERN)
+			sp->sclass = EXTDEF;
+		simpleinit(sp, bcon(0));
+		return;
+	}
+#endif
+
+	if ((name = sp->soname) == NULL)
+		name = exname(sp->sname);
+	al = talign(sp->stype, sp->sap)/SZCHAR;
+	off = (int)tsize(sp->stype, sp->sdf, sp->sap);
+	off = (off+(SZCHAR-1))/SZCHAR;
+#ifdef GCC_COMPAT
+	{
+		struct attr *ap;
+		if ((ap = attr_find(sp->sap, GCC_ATYP_VISIBILITY)) &&
+		    strcmp(ap->sarg(0), "default"))
+			printf("\t.%s %s\n", ap->sarg(0), name);
+	}
+#endif
+	printf("	.%scomm ", sp->sclass == STATIC ? "l" : "");
+	if (sp->slevel == 0)
+		printf("%s,0%o", name, off);
+	else
+		printf(LABFMT ",0%o", sp->soffset, off);
+	if (sp->sclass != STATIC) {
+#if defined(ELFABI)
+		printf(",%d", al);
+#elif defined(MACHOABI)
+		printf(",%d", ispow2(al));
+#endif
+	}
+	printf("\n");
+}
+
+static char *
+section2string(char *name, int len)
+{
+#if defined(ELFABI)
+	char *s;
+	int n;
+
+	if (strncmp(name, "link_set", 8) == 0) {
+		const char *postfix = ",\"aw\",@progbits";
+		n = len + strlen(postfix) + 1;
+		s = IALLOC(n);
+		strlcpy(s, name, n);
+		strlcat(s, postfix, n);
+		return s;
+	}
+#endif
+
+	return newstring(name, len);
+}
+
+char *nextsect;
+#ifdef TLS
+static int gottls;
+#endif
+static int stdcall;
+#ifdef os_win32
+static int dllindirect;
+#endif
+static char *alias;
+static int constructor;
+static int destructor;
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+	char *a2 = pragtok(NULL);
+
+#ifdef TLS
+	if (strcmp(str, "tls") == 0 && a2 == NULL) {
+		gottls = 1;
+		return 1;
+	}
+#endif
+	if (strcmp(str, "stdcall") == 0) {
+		stdcall = 1;
+		return 1;
+	}
+	if (strcmp(str, "cdecl") == 0) {
+		stdcall = 0;
+		return 1;
+	}
+#ifdef os_win32
+	if (strcmp(str, "fastcall") == 0) {
+		stdcall = 2;
+		return 1;
+	}
+	if (strcmp(str, "dllimport") == 0) {
+		dllindirect = 1;
+		return 1;
+	}
+	if (strcmp(str, "dllexport") == 0) {
+		dllindirect = 1;
+		return 1;
+	}
+#endif
+	if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
+		constructor = 1;
+		return 1;
+	}
+	if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
+		destructor = 1;
+		return 1;
+	}
+	if (strcmp(str, "section") == 0 && a2 != NULL) {
+		nextsect = section2string(a2, strlen(a2));
+		return 1;
+	}
+	if (strcmp(str, "alias") == 0 && a2 != NULL) {
+		alias = tmpstrdup(a2);
+		return 1;
+	}
+	if (strcmp(str, "ident") == 0)
+		return 1; /* Just ignore */
+
+	return 0;
+}
+
+/*
+ * Called when a identifier has been declared.
+ */
+void
+fixdef(struct symtab *sp)
+{
+	struct attr *ap;
+#ifdef TLS
+	/* may have sanity checks here */
+	if (gottls)
+		sp->sflags |= STLS;
+	gottls = 0;
+#endif
+	if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) {
+		char *an = ap->sarg(0);	 
+		char *sn = sp->soname ? sp->soname : sp->sname; 
+		char *v;
+
+		v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl";
+		printf("\t.%s %s\n", v, sn);
+		printf("\t.set %s,%s\n", sn, an);
+	}	
+
+	if (alias != NULL && (sp->sclass != PARAM)) {
+		char *name;
+		if ((name = sp->soname) == NULL)
+			name = exname(sp->sname);
+		printf("\t.globl %s\n", name);
+		printf("%s = ", name);
+		printf("%s\n", exname(alias));
+		alias = NULL;
+	}
+	if ((constructor || destructor) && (sp->sclass != PARAM)) {
+#if defined(ELFABI)
+		printf("\t.section .%ctors,\"aw\",@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));
+#ifdef MACHOABI
+		printf("\t.text\n");
+#else
+		printf("\t.previous\n");
+#endif
+		constructor = destructor = 0;
+	}
+	if (stdcall && (sp->sclass != PARAM)) {
+		sp->sflags |= SSTDCALL;
+		stdcall = 0;
+	}
+#ifdef os_win32
+	if (dllindirect && (sp->sclass != PARAM)) {
+		sp->sflags |= SDLLINDIRECT;
+		dllindirect = 0;
+	}
+#endif
+}
+
+NODE *
+i386_builtin_return_address(NODE *f, NODE *a, TWORD rt)
+{
+	int nframes;
+
+	if (a == NULL || a->n_op != ICON)
+		goto bad;
+
+	nframes = (int)a->n_lval;
+
+	tfree(f);
+	tfree(a);
+
+	f = block(REG, NIL, NIL, PTR+VOID, 0, MKAP(VOID));
+	regno(f) = FPREG;
+
+	while (nframes--)
+		f = block(UMUL, f, NIL, PTR+VOID, 0, MKAP(VOID));
+
+	f = block(PLUS, f, bcon(4), INCREF(PTR+VOID), 0, MKAP(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, TWORD rt)
+{
+	int nframes;
+
+	if (a == NULL || a->n_op != ICON)
+		goto bad;
+
+	nframes = (int)a->n_lval;
+
+	tfree(f);
+	tfree(a);
+
+	f = block(REG, NIL, NIL, PTR+VOID, 0, MKAP(VOID));
+	regno(f) = FPREG;
+
+	while (nframes--)
+		f = block(UMUL, f, NIL, PTR+VOID, 0, MKAP(VOID));
+
+	return f;
+bad:
+        uerror("bad argument to __builtin_frame_address");
+        return bcon(0);
+}
+
+/*
+ *  Postfix external functions with the arguments size.
+ */
+static void
+mangle(NODE *p)
+{
+	NODE *l;
+
+	if (p->n_op == NAME || p->n_op == ICON) {
+		p->n_flags = 0; /* for later setting of STDCALL */
+		if (p->n_sp) {
+			 if (p->n_sp->sflags & SSTDCALL)
+				p->n_flags = FSTDCALL;
+		}
+	} else if (p->n_op == TEMP)
+		p->n_flags = 0; /* STDCALL fun ptr not allowed */
+
+	if (p->n_op != CALL && p->n_op != STCALL &&
+	    p->n_op != UCALL && p->n_op != USTCALL)
+		return;
+
+	p->n_flags = 0;
+
+	l = p->n_left;
+	while (cdope(l->n_op) & CALLFLG)
+		l = l->n_left;
+	if (l->n_op == TEMP)
+		return;
+	if (l->n_op == ADDROF)
+		l = l->n_left;
+	if (l->n_sp == NULL)
+		return;
+#ifdef GCC_COMPAT
+	if (attr_find(l->n_sp->sap, GCC_ATYP_STDCALL) != NULL)
+		l->n_sp->sflags |= SSTDCALL;
+#endif
+#ifdef os_win32
+	if (l->n_sp->sflags & SSTDCALL) {
+		if (strchr(l->n_name, '@') == NULL) {
+			int size = 0;
+			char buf[256];
+			NODE *r;
+			TWORD t;
+
+			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 += tsize(t, r->n_df, r->n_ap);
+					else
+						size += szty(t) * SZINT / SZCHAR;
+				}
+				t = r->n_type;
+				if (t == STRTY || t == UNIONTY)
+					size += tsize(t, r->n_df, r->n_ap);
+				else
+					size += szty(t) * SZINT / SZCHAR;
+			}
+			snprintf(buf, 256, "%s@%d", l->n_name, size);
+	        	l->n_name = IALLOC(strlen(buf) + 1);
+			strcpy(l->n_name, buf);
+		}
+	}
+#endif
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+	if (ip->type == IP_NODE &&
+	    (ip->ip_node->n_op == CALL || ip->ip_node->n_op == UCALL) &&
+	    ISFTY(ip->ip_node->n_type))
+		ip->ip_node->n_flags = FFPPOP;
+ 
+	if (ip->type == IP_EPILOG) {
+		struct interpass_prolog *ipp = (struct interpass_prolog *)ip;
+		ipp->ipp_argstacksize = argstacksize;
+	}
+}
Index: uspace/app/pcc/arch/i386/local2.c
===================================================================
--- uspace/app/pcc/arch/i386/local2.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
+++ uspace/app/pcc/arch/i386/local2.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
@@ -0,0 +1,1602 @@
+/*	$Id: local2.c,v 1.154.2.2 2011/02/26 07:17:34 ragge Exp $	*/
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass2.h"
+# include <ctype.h>
+# include <string.h>
+
+#if defined(PECOFFABI) || defined(MACHOABI)
+#define EXPREFIX	"_"
+#else
+#define EXPREFIX	""
+#endif
+
+
+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)
+{
+	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 = 0; i < MAXREGS; i++)
+		if (TESTBIT(ipp->ipp_regs, i))
+			fprintf(stdout, "	movl %s,-%d(%s)\n",
+			    rnames[i], regoff[i], rnames[FPREG]);
+}
+
+/*
+ * 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);
+#if defined(MACHOABI)
+	addto = (addto + 15) & ~15;	/* stack alignment */
+#endif
+	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 + ipp->ipp_argstacksize);
+	} else {
+		printf("	leave\n");
+		if (ipp->ipp_argstacksize)
+			printf("	ret $%d\n", ipp->ipp_argstacksize);
+		else
+			printf("	ret\n");
+	}
+
+#if defined(ELFABI)
+	printf("\t.size " EXPREFIX "%s,.-" EXPREFIX "%s\n", ipp->ipp_name,
+	    ipp->ipp_name);
+#endif
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+	char *str;
+
+	switch (o) {
+	case PLUS:
+		str = "add";
+		break;
+	case MINUS:
+		str = "sub";
+		break;
+	case AND:
+		str = "and";
+		break;
+	case OR:
+		str = "or";
+		break;
+	case ER:
+		str = "xor";
+		break;
+	default:
+		comperr("hopcode2: %d", o);
+		str = 0; /* XXX gcc */
+	}
+	printf("%s%c", str, f);
+}
+
+/*
+ * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(p) NODE *p;
+{
+	switch(p->n_type) {
+		case CHAR:
+		case UCHAR:
+			return(1);
+
+		case SHORT:
+		case USHORT:
+			return(SZSHORT/SZCHAR);
+
+		case DOUBLE:
+			return(SZDOUBLE/SZCHAR);
+
+		case INT:
+		case UNSIGNED:
+		case LONG:
+		case ULONG:
+			return(SZINT/SZCHAR);
+
+		case LONGLONG:
+		case ULONGLONG:
+			return SZLONGLONG/SZCHAR;
+
+		default:
+			if (!ISPTR(p->n_type))
+				comperr("tlen type %d not pointer");
+			return SZPOINT(p->n_type)/SZCHAR;
+		}
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+	int u;
+	int s = getlab2();
+	int e = p->n_label;
+	int cb1, cb2;
+
+	u = p->n_op;
+	switch (p->n_op) {
+	case NE:
+		cb1 = 0;
+		cb2 = NE;
+		break;
+	case EQ:
+		cb1 = NE;
+		cb2 = 0;
+		break;
+	case LE:
+	case LT:
+		u += (ULE-LE);
+		/* FALLTHROUGH */
+	case ULE:
+	case ULT:
+		cb1 = GT;
+		cb2 = LT;
+		break;
+	case GE:
+	case GT:
+		u += (ULE-LE);
+		/* FALLTHROUGH */
+	case UGE:
+	case UGT:
+		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(u, 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:
+	case LONG:
+		ch = 'l';
+		sz = 32;
+		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");
+}
+
+/* long long bitfield assign */
+static void
+llbf(NODE *p)
+{
+	NODE *q;
+	char buf[50];
+	CONSZ m, n;
+	int o, s;
+	int ml, mh, nl, nh;
+
+	q = p->n_left;
+	o = UPKFOFF(q->n_rval);
+	s = UPKFSZ(q->n_rval);
+	m = (CONSZ)1 << (s-1);
+	m--;
+	m = (m << 1) | 1;
+	m <<= o;
+	n = ~m;
+
+	ml = m & 0xffffffff;
+	nl = n & 0xffffffff;
+	mh = (m >> 32) & 0xffffffff;
+	nh = (n >> 32) & 0xffffffff;
+
+#define	S(...)	snprintf(buf, sizeof buf, __VA_ARGS__); expand(p, 0, buf)
+
+	if (o < 32) { /* lower 32 buts */
+		S("	andl $0x%x,AL\n", nl);
+		S("	movl AR,A1\n");
+		S("	sall $%d,A1\n", o);
+		S("	andl $0x%x,A1\n", ml);
+		S("	orl A1,AL\n");
+	}
+	if ((o+s) >= 32) { /* upper 32 bits */
+		S("	andl $0x%x,UL\n", nh);
+		S("	movl UR,A1\n");
+		S("	sall $%d,A1\n", o);
+		S("	movl AR,U1\n");
+		S("	shrl $%d,U1\n", 32-o);
+		S("	orl U1,A1\n");
+		S("	andl $0x%x,A1\n", mh);
+		S("	orl A1,UL\n");
+	}
+#undef S
+//	fwalk(p, e2print, 0);
+
+	
+}
+
+/*
+ * Push a structure on stack as argument.
+ * the scratch registers are already free here
+ */
+static void
+starg(NODE *p)
+{
+	FILE *fp = stdout;
+
+#if defined(MACHOABI)
+	fprintf(fp, "	subl $%d,%%esp\n", p->n_stsize);
+	fprintf(fp, "	subl $4,%%esp\n");
+	fprintf(fp, "	pushl $%d\n", p->n_stsize);
+	expand(p, 0, "	pushl AL\n");
+	expand(p, 0, "	leal 12(%esp),A1\n");
+	expand(p, 0, "	pushl A1\n");
+	if (kflag) {
+		fprintf(fp, "	call L%s$stub\n", EXPREFIX "memcpy");
+		addstub(&stublist, EXPREFIX "memcpy");
+	} else {
+		fprintf(fp, "	call %s\n", EXPREFIX "memcpy");
+	}
+	fprintf(fp, "	addl $16,%%esp\n");
+#else
+	fprintf(fp, "	subl $%d,%%esp\n", (p->n_stsize+3) & ~3);
+	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 %s%s\n", EXPREFIX "memcpy", kflag ? "@PLT" : "");
+	fprintf(fp, "	addl $12,%%esp\n");
+#endif
+}
+
+/*
+ * Compare two floating point numbers.
+ */
+static void
+fcomp(NODE *p)  
+{
+	static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" };
+
+	if ((p->n_su & DORIGHT) == 0)
+		expand(p, 0, "  fxch\n");
+	expand(p, 0, "  fucomip %st(1),%st\n");	/* emit compare insn  */
+	expand(p, 0, "  fstp %st(0)\n");	/* pop fromstack */
+
+	if (p->n_op == NE || p->n_op == GT || p->n_op == GE)
+		expand(p, 0, "  jp LC\n");
+	else if (p->n_op == EQ)
+		printf("\tjp 1f\n");
+	printf("	%s ", fpcb[p->n_op - EQ]);
+	expand(p, 0, "LC\n");
+	if (p->n_op == EQ)
+		printf("1:\n");
+}
+
+/*
+ * Convert an unsigned long long to floating point number.
+ */
+static void
+ulltofp(NODE *p)
+{
+	static int loadlab;
+	int jmplab;
+
+	if (loadlab == 0) {
+		loadlab = getlab2();
+		expand(p, 0, "	.data\n");
+		printf(LABFMT ":	.long 0,0x80000000,0x403f\n", loadlab);
+		expand(p, 0, "	.text\n");
+	}
+	jmplab = getlab2();
+	expand(p, 0, "	pushl UL\n	pushl AL\n");
+	expand(p, 0, "	fildq (%esp)\n");
+	expand(p, 0, "	addl $8,%esp\n");
+	expand(p, 0, "	cmpl $0,UL\n");
+	printf("	jge " LABFMT "\n", jmplab);
+	printf("	fldt " LABFMT "\n", loadlab);
+	printf("	faddp %%st,%%st(1)\n");
+	printf(LABFMT ":\n", jmplab);
+}
+
+static int
+argsiz(NODE *p)
+{
+	TWORD t = p->n_type;
+
+	if (t < LONGLONG || t == FLOAT || t > BTMASK)
+		return 4;
+	if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
+		return 8;
+	if (t == LDOUBLE)
+		return 12;
+	if (t == STRTY || t == UNIONTY)
+		return (p->n_stsize+3) & ~3;
+	comperr("argsiz");
+	return 0;
+}
+
+static void
+fcast(NODE *p)
+{
+	TWORD t = p->n_type;
+	int sz, c;
+
+	if (t >= p->n_left->n_type)
+		return; /* cast to more precision */
+	if (t == FLOAT)
+		sz = 4, c = 's';
+	else
+		sz = 8, c = 'l';
+
+	printf("	sub $%d,%%esp\n", sz);
+	printf("	fstp%c (%%esp)\n", c);
+	printf("	fld%c (%%esp)\n", c);
+	printf("	add $%d,%%esp\n", sz);
+}
+
+static void
+llshft(NODE *p)
+{
+	char *d[3];
+
+	if (p->n_op == LS) {
+		d[0] = "l", d[1] = "%eax", d[2] = "%edx";
+	} else
+		d[0] = "r", d[1] = "%edx", d[2] = "%eax";
+
+	printf("\tsh%sdl %s,%s\n",d[0], d[1], d[2]);
+	printf("\ts%s%sl %%cl,%s\n", p->n_op == RS &&
+	    p->n_left->n_type == ULONGLONG ? "h" : "a", d[0], d[1]);
+	printf("\ttestb $32,%%cl\n");
+	printf("\tje 1f\n");
+	printf("\tmovl %s,%s\n", d[1], d[2]);
+	if (p->n_op == RS && p->n_left->n_type == LONGLONG)
+		printf("\tsarl $31,%%edx\n");
+	else
+		printf("\txorl %s,%s\n",d[1],d[1]);
+	printf("1:\n");
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+	NODE *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 'B': { /* packed bitfield ops */
+		int sz, off;
+
+		l = p->n_left;
+		sz = UPKFSZ(l->n_rval);
+		off = UPKFOFF(l->n_rval);
+		if (sz + off <= SZINT)
+			break;
+		/* lower already printed */
+		expand(p, INAREG, "	movl AR,A1\n");
+		expand(p, INAREG, "	andl $M,UL\n");
+		printf("	sarl $%d,", SZINT-off);
+		expand(p, INAREG, "A1\n");
+		expand(p, INAREG, "	andl $N,A1\n");
+		expand(p, INAREG, "	orl A1,UL\n");
+		}
+		break;
+
+	case 'C':  /* remove from stack after subroutine call */
+#ifdef notyet
+		if (p->n_left->n_flags & FSTDCALL)
+			break;
+#endif
+		pr = p->n_qual;
+		if (p->n_op == STCALL || p->n_op == USTCALL)
+			pr += 4;
+		if (p->n_flags & FFPPOP)
+			printf("	fstp	%%st(0)\n");
+		if (p->n_op == UCALL)
+			return; /* XXX remove ZC from UCALL */
+		if (pr)
+			printf("	addl $%d, %s\n", pr, rnames[ESP]);
+		break;
+
+	case 'D': /* Long long comparision */
+		twollcomp(p);
+		break;
+
+	case 'E': /* 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 'H': /* assign of longlong between regs */
+		rmove(DECRA(p->n_right->n_reg, 0),
+		    DECRA(p->n_left->n_reg, 0), LONGLONG);
+		break;
+
+	case 'I': /* float casts */
+		fcast(p);
+		break;
+
+	case 'J': /* convert unsigned long long to floating point */
+		ulltofp(p);
+		break;
+
+	case 'K': /* Load longlong reg into another reg */
+		rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG);
+		break;
+
+	case 'L': /* long long bitfield assign */
+		llbf(p);
+		break;
+
+	case 'M': /* Output sconv move, if needed */
+		l = getlr(p, 'L');
+		/* XXX fixneed: regnum */
+		pr = DECRA(p->n_reg, 0);
+		lr = DECRA(l->n_reg, 0);
+		if ((pr == AL && lr == EAX) || (pr == BL && lr == EBX) ||
+		    (pr == CL && lr == ECX) || (pr == DL && lr == EDX))
+			;
+		else
+			printf("	movb %%%cl,%s\n",
+			    rnames[lr][2], rnames[pr]);
+		l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
+		break;
+
+	case 'N': /* output extended reg name */
+		printf("%s", rnames[getlr(p, '1')->n_rval]);
+		break;
+
+	case 'O': /* print out emulated ops */
+		pr = 16;
+		if (p->n_op == RS || p->n_op == LS) {
+			llshft(p);
+			break;
+		} else if (p->n_op == MUL) {
+			printf("\timull %%ecx, %%edx\n");
+			printf("\timull %%eax, %%esi\n");
+			printf("\taddl %%edx, %%esi\n");
+			printf("\tmull %%ecx\n");
+			printf("\taddl %%esi, %%edx\n");
+			break;
+		}
+		expand(p, INCREG, "\tpushl UR\n\tpushl AR\n");
+		expand(p, INCREG, "\tpushl UL\n\tpushl AL\n");
+		if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv";
+		else if (p->n_op == DIV) ch = "div";
+		else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod";
+		else if (p->n_op == MOD) ch = "mod";
+		else ch = 0, comperr("ZO");
+#ifdef ELFABI
+		printf("\tcall " EXPREFIX "__%sdi3%s\n\taddl $%d,%s\n",
+			ch, (kflag ? "@PLT" : ""), pr, rnames[ESP]);
+#else
+		printf("\tcall " EXPREFIX "__%sdi3\n\taddl $%d,%s\n",
+			ch, pr, rnames[ESP]);
+#endif
+                break;
+
+	case 'P': /* push hidden argument on stack */
+		printf("\tleal -%d(%%ebp),", stkpos);
+		adrput(stdout, getlr(p, '1'));
+		printf("\n\tpushl ");
+		adrput(stdout, getlr(p, '1'));
+		putchar('\n');
+		break;
+
+	case 'Q': /* emit struct assign */
+		/*
+		 * With <= 16 bytes, put out mov's, otherwise use movsb/w/l.
+		 * esi/edi/ecx are available.
+		 * XXX should not need esi/edi if not rep movsX.
+		 * XXX can save one insn if src ptr in reg.
+		 */
+		switch (p->n_stsize) {
+		case 1:
+			expand(p, INAREG, "	movb (%esi),%cl\n");
+			expand(p, INAREG, "	movb %cl,AL\n");
+			break;
+		case 2:
+			expand(p, INAREG, "	movw (%esi),%cx\n");
+			expand(p, INAREG, "	movw %cx,AL\n");
+			break;
+		case 4:
+			expand(p, INAREG, "	movl (%esi),%ecx\n");
+			expand(p, INAREG, "	movl %ecx,AL\n");
+			break;
+		default:
+			expand(p, INAREG, "	leal AL,%edi\n");
+			if (p->n_stsize <= 16 && (p->n_stsize & 3) == 0) {
+				printf("	movl (%%esi),%%ecx\n");
+				printf("	movl %%ecx,(%%edi)\n");
+				printf("	movl 4(%%esi),%%ecx\n");
+				printf("	movl %%ecx,4(%%edi)\n");
+				if (p->n_stsize > 8) {
+					printf("	movl 8(%%esi),%%ecx\n");
+					printf("	movl %%ecx,8(%%edi)\n");
+				}
+				if (p->n_stsize == 16) {
+					printf("\tmovl 12(%%esi),%%ecx\n");
+					printf("\tmovl %%ecx,12(%%edi)\n");
+				}
+			} else {
+				if (p->n_stsize > 4) {
+					printf("\tmovl $%d,%%ecx\n",
+					    p->n_stsize >> 2);
+					printf("	rep movsl\n");
+				}
+				if (p->n_stsize & 2)
+					printf("	movsw\n");
+				if (p->n_stsize & 1)
+					printf("	movsb\n");
+			}
+			break;
+		}
+		break;
+
+	case 'S': /* emit eventual move after cast from longlong */
+		pr = DECRA(p->n_reg, 0);
+		lr = p->n_left->n_rval;
+		switch (p->n_type) {
+		case CHAR:
+		case UCHAR:
+			if (rnames[pr][2] == 'l' && rnames[lr][2] == 'x' &&
+			    rnames[pr][1] == rnames[lr][1])
+				break;
+			if (rnames[lr][2] == 'x') {
+				printf("\tmovb %%%cl,%s\n",
+				    rnames[lr][1], rnames[pr]);
+				break;
+			}
+			/* Must go via stack */
+			s = BITOOR(freetemp(1));
+			printf("\tmovl %%e%ci,%d(%%ebp)\n", rnames[lr][1], s);
+			printf("\tmovb %d(%%ebp),%s\n", s, rnames[pr]);
+//			comperr("SCONV1 %s->%s", rnames[lr], rnames[pr]);
+			break;
+
+		case SHORT:
+		case USHORT:
+			if (rnames[lr][1] == rnames[pr][2] &&
+			    rnames[lr][2] == rnames[pr][3])
+				break;
+			printf("\tmovw %%%c%c,%%%s\n",
+			    rnames[lr][1], rnames[lr][2], rnames[pr]+2);
+			break;
+		case INT:
+		case UNSIGNED:
+			if (rnames[lr][1] == rnames[pr][2] &&
+			    rnames[lr][2] == rnames[pr][3])
+				break;
+			printf("\tmovl %%e%c%c,%s\n",
+				    rnames[lr][1], rnames[lr][2], rnames[pr]);
+			break;
+
+		default:
+			if (rnames[lr][1] == rnames[pr][2] &&
+			    rnames[lr][2] == rnames[pr][3])
+				break;
+			comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]);
+			break;
+		}
+		break;
+
+	default:
+		comperr("zzzcode %c", c);
+	}
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+	return(1);
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+	int o = p->n_op;
+
+	if (o==NAME || o==REG || o==ICON || o==OREG ||
+	    (o==UMUL && shumul(p->n_left, 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 = (int)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)
+{
+
+	if (p->n_op == FLD)
+		p = p->n_left;
+
+	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,4)", 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] && 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;
+	case LS:
+	case RS:
+		if (p->n_type != LONGLONG && p->n_type != ULONGLONG)
+			break;
+		if (p->n_right->n_op == ICON) /* constants must be char */
+			p->n_right->n_type = CHAR;
+		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;
+	}
+}
+
+static void
+outfargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c)
+{
+	struct interpass *ip2;
+	NODE *q, *r;
+	int i;
+
+	for (i = 0; i < num; i++)
+		if (XASMVAL(cwp[i]) == c && (cwp[i] & (XASMASG|XASMINOUT)))
+			break;
+	if (i == num)
+		return;
+	q = ary[i]->n_left;
+	r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type);
+	ary[i]->n_left = tcopy(r);
+	ip2 = ipnode(mkbinode(ASSIGN, q, r, q->n_type));
+	DLIST_INSERT_AFTER(ip, ip2, qelem);
+}
+
+static void
+infargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c)
+{
+	struct interpass *ip2;
+	NODE *q, *r;
+	int i;
+
+	for (i = 0; i < num; i++)
+		if (XASMVAL(cwp[i]) == c && (cwp[i] & XASMASG) == 0)
+			break;
+	if (i == num)
+		return;
+	q = ary[i]->n_left;
+	q = (cwp[i] & XASMINOUT) ? tcopy(q) : q;
+	r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type);
+	if ((cwp[i] & XASMINOUT) == 0)
+		ary[i]->n_left = tcopy(r);
+	ip2 = ipnode(mkbinode(ASSIGN, r, q, q->n_type));
+	DLIST_INSERT_BEFORE(ip, ip2, qelem);
+}
+
+/*
+ * Extract float args to XASM and ensure that they are put on the stack
+ * in correct order.
+ * This should be done sow other way.
+ */
+static void
+fixxfloat(struct interpass *ip, NODE *p)
+{
+	NODE *w, **ary;
+	int nn, i, c, *cwp;
+
+	nn = 1;
+	w = p->n_left;
+	if (w->n_op == ICON && w->n_type == STRTY)
+		return;
+	/* index all xasm args first */
+	for (; w->n_op == CM; w = w->n_left)
+		nn++;
+	ary = tmpcalloc(nn * sizeof(NODE *));
+	cwp = tmpcalloc(nn * sizeof(int));
+	for (i = 0, w = p->n_left; w->n_op == CM; w = w->n_left) {
+		ary[i] = w->n_right;
+		cwp[i] = xasmcode(ary[i]->n_name);
+		i++;
+	}
+	ary[i] = w;
+	cwp[i] = xasmcode(ary[i]->n_name);
+	for (i = 0; i < nn; i++)
+		if (XASMVAL(cwp[i]) == 't' || XASMVAL(cwp[i]) == 'u')
+			break;
+	if (i == nn)
+		return;
+
+	for (i = 0; i < nn; i++) {
+		c = XASMVAL(cwp[i]);
+		if (c >= '0' && c <= '9')
+			cwp[i] = (cwp[i] & ~0377) | XASMVAL(cwp[c-'0']);
+	}
+	infargs(ip, ary, nn, cwp, 'u');
+	infargs(ip, ary, nn, cwp, 't');
+	outfargs(ip, ary, nn, cwp, 't');
+	outfargs(ip, ary, nn, cwp, 'u');
+}
+
+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 (ip->ip_node->n_op == XASM)
+			fixxfloat(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)
+{
+}
+
+static char rl[] =
+  { EAX, EAX, EAX, EAX, EAX, EDX, EDX, EDX, EDX, ECX, ECX, ECX, EBX, EBX, ESI };
+static char rh[] =
+  { EDX, ECX, EBX, ESI, EDI, ECX, EBX, ESI, EDI, EBX, ESI, EDI, ESI, EDI, EDI };
+
+void
+rmove(int s, int d, TWORD t)
+{
+	int sl, sh, dl, dh;
+
+	switch (t) {
+	case LONGLONG:
+	case ULONGLONG:
+#if 1
+		sl = rl[s-EAXEDX];
+		sh = rh[s-EAXEDX];
+		dl = rl[d-EAXEDX];
+		dh = rh[d-EAXEDX];
+
+		/* sanity checks, remove when satisfied */
+		if (memcmp(rnames[s], rnames[sl]+1, 3) != 0 ||
+		    memcmp(rnames[s]+3, rnames[sh]+1, 3) != 0)
+			comperr("rmove source error");
+		if (memcmp(rnames[d], rnames[dl]+1, 3) != 0 ||
+		    memcmp(rnames[d]+3, rnames[dh]+1, 3) != 0)
+			comperr("rmove dest error");
+#define	SW(x,y) { int i = x; x = y; y = i; }
+		if (sh == dl) {
+			/* Swap if overwriting */
+			SW(sl, sh);
+			SW(dl, dh);
+		}
+		if (sl != dl)
+			printf("	movl %s,%s\n", rnames[sl], rnames[dl]);
+		if (sh != dh)
+			printf("	movl %s,%s\n", rnames[sh], rnames[dh]);
+#else
+		if (memcmp(rnames[s], rnames[d], 3) != 0)
+			printf("	movl %%%c%c%c,%%%c%c%c\n",
+			    rnames[s][0],rnames[s][1],rnames[s][2],
+			    rnames[d][0],rnames[d][1],rnames[d][2]);
+		if (memcmp(&rnames[s][3], &rnames[d][3], 3) != 0)
+			printf("	movl %%%c%c%c,%%%c%c%c\n",
+			    rnames[s][3],rnames[s][4],rnames[s][5],
+			    rnames[d][3],rnames[d][4],rnames[d][5]);
+#endif
+		break;
+	case CHAR:
+	case UCHAR:
+		printf("	movb %s,%s\n", rnames[s], rnames[d]);
+		break;
+	case FLOAT:
+	case DOUBLE:
+	case LDOUBLE:
+#ifdef notdef
+		/* a=b()*c(); will generate this */
+		comperr("bad float rmove: %d %d", s, d);
+#endif
+		break;
+	default:
+		printf("	movl %s,%s\n", rnames[s], rnames[d]);
+	}
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+	int num;
+
+	switch (c) {
+	case CLASSA:
+		num = r[CLASSB] > 4 ? 4 : r[CLASSB];
+		num += 2*r[CLASSC];
+		num += r[CLASSA];
+		return num < 6;
+	case CLASSB:
+		num = r[CLASSA];
+		num += 2*r[CLASSC];
+		num += r[CLASSB];
+		return num < 4;
+	case CLASSC:
+		num = r[CLASSA];
+		num += r[CLASSB] > 4 ? 4 : r[CLASSB];
+		num += 2*r[CLASSC];
+		return num < 5;
+	case CLASSD:
+		return r[CLASSD] < DREGCNT;
+	}
+	return 0; /* XXX gcc */
+}
+
+char *rnames[] = {
+	"%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp",
+	"%al", "%ah", "%dl", "%dh", "%cl", "%ch", "%bl", "%bh",
+	"eaxedx", "eaxecx", "eaxebx", "eaxesi", "eaxedi", "edxecx",
+	"edxebx", "edxesi", "edxedi", "ecxebx", "ecxesi", "ecxedi",
+	"ebxesi", "ebxedi", "esiedi",
+	"%st0", "%st1", "%st2", "%st3", "%st4", "%st5", "%st6", "%st7",
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+	if (t == CHAR || t == UCHAR)
+		return CLASSB;
+	if (t == LONGLONG || t == ULONGLONG)
+		return CLASSC;
+	if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+		return CLASSD;
+	return CLASSA;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+	NODE *op = p;
+	int size = 0;
+
+	p->n_qual = 0;
+	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+		return;
+	for (p = p->n_right; p->n_op == CM; p = p->n_left)
+		size += argsiz(p->n_right);
+	size += argsiz(p);
+#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 */
+}
+
+/*
+ * 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;
+	int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 };
+	NODE *in = 0, *ut = 0;
+	TWORD t;
+	char *w;
+	int reg;
+	int c, cw, v;
+
+	cw = xasmcode(p->n_name);
+	if (cw & (XASMASG|XASMINOUT))
+		ut = p->n_left;
+	if ((cw & XASMASG) == 0)
+		in = p->n_left;
+
+	c = XASMVAL(cw);
+	switch (c) {
+	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':
+	case 'u':
+		p->n_name = tmpstrdup(p->n_name);
+		w = strchr(p->n_name, XASMVAL(cw));
+		*w = 'r'; /* now reg */
+		return 1;
+
+	case 'A': reg = EAXEDX; break;
+	case 'q': {
+		/* Set edges in MYSETXARG */
+		if (p->n_left->n_op == REG || p->n_left->n_op == TEMP)
+			return 1;
+		t = p->n_left->n_type;
+		if (in && ut)
+			in = tcopy(in);
+		p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, 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;
+	}
+
+	case 'I':
+	case 'J':
+	case 'K':
+	case 'L':
+	case 'M':
+	case 'N':
+		if (p->n_left->n_op != ICON)
+			uerror("xasm arg not constant");
+		v = p->n_left->n_lval;
+		if ((c == 'K' && v < -128) ||
+		    (c == 'L' && v != 0xff && v != 0xffff) ||
+		    (c != 'K' && v < 0) ||
+		    (v > Cmax[c-'I']))
+			uerror("xasm val out of range");
+		p->n_name = "i";
+		return 1;
+
+	default:
+		return 0;
+	}
+	/* If there are requested either memory or register, delete memory */
+	w = p->n_name = tmpstrdup(p->n_name);
+	if (*w == '=')
+		w++;
+	*w++ = 'r';
+	*w = 0;
+
+	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;
+
+	if (ary[(int)w[1]-'0'] == 0)
+		p = ary[(int)w[1]-'0'-1]->n_left; /* XXX */
+	else
+		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] = (char)XASMVAL(cw);
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static struct {
+	char *name; int num;
+} xcr[] = {
+	{ "eax", EAX },
+	{ "ebx", EBX },
+	{ "ecx", ECX },
+	{ "edx", EDX },
+	{ "esi", ESI },
+	{ "edi", EDI },
+	{ "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;
+
+	if (strncmp(s, "st", 2) == 0) {
+		int off =0;
+		if (s[2] == '(' && s[4] == ')')
+			off = s[3] - '0';
+		return ESIEDI + 1 + off;
+	}
+
+	for (i = 0; xcr[i].name; i++)
+		if (strcmp(xcr[i].name, s) == 0)
+			return xcr[i].num;
+	return -1;
+}
+
Index: uspace/app/pcc/arch/i386/macdefs.h
===================================================================
--- uspace/app/pcc/arch/i386/macdefs.h	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
+++ uspace/app/pcc/arch/i386/macdefs.h	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
@@ -0,0 +1,374 @@
+/*	$Id: macdefs.h,v 1.77 2011/02/04 15:08:58 ragge Exp $	*/
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ */
+#define makecc(val,i)	lastcon = (lastcon<<8)|((val<<24)>>24);
+
+#define ARGINIT		64	/* # bits above fp where arguments start */
+#define AUTOINIT	0	/* # bits below fp where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR		8
+#define SZBOOL		8
+#define SZINT		32
+#define SZFLOAT		32
+#define SZDOUBLE	64
+#ifdef MACHOABI
+#define SZLDOUBLE	128
+#else
+#define SZLDOUBLE	96
+#endif
+#define SZLONG		32
+#define SZSHORT		16
+#define SZLONGLONG	64
+#define SZPOINT(t)	32
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR		8
+#define ALBOOL		8
+#define ALINT		32
+#define ALFLOAT		32
+#define ALDOUBLE	32
+#ifdef MACHOABI
+#define ALLDOUBLE	128
+#else
+#define ALLDOUBLE	32
+#endif
+#define ALLONG		32
+#define ALLONGLONG	32
+#define ALSHORT		16
+#define ALPOINT		32
+#undef ALSTRUCT		/* Not defined if ELF ABI */
+#define ALSTACK		32 
+#define	ALMAX		128	/* not yet supported type */
+
+/*
+ * 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_INT
+#define	MAX_LONG	MAX_INT
+#define	MAX_ULONG	MAX_UNSIGNED
+#define	MIN_LONGLONG	0x8000000000000000LL
+#define	MAX_LONGLONG	0x7fffffffffffffffLL
+#define	MAX_ULONGLONG	0xffffffffffffffffULL
+
+/* Default char is signed */
+#undef	CHAR_UNSIGNED
+#define	BOOL_TYPE	CHAR	/* what used to store _Bool */
+
+/*
+ * 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 */
+#if defined(ELFABI)
+#define LABFMT	".L%d"		/* format for printing labels */
+#define	STABLBL	".LL%d"		/* format for stab (debugging) labels */
+#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	AUTOREG	EBP
+#define	ARGREG	EBP
+#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 */
+
+#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 */
+#define	CC_DIV_0	/* division by zero is safe in the compiler */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)	((x)&03)
+#define wdal(k)		(BYTEOFF(k)==0)
+#define BITOOR(x)	(x)	/* bit offset to oreg offset XXX die! */
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+#define genfcall(a,b)	gencall(a,b)
+
+#define	szty(t)	(((t) == DOUBLE || (t) == FLOAT || \
+	(t) == LONGLONG || (t) == ULONGLONG) ? 2 : (t) == LDOUBLE ? 3 : 1)
+
+/*
+ * The x86 has a bunch of register classes, most of them interfering
+ * with each other.  All registers are given a sequential number to
+ * identify it which must match rnames[] in local2.c.
+ * Class membership and overlaps are defined in the macros RSTATUS
+ * and ROVERLAP below.
+ *
+ * The classes used on x86 are:
+ *	A - short and int regs
+ *	B - char regs
+ *	C - long long regs
+ *	D - floating point
+ */
+#define	EAX	000	/* Scratch and return register */
+#define	EDX	001	/* Scratch and secondary return register */
+#define	ECX	002	/* Scratch (and shift count) register */
+#define	EBX	003	/* GDT pointer or callee-saved temporary register */
+#define	ESI	004	/* Callee-saved temporary register */
+#define	EDI	005	/* Callee-saved temporary register */
+#define	EBP	006	/* Frame pointer */
+#define	ESP	007	/* Stack pointer */
+
+#define	AL	010
+#define	AH	011
+#define	DL	012
+#define	DH	013
+#define	CL	014
+#define	CH	015
+#define	BL	016
+#define	BH	017
+
+#define	EAXEDX	020
+#define	EAXECX	021
+#define	EAXEBX	022
+#define	EAXESI	023
+#define	EAXEDI	024
+#define	EDXECX	025
+#define	EDXEBX	026
+#define	EDXESI	027
+#define	EDXEDI	030
+#define	ECXEBX	031
+#define	ECXESI	032
+#define	ECXEDI	033
+#define	EBXESI	034
+#define	EBXEDI	035
+#define	ESIEDI	036
+
+/* The 8 math registers in class D lacks names */
+
+#define	MAXREGS	047	/* 39 registers */
+
+#define	RSTATUS	\
+	SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG,	\
+	SAREG|PERMREG, SAREG|PERMREG, 0, 0,	 			\
+	SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,		\
+	SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, 	\
+	SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,		\
+	SDREG, SDREG, SDREG, SDREG,  SDREG, SDREG, SDREG, SDREG,
+
+#define	ROVERLAP \
+	/* 8 basic registers */\
+	{ AL, AH, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\
+	{ DL, DH, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\
+	{ CL, CH, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\
+	{ BL, BH, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+	{ EAXESI, EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\
+	{ EAXEDI, EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\
+	{ -1 },\
+	{ -1 },\
+\
+	/* 8 char registers */\
+	{ EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\
+	{ EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\
+	{ EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\
+	{ EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\
+	{ ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\
+	{ ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\
+	{ EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+	{ EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+\
+	/* 15 long-long-emulating registers */\
+	{ EAX, AL, AH, EDX, DL, DH, EAXECX, EAXEBX, EAXESI,	/* eaxedx */\
+	  EAXEDI, EDXECX, EDXEBX, EDXESI, EDXEDI, -1, },\
+	{ EAX, AL, AH, ECX, CL, CH, EAXEDX, EAXEBX, EAXESI,	/* eaxecx */\
+	  EAXEDI, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\
+	{ EAX, AL, AH, EBX, BL, BH, EAXEDX, EAXECX, EAXESI,	/* eaxebx */\
+	  EAXEDI, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+	{ EAX, AL, AH, ESI, EAXEDX, EAXECX, EAXEBX, EAXEDI,	/* eaxesi */\
+	  EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\
+	{ EAX, AL, AH, EDI, EAXEDX, EAXECX, EAXEBX, EAXESI,	/* eaxedi */\
+	  EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\
+	{ EDX, DL, DH, ECX, CL, CH, EAXEDX, EAXECX, EDXEBX,	/* edxecx */\
+	  EDXESI, EDXEDI, ECXEBX, ECXESI, ECXEDI, -1 },\
+	{ EDX, DL, DH, EBX, BL, BH, EAXEDX, EDXECX, EDXESI,	/* edxebx */\
+	  EDXEDI, EAXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\
+	{ EDX, DL, DH, ESI, EAXEDX, EDXECX, EDXEBX, EDXEDI,	/* edxesi */\
+	  EAXESI, ECXESI, EBXESI, ESIEDI, -1 },\
+	{ EDX, DL, DH, EDI, EAXEDX, EDXECX, EDXEBX, EDXESI,	/* edxedi */\
+	  EAXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\
+	{ ECX, CL, CH, EBX, BL, BH, EAXECX, EDXECX, ECXESI,	/* ecxebx */\
+	  ECXEDI, EAXEBX, EDXEBX, EBXESI, EBXEDI, -1 },\
+	{ ECX, CL, CH, ESI, EAXECX, EDXECX, ECXEBX, ECXEDI,	/* ecxesi */\
+	  EAXESI, EDXESI, EBXESI, ESIEDI, -1 },\
+	{ ECX, CL, CH, EDI, EAXECX, EDXECX, ECXEBX, ECXESI,	/* ecxedi */\
+	  EAXEDI, EDXEDI, EBXEDI, ESIEDI, -1 },\
+	{ EBX, BL, BH, ESI, EAXEBX, EDXEBX, ECXEBX, EBXEDI,	/* ebxesi */\
+	  EAXESI, EDXESI, ECXESI, ESIEDI, -1 },\
+	{ EBX, BL, BH, EDI, EAXEBX, EDXEBX, ECXEBX, EBXESI,	/* ebxedi */\
+	  EAXEDI, EDXEDI, ECXEDI, ESIEDI, -1 },\
+	{ ESI, EDI, EAXESI, EDXESI, ECXESI, EBXESI,		/* esiedi */\
+	  EAXEDI, EDXEDI, ECXEDI, EBXEDI, -1 },\
+\
+	/* The fp registers do not overlap with anything */\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },
+
+
+/* Return a register class based on the type of the node */
+#define PCLASS(p) (p->n_type <= UCHAR ? SBREG : \
+		  (p->n_type == LONGLONG || p->n_type == ULONGLONG ? SCREG : \
+		  (p->n_type >= FLOAT && p->n_type <= LDOUBLE ? SDREG : SAREG)))
+
+#define	NUMCLASS 	4	/* highest number of reg classes used */
+
+int COLORMAP(int c, int *r);
+#define	GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : x < 31 ? CLASSC : CLASSD)
+#define DECRA(x,y)	(((x) >> (y*6)) & 63)	/* decode encoded regs */
+#define	ENCRD(x)	(x)		/* Encode dest reg in n_reg */
+#define ENCRA1(x)	((x) << 6)	/* A1 */
+#define ENCRA2(x)	((x) << 12)	/* A2 */
+#define ENCRA(x,y)	((x) << (6+y*6))	/* encode regs in int */
+/* XXX - return char in al? */
+#define	RETREG(x)	(x == CHAR || x == UCHAR ? AL : \
+			 x == LONGLONG || x == ULONGLONG ? EAXEDX : \
+			 x == FLOAT || x == DOUBLE || x == LDOUBLE ? 31 : EAX)
+
+#if 0
+#define R2REGS	1	/* permit double indexing */
+#endif
+
+/* XXX - to die */
+#define FPREG	EBP	/* frame pointer */
+#define STKREG	ESP	/* 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 SSTDCALL	SLOCAL2	
+#define SDLLINDIRECT	SLOCAL3
+
+/*
+ * i386-specific node flags.
+ */
+#define FSTDCALL	NLOCAL1
+#define FFPPOP		NLOCAL2
+
+/*
+ * 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)
+#define	MYSETXARG if (XASMVAL(cw) == 'q') {	\
+	c = 'r'; addalledges(&ablock[ESI]); addalledges(&ablock[EDI]); }
+
+/*
+ * builtins.
+ */
+#define TARGET_BUILTINS							\
+	{ "__builtin_frame_address", i386_builtin_frame_address, -1 },	\
+	{ "__builtin_return_address", i386_builtin_return_address, -1 },
+
+#define NODE struct node
+struct node;
+NODE *i386_builtin_frame_address(NODE *f, NODE *a, unsigned int);
+NODE *i386_builtin_return_address(NODE *f, NODE *a, unsigned int);
+#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: uspace/app/pcc/arch/i386/order.c
===================================================================
--- uspace/app/pcc/arch/i386/order.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
+++ uspace/app/pcc/arch/i386/order.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
@@ -0,0 +1,313 @@
+/*	$Id: order.c,v 1.59 2011/01/29 09:55:29 ragge Exp $	*/
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+	return(0);  /* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ * Be careful about register classes, this is a place where classes change.
+ */
+void
+offstar(NODE *p, int shape)
+{
+	NODE *r;
+
+	if (x2debug)
+		printf("offstar(%p)\n", p);
+
+	if (isreg(p))
+		return; /* Is already OREG */
+
+	r = p->n_right;
+	if( p->n_op == PLUS || p->n_op == MINUS ){
+		if( r->n_op == ICON ){
+			if (isreg(p->n_left) == 0)
+				(void)geninsn(p->n_left, INAREG);
+			/* Converted in ormake() */
+			return;
+		}
+		if (r->n_op == LS && r->n_right->n_op == ICON &&
+		    r->n_right->n_lval == 2 && p->n_op == PLUS) {
+			if (isreg(p->n_left) == 0)
+				(void)geninsn(p->n_left, INAREG);
+			if (isreg(r->n_left) == 0)
+				(void)geninsn(r->n_left, INAREG);
+			return;
+		}
+	}
+	(void)geninsn(p, INAREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *q)
+{
+	NODE *p, *r;
+
+	if (x2debug)
+		printf("myormake(%p)\n", q);
+
+	p = q->n_left;
+	if (p->n_op == PLUS && (r = p->n_right)->n_op == LS &&
+	    r->n_right->n_op == ICON && r->n_right->n_lval == 2 &&
+	    p->n_left->n_op == REG && r->n_left->n_op == REG) {
+		q->n_op = OREG;
+		q->n_lval = 0;
+		q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0);
+		tfree(p);
+	}
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, 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:
+		{
+			static struct rspecial s[] = {
+				{ NEVER, EDI },
+				{ NRIGHT, ESI }, { NOLEFT, ESI },
+				{ NOLEFT, ECX }, { NORIGHT, ECX },
+				{ NEVER, ECX }, { 0 } };
+			return s;
+		}
+
+	case STARG:
+		{
+			static struct rspecial s[] = {
+				{ NEVER, EAX }, { NEVER, EDX },
+				{ NEVER, ECX }, { 0 } };
+			return s;
+		}
+
+	case SCONV:
+		if ((q->ltype & (TINT|TUNSIGNED|TSHORT|TUSHORT)) && 
+		    q->rtype == (TCHAR|TUCHAR)) {
+			static struct rspecial s[] = { 
+				{ NOLEFT, ESI }, { NOLEFT, EDI }, { 0 } };
+			return s;
+		} else if ((q->ltype & TINT) &&
+		    q->rtype == (TLONGLONG|TULONGLONG)) {
+			static struct rspecial s[] = {
+				{ NLEFT, EAX }, { NRES, EAXEDX },
+				{ NEVER, EAX }, { NEVER, EDX }, { 0 } };
+			return s;
+		} else if (q->ltype == TSHORT &&
+		    q->rtype == (TLONGLONG|TULONGLONG)) {
+			static struct rspecial s[] = {
+				{ NRES, EAXEDX },
+				{ NEVER, EAX }, { NEVER, EDX }, { 0 } };
+			return s;
+		} else if (q->ltype == TCHAR &&
+		    q->rtype == (TLONGLONG|TULONGLONG)) {
+			static struct rspecial s[] = {
+				{ NRES, EAXEDX },
+				{ NEVER, EAX }, { NEVER, EDX }, { 0 } };
+			return s;
+		}
+		break;
+	case DIV:
+		if (q->lshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NEVER, AL }, { NEVER, AH },
+				{ NLEFT, AL }, { NRES, AL },
+				{ NORIGHT, AH }, { NORIGHT, AL }, { 0 } };
+				return s;
+		} else if (q->lshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NEVER, EAX }, { NEVER, EDX },
+				{ NLEFT, EAX }, { NRES, EAX },
+				{ NORIGHT, EDX }, { NORIGHT, EAX }, { 0 } };
+			return s;
+		} else if (q->lshape & SCREG) {
+			static struct rspecial s[] = {
+				{ NEVER, EAX }, { NEVER, EDX },
+				{ NEVER, ECX }, { NRES, EAXEDX }, { 0 } };
+			return s;
+		}
+		break;
+	case MOD:
+		if (q->lshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NEVER, AL }, { NEVER, AH },
+				{ NLEFT, AL }, { NRES, AH },
+				{ NORIGHT, AH }, { NORIGHT, AL }, { 0 } };
+			return s;
+		} else if (q->lshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NEVER, EAX }, { NEVER, EDX },
+				{ NLEFT, EAX }, { NRES, EDX },
+				{ NORIGHT, EDX }, { NORIGHT, EAX }, { 0 } };
+			return s;
+		} else if (q->lshape & SCREG) {
+			static struct rspecial s[] = {
+				{ NEVER, EAX }, { NEVER, EDX },
+				{ NEVER, ECX }, { NRES, EAXEDX }, { 0 } };
+			return s;
+		}
+		break;
+	case MUL:
+		if (q->lshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NEVER, AL }, { NEVER, AH },
+				{ NLEFT, AL }, { NRES, AL }, { 0 } };
+			return s;
+		} else if (q->lshape & SCREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, EAXEDX }, { NRIGHT, ECXESI },
+				{ NEVER, ESI }, { NRES, EAXEDX }, { 0 } };
+			return s;
+		}
+		break;
+	case LS:
+	case RS:
+		if (q->visit & (INAREG|INBREG)) {
+			static struct rspecial s[] = {
+				{ NRIGHT, CL }, { NOLEFT, ECX }, { 0 } };
+			return s;
+		} else if (q->visit & INCREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, EAXEDX }, { NRIGHT, CL },
+				{ NRES, EAXEDX }, { 0 } };
+			return s;
+		}
+		break;
+
+	default:
+		break;
+	}
+	comperr("nspecial entry %d", q - table);
+	return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+	return 0; /* nothing differs on x86 */
+}
+
+/*
+ * 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@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: uspace/app/pcc/arch/i386/table.c
===================================================================
--- uspace/app/pcc/arch/i386/table.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
+++ uspace/app/pcc/arch/i386/table.c	(revision a7de7182d18160e8d93036ebe6875ba02f0d95ee)
@@ -0,0 +1,1643 @@
+/*	$Id: table.c,v 1.128 2011/01/29 09:55:29 ragge Exp $	*/
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+# define TLL TLONGLONG|TULONGLONG
+# define ANYSIGNED TINT|TLONG|TSHORT|TCHAR
+# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TUWORD TUNSIGNED|TULONG
+# define TSWORD TINT|TLONG
+# define TWORD TUWORD|TSWORD
+#define	 SHINT	SAREG	/* short and int */
+#define	 ININT	INAREG
+#define	 SHCH	SBREG	/* shape for char */
+#define	 INCH	INBREG
+#define	 SHLL	SCREG	/* shape for long long */
+#define	 INLL	INCREG
+#define	 SHFL	SDREG	/* shape for float/double */
+#define	 INFL	INDREG	/* shape for float/double */
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are usually not necessary */
+{ PCONV,	INAREG,
+	SAREG,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		0,	RLEFT,
+		"", },
+
+/*
+ * A bunch conversions of integral<->integral types
+ * There are lots of them, first in table conversions to itself
+ * and then conversions from each type to the others.
+ */
+
+/* itself to itself, including pointers */
+
+/* convert (u)char to (u)char. */
+{ SCONV,	INCH,
+	SHCH,	TCHAR|TUCHAR,
+	SHCH,	TCHAR|TUCHAR,
+		0,	RLEFT,
+		"", },
+
+/* convert pointers to int. */
+{ SCONV,	ININT,
+	SHINT,	TPOINT|TWORD,
+	SANY,	TWORD,
+		0,	RLEFT,
+		"", },
+
+/* convert (u)longlong to (u)longlong. */
+{ SCONV,	INLL,
+	SHLL,	TLL,
+	SHLL,	TLL,
+		0,	RLEFT,
+		"", },
+
+/* convert between float/double/long double. */
+{ SCONV,	INFL,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"ZI", },
+
+/* convert pointers to pointers. */
+{ SCONV,	ININT,
+	SHINT,	TPOINT,
+	SANY,	TPOINT,
+		0,	RLEFT,
+		"", },
+
+/* char to something */
+
+/* convert char to (unsigned) short. */
+{ SCONV,	ININT,
+	SBREG|SOREG|SNAME,	TCHAR,
+	SAREG,	TSHORT|TUSHORT,
+		NASL|NAREG,	RESC1,
+		"	movsbw AL,A1\n", },
+
+/* convert unsigned char to (u)short. */
+{ SCONV,	ININT,
+	SHCH|SOREG|SNAME,	TUCHAR,
+	SAREG,	TSHORT|TUSHORT,
+		NASL|NAREG,	RESC1,
+		"	movzbw AL,A1\n", },
+
+/* convert signed char to int (or pointer). */
+{ SCONV,	ININT,
+	SHCH|SOREG|SNAME,	TCHAR,
+	SAREG,	TWORD|TPOINT,
+		NASL|NAREG,	RESC1,
+		"	movsbl AL,A1\n", },
+
+/* convert unsigned char to (u)int. */
+{ SCONV,	ININT,
+	SHCH|SOREG|SNAME,	TUCHAR,
+	SAREG,	TWORD,
+		NASL|NAREG,	RESC1,
+		"	movzbl AL,A1\n", },
+
+/* convert char to (u)long long */
+{ SCONV,	INLL,
+	SHCH|SOREG|SNAME,	TCHAR,
+	SANY,	TLL,
+		NSPECIAL|NCREG|NCSL,	RESC1,
+		"	movsbl AL,%eax\n	cltd\n", },
+
+/* convert unsigned char to (u)long long */
+{ SCONV,	INLL,
+	SHCH|SOREG|SNAME,	TUCHAR,
+	SANY,			TLL,
+		NCREG|NCSL,	RESC1,
+		"	movzbl AL,A1\n	xorl U1,U1\n", },
+
+/* convert char (in register) to double XXX - use NTEMP */
+{ SCONV,	INFL,
+	SHCH|SOREG|SNAME,	TCHAR,
+	SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
+		NAREG|NASL|NDREG,	RESC2,
+		"	movsbl AL,A1\n	pushl A1\n"
+		"	fildl (%esp)\n	addl $4,%esp\n", },
+
+/* convert (u)char (in register) to double XXX - use NTEMP */
+{ SCONV,	INFL,
+	SHCH|SOREG|SNAME,	TUCHAR,
+	SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
+		NAREG|NASL|NDREG,	RESC2,
+		"	movzbl AL,A1\n	pushl A1\n"
+		"	fildl (%esp)\n	addl $4,%esp\n", },
+
+/* short to something */
+
+/* convert short (in memory) to char */
+{ SCONV,	INCH,
+	SNAME|SOREG,	TSHORT|TUSHORT,
+	SHCH,		TCHAR|TUCHAR,
+		NBREG|NBSL,	RESC1,
+		"	movb AL,A1\n", },
+
+/* convert short (in reg) to char. */
+{ SCONV,	INCH,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL|NBREG|NBSL,	RESC1,
+		"ZM", },
+
+/* convert short to (u)int. */
+{ SCONV,	ININT,
+	SAREG|SOREG|SNAME,	TSHORT,
+	SAREG,	TWORD,
+		NASL|NAREG,	RESC1,
+		"	movswl AL,A1\n", },
+
+/* convert unsigned short to (u)int. */
+{ SCONV,	ININT,
+	SAREG|SOREG|SNAME,	TUSHORT,
+	SAREG,	TWORD,
+		NASL|NAREG,	RESC1,
+		"	movzwl AL,A1\n", },
+
+/* convert short to (u)long long */
+{ SCONV,	INLL,
+	SAREG|SOREG|SNAME,	TSHORT,
+	SHLL,			TLL,
+		NSPECIAL|NCREG|NCSL,	RESC1,
+		"	movswl AL,%eax\n	cltd\n", },
+
+/* convert unsigned short to (u)long long */
+{ SCONV,	INLL,
+	SAREG|SOREG|SNAME,	TUSHORT,
+	SHLL,			TLL,
+		NCREG|NCSL,	RESC1,
+		"	movzwl AL,A1\n	xorl U1,U1\n", },
+
+/* convert short (in memory) to float/double */
+{ SCONV,	INFL,
+	SOREG|SNAME,	TSHORT,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NDREG,	RESC1,
+		"	fild AL\n", },
+
+/* convert short (in register) to float/double */
+{ SCONV,	INFL,
+	SAREG,	TSHORT,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NTEMP|NDREG,	RESC1,
+		"	pushw AL\n	fild (%esp)\n	addl $2,%esp\n", },
+
+/* convert unsigned short to double XXX - use NTEMP */
+{ SCONV,	INFL,
+	SAREG|SOREG|SNAME,	TUSHORT,
+	SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
+		NAREG|NASL|NDREG|NTEMP,	RESC2,
+		"	movzwl AL,A1\n	pushl A1\n"
+		"	fildl (%esp)\n	addl $4,%esp\n", },
+
+/* int to something */
+
+/* convert int to char. This is done when register is loaded */
+{ SCONV,	INCH,
+	SAREG,	TWORD|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,
+		"	movl AL,A1\n	xorl U1,U1\n", },
+
+/* convert int (in memory) to double */
+{ SCONV,	INFL,
+	SOREG|SNAME,	TWORD,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NDREG,	RESC1,
+		"	fildl AL\n", },
+
+/* convert int (in register) to double */
+{ SCONV,	INFL,
+	SAREG,	TWORD,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NTEMP|NDREG,	RESC1,
+		"	pushl AL\n	fildl (%esp)\n	addl $4,%esp\n", },
+
+/* long long to something */
+
+/* convert (u)long long to (u)char (mem->reg) */
+{ SCONV,	INCH,
+	SOREG|SNAME,	TLL,
+	SANY,	TCHAR|TUCHAR,
+		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,
+		"	fildq AL\n", },
+
+/* convert long long (in register) to floating */
+{ SCONV,	INFL,
+	SHLL,	TLONGLONG,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NTEMP|NDREG,	RESC1,
+		"	pushl UL\n	pushl AL\n"
+		"	fildq (%esp)\n	addl $8,%esp\n", },
+
+/* convert unsigned long long to floating */
+{ SCONV,	INFL,
+	SCREG,	TULONGLONG,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NDREG,	RESC1,
+		"ZJ", },
+
+/* float to something */
+
+#if 0 /* go via int by adding an extra sconv in clocal() */
+/* convert float/double to (u) char. XXX should use NTEMP here */
+{ SCONV,	INCH,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SHCH,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NBREG,	RESC1,
+		"	subl $4,%esp\n	fistpl (%esp)\n	popl A1\n", },
+
+/* convert float/double to (u) int/short/char. XXX should use NTEMP here */
+{ SCONV,	INCH,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SHCH,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NCREG,	RESC1,
+		"	subl $4,%esp\n	fistpl (%esp)\n	popl A1\n", },
+#endif
+
+/* convert float/double to (u)int. XXX should use NTEMP here */
+{ SCONV,	INAREG,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SAREG,	TWORD,
+		NAREG,	RESC1,
+#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,
+#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.
+ */
+
+{ UCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	call CL\nZC", },
+
+{ CALL,		FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	call CL\nZC", },
+
+{ UCALL,	FOREFF,
+	SCON,	TANY,
+	SAREG,	TWORD|TPOINT,
+		0,	0,
+		"	call CL\nZC", },
+
+{ 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\nZC", },
+
+{ 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\nZC", },
+
+{ 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\nZC", },
+
+{ CALL,	INDREG,
+	SCON,	TANY,
+	SDREG,	TANY,
+		NDREG|NDSL,	RESC1,	/* should be 0 */
+		"	call CL\nZC", },
+
+{ UCALL,	INDREG,
+	SCON,	TANY,
+	SDREG,	TANY,
+		NDREG|NDSL,	RESC1,	/* should be 0 */
+		"	call CL\nZC", },
+
+{ CALL,		FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	call *AL\nZC", },
+
+{ UCALL,	FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	call *AL\nZC", },
+
+{ CALL,		INAREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ UCALL,	INAREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ CALL,		INBREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NBREG|NBSL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ UCALL,	INBREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NBREG|NBSL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ CALL,		INCREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NCREG|NCSL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ UCALL,	INCREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NCREG|NCSL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ CALL,		INDREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NDREG|NDSL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ UCALL,	INDREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NDREG|NDSL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+/* struct return */
+{ USTCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	0,
+		"ZP	call CL\nZC", },
+
+{ USTCALL,	INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"ZP	call CL\nZC", },
+
+{ USTCALL,	INAREG,
+	SNAME|SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"ZP	call *AL\nZC", },
+
+{ STCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	0,
+		"ZP	call CL\nZC", },
+
+{ STCALL,	INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"ZP	call CL\nZC", },
+
+{ STCALL,	INAREG,
+	SNAME|SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"ZP	call *AL\nZC", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+/* Special treatment for long long */
+{ PLUS,		INLL|FOREFF,
+	SHLL,		TLL,
+	SHLL|SNAME|SOREG,	TLL,
+		0,	RLEFT,
+		"	addl AR,AL\n	adcl UR,UL\n", },
+
+{ PLUS,		INLL|FOREFF,
+	SHLL|SNAME|SOREG,	TLL,
+	SHLL|SCON,		TLL,
+		0,	RLEFT,
+		"	addl AR,AL\n	adcl UR,UL\n", },
+
+/* Special treatment for long long  XXX - fix commutative check */
+{ PLUS,		INLL|FOREFF,
+	SHLL|SNAME|SOREG,	TLL,
+	SHLL,			TLL,
+		0,	RRIGHT,
+		"	addl AL,AR\n	adcl UL,UR\n", },
+
+{ PLUS,		INFL,
+	SHFL,		TDOUBLE,
+	SNAME|SOREG,	TDOUBLE,
+		0,	RLEFT,
+		"	faddl AR\n", },
+
+{ PLUS,		INFL|FOREFF,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"	faddp\n", },
+
+{ PLUS,		INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SONE,	TANY,
+		0,	RLEFT,
+		"	incl AL\n", },
+
+{ PLUS,		INAREG|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,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	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,	INLL|FOREFF,
+	SHLL,	TLL,
+	SHLL|SNAME|SOREG,	TLL,
+		0,	RLEFT,
+		"	subl AR,AL\n	sbbl UR,UL\n", },
+
+{ MINUS,	INLL|FOREFF,
+	SHLL|SNAME|SOREG,	TLL,
+	SHLL|SCON,	TLL,
+		0,	RLEFT,
+		"	subl AR,AL\n	sbbl UR,UL\n", },
+
+{ MINUS,	INFL,
+	SHFL,	TDOUBLE,
+	SNAME|SOREG,	TDOUBLE,
+		0,	RLEFT,
+		"	fsubl AR\n", },
+
+{ MINUS,	INFL|FOREFF,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"	fsubZAp\n", },
+
+/* Simple r/m->reg ops */
+/* 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|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,	INAREG|FOREFF|FORCC,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SCON,	TWORD|TPOINT,
+		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,
+	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", },
+
+/* Try use-reg instructions first */
+{ PLUS,		INAREG,
+	SAREG,	TWORD|TPOINT,
+	SCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	leal CR(AL),A1\n", },
+
+{ MINUS,	INAREG,
+	SAREG,	TWORD|TPOINT,
+	SPCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	leal -CR(AL),A1\n", },
+
+
+/*
+ * The next rules handle all shift operators.
+ */
+/* (u)longlong left shift is emulated */
+{ LS,	INCREG,
+	SCREG,	TLL,
+	SHCH,	TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"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|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", },
+
+/* (u)longlong right shift is emulated */
+{ RS,	INCREG,
+	SCREG,	TLL,
+	SHCH,	TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"ZO", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSWORD,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	sarl AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSWORD,
+	SCON,			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,
+	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,	FORCC|FOREFF|INAREG,
+	SAREG,	TWORD|TPOINT,
+	SMIXOR,		TANY,
+		0,	RDEST,
+		"	xorl AL,AL\n", },
+
+{ ASSIGN,	FOREFF,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SCON,		TANY,
+		0,	0,
+		"	movl AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TWORD|TPOINT,
+	SCON,		TANY,
+		0,	RDEST,
+		"	movl AR,AL\n", },
+
+{ ASSIGN,	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,
+	SNAME|SOREG,	TLL,
+	SHLL,		TLL,
+		0,	RDEST,
+		"	movl AR,AL\n	movl UR,UL\n", },
+
+{ ASSIGN,	FOREFF|INLL,
+	SHLL,	TLL,
+	SHLL,	TLL,
+		0,	RDEST,
+		"ZH", },
+
+{ 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"
+		"ZB"
+		"F	movl AR,AD\n"
+		"FZE", },
+
+
+{ ASSIGN,	FOREFF|INCREG,
+	SFLD,	TLL,
+	SCREG,	TLL,
+		NCREG,	RDEST,
+		"ZL", },
+
+
+{ 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,
+		"	fstpt AL\n	fldt AL\n", }, /* XXX */
+
+{ 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,		TPTRTO|TANY,
+		NSPECIAL,	RDEST,
+		"ZQ", },
+
+/*
+ * DIV/MOD/MUL 
+ */
+/* long long div is emulated */
+{ DIV,	INCREG,
+	SCREG|SNAME|SOREG|SCON, TLL,
+	SCREG|SNAME|SOREG|SCON, TLL,
+		NSPECIAL|NCREG|NCSL|NCSR,	RESC1,
+		"ZO", },
+
+{ DIV,	INAREG,
+	SAREG,			TSWORD,
+	SAREG|SNAME|SOREG,	TWORD,
+		NSPECIAL,	RDEST,
+		"	cltd\n	idivl AR\n", },
+
+{ DIV,	INAREG,
+	SAREG,			TUWORD|TPOINT,
+	SAREG|SNAME|SOREG,	TUWORD|TPOINT,
+		NSPECIAL,	RDEST,
+		"	xorl %edx,%edx\n	divl AR\n", },
+
+{ DIV,	INAREG,
+	SAREG,			TUSHORT,
+	SAREG|SNAME|SOREG,	TUSHORT,
+		NSPECIAL,	RDEST,
+		"	xorl %edx,%edx\n	divw AR\n", },
+
+{ DIV,	INCH,
+	SHCH,			TUCHAR,
+	SHCH|SNAME|SOREG,	TUCHAR,
+		NSPECIAL,	RDEST,
+		"	xorb %ah,%ah\n	divb AR\n", },
+
+{ DIV,	INFL,
+	SHFL,		TDOUBLE,
+	SNAME|SOREG,	TDOUBLE,
+		0,	RLEFT,
+		"	fdivl AR\n", },
+
+{ DIV,	INFL,
+	SHFL,		TLDOUBLE|TDOUBLE|TFLOAT,
+	SHFL,		TLDOUBLE|TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"	fdivZAp\n", },
+
+/* (u)longlong mod is emulated */
+{ MOD,	INCREG,
+	SCREG|SNAME|SOREG|SCON, TLL,
+	SCREG|SNAME|SOREG|SCON, TLL,
+		NSPECIAL|NCREG|NCSL|NCSR,	RESC1,
+		"ZO", },
+
+{ MOD,	INAREG,
+	SAREG,			TSWORD,
+	SAREG|SNAME|SOREG,	TSWORD,
+		NAREG|NSPECIAL,	RESC1,
+		"	cltd\n	idivl AR\n", },
+
+{ MOD,	INAREG,
+	SAREG,			TWORD|TPOINT,
+	SAREG|SNAME|SOREG,	TUWORD|TPOINT,
+		NAREG|NSPECIAL,	RESC1,
+		"	xorl %edx,%edx\n	divl AR\n", },
+
+{ MOD,	INAREG,
+	SAREG,			TUSHORT,
+	SAREG|SNAME|SOREG,	TUSHORT,
+		NAREG|NSPECIAL,	RESC1,
+		"	xorl %edx,%edx\n	divw AR\n", },
+
+{ MOD,	INCH,
+	SHCH,			TUCHAR,
+	SHCH|SNAME|SOREG,	TUCHAR,
+		NBREG|NSPECIAL,	RESC1,
+		"	xorb %ah,%ah\n	divb AR\n", },
+
+/* (u)longlong mul is emulated */
+{ MUL,	INCREG,
+	SCREG,	TLL,
+	SCREG,	TLL,
+		NSPECIAL,	RLEFT,
+		"ZO", },
+
+{ MUL,	INAREG,
+	SAREG,				TWORD|TPOINT,
+	SAREG|SNAME|SOREG|SCON,		TWORD|TPOINT,
+		0,	RLEFT,
+		"	imull AR,AL\n", },
+
+{ MUL,	INAREG,
+	SAREG,			TSHORT|TUSHORT,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	imulw AR,AL\n", },
+
+{ MUL,	INCH,
+	SHCH,			TCHAR|TUCHAR,
+	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
+		NSPECIAL,	RDEST,
+		"	imulb AR\n", },
+
+{ MUL,	INFL,
+	SHFL,		TDOUBLE,
+	SNAME|SOREG,	TDOUBLE,
+		0,	RLEFT,
+		"	fmull AR\n", },
+
+{ MUL,	INFL,
+	SHFL,		TLDOUBLE|TDOUBLE|TFLOAT,
+	SHFL,		TLDOUBLE|TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"	fmulp\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL,	INLL,
+	SANY,	TANY,
+	SOREG,	TLL,
+		NCREG,	RESC1,
+		"	movl UL,U1\n	movl AL,A1\n", },
+
+{ UMUL,	INAREG,
+	SANY,	TPOINT|TWORD,
+	SOREG,	TPOINT|TWORD,
+		NAREG|NASL,	RESC1,
+		"	movl AL,A1\n", },
+
+{ UMUL,	INCH,
+	SANY,	TANY,
+	SOREG,	TCHAR|TUCHAR,
+		NBREG|NBSL,	RESC1,
+		"	movb AL,A1\n", },
+
+{ UMUL,	INAREG,
+	SANY,	TANY,
+	SOREG,	TSHORT|TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	movw AL,A1\n", },
+
+{ UMUL,	INFL,
+	SANY,	TANY,
+	SOREG,	TLDOUBLE,
+		NDREG|NDSL,	RESC1,
+		"	fldt AL\n", },
+
+{ UMUL,	INFL,
+	SANY,	TANY,
+	SOREG,	TDOUBLE,
+		NDREG|NDSL,	RESC1,
+		"	fldl AL\n", },
+
+{ UMUL,	INFL,
+	SANY,	TANY,
+	SOREG,	TFLOAT,
+		NDREG|NDSL,	RESC1,
+		"	flds AL\n", },
+
+/*
+ * Logical/branching operators
+ */
+
+/* Comparisions, take care of everything */
+{ OPLOG,	FORCC,
+	SHLL|SOREG|SNAME,	TLL,
+	SHLL,			TLL,
+		0,	0,
+		"ZD", },
+
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME,	TWORD|TPOINT,
+	SCON|SAREG,	TWORD|TPOINT,
+		0, 	RESCC,
+		"	cmpl AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SCON|SAREG,	TWORD|TPOINT,
+	SAREG|SOREG|SNAME,	TWORD|TPOINT,
+		0, 	RESCC,
+		"	cmpl AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME,	TSHORT|TUSHORT,
+	SCON|SAREG,	TANY,
+		0, 	RESCC,
+		"	cmpw AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SBREG|SOREG|SNAME,	TCHAR|TUCHAR,
+	SCON|SBREG,	TANY,
+		0, 	RESCC,
+		"	cmpb AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+		0, 	RNOP,
+		"ZG", },
+
+{ OPLOG,	FORCC,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"diediedie!", },
+
+/* AND/OR/ER/NOT */
+{ AND,	INAREG|FOREFF,
+	SAREG|SOREG|SNAME,	TWORD,
+	SCON|SAREG,		TWORD,
+		0,	RLEFT,
+		"	andl AR,AL\n", },
+
+{ AND,	INCREG|FOREFF,
+	SCREG,			TLL,
+	SCREG|SOREG|SNAME,	TLL,
+		0,	RLEFT,
+		"	andl AR,AL\n	andl UR,UL\n", },
+
+{ AND,	INAREG|FOREFF,
+	SAREG,			TWORD,
+	SAREG|SOREG|SNAME,	TWORD,
+		0,	RLEFT,
+		"	andl AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,  
+	SAREG|SOREG|SNAME,	TSHORT|TUSHORT,
+	SCON|SAREG,		TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	andw AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,  
+	SAREG,			TSHORT|TUSHORT,
+	SAREG|SOREG|SNAME,	TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	andw AR,AL\n", },
+
+{ AND,	INBREG|FOREFF,
+	SBREG|SOREG|SNAME,	TCHAR|TUCHAR,
+	SCON|SBREG,		TCHAR|TUCHAR,
+		0,	RLEFT,
+		"	andb AR,AL\n", },
+
+{ AND,	INBREG|FOREFF,
+	SBREG,			TCHAR|TUCHAR,
+	SBREG|SOREG|SNAME,	TCHAR|TUCHAR,
+		0,	RLEFT,
+		"	andb AR,AL\n", },
+/* AND/OR/ER/NOT */
+
+/*
+ * Jumps.
+ */
+{ GOTO, 	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	jmp LL\n", },
+
+#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,
+	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,	TLL,
+		NCREG,	RESC1,
+		"ZK", },
+
+{ OPLTYPE,	INLL,
+	SANY,	TANY,
+	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,
+		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,
+	SCREG,	TLL,
+		0,	RLEFT,
+		"	negl AL\n	adcl $0,UL\n	negl UL\n", },
+
+{ UMINUS,	INAREG|FOREFF,
+	SAREG,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	negl AL\n", },
+
+{ UMINUS,	INAREG|FOREFF,
+	SAREG,	TSHORT|TUSHORT,
+	SAREG,	TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	negw AL\n", },
+
+{ UMINUS,	INBREG|FOREFF,
+	SBREG,	TCHAR|TUCHAR,
+	SBREG,	TCHAR|TUCHAR,
+		0,	RLEFT,
+		"	negb AL\n", },
+
+{ UMINUS,	INFL|FOREFF,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"	fchs\n", },
+
+{ COMPL,	INCREG,
+	SCREG,	TLL,
+	SANY,	TANY,
+		0,	RLEFT,
+		"	notl AL\n	notl UL\n", },
+
+{ COMPL,	INAREG,
+	SAREG,	TWORD,
+	SANY,	TANY,
+		0,	RLEFT,
+		"	notl AL\n", },
+
+{ COMPL,	INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SANY,	TANY,
+		0,	RLEFT,
+		"	notw AL\n", },
+
+{ COMPL,	INBREG,
+	SBREG,	TCHAR|TUCHAR,
+	SANY,	TANY,
+		0,	RLEFT,
+		"	notb AL\n", },
+
+/*
+ * Arguments to functions.
+ */
+{ FUNARG,	FOREFF,
+	SCON|SCREG|SNAME|SOREG,	TLL,
+	SANY,	TLL,
+		0,	RNULL,
+		"	pushl UL\n	pushl AL\n", },
+
+{ FUNARG,	FOREFF,
+	SCON|SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SANY,	TWORD|TPOINT,
+		0,	RNULL,
+		"	pushl AL\n", },
+
+{ FUNARG,	FOREFF,
+	SCON,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SANY,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		0,	RNULL,
+		"	pushl AL\n", },
+
+{ FUNARG,	FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT,
+	SANY,	TSHORT,
+		NAREG,	0,
+		"	movswl AL,ZN\n	pushl ZN\n", },
+
+{ FUNARG,	FOREFF,
+	SAREG|SNAME|SOREG,	TUSHORT,
+	SANY,	TUSHORT,
+		NAREG,	0,
+		"	movzwl AL,ZN\n	pushl ZN\n", },
+
+{ FUNARG,	FOREFF,
+	SHCH|SNAME|SOREG,	TCHAR,
+	SANY,			TCHAR,
+		NAREG,	0,
+		"	movsbl AL,A1\n	pushl A1\n", },
+
+{ FUNARG,	FOREFF,
+	SHCH|SNAME|SOREG,	TUCHAR,
+	SANY,	TUCHAR,
+		NAREG,	0,
+		"	movzbl AL,A1\n	pushl A1\n", },
+
+{ FUNARG,	FOREFF,
+	SNAME|SOREG,	TDOUBLE,
+	SANY,	TDOUBLE,
+		0,	0,
+		"	pushl UL\n	pushl AL\n", },
+
+{ FUNARG,	FOREFF,
+	SDREG,	TDOUBLE,
+	SANY,		TDOUBLE,
+		0,	0,
+		"	subl $8,%esp\n	fstpl (%esp)\n", },
+
+{ FUNARG,	FOREFF,
+	SNAME|SOREG,	TFLOAT,
+	SANY,		TFLOAT,
+		0,	0,
+		"	pushl AL\n", },
+
+{ FUNARG,	FOREFF,
+	SDREG,	TFLOAT,
+	SANY,		TFLOAT,
+		0,	0,
+		"	subl $4,%esp\n	fstps (%esp)\n", },
+
+{ FUNARG,	FOREFF,
+	SDREG,	TLDOUBLE,
+	SANY,		TLDOUBLE,
+		0,	0,
+		"	subl $12,%esp\n	fstpt (%esp)\n", },
+
+{ STARG,	FOREFF,
+	SAREG|SOREG|SNAME|SCON,	TANY,
+	SANY,	TSTRUCT,
+		NSPECIAL|NAREG,	0,
+		"ZF", },
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	"help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
