Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision e6165bed4794b3ee0af1ee32530fbf6bebde35bf)
+++ uspace/Makefile	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -37,4 +37,8 @@
 	app/blkdump \
 	app/bnchmark \
+	app/cc \
+	app/ccom \
+	app/ccom/mkext \
+	app/cpp \
 	app/edit \
 	app/ext2info \
Index: uspace/app/cc
===================================================================
--- uspace/app/cc	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/cc	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1 @@
+pcc/cc/cc
Index: uspace/app/ccom
===================================================================
--- uspace/app/ccom	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/ccom	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1 @@
+pcc/cc/ccom
Index: uspace/app/cpp
===================================================================
--- uspace/app/cpp	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/cpp	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1 @@
+pcc/cc/cpp
Index: uspace/app/pcc/DATESTAMP
===================================================================
--- uspace/app/pcc/DATESTAMP	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/DATESTAMP	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1 @@
+20110221
Index: uspace/app/pcc/Makefile.in
===================================================================
--- uspace/app/pcc/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,34 @@
+#	$Id: Makefile.in,v 1.6 2008/07/18 14:00:38 gmcgarry Exp $
+#
+# Makefile.in for top-level of pcc.
+#
+
+@SET_MAKE@
+VPATH=@srcdir@
+CC=@CC@
+CFLAGS=@CFLAGS@ @ADD_CFLAGS@
+LDFLAGS=@LDFLAGS@
+CPPFLAGS=@CPPFLAGS@
+YACC=@YACC@
+LEX=@LEX@
+
+SUBDIR=cc
+
+all: ${SUBDIR}
+
+install:
+	cd cc && ${MAKE} install
+
+clean:
+	cd cc && ${MAKE} clean
+
+distclean:
+	cd cc && ${MAKE} distclean
+	cd f77 && ${MAKE} distclean
+	/bin/rm -rf Makefile config.log stamp-h1 config.status \
+	configure.lineno config.h autom4te.cache
+
+${SUBDIR}: nonexistant
+	cd $@ && $(MAKE) all $(MFLAGS)
+
+nonexistant:
Index: uspace/app/pcc/arch/amd64/code.c
===================================================================
--- uspace/app/pcc/arch/amd64/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/amd64/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,973 @@
+/*	$Id: code.c,v 1.49 2011/01/29 14:55:33 ragge Exp $	*/
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * 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"
+
+static int nsse, ngpr, nrsp, rsaoff;
+static int thissse, thisgpr, thisrsp;
+enum { INTEGER = 1, INTMEM, SSE, SSEMEM, X87, STRREG, STRMEM, STRCPX };
+static const int argregsi[] = { RDI, RSI, RDX, RCX, R08, R09 };
+/*
+ * The Register Save Area looks something like this.
+ * It is put first on stack with fixed offsets.
+ * struct {
+ *	long regs[6];
+ *	double xmm[8][2]; // 16 byte in width
+ * };
+ */
+#define	RSASZ		(6*SZLONG+8*2*SZDOUBLE)
+#define	RSALONGOFF(x)	(RSASZ-(x)*SZLONG)
+#define	RSADBLOFF(x)	((8*2*SZDOUBLE)-(x)*SZDOUBLE*2)
+/* va_list */
+#define	VAARGSZ		(SZINT*2+SZPOINT(CHAR)*2)
+#define	VAGPOFF(x)	(x)
+#define	VAFPOFF(x)	(x-SZINT)
+#define	VAOFA(x)	(x-SZINT-SZINT)
+#define	VARSA(x)	(x-SZINT-SZINT-SZPOINT(0))
+
+int lastloc = -1;
+static int stroffset;
+
+static int varneeds;
+#define	NEED_GPNEXT	001
+#define	NEED_FPNEXT	002
+#define	NEED_1REGREF	004
+#define	NEED_2REGREF	010
+#define	NEED_MEMREF	020
+
+static int argtyp(TWORD t, union dimfun *df, struct attr *ap);
+static NODE *movtomem(NODE *p, int off, int reg);
+static NODE *movtoreg(NODE *p, int rno);
+void varattrib(char *name, struct attr *sap);
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+	extern char *nextsect;
+	static char *loctbl[] = { "text", "data", "section .rodata" };
+	extern int tbss;
+	char *name;
+	TWORD t;
+	int s;
+
+	if (sp == NULL) {
+		lastloc = -1;
+		return;
+	}
+	if (kflag) {
+#ifdef MACHOABI
+		loctbl[DATA] = "section .data.rel.rw,\"aw\"";
+		loctbl[RDATA] = "section .data.rel.ro,\"aw\"";
+#else
+		loctbl[DATA] = "section .data.rel.rw,\"aw\",@progbits";
+		loctbl[RDATA] = "section .data.rel.ro,\"aw\",@progbits";
+#endif
+	}
+	t = sp->stype;
+	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+	if ((name = sp->soname) == NULL)
+		name = exname(sp->sname);
+
+	if (sp->sflags & STLS) {
+		if (s != DATA)
+			cerror("non-data symbol in tls section");
+		if (tbss)
+			nextsect = ".tbss,\"awT\",@nobits";
+		else
+			nextsect = ".tdata,\"awT\",@progbits";
+		tbss = 0;
+		lastloc = -1;
+	}
+
+	varattrib(name, sp->sap);
+
+	if (nextsect) {
+		printf("	.section %s\n", nextsect);
+		nextsect = NULL;
+		s = -1;
+	} else if (s != lastloc)
+		printf("	.%s\n", loctbl[s]);
+	lastloc = s;
+	while (ISARY(t))
+		t = DECREF(t);
+	s = ISFTN(t) ? ALINT : talign(t, sp->sap);
+	if (s > ALCHAR)
+		printf("	.align %d\n", s/ALCHAR);
+	if (sp->sclass == EXTDEF) {
+		printf("\t.globl %s\n", name);
+#ifndef MACHOABI
+		printf("\t.type %s,@%s\n", name,
+		    ISFTN(t)? "function" : "object");
+#endif
+	}
+	if (sp->slevel == 0)
+		printf("%s:\n", name);
+	else
+		printf(LABFMT ":\n", sp->soffset);
+}
+
+/*
+ * Print out variable attributes.
+ */
+void
+varattrib(char *name, struct attr *sap)
+{
+	extern char *nextsect;
+	struct attr *ga;
+
+	if ((ga = attr_find(sap, GCC_ATYP_SECTION)) != NULL)
+		nextsect = ga->sarg(0);
+	if ((ga = attr_find(sap, GCC_ATYP_WEAK)) != NULL)
+		printf("	.weak %s\n", name);
+	if (attr_find(sap, GCC_ATYP_DESTRUCTOR)) {
+		printf("\t.section\t.dtors,\"aw\",@progbits\n");
+		printf("\t.align 8\n\t.quad\t%s\n", name);
+		lastloc = -1;
+	}
+	if (attr_find(sap, GCC_ATYP_CONSTRUCTOR)) {
+		printf("\t.section\t.ctors,\"aw\",@progbits\n");
+		printf("\t.align 8\n\t.quad\t%s\n", name);
+		lastloc = -1;
+	}
+	if ((ga = attr_find(sap, GCC_ATYP_VISIBILITY)) &&
+	    strcmp(ga->sarg(0), "default"))
+		printf("\t.%s %s\n", ga->sarg(0), name);
+	if ((ga = attr_find(sap, GCC_ATYP_ALIASWEAK))) {
+		printf("	.weak %s\n", ga->sarg(0));
+		printf("	.set %s,%s\n", ga->sarg(0), name);
+	}
+}
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ * The return value is in (or pointed to by) RETREG.
+ */
+void
+efcode()
+{
+	struct symtab *sp;
+	extern int gotnr;
+	TWORD t;
+	NODE *p, *r, *l;
+	int typ, ssz, rno;
+
+	gotnr = 0;	/* new number for next fun */
+	sp = cftnsp;
+	t = DECREF(sp->stype);
+	if (t != STRTY && t != UNIONTY)
+		return;
+
+	/* XXX should have one routine for this */
+	if ((typ = argtyp(t, sp->sdf, sp->sap)) == STRREG || typ == STRCPX) {
+		/* Cast to long pointer and move to the registers */
+		/* XXX can overrun struct size */
+		/* XXX check carefully for SSE members */
+
+		if ((ssz = tsize(t, sp->sdf, sp->sap)) > SZLONG*2)
+			cerror("efcode1");
+
+		if (typ == STRCPX) {
+			t = DOUBLE;
+			rno = XMM0;
+		} else {
+			t = LONG;
+			rno = RAX;
+		}
+		if (ssz > SZLONG) {
+			p = block(REG, NIL, NIL, INCREF(t), 0, MKAP(t));
+			regno(p) = RAX;
+			p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL);
+			ecomp(movtoreg(p, rno+1));
+		}
+		p = block(REG, NIL, NIL, INCREF(t), 0, MKAP(t));
+		regno(p) = RAX;
+		p = buildtree(UMUL, p, NIL);
+		ecomp(movtoreg(p, rno));
+	} else if (typ == STRMEM) {
+		r = block(REG, NIL, NIL, INCREF(t), sp->sdf, sp->sap);
+		regno(r) = RAX;
+		r = buildtree(UMUL, r, NIL);
+		l = tempnode(stroffset, INCREF(t), sp->sdf, sp->sap);
+		l = buildtree(UMUL, l, NIL);
+		ecomp(buildtree(ASSIGN, l, r));
+		l = block(REG, NIL, NIL, LONG, 0, MKAP(LONG));
+		regno(l) = RAX;
+		r = tempnode(stroffset, LONG, 0, MKAP(LONG));
+		ecomp(buildtree(ASSIGN, l, r));
+	} else
+		cerror("efcode");
+}
+
+/*
+ * 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 **s, int cnt)
+{
+	union arglist *al;
+	struct symtab *sp;
+	NODE *p, *r;
+	TWORD t;
+	int i, rno, typ;
+
+	/* recalculate the arg offset and create TEMP moves */
+	/* Always do this for reg, even if not optimizing, to free arg regs */
+	nsse = ngpr = 0;
+	nrsp = ARGINIT;
+	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+		sp = cftnsp;
+		if (argtyp(DECREF(sp->stype), sp->sdf, sp->sap) == STRMEM) {
+			r = block(REG, NIL, NIL, LONG, 0, MKAP(LONG));
+			regno(r) = argregsi[ngpr++];
+			p = tempnode(0, r->n_type, r->n_df, r->n_ap);
+			stroffset = regno(p);
+			ecomp(buildtree(ASSIGN, p, r));
+		}
+	}
+
+	for (i = 0; i < cnt; i++) {
+		sp = s[i];
+
+		if (sp == NULL)
+			continue; /* XXX when happens this? */
+
+		switch (typ = argtyp(sp->stype, sp->sdf, sp->sap)) {
+		case INTEGER:
+		case SSE:
+			if (typ == SSE)
+				rno = XMM0 + nsse++;
+			else
+				rno = argregsi[ngpr++];
+			r = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->sap);
+			regno(r) = rno;
+			p = tempnode(0, sp->stype, sp->sdf, sp->sap);
+			sp->soffset = regno(p);
+			sp->sflags |= STNODE;
+			ecomp(buildtree(ASSIGN, p, r));
+			break;
+
+		case SSEMEM:
+			sp->soffset = nrsp;
+			nrsp += SZDOUBLE;
+			if (xtemps) {
+				p = tempnode(0, sp->stype, sp->sdf, sp->sap);
+				p = buildtree(ASSIGN, p, nametree(sp));
+				sp->soffset = regno(p->n_left);
+				sp->sflags |= STNODE;
+				ecomp(p);
+			}
+			break;
+
+		case INTMEM:
+			sp->soffset = nrsp;
+			nrsp += SZLONG;
+			if (xtemps) {
+				p = tempnode(0, sp->stype, sp->sdf, sp->sap);
+				p = buildtree(ASSIGN, p, nametree(sp));
+				sp->soffset = regno(p->n_left);
+				sp->sflags |= STNODE;
+				ecomp(p);
+			}
+			break;
+
+		case STRMEM: /* Struct in memory */
+			sp->soffset = nrsp;
+			nrsp += tsize(sp->stype, sp->sdf, sp->sap);
+			break;
+
+		case X87: /* long double args */
+			sp->soffset = nrsp;
+			nrsp += SZLDOUBLE;
+			break;
+
+		case STRCPX:
+		case STRREG: /* Struct in register */
+			/* Allocate space on stack for the struct */
+			/* For simplicity always fetch two longwords */
+			autooff += (2*SZLONG);
+
+			if (typ == STRCPX) {
+				t = DOUBLE;
+				rno = XMM0 + nsse++;
+			} else {
+				t = LONG;
+				rno = argregsi[ngpr++];
+			}
+			r = block(REG, NIL, NIL, t, 0, MKAP(t));
+			regno(r) = rno;
+			ecomp(movtomem(r, -autooff, FPREG));
+
+			if (tsize(sp->stype, sp->sdf, sp->sap) > SZLONG) {
+				r = block(REG, NIL, NIL, t, 0, MKAP(t));
+				regno(r) = (typ == STRCPX ?
+				    XMM0 + nsse++ : argregsi[ngpr++]);
+				ecomp(movtomem(r, -autooff+SZLONG, FPREG));
+			}
+
+			sp->soffset = -autooff;
+			break;
+
+		default:
+			cerror("bfcode: %d", typ);
+		}
+	}
+
+	/* Check if there are varargs */
+	if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL)
+		return; /* no prototype */
+	al = cftnsp->sdf->dfun;
+
+	for (; al->type != TELLIPSIS; al++) {
+		t = al->type;
+		if (t == TNULL)
+			return;
+		if (BTYPE(t) == STRTY || BTYPE(t) == UNIONTY)
+			al++;
+		for (; t > BTMASK; t = DECREF(t))
+			if (ISARY(t) || ISFTN(t))
+				al++;
+	}
+
+	/* fix stack offset */
+	SETOFF(autooff, ALMAX);
+
+	/* Save reg arguments in the reg save area */
+	p = NIL;
+	for (i = ngpr; i < 6; i++) {
+		r = block(REG, NIL, NIL, LONG, 0, MKAP(LONG));
+		regno(r) = argregsi[i];
+		r = movtomem(r, -RSALONGOFF(i)-autooff, FPREG);
+		p = (p == NIL ? r : block(COMOP, p, r, INT, 0, MKAP(INT)));
+	}
+	for (i = nsse; i < 8; i++) {
+		r = block(REG, NIL, NIL, DOUBLE, 0, MKAP(DOUBLE));
+		regno(r) = i + XMM0;
+		r = movtomem(r, -RSADBLOFF(i)-autooff, FPREG);
+		p = (p == NIL ? r : block(COMOP, p, r, INT, 0, MKAP(INT)));
+	}
+	autooff += RSASZ;
+	rsaoff = autooff;
+	thissse = nsse;
+	thisgpr = ngpr;
+	thisrsp = nrsp;
+
+	ecomp(p);
+}
+
+
+/*
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+	SETOFF(autooff, SZINT);
+}
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag )
+{
+	if (flag)
+		return;
+
+#ifdef MACHOAPI
+#define PT(x)
+#else
+#define	PT(x) printf(".type __pcc_" x ",@function\n")
+#endif
+
+	/* printout varargs routines if used */
+	if (varneeds & NEED_GPNEXT) {
+		printf(".text\n.align 4\n");
+		PT("gpnext");
+		printf("__pcc_gpnext:\n");
+		printf("cmpl $48,(%%rdi)\njae 1f\n");
+		printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
+		printf("movq (%%rax),%%rax\naddl $8,(%%rdi)\nret\n");
+		printf("1:movq 8(%%rdi),%%rax\nmovq (%%rax),%%rax\n");
+		printf("addq $8,8(%%rdi)\nret\n");
+	}
+	if (varneeds & NEED_FPNEXT) {
+		printf(".text\n.align 4\n");
+		PT("fpnext");
+		printf("__pcc_fpnext:\n");
+		printf("cmpl $176,4(%%rdi)\njae 1f\n");
+		printf("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
+		printf("movsd (%%rax),%%xmm0\naddl $16,4(%%rdi)\nret\n");
+		printf("1:movq 8(%%rdi),%%rax\nmovsd (%%rax),%%xmm0\n");
+		printf("addq $8,8(%%rdi)\nret\n");
+	}
+	if (varneeds & NEED_1REGREF) {
+		printf(".text\n.align 4\n");
+		PT("1regref");
+		printf("__pcc_1regref:\n");
+		printf("cmpl $48,(%%rdi)\njae 1f\n");
+		printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
+		printf("addl $8,(%%rdi)\nret\n");
+		printf("1:movq 8(%%rdi),%%rax\n");
+		printf("addq $8,8(%%rdi)\nret\n");
+	}
+	if (varneeds & NEED_2REGREF) {
+		printf(".text\n.align 4\n");
+		PT("2regref");
+		printf("__pcc_2regref:\n");
+		printf("cmpl $40,(%%rdi)\njae 1f\n");
+		printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n");
+		printf("addl $16,(%%rdi)\nret\n");
+		printf("1:movq 8(%%rdi),%%rax\n");
+		printf("addq $16,8(%%rdi)\nret\n");
+	}
+	if (varneeds & NEED_MEMREF) {
+		printf(".text\n.align 4\n");
+		PT("memref");
+		printf("__pcc_memref:\n");
+		printf("movq 8(%%rdi),%%rax\n");
+		printf("addq %%rsi,8(%%rdi)\nret\n");
+	}
+		
+
+#define _MKSTR(x) #x
+#define MKSTR(x) _MKSTR(x)
+#define OS MKSTR(TARGOS)
+#ifdef MACHOABI
+	printf("\t.ident \"PCC: %s (%s)\"\n", PACKAGE_STRING, OS);
+#else
+        printf("\t.ident \"PCC: %s (%s)\"\n\t.end\n", PACKAGE_STRING, OS);
+#endif
+}
+
+/*
+ * Varargs stuff:
+ * The ABI says that va_list should be declared as this typedef.
+ * We handcraft it here and then just reference it.
+ *
+ * typedef struct {
+ *	unsigned int gp_offset;
+ *	unsigned int fp_offset;
+ *	void *overflow_arg_area;
+ *	void *reg_save_area;
+ * } __builtin_va_list[1];
+ *
+ * There are a number of asm routines printed out if varargs are used:
+ *	long __pcc_gpnext(va)	- get a gpreg value
+ *	long __pcc_fpnext(va)	- get a fpreg value
+ *	void *__pcc_1regref(va)	- get reference to a onereg struct 
+ *	void *__pcc_2regref(va)	- get reference to a tworeg struct 
+ *	void *__pcc_memref(va,sz)	- get reference to a large struct 
+ */
+
+static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area;
+static char *gpnext, *fpnext, *_1regref, *_2regref, *memref;
+
+void
+bjobcode()
+{
+	struct symtab *sp;
+	struct rstack *rp;
+	NODE *p, *q;
+	char *c;
+
+	gp_offset = addname("gp_offset");
+	fp_offset = addname("fp_offset");
+	overflow_arg_area = addname("overflow_arg_area");
+	reg_save_area = addname("reg_save_area");
+
+	rp = bstruct(NULL, STNAME, NULL);
+	p = block(NAME, NIL, NIL, UNSIGNED, 0, MKAP(UNSIGNED));
+	soumemb(p, gp_offset, 0);
+	soumemb(p, fp_offset, 0);
+	p->n_type = VOID+PTR;
+	p->n_ap = MKAP(VOID);
+	soumemb(p, overflow_arg_area, 0);
+	soumemb(p, reg_save_area, 0);
+	nfree(p);
+	q = dclstruct(rp);
+	c = addname("__builtin_va_list");
+	p = block(LB, bdty(NAME, c), bcon(1), INT, 0, MKAP(INT));
+	p = tymerge(q, p);
+	p->n_sp = lookup(c, 0);
+	defid(p, TYPEDEF);
+	nfree(q);
+	nfree(p);
+
+	/* for the static varargs functions */
+#define	MKN(vn, rn, tp) \
+	{ vn = addname(rn); sp = lookup(vn, SNORMAL); \
+	  sp->sclass = USTATIC; sp->stype = tp; }
+
+	MKN(gpnext, "__pcc_gpnext", FTN|LONG);
+	MKN(fpnext, "__pcc_fpnext", FTN|DOUBLE);
+	MKN(_1regref, "__pcc_1regref", FTN|VOID|(PTR<<TSHIFT));
+	MKN(_2regref, "__pcc_2regref", FTN|VOID|(PTR<<TSHIFT));
+	MKN(memref, "__pcc_memref", FTN|VOID|(PTR<<TSHIFT));
+}
+
+static NODE *
+mkstkref(int off, TWORD typ)
+{
+	NODE *p;
+
+	p = block(REG, NIL, NIL, PTR|typ, 0, MKAP(LONG));
+	regno(p) = FPREG;
+	return buildtree(PLUS, p, bcon(off/SZCHAR));
+}
+
+NODE *
+amd64_builtin_stdarg_start(NODE *f, NODE *a, TWORD t)
+{
+	NODE *p, *r;
+
+	/* use the values from the function header */
+	p = a->n_left;
+	r = buildtree(ASSIGN, structref(ccopy(p), STREF, reg_save_area),
+	    mkstkref(-rsaoff, VOID));
+	r = buildtree(COMOP, r,
+	    buildtree(ASSIGN, structref(ccopy(p), STREF, overflow_arg_area),
+	    mkstkref(thisrsp, VOID)));
+	r = buildtree(COMOP, r,
+	    buildtree(ASSIGN, structref(ccopy(p), STREF, gp_offset),
+	    bcon(thisgpr*(SZLONG/SZCHAR))));
+	r = buildtree(COMOP, r,
+	    buildtree(ASSIGN, structref(ccopy(p), STREF, fp_offset),
+	    bcon(thissse*(SZDOUBLE*2/SZCHAR)+48)));
+
+	tfree(f);
+	tfree(a);
+	return r;
+}
+
+NODE *
+amd64_builtin_va_arg(NODE *f, NODE *a, TWORD t)
+{
+	NODE *ap, *r, *dp;
+
+	ap = a->n_left;
+	dp = a->n_right;
+	if (dp->n_type <= ULONGLONG || ISPTR(dp->n_type) ||
+	    dp->n_type == FLOAT || dp->n_type == DOUBLE) {
+		/* type might be in general register */
+		if (dp->n_type == FLOAT || dp->n_type == DOUBLE) {
+			f->n_sp = lookup(fpnext, SNORMAL);
+			varneeds |= NEED_FPNEXT;
+		} else {
+			f->n_sp = lookup(gpnext, SNORMAL);
+			varneeds |= NEED_GPNEXT;
+		}
+		f->n_type = f->n_sp->stype = INCREF(dp->n_type) + (FTN-PTR);
+		f->n_ap = dp->n_ap;
+		f->n_df = /* dp->n_df */ NULL;
+		f = clocal(f);
+		r = buildtree(CALL, f, ccopy(ap));
+	} else if (ISSOU(dp->n_type) || dp->n_type == LDOUBLE) {
+		/* put a reference directly to the stack */
+		int sz = tsize(dp->n_type, dp->n_df, dp->n_ap);
+		int al = talign(dp->n_type, dp->n_ap);
+		if (al < ALLONG)
+			al = ALLONG;
+		if (sz <= SZLONG*2 && al == ALLONG) {
+			if (sz <= SZLONG) {
+				f->n_sp = lookup(_1regref, SNORMAL);
+				varneeds |= NEED_1REGREF;
+			} else {
+				f->n_sp = lookup(_2regref, SNORMAL);
+				varneeds |= NEED_2REGREF;
+			}
+			f->n_type = f->n_sp->stype;
+			f = clocal(f);
+			r = buildtree(CALL, f, ccopy(ap));
+			r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap);
+			r = buildtree(UMUL, r, NIL);
+		} else {
+			f->n_sp = lookup(memref, SNORMAL);
+			varneeds |= NEED_MEMREF;
+			f->n_type = f->n_sp->stype;
+			f = clocal(f);
+			SETOFF(sz, al);
+			r = buildtree(CALL, f,
+			    buildtree(CM, ccopy(ap), bcon(sz/SZCHAR)));
+			r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap);
+			r = buildtree(UMUL, r, NIL);
+		}
+	} else {
+		uerror("amd64_builtin_va_arg not supported type");
+		goto bad;
+	}
+	tfree(a);
+	return r;
+bad:
+	uerror("bad argument to __builtin_va_arg");
+	return bcon(0);
+}
+
+NODE *
+amd64_builtin_va_end(NODE *f, NODE *a, TWORD t)
+{
+	tfree(f);
+	tfree(a);
+	return bcon(0); /* nothing */
+}
+
+NODE *
+amd64_builtin_va_copy(NODE *f, NODE *a, TWORD t)
+{
+	tfree(f);
+	f = buildtree(ASSIGN, buildtree(UMUL, a->n_left, NIL),
+	    buildtree(UMUL, a->n_right, NIL));
+	nfree(a);
+	return f;
+}
+
+static NODE *
+movtoreg(NODE *p, int rno)
+{
+	NODE *r;
+
+	r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+	regno(r) = rno;
+	return clocal(buildtree(ASSIGN, r, p));
+}  
+
+static NODE *
+movtomem(NODE *p, int off, int reg)
+{
+	struct symtab s;
+	NODE *r, *l;
+
+	s.stype = p->n_type;
+	s.squal = 0;
+	s.sdf = p->n_df;
+	s.sap = p->n_ap;
+	s.soffset = off;
+	s.sclass = AUTO;
+
+	l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+	l->n_lval = 0;
+	regno(l) = reg;
+
+	r = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+	r->n_sp = &s;
+	r = stref(block(STREF, l, r, 0, 0, 0));
+
+	return clocal(buildtree(ASSIGN, r, p));
+}  
+
+
+/*
+ * AMD64 parameter classification.
+ */
+static int
+argtyp(TWORD t, union dimfun *df, struct attr *ap)
+{
+	int cl = 0;
+
+	if (t <= ULONG || ISPTR(t) || t == BOOL) {
+		cl = ngpr < 6 ? INTEGER : INTMEM;
+	} else if (t == FLOAT || t == DOUBLE || t == FIMAG || t == IMAG) {
+		cl = nsse < 8 ? SSE : SSEMEM;
+	} else if (t == LDOUBLE || t == LIMAG) {
+		cl = X87; /* XXX */
+	} else if (t == STRTY || t == UNIONTY) {
+		int sz = tsize(t, df, ap);
+
+		if (sz <= 2*SZLONG && attr_find(ap, ATTR_COMPLEX) != NULL) {
+			cl = nsse < 7 ? STRCPX : STRMEM;
+		} else if (sz > 2*SZLONG || ((sz+SZLONG)/SZLONG)+ngpr > 6 ||
+		    attr_find(ap, GCC_ATYP_PACKED) != NULL)
+			cl = STRMEM;
+		else
+			cl = STRREG;
+	} else
+		cerror("FIXME: classify");
+	return cl;
+}
+
+/*
+ * Do the "hard work" in assigning correct destination for arguments.
+ * Also convert arguments < INT to inte (default argument promotions).
+ * XXX - should be dome elsewhere.
+ */
+static NODE *
+argput(NODE *p)
+{
+	NODE *q;
+	TWORD ty;
+	int typ, r, ssz;
+
+	if (p->n_op == CM) {
+		p->n_left = argput(p->n_left);
+		p->n_right = argput(p->n_right);
+		return p;
+	}
+
+	/* first arg may be struct return pointer */
+	/* XXX - check if varargs; setup al */
+	switch (typ = argtyp(p->n_type, p->n_df, p->n_ap)) {
+	case INTEGER:
+	case SSE:
+		if (typ == SSE)
+			r = XMM0 + nsse++;
+		else
+			r = argregsi[ngpr++];
+		if (p->n_type < INT || p->n_type == BOOL)
+			p = cast(p, INT, 0);
+		p = movtoreg(p, r);
+		break;
+
+	case X87:
+		r = nrsp;
+		nrsp += SZLDOUBLE;
+		p = movtomem(p, r, STKREG);
+		break;
+
+	case SSEMEM:
+		r = nrsp;
+		nrsp += SZDOUBLE;
+		p = movtomem(p, r, STKREG);
+		break;
+
+	case INTMEM:
+		r = nrsp;
+		nrsp += SZLONG;
+		p = movtomem(p, r, STKREG);
+		break;
+
+	case STRCPX:
+	case STRREG: /* Struct in registers */
+		/* Cast to long pointer and move to the registers */
+		/* XXX can overrun struct size */
+		/* XXX check carefully for SSE members */
+		ssz = tsize(p->n_type, p->n_df, p->n_ap);
+
+		if (typ == STRCPX) {
+			ty = DOUBLE;
+			r = XMM0 + nsse++;
+		} else {
+			ty = LONG;
+			r = argregsi[ngpr++];
+		}
+		if (ssz <= SZLONG) {
+			q = cast(p->n_left, INCREF(ty), 0);
+			nfree(p);
+			q = buildtree(UMUL, q, NIL);
+			p = movtoreg(q, r);
+		} else if (ssz <= SZLONG*2) {
+			NODE *ql, *qr;
+
+			qr = cast(ccopy(p->n_left), INCREF(ty), 0);
+			qr = movtoreg(buildtree(UMUL, qr, NIL), r);
+
+			ql = cast(p->n_left, INCREF(ty), 0);
+			ql = buildtree(UMUL, buildtree(PLUS, ql, bcon(1)), NIL);
+			r = (typ == STRCPX ? XMM0 + nsse++ : argregsi[ngpr++]);
+			ql = movtoreg(ql, r);
+
+			nfree(p);
+			p = buildtree(CM, ql, qr);
+		} else
+			cerror("STRREG");
+		break;
+
+	case STRMEM: {
+		struct symtab s;
+		NODE *l, *t;
+
+		q = buildtree(UMUL, p->n_left, NIL);
+
+		s.stype = p->n_type;
+		s.squal = 0;
+		s.sdf = p->n_df;
+		s.sap = p->n_ap;
+		s.soffset = nrsp;
+		s.sclass = AUTO;
+
+		nrsp += tsize(p->n_type, p->n_df, p->n_ap);
+
+		l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+		l->n_lval = 0;
+		regno(l) = STKREG;
+
+		t = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+		t->n_sp = &s;
+		t = stref(block(STREF, l, t, 0, 0, 0));
+
+		t = (buildtree(ASSIGN, t, q));
+		nfree(p);
+		p = t->n_left;
+		nfree(t);
+		break;
+		}
+
+	default:
+		cerror("argument %d", typ);
+	}
+	return p;
+}
+
+/*
+ * Sort arglist so that register assignments ends up last.
+ */
+static int
+argsort(NODE *p)
+{
+	NODE *q, *r;
+	int rv = 0;
+
+	if (p->n_op != CM) {
+		if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
+		    coptype(p->n_right->n_op) != LTYPE) {
+			q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+			r = ccopy(q);
+			p->n_right = buildtree(COMOP,
+			    buildtree(ASSIGN, q, p->n_right), r);
+		}
+		return rv;
+	}
+	if (p->n_right->n_op == CM) {
+		/* fixup for small structs in regs */
+		q = p->n_right->n_left;
+		p->n_right->n_left = p->n_left;
+		p->n_left = p->n_right;
+		p->n_right = q;
+	}
+	if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG &&
+	    coptype(p->n_right->n_right->n_op) != LTYPE) {
+		/* move before everything to avoid reg trashing */
+		q = tempnode(0, p->n_right->n_type,
+		    p->n_right->n_df, p->n_right->n_ap);
+		r = ccopy(q);
+		p->n_right->n_right = buildtree(COMOP,
+		    buildtree(ASSIGN, q, p->n_right->n_right), r);
+	}
+	if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) {
+		if (p->n_left->n_op == CM &&
+		    p->n_left->n_right->n_op == STASG) {
+			q = p->n_left->n_right;
+			p->n_left->n_right = p->n_right;
+			p->n_right = q;
+			rv = 1;
+		} else if (p->n_left->n_op == STASG) {
+			q = p->n_left;
+			p->n_left = p->n_right;
+			p->n_right = q;
+			rv = 1;
+		}
+	}
+	return rv | argsort(p->n_left);
+}
+
+/*
+ * 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)
+{
+	NODE *l, *r;
+	TWORD t;
+
+	nsse = ngpr = nrsp = 0;
+	/* Check if hidden arg needed */
+	/* If so, add it in pass2 */
+	if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY ||
+	    l->n_type == INCREF(FTN)+UNIONTY) {
+		int ssz = tsize(BTYPE(l->n_type), l->n_df, l->n_ap);
+		if (ssz > 2*SZLONG)
+			ngpr++;
+	}
+
+	/* Convert just regs to assign insn's */
+	p->n_right = argput(p->n_right);
+
+	/* Must sort arglist so that STASG ends up first */
+	/* This avoids registers being clobbered */
+	while (argsort(p->n_right))
+		;
+	/* Check if there are varargs */
+	if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) {
+		; /* Need RAX */
+	} else {
+		union arglist *al = l->n_df->dfun;
+
+		for (; al->type != TELLIPSIS; al++) {
+			if ((t = al->type) == TNULL)
+				return p; /* No need */
+			if (BTYPE(t) == STRTY || BTYPE(t) == UNIONTY)
+				al++;
+			for (; t > BTMASK; t = DECREF(t))
+				if (ISARY(t) || ISFTN(t))
+					al++;
+		}
+	}
+
+	/* Always emit number of SSE regs used */
+	l = movtoreg(bcon(nsse), RAX);
+	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));
+	}
+	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/amd64/local.c
===================================================================
--- uspace/app/pcc/arch/amd64/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/amd64/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1266 @@
+/*	$Id: local.c,v 1.41.2.2 2011/03/02 17:40:07 ragge Exp $	*/
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+
+/*	this file contains code which is dependent on the target machine */
+
+/*
+ * Check if a constant is too large for a type.
+ */
+static int
+toolarge(TWORD t, CONSZ con)
+{
+	U_CONSZ ucon = con;
+
+	switch (t) {
+	case ULONG:
+	case LONG:
+	case ULONGLONG:
+	case LONGLONG:
+		break; /* cannot be too large */
+#define	SCHK(i)	case i: if (con > MAX_##i || con < MIN_##i) return 1; break
+#define	UCHK(i)	case i: if (ucon > MAX_##i) return 1; break
+	SCHK(INT);
+	SCHK(SHORT);
+	case BOOL:
+	SCHK(CHAR);
+	UCHK(UNSIGNED);
+	UCHK(USHORT);
+	UCHK(UCHAR);
+	default:
+		cerror("toolarge");
+	}
+	return 0;
+}
+
+#define	IALLOC(sz)	(isinlining ? permalloc(sz) : tmpalloc(sz))
+
+/*
+ * Make a symtab entry for PIC use.
+ */
+static struct symtab *
+picsymtab(char *p, char *s, char *s2)
+{
+	struct symtab *sp = IALLOC(sizeof(struct symtab));
+	size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
+
+	sp->sname = sp->soname = IALLOC(len);
+	strlcpy(sp->soname, p, len);
+	strlcat(sp->soname, s, len);
+	strlcat(sp->soname, s2, len);
+	sp->sclass = EXTERN;
+	sp->sflags = sp->slevel = 0;
+	return sp;
+}
+
+int gotnr; /* tempnum for GOT register */
+int argstacksize;
+static int ininval;
+
+/*
+ * Create a reference for an extern variable or function.
+ */
+static NODE *
+picext(NODE *p)
+{
+	NODE *q;
+	struct symtab *sp;
+	char *c, *g;
+
+	if (p->n_sp->sflags & SBEENHERE)
+		return p;
+
+	c = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname);
+#ifdef notdef
+	g = ISFTN(p->n_sp->stype) ? "@PLT" : "@GOTPCREL";
+#endif
+	g = "@GOTPCREL";
+	sp = picsymtab("", c, g);
+	sp->sflags = SBEENHERE;
+	q = block(NAME, NIL, NIL, INCREF(p->n_type), p->n_df, p->n_ap);
+	q->n_sp = sp;
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+	q->n_sp = sp;
+	nfree(p);
+	return q;
+}
+
+#ifdef notdef
+/*
+ * Create a reference for a static variable.
+ */
+static NODE *
+picstatic(NODE *p)
+{
+	struct symtab *sp;
+	char *c, buf[32];
+
+	if (p->n_sp->slevel > 0)
+		snprintf(c = buf, 32, LABFMT, (int)p->n_sp->soffset);
+	else
+		c = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname;
+	sp = picsymtab("", c, "");
+	sp->sclass = STATIC;
+	sp->stype = p->n_sp->stype;
+	p->n_sp = sp;
+	return p;
+}
+#endif
+
+static NODE *
+cmop(NODE *l, NODE *r)
+{
+	return block(CM, l, r, INT, 0, MKAP(INT));
+}
+
+static NODE *
+mkx(char *s, NODE *p)
+{
+	p = block(XARG, p, NIL, INT, 0, MKAP(INT));
+	p->n_name = s;
+	return p;
+}
+
+static char *
+mk3str(char *s1, char *s2, char *s3)
+{
+	int len = strlen(s1) + strlen(s2) + strlen(s3) + 1;
+	char *sd;
+
+	sd = inlalloc(len);
+	strlcpy(sd, s1, len);
+	strlcat(sd, s2, len);
+	strlcat(sd, s3, len);
+	return sd;
+}
+
+/*
+ * Create a reference for a TLS variable.
+ * This is the "General dynamic" version.
+ */
+static NODE *
+tlspic(NODE *p)
+{
+	NODE *q, *r, *s;
+	char *s1, *s2;
+
+	/*
+	 * .byte   0x66
+	 * leaq x@TLSGD(%rip),%rdi
+	 * .word   0x6666
+	 * rex64
+	 * call __tls_get_addr@PLT
+	 */
+
+	/* Need the .byte stuff around.  Why? */
+	/* Use inline assembler */
+	q = mkx("%rdx", bcon(0));
+	q = cmop(q, mkx("%rcx", bcon(0)));
+	q = cmop(q, mkx("%rsi", bcon(0)));
+	q = cmop(q, mkx("%rdi", bcon(0)));
+	q = cmop(q, mkx("%r8", bcon(0)));
+	q = cmop(q, mkx("%r9", bcon(0)));
+	q = cmop(q, mkx("%r10", bcon(0)));
+	q = cmop(q, mkx("%r11", bcon(0)));
+
+	s = ccopy(r = tempnode(0, INCREF(p->n_type), p->n_df, p->n_ap));
+	r = mkx("=a", r);
+	r = block(XASM, r, q, INT, 0, MKAP(INT));
+
+	/* Create the magic string */
+	s1 = ".byte 0x66\n\tleaq ";
+	s2 = "@TLSGD(%%rip),%%rdi\n"
+	    "\t.word 0x6666\n\trex64\n\tcall __tls_get_addr@PLT";
+	if (p->n_sp->soname == NULL)
+		p->n_sp->soname = p->n_sp->sname;
+	r->n_name = mk3str(s1, p->n_sp->soname, s2);
+
+	r = block(COMOP, r, s, INCREF(p->n_type), p->n_df, p->n_ap);
+	r = buildtree(UMUL, r, NIL);
+	tfree(p);
+	return r;
+}
+
+/*
+ * The "initial exec" tls model.
+ */
+static NODE *
+tlsinitialexec(NODE *p)
+{
+	NODE *q, *r, *s;
+	char *s1, *s2;
+
+	/*
+	 * movq %fs:0,%rax
+	 * addq x@GOTTPOFF(%rip),%rax
+	 */
+
+	q = bcon(0);
+	q->n_type = STRTY;
+
+	s = ccopy(r = tempnode(0, INCREF(p->n_type), p->n_df, p->n_ap));
+	r = mkx("=r", r);
+	r = block(XASM, r, q, INT, 0, MKAP(INT));
+
+	s1 = "movq %%fs:0,%0\n\taddq ";
+	s2 = "@GOTTPOFF(%%rip),%0";
+	if (p->n_sp->soname == NULL)
+		p->n_sp->soname = p->n_sp->sname;
+	r->n_name = mk3str(s1, p->n_sp->soname, s2);
+
+	r = block(COMOP, r, s, INCREF(p->n_type), p->n_df, p->n_ap);
+	r = buildtree(UMUL, r, NIL);
+	tfree(p);
+	return r;
+}
+
+static NODE *
+tlsref(NODE *p)
+{
+	struct symtab *sp = p->n_sp;
+	struct attr *ga;
+	char *c;
+
+	if ((ga = attr_find(sp->sap, GCC_ATYP_TLSMODEL)) != NULL) {
+		c = ga->sarg(0);
+		if (strcmp(c, "initial-exec") == 0)
+			return tlsinitialexec(p);
+		else if (strcmp(c, "global-dynamic") == 0)
+			;
+		else
+			werror("unsupported tls model '%s'", c);
+	}
+	return tlspic(p);
+}
+
+static NODE *
+stkblk(TWORD t)
+{
+	int al, tsz, off, noff;
+	struct attr *bt;
+	NODE *p;
+
+	bt = MKAP(BTYPE(t));
+	al = talign(t, bt);
+	tsz = (int)tsize(t, 0, bt);
+
+	noff = autooff + tsz;
+	SETOFF(noff, al);
+	off = -noff;
+	autooff = noff;
+
+	p = block(REG, NIL, NIL, INCREF(t), 0, bt);
+	p->n_lval = 0;
+	p->n_rval = FPREG;
+	p = buildtree(UMUL, buildtree(PLUS, p, bcon(off/SZLDOUBLE)), NIL);
+	return p;
+}
+
+
+/* clocal() is called to do local transformations on
+ * an expression tree preparitory to its being
+ * written out in intermediate code.
+ *
+ * the major essential job is rewriting the
+ * automatic variables and arguments in terms of
+ * REG and OREG nodes
+ * conversion ops which are not necessary are also clobbered here
+ * in addition, any special features (such as rewriting
+ * exclusive or) are easily handled here as well
+ */
+NODE *
+clocal(NODE *p)
+{
+
+	register struct symtab *q;
+	register NODE *r, *l;
+	register int o;
+	register int m;
+	TWORD t;
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal: %p\n", p);
+		fwalk(p, eprint, 0);
+	}
+#endif
+	switch( o = p->n_op ){
+
+	case NAME:
+		if ((q = p->n_sp) == NULL)
+			return p; /* Nothing to care about */
+
+		switch (q->sclass) {
+
+		case PARAM:
+		case AUTO:
+			/* fake up a structure reference */
+			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+			r->n_lval = 0;
+			r->n_rval = FPREG;
+			p = stref(block(STREF, r, p, 0, 0, 0));
+			break;
+
+		case USTATIC:
+			if (kflag == 0)
+				break;
+			/* FALLTHROUGH */
+		case STATIC:
+#ifdef TLS
+			if (q->sflags & STLS) {
+				p = tlsref(p);
+				break;
+			}
+#endif
+#ifdef notdef
+			if (kflag == 0) {
+				if (q->slevel == 0)
+					break;
+				p->n_lval = 0;
+			} else if (blevel > 0) {
+				if (!ISFTN(q->stype))
+					p = picstatic(p);
+			}
+#endif
+			break;
+
+		case REGISTER:
+			p->n_op = REG;
+			p->n_lval = 0;
+			p->n_rval = q->soffset;
+			break;
+
+		case EXTERN:
+		case EXTDEF:
+			if (q->sflags & STLS) {
+				p = tlsref(p);
+				break;
+			}
+			if (kflag == 0)
+				break;
+			if (blevel > 0)
+				p = picext(p);
+			break;
+		}
+		break;
+
+#if 0
+	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;
+#endif
+
+	case UCALL:
+	case USTCALL:
+		/* For now, always clear eax */
+		l = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		regno(l) = RAX;
+		p->n_right = clocal(buildtree(ASSIGN, l, bcon(0)));
+		p->n_op -= (UCALL-CALL);
+
+		/* FALLTHROUGH */
+	case CALL:
+	case STCALL:
+		if (p->n_type == VOID)
+			break; /* nothing to do */
+		/* have the call at left of a COMOP to avoid arg trashing */
+		if (p->n_type == LDOUBLE) {
+			r = stkblk(LDOUBLE);
+		} else
+			r = tempnode(0, p->n_type, p->n_df, p->n_ap);
+		l = ccopy(r);
+		p = buildtree(COMOP, buildtree(ASSIGN, r, p), l);
+		break;
+
+#ifdef notyet
+	case CBRANCH:
+		l = p->n_left;
+
+		/*
+		 * Remove unnecessary conversion ops.
+		 */
+		if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
+			if (coptype(l->n_op) != BITYPE)
+				break;
+			if (l->n_right->n_op == ICON) {
+				r = l->n_left->n_left;
+				if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
+					break;
+				if (ISPTR(r->n_type))
+					break; /* no opt for pointers */
+				if (toolarge(r->n_type, l->n_right->n_lval))
+					break;
+				/* Type must be correct */
+				t = r->n_type;
+				nfree(l->n_left);
+				l->n_left = r;
+				l->n_type = t;
+				l->n_right->n_type = t;
+			}
+		}
+		break;
+#endif
+
+	case PCONV:
+		/* Remove redundant PCONV's. Be careful */
+		l = p->n_left;
+		if (l->n_op == ICON) {
+			goto delp;
+		}
+		if (l->n_type < LONG) {
+			/* 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 ((l->n_op == REG || l->n_op == TEMP) && ISPTR(l->n_type))
+			goto delp;
+#ifdef notdef
+		/* if conversion to another pointer type, just remove */
+		/* XXX breaks ADDROF NAME */
+		if (p->n_type > BTMASK && l->n_type > BTMASK)
+			goto delp;
+#endif
+		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:
+		/* Special-case shifts */
+		if (p->n_type == LONG && (l = p->n_left)->n_op == LS && 
+		    l->n_type == INT && l->n_right->n_op == ICON) {
+			p->n_left = l->n_left;
+			p = buildtree(LS, p, l->n_right);
+			nfree(l);
+			break;
+		}
+
+		l = p->n_left;
+
+		/* Float conversions may need extra casts */
+		if (p->n_type == FLOAT || p->n_type == DOUBLE ||
+		    p->n_type == LDOUBLE) {
+			if (l->n_type < INT || l->n_type == BOOL) {
+				p->n_left = block(SCONV, l, NIL,
+				    ISUNSIGNED(l->n_type) ? UNSIGNED : INT,
+				    l->n_df, l->n_ap);
+				break;
+			}
+		}
+
+		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 UNSIGNED:
+				l->n_lval = val & 0xffffffff;
+				break;
+			case INT:
+				l->n_lval = (int)val;
+				break;
+			case LONG:
+			case LONGLONG:
+				l->n_lval = (long long)val;
+				break;
+			case ULONG:
+			case ULONGLONG:
+				l->n_lval = val;
+				break;
+			case VOID:
+				break;
+			case LDOUBLE:
+			case DOUBLE:
+			case FLOAT:
+				l->n_op = FCON;
+				l->n_dcon = val;
+				break;
+			default:
+				cerror("unknown type %d", m);
+			}
+			l->n_type = m;
+			l->n_ap = MKAP(m);
+			nfree(p);
+			return l;
+		} else if (l->n_op == FCON) {
+			if (p->n_type == BOOL)
+				l->n_lval = l->n_dcon != 0.0;
+			else
+				l->n_lval = 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));
+		t = p->n_type;
+		if (ISITY(t))
+			t = t - (FIMAG-FLOAT);
+		p->n_left->n_rval = p->n_left->n_type == BOOL ? 
+		    RETREG(CHAR) : RETREG(t);
+		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;
+	}
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal end: %p\n", p);
+		fwalk(p, eprint, 0);
+	}
+#endif
+	return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+	struct symtab *sp, sps;
+	static int dblxor, fltxor;
+
+	if (p->n_op == UMINUS && (p->n_type == FLOAT || p->n_type == DOUBLE)) {
+		/* Store xor code for sign change */
+		if (dblxor == 0) {
+			dblxor = getlab();
+			fltxor = getlab();
+			sps.stype = LDOUBLE;
+			sps.squal = CON >> TSHIFT;
+			sps.sflags = sps.sclass = 0;
+			sps.sname = sps.soname = "";
+			sps.slevel = 1;
+			sps.sap = MKAP(LDOUBLE); /* alignment */
+			sps.soffset = dblxor;
+			defloc(&sps);
+			printf("\t.long 0,0x80000000,0,0\n");
+			printf(LABFMT ":\n", fltxor);
+			printf("\t.long 0x80000000,0,0,0\n");
+		}
+		p->n_label = p->n_type == FLOAT ? fltxor : dblxor;
+		return;
+	}
+	if (p->n_op != FCON)
+		return;
+
+	/* XXX should let float constants follow */
+	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, tsize(sp->stype, sp->sdf, sp->sap), p);
+
+	p->n_op = NAME;
+	p->n_lval = 0;
+	p->n_sp = sp;
+}
+
+/*
+ * Convert ADDROF NAME to ICON?
+ */
+int
+andable(NODE *p)
+{
+	if (ininval)
+		return 1;
+	if (p->n_sp->sclass == STATIC || p->n_sp->sclass == USTATIC)
+		return 0;
+	return 1;
+}
+
+/*
+ * 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 == LDOUBLE)
+		return 0;
+	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, (int)tsize(t, d, ap));
+
+	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));
+	p = buildtree(PLUS, p, bcon(30));
+	p = buildtree(AND, p, xbcon(-16, NULL, LONG));
+
+	/* sub the size from sp */
+	sp = block(REG, NIL, NIL, p->n_type, 0, MKAP(LONG));
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	ecomp(buildtree(MINUSEQ, sp, p));
+
+	/* save the address of sp */
+	sp = block(REG, NIL, NIL, PTR+LONG, 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;
+
+	defloc(sp);
+
+	/* be kind to assemblers and avoid long strings */
+	printf("\t.ascii \"");
+	for (s = str; *s != 0; ) {
+		if (*s++ == '\\') {
+			(void)esccon(&s);
+		}
+		if (s - str > 60) {
+			fwrite(str, 1, s - str, stdout);
+			printf("\"\n\t.ascii \"");
+			str = s;
+		}
+	}
+	fwrite(str, 1, s - str, stdout);
+	printf("\\0\"\n");
+}
+
+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 MACHOABI
+		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))-1)<<1)|1);
+	while (fsz + inbits >= SZCHAR) {
+		inval |= (val << inbits);
+		printf("\t.byte %d\n", inval & 255);
+		fsz -= (SZCHAR - inbits);
+		val >>= (SZCHAR - inbits);
+		inval = inbits = 0;
+	}
+	if (fsz) {
+		inval |= (val << inbits);
+		inbits += fsz;
+	}
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ */
+void
+ninval(CONSZ off, int fsz, NODE *p)
+{
+	union { float f; double d; long double l; int i[3]; } u;
+	struct symtab *q;
+	NODE st, *op = NIL;
+	TWORD t;
+
+	if (coptype(p->n_op) != LTYPE) {
+		ininval = 1;
+		op = p = optim(ccopy(p));
+		ininval = 0;
+	}
+
+	while (p->n_op == PCONV)
+		p = p->n_left;
+
+	t = p->n_type;
+
+	if (kflag && p->n_op == NAME && ISPTR(t) &&
+	    (ISFTN(DECREF(t)) || ISSOU(BTYPE(t)))) {
+		/* functions as initializers will be NAME here */
+		if (op == NIL) {
+			st = *p;
+			p = &st;
+		}
+		p->n_op = ICON;
+	}
+
+	if (t > BTMASK)
+		t = LONG; /* pointer */
+
+	if (p->n_op == COMOP) {
+		NODE *r = p->n_right;
+		tfree(p->n_left);
+		nfree(p);
+		p = r;
+	}
+
+	if (p->n_op != ICON && p->n_op != FCON) {
+fwalk(p, eprint, 0);
+		cerror("ninval: init node not constant");
+	}
+
+	if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != LONG)
+		uerror("element not constant");
+
+	switch (t) {
+	case LONG:
+	case ULONG:
+		printf("\t.quad 0x%llx", 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 = q->sname;
+				/* Never any PIC stuff in static init */
+				if (strchr(name, '@')) {
+					name = tmpstrdup(name);
+					*strchr(name, '@') = 0;
+				}
+				printf("+%s", name);
+			}
+		}
+		printf("\n");
+		break;
+	case INT:
+	case UNSIGNED:
+		printf("\t.long 0x%x\n", (int)p->n_lval & 0xffffffff);
+		break;
+	case SHORT:
+	case USHORT:
+		printf("\t.short 0x%x\n", (int)p->n_lval & 0xffff);
+		break;
+	case BOOL:
+		if (p->n_lval > 1)
+			p->n_lval = p->n_lval != 0;
+		/* FALLTHROUGH */
+	case CHAR:
+	case UCHAR:
+		printf("\t.byte %d\n", (int)p->n_lval & 0xff);
+		break;
+	case LDOUBLE:
+		u.i[2] = 0;
+		u.l = (long double)p->n_dcon;
+#if defined(HOST_BIG_ENDIAN)
+		/* XXX probably broken on most hosts */
+		printf("\t.long\t0x%x,0x%x,0x%x,0\n", u.i[2], u.i[1], u.i[0]);
+#else
+		printf("\t.long\t0x%x,0x%x,0x%x,0\n", u.i[0], u.i[1], u.i[2]);
+#endif
+		break;
+	case DOUBLE:
+		u.d = (double)p->n_dcon;
+#if defined(HOST_BIG_ENDIAN)
+		printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]);
+#else
+		printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+#endif
+		break;
+	case FLOAT:
+		u.f = (float)p->n_dcon;
+		printf("\t.long\t0x%x\n", u.i[0]);
+		break;
+	default:
+		cerror("ninval");
+	}
+	if (op)
+		tfree(op);
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+#ifdef 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 LONGLONG:
+		MODTYPE(type,LONG);
+		break;
+
+	case ULONGLONG:
+		MODTYPE(type,ULONG);
+
+	}
+	return (type);
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+int tbss;
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+	TWORD t;
+	int off;
+	char *name;
+
+	if (sp->sflags & STLS) {
+		if (sp->sclass == EXTERN)
+			sp->sclass = EXTDEF;
+		tbss = 1;
+		for (t = sp->stype; ISARY(t); t = DECREF(t))
+			;
+		if (t == STRTY || t == UNIONTY) {
+			beginit(sp);
+			endinit();
+		} else
+			simpleinit(sp, bcon(0));
+		return;
+	}
+
+	if ((name = sp->soname) == NULL)
+		name = exname(sp->sname);
+	off = tsize(sp->stype, sp->sdf, sp->sap);
+	off = (off+(SZCHAR-1))/SZCHAR;
+#ifdef GCC_COMPAT
+	{
+		struct attr *ga;
+		if ((ga = attr_find(sp->sap, GCC_ATYP_VISIBILITY)) &&
+		    strcmp(ga->sarg(0), "default"))
+			printf("\t.%s %s\n", ga->sarg(0), name);
+	}
+#endif
+	printf("	.%scomm ", sp->sclass == STATIC ? "l" : "");
+	if (sp->slevel == 0) {
+		printf("%s,0%o\n", name, off);
+	} else
+		printf(LABFMT ",0%o\n", sp->soffset, off);
+}
+
+static char *
+section2string(char *name, int len)
+{
+	char *s;
+	int n;
+
+	if (strncmp(name, "link_set", 8) == 0) {
+		const char *postfix = ",\"aw\",@progbits";
+		n = len + strlen(postfix) + 1;
+		s = IALLOC(n);
+		strlcpy(s, name, n);
+		strlcat(s, postfix, n);
+		return s;
+	}
+
+	return newstring(name, len);
+}
+
+char *nextsect;
+static int gottls;
+static char *alias;
+static int constructor;
+static int destructor;
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+	char *a2 = pragtok(NULL);
+
+	if (strcmp(str, "tls") == 0 && a2 == NULL) {
+		gottls = 1;
+		return 1;
+	}
+	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;
+	}
+
+	return 0;
+}
+
+/*
+ * Called when a identifier has been declared.
+ */
+void
+fixdef(struct symtab *sp)
+{
+	struct attr *ga;
+
+	/* may have sanity checks here */
+	if (gottls)
+		sp->sflags |= STLS;
+	gottls = 0;
+
+#ifdef HAVE_WEAKREF
+	/* not many as'es have this directive */
+	if ((ga = gcc_get_attr(sp->sap, GCC_ATYP_WEAKREF)) != NULL) {
+		char *wr = ga->a1.sarg;
+		char *sn = sp->soname ? sp->soname : sp->sname;
+		if (wr == NULL) {
+			if ((ga = gcc_get_attr(sp->sap, GCC_ATYP_ALIAS))) {
+				wr = ga->a1.sarg;
+			}
+		}
+		if (wr == NULL)
+			printf("\t.weak %s\n", sn);
+		else
+			printf("\t.weakref %s,%s\n", sn, wr);
+	} else
+#endif
+	       if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) {
+		char *an = ga->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)) {
+		printf("\t.globl %s\n", exname(sp->soname));
+		printf("%s = ", exname(sp->soname));
+		printf("%s\n", exname(alias));
+		alias = NULL;
+	}
+	if ((constructor || destructor) && (sp->sclass != PARAM)) {
+		NODE *p = talloc();
+
+		p->n_op = NAME;
+		p->n_sp =
+		  (struct symtab *)(constructor ? "constructor" : "destructor");
+		sp->sap = attr_add(sp->sap, gcc_attr_parse(p));
+		constructor = destructor = 0;
+	}
+}
+
+NODE *
+i386_builtin_return_address(NODE *f, NODE *a, TWORD t)
+{
+	int nframes;
+
+	if (a == NULL || a->n_op != ICON)
+		goto bad;
+
+	nframes = a->n_lval;
+
+	tfree(f);
+	tfree(a);
+
+	f = block(REG, NIL, NIL, PTR+VOID, 0, 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 t)
+{
+	int nframes;
+
+	if (a == NULL || a->n_op != ICON)
+		goto bad;
+
+	nframes = a->n_lval;
+
+	tfree(f);
+	tfree(a);
+
+	f = block(REG, NIL, NIL, PTR+VOID, 0, 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);
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
Index: uspace/app/pcc/arch/amd64/local2.c
===================================================================
--- uspace/app/pcc/arch/amd64/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/amd64/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1185 @@
+/*	$Id: local2.c,v 1.41 2011/02/18 16:52:37 ragge Exp $	*/
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * 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>
+
+static int stkpos;
+
+void
+deflab(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+static int regoff[MAXREGS];
+static TWORD ftype;
+char *rbyte[], *rshort[], *rlong[];
+
+/*
+ * Print out the prolog assembler.
+ * addto and regoff are already calculated.
+ */
+static void
+prtprolog(struct interpass_prolog *ipp, int addto)
+{
+	int i;
+
+	/* XXX should look if there is any need to emit this */
+	printf("\tpushq %%rbp\n");
+	printf("\tmovq %%rsp,%%rbp\n");
+	addto = (addto+15) & ~15; /* 16-byte aligned */
+	if (addto)
+		printf("\tsubq $%d,%%rsp\n", addto);
+
+	/* save permanent registers */
+	for (i = 0; i < MAXREGS; i++)
+		if (TESTBIT(ipp->ipp_regs, i))
+			fprintf(stdout, "\tmovq %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 += SZLONG/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 16\n");
+	printf("%s:\n", ipp->ipp_name);
+#endif
+	/*
+	 * We here know what register to save and how much to 
+	 * add to the stack.
+	 */
+	addto = offcalc(ipp);
+	prtprolog(ipp, addto);
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+	int i;
+
+	if (ipp->ipp_ip.ip_lbl == 0)
+		return; /* no code needs to be generated */
+
+	/* return from function code */
+	for (i = 0; i < MAXREGS; i++)
+		if (TESTBIT(ipp->ipp_regs, i))
+			fprintf(stdout, "	movq -%d(%s),%s\n",
+			    regoff[i], rnames[FPREG], rnames[i]);
+
+	/* struct return needs special treatment */
+	if (ftype == STRTY || ftype == UNIONTY) {
+		printf("	movl 8(%%ebp),%%eax\n");
+		printf("	leave\n");
+		printf("	ret $%d\n", 4);
+	} else {
+		printf("	leave\n");
+		printf("	ret\n");
+	}
+#ifndef MACHOABI
+	printf("\t.size %s,.-%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(NODE *p)
+{
+	switch(p->n_type) {
+		case CHAR:
+		case UCHAR:
+			return(1);
+
+		case SHORT:
+		case USHORT:
+			return(SZSHORT/SZCHAR);
+
+		case DOUBLE:
+			return(SZDOUBLE/SZCHAR);
+
+		case INT:
+		case UNSIGNED:
+			return(SZINT/SZCHAR);
+
+		case LONG:
+		case ULONG:
+		case LONGLONG:
+		case ULONGLONG:
+			return SZLONGLONG/SZCHAR;
+
+		default:
+			if (!ISPTR(p->n_type))
+				comperr("tlen type %d not pointer");
+			return SZPOINT(p->n_type)/SZCHAR;
+		}
+}
+
+/*
+ * Compare two floating point numbers.
+ */
+static void
+fcomp(NODE *p)	
+{
+
+	if (p->n_left->n_op != REG)
+		comperr("bad compare %p\n", p);
+	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 */
+	zzzcode(p, 'U');
+}
+
+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)-1))-1)<<1)|1);
+		val <<= UPKFOFF(p->n_rval);
+		if (p->n_type > UNSIGNED)
+			printf("0x%llx", (**cp == 'M' ? val : ~val));
+		else
+			printf("0x%llx", (**cp == 'M' ? val : ~val)&0xffffffff);
+		break;
+	default:
+		comperr("fldexpand");
+	}
+	return 1;
+}
+
+static void
+bfext(NODE *p)
+{
+	int ch = 0, sz = 0;
+
+	if (ISUNSIGNED(p->n_right->n_type))
+		return;
+	switch (p->n_right->n_type) {
+	case CHAR:
+		ch = 'b';
+		sz = 8;
+		break;
+	case SHORT:
+		ch = 'w';
+		sz = 16;
+		break;
+	case INT:
+		ch = 'l';
+		sz = 32;
+		break;
+	case LONG:
+		ch = 'q';
+		sz = 64;
+		break;
+	default:
+		comperr("bfext");
+	}
+
+	sz -= UPKFSZ(p->n_left->n_rval);
+	printf("\tshl%c $%d,", ch, sz);
+	adrput(stdout, getlr(p, 'D'));
+	printf("\n\tsar%c $%d,", ch, sz);
+	adrput(stdout, getlr(p, 'D'));
+	printf("\n");
+}
+
+static void
+stasg(NODE *p)
+{
+	expand(p, INAREG, "	leaq AL,%rdi\n");
+	if (p->n_stsize >= 8)
+		printf("\tmovl $%d,%%ecx\n\trep movsq\n", p->n_stsize >> 3);
+	if (p->n_stsize & 3)
+		printf("\tmovsl\n");
+	if (p->n_stsize & 2)
+		printf("\tmovsw\n");
+	if (p->n_stsize & 1)
+		printf("\tmovsb\n");
+}
+
+#define	E(x)	expand(p, 0, x)
+/*
+ * Generate code to convert an unsigned long to xmm float/double.
+ */
+static void
+ultofd(NODE *p)
+{
+
+	E("	movq AL,A1\n");
+	E("	testq A1,A1\n");
+	E("	js 2f\n");
+	E("	cvtsi2sZfq A1,A3\n");
+	E("	jmp 3f\n");
+	E("2:\n");
+	E("	movq A1,A2\n");
+	E("	shrq A2\n");
+	E("	andq $1,A1\n");
+	E("	orq A1,A2\n");
+	E("	cvtsi2sZfq A2,A3\n");
+	E("	addsZf A3,A3\n");
+	E("3:\n");
+}
+
+/*
+ * Generate code to convert an x87 long double to an unsigned long.
+ * This is ugly :-/
+ */
+static void
+ldtoul(NODE *p)
+{
+	int r;
+
+	r = getlr(p, '1')->n_rval;
+
+	E("	subq $16,%rsp\n");
+	E("	movl $0x5f000000,(%rsp)\n"); /* More than long can have */
+	E("	flds (%rsp)\n");
+	if (p->n_left->n_op == REG) {
+		E("	fxch\n");
+	} else
+		E("	fldt AL\n");
+	E("	fucomi %st(1), %st\n");
+	E("	jae 2f\n");
+
+	E("	fstp %st(1)\n");	 /* Pop huge val from stack */
+	E("	fnstcw (%rsp)\n");	 /* store cw */
+	E("	movw $0x0f3f,4(%rsp)\n");/* round towards 0 */
+	E("	fldcw 4(%rsp)\n");	 /* new cw */
+	E("	fistpll 8(%rsp)\n");	 /* save val */
+	E("	fldcw (%rsp)\n");	 /* fetch old cw */
+	E("	movq 8(%rsp),A1\n");
+
+	E("	jmp 3f\n");
+
+	E("2:\n");
+
+	E("	fsubp %st, %st(1)\n");
+	E("	fnstcw (%rsp)\n");	
+	E("	movw $0x0f3f,4(%rsp)\n");
+	E("	fldcw 4(%rsp)\n");
+	E("	fistpll 8(%rsp)\n");
+	E("	fldcw (%rsp)\n");
+	E("	movabsq $0x8000000000000000,A1\n");
+	E("	xorq 8(%rsp),A1\n");
+
+	E("3:	addq $16,%rsp\n");
+}
+
+/*
+ * Generate code to convert an SSE float/double to an unsigned long.
+ */     
+static void     
+fdtoul(NODE *p) 
+{
+	if (p->n_left->n_type == FLOAT)
+		E("	movabsq $0x5f000000,A1\n");
+	else
+		E("	movabsq $0x43e0000000000000,A1\n");
+	E("	movd A1,A3\n");
+	E("	ucomisZg A3,AL\n");
+	E("	jae 2f\n");
+	E("	cvttsZg2siq AL,A1\n");
+	E("	jmp 3f\n");
+	E("2:\n");
+	E("	subsZg A3,AL\n");
+	E("	cvttsZg2siq AL,A1\n");
+	E("	movabsq $0x8000000000000000,A2\n");
+	E("	xorq A2,A1\n");
+	E("3:\n");
+}
+#undef E
+
+void
+zzzcode(NODE *p, int c)
+{
+	NODE *l;
+	int pr, lr, s;
+	char **rt;
+
+	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': /* ldouble to unsigned long cast */
+		ldtoul(p);
+		break;
+
+	case 'b': /* float/double to unsigned long cast */
+		fdtoul(p);
+		break;
+
+	case 'C':  /* remove from stack after subroutine call */
+		pr = p->n_qual;
+		if (p->n_op == UCALL)
+			return; /* XXX remove ZC from UCALL */
+		if (pr)
+			printf("	addq $%d, %s\n", pr, rnames[RSP]);
+		break;
+
+	case 'E': /* Perform bitfield sign-extension */
+		bfext(p);
+		break;
+
+	case 'F': /* Structure argument */
+		printf("	subq $%d,%%rsp\n", p->n_stsize);
+		printf("	movq %%rsp,%%rsi\n");
+		stasg(p);
+		break;
+
+	case 'G': /* Floating point compare */
+		fcomp(p);
+		break;
+
+	case 'j': /* convert unsigned long to f/d */
+		ultofd(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 == lr)
+			break;
+		printf("	movb %s,%s\n", rbyte[lr], rbyte[pr]);
+		l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
+		break;
+
+	case 'N': /* output long reg name */
+		printf("%s", rlong[getlr(p, '1')->n_rval]);
+		break;
+
+	case 'P': /* Put hidden argument in rdi */
+		printf("\tleaq -%d(%%rbp),%%rdi\n", stkpos);
+		break;
+
+        case 'Q': /* emit struct assign */
+		stasg(p);
+		break;
+
+	case 'R': /* print opname based on right type */
+	case 'L': /* print opname based on left type */
+		switch (getlr(p, c)->n_type) {
+		case CHAR: case UCHAR: s = 'b'; break;
+		case SHORT: case USHORT: s = 'w'; break;
+		case INT: case UNSIGNED: s = 'l'; break;
+		default: s = 'q'; break;
+		printf("%c", s);
+		}
+		break;
+
+	case 'U': { /* output branch insn for ucomi */
+		static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" };
+		if (p->n_op < EQ || p->n_op > GT)
+			comperr("bad fp branch");
+		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");
+		break;
+		}
+
+	case '8': /* special reg name printout (64-bit) */
+	case '1': /* special reg name printout (32-bit) */
+		l = getlr(p, '1');
+		rt = c == '8' ? rnames : rlong;
+		printf("%s", rt[l->n_rval]);
+		break;
+
+	case 'g':
+		p = p->n_left;
+		/* FALLTHROUGH */
+	case 'f': /* float or double */
+		printf("%c", p->n_type == FLOAT ? 's' : 'd');
+		break;
+
+	case 'q': /* int or long */
+		printf("%c", p->n_left->n_type == LONG ? 'q' : ' ');
+		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)
+{
+	long val = p->n_lval;
+
+	switch (p->n_op) {
+	case ICON:
+		if (p->n_name[0] != '\0') {
+			fprintf(fp, "%s", p->n_name);
+			if (val)
+				fprintf(fp, "+%ld", val);
+		} else
+			fprintf(fp, "%ld", 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.
+ * XXX - not needed on amd64
+ */
+void
+upput(NODE *p, int size)
+{
+
+	size /= SZCHAR;
+	switch (p->n_op) {
+	case REG:
+		fprintf(stdout, "%%%s", &rnames[p->n_rval][3]);
+		break;
+
+	case NAME:
+	case OREG:
+		p->n_lval += size;
+		adrput(stdout, p);
+		p->n_lval -= size;
+		break;
+	case ICON:
+		fprintf(stdout, "$" CONFMT, p->n_lval >> 32);
+		break;
+	default:
+		comperr("upput bad op %d size %d", p->n_op, size);
+	}
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+	int r;
+	char **rc;
+	/* 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') {
+			if (p->n_lval != 0)
+				fprintf(io, CONFMT "+", p->n_lval);
+			fprintf(io, "%s(%%rip)", p->n_name);
+		} 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, "%lld", p->n_lval);
+		if (R2TEST(r)) {
+			int r1 = R2UPK1(r);
+			int r2 = R2UPK2(r);
+			int sh = R2UPK3(r);
+
+			fprintf(io, "(%s,%s,%d)", 
+			    r1 == MAXREGS ? "" : rnames[r1],
+			    r2 == MAXREGS ? "" : rnames[r2], sh);
+		} else
+			fprintf(io, "(%s)", rnames[p->n_rval]);
+		return;
+	case ICON:
+#ifdef PCC_DEBUG
+		/* Sanitycheck for PIC, to catch adressable constants */
+		if (kflag && p->n_name[0]) {
+			static int foo;
+
+			if (foo++ == 0) {
+				printf("\nfailing...\n");
+				fwalk(p, e2print, 0);
+				comperr("pass2 conput");
+			}
+		}
+#endif
+		/* addressable value of the constant */
+		fputc('$', io);
+		conput(io, p);
+		return;
+
+	case REG:
+		switch (p->n_type) {
+		case CHAR:
+		case UCHAR:
+			rc = rbyte;
+			break;
+		case SHORT:
+		case USHORT:
+			rc = rshort;
+			break;
+		case INT:
+		case UNSIGNED:
+			rc = rlong;
+			break;
+		default:
+			rc = rnames;
+			break;
+		}
+		fprintf(io, "%s", rc[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;
+	}
+}
+
+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);
+	}
+	if (stkpos > p2autooff)
+		p2autooff = stkpos;
+	if (stkpos > p2maxautooff)
+		p2maxautooff = stkpos;
+	if (x2debug)
+		printip(ipole);
+}
+
+/*
+ * Remove some PCONVs after OREGs are created.
+ */
+static void
+pconv2(NODE *p, void *arg)
+{
+	NODE *q;
+
+	if (p->n_op == PLUS) {
+		if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
+			if (p->n_right->n_op != ICON)
+				return;
+			if (p->n_left->n_op != PCONV)
+				return;
+			if (p->n_left->n_left->n_op != OREG)
+				return;
+			q = p->n_left->n_left;
+			nfree(p->n_left);
+			p->n_left = q;
+			/*
+			 * This will be converted to another OREG later.
+			 */
+		}
+	}
+}
+
+void
+mycanon(NODE *p)
+{
+	walkf(p, pconv2, 0);
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+
+	switch (t) {
+	case INT:
+	case UNSIGNED:
+		printf("	movl %s,%s\n", rlong[s], rlong[d]);
+		break;
+	case CHAR:
+	case UCHAR:
+		printf("	movb %s,%s\n", rbyte[s], rbyte[d]);
+		break;
+	case SHORT:
+	case USHORT:
+		printf("	movw %s,%s\n", rshort[s], rshort[d]);
+		break;
+	case FLOAT:
+		printf("	movss %s,%s\n", rnames[s], rnames[d]);
+		break;
+	case DOUBLE:
+		printf("	movsd %s,%s\n", rnames[s], rnames[d]);
+		break;
+	case LDOUBLE:
+#ifdef notdef
+		/* a=b()*c(); will generate this */
+		/* XXX can it fail anyway? */
+		comperr("bad float rmove: %d %d", s, d);
+#endif
+		break;
+	default:
+		printf("	movq %s,%s\n", rnames[s], rnames[d]);
+		break;
+	}
+}
+
+/*
+ * 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)
+{
+
+	switch (c) {
+	case CLASSA:
+		return r[CLASSA] < 14;
+	case CLASSB:
+		return r[CLASSB] < 16;
+	case CLASSC:
+		return r[CLASSC] < CREGCNT;
+	}
+	return 0; /* XXX gcc */
+}
+
+char *rnames[] = {
+	"%rax", "%rdx", "%rcx", "%rbx", "%rsi", "%rdi", "%rbp", "%rsp",
+	"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+	"%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7",
+	"%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", "%xmm14",
+	"%xmm15",
+};
+
+/* register names for shorter sizes */
+char *rbyte[] = {
+	"%al", "%dl", "%cl", "%bl", "%sil", "%dil", "%bpl", "%spl",
+	"%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b", 
+};
+char *rshort[] = {
+	"%ax", "%dx", "%cx", "%bx", "%si", "%di", "%bp", "%sp",
+	"%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w", 
+};
+char *rlong[] = {
+	"%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp",
+	"%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d", 
+};
+
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+	if (t == LDOUBLE)
+		return CLASSC;
+	if (t == FLOAT || t == DOUBLE)
+		return CLASSB;
+	return CLASSA;
+}
+
+static int
+argsiz(NODE *p)
+{
+	TWORD t = p->n_type;
+
+	if (p->n_left->n_op == REG)
+		return 0; /* not on stack */
+	if (t == LDOUBLE)
+		return 16;
+	if (p->n_op == STASG)
+		return p->n_stsize;
+	return 8;
+}
+
+/*
+ * 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);
+	size = (size+15) & ~15;
+	if (size)
+		printf("	subq $%d,%s\n", size, rnames[RSP]);
+	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;
+	case SCON32:
+		if (o != ICON || p->n_name[0])
+			break;
+		if (p->n_lval < MIN_INT || p->n_lval > MAX_INT)
+			break;
+		return SRDIR;
+	default:
+		cerror("special: %x\n", shape);
+	}
+	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);
+retry:	switch (c) {
+	case 'D': reg = RDI; break;
+	case 'S': reg = RSI; break;
+	case 'A': 
+	case 'a': reg = RAX; break;
+	case 'b': reg = RBX; break;
+	case 'c': reg = RCX; break;
+	case 'd': reg = RDX; break;
+
+	case 'x':
+	case 'q':
+	case 't':
+	case 'u':
+		p->n_name = tmpstrdup(p->n_name);
+		w = strchr(p->n_name, c);
+		*w = 'r'; /* now reg */
+		return c == 'q' || c == 'x' ? 0 : 1;
+
+	case 'I':
+	case 'J':
+	case 'K':
+	case 'L':
+	case 'M':
+	case 'N':
+		if (p->n_left->n_op != ICON) {
+			if ((c = XASMVAL1(cw)))
+				goto retry;
+			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 (t == FLOAT || t == DOUBLE) {
+		p->n_label = CLASSB;
+		reg += 16;
+	} else if (t == LDOUBLE) {
+		p->n_label = CLASSC;
+		reg += 32;
+	} else
+		p->n_label = CLASSA;
+
+	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, int n)
+{
+	NODE **ary = arg;
+	NODE *p, *q;
+
+	if (w[1] < '0' || w[1] > (n + '0'))
+		uerror("bad xasm arg number %c", w[1]);
+	if (w[1] == (n + '0'))
+		p = ary[(int)w[1]-'0' - 1]; /* XXX */
+	else
+		p = ary[(int)w[1]-'0'];
+	p = p->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') {
+			cerror("targarg"); /* XXX ??? */
+			if (q->n_type > UCHAR) {
+				regno(q) = regno(q)*2+8;
+				if (*w == 'h')
+					regno(q)++;
+			}
+			q->n_type = INT;
+		} else
+			q->n_type = SHORT;
+	}
+	adrput(stdout, q);
+	tfree(q);
+}
+
+/*
+ * target-specific conversion of numeric arguments.
+ */
+int
+numconv(void *ip, void *p1, void *q1)
+{
+	NODE *p = p1, *q = q1;
+	int cw = xasmcode(q->n_name);
+
+	switch (XASMVAL(cw)) {
+	case 'a':
+	case 'b':
+	case 'c':
+	case 'd':
+		p->n_name = tmpcalloc(2);
+		p->n_name[0] = XASMVAL(cw);
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static struct {
+	char *name; int num;
+} xcr[] = {
+	{ "rax", RAX },
+	{ "rbx", RBX },
+	{ "rcx", RCX },
+	{ "rdx", RDX },
+	{ "rsi", RSI },
+	{ "rdi", RDI },
+	{ "st", 040 },
+	{ "st(0)", 040 },
+	{ "st(1)", 041 },
+	{ "st(2)", 042 },
+	{ "st(3)", 043 },
+	{ "st(4)", 044 },
+	{ "st(5)", 045 },
+	{ "st(6)", 046 },
+	{ "st(7)", 047 },
+	{ NULL, 0 },
+};
+
+/*
+ * Check for other names of the xasm constraints registers.
+ */
+int xasmconstregs(char *s)
+{
+	int i;
+
+	for (i = 0; xcr[i].name; i++)
+		if (strcmp(xcr[i].name, s) == 0)
+			return xcr[i].num;
+	return -1;
+}
+
Index: uspace/app/pcc/arch/amd64/macdefs.h
===================================================================
--- uspace/app/pcc/arch/amd64/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/amd64/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,286 @@
+/*	$Id: macdefs.h,v 1.17 2011/02/18 17:16:57 ragge Exp $	*/
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * 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		128	/* # bits above fp where arguments start */
+#define AUTOINIT	0	/* # bits below fp where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR		8
+#define SZBOOL		8
+#define SZSHORT		16
+#define SZINT		32
+#define SZLONG		64
+#define SZPOINT(t)	64
+#define SZLONGLONG	64
+#define SZFLOAT		32
+#define SZDOUBLE	64
+#define SZLDOUBLE	128
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR		8
+#define ALBOOL		8
+#define ALSHORT		16
+#define ALINT		32
+#define ALLONG		64
+#define ALPOINT		64
+#define ALLONGLONG	64
+#define ALFLOAT		32
+#define ALDOUBLE	64
+#define ALLDOUBLE	128
+/* #undef ALSTRUCT	amd64 struct alignment is member defined */
+#define ALSTACK		64
+#define ALMAX		128 
+
+/*
+ * Min/max values.
+ */
+#define	MIN_CHAR	-128
+#define	MAX_CHAR	127
+#define	MAX_UCHAR	255
+#define	MIN_SHORT	-32768
+#define	MAX_SHORT	32767
+#define	MAX_USHORT	65535
+#define	MIN_INT		(-0x7fffffff-1)
+#define	MAX_INT		0x7fffffff
+#define	MAX_UNSIGNED	0xffffffffU
+#define	MIN_LONG	0x8000000000000000L
+#define	MAX_LONG	0x7fffffffffffffffL
+#define	MAX_ULONG	0xffffffffffffffffUL
+#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 */
+#define LABFMT	".L%d"		/* format for printing labels */
+#define	STABLBL	".LL%d"		/* format for stab (debugging) labels */
+#ifdef LANG_F77
+#define BLANKCOMMON "_BLNK_"
+#define MSKIREG  (M(TYSHORT)|M(TYLONG))
+#define TYIREG TYLONG
+#define FSZLENG  FSZLONG
+#define	AUTOREG	EBP
+#define	ARGREG	EBP
+#define ARGOFFSET 8
+#endif
+
+#define BACKAUTO 		/* stack grows negatively for automatics */
+#define BACKTEMP 		/* stack grows negatively for temporaries */
+
+#undef	FIELDOPS		/* no bit-field instructions */
+#define	RTOLBYTES		/* bytes are numbered right to left */
+
+#define ENUMSIZE(high,low) INT	/* enums are always stored in full int */
+
+#define FINDMOPS	/* i386 has instructions that modifies memory */
+
+#define	CC_DIV_0	/* division by zero is safe in the compiler */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)	((x)&07)
+#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)
+
+/* How many integer registers are needed? (used for stack allocation) */
+#define	szty(t)	(t < LONG || t == FLOAT ? 1 : t == LDOUBLE ? 4 : 2)
+
+/*
+ * The amd64 architecture has a much cleaner interface to its registers
+ * than the x86, even though a part of the register block comes from 
+ * the x86 architecture.  Therefore currently only two non-overlapping 
+ * register classes are used; integer and xmm registers.
+ *
+ * All registers are given a sequential number to
+ * identify it which must match rnames[] in local2.c.
+ *
+ * The classes used on amd64 are:
+ *	A - integer registers
+ *	B - xmm registers
+ *	C - x87 registers
+ */
+#define	RAX	000
+#define	RDX	001
+#define	RCX	002
+#define	RBX	003
+#define	RSI	004
+#define	RDI	005
+#define	RBP	006
+#define	RSP	007
+#define	R08	010
+#define	R09	011
+#define	R10	012
+#define	R11	013
+#define	R12	014
+#define	R13	015
+#define	R14	016
+#define	R15	017
+
+#define	XMM0	020
+#define	XMM1	021
+#define	XMM2	022
+#define	XMM3	023
+#define	XMM4	024
+#define	XMM5	025
+#define	XMM6	026
+#define	XMM7	027
+#define	XMM8	030
+#define	XMM9	031
+#define	XMM10	032
+#define	XMM11	033
+#define	XMM12	034
+#define	XMM13	035
+#define	XMM14	036
+#define	XMM15	037
+
+#define	MAXREGS	050	/* 40 registers */
+
+#define	RSTATUS	\
+	SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG,	\
+	SAREG|TEMPREG, SAREG|TEMPREG, 0, 0,	 			\
+	SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,	\
+	SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, 	\
+	SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,	\
+	SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,	\
+	SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,	\
+	SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,	\
+	SCREG, SCREG, SCREG, SCREG,  SCREG, SCREG, SCREG, SCREG,
+
+
+/* no overlapping registers at all */
+#define	ROVERLAP \
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+	{ -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 == FLOAT || p->n_type == DOUBLE ? SBREG : \
+		   p->n_type == LDOUBLE ? SCREG : SAREG)
+
+#define	NUMCLASS 	3	/* highest number of reg classes used */
+
+int COLORMAP(int c, int *r);
+#define	GCLASS(x) (x < 16 ? CLASSA : x < 32 ? CLASSB : CLASSC)
+#define DECRA(x,y)	(((x) >> (y*8)) & 255)	/* decode encoded regs */
+#define	ENCRD(x)	(x)		/* Encode dest reg in n_reg */
+#define ENCRA1(x)	((x) << 8)	/* A1 */
+#define ENCRA2(x)	((x) << 16)	/* A2 */
+#define ENCRA(x,y)	((x) << (8+y*8))	/* encode regs in int */
+
+#define	RETREG(x)	(x == FLOAT || x == DOUBLE ? XMM0 : \
+			 x == LDOUBLE ? 32 : RAX)
+
+/* XXX - to die */
+#define FPREG	RBP	/* frame pointer */
+#define STKREG	RSP	/* stack pointer */
+
+#define	SHSTR		(MAXSPECIAL+1)	/* short struct */
+#define	SFUNCALL	(MAXSPECIAL+2)	/* struct assign after function call */
+#define	SPCON		(MAXSPECIAL+3)	/* positive nonnamed constant */
+
+/*
+ * Specials that indicate the applicability of machine idioms.
+ */
+#define SMIXOR		(MAXSPECIAL+4)
+#define SMILWXOR	(MAXSPECIAL+5)
+#define SMIHWXOR	(MAXSPECIAL+6)
+#define SCON32		(MAXSPECIAL+7)	/* 32-bit constant */
+
+/*
+ * i386-specific symbol table flags.
+ */
+#define SBEENHERE	SLOCAL1
+#define	STLS		SLOCAL2
+
+/*
+ * Extended assembler macros.
+ */
+int xasmconstregs(char *);
+void targarg(char *w, void *arg, int n);
+#define	XASM_TARGARG(w, ary)	\
+	(w[1] == 'b' || w[1] == 'h' || w[1] == 'w' || w[1] == 'k' ? \
+	w++, targarg(w, ary, n), 1 : 0)
+int numconv(void *ip, void *p, void *q);
+#define	XASM_NUMCONV(ip, p, q)	numconv(ip, p, q)
+#define	XASMCONSTREGS(x)	xasmconstregs(x)
+
+/*
+ * builtins.
+ */
+#define TARGET_VALIST
+#define TARGET_STDARGS
+#define TARGET_BUILTINS							\
+	{ "__builtin_stdarg_start", amd64_builtin_stdarg_start, 2 },	\
+	{ "__builtin_va_start", amd64_builtin_stdarg_start, 2 },	\
+	{ "__builtin_va_arg", amd64_builtin_va_arg, 2 },		\
+	{ "__builtin_va_end", amd64_builtin_va_end, 1 },		\
+	{ "__builtin_va_copy", amd64_builtin_va_copy, 2 },		\
+	{ "__builtin_frame_address", i386_builtin_frame_address, -1 },	\
+	{ "__builtin_return_address", i386_builtin_return_address, -1 },
+
+#define NODE struct node
+struct node;
+NODE *amd64_builtin_stdarg_start(NODE *f, NODE *a, unsigned int);
+NODE *amd64_builtin_va_arg(NODE *f, NODE *a, unsigned int);
+NODE *amd64_builtin_va_end(NODE *f, NODE *a, unsigned int);
+NODE *amd64_builtin_va_copy(NODE *f, NODE *a, unsigned int);
+NODE *i386_builtin_frame_address(NODE *f, NODE *a, unsigned int);
+NODE *i386_builtin_return_address(NODE *f, NODE *a, unsigned int);
+#undef NODE
Index: uspace/app/pcc/arch/amd64/order.c
===================================================================
--- uspace/app/pcc/arch/amd64/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/amd64/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,358 @@
+/*	$Id: order.c,v 1.14 2011/02/18 17:08:31 ragge Exp $	*/
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * 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 */
+}
+
+/*
+ * Check if LS and try to make it indexable.
+ * Ignore SCONV to long.
+ * Return 0 if failed.
+ */
+static int
+findls(NODE *p, int check)
+{
+	CONSZ c;
+
+	if (p->n_op == SCONV && p->n_type == LONG && p->n_left->n_type == INT)
+		p = p->n_left; /* Ignore pointless SCONVs here */
+	if (p->n_op != LS || p->n_right->n_op != ICON)
+		return 0;
+	if ((c = p->n_right->n_lval) != 1 && c != 2 && c != 3)
+		return 0;
+	if (check == 1 && p->n_left->n_op != REG)
+		return 0;
+	if (!isreg(p->n_left))
+		(void)geninsn(p->n_left, INAREG);
+	return 1;
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ * Be careful about register classes, this is a place where classes change.
+ *
+ * AMD64 (and i386) have a quite powerful addressing scheme:
+ * 	:	4(%rax)		4 + %rax
+ * 	:	4(%rbx,%rax,8)	4 + %rbx + %rax * 8
+ * 	:	4(,%rax)	4 + %rax * 8
+ * The 8 above can be 1,2,4 or 8.
+ */
+void
+offstar(NODE *p, int shape)
+{
+	NODE *l;
+
+	if (x2debug) {
+		printf("offstar(%p)\n", p);
+		fwalk(p, e2print, 0);
+	}
+
+	if (isreg(p))
+		return; /* Matched (%rax) */
+
+	if (findls(p, 0))
+		return; /* Matched (,%rax,8) */
+
+	if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_left->n_op == ICON) {
+		l = p->n_right;
+		if (isreg(l))
+			return; /* Matched 4(%rax) */
+		if (findls(l, 0))
+			return; /* Matched 4(,%rax,8) */
+		if (l->n_op == PLUS && isreg(l->n_right)) {
+			if (findls(l->n_left, 0))
+				return; /* Matched 4(%rbx,%rax,8) */
+			(void)geninsn(l->n_left, INAREG);
+			return; /* Generate 4(%rbx,%rax) */
+		}
+		(void)geninsn(l, INAREG);
+		return; /* Generate 4(%rbx) */
+	}
+
+	if (p->n_op == PLUS) {
+		if (!isreg(p->n_left)) /* ensure right is REG */
+			(void)geninsn(p->n_left, INAREG);
+		if (isreg(p->n_right))
+			return; /* Matched (%rax,%rbx) */
+		if (findls(p->n_right, 0))
+			return; /* Matched (%rax,%rbx,4) */
+		(void)geninsn(p->n_right, INAREG);
+		return; /* Generate (%rbx,%rax) */
+	}
+		
+	(void)geninsn(p, INAREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ * For simple OREGs conversion should already be done.
+ */
+void
+myormake(NODE *q)
+{
+	static int shtbl[] = { 1,2,4,8 };
+	NODE *p, *r;
+	CONSZ c = 0;
+	int r1, r2, sh;
+	int mkconv = 0;
+	char *n = "";
+
+#define	risreg(p)	(p->n_op == REG)
+	if (x2debug) {
+		printf("myormake(%p)\n", q);
+		fwalk(q, e2print, 0);
+	}
+	r1 = r2 = MAXREGS;
+	sh = 1;
+
+	r = p = q->n_left;
+
+	if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_left->n_op == ICON) {
+		c = p->n_left->n_lval;
+		n = p->n_left->n_name;
+		p = p->n_right;
+	}
+
+	if (p->n_op == PLUS && risreg(p->n_left)) {
+		r1 = regno(p->n_left);
+		p = p->n_right;
+	}
+
+	if (findls(p, 1)) {
+		if (p->n_op == SCONV)
+			p = p->n_left;
+		sh = shtbl[(int)p->n_right->n_lval];
+		r2 = regno(p->n_left);
+		mkconv = 1;
+	} else if (risreg(p)) {
+		r2 = regno(p);
+		mkconv = 1;
+	} //else
+	//	comperr("bad myormake tree");
+
+	if (mkconv == 0)
+		return;
+
+	q->n_op = OREG;
+	q->n_lval = c;
+	q->n_rval = R2PACK(r1, r2, sh);
+	q->n_name = n;
+	tfree(r);
+	if (x2debug) {
+		printf("myormake converted %p\n", q);
+		fwalk(q, e2print, 0);
+	}
+}
+
+/*
+ * 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 SCONV:
+		if ((q->ltype & TINT) &&
+		    q->rtype == (TLONGLONG|TULONGLONG|TLONG|TULONG)) {
+			static struct rspecial s[] = { 
+				{ NLEFT, RAX }, { NRES, RAX }, { 0 } };
+			return s;
+		}
+		break;
+
+	case DIV:
+		{
+			static struct rspecial s[] = {
+				{ NEVER, RAX }, { NEVER, RDX },
+				{ NLEFT, RAX }, { NRES, RAX },
+				{ NORIGHT, RDX }, { NORIGHT, RAX }, { 0 } };
+			return s;
+		}
+		break;
+
+	case MOD:
+		if (q->ltype & TUCHAR) {
+			static struct rspecial s[] = {
+				{ NEVER, RAX },
+				{ NLEFT, RAX }, { NRES, RAX },
+				{ NORIGHT, RAX }, { 0 } };
+			return s;
+		} else {
+			static struct rspecial s[] = {
+				{ NEVER, RAX }, { NEVER, RDX },
+				{ NLEFT, RAX }, { NRES, RDX },
+				{ NORIGHT, RDX }, { NORIGHT, RAX }, { 0 } };
+			return s;
+		}
+		break;
+
+	case STARG:
+		{
+			static struct rspecial s[] = {
+				{ NEVER, RDI }, 
+				{ NLEFT, RSI },
+				{ NEVER, RCX }, { 0 } };
+			return s;
+		}
+
+	case STASG:
+		{
+			static struct rspecial s[] = {
+				{ NEVER, RDI }, 
+				{ NRIGHT, RSI }, { NOLEFT, RSI },
+				{ NOLEFT, RCX }, { NORIGHT, RCX },
+				{ NEVER, RCX }, { 0 } };
+			return s;
+		}
+
+	case MUL:
+		if (q->lshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NEVER, RAX },
+				{ NLEFT, RAX }, { NRES, RAX }, { 0 } };
+			return s;
+		}
+		break;
+
+	case LS:
+	case RS:
+		{
+			static struct rspecial s[] = {
+				{ NRIGHT, RCX }, { NOLEFT, RCX }, { 0 } };
+			return s;
+		}
+		break;
+
+	default:
+		break;
+	}
+	comperr("nspecial entry %d", q - table);
+	return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+	return 0; /* nothing differs on x86 */
+}
+
+/*
+ * set registers in calling conventions live.
+ */
+int *
+livecall(NODE *p)
+{
+	static int r[NTEMPREG+1];
+	NODE *q;
+	int cr = 0;
+
+	if (optype(p->n_op) != BITYPE)
+		return r[0] = -1, r;
+
+	for (q = p->n_right; q->n_op == CM; q = q->n_left) {
+		if (q->n_right->n_op == ASSIGN &&
+		    q->n_right->n_left->n_op == REG)
+			r[cr++] = regno(q->n_right->n_left);
+	}
+	if (q->n_op == ASSIGN && q->n_left->n_op == REG)
+		r[cr++] = regno(q->n_left);
+	r[cr++] = -1;
+	return r;
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+	return 1;
+}
Index: uspace/app/pcc/arch/amd64/table.c
===================================================================
--- uspace/app/pcc/arch/amd64/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/amd64/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1594 @@
+/*	$Id: table.c,v 1.45 2011/02/18 17:08:31 ragge Exp $	*/
+/*
+ * Copyright (c) 2008 Michael Shalayeff
+ * Copyright (c) 2008 Anders Magnusson (ragge@ludd.ltu.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+#define TLL TLONG|TULONG
+# define ANYSIGNED TINT|TSHORT|TCHAR
+# define ANYUSIGNED TUNSIGNED|TUSHORT|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TUWORD TUNSIGNED
+# define TSWORD TINT
+# define TWORD	TUWORD|TSWORD
+#define	TANYINT	TLL|ANYFIXED
+#define	 SHINT	SAREG	/* Any integer */
+#define	 ININT	INAREG
+#define	 SHFL	SCREG	/* shape for long double */
+#define	 INFL	INCREG	/* shape for long 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,	TLL|TPOINT,
+	SAREG,	TLL|TPOINT,
+		0,	RLEFT,
+		"", },
+
+{ PCONV,	INAREG,
+	SAREG|SOREG|SNAME,	TUWORD,
+	SAREG,	TPOINT,
+		NASL|NAREG,	RESC1,
+		"	movl AL,Z1\n", },/* amd64 zero-extends 32-bit movl */
+	
+
+/*
+ * On amd64 casts from larger to smaller integer type in register do nothing.
+ */
+/* 64-bit to smaller */
+{ SCONV,	INAREG,
+	SAREG,	TLL|TPOINT,
+	SAREG,	TANYINT,
+		0,	RLEFT,
+		"", },
+
+/* 32-bit to smaller */
+{ SCONV,	INAREG,
+	SAREG,	TWORD,
+	SAREG,	ANYFIXED,
+		0,	RLEFT,
+		"", },
+
+/* 16-bit to smaller */
+{ SCONV,	INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SAREG,	TUSHORT|TUCHAR|TSHORT|TCHAR,
+		0,	RLEFT,
+		"", },
+
+/* 8-bit to 8-bit */
+{ SCONV,	INAREG,
+	SAREG,	TCHAR|TUCHAR,
+	SAREG,	TUCHAR|TCHAR,
+		0,	RLEFT,
+		"", },
+
+/*
+ * Casts from memory to same or smaller register is equally simple.
+ */
+/* 64-bit to smaller */
+{ SCONV,	INAREG,
+	SNAME|SOREG,	TLL|TPOINT,
+	SAREG,		TANYINT,
+		NAREG,	RESC1,
+		"	movZR AL,A1\n", },
+
+/* 32-bit to smaller */
+{ SCONV,	INAREG,
+	SNAME|SOREG,	TWORD,
+	SAREG,		ANYFIXED,
+		NAREG,	RESC1,
+		"	movZR AL,A1\n", },
+
+/* 16-bit to smaller */
+{ SCONV,	INAREG,
+	SNAME|SOREG,	TSHORT|TUSHORT,
+	SAREG,		TUSHORT|TUCHAR|TSHORT|TCHAR,
+		NAREG,	RESC1,
+		"	movZR AL,A1\n", },
+
+/* 8-bit to 8-bit */
+{ SCONV,	INAREG,
+	SNAME|SOREG,	TCHAR|TUCHAR,
+	SAREG,		TUCHAR|TCHAR,
+		NAREG,	RESC1,
+		"	movZR AL,A1\n", },
+
+
+/* char to something */
+
+/* convert char to (unsigned) short. */
+{ SCONV,	ININT,
+	SAREG|SOREG|SNAME,	TCHAR,
+	SAREG,	TSHORT|TUSHORT,
+		NASL|NAREG,	RESC1,
+		"	movsbw AL,A1\n", },
+
+/* convert unsigned char to (u)short. */
+{ SCONV,	ININT,
+	SAREG|SOREG|SNAME,	TUCHAR,
+	SAREG,	TSHORT|TUSHORT,
+		NASL|NAREG,	RESC1,
+		"	movzbw AL,A1\n", },
+
+/* convert signed char to int (or pointer). */
+{ SCONV,	ININT,
+	SAREG|SOREG|SNAME,	TCHAR,
+	SAREG,	TWORD|TPOINT,
+		NASL|NAREG,	RESC1,
+		"	movsbl AL,A1\n", },
+
+/* convert unsigned char to (u)int. */
+{ SCONV,	ININT,
+	SAREG|SOREG|SNAME,	TUCHAR,
+	SAREG,	TWORD,
+		NASL|NAREG,	RESC1,
+		"	movzbl AL,A1\n", },
+
+/* convert char to (u)long long */
+{ SCONV,	INAREG,
+	SAREG|SOREG|SNAME,	TCHAR,
+	SANY,	TLL,
+		NAREG|NASL,	RESC1,
+		"	movsbq AL,A1\n", },
+
+/* convert unsigned char to (u)long long */
+{ SCONV,	INAREG,
+	SAREG|SOREG|SNAME,	TUCHAR,
+	SANY,			TLL,
+		NAREG|NASL,	RESC1,
+		"	movzbq AL,A1\n", },
+
+/* short to something */
+
+/* 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,	INAREG,
+	SAREG|SOREG|SNAME,	TSHORT,
+	SAREG,			TLL,
+		NAREG|NASL,	RESC1,
+		"	movswq AL,A1\n", },
+
+/* convert unsigned short to (u)long long */
+{ SCONV,	INAREG,
+	SAREG|SOREG|SNAME,	TUSHORT,
+	SAREG,			TLL,
+		NAREG|NASL,	RESC1,
+		"	movzwq AL,A1\n", },
+
+/* int to something */
+
+/* convert signed int to (u)long long */
+{ SCONV,	INAREG,
+	SAREG,	TSWORD,
+	SAREG,	TLL,
+		NASL|NAREG,	RESC1,
+		"	movslq AL,A1\n", },
+
+/* convert unsigned int to (u)long long */
+{ SCONV,	INAREG,
+	SAREG|SOREG|SNAME,	TUWORD,
+	SAREG,	TLL,
+		NASL|NAREG,	RESC1,
+		"	movl AL,Z1\n", },/* amd64 zero-extends 32-bit movl */
+
+/*
+ * Floating point casts.  amd64 uses xmm for float/double and x87
+ * for long double calculations.
+ *
+ * Types smaller than int are casted to int/(unsigned).
+ */
+/* no casts */
+{ SCONV,	INBREG,
+	SBREG,	TFLOAT,
+	SBREG,	TFLOAT,
+		0,	RLEFT,
+		"", },
+
+{ SCONV,	INBREG,
+	SBREG,	TDOUBLE,
+	SBREG,	TDOUBLE,
+		0,	RLEFT,
+		"", },
+
+{ SCONV,	INCREG,
+	SCREG,	TLDOUBLE,
+	SCREG,	TLDOUBLE,
+		0,	RLEFT,
+		"", },
+
+
+/* convert int/long to float/double */
+{ SCONV,	INBREG,
+	SAREG|SOREG|SNAME,	TINT|TLONG,
+	SBREG,			TFLOAT|TDOUBLE,
+		NBREG,	RESC1,
+		"	cvtsi2sZfZq AL,A1\n", },
+
+/* convert unsigned int to float/double */
+{ SCONV,	INBREG,
+	SAREG|SOREG|SNAME,	TUNSIGNED,
+	SBREG,			TFLOAT|TDOUBLE,
+		NAREG|NBREG,	RESC2,
+		"	movl AL,Z1\n	cvtsi2sZfq A1,A2\n", },
+
+/* convert unsigned long to float/double */
+{ SCONV,	INBREG,
+	SAREG|SOREG|SNAME,	TULONG,
+	SBREG,			TFLOAT|TDOUBLE,
+		NAREG*2|NASL|NBREG,	RESC3,
+		"Zj", },
+
+/* convert float/double to (u)char/(u)short/int */
+{ SCONV,	INAREG,
+	SBREG|SOREG|SNAME,	TFLOAT|TDOUBLE,
+	SAREG,			TCHAR|TUCHAR|TSHORT|TUSHORT|INT,
+		NAREG,		RESC1,
+		"	cvttsZg2si AL,A1\n", },
+
+/* convert float/double to  unsigned int/long */
+{ SCONV,	INAREG,
+	SBREG|SOREG|SNAME,	TFLOAT|TDOUBLE,
+	SAREG,			TUNSIGNED|TLONG,
+		NAREG,		RESC1,
+		"	cvttsZg2siq AL,Z8\n", },
+
+/* convert float to double */
+{ SCONV,	INBREG,
+	SBREG|SNAME|SOREG,	TFLOAT,
+	SBREG,	TDOUBLE,
+		NBREG|NBSL,	RESC1,
+		"	cvtss2sd AL,A1\n", },
+
+/* convert double to float */
+{ SCONV,	INBREG,
+	SBREG|SNAME|SOREG,	TDOUBLE,
+	SBREG,	TFLOAT,
+		NBREG|NBSL,	RESC1,
+		"	cvtsd2ss AL,A1\n", },
+
+/* x87 conversions */
+/* float -> ldouble */
+{ SCONV,	INCREG,
+	SBREG,	TFLOAT,
+	SCREG,	TLDOUBLE,
+		NCREG,		RESC1,
+		"\tsubq $4,%rsp\n\tmovss AL,(%rsp)\n"
+		"\tflds (%rsp)\n\taddq $4,%rsp\n", },
+
+/* double -> ldouble */
+{ SCONV,	INCREG,
+	SBREG,	TDOUBLE,
+	SCREG,	TLDOUBLE,
+		NCREG,		RESC1,
+		"\tsubq $8,%rsp\n\tmovsd AL,(%rsp)\n"
+		"\tfldl (%rsp)\n\taddq $8,%rsp\n", },
+
+/* ldouble -> double */
+{ SCONV,	INBREG,
+	SCREG,	TLDOUBLE,
+	SBREG,	TDOUBLE,
+		NBREG,		RESC1,
+		"\tsubq $8,%rsp\n\tfstpl (%rsp)\n"
+		"\tmovsd (%rsp),A1\n\taddq $8,%rsp\n", },
+
+/* ldouble -> float */
+{ SCONV,	INBREG,
+	SCREG,	TLDOUBLE,
+	SBREG,	TFLOAT,
+		NBREG,		RESC1,
+		"\tsubq $4,%rsp\n\tfstps (%rsp)\n"
+		"\tmovss (%rsp),A1\n\taddq $4,%rsp\n", },
+
+/* convert int (in memory) to long double */
+{ SCONV,	INCREG,
+	SOREG|SNAME,	TSWORD,
+	SCREG,	 TLDOUBLE,
+		NCREG,	RESC1,
+		"	fildl AL\n", },
+
+/* convert unsigned int to long double */
+{ SCONV,	INCREG,
+	SAREG,	TUWORD,
+	SCREG,	TLDOUBLE,
+		NAREG|NASL|NCREG,	RESC2,
+		"	subq $16,%rsp\n"
+		"	movl AL,Z1\n"
+		"	movq A1,(%rsp)\n"
+		"	fildll (%rsp)\n"
+		"	addq $16,%rsp\n", },
+
+/* convert int (in register) to long double */
+{ SCONV,	INCREG,
+	SAREG,	TSWORD,
+	SCREG,	TLDOUBLE,
+		NCREG,	RESC1,
+		"	subq $4,%rsp\n"
+		"	movl AL,(%rsp)\n"
+		"	fildl (%rsp)\n"
+		"	addq $4,%rsp\n", },
+
+/* unsigned long (in reg) to long double */
+{ SCONV,	INCREG,
+	SAREG,		TULONG,
+	SCREG,		TLDOUBLE,
+		NCREG,	RESC1,
+		"	subq $16,%rsp\n"
+		"	movq AL,(%rsp)\n"
+		"	fildll (%rsp)\n"
+		"	cmpq $0,AL\n"
+		"	jns 1f\n"
+		"	movl $1602224128,(%rsp)\n"
+		"	fadds (%rsp)\n"
+		"	addq $16,%rsp\n"
+		"1:\n", },
+
+/* unsigned long (in mem) to long double */
+{ SCONV,	INCREG,
+	SNAME|SOREG,	TULONG,
+	SCREG,		TLDOUBLE,
+		NCREG,	RESC1,
+		"	fildll AL\n"
+		"	cmpq $0,AL\n"
+		"	jns 1f\n"
+		"	push $1602224128\n"
+		"	fadds (%rsp)\n"
+		"	addq $8,%rsp\n"
+		"1:\n", },
+
+/* convert float/double to  unsigned long */
+{ SCONV,	INAREG,
+	SBREG,		TFLOAT|TDOUBLE,
+	SAREG,		TULONG,
+		(NAREG*2)|NBREG,	RESC1,
+		"Zb\n", },
+
+/* long double to unsigned long */
+{ SCONV,	INAREG,
+	SCREG|SNAME|SOREG,	TLDOUBLE,
+	SAREG,			TULONG,
+		NAREG,	RESC1,
+		"ZB", },
+
+/* ldouble -> long  XXX merge with int */
+{ SCONV,	INAREG,
+	SCREG,	TLDOUBLE,
+	SAREG,	TLONG,
+		NAREG,	RESC1,
+		"	subq $16,%rsp\n"
+		"	fnstcw (%rsp)\n"
+		"	fnstcw 4(%rsp)\n"
+		"	movb $12,1(%rsp)\n"
+		"	fldcw (%rsp)\n"
+		"	fistpll 8(%rsp)\n"
+		"	movq 8(%rsp),A1\n"
+		"	fldcw 4(%rsp)\n"
+		"	addq $16,%rsp\n", },
+
+/* ldouble -> (u)int */
+{ SCONV,	INAREG,
+	SCREG,	TLDOUBLE,
+	SAREG,	TINT|TUNSIGNED,
+		NAREG,	RESC1,
+		"	subq $16,%rsp\n"
+		"	fnstcw (%rsp)\n"
+		"	fnstcw 4(%rsp)\n"
+		"	movb $12,1(%rsp)\n"
+		"	fldcw (%rsp)\n"
+		"	fistpl 8(%rsp)\n"
+		"	movl 8(%rsp),A1\n"
+		"	fldcw 4(%rsp)\n"
+		"	addq $16,%rsp\n", },
+
+/* long (in mem) -> ldouble */
+{ SCONV,	INCREG,
+	SNAME|SOREG,	TLONG,
+	SCREG,		TLDOUBLE,
+		NCREG,	RESC1,
+		"	fildll AL\n", },
+
+/* long (in reg) -> ldouble */
+{ SCONV,	INCREG,
+	SAREG,		TLONG,
+	SCREG,		TLDOUBLE,
+		NCREG,	RESC1,
+		"	subq $16,%rsp\n"
+		"	movq AL,(%rsp)\n"
+		"	fildll (%rsp)\n"
+		"	addq $16,%rsp\n", },
+
+
+
+/* slut sconv */
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,		FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	call CL\nZC", },
+
+{ UCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	call CL\n", },
+
+{ CALL,	INAREG,
+	SCON,	TANY,
+	SAREG,	TLL|ANYFIXED|TPOINT,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	call CL\nZC", },
+
+{ UCALL,	INAREG,
+	SCON,	TANY,
+	SAREG,	TLL|ANYFIXED|TPOINT,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	call CL\n", },
+
+{ CALL,	INBREG,
+	SCON,	TANY,
+	SBREG,	TANY,
+		NBREG|NBSL,	RESC1,	/* should be 0 */
+		"	call CL\nZC", },
+
+{ UCALL,	INBREG,
+	SCON,	TANY,
+	SBREG,	TANY,
+		NBREG|NBSL,	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,		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", },
+
+/* 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.
+ */
+/* floating point add */
+{ PLUS,		INBREG,
+	SBREG,			TFLOAT|TDOUBLE,
+	SBREG|SNAME|SOREG,	TFLOAT|TDOUBLE,
+		0,	RLEFT,
+		"	addsZf AR,AL\n", },
+
+{ PLUS,		INCREG|FOREFF,
+	SHFL,	TLDOUBLE,
+	SHFL,	TLDOUBLE,
+		0,	RLEFT,
+		"	faddp\n", },
+
+
+{ PLUS,		INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TLL|TPOINT,
+	SONE,	TANY,
+		0,	RLEFT,
+		"	incq AL\n", },
+
+{ PLUS,		INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TWORD,
+	SONE,	TANY,
+		0,	RLEFT,
+		"	incl AL\n", },
+
+{ PLUS,		INAREG,
+	SAREG,	TLL|TPOINT,
+	SCON,	TWORD,
+		NAREG|NASL,	RESC1,
+		"	leaq CR(AL),A1\n", },
+
+#ifdef notdef
+/* older binutils are missing leal */
+{ PLUS,		INAREG,
+	SAREG,	TWORD,
+	SCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	leal CR(AL),A1\n", },
+#endif
+
+{ PLUS,		INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SONE,	TANY,
+		0,	RLEFT,
+		"	incw AL\n", },
+
+{ PLUS,		INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
+	SONE,	TANY,
+		0,	RLEFT,
+		"	incb AL\n", },
+
+#ifdef notdef
+/* older binutils are missing leal */
+{ PLUS,		INAREG,
+	SAREG,	TWORD,
+	SAREG,	TWORD,
+		NAREG|NASL|NASR,	RESC1,
+		"	leal (AL,AR),A1\n", },
+#endif
+
+{ MINUS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TLL|TPOINT,
+	SONE,			TANY,
+		0,	RLEFT,
+		"	decq AL\n", },
+
+{ MINUS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TWORD,
+	SONE,			TANY,
+		0,	RLEFT,
+		"	decl AL\n", },
+
+{ MINUS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SONE,			TANY,
+		0,	RLEFT,
+		"	decw AL\n", },
+
+{ MINUS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
+	SONE,	TANY,
+		0,	RLEFT,
+		"	decb AL\n", },
+
+/* address as register offset, negative */
+{ MINUS,	INAREG,
+	SAREG,	TLL|TPOINT,
+	SPCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	leaq -CR(AL),A1\n", },
+
+{ MINUS,	INBREG|FOREFF,
+	SBREG,			TDOUBLE|TFLOAT,
+	SBREG|SNAME|SOREG,	TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"	subsZf AR,AL\n", },
+
+{ MINUS,	INCREG|FOREFF,
+	SHFL,	TLDOUBLE,
+	SHFL,	TLDOUBLE,
+		0,	RLEFT,
+		"	fsubZAp\n", },
+
+/* Simple r/m->reg ops */
+/* m/r |= r */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SAREG|SNAME|SOREG,	TLL|TPOINT,
+	SAREG,			TLL|TPOINT,
+		0,	RLEFT|RESCC,
+		"	Oq AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SAREG,			TLL|TPOINT,
+	SAREG|SNAME|SOREG,	TLL|TPOINT,
+		0,	RLEFT|RESCC,
+		"	Oq AR,AL\n", },
+
+/* m/r |= r */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SAREG|SNAME|SOREG,	TWORD,
+	SAREG,			TWORD,
+		0,	RLEFT|RESCC,
+		"	Ol AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SAREG,			TWORD,
+	SAREG|SNAME|SOREG,	TWORD,
+		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,	INAREG|FOREFF|FORCC,
+	SAREG,		TCHAR|TUCHAR,
+	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
+		0,	RLEFT|RESCC,
+		"	Ob AR,AL\n", },
+
+/* r |= r/m */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SAREG,		TCHAR|TUCHAR,
+	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
+		0,	RLEFT|RESCC,
+		"	Ob AR,AL\n", },
+
+/* m/r |= const */
+#ifdef notdef	/* amd64 lacks immediate 64-bit simple ops */
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SAREG|SNAME|SOREG,	TLL|TPOINT,
+	SCON,	TANY,
+		0,	RLEFT|RESCC,
+		"	Oq AR,AL\n", },
+#endif
+
+{ OPSIMP,	INAREG|FOREFF|FORCC,
+	SAREG|SNAME|SOREG,	TWORD,
+	SCON,	TANY,
+		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,	INAREG|FOREFF|FORCC,
+	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
+	SCON,	TANY,
+		0,	RLEFT|RESCC,
+		"	Ob AR,AL\n", },
+
+/*
+ * The next rules handle all shift operators.
+ */
+/* r/m <<= r */
+{ LS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TLL,
+	SAREG,		TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	salq AR,AL\n", },
+
+/* r/m <<= const */
+{ LS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TLL,
+	SCON,	TANY,
+		0,	RLEFT,
+		"	salq AR,AL\n", },
+
+/* r/m <<= r */
+{ LS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TWORD,
+	SAREG,		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,
+	SAREG,			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,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
+	SAREG,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	salb AR,AL\n", },
+
+{ LS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
+	SCON,			TANY,
+		0,	RLEFT,
+		"	salb AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TLONG|TLONGLONG,
+	SAREG,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	sarq AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TLONG|TLONGLONG,
+	SCON,			TANY,
+		0,		RLEFT,
+		"	sarq AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TULONG|TULONGLONG,
+	SAREG,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	shrq AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TULONG|TULONGLONG,
+	SCON,			TANY,
+		0,		RLEFT,
+		"	shrq AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSWORD,
+	SAREG,			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,
+	SAREG,			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,
+	SAREG,			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,
+	SAREG,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	shrw AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TUSHORT,
+	SCON,			TANY,
+		0,		RLEFT,
+		"	shrw AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TCHAR,
+	SAREG,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	sarb AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TCHAR,
+	SCON,			TANY,
+		0,		RLEFT,
+		"	sarb AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TUCHAR,
+	SAREG,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	shrb AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TUCHAR,
+	SCON,			TANY,
+		0,		RLEFT,
+		"	shrb AR,AL\n", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+{ ASSIGN,	FORCC|FOREFF|INAREG,
+	SAREG,		TLL|TPOINT,
+	SMIXOR,		TANY,
+		0,	RDEST,
+		"	xorq AL,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TLL|TPOINT,
+	SCON,		TANY,
+		0,	RDEST,
+		"	movabs AR,AL\n", },
+
+{ ASSIGN,	FORCC|FOREFF|INAREG,
+	SAREG,		TWORD,
+	SMIXOR,		TANY,
+		0,	RDEST,
+		"	xorl AL,AL\n", },
+
+{ ASSIGN,	FOREFF,
+	SAREG|SNAME|SOREG,	TWORD,
+	SCON,		TANY,
+		0,	0,
+		"	movl AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TWORD,
+	SCON,		TANY,
+		0,	RDEST,
+		"	movl AR,AL\n", },
+
+{ ASSIGN,	FORCC|FOREFF|INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SMIXOR,		TANY,
+		0,	RDEST,
+		"	xorw AL,AL\n", },
+
+{ ASSIGN,	FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SCON,		TANY,
+		0,	0,
+		"	movw AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SCON,		TANY,
+		0,	RDEST,
+		"	movw AR,AL\n", },
+
+{ ASSIGN,	FOREFF,
+	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
+	SCON,		TANY,
+		0,	0,
+		"	movb AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TCHAR|TUCHAR,
+	SCON,		TANY,
+		0,	RDEST,
+		"	movb AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG|SNAME|SOREG,	TLL|TPOINT,
+	SAREG,			TLL|TPOINT,
+		0,	RDEST,
+		"	movq AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG|SNAME|SOREG,	TWORD,
+	SAREG,		TWORD,
+		0,	RDEST,
+		"	movl AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,			TWORD,
+	SAREG|SNAME|SOREG,	TWORD,
+		0,	RDEST,
+		"	movl AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,			TPOINT,
+	SAREG|SNAME|SOREG,	TPOINT,
+		0,	RDEST,
+		"	movq AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SAREG,		TSHORT|TUSHORT,
+		0,	RDEST,
+		"	movw AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
+	SAREG,		TCHAR|TUCHAR|TWORD,
+		0,	RDEST,
+		"	movb AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,		TCHAR|TUCHAR,
+	SAREG|SCON,	TCHAR|TUCHAR,
+		NAREG*2,	RDEST,
+		"	movb AR,A2\n"
+		"	movzbl A2,ZN\n"
+		"	andl $N,AL\n"
+		"	sall $H,ZN\n"
+		"	andl $M,ZN\n"
+		"	orl ZN,AL\n"
+		"F	movb AR,AD\n"
+		"FZE", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,		TSHORT|TUSHORT,
+	SAREG|SCON,	TSHORT|TUSHORT,
+		NAREG,	RDEST,
+		"	movw AR,A1\n"
+		"	movzwl A1,ZN\n"
+		"	andl $N,AL\n"
+		"	sall $H,ZN\n"
+		"	andl $M,ZN\n"
+		"	orl ZN,AL\n"
+		"F	movw AR,AD\n"
+		"FZE", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,		TWORD,
+	SAREG|SNAME|SOREG|SCON,	TWORD,
+		NAREG,	RDEST,
+		"	movl AR,A1\n"
+		"	andl $N,AL\n"
+		"	sall $H,A1\n"
+		"	andl $M,A1\n"
+		"	orl A1,AL\n"
+		"F	movl AR,AD\n"
+		"FZE", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,		TLL,
+	SAREG|SNAME|SOREG|SCON,	TLL,
+		NAREG*2,	RDEST,
+		"	movq AR,A1\n"
+		"	movq $N,A2\n"
+		"	andq A2,AL\n"
+		"	salq $H,A1\n"
+		"	movq $M,A2\n"
+		"	andq A2,A1\n"
+		"	orq A1,AL\n"
+		"F	movq AR,AD\n"
+		"FZE", },
+
+{ ASSIGN,	INBREG|FOREFF,
+	SBREG,			TFLOAT|TDOUBLE,
+	SBREG|SOREG|SNAME,	TFLOAT|TDOUBLE,
+		0,	RDEST,
+		"	movsZf AR,AL\n", },
+
+{ ASSIGN,	INBREG|FOREFF,
+	SBREG|SOREG|SNAME,	TFLOAT|TDOUBLE,
+	SBREG,			TFLOAT|TDOUBLE,
+		0,	RDEST,
+		"	movsZf AR,AL\n", },
+
+/* x87 entries */
+{ ASSIGN,	INDREG|FOREFF,
+	SHFL,	TLDOUBLE,
+	SHFL,	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,	TLDOUBLE,
+		0,	RDEST,
+		"	fstpt AL\n	fldt AL\n", }, /* XXX */
+
+{ ASSIGN,	FOREFF,
+	SNAME|SOREG,	TLDOUBLE,
+	SHFL,	TLDOUBLE,
+		0,	0,
+		"	fstpt AL\n", },
+
+/* end very important order */
+
+{ ASSIGN,	INFL|FOREFF,
+	SHFL,		TLDOUBLE,
+	SHFL|SOREG|SNAME,	TLDOUBLE,
+		0,	RDEST,
+		"	fldt AR\n", },
+
+/* end x87 */
+
+/* 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 
+ */
+{ DIV,	INAREG,
+	SAREG,			TLONG,
+	SAREG|SNAME|SOREG,	TLL,
+		NSPECIAL,	RDEST,
+		"	cqto\n	idivq AR\n", },
+
+{ DIV,	INAREG,
+	SAREG,			TULONG|TPOINT,
+	SAREG|SNAME|SOREG,	TLL|TPOINT,
+		NSPECIAL,	RDEST,
+		"	xorq %rdx,%rdx\n	divq AR\n", },
+
+{ DIV,	INAREG,
+	SAREG,			TSWORD,
+	SAREG|SNAME|SOREG,	TWORD,
+		NSPECIAL,	RDEST,
+		"	cltd\n	idivl AR\n", },
+
+{ DIV,	INAREG,
+	SAREG,			TUWORD,
+	SAREG|SNAME|SOREG,	TWORD,
+		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,	INAREG,
+	SAREG,			TUCHAR,
+	SAREG|SNAME|SOREG,	TUCHAR,
+		NSPECIAL,	RDEST,
+		"	xorb %ah,%ah\n	divb AR\n", },
+
+{ DIV,	INBREG,
+	SBREG,			TFLOAT|TDOUBLE,
+	SBREG|SNAME|SOREG,	TFLOAT|TDOUBLE,
+		0,	RLEFT,
+		"	divsZf AR,AL\n", },
+
+{ DIV,	INCREG,
+	SHFL,		TLDOUBLE,
+	SHFL,		TLDOUBLE,
+		0,	RLEFT,
+		"	fdivZAp\n", },
+
+{ MOD,	INAREG,
+	SAREG,			TLONG,
+	SAREG|SNAME|SOREG,	TLONG,
+		NAREG|NSPECIAL,	RESC1,
+		"	cqto\n	idivq AR\n", },
+
+{ MOD,	INAREG,
+	SAREG,			TLL|TPOINT,
+	SAREG|SNAME|SOREG,	TULONG|TPOINT,
+		NAREG|NSPECIAL,	RESC1,
+		"	xorq %rdx,%rdx\n	divq AR\n", },
+
+{ MOD,	INAREG,
+	SAREG,			TSWORD,
+	SAREG|SNAME|SOREG,	TSWORD,
+		NAREG|NSPECIAL,	RESC1,
+		"	cltd\n	idivl AR\n", },
+
+{ MOD,	INAREG,
+	SAREG,			TWORD,
+	SAREG|SNAME|SOREG,	TUWORD,
+		NAREG|NSPECIAL,	RESC1,
+		"	xorl %edx,%edx\n	divl AR\n", },
+
+{ MOD,	INAREG,
+	SAREG,			TUSHORT,
+	SAREG|SNAME|SOREG,	TUSHORT,
+		NAREG|NSPECIAL,	RESC1,
+		"	xorl %edx,%edx\n	divw AR\n", },
+
+{ MOD,	INAREG,
+	SAREG,			TUCHAR,
+	SAREG|SNAME|SOREG,	TUCHAR,
+		NAREG|NSPECIAL,	RESC1,
+		"	xorb %ah,%ah\n	divb AR\n	movb %ah,%al\n", },
+
+{ MUL,	INAREG,
+	SAREG,				TLL|TPOINT,
+	SAREG|SNAME|SOREG,		TLL|TPOINT,
+		0,	RLEFT,
+		"	imulq AR,AL\n", },
+
+{ MUL,	INAREG,
+	SAREG,				TWORD,
+	SAREG|SNAME|SOREG|SCON,		TWORD,
+		0,	RLEFT,
+		"	imull AR,AL\n", },
+
+{ MUL,	INAREG,
+	SAREG,			TSHORT|TUSHORT,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	imulw AR,AL\n", },
+
+{ MUL,	INAREG,
+	SAREG,			TCHAR|TUCHAR,
+	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	imulb AR\n", },
+
+{ MUL,	INBREG,
+	SBREG,			TFLOAT|TDOUBLE,
+	SBREG|SNAME|SOREG,	TFLOAT|TDOUBLE,
+		0,	RLEFT,
+		"	mulsZf AR,AL\n", },
+
+{ MUL,	INCREG,
+	SHFL,		TLDOUBLE,
+	SHFL,		TLDOUBLE,
+		0,	RLEFT,
+		"	fmulp\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL,	INAREG,
+	SANY,	TANY,
+	SOREG,	TLL|TPOINT,
+		NAREG,	RESC1,
+		"	movq AL,A1\n", },
+
+{ UMUL,	INAREG,
+	SANY,	TWORD,
+	SOREG,	TWORD,
+		NAREG|NASL,	RESC1,
+		"	movl AL,A1\n", },
+
+{ UMUL,	INAREG,
+	SANY,	TANY,
+	SOREG,	TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	movb AL,A1\n", },
+
+{ UMUL,	INAREG,
+	SANY,	TANY,
+	SOREG,	TSHORT|TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	movw AL,A1\n", },
+
+{ UMUL,	INBREG,
+	SANY,	TANY,
+	SOREG,	TFLOAT|TDOUBLE,
+		NBREG|NBSL,	RESC1,
+		"	movsZf AL,A1\n", },
+
+{ UMUL,	INCREG,
+	SANY,	TANY,
+	SOREG,	TLDOUBLE,
+		NCREG|NCSL,	RESC1,
+		"	fldt AL\n", },
+
+/*
+ * Logical/branching operators
+ */
+
+/* Comparisions, take care of everything */
+
+{ OPLOG,	FORCC,
+	SAREG,			TLL|TPOINT,
+	SAREG|SOREG|SNAME,	TLL|TPOINT,
+		0, 	RESCC,
+		"	cmpq AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME,	TLL|TPOINT,
+	SAREG,			TLL|TPOINT,
+		0,	RESCC,
+		"	cmpq AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME,	TLL|TPOINT,
+	SCON32,			TANY,
+		0,	RESCC,
+		"	cmpq AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME,	TWORD,
+	SCON|SAREG,	TWORD,
+		0, 	RESCC,
+		"	cmpl AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SCON|SAREG,	TWORD,
+	SAREG|SOREG|SNAME,	TWORD,
+		0, 	RESCC,
+		"	cmpl AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME,	TSHORT|TUSHORT,
+	SCON|SAREG,	TANY,
+		0, 	RESCC,
+		"	cmpw AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME,	TCHAR|TUCHAR,
+	SCON|SAREG,	TANY,
+		0, 	RESCC,
+		"	cmpb AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SBREG,			TDOUBLE|TFLOAT,
+	SBREG|SNAME|SOREG,	TDOUBLE|TFLOAT,
+		0,	 	RNOP,
+		"	ucomisZg AR,AL\nZU\n", },
+
+/* x87 */
+{ OPLOG,	FORCC,
+	SCREG,	TLDOUBLE,
+	SCREG,	TLDOUBLE,
+		0,	RNOP,
+		"ZG", },
+
+{ OPLOG,	FORCC,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"diediedie!", },
+
+/* AND/OR/ER/NOT */
+{ AND,	INAREG|FOREFF,
+	SAREG|SOREG|SNAME,	TLL,
+	SCON,			TWORD,
+		0,	RLEFT,
+		"	andq AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,
+	SAREG|SOREG|SNAME,	TLL,
+	SAREG,			TLL,
+		0,	RLEFT,
+		"	andq AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,
+	SAREG,			TLL,
+	SAREG|SOREG|SNAME,	TLL,
+		0,	RLEFT,
+		"	andq AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,
+	SAREG|SOREG|SNAME,	TWORD,
+	SCON|SAREG,		TWORD,
+		0,	RLEFT,
+		"	andl AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,
+	SAREG,			TWORD,
+	SAREG|SOREG|SNAME,	TWORD,
+		0,	RLEFT,
+		"	andl AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,  
+	SAREG|SOREG|SNAME,	TSHORT|TUSHORT,
+	SCON|SAREG,		TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	andw AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,  
+	SAREG,			TSHORT|TUSHORT,
+	SAREG|SOREG|SNAME,	TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	andw AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,
+	SAREG|SOREG|SNAME,	TCHAR|TUCHAR,
+	SCON|SAREG,		TCHAR|TUCHAR,
+		0,	RLEFT,
+		"	andb AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,
+	SAREG,			TCHAR|TUCHAR,
+	SAREG|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|INAREG,
+	SAREG,	TLL|TPOINT,
+	SMIXOR,	TANY,
+		NAREG,	RESC1,
+		"	xorq A1,A1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SAREG|SCON|SOREG|SNAME,	TLL|TPOINT,
+		NAREG,	RESC1,
+		"	movq AL,A1\n", },
+
+{ OPLTYPE,	FORCC|INAREG,
+	SAREG,	TWORD,
+	SMIXOR,	TANY,
+		NAREG|NASL,	RESC1,
+		"	xorl A1,A1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SAREG|SCON|SOREG|SNAME,	TWORD,
+		NAREG|NASL,	RESC1,
+		"	movl AL,A1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SAREG|SOREG|SNAME|SCON,	TCHAR|TUCHAR,
+		NAREG,	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,	INBREG,
+	SANY,		TFLOAT|TDOUBLE,
+	SOREG|SNAME|SBREG,	TFLOAT|TDOUBLE,
+		NBREG,	RESC1,
+		"	movsZf AL,A1\n", },
+
+/* x87 entry */
+{ OPLTYPE,	INCREG,
+	SANY,		TLDOUBLE,
+	SOREG|SNAME,	TLDOUBLE,
+		NCREG,	RESC1,
+		"	fldt AL\n", },
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS,	INAREG|FOREFF,
+	SAREG,	TLL|TPOINT,
+	SAREG,	TLL|TPOINT,
+		0,	RLEFT,
+		"	negq AL\n", },
+
+{ UMINUS,	INAREG|FOREFF,
+	SAREG,	TWORD,
+	SAREG,	TWORD,
+		0,	RLEFT,
+		"	negl AL\n", },
+
+{ UMINUS,	INAREG|FOREFF,
+	SAREG,	TSHORT|TUSHORT,
+	SAREG,	TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	negw AL\n", },
+
+{ UMINUS,	INAREG|FOREFF,
+	SAREG,	TCHAR|TUCHAR,
+	SAREG,	TCHAR|TUCHAR,
+		0,	RLEFT,
+		"	negb AL\n", },
+
+{ UMINUS,	INBREG,
+	SBREG,		TDOUBLE|TFLOAT,
+	SBREG,		TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"	xorpZf LC(%rip),AL\n", },
+
+{ UMINUS,	INCREG,
+	SCREG,	TLDOUBLE,
+	SCREG,	TLDOUBLE,
+		0,	RLEFT,
+		"	fchs\n", },
+
+{ COMPL,	INAREG,
+	SAREG,	TLL,
+	SANY,	TANY,
+		0,	RLEFT,
+		"	notq AL\n", },
+
+{ COMPL,	INAREG,
+	SAREG,	TWORD,
+	SANY,	TANY,
+		0,	RLEFT,
+		"	notl AL\n", },
+
+{ COMPL,	INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SANY,	TANY,
+		0,	RLEFT,
+		"	notw AL\n", },
+
+{ COMPL,	INAREG,
+	SAREG,	TCHAR|TUCHAR,
+	SANY,	TANY,
+		0,	RLEFT,
+		"	notb AL\n", },
+
+{ STARG,	FOREFF,
+	SAREG|SOREG|SNAME|SCON, TANY,
+	SANY,	TSTRUCT,
+		NSPECIAL, 0,
+		"ZF", },
+
+{ ADDROF,	INAREG,
+	SNAME,	TANY,
+	SANY,	TANY,
+		NAREG, RESC1,
+		"	leaq AL,A1\n", },
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	"help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
Index: uspace/app/pcc/arch/arm/code.c
===================================================================
--- uspace/app/pcc/arch/arm/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/arm/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,889 @@
+/*      $Id: code.c,v 1.21 2009/02/08 16:07:52 ragge Exp $    */
+/*
+ * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
+ * 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.
+ */
+
+/*
+ *  Stuff for pass1.
+ */
+
+#include <assert.h>
+
+#include "pass1.h"
+#include "pass2.h"
+
+int lastloc = -1;
+static int rvnr;
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+	extern char *nextsect;
+	static char *loctbl[] = { "text", "data", "section .rodata" };
+	char *n;
+	TWORD t;
+	int s;
+
+	if (sp == NULL) {
+		lastloc = -1;
+		return;
+	}
+	t = sp->stype;
+	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? PROG : DATA;
+	if (nextsect) {
+		printf("\t.section %s\n", nextsect);
+		nextsect = NULL;
+		s = -1;
+	} else if (s != lastloc)
+		printf("\t.%s\n", loctbl[s]);
+	lastloc = s;
+	while (ISARY(t))
+		t = DECREF(t);
+	if (t > UCHAR)
+		printf("\t.align %d\n", t > USHORT ? 4 : 2);
+	n = sp->soname ? sp->soname : exname(sp->sname);
+#ifdef USE_GAS
+	if (ISFTN(t))
+		printf("\t.type %s,%%function\n", n);
+#endif
+	if (sp->sclass == EXTDEF)
+		printf("\t.global %s\n", n);
+	if (ISFTN(t))
+		return;
+	if (sp->slevel == 0)
+		printf("%s:\n", n);
+	else
+		printf(LABFMT ":\n", sp->soffset);
+}
+
+/* Put a symbol in a temporary
+ * used by bfcode() and its helpers
+ */
+static void
+putintemp(struct symtab *sym)
+{
+        NODE *p;
+
+        p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
+        p = buildtree(ASSIGN, p, nametree(sym));
+        sym->soffset = regno(p->n_left);
+        sym->sflags |= STNODE;
+        ecomp(p);
+}
+
+/* setup a 64-bit parameter (double/ldouble/longlong)
+ * used by bfcode() */
+static void
+param_64bit(struct symtab *sym, int *argofsp, int dotemps)
+{
+        int argofs = *argofsp;
+        NODE *p, *q;
+        int navail;
+
+#if ALLONGLONG == 64
+	/* alignment */
+	++argofs;
+	argofs &= ~1;
+	*argofsp = argofs;
+#endif
+
+        navail = NARGREGS - argofs;
+
+        if (navail < 2) {
+		/* half in and half out of the registers */
+		if (features(FEATURE_BIGENDIAN)) {
+			cerror("param_64bit");
+			p = q = NULL;
+		} else {
+        		q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+		        regno(q) = R0 + argofs;
+			if (dotemps) {
+				q = block(SCONV, q, NIL,
+				    ULONGLONG, 0, MKSUE(ULONGLONG));
+		                p = nametree(sym);
+				p->n_type = ULONGLONG;
+				p->n_df = 0;
+				p->n_sue = MKSUE(ULONGLONG);
+				p = block(LS, p, bcon(32), ULONGLONG,
+				    0, MKSUE(ULONGLONG));
+				q = block(PLUS, p, q, ULONGLONG,
+				    0, MKSUE(ULONGLONG));
+				p = tempnode(0, ULONGLONG,
+				    0, MKSUE(ULONGLONG));
+				sym->soffset = regno(p);
+				sym->sflags |= STNODE;
+			} else {
+		                p = nametree(sym);
+				regno(p) = sym->soffset;
+				p->n_type = INT;
+				p->n_df = 0;
+				p->n_sue = MKSUE(INT);
+			}
+		}
+	        p = buildtree(ASSIGN, p, q);
+		ecomp(p);
+	        *argofsp = argofs + 2;
+		return;
+        }
+
+        q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->ssue);
+        regno(q) = R0R1 + argofs;
+        if (dotemps) {
+                p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
+                sym->soffset = regno(p);
+                sym->sflags |= STNODE;
+        } else {
+                p = nametree(sym);
+        }
+        p = buildtree(ASSIGN, p, q);
+        ecomp(p);
+        *argofsp = argofs + 2;
+}
+
+/* setup a 32-bit param on the stack
+ * used by bfcode() */
+static void
+param_32bit(struct symtab *sym, int *argofsp, int dotemps)
+{
+        NODE *p, *q;
+
+        q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->ssue);
+        regno(q) = R0 + (*argofsp)++;
+        if (dotemps) {
+                p = tempnode(0, sym->stype, sym->sdf, sym->ssue);
+                sym->soffset = regno(p);
+                sym->sflags |= STNODE;
+        } else {
+                p = nametree(sym);
+        }
+        p = buildtree(ASSIGN, p, q);
+        ecomp(p);
+}
+
+/* setup a double param on the stack
+ * used by bfcode() */
+static void
+param_double(struct symtab *sym, int *argofsp, int dotemps)
+{
+        NODE *p, *q, *t;
+        int tmpnr;
+
+	/*
+	 * we have to dump the float from the general register
+	 * into a temp, since the register allocator doesn't like
+	 * floats to be in CLASSA.  This may not work for -xtemps.
+	 */
+
+        t = tempnode(0, ULONGLONG, 0, MKSUE(ULONGLONG));
+        tmpnr = regno(t);
+        q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+        q->n_rval = R0R1 + (*argofsp)++;
+        p = buildtree(ASSIGN, t, q);
+        ecomp(p);
+
+        if (dotemps) {
+                sym->soffset = tmpnr;
+                sym->sflags |= STNODE;
+        } else {
+                q = tempnode(tmpnr, sym->stype, sym->sdf, sym->ssue);
+                p = nametree(sym);
+                p = buildtree(ASSIGN, p, q);
+                ecomp(p);
+        }
+}
+
+/* setup a float param on the stack
+ * used by bfcode() */
+static void
+param_float(struct symtab *sym, int *argofsp, int dotemps)
+{
+        NODE *p, *q, *t;
+        int tmpnr;
+
+	/*
+	 * we have to dump the float from the general register
+	 * into a temp, since the register allocator doesn't like
+	 * floats to be in CLASSA.  This may not work for -xtemps.
+	 */
+
+        t = tempnode(0, INT, 0, MKSUE(INT));
+        tmpnr = regno(t);
+        q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+        q->n_rval = R0 + (*argofsp)++;
+        p = buildtree(ASSIGN, t, q);
+        ecomp(p);
+
+        if (dotemps) {
+                sym->soffset = tmpnr;
+                sym->sflags |= STNODE;
+        } else {
+                q = tempnode(tmpnr, sym->stype, sym->sdf, sym->ssue);
+                p = nametree(sym);
+                p = buildtree(ASSIGN, p, q);
+                ecomp(p);
+        }
+}
+
+/* setup the hidden pointer to struct return parameter
+ * used by bfcode() */
+static void
+param_retstruct(void)
+{
+        NODE *p, *q;
+
+        p = tempnode(0, PTR-FTN+cftnsp->stype, 0, cftnsp->ssue);
+        rvnr = regno(p);
+        q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
+        regno(q) = R0;
+        p = buildtree(ASSIGN, p, q);
+        ecomp(p);
+}
+
+
+/* setup struct parameter
+ * push the registers out to memory
+ * used by bfcode() */
+static void
+param_struct(struct symtab *sym, int *argofsp)
+{
+        int argofs = *argofsp;
+        NODE *p, *q;
+        int navail;
+        int sz;
+        int off;
+        int num;
+        int i;
+
+        navail = NARGREGS - argofs;
+        sz = tsize(sym->stype, sym->sdf, sym->ssue) / SZINT;
+        off = ARGINIT/SZINT + argofs;
+        num = sz > navail ? navail : sz;
+        for (i = 0; i < num; i++) {
+                q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+                regno(q) = R0 + argofs++;
+                p = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+                regno(p) = SP;
+                p = block(PLUS, p, bcon(4*off++), INT, 0, MKSUE(INT));
+                p = block(UMUL, p, NIL, INT, 0, MKSUE(INT));
+                p = buildtree(ASSIGN, p, q);
+                ecomp(p);
+        }
+
+        *argofsp = argofs;
+}
+
+
+/*
+ * Beginning-of-function code:
+ *
+ * 'sp' is an array of indices in symtab for the arguments
+ * 'cnt' is the number of arguments
+ */
+void
+bfcode(struct symtab **sp, int cnt)
+{
+	union arglist *usym;
+	int saveallargs = 0;
+	int i, argofs = 0;
+
+        /*
+         * Detect if this function has ellipses and save all
+         * argument registers onto stack.
+         */
+        usym = cftnsp->sdf->dfun;
+        while (usym && usym->type != TNULL) {
+                if (usym->type == TELLIPSIS) {
+                        saveallargs = 1;
+                        break;
+                }
+                ++usym;
+        }
+
+	/* if returning a structure, move the hidden argument into a TEMP */
+        if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+		param_retstruct();
+		++argofs;
+	}
+
+        /* recalculate the arg offset and create TEMP moves */
+        for (i = 0; i < cnt; i++) {
+
+		if (sp[i] == NULL)
+			continue;
+
+                if ((argofs >= NARGREGS) && !xtemps)
+                        break;
+
+                if (argofs > NARGREGS) {
+                        putintemp(sp[i]);
+                } else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) {
+			param_struct(sp[i], &argofs);
+                } else if (DEUNSIGN(sp[i]->stype) == LONGLONG) {
+                        param_64bit(sp[i], &argofs, xtemps && !saveallargs);
+                } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) {
+			if (features(FEATURE_HARDFLOAT))
+	                        param_double(sp[i], &argofs,
+				    xtemps && !saveallargs);
+			else
+	                        param_64bit(sp[i], &argofs,
+				    xtemps && !saveallargs);
+                } else if (sp[i]->stype == FLOAT) {
+			if (features(FEATURE_HARDFLOAT))
+                        	param_float(sp[i], &argofs,
+				    xtemps && !saveallargs);
+			else
+                        	param_32bit(sp[i], &argofs,
+				    xtemps && !saveallargs);
+                } else {
+                        param_32bit(sp[i], &argofs, xtemps && !saveallargs);
+		}
+        }
+
+        /* if saveallargs, save the rest of the args onto the stack */
+        while (saveallargs && argofs < NARGREGS) {
+      		NODE *p, *q;
+		int off = ARGINIT/SZINT + argofs;
+		q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+		regno(q) = R0 + argofs++;
+		p = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+		regno(p) = FPREG;
+		p = block(PLUS, p, bcon(4*off), INT, 0, MKSUE(INT));
+		p = block(UMUL, p, NIL, INT, 0, MKSUE(INT));
+		p = buildtree(ASSIGN, p, q);
+		ecomp(p);
+	}
+
+}
+
+/*
+ * End-of-Function code:
+ */
+void
+efcode()
+{
+	NODE *p, *q;
+	int tempnr;
+
+	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+		return;
+
+	/*
+	 * At this point, the address of the return structure on
+	 * has been FORCEd to RETREG, which is R0.
+	 * We want to copy the contents from there to the address
+	 * we placed into the tempnode "rvnr".
+	 */
+
+	/* move the pointer out of R0 to a tempnode */
+	q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
+	q->n_rval = R0;
+	p = tempnode(0, PTR+STRTY, 0, cftnsp->ssue);
+	tempnr = regno(p);
+	p = buildtree(ASSIGN, p, q);
+	ecomp(p);
+
+	/* get the address from the tempnode */
+	q = tempnode(tempnr, PTR+STRTY, 0, cftnsp->ssue);
+	q = buildtree(UMUL, q, NIL);
+	
+	/* now, get the structure destination */
+	p = tempnode(rvnr, PTR+STRTY, 0, cftnsp->ssue);
+	p = buildtree(UMUL, p, NIL);
+
+	/* struct assignment */
+	p = buildtree(ASSIGN, p, q);
+	ecomp(p);
+}
+
+/*
+ * Beginning-of-code: finished generating function prologue
+ *
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+	SETOFF(autooff, SZINT);
+}
+
+/*
+ * End-of-job: called just before final exit.
+ */
+void
+ejobcode(int flag )
+{
+#define _MKSTR(x) #x
+#define MKSTR(x) _MKSTR(x) 
+#define OS MKSTR(TARGOS)
+	printf("\t.ident \"PCC: %s (%s)\"\n", PACKAGE_STRING, OS);
+}
+
+/*
+ * Beginning-of-job: called before compilation starts
+ *
+ * Initialise data structures specific for the local machine.
+ */
+void
+bjobcode()
+{
+}
+
+/*
+ * Compute the alignment of object with type 't'.
+ */
+int
+fldal(unsigned int t)
+{
+	uerror("illegal field type");
+	return(ALINT);
+}
+
+/*
+ * fix up type of field p
+ */
+void
+fldty(struct symtab *p)
+{
+}
+
+/*
+ * Build target-dependent switch tree/table.
+ *
+ * Return 1 if successfull, otherwise return 0 and the
+ * target-independent tree will be used.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+	return 0;
+}
+
+
+/*
+ * Straighten a chain of CM ops so that the CM nodes
+ * only appear on the left node.
+ *
+ *          CM               CM
+ *        CM  CM           CM  b
+ *       x y  a b        CM  a
+ *                      x  y
+ */
+static NODE *
+straighten(NODE *p)
+{
+	NODE *r = p->n_right;
+
+	if (p->n_op != CM || r->n_op != CM)
+		return p;
+
+	p->n_right = r->n_left;
+	r->n_left = p;
+
+	return r;
+}
+
+static NODE *
+reverse1(NODE *p, NODE *a)
+{
+	NODE *l = p->n_left;
+	NODE *r = p->n_right;
+
+	a->n_right = r;
+	p->n_left = a;
+
+	if (l->n_op == CM) {
+		return reverse1(l, p);
+	} else {
+		p->n_right = l;
+		return p;
+	}
+}
+
+/*
+ * Reverse a chain of CM ops
+ */
+static NODE *
+reverse(NODE *p)
+{
+	NODE *l = p->n_left;
+	NODE *r = p->n_right;
+
+	p->n_left = r;
+
+	if (l->n_op == CM)
+		return reverse1(l, p);
+
+	p->n_right = l;
+
+	return p;
+}
+
+
+/* push arg onto the stack */
+/* called by moveargs() */
+static NODE *
+pusharg(NODE *p, int *regp)
+{
+	NODE *q;
+	int sz;
+
+        /* convert to register size, if smaller */
+        sz = tsize(p->n_type, p->n_df, p->n_sue);
+        if (sz < SZINT)
+                p = block(SCONV, p, NIL, INT, 0, MKSUE(INT));
+
+        q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+        regno(q) = SP;
+
+	if (szty(p->n_type) == 1) {
+		++(*regp);
+		q = block(MINUSEQ, q, bcon(4), INT, 0, MKSUE(INT));
+	} else {
+		(*regp) += 2;
+		q = block(MINUSEQ, q, bcon(8), INT, 0, MKSUE(INT));
+	}
+
+	q = block(UMUL, q, NIL, p->n_type, p->n_df, p->n_sue);
+
+	return buildtree(ASSIGN, q, p);
+}
+
+/* setup call stack with 32-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_32bit(NODE *p, int *regp)
+{
+	int reg = *regp;
+	NODE *q;
+
+	q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue);
+	regno(q) = reg++;
+	q = buildtree(ASSIGN, q, p);
+
+	*regp = reg;
+	return q;
+}
+
+/* setup call stack with 64-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_64bit(NODE *p, int *regp)
+{
+        int reg = *regp;
+        NODE *q, *r;
+
+#if ALLONGLONG == 64
+        /* alignment */
+        ++reg;
+        reg &= ~1;
+	*regp = reg;
+#endif
+
+        if (reg > R3) {
+                q = pusharg(p, regp);
+	} else if (reg == R3) {
+		/* half in and half out of the registers */
+		r = tcopy(p);
+		if (!features(FEATURE_BIGENDIAN)) {
+			q = block(SCONV, p, NIL, INT, 0, MKSUE(INT));
+			q = movearg_32bit(q, regp);     /* little-endian */
+			r = buildtree(RS, r, bcon(32));
+			r = block(SCONV, r, NIL, INT, 0, MKSUE(INT));
+			r = pusharg(r, regp); /* little-endian */
+		} else {
+			q = buildtree(RS, p, bcon(32));
+			q = block(SCONV, q, NIL, INT, 0, MKSUE(INT));
+			q = movearg_32bit(q, regp);     /* big-endian */
+			r = block(SCONV, r, NIL, INT, 0, MKSUE(INT));
+			r = pusharg(r, regp); /* big-endian */
+		}
+		q = straighten(block(CM, q, r, p->n_type, p->n_df, p->n_sue));
+        } else {
+                q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue);
+                regno(q) = R0R1 + (reg - R0);
+                q = buildtree(ASSIGN, q, p);
+                *regp = reg + 2;
+        }
+
+        return q;
+}
+
+/* setup call stack with float/double argument */
+/* called from moveargs() */
+static NODE *
+movearg_float(NODE *p, int *regp)
+{
+	NODE *q, *r;
+	TWORD ty = INCREF(p->n_type);
+	int tmpnr;
+
+        /*
+         * Floats are passed in the general registers for
+	 * compatibily with libraries compiled to handle soft-float.
+         */
+
+	if (xtemps) {
+		/* bounce on TOS */
+		r = block(REG, NIL, NIL, ty, p->n_df, p->n_sue);
+		regno(r) = SP;
+		r = block(PLUS, r, bcon(-4), ty, p->n_df, p->n_sue);
+		r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_sue);
+		r = buildtree(ASSIGN, r, p);
+		ecomp(r);
+
+		/* bounce into temp */
+		r = block(REG, NIL, NIL, PTR+INT, 0, MKSUE(INT));
+		regno(r) = SP;
+		r = block(PLUS, r, bcon(-8), PTR+INT, 0, MKSUE(INT));
+		r = block(UMUL, r, NIL, INT, 0, MKSUE(INT));
+		q = tempnode(0, INT, 0, MKSUE(INT));
+		tmpnr = regno(q);
+		r = buildtree(ASSIGN, q, r);
+		ecomp(r);
+	} else {
+		/* copy directly into temp */
+		q = tempnode(0, p->n_type, p->n_df, p->n_sue);
+		tmpnr = regno(q);
+		r = buildtree(ASSIGN, q, p);
+		ecomp(r);
+	}
+
+	/* copy from temp to register parameter */
+	r = tempnode(tmpnr, INT, 0, MKSUE(INT));
+	q = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+	regno(q) = (*regp)++;
+	p = buildtree(ASSIGN, q, r);
+
+	return p;
+}
+
+/* setup call stack with float/double argument */
+/* called from moveargs() */
+static NODE *
+movearg_double(NODE *p, int *regp)
+{
+	NODE *q, *r;
+	TWORD ty = INCREF(p->n_type);
+	int tmpnr;
+
+	if (xtemps) {
+		/* bounce on TOS */
+		r = block(REG, NIL, NIL, ty, p->n_df, p->n_sue);
+		regno(r) = SP;
+		r = block(PLUS, r, bcon(-8), ty, p->n_df, p->n_sue);
+		r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_sue);
+		r = buildtree(ASSIGN, r, p);
+		ecomp(r);
+
+		/* bounce into temp */
+		r = block(REG, NIL, NIL, PTR+LONGLONG, 0, MKSUE(LONGLONG));
+		regno(r) = SP;
+		r = block(PLUS, r, bcon(-8), PTR+LONGLONG, 0, MKSUE(LONGLONG));
+		r = block(UMUL, r, NIL, LONGLONG, 0, MKSUE(LONGLONG));
+		q = tempnode(0, LONGLONG, 0, MKSUE(LONGLONG));
+		tmpnr = regno(q);
+		r = buildtree(ASSIGN, q, r);
+		ecomp(r);
+	} else {
+		/* copy directly into temp */
+		q = tempnode(0, p->n_type, p->n_df, p->n_sue);
+		tmpnr = regno(q);
+		r = buildtree(ASSIGN, q, p);
+		ecomp(r);
+	}
+
+	/* copy from temp to register parameter */
+	r = tempnode(tmpnr, LONGLONG, 0, MKSUE(LONGLONG));
+	q = block(REG, NIL, NIL, LONGLONG, 0, MKSUE(LONGLONG));
+	regno(q) = R0R1 - R0 + (*regp);
+	p = buildtree(ASSIGN, q, r);
+
+        (*regp) += 2;
+
+	return p;
+}
+
+
+/* setup call stack with a structure */
+/* called from moveargs() */
+static NODE *
+movearg_struct(NODE *p, int *regp)
+{
+	int reg = *regp;
+	NODE *l, *q, *t, *r;
+	int tmpnr;
+	int navail;
+	int num;
+	int sz;
+	int ty;
+	int i;
+
+	assert(p->n_op == STARG);
+
+	navail = NARGREGS - (reg - R0);
+	navail = navail < 0 ? 0 : navail;
+	sz = tsize(p->n_type, p->n_df, p->n_sue) / SZINT;
+	num = sz > navail ? navail : sz;
+
+	/* remove STARG node */
+	l = p->n_left;
+	nfree(p);
+	ty = l->n_type;
+
+	/*
+	 * put it into a TEMP, rather than tcopy(), since the tree
+	 * in p may have side-affects
+	 */
+	t = tempnode(0, ty, l->n_df, l->n_sue);
+	tmpnr = regno(t);
+	q = buildtree(ASSIGN, t, l);
+
+	/* copy structure into registers */
+	for (i = 0; i < num; i++) {
+                t = tempnode(tmpnr, ty, 0, MKSUE(PTR+ty));
+                t = block(SCONV, t, NIL, PTR+INT, 0, MKSUE(PTR+INT));
+                t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKSUE(PTR+INT));
+                t = buildtree(UMUL, t, NIL);
+
+                r = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
+                regno(r) = reg++;
+                r = buildtree(ASSIGN, r, t);
+
+                q = block(CM, q, r, INT, 0, MKSUE(INT));
+	}
+
+	/* put the rest of the structure on the stack */
+	for (i = num; i < sz; i++) {
+                t = tempnode(tmpnr, ty, 0, MKSUE(PTR+ty));
+                t = block(SCONV, t, NIL, PTR+INT, 0, MKSUE(PTR+INT));
+                t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKSUE(PTR+INT));
+                t = buildtree(UMUL, t, NIL);
+                r = pusharg(t, &reg);
+                q = block(CM, q, r, INT, 0, MKSUE(INT));
+	}
+
+	q = reverse(q);
+
+	*regp = reg;
+	return q;
+}
+
+
+static NODE *
+moveargs(NODE *p, int *regp)
+{
+        NODE *r, **rp;
+        int reg;
+
+        if (p->n_op == CM) {
+                p->n_left = moveargs(p->n_left, regp);
+                r = p->n_right;
+                rp = &p->n_right;
+        } else {
+                r = p;
+                rp = &p;
+        }
+
+        reg = *regp;
+
+        if (reg > R3 && r->n_op != STARG) {
+                *rp = pusharg(r, regp);
+	} else if (r->n_op == STARG) {
+		*rp = movearg_struct(r, regp);
+        } else if (DEUNSIGN(r->n_type) == LONGLONG) {
+                *rp = movearg_64bit(r, regp);
+	} else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
+		*rp = movearg_double(r, regp);
+	} else if (r->n_type == FLOAT) {
+		*rp = movearg_float(r, regp);
+        } else {
+                *rp = movearg_32bit(r, regp);
+        }
+
+	return straighten(p);
+}
+
+/*
+ * Fixup arguments to pass pointer-to-struct as first argument.
+ *
+ * called from funcode().
+ */
+static NODE *
+retstruct(NODE *p)
+{
+        NODE *l, *r, *t, *q;
+        TWORD ty;
+
+        l = p->n_left;
+        r = p->n_right;
+
+        ty = DECREF(l->n_type) - FTN;
+
+//      assert(tsize(ty, l->n_df, l->n_sue) == SZINT);
+
+        /* structure assign */
+        q = tempnode(0, ty, l->n_df, l->n_sue);
+        q = buildtree(ADDROF, q, NIL);
+
+        /* insert hidden assignment at beginning of list */
+        if (r->n_op != CM) {
+                p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_sue);
+        } else {
+                for (t = r; t->n_left->n_op == CM; t = t->n_left)
+                        ;
+                t->n_left = block(CM, q, t->n_left, INCREF(ty),
+                            l->n_df, l->n_sue);
+        }
+
+        return p;
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+	int reg = R0;
+
+	if (p->n_type == STRTY+FTN || p->n_type == UNIONTY+FTN) {
+		p = retstruct(p);
+		reg = R1;
+	}
+
+	p->n_right = moveargs(p->n_right, &reg);
+
+	if (p->n_right == NULL)
+		p->n_op += (UCALL - CALL);
+
+	return p;
+}
Index: uspace/app/pcc/arch/arm/local.c
===================================================================
--- uspace/app/pcc/arch/arm/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/arm/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,816 @@
+/*      $Id: local.c,v 1.24 2011/01/21 21:47:58 ragge Exp $    */
+/*
+ * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
+ * 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.
+ */
+
+/*
+ * We define location operations which operate on the expression tree
+ * during the first pass (before sending to the backend for code generation.)
+ */
+
+#include <assert.h>
+
+#include "pass1.h"
+
+extern void defalign(int);
+
+/*
+ * clocal() is called to do local transformations on
+ * an expression tree before being sent to the backend.
+ */
+NODE *
+clocal(NODE *p)
+{
+	struct symtab *q;
+	NODE *l, *r, *t;
+	int o;
+	int ty;
+	int tmpnr, isptrvoid = 0;
+	char *n;
+
+	o = p->n_op;
+	switch (o) {
+
+	case STASG:
+
+		l = p->n_left;
+		r = p->n_right;
+		if (r->n_op != STCALL && r->n_op != USTCALL)
+			return p;
+
+		/* assign left node as first argument to function */
+		nfree(p);
+		t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_sue);
+		l->n_rval = R0;
+		l = buildtree(ADDROF, l, NIL);
+		l = buildtree(ASSIGN, t, l);
+
+		if (r->n_right->n_op != CM) {
+			r->n_right = block(CM, l, r->n_right,
+			    INT, 0, MKSUE(INT));
+		} else {
+			for (t = r->n_right; t->n_left->n_op == CM;
+			    t = t->n_left)
+				;
+			t->n_left = block(CM, l, t->n_left,
+			    INT, 0, MKSUE(INT));
+		}
+		return r;
+
+	case CALL:
+	case STCALL:
+	case USTCALL:
+                if (p->n_type == VOID)
+                        break;
+                /*
+                 * if the function returns void*, ecode() invokes
+                 * delvoid() to convert it to uchar*.
+                 * We just let this happen on the ASSIGN to the temp,
+                 * and cast the pointer back to void* on access
+                 * from the temp.
+                 */
+                if (p->n_type == PTR+VOID)
+                        isptrvoid = 1;
+                r = tempnode(0, p->n_type, p->n_df, p->n_sue);
+                tmpnr = regno(r);
+                r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_sue);
+
+                p = tempnode(tmpnr, r->n_type, r->n_df, r->n_sue);
+                if (isptrvoid) {
+                        p = block(PCONV, p, NIL, PTR+VOID,
+                            p->n_df, MKSUE(PTR+VOID));
+                }
+                p = buildtree(COMOP, r, p);
+                break;
+
+	case NAME:
+		if ((q = p->n_sp) == NULL)
+			return p;
+		if (blevel == 0)
+			return p;
+
+		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 REGISTER:
+                        p->n_op = REG;
+                        p->n_lval = 0;
+                        p->n_rval = q->soffset;
+                        break;
+                case STATIC:
+                        if (q->slevel > 0) {
+				p->n_lval = 0;
+				p->n_sp = q;
+			}
+			/* FALL-THROUGH */
+		default:
+			ty = p->n_type;
+			n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname;
+			if (strncmp(n, "__builtin", 9) == 0)
+				break;
+			p = block(ADDROF, p, NIL, INCREF(ty), p->n_df, p->n_sue);
+			p = block(UMUL, p, NIL, ty, p->n_df, p->n_sue);
+			break;
+		}
+		break;
+
+	case STNAME:
+		if ((q = p->n_sp) == NULL)
+			return p;
+		if (q->sclass != STNAME)
+			return p;
+		ty = p->n_type;
+		p = block(ADDROF, p, NIL, INCREF(ty),
+		    p->n_df, p->n_sue);
+		p = block(UMUL, p, NIL, ty, p->n_df, p->n_sue);
+		break;
+
+        case FORCE:
+                /* put return value in return reg */
+                p->n_op = ASSIGN;
+                p->n_right = p->n_left;
+                p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
+                p->n_left->n_rval = p->n_left->n_type == BOOL ? 
+                    RETREG(BOOL_TYPE) : RETREG(p->n_type);
+                break;
+
+	case PMCONV:
+	case PVCONV:
+		nfree(p);
+		return buildtree(o == PMCONV ? MUL : DIV, p->n_left, p->n_right);
+
+	case SCONV:
+		l = p->n_left;
+		if (p->n_type == l->n_type) {
+			nfree(p);
+			return l;
+		}
+                if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+                    btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
+                        if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+                            l->n_type != FLOAT && l->n_type != DOUBLE &&
+                            l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+                                if (l->n_op == NAME || l->n_op == UMUL ||
+                                    l->n_op == TEMP) {
+                                        l->n_type = p->n_type;
+                                        nfree(p);
+                                        return l;
+                                }
+                        }
+                }
+
+                if (l->n_op == ICON) {
+                        CONSZ val = l->n_lval;
+
+                        if (!ISPTR(p->n_type)) /* Pointers don't need to be conv'd */
+                        switch (p->n_type) {
+                        case BOOL:
+                                l->n_lval = l->n_lval != 0;
+                                break;
+                        case CHAR:
+                                l->n_lval = (char)val;
+                                break;
+                        case UCHAR:
+                                l->n_lval = val & 0377;
+                                break;
+                        case SHORT:
+                                l->n_lval = (short)val;
+                                break;
+                        case USHORT:
+                                l->n_lval = val & 0177777;
+                                break;
+                        case ULONG:
+                        case UNSIGNED:
+                                l->n_lval = val & 0xffffffff;
+                                break;
+                        case 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", l->n_type);
+                        }
+			l->n_type = p->n_type;
+			l->n_sue = MKSUE(p->n_type);
+                        nfree(p);
+                        return l;
+                } else if (p->n_op == FCON) {
+			l->n_lval = l->n_dcon;
+			l->n_sp = NULL;
+			l->n_op = ICON;
+			l->n_type = p->n_type;
+			l->n_sue = MKSUE(p->n_type);
+			nfree(p);
+			return clocal(l);
+		}
+                if ((DEUNSIGN(p->n_type) == CHAR ||
+                    DEUNSIGN(p->n_type) == SHORT) &&
+                    (l->n_type == FLOAT || l->n_type == DOUBLE ||
+                    l->n_type == LDOUBLE)) {
+                        p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
+                        p->n_left->n_type = INT;
+                        return p;
+                }
+		break;
+
+	case PCONV:
+		l = p->n_left;
+		if (l->n_op == ICON) {
+			l->n_lval = (unsigned)l->n_lval;
+			goto delp;
+		}
+		if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
+			p->n_left = block(SCONV, l, NIL,
+			    UNSIGNED, 0, MKSUE(UNSIGNED));
+			break;
+		}
+		if (l->n_op == SCONV)
+			break;
+		if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
+			goto delp;
+		if (p->n_type > BTMASK && l->n_type > BTMASK)
+			goto delp;
+		break;
+
+	delp:
+		l->n_type = p->n_type;
+		l->n_qual = p->n_qual;
+		l->n_df = p->n_df;
+		l->n_sue = p->n_sue;
+		nfree(p);
+		p = l;
+		break;
+	}
+
+	return p;
+}
+
+/*
+ * Called before sending the tree to the backend.
+ */
+void
+myp2tree(NODE *p)
+{
+	struct symtab *sp;
+
+	if (p->n_op != FCON)
+		return;
+
+#define IALLOC(sz)	(isinlining ? permalloc(sz) : tmpalloc(sz))
+
+	sp = IALLOC(sizeof(struct symtab));
+	sp->sclass = STATIC;
+	sp->ssue = MKSUE(p->n_type);
+	sp->slevel = 1; /* fake numeric label */
+	sp->soffset = getlab();
+	sp->sflags = 0;
+	sp->stype = p->n_type;
+	sp->squal = (CON >> TSHIFT);
+
+	defloc(sp);
+	ninval(0, sp->ssue->suesize, p);
+
+	p->n_op = NAME;
+	p->n_lval = 0;	
+	p->n_sp = sp;
+
+}
+
+/*
+ * Called during the first pass to determine if a NAME can be addressed.
+ *
+ * Return nonzero if supported, otherwise return 0.
+ */
+int
+andable(NODE *p)
+{
+	if (blevel == 0)
+		return 1;
+	if (ISFTN(p->n_type))
+		return 1;
+	return 0;
+}
+
+/*
+ * Called just after function arguments are built.  Re-initialize the
+ * offset of the arguments on the stack.
+ * Is this necessary anymore?  bfcode() is called immediately after.
+ */
+void
+cendarg()
+{
+	autooff = AUTOINIT;
+}
+
+/*
+ * Return 1 if a variable of type 't' is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+	if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+		return 0; /* not yet */
+	return 1;
+}
+
+/*
+ * Used for generating pointer offsets into structures and arrays.
+ *
+ * For a pointer of type 't', generate an the offset 'off'.
+ */
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
+{
+	return bcon(off/SZCHAR);
+}
+
+/*
+ * Allocate bits from the stack for dynamic-sized arrays.
+ *
+ * 'p' is the tree which represents the type being allocated.
+ * 'off' is the number of 'p's to be allocated.
+ * 't' is the storeable node where the address is written.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+	NODE *sp;
+
+	p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
+
+	/* sub the size from sp */
+	sp = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
+	sp->n_lval = 0;
+	sp->n_rval = SP;
+	ecomp(buildtree(MINUSEQ, sp, p));
+
+	/* save the address of sp */
+	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
+	sp->n_lval = 0;
+	sp->n_rval = SP;
+	t->n_type = sp->n_type;
+	ecomp(buildtree(ASSIGN, t, sp));
+}
+
+/*
+ * Print out a string of characters.
+ * Assume that the assembler understands C-style escape
+ * sequences.
+ */
+void
+instring(struct symtab *sp)
+{
+	char *s, *str;
+
+	defloc(sp);
+	str = sp->sname;
+
+	/* 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 = 0, inval = 0;
+
+/*
+ * set 'fsz' bits in sequence to zero.
+ */
+void
+zbits(OFFSZ off, int fsz)
+{
+	int m;
+
+	if (idebug)
+		printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
+	if ((m = (inbits % SZCHAR))) {
+		m = SZCHAR - m;
+		if (fsz < m) {
+			inbits += fsz;
+			return;
+		} else {
+			fsz -= m;
+			printf("\t.byte %d\n", inval);
+			inval = inbits = 0;
+		}
+	}
+	if (fsz >= SZCHAR) {
+		printf("\t.space %d\n", fsz/SZCHAR);
+		fsz -= (fsz/SZCHAR) * SZCHAR;
+	}
+	if (fsz) {
+		inval = 0;
+		inbits = fsz;
+	}
+}
+
+/*
+ * Initialize a bitfield.
+ */
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+	if (idebug)
+		printf("infld off %lld, fsz %d, val %lld inbits %d\n",
+		    off, fsz, val, inbits);
+	val &= (1 << fsz)-1;
+	while (fsz + inbits >= SZCHAR) {
+		inval |= (val << inbits);
+		printf("\t.byte %d\n", inval & 255);
+		fsz -= (SZCHAR - inbits);
+		val >>= (SZCHAR - inbits);
+		inval = inbits = 0;
+	}
+	if (fsz) {
+		inval |= (val << inbits);
+		inbits += fsz;
+	}
+}
+
+/*
+ * Print an integer 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; int i[2]; } u;
+	struct symtab *q;
+	TWORD t;
+	int i, j;
+
+	t = p->n_type;
+	if (t > BTMASK)
+		t = INT; /* pointer */
+
+	/*
+	 * The target-independent code does rewrite the NAME nodes
+	 * to ICONS after we prefixed the NAME nodes with ADDROF.
+	 * We do it here.  Maybe this is too much of a hack!
+	 */
+	if (p->n_op == ADDROF && p->n_left->n_op == NAME) {
+		p = p->n_left;
+		p->n_op = ICON;
+	}
+
+	if (p->n_op != ICON && p->n_op != FCON)
+		cerror("ninval: init node not constant: node %p", p);
+
+	if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
+		uerror("element not constant");
+
+	switch (t) {
+	case LONGLONG:
+	case ULONGLONG:
+		i = (p->n_lval >> 32);
+		j = (p->n_lval & 0xffffffff);
+		p->n_type = INT;
+		if (features(FEATURE_BIGENDIAN)) {
+			p->n_lval = i;
+			ninval(off+32, 32, p);
+			p->n_lval = j;
+			ninval(off, 32, p);
+		} else {
+			p->n_lval = j;
+			ninval(off, 32, p);
+			p->n_lval = i;
+			ninval(off+32, 32, p);
+		}
+		break;
+	case INT:
+	case UNSIGNED:
+		printf("\t.word 0x%x", (int)p->n_lval);
+		if ((q = p->n_sp) != NULL) {
+			if ((q->sclass == STATIC && q->slevel > 0)) {
+				printf("+" LABFMT, q->soffset);
+			} else
+				printf("+%s",
+				    q->soname ? q->soname : exname(q->sname));
+		}
+		printf("\n");
+		break;
+	case SHORT:
+	case USHORT:
+		printf("\t.short 0x%x\n", (int)p->n_lval & 0xffff);
+		break;
+	case BOOL:
+		if (p->n_lval > 1)
+			p->n_lval = p->n_lval != 0;
+		/* FALLTHROUGH */
+	case CHAR:
+	case UCHAR:
+		printf("\t.byte %d\n", (int)p->n_lval & 0xff);
+		break;
+	case LDOUBLE:
+	case DOUBLE:
+		u.d = (double)p->n_dcon;
+#if defined(HOST_BIG_ENDIAN)
+		if (features(FEATURE_BIGENDIAN))
+#else
+		if (!features(FEATURE_BIGENDIAN))
+#endif
+			printf("\t.word\t0x%x\n\t.word\t0x%x\n",
+			    u.i[0], u.i[1]);
+		else
+			printf("\t.word\t0x%x\n\t.word\t0x%x\n",
+			    u.i[1], u.i[0]);
+		break;
+	case FLOAT:
+		u.f = (float)p->n_dcon;
+		printf("\t.word\t0x%x\n", u.i[0]);
+		break;
+	default:
+		cerror("ninval");
+	}
+}
+
+/*
+ * Prefix a leading underscore to a global variable (if necessary).
+ */
+char *
+exname(char *p)
+{
+	return (p == NULL ? "" : p);
+}
+
+/*
+ * Map types which are not defined on the local machine.
+ */
+TWORD
+ctype(TWORD type)
+{
+	switch (BTYPE(type)) {
+	case LONG:
+		MODTYPE(type,INT);
+		break;
+	case ULONG:
+		MODTYPE(type,UNSIGNED);
+		break;
+	}
+	return (type);
+}
+
+/*
+ * Before calling a function do any tree re-writing for the local machine.
+ *
+ * 'p' is the function tree (NAME)
+ * 'q' is the CM-separated list of arguments.
+ */
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+/*
+ * While handling uninitialised variables, handle variables marked extern.
+ */
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+	int off;
+
+	off = tsize(sp->stype, sp->sdf, sp->ssue);
+	off = (off+(SZCHAR-1))/SZCHAR;
+	printf("        .%scomm ", sp->sclass == STATIC ? "l" : "");
+	if (sp->slevel == 0)
+		printf("%s,0%o\n",
+		    sp->soname ? sp->soname : exname(sp->sname), off);
+	else
+		printf(LABFMT ",0%o\n", sp->soffset, off);
+}
+
+/*
+ * va_start(ap, last) implementation.
+ *
+ * f is the NAME node for this builtin function.
+ * a is the argument list containing:
+ *	   CM
+ *	ap   last
+ */
+NODE *
+arm_builtin_stdarg_start(NODE *f, NODE *a)
+{
+        NODE *p, *q;
+        int sz = 1;
+
+        /* check num args and type */
+        if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+            !ISPTR(a->n_left->n_type))
+                goto bad;
+
+        /* must first deal with argument size; use int size */
+        p = a->n_right;
+        if (p->n_type < INT) {
+                /* round up to word */
+                sz = SZINT / tsize(p->n_type, p->n_df, p->n_sue);
+        }
+
+        p = buildtree(ADDROF, p, NIL);  /* address of last arg */
+        p = optim(buildtree(PLUS, p, bcon(sz)));
+        q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
+        q = buildtree(CAST, q, p);
+        p = q->n_right;
+        nfree(q->n_left);
+        nfree(q);
+        p = buildtree(ASSIGN, a->n_left, p);
+        tfree(f);
+        nfree(a);
+
+        return p;
+
+bad:
+        uerror("bad argument to __builtin_stdarg_start");
+        return bcon(0);
+}
+
+NODE *
+arm_builtin_va_arg(NODE *f, NODE *a)
+{
+        NODE *p, *q, *r;
+        int sz, tmpnr;
+
+        /* check num args and type */
+        if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+            !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
+                goto bad;
+
+        r = a->n_right;
+
+        /* get type size */
+        sz = tsize(r->n_type, r->n_df, r->n_sue) / SZCHAR;
+        if (sz < SZINT/SZCHAR) {
+                werror("%s%s promoted to int when passed through ...",
+                        ISUNSIGNED(r->n_type) ? "unsigned " : "",
+                        DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
+                sz = SZINT/SZCHAR;
+        }
+
+        /* alignment */
+        p = tcopy(a->n_left);
+        if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
+                p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1));
+                p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_sue);
+        }
+
+        /* create a copy to a temp node */
+        q = tempnode(0, p->n_type, p->n_df, p->n_sue);
+        tmpnr = regno(q);
+        p = buildtree(ASSIGN, q, p);
+
+        q = tempnode(tmpnr, p->n_type, p->n_df,p->n_sue);
+        q = buildtree(PLUS, q, bcon(sz));
+        q = buildtree(ASSIGN, a->n_left, q);
+
+        q = buildtree(COMOP, p, q);
+
+        nfree(a->n_right);
+        nfree(a);
+        nfree(f);
+
+        p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_sue);
+        p = buildtree(UMUL, p, NIL);
+        p = buildtree(COMOP, q, p);
+
+        return p;
+
+bad:
+        uerror("bad argument to __builtin_va_arg");
+        return bcon(0);
+}
+
+NODE *
+arm_builtin_va_end(NODE *f, NODE *a)
+{
+	tfree(f);
+	tfree(a);
+ 
+	return bcon(0);
+}
+
+NODE *
+arm_builtin_va_copy(NODE *f, NODE *a)
+{
+        if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
+                goto bad;
+        tfree(f);
+        f = buildtree(ASSIGN, a->n_left, a->n_right);
+        nfree(a);
+        return f;
+
+bad:
+        uerror("bad argument to __buildtin_va_copy");
+        return bcon(0);
+}
+
+char *nextsect;
+static int constructor;
+static int destructor;
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+	char *a2 = pragtok(NULL);
+
+	if (strcmp(str, "tls") == 0) { 
+		uerror("thread-local storage not supported for this target");
+		return 1;
+	} 
+	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") || s2 == NULL)
+		return 0;
+	nextsect = newstring(s2, strlen(s2));
+	return 1;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+	if ((constructor || destructor) && (sp->sclass != PARAM)) {
+		printf("\t.section .%ctors,\"aw\",@progbits\n",
+		    constructor ? 'c' : 'd');
+		printf("\t.p2align 2\n");
+		printf("\t.long %s\n", exname(sp->sname));
+		printf("\t.previous\n");
+		constructor = destructor = 0;
+	}
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
Index: uspace/app/pcc/arch/arm/local2.c
===================================================================
--- uspace/app/pcc/arch/arm/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/arm/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1496 @@
+/*      $Id: local2.c,v 1.34 2008/12/14 21:16:58 ragge Exp $    */
+/*
+ * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
+ * 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 <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "pass2.h"
+
+extern void defalign(int);
+
+#define	exname(x) x
+
+char *rnames[] = {
+	"r0", "r1", "r2", "r3","r4","r5", "r6", "r7",
+	"r8", "r9", "r10", "fp", "ip", "sp", "lr", "pc",
+	"r0r1", "r1r2", "r2r3", "r3r4", "r4r5", "r5r6",
+	"r6r7", "r7r8", "r8r9", "r9r10",
+	"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+};
+
+/*
+ * Handling of integer constants.  We have 8 bits + an even
+ * number of rotates available as a simple immediate.
+ * If a constant isn't trivially representable, use an ldr
+ * and a subsequent sequence of orr operations.
+ */
+
+static int
+trepresent(const unsigned int val)
+{
+	int i;
+#define rotate_left(v, n) (v << n | v >> (32 - n))
+
+	for (i = 0; i < 32; i += 2)
+		if (rotate_left(val, i) <= 0xff)
+			return 1;
+	return 0;
+}
+
+/*
+ * Return values are:
+ * 0 - output constant as is (should be covered by trepresent() above)
+ * 1 - 4 generate 1-4 instructions as needed.
+ */
+static int
+encode_constant(int constant, int *values)
+{
+	int tmp = constant;
+	int i = 0;
+	int first_bit, value;
+
+	while (tmp) {
+		first_bit = ffs(tmp);
+		first_bit -= 1; /* ffs indexes from 1, not 0 */
+		first_bit &= ~1; /* must use even bit offsets */
+
+		value = tmp & (0xff << first_bit);
+		values[i++] = value;
+		tmp &= ~value;
+	}
+	return i;
+}
+
+#if 0
+static void
+load_constant(NODE *p)
+{
+	int v = p->n_lval & 0xffffffff;
+	int reg = DECRA(p->n_reg, 1);
+
+	load_constant_into_reg(reg, v);
+}
+#endif
+
+static void
+load_constant_into_reg(int reg, int v)
+{
+	if (trepresent(v))
+		printf("\tmov %s,#%d\n", rnames[reg], v);
+	else if (trepresent(-v))
+		printf("\tmvn %s,#%d\n", rnames[reg], -v);
+	else {
+		int vals[4], nc, i;
+
+		nc = encode_constant(v, vals);
+		for (i = 0; i < nc; i++) {
+			if (i == 0) {
+				printf("\tmov %s,#%d" COM "load constant %d\n",
+				    rnames[reg], vals[i], v);
+			} else {
+				printf("\torr %s,%s,#%d\n",	
+				    rnames[reg], rnames[reg], vals[i]);
+			}
+		}
+	}
+}
+
+static TWORD ftype;
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog *ipp)
+{
+	int addto;
+
+#ifdef PCC_DEBUG
+	if (x2debug)
+		printf("offcalc: p2maxautooff=%d\n", p2maxautooff);
+#endif
+
+	addto = p2maxautooff;
+
+#if 0
+	addto += 7;
+	addto &= ~7;
+#endif
+
+#ifdef PCC_DEBUG
+	if (x2debug)
+		printf("offcalc: addto=%d\n", addto);
+#endif
+
+	addto -= AUTOINIT / SZCHAR;
+
+	return addto;
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+	int addto;
+	int vals[4], nc, i;
+
+#ifdef PCC_DEBUG
+	if (x2debug)
+		printf("prologue: type=%d, lineno=%d, name=%s, vis=%d, ipptype=%d, regs=0x%x, autos=%d, tmpnum=%d, lblnum=%d\n",
+			ipp->ipp_ip.type,
+			ipp->ipp_ip.lineno,
+			ipp->ipp_name,
+			ipp->ipp_vis,
+			ipp->ipp_type,
+			ipp->ipp_regs[0],
+			ipp->ipp_autos,
+			ipp->ip_tmpnum,
+			ipp->ip_lblnum);
+#endif
+
+	ftype = ipp->ipp_type;
+
+#if 0
+	printf("\t.align 2\n");
+	if (ipp->ipp_vis)
+		printf("\t.global %s\n", exname(ipp->ipp_name));
+	printf("\t.type %s,%%function\n", exname(ipp->ipp_name));
+#endif
+	printf("%s:\n", exname(ipp->ipp_name));
+
+	/*
+	 * We here know what register to save and how much to 
+	 * add to the stack.
+	 */
+	addto = offcalc(ipp);
+
+	printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], 16);
+	printf("\tmov %s,%s\n", rnames[IP], rnames[SP]);
+	printf("\tstmfd %s!,{%s,%s,%s,%s}\n", rnames[SP], rnames[FP],
+	    rnames[IP], rnames[LR], rnames[PC]);
+	printf("\tsub %s,%s,#4\n", rnames[FP], rnames[IP]);
+
+	if (addto == 0)
+		return;
+
+	if (trepresent(addto)) {
+		printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], addto);
+	} else {
+		nc = encode_constant(addto, vals);
+		for (i = 0; i < nc; i++)
+			printf("\tsub %s,%s,#%d\n",
+			    rnames[SP], rnames[SP], vals[i]);
+	}
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+	if (ipp->ipp_ip.ip_lbl == 0)
+		return; /* no code needs to be generated */
+
+	/* struct return needs special treatment */
+	if (ftype == STRTY || ftype == UNIONTY) {
+		assert(0);
+	} else {
+		printf("\tldmea %s,{%s,%s,%s}\n", rnames[FP], rnames[FP],
+		    rnames[SP], rnames[PC]);
+		printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], 16);
+	}
+	printf("\t.size %s,.-%s\n", exname(ipp->ipp_name),
+	    exname(ipp->ipp_name));
+}
+
+
+/*
+ * these mnemonics match the order of the preprocessor decls
+ * EQ, NE, LE, LT, GE, GT, ULE, ULT, UGE, UGT
+ */
+
+static char *
+ccbranches[] = {
+	"beq",		/* branch if equal */
+	"bne",		/* branch if not-equal */
+	"ble",		/* branch if less-than-or-equal */
+	"blt",		/* branch if less-than */
+	"bge",		/* branch if greater-than-or-equal */
+	"bgt",		/* branch if greater-than */
+	/* what should these be ? */
+	"bls",		/* branch if lower-than-or-same */
+	"blo",		/* branch if lower-than */
+	"bhs",		/* branch if higher-than-or-same */
+	"bhi",		/* branch if higher-than */
+};
+
+/*
+ * 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 = "orr";
+		break;
+	case ER:
+		str = "eor";
+		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(NODE *p)
+{
+	switch(p->n_type) {
+		case CHAR:
+		case UCHAR:
+			return(1);
+
+		case SHORT:
+		case USHORT:
+			return(SZSHORT/SZCHAR);
+
+		case DOUBLE:
+			return(SZDOUBLE/SZCHAR);
+
+		case INT:
+		case UNSIGNED:
+		case LONG:
+		case ULONG:
+			return(SZINT/SZCHAR);
+
+		case LONGLONG:
+		case ULONGLONG:
+			return SZLONGLONG/SZCHAR;
+
+		default:
+			if (!ISPTR(p->n_type))
+				comperr("tlen type %d not pointer");
+			return SZPOINT(p->n_type)/SZCHAR;
+		}
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+	int o = p->n_op;
+	int s = getlab2();
+	int e = p->n_label;
+	int cb1, cb2;
+
+	if (o >= ULE)
+		o -= (ULE-LE);
+	switch (o) {
+	case NE:
+		cb1 = 0;
+		cb2 = NE;
+		break;
+	case EQ:
+		cb1 = NE;
+		cb2 = 0;
+		break;
+	case LE:
+	case LT:
+		cb1 = GT;
+		cb2 = LT;
+		break;
+	case GE:
+	case GT:
+		cb1 = LT;
+		cb2 = GT;
+		break;
+	
+	default:
+		cb1 = cb2 = 0; /* XXX gcc */
+	}
+	if (p->n_op >= ULE)
+		cb1 += 4, cb2 += 4;
+	expand(p, 0, "\tcmp UR,UL" COM "compare 64-bit values (upper)\n");
+	if (cb1) cbgen(cb1, s);
+	if (cb2) cbgen(cb2, e);
+	expand(p, 0, "\tcmp AR,AL" COM "(and lower)\n");
+	cbgen(p->n_op, e);
+	deflab(s);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+	CONSZ val;
+	int shft;
+
+        if (p->n_op == ASSIGN)
+                p = p->n_left;
+
+	if (features(FEATURE_BIGENDIAN))
+		shft = SZINT - UPKFSZ(p->n_rval) - UPKFOFF(p->n_rval);
+	else
+		shft = UPKFOFF(p->n_rval);
+
+        switch (**cp) {
+        case 'S':
+                printf("#%d", UPKFSZ(p->n_rval));
+                break;
+        case 'H':
+                printf("#%d", shft);
+                break;
+        case 'M':
+        case 'N':
+                val = (CONSZ)1 << UPKFSZ(p->n_rval);
+                --val;
+                val <<= shft;
+                printf("%lld", (**cp == 'M' ? val : ~val)  & 0xffffffff);
+                break;
+        default:
+                comperr("fldexpand");
+        }
+        return 1;
+}
+
+
+/*
+ * Structure assignment.
+ */
+static void
+stasg(NODE *p)
+{
+	NODE *l = p->n_left;
+	int val = l->n_lval;
+
+	/* R0 = dest, R1 = src, R2 = len */
+	load_constant_into_reg(R2, p->n_stsize);
+	if (l->n_op == OREG) {
+		if (R2TEST(regno(l))) {
+			int r = regno(l);
+			printf("\tadd %s,%s,lsl #%d\n",
+			    rnames[R0], rnames[R2UPK2(r)], R2UPK3(r));
+			printf("\tadd %s,%s,%s\n", rnames[R0], rnames[R0],
+			    rnames[R2UPK1(r)]);
+		} else  {
+			if (trepresent(val)) {
+				printf("\tadd %s,%s,#%d\n",
+				    rnames[R0], rnames[regno(l)], val);
+			} else {
+				load_constant_into_reg(R0, val);
+				printf("\tadd %s,%s,%s\n", rnames[R0],
+				    rnames[R0], rnames[regno(l)]);
+			}
+		}
+	} else if (l->n_op == NAME) {
+		cerror("not implemented");
+	}
+
+	printf("\tbl %s\n", exname("memcpy"));
+}
+
+static void
+shiftop(NODE *p)
+{
+	NODE *r = p->n_right;
+	TWORD ty = p->n_type;
+	char *shifttype;
+
+	if (p->n_op == LS && r->n_op == ICON && r->n_lval < 32) {
+		expand(p, INBREG, "\tmov A1,AL,lsr ");
+		printf(CONFMT COM "64-bit left-shift\n", 32 - r->n_lval);
+		expand(p, INBREG, "\tmov U1,UL,asl AR\n");
+		expand(p, INBREG, "\torr U1,U1,A1\n");
+		expand(p, INBREG, "\tmov A1,AL,asl AR\n");
+	} else if (p->n_op == LS && r->n_op == ICON && r->n_lval < 64) {
+		expand(p, INBREG, "\tmov A1,#0" COM "64-bit left-shift\n");
+		expand(p, INBREG, "\tmov U1,AL");
+		if (r->n_lval - 32 != 0)
+			printf(",asl " CONFMT, r->n_lval - 32);
+		printf("\n");
+	} else if (p->n_op == LS && r->n_op == ICON) {
+		expand(p, INBREG, "\tmov A1,#0" COM "64-bit left-shift\n");
+		expand(p, INBREG, "\tmov U1,#0\n");
+	} else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 32) {
+		expand(p, INBREG, "\tmov U1,UL,asl ");
+		printf(CONFMT COM "64-bit right-shift\n", 32 - r->n_lval);
+		expand(p, INBREG, "\tmov A1,AL,lsr AR\n");
+		expand(p, INBREG, "\torr A1,A1,U1\n");
+		if (ty == LONGLONG)
+			expand(p, INBREG, "\tmov U1,UL,asr AR\n");
+		else
+			expand(p, INBREG, "\tmov U1,UL,lsr AR\n");
+	} else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 64) {
+		if (ty == LONGLONG) {
+			expand(p, INBREG, "\tmvn U1,#1" COM "64-bit right-shift\n");
+			expand(p, INBREG, "\tmov A1,UL");
+			shifttype = "asr";
+		}else {
+			expand(p, INBREG, "\tmov U1,#0" COM "64-bit right-shift\n");
+			expand(p, INBREG, "\tmov A1,UL");
+			shifttype = "lsr";
+		}
+		if (r->n_lval - 32 != 0)
+			printf(",%s " CONFMT, shifttype, r->n_lval - 32);
+		printf("\n");
+	} else if (p->n_op == RS && r->n_op == ICON) {
+		expand(p, INBREG, "\tmov A1,#0" COM "64-bit right-shift\n");
+		expand(p, INBREG, "\tmov U1,#0\n");
+	}
+}
+
+/*
+ * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
+ */
+static void
+fpemul(NODE *p)
+{
+	NODE *l = p->n_left;
+	char *ch = NULL;
+
+	if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3";
+	else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3";
+	else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "adddf3";
+
+	else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3";
+	else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3";
+	else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subdf3";
+
+	else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3";
+	else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3";
+	else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "muldf3";
+
+	else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3";
+	else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3";
+	else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divdf3";
+
+	else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2";
+	else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2";
+	else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negdf2";
+
+	else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2";
+	else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2";
+	else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqdf2";
+
+	else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2";
+	else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2";
+	else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "nedf2";
+
+	else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2";
+	else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2";
+	else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "gedf2";
+
+	else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2";
+	else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2";
+	else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "ledf2";
+
+	else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2";
+	else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2";
+	else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gtdf2";
+
+	else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2";
+	else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2";
+	else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "ltdf2";
+
+	else if (p->n_op == SCONV && p->n_type == FLOAT) {
+		if (l->n_type == DOUBLE) ch = "truncdfsf2";
+		else if (l->n_type == LDOUBLE) ch = "truncdfsf2";
+		else if (l->n_type == ULONGLONG) ch = "floatunsdisf";
+		else if (l->n_type == LONGLONG) ch = "floatdisf";
+		else if (l->n_type == LONG) ch = "floatsisf";
+		else if (l->n_type == ULONG) ch = "floatunsisf";
+		else if (l->n_type == INT) ch = "floatsisf";
+		else if (l->n_type == UNSIGNED) ch = "floatunsisf";
+	} else if (p->n_op == SCONV && p->n_type == DOUBLE) {
+		if (l->n_type == FLOAT) ch = "extendsfdf2";
+		else if (l->n_type == LDOUBLE) ch = "trunctfdf2";
+		else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+		else if (l->n_type == LONGLONG) ch = "floatdidf";
+		else if (l->n_type == LONG) ch = "floatsidf";
+		else if (l->n_type == ULONG) ch = "floatunsidf";
+		else if (l->n_type == INT) ch = "floatsidf";
+		else if (l->n_type == UNSIGNED) ch = "floatunsidf";
+	} else if (p->n_op == SCONV && p->n_type == LDOUBLE) {
+		if (l->n_type == FLOAT) ch = "extendsfdf2";
+		else if (l->n_type == DOUBLE) ch = "extenddftd2";
+		else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+		else if (l->n_type == LONGLONG) ch = "floatdidf";
+		else if (l->n_type == LONG) ch = "floatsidf";
+		else if (l->n_type == ULONG) ch = "floatunsidf";
+		else if (l->n_type == INT) ch = "floatsidf";
+		else if (l->n_type == UNSIGNED) ch = "floatunsidf";
+	} else if (p->n_op == SCONV && p->n_type == ULONGLONG) {
+		if (l->n_type == FLOAT) ch = "fixunssfdi";
+		else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
+		else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
+	} else if (p->n_op == SCONV && p->n_type == LONGLONG) {
+		if (l->n_type == FLOAT) ch = "fixsfdi";
+		else if (l->n_type == DOUBLE) ch = "fixdfdi";
+		else if (l->n_type == LDOUBLE) ch = "fixdfdi";
+	} else if (p->n_op == SCONV && p->n_type == LONG) {
+		if (l->n_type == FLOAT) ch = "fixsfsi";
+		else if (l->n_type == DOUBLE) ch = "fixdfsi";
+		else if (l->n_type == LDOUBLE) ch = "fixdfsi";
+	} else if (p->n_op == SCONV && p->n_type == ULONG) {
+		if (l->n_type == FLOAT) ch = "fixunssfdi";
+		else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
+		else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
+	} else if (p->n_op == SCONV && p->n_type == INT) {
+		if (l->n_type == FLOAT) ch = "fixsfsi";
+		else if (l->n_type == DOUBLE) ch = "fixdfsi";
+		else if (l->n_type == LDOUBLE) ch = "fixdfsi";
+	} else if (p->n_op == SCONV && p->n_type == UNSIGNED) {
+		if (l->n_type == FLOAT) ch = "fixunssfsi";
+		else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
+		else if (l->n_type == LDOUBLE) ch = "fixunsdfsi";
+	}
+
+	if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op);
+
+	printf("\tbl __%s" COM "softfloat operation\n", exname(ch));
+
+	if (p->n_op >= EQ && p->n_op <= GT)
+		printf("\tcmp %s,#0\n", rnames[R0]);
+}
+
+
+/*
+ * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
+ */
+
+static void
+emul(NODE *p)
+{
+	char *ch = NULL;
+
+	if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3";
+	else if (p->n_op == LS && DEUNSIGN(p->n_type) == LONG) ch = "ashlsi3";
+	else if (p->n_op == LS && DEUNSIGN(p->n_type) == INT) ch = "ashlsi3";
+
+	else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3";
+	else if (p->n_op == RS && p->n_type == ULONG) ch = "lshrsi3";
+	else if (p->n_op == RS && p->n_type == UNSIGNED) ch = "lshrsi3";
+
+	else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3";
+	else if (p->n_op == RS && p->n_type == LONG) ch = "ashrsi3";
+	else if (p->n_op == RS && p->n_type == INT) ch = "ashrsi3";
+	
+	else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3";
+	else if (p->n_op == DIV && p->n_type == LONG) ch = "divsi3";
+	else if (p->n_op == DIV && p->n_type == INT) ch = "divsi3";
+
+	else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3";
+	else if (p->n_op == DIV && p->n_type == ULONG) ch = "udivsi3";
+	else if (p->n_op == DIV && p->n_type == UNSIGNED) ch = "udivsi3";
+
+	else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3";
+	else if (p->n_op == MOD && p->n_type == LONG) ch = "modsi3";
+	else if (p->n_op == MOD && p->n_type == INT) ch = "modsi3";
+
+	else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3";
+	else if (p->n_op == MOD && p->n_type == ULONG) ch = "umodsi3";
+	else if (p->n_op == MOD && p->n_type == UNSIGNED) ch = "umodsi3";
+
+	else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3";
+	else if (p->n_op == MUL && p->n_type == LONG) ch = "mulsi3";
+	else if (p->n_op == MUL && p->n_type == INT) ch = "mulsi3";
+
+	else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2";
+	else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2";
+	else if (p->n_op == UMINUS && p->n_type == INT) ch = "negsi2";
+
+	else ch = 0, comperr("ZE");
+	printf("\tbl __%s" COM "emulated operation\n", exname(ch));
+}
+
+static void
+halfword(NODE *p)
+{
+        NODE *r = getlr(p, 'R');
+        NODE *l = getlr(p, 'L');
+	int idx0 = 0, idx1 = 1;
+
+	if (features(FEATURE_BIGENDIAN)) {
+		idx0 = 1;
+		idx1 = 0;
+	}
+
+	if (p->n_op == ASSIGN && r->n_op == OREG) {
+                /* load */
+                expand(p, 0, "\tldrb A1,");
+                printf("[%s," CONFMT "]\n", rnames[r->n_rval], r->n_lval+idx0);
+                expand(p, 0, "\tldrb AL,");
+                printf("[%s," CONFMT "]\n", rnames[r->n_rval], r->n_lval+idx1);
+                expand(p, 0, "\torr AL,A1,AL,asl #8\n");
+        } else if (p->n_op == ASSIGN && l->n_op == OREG) {
+                /* store */
+                expand(p, 0, "\tstrb AR,");
+                printf("[%s," CONFMT "]\n", rnames[l->n_rval], l->n_lval+idx0);
+                expand(p, 0, "\tmov A1,AR,asr #8\n");
+                expand(p, 0, "\tstrb A1,");
+                printf("[%s," CONFMT "]\n", rnames[l->n_rval], l->n_lval+idx1);
+        } else if (p->n_op == SCONV || p->n_op == UMUL) {
+                /* load */
+                expand(p, 0, "\tldrb A1,");
+                printf("[%s," CONFMT "]\n", rnames[l->n_rval], l->n_lval+idx0);
+                expand(p, 0, "\tldrb A2,");
+                printf("[%s," CONFMT "]\n", rnames[l->n_rval], l->n_lval+idx1);
+                expand(p, 0, "\torr A1,A1,A2,asl #8\n");
+        } else if (p->n_op == NAME || p->n_op == ICON || p->n_op == OREG) {
+                /* load */
+                expand(p, 0, "\tldrb A1,");
+                printf("[%s," CONFMT "]\n", rnames[p->n_rval], p->n_lval+idx0);
+                expand(p, 0, "\tldrb A2,");
+                printf("[%s," CONFMT "]\n", rnames[p->n_rval], p->n_lval+idx1);
+                expand(p, 0, "\torr A1,A1,A2,asl #8\n");
+	} else {
+		comperr("halfword");
+        }
+}
+
+static void
+bfext(NODE *p)
+{
+        int sz;
+
+        if (ISUNSIGNED(p->n_right->n_type))
+                return;
+        sz = 32 - UPKFSZ(p->n_left->n_rval);
+
+	expand(p, 0, "\tmov AD,AD,asl ");
+        printf("#%d\n", sz);
+	expand(p, 0, "\tmov AD,AD,asr ");
+        printf("#%d\n", sz);
+}
+
+static int
+argsiz(NODE *p)
+{
+	TWORD t = p->n_type;
+
+	if (t < LONGLONG || t == FLOAT || t > BTMASK)
+		return 4;
+	if (t == LONGLONG || t == ULONGLONG)
+		return 8;
+	if (t == DOUBLE || t == LDOUBLE)
+		return 8;
+	if (t == STRTY || t == UNIONTY)
+		return p->n_stsize;
+	comperr("argsiz");
+	return 0;
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+	int pr;
+
+	switch (c) {
+
+	case 'B': /* bit-field sign extension */
+		bfext(p);
+		break;
+
+	case 'C':  /* remove from stack after subroutine call */
+		pr = p->n_qual;
+#if 0
+		if (p->n_op == STCALL || p->n_op == USTCALL)
+			pr += 4;
+#endif
+		if (p->n_op == UCALL)
+			return; /* XXX remove ZC from UCALL */
+		if (pr > 0)
+			printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], pr);
+		break;
+
+	case 'D': /* Long long comparision */
+		twollcomp(p);
+		break;
+
+	case 'E': /* print out emulated ops */
+		emul(p);
+                break;
+
+	case 'F': /* print out emulated floating-point ops */
+		fpemul(p);
+		break;
+
+	case 'H':		/* do halfword access */
+		halfword(p);
+		break;
+
+	case 'I':		/* init constant */
+		if (p->n_name[0] != '\0')
+			comperr("named init");
+		load_constant_into_reg(DECRA(p->n_reg, 1),
+		    p->n_lval & 0xffffffff);
+		break;
+
+	case 'J':		/* init longlong constant */
+		load_constant_into_reg(DECRA(p->n_reg, 1) - R0R1,
+		    p->n_lval & 0xffffffff);
+		load_constant_into_reg(DECRA(p->n_reg, 1) - R0R1 + 1,
+                    (p->n_lval >> 32));
+                break;
+
+	case 'O': /* 64-bit left and right shift operators */
+		shiftop(p);
+		break;
+
+	case 'Q': /* emit struct assign */
+		stasg(p);
+		break;
+
+	default:
+		comperr("zzzcode %c", c);
+	}
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+	return(1);
+}
+
+/*
+ * 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)
+{
+	char *s;
+	int val = p->n_lval;
+
+	switch (p->n_op) {
+	case ICON:
+#if 0
+		if (p->n_sp)
+			printf(" [class=%d,level=%d] ", p->n_sp->sclass, p->n_sp->slevel);
+#endif
+#ifdef notdef	/* ICON cannot ever use sp here */
+		/* If it does, it's a giant bug */
+		if (p->n_sp == NULL || (
+		   (p->n_sp->sclass == STATIC && p->n_sp->slevel > 0)))
+			s = p->n_name;
+		else
+			s = exname(p->n_name);
+#else
+		s = p->n_name;
+#endif
+			
+		if (*s != '\0') {
+			fprintf(fp, "%s", s);
+			if (val > 0)
+				fprintf(fp, "+%d", val);
+			else if (val < 0)
+				fprintf(fp, "-%d", -val);
+		} else
+			fprintf(fp, CONFMT, (CONSZ)val);
+		return;
+
+	default:
+		comperr("illegal conput, p %p", p);
+	}
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+	comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+	size /= SZCHAR;
+	switch (p->n_op) {
+	case REG:
+		fprintf(stdout, "%s", rnames[p->n_rval-R0R1+1]);
+		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, "+%lld", p->n_lval);
+		} else
+			fprintf(io, CONFMT, p->n_lval);
+		return;
+
+	case OREG:
+		r = p->n_rval;
+                if (R2TEST(r))
+			fprintf(io, "[%s, %s, lsl #%d]",
+				rnames[R2UPK1(r)],
+				rnames[R2UPK2(r)],
+				R2UPK3(r));
+		else
+			fprintf(io, "[%s,#%d]", rnames[p->n_rval], (int)p->n_lval);
+		return;
+
+	case ICON:
+		/* addressable value of the constant */
+		conput(io, p);
+		return;
+
+	case REG:
+		switch (p->n_type) {
+		case DOUBLE:
+		case LDOUBLE:
+			if (features(FEATURE_HARDFLOAT)) {
+				fprintf(io, "%s", rnames[p->n_rval]);
+				break;
+			}
+			/* FALLTHROUGH */
+		case LONGLONG:
+		case ULONGLONG:
+			fprintf(stdout, "%s", rnames[p->n_rval-R0R1]);
+			break;
+		default:
+			fprintf(io, "%s", rnames[p->n_rval]);
+		}
+		return;
+
+	default:
+		comperr("illegal address, op %d, node %p", p->n_op, p);
+		return;
+
+	}
+}
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+	if (o < EQ || o > UGT)
+		comperr("bad conditional branch: %s", opst[o]);
+	printf("\t%s " LABFMT COM "conditional branch\n",
+	    ccbranches[o-EQ], lab);
+}
+
+/*
+ * The arm can only address 4k to get a NAME, so there must be some
+ * rewriting here.  Strategy:
+ * For first 1000 nodes found, print out the word directly.
+ * For the following 1000 nodes, group them together in asm statements
+ * and create a jump over.
+ * For the last <1000 statements, print out the words last.
+ */
+struct addrsymb {
+	SLIST_ENTRY(addrsymb) link;
+	char *name;	/* symbol name */
+	int num;	/* symbol offset */
+	char *str;	/* replace label */
+};
+SLIST_HEAD(, addrsymb) aslist;
+static struct interpass *ipbase;
+static int prtnumber, nodcnt, notfirst;
+#define	PRTLAB	".LY%d"	/* special for here */
+
+static struct interpass *
+anode(char *p)
+{
+	extern int thisline;
+	struct interpass *ip = tmpalloc(sizeof(struct interpass));
+
+	ip->ip_asm = p;
+	ip->type = IP_ASM;
+	ip->lineno = thisline;
+	return ip;
+}
+
+static void
+flshlab(void)
+{
+	struct interpass *ip;
+	struct addrsymb *el;
+	int lab = prtnumber++;
+	char *c;
+
+	if (SLIST_FIRST(&aslist) == NULL)
+		return;
+
+	snprintf(c = tmpalloc(32), 32, "\tb " PRTLAB "\n", lab);
+	ip = anode(c);
+	DLIST_INSERT_BEFORE(ipbase, ip, qelem);
+
+	SLIST_FOREACH(el, &aslist, link) {
+		/* insert each node as asm */
+		int l = 32+strlen(el->name);
+		c = tmpalloc(l);
+		if (el->num)
+			snprintf(c, l, "%s:\n\t.word %s+%d\n",
+			    el->str, el->name, el->num);
+		else
+			snprintf(c, l, "%s:\n\t.word %s\n", el->str, el->name);
+		ip = anode(c);
+		DLIST_INSERT_BEFORE(ipbase, ip, qelem);
+	}
+	/* generate asm label */
+	snprintf(c = tmpalloc(32), 32, PRTLAB ":\n", lab);
+	ip = anode(c);
+	DLIST_INSERT_BEFORE(ipbase, ip, qelem);
+}
+
+static void
+prtaddr(NODE *p, void *arg)
+{
+	NODE *l = p->n_left;
+	struct addrsymb *el;
+	int found = 0;
+	int lab;
+
+	nodcnt++;
+
+	if (p->n_op == ASSIGN && p->n_right->n_op == ICON &&
+	    p->n_right->n_name[0] != '\0') {
+		/* named constant */
+		p = p->n_right;
+
+		/* Restore addrof */
+		l = mklnode(NAME, p->n_lval, 0, 0);
+		l->n_name = p->n_name;
+		p->n_left = l;
+		p->n_op = ADDROF;
+	}
+
+	if (p->n_op != ADDROF || l->n_op != NAME)
+		return;
+
+	/* if we passed 1k nodes printout list */
+	if (nodcnt > 1000) {
+		if (notfirst)
+			flshlab();
+		SLIST_INIT(&aslist);
+		notfirst = 1;
+		nodcnt = 0;
+	}
+
+	/* write address to byte stream */
+
+	SLIST_FOREACH(el, &aslist, link) {
+		if (el->num == l->n_lval && el->name[0] == l->n_name[0] &&
+		    strcmp(el->name, l->n_name) == 0) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		/* we know that this is text segment */
+		lab = prtnumber++;
+		if (nodcnt <= 1000 && notfirst == 0) {
+			if (l->n_lval)
+				printf(PRTLAB ":\n\t.word %s+%lld\n",
+				    lab, l->n_name, l->n_lval);
+			else
+				printf(PRTLAB ":\n\t.word %s\n",
+				    lab, l->n_name);
+		}
+		el = tmpalloc(sizeof(struct addrsymb));
+		el->num = l->n_lval;
+		el->name = l->n_name;
+		el->str = tmpalloc(32);
+		snprintf(el->str, 32, PRTLAB, lab);
+		SLIST_INSERT_LAST(&aslist, el, link);
+	}
+
+	nfree(l);
+	p->n_op = NAME;
+	p->n_lval = 0;
+	p->n_name = el->str;
+}
+
+void
+myreader(struct interpass *ipole)
+{
+	struct interpass *ip;
+
+	SLIST_INIT(&aslist);
+	notfirst = nodcnt = 0;
+
+	DLIST_FOREACH(ip, ipole, qelem) {
+		switch (ip->type) {
+		case IP_NODE:
+			lineno = ip->lineno;
+			ipbase = ip;
+			walkf(ip->ip_node, prtaddr, 0);
+			break;
+		case IP_EPILOG:
+			ipbase = ip;
+			if (notfirst)
+				flshlab();
+			break;
+		default:
+			break;
+		}
+	}
+	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 *ipp)
+{
+}
+
+/*
+ * Register move: move contents of register 's' to register 'r'.
+ */
+void
+rmove(int s, int d, TWORD t)
+{
+        switch (t) {
+	case DOUBLE:
+	case LDOUBLE:
+		if (features(FEATURE_HARDFLOAT)) {
+			printf("\tfmr %s,%s" COM "rmove\n",
+				rnames[d], rnames[s]);
+			break;
+		}
+		/* FALLTHROUGH */
+        case LONGLONG:
+        case ULONGLONG:
+#define LONGREG(x, y) rnames[(x)-(R0R1-(y))]
+                if (s == d+1) {
+                        /* dh = sl, copy low word first */
+                        printf("\tmov %s,%s" COM "rmove\n",
+			    LONGREG(d,0), LONGREG(s,0));
+                        printf("\tmov %s,%s\n",
+			    LONGREG(d,1), LONGREG(s,1));
+                } else {
+                        /* copy high word first */
+                        printf("\tmov %s,%s" COM "rmove\n",
+			    LONGREG(d,1), LONGREG(s,1));
+                        printf("\tmov %s,%s\n",
+			    LONGREG(d,0), LONGREG(s,0));
+                }
+#undef LONGREG
+                break;
+	case FLOAT:
+		if (features(FEATURE_HARDFLOAT)) {
+			printf("\tmr %s,%s" COM "rmove\n",
+				rnames[d], rnames[s]);
+			break;
+		}
+		/* FALLTHROUGH */
+        default:
+		printf("\tmov %s,%s" COM "rmove\n", rnames[d], rnames[s]);
+        }
+}
+
+/*
+ * Can we assign a register from class 'c', given the set
+ * of number of assigned registers in each class 'r'.
+ *
+ * On ARM, we have:
+ *	11  CLASSA registers (32-bit hard registers)
+ *	10  CLASSB registers (64-bit composite registers)
+ *	8 or 32 CLASSC registers (floating-point)
+ *
+ *  There is a problem calculating the available composite registers
+ *  (ie CLASSB).  The algorithm below assumes that given any two
+ *  registers, we can make a composite register.  But this isn't true
+ *  here (or with other targets), since the number of combinations
+ *  of register pairs could become very large.  Additionally,
+ *  having so many combinations really isn't so practical, since
+ *  most register pairs cannot be used to pass function arguments.
+ *  Consequently, when there is pressure composite registers,
+ *  "beenhere" compilation failures are common.
+ *
+ *  [We need to know which registers are allocated, not simply
+ *  the number in each class]
+ */
+int
+COLORMAP(int c, int *r)
+{
+	int num = 0;	/* number of registers used */
+
+#if 0
+	static const char classes[] = { 'X', 'A', 'B', 'C', 'D' };
+	printf("COLORMAP: requested class %c\n", classes[c]);
+	printf("COLORMAP: class A: %d\n", r[CLASSA]);
+	printf("COLORMAP: class B: %d\n", r[CLASSB]);
+#endif
+
+	switch (c) {
+	case CLASSA:
+		num += r[CLASSA];
+		num += 2*r[CLASSB];
+		return num < 11;
+	case CLASSB:
+		num += 2*r[CLASSB];
+		num += r[CLASSA];
+		return num < 6;  /* XXX see comments above */
+	case CLASSC:
+		num += r[CLASSC];
+		if (features(FEATURE_FPA))
+			return num < 8;
+		else if (features(FEATURE_VFP))
+			return num < 8;
+		else
+			cerror("colormap 1");
+	}
+	cerror("colormap 2");
+	return 0; /* XXX gcc */
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+	if (t == DOUBLE || t == LDOUBLE) {
+		if (features(FEATURE_HARDFLOAT))
+			return CLASSC;
+		else
+			return CLASSB;
+	}
+	if (t == FLOAT) {
+		if (features(FEATURE_HARDFLOAT))
+			return CLASSC;
+		else
+			return CLASSA;
+	}
+	if (DEUNSIGN(t) == LONGLONG)
+		return CLASSB;
+	return CLASSA;
+}
+
+int
+retreg(int t)
+{
+	int c = gclass(t);
+	if (c == CLASSB)
+		return R0R1;
+	else if (c == CLASSC)
+		return F0;
+	return R0;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+	NODE *op = p;
+	int size = 0;
+
+	p->n_qual = 0;
+	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+		return;
+	for (p = p->n_right; p->n_op == CM; p = p->n_left)
+		size += argsiz(p->n_right);
+	size += argsiz(p);
+	op->n_qual = size - 16; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+	return SRNOPE;
+}
+
+/*
+ * default to ARMv2
+ */
+#ifdef TARGET_BIG_ENDIAN
+#define DEFAULT_FEATURES	FEATURE_BIGENDIAN | FEATURE_MUL
+#else
+#define DEFAULT_FEATURES	FEATURE_MUL
+#endif
+
+static int fset = DEFAULT_FEATURES;
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+	if (strcasecmp(str, "little-endian") == 0) {
+		fset &= ~FEATURE_BIGENDIAN;
+	} else if (strcasecmp(str, "big-endian") == 0) {
+		fset |= FEATURE_BIGENDIAN;
+	} else if (strcasecmp(str, "fpe=fpa") == 0) {
+		fset &= ~(FEATURE_VFP | FEATURE_FPA);
+		fset |= FEATURE_FPA;
+	} else if (strcasecmp(str, "fpe=vfp") == 0) {
+		fset &= ~(FEATURE_VFP | FEATURE_FPA);
+		fset |= FEATURE_VFP;
+	} else if (strcasecmp(str, "soft-float") == 0) {
+		fset &= ~(FEATURE_VFP | FEATURE_FPA);
+	} else if (strcasecmp(str, "arch=armv1") == 0) {
+		fset &= ~FEATURE_HALFWORDS;
+		fset &= ~FEATURE_EXTEND;
+		fset &= ~FEATURE_MUL;
+		fset &= ~FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv2") == 0) {
+		fset &= ~FEATURE_HALFWORDS;
+		fset &= ~FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset &= ~FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv2a") == 0) {
+		fset &= ~FEATURE_HALFWORDS;
+		fset &= ~FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset &= ~FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv3") == 0) {
+		fset &= ~FEATURE_HALFWORDS;
+		fset &= ~FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset &= ~FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv4") == 0) {
+		fset |= FEATURE_HALFWORDS;
+		fset &= ~FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset |= FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv4t") == 0) {
+		fset |= FEATURE_HALFWORDS;
+		fset &= ~FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset |= FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv4tej") == 0) {
+		fset |= FEATURE_HALFWORDS;
+		fset &= ~FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset |= FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv5") == 0) {
+		fset |= FEATURE_HALFWORDS;
+		fset &= ~FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset |= FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv5te") == 0) {
+		fset |= FEATURE_HALFWORDS;
+		fset &= ~FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset |= FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv5tej") == 0) {
+		fset |= FEATURE_HALFWORDS;
+		fset &= ~FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset |= FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv6") == 0) {
+		fset |= FEATURE_HALFWORDS;
+		fset |= FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset |= FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv6t2") == 0) {
+		fset |= FEATURE_HALFWORDS;
+		fset |= FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset |= FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv6kz") == 0) {
+		fset |= FEATURE_HALFWORDS;
+		fset |= FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset |= FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv6k") == 0) {
+		fset |= FEATURE_HALFWORDS;
+		fset |= FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset |= FEATURE_MULL;
+	} else if (strcasecmp(str, "arch=armv7") == 0) {
+		fset |= FEATURE_HALFWORDS;
+		fset |= FEATURE_EXTEND;
+		fset |= FEATURE_MUL;
+		fset |= FEATURE_MULL;
+	} else {
+		fprintf(stderr, "unknown m option '%s'\n", str);
+		exit(1);
+	}
+}
+
+int
+features(int mask)
+{
+	if (mask == FEATURE_HARDFLOAT)
+		return ((fset & mask) != 0);
+	return ((fset & mask) == mask);
+}
+
+/*
+ * Define the current location as an internal label.
+ */
+void
+deflab(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+	return 0;
+}
Index: uspace/app/pcc/arch/arm/macdefs.h
===================================================================
--- uspace/app/pcc/arch/arm/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/arm/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,263 @@
+/*	$Id: macdefs.h,v 1.12 2009/01/24 21:43:48 gmcgarry 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);
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR		8
+#define SZBOOL		32
+#define SZINT		32
+#define SZFLOAT		32
+#define SZDOUBLE	64
+#define SZLDOUBLE	64
+#define SZLONG		32
+#define SZSHORT		16
+#define SZLONGLONG	64
+#define SZPOINT(t)	32
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR		8
+#define ALBOOL		32
+#define ALINT		32
+#define ALFLOAT		32
+#define ALDOUBLE	32
+#define ALLDOUBLE	32
+#define ALLONG		32
+#define ALLONGLONG	32
+#define ALSHORT		16
+#define ALPOINT		32
+#define ALSTRUCT	32
+#define ALSTACK		32 
+
+/*
+ * Min/max values.
+ */
+#define	MIN_CHAR	-128
+#define	MAX_CHAR	127
+#define	MAX_UCHAR	255
+#define	MIN_SHORT	-32768
+#define	MAX_SHORT	32767
+#define	MAX_USHORT	65535
+#define	MIN_INT		-1
+#define	MAX_INT		0x7fffffff
+#define	MAX_UNSIGNED	0xffffffff
+#define	MIN_LONG	MIN_INT
+#define	MAX_LONG	MAX_INT
+#define	MAX_ULONG	MAX_UNSIGNED
+#define	MIN_LONGLONG	0x8000000000000000LL
+#define	MAX_LONGLONG	0x7fffffffffffffffLL
+#define	MAX_ULONGLONG	0xffffffffffffffffULL
+
+#define	BOOL_TYPE	INT	/* 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 */
+#define LABFMT	".L%d"		/* format for printing labels */
+#define	STABLBL	"LL%d"		/* format for stab (debugging) labels */
+#define STAB_LINE_ABSOLUTE	/* S_LINE fields use absolute addresses */
+
+#undef	FIELDOPS		/* no bit-field instructions */
+
+#define ENUMSIZE(high,low) INT	/* enums are always stored in full int */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)	((x)&03)
+#define wdal(k)		(BYTEOFF(k)==0)
+#define BITOOR(x)	(x)	/* bit offset to oreg offset XXX die! */
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+
+#define	szty(t)	(((t) == DOUBLE || (t) == LDOUBLE || \
+	(t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1)
+
+#define R0	0
+#define R1	1
+#define R2	2
+#define R3	3
+#define R4	4
+#define R5	5
+#define R6	6
+#define R7	7
+#define R8	8
+#define R9	9
+#define R10	10
+#define R11	11
+#define R12	12
+#define	R13	13
+#define R14	14
+#define R15	15
+
+#define SL	R10
+#define FP	R11
+#define IP	R12
+#define SP	R13
+#define LR	R14
+#define PC	R15
+
+#define R0R1	16
+#define R1R2	17
+#define R2R3	18
+#define R3R4	19
+#define R4R5	20
+#define R5R6	21
+#define R6R7	22
+#define R7R8	23
+#define R8R9	24
+#define R9R10	25
+
+#define F0	26
+#define F1	27
+#define F2	28
+#define F3	29
+#define F4	30
+#define F5	31
+#define F6	32
+#define F7	33
+
+#define NUMCLASS 3
+#define	MAXREGS	34
+
+#define RSTATUS \
+	SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,	\
+	SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,	\
+	SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,			\
+	0, 0, 0, 0, 0,							\
+        SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG,		\
+        SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,			\
+	SCREG, SCREG, SCREG, SCREG,					\
+	SCREG, SCREG, SCREG, SCREG,					\
+
+#define ROVERLAP \
+	{ R0R1, -1 },					\
+	{ R0R1, R1R2, -1 },				\
+	{ R1R2, R2R3, -1 },				\
+	{ R2R3, R3R4, -1 },				\
+	{ R3R4, R4R5, -1 },				\
+	{ R4R5, R5R6, -1 },				\
+	{ R5R6, R6R7, -1 },				\
+	{ R6R7, R7R8, -1 },				\
+	{ R7R8, R8R9, -1 },				\
+	{ R8R9, R9R10, -1 },				\
+	{ R9R10, -1 },					\
+	{ -1 }, 					\
+	{ -1 }, 					\
+	{ -1 }, 					\
+	{ -1 }, 					\
+	{ -1 }, 					\
+	{ R0, R1, R1R2, -1 },				\
+	{ R1, R2, R0R1, R2R3, -1 },			\
+	{ R2, R3, R1R2, R3R4, -1 },			\
+	{ R3, R4, R2R3, R4R5, -1 },			\
+	{ R4, R5, R3R4, R5R6, -1 },			\
+	{ R5, R6, R4R5, R6R7, -1 },			\
+	{ R6, R7, R5R6, R7R8, -1 },			\
+	{ R7, R8, R6R7, R8R9, -1 },			\
+	{ R8, R9, R7R8, R9R10, -1 },			\
+	{ R9, R10, R8R9, -1 },				\
+	{ -1, },					\
+	{ -1, },					\
+	{ -1, },					\
+	{ -1, },					\
+	{ -1, },					\
+	{ -1, },					\
+	{ -1, },					\
+	{ -1, },					\
+
+#define BACKTEMP 		/* stack grows negatively for temporaries */
+#define BACKAUTO 		/* stack grows negatively for automatics */
+
+#define ARGINIT		(4*8)	/* # bits above fp where arguments start */
+#define AUTOINIT	(12*8)	/* # bits above fp where automatics start */
+
+#undef	FIELDOPS		/* no bit-field instructions */
+#define RTOLBYTES 1		/* bytes are numbered right to left */
+
+/* XXX - to die */
+#define FPREG   FP	/* frame pointer */
+
+/* Return a register class based on the type of the node */
+#define PCLASS(p)	(1 << gclass((p)->n_type))
+
+#define GCLASS(x)	(x < 16 ? CLASSA : x < 26 ? CLASSB : CLASSC)
+#define DECRA(x,y)      (((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define ENCRD(x)        (x)             /* Encode dest reg in n_reg */
+#define ENCRA1(x)       ((x) << 6)      /* A1 */
+#define ENCRA2(x)       ((x) << 12)     /* A2 */
+#define ENCRA(x,y)      ((x) << (6+y*6))        /* encode regs in int */
+#define RETREG(x)	retreg(x)
+
+int COLORMAP(int c, int *r);
+int retreg(int ty);
+int features(int f);
+
+#define FEATURE_BIGENDIAN	0x00010000
+#define FEATURE_HALFWORDS	0x00020000	/* ldrsh/ldrh, ldrsb */
+#define FEATURE_EXTEND		0x00040000	/* sxth, sxtb, uxth, uxtb */
+#define FEATURE_MUL		0x00080000
+#define FEATURE_MULL		0x00100000
+#define FEATURE_FPA		0x10000000
+#define FEATURE_VFP		0x20000000
+#define FEATURE_HARDFLOAT	(FEATURE_FPA|FEATURE_VFP)
+
+#define TARGET_STDARGS
+#define TARGET_BUILTINS						\
+	{ "__builtin_stdarg_start", arm_builtin_stdarg_start },	\
+	{ "__builtin_va_arg", arm_builtin_va_arg },		\
+	{ "__builtin_va_end", arm_builtin_va_end },		\
+	{ "__builtin_va_copy", arm_builtin_va_copy },
+
+#define NODE struct node
+struct node;
+NODE *arm_builtin_stdarg_start(NODE *f, NODE *a);
+NODE *arm_builtin_va_arg(NODE *f, NODE *a);
+NODE *arm_builtin_va_end(NODE *f, NODE *a);
+NODE *arm_builtin_va_copy(NODE *f, NODE *a);
+#undef NODE
+
+#define COM     "\t@ "
+#define NARGREGS	4
Index: uspace/app/pcc/arch/arm/order.c
===================================================================
--- uspace/app/pcc/arch/arm/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/arm/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,339 @@
+/*      $Id: order.c,v 1.9 2008/09/27 07:35:22 ragge Exp $    */
+/*
+ * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
+ * 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 code-generation strategy (pass 2).
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "pass2.h"
+
+/*
+ * Check size of offset in OREG.  Called by oregok() to see if an
+ * OREG can be generated.
+ */
+int
+notoff(TWORD ty, int r, CONSZ off, char *cp)
+{
+	if (cp && cp[0]) return 1;
+	if (DEUNSIGN(ty) == INT || ty == UCHAR)
+		return !(off < 4096 && off > -4096);
+	else
+		return !(off < 256 && off > -256);
+}
+
+/*
+ * Generate instructions for an OREG.  Why is this routine MD?
+ * Called by swmatch().
+ */
+void
+offstar(NODE *p, int shape)
+{
+	NODE *r;
+
+	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;
+		}
+		/* usually for arraying indexing: */
+		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);
+}
+
+/*
+ * Unable to convert to OREG (notoff() returned failure).  Output
+ * suitable instructions to replace OREG.
+ */
+void
+myormake(NODE *q)
+{
+        NODE *p, *r;
+
+	if (x2debug)
+		printf("myormake(%p)\n", q);
+
+	p = q->n_left;
+
+	/*
+	 * This handles failed OREGs conversions, due to the offset
+	 * being too large for an OREG.
+	 */
+	if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_right->n_op == ICON) {
+		if (isreg(p->n_left) == 0)
+			(void)geninsn(p->n_left, INAREG);
+		if (isreg(p->n_right) == 0)
+			(void)geninsn(p->n_right, INAREG);
+		(void)geninsn(p, INAREG);
+	} else if (p->n_op == REG) {
+		q->n_op = OREG;
+		q->n_lval = p->n_lval;
+		q->n_rval = p->n_rval;
+		tfree(p);
+	} else 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,
+				   r->n_right->n_lval);
+		tfree(p);
+	}
+}
+
+/*
+ * Check to if the UMUL node can be converted into an OREG.
+ */
+int
+shumul(NODE *p, int shape)
+{
+	/* Turns currently anything into OREG */
+	if (shape & SOREG)
+		return SROREG;
+	return SRNOPE;
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of a failed table lookup.
+ *
+ * Return nonzero to retry table search on new tree, or zero to fail.
+ */
+int
+setbin(NODE *p)
+{
+	return 0;
+
+}
+
+/*
+ * Rewrite assignment operations.
+ * Called as a result of a failed table lookup.
+ *
+ * Return nonzero to retry table search on new tree, or zero to fail.
+ */
+int
+setasg(NODE *p, int cookie)
+{
+	return 0;
+}
+
+/*
+ * Rewrite UMUL operation.
+ * Called as a result of a failed table lookup.
+ *
+ * Return nonzero to retry table search on new tree, or zero to fail.
+ */
+int
+setuni(NODE *p, int cookie)
+{
+	return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ *
+ * Called as a result of specifying NSPECIAL in the table.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+
+	switch (q->op) {
+
+#if !defined(ARM_HAS_FPA) && !defined(ARM_HAS_VFP)
+	case UMINUS:
+	case SCONV:
+		if (q->lshape == SBREG && q->rshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R0R1 },
+				{ NRES, R0 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SAREG && q->rshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R0 },
+				{ NRES, R0R1 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SAREG && q->rshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R0 },
+				{ NRES, R0 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SBREG && q->rshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R0R1 },
+				{ NRES, R0R1 },
+				{ 0 }
+			};
+			return s;
+		}
+
+	case OPLOG:
+		if (q->lshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R0R1 },
+				{ NRIGHT, R2R3 },
+				{ NRES, R0 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R0 },
+				{ NRIGHT, R1 },
+				{ NRES, R0 },
+				{ 0 }
+			};
+			return s;
+		}
+	case PLUS:
+	case MINUS:
+	case MUL:
+#endif
+	case MOD:
+	case DIV:
+		if (q->lshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R0R1 },
+				{ NRIGHT, R2R3 },
+				{ NRES, R0R1 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R0 },
+				{ NRIGHT, R1 },
+				{ NRES, R0 },
+				{ 0 }
+			};
+			return s;
+		}
+	case LS:
+	case RS:
+		if (q->lshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R0R1 },
+				{ NRIGHT, R2 },
+				{ NRES, R0R1 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R0 },
+				{ NRIGHT, R1 },
+				{ NRES, R0 },
+				{ 0 }
+			};
+			return s;
+		}
+	case STASG:
+		{
+			static struct rspecial s[] = {
+				{ NEVER, R0 },
+				{ NRIGHT, R1 },
+				{ NEVER, R2 },
+				{ 0 } };
+			return s;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+#ifdef PCC_DEBUG
+	comperr("nspecial entry %d [0x%x]: %s", q - table, q->op, q->cstring);
+#endif
+	return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node ('+','-', '*', '/', etc) if it
+ * differs from default.
+ */
+int
+setorder(NODE *p)
+{
+	return 0;
+}
+
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+        static int r[] = { R3, R2, R1, R0, -1 };
+	int num = 1;
+
+	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+		return &r[4-0];
+
+        for (p = p->n_right; p->n_op == CM; p = p->n_left)
+                num += szty(p->n_right->n_type);
+        num += szty(p->n_right->n_type);
+
+	num = (num > 4 ? 4 : num);
+
+        return &r[4 - num];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+	return features(op->visit & 0xffff0000);
+}
Index: uspace/app/pcc/arch/arm/table.c
===================================================================
--- uspace/app/pcc/arch/arm/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/arm/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1847 @@
+/*	$Id: table.c,v 1.19 2008/05/16 02:20:36 gmcgarry Exp $	*/
+/*-
+ * Copyright (c) 2007 Gregory McGarry <g.mcgarry@ieee.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * A template has five logical sections:
+ *
+ *	1) subtree (operator); goal to achieve (cookie)
+ *	2) left node descendent of operator (node class; type)
+ *	3) right node descendent of operator (node class; type)
+ *	4) resource requirements (number of scratch registers);
+ *	   subtree rewriting rule
+ *	5) emitted instructions
+ */
+
+#include "pass2.h"
+
+#define TUWORD	TUNSIGNED|TULONG
+#define TSWORD	TINT|TLONG
+#define TWORD	TUWORD|TSWORD
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are not necessary */
+{ PCONV,	INAREG,
+	SAREG,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		0,	RLEFT,
+		COM "pointer conversion\n", },
+
+
+/*
+ * Conversions of integral types
+ *
+ * For each deunsigned type, they look something like this:
+ *
+ * signed -> bigger signed	- nothing to do
+ * signed -> bigger unsigned	- clear the top bits (of source type)
+ *
+ * signed -> smaller signed	- sign-extend the bits (to dest type)
+ * signed -> smaller unsigned	- clear the top bits (of dest type)
+ * unsigned -> smaller signed	- sign-extend top bits (to dest type)
+ * unsigned -> smaller unsigned	- clear the top bits (of dest type)
+ *
+ * unsigned -> bigger		- nothing to do
+ */
+
+{ SCONV,	INAREG,
+	SAREG,	TCHAR,
+	SAREG,	TSWORD|TSHORT,
+		0,	RLEFT,
+		COM "convert char to short/int\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TCHAR,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	and A1,AL,#255" COM "convert char to uchar/ushort/uint\n", },
+
+{ SCONV,	INAREG | FEATURE_EXTEND,
+	SAREG,	TUCHAR,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	sxtb A1,AL" COM "convert uchar to char\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUCHAR,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	mov A1,AL,asl #24" COM "convert uchar to char\n"
+		"	mov A1,A1,asr #24\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT,
+		0,	RLEFT,
+		COM "convert uchar to (u)short/(u)int\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSHORT,
+	SAREG,	TSWORD,
+		0,	RLEFT,
+		COM "convert short to int\n", },
+
+{ SCONV,	INAREG | FEATURE_EXTEND,
+	SAREG,	TSHORT,
+	SAREG,	TUWORD|TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	uxth A1,AL" COM "convert short to uint\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSHORT,
+	SAREG,	TUWORD|TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	mov A1,AL,asl #16" COM "convert short to uint\n"
+		"	mov A1,AL,lsr #16\n", },
+
+{ SCONV,	INAREG | FEATURE_EXTEND,
+	SAREG,	TUSHORT,
+	SAREG,	TSHORT,
+		NAREG|NASL,	RESC1,
+		"	sxth A1,AL" COM "convert ushort to short\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUSHORT,
+	SAREG,	TSHORT,
+		NAREG|NASL,	RESC1,
+		"	mov A1,AL,asl #16" COM "convert ushort to short\n"
+		"	mov A1,A1,asr #16\n", },
+
+{ SCONV,	INAREG | FEATURE_EXTEND,
+	SAREG,	TSHORT|TUSHORT,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	sxtb A1,AL" COM "convert (u)short to char\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	mov A1,AL,asl #24" COM "convert (u)short to char\n"
+		"	mov A1,A1,asr #24\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	sxtb A1,AL" COM "convert (u)short to char\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SAREG,	TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	and A1,AL,#255" COM "convert (u)short to uchar\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUSHORT,
+	SAREG,	TWORD,
+		0,	RLEFT,
+		COM "convert ushort to (u)int\n", },
+
+{ SCONV,	INAREG | FEATURE_EXTEND,
+	SAREG,	TWORD,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	sxtb A1,AL" COM "convert (u)int to char\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TWORD,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	mov A1,AL,asl #24" COM "convert (u)int to char\n"
+		"	mov A1,A1,asr #24\n", },
+
+{ SCONV,	INAREG | FEATURE_EXTEND,
+	SAREG,	TWORD,
+	SAREG,	TSHORT,
+		NAREG|NASL,	RESC1,
+		"	sxth A1,AL" COM "convert (u)int to short\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TWORD,
+	SAREG,	TSHORT,
+		NAREG|NASL,	RESC1,
+		"	mov A1,AL,asl #16" COM "convert (u)int to short\n"
+		"	mov A1,A1,asr #16\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TWORD,
+	SAREG,	TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	and A1,AL,#255" COM "convert uchar to char\n", },
+
+{ SCONV,	INAREG | FEATURE_EXTEND,
+	SAREG,	TWORD,
+	SAREG,	TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	uxth A1,AL" COM "convert int to ushort\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TWORD,
+	SAREG,	TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	mov A1,AL,asl #16" COM "convert int to ushort\n"
+		"	mov A1,AL,lsr #16\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TPOINT|TWORD,
+	SAREG,	TWORD|TPOINT,
+		0,	RLEFT,
+		COM "convert between pointers and words\n", },
+
+{ SCONV,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		0,	RLEFT,
+		COM "convert (u)longlong to (u)longlong\n", },
+
+/* convert (u)char/(u)short/(u)int to longlong */
+{ SCONV,	INBREG,
+	SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,		RESC1,
+		"	mov A1,AL" COM "convert (u)char/(u)short/(u)int to (u)longlong\n"
+		"	mov U1,AL,asr #31\n", },
+
+{ SCONV,	INAREG | FEATURE_EXTEND,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TCHAR,
+		NAREG,		RESC1,
+		"	sxtb A1,AL" COM "convert (u)longlong to char\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TCHAR,
+		NAREG,		RESC1,
+		"	mov A1,AL,asl #24" COM "convert (u)longlong to char\n"
+		"	mov A1,A1,asr #24\n", },
+
+{ SCONV,	INAREG | FEATURE_EXTEND,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TSHORT,
+		NAREG,		RESC1,
+		"	sxth A1,AL" COM "convert (u)longlong to short\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TSHORT,
+		NAREG,		RESC1,
+		"	mov A1,AL,asl #16" COM "convert (u)longlong to short\n"
+		"	mov A1,A1,asr #16\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TWORD,
+		NAREG,		RESC1,
+		"	mov A1,AL" COM "convert (u)longlong to (u)int\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TUCHAR,
+		NAREG,		RESC1,
+		"	and A1,AL,#255" COM "convert (u)longlong to uchar\n", },
+
+{ SCONV,	INAREG | FEATURE_EXTEND,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TUSHORT,
+		NAREG,		RESC1,
+		"	uxth A1,AL" COM "convert (u)longlong to ushort\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TUSHORT,
+		NAREG,		RESC1,
+		"	mov A1,AL,asl #16" COM "convert (u)longlong to ushort\n"
+		"	mov A1,A1,lsr #16\n", },
+
+/* conversions on load from memory */
+
+/* char */
+{ SCONV,	INAREG,
+	SOREG,	TCHAR,
+	SAREG,	TWORD,
+		NASL|NAREG,	RESC1,
+		"	ldrsb A1,AL" COM "convert char to int/long\n", },
+
+/* uchar */
+{ SCONV,	INAREG,
+	SOREG,	TUCHAR,
+	SAREG,	TWORD,
+		NASL|NAREG,	RESC1,
+		"	ldrb A1,AL" COM "convert uchar to int/long\n", },
+ 
+/* short */
+{ SCONV,	INAREG | FEATURE_HALFWORDS,
+	SOREG,	TSHORT,
+	SAREG,	TWORD,
+		NASL|NAREG,	RESC1,
+		"	ldrsh A1,AL" COM "convert short to int/long\n", },
+
+/* ushort */
+{ SCONV,	INAREG | FEATURE_HALFWORDS,
+	SOREG,	TSHORT,
+	SAREG,	TWORD,
+		NASL|NAREG,	RESC1,
+		"	ldrh A1,AL" COM "convert ushort to int/long\n", },
+
+/* short */
+{ SCONV,	INAREG,
+	SOREG,	TSHORT|TUSHORT,
+	SAREG,	TWORD,
+		2*NAREG|NASL,	RESC1,
+		"ZH", },
+
+{ SCONV,	INAREG | FEATURE_FPA,
+	SCREG,	TFLOAT,
+	SAREG,	TWORD,
+		NAREG,		RESC1,
+		"	fix AL,AR" COM "convert float to int\n", },
+
+{ SCONV,	INAREG | FEATURE_VFP,
+	SCREG,	TFLOAT,
+	SAREG,	TSWORD,
+		NAREG,		RESC1,
+		"	ftosis AL,AR" COM "convert float to int\n", },
+
+{ SCONV,	INAREG | FEATURE_VFP,
+	SCREG,	TFLOAT,
+	SAREG,	TSWORD,
+		NAREG,		RESC1,
+		"	ftouis AL,AR" COM "convert float to int\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TFLOAT,
+	SAREG,	TWORD,
+		NSPECIAL|NAREG,		RESC1,
+		"ZF", },
+
+{ SCONV,	INBREG | FEATURE_FPA,
+	SCREG,	TFLOAT,
+	SBREG,	TULONGLONG|TLONGLONG,
+		NBREG,		RESC1,
+		COM "unimplemented\n", },
+
+{ SCONV,	INBREG | FEATURE_VFP,
+	SCREG,	TFLOAT,
+	SBREG,	TULONGLONG|TLONGLONG,
+		NBREG,		RESC1,
+		COM "unimplemented\n", },
+
+{ SCONV,	INBREG,
+	SAREG,	TFLOAT,
+	SBREG,	TULONGLONG|TLONGLONG,
+		NSPECIAL|NBREG,		RESC1,
+		"ZF", },
+
+{ SCONV,	INAREG | FEATURE_FPA,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SAREG,	TWORD,
+		NAREG,		RESC1,
+		"	fix AL,AR" COM "convert double/ldouble to int\n", },
+
+{ SCONV,	INAREG | FEATURE_VFP,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SAREG,	TSWORD,
+		NAREG,		RESC1,
+		"	ftosid AL,AR" COM "convert double/ldouble to int\n", },
+
+{ SCONV,	INAREG | FEATURE_VFP,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SAREG,	TUWORD,
+		NAREG,		RESC1,
+		"	ftouid AL,AR" COM "convert double/ldouble to int\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TDOUBLE|TLDOUBLE,
+	SAREG,	TWORD,
+		NSPECIAL|NAREG,		RESC1,
+		"ZF", },
+
+{ SCONV,	INBREG | FEATURE_FPA,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG,		RESC1,
+		COM "unimplemented\n", },
+
+{ SCONV,	INBREG | FEATURE_VFP,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SBREG,	TULONGLONG|TLONGLONG,
+		NBREG,		RESC1,
+		COM "unimplemented\n", },
+
+{ SCONV,	INBREG,
+	SBREG,	TDOUBLE|TLDOUBLE,
+	SBREG,	TULONGLONG|TLONGLONG,
+		NSPECIAL|NBREG,		RESC1,
+		"ZF", },
+
+{ SCONV,	INCREG | FEATURE_FPA,
+	SAREG,	TWORD,
+	SCREG,	TFLOAT,
+		NCREG,		RESC1,
+		"	flts AL,AR" COM "convert int to float\n" },
+
+{ SCONV,	INCREG | FEATURE_VFP,
+	SAREG,	TSWORD,
+	SCREG,	TFLOAT,
+		NCREG,		RESC1,
+		"	fsitos AL,AR" COM "convert int to float\n" },
+
+{ SCONV,	INCREG | FEATURE_VFP,
+	SAREG,	TUWORD,
+	SCREG,	TFLOAT,
+		NCREG,		RESC1,
+		"	fuitos AL,AR" COM "convert int to float\n" },
+
+{ SCONV,	INAREG,
+	SAREG,	TWORD,
+	SAREG,	TFLOAT,
+		NSPECIAL|NAREG,		RESC1,
+		"ZF", },
+
+{ SCONV,	INCREG | FEATURE_FPA,
+	SBREG,	TULONGLONG|TLONGLONG,
+	SCREG,	TFLOAT,
+		NCREG,		RESC1,
+		COM "unimplemented\n", },
+
+{ SCONV,	INCREG | FEATURE_VFP,
+	SBREG,	TULONGLONG|TLONGLONG,
+	SCREG,	TFLOAT,
+		NCREG,		RESC1,
+		COM "unimplemented\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TULONGLONG|TLONGLONG,
+	SAREG,	TFLOAT,
+		NAREG,		RESC1,
+		COM "unimplemented\n", },
+
+{ SCONV,	INCREG | FEATURE_FPA,
+	SAREG,	TWORD,
+	SCREG,	TDOUBLE,
+		NCREG,		RESC1,
+		"	fltd AL,AR" COM "convert int to double\n" },
+
+{ SCONV,	INCREG | FEATURE_VFP,
+	SAREG,	TSWORD,
+	SCREG,	TDOUBLE,
+		NCREG,		RESC1,
+		"	fsitod AL,AR" COM "convert int to double\n" },
+
+{ SCONV,	INCREG | FEATURE_VFP,
+	SAREG,	TUWORD,
+	SCREG,	TDOUBLE,
+		NCREG,		RESC1,
+		"	fuitod AL,AR" COM "convert int to double\n" },
+
+{ SCONV,	INBREG,
+	SAREG,	TWORD,
+	SBREG,	TDOUBLE,
+		NSPECIAL|NBREG,		RESC1,
+		"ZF", },
+
+{ SCONV,	INCREG | FEATURE_FPA,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCREG,	TDOUBLE,
+		NCREG,		RESC1,
+		COM "unimplemented\n", },
+
+{ SCONV,	INCREG | FEATURE_VFP,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCREG,	TDOUBLE,
+		NCREG,		RESC1,
+		COM "unimplemented\n", },
+
+{ SCONV,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TDOUBLE,
+		NSPECIAL|NBREG,		RESC1,
+		"ZF", },
+
+{ SCONV,	INCREG | FEATURE_FPA,
+	SAREG,	TWORD,
+	SCREG,	TLDOUBLE,
+		NCREG,		RESC1,
+		"	flte AL,AR" COM "convert int to ldouble\n" },
+
+{ SCONV,	INCREG | FEATURE_VFP,
+	SAREG,	TSWORD,
+	SCREG,	TLDOUBLE,
+		NCREG,		RESC1,
+		"	fsitod AL,AR" COM "convert int to ldouble\n" },
+
+{ SCONV,	INCREG | FEATURE_VFP,
+	SAREG,	TUWORD,
+	SCREG,	TLDOUBLE,
+		NCREG,		RESC1,
+		"	fuitod AL,AR" COM "convert uint to ldouble\n" },
+
+{ SCONV,	INBREG,
+	SAREG,	TWORD,
+	SBREG,	TLDOUBLE,
+		NSPECIAL|NBREG,		RESC1,
+		"ZF", },
+
+{ SCONV,	INCREG | FEATURE_FPA,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCREG,	TLDOUBLE,
+		NCREG,		RESC1,
+		COM "unimplemented\n", },
+
+{ SCONV,	INCREG | FEATURE_VFP,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCREG,	TLDOUBLE,
+		NCREG,		RESC1,
+		COM "unimplemented\n", },
+
+{ SCONV,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLDOUBLE,
+		NSPECIAL|NBREG,		RESC1,
+		"ZF", },
+
+{ SCONV,	INCREG | FEATURE_FPA,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TFLOAT,
+		NCREG,		RESC1,
+		COM "unimplemented\n", },
+
+{ SCONV,	INCREG | FEATURE_VFP,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TFLOAT,
+		NCREG,		RESC1,
+		"	fcvtds AL,AR" COM "convert float to double\n" },
+
+{ SCONV,	INAREG,
+	SBREG,	TDOUBLE|TLDOUBLE,
+	SAREG,	TFLOAT,
+		NSPECIAL|NAREG,		RESC1,
+		"ZF", },
+
+{ SCONV,	INCREG | FEATURE_FPA,
+	SCREG,	TFLOAT,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		NCREG,		RESC1,
+		COM "unimplemented\n", },
+
+{ SCONV,	INCREG | FEATURE_VFP,
+	SCREG,	TFLOAT,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		NCREG,		RESC1,
+		"	fcvtsd AL,AR" COM "convert float to double\n" },
+
+{ SCONV,	INBREG,
+	SAREG,	TFLOAT,
+	SBREG,	TDOUBLE|TLDOUBLE,
+		NSPECIAL|NBREG,		RESC1,
+		"ZF", },
+
+{ SCONV,	INCREG | FEATURE_FPA,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		0,		RLEFT,
+		COM "convert (l)double to (l)double", },
+
+{ SCONV,	INCREG | FEATURE_VFP,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		0,		RLEFT,
+		COM "convert (l)double to (l)double", },
+
+{ SCONV,	INBREG,
+	SBREG,	TDOUBLE|TLDOUBLE,
+	SBREG,	TDOUBLE|TLDOUBLE,
+		0,		RLEFT,
+		COM "convert (l)double to (l)double", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,		FOREFF,
+	SCON|SNAME,	TANY,
+	SANY,		TANY,
+		0,	0,
+		"	bl CL" COM "call (args, no result) to scon/sname (CL)\n"
+		"ZC", },
+
+{ UCALL,	FOREFF,
+	SCON|SNAME,	TANY,
+	SANY,		TANY,
+		0,	0,
+		"	bl CL" COM "call (no args, no result) to scon/sname (CL)\n", },
+
+{ CALL,		INAREG,
+	SCON|SNAME,	TANY,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (args, result in r0) to scon/sname (CL)\n"
+		"ZC", },
+
+{ CALL,		INBREG,
+	SCON|SNAME,	TANY,
+	SBREG,		TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n"
+		"ZC", },
+
+{ CALL,		INCREG | FEATURE_FPA,
+	SCON|SNAME,	TANY,
+	SCREG,		TFLOAT,
+		NCREG|NCSL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (args, result r0) to scon/sname (CL)\n"
+		"ZC", },
+
+{ CALL,		INCREG | FEATURE_FPA,
+	SCON|SNAME,	TANY,
+	SCREG,		TDOUBLE|TLDOUBLE,
+		NCREG|NCSL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n"
+		"ZC", },
+
+{ CALL,		INAREG,
+	SCON|SNAME,	TANY,
+	SAREG,		TFLOAT,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (args, result r0) to scon/sname (CL)\n"
+		"ZC", },
+
+{ CALL,		INBREG,
+	SCON|SNAME,	TANY,
+	SBREG,		TDOUBLE|TLDOUBLE,
+		NBREG|NBSL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n"
+		"ZC", },
+
+{ UCALL,	INAREG,
+	SCON|SNAME,	TANY,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", },
+
+{ UCALL,	INBREG,
+	SCON|SNAME,	TANY,
+	SBREG,		TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", },
+
+{ UCALL,	INCREG | FEATURE_FPA,
+	SCON|SNAME,	TANY,
+	SCREG,		TFLOAT,
+		NCREG|NCSL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", },
+
+{ UCALL,	INCREG | FEATURE_FPA,
+	SCON|SNAME,	TANY,
+	SCREG,		TDOUBLE|TLDOUBLE,
+		NCREG|NCSL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", },
+
+{ CALL,		FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	mov lr,pc\n"
+		"	mov pc,AL\n"
+		"ZC", },
+
+{ UCALL,	FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	mov lr,pc\n"
+		"	mov pc,AL\n", },
+
+{ CALL,		INAREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NAREG,	RESC1,
+		"	mov lr,pc\n"
+		"	mov pc,AL\n"
+		"ZC", },
+
+{ UCALL,	INAREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NAREG,	RESC1,
+		"	mov lr,pc\n"
+		"	mov pc,AL\n", },
+
+{ CALL,		INBREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NBREG,	RESC1,
+		"	mov lr,pc\n"
+		"	mov pc,AL\n"
+		"ZC", },
+
+{ UCALL,	INBREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NBREG,	RESC1,
+		"	mov lr,pc\n"
+		"	mov pc,AL\n", },
+
+/* struct return */
+{ USTCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	bl CL\n", },
+
+{ USTCALL,	INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	bl CL\n", },
+
+{ USTCALL,	INAREG,
+	SNAME|SAREG,	TANY,
+	SANY,		TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	mov lr,pc\n"
+		"	mov pc,AL\n", },
+
+{ STCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	bl CL\n"
+		"ZC", },
+
+{ STCALL,	INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	bl CL\n"
+		"ZC", },
+
+{ STCALL,	INAREG,
+	SNAME|SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	mov lr,pc\n"
+		"	mov pc,AL\n"
+		"ZC", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+
+{ PLUS,		INAREG,
+	SAREG,	TWORD|TPOINT,
+	SCCON,	TANY,
+		NAREG,	RESC1,
+		"	add A1,AL,AR" COM "addition of constant\n", },
+
+{ PLUS,		INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SSCON,	TANY,
+		NBREG|NBSL,	RESC1,
+		"	adds A1,AL,AR" COM "64-bit addition of constant\n"
+		"	adc U1,UL,UR\n", },
+
+{ PLUS,		INAREG,
+	SAREG,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		NAREG|NASL,	RESC1,
+		"	add A1,AL,AR" COM "addition\n", },
+
+{ PLUS,		INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,
+		"	adds A1,AL,AR" COM "64-bit addition\n"
+		"	adc U1,UL,UR\n", },
+
+{ PLUS,		INCREG | FEATURE_FPA,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	adfs A1,AL,AR" COM "float add\n", },
+
+{ PLUS,		INCREG | FEATURE_VFP,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	fadds A1,AL,AR" COM "float add\n", },
+
+{ PLUS,		INAREG,
+	SAREG,	TFLOAT,
+	SAREG,	TFLOAT,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+
+{ PLUS,		INCREG | FEATURE_FPA,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	adfd A1,AL,AR" COM "double add\n", },
+
+{ PLUS,		INCREG | FEATURE_VFP,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	faddd A1,AL,AR" COM "double add\n", },
+
+{ PLUS,		INBREG,
+	SBREG,	TDOUBLE,
+	SBREG,	TDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+{ PLUS,		INCREG | FEATURE_FPA,
+	SCREG,	TLDOUBLE,
+	SCREG,	TLDOUBLE,
+		NCREG,	RESC1,
+		"	adfe A1,AL,AR" COM "ldouble add\n", },
+
+{ PLUS,		INCREG | FEATURE_VFP,
+	SCREG,	TLDOUBLE,
+	SCREG,	TLDOUBLE,
+		NCREG,	RESC1,
+		"	faddd A1,AL,AR" COM "ldouble add\n", },
+
+{ PLUS,		INBREG,
+	SBREG,	TLDOUBLE,
+	SBREG,	TLDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+{ MINUS,	INAREG,
+	SAREG,	TWORD|TPOINT,
+	SCCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	sub A1,AL,AR" COM "subtraction of constant\n", },
+
+{ MINUS,	INAREG,
+	SAREG,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		NAREG|NASL,	RESC1,
+		"	sub A1,AL,AR" COM "subtraction\n", },
+
+{ MINUS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCCON,	TANY,
+		NBREG|NBSL,	RESC1,
+		"	subs A1,AL,AR" COM "64-bit subtraction of constant\n"
+		"	rsc  U1,UL,AR\n", },
+
+{ MINUS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,
+		"	subs A1,AL,AR" COM "64-bit subtraction\n"
+		"	sbc  U1,UL,AR\n", },
+
+{ MINUS,	INCREG | FEATURE_FPA,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	sufs A1,AL,AR" COM "float subtraction\n", },
+
+{ MINUS,	INCREG | FEATURE_VFP,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	fsubs A1,AL,AR" COM "float subtraction\n", },
+
+{ MINUS,	INAREG,
+	SAREG,	TFLOAT,
+	SAREG,	TFLOAT,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+
+{ MINUS,	INCREG | FEATURE_FPA,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	sufd A1,AL,AR" COM "double subtraction\n", },
+
+{ MINUS,	INCREG | FEATURE_VFP,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	fsubd A1,AL,AR" COM "double subtraction\n", },
+
+{ MINUS,	INBREG,
+	SBREG,	TDOUBLE,
+	SBREG,	TDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+{ MINUS,	INCREG | FEATURE_FPA,
+	SCREG,	TLDOUBLE,
+	SCREG,	TLDOUBLE,
+		NCREG,	RESC1,
+		"	sufe A1,AL,AR" COM "ldouble subtraction\n", },
+
+{ MINUS,	INCREG | FEATURE_VFP,
+	SCREG,	TLDOUBLE,
+	SCREG,	TLDOUBLE,
+		NCREG,	RESC1,
+		"	fsubd A1,AL,AR" COM "double subtraction\n", },
+
+{ MINUS,	INBREG,
+	SBREG,	TLDOUBLE,
+	SBREG,	TLDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+/*
+ * The next rules handle all shift operators.
+ */
+
+{ LS,	INAREG,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TANY,
+		NAREG|NASL,	RESC1,
+		"	mov A1,AL,asl AR" COM "left shift\n", },
+
+{ LS,	INAREG,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SCCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	mov A1,AL,asl AR" COM "left shift by constant\n", },
+
+{ LS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCON,	TANY,
+		NBREG,	RESC1,
+		"ZO" },
+
+{ LS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TANY,
+		NSPECIAL|NBREG,	RESC1,
+		"ZE" },
+
+{ RS,	INAREG,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SAREG,	TANY,
+		NAREG|NASL,	RESC1,
+		"	mov A1,AL,asr AR" COM "right shift\n", },
+
+{ RS,	INAREG,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+	SAREG,	TANY,
+		NAREG|NASL,	RESC1,
+		"	mov A1,AL,lsr AR" COM "right shift\n", },
+
+{ RS,	INAREG,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SCCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	mov A1,AL,asr AR" COM "right shift by constant\n", },
+
+{ RS,	INAREG,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+	SCCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	mov A1,AL,lsr AR" COM "right shift by constant\n", },
+
+{ RS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCON,	TANY,
+		NBREG,	RESC1,
+		"ZO" },
+
+{ RS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TANY,
+		NSPECIAL|NBREG,	RESC1,
+		"ZE" },
+
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG|SNAME,	TWORD|TPOINT,
+	SAREG,		TWORD|TPOINT,
+		0,	RDEST,
+		"	str AR,AL" COM "assign word\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SOREG|SNAME,	TLONGLONG|TULONGLONG,
+	SBREG,		TLONGLONG|TULONGLONG,
+		0,	RDEST,
+		"	str AR,AL" COM "assign 64-bit value\n"
+		"	str UR,UL\n", },
+
+/* XXX don't know if this works */
+{ ASSIGN,	FOREFF|INBREG,
+	SAREG,		TPTRTO|TLONGLONG|TULONGLONG,
+	SBREG,		TLONGLONG|TULONGLONG,
+		0,	RDEST,
+		"	stmdb AL,{AR-UR}" COM "assign 64-bit value\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG|SNAME,	TCHAR|TUCHAR,
+	SAREG,		TCHAR|TUCHAR,
+		0,	RDEST,
+		"	strb AR,AL" COM "assign (u)char\n", },
+
+{ ASSIGN,	FOREFF|INAREG | FEATURE_HALFWORDS,
+	SOREG|SNAME,	TSHORT|TUSHORT,
+	SAREG,		TSHORT|TUSHORT,
+		0,	RDEST,
+		"	strh AR,AL" COM "assign (u)short\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG|SNAME,	TSHORT|TUSHORT,
+	SAREG,		TSHORT|TUSHORT,
+		NAREG|NASL,	RDEST,
+		"ZH", },
+
+{ ASSIGN, 	FOREFF|INCREG | FEATURE_FPA,
+	SOREG|SNAME,	TFLOAT,
+	SCREG,		TFLOAT,
+		0,	RDEST,
+		"	stfs AR,AL" COM "assign float\n", },
+
+{ ASSIGN, 	FOREFF|INCREG | FEATURE_VFP,
+	SOREG|SNAME,	TFLOAT,
+	SCREG,		TFLOAT,
+		0,	RDEST,
+		COM "unimplemented\n", },
+
+{ ASSIGN, 	FOREFF|INAREG,
+	SOREG|SNAME,	TFLOAT,
+	SAREG,		TFLOAT,
+		0,	RDEST,
+		"	str AR,AL" COM "assign float (soft-float)\n", },
+
+{ ASSIGN, 	FOREFF|INCREG | FEATURE_FPA,
+	SOREG|SNAME,	TDOUBLE,
+	SCREG,		TDOUBLE,
+		0,	RDEST,
+		"	stfd AR,AL" COM "assign double\n", },
+
+{ ASSIGN, 	FOREFF|INCREG | FEATURE_VFP,
+	SOREG|SNAME,	TDOUBLE,
+	SCREG,		TDOUBLE,
+		0,	RDEST,
+		COM "unimplemented\n", },
+
+{ ASSIGN, 	FOREFF|INBREG,
+	SOREG|SNAME,	TDOUBLE,
+	SBREG,		TDOUBLE,
+		0,	RDEST,
+		"	str AR,AL" COM "assign double (soft-float)\n"
+		"	str UR,UL\n", },
+
+{ ASSIGN, 	FOREFF|INCREG | FEATURE_FPA,
+	SOREG|SNAME,	TLDOUBLE,
+	SCREG,		TLDOUBLE,
+		0,	RDEST,
+		"	stfe AR,AL" COM "assign ldouble\n", },
+
+{ ASSIGN, 	FOREFF|INCREG | FEATURE_VFP,
+	SOREG|SNAME,	TLDOUBLE,
+	SCREG,		TLDOUBLE,
+		0,	RDEST,
+		COM "not implemented", },
+
+{ ASSIGN, 	FOREFF|INBREG,
+	SOREG|SNAME,	TLDOUBLE,
+	SBREG,		TLDOUBLE,
+		0,	RDEST,
+		"	str AR,AL" COM "assign ldouble (soft-float)\n"
+		"	str UR,UL\n", },
+
+/* assign register to register */
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		0,	RDEST,
+		"	mov AL,AR" COM "assign AR to AL\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+        SBREG,	TLONGLONG|TULONGLONG,
+        SBREG,	TLONGLONG|TULONGLONG,
+                0,	RDEST,
+		"	mov AL,AR" COM "assign UR:AR to UL:AL\n"
+                "	mov UL,UR\n", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_FPA,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		0,	RDEST,
+		"	mvf AL,AR" COM "assign float reg to float reg\n", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_VFP,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		0,	RDEST,
+		"	fcpys AL,AR" COM "assign float reg to float reg\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TFLOAT,
+	SAREG,	TFLOAT,
+		0,	RDEST,
+		"	mov AL,AR" COM "assign float reg to float reg\n", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_FPA,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"	mvf AL,AR" COM "assign float reg to float reg\n", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_VFP,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"	fcpyd AL,AR" COM "assign float reg to float reg\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,	TDOUBLE|TLDOUBLE,
+	SBREG,	TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"	mov AL,AR" COM "assign (l)double reg to (l)double reg\n"
+		"	mov UL,UR\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,		TANY,
+	SOREG|SNAME,	TANY,
+		3*NAREG,	RDEST,
+		"	ldr A1,AR" COM "bit-field assignment\n"
+		"	ldr A2,AL\n"
+		"	ldr A3,=M\n"
+		"	mov A1,A1,asl H\n"
+		"	and A1,A1,A3\n"
+		"	bic A2,A2,A3\n"
+		"	orr A3,A2,A1\n"
+		"	str A3,AL\n"
+		"F	ldr AD,AR\n"
+		"FZB", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,	TANY,
+	SAREG,	TANY,
+		3*NAREG,	RDEST,
+		"	ldr A2,AL" COM "bit-field assignment\n"
+		"	ldr A3,=M\n"
+		"	mov A1,AR,asl H\n"
+		"	and A1,A1,A3\n"
+		"	bic A2,A2,A3\n"
+		"	orr A3,A2,A1\n"
+		"	str A3,AL\n"
+		"F	mov AD,AR\n"
+		"FZB", },
+
+{ STASG,	INAREG|FOREFF,
+	SOREG|SNAME,	TANY,
+	SAREG,		TPTRTO|TANY,
+		NSPECIAL,	RRIGHT,
+		"ZQ", },
+
+/*
+ * DIV/MOD/MUL 
+ */
+
+{ DIV,	INAREG,
+	SAREG,	TWORD,
+	SAREG,	TWORD,
+		NSPECIAL|NAREG|NASL,	RESC1,
+		"ZE", },
+
+{ DIV,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NSPECIAL|NBREG|NBSL,	RESC1,
+		"ZE", },
+
+{ DIV,	INCREG | FEATURE_FPA,
+	SCREG,		TFLOAT,
+	SCREG,		TFLOAT,
+		NCREG,	RESC1,
+		"	dvfs A1,AL,AL" COM "fast (float) divide\n", },
+
+{ DIV,	INCREG | FEATURE_VFP,
+	SCREG,		TFLOAT,
+	SCREG,		TFLOAT,
+		NCREG,	RESC1,
+		"	fdivs A1,AL,AL" COM "fast (float) divide\n", },
+
+{ DIV,	INAREG,
+	SAREG,		TFLOAT,
+	SAREG,		TFLOAT,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+
+{ DIV,	INCREG | FEATURE_FPA,
+	SCREG,		TDOUBLE,
+	SCREG,		TDOUBLE,
+		NCREG,	RESC1,
+		"	dvfd A1,AL,AL" COM "double divide\n", },
+
+{ DIV,	INCREG | FEATURE_VFP,
+	SCREG,		TDOUBLE,
+	SCREG,		TDOUBLE,
+		NCREG,	RESC1,
+		"	fdivd A1,AL,AL" COM "double divide\n", },
+
+{ DIV,	INBREG,
+	SBREG,		TDOUBLE,
+	SBREG,		TDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+{ DIV,	INCREG | FEATURE_FPA,
+	SCREG,		TLDOUBLE,
+	SCREG,		TLDOUBLE,
+		NCREG,	RESC1,
+		"	dvfe A1,AL,AR" COM "long double load\n", },
+
+{ DIV,	INCREG | FEATURE_VFP,
+	SCREG,		TLDOUBLE,
+	SCREG,		TLDOUBLE,
+		NCREG,	RESC1,
+		"	fdivd A1,AL,AL" COM "double divide\n", },
+
+{ DIV,	INBREG,
+	SBREG,		TLDOUBLE,
+	SBREG,		TLDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+{ MOD,	INAREG,
+	SAREG,	TWORD,
+	SAREG,	TWORD,
+		NSPECIAL|NAREG,	RESC1,
+		"ZE", },
+
+{ MOD,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NSPECIAL|NBREG,	RESC1,
+		"ZE", },
+
+{ MUL,	INAREG | FEATURE_MUL,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG,	RESC1,
+		"	mul A1,AL,AR\n", },
+
+{ MUL,	INAREG,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NSPECIAL|NAREG,	RESC1,
+		"ZE", },
+
+{ MUL,	INBREG | FEATURE_MULL,
+	SAREG,		TUWORD|TPOINT|TUSHORT|TUCHAR,
+	SAREG,		TUWORD|TPOINT|TUSHORT|TUCHAR,
+		NBREG,	RESC1,
+		"	smull U1,A1,AL,AR\n", },
+
+{ MUL,	INBREG | FEATURE_MUL,
+	SAREG,		TUWORD|TPOINT|TUSHORT|TUCHAR,
+	SAREG,		TUWORD|TPOINT|TUSHORT|TUCHAR,
+		NBREG,	RESC1,
+		"	mul A1,AL,AR\n"
+		"	mov U1,A1,asr #31\n", },
+
+{ MUL,	INBREG,
+	SAREG,		TUWORD|TPOINT|TUSHORT|TUCHAR,
+	SAREG,		TUWORD|TPOINT|TUSHORT|TUCHAR,
+		NSPECIAL|NBREG,	RESC1,
+		"ZE", },
+
+{ MUL,	INBREG | FEATURE_MULL,
+	SAREG,		TSWORD|TSHORT|TCHAR,
+	SAREG,		TSWORD|TSHORT|TCHAR,
+		NBREG,	RESC1,
+		"	umull U1,A1,AL,AR\n", },
+
+{ MUL,	INBREG | FEATURE_MUL,
+	SAREG,		TSWORD|TSHORT|TCHAR,
+	SAREG,		TSWORD|TSHORT|TCHAR,
+		NBREG,	RESC1,
+		"	mul A1,AL,AR\n"
+		"	mov U1,#0\n", },
+
+{ MUL,	INBREG,
+	SAREG,		TSWORD|TSHORT|TCHAR,
+	SAREG,		TSWORD|TSHORT|TCHAR,
+		NSPECIAL|NBREG,	RESC1,
+		"ZE", },
+
+{ MUL,	INBREG | FEATURE_MULL,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SBREG,		TLONGLONG|TULONGLONG,
+		NBREG,	RESC1,
+		"	umull U1,A1,AL,AR\n", },
+
+{ MUL,	INBREG | FEATURE_MUL,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SBREG,		TLONGLONG|TULONGLONG,
+		NBREG,	RESC1,
+		"	mul A1,AL,AR\n"
+		"	mov U1,A1,asr #31\n", },
+
+{ MUL,	INBREG,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SBREG,		TLONGLONG|TULONGLONG,
+		NSPECIAL|NBREG,	RESC1,
+		"ZE", },
+
+{ MUL,	INCREG | FEATURE_FPA,
+	SCREG,		TFLOAT,
+	SCREG,		TFLOAT,
+		NCREG,	RESC1,
+		"	fmls A1,AL,AL" COM "fast (float) multiply\n", },
+
+{ MUL,	INCREG | FEATURE_VFP,
+	SCREG,		TFLOAT,
+	SCREG,		TFLOAT,
+		NCREG,	RESC1,
+		"	fmuls A1,AL,AL" COM "float multiply\n", },
+
+{ MUL,	INAREG,
+	SAREG,		TFLOAT,
+	SAREG,		TFLOAT,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+
+{ MUL,	INCREG | FEATURE_FPA,
+	SCREG,		TDOUBLE|TLDOUBLE,
+	SCREG,		TDOUBLE|TLDOUBLE,
+		NCREG,	RESC1,
+		"	mufd A1,AL,AL" COM "fast (l)double multiply\n", },
+
+{ MUL,	INCREG | FEATURE_VFP,
+	SCREG,		TDOUBLE|TLDOUBLE,
+	SCREG,		TDOUBLE|TLDOUBLE,
+		NCREG,	RESC1,
+		"	muld A1,AL,AL" COM "(l)double multiply\n", },
+
+{ MUL,	INBREG,
+	SBREG,		TDOUBLE|TLDOUBLE,
+	SBREG,		TDOUBLE|TLDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+/*
+ * Indirection operators.
+ */
+
+{ UMUL,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TWORD|TPOINT,
+		NAREG,	RESC1,
+		"	ldr A1,AL" COM "word load\n", },
+
+{ UMUL,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TCHAR,
+		NAREG,	RESC1,
+		"	ldrsb A1,AL" COM "char load\n", },
+
+{ UMUL,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TUCHAR,
+		NAREG,	RESC1,
+		"	ldrb A1,AL" COM "uchar load\n", },
+
+{ UMUL,	INAREG | FEATURE_HALFWORDS,
+	SANY,		TANY,
+	SOREG|SNAME,	TUSHORT,
+		NAREG,	RESC1,
+		"	ldrh A1,AL" COM "short load\n", },
+
+{ UMUL,	INAREG | FEATURE_HALFWORDS,
+	SANY,		TANY,
+	SOREG|SNAME,	TSHORT,
+		NAREG,	RESC1,
+		"	ldrsh A1,AL" COM "short load\n", },
+
+{ UMUL,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TSHORT|TUSHORT,
+		2*NAREG|NASL,	RESC1,
+		"ZH", },
+
+{ UMUL, INBREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TLONGLONG|TULONGLONG,
+		NBREG,	RESC1,
+		"	ldr A1,AL" COM "64-bit load\n"
+		"	ldr U1,UL\n", },
+
+{ UMUL, INCREG | FEATURE_FPA,
+	SANY,		TANY,
+	SOREG|SNAME,	TFLOAT,
+		NCREG,	RESC1,
+		"	ldfs A1,AL" COM "float load\n", },
+
+{ UMUL, INCREG | FEATURE_VFP,
+	SANY,		TANY,
+	SOREG|SNAME,	TFLOAT,
+		NCREG,	RESC1,
+		COM "not implemented\n", },
+
+{ UMUL, INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TFLOAT,
+		NAREG,	RESC1,
+		"	ldr A1,AL" COM "float load\n", },
+
+{ UMUL, INCREG | FEATURE_FPA,
+	SANY,		TANY,
+	SOREG|SNAME,	TDOUBLE,
+		NCREG,	RESC1,
+		"	ldfd A1,AL" COM "double load\n", },
+
+{ UMUL, INCREG | FEATURE_VFP,
+	SANY,		TANY,
+	SOREG|SNAME,	TDOUBLE,
+		NCREG,	RESC1,
+		COM "not implemented\n", },
+
+{ UMUL, INBREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TDOUBLE,
+		NBREG,	RESC1,
+		"	ldr A1,AL" COM "double load\n"
+		"	ldr U1,UL\n", },
+
+{ UMUL, INCREG | FEATURE_FPA,
+	SANY,		TANY,
+	SOREG|SNAME,	TLDOUBLE,
+		NCREG,	RESC1,
+		"	ldfe A1,AL" COM "long double load\n", },
+
+{ UMUL, INCREG | FEATURE_VFP,
+	SANY,		TANY,
+	SOREG|SNAME,	TLDOUBLE,
+		NCREG,	RESC1,
+		COM "not implemented\n", },
+
+{ UMUL, INBREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TLDOUBLE,
+		NBREG,	RESC1,
+		"	ldr A1,AL" COM "long double load (soft-float)\n"
+		"	ldr U1,UL\n", },
+
+/*
+ * Logical/branching operators
+ */
+
+/* compare with register */
+{ OPLOG,	FORCC,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+		0, 	RESCC,
+		"	cmp AL,AR" COM "AR-AL (sets flags)\n", },
+
+/* compare with register */
+{ OPLOG,	FORCC,
+	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
+	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
+		0, 	RESCC,
+		"	cmp AL,AR" COM "AR-AL (sets flags)\n", },
+
+/* compare with register */
+{ OPLOG,	FORCC,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		0, 	RESCC,
+		"ZD", },
+
+{ OPLOG,	FORCC | FEATURE_FPA,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NSPECIAL,	RESCC,
+		"	cmfs AL,AR" COM "float compare\n", },
+
+{ OPLOG,	FORCC | FEATURE_VFP,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		0,	RESCC,
+		"	fcmps AL,AR" COM "float compare\n", },
+
+{ OPLOG,	FORCC,
+	SAREG,	TFLOAT,
+	SAREG,	TFLOAT,
+		NSPECIAL,	RESCC,
+		"ZF", },
+
+{ OPLOG,	FORCC | FEATURE_FPA,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NSPECIAL,	RESCC,
+		"	cmfd AL,AR" COM "double compare\n", },
+
+{ OPLOG,	FORCC | FEATURE_VFP,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		0,	RESCC,
+		"	fcmpd AL,AR" COM "double compare\n", },
+
+{ OPLOG,	FORCC,
+	SBREG,	TDOUBLE,
+	SBREG,	TDOUBLE,
+		NSPECIAL,	RESCC,
+		"ZF", },
+
+{ OPLOG,	FORCC | FEATURE_FPA,
+	SCREG,	TLDOUBLE,
+	SCREG,	TLDOUBLE,
+		NSPECIAL,	RESCC,
+		"	cmfe AL,AR" COM "ldouble compare\n", },
+
+{ OPLOG,	FORCC | FEATURE_VFP,
+	SCREG,	TLDOUBLE,
+	SCREG,	TLDOUBLE,
+		0,	RESCC,
+		"	fcmpd AL,AR" COM "double compare\n", },
+
+{ OPLOG,	FORCC,
+	SBREG,	TLDOUBLE,
+	SBREG,	TLDOUBLE,
+		NSPECIAL,	RESCC,
+		"ZF", },
+
+/* AND/OR/ER */
+{ AND,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1|RESCC,
+		"	and A1,AL,AR" COM "64-bit and\n"
+		"	and U1,UL,UR\n", },
+
+{ OR,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,
+		"	orr A1,AL,AR" COM "64-bit or\n"
+		"	orr U1,UL,UR\n" },
+
+{ ER,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,
+		"	eor A1,AL,AR" COM "64-bit xor\n"
+		"	eor U1,UL,UR\n" },
+
+{ OPSIMP,	INAREG,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1|RESCC,
+		"	O A1,AL,AR\n", },
+
+{ OPSIMP,	INAREG|FORCC,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	Os A1,AL,AR\n", },
+
+
+/*
+ * Jumps.
+ */
+{ GOTO, 	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	b LL\n", },
+
+#if 0
+{ GOTO, 	FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	mov pc,AL\n", },
+#endif
+
+/*
+ * Convert LTYPE to reg.
+ */
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TWORD|TPOINT,
+		NAREG,	RESC1,
+		"	ldr A1,AL" COM "load word from memory\n", },
+
+{ OPLTYPE,      INBREG,
+        SANY,   	TANY,
+        SOREG|SNAME,	TLONGLONG|TULONGLONG,
+                NBREG,  RESC1,
+                "	ldr A1,AL" COM "load long long from memory\n"
+		"	ldr U1,UL\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TCHAR,
+		NAREG,	RESC1,
+		"	ldrsb A1,AL" COM "load char from memory\n" },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TUCHAR,
+		NAREG,	RESC1,
+		"	ldrb A1,AL" COM "load uchar from memory\n", },
+
+{ OPLTYPE,	INAREG | FEATURE_HALFWORDS,
+	SANY,		TANY,
+	SOREG|SNAME,	TSHORT,
+		NAREG,	RESC1,
+		"	ldrsh A1,AL" COM "load short from memory\n", },
+
+{ OPLTYPE,	INAREG | FEATURE_HALFWORDS,
+	SANY,		TANY,
+	SOREG|SNAME,	TUSHORT,
+		NAREG,	RESC1,
+		"	ldrh A1,AL" COM "load ushort from memory\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TSHORT|TUSHORT,
+		2*NAREG,	RESC1,
+		"ZH", },
+
+#if 0
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SCON,		TPOINT,
+		NAREG,	RESC1,
+		"	ldr A1,AL" COM "load integer constant\n", },
+#endif
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SCON,		TANY,
+		NAREG,	RESC1,
+		"ZI", },
+
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SCON,	TANY,
+		NBREG,	RESC1,
+		"ZJ", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SAREG,	TANY,
+		NAREG,	RESC1,
+		"	mov A1,AL" COM "load AL into A1\n" },
+
+{ OPLTYPE,      INBREG,
+        SANY,   TANY,
+        SBREG,	TLONGLONG|TULONGLONG,
+                NBREG,  RESC1,
+		"	mov A1,AL" COM "load UL:AL into U1:A1\n"
+                "       mov U1,UL\n", },
+
+{ OPLTYPE,	INCREG | FEATURE_FPA,
+	SANY,		TANY,
+	SOREG|SNAME,	TFLOAT,
+		NCREG,	RESC1,
+		"	ldfs A1,AL" COM "load float\n", },
+
+{ OPLTYPE,	INCREG | FEATURE_VFP,
+	SANY,		TANY,
+	SOREG|SNAME,	TFLOAT,
+		NCREG,	RESC1,
+		COM "not implemented\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TFLOAT,
+		NAREG,	RESC1,
+		"	ldr A1,AL" COM "load float (soft-float)\n", },
+
+{ OPLTYPE,	INCREG | FEATURE_FPA,
+	SANY,		TANY,
+	SOREG|SNAME,	TDOUBLE,
+		NCREG,	RESC1,
+		"	ldfd A1,AL" COM "load double\n", },
+
+{ OPLTYPE,	INCREG | FEATURE_VFP,
+	SANY,		TANY,
+	SOREG|SNAME,	TDOUBLE,
+		NCREG,	RESC1,
+		COM "not implemented\n" },
+
+{ OPLTYPE,	INBREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TDOUBLE,
+		NBREG,	RESC1,
+		"	ldr A1,AL" COM "load double (soft-float)\n"
+		"	ldr U1,UL\n", },
+
+{ OPLTYPE,	INCREG | FEATURE_FPA,
+	SANY,		TANY,
+	SOREG|SNAME,	TLDOUBLE,
+		NCREG,	RESC1,
+		"	ldfe A1,AL" COM "load ldouble\n", },
+
+{ OPLTYPE,	INCREG | FEATURE_VFP,
+	SANY,		TANY,
+	SOREG|SNAME,	TLDOUBLE,
+		NCREG,	RESC1,
+		COM "not implemented\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TLDOUBLE,
+		NBREG,	RESC1,
+		"	ldr A1,AL" COM "load ldouble (soft-float)\n"
+		"	ldr U1,UL\n", },
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS,	INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	rsb A1,AL,#0" COM "negation\n", },
+
+{ UMINUS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,
+		"	rsbs A1,AL,#0" COM "64-bit negation\n"
+		"	rsc U1,UL,#0\n", },
+
+{ UMINUS,	INCREG | FEATURE_FPA,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	mvfs A1,AL" COM "float negation\n", },
+
+{ UMINUS,	INCREG | FEATURE_VFP,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	negs A1,AL" COM "float negation\n", },
+
+{ UMINUS,	INAREG,
+	SAREG,	TFLOAT,
+	SAREG,	TFLOAT,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+
+{ UMINUS,	INCREG | FEATURE_FPA,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	mvfd A1,AL" COM "double negation\n", },
+
+{ UMINUS,	INCREG | FEATURE_VFP,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	negd A1,AL" COM "double negation\n", },
+
+{ UMINUS,	INBREG,
+	SBREG,	TDOUBLE,
+	SBREG,	TDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+{ UMINUS,	INCREG | FEATURE_FPA,
+	SCREG,	TLDOUBLE,
+	SCREG,	TLDOUBLE,
+		NCREG,	RESC1,
+		"	mvfe A1,AL" COM "ldouble negation\n", },
+
+{ UMINUS,	INCREG | FEATURE_VFP,
+	SCREG,	TLDOUBLE,
+	SCREG,	TLDOUBLE,
+		NCREG,	RESC1,
+		"	negd A1,AL" COM "ldouble negation\n", },
+
+{ UMINUS,	INBREG,
+	SBREG,	TLDOUBLE,
+	SBREG,	TLDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+{ COMPL,	INAREG,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,
+		"	mvn A1,AL" COM "complement\n", },
+
+{ COMPL,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SANY,	TANY,
+		NBREG|NBSL,	RESC1,
+		"	mvn A1,AL" COM "64-bit complement\n"
+		"	mvn U1,UL\n", },
+
+/*
+ * Arguments to functions.
+ */
+
+{ FUNARG,       FOREFF,
+        SAREG,  TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SANY,   TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+                0,      0,
+		"	stmfd sp!,{AL}" COM "save function arg to stack\n", },
+
+{ FUNARG,       FOREFF,
+        SBREG,  TLONGLONG|TULONGLONG,
+        SANY,	TLONGLONG|TULONGLONG,
+                0,      0,
+		"	stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", },
+
+{ FUNARG,	FOREFF,
+	SCREG,	TFLOAT,
+	SANY,	TFLOAT,
+		0,	0,
+		"	stmfd sp!,{AL}" COM "save function arg to stack\n", },
+
+{ FUNARG,       FOREFF,
+        SCREG,  TDOUBLE|TLDOUBLE,
+        SANY,  TDOUBLE|TLDOUBLE,
+                0,      0,
+		"	stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", },
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	"help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
Index: uspace/app/pcc/arch/arm32
===================================================================
--- uspace/app/pcc/arch/arm32	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/arm32	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1 @@
+arm
Index: uspace/app/pcc/arch/hppa/code.c
===================================================================
--- uspace/app/pcc/arch/hppa/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/hppa/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,277 @@
+/*	$OpenBSD: code.c,v 1.2 2007/11/22 15:06:43 stefan Exp $	*/
+
+/*
+ * Copyright (c) 2007 Michael Shalayeff
+ * 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"
+
+NODE *funarg(NODE *, int *);
+int argreg(TWORD, int *);
+
+static const char *const loctbl[] = { "text", "data", "section .rodata" };
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+	extern char *nextsect;
+	static int lastloc = -1;
+	TWORD t;
+	char *n;
+	int s;
+
+	if (sp == NULL) {
+		lastloc = -1;
+		return;
+	}
+	t = sp->stype;
+	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+	if (nextsect) {
+		printf("\t.section %s\n", nextsect);
+		nextsect = NULL;
+		s = -1;
+	} else if (s != lastloc)
+		printf("\t.%s\n", loctbl[s]);
+	lastloc = s;
+	while (ISARY(t))
+		t = DECREF(t);
+	s = ISFTN(t) ? ALINT : talign(t, sp->ssue);
+	if (s > ALCHAR)
+		printf("\t.align\t%d\n", s / ALCHAR);
+	n = sp->soname ? sp->soname : sp->sname;
+	if (sp->sclass == EXTDEF)
+		printf("\t.export %s, %s\n", n,
+		    ISFTN(t)? "code" : "data");
+	if (sp->slevel == 0)
+		printf("\t.type\t%s, @%s\n\t.label %s\n",
+		    n, ISFTN(t)? "function" : "object", n);
+	else
+		printf("\t.type\t" LABFMT ", @%s\n\t.label\t" LABFMT "\n", 
+		    sp->soffset, ISFTN(t)? "function" : "object", sp->soffset);
+}
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode()
+{
+	NODE *p, *q;
+	int sz;
+
+	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+		return;
+	/* address of return struct is in %ret0 */
+	/* create a call to memcpy() */
+	/* will get the result in %ret0 */
+	p = block(REG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+	p->n_rval = RET0;
+	q = block(OREG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+	q->n_rval = FP;
+	q->n_lval = 8; /* return buffer offset */
+	p = block(CM, q, p, INT, 0, MKSUE(INT));
+	sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR;
+	p = block(CM, p, bcon(sz), INT, 0, MKSUE(INT));
+	p->n_right->n_name = "";
+	p = block(CALL, bcon(0), p, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+	p->n_left->n_name = "memcpy";
+	p = clocal(p);
+	send_passt(IP_NODE, p);
+}
+
+int
+argreg(TWORD t, int *n)
+{
+	switch (t) {
+	case FLOAT:
+		return FR7L - 2 * (*n)++;
+	case DOUBLE:
+	case LDOUBLE:
+		*n += 2;
+		return FR6 - *n - 2;
+	case LONGLONG:
+	case ULONGLONG:
+		*n += 2;
+		return AD1 - (*n - 2) / 2;
+	default:
+		return ARG0 - (*n)++;
+	}
+}
+
+/*
+ * code for the beginning of a function; 'a' is an array of
+ * indices in symtab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **a, int cnt)
+{
+	struct symtab *sp;
+	NODE *p, *q;
+	int i, n, sz;
+
+	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+		/* Function returns struct, adjust arg offset */
+		for (i = 0; i < n; i++)
+			a[i]->soffset += SZPOINT(LONG);
+	}
+
+	/* recalculate the arg offset and create TEMP moves */
+	for (n = 0, i = 0; i < cnt; i++) {
+		sp = a[i];
+
+		sz = szty(sp->stype);
+		if (n % sz)
+			n++;	/* XXX LDOUBLE */
+
+		if (n < 4) {
+			p = tempnode(0, sp->stype, sp->sdf, sp->ssue);
+			/* TODO p->n_left->n_lval = -(32 + n * 4); */
+			q = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->ssue);
+			q->n_rval = argreg(sp->stype, &n);
+			p = buildtree(ASSIGN, p, q);
+			sp->soffset = regno(p->n_left);
+			sp->sflags |= STNODE;
+			ecomp(p);
+		} else {
+			sp->soffset += SZINT * n;
+			if (xtemps) {
+				/* put stack args in temps if optimizing */
+				p = tempnode(0, sp->stype, sp->sdf, sp->ssue);
+				p = buildtree(ASSIGN, p, buildtree(NAME, 0, 0));
+				sp->soffset = regno(p->n_left);
+				sp->sflags |= STNODE;
+				ecomp(p);
+			}
+		}
+	}
+}
+
+
+/*
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+	SETOFF(autooff, SZINT);
+}
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int errors)
+{
+	if (errors)
+		return;
+
+	printf("\t.end\n");
+}
+
+void
+bjobcode(void)
+{
+	printf("\t.level\t1.1\n"
+	    "\t.import $global$, data\n"
+	    "\t.import $$dyncall, millicode\n");
+}
+
+/*
+ * 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;
+}
+
+NODE *
+funarg(NODE *p, int *n)
+{
+	NODE *r;
+	int sz;
+
+	if (p->n_op == CM) {
+		p->n_left = funarg(p->n_left, n);
+		p->n_right = funarg(p->n_right, n);
+		return p;
+	}
+
+	sz = szty(p->n_type);
+	if (*n % sz)
+		(*n)++;	/* XXX LDOUBLE */
+
+	if (*n >= 4) {
+		*n += sz;
+		r = block(OREG, NIL, NIL, p->n_type|PTR, 0,
+		    MKSUE(p->n_type|PTR));
+		r->n_rval = SP;
+		r->n_lval = -(32 + *n * 4);
+	} else {
+		r = block(REG, NIL, NIL, p->n_type, 0, 0);
+		r->n_lval = 0;
+		r->n_rval = argreg(p->n_type, n);
+	}
+	p = block(ASSIGN, r, p, p->n_type, 0, 0);
+	clocal(p);
+
+	return p;
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+	int n = 0;
+
+	p->n_right = funarg(p->n_right, &n);
+	return p;
+}
Index: uspace/app/pcc/arch/hppa/local.c
===================================================================
--- uspace/app/pcc/arch/hppa/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/hppa/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,994 @@
+/*	$OpenBSD: local.c,v 1.2 2007/11/18 17:39:55 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2007 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+#include "pass2.h"
+
+/*	this file contains code which is dependent on the target machine */
+
+#define	IALLOC(sz)	(isinlining ? permalloc(sz) : tmpalloc(sz))
+
+struct symtab *makememcpy(void);
+char *section2string(char *, int);
+
+/* 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, *sp;
+	register NODE *r, *l, *s;
+	register int o, m, rn;
+	char *ch, name[16], *n;
+	TWORD t;
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal: %p\n", p);
+		fwalk(p, eprint, 0);
+	}
+#endif
+	switch (o = p->n_op) {
+
+	case NAME:
+		if ((q = p->n_sp) == NULL)
+			break;	/* Nothing to care about */
+
+		switch (q->sclass) {
+
+		case PARAM:
+			/* first four integral args are in regs */
+			rn = (q->soffset >> 5) - 8;
+			if (rn < 4) {
+				r = block(REG, NIL, NIL, p->n_type, 0, 0);
+				r->n_lval = 0;
+				switch (p->n_type) {
+				case FLOAT:
+					r->n_rval = FR7L - rn;
+					break;
+				case DOUBLE:
+				case LDOUBLE:
+					r->n_rval = FR6 - rn;
+					break;
+				case LONGLONG:
+				case ULONGLONG:
+					r->n_rval = AD1 - rn / 2;
+					break;
+				default:
+					r->n_rval = ARG0 - rn;
+				}
+				r->n_sue = p->n_sue;
+				p->n_sue = NULL;
+				nfree(p);
+				p = r;
+				break;
+			}
+			/* FALLTHROUGH */
+
+		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 REGISTER:
+			p->n_op = REG;
+			p->n_lval = 0;
+			p->n_rval = q->soffset;
+			break;
+
+		case STATIC:
+		case EXTERN:
+			if (p->n_sp->sflags & SSTRING)
+				break;
+
+			n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname;
+			if (strncmp(n, "__builtin", 9) == 0)
+				break;
+
+			l = block(REG, NIL, NIL, INT, 0, 0);
+			l->n_lval = 0;
+			l->n_rval = R1;
+			l = block(ASSIGN, l, p, INT, 0, 0);
+			r = xbcon(0, p->n_sp, INT);
+			p = block(UMUL,
+			    block(PLUS, l, r, INT, 0, 0),
+			    NIL, p->n_type, p->n_df, p->n_sue);
+			break;
+		}
+		break;
+
+	case ADDROF:
+		l = p->n_left;
+		if (!l->n_sp)
+			break;
+
+		if (l->n_sp->sclass != EXTERN &&
+		    l->n_sp->sclass != STATIC &&
+		    l->n_sp->sclass != USTATIC &&
+		    l->n_sp->sclass != EXTDEF)
+			break;
+
+		l = block(REG, NIL, NIL, INT, 0, 0);
+		l->n_lval = 0;
+		l->n_rval = R1;
+		l = block(ASSIGN, l, p->n_left, INT, 0, 0);
+		r = xbcon(0, p->n_left->n_sp, INT);
+		l = block(PLUS, l, r, p->n_type, p->n_df, p->n_sue);
+		nfree(p);
+		p = l;
+		break;
+
+	case CBRANCH:
+		l = p->n_left;
+
+		/*
+		 * Remove unnecessary conversion ops.
+		 */
+		if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
+			if (coptype(l->n_op) != BITYPE)
+				break;
+			if (l->n_right->n_op == ICON) {
+				r = l->n_left->n_left;
+				if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
+					break;
+				/* Type must be correct */
+				t = r->n_type;
+				nfree(l->n_left);
+				l->n_left = r;
+				l->n_type = t;
+				l->n_right->n_type = t;
+			}
+		}
+		break;
+
+	case PCONV:
+		/* Remove redundant PCONV's. Be careful */
+		l = p->n_left;
+		if (l->n_op == ICON) {
+			l->n_lval = (unsigned)l->n_lval;
+			goto delp;
+		}
+		if (l->n_type < INT || l->n_type == LONGLONG ||
+		    l->n_type == ULONGLONG) {
+			/* float etc? */
+			p->n_left = block(SCONV, l, NIL,
+			    UNSIGNED, 0, MKSUE(UNSIGNED));
+			break;
+		}
+		/* if left is SCONV, cannot remove */
+		if (l->n_op == SCONV)
+			break;
+
+		/* avoid ADDROF TEMP */
+		if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
+			break;
+
+		/* if conversion to another pointer type, just remove */
+		if (p->n_type > BTMASK && l->n_type > BTMASK)
+			goto delp;
+		break;
+
+	delp:	l->n_type = p->n_type;
+		l->n_qual = p->n_qual;
+		l->n_df = p->n_df;
+		l->n_sue = p->n_sue;
+		nfree(p);
+		p = l;
+		break;
+
+	case SCONV:
+		l = p->n_left;
+
+		if (p->n_type == l->n_type) {
+			nfree(p);
+			p = l;
+			break;
+		}
+
+		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+		    btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
+			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+			    l->n_type != FLOAT && l->n_type != DOUBLE &&
+			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+				if (l->n_op == UMUL || l->n_op == TEMP ||
+				    l->n_op == NAME) {
+					l->n_type = p->n_type;
+					nfree(p);
+					p = l;
+					break;
+				}
+			}
+		}
+
+		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+		    coptype(l->n_op) == BITYPE) {
+			l->n_type = p->n_type;
+			nfree(p);
+			p = l;
+			break;
+		}
+
+		o = l->n_op;
+		m = p->n_type;
+
+		if (o == ICON) {
+			CONSZ val = l->n_lval;
+
+			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
+			    switch (m) {
+			case BOOL:
+				l->n_lval = l->n_lval != 0;
+				break;
+			case CHAR:
+				l->n_lval = (char)val;
+				break;
+			case UCHAR:
+				l->n_lval = val & 0377;
+				break;
+			case SHORT:
+				l->n_lval = (short)val;
+				break;
+			case USHORT:
+				l->n_lval = val & 0177777;
+				break;
+			case ULONG:
+			case UNSIGNED:
+				l->n_lval = val & 0xffffffff;
+				break;
+			case LONG:
+			case INT:
+				l->n_lval = (int)val;
+				break;
+			case LONGLONG:
+				l->n_lval = (long long)val;
+				break;
+			case ULONGLONG:
+				l->n_lval = val;
+				break;
+			case VOID:
+				break;
+			case LDOUBLE:
+			case DOUBLE:
+			case FLOAT:
+				l->n_op = FCON;
+				l->n_dcon = val;
+				break;
+			default:
+				cerror("unknown type %d", m);
+			}
+			l->n_type = m;
+			l->n_sue = MKSUE(m);
+			nfree(p);
+			return l;
+                } else if (l->n_op == FCON) {
+			l->n_lval = l->n_dcon;
+			l->n_sp = NULL;
+			l->n_op = ICON;
+			l->n_type = m;
+			l->n_sue = MKSUE(m);
+			nfree(p);
+			return clocal(l);
+		}
+
+		if (DEUNSIGN(p->n_type) == SHORT &&
+		    DEUNSIGN(l->n_type) == SHORT) {
+			nfree(p);
+			p = l;
+		}
+		if ((p->n_type == CHAR || p->n_type == UCHAR ||
+		    p->n_type == SHORT || p->n_type == USHORT) &&
+		    (l->n_type == FLOAT || l->n_type == DOUBLE ||
+		    l->n_type == LDOUBLE)) {
+			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
+			p->n_left->n_type = INT;
+			break;
+		}
+		break;
+
+	case MOD:
+	case DIV:
+		if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
+			break;
+		if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
+			break;
+		/* make it an int division by inserting conversions */
+		p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKSUE(INT));
+		p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKSUE(INT));
+		p = block(SCONV, p, NIL, p->n_type, 0, MKSUE(p->n_type));
+		p->n_left->n_type = INT;
+		break;
+
+	case PMCONV:
+	case PVCONV:
+                if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
+                nfree(p);
+                return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
+
+	case LS:
+	case RS:
+		/* shift count must be in an int */
+		if (p->n_right->n_op == ICON || p->n_right->n_lval <= 32)
+			break;	/* do not do anything */
+		if (p->n_right->n_type != INT || p->n_right->n_lval > 32)
+			p->n_right = block(SCONV, p->n_right, NIL,
+			    INT, 0, MKSUE(INT));
+		break;
+
+#if 0
+	case FLD:
+		/* already rewritten (in ASSIGN) */
+		if (p->n_left->n_op == TEMP)
+			break;
+
+		r = tempnode(0, p->n_type, p->n_df, p->n_sue);
+		l = block(ASSIGN, r, p->n_left, p->n_type, p->n_df, p->n_sue);
+		p->n_left = tcopy(r);
+		p = block(COMOP, l, p, p->n_type, p->n_df, p->n_sue);
+		break;
+#endif
+
+	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, p->n_df, p->n_sue);
+		p->n_left->n_rval = p->n_left->n_type == BOOL ?
+		    RETREG(CHAR) : RETREG(p->n_type);
+		if (p->n_right->n_op != FLD)
+			break;
+		break;
+
+	case ASSIGN:
+		r = p->n_right;
+		l = p->n_left;
+
+		/* rewrite ICON#0 into %r0 */
+		if (r->n_op == ICON && r->n_lval == 0 &&
+		    (l->n_op == REG || l->n_op == OREG)) {
+			r->n_op = REG;
+			r->n_rval = R0;
+		}
+
+		/* rewrite FCON#0 into %fr0 */
+		if (r->n_op == FCON && r->n_lval == 0 && l->n_op == REG) {
+			r->n_op = REG;
+			r->n_rval = r->n_type == FLOAT? FR0L : FR0;
+		}
+
+		if (p->n_left->n_op != FLD)
+			break;
+
+		r = tempnode(0, l->n_type, l->n_df, l->n_sue);
+		p = block(COMOP,
+		    block(ASSIGN, r, l->n_left, l->n_type, l->n_df, l->n_sue),
+		    p, p->n_type, p->n_df, p->n_sue);
+		s = tcopy(l->n_left);
+		p = block(COMOP, p,
+		    block(ASSIGN, s, tcopy(r), l->n_type, l->n_df, l->n_sue),
+		    p->n_type, p->n_df, p->n_sue);
+		l->n_left = tcopy(r);
+		break;
+
+	case STASG:
+		/* memcpy(left, right, size) */
+		sp = makememcpy();
+		l = p->n_left;
+		/* guess struct return */
+		if (l->n_op == NAME && ISFTN(l->n_sp->stype)) {
+			l = block(REG, NIL, NIL, VOID|PTR, 0, MKSUE(LONG));
+			l->n_lval = 0;
+			l->n_rval = RET0;
+		} else if (l->n_op == UMUL)
+			l = tcopy(l->n_left);
+		else if (l->n_op == NAME)
+			l = block(ADDROF,tcopy(l),NIL,PTR|STRTY,0,MKSUE(LONG));
+		l = block(CALL, block(ADDROF,
+		    (s = block(NAME, NIL, NIL, FTN, 0, MKSUE(LONG))),
+		    NIL, PTR|FTN, 0, MKSUE(LONG)),
+		    block(CM, block(CM, l, tcopy(p->n_right),
+		    STRTY|PTR, 0, MKSUE(LONG)),
+		    (r = block(ICON, NIL, NIL, INT, 0, MKSUE(LONG))), 0, 0, 0),
+		    INT, 0, MKSUE(LONG));
+		r->n_lval = p->n_sue->suesize/SZCHAR;
+		s->n_sp = sp;
+		s->n_df = s->n_sp->sdf;
+		defid(s, EXTERN);
+		tfree(p);
+		p = l;
+		p->n_left = clocal(p->n_left);
+		p->n_right = clocal(p->n_right);
+		calldec(p->n_left, p->n_right);
+		funcode(p);
+		break;
+
+	case STARG:
+		/* arg = memcpy(argN-size, src, size) */
+		sp = makememcpy();
+		l = block(CALL, block(ADDROF,
+		    (s = block(NAME, NIL, NIL, FTN, 0, MKSUE(LONG))),NIL,0,0,0),
+		    block(CM, block(CM, tcopy(p), tcopy(p->n_left), 0, 0, 0),
+		    (r = block(ICON, NIL, NIL, INT, 0, MKSUE(LONG))), 0, 0, 0),
+		    INT, 0, MKSUE(LONG));
+		r->n_lval = p->n_sue->suesize/SZCHAR;
+		s->n_sp = sp;
+		s->n_df = s->n_sp->sdf;
+		defid(s, EXTERN);
+		tfree(p);
+		p = l;
+		p->n_left = clocal(p->n_left);
+		calldec(p->n_left, p->n_right);
+		funcode(p);
+		break;
+
+	case STCALL:
+	case CALL:
+		for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+			if (r->n_right->n_op == ASSIGN &&
+			    r->n_right->n_right->n_op == CALL) {
+				s = r->n_right->n_right;
+				l = tempnode(0, s->n_type, s->n_df, s->n_sue);
+				ecode(buildtree(ASSIGN, l, s));
+				r->n_right->n_right = tcopy(l);
+			}
+			if (r->n_left->n_op == ASSIGN &&
+			    r->n_left->n_right->n_op == CALL) {
+				s = r->n_left->n_right;
+				l = tempnode(0, s->n_type, s->n_df, s->n_sue);
+				ecode(buildtree(ASSIGN, l, s));
+				r->n_left->n_right = tcopy(l);
+			}
+		}
+		break;
+	}
+
+	/* second pass - rewrite long ops */
+	switch (o) {
+	case DIV:
+	case MOD:
+	case MUL:
+	case RS:
+	case LS:
+		if (!(p->n_type == LONGLONG || p->n_type == ULONGLONG) ||
+		    !((o == DIV || o == MOD || o == MUL) &&
+		      p->n_type < FLOAT))
+			break;
+		if (o == DIV && p->n_type == ULONGLONG) ch = "udiv";
+		else if (o == DIV) ch = "div";
+		else if (o == MUL) ch = "mul";
+		else if (o == MOD && p->n_type == ULONGLONG) ch = "umod";
+		else if (o == MOD) ch = "mod";
+		else if (o == RS && p->n_type == ULONGLONG) ch = "lshr";
+		else if (o == RS) ch = "ashr";
+		else if (o == LS) ch = "ashl";
+		else break;
+		snprintf(name, sizeof(name), "__%sdi3", ch);
+		p->n_right = block(CM, p->n_left, p->n_right, 0, 0, 0);
+		p->n_left = block(ADDROF,
+		    block(NAME, NIL, NIL, FTN, 0, MKSUE(INT)), NIL,
+		    PTR|FTN, 0, MKSUE(INT));
+		p->n_left->n_left->n_sp = lookup(addname(name), 0);
+		defid(p->n_left->n_left, EXTERN);
+		p->n_left = clocal(p->n_left);
+		calldec(p->n_left, p->n_right);
+		p->n_op = CALL;
+		funcode(p);
+		break;
+	}
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal end: %p\n", p);
+		fwalk(p, eprint, 0);
+	}
+#endif
+	return(p);
+}
+
+struct symtab *
+makememcpy()
+{
+	NODE *memcpy, *args, *t, *u;
+	struct symtab *sp;
+
+	/* TODO check that it's a func proto */
+	if ((sp = lookup(addname("memcpy"), SNORMAL)))
+		return sp;
+
+	memcpy = block(NAME, NIL, NIL, 0, 0, MKSUE(LONG));
+	memcpy->n_sp = sp = lookup(addname("memcpy"), SNORMAL);
+	defid(memcpy, EXTERN);
+
+	args = block(CM, block(CM,
+	    block(NAME, NIL, NIL, VOID|PTR, 0, MKSUE(LONG)),
+	    block(NAME, NIL, NIL, VOID|PTR, 0, MKSUE(LONG)), 0, 0, 0),
+	    block(NAME, NIL, NIL, LONG, 0, MKSUE(LONG)), 0, 0, 0);
+
+	tymerge(t = block(TYPE, NIL, NIL, VOID|PTR, 0, 0),
+	    (u = block(UMUL, block(CALL, memcpy, args, LONG, 0, 0),
+	    NIL, LONG, 0, 0)));
+	tfree(t);
+	tfree(u);
+
+	return sp;
+}
+
+void
+myp2tree(NODE *p)
+{
+	struct symtab *sp;
+	int o = p->n_op;
+
+	if (o != FCON)
+		return;
+
+	/* Write float constants to memory */
+	/* Should be volontary per architecture */
+
+#if 0
+	setloc1(RDATA);
+	defalign(p->n_type == FLOAT ? ALFLOAT : p->n_type == DOUBLE ?
+	    ALDOUBLE : ALLDOUBLE );
+	deflab1(i = getlab());
+#endif
+	sp = inlalloc(sizeof(struct symtab));
+	sp->sclass = STATIC;
+	sp->ssue = MKSUE(p->n_type);
+	sp->slevel = 1; /* fake numeric label */
+	sp->soffset = getlab();
+	sp->sflags = 0;
+	sp->stype = p->n_type;
+	sp->squal = (CON >> TSHIFT);
+
+	defloc(sp);
+	ninval(0, btdims[p->n_type].suesize, p);
+
+	p->n_op = NAME;
+	p->n_lval = 0;
+	p->n_sp = sp;
+
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+	return(1);  /* all names can have & taken on them */
+}
+
+/*
+ * at the end of the arguments of a ftn, set the automatic offset
+ */
+void
+cendarg()
+{
+	/* TODO can use to generate sp/rp tree ops? */
+	autooff = AUTOINIT;
+}
+
+/*
+ * Return 1 if a variable of type "t" is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+	return 1;
+}
+
+/*
+ * return a node, for structure references, which is suitable for
+ * being added to a pointer of type t, in order to be off bits offset
+ * into a structure
+ * t, d, and s are the type, dimension offset, and sizeoffset
+ * For pdp10, return the type-specific index number which calculation
+ * is based on its size. For example, short a[3] would return 3.
+ * Be careful about only handling first-level pointers, the following
+ * indirections must be fullword.
+ */
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
+{
+	register NODE *p;
+
+	if (xdebug)
+		printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
+		    off, t, d, sue->suesize);
+
+	p = bcon(0);
+	p->n_lval = off/SZCHAR;	/* Default */
+	return(p);
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a storeable node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+	NODE *sp;
+
+	p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
+
+	/* sub the size from sp */
+	sp = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	ecomp(buildtree(PLUSEQ, sp, p));
+
+	/* save the address of sp */
+	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	t->n_type = sp->n_type;
+	ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+}
+
+#if 0
+/*
+ * Print out an integer constant of size size.
+ * can only be sizes <= SZINT.
+ */
+void
+indata(CONSZ val, int size)
+{
+	switch (size) {
+	case SZCHAR:
+		printf("\t.byte %d\n", (int)val & 0xff);
+		break;
+	case SZSHORT:
+		printf("\t.word %d\n", (int)val & 0xffff);
+		break;
+	case SZINT:
+		printf("\t.long %d\n", (int)val & 0xffffffff);
+		break;
+	default:
+		cerror("indata");
+	}
+}
+#endif
+
+/*
+ * Print out a string of characters.
+ * Assume that the assembler understands C-style escape
+ * sequences.  Location is already set.
+ */
+void
+instring(struct symtab *sp)
+{
+	char *s, *str;
+
+	defloc(sp);
+	str = sp->sname;
+
+	/* be kind to assemblers and avoid long strings */
+	printf("\t.ascii\t\"");
+	for (s = str; *s != 0; ) {
+		if (*s++ == '\\') {
+			(void)esccon(&s);
+		}
+		if (s - str > 64) {
+			fwrite(str, 1, s - str, stdout);
+			printf("\"\n\t.ascii\t\"");
+			str = s;
+		}
+	}
+	fwrite(str, 1, s - str, stdout);
+	printf("\\0\"\n");
+}
+
+static int inbits, inval;
+
+/*
+ * set fsz bits in sequence to zero.
+ */
+void
+zbits(OFFSZ off, int fsz)
+{
+	int m;
+
+	if (idebug)
+		printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
+	if ((m = (inbits % SZCHAR))) {
+		m = SZCHAR - m;
+		if (fsz < m) {
+			inbits += fsz;
+			return;
+		} else {
+			fsz -= m;
+			printf("\t.byte %d\n", inval);
+			inval = inbits = 0;
+		}
+	}
+	if (fsz >= SZCHAR) {
+		printf("\t.zero %d\n", fsz/SZCHAR);
+		fsz -= (fsz/SZCHAR) * SZCHAR;
+	}
+	if (fsz) {
+		inval = 0;
+		inbits = fsz;
+	}
+}
+
+/*
+ * Initialize a bitfield.
+ */
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+	if (idebug)
+		printf("infld off %lld, fsz %d, val %lld inbits %d\n",
+		    off, fsz, val, inbits);
+	val &= (1 << fsz)-1;
+	while (fsz + inbits >= SZCHAR) {
+		inval |= (val << inbits);
+		printf("\t.byte %d\n", inval & 255);
+		fsz -= (SZCHAR - inbits);
+		val >>= (SZCHAR - inbits);
+		inval = inbits = 0;
+	}
+	if (fsz) {
+		inval |= (val << inbits);
+		inbits += fsz;
+	}
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ *
+ * XXX this relies on the host fp numbers representation
+ */
+void
+ninval(CONSZ off, int fsz, NODE *p)
+{
+	union { float f; double d; long double l; int i[3]; } u;
+	struct symtab *q;
+	TWORD t;
+	int i;
+
+	t = p->n_type;
+	if (t > BTMASK)
+		t = INT; /* pointer */
+
+	if (p->n_op != ICON && p->n_op != FCON)
+		cerror("ninval: init node not constant");
+
+	if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
+		uerror("element not constant");
+
+	switch (t) {
+	case LONGLONG:
+	case ULONGLONG:
+		i = (p->n_lval >> 32);
+		p->n_lval &= 0xffffffff;
+		p->n_type = INT;
+		ninval(off, 32, p);
+		p->n_lval = i;
+		ninval(off+32, 32, p);
+		break;
+	case INT:
+	case UNSIGNED:
+		printf("\t.long 0x%x", (int)p->n_lval);
+		if ((q = p->n_sp) != NULL) {
+			if ((q->sclass == STATIC && q->slevel > 0)) {
+				printf("+" LABFMT, q->soffset);
+			} else
+				printf("+%s",
+				    q->soname ? q->soname : exname(q->sname));
+		}
+		printf("\n");
+		break;
+	case SHORT:
+	case USHORT:
+		printf("\t.short 0x%x\n", (int)p->n_lval & 0xffff);
+		break;
+	case BOOL:
+		if (p->n_lval > 1)
+			p->n_lval = p->n_lval != 0;
+		/* FALLTHROUGH */
+	case CHAR:
+	case UCHAR:
+		/* TODO make the upper layer give an .asciz */
+		printf("\t.byte %d\n", (int)p->n_lval & 0xff);
+		break;
+	case LDOUBLE:
+	case DOUBLE:
+		u.d = (double)p->n_dcon;
+		printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+		break;
+	case FLOAT:
+		u.f = (float)p->n_dcon;
+		printf("\t.long\t0x%x\n", u.i[0]);
+		break;
+	default:
+		cerror("ninval");
+	}
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+	if (p == NULL)
+		return "";
+	return p;
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+	switch (BTYPE(type)) {
+	case LONG:
+		MODTYPE(type,INT);
+		break;
+
+	case ULONG:
+		MODTYPE(type,UNSIGNED);
+	}
+
+	return (type);
+}
+
+void
+calldec(NODE *f, NODE *a)
+{
+	struct symtab *q;
+	if (f->n_op == UMUL && f->n_left->n_op == PLUS &&
+	    f->n_left->n_right->n_op == ICON)
+		q = f->n_left->n_right->n_sp;
+	else if (f->n_op == PLUS && f->n_right->n_op == ICON)
+		q = f->n_right->n_sp;
+	else {
+		fwalk(f, eprint, 0);
+		cerror("unknown function");
+		return;
+	}
+
+	printf("\t.import\t%s,code\n", q->soname ? q->soname : exname(q->sname));
+}
+
+void
+extdec(struct symtab *q)
+{
+	printf("\t.import\t%s,data\n", q->soname ? q->soname : exname(q->sname));
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+	int off;
+
+	off = tsize(sp->stype, sp->sdf, sp->ssue);
+	off = (off + (SZCHAR - 1)) / SZCHAR;
+	printf("\t.%scomm\t", sp->sclass == STATIC ? "l" : "");
+	if (sp->slevel == 0)
+		printf("%s,0%o\n", sp->soname ? sp->soname : exname(sp->sname), off);
+	else
+		printf(LABFMT ",0%o\n", sp->soffset, off);
+}
+
+char *
+section2string(char *name, int len)
+{
+	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;
+	}
+
+	return newstring(name, len);
+}
+
+char *nextsect;
+char *alias;
+int constructor;
+int destructor;
+
+#define	SSECTION	010000
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+	char *a2 = pragtok(NULL);
+
+	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, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+	if (alias != NULL && (sp->sclass != PARAM)) {
+		printf("\t.globl %s\n%s = %s\n", exname(sp->soname),
+		    exname(sp->soname), exname(alias));
+		alias = NULL;
+	}
+	if ((constructor || destructor) && (sp->sclass != PARAM)) {
+		printf("\t.section .%ctors,\"aw\",@progbits\n"
+		    "\t.p2align 2\n\t.long %s\n\t.previous\n",
+		    constructor ? 'c' : 'd', exname(sp->sname));
+		constructor = destructor = 0;
+	}
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
Index: uspace/app/pcc/arch/hppa/local2.c
===================================================================
--- uspace/app/pcc/arch/hppa/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/hppa/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,879 @@
+/*	$OpenBSD$	*/
+
+/*
+ * Copyright (c) 2007 Michael Shalayeff
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+# include <ctype.h>
+# include <string.h>
+
+void acon(NODE *p);
+void prtprolog(struct interpass_prolog *, int);
+int countargs(NODE *p, int *);
+void fixcalls(NODE *p, void *);
+
+static int stkpos;
+int p2calls;
+
+static const int rl[] =
+  { R0, R1, R1, R1, R1, R1, R31, R31, R31, R31,
+    R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18,
+    T1, T4, T3, T2, ARG3, ARG1, RET1 };
+static const int rh[] =
+  { R0, R31, T4, T3, T2, T1, T4, T3, T2, T1,
+    R18, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17,
+    T4, T3, T2, T1, ARG2, ARG0, RET0 };
+
+void
+deflab(int label)
+{
+	printf("\t.label\t" LABFMT "\n", label);
+}
+
+static int regoff[MAXREGS];
+static TWORD ftype;
+
+/*
+ * Print out the prolog assembler.
+ * addto and regoff are already calculated.
+ */
+void
+prtprolog(struct interpass_prolog *ipp, int addto)
+{
+	int i;
+
+	/* if this functions calls nothing -- no frame is needed */
+	if (p2calls || p2maxautooff > 4) {
+		printf("\tcopy\t%%r3,%%r1\n\tcopy\t%%sp,%%r3\n");
+		if (addto < 0x2000)
+			printf("\tstw,ma\t%%r1,%d(%%sp)\n", addto);
+		else if (addto < 0x802000)
+			printf("\tstw,ma\t%%r1,8192(%%sp)\n"
+			    "\taddil\t%d-8192,%%sp\n"
+			    "\tcopy\t%%r1,%%sp\n", addto);
+		else
+			comperr("too much local allocation");
+		if (p2calls)
+			printf("\tstw\t%%rp,-20(%%r3)\n");
+	}
+
+	for (i = 0; i < MAXREGS; i++)
+		if (TESTBIT(ipp->ipp_regs, i)) {
+			if (i <= R31)
+				printf("\tstw\t%s,%d(%%r3)\n",
+				    rnames[i], regoff[i]);
+			else if (i <= RETD0)
+				printf("\tstw\t%s,%d(%%r3)\n"
+				    "\tstw\t%s,%d(%%r3)\n",
+				    rnames[rl[i - RD0]], regoff[i] + 0,
+				    rnames[rh[i - RD0]], regoff[i] + 4);
+			else if (i <= FR31)
+				printf("\tfstws\t%s,%d(%%r3)\n",
+				    rnames[i], regoff[i]);
+			else
+				printf("\tfstds\t%s,%d(%%r3)\n",
+				    rnames[i], regoff[i]);
+		}
+}
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog *ipp)
+{
+	int i, addto, off;
+
+	addto = 32;
+	if (p2calls) {
+		i = p2calls - 1;
+		/* round up to 4 args */
+		if (i < 4)
+			i = 4;
+		addto += i * 4;
+	}
+
+	for (off = 4, i = 0; i < MAXREGS; i++)
+		if (TESTBIT(ipp->ipp_regs, i)) {
+			regoff[i] = off;
+			off += szty(PERMTYPE(i)) * SZINT/SZCHAR;
+		}
+	addto += off + p2maxautooff;
+	return (addto + 63) & ~63;
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+	int addto;
+
+	ftype = ipp->ipp_type;
+
+	/*
+	 * We here know what registers to save and how much to 
+	 * add to the stack.
+	 */
+	addto = offcalc(ipp);
+	printf("\t.proc\ncallinfo frame=%d, save_rp, save_sp\n\t.entry\n",
+	    addto);
+	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)) {
+			if (i <= R31)
+				printf("\tldw\t%d(%%r3),%s\n",
+				    regoff[i], rnames[i]);
+			else if (i <= RETD0)
+				printf("\tldw\t%d(%%r3),%s\n"
+				    "\tldw\t%d(%%r3),%s\n",
+				    regoff[i] + 0, rnames[rl[i - RD0]],
+				    regoff[i] + 4, rnames[rh[i - RD0]]);
+			else if (i <= FR31)
+				printf("\tfldws\t%d(%%r3),%s\n",
+				    regoff[i], rnames[i]);
+			else
+				printf("\tfldds\t%d(%%r3),%s\n",
+				    regoff[i], rnames[i]);
+		}
+
+	if (p2calls || p2maxautooff > 4) {
+		if (p2calls)
+			printf("\tldw\t-20(%%r3),%%rp\n");
+		printf("\tcopy\t%%r3,%%r1\n"
+		    "\tldw\t0(%%r3),%%r3\n"
+		    "\tbv\t%%r0(%%rp)\n"
+		    "\tcopy\t%%r1,%%sp\n");
+	} else
+		printf("\tbv\t%%r0(%%rp)\n\tnop\n");
+
+	printf("\t.exit\n\t.procend\n\t.size\t%s, .-%s\n",
+	    ipp->ipp_name, ipp->ipp_name);
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+	char *str;
+
+	switch (o) {
+	case PLUS:
+		str = "add";
+		break;
+	case MINUS:
+		str = "sub";
+		break;
+	case AND:
+		str = "and";
+		break;
+	case OR:
+		str = "or";
+		break;
+	case ER:
+		str = "xor";
+		break;
+	case EQ:
+		str = "=";
+		break;
+	case NE:
+		str = "<>";
+		break;
+	case LE:
+		str = "<";
+		break;
+	case LT:
+		str = "<=";
+		break;
+	case ULE:
+		str = "<<";
+		break;
+	case ULT:
+		str = "<<=";
+		break;
+	case GE:
+		str = ">=";
+		break;
+	case GT:
+		str = ">";
+		break;
+	case UGE:
+		str = ">>";
+		break;
+	case UGT:
+		str = ">>=";
+		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 FLOAT:
+			return(SZFLOAT/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", p->n_type);
+			return SZPOINT(p->n_type)/SZCHAR;
+		}
+}
+
+static int
+argsiz(NODE *p)
+{
+	NODE *q;
+	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 8;	/* LDOUBLE is 16 */
+	if ((t == STRTY || t == UNIONTY) && p->n_right->n_op == STARG)
+		return 4 + p->n_right->n_stsize;
+        /* perhaps it's down there somewhere -- let me take another look! */
+	if ((t == STRTY || t == UNIONTY) && p->n_right->n_op == CALL) {
+		q = p->n_right->n_right->n_left->n_left->n_right;
+		if (q->n_op == STARG)
+			return 4 + q->n_stsize;
+	}
+	comperr("argsiz %p", p);
+	return 0;
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+	int o = p->n_op;
+	int s = getlab2();
+	int e = p->n_label;
+	int cb1, cb2;
+
+	if (o >= ULE)
+		o -= (ULE-LE);
+	switch (o) {
+	case NE:
+		cb1 = 0;
+		cb2 = NE;
+		break;
+	case EQ:
+		cb1 = NE;
+		cb2 = 0;
+		break;
+	case LE:
+	case LT:
+		cb1 = GT;
+		cb2 = LT;
+		break;
+	case GE:
+	case GT:
+		cb1 = LT;
+		cb2 = GT;
+		break;
+	
+	default:
+		cb1 = cb2 = 0; /* XXX gcc */
+	}
+	if (p->n_op >= ULE)
+		cb1 += 4, cb2 += 4;
+	if (cb1) {
+		p->n_op = cb1;
+		p->n_label = s;
+		expand(p, 0, "\tcomb,O\tUR,UL,LC\n\tnop\n");
+		p->n_label = e;
+		p->n_op = o;
+	}
+	if (cb2) {
+		p->n_op = cb2;
+		expand(p, 0, "\tcomb,O\tUR,UL,LC\n\tnop\n");
+		p->n_op = o;
+	}
+	expand(p, 0, "\tcomb,O\tAR,AL,LC\n\tnop\n");
+	deflab(s);
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+	int n;
+
+	switch (c) {
+
+	case 'C':	/* after-call fixup */
+		n = p->n_qual;	/* args */
+		break;
+
+	case 'P':	/* returning struct-call setup */
+		n = p->n_qual;	/* args */
+		break;
+
+	case 'D':	/* Long long comparision */
+		twollcomp(p);
+		break;
+
+	case 'F':	/* struct as an arg */
+
+	default:
+		comperr("zzzcode %c", c);
+	}
+}
+
+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);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+	return 0;
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+	if (isreg(p))
+		return SRDIR; /* Direct match */
+
+	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)
+{
+	/* fix for L% and R% */
+	printf(CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+	CONSZ val = p->n_lval;
+
+	switch (p->n_op) {
+	case ICON:
+		if (p->n_name[0] != '\0') {
+			fprintf(fp, "RR'%s-$global$", p->n_name);
+			if (val)
+				fprintf(fp, "+" CONFMT, val);
+		} else
+			fprintf(fp, CONFMT, val);
+		return;
+
+	default:
+		comperr("illegal conput, p %p", p);
+	}
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+	comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+	size /= SZCHAR;
+	switch (p->n_op) {
+	case REG:
+		printf("%s", rnames[rh[p->n_rval - RD0]]);
+		break;
+
+	case OREG:
+		p->n_lval += size;
+		adrput(stdout, p);
+		p->n_lval -= size;
+		break;
+
+	case ICON:
+	case NAME:
+		if (p->n_name[0] != '\0') {
+			printf("LR'%s-$global$", p->n_name);
+			if (p->n_lval != 0)
+				printf("+" CONFMT, p->n_lval);
+		} else
+			printf("L%%" 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 ICON:
+	case NAME:
+		if (p->n_name[0] != '\0') {
+			fprintf(io, "RR'%s-$global$", p->n_name);
+			if (p->n_lval != 0)
+				fprintf(io, "+" CONFMT, p->n_lval);
+		} else
+			fprintf(io, "R%%" CONFMT, p->n_lval);
+		return;
+
+	case OREG:
+		r = p->n_rval;
+		if (p->n_name[0] != '\0') {
+			fprintf(io, "RR'%s-$global$", p->n_name);
+			if (p->n_lval != 0)
+				fprintf(io, "+" CONFMT, p->n_lval);
+		} else
+			fprintf(io, "%d", (int)p->n_lval);
+		if (R2TEST(r)) {
+			fprintf(io, "%s(%s)", rnames[R2UPK1(r)],
+			    rnames[R2UPK2(r)]);
+		} else
+			fprintf(io, "(%s)", rnames[p->n_rval]);
+		return;
+	case REG:
+		if (RD0 <= p->n_rval && p->n_rval <= RETD0)
+			fprintf(io, "%s", rnames[rl[p->n_rval - RD0]]);
+		else
+			fprintf(io, "%s", rnames[p->n_rval]);
+		return;
+
+	default:
+		comperr("illegal address, op %d, node %p", p->n_op, p);
+		return;
+
+	}
+}
+
+/* not used */
+void
+cbgen(int o, int lab)
+{
+}
+
+int
+countargs(NODE *p, int *n)
+{
+	int sz;
+	
+	if (p->n_op == CM) {
+		countargs(p->n_left, n);
+		countargs(p->n_right, n);
+		return *n;
+	}
+
+	sz = argsiz(p) / 4;
+	if (*n % (sz > 4? 4 : sz))
+		(*n)++; /* XXX */
+
+	return *n += sz;
+}
+
+void
+fixcalls(NODE *p, void *arg)
+{
+	int n, o;
+
+	/* Prepare for struct return by allocating bounce space on stack */
+	switch (o = p->n_op) {
+	case STCALL:
+	case USTCALL:
+		if (p->n_stsize + p2autooff > stkpos)
+			stkpos = p->n_stsize + p2autooff;
+		/* FALLTHROGH */
+	case CALL:
+	case UCALL:
+		n = 0;
+		n = 1 + countargs(p->n_right, &n);
+		if (n > p2calls)
+			p2calls = n;
+		break;
+	}
+}
+
+void
+myreader(struct interpass *ipole)
+{
+	struct interpass *ip;
+
+	stkpos = p2autooff;
+	DLIST_FOREACH(ip, ipole, qelem) {
+		switch (ip->type) {
+		case IP_PROLOG:
+			p2calls = 0;
+			break;
+
+		case IP_NODE:
+			walkf(ip->ip_node, fixcalls, 0);
+			break;
+		}
+	}
+	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 *ipole)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+	int sl, sh, dl, dh;
+
+	switch (t) {
+	case LONGLONG:
+	case ULONGLONG:
+		sl = rl[s-RD0];
+		sh = rh[s-RD0];
+		dl = rl[d-RD0];
+		dh = rh[d-RD0];
+
+#define	SW(x,y) { int i = x; x = y; y = i; }
+		if (sl == dh || sh == dl) {
+			/* Swap if moving to itself */
+			SW(sl, sh);
+			SW(dl, dh);
+		}
+		if (sl != dl)
+			printf("\tcopy\t%s,%s\n", rnames[sl], rnames[dl]);
+		if (sh != dh)
+			printf("\tcopy\t%s,%s\n", rnames[sh], rnames[dh]);
+		break;
+	case FLOAT:
+		printf("\tfcpy,sgl\t%s,%s\n", rnames[s], rnames[d]);
+		break;
+	case DOUBLE:
+	case LDOUBLE:
+		printf("\tfcpy,dbl\t%s,%s\n", rnames[s], rnames[d]);
+		break;
+	default:
+		printf("\tcopy\t%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 = 2 * r[CLASSB];
+		num += r[CLASSA];
+		return num < 28;
+	case CLASSB:
+		num = r[CLASSA];
+		num += r[CLASSB] * 2;
+		return num < 28;
+	case CLASSC:
+		num = (r[CLASSD] > 8? 8 : r[CLASSD]) * 2;
+		num += r[CLASSC];
+		return num < 28;
+	case CLASSD:
+		num = (r[CLASSC] + 1) / 2;
+		num += r[CLASSD];
+		return num < 28;
+	}
+	return 0; /* XXX gcc */
+}
+
+char * rnames[MAXREGS] = {
+	"%r0", "%r1", "%rp", "%r3", "%r4", "%r5", "%r6", "%r7", "%r8", "%r9",
+	"%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "%r16", "%r17", "%r18",
+	"%t4", "%t3", "%t2", "%t1", "%arg3", "%arg2", "%arg1", "%arg0", "%dp",
+	"%ret0", "%ret1", "%sp", "%r31",
+	"%rd0", "%rd1", "%rd2", "%rd3", "%rd4", "%rd5", "%rd6", "%rd7",
+	"%rd8", "%rd9", "%rd10", "%rd11", "%rd12", "%rd13", "%rd14", "%rd15",
+	"%rd16", "%rd17", "%rd18", "%rd19", "%rd20", "%rd21", "%rd22", "%rd23",
+	"%rd24", "%td4", "%td3", "%td2", "%td1", "%ad1", "%ad0", "%retd0",
+	"%fr0", "%fr4", "%fr5", "%fr6", "%fr7", "%fr8", "%fr9", "%fr10",
+	"%fr11", "%fr12", "%fr13", "%fr14", "%fr15", "%fr16", "%fr17", "%fr18",
+	"%fr19", "%fr20", "%fr21", "%fr22", "%fr23", "%fr24", "%fr25", "%fr26",
+	"%fr27", "%fr28", "%fr29", "%fr30", "%fr31",
+	"%fr0l", "%fr0r", "%fr4l", "%fr4r", "%fr5l", "%fr5r", "%fr6l", "%fr6r",
+	"%fr7l", "%fr7r", "%fr8l", "%fr8r", "%fr9l", "%fr9r",
+	"%fr10l", "%fr10r", "%fr11l", "%fr11r", "%fr12l", "%fr12r",
+	"%fr13l", "%fr13r", "%fr14l", "%fr14r", "%fr15l", "%fr15r",
+	"%fr16l", "%fr16r", "%fr17l", "%fr17r", "%fr18l", "%fr18r",
+#ifdef __hppa64__
+	"%fr19l", "%fr19r",
+	"%fr20l", "%fr20r", "%fr21l", "%fr21r", "%fr22l", "%fr22r",
+	"%fr23l", "%fr23r", "%fr24l", "%fr24r", "%fr25l", "%fr25r",
+	"%fr26l", "%fr26r", "%fr27l", "%fr27r", "%fr28l", "%fr28r",
+	"%fr29l", "%fr29r", "%fr30l", "%fr30r", "%fr31l", "%fr31r",
+#endif
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+	switch (t) {
+	case LONGLONG:
+	case ULONGLONG:
+		return CLASSB;
+	case FLOAT:
+		return CLASSC;
+	case DOUBLE:
+	case LDOUBLE:
+		return CLASSD;
+	default:
+		return CLASSA;
+	}
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+	NODE *op = p;
+	int size = 64;
+
+	p->n_qual = size;
+	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+		return;
+	for (p = p->n_right; p->n_op == CM; p = p->n_left)
+		size += argsiz(p->n_right);
+	size += argsiz(p);
+	op->n_qual = size; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+	int o = p->n_op;
+
+	switch (shape) {
+	case SFUNCALL:
+		if (o == STCALL || o == USTCALL)
+			return SRREG;
+		break;
+	case SPIMM:
+		if (o != ICON || p->n_name[0] ||
+		    p->n_lval < -31 || p->n_lval >= 32)
+			break;
+		return SRDIR;
+	case SPICON:
+		if (o != ICON || p->n_name[0] ||
+		    p->n_lval < -1024 || p->n_lval >= 1024)
+			break;
+		return SRDIR;
+	case SPCNHW:
+		if (o != ICON || p->n_name[0] || (p->n_lval & 0xffffffffLL))
+			break;
+		return SRDIR;
+	case SPCNLW:
+		if (o != ICON || p->n_name[0] || (p->n_lval & ~0xffffffffLL))
+			break;
+		return SRDIR;
+	case SPCNHI:
+		if (o != ICON || p->n_name[0] || (p->n_lval & ~0xfffff800LL))
+			break;
+		return SRDIR;
+	case SPCON:
+		if (o != ICON || p->n_name[0] ||
+		    p->n_lval < -8192 || p->n_lval >= 8192)
+			break;
+		return SRDIR;
+	case SPNAME:
+		if (o != ICON || !p->n_name[0])
+			break;
+		return SRDIR;
+	}
+	return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+	return 0;
+}
Index: uspace/app/pcc/arch/hppa/macdefs.h
===================================================================
--- uspace/app/pcc/arch/hppa/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/hppa/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,473 @@
+/*	$OpenBSD$	*/
+
+/*
+ * Copyright (c) 2007 Michael Shalayeff
+ * 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.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ */
+#define	makecc(val,i)	(lastcon = (lastcon<<8)|((val<<24)>>24))
+
+#define	ARGINIT		(32*8)	/* bits below fp where args start */
+#define	AUTOINIT	(4*8)	/* bits above fp where locals start */
+
+/*
+ * storage sizes
+ */
+#define	SZCHAR		8
+#define	SZBOOL		8
+#define	SZINT		32
+#define	SZFLOAT		32
+#define	SZDOUBLE	64
+#define	SZLDOUBLE	64	/* or later 128 */
+#define	SZLONG		32
+#define	SZSHORT		16
+#define	SZLONGLONG	64
+#define	SZPOINT(t)	32
+
+/*
+ * alignment requirements
+ */
+#define	ALCHAR		8
+#define	ALBOOL		8
+#define	ALINT		32
+#define	ALFLOAT		32
+#define	ALDOUBLE	64
+#define	ALLDOUBLE	64	/* 128 later */
+#define	ALLONG		32
+#define	ALLONGLONG	32
+#define	ALSHORT		16
+#define	ALPOINT		32
+#define	ALSTRUCT	32
+#define	ALSTACK		64
+
+/*
+ * type value limits
+ */
+#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	(-0x7fffffffffffffffLL-1)
+#define	MAX_LONGLONG	0x7fffffffffffffffLL
+#define	MAX_ULONGLONG	0xffffffffffffffffULL
+
+#undef	CHAR_UNSIGNED
+#define	BOOL_TYPE	CHAR
+#define	ENUMSIZE(high,low)	INT
+
+typedef long long CONSZ;
+typedef unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define	CONFMT	"%lld"		/* format for printing constants */
+#define	LABFMT	".L%d"		/* format for printing labels */
+#define	STABLBL	".LL%d"		/* format for stab (debugging) labels */
+
+#undef	BACKAUTO	/* stack grows upwards */
+#undef	BACKTEMP	/* stack grows upwards */
+
+#define	FIELDOPS	/* have bit field ops */
+#define	LTORBYTES	/* big endian */
+
+#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	szty(t)	(((t) == DOUBLE || (t) == LONGLONG || (t) == ULONGLONG) ? 2 : \
+	    (t) == LDOUBLE ? 2 : 1)
+
+#define	R0	0
+#define	R1	1
+#define	RP	2
+#define	FP	3
+#define	R4	4
+#define	R5	5
+#define	R6	6
+#define	R7	7
+#define	R8	8
+#define	R9	9
+#define	R10	10
+#define	R11	11
+#define	R12	12
+#define	R13	13
+#define	R14	14
+#define	R15	15
+#define	R16	16
+#define	R17	17
+#define	R18	18
+#define	T4	19
+#define	T3	20
+#define	T2	21
+#define	T1	22
+#define	ARG3	23
+#define	ARG2	24
+#define	ARG1	25
+#define	ARG0	26
+#define	DP	27
+#define	RET0	28
+#define	RET1	29
+#define	SP	30
+#define	R31	31
+
+/* double regs overlay */
+#define	RD0	32	/* r0:r0 */
+#define	RD1	33	/* r1:r31 */
+#define	RD2	34	/* r1:t4 */
+#define	RD3	35	/* r1:t3 */
+#define	RD4	36	/* r1:t2 */
+#define	RD5	37	/* r1:t1 */
+#define	RD6	38	/* r31:t4 */
+#define	RD7	39	/* r31:t3 */
+#define	RD8	40	/* r31:t2 */
+#define	RD9	41	/* r31:t1 */
+#define	RD10	42	/* r4:r18 */
+#define	RD11	43	/* r5:r4 */
+#define	RD12	44	/* r6:r5 */
+#define	RD13	45	/* r7:r6 */
+#define	RD14	46	/* r8:r7 */
+#define	RD15	47	/* r9:r8 */
+#define	RD16	48	/* r10:r9 */
+#define	RD17	49	/* r11:r10 */
+#define	RD18	50	/* r12:r11 */
+#define	RD19	51	/* r13:r12 */
+#define	RD20	52	/* r14:r13 */
+#define	RD21	53	/* r15:r14 */
+#define	RD22	54	/* r16:r15 */
+#define	RD23	55	/* r17:r16 */
+#define	RD24	56	/* r18:r17 */
+#define	TD4	57	/* t1:t4 */
+#define	TD3	58	/* t4:t3 */
+#define	TD2	59	/* t3:t2 */
+#define	TD1	60	/* t2:t1 */
+#define	AD2	61	/* arg3:arg2 */
+#define	AD1	62	/* arg1:arg0 */
+#define	RETD0	63	/* ret1:ret0 */
+
+/* FPU regs */
+#define	FR0	64
+#define	FR4	65
+#define	FR5	66
+#define	FR6	67
+#define	FR7	68
+#define	FR8	69
+#define	FR9	70
+#define	FR10	71
+#define	FR11	72
+#define	FR12	73
+#define	FR13	74
+#define	FR14	75
+#define	FR15	76
+#define	FR16	77
+#define	FR17	78
+#define	FR18	79
+#define	FR19	80
+#define	FR20	81
+#define	FR21	82
+#define	FR22	83
+#define	FR23	84
+#define	FR24	85
+#define	FR25	86
+#define	FR26	87
+#define	FR27	88
+#define	FR28	89
+#define	FR29	90
+#define	FR30	91
+#define	FR31	92
+
+#define	FR0L	93
+#define	FR0R	94
+#define	FR4L	95
+#define	FR4R	96
+#define	FR5L	97
+#define	FR5R	98
+#define	FR6L	99
+#define	FR6R	100
+#define	FR7L	101
+#define	FR7R	102
+#define	FR8L	103
+#define	FR8R	104
+#define	FR9L	105
+#define	FR9R	106
+#define	FR10L	107
+#define	FR10R	108
+#define	FR11L	109
+#define	FR11R	110
+#define	FR12L	111
+#define	FR12R	112
+#define	FR13L	113
+#define	FR13R	114
+#define	FR14L	115
+#define	FR14R	116
+#define	FR15L	117
+#define	FR15R	118
+#define	FR16L	119
+#define	FR16R	120
+#define	FR17L	121
+#define	FR17R	122
+#define	FR18L	123
+#define	FR18R	124
+#ifdef __hppa64__
+#define	FR19L	125
+#define	FR19R	126
+#define	FR20L	127
+#define	FR20R	128
+#define	FR21L	129
+#define	FR21R	130
+#define	FR22L	131
+#define	FR22R	132
+#define	FR23L	133
+#define	FR23R	134
+#define	FR24L	135
+#define	FR24R	136
+#define	FR25L	137
+#define	FR25R	138
+#define	FR26L	139
+#define	FR26R	140
+#define	FR27L	141
+#define	FR27R	142
+#define	FR28L	143
+#define	FR28R	144
+#define	FR29L	145
+#define	FR29R	146
+#define	FR30L	147
+#define	FR30R	148
+#define	FR31L	149
+#define	FR31R	150
+
+#define	MAXREGS	151
+#else
+#define	MAXREGS	125
+#endif
+
+#define	RSTATUS \
+	0, SAREG|TEMPREG, 0, 0, SAREG|PERMREG, SAREG|PERMREG,		\
+	SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,	\
+	SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,	\
+	SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,	\
+	SAREG|PERMREG,							\
+	SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, 	\
+	SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, 	\
+	0, SAREG|TEMPREG, SAREG|TEMPREG, 0, SAREG|TEMPREG,		\
+	/* double overlays */						\
+	0,								\
+	SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,		\
+	SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,		\
+	SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,		\
+	SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,		\
+	/* double-precision floats */					\
+	0,								\
+	SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG,	\
+	SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG,	\
+	SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG,	\
+	SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG,	\
+	SDREG|PERMREG, SDREG|PERMREG,					\
+	SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG,	\
+	SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG,	\
+	SDREG|TEMPREG, SDREG|TEMPREG,					\
+	/* single-precision floats */					\
+	0, 0,								\
+	SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,		\
+	SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,		\
+	SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,		\
+	SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,
+#ifdef __hppa64__
+	SCREG, SCREG,		\
+	SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,		\
+	SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,		\
+	SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG,
+#endif
+
+#define	ROVERLAP \
+	{ -1 },				\
+	{ RD1, RD2, RD3, RD4, RD5, -1 },\
+	{ -1 }, { -1 },			\
+	{ RD10, RD11, -1 },		\
+	{ RD11, RD12, -1 },		\
+	{ RD12, RD13, -1 },		\
+	{ RD13, RD14, -1 },		\
+	{ RD14, RD15, -1 },		\
+	{ RD15, RD16, -1 },		\
+	{ RD16, RD17, -1 },		\
+	{ RD17, RD18, -1 },		\
+	{ RD18, RD19, -1 },		\
+	{ RD19, RD20, -1 },		\
+	{ RD20, RD21, -1 },		\
+	{ RD21, RD22, -1 },		\
+	{ RD22, RD23, -1 },		\
+	{ RD23, RD24, -1 },		\
+	{ RD24, RD10, -1 },		\
+	{ TD1, TD4, -1 },		\
+	{ TD3, TD2, -1 },		\
+	{ TD1, TD2, -1 },		\
+	{ TD1, TD4, -1 },		\
+	{ AD2, -1 }, { AD2, -1 },	\
+	{ AD1, -1 }, { AD1, -1 },	\
+	{ -1 },				\
+	{ RETD0, -1 }, { RETD0, -1 },	\
+	{ -1 },				\
+	{ RD1, RD5, RD6, RD7, RD8, -1 },\
+	{ -1 },				\
+	{ R1, R31, -1 },		\
+	{ R1, T4, -1 },			\
+	{ R1, T3, -1 },			\
+	{ R1, T2, -1 },			\
+	{ R1, T1, -1 },			\
+	{ R31, T4, -1 },		\
+	{ R31, T3, -1 },		\
+	{ R31, T2, -1 },		\
+	{ R31, T1, -1 },		\
+	{ R4, R18, -1 },		\
+	{ R5, R4, -1 },			\
+	{ R6, R5, -1 },			\
+	{ R7, R6, -1 },			\
+	{ R8, R7, -1 },			\
+	{ R9, R8, -1 },			\
+	{ R10, R9, -1 },		\
+	{ R11, R10, -1 },		\
+	{ R12, R11, -1 },		\
+	{ R13, R12, -1 },		\
+	{ R14, R15, -1 },		\
+	{ R15, R14, -1 },		\
+	{ R16, R15, -1 },		\
+	{ R17, R16, -1 },		\
+	{ R18, R17, -1 },		\
+	{ T1, T4, -1 },			\
+	{ T4, T3, -1 },			\
+	{ T3, T2, -1 },			\
+	{ T2, T1, -1 },			\
+	{ ARG3, ARG2, -1 },		\
+	{ ARG1, ARG0, -1 },		\
+	{ RET1, RET0, -1 },		\
+	{ -1 },				\
+	{ FR4L, FR4R, -1 },		\
+	{ FR5L, FR5R, -1 },		\
+	{ FR6L, FR6R, -1 },		\
+	{ FR7L, FR7R, -1 },		\
+	{ FR8L, FR8R, -1 },		\
+	{ FR9L, FR9R, -1 },		\
+	{ FR10L, FR10R, -1 },		\
+	{ FR11L, FR11R, -1 },		\
+	{ FR12L, FR12R, -1 },		\
+	{ FR13L, FR13R, -1 },		\
+	{ FR14L, FR14R, -1 },		\
+	{ FR15L, FR15R, -1 },		\
+	{ FR16L, FR16R, -1 },		\
+	{ FR17L, FR17R, -1 },		\
+	{ FR18L, FR18R, -1 },		\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 }, { -1 },			\
+	{ FR4, -1 }, { FR4, -1 },	\
+	{ FR5, -1 }, { FR5, -1 },	\
+	{ FR6, -1 }, { FR6, -1 },	\
+	{ FR7, -1 }, { FR7, -1 },	\
+	{ FR8, -1 }, { FR8, -1 },	\
+	{ FR9, -1 }, { FR9, -1 },	\
+	{ FR10, -1 }, { FR10, -1 },	\
+	{ FR11, -1 }, { FR11, -1 },	\
+	{ FR12, -1 }, { FR12, -1 },	\
+	{ FR13, -1 }, { FR13, -1 },	\
+	{ FR14, -1 }, { FR14, -1 },	\
+	{ FR15, -1 }, { FR15, -1 },	\
+	{ FR16, -1 }, { FR16, -1 },	\
+	{ FR17, -1 }, { FR17, -1 },	\
+	{ FR18, -1 }, { FR18, -1 },
+#ifdef __hppa64__
+	{ FR19, -1 }, { FR19, -1 },	\
+	{ FR20, -1 }, { FR20, -1 },	\
+	{ FR21, -1 }, { FR21, -1 },	\
+	{ FR22, -1 }, { FR22, -1 },	\
+	{ FR23, -1 }, { FR23, -1 },	\
+	{ FR24, -1 }, { FR24, -1 },	\
+	{ FR25, -1 }, { FR25, -1 },	\
+	{ FR26, -1 }, { FR26, -1 },	\
+	{ FR27, -1 }, { FR27, -1 },	\
+	{ FR28, -1 }, { FR28, -1 },	\
+	{ FR29, -1 }, { FR29, -1 },	\
+	{ FR30, -1 }, { FR30, -1 },	\
+	{ FR31, -1 }, { FR31, -1 },
+#endif
+
+#define	PCLASS(p)	\
+	(p->n_type == LONGLONG || p->n_type == ULONGLONG ? SBREG : \
+	(p->n_type == FLOAT ? SCREG : \
+	(p->n_type == DOUBLE || p->n_type == LDOUBLE ? SDREG : SAREG)))
+
+#define	NUMCLASS	4	/* highest number of reg classes used */
+
+int COLORMAP(int c, int *r);
+#define	PERMTYPE(x) ((x) < 32? INT : ((x) < 64? LONGLONG : ((x) < 93? LDOUBLE : FLOAT)))
+#define	GCLASS(x) ((x) < 32? CLASSA : ((x) < 64? CLASSB : ((x) < 93? CLASSD : CLASSC)))
+#define	DECRA(x,y)	(((x) >> (y*8)) & 255)	/* decode encoded regs */
+#define	ENCRD(x)	(x)			/* Encode dest reg in n_reg */
+#define	ENCRA1(x)	((x) << 8)		/* A1 */
+#define	ENCRA2(x)	((x) << 16)		/* A2 */
+#define	ENCRA(x,y)	((x) << (8+y*8))	/* encode regs in int */
+#define	RETREG(x)	(x == LONGLONG || x == ULONGLONG ? RETD0 : \
+			 x == FLOAT? FR4L : \
+			 x == DOUBLE || x == LDOUBLE ? FR4 : RET0)
+
+#define	FPREG	FP	/* frame pointer */
+#define	STKREG	SP	/* stack pointer */
+
+#define	MYREADER(p)	myreader(p)
+#define	MYCANON(p)	mycanon(p)
+#define	MYOPTIM
+
+#define	SFUNCALL	(MAXSPECIAL+1)	/* struct assign after function call */
+#define	SPCNHI		(MAXSPECIAL+2)	/* high 21bits constant */
+#define	SPCON		(MAXSPECIAL+3)	/* smaller constant */
+#define	SPICON		(MAXSPECIAL+4)	/* even smaller constant */
+#define	SPCNHW		(MAXSPECIAL+5)	/* LL const w/ 0 in low word */
+#define	SPCNLW		(MAXSPECIAL+6)	/* LL const w/ 0 in high word */
+#define	SPIMM		(MAXSPECIAL+7)	/* immidiate const for depi/comib */
+#define	SPNAME		(MAXSPECIAL+8)	/* ext symbol reference load/store */
Index: uspace/app/pcc/arch/hppa/order.c
===================================================================
--- uspace/app/pcc/arch/hppa/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/hppa/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,216 @@
+/*	$OpenBSD$	*/
+
+/*
+ * Copyright (c) 2007 Michael Shalayeff
+ * 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;
+		}
+	}
+	(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 hppa */
+	if (shape & SOREG)
+		return SOREG;
+	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,%s)\n", p, prcook(cookie));
+
+	if (p->n_left->n_op == FLD && !isreg(p->n_left->n_left)) {
+		NODE *l, *r;
+		int reg;
+
+		geninsn(p->n_left->n_left, INAREG);
+
+		reg = DECRA(p->n_left->n_left->n_reg, 0);
+		l = tcopy(p->n_left->n_left);
+		p->n_left->n_left->n_op = REG;
+		p->n_left->n_left->n_rval = reg;
+		p->n_left->n_left->n_lval = 0;
+		r = tcopy(p->n_left->n_left);
+
+		geninsn(p->n_left, INAREG);
+		l = mkbinode(ASSIGN, l, r, l->n_type);
+		geninsn(l, INAREG);
+		return (1);
+	}
+
+	return (0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+	if (x2debug)
+		printf("setuni(%p,%s)\n", p, prcook(cookie));
+
+	return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+	comperr("nspecial entry %d", q - table);
+	return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+	return 0; /* nothing differs on hppa */
+}
+
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+	static int r[5], *s = &r[4];
+	 
+	*s = -1;
+	if (p->n_op == UCALL || p->n_op == UFORTCALL || p->n_op == USTCALL ||
+	    p->n_op == FORTCALL)
+		return s;
+
+	for (p = p->n_right; p->n_op == CM; p = p->n_left)
+		if (p->n_right->n_op == ASSIGN &&
+		    p->n_right->n_left->n_op == REG)
+			*--s = p->n_right->n_left->n_rval;
+
+	if (p->n_op == ASSIGN &&
+	    p->n_left->n_op == REG)
+		*--s = p->n_left->n_rval;
+
+	return s;
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+	return 1;
+}
Index: uspace/app/pcc/arch/hppa/table.c
===================================================================
--- uspace/app/pcc/arch/hppa/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/hppa/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1014 @@
+/*	$OpenBSD: table.c,v 1.2 2007/12/19 20:19:54 otto Exp $	*/
+
+/*
+ * Copyright (c) 2007 Michael Shalayeff
+ * 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	THWORD		TUSHORT|TSHORT
+#define	TBYTE		TUCHAR|TCHAR
+
+#define	SHINT	SAREG	/* char, short and int */
+#define	ININT	INAREG
+#define	SHLL	SBREG	/* shape for long long */
+#define	INLL	INBREG
+#define	SHFL	SCREG	/* shape for float */
+#define	INFL	INCREG
+#define	SHDBL	SDREG	/* shape for double */
+#define	INDBL	INDREG
+
+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 int,short,char <-> int,short,char. */
+{ SCONV,	ININT,
+	SHINT,	TBYTE,
+	SHINT,	TBYTE,
+		0,	RLEFT,
+		"", },
+
+{ SCONV,	ININT,
+	SHINT,	THWORD,
+	SHINT,	THWORD,
+		0,	RLEFT,
+		"", },
+
+{ SCONV,	ININT,
+	SHINT,	TWORD,
+	SHINT,	TWORD,
+		0,	RLEFT,
+		"", },
+
+/* convert pointers to int. */
+{ SCONV,	ININT,
+	SHINT,	TWORD|TPOINT,
+	SANY,	TWORD,
+		0,	RLEFT,
+		"", },
+
+/* convert (u)longlong to (u)longlong. */
+{ SCONV,	INLL,
+	SHLL,	TLL,
+	SHLL,	TLL,
+		0,	RLEFT,
+		"", },
+
+/* convert pointers to pointers. */
+{ SCONV,	ININT,
+	SHINT,	TPOINT,
+	SANY,	TPOINT,
+		0,	RLEFT,
+		"", },
+
+/* convert double <-> ldouble. nothing to do here (or support quads later) */
+{ SCONV,	INDBL,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		0,	RLEFT,
+		"", },
+
+/* convert float -> double */
+{ SCONV,	INFL,
+	SHFL,	TFLOAT,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		0,	0,
+		"\tfcnvff,sgl,dbl AL,AR\n", },
+
+/* convert double -> float */
+{ SCONV,	INDBL,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+	SHFL,	TFLOAT,
+		0,	0,
+		"\tfcnvff,dbl,sgl\tAL,AR\n", },
+
+/* convert int,short,char to (u)long long */
+{ SCONV,	INLL,
+	SHINT,	ANYSIGNED,
+	SANY,	TLL,
+		NBREG,	RESC1,
+		"\tcopy\tAL,A1\n"
+		"\textrs\tAL,0,1,U1\n", },
+
+/* convert unsigned int,short,char to (u)long long */
+{ SCONV,	INLL,
+	SHINT,	TWORD,
+	SANY,	TLL,
+		NBREG,	RESC1,
+		"\tcopy\tAL,A1\n"
+		"\tcopy\t%r0,U1\n", },
+
+/* convert int,short,char (in memory) to float */
+{ SCONV,	INFL,
+	SOREG,	ANYSIGNED,
+	SHFL,	TFLOAT,
+		NCREG,	RESC1,
+		"\tfldws\tAL,A1\n"
+		"\tfcnvxf,sgl,sgl\tA1,A1\n", },
+
+/* convert int,short,char (in memory) to double */
+{ SCONV,	INDBL,
+	SOREG,	TSWORD,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		NDREG,	RESC1,
+		"\tfldws\tAL,A1\n"
+		"\tfcnvxf,sgl,dbl\tA1,A1\n", },
+
+/* convert (u)long (in memory) to double */
+{ SCONV,	INDBL,
+	SOREG,	TLL,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		NDREG,	RESC1,
+		"\tfldds\tAL,A1\n"
+		"\tfcnvxf,dbl,dbl\tA1,A1\n", },
+
+/* convert int,short,char (in register) to float */
+{ SCONV,	INFL,
+	SHINT,	TSWORD,
+	SHFL,	TFLOAT,
+		NCREG,	RESC1,
+		"\tstw,ma\tAL,4(%sp)\n"
+		"\tfldws,ma\t-4(%sp),A1\n"
+		"\tfcnvxf,sgl,sgl\tA1,A1\n", },
+
+/* convert int,short,char (in register) to double */
+{ SCONV,	INDBL,
+	SHINT,	TSWORD,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		NDREG,	RESC1,
+		"\tstw,ma\tAL,4(%sp)\n"
+		"\tfldws,mb\t-4(%sp),AR\n"
+		"\tfcnvxf,sgl,dbl\tA1,A1\n", },
+
+/* convert (u)long (in register) to double */
+{ SCONV,	INDBL,
+	SHLL,	TLL,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		NDREG,	RESC1,
+		"\tldo\t8(%sp),%sp\n"
+		"\tstw\tAL,-8(%sp)\n"
+		"\tstw\tUL,-4(%sp)\n"
+		"\tfldds,mb\t-8(%sp),A1\n"
+		"\tfcnvxf,dbl,dbl\tA1,A1\n", },
+
+/* convert char to (unsigned) short/int. */
+{ SCONV,	ININT,
+	SAREG,	TCHAR,
+	SAREG,	THWORD|TWORD,
+		NASL|NAREG,	RESC1,
+		"\textrs\tAL,31,8,A1\n", },
+
+/* convert unsigned char to (unsigned) short/int. */
+{ SCONV,	ININT,
+	SAREG,	TUCHAR,
+	SAREG,	THWORD|TWORD,
+		NASL|NAREG,	RESC1,
+		"\textru\tAL,31,8,A1\n", },
+
+/* convert char to (unsigned) long long. */
+{ SCONV,	INLL,
+	SAREG,	TCHAR,
+	SBREG,	TLL,
+		NBSL|NBREG,	RESC1,
+		"\textrs\tAL,31,8,A1\n\textrs\tA1,0,1,U1", },
+
+/* convert unsigned char to (unsigned) long long. */
+{ SCONV,	INLL,
+	SAREG,	TUCHAR,
+	SBREG,	TLL,
+		NBSL|NBREG,	RESC1,
+		"\textru\tAL,31,8,A1\n\tcopy\t%r0,U1", },
+
+/* convert short to (unsigned) int. */
+{ SCONV,	ININT,
+	SAREG,	TSHORT,
+	SAREG,	TWORD,
+		NASL|NAREG,	RESC1,
+		"\textrs\tAL,31,16,A1\n", },
+
+/* convert unsigned short to (unsigned) int. */
+{ SCONV,	ININT,
+	SAREG,	TUSHORT,
+	SAREG,	THWORD,
+		NASL|NAREG,	RESC1,
+		"\textru\tAL,31,16,A1\n", },
+
+/* convert short to (unsigned) long long. */
+{ SCONV,	INLL,
+	SAREG,	TSHORT,
+	SBREG,	TLL,
+		NBSL|NBREG,	RESC1,
+		"\textrs\tAL,31,16,A1\n\textrs\tA1,0,1,U1", },
+
+/* convert unsigned short to (unsigned) long long. */
+{ SCONV,	INLL,
+	SAREG,	TUSHORT,
+	SBREG,	TLL,
+		NBSL|NBREG,	RESC1,
+		"\textru\tAL,31,16,A1\n\tcopy\t%r0,U1", },
+
+/* convert int,short,char (in memory) to int,short,char */
+{ SCONV,	ININT,
+	SOREG,	TBYTE,
+	SHINT,	TBYTE|TPOINT,
+		NAREG|NASL,	RESC1,
+		"\tldb\tAL,A1\n", },
+
+{ SCONV,	ININT,
+	SOREG,	THWORD,
+	SHINT,	THWORD|TPOINT,
+		NAREG|NASL,	RESC1,
+		"\tldh\tAL,A1\n", },
+
+{ SCONV,	ININT,
+	SOREG,	TWORD,
+	SHINT,	TWORD|TPOINT,
+		NAREG|NASL,	RESC1,
+		"\tldw\tAL,A1\n", },
+
+/* convert (u)long long (in register) to int,short,char */
+{ SCONV,	ININT,
+	SHLL,	TLL,
+	SHINT,	ANYFIXED,
+		NAREG|NASL,	RESC1,
+		"\tcopy\tAL,A1\n", },
+
+/* convert (u)long (in memory) to int,short,char */
+{ SCONV,	ININT,
+	SOREG,	TLL,
+	SHINT,	ANYFIXED,
+		NAREG|NASL,	RESC1,
+		"\tldw\tAL,A1\n", },
+
+/* convert float (in register) to (u)int */
+{ SCONV,	ININT,
+	SHFL,	TFLOAT,
+	SHINT,	TWORD,
+		NAREG,	RESC1,
+		"\tfcnvfxt,sgl,sgl\tAL,AL\n"
+		"\tfstws,ma\tAL,4(%sp)\n"
+		"\tldw,mb\t-4(%sp),A1\n", },
+
+/* convert double (in register) to (u)int */
+{ SCONV,	ININT,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+	SHINT,	TWORD,
+		NCREG|NCSL|NAREG,	RESC2,
+		"\tfcnvfxt,dbl,sgl\tAL,A1\n"
+		"\tfstws,ma\tA1,4(%sp)\n"
+		"\tldw,mb\t-4(%sp),A2\n", },
+
+/* convert float (in register) to (u)long */
+{ SCONV,	INLL,
+	SHFL,	TFLOAT,
+	SHLL,	TLL,
+		NDREG|NDSL|NBREG,	RESC2,
+		"\tfcnvfxt,sgl,dbl\tAL,A1\n"
+		"\tfstds,ma\tA1,8(%sp)\n"
+		"\tldw\t-8(%sp),A2\n"
+		"\tldw\t-4(%sp),U2\n"
+		"\tldo\t-8(%sp),%sp)\n", },
+
+/* convert double (in register) to (u)long */
+{ SCONV,	INLL,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+	SHLL,	TLL,
+		NBREG,	RESC1,
+		"\tfcnvfxt,dbl,dbl\tAL,AL\n"
+		"\tfstds,ma\tAL,8(%sp)\n"
+		"\tldw\t-8(%sp),A1\n"
+		"\tldw\t-4(%sp),U1\n"
+		"\tldo\t-8(%sp),%sp)\n", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,		FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"ZP\tblr\t%r0, %rp\n"
+		"\tbv,n\t%r0(AL)\n"
+		"\tnop\nZC",	},
+
+{ UCALL,	FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"ZP\tblr\t%r0, %rp\n"
+		"\tbv,n\t%r0(AL)\n"
+		"\tnop\nZC",	},
+
+{ CALL,		ININT,
+	SAREG,	TANY,
+	SHINT,	ANYFIXED|TPOINT,
+		NAREG|NASL,	RESC1,
+		"ZP\tblr\t%r0, %rp\n"
+		"\tbv,n\t%r0(AL)\n"
+		"\tnop\nZC",	},
+
+{ UCALL,	ININT,
+	SAREG,	TANY,
+	SHINT,	ANYFIXED|TPOINT,
+		NAREG|NASL,	RESC1,
+		"ZP\tblr\t%r0, %rp\n"
+		"\tbv,n\t%r0(AL)\n"
+		"\tnop\nZC",	},
+
+{ CALL,		INLL,
+	SAREG,	TANY,
+	SHLL,	TLL,
+		NBREG|NBSL,	RESC1,
+		"ZP\tblr\t%r0, %rp\n"
+		"\tbv,n\t%r0(AL)\n"
+		"\tnop\nZC",	},
+
+{ UCALL,	INLL,
+	SAREG,	TANY,
+	SHLL,	TLL,
+		NBREG|NBSL,	RESC1,
+		"ZP\tblr\t%r0, %rp\n"
+		"\tbv,n\t%r0(AL)\n"
+		"\tnop\nZC",	},
+
+{ CALL,		INFL,
+	SAREG,	TANY,
+	SHFL,	TFLOAT,
+		NCREG|NCSL,	RESC1,
+		"ZP\tblr\t%r0, %rp\n"
+		"\tbv,n\t%r0(AL)\n"
+		"\tnop\nZC",	},
+
+{ UCALL,	INFL,
+	SAREG,	TANY,
+	SHFL,	TFLOAT,
+		NCREG|NCSL,	RESC1,
+		"ZP\tblr\t%r0, %rp\n"
+		"\tbv,n\t%r0(AL)\n"
+		"\tnop\nZC",	},
+
+{ CALL,		INDBL,
+	SAREG,	TANY,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		NDREG|NDSL,	RESC1,
+		"ZP\tblr\t%r0, %rp\n"
+		"\tbv,n\t%r0(AL)\n"
+		"\tnop\nZC",	},
+
+{ UCALL,	INDBL,
+	SAREG,	TANY,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		NDREG|NDSL,	RESC1,
+		"ZP\tblr\t%r0, %rp\n"
+		"\tbv,n\t%r0(AL)\n"
+		"\tnop\nZC",	},
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+/* TODO fix char/short overflows */
+
+{ PLUS,		INLL,
+	SHLL,	TLL,
+	SPICON,	TANY,
+		NBREG|NBSL,	RESC1,
+		"\taddi\tAL,AR,A1\n"
+		"\taddc\tUL,%r0,U1\n", },
+
+{ PLUS,		INLL,
+	SHLL,	TLL,
+	SHLL,	TLL,
+		NBREG|NBSL|NBSR,	RESC1,
+		"\tadd\tAL,AR,A1\n"
+		"\taddc\tUL,UR,U1\n", },
+
+{ PLUS,		INFL,
+	SHFL,	TFLOAT,
+	SHFL,	TFLOAT,
+		NCREG|NCSL|NCSR,	RESC1,
+		"\tfadd,sgl\tAL,AR,A1\n", },
+
+{ PLUS,		INDBL,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		NDREG|NDSL|NDSR,	RESC1,
+		"\tfadd,dbl\tAL,AR,A1\n", },
+
+{ PLUS,		ININT,
+	SHINT,	ANYFIXED|TPOINT,
+	SONE,	TANY,
+		NAREG|NASL,	RESC1,
+		"\tldo\t1(AL),A1\n", },
+
+{ PLUS,		ININT,
+	SHINT,	ANYFIXED|TPOINT,
+	SPCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"\tldo\tCR(AL),A1\n", },
+
+{ MINUS,	INLL,
+	SHLL,	TLL,
+	SPICON,	TANY,
+		NBREG|NBSL|NBSR,	RESC1,
+		"\tsubi\tAL,AR,A1\n"
+		"\tsubb\tUL,%r0,U1\n", },
+
+{ PLUS,		ININT,
+	SHINT,	TANY|TPOINT,
+	SPNAME,	TANY,
+		NAREG|NASL,	RESC1,
+		"\tldo\tAR(AL),A1\n", },
+
+{ MINUS,	INLL,
+	SHLL,	TLL,
+	SHLL,	TLL,
+		NBREG|NBSL|NBSR,	RESC1,
+		"\tsub\tAL,AR,A1\n"
+		"\tsubb\tUL,UR,U1\n", },
+
+{ MINUS,	INFL,
+	SHFL,	TFLOAT,
+	SHFL,	TFLOAT,
+		NCREG|NCSL|NCSR,	RESC1,
+		"\tfsub,sgl\tAL,AR,A1\n", },
+
+{ MINUS,	INDBL,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		NDREG|NDSL|NDSR,	RESC1,
+		"\tfsub,dbl\tAL,AR,A1\n", },
+
+{ MINUS,	ININT,
+	SHINT,	ANYFIXED|TPOINT,
+	SONE,	TANY,
+		NAREG|NASL,	RESC1,
+		"\tldo\t-1(AL),A1\n", },
+
+{ MINUS,	ININT,
+	SHINT,	ANYFIXED|TPOINT,
+	SPCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"\tldo\t-CR(AL),A1\n", },
+
+/* Simple reg->reg ops */
+{ OPSIMP,	ININT,
+	SAREG,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		NAREG|NASL,	RESC1,
+		"\tO\tAL,AR,A1\n", },
+
+{ OPSIMP,	INLL,
+	SHLL,	TLL,
+	SHLL,	TLL,
+		NBREG|NBSL|NBSR,	RESC1,
+		"\tO\tAL,AR,A1\n"
+		"\tO\tUL,UR,U1\n", },
+
+/*
+ * The next rules handle all shift operators.
+ */
+{ LS,	ININT,
+	SHINT,	ANYFIXED,
+	SCON,	ANYFIXED,
+		NAREG|NASL,	RESC1,
+		"\tzdep\tAL,31-AR,32-AR,A1\n", },
+
+{ LS,	ININT,
+	SHINT,	ANYFIXED,
+	SHINT,	ANYFIXED,
+		NAREG|NASR,	RESC1,
+		"\tsubi\t31,AR,A1\n"
+		"\tmtsar\tA1\n"
+		"\tzvdep\tAL,32,A1\n", },
+
+{ RS,	INLL,
+	SHLL,	TLONGLONG,
+	SCON,	ANYFIXED,
+		NBREG|NBSL,	RESC1,
+		"\tshd\tUL,AL,31-AR,A1\n"
+		"\textrs\tUL,31-AR,32,U1\n", },
+
+{ RS,	INLL,
+	SHLL,	TULONGLONG,
+	SCON,	ANYFIXED,
+		NBREG|NBSL,	RESC1,
+		"\tshd\tUL,AL,AR,A1\n"
+		"\textru\tUL,31-AR,32,U1\n", },
+
+{ RS,	ININT,
+	SHINT,	ANYSIGNED,
+	SCON,	ANYFIXED,
+		NAREG|NASL,	RESC1,
+		"\textrs\tAL,31-AR,32,A1\n", },
+
+{ RS,	ININT,
+	SHINT,	ANYUSIGNED,
+	SCON,	ANYFIXED,
+		NAREG|NASL,	RESC1,
+		"\textru\tAL,31-AR,32,A1\n", },
+
+/* TODO the following should be split into mtsar and actual shift parts */
+{ RS,	ININT,
+	SHINT,	ANYSIGNED,
+	SHINT,	ANYFIXED,
+		NAREG|NASR,	RESC1,
+		"\tsubi\t31,AR,A1\n"
+		"\tmtsar\tA1\n"
+		"\tvextrs\tAL,32,A1\n", },
+
+{ RS,	ININT,
+	SHINT,	ANYUSIGNED,
+	SHINT,	ANYFIXED,
+		NAREG|NASR,	RESC1,
+		"\tsubi\t31,AR,A1\n"
+		"\tmtsar\tA1\n"
+		"\tvextru\tAL,32,A1\n", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TWORD|TPOINT,
+	SPCON,	TANY,
+		0,	RDEST,
+		"\tldi\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,	TBYTE,
+	SHINT,	TBYTE,
+		0,	RDEST,
+		"\tstb\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,	THWORD,
+	SHINT,	THWORD,
+		0,	RDEST,
+		"\tsth\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,	TWORD|TPOINT,
+	SHINT,	TWORD|TPOINT,
+		0,	RDEST,
+		"\tstw\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|INLL,
+	SOREG,	TLL,
+	SHLL,	TLL,
+		0,	RDEST,
+		"\tstw\tAR,AL\n"
+		"\tstw\tUR,UL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SHINT,	TBYTE,
+	SOREG,	TBYTE,
+		0,	RDEST,
+		"\tldb\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SHINT,	THWORD,
+	SOREG,	THWORD,
+		0,	RDEST,
+		"\tldh\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SHINT,	TWORD|TPOINT,
+	SOREG,	TWORD|TPOINT,
+		0,	RDEST,
+		"\tldw\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|INLL,
+	SHLL,	TLL,
+	SOREG,	TLL,
+		0,	RDEST,
+		"\tldw\tAR,AL\n"
+		"\tldw\tUR,UL\n", },
+
+{ ASSIGN,	FOREFF|ININT,
+	SHINT,	TWORD|TPOINT,
+	SHINT,	TWORD|TPOINT,
+		0,	RDEST,
+		"\tcopy\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|ININT,
+	SHINT,	ANYFIXED,
+	SHINT,	ANYFIXED,
+		0,	RDEST,
+		"\tcopy\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|ININT,
+	SFLD,	TANY,
+	SPIMM,	TANY,
+		0,	RDEST,
+		"\tdepi\tAR,31-H,S,AL\n", },
+
+{ ASSIGN,	FOREFF|ININT,
+	SFLD,	TANY,
+	SHINT,	TANY,
+		0,	RDEST,
+		"\tdep\tAR,31-H,S,AL\n", },
+
+{ ASSIGN,	FOREFF|INLL,
+	SHLL,	TLL,
+	SHLL,	TLL,
+		0,	RDEST,
+		"\tcopy\tAR,AL\n"
+		"\tcopy\tUR,UL\n", },
+
+{ ASSIGN,	FOREFF|INFL,
+	SHFL,	TFLOAT,
+	SHFL,	TFLOAT,
+		0,	RDEST,
+		"\tfcpy,sgl\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|INDBL,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"\tfcpy,dbl\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|INFL,
+	SHFL,	TFLOAT,
+	SOREG,	TFLOAT,
+		0,	RDEST,
+		"\tfldws\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|INDBL,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+	SOREG,	TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"\tfldds\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|INFL,
+	SOREG,	TFLOAT,
+	SHFL,	TFLOAT,
+		0,	RDEST,
+		"\tfstws\tAR,AL\n", },
+
+{ ASSIGN,	FOREFF|INDBL,
+	SOREG,	TDOUBLE|TLDOUBLE,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"\tfstds\tAR,AL\n", },
+
+/*
+ * DIV/MOD/MUL
+ */
+{ DIV,	INFL,
+	SHFL,	TFLOAT,
+	SHFL,	TFLOAT,
+		NCREG|NCSL|NCSR,	RESC1,
+		"\tfdiv,sgl\tAL,AR,A1\n", },
+
+{ DIV,	INDBL,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		NDREG|NDSL|NDSR,	RESC1,
+		"\tfdiv,dbl\tAL,AR,A1\n", },
+
+{ MUL,	INFL,
+	SHFL,	TFLOAT,
+	SHFL,	TFLOAT,
+		NCREG|NCSL|NCSR,	RESC1,
+		"\tfmul,sgl\tAL,AR,A1\n", },
+
+{ MUL,	INDBL,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		NDREG|NDSL|NDSR,	RESC1,
+		"\tfmul,dbl\tAL,AR,A1\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL,	INLL,
+	SANY,	TANY,
+	SOREG,	TLL,
+		NBREG,	RESC1,
+		"\tldw\tAL,A1\n"
+		"\tldw\tUL,U1\n", },
+
+{ UMUL,	ININT,
+	SANY,	TPOINT|TWORD,
+	SOREG,	TPOINT|TWORD,
+		NAREG|NASL,	RESC1,
+		"\tldw\tAL,A1\n", },
+
+{ UMUL,	ININT,
+	SANY,	TANY,
+	SOREG,	THWORD,
+		NAREG|NASL,	RESC1,
+		"\tldh\tAL,A1\n", },
+
+{ UMUL,	ININT,
+	SANY,	TANY,
+	SOREG,	TBYTE,
+		NAREG|NASL,	RESC1,
+		"\tldb\tAL,A1\n", },
+
+{ UMUL,	INDBL,
+	SANY,	TANY,
+	SOREG,	TDOUBLE|TLDOUBLE,
+		NDREG|NDSL,	RESC1,
+		"\tfldds\tAL,A1\n", },
+
+{ UMUL,	INFL,
+	SANY,	TANY,
+	SOREG,	TFLOAT,
+		NCREG|NCSL,	RESC1,
+		"\tfldws\tAL,A1\n", },
+
+/*
+ * Logical/branching operators
+ */
+{ OPLOG,	FORCC,
+	SHLL,	TLL,
+	SHLL,	TLL,
+		0,	0,
+		"ZD", },
+
+{ OPLOG,	FORCC,
+	SHINT,	ANYFIXED|TPOINT,
+	SPIMM,	ANYFIXED|TPOINT,
+		0,	0,
+		"\tcomib,O\tAR,AL,LC\n\tnop\n", },
+
+{ OPLOG,	FORCC,
+	SHINT,	ANYFIXED|TPOINT,
+	SHINT,	ANYFIXED|TPOINT,
+		0,	0,
+		"\tcomb,O\tAR,AL,LC\n\tnop\n", },
+
+{ OPLOG,	FORCC,
+	SHFL,	TFLOAT,
+	SHFL,	TFLOAT,
+		0,	RESCC,
+		"\tfcmp,sgl,!O\tAR,AL\n"
+		"\tftest\n"
+		"\tb\tLC\n"
+		"\tnop", },
+
+{ OPLOG,	FORCC,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		0,	RESCC,
+		"\tfcmp,dbl,!O\tAR,AL\n"
+		"\tftest\n"
+		"\tb\tLC\n"
+		"\tnop", },
+
+/*
+ * Jumps.
+ */
+{ GOTO,		FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"\tb\tLL\n\tnop\n", },
+
+#ifdef GCC_COMPAT
+{ GOTO,		FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"\tbv\t%r0(AL)\n\tnop\n", },
+#endif
+
+
+/*
+ * Convert LTYPE to reg.
+ */
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SNAME,	TANY,
+		0,	RDEST,
+		"\taddil\tUR,%r27\n", },
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SCON,	TPOINT,
+		0,	RDEST,
+		"\taddil\tUR,%r27\n", },
+
+{ OPLTYPE,	INLL,
+	SANY,	TANY,
+	SOREG,	TLL,
+		NBREG|NBSL,	RESC1,
+		"\tldw\tAL,A1\n"
+		"\tldw\tUL,U1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SOREG,	TWORD|TPOINT,
+		NAREG|NASL,	RESC1,
+		"\tldw\tAL,A1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SAREG,	TWORD|TPOINT,
+		NAREG|NASL,	RESC1,
+		"\tcopy\tAL,A1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SPCNHI,	ANYFIXED,
+		NAREG,		RESC1,
+		"\tldil\tUR,A1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SPCON,	ANYFIXED,
+		NAREG,		RESC1,
+		"\tldi\tAR,A1\n", },
+
+{ OPLTYPE,	INLL,
+	SANY,	TANY,
+	SPCON,	TLL,
+		NBREG,		RESC1,
+		"\tldi\tAR,A1\n"
+		"\tcopy\t%r0,U1\n", },
+
+{ OPLTYPE,	ININT,
+	SANY,	TANY,
+	SCON,	TWORD,
+		NAREG,		RESC1,
+		"\tldil\tUR,A1\n"
+		"\tldo\tAR(A1),A1\n", },
+
+{ OPLTYPE,	INLL,
+	SHLL,	TLL,
+	SPCNHW,	TLL,
+		NBREG,		RESC1,
+		"\tldil\tUR>>32,U1\n"
+		"\tldo\tAR>>32(U1),U1\n"
+		"\tcopy\t%r0,A1\n", },
+
+{ OPLTYPE,	INLL,
+	SHLL,	TLL,
+	SPCNLW,	TLL,
+		NBREG,		RESC1,
+		"\tcopy\t%r0,U1\n"
+		"\tldil\tUR,A1\n"
+		"\tldo\tAR(A1),A1\n", },
+
+{ OPLTYPE,	INLL,
+	SHLL,	TLL,
+	SCON,	TLL,
+		NBREG,		RESC1,
+		"\tldil\tUR,A1\n"
+		"\tldo\tAR(A1),A1\n"
+		"\tldil\tUR>>32,U1\n"
+		"\tldo\tAR>>32(U1),U1\n", },
+
+{ OPLTYPE,	INCREG,
+	SANY,	TFLOAT,
+	SHFL,	TFLOAT,
+		NCREG,	RESC1,
+		"\tfldws\tAL,A1\n", },
+
+{ OPLTYPE,	INDREG,
+	SANY,	TDOUBLE|TLDOUBLE,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		NDREG,	RESC1,
+		"\tfldds\tAL,A1\n", },
+
+/*
+ * Negate a word.
+ */
+{ UMINUS,	INLL,
+	SHLL,	TLL,
+	SHLL,	TLL,
+		NBREG|NBSL,	RESC1,
+		"\tsub\t%r0,AL,A1\n"
+		"\tsubb\t%r0,UL,A1\n", },
+
+{ UMINUS,	ININT,
+	SHINT,	TWORD,
+	SHINT,	TWORD,
+		NAREG|NASL,	RESC1,
+		"\tsub\t%r0,AL,A1\n", },
+
+{ UMINUS,	INFL,
+	SHFL,	TFLOAT,
+	SHFL,	TFLOAT,
+		NCREG|NCSL,	RESC1,
+		"\tfsub,sgl\t%fr0,AL,A1\n", },
+
+{ UMINUS,	INDBL,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+	SHDBL,	TDOUBLE|TLDOUBLE,
+		NDREG|NDSL,	RESC1,
+		"\tfsub,dbl\t%fr0,AL,A1\n", },
+
+{ COMPL,	INLL,
+	SHLL,	TLL,
+	SANY,	TANY,
+		NBREG|NBSL,	RESC1,
+		"\tuaddcm\t%r0,AL,A1\n"
+		"\tuaddcm\t%r0,UL,U1\n", },
+
+{ COMPL,	ININT,
+	SHINT,	ANYFIXED,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,
+		"\tuaddcm\t%r0,AL,A1\n", },
+
+/*
+ * Arguments to functions.
+ */
+
+{ STARG,	FOREFF,
+	SAREG|SOREG|SNAME|SCON,	TANY,
+	SANY,	TSTRUCT,
+		NAREG | RNULL,	0,
+		"ZS", },
+
+/*
+ * struct field ops
+ */
+{ FLD,	ININT,
+	SHINT,	TANY,
+	SFLD,	ANYSIGNED,
+		NAREG|NASL,	RESC1,
+		"\textrs\tAL,31-H,S,A1\n", },
+
+{ FLD,	ININT,
+	SHINT,	TANY,
+	SFLD,	ANYUSIGNED,
+		NAREG|NASL,	RESC1,
+		"\textru\tAL,31-H,S,A1\n", },
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,		FREE,
+	FREE,	FREE,
+	FREE,	FREE,
+		FREE,	FREE,
+		"HELP; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
Index: uspace/app/pcc/arch/i386/code.c
===================================================================
--- uspace/app/pcc/arch/i386/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/i386/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -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 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/i386/flocal.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -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 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/i386/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -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 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/i386/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -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 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/i386/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -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 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/i386/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -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 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/i386/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -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]);
Index: uspace/app/pcc/arch/ia32
===================================================================
--- uspace/app/pcc/arch/ia32	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/ia32	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1 @@
+i386
Index: uspace/app/pcc/arch/m16c/TODO
===================================================================
--- uspace/app/pcc/arch/m16c/TODO	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/m16c/TODO	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1 @@
+* Mul/Div does not work.
Index: uspace/app/pcc/arch/m16c/code.c
===================================================================
--- uspace/app/pcc/arch/m16c/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/m16c/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,350 @@
+/*	$Id: code.c,v 1.20 2008/07/29 13:25: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.
+ */
+
+
+# include "pass1.h"
+
+/*
+ * cause the alignment to become a multiple of n
+ */
+void
+defalign(int n)
+{
+#if 0
+	char *s;
+
+	n /= SZCHAR;
+	if (lastloc == PROG || n == 1)
+		return;
+	s = (isinlining ? permalloc(40) : tmpalloc(40));
+	sprintf(s, ".align %d", n);
+	send_passt(IP_ASM, s);
+#endif
+}
+
+/*
+ * define the current location as the name p->soname
+ */
+void
+defnam(struct symtab *p)
+{
+	char *c = p->soname;
+
+	if (p->sclass == EXTDEF)
+		printf("	PUBLIC %s\n", c);
+	printf("%s:\n", c);
+}
+
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode()
+{
+	NODE *p, *q;
+	int sz;
+
+	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+		return;
+	/* address of return struct is in eax */
+	/* create a call to memcpy() */
+	/* will get the result in eax */
+	p = block(REG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+	p->n_rval = R0;
+	q = block(OREG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+	q->n_rval = FB;
+	q->n_lval = 8; /* return buffer offset */
+	p = block(CM, q, p, INT, 0, MKSUE(INT));
+	sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR;
+	p = block(CM, p, bcon(sz), INT, 0, MKSUE(INT));
+	p->n_right->n_name = "";
+	p = block(CALL, bcon(0), p, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+	p->n_left->n_name = "memcpy";
+	send_passt(IP_NODE, p);
+}
+
+/*
+ * helper for bfcode() to put register arguments on stack.
+ */
+static void
+argmove(struct symtab *s, int regno)
+{
+	NODE *p, *r;
+
+	s->sclass = AUTO;
+	s->soffset = NOOFFSET;
+	oalloc(s, &autooff);
+	p = nametree(s);
+	r = bcon(0);
+	r->n_op = REG;
+	r->n_rval = regno;
+	r->n_type = p->n_type;
+	r->n_sue = p->n_sue;
+	r->n_df = p->n_df;
+	ecode(buildtree(ASSIGN, p, r));
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ * On m16k, space is allocated on stack for register arguments,
+ * arguments are moved to the stack and symtab is updated accordingly.
+ */
+void
+bfcode(struct symtab **a, int n)
+{
+	struct symtab *s;
+	int i, r0l, r0h, a0, r2, sz, hasch, stk;
+	int argoff = ARGINIT;
+
+	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+		/* Function returns struct, adjust arg offset */
+		for (i = 0; i < n; i++)
+			a[i]->soffset += SZPOINT(INT);
+	}
+	/* first check if there are 1-byte parameters */
+	for (hasch = i = 0; i < n && i < 6; i++)
+		if (DEUNSIGN(a[i]->stype) == CHAR)
+			hasch = 1;
+
+	stk = r0l = r0h = a0 = r2 = 0;
+	for (i = 0; i < n; i++) {
+		s = a[i];
+		sz = tsize(s->stype, s->sdf, s->ssue);
+		if (ISPTR(s->stype) && ISFTN(DECREF(s->stype)))
+			sz = SZLONG; /* function pointers are always 32 */
+		if (stk == 0)
+		    switch (sz) {
+		case SZCHAR:
+			if (r0l) {
+				if (r0h)
+					break;
+				argmove(s, 1);
+				r0h = 1;
+			} else {
+				argmove(s, 0);
+				r0l = 1;
+			}
+			continue;
+
+		case SZINT:
+			if (s->stype > BTMASK) {
+				/* is a pointer */
+				if (a0) {
+					if (r0l || hasch) {
+						if (r2)
+							break;
+						argmove(s, R2);
+						r2 = 1;
+					} else {
+						argmove(s, R0);
+						r0l = r0h = 1;
+					}
+				} else {
+					argmove(s, A0);
+					a0 = 1;
+				}
+			} else if (r0l || hasch) {
+				if (r2) {
+					if (a0)
+						break;
+					argmove(s, A0);
+					a0 = 1;
+				} else {
+					argmove(s, R2);
+					r2 = 1;
+				}
+			} else {
+				argmove(s, R0);
+				r0l = r0h = 1;
+			}
+			continue;
+		case SZLONG:
+			if (r0l||r0h||r2)
+				break;
+			argmove(s, R0);
+			r0l = r0h = r2 = 1;
+			continue;
+
+		default:
+			break;
+		}
+		stk = 1;
+		s->soffset = argoff;
+		argoff += sz;
+	}
+}
+
+/*
+ * Add a symbol to an internal list printed out at the end.
+ */
+void addsym(struct symtab *);
+static struct symlst {
+	struct symlst *next;
+	struct symtab *sp;
+} *sympole;
+
+void
+addsym(struct symtab *q)
+{
+	struct symlst *w = sympole;
+
+	if (q == NULL)
+		return;
+
+	while (w) {
+		if (q == w->sp)
+			return; /* exists */
+		w = w->next;
+	}
+	w = permalloc(sizeof(struct symlst));
+	w->sp = q;
+	w->next = sympole;
+	sympole = w;
+}
+
+/*
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+}
+
+struct caps {
+	char *cap, *stat;
+} caps[] = {
+	{ "__64bit_doubles", "Disabled" },
+	{ "__calling_convention", "Normal" },
+	{ "__constant_data", "near" },
+	{ "__data_alignment", "2" },
+	{ "__data_model", "near" },
+	{ "__processor", "M16C" },
+	{ "__rt_version", "1" },
+	{ "__variable_data", "near" },
+	{ NULL, NULL },
+};
+/*
+ * Called before parsing begins.
+ */
+void
+bjobcode()
+{
+	struct caps *c;
+
+	printf("	NAME gurka.c\n"); /* Don't have the name */
+	for (c = caps; c->cap; c++)
+		printf("	RTMODEL \"%s\", \"%s\"\n", c->cap, c->stat);
+	//printf("	RSEG CODE:CODE:REORDER:NOROOT(0)\n");
+}
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag )
+{
+	struct symlst *w = sympole;
+
+	for (w = sympole; w; w = w->next) {
+		if (w->sp->sclass != EXTERN)
+			continue;
+		printf("	EXTERN %s\n", w->sp->soname);
+	}
+	
+	printf("	END\n");
+}
+
+/*
+ * Print character t at position i in one string, until t == -1.
+ * Locctr & label is already defined.
+ */
+void
+bycode(int t, int i)
+{
+	static	int	lastoctal = 0;
+
+	/* put byte i+1 in a string */
+
+	if (t < 0) {
+		if (i != 0)
+			puts("\"");
+	} else {
+		if (i == 0)
+			printf("\t.ascii \"");
+		if (t == '\\' || t == '"') {
+			lastoctal = 0;
+			putchar('\\');
+			putchar(t);
+		} else if (t < 040 || t >= 0177) {
+			lastoctal++;
+			printf("\\%o",t);
+		} else if (lastoctal && '0' <= t && t <= '9') {
+			lastoctal = 0;
+			printf("\"\n\t.ascii \"%c", t);
+		} else {	
+			lastoctal = 0;
+			putchar(t);
+		}
+	}
+}
+
+/*
+ * 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;
+}
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+	return p;
+}
Index: uspace/app/pcc/arch/m16c/local.c
===================================================================
--- uspace/app/pcc/arch/m16c/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/m16c/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,519 @@
+/*	$Id: local.c,v 1.15 2008/12/14 21:16: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.
+ */
+
+
+# include "pass1.h"
+
+/*	this file contains code which is dependent on the target machine */
+
+NODE *
+clocal(NODE *p)
+{
+	/* this is called to do local transformations on
+	   an expression tree preparitory to its being
+	   written out in intermediate code.
+	*/
+
+	/* the major essential job is rewriting the
+	   automatic variables and arguments in terms of
+	   REG and OREG nodes */
+	/* conversion ops which are not necessary are also clobbered here */
+	/* in addition, any special features (such as rewriting
+	   exclusive or) are easily handled here as well */
+
+	struct symtab *q;
+	NODE *l, *r;
+	int o;
+	TWORD ml;
+
+	switch( o = p->n_op ){
+
+	case NAME:
+		if ((q = p->n_sp) == NULL)
+			return p; /* Nothing to care about */
+
+		switch (q->sclass) {
+
+		case PARAM:
+		case AUTO:
+			/* fake up a structure reference */
+			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+			r->n_lval = 0;
+			r->n_rval = FPREG;
+			p = stref(block(STREF, r, p, 0, 0, 0));
+			break;
+
+		case STATIC:
+			if (q->slevel == 0)
+				break;
+			p->n_lval = 0;
+			p->n_sp = q;
+			break;
+
+		case REGISTER:
+			p->n_op = REG;
+			p->n_lval = 0;
+			p->n_rval = q->soffset;
+			break;
+
+			}
+		break;
+
+	case PMCONV:
+	case PVCONV:
+		if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
+		nfree(p);
+		return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
+	
+	case PCONV:
+		ml = p->n_left->n_type;
+		l = p->n_left;
+		if ((ml == CHAR || ml == UCHAR) && l->n_op != ICON)
+			break;
+		l->n_type = p->n_type;
+		l->n_qual = p->n_qual;
+		l->n_df = p->n_df;
+		l->n_sue = p->n_sue;
+		nfree(p);
+		p = l;
+		break;
+
+	case SCONV:
+		l = p->n_left;
+		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT) {
+			nfree(p);
+			return l;
+		}
+		if (l->n_op == ICON) {
+			CONSZ val = l->n_lval;
+			switch (p->n_type) {
+			case CHAR:
+				l->n_lval = (char)val;
+				break;
+			case UCHAR:
+				l->n_lval = val & 0377;
+				break;
+			case SHORT:
+			case INT:
+				l->n_lval = (short)val;
+				break;
+			case USHORT:
+			case UNSIGNED:
+				l->n_lval = val & 0177777;
+				break;
+			case ULONG:
+			case ULONGLONG:
+				l->n_lval = val & 0xffffffff;
+				break;
+			case LONG:
+			case LONGLONG:
+				l->n_lval = (int)val;
+				break;
+			case VOID:
+				break;
+			case LDOUBLE:
+			case DOUBLE:
+			case FLOAT:
+				l->n_op = FCON;
+				l->n_dcon = val;
+				break;
+			default:
+				cerror("unknown type %d", p->n_type);
+			}
+			l->n_type = p->n_type;
+			nfree(p);
+			return l;
+		}
+		break;
+		
+
+	}
+
+	return(p);
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+	return(1);  /* all names can have & taken on them */
+}
+
+/*
+ * at the end of the arguments of a ftn, set the automatic offset
+ */
+void
+cendarg()
+{
+	autooff = AUTOINIT;
+}
+
+/*
+ * is an automatic variable of type t OK for a register variable
+ */
+int
+cisreg(TWORD t)
+{
+	if (t == INT || t == UNSIGNED || t == CHAR || t == UCHAR ||
+		ISPTR(t))
+		return(1);
+	return 0; /* XXX - fix reg assignment in pftn.c */
+}
+
+/*
+ * return a node, for structure references, which is suitable for
+ * being added to a pointer of type t, in order to be off bits offset
+ * into a structure
+ * t, d, and s are the type, dimension offset, and sizeoffset
+ * For pdp10, return the type-specific index number which calculation
+ * is based on its size. For example, short a[3] would return 3.
+ * Be careful about only handling first-level pointers, the following
+ * indirections must be fullword.
+ */
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
+{
+	register NODE *p;
+
+	if (xdebug)
+		printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
+		    off, t, d, sue->suesize);
+
+	p = bcon(0);
+	p->n_lval = off/SZCHAR; /* Default */
+	return(p);
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a NAME node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+	NODE *sp;
+
+	if ((off % SZINT) == 0)
+		p =  buildtree(MUL, p, bcon(off/SZINT));
+	else if ((off % SZSHORT) == 0) {
+		p = buildtree(MUL, p, bcon(off/SZSHORT));
+		p = buildtree(PLUS, p, bcon(1));
+		p = buildtree(RS, p, bcon(1));
+	} else if ((off % SZCHAR) == 0) {
+		p = buildtree(MUL, p, bcon(off/SZCHAR));
+		p = buildtree(PLUS, p, bcon(3));
+		p = buildtree(RS, p, bcon(2));
+	} else
+		cerror("roundsp");
+
+	/* save the address of sp */
+	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	t->n_type = sp->n_type;
+	ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+	/* add the size to sp */
+	sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	ecomp(buildtree(PLUSEQ, sp, p));
+}
+
+/*
+ * print out a constant node
+ * mat be associated with a label
+ */
+void
+ninval(NODE *p)
+{
+	struct symtab *q;
+	TWORD t;
+
+	p = p->n_left;
+	t = p->n_type;
+	if (t > BTMASK)
+		t = INT; /* pointer */
+
+	switch (t) {
+	case LONGLONG:
+	case ULONGLONG:
+		inval(p->n_lval & 0xffffffff);
+		inval(p->n_lval >> 32);
+		break;
+	case LONG:
+	case ULONG:
+	case INT:
+	case UNSIGNED:
+		printf("\t.long 0x%x", (int)p->n_lval);
+		if ((q = p->n_sp) != NULL) {
+			if ((q->sclass == STATIC && q->slevel > 0)) {
+				printf("+" LABFMT, q->soffset);
+			} else
+				printf("+%s", exname(q->soname));
+		}
+		printf("\n");
+		break;
+	default:
+		fwalk(p, eprint, 0);
+		cerror("ninval");
+	}
+}
+
+/*
+ * print out an integer.
+ */
+void
+inval(CONSZ word)
+{
+	word &= 0xffffffff;
+	printf("	.long 0x%llx\n", word);
+}
+
+/* output code to initialize a floating point value */
+/* the proper alignment has been obtained */
+void
+finval(NODE *p)
+{
+	switch (p->n_type) {
+	case LDOUBLE:
+		printf("\t.tfloat\t0t%.20Le\n", p->n_dcon);
+		break;
+	case DOUBLE:
+		printf("\t.dfloat\t0d%.20e\n", (double)p->n_dcon);
+		break;
+	case FLOAT:
+		printf("\t.ffloat\t0f%.20e\n", (float)p->n_dcon);
+		break;
+	}
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+	if (p == NULL)
+		return "";
+	return p;
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+	switch (BTYPE(type)) {
+	case SHORT:
+		MODTYPE(type,INT);
+		break;
+
+	case USHORT:
+		MODTYPE(type,UNSIGNED);
+		break;
+
+	case LONGLONG:
+		MODTYPE(type,LONG);
+		break;
+
+	case ULONGLONG:
+		MODTYPE(type,ULONG);
+		break;
+
+	case LDOUBLE:
+		MODTYPE(type,DOUBLE);
+		break;
+	}
+	return (type);
+}
+
+/* curid is a variable which is defined but
+ * is not initialized (and not a function );
+ * This routine returns the storage class for an uninitialized declaration
+ */
+int
+noinit()
+{
+	return(EXTERN);
+}
+
+/*
+ * Extern variable not necessary common.
+ */
+void
+extdec(struct symtab *q)
+{
+	extern void addsym(struct symtab *);
+	addsym(q);
+}
+
+/*
+ * Call to a function
+ */
+void
+calldec(NODE *p, NODE *r)
+{
+	struct symtab *q = p->n_sp;
+	extern void addsym(struct symtab *);
+	addsym(q);
+}
+
+/* make a common declaration for id, if reasonable */
+void
+commdec(struct symtab *q)
+{
+	int off;
+	char *c = q->soname;
+
+	off = tsize(q->stype, q->sdf, q->ssue);
+	off = (off+(SZCHAR-1))/SZCHAR;
+
+	printf("	PUBLIC %s\n", c);
+	/* XXX - NOROOT??? */
+	printf("	RSEG DATA16_Z:NEARDATA:SORT:NOROOT(1)\n");
+	printf("%s:\n", c);
+	printf("	DS8 %d\n", off);
+	printf("	REQUIRE __data16_zero\n");
+}
+
+/* make a local common declaration for id, if reasonable */
+void
+lcommdec(struct symtab *q)
+{
+	int off;
+
+	off = tsize(q->stype, q->sdf, q->ssue);
+	off = (off+(SZCHAR-1))/SZCHAR;
+	if (q->slevel == 0)
+		printf("	.lcomm %s,0%o\n", exname(q->soname), off);
+	else
+		printf("	.lcomm " LABFMT ",0%o\n", q->soffset, off);
+}
+
+/*
+ * print a (non-prog) label.
+ */
+void
+deflab1(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+void
+setloc1(int locc)
+{
+	if (locc == lastloc)
+		return;
+	lastloc = locc;
+}
+
+/*
+ * special handling before tree is written out.
+ */
+void
+myp2tree(NODE *p)
+{
+	struct symtab *sp;
+	union dimfun *df;
+	union arglist *al;
+	NODE *q;
+	int i;
+
+	switch (p->n_op) {
+	case MOD:
+	case DIV:
+		if (p->n_type == LONG || p->n_type == ULONG) {
+			/* Swap arguments for hardops() later */
+			q = p->n_left;
+			p->n_left = p->n_right;
+			p->n_right = q;
+		}
+		break;
+
+	case CALL:
+	case STCALL:
+		/*
+		 * inform pass2 about varargs.
+		 * store first variadic argument number in n_stalign
+		 * in the CM node.
+		 */
+		if (p->n_right->n_op != CM)
+			break; /* nothing to care about */
+		df = p->n_left->n_df;
+		if (df && (al = df->dfun)) {
+			for (i = 0; i < 6; i++, al++) {
+				if (al->type == TELLIPSIS || al->type == TNULL)
+					break;
+			}
+			p->n_right->n_stalign = al->type == TELLIPSIS ? i : 0;
+		} else
+			p->n_right->n_stalign = 0;
+		break;
+
+	case FCON:
+		/* Write float constants to memory */
+		sp = inlalloc(sizeof(struct symtab));
+		sp->sclass = STATIC;
+		sp->ssue = MKSUE(p->n_type);
+		sp->slevel = 1; /* fake numeric label */
+		sp->soffset = getlab();
+		sp->sflags = 0;
+		sp->stype = p->n_type;
+		sp->squal = (CON >> TSHIFT);
+
+		defloc(sp);
+		ninval(0, sp->ssue->suesize, p);
+
+		p->n_op = NAME;
+		p->n_lval = 0;
+		p->n_sp = sp;
+		break;
+	}
+
+}
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char **ary)
+{
+	return 0; }
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
Index: uspace/app/pcc/arch/m16c/local2.c
===================================================================
--- uspace/app/pcc/arch/m16c/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/m16c/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,664 @@
+/*	$Id: local2.c,v 1.40 2008/11/22 16:12: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 "pass2.h"
+# include <ctype.h>
+
+void acon(NODE *p);
+int argsize(NODE *p);
+void genargs(NODE *p);
+
+static int ftlab1, ftlab2;
+
+void
+deflab(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+static TWORD ftype;
+static int addto;
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+    ftype = ipp->ipp_type;
+
+#if 0
+    if (ipp->ipp_regs > 0 && ipp->ipp_regs != MINRVAR)
+	comperr("fix prologue register savings", ipp->ipp_regs);
+#endif
+    
+    printf("	RSEG CODE:CODE:REORDER:NOROOT(0)\n");
+    if (ipp->ipp_vis)	
+	printf("	PUBLIC %s\n", ipp->ipp_name);
+    printf("%s:\n", ipp->ipp_name);
+    
+#if 0	
+    if (xsaveip) {
+	/* Optimizer running, save space on stack */
+	addto = (p2maxautooff - AUTOINIT)/SZCHAR;
+	printf("	enter #%d\n", addto);
+    } else {
+#endif
+
+	/* non-optimized code, jump to epilogue for code generation */
+	ftlab1 = getlab2();
+	ftlab2 = getlab2();
+	printf("	jmp.w " LABFMT "\n", ftlab1);
+	deflab(ftlab2);
+}
+
+/*
+ * End of block.
+ */
+void
+eoftn(struct interpass_prolog *ipp)
+{
+#if 0
+	if (ipp->ipp_regs != MINRVAR)
+		comperr("fix eoftn register savings %x", ipp->ipp_regs);
+#endif
+
+	//	if (xsaveip == 0)
+	addto = (p2maxautooff - AUTOINIT)/SZCHAR;
+
+	/* return from function code */
+	//deflab(ipp->ipp_ip.ip_lbl);   //XXX - is this necessary?
+	
+	/* If retval is a pointer and not a function pointer, put in A0 */
+	if (ISPTR(DECREF(ipp->ipp_type)) &&
+	    !ISFTN(DECREF(DECREF(ipp->ipp_type))))
+	    printf("	mov.w r0,a0\n");
+	
+	/* struct return needs special treatment */
+	if (ftype == STRTY || ftype == UNIONTY) {
+		comperr("fix struct return in eoftn");
+	} else
+		printf("	exitd\n");
+
+	/* Prolog code */
+	//	if (xsaveip == 0) {
+		deflab(ftlab1);
+		printf("	enter #%d\n", addto);
+		printf("	jmp.w " LABFMT "\n", ftlab2);
+		//}
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+	char *str;
+
+	switch (o) {
+	case PLUS:
+		str = "add";
+		break;
+	case MINUS:
+		str = "sub";
+		break;
+	case AND:
+		str = "and";
+		break;
+	case OR:
+		str = "or";
+		break;
+	case ER:
+		str = "xor";
+		break;
+	default:
+		comperr("hopcode2: %d", o);
+		str = 0; /* XXX gcc */
+	}
+	printf("%s.%c", str, f);
+}
+
+char *
+rnames[] = {  /* keyed to register number tokens */
+    "r0", "r2", "r1", "r3", "a0", "a1", "fb", "sp", "r0h", "r0l",
+    "r1h", "r1l",
+};
+
+/*
+ * Return the size (in bytes) of some types.
+ */
+int
+tlen(p) NODE *p;
+{
+	switch(p->n_type) {
+		case CHAR:
+		case UCHAR:
+			return(1);
+
+		case INT:
+		case UNSIGNED:
+		case FLOAT:
+			return 2;
+
+		case DOUBLE:
+		case LONG:
+		case ULONG:
+			return 4;
+
+		default:
+			if (!ISPTR(p->n_type))
+				comperr("tlen type %d not pointer");
+			return SZPOINT(p->n_type)/SZCHAR;
+		}
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+	int o = p->n_op;
+	int s = getlab2();
+	int e = p->n_label;
+	int cb1, cb2;
+
+	if (o >= ULE)
+		o -= (ULE-LE);
+	switch (o) {
+	case NE:
+		cb1 = 0;
+		cb2 = NE;
+		break;
+	case EQ:
+		cb1 = NE;
+		cb2 = 0;
+		break;
+	case LE:
+	case LT:
+		cb1 = GT;
+		cb2 = LT;
+		break;
+	case GE:
+	case GT:
+		cb1 = LT;
+		cb2 = GT;
+		break;
+	
+	default:
+		cb1 = cb2 = 0; /* XXX gcc */
+	}
+	if (p->n_op >= ULE)
+		cb1 += 4, cb2 += 4;
+	expand(p, 0, "	cmp.w UR,UL\n");
+	if (cb1) cbgen(cb1, s);
+	if (cb2) cbgen(cb2, e);
+	expand(p, 0, "	cmp.w AR,AL\n");
+	cbgen(p->n_op, e);
+	deflab(s);
+}
+
+
+void
+zzzcode(NODE *p, int c)
+{
+	NODE *l;
+
+	switch (c) {
+	case 'A': /* print negative shift constant */
+		p = getlr(p, 'R');
+		if (p->n_op != ICON)
+			comperr("ZA bad use");
+		p->n_lval = -p->n_lval;
+		adrput(stdout, p);
+		p->n_lval = -p->n_lval;
+		break;
+
+	case 'B':
+		if (p->n_rval)
+			printf("	add.b #%d,%s\n",
+			    p->n_rval, rnames[STKREG]);
+		break;
+
+	case 'C': /* Print label address */
+		p = p->n_left;
+		if (p->n_lval)
+			printf(LABFMT, (int)p->n_lval);
+		else
+			printf("%s", p->n_name);
+		break;
+
+	case 'D': /* copy function pointers */
+		l = p->n_left;
+		printf("\tmov.w #HWRD(%s),%s\n\tmov.w #LWRD(%s),%s\n",
+		    p->n_right->n_name, rnames[l->n_rval+1],
+		    p->n_right->n_name, rnames[l->n_rval]);
+		break;
+
+	case 'E': /* double-reg printout */
+		/* XXX - always r0r2 here */
+		printf("%s%s", rnames[R0], rnames[R2]);
+		break;
+
+	case 'F': /* long comparisions */
+		twollcomp(p);
+		break;
+
+	case 'G':
+		printf("R0R2");
+		break;
+
+	case 'H': /* push 32-bit address (for functions) */
+		printf("\tpush.w #HWRD(%s)\n\tpush.w #LWRD(%s)\n",
+		    p->n_left->n_name, p->n_left->n_name);
+		break;
+
+	case 'I': /* push 32-bit address (for functions) */
+		l = p->n_left;
+		printf("\tpush.w %d[%s]\n\tpush.w %d[%s]\n",
+		    (int)l->n_lval, rnames[l->n_rval],
+		    (int)l->n_lval+2, rnames[l->n_rval]);
+		break;
+
+	default:
+		comperr("bad zzzcode %c", c);
+	}
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+	return(1);
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+	int o = p->n_op;
+
+	if (o==NAME || o==REG || o==ICON || o==OREG ||
+	    (o==UMUL && shumul(p->n_left, SOREG) == SRDIR))
+		return(1);
+	return(0);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+	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;
+}
+
+void
+adrcon(CONSZ val)
+{
+	printf("$" CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+	int val = p->n_lval;
+
+	switch (p->n_op) {
+	case ICON:
+		if (p->n_name[0] != '\0') {
+			fprintf(fp, "%s", p->n_name);
+			if (val)
+				fprintf(fp, "+%d", val);
+		} else
+			fprintf(fp, "%d", val);
+		return;
+
+	default:
+		comperr("illegal conput");
+	}
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+	comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+	size /= SZINT;
+	switch (p->n_op) {
+	case REG:
+		fputs(rnames[p->n_rval + 1], stdout);
+		break;
+
+	case NAME:
+	case OREG:
+		p->n_lval += size;
+		adrput(stdout, p);
+		p->n_lval -= size;
+		break;
+	case ICON:
+		fprintf(stdout, "#" CONFMT, p->n_lval >> 16);
+		break;
+	default:
+		comperr("upput bad op %d size %d", p->n_op, size);
+	}
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+	/* output an address, with offsets, from p */
+
+	if (p->n_op == FLD)
+		p = p->n_left;
+
+	switch (p->n_op) {
+
+	case NAME:
+		if (p->n_name[0] != '\0')
+			fputs(p->n_name, io);
+		if (p->n_lval != 0)
+			fprintf(io, "+" CONFMT, p->n_lval);
+		return;
+
+	case OREG:
+		if (p->n_lval)
+			fprintf(io, "%d", (int)p->n_lval);
+		fprintf(io, "[%s]", rnames[p->n_rval]);
+		return;
+	case ICON:
+		/* addressable value of the constant */
+		fputc('#', io);
+		conput(io, p);
+		return;
+
+	case REG:
+	    /*if (DEUNSIGN(p->n_type) == CHAR) {
+			fprintf(io, "R%c%c", p->n_rval < 2 ? '0' : '1',
+			    (p->n_rval & 1) ? 'H' : 'L');
+			    } else*/
+	    fprintf(io, "%s", rnames[p->n_rval]);
+	    return;
+
+	default:
+		comperr("illegal address, op %d, node %p", p->n_op, p);
+		return;
+
+	}
+}
+
+static char *
+ccbranches[] = {
+	"jeq",		/* jumpe */
+	"jne",		/* jumpn */
+	"jle",		/* jumple */
+	"jlt",		/* jumpl */
+	"jge",		/* jumpge */
+	"jgt",		/* jumpg */
+	"jleu",		/* jumple (jlequ) */
+	"jltu",		/* jumpl (jlssu) */
+	"jgeu",		/* jumpge (jgequ) */
+	"jgtu",		/* jumpg (jgtru) */
+};
+
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+	if (o < EQ || o > UGT)
+		comperr("bad conditional branch: %s", opst[o]);
+	printf("	%s " LABFMT "\n", ccbranches[o-EQ], lab);
+}
+
+void
+mycanon(NODE *p)
+{
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+#if 0
+void
+mygenregs(NODE *p)
+{
+
+	if (p->n_op == MINUS && p->n_type == DOUBLE &&
+	    (p->n_su & (LMASK|RMASK)) == (LREG|RREG)) {
+		p->n_su |= DORIGHT;
+	}
+	/* Must walk down correct node first for logops to work */
+	if (p->n_op != CBRANCH)
+		return;
+	p = p->n_left;
+	if ((p->n_su & (LMASK|RMASK)) != (LREG|RREG))
+		return;
+	p->n_su &= ~DORIGHT;
+
+}
+#endif
+
+struct hardops hardops[] = {
+	{ PLUS, FLOAT, "?F_ADD_L04" },
+	{ MUL, LONG, "?L_MUL_L03" },
+	{ MUL, ULONG, "?L_MUL_L03" },
+	{ DIV, LONG, "?SL_DIV_L03" },
+	{ DIV, ULONG, "?UL_DIV_L03" },
+	{ MOD, LONG, "?SL_MOD_L03" },
+	{ MOD, ULONG, "?UL_MOD_L03" },
+	{ RS, LONGLONG, "__ashrdi3" },
+	{ RS, ULONGLONG, "__lshrdi3" },
+	{ LS, LONGLONG, "__ashldi3" },
+	{ LS, ULONGLONG, "__ashldi3" },
+	{ 0 },
+};
+
+int
+special(NODE *p, int shape)
+{
+	switch (shape) {
+	case SFTN:
+		if (ISPTR(p->n_type) && ISFTN(DECREF(p->n_type))) {
+			if (p->n_op == NAME || p->n_op == OREG)
+				return SRDIR;
+			else
+				return SRREG;
+		}
+		break;
+	}
+	return SRNOPE;
+}
+
+void    
+myreader(NODE *p)
+{
+	NODE *q, *r, *s, *right;
+
+	if (optype(p->n_op) == LTYPE)
+		return;
+	if (optype(p->n_op) != UTYPE)
+		myreader(p->n_right);
+	myreader(p->n_left);
+
+	switch (p->n_op) {
+	case PLUS:
+	case MINUS:
+		if (p->n_type != LONG && p->n_type != ULONG)
+			break;
+		if (p->n_right->n_op == NAME || p->n_right->n_op == OREG)
+			break;
+		/* Must convert right into OREG */
+		right = p->n_right;
+		q = mklnode(OREG, BITOOR(freetemp(szty(right->n_type))),
+		    FPREG, right->n_type);
+		s = mkbinode(ASSIGN, q, right, right->n_type);
+		r = talloc(); 
+		*r = *q;
+		p->n_right = r;
+		pass2_compile(ipnode(s));
+		break;
+	}
+}
+
+
+void
+rmove(int s, int d, TWORD t)
+{
+	switch (t) {
+	case CHAR:
+	case UCHAR:
+	    printf("	mov.b %s,%s\n", rnames[s], rnames[d]);
+	    break;
+	default:
+	    printf("	mov.w %s,%s\n", rnames[s], rnames[d]);
+	}
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ */
+int
+COLORMAP(int c, int *r)
+{
+	int num;
+
+	switch (c) {
+	case CLASSA:
+		num = r[CLASSA];
+		num += r[CLASSC];
+		return num < 4;
+	case CLASSB:
+		num = r[CLASSB];
+		return num < 2;
+	case CLASSC:
+		num = 2*r[CLASSA];
+		num += r[CLASSC];
+		return num < 4;
+	}
+	return 0; /* XXX gcc */
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+	if (t == CHAR || t == UCHAR)
+		return CLASSC;
+	
+	if(ISPTR(t))
+		return CLASSB;
+	
+	return CLASSA;
+}
+
+static int sizen;
+
+/* XXX: Fix this. */
+static int
+argsiz(NODE *p)
+{
+        TWORD t = p->n_type;
+
+        if (t < LONGLONG || t > MAXTYPES)
+                return 4;
+        if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
+                return 8;
+        if (t == LDOUBLE)
+                return 12;
+        if (t == STRTY)
+                return p->n_stsize;
+        comperr("argsiz");
+        return 0;
+}
+
+/*
+ * Calculate argument sizes.
+ * XXX: Fix this.
+ */
+void
+lastcall(NODE *p)
+{
+        sizen = 0;
+        for (p = p->n_right; p->n_op == CM; p = p->n_left)
+                sizen += argsiz(p->n_right);
+        sizen += argsiz(p);
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+	return 0;
+}
Index: uspace/app/pcc/arch/m16c/macdefs.h
===================================================================
--- uspace/app/pcc/arch/m16c/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/m16c/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,196 @@
+/*	$Id: macdefs.h,v 1.23 2007/11/16 22:23:04 gmcgarry Exp $	*/
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+#define makecc(val,i)   lastcon = (lastcon<<8)|((val<<8)>>8);
+
+#define ARGINIT		40	/* # bits above fp where arguments start */
+#define AUTOINIT	0	/* # bits below fp where automatics start */
+
+/*
+ * Convert (multi-)character constant to integer.
+ * Assume: If only one value; store at left side (char size), otherwise 
+ * treat it as an integer.
+ */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR		8
+#define SZINT		16
+#define SZFLOAT         16
+#define SZDOUBLE        16
+#define SZLDOUBLE       16
+#define SZLONG		32
+#define SZSHORT		16
+#define SZLONGLONG      32
+/* pointers are of different sizes on m16c */
+#define SZPOINT(t) 	(ISFTN(DECREF(t)) ? 32 : 16)
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR		8
+#define ALINT		16
+#define ALFLOAT		16
+#define ALDOUBLE	16
+#define ALLDOUBLE	16
+#define ALLONG		16
+#define ALLONGLONG	16
+#define ALSHORT		16
+#define ALPOINT		16
+#define ALSTRUCT	16
+#define ALSTACK		16
+
+/*
+ * Min/max values.
+ */
+#define MIN_CHAR	-128
+#define MAX_CHAR	127
+#define MAX_UCHAR	255
+#define MIN_SHORT	-32768
+#define MAX_SHORT	32767
+#define MAX_USHORT	65535
+#define MIN_INT		-32768
+#define MAX_INT		32767
+#define MAX_UNSIGNED	65535
+#define MIN_LONG	-2147483648
+#define MAX_LONG	2147483647
+#define MAX_ULONG	4294967295UL
+#define MIN_LONGLONG	-2147483648
+#define MAX_LONGLONG	2147483647
+#define MAX_ULONGLONG	4294967295UL
+
+/* Default char is unsigned */
+#undef	CHAR_UNSIGNED
+
+/*
+ * Use large-enough types.
+ */
+typedef long long CONSZ;
+typedef unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT	"%lld"		/* format for printing constants */
+#define LABFMT	"L%d"		/* format for printing labels */
+
+#define BACKAUTO		/* stack grows negatively for automatics */
+#define BACKTEMP		/* stack grows negatively for temporaries */
+
+#undef	FIELDOPS		/* no bit-field instructions */
+#define RTOLBYTES		/* bytes are numbered right to left */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)	1
+#define BITOOR(x)	((x)/SZCHAR)	/* bit offset to oreg offset */
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+#define genfcall(a,b)	gencall(a,b)
+
+#define szty(t) (((t) == LONG || (t) == ULONG || \
+	(ISPTR(t) && ISFTN(DECREF(t)))) ? 2 : 1)
+
+/*
+ * m16c register classes:
+ * A - 16-bit data registers R0-R3
+ * B - 16-bit address registers A0-A1
+ * C - 8-bit data registers R0H, R0L, R1H, R1L
+ */
+
+#define R0	0
+#define R2	1
+#define R1	2
+#define R3	3
+
+#define A0	4
+#define A1	5
+#define FB	6
+#define SP	7
+
+#define R0H     8
+#define R0L     9
+#define R1H     10
+#define R1L     11
+
+#define NUMCLASS 4      /* Number of register classes */
+
+#define RETREG(x)	(x == CHAR || x == UCHAR ? R0L : R0)
+
+#define FPREG	FB	/* frame pointer */
+#define STKREG	SP	/* stack pointer */
+
+#if 0
+#define REGSZ	8	/* Number of registers */
+#define MINRVAR R1	/* first register variable */
+#define MAXRVAR R2	/* last register variable */
+#endif
+
+#define MAXREGS 12 /* 12 registers */
+
+#define RSTATUS \
+	SAREG|TEMPREG, SAREG|PERMREG, SAREG|TEMPREG, SAREG|PERMREG, \
+	SBREG|TEMPREG, SBREG|PERMREG, 0, 0, SCREG, SCREG, SCREG, SCREG,
+
+#define ROVERLAP \
+	{R0H, R0L, -1},\
+	{-1},\
+	{R1H, R1L, -1},\
+	{-1},\
+\
+	{-1},\
+	{-1},\
+\
+	{-1},\
+	{-1},\
+\
+	{R0, -1},\
+	{R0, -1},\
+	{R1, -1},\
+	{R1, -1},
+
+#define PCLASS(p) (p->n_type <= UCHAR ? SCREG : ISPTR(p->n_type) ? SBREG:SAREG)
+	    
+int COLORMAP(int c, int *r);
+#define	GCLASS(x) (x < 4 ? CLASSA : x < 6 ? CLASSB : x < 12 ? CLASSC : CLASSD)
+#define DECRA(x,y)	(((x) >> (y*6)) & 63)	/* decode encoded regs */
+#define	ENCRD(x)	(x)		/* Encode dest reg in n_reg */
+#define ENCRA1(x)	((x) << 6)	/* A1 */
+#define ENCRA2(x)	((x) << 12)	/* A2 */
+#define ENCRA(x,y)	((x) << (6+y*6))	/* encode regs in int */
+
+#define	MYADDEDGE(x, t)
+
+#ifndef NEW_READER
+//#define TAILCALL
+#endif
+#define	SFTN	(SPECIAL|6)
Index: uspace/app/pcc/arch/m16c/order.c
===================================================================
--- uspace/app/pcc/arch/m16c/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/m16c/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,621 @@
+/*	$Id: order.c,v 1.20 2008/09/27 07:35:23 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 <strings.h>
+
+int canaddr(NODE *);
+
+/*
+ * should the assignment op p be stored,
+ * given that it lies as the right operand of o
+ * (or the left, if o==UNARY MUL)
+ */
+/*
+void
+stoasg(NODE *p, int o)
+{
+	if (x2debug)
+		printf("stoasg(%p, %o)\n", p, o);
+}
+*/
+/* should we delay the INCR or DECR operation p */
+int
+deltest(NODE *p)
+{
+	return 0;
+}
+
+/*
+ * Check if p can be autoincremented.
+ * XXX - nothing can be autoincremented for now.
+ */
+int
+autoincr(NODE *p)
+{
+	return 0;
+}
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+	return(0);  /* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ */
+int
+offstar(NODE *p, int shape)
+{
+	if (x2debug)
+		printf("offstar(%p)\n", p);
+
+	if( p->n_op == PLUS || p->n_op == MINUS ){
+		if( p->n_right->n_op == ICON ){
+			geninsn(p->n_left, INBREG);
+			p->n_su = -1;
+			return 1;
+		}
+	}
+	geninsn(p, INBREG);
+	return 0;
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+//	NODE *l = p->n_left;
+
+#ifdef PCC_DEBUG
+	if (x2debug) {
+		printf("shumul(%p)\n", p);
+		fwalk(p, e2print, 0);
+	}
+#endif
+	/* XXX - fix */
+
+	/* Can only generate OREG of BREGs (or FB) */
+	if (p->n_op == REG && (isbreg(p->n_rval) || p->n_rval == FB))
+		return SROREG;
+#if 0
+	if ((p->n_op == PLUS || p->n_op == MINUS) &&
+	    (l->n_op == REG && (isbreg(l->n_rval) || l->n_rval == FB)) &&
+	    p->n_right->n_op == ICON)
+		return SOREG;
+	return 0;
+#else
+	return SROREG;
+#endif
+}
+
+/*
+ * Rewrite increment/decrement operation.
+ */
+int
+setincr(NODE *p)
+{
+	if (x2debug)
+		printf("setincr(%p)\n", p);
+
+	return(0);
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE *p)
+{
+
+	if (x2debug)
+		printf("setbin(%p)\n", p);
+	return 0;
+
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+	if (x2debug)
+		printf("setasg(%p)\n", p);
+	return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+	return 0;
+}
+
+#if 0
+/*
+ * register allocation for instructions with special preferences.
+ */
+regcode
+regalloc(NODE *p, struct optab *q, int wantreg)
+{
+	regcode regc;
+
+	if (q->op == DIV || q->op == MOD) {
+		/*
+		 * 16-bit div.
+		 */
+		if (regblk[R0] & 1 || regblk[R2] & 1)
+			comperr("regalloc: needed regs inuse, node %p", p);
+		if (p->n_su & DORIGHT) {
+			regc = alloregs(p->n_right, A0);
+			if (REGNUM(regc) != A0) {
+				p->n_right = movenode(p->n_right, A0);
+				if ((p->n_su & RMASK) == ROREG) {
+					p->n_su &= ~RMASK;
+					p->n_su |= RREG;
+					p->n_right->n_su &= ~LMASK;
+					p->n_right->n_su |= LOREG;
+				}
+				freeregs(regc);
+				regblk[A0] |= 1;
+			}
+		}
+		regc = alloregs(p->n_left, R0);
+		if (REGNUM(regc) != R0) {
+			p->n_left = movenode(p->n_left, R0);
+			freeregs(regc);
+			regblk[R0] |= 1;
+		}
+		if ((p->n_su & RMASK) && !(p->n_su & DORIGHT)) {
+			regc = alloregs(p->n_right, A0);
+			if (REGNUM(regc) != A0) {
+				p->n_right = movenode(p->n_right, A0);
+				if ((p->n_su & RMASK) == ROREG) {
+					p->n_su &= ~RMASK;
+					p->n_su |= RREG;
+					p->n_right->n_su &= ~LMASK;
+					p->n_right->n_su |= LOREG;
+				}
+			}
+		}
+		regblk[A0] &= ~1;
+		regblk[R0] &= ~1;
+		regblk[R2] &= ~1;
+		if (q->op == DIV) {
+			MKREGC(regc, R0, 1);
+			regblk[R0] |= 1;
+		} else {
+			MKREGC(regc, R2, 1);
+			regblk[R2] |= 1;
+		}
+	} else
+		comperr("regalloc");
+	p->n_rall = REGNUM(regc);
+	return regc;
+}
+#endif
+
+/*
+ * Special handling of some instruction register allocation.
+ * - left is the register that left node wants.
+ * - right is the register that right node wants.
+ * - res is in which register the result will end up.
+ * - mask is registers that will be clobbered.
+ *
+ *  XXX - Fix this function
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+    switch (q->op) {
+
+    case DIV:
+    case MOD:
+	if(q->ltype & (TINT|TSHORT)){
+	    static struct rspecial s[] = {
+		{ NRES, R0 }, { NRES, R2}, { 0 } };
+	    return s;
+	}
+	/*
+	else if(q->ltype & TCHAR) {
+	    static struct rspecial s[] = {
+		{ NRES, R0L }, { NRES, R0H}, { 0 } };
+	    return s;
+	    }*/
+	break;
+
+    case MUL:
+	/*
+	if(q->ltype & (TINT|TSHORT)){
+	    static struct rspecial s[] = {
+		{ NRES, R0 }, { NRES, R2}, { 0 } };
+	    return s;
+	    }*/
+	comperr("multiplication not implemented");
+	break;
+	
+    default:
+	break;
+    }
+    comperr("nspecial entry %d", q - table);
+    return 0; /* XXX gcc */
+}
+
+
+/*
+ * Splitup a function call and give away its arguments first.
+ * Calling convention used ("normal" in IAR syntax) is:
+ * - 1-byte parameters in R0L if possible, otherwise in R0H.
+ * - 2-byte pointers in A0.
+ * - 2-byte non-pointers in R0 if no byte-size arguments are found in
+ *   in the first 6 bytes of parameters, otherwise R2 or at last A0.
+ * - 4-byte parameters in R2R0.
+ */
+void
+gencall(NODE *p, NODE *prev)
+{
+	NODE *n = 0; /* XXX gcc */
+	static int storearg(NODE *);
+	int o = p->n_op;
+	int ty = optype(o);
+
+	if (ty == LTYPE)
+		return;
+
+	switch (o) {
+	case CALL:
+		/* swap arguments on some hardop-converted insns */
+		/* Normal call, just push args and be done with it */
+		p->n_op = UCALL;
+//printf("call\n");
+		/* Check if left can be evaluated directly */
+		if (p->n_left->n_op == UMUL) {
+			TWORD t = p->n_left->n_type;
+			int k = BITOOR(freetemp(szty(t)));
+			NODE *n = mklnode(OREG, k, FB, t);
+			NODE *q = tcopy(n);
+			pass2_compile(ipnode(mkbinode(ASSIGN, n, p->n_left,t)));
+			p->n_left = q;
+		}
+		gencall(p->n_left, p);
+		p->n_rval = storearg(p->n_right);
+//printf("end call\n");
+		break;
+
+	case UFORTCALL:
+	case FORTCALL:
+		comperr("FORTCALL");
+
+	case USTCALL:
+	case STCALL:
+		/*
+		 * Structure return.  Look at the node above
+		 * to decide about buffer address:
+		 * - FUNARG, allocate space on stack, don't remove.
+		 * - nothing, allocate space on stack and remove.
+		 * - STASG, get the address of the left side as arg.
+		 * - FORCE, this ends up in a return, get supplied addr.
+		 * (this is not pretty, but what to do?)
+		 */
+		if (prev == NULL || prev->n_op == FUNARG) {
+			/* Create nodes to generate stack space */
+			n = mkbinode(ASSIGN, mklnode(REG, 0, STKREG, INT),
+			    mkbinode(MINUS, mklnode(REG, 0, STKREG, INT),
+			    mklnode(ICON, p->n_stsize, 0, INT), INT), INT);
+//printf("stsize %d\n", p->n_stsize);
+			pass2_compile(ipnode(n));
+		} else if (prev->n_op == STASG) {
+			n = prev->n_left;
+			if (n->n_op == UMUL)
+				n = nfree(n);
+			else if (n->n_op == NAME) {
+				n->n_op = ICON; /* Constant reference */
+				n->n_type = INCREF(n->n_type);
+			} else
+				comperr("gencall stasg");
+		} else if (prev->n_op == FORCE) {
+			; /* do nothing here */
+		} else {
+			comperr("gencall bad op %d", prev->n_op);
+		}
+
+		/* Deal with standard arguments */
+		gencall(p->n_left, p);
+		if (o == STCALL) {
+			p->n_op = USTCALL;
+			p->n_rval = storearg(p->n_right);
+		} else
+			p->n_rval = 0;
+		/* push return struct address */
+		if (prev == NULL || prev->n_op == FUNARG) {
+			n = mklnode(REG, 0, STKREG, INT);
+			if (p->n_rval)
+				n = mkbinode(PLUS, n,
+				    mklnode(ICON, p->n_rval, 0, INT), INT);
+			pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
+			if (prev == NULL)
+				p->n_rval += p->n_stsize/4;
+		} else if (prev->n_op == FORCE) {
+			/* return value for this function */
+			n = mklnode(OREG, 8, FPREG, INT);
+			pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
+			p->n_rval++;
+		} else {
+			pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
+			n = p;
+			*prev = *p;
+			nfree(n);
+		}
+//printf("end stcall\n");
+		break;
+
+	default:
+		if (ty != UTYPE)
+			gencall(p->n_right, p);
+		gencall(p->n_left, p);
+		break;
+	}
+}
+
+/*
+ * Create separate node trees for function arguments.
+ * This is partly ticky, the strange calling convention 
+ * may cause a bunch of code reorganization here.
+ */
+static int
+storearg(NODE *p)
+{
+	NODE *n, *q, **narry;
+	int nch, k, i, nn, rary[4];
+	int r0l, r0h, r2, a0, stk, sz;
+	TWORD t;
+	int maxrargs = 0;
+
+	if (p->n_op == CM)
+		maxrargs = p->n_stalign;
+
+	/* count the arguments */
+	for (i = 1, q = p; q->n_op == CM; q = q->n_left)
+		i++;
+	nn = i;
+
+	/* allocate array to store arguments */
+	narry = tmpalloc(sizeof(NODE *)*nn);
+
+	/* enter nodes into array */
+	for (q = p; q->n_op == CM; q = q->n_left)
+		narry[--i] = q->n_right;
+	narry[--i] = q;
+
+	/* free CM nodes */
+	for (q = p; q->n_op == CM; ) {
+		n = q->n_left;
+		nfree(q);
+		q = n;
+	}
+
+	/* count char args */
+	r0l = r0h = r2 = a0 = 0;
+	for (sz = nch = i = 0; i < nn && i < 6; i++) {
+		TWORD t = narry[i]->n_type;
+		if (sz >= 6)
+			break;
+		if (t == CHAR || t == UCHAR) {
+			nch++;
+			sz++;
+		} else if ((t >= SHORT && t <= UNSIGNED) ||
+		    t > BTMASK || t == FLOAT) {
+			sz += 2;
+		} else /* long, double */
+			sz += 4;
+			
+	}
+
+	/*
+	 * Now the tricky part. The parameters that should be on stack
+	 * must be found and pushed first, then the register parameters.
+	 * For the latter, be sure that evaluating them do not use any
+	 * registers where argument values already are inserted.
+	 * XXX - function pointers?
+	 * XXX foo(long a, char b) ???
+	 */
+	for (stk = 0; stk < 4; stk++) {
+		TWORD t;
+
+		if (stk == nn)
+			break;
+		t = narry[stk]->n_type;
+		if (ISFTN(DECREF(t)))
+			t = LONG;
+		switch (t) {
+		case CHAR: case UCHAR:
+			if (r0l) {
+				if (r0h)
+					break;
+				rary[stk] = R2; /* char talk for 'R0H' */
+				r0h = 1;
+			} else {
+				rary[stk] = R0;
+				r0l = 1;
+			}
+			continue;
+
+		case INT: case UNSIGNED:
+			if (r0l || nch) {
+				if (r2) {
+					if (a0)
+						break;
+					rary[stk] = A0;
+					a0 = 1;
+				} else {
+					rary[stk] = R2;
+					r2 = 1;
+				}
+			} else {
+				rary[stk] = R0;
+				r0l = r0h = 1;
+			}
+			continue;
+
+		case LONG: case ULONG:
+			if (r0l || r2)
+				break;
+			rary[stk] = R0;
+			r0l = r0h = r2 = 1;
+			continue;
+
+		default:
+			if (ISPTR(narry[stk]->n_type) &&
+			    !ISFTN(DECREF(narry[stk]->n_type))) {
+				if (a0) {
+					if (r0l || nch) {
+						if (r2)
+							break;
+						rary[stk] = R2;
+						r2 = 1;
+					} else {
+						rary[stk] = R0;
+						r0l = r0h = 1;
+					}
+				} else {
+					rary[stk] = A0;
+					a0 = 1;
+				}
+				continue;
+			}
+			break;
+		}
+		break;
+	}
+
+	/*
+	 * The arguments that must be on stack are stk->nn args.
+	 * Argument 0->stk-1 should be put in the rary[] register.
+	 */
+	for (sz = 0, i = nn-1; i >= stk; i--) { /* first stack args */
+		NODE nod;
+		pass2_compile(ipnode(mkunode(FUNARG,
+		    narry[i], 0, narry[i]->n_type)));
+		nod.n_type = narry[i]->n_type;
+		sz += tlen(&nod);
+	}
+	/* if param cannot be addressed directly, evaluate and put on stack */
+	for (i = 0; i < stk; i++) {
+
+		if (canaddr(narry[i]))
+			continue;
+		t = narry[i]->n_type;
+		k = BITOOR(freetemp(szty(t)));
+		n = mklnode(OREG, k, FB, t);
+		q = tcopy(n);
+		pass2_compile(ipnode(mkbinode(ASSIGN, n, narry[i], t)));
+		narry[i] = q;
+	}
+	/* move args to registers */
+	for (i = 0; i < stk; i++) {
+		t = narry[i]->n_type;
+		pass2_compile(ipnode(mkbinode(ASSIGN, 
+		    mklnode(REG, 0, rary[i], t), narry[i], t)));
+	}
+	return sz;
+}
+
+/*
+ * Tell if a register can hold a specific datatype.
+ */
+#if 0
+int
+mayuse(int reg, TWORD type)
+{
+	return 1;  /* Everything is OK */
+}
+#endif
+
+#ifdef TAILCALL
+void
+mktailopt(struct interpass *ip1, struct interpass *ip2)
+{
+	extern int earlylab;
+	extern char *cftname;
+	char *fn;
+	NODE *p;
+
+	p = ip1->ip_node->n_left->n_left;
+	if (p->n_op == ICON) {
+		fn = p->n_name;
+		/* calling ourselves */
+		p = ip1->ip_node->n_left;
+		if (p->n_op == CALL) {
+			if (storearg(p->n_right))
+				comperr("too many args: fix mktailopt");
+			p->n_op = UCALL;
+		}
+		tfree(ip1->ip_node);
+		p = ip2->ip_node->n_left;
+		if (strcmp(fn, cftname)) {
+			/* Not us, must generate fake prologue */
+			ip1->type = IP_ASM;
+			ip1->ip_asm = "mov.w FB,SP\n\tpop.w FB";
+			pass2_compile(ip1);
+			p->n_lval = p->n_rval = 0;
+			p->n_name = fn;
+		} else
+			p->n_lval = earlylab;
+	} else {
+		pass2_compile(ip1);
+	}
+	pass2_compile(ip2);
+}
+#endif
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+	static int r[1] = { -1 }; /* Terminate with -1 */
+
+	return &r[0];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+	return 1;
+}
Index: uspace/app/pcc/arch/m16c/table.c
===================================================================
--- uspace/app/pcc/arch/m16c/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/m16c/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,587 @@
+#include "pass2.h"
+
+# define ANYSIGNED TINT|TLONG|TCHAR
+# define ANYUSIGNED TUNSIGNED|TULONG|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TL TLONG|TULONG
+# define TWORD TUNSIGNED|TINT
+# define TCH TCHAR|TUCHAR
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* (signed) char -> int/pointer */
+{ SCONV,	INAREG,
+	SCREG,		TCHAR,
+	SANY,		TINT|TPOINT,
+		NAREG,	RESC1,
+		"	mov.b AL, A1\n\texts.b A1\n", },
+
+/* (unsigned) char -> int/pointer */
+{ SCONV,	INAREG,
+	SCREG,		TUCHAR,
+	SANY,		TINT|TPOINT,
+		NAREG,	RESC1,
+		"	mov.b AL, A1\n", },
+    
+/* unsigned char -> long */
+{ SCONV,	INAREG,
+	SCREG,		TUCHAR,
+	SANY,		TL,
+		NAREG|NASL,	RESC1,
+		"	mov.b AL, A1\n	mov.w #0,U1\n", },
+
+/* int or pointer -> (unsigned) long */
+{ SCONV,	INAREG,
+	SAREG|SNAME,	TWORD|TPOINT,
+	SANY,			TL,
+		NAREG|NASL,	RESC1,
+		"	mov.w AL,A1\n	mov.w #0,U1\n", },
+
+/* char -> (signed) long */
+{ SCONV,	INAREG,
+	SAREG|SNAME,	TCHAR,
+	SANY,			TLONG,
+		NAREG|NASL,	RESC1,
+		"	exts.b AL\n	exts.w AL\n", },
+
+/* long -> ulong */
+{ SCONV,	INAREG,
+	SAREG,		TL,
+	SANY,			TL,
+		0,	RLEFT,
+	"", },
+
+/* long -> int or pointer */
+{ SCONV,	INAREG,
+	SAREG|SOREG|SNAME,	TL,
+	SANY,			TWORD|TPOINT,
+		NAREG|NASL,	RESC1,
+		"	mov.w AL,A1\n", },
+
+/* int -> char */
+{ SCONV,	INCREG,
+	SAREG,		TWORD,
+	SANY,		TCH,
+		NCREG,	RESC1,
+		"	mov.b AL, A1\n", },
+
+/* int -> long */
+{ SCONV,	INAREG,
+	SAREG,		TWORD,
+	SANY,		TLONG,
+		NAREG|NASL,	RESC1,
+		"	exts.w AL", },
+
+/* long -> char */
+{ SCONV,	INAREG,
+	SAREG,		TL,
+	SANY,		TCH,
+		NAREG|NASL,     RESC1,
+		"", },
+
+{ SCONV,	INAREG,
+	SAREG,		TPOINT,
+	SANY,		TWORD,
+		0,	RLEFT,
+		"", },
+
+{ PLUS,	INAREG|FOREFF,
+	SAREG,	TL,
+	SCON|SNAME|SOREG,	TL,
+		0,	RLEFT,
+		"	add.w AR,AL\n	adc.w UR,UL\n", },
+
+{ MINUS,	INAREG|FOREFF,
+	SAREG,	TL,
+	SCON|SNAME|SOREG,	TL,
+		0,	RLEFT,
+		"	sub.w AR,AL\n	sbb.w UR,UL\n", },
+
+{ AND,		INAREG|FOREFF,
+	SAREG,			TL,
+	SAREG|SNAME|SOREG,	TL,
+		0,	RLEFT,
+		"	and.w AR,AL\n	and.w UR,UL\n", },
+
+{ ER,		INAREG|FOREFF,
+	SAREG,			TL,
+	SAREG|SNAME|SOREG,	TL,
+		0,	RLEFT,
+		"	xor.w AR,AL\n	xor.w UR,UL\n", },
+
+{ OR,		INAREG|FOREFF,
+	SAREG,			TL,
+	SAREG|SNAME|SOREG,	TL,
+		0,	RLEFT,
+		"	xor.w AR,AL\n	xor.w UR,UL\n", },
+
+{ COMPL,	INAREG|FOREFF,
+	SAREG,			TL,
+	SAREG|SNAME|SOREG,	TL,
+		0,	RLEFT,
+		"	not.w AR,AL\n	not.w UR,UL\n", },
+	
+{ OPSIMP,	INAREG|FOREFF,
+	SAREG,			TWORD|TPOINT,
+	SAREG|SNAME|SOREG|SCON,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	Ow AR,AL\n", },
+
+/* XXX - Is this rule really correct? Having a SAREG shape seems kind of
+   strange. Doesn't work. Gives a areg as A1. */
+#if 0	
+{ OPSIMP,	INBREG,
+	SAREG,			TWORD|TPOINT,
+	SAREG|SBREG|SNAME|SOREG|SCON,	TWORD|TPOINT,
+		NBREG,	RESC1,
+		"	++Ow AR,A1\n", },
+#endif
+	
+{ OPSIMP,	INBREG,
+	SBREG,			TWORD|TPOINT,
+	SAREG|SBREG|SNAME|SOREG|SCON,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	Ow AR,AL\n", },
+	
+{ OPSIMP,	INCREG|FOREFF,
+	SCREG,			TCH,
+	SCREG|SNAME|SOREG|SCON,	TCH,
+		0,	RLEFT,
+		"	Ob AR,AL\n", },
+	
+/* XXX - Do these work? check nspecial in order.c */
+/* signed integer division */
+{ DIV,		INAREG,
+	SAREG,			TINT,
+	SAREG|SNAME|SOREG,	TWORD,
+	  /*2*NAREG|NASL|*/NSPECIAL,		RLEFT,
+		"	div.w AR\n	mov.w r0,AL\n", },
+      //		"	xor.w r2\n	div.w AR\n", },
+
+
+/* signed integer/char division - separate entry for FOREFF */
+{ DIV,		FOREFF,
+	SAREG,			TINT,
+	SAREG|SNAME|SOREG,	TWORD,
+		0,		0,
+		"", },
+
+#if 0
+/* signed char division */
+{ DIV,		INCREG,
+	SCREG,			TCHAR,
+	SCREG|SNAME|SOREG,	TCH,
+		2*NCREG|NCSL|NSPECIAL,		RLEFT,
+		"	div.b AR\n\tmov.b r0l,AL\n", },
+      //		"	xor.w r2\n	div.w AR\n", },
+#endif
+	
+/* signed integer modulus, equal to above */
+{ MOD,		INAREG,
+	SAREG,			TINT,
+	SAREG|SNAME|SOREG,	TWORD,
+	  /*2*NAREG|NASL|*/NSPECIAL,		RLEFT,
+		"	div.w AR\n\tmov r2,AL\n", },
+
+/* signed integer modulus - separate entry for FOREFF */
+{ MOD,		FOREFF,
+	SAREG,			TINT,
+	SAREG|SNAME|SOREG,	TWORD,
+		0,		0,
+		"", },
+
+/* signed integer multiplication */
+{ MUL,		INAREG,
+	SAREG,			TINT,
+	SAREG|SNAME|SOREG,	TWORD,
+		2*NAREG|NASL|NSPECIAL,		RESC1,
+		"	mul.w AL,AR\n", },
+
+{ MUL,		FOREFF,
+	SAREG,			TINT,
+	SAREG|SNAME|SOREG,	TWORD,
+		0,	0,
+		"", },
+
+#if 0
+{ LS,		INAREG,
+	SAREG,	TWORD,
+	SCON,		TANY,
+		0,	RLEFT,
+		"	shl.w AR,AL\n", },
+#endif
+
+{ LS,		INAREG,
+	SAREG,	TWORD,
+	SAREG,	TWORD,
+		0,	RLEFT,
+		"	push.b r1h\n"
+		"	mov.b AR,r1h\n"
+		"	shl.w r1h,AL\n"
+		"	pop.b r1h\n", },
+
+{ LS,		INAREG,
+	SAREG,	TL,
+	SAREG,	TWORD,
+		0,	RLEFT,
+		"	push.b r1h\n"
+		"	mov.b AR,r1h\n"
+		"	shl.l r1h,ZG\n"
+		"	pop.b r1h\n", },
+
+{ RS,		INAREG,
+	SAREG,	TWORD,
+	SAREG,	TWORD,
+		0,	RLEFT,
+		"	push.b r1h\n"
+		"	mov.b AR,r1h\n"
+		"	neg.b r1h\n"
+		"	shl.w r1h,AL\n"
+		"	pop.b r1h\n", },
+
+{ RS,		INAREG,
+	SAREG,	TL,
+	SAREG,	TWORD,
+		0,	RLEFT,
+		"	push.b r1h\n"
+		"	mov.b AR,r1h\n"
+		"	neg.b r1h\n"
+		"	shl.l r1h,ZG\n"
+		"	pop.b r1h\n", },
+
+#if 0
+{ RS,		INAREG,
+	SAREG,	TUNSIGNED,
+	SCON,		TANY,
+		0,	RLEFT,
+		"	shl ZA,AL\n", },
+
+{ RS,		INAREG,
+	SAREG,	TINT,
+	SCON,		TANY,
+		0,	RLEFT,
+		"	sha ZA,AL\n", },
+#endif
+
+{ OPLOG,	FORCC,
+	SAREG|SBREG|SOREG|SNAME,	TL,
+	SAREG|SBREG|SOREG|SNAME,	TL,
+		0,	0,
+		"ZF", },
+
+{ OPLOG,	FORCC,
+	SBREG|SOREG,	TWORD|TPOINT,
+	SCON,			TWORD|TPOINT,
+		0,	RESCC,
+		"	cmp.w AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|SBREG|SOREG|SNAME,	TWORD|TPOINT,
+	SAREG|SBREG|SOREG|SNAME,	TWORD|TPOINT,
+		0,	RESCC,
+		"	cmp.w AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SCREG|SOREG|SNAME,	TCH,
+	SCREG|SOREG|SNAME,	TCH,
+		0,	RESCC,
+		"	cmp.b AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SCREG|SOREG|SNAME,	TCH,
+	SCREG|SOREG|SNAME,	TCH,
+		0,	RESCC,
+		"	cmp.b AR,AL\n", },
+
+{ GOTO,		FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	jmp.w ZC\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SCON|SNAME|SOREG|SAREG,	TL|TFTN,
+		NAREG,	RESC1,
+		"	mov.w AR,A1\n	mov.w UR,U1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SCON|SNAME|SOREG|SAREG|SBREG,	TWORD|TPOINT,
+		NAREG,	RESC1,
+		"	mov.w AR,A1\n", },	
+
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SBREG|SCON|SNAME|SOREG|SAREG,	TWORD|TPOINT,
+		NBREG,	RESC1,
+		"	mov.w AR,A1\n", },	
+    /*
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SCON|SNAME|SOREG,	TCH,
+		NAREG,	RESC1,
+		"	mov.b AR, A1\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,			TANY,
+	SCON|SNAME|SOREG,	TCHAR|TUCHAR,
+		NBREG,	RESC1,
+		"	mov.b AR,A1\n", },
+    */
+    
+{ OPLTYPE,	INCREG,
+	SANY,			TANY,
+	SCON|SNAME|SOREG,	TCHAR|TUCHAR,
+		NCREG,	RESC1,
+		"	mov.b AR,A1\n", },
+    
+{ COMPL,	INAREG,
+	SAREG,	TWORD,
+	SANY,		TANY,
+		0,	RLEFT,
+		"	not.w AL\n", },
+
+{ COMPL,	INCREG,
+	SCREG,	TCH,
+	SANY,		TANY,
+		0,	RLEFT,
+		"	not.b AL\n", },
+	
+/* Push function address */
+{ FUNARG,	FOREFF,
+	SCON,	TFTN,
+	SANY,	TANY,
+		0,	RNULL,
+		"ZH", },
+
+{ FUNARG,	FOREFF,
+	SOREG,	TFTN,
+	SANY,	TANY,
+		0,	RNULL,
+		"ZI", },
+
+{ FUNARG,	FOREFF,
+	SNAME|SAREG,	TL|TFTN,
+	SANY,	TANY,
+		0,	RNULL,
+		"	push.w UL\n	push.w AL\n", },
+
+{ FUNARG,	FOREFF,
+	SCON|SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SANY,			TANY,
+		0,	RNULL,
+		"	push.w AL\n", },
+
+{ FUNARG,	FOREFF,
+	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
+	SANY,				TANY,
+		0,	RNULL,
+		"	push.b AL\n", },
+
+/* Match function pointers first */
+#if 0
+{ ASSIGN,	FOREFF,
+	SFTN,	TWORD|TPOINT,
+	SFTN,	TWORD|TPOINT,
+		NAREG,	0,
+		"ZD", },
+#endif
+
+{ ASSIGN,	INAREG,
+	SAREG,	TFTN,
+	SCON,	TFTN,
+		0,	RLEFT,
+		"ZD", },
+    
+{ ASSIGN,	INBREG,
+	SBREG,	TFTN,
+	SCON,	TFTN,
+		0,	RLEFT,
+		"ZD", },
+
+{ ASSIGN,	INAREG,
+	SAREG,	TFTN,
+	SBREG|SAREG|SOREG|SNAME,	TFTN,
+		0,	RLEFT,
+		"	mov.w AR,AL\n	mov.w UR,UL\n", },
+
+{ ASSIGN,	INBREG,
+	SBREG,	TFTN,
+	SBREG|SAREG|SOREG|SNAME,	TFTN,
+		0,	RLEFT,
+		"	mov.w AR,AL\n	mov.w UR,UL\n", },
+    
+{ ASSIGN,	INAREG,
+	SBREG|SAREG|SOREG|SNAME,	TFTN,
+	SAREG,	TFTN,
+		0,	RRIGHT,
+		"	mov.w AR,AL\n	mov.w UR,UL\n", },
+
+{ ASSIGN,	INBREG,
+	SBREG|SAREG|SOREG|SNAME,	TFTN,
+	SBREG,	TFTN,
+		0,	RRIGHT,
+		"	mov.w AR,AL\n	mov.w UR,UL\n", },
+
+/* a reg -> a reg */
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	mov.w AR,AL\n", },
+
+{ ASSIGN,	INAREG,
+	SBREG|SAREG|SOREG|SNAME,	TL,
+	SAREG,	TL,
+		0,	RRIGHT,
+		"	mov.w AR,AL\n	mov.w UR,UL\n", },
+
+{ ASSIGN,	INBREG,
+	SBREG|SAREG|SOREG|SNAME,	TL,
+	SBREG,	TL,
+		0,	RRIGHT,
+		"	mov.w AR,AL\n	mov.w UR,UL\n", },
+    
+{ ASSIGN,	FOREFF,
+	SBREG|SAREG|SOREG|SNAME,	TL,
+	SCON|SBREG|SAREG|SOREG|SNAME,	TL,
+		0,	0,
+		"	mov.w AR,AL\n	mov.w UR,UL\n", },
+
+{ ASSIGN,	INAREG|FOREFF,
+	SAREG,	TWORD|TPOINT,
+	SCON,	TANY,
+		0,	RLEFT,
+		"	mov.w AR,AL\n", },
+
+{ ASSIGN,	INBREG|FOREFF,
+	SBREG,	TWORD|TPOINT,
+	SCON,	TANY,
+		0,	RLEFT,
+		"	mov.w AR,AL\n", },
+    
+{ ASSIGN,	FOREFF,
+	SNAME|SOREG,	TWORD|TPOINT,
+	SCON,		TANY,
+		0,	0,
+		"	mov.w AR,AL\n", },
+
+/* char, oreg/name -> c reg */
+{ ASSIGN,	FOREFF|INCREG,
+	SCREG,	TCHAR|TUCHAR,
+	SOREG|SNAME|SCON,	TCHAR|TUCHAR,
+		0,	RLEFT,
+		"	mov.b AR,AL\n", },
+
+/* int, oreg/name -> a reg */
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TWORD|TPOINT,
+	SOREG|SNAME,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	mov.w AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,	TWORD|TPOINT,
+	SOREG|SNAME,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	mov.w AR,AL\n", },
+    
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG|SNAME,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		0,	RRIGHT,
+		"	mov.w AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SOREG|SNAME,	TWORD|TPOINT,
+	SBREG,	TWORD|TPOINT,
+		0,	RRIGHT,
+		"	mov.w AR,AL\n", },
+    
+{ ASSIGN,	FOREFF|INCREG,
+	SOREG|SNAME,	TCHAR|TUCHAR,
+	SCREG,	TCHAR|TUCHAR,
+		0,	RRIGHT,
+		"	mov.b AR,AL\n", },
+
+{ ASSIGN,       FOREFF|INCREG,
+        SCREG,    TCHAR|TUCHAR,
+        SCREG,  TCHAR|TUCHAR,
+                0,      RRIGHT,
+                "	mov.b AR,AL\n", },
+
+{ ASSIGN,       FOREFF|INBREG,
+        SBREG,    TWORD|TPOINT,
+        SBREG,  TWORD|TPOINT,
+                0,      RRIGHT,
+                "	mov.w AR,AL\n", },
+	
+{ UMUL, 	INAREG,
+	SBREG,	TPOINT|TWORD,
+	SANY,  	TFTN,
+		NAREG,	RESC1,
+		"	mov.w [AL],A1\n	mov.w 2[AL],U1\n", },
+
+{ UMUL, 	INAREG,
+	SBREG,	TPOINT|TWORD,
+	SANY,  	TPOINT|TWORD,
+		NAREG,	RESC1,
+		"	mov.w [AL],A1\n", },
+
+{ UMUL, 	INBREG,
+	SBREG,	TPOINT|TWORD,
+	SANY,  	TPOINT|TWORD,
+		NBREG|NBSL,	RESC1,
+		"	mov.w [AL],A1\n", },
+
+{ UMUL,		INAREG,
+	SBREG,	TCHAR|TUCHAR|TPTRTO,
+	SANY,	TCHAR|TUCHAR,
+		NAREG,	RESC1,
+    		"	mov.b [AL], A1\n", },
+    
+{ UCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	jsr.w CL\nZB", },
+    
+{ UCALL,	INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG,	RESC1,
+		"	jsr.w CL\nZB", },
+
+{ UCALL,        INAREG,
+	SNAME|SOREG,	TANY,
+	SANY,		TANY,
+		NAREG|NASL,     RESC1,  /* should be 0 */
+		"	jsri.a AL\nZB", },
+
+{ UCALL,        FOREFF,
+	SNAME|SOREG,	TANY,
+	SANY,		TANY,
+		0,     0,  
+		"	jsri.a AL\nZB", },
+    
+{ UCALL,        INAREG,
+	SBREG,   TANY,
+	SANY,   TANY,
+		NAREG|NASL,     RESC1,  /* should be 0 */
+		"	jsri.a [AL]\nZB", },
+
+{ UCALL,        FOREFF,
+	SBREG,   TANY,
+	SANY,   TANY,
+		0,     0,
+		"	jsri.a [AL]\nZB", },
+
+    
+{ FREE, FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	"help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
+
Index: uspace/app/pcc/arch/mips/TODO
===================================================================
--- uspace/app/pcc/arch/mips/TODO	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/mips/TODO	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,2 @@
+* Fix floating-point arguments in registers
+* Fix structure arguments in registers
Index: uspace/app/pcc/arch/mips/code.c
===================================================================
--- uspace/app/pcc/arch/mips/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/mips/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,726 @@
+/*	$Id: code.c,v 1.17 2010/09/19 14:01:35 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.
+ */
+
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+#include <assert.h>
+#include "pass1.h"
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+	static char *loctbl[] = { "text", "data", "section .rodata" };
+	static int lastloc = -1;
+	TWORD t;
+	char *n;
+	int s;
+
+	if (sp == NULL) {
+		lastloc = -1;
+		return;
+	}
+	t = sp->stype;
+	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+	lastloc = s;
+	if (s == PROG)
+		return; /* text is written in prologue() */
+	if (s != lastloc)
+		printf("	.%s\n", loctbl[s]);
+	printf("	.p2align %d\n", ispow2(talign(t, sp->sap)));
+	n = sp->soname ? sp->soname : sp->sname;
+	if (sp->sclass == EXTDEF)
+		printf("	.globl %s\n", n);
+	if (sp->slevel == 0) {
+#ifdef USE_GAS
+		printf("\t.type %s,@object\n", n);
+		printf("\t.size %s," CONFMT "\n", n,
+		    tsize(sp->stype, sp->sdf, sp->sap));
+#endif
+		printf("%s:\n", n);
+	} else
+		printf(LABFMT ":\n", sp->soffset);
+}
+
+
+#ifdef notdef
+/*
+ * cause the alignment to become a multiple of n
+ * never called for text segment.
+ */
+void
+defalign(int n)
+{
+	n = ispow2(n / SZCHAR);
+	if (n == -1)
+		cerror("defalign: n != 2^i");
+	printf("\t.p2align %d\n", n);
+}
+
+/*
+ * define the current location as the name p->sname
+ * never called for text segment.
+ */
+void
+defnam(struct symtab *p)
+{
+	char *c = p->soname;
+
+	if (p->sclass == EXTDEF)
+		printf("\t.globl %s\n", c);
+#ifdef USE_GAS
+	printf("\t.type %s,@object\n", c);
+	printf("\t.size %s," CONFMT "\n", c, tsize(p->stype, p->sdf, p->sap));
+#endif
+	printf("%s:\n", c);
+}
+#endif
+
+static int rvnr;
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode()
+{
+	NODE *p, *q;
+	int tempnr;
+	int ty;
+
+	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+		return;
+
+	ty = cftnsp->stype - FTN;
+
+	q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
+	q->n_rval = V0;
+	p = tempnode(0, INCREF(ty), 0, cftnsp->sap);
+	tempnr = regno(p);
+	p = buildtree(ASSIGN, p, q);
+	ecomp(p);
+
+	q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap);
+	q = buildtree(UMUL, q, NIL);
+
+	p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
+	p = buildtree(UMUL, p, NIL);
+
+	p = buildtree(ASSIGN, p, q);
+	ecomp(p);
+
+	q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
+	p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
+	p->n_rval = V0;
+	p = buildtree(ASSIGN, p, q);
+	ecomp(p);
+}
+
+/* Put a symbol in a temporary
+ * used by bfcode() and its helpers */
+static void
+putintemp(struct symtab *sym)
+{
+	NODE *p;
+	p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+	p = buildtree(ASSIGN, p, nametree(sym));
+	sym->soffset = regno(p->n_left);
+	sym->sflags |= STNODE;
+	ecomp(p);
+}
+
+/* setup the hidden pointer to struct return parameter
+ * used by bfcode() */
+static void
+param_retptr(void)
+{
+	NODE *p, *q;
+
+	p = tempnode(0, PTR+STRTY, 0, cftnsp->sap);
+	rvnr = regno(p);
+	q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
+	q->n_rval = A0;
+	p = buildtree(ASSIGN, p, q);
+	ecomp(p);
+}
+
+/* setup struct parameter
+ * push the registers out to memory
+ * used by bfcode() */
+static void
+param_struct(struct symtab *sym, int *regp)
+{
+	int reg = *regp;
+	NODE *p, *q;
+	int navail;
+	int sz;
+	int off;
+	int num;
+	int i;
+
+	navail = nargregs - (reg - A0);
+	sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT;
+	off = ARGINIT/SZINT + (reg - A0);
+	num = sz > navail ? navail : sz;
+	for (i = 0; i < num; i++) {
+		q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		q->n_rval = reg++;
+		p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		p->n_rval = FP;
+		p = block(PLUS, p, bcon(4*off++), INT, 0, MKAP(INT));
+		p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
+		p = buildtree(ASSIGN, p, q);
+		ecomp(p);
+	}
+
+	*regp = reg;
+}
+
+/* setup a 64-bit parameter (double/ldouble/longlong)
+ * used by bfcode() */
+static void
+param_64bit(struct symtab *sym, int *regp, int dotemps)
+{
+	int reg = *regp;
+	NODE *p, *q;
+	int navail;
+
+	/* alignment */
+	++reg;
+	reg &= ~1;
+
+	navail = nargregs - (reg - A0);
+
+	if (navail < 2) {
+		/* would have appeared half in registers/half
+		 * on the stack, but alignment ensures it
+		 * appears on the stack */
+		if (dotemps)
+			putintemp(sym);
+		*regp = reg;
+		return;
+	}
+
+	q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
+	q->n_rval = A0A1 + (reg - A0);
+	if (dotemps) {
+		p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+		sym->soffset = regno(p);
+		sym->sflags |= STNODE;
+	} else {
+		p = nametree(sym);
+	}
+	p = buildtree(ASSIGN, p, q);
+	ecomp(p);
+	*regp = reg + 2;
+}
+
+/* setup a 32-bit param on the stack
+ * used by bfcode() */
+static void
+param_32bit(struct symtab *sym, int *regp, int dotemps)
+{
+	NODE *p, *q;
+
+	q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
+	q->n_rval = (*regp)++;
+	if (dotemps) {
+		p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+		sym->soffset = regno(p);
+		sym->sflags |= STNODE;
+	} else {
+		p = nametree(sym);
+	}
+	p = buildtree(ASSIGN, p, q);
+	ecomp(p);
+}
+
+/*
+ * XXX This is a hack.  We cannot have (l)doubles in more than one
+ * register class.  So we bounce them in and out of temps to
+ * move them in and out of the right registers.
+ */
+static void
+param_double(struct symtab *sym, int *regp, int dotemps)
+{
+	int reg = *regp;
+	NODE *p, *q, *t;
+	int navail;
+	int tmpnr;
+
+	/* alignment */
+	++reg;
+	reg &= ~1;
+
+	navail = nargregs - (reg - A0);
+
+	if (navail < 2) {
+		/* would have appeared half in registers/half
+		 * on the stack, but alignment ensures it
+		 * appears on the stack */
+		if (dotemps)
+			putintemp(sym);
+		*regp = reg;
+		return;
+	}
+
+	t = tempnode(0, LONGLONG, 0, MKAP(LONGLONG));
+	tmpnr = regno(t);
+	q = block(REG, NIL, NIL, LONGLONG, 0, MKAP(LONGLONG));
+	q->n_rval = A0A1 + (reg - A0);
+	p = buildtree(ASSIGN, t, q);
+	ecomp(p);
+
+	if (dotemps) {
+		sym->soffset = tmpnr;
+		sym->sflags |= STNODE;
+	} else {
+		q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
+		p = nametree(sym);
+		p = buildtree(ASSIGN, p, q);
+		ecomp(p);
+	}
+	*regp = reg + 2;
+}
+
+/*
+ * XXX This is a hack.  We cannot have floats in more than one
+ * register class.  So we bounce them in and out of temps to
+ * move them in and out of the right registers.
+ */
+static void
+param_float(struct symtab *sym, int *regp, int dotemps)
+{
+	NODE *p, *q, *t;
+	int tmpnr;
+
+	t = tempnode(0, INT, 0, MKAP(INT));
+	tmpnr = regno(t);
+	q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+	q->n_rval = (*regp)++;
+	p = buildtree(ASSIGN, t, q);
+	ecomp(p);
+
+	if (dotemps) {
+		sym->soffset = tmpnr;
+		sym->sflags |= STNODE;
+	} else {
+		q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
+		p = nametree(sym);
+		p = buildtree(ASSIGN, p, q);
+		ecomp(p);
+	}
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **sp, int cnt)
+{
+	union arglist *usym;
+	int lastreg = A0 + nargregs - 1;
+	int saveallargs = 0;
+	int i, reg;
+
+	/*
+	 * Detect if this function has ellipses and save all
+	 * argument register onto stack.
+	 */
+	usym = cftnsp->sdf->dfun;
+	while (usym && usym->type != TNULL) {
+		if (usym->type == TELLIPSIS) {
+			saveallargs = 1;
+			break;
+		}
+		++usym;
+	}
+
+	reg = A0;
+
+	/* assign hidden return structure to temporary */
+	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+		param_retptr();
+		++reg;
+	}
+
+        /* recalculate the arg offset and create TEMP moves */
+        for (i = 0; i < cnt; i++) {
+
+		if ((reg > lastreg) && !xtemps)
+			break;
+		else if (reg > lastreg) 
+			putintemp(sp[i]);
+		else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY)
+			param_struct(sp[i], &reg);
+		else if (DEUNSIGN(sp[i]->stype) == LONGLONG)
+			param_64bit(sp[i], &reg, xtemps && !saveallargs);
+		else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE)
+			param_double(sp[i], &reg, xtemps && !saveallargs);
+		else if (sp[i]->stype == FLOAT)
+			param_float(sp[i], &reg, xtemps && !saveallargs);
+		else
+			param_32bit(sp[i], &reg, xtemps && !saveallargs);
+	}
+
+	/* if saveallargs, save the rest of the args onto the stack */
+	if (!saveallargs)
+		return;
+	while (reg <= lastreg) {
+		NODE *p, *q;
+		int off = ARGINIT/SZINT + (reg - A0);
+		q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		q->n_rval = reg++;
+		p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		p->n_rval = FP;
+		p = block(PLUS, p, bcon(4*off), INT, 0, MKAP(INT));
+		p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
+		p = buildtree(ASSIGN, p, q);
+		ecomp(p);
+	}
+
+}
+
+
+/*
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+	SETOFF(autooff, SZINT);
+}
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag )
+{
+}
+
+void
+bjobcode()
+{
+	printf("\t.section .mdebug.abi32\n");
+	printf("\t.previous\n");
+	printf("\t.abicalls\n");
+}
+
+#ifdef notdef
+/*
+ * Print character t at position i in one string, until t == -1.
+ * Locctr & label is already defined.
+ */
+void
+bycode(int t, int i)
+{
+	static int lastoctal = 0;
+
+	/* put byte i+1 in a string */
+
+	if (t < 0) {
+		if (i != 0)
+			puts("\\000\"");
+	} else {
+		if (i == 0)
+			printf("\t.ascii \"");
+		if (t == 0)
+			return;
+		else if (t == '\\' || t == '"') {
+			lastoctal = 0;
+			putchar('\\');
+			putchar(t);
+		} else if (t == 011) {
+			printf("\\t");
+		} else if (t == 012) {
+			printf("\\n");
+		} else if (t < 040 || t >= 0177) {
+			lastoctal++;
+			printf("\\%o",t);
+		} else if (lastoctal && '0' <= t && t <= '9') {
+			lastoctal = 0;
+			printf("\"\n\t.ascii \"%c", t);
+		} else {	
+			lastoctal = 0;
+			putchar(t);
+		}
+	}
+}
+#endif
+
+/*
+ * 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;
+}
+
+
+/* setup call stack with a structure */
+/* called from moveargs() */
+static NODE *
+movearg_struct(NODE *p, NODE *parent, int *regp)
+{
+	int reg = *regp;
+	NODE *l, *q, *t, *r;
+	int tmpnr;
+	int navail;
+	int off;
+	int num;
+        int sz;
+	int ty;
+	int i;
+
+	navail = nargregs - (reg - A0);
+	sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT;
+	num = sz > navail ? navail : sz;
+
+	l = p->n_left;
+	nfree(p);
+	ty = l->n_type;
+	t = tempnode(0, l->n_type, l->n_df, l->n_ap);
+	tmpnr = regno(t);
+	l = buildtree(ASSIGN, t, l);
+
+	if (p != parent) {
+		q = parent->n_left;
+	} else
+		q = NULL;
+
+	/* copy structure into registers */
+	for (i = 0; i < num; i++) {
+		t = tempnode(tmpnr, ty, 0, MKAP(PTR+ty));
+		t = block(SCONV, t, NIL, PTR+INT, 0, MKAP(PTR+INT));
+		t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKAP(PTR+INT));
+		t = buildtree(UMUL, t, NIL);
+
+		r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		r->n_rval = reg++;
+
+               	r = buildtree(ASSIGN, r, t);
+		if (q == NULL)
+			q = r;
+		else 
+			q = block(CM, q, r, INT, 0, MKAP(INT));
+	}
+	off = ARGINIT/SZINT + nargregs;
+	for (i = num; i < sz; i++) {
+		t = tempnode(tmpnr, ty, 0, MKAP(PTR+ty));
+		t = block(SCONV, t, NIL, PTR+INT, 0, MKAP(PTR+INT));
+		t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKAP(PTR+INT));
+		t = buildtree(UMUL, t, NIL);
+
+		r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		r->n_rval = FP;
+		r = block(PLUS, r, bcon(4*off++), INT, 0, MKAP(INT));
+		r = block(UMUL, r, NIL, INT, 0, MKAP(INT));
+
+               	r = buildtree(ASSIGN, r, t);
+		if (q == NULL)
+			q = r;
+		else
+			q = block(CM, q, r, INT, 0, MKAP(INT));
+	}
+
+	if (parent->n_op == CM) {
+		parent->n_left = q;
+		q = l;
+	} else {
+		q = block(CM, q, l, INT, 0, MKAP(INT));
+	}
+
+	*regp = reg;
+	return q;
+}
+
+/* setup call stack with 64-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_64bit(NODE *p, int *regp)
+{
+	int reg = *regp;
+	NODE *q;
+	int lastarg;
+
+	/* alignment */
+	++reg;
+	reg &= ~1;
+
+	lastarg = A0 + nargregs - 1;
+	if (reg > lastarg) {
+		*regp = reg;
+		return block(FUNARG, p, NIL, p->n_type, p->n_df, p->n_ap);
+	}
+
+	q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+	q->n_rval = A0A1 + (reg - A0);
+	q = buildtree(ASSIGN, q, p);
+
+	*regp = reg + 2;
+	return q;
+}
+
+/* setup call stack with 32-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_32bit(NODE *p, int *regp)
+{
+	int reg = *regp;
+	NODE *q;
+
+	q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+	q->n_rval = reg++;
+	q = buildtree(ASSIGN, q, p);
+
+	*regp = reg;
+	return q;
+}
+
+static NODE *
+moveargs(NODE *p, int *regp)
+{
+        NODE *r, **rp;
+	int lastreg;
+	int reg;
+
+        if (p->n_op == CM) {
+                p->n_left = moveargs(p->n_left, regp);
+                r = p->n_right;
+		rp = &p->n_right;
+        } else {
+		r = p;
+		rp = &p;
+	}
+
+ 	lastreg = A0 + nargregs - 1;
+        reg = *regp;
+
+	if (reg > lastreg && r->n_op != STARG)
+		*rp = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap);
+	else if (r->n_op == STARG) {
+		*rp = movearg_struct(r, p, regp);
+	} else if (DEUNSIGN(r->n_type) == LONGLONG) {
+		*rp = movearg_64bit(r, regp);
+	} else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
+		/* XXX bounce in and out of temporary to change to longlong */
+		NODE *t1 = tempnode(0, LONGLONG, 0, MKAP(LONGLONG));
+		int tmpnr = regno(t1);
+		NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
+		t1 =  movearg_64bit(t1, regp);
+		r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap);
+		if (p->n_op == CM) {
+			p->n_left = buildtree(CM, p->n_left, t1);
+			p->n_right = r;
+		} else {
+			p = buildtree(CM, t1, r);
+		}
+	} else if (r->n_type == FLOAT) {
+		/* XXX bounce in and out of temporary to change to int */
+		NODE *t1 = tempnode(0, INT, 0, MKAP(INT));
+		int tmpnr = regno(t1);
+		NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
+		t1 =  movearg_32bit(t1, regp);
+		r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap);
+		if (p->n_op == CM) {
+			p->n_left = buildtree(CM, p->n_left, t1);
+			p->n_right = r;
+		} else {
+			p = buildtree(CM, t1, r);
+		}
+	} else {
+		*rp = movearg_32bit(r, regp);
+	}
+
+	return p;
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+	int regnum = A0;
+	NODE *l, *r, *t, *q;
+	int ty;
+
+	l = p->n_left;
+	r = p->n_right;
+
+	/*
+	 * if returning a structure, make the first argument
+	 * a hidden pointer to return structure.
+	 */
+	ty = DECREF(l->n_type);
+	if (ty == STRTY+FTN || ty == UNIONTY+FTN) {
+		ty = DECREF(l->n_type) - FTN;
+		q = tempnode(0, ty, l->n_df, l->n_ap);
+		q = buildtree(ADDROF, q, NIL);
+		if (r->n_op != CM) {
+			p->n_right = block(CM, q, r, INCREF(ty),
+			    l->n_df, l->n_ap);
+		} else {
+			for (t = r; t->n_left->n_op == CM; t = t->n_left)
+				;
+			t->n_left = block(CM, q, t->n_left, INCREF(ty),
+			    l->n_df, l->n_ap);
+		}
+	}
+
+	p->n_right = moveargs(p->n_right, &regnum);
+
+	return p;
+}
Index: uspace/app/pcc/arch/mips/local.c
===================================================================
--- uspace/app/pcc/arch/mips/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/mips/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,926 @@
+/*	$Id: local.c,v 1.24 2011/01/21 21:47: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.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+#include <assert.h>
+#include "pass1.h"
+
+#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
+
+static int inbits, inval;
+
+/* this is called to do local transformations on
+ * an expression tree preparitory to its being
+ * written out in intermediate code.
+ */
+NODE *
+clocal(NODE *p)
+{
+	struct symtab *q;
+	NODE *r, *l;
+	int o;
+	int m;
+	TWORD ty;
+	int tmpnr, isptrvoid = 0;
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal in: %p\n", p);
+		fwalk(p, eprint, 0);
+	}
+#endif
+
+	switch (o = p->n_op) {
+
+	case UCALL:
+	case CALL:
+	case STCALL:
+	case USTCALL:
+		if (p->n_type == VOID)
+			break;
+		/*
+		 * if the function returns void*, ecode() invokes
+		 * delvoid() to convert it to uchar*.
+		 * We just let this happen on the ASSIGN to the temp,
+		 * and cast the pointer back to void* on access
+		 * from the temp.
+		 */
+		if (p->n_type == PTR+VOID)
+			isptrvoid = 1;
+		r = tempnode(0, p->n_type, p->n_df, p->n_ap);
+		tmpnr = regno(r);
+		r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap);
+
+		p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
+		if (isptrvoid) {
+			p = block(PCONV, p, NIL, PTR+VOID,
+			    p->n_df, MKAP(PTR+VOID));
+		}
+		p = buildtree(COMOP, r, p);
+		break;
+
+	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 = FP;
+			p = stref(block(STREF, r, p, 0, 0, 0));
+			break;
+
+		case STATIC:
+			if (q->slevel == 0)
+				break;
+			p->n_lval = 0;
+			p->n_sp = q;
+			break;
+
+		case REGISTER:
+			p->n_op = REG;
+			p->n_lval = 0;
+			p->n_rval = q->soffset;
+			break;
+
+		}
+		break;
+
+	case FUNARG:
+		/* Args smaller than int are given as int */
+		if (p->n_type != CHAR && p->n_type != UCHAR && 
+		    p->n_type != SHORT && p->n_type != USHORT)
+			break;
+		p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKAP(INT));
+		p->n_type = INT;
+		p->n_ap = MKAP(INT);
+		p->n_rval = SZINT;
+		break;
+
+	case CBRANCH:
+		l = p->n_left;
+
+		/*
+		 * Remove unnecessary conversion ops.
+		 */
+		if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
+			if (coptype(l->n_op) != BITYPE)
+				break;
+			if (l->n_right->n_op == ICON) {
+				r = l->n_left->n_left;
+				if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
+					break;
+				/* Type must be correct */
+				ty = r->n_type;
+				nfree(l->n_left);
+				l->n_left = r;
+				l->n_type = ty;
+				l->n_right->n_type = ty;
+			}
+#if 0
+			  else if (l->n_right->n_op == SCONV &&
+			    l->n_left->n_type == l->n_right->n_type) {
+				r = l->n_left->n_left;
+				nfree(l->n_left);
+				l->n_left = r;
+				r = l->n_right->n_left;
+				nfree(l->n_right);
+				l->n_right = r;
+			}
+#endif
+		}
+		break;
+
+	case PCONV:
+		/* 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 || DEUNSIGN(l->n_type) == LONGLONG) {
+			/* 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:
+		l = p->n_left;
+
+		if (p->n_type == l->n_type) {
+			nfree(p);
+			p = l;
+			break;
+		}
+
+		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);
+					p = l;
+					break;
+				}
+			}
+		}
+
+		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+		    coptype(l->n_op) == BITYPE) {
+			l->n_type = p->n_type;
+			nfree(p);
+			p = l;
+		}
+
+		if (DEUNSIGN(p->n_type) == SHORT &&
+		    DEUNSIGN(l->n_type) == SHORT) {
+			nfree(p);
+			p = l;
+		}
+
+		/* convert float/double to int before to (u)char/(u)short */
+		if ((DEUNSIGN(p->n_type) == CHAR ||
+		    DEUNSIGN(p->n_type) == SHORT) &&
+                    (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;
+			break;
+                }
+
+		/* convert (u)char/(u)short to int before float/double */
+		if  ((p->n_type == FLOAT || p->n_type == DOUBLE ||
+		    p->n_type == LDOUBLE) && (DEUNSIGN(l->n_type) == CHAR ||
+		    DEUNSIGN(l->n_type) == SHORT)) {
+			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
+			p->n_left->n_type = INT;
+			break;
+                }
+
+		o = l->n_op;
+		m = p->n_type;
+
+		if (o == ICON) {
+			CONSZ val = l->n_lval;
+
+			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
+			    switch (m) {
+			case BOOL:
+				l->n_lval = l->n_lval != 0;
+				break;
+			case CHAR:
+				l->n_lval = (char)val;
+				break;
+			case UCHAR:
+				l->n_lval = val & 0377;
+				break;
+			case SHORT:
+				l->n_lval = (short)val;
+				break;
+			case USHORT:
+				l->n_lval = val & 0177777;
+				break;
+			case ULONG:
+			case UNSIGNED:
+				l->n_lval = val & 0xffffffff;
+				break;
+			case LONG:
+			case INT:
+				l->n_lval = (int)val;
+				break;
+			case LONGLONG:
+				l->n_lval = (long long)val;
+				break;
+			case ULONGLONG:
+				l->n_lval = val;
+				break;
+			case VOID:
+				break;
+			case LDOUBLE:
+			case DOUBLE:
+			case FLOAT:
+				l->n_op = FCON;
+				l->n_dcon = val;
+				break;
+			default:
+				cerror("unknown type %d", m);
+			}
+			l->n_type = m;
+			nfree(p);
+			p = l;
+		} else if (o == FCON) {
+			l->n_lval = l->n_dcon;
+			l->n_sp = NULL;
+			l->n_op = ICON;
+			l->n_type = m;
+			l->n_ap = MKAP(m);
+			nfree(p);
+			p = clocal(l);
+		}
+		break;
+
+	case MOD:
+	case DIV:
+		if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
+			break;
+		if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
+			break;
+		/* make it an int division by inserting conversions */
+		p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 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:
+                if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
+                nfree(p);
+                p = buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right);
+		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 = RETREG(p->n_type);
+		break;
+	}
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal out: %p\n", p);
+		fwalk(p, eprint, 0);
+	}
+#endif
+
+	return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+	struct symtab *sp;
+
+	if (p->n_op != FCON) 
+		return;
+
+	/* Write float constants to memory */
+ 
+	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;
+}
+
+/*
+ * is an automatic variable of type t OK for a register variable
+ */
+int
+cisreg(TWORD t)
+{
+	if (t == INT || t == UNSIGNED || t == LONG || t == ULONG)
+		return(1);
+	return 0; /* XXX - fix reg assignment in pftn.c */
+}
+
+/*
+ * return a node, for structure references, which is suitable for
+ * being added to a pointer of type t, in order to be off bits offset
+ * into a structure
+ * t, d, and s are the type, dimension offset, and sizeoffset
+ * 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 *sue)
+{
+	NODE *p;
+
+	if (xdebug)
+		printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
+		    off, t, d, 0);
+
+	p = bcon(off/SZCHAR);
+	return p;
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a NAME node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+	NODE *sp;
+	int nbytes = off / SZCHAR;
+
+	p = buildtree(MUL, p, bcon(nbytes));
+	p = buildtree(PLUS, p, bcon(7));
+	p = buildtree(AND, p, bcon(~7));
+
+	/* subtract the size from sp */
+	sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+	sp->n_lval = 0;
+	sp->n_rval = SP;
+	ecomp(buildtree(MINUSEQ, sp, p));
+
+	/* save the address of sp */
+	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap);
+	sp->n_rval = SP;
+	t->n_type = sp->n_type;
+	ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+}
+
+/*
+ * print out a constant node
+ * mat be associated with a label
+ */
+void
+ninval(CONSZ off, int fsz, NODE *p)
+{
+        union { float f; double d; int i[2]; } u;
+        struct symtab *q;
+        TWORD t;
+#ifndef USE_GAS
+        int i, j;
+#endif
+
+        t = p->n_type;
+        if (t > BTMASK)
+                t = INT; /* pointer */
+
+        if (p->n_op != ICON && p->n_op != FCON)
+                cerror("ninval: init node not constant");
+
+        if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
+                uerror("element not constant");
+
+        switch (t) {
+        case LONGLONG:
+        case ULONGLONG:
+#ifdef USE_GAS
+                printf("\t.dword %lld\n", (long long)p->n_lval);
+#else
+                i = p->n_lval >> 32;
+                j = p->n_lval & 0xffffffff;
+                p->n_type = INT;
+		if (bigendian) {
+			p->n_lval = j;
+	                ninval(off, 32, p);
+			p->n_lval = i;
+			ninval(off+32, 32, p);
+		} else {
+			p->n_lval = i;
+	                ninval(off, 32, p);
+			p->n_lval = j;
+			ninval(off+32, 32, p);
+		}
+#endif
+                break;
+        case BOOL:
+                if (p->n_lval > 1)
+                        p->n_lval = p->n_lval != 0;
+                /* FALLTHROUGH */
+        case INT:
+        case UNSIGNED:
+                printf("\t.word " CONFMT, (CONSZ)p->n_lval);
+                if ((q = p->n_sp) != NULL) {
+                        if ((q->sclass == STATIC && q->slevel > 0)) {
+                                printf("+" LABFMT, q->soffset);
+                        } else
+                                printf("+%s",
+				    q->soname ? q->soname : exname(q->sname));
+                }
+                printf("\n");
+                break;
+        case SHORT:
+        case USHORT:
+                printf("\t.half %d\n", (int)p->n_lval & 0xffff);
+                break;
+        case CHAR:
+        case UCHAR:
+                printf("\t.byte %d\n", (int)p->n_lval & 0xff);
+                break;
+        case LDOUBLE:
+        case DOUBLE:
+                u.d = (double)p->n_dcon;
+		if (bigendian) {
+	                printf("\t.word\t%d\n", u.i[0]);
+			printf("\t.word\t%d\n", u.i[1]);
+		} else {
+			printf("\t.word\t%d\n", u.i[1]);
+	                printf("\t.word\t%d\n", u.i[0]);
+		}
+                break;
+        case FLOAT:
+                u.f = (float)p->n_dcon;
+                printf("\t.word\t0x%x\n", u.i[0]);
+                break;
+        default:
+                cerror("ninval");
+        }
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+	if (p == NULL)
+		return "";
+	return p;
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+	switch (BTYPE(type)) {
+	case LONG:
+		MODTYPE(type,INT);
+		break;
+
+	case ULONG:
+		MODTYPE(type,UNSIGNED);
+
+	}
+	return (type);
+}
+
+/* curid is a variable which is defined but
+ * is not initialized (and not a function );
+ * This routine returns the storage class for an uninitialized declaration
+ */
+int
+noinit(void)
+{
+	return(EXTERN);
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+/*
+ * Print out a string of characters.
+ * Assume that the assembler understands C-style escape
+ * sequences.
+ */
+void
+instring(struct symtab *sp)
+{
+	char *s, *str;
+
+	defloc(sp);
+	str = sp->sname;
+
+	/* 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");
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+	int off;
+
+	off = tsize(sp->stype, sp->sdf, sp->sap);
+	off = (off+(SZCHAR-1))/SZCHAR;
+	printf("	.%scomm ", sp->sclass == STATIC ? "l" : "");
+	if (sp->slevel == 0)
+		printf("%s,0%o\n", sp->soname ? sp->soname : exname(sp->sname), off);
+	else
+		printf(LABFMT ",0%o\n", sp->soffset, off);
+}
+
+
+#ifdef notdef
+/* make a common declaration for id, if reasonable */
+void
+commdec(struct symtab *q)
+{
+	int off;
+
+	off = tsize(q->stype, q->sdf, q->ssue);
+	off = (off+(SZCHAR-1))/SZCHAR;
+
+	printf("	.comm %s,%d\n", exname(q->soname), off);
+}
+
+/* make a local common declaration for id, if reasonable */
+void
+lcommdec(struct symtab *q)
+{
+	int off;
+
+	off = tsize(q->stype, q->sdf, q->ssue);
+	off = (off+(SZCHAR-1))/SZCHAR;
+	if (q->slevel == 0)
+		printf("\t.lcomm %s,%d\n", exname(q->soname), off);
+	else
+		printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off);
+}
+
+/*
+ * print a (non-prog) label.
+ */
+void
+deflab1(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+/* ro-text, rw-data, ro-data, ro-strings */
+static char *loctbl[] = { "text", "data", "rdata", "rdata" };
+
+void
+setloc1(int locc)
+{
+	if (locc == lastloc && locc != STRNG)
+		return;
+	if (locc == RDATA && lastloc == STRNG)
+		return;
+
+	if (locc != lastloc) {
+		lastloc = locc;
+		printf("\t.%s\n", loctbl[locc]);
+	}
+
+	if (locc == STRNG)
+		printf("\t.align 2\n");
+}
+#endif
+
+/*
+ * Initialize a bitfield.
+ */
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+        if (idebug)
+                printf("infld off %lld, fsz %d, val %lld inbits %d\n",
+                    off, fsz, val, inbits);
+        val &= (1 << fsz)-1;
+        while (fsz + inbits >= SZCHAR) {
+                inval |= (val << inbits);
+                printf("\t.byte %d\n", inval & 255);
+                fsz -= (SZCHAR - inbits);
+                val >>= (SZCHAR - inbits);
+                inval = inbits = 0;
+        }
+        if (fsz) {
+                inval |= (val << inbits);
+                inbits += fsz;
+        }
+}
+
+/*
+ * set fsz bits in sequence to zero.
+ */
+void
+zbits(OFFSZ off, int fsz)
+{
+        int m;
+
+        if (idebug)
+                printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
+        if ((m = (inbits % SZCHAR))) {
+                m = SZCHAR - m;
+                if (fsz < m) {
+                        inbits += fsz;
+                        return;
+                } else {
+                        fsz -= m;
+                        printf("\t.byte %d\n", inval);
+                        inval = inbits = 0;
+                }
+        }
+        if (fsz >= SZCHAR) {
+                printf("\t.zero %d\n", fsz/SZCHAR);
+                fsz -= (fsz/SZCHAR) * SZCHAR;
+        }
+        if (fsz) {
+                inval = 0;
+                inbits = fsz;
+        }
+}
+
+/*
+ * va_start(ap, last) implementation.
+ *
+ * f is the NAME node for this builtin function.
+ * a is the argument list containing:
+ *	   CM
+ *	ap   last
+ *
+ * It turns out that this is easy on MIPS.  Just write the
+ * argument registers to the stack in va_arg_start() and
+ * use the traditional method of walking the stackframe.
+ */
+NODE *
+mips_builtin_stdarg_start(NODE *f, NODE *a, TWORD t)
+{
+	NODE *p, *q;
+	int sz = 1;
+
+	/* check num args and type */
+	if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+	    !ISPTR(a->n_left->n_type))
+		goto bad;
+
+	/* must first deal with argument size; use int size */
+	p = a->n_right;
+	if (p->n_type < INT) {
+		/* round up to word */
+		sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap);
+	}
+
+	p = buildtree(ADDROF, p, NIL);	/* address of last arg */
+	p = optim(buildtree(PLUS, p, bcon(sz)));
+	q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
+	q = buildtree(CAST, q, p);
+	p = q->n_right;
+	nfree(q->n_left);
+	nfree(q);
+	p = buildtree(ASSIGN, a->n_left, p);
+	tfree(f);
+	nfree(a);
+
+	return p;
+
+bad:
+	uerror("bad argument to __builtin_stdarg_start");
+	return bcon(0);
+}
+
+NODE *
+mips_builtin_va_arg(NODE *f, NODE *a, TWORD t)
+{
+	NODE *p, *q, *r;
+	int sz, tmpnr;
+
+	/* check num args and type */
+	if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+	    !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
+		goto bad;
+
+	r = a->n_right;
+
+	/* get type size */
+	sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
+	if (sz < SZINT/SZCHAR) {
+		werror("%s%s promoted to int when passed through ...",
+			r->n_type & 1 ? "unsigned " : "",
+			DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
+		sz = SZINT/SZCHAR;
+	}
+
+	/* alignment */
+	p = tcopy(a->n_left);
+	if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
+		p = buildtree(PLUS, p, bcon(7));
+		p = block(AND, p, bcon(-8), p->n_type, p->n_df, p->n_ap);
+	}
+
+	/* create a copy to a temp node */
+	q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+	tmpnr = regno(q);
+	p = buildtree(ASSIGN, q, p);
+
+	q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap);
+	q = buildtree(PLUS, q, bcon(sz));
+	q = buildtree(ASSIGN, a->n_left, q);
+
+	q = buildtree(COMOP, p, q);
+
+	nfree(a->n_right);
+	nfree(a);
+	nfree(f); 
+
+	p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
+	p = buildtree(UMUL, p, NIL);
+	p = buildtree(COMOP, q, p);
+
+	return p;
+
+bad:
+	uerror("bad argument to __builtin_va_arg");
+	return bcon(0);
+}
+
+NODE *
+mips_builtin_va_end(NODE *f, NODE *a, TWORD t)
+{
+	tfree(f);
+	tfree(a);
+	return bcon(0);
+}
+
+NODE *
+mips_builtin_va_copy(NODE *f, NODE *a, TWORD t)
+{
+	if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
+		goto bad;
+	tfree(f);
+	f = buildtree(ASSIGN, a->n_left, a->n_right);
+	nfree(a);
+	return f;
+
+bad:
+	uerror("bad argument to __buildtin_va_copy");
+	return bcon(0);
+}
+
+static int constructor;
+static int destructor;
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+
+	if (strcmp(str, "tls") == 0) { 
+		uerror("thread-local storage not supported for this target");
+		return 1;
+	} 
+	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;
+	}
+
+	return 0;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+	if ((constructor || destructor) && (sp->sclass != PARAM)) {
+		printf("\t.section .%ctors,\"aw\",@progbits\n",
+		    constructor ? 'c' : 'd');
+		printf("\t.p2align 2\n");
+		printf("\t.long %s\n", exname(sp->sname));
+		printf("\t.previous\n");
+		constructor = destructor = 0;
+	}
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
Index: uspace/app/pcc/arch/mips/local2.c
===================================================================
--- uspace/app/pcc/arch/mips/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/mips/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1329 @@
+/*	$Id: local2.c,v 1.25 2008/12/03 22:23:38 gmcgarry Exp $	 */
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "pass1.h"
+#include "pass2.h"
+
+#ifdef TARGET_BIG_ENDIAN
+int bigendian = 1;
+#else
+int bigendian = 0;
+#endif
+
+int nargregs = MIPS_O32_NARGREGS;
+
+static int argsiz(NODE *p);
+
+void
+deflab(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+static int regoff[32];
+static TWORD ftype;
+
+/*
+ * calculate stack size and offsets
+ */
+static int
+offcalc(struct interpass_prolog * ipp)
+{
+	int i, j, addto;
+
+	addto = p2maxautooff;
+
+	for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++) {
+		if (i & 1) {
+			addto += SZINT / SZCHAR;
+			regoff[j] = addto;
+		}
+	}
+
+        /* round to 8-byte boundary */
+        addto += 7;
+        addto &= ~7;
+
+	return addto;
+}
+
+/*
+ * Print out the prolog assembler.
+ */
+void
+prologue(struct interpass_prolog * ipp)
+{
+	int addto;
+	int i, j;
+
+	ftype = ipp->ipp_type;
+	printf("\t.align 2\n");
+	if (ipp->ipp_vis)
+		printf("\t.globl %s\n", ipp->ipp_name);
+	printf("\t.ent %s\n", ipp->ipp_name);
+	printf("%s:\n", ipp->ipp_name);
+
+	addto = offcalc(ipp);
+
+	/* for the moment, just emit this PIC stuff - NetBSD does it */
+	printf("\t.frame %s,%d,%s\n", rnames[FP], ARGINIT/SZCHAR, rnames[RA]);
+	printf("\t.set noreorder\n");
+	printf("\t.cpload $25\t# pseudo-op to load GOT ptr into $25\n");
+	printf("\t.set reorder\n");
+
+	printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], ARGINIT/SZCHAR);
+	/* for the moment, just emit PIC stuff - NetBSD does it */
+	printf("\t.cprestore 8\t# pseudo-op to store GOT ptr at 8(sp)\n");
+
+	printf("\tsw %s,4(%s)\n", rnames[RA], rnames[SP]);
+	printf("\tsw %s,(%s)\n", rnames[FP], rnames[SP]);
+	printf("\tmove %s,%s\n", rnames[FP], rnames[SP]);
+
+#ifdef notyet
+	/* profiling */
+	if (pflag) {
+		printf("\t.set noat\n");
+		printf("\tmove %s,%s\t# save current return address\n",
+		    rnames[AT], rnames[RA]);
+		printf("\tsubu %s,%s,8\t# _mcount pops 2 words from stack\n",
+		    rnames[SP], rnames[SP]);
+		printf("\tjal %s\n", exname("_mcount"));
+		printf("\tnop\n");
+		printf("\t.set at\n");
+	}
+#endif
+
+	if (addto)
+		printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], addto);
+
+	for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++)
+		if (i & 1)
+			fprintf(stdout, "\tsw %s,-%d(%s) # save permanent\n",
+				rnames[j], regoff[j], rnames[FP]);
+
+}
+
+void
+eoftn(struct interpass_prolog * ipp)
+{
+	int i, j;
+	int addto;
+
+	addto = offcalc(ipp);
+
+	if (ipp->ipp_ip.ip_lbl == 0)
+		return;		/* no code needs to be generated */
+
+	/* return from function code */
+	for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++) {
+		if (i & 1)
+			fprintf(stdout, "\tlw %s,-%d(%s)\n\tnop\n",
+				rnames[j], regoff[j], rnames[FP]);
+	}
+
+	printf("\taddiu %s,%s,%d\n", rnames[SP], rnames[FP], ARGINIT/SZCHAR);
+	printf("\tlw %s,%d(%s)\n", rnames[RA], 4-ARGINIT/SZCHAR,  rnames[SP]);
+	printf("\tlw %s,%d(%s)\n", rnames[FP], 0-ARGINIT/SZCHAR,  rnames[SP]);
+
+	printf("\tjr %s\n", rnames[RA]);
+	printf("\tnop\n");
+
+#ifdef USE_GAS
+	printf("\t.end %s\n", ipp->ipp_name);
+	printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name);
+#endif
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+	char *str;
+
+	switch (o) {
+	case EQ:
+		str = "beqz";	/* pseudo-op */
+		break;
+	case NE:
+		str = "bnez";	/* pseudo-op */
+		break;
+	case ULE:
+	case LE:
+		str = "blez";
+		break;
+	case ULT:
+	case LT:
+		str = "bltz";
+		break;
+	case UGE:
+	case GE:
+		str = "bgez";
+		break;
+	case UGT:
+	case GT:
+		str = "bgtz";
+		break;
+	case PLUS:
+		str = "add";
+		break;
+	case MINUS:
+		str = "sub";
+		break;
+	case AND:
+		str = "and";
+		break;
+	case OR:
+		str = "or";
+		break;
+	case ER:
+		str = "xor";
+		break;
+	default:
+		comperr("hopcode2: %d", o);
+		str = 0;	/* XXX gcc */
+	}
+
+	printf("%s%c", str, f);
+}
+
+char *
+rnames[] = {
+#ifdef USE_GAS
+	/* gnu assembler */
+	"$zero", "$at", "$2", "$3", "$4", "$5", "$6", "$7",
+	"$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
+	"$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
+	"$24", "$25",
+	"$kt0", "$kt1", "$gp", "$sp", "$fp", "$ra",
+	"$2!!$3!!",
+	"$4!!$5!!", "$5!!$6!!", "$6!!$7!!", "$7!!$8!!",
+	"$8!!$9!!", "$9!!$10!", "$10!$11!", "$11!$12!",
+	"$12!$13!", "$13!$14!", "$14!$15!", "$15!$24!", "$24!$25!",
+	"$16!$17!", "$17!$18!", "$18!$19!", "$19!$20!",
+	"$20!$21!", "$21!$22!", "$22!$23!",
+#else
+	/* mips assembler */
+	 "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
+	"$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
+	"$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
+	"$t8", "$t9",
+	"$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
+	"$v0!$v1!",
+	"$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$t0!",
+	"$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t4!",
+	"$t4!$t5!", "$t5!$t6!", "$t6!$t7!", "$t7!$t8!", "$t8!$t9!",
+	"$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!",
+	"$s4!$s5!", "$s5!$s6!", "$s6!$s7!",
+#endif
+	"$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!",
+	"$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15",
+	"$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23",
+	"$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31",
+};
+
+char *
+rnames_n32[] = {
+	/* mips assembler */
+	"$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
+	"$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3",
+	"$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
+	"$t8", "$t9",
+	"$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
+	"$v0!$v1!",
+	"$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$a4!",
+	"$a4!$a5!", "$a5!$a6!", "$a6!$a7!", "$a7!$t0!",
+	"$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t8!", "$t8!$t9!",
+	"$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!",
+	"$s4!$s5!", "$s5!$s6!", "$s6!$s7!",
+	"$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!",
+	"$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15",
+	"$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23",
+	"$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31",
+};
+
+int
+tlen(NODE *p)
+{
+	switch (p->n_type) {
+	case CHAR:
+	case UCHAR:
+		return (1);
+
+	case SHORT:
+	case USHORT:
+		return (SZSHORT / SZCHAR);
+
+	case DOUBLE:
+		return (SZDOUBLE / SZCHAR);
+
+	case INT:
+	case UNSIGNED:
+	case LONG:
+	case ULONG:
+		return (SZINT / SZCHAR);
+
+	case LONGLONG:
+	case ULONGLONG:
+		return SZLONGLONG / SZCHAR;
+
+	default:
+		if (!ISPTR(p->n_type))
+			comperr("tlen type %d not pointer");
+		return SZPOINT(p->n_type) / SZCHAR;
+	}
+}
+
+
+/*
+ * Push a structure on stack as argument.
+ */
+static void
+starg(NODE *p)
+{
+	//assert(p->n_rval == A1);
+	printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], p->n_stsize);
+	/* A0 = dest, A1 = src, A2 = len */
+	printf("\tmove %s,%s\n", rnames[A0], rnames[SP]);
+	printf("\tli %s,%d\t# structure size\n", rnames[A2], p->n_stsize);
+	printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
+	printf("\tjal %s\t# structure copy\n", exname("memcpy"));
+	printf("\tnop\n");
+	printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
+}
+
+/*
+ * Structure assignment.
+ */
+static void
+stasg(NODE *p)
+{
+	assert(p->n_right->n_rval == A1);
+	/* A0 = dest, A1 = src, A2 = len */
+	printf("\tli %s,%d\t# structure size\n", rnames[A2], p->n_stsize);
+	if (p->n_left->n_op == OREG) {
+		printf("\taddiu %s,%s," CONFMT "\t# dest address\n",
+		    rnames[A0], rnames[p->n_left->n_rval],
+		    p->n_left->n_lval);
+	} else if (p->n_left->n_op == NAME) {
+		printf("\tla %s,", rnames[A0]);
+		adrput(stdout, p->n_left);
+		printf("\n");
+	}
+	printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
+	printf("\tjal %s\t# structure copy\n", exname("memcpy"));
+	printf("\tnop\n");
+	printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
+}
+
+static void
+shiftop(NODE *p)
+{
+	NODE *r = p->n_right;
+	TWORD ty = p->n_type;
+
+	if (p->n_op == LS && r->n_op == ICON && r->n_lval < 32) {
+		expand(p, INBREG, "\tsrl A1,AL,");
+		printf(CONFMT "\t# 64-bit left-shift\n", 32 - r->n_lval);
+		expand(p, INBREG, "\tsll U1,UL,AR\n");
+		expand(p, INBREG, "\tor U1,U1,A1\n");
+		expand(p, INBREG, "\tsll A1,AL,AR\n");
+	} else if (p->n_op == LS && r->n_op == ICON && r->n_lval < 64) {
+		expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n");
+		expand(p, INBREG, "\tsll U1,AL,");
+		printf(CONFMT "\n", r->n_lval - 32);
+	} else if (p->n_op == LS && r->n_op == ICON) {
+		expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n");
+		expand(p, INBREG, "\tli U1,0\n");
+	} else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 32) {
+		expand(p, INBREG, "\tsll U1,UL,");
+		printf(CONFMT "\t# 64-bit right-shift\n", 32 - r->n_lval);
+		expand(p, INBREG, "\tsrl A1,AL,AR\n");
+		expand(p, INBREG, "\tor A1,A1,U1\n");
+		if (ty == LONGLONG)
+			expand(p, INBREG, "\tsra U1,UL,AR\n");
+		else
+			expand(p, INBREG, "\tsrl U1,UL,AR\n");
+	} else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 64) {
+		if (ty == LONGLONG) {
+			expand(p, INBREG, "\tsra U1,UL,31\t# 64-bit right-shift\n");
+			expand(p, INBREG, "\tsra A1,UL,");
+		}else {
+			expand(p, INBREG, "\tli U1,0\t# 64-bit right-shift\n");
+			expand(p, INBREG, "\tsrl A1,UL,");
+		}
+		printf(CONFMT "\n", r->n_lval - 32);
+	} else if (p->n_op == LS && r->n_op == ICON) {
+		expand(p, INBREG, "\tli A1,0\t# 64-bit right-shift\n");
+		expand(p, INBREG, "\tli U1,0\n");
+	} else {
+		comperr("shiftop");
+	}
+}
+
+/*
+ * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
+ */
+static void
+fpemulop(NODE *p)
+{
+	NODE *l = p->n_left;
+	char *ch = NULL;
+
+	if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3";
+	else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3";
+	else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3";
+
+	else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3";
+	else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3";
+	else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3";
+
+	else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3";
+	else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3";
+	else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3";
+
+	else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3";
+	else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3";
+	else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3";
+
+	else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2";
+	else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2";
+	else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2";
+
+	else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2";
+	else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2";
+	else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2";
+
+	else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2";
+	else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2";
+	else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2";
+
+	else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2";
+	else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2";
+	else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2";
+
+	else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2";
+	else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2";
+	else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2";
+
+	else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2";
+	else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2";
+	else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2";
+
+	else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2";
+	else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2";
+	else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2";
+
+	else if (p->n_op == SCONV && p->n_type == FLOAT) {
+		if (l->n_type == DOUBLE) ch = "truncdfsf2";
+		else if (l->n_type == LDOUBLE) ch = "trunctfsf2";
+		else if (l->n_type == ULONGLONG) ch = "floatdisf"; /**/
+		else if (l->n_type == LONGLONG) ch = "floatdisf";
+		else if (l->n_type == LONG) ch = "floatsisf";
+		else if (l->n_type == ULONG) ch = "floatunsisf";
+		else if (l->n_type == INT) ch = "floatsisf";
+		else if (l->n_type == UNSIGNED) ch = "floatunsisf";
+	} else if (p->n_op == SCONV && p->n_type == DOUBLE) {
+		if (l->n_type == FLOAT) ch = "extendsfdf2";
+		else if (l->n_type == LDOUBLE) ch = "trunctfdf2";
+		else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+		else if (l->n_type == LONGLONG) ch = "floatdidf";
+		else if (l->n_type == LONG) ch = "floatsidf";
+		else if (l->n_type == ULONG) ch = "floatunsidf";
+		else if (l->n_type == INT) ch = "floatsidf";
+		else if (l->n_type == UNSIGNED) ch = "floatunsidf";
+	} else if (p->n_op == SCONV && p->n_type == LDOUBLE) {
+		if (l->n_type == FLOAT) ch = "extendsftf2";
+		else if (l->n_type == DOUBLE) ch = "extenddfdf2";
+		else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+		else if (l->n_type == LONGLONG) ch = "floatdidf";
+		else if (l->n_type == LONG) ch = "floatsidf";
+		else if (l->n_type == ULONG) ch = "floatunssidf";
+		else if (l->n_type == INT) ch = "floatsidf";
+		else if (l->n_type == UNSIGNED) ch = "floatunsidf";
+	} else if (p->n_op == SCONV && p->n_type == ULONGLONG) {
+		if (l->n_type == FLOAT) ch = "fixunssfdi";
+		else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
+		else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
+	} else if (p->n_op == SCONV && p->n_type == LONGLONG) {
+		if (l->n_type == FLOAT) ch = "fixsfdi";
+		else if (l->n_type == DOUBLE) ch = "fixdfdi";
+		else if (l->n_type == LDOUBLE) ch = "fixdfdi";
+	} else if (p->n_op == SCONV && p->n_type == LONG) {
+		if (l->n_type == FLOAT) ch = "fixsfsi";
+		else if (l->n_type == DOUBLE) ch = "fixdfsi";
+		else if (l->n_type == LDOUBLE) ch = "fixdfsi";
+	} else if (p->n_op == SCONV && p->n_type == ULONG) {
+		if (l->n_type == FLOAT) ch = "fixunssfsi";
+		else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
+		else if (l->n_type == LDOUBLE) ch = "fixunsdfsi";
+	} else if (p->n_op == SCONV && p->n_type == INT) {
+		if (l->n_type == FLOAT) ch = "fixsfsi";
+		else if (l->n_type == DOUBLE) ch = "fixdfsi";
+		else if (l->n_type == LDOUBLE) ch = "fixdfsi";
+	} else if (p->n_op == SCONV && p->n_type == UNSIGNED) {
+		if (l->n_type == FLOAT) ch = "fixunssfsi";
+		else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
+		else if (l->n_type == LDOUBLE) ch = "fixunsdfsi";
+	}
+
+	if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op);
+
+	if (p->n_op == SCONV) {
+		if (l->n_type == FLOAT) {
+			printf("\tmfc1 %s,", rnames[A0]);
+			adrput(stdout, l);
+			printf("\n\tnop\n");
+		}  else if (l->n_type == DOUBLE || l->n_type == LDOUBLE) {
+			printf("\tmfc1 %s,", rnames[A1]);
+			upput(l, 0);
+			printf("\n\tnop\n");
+			printf("\tmfc1 %s,", rnames[A0]);
+			adrput(stdout, l);
+			printf("\n\tnop\n");
+		}
+	} else {
+		comperr("ZF: incomplete softfloat - put args in registers");
+	}
+
+	printf("\tjal __%s\t# softfloat operation\n", exname(ch));
+	printf("\tnop\n");
+
+	if (p->n_op >= EQ && p->n_op <= GT)
+		printf("\tcmp %s,0\n", rnames[V0]);
+}
+
+/*
+ * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
+ */
+static void
+emulop(NODE *p)
+{
+	char *ch = NULL;
+
+	if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3";
+	else if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG ||
+	    DEUNSIGN(p->n_type) == INT))
+		ch = "ashlsi3";
+
+	else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3";
+	else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == INT))
+		ch = "lshrsi3";
+
+	else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3";
+	else if (p->n_op == RS && (p->n_type == LONG || p->n_type == INT))
+		ch = "ashrsi3";
+	
+	else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3";
+	else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == INT))
+		ch = "divsi3";
+
+	else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3";
+	else if (p->n_op == DIV && (p->n_type == ULONG ||
+	    p->n_type == UNSIGNED))
+		ch = "udivsi3";
+
+	else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3";
+	else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == INT))
+		ch = "modsi3";
+
+	else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3";
+	else if (p->n_op == MOD && (p->n_type == ULONG ||
+	    p->n_type == UNSIGNED))
+		ch = "umodsi3";
+
+	else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3";
+	else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == INT))
+		ch = "mulsi3";
+
+	else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2";
+	else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2";
+
+	else ch = 0, comperr("ZE");
+	printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
+	printf("\tjal __%s\t# emulated operation\n", exname(ch));
+	printf("\tnop\n");
+	printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+	int o = p->n_op;
+	int s = getlab2();
+	int e = p->n_label;
+	int cb1, cb2;
+
+	if (o >= ULE)
+		o -= (ULE-LE);
+	switch (o) {
+	case NE:
+		cb1 = 0;
+		cb2 = NE;
+		break;
+	case EQ:
+		cb1 = NE;
+		cb2 = 0;
+		break;
+	case LE:
+	case LT:
+		cb1 = GT;
+		cb2 = LT;
+		break;
+	case GE:
+	case GT:
+		cb1 = LT;
+		cb2 = GT;
+		break;
+	
+	default:
+		cb1 = cb2 = 0; /* XXX gcc */
+	}
+	if (p->n_op >= ULE)
+		cb1 += 4, cb2 += 4;
+	expand(p, 0, "\tsub A1,UL,UR\t# compare 64-bit values (upper)\n");
+	if (cb1) {
+		printf("\t");
+		hopcode(' ', cb1);
+		expand(p, 0, "A1");
+		printf("," LABFMT "\n", s);
+		printf("\tnop\n");
+	}
+	if (cb2) {
+		printf("\t");
+		hopcode(' ', cb2);
+		expand(p, 0, "A1");
+		printf("," LABFMT "\n", e);
+		printf("\tnop\n");
+	}
+	expand(p, 0, "\tsub A1,AL,AR\t# (and lower)\n");
+	printf("\t");
+	hopcode(' ', o);
+	expand(p, 0, "A1");
+	printf("," LABFMT "\n", e);
+	printf("\tnop\n");
+	deflab(s);
+}
+
+static void
+fpcmpops(NODE *p)
+{
+	NODE *l = p->n_left;
+
+	switch (p->n_op) {
+	case EQ:
+		if (l->n_type == FLOAT)
+			expand(p, 0, "\tc.eq.s AL,AR\n");
+		else
+			expand(p, 0, "\tc.eq.d AL,AR\n");
+		expand(p, 0, "\tnop\n\tbc1t LC\n");
+		break;
+	case NE:
+		if (l->n_type == FLOAT)
+			expand(p, 0, "\tc.eq.s AL,AR\n");
+		else
+			expand(p, 0, "\tc.eq.d AL,AR\n");
+		expand(p, 0, "\tnop\n\tbc1f LC\n");
+		break;
+	case LT:
+		if (l->n_type == FLOAT)
+			expand(p, 0, "\tc.lt.s AL,AR\n");
+		else
+			expand(p, 0, "\tc.lt.d AL,AR\n");
+		expand(p, 0, "\tnop\n\tbc1t LC\n");
+		break;
+	case GE:
+		if (l->n_type == FLOAT)
+			expand(p, 0, "\tc.lt.s AL,AR\n");
+		else
+			expand(p, 0, "\tc.lt.d AL,AR\n");
+		expand(p, 0, "\tnop\n\tbc1f LC\n");
+		break;
+	case LE:
+		if (l->n_type == FLOAT)
+			expand(p, 0, "\tc.le.s AL,AR\n");
+		else
+			expand(p, 0, "\tc.le.d AL,AR\n");
+		expand(p, 0, "\tnop\n\tbc1t LC\n");
+		break;
+	case GT:
+		if (l->n_type == FLOAT)
+			expand(p, 0, "\tc.le.s AL,AR\n");
+		else
+			expand(p, 0, "\tc.le.d AL,AR\n");
+		expand(p, 0, "\tnop\n\tbc1f LC\n");
+		break;
+	}
+	printf("\tnop\n\tnop\n");
+}
+
+void
+zzzcode(NODE * p, int c)
+{
+	int sz;
+
+	switch (c) {
+
+	case 'C':	/* remove arguments from stack after subroutine call */
+		sz = p->n_qual > 16 ? p->n_qual : 16;
+		printf("\taddiu %s,%s,%d\n", rnames[SP], rnames[SP], sz);
+		break;
+
+	case 'D':	/* long long comparison */
+		twollcomp(p);
+		break;
+
+	case 'E':	/* emit emulated ops */
+		emulop(p);
+		break;
+
+	case 'F':	/* emit emulate floating point ops */
+		fpemulop(p);
+		break;
+
+	case 'G':	/* emit hardware floating-point compare op */
+		fpcmpops(p);
+		break;
+
+	case 'H':	/* structure argument */
+		starg(p);
+		break;
+
+	case 'I':		/* high part of init constant */
+		if (p->n_name[0] != '\0')
+			comperr("named highword");
+		fprintf(stdout, CONFMT, (p->n_lval >> 32) & 0xffffffff);
+		break;
+
+        case 'O': /* 64-bit left and right shift operators */
+		shiftop(p);
+		break;
+
+	case 'Q':		/* emit struct assign */
+		stasg(p);
+		break;
+
+	default:
+		comperr("zzzcode %c", c);
+	}
+}
+
+/* ARGSUSED */
+int
+rewfld(NODE * p)
+{
+	return (1);
+}
+
+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;
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE * p)
+{
+	int o = p->n_op;
+
+	if (o == OREG || o == REG || o == NAME)
+		return SRDIR;	/* Direct match */
+	if (o == UMUL && shumul(p->n_left, SOREG))
+		return SROREG;	/* Convert into oreg */
+	return SRREG;		/* put it into a register */
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+/* XXX should this go away now? */
+int
+shtemp(NODE * p)
+{
+	return 0;
+#if 0
+	int r;
+
+	if (p->n_op == STARG)
+		p = p->n_left;
+
+	switch (p->n_op) {
+	case REG:
+		return (!istreg(p->n_rval));
+
+	case OREG:
+		r = p->n_rval;
+		if (R2TEST(r)) {
+			if (istreg(R2UPK1(r)))
+				return (0);
+			r = R2UPK2(r);
+		}
+		return (!istreg(r));
+
+	case UMUL:
+		p = p->n_left;
+		return (p->n_op != UMUL && shtemp(p));
+	}
+
+	if (optype(p->n_op) != LTYPE)
+		return (0);
+	return (1);
+#endif
+}
+
+void
+adrcon(CONSZ val)
+{
+	printf(CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+	int val = p->n_lval;
+
+	switch (p->n_op) {
+	case ICON:
+		if (p->n_name[0] != '\0') {
+			fprintf(fp, "%s", p->n_name);
+			if (p->n_lval)
+				fprintf(fp, "+%d", val);
+		} else
+			fprintf(fp, "%d", val);
+		return;
+
+	default:
+		comperr("illegal conput");
+	}
+}
+
+/* ARGSUSED */
+void
+insput(NODE * p)
+{
+	comperr("insput");
+}
+
+/*
+ * Print lower or upper name of 64-bit register.
+ */
+static void
+print_reg64name(FILE *fp, int rval, int hi)
+{
+        int off = 4 * (hi != 0);
+	char *regname = rnames[rval];
+
+        fprintf(fp, "%c%c",
+                 regname[off],
+                 regname[off + 1]);
+        if (regname[off + 2] != '!')
+                fputc(regname[off + 2], fp);
+        if (regname[off + 3] != '!')
+                fputc(regname[off + 3], fp);
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE * p, int size)
+{
+
+	size /= SZCHAR;
+	switch (p->n_op) {
+	case REG:
+		if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC)
+			print_reg64name(stdout, p->n_rval, 1);
+		else
+			fputs(rnames[p->n_rval], stdout);
+		break;
+
+	case NAME:
+	case OREG:
+		p->n_lval += size;
+		adrput(stdout, p);
+		p->n_lval -= size;
+		break;
+	case ICON:
+		fprintf(stdout, CONFMT, p->n_lval >> 32);
+		break;
+	default:
+		comperr("upput bad op %d size %d", p->n_op, size);
+	}
+}
+
+void
+adrput(FILE * io, NODE * p)
+{
+	int r;
+	/* output an address, with offsets, from p */
+
+	if (p->n_op == FLD)
+		p = p->n_left;
+
+	switch (p->n_op) {
+
+	case NAME:
+		if (p->n_name[0] != '\0')
+			fputs(p->n_name, io);
+		if (p->n_lval != 0)
+			fprintf(io, "+" CONFMT, p->n_lval);
+		return;
+
+	case OREG:
+		r = p->n_rval;
+
+		if (p->n_lval)
+			fprintf(io, "%d", (int) p->n_lval);
+
+		fprintf(io, "(%s)", rnames[p->n_rval]);
+		return;
+	case ICON:
+		/* addressable value of the constant */
+		conput(io, p);
+		return;
+
+	case REG:
+		if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC)
+			print_reg64name(io, p->n_rval, 0);
+		else
+			fputs(rnames[p->n_rval], io);
+		return;
+
+	default:
+		comperr("illegal address, op %d, node %p", p->n_op, p);
+		return;
+
+	}
+}
+
+/* printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+}
+
+void
+myreader(struct interpass * ipole)
+{
+}
+
+#if 0
+/*
+ *  Calculate the stack size for arguments
+ */
+static int stacksize;
+
+static void
+calcstacksize(NODE *p, void *arg)
+{
+	int sz;
+
+	printf("op=%d\n", p->n_op);
+
+	if (p->n_op != CALL && p->n_op != STCALL)
+		return;
+
+	sz = argsiz(p->n_right);
+	if (sz > stacksize)
+		stacksize = sz;
+
+#ifdef PCC_DEBUG
+	if (x2debug)
+		printf("stacksize: %d\n", stacksize);
+#endif
+}
+#endif
+
+/*
+ * If we're big endian, then all OREG loads of a type
+ * larger than the destination, must have the
+ * offset changed to point to the correct bytes in memory.
+ */
+static void
+offchg(NODE *p, void *arg)
+{
+	NODE *l;
+
+	if (p->n_op != SCONV)
+		return;
+
+	l = p->n_left;
+
+	if (l->n_op != OREG)
+		return;
+
+	switch (l->n_type) {
+	case SHORT:
+	case USHORT:
+		if (DEUNSIGN(p->n_type) == CHAR)
+			l->n_lval += 1;
+		break;
+	case LONG:
+	case ULONG:
+	case INT:
+	case UNSIGNED:
+		if (DEUNSIGN(p->n_type) == CHAR)
+			l->n_lval += 3;
+		else if (DEUNSIGN(p->n_type) == SHORT)
+			l->n_lval += 2;
+		break;
+	case LONGLONG:
+	case ULONGLONG:
+		if (DEUNSIGN(p->n_type) == CHAR)
+			l->n_lval += 7;
+		else if (DEUNSIGN(p->n_type) == SHORT)
+			l->n_lval += 6;
+		else if (DEUNSIGN(p->n_type) == INT ||
+		    DEUNSIGN(p->n_type) == LONG)
+			l->n_lval += 4;
+		break;
+	default:
+		comperr("offchg: unknown type");
+		break;
+	}
+}
+
+/*
+ * 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 * ipole)
+{
+	struct interpass *ip;
+
+#ifdef PCC_DEBUG
+	if (x2debug)
+		printf("myoptim:\n");
+#endif
+
+#if 0
+	stacksize = 0;
+#endif
+
+	DLIST_FOREACH(ip, ipole, qelem) {
+		if (ip->type != IP_NODE)
+			continue;
+		if (bigendian)
+			walkf(ip->ip_node, offchg, 0);
+#if 0
+		walkf(ip->ip_node, calcstacksize, 0);
+#endif
+	}
+}
+
+/*
+ * Move data between registers.  While basic registers aren't a problem,
+ * we have to handle the special case of overlapping composite registers.
+ */
+void
+rmove(int s, int d, TWORD t)
+{
+        switch (t) {
+        case LONGLONG:
+        case ULONGLONG:
+                if (s == d+1) {
+                        /* dh = sl, copy low word first */
+                        printf("\tmove ");
+			print_reg64name(stdout, d, 0);
+			printf(",");
+			print_reg64name(stdout, s, 0);
+			printf("\t# 64-bit rmove\n");
+                        printf("\tmove ");
+			print_reg64name(stdout, d, 1); 
+			printf(",");
+			print_reg64name(stdout, s, 1);
+			printf("\n");
+                } else {
+                        /* copy high word first */
+                        printf("\tmove ");
+			print_reg64name(stdout, d, 1);
+			printf(",");
+			print_reg64name(stdout, s, 1);
+			printf(" # 64-bit rmove\n");
+                        printf("\tmove ");
+			print_reg64name(stdout, d, 0);
+			printf(",");
+			print_reg64name(stdout, s, 0);
+			printf("\n");
+                }
+                break;
+	case FLOAT:
+	case DOUBLE:
+        case LDOUBLE:
+		if (t == FLOAT)
+			printf("\tmov.s ");
+		else
+			printf("\tmov.d ");
+		print_reg64name(stdout, d, 0);
+		printf(",");
+		print_reg64name(stdout, s, 0);
+		printf("\t# float/double rmove\n");
+                break;
+        default:
+                printf("\tmove %s,%s\t# default rmove\n", rnames[d], rnames[s]);
+        }
+}
+
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ *
+ * On MIPS, we have:
+ *
+ * 32 32-bit registers (8 reserved)
+ * 26 64-bit pseudo registers (1 unavailable)
+ * 16 floating-point register pairs
+ */
+int
+COLORMAP(int c, int *r)
+{
+	int num = 0;
+
+        switch (c) {
+        case CLASSA:
+                num += r[CLASSA];
+                num += 2*r[CLASSB];
+                return num < 24;
+        case CLASSB:
+                num += 2*r[CLASSB];
+                num += r[CLASSA];
+                return num < 25;
+	case CLASSC:
+		num += r[CLASSC];
+		return num < 6;
+        }
+	comperr("COLORMAP");
+        return 0; /* XXX gcc */
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+	if (t == LONGLONG || t == ULONGLONG)
+		return CLASSB;
+	if (t >= FLOAT && t <= LDOUBLE)
+		return CLASSC;
+	return CLASSA;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+	int sz;
+
+#ifdef PCC_DEBUG
+	if (x2debug)
+		printf("lastcall:\n");
+#endif
+
+	p->n_qual = 0;
+	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+		return;
+
+	sz = argsiz(p->n_right);
+
+	if ((sz > 4*nargregs) && (sz & 7) != 0) {
+		printf("\tsubu %s,%s,4\t# align stack\n",
+		    rnames[SP], rnames[SP]);
+		sz += 4;
+		assert((sz & 7) == 0);
+	}
+
+	p->n_qual = sz; /* XXX */
+}
+
+static int
+argsiz(NODE *p)
+{
+	TWORD t;
+	int size = 0;
+	int sz = 0;
+
+	if (p->n_op == CM) {
+		size = argsiz(p->n_left);
+		p = p->n_right;
+	}
+
+	t = p->n_type;
+	if (t < LONGLONG || t > BTMASK)
+		sz = 4;
+	else if (DEUNSIGN(t) == LONGLONG)
+		sz = 8;
+	else if (t == DOUBLE || t == LDOUBLE)
+		sz = 8;
+	else if (t == FLOAT)
+		sz = 4;
+	else if (t == STRTY || t == UNIONTY)
+		sz = p->n_stsize;
+
+	if (p->n_type == STRTY || p->n_type == UNIONTY) {
+		return (size + sz);
+	}
+
+	/* alignment */
+	if (sz == 8 && (size & 7) != 0)
+		sz += 4;
+
+//	printf("size=%d, sz=%d -> %d\n", size, sz, size + sz);
+	return (size + sz);
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+	int o = p->n_op;
+	switch(shape) {
+	case SPCON:
+		if (o == ICON && p->n_name[0] == 0 &&
+		    (p->n_lval & ~0xffff) == 0)
+			return SRDIR;
+		break;
+	}
+
+	return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+	if (strcasecmp(str, "big-endian") == 0) {
+		bigendian = 1;
+	} else if (strcasecmp(str, "little-endian") == 0) {
+		bigendian = 0;
+	} else {
+		fprintf(stderr, "unknown m option '%s'\n", str);
+		exit(1);
+	}
+
+#if 0
+	 else if (strcasecmp(str, "ips2")) {
+	} else if (strcasecmp(str, "ips2")) {
+	} else if (strcasecmp(str, "ips3")) {
+	} else if (strcasecmp(str, "ips4")) {
+	} else if (strcasecmp(str, "hard-float")) {
+	} else if (strcasecmp(str, "soft-float")) {
+	} else if (strcasecmp(str, "abi=32")) {
+		nargregs = MIPS_O32_NARGREGS;
+	} else if (strcasecmp(str, "abi=n32")) {
+		nargregs = MIPS_N32_NARGREGS;
+	} else if (strcasecmp(str, "abi=64")) {
+		nargregs = MIPS_N32_NARGREGS;
+	}
+#endif
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+	return 0;
+}
Index: uspace/app/pcc/arch/mips/macdefs.h
===================================================================
--- uspace/app/pcc/arch/mips/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/mips/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,350 @@
+/*	$Id: macdefs.h,v 1.12 2010/09/21 05:43:59 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.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+#if TARGOS == netbsd
+#define USE_GAS
+#endif
+
+/*
+ * Convert (multi-)character constant to integer.
+ * Assume: If only one value; store at left side (char size), otherwise 
+ * treat it as an integer.
+ */
+#define makecc(val,i)	lastcon = (lastcon<<8)|((val<<24)>>24);
+
+#define ARGINIT		(16*8)	/* # bits above fp where arguments start */
+#define AUTOINIT	(0)	/* # bits below fp where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR		8
+#define SZBOOL		32
+#define SZINT		32
+#define SZFLOAT		32
+#define SZDOUBLE	64
+#define SZLDOUBLE	64
+#define SZLONG		32
+#define SZSHORT		16
+#define SZLONGLONG	64
+#define SZPOINT(t)	32
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR		8
+#define ALBOOL		32
+#define ALINT		32
+#define ALFLOAT		32
+#define ALDOUBLE	64
+#define ALLDOUBLE	64
+#define ALLONG		32
+#define ALLONGLONG	64
+#define ALSHORT		16
+#define ALPOINT		32
+#define ALSTRUCT	64
+#define ALSTACK		32 
+
+/*
+ * Min/max values.
+ */
+#define	MIN_CHAR	-128
+#define	MAX_CHAR	127
+#define	MAX_UCHAR	255
+#define	MIN_SHORT	-32768
+#define	MAX_SHORT	32767
+#define	MAX_USHORT	65535
+#define	MIN_INT		-1
+#define	MAX_INT		0x7fffffff
+#define	MAX_UNSIGNED	0xffffffff
+#define	MIN_LONG	MIN_INT
+#define	MAX_LONG	MAX_INT
+#define	MAX_ULONG	MAX_UNSIGNED
+#define	MIN_LONGLONG	0x8000000000000000LL
+#define	MAX_LONGLONG	0x7fffffffffffffffLL
+#define	MAX_ULONGLONG	0xffffffffffffffffULL
+
+#undef	CHAR_UNSIGNED
+#define BOOL_TYPE	INT
+
+/*
+ * 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 */
+#ifdef USE_GAS
+#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
+
+#define BACKAUTO 		/* stack grows negatively for automatics */
+#define BACKTEMP 		/* stack grows negatively for temporaries */
+
+#undef	FIELDOPS		/* no bit-field instructions */
+#define RTOLBYTES 1		/* bytes are numbered right to left */
+
+#define ENUMSIZE(high,low) INT	/* enums are always stored in full int */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)	((x)&03)
+#define BITOOR(x)	(x)	/* bit offset to oreg offset */
+
+#define	szty(t)		(((t) == DOUBLE || (t) == LDOUBLE || \
+	DEUNSIGN(t) == LONGLONG) ? 2 : 1)
+
+/*
+ * Register names.  These must match rnames[] and rstatus[] in local2.c.
+ */
+#define ZERO	0
+#define AT	1
+#define V0	2
+#define V1	3
+#define A0	4
+#define A1	5
+#define A2	6
+#define A3	7
+#define A4	8
+#define A5	9
+#define A6	10
+#define A7	11
+#if defined(MIPS_N32) || defined(MIPS_N64)
+#define T0	12
+#define T1	13
+#define	T2	14
+#define	T3	15
+#else
+#define	T0	8
+#define	T1	9
+#define	T2	10
+#define	T3	11
+#endif
+#define	T4	12
+#define	T5	13
+#define	T6	14
+#define	T7	15
+#define S0	16
+#define S1	17
+#define S2	18
+#define S3	19
+#define S4	20
+#define S5	21
+#define S6	22
+#define S7	23
+#define T8	24
+#define T9	25
+#define K0	26
+#define K1	27
+#define GP	28
+#define SP	29
+#define FP	30
+#define RA	31
+
+#define V0V1	32
+#define A0A1	33
+#define A1A2	34
+#define A2A3	35
+
+/* we just use o32 naming here, but it works ok for n32/n64 */
+#define A3T0	36
+#define T0T1	37
+#define T1T2	38
+#define T2T3	39
+#define T3T4	40
+#define T4T5	41
+#define T5T6	42
+#define T6T7	43
+#define T7T8	44
+
+#define T8T9	45
+#define S0S1	46
+#define S1S2	47
+#define S2S3	48
+#define S3S4	49
+#define S4S5	50
+#define S5S6	51
+#define S6S7	52
+
+#define F0	53
+#define F2	54
+#define F4	55
+#define F6	56
+#define F8	57
+#define F10	58
+#define F12	59
+#define F14	60
+#define F16	61
+#define F18	62
+#define F20	63
+/* and the rest for later */
+#define F22	64
+#define F24	65
+#define F26	66
+#define F28	67
+#define F30	68
+
+#define MAXREGS 64
+#define NUMCLASS 3
+
+#define RETREG(x)	(DEUNSIGN(x) == LONGLONG ? V0V1 : \
+			    (x) == DOUBLE || (x) == LDOUBLE || (x) == FLOAT ? \
+			    F0 : V0)
+#define FPREG	FP	/* frame pointer */
+
+#define MIPS_N32_NARGREGS	8
+#define MIPS_O32_NARGREGS	4
+
+#define RSTATUS \
+	0, 0,								\
+	SAREG|TEMPREG, SAREG|TEMPREG, 					\
+	SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,	\
+	SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,	\
+	SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,	\
+	SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,	\
+	SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,	\
+	SAREG|TEMPREG, SAREG|TEMPREG, 					\
+	0, 0,								\
+	0, 0, 0, 0,							\
+	\
+	SBREG|TEMPREG,							\
+	SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,			\
+ 	SBREG|TEMPREG,							\
+	SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,			\
+	SBREG|TEMPREG, SBREG|TEMPREG,					\
+	SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG,	\
+	SBREG, SBREG, SBREG, SBREG,					\
+	SBREG, SBREG, SBREG, 						\
+	SCREG, SCREG, SCREG, SCREG,					\
+	SCREG, SCREG, SCREG, SCREG,					\
+	SCREG, SCREG, SCREG, 						\
+
+#define ROVERLAP \
+	{ -1 },				/* $zero */			\
+	{ -1 },				/* $at */			\
+	{ V0V1, -1 },			/* $v0 */			\
+	{ V0V1, -1 },			/* $v1 */			\
+	{ A0A1, -1 },			/* $a0 */			\
+	{ A0A1, A1A2, -1 },		/* $a1 */			\
+	{ A1A2, A2A3, -1 },		/* $a2 */			\
+	{ A2A3, A3T0, -1 },		/* $a3 */			\
+	{ A3T0, T0T1, -1 },		/* $t0 */			\
+	{ T0T1, T1T2, -1 },		/* $t1 */			\
+	{ T1T2, T2T3, -1 },		/* $t2 */			\
+	{ T2T3, T3T4, -1 },		/* $t3 */			\
+	{ T3T4, T4T5, -1 },		/* $t4 */			\
+	{ T4T5, T5T6, -1 },		/* $t5 */			\
+	{ T6T7, T7T8, -1 },		/* $t6 */			\
+	{ T7T8, T8T9, -1 },		/* $t7 */			\
+	\
+	{ S0S1, -1 },			/* $s0 */			\
+	{ S0S1, S1S2, -1 },		/* $s1 */			\
+	{ S1S2, S2S3, -1 },		/* $s2 */			\
+	{ S2S3, S3S4, -1 },		/* $s3 */			\
+	{ S3S4, S4S5, -1 },		/* $s4 */			\
+	{ S4S5, S5S6, -1 },		/* $s5 */			\
+	{ S5S6, S6S7, -1 },		/* $s6 */			\
+	{ S6S7, -1 },			/* $s7 */			\
+	\
+	{ T7T8, T8T9, -1 },		/* $t8 */			\
+	{ T8T9, -1 },			/* $t9 */			\
+	\
+	{ -1 },				/* $k0 */			\
+	{ -1 },				/* $k1 */			\
+	{ -1 },				/* $gp */			\
+	{ -1 },				/* $sp */			\
+	{ -1 },				/* $fp */			\
+	{ -1 },				/* $ra */			\
+	\
+	{ V0, V1, -1 },			/* $v0:$v1 */			\
+	\
+	{ A0, A1, A1A2, -1 },		/* $a0:$a1 */			\
+	{ A1, A2, A0A1, A2A3, -1 },	/* $a1:$a2 */			\
+	{ A2, A3, A1A2, A3T0, -1 },	/* $a2:$a3 */			\
+	{ A3, T0, A2A3, T0T1, -1 },	/* $a3:$t0 */			\
+	{ T0, T1, A3T0, T1T2, -1 },	/* $t0:$t1 */			\
+	{ T1, T2, T0T1, T2T3, -1 },	/* $t1:$t2 */			\
+	{ T2, T3, T1T2, T3T4, -1 },	/* $t2:$t3 */			\
+	{ T3, T4, T2T3, T4T5, -1 },	/* $t3:$t4 */			\
+	{ T4, T5, T3T4, T5T6, -1 },	/* $t4:$t5 */			\
+	{ T5, T6, T4T5, T6T7, -1 },	/* $t5:$t6 */			\
+	{ T6, T7, T5T6, T7T8, -1 },	/* $t6:$t7 */			\
+	{ T7, T8, T6T7, T8T9, -1 },	/* $t7:$t8 */			\
+	{ T8, T9, T7T8, -1 },		/* $t8:$t9 */			\
+	\
+	{ S0, S1, S1S2, -1 },		/* $s0:$s1 */			\
+	{ S1, S2, S0S1, S2S3, -1 },					\
+	{ S2, S3, S1S2, S3S4, -1 },					\
+	{ S3, S4, S2S3, S4S5, -1 },					\
+	{ S4, S5, S3S4, S5S6, -1 },					\
+	{ S5, S6, S4S5, S6S7, -1 },					\
+	{ S6, S7, S5S6, -1 },						\
+	\
+	{ -1 }, { -1 }, { -1 }, { -1 },					\
+	{ -1 }, { -1 }, { -1 }, { -1 },					\
+	{ -1 }, { -1 }, { -1 }, 					\
+
+#define GCLASS(x)	(x < 32 ? CLASSA : (x < 52 ? CLASSB : CLASSC))
+#define PCLASS(p)	(1 << gclass((p)->n_type))
+#define DECRA(x,y)	(((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define ENCRA(x,y)	((x) << (6+y*6))        /* encode regs in int */
+#define ENCRD(x)	(x)			/* Encode dest reg in n_reg */
+
+int COLORMAP(int c, int *r);
+
+extern int bigendian;
+extern int nargregs;
+
+#define SPCON           (MAXSPECIAL+1)  /* positive constant */
+
+#define TARGET_STDARGS
+#define TARGET_BUILTINS						\
+	{ "__builtin_stdarg_start", mips_builtin_stdarg_start, 2 },	\
+	{ "__builtin_va_arg", mips_builtin_va_arg, 2 },		\
+	{ "__builtin_va_end", mips_builtin_va_end, 1 },		\
+	{ "__builtin_va_copy", mips_builtin_va_copy, 2 },
+
+struct node;
+struct node *mips_builtin_stdarg_start(struct node *f, struct node *a, unsigned int);
+struct node *mips_builtin_va_arg(struct node *f, struct node *a, unsigned int);
+struct node *mips_builtin_va_end(struct node *f, struct node *a, unsigned int);
+struct node *mips_builtin_va_copy(struct node *f, struct node *a, unsigned int);
Index: uspace/app/pcc/arch/mips/order.c
===================================================================
--- uspace/app/pcc/arch/mips/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/mips/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,259 @@
+/*	$Id: order.c,v 1.12 2008/11/30 21:00: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.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ */
+
+#include "pass2.h"
+
+/*
+ * 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)
+{
+	/*
+	 * although the hardware doesn't permit offsets greater
+	 * than +/- 32K, the assembler fixes it for us.
+	 */
+	return 0;		/* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ */
+void
+offstar(NODE * p, int shape)
+{
+	if (x2debug)
+		printf("offstar(%p)\n", p);
+
+	if (p->n_op == PLUS || p->n_op == MINUS) {
+		if (p->n_right->n_op == ICON) {
+			if (isreg(p->n_left) == 0)
+				(void)geninsn(p->n_left, INAREG);
+			/* Converted in ormake() */
+			return;
+		}
+	}
+	(void)geninsn(p, INAREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE * q)
+{
+	if (x2debug)
+		printf("myormake(%p)\n", q);
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+	if (x2debug)
+		printf("shumul(%p)\n", p);
+
+	/* Always turn it into OREG */
+	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.
+ * - left is the register that left node wants.
+ * - right is the register that right node wants.
+ * - res is in which register the result will end up.
+ * - mask is registers that will be clobbered.
+ */
+struct rspecial *
+nspecial(struct optab * q)
+{
+	switch (q->op) {
+
+	case SCONV:
+		if (q->lshape == SBREG && q->rshape == SCREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, A0A1 },
+				{ NRES, F0 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SCREG && q->rshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, F0 },
+				{ NRES, A0A1 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SAREG && q->rshape == SCREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, A0 },
+				{ NRES, F0 },
+				{ 0 }
+			};
+			return s;
+		}
+		break;
+
+	case MOD:
+	case DIV:
+		if (q->lshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, A0A1 },
+				{ NRIGHT, A2A3 },
+				{ NRES, V0V1 },
+				{ 0 },
+			};
+			return s;
+		} else if (q->lshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, A0 },
+				{ NRIGHT, A1 },
+				{ NRES, V0 },
+				{ 0 },
+			};
+			return s;
+		}
+
+	case RS:
+	case LS:
+		if (q->lshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, A0A1 },
+				{ NRIGHT, A2 },
+				{ NRES, V0V1 },
+				{ 0 },
+			};
+			return s;
+		} else if (q->lshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, A0 },
+				{ NRIGHT, A1 },
+				{ NRES, V0 },
+				{ 0 },
+			};
+			return s;
+		}
+		break;
+
+	case STARG:
+                {
+                        static struct rspecial s[] = {
+                                { NEVER, A0 },
+                                { NLEFT, A1 },
+                                { NEVER, A2 },
+                                { 0 }
+			};
+                        return s;
+                }
+
+        case STASG:
+                {
+                        static struct rspecial s[] = {
+                                { NEVER, A0 },
+                                { NRIGHT, A1 },
+                                { NEVER, A2 },
+                                { 0 }
+			};
+                        return s;
+                }
+	}
+
+	comperr("nspecial entry %d: %s", q - table, q->cstring);
+
+	return 0;		/* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE * p)
+{
+	return 0;		/* nothing differs */
+}
+
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+	static int r[1] = { -1 }; /* Terminate with -1 */
+
+	return &r[0];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+	return 1;
+}
Index: uspace/app/pcc/arch/mips/table.c
===================================================================
--- uspace/app/pcc/arch/mips/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/mips/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1580 @@
+/*	$Id: table.c,v 1.14 2010/09/19 13:54:41 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.
+ */
+
+/*
+ * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
+ * Simon Olsson (simols-1@student.ltu.se) 2005.
+ *
+ * It appears that the target machine was big endian.  The original
+ * code contained many endian aspects which are now handled in
+ * machine-independent code.
+ * 
+ * On MIPS, the assembler does an amazing amount of work for us.
+ * We don't have to worry about PIC, nor about finding the address
+ * of SNAMES.  Whenever possible, we defer the work to the assembler.
+ */
+
+#include "pass2.h"
+
+#define TUWORD TUNSIGNED|TULONG
+#define TSWORD TINT|TLONG
+#define TWORD TUWORD|TSWORD
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are usually not necessary */
+{ PCONV,	INAREG,
+	SAREG,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	# convert between word and pointer", },
+
+/*
+ * Conversions of integral<->integral types
+ */
+
+{ SCONV,	INAREG,
+	SOREG,  TCHAR,
+	SAREG,	TSWORD|TSHORT,
+		NAREG,	RESC1,
+		"	lb A1,AL	# convert oreg char to short/int\n"
+		"	nop\n", },
+
+{ SCONV, 	INAREG,
+	SOREG,	TCHAR,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+		NAREG,	RESC1,
+		"	lbu A1,AL	# convert oreg char to uchar/ushort/uint\n"
+		"	nop\n", },
+
+{ SCONV,	INAREG,
+	SOREG,  TUCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT,
+		NAREG,	RESC1,
+		"	lbu A1,AL	# convert oreg uchar to (u)short/(u)int\n"
+		"	nop\n", },
+
+{ SCONV,	INBREG,
+	SOREG,	TCHAR,
+	SBREG,	TLONGLONG,
+		NBREG,	RESC1,
+      		"	lb A1,AL	# convert oreg char to longlong\n"
+      		"	nop\n"
+      		"	sra U1,A1,31\n", },
+
+/* chor -> ulonglong handled later */
+
+{ SCONV,	INBREG,
+	SOREG,	TUCHAR,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG,	RESC1,
+		"	lbu A1,AL	# convert oreg uchar to (u)longlong\n"
+      		"	move U1,$zero\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TSHORT|TUSHORT,
+	SAREG,	TCHAR,
+		NAREG,	RESC1,
+		"	lb A1,AL	# convert oreg (u)short to char (endianness problem?)\n"
+		"	nop\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TSHORT|TUSHORT,
+	SAREG,  TUCHAR,
+		NAREG,	RESC1,
+		"	lbu A1,AL	# convert oreg (u)short to uchar (endianness problem?)\n"
+		"	nop\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TSHORT,
+	SAREG,	TSWORD,
+		NAREG,	RESC1,
+		"	lh A1,AL	# convert oreg short to int\n"
+		"	nop\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TSHORT,
+	SAREG,	TUWORD,
+		NAREG,	RESC1,
+		"	lhu A1,AL	# convert oreg short to uint\n"
+		"	nop\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TUSHORT,
+	SAREG,	TWORD,
+		NAREG,	RESC1,
+		"	lhu A1,AL	# convert oreg ushort to (u)int\n"
+		"	nop\n", },
+
+{ SCONV,	INBREG,
+	SOREG,	TSHORT,
+	SBREG,	TLONGLONG,
+		NBREG,	RESC1,
+      		"	lh A1,AL	# convert oreg short to longlong\n"
+      		"	nop\n"
+      		"	sra U1,A1,31\n", },
+
+{ SCONV,	INBREG,
+	SOREG,	TSHORT,
+	SBREG,	TULONGLONG,
+		NBREG,	RESC1,
+      		"	lhu A1,AL	# convert oreg short to ulonglong\n"
+      		"	nop\n"
+		"	move U1,$zero\n", },
+
+{ SCONV,	INBREG,
+	SOREG,	TUSHORT,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG,	RESC1,
+		"	lhu A1,AL	# convert oreg ushort to (u)longlong\n"
+      		"	move U1,$zero\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TWORD,
+	SAREG,	TCHAR,
+		NAREG,	RESC1,
+		"	lb A1,AL	# convert oreg word to char (endianness problem here?)\n"
+		"	nop\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TWORD,
+	SAREG,	TUCHAR,
+		NAREG,	RESC1,
+		"	lbu A1,AL	# convert oreg word to uchar (endianness problem here?)\n"
+		"	nop\n", },
+    
+{ SCONV,	INAREG,
+	SOREG,	TWORD,
+	SAREG,	TSHORT,
+		NAREG,	RESC1,
+		"	lh A1,AL	# convert oreg word to short (endianness problem here?)\n"
+		"	nop\n", },
+
+/* convert (u)long to ushort */
+{ SCONV,	INAREG,
+	SOREG,	TWORD,
+	SAREG,	TUSHORT,
+		NAREG,	RESC1,
+		"	lhu A1,AL	# convert oreg word to ushort (endianness problem here?)\n"
+		"	nop\n", },
+
+{ SCONV,	INBREG,
+	SOREG,	TSWORD,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG,	RESC1,
+      		"	lw A1,AL	# convert oreg int/long to (u)llong (endianness problem here?)\n"
+      		"	nop\n"
+      		"	sra U1,A1,31\n" },
+
+{ SCONV,	INBREG,
+	SOREG,	TUWORD,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG,	RESC1,
+		"	lw A1,AL	# convert oreg (u)int to (u)llong (endianness problem here?)\n"
+      		"	move U1,$zero\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TCHAR,
+		NAREG,	RESC1,
+		"	lb A1,AL	# convert oreg (u)llong to char	(endianness problem here?)\n"
+		"	nop\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TUCHAR,
+		NAREG,	RESC1,
+		"	lbu A1,AL	# convert oreg (u)llong to uchar (endianness problem?)\n"
+		"	nop\n", },
+    
+{ SCONV,	INAREG,
+	SOREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TSHORT,
+		NAREG,	RESC1,
+		"	lh A1,AL	# convert oreg (u)llong to short (endianness problem?)\n"
+		"	nop\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TUSHORT,
+		NAREG,	RESC1,
+		"	lhu A1,AL	# convert oreg (u)llong to ushort (endianness problem here?)\n"
+		"	nop\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TWORD,
+		NAREG,	RESC1,
+      		"	lw A1,AL	# convert oreg (u)llong to (u)int (endianness problem here?)\n"
+		"	nop\n", },
+
+/*
+ * Conversions of integral types (register-register)
+ *
+ * For each deunsigned type, they look something like this:
+ *
+ * signed -> bigger signed      - nothing to do
+ * signed -> bigger unsigned    - clear the top bits (of source type)
+ *
+ * signed -> smaller signed     - sign-extend the bits (to dest type)
+ * signed -> smaller unsigned   - clear the top bits (of dest type)
+ * unsigned -> smaller signed   - sign-extend top bits (to dest type)
+ * unsigned -> smaller unsigned - clear the top bits (of dest type)
+ *
+ * unsigned -> bigger           - nothing to do
+ */
+
+{ SCONV,	INAREG,
+	SAREG,	TPOINT|TWORD,
+	SAREG,	TPOINT|TWORD,
+		0,	RLEFT,
+		"	# convert int to int\n", },
+
+{ SCONV,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		0,	RLEFT,
+		"	# convert (u)longlong to (u)longlong", },
+
+{ SCONV,	INAREG,
+	SAREG,	TCHAR,
+	SAREG,	TSWORD|TSHORT,
+		0,	RLEFT,
+		"	# convert char to short/int\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TCHAR,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	andi A1,AL,255	# convert char to uchar/ushort/uint\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUCHAR,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	sll A1,AL,24	# convert uchar to char\n"
+		"	sra A1,A1,24\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	# convert uchar to (u)short/(u)int\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSHORT,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	sll A1,AL,24	# convert short to char\n"
+		"	sra A1,A1,24\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSHORT,
+	SAREG,	TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	andi A1,AL,255	# convert short to uchar\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSHORT,
+	SAREG,	TUWORD|TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	andi A1,AL,65535	# convert short to ushort\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSHORT,
+	SAREG,	TSWORD,
+		NAREG|NASL,	RESC1,
+		"	sll A1,AL,16	# convert short to ushort\n"
+		"	sra A1,A1,16\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUSHORT,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	sll A1,AL,24	# convert short to char\n"
+		"	sra A1,A1,24\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUSHORT,
+	SAREG,	TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	andi A1,AL,255	# convert ushort to char\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUSHORT,
+	SAREG,	TSHORT,
+		NAREG|NASL,	RESC1,
+		"	sll A1,AL,16	# convert short to ushort\n"
+		"	sra A1,A1,16\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUSHORT,
+	SAREG,	TWORD,
+		0,	RDEST,
+		"	# convert ushort to (u)int\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSWORD,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	sll A1,AL,8	# convert int to char\n"
+		"	sra A1,A1,8\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSWORD,
+	SAREG,	TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	andi A1,AL,255	# convert int to uchar\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSWORD,
+	SAREG,	TSHORT,
+		NAREG|NASL,	RESC1,
+		"	sll A1,AL,16	# convert int to short\n"
+		"	sra A1,A1,16\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSWORD,
+	SAREG,	TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	andi A1,AL,65535	# convert int to ushort\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUWORD,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	sll A1,AL,24	# convert int to char\n"
+		"	sra A1,A1,24\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUWORD,
+	SAREG,	TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	andi A1,AL,255	# convert int to uchar\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUWORD,
+	SAREG,	TSHORT,
+		NAREG|NASL,	RESC1,
+		"	sll A1,AL,16	# convert int to short\n"
+		"	sra A1,A1,16\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUWORD,
+	SAREG,	TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	andi A1,AL,65535	# convert int to ushort\n", },
+
+{ SCONV,	INBREG,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SBREG,	TLONGLONG,
+		NBREG,	RESC1,
+		"	move A1,AL	# convert int/short/char to longlong\n"
+		"	sra U1,AL,31\n", },
+
+{ SCONV,	INBREG,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SBREG,	TULONGLONG,
+		NBREG,	RESC1,
+		"	move A1,AL	# convert int/short/char to ulonglong\n"
+		"	move U1,$zero\n", },
+
+{ SCONV,	INBREG,
+	SAREG,	TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG,	RESC1,
+		"	move A1,AL	# convert (u)int/(u)short/(u)char to ulonglong\n"
+		"	move U1,$zero\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TWORD,
+		NAREG,	RESC1,
+		"	move A1,AL	# convert (u)longlong to int\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TSHORT,
+		NAREG,	RESC1,
+		"	sll A1,AL,16	# convert (u)longlong to short\n"
+		"	sra A1,A1,16\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TCHAR,
+		NAREG,	RESC1,
+		"	sll A1,AL,24	# convert (u)longlong to char\n"
+		"	sra A1,A1,24\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TUSHORT,
+		NAREG,	RESC1,
+		"	andi A1,AL,65535	# convert (u)longlong to ushort\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TUCHAR,
+		NAREG,	RESC1,
+		"	andi A1,AL,255	# convert (u)longlong to uchar\n", },
+
+{ SCONV,	INCREG,
+	SCREG,	TFLOAT,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		NCREG,	RESC1,
+		"	cvt.d.s A1,AL	# convert float to (l)double\n", },
+
+{ SCONV,	INCREG,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	cvt.s.d A1,AL	# convert (l)double to float\n", },
+
+{ SCONV,	INCREG,
+	SAREG,	TWORD,
+	SCREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	mtc1 AL,A1	# convert (u)int to float\n"
+		"	nop\n"
+		"	cvt.s.w A1,A1\n", },
+
+{ SCONV,	INCREG,
+	SOREG,	TWORD,
+	SCREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	l.s A1,AL	# convert (u)int to float\n"
+		"	nop\n"
+		"	cvt.s.w A1,A1\n", },
+
+{ SCONV,	INCREG,
+	SAREG,	TWORD,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		NCREG,	RESC1,
+		"	mtc1 AL,A1	# convert (u)int to (l)double\n"
+		"	nop\n"
+		"	cvt.d.w A1,A1\n", },
+
+{ SCONV,	INCREG,
+	SOREG,	TWORD,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		NCREG,	RESC1,
+		"	l.d A1,AL	# convert (u)int to (l)double\n"
+		"	nop\n"
+		"	cvt.d.w A1,A1\n", },
+
+{ SCONV,	INAREG,
+	SCREG,	TFLOAT,
+	SAREG,	TWORD,
+		NCREG|NAREG,	RESC1,
+		"	cvt.w.s A2,AL	# convert float to (u)int\n"
+		"	mfc1 A1,A2\n"
+		"	nop\n", },
+
+{ SCONV,	FOREFF,
+	SCREG,	TFLOAT,
+	SOREG,	TWORD,
+		NCREG,	RDEST,
+		"	cvt.w.s A1,AL	# convert float to (u)int\n"
+		"	s.s A1,AR\n"
+		"	nop\n", },
+
+{ SCONV,	INAREG,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SAREG,	TWORD,
+		NCREG|NAREG,	RESC1,
+		"	cvt.w.d A2,AL	# convert (l)double to (u)int\n"
+		"	mfc1 A1,A2\n"
+		"	nop\n", },
+
+{ SCONV,	INCREG,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		0,	RLEFT,
+		"	# convert between double and ldouble\n", },
+
+{ SCONV,	INCREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCREG,	TFLOAT,
+		NSPECIAL|NCREG,	RESC1,
+		"ZF", },
+
+{ SCONV,	INCREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		NSPECIAL|NCREG,	RESC1,
+		"ZF", },
+
+{ SCONV,	INBREG,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NSPECIAL|NBREG,		RESC1,
+		"ZF", },
+
+{ SCONV,	INBREG,
+	SCREG,	TFLOAT,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NSPECIAL|NBREG,		RESC1,
+		"ZF", },
+
+/*
+ * Multiplication and division
+ */
+
+{ MUL,	INAREG,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+		NAREG|NASR|NASL,	RESC1,
+		"	multu AL,AR	# unsigned multiply\n"
+		"	mflo A1\n"
+		"	nop\n"
+		"	nop\n", },
+
+/* this previous will match on unsigned/unsigned multiplication first */
+{ MUL,	INAREG,
+	SAREG,	TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+	SAREG,	TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+		NAREG|NASR|NASL,	RESC1,
+		"	mult AL,AR	# signed multiply\n"
+		"	mflo A1\n"
+		"	nop\n"
+		"	nop\n", },
+
+{ MUL,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		2*NBREG,	RESC1,
+		"	multu AL,AR\n"
+		"	mfhi U1\n"
+		"	mflo A1\n"
+		"	mult AL,UR\n"
+		"	mflo A2\n"
+		"	nop\n"
+		"	nop\n"
+		"	addu A2,U1,A2\n"
+		"	mult UL,AR\n"
+		"	mflo U2\n"
+		"	nop\n"
+		"	nop\n"
+		"	addu U1,A2,U2\n", },
+
+{ MUL,	INCREG,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	mul.s A1,AL,AR		# floating-point multiply\n", },
+
+{ MUL,	INCREG,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		NCREG,	RESC1, 
+		"	mul.d	A1,AL,AR	# double-floating-point multiply\n", },
+
+{ DIV,	INAREG,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+		NAREG|NASR|NASL,	RESC1,
+		"	divu AL,AR	# unsigned division\n"
+		"	mflo A1\n"
+		"	nop\n"
+		"	nop\n", },
+
+/* the previous rule will match unsigned/unsigned first */
+{ DIV,	INAREG,
+	SAREG,	TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+	SAREG,	TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+		NAREG|NASR|NASL,	RESC1,
+		"	div AL,AR	# signed division\n"
+		"	mflo A1\n"
+		"	nop\n"
+		"	nop\n", },
+
+{ DIV, INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NSPECIAL|NBREG,	RESC1,
+		"ZE", },
+
+{ DIV,	INCREG,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	div.s A1,AL,AR		# floating-point division\n", },
+
+{ DIV,	INCREG,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		NCREG,	RESC1, 
+		"	div.d	A1,AL,AR	# double-floating-point division\n", },
+
+{ MOD,  INAREG,
+        SAREG,  TUWORD|TUSHORT|TUCHAR,
+        SAREG,  TUWORD|TUSHORT|TUCHAR,
+                NAREG,  RESC1,
+                "       divu AL,AR	# signed modulo\n"
+		"	mfhi A1\n"
+		"	nop\n"
+		"	nop\n", },
+
+/* the previous rule will match unsigned%unsigned first */
+{ MOD,  INAREG,
+        SAREG,  TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+        SAREG,  TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR,
+                NAREG,  RESC1,
+                "	div AL,AR	# signed modulo\n"
+		"	mfhi A1\n"
+		"	nop\n"
+		"	nop\n", },
+
+{ MOD,  INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+                NSPECIAL|NBREG,  RESC1,
+                "ZE", },
+    
+/*
+ * Templates for unsigned values needs to come before OPSIMP 
+ */
+
+{ PLUS,	INBREG,
+	SBREG,	TULONGLONG|TLONGLONG,
+	SBREG,	TULONGLONG|TLONGLONG,
+		2*NBREG,	RESC1,
+      		"	addu A1,AL,AR	# 64-bit addition\n"
+      		"	sltu A2,A1,AR\n"
+      		"	addu U1,UL,UR\n"
+      		"	addu U1,U1,A2\n", },
+
+{ PLUS,	INAREG,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SSCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	addi A1,AL,AR\n", },
+
+{ PLUS,	INAREG,
+	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
+	SSCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	addiu A1,AL,AR\n", },
+
+{ PLUS,	INAREG,
+	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+		NAREG|NASL,	RESC1,
+      		"	addu A1,AL,AR\n", },
+
+{ PLUS,	INAREG,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+		NAREG|NASL,	RESC1,
+      		"	add A1,AL,AR\n", },
+
+{ PLUS,	INCREG,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NCREG|NCSL,	RESC1,
+		"	add.s A1,AL,AR\n", },
+
+{ PLUS,	INCREG,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		NCREG|NCSL,	RESC1,
+		"	add.d A1,AL,AR\n", },
+
+{ MINUS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		2*NBREG,	RESC1,
+      		"	sltu A2,AL,AR	# 64-bit subtraction\n"
+      		"	subu A1,AL,AR\n"
+      		"	subu U1,UL,UR\n"
+      		"	subu U1,U1,A2\n", },
+
+{ MINUS,	INAREG,
+	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
+	SSCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	subu A1,AL,AR\n", },
+
+{ MINUS,	INAREG,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SSCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	sub A1,AL,AR\n", },
+
+{ MINUS,	INAREG,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+		NAREG|NASL,	RESC1,
+      		"	sub A1,AL,AR\n", },
+
+{ MINUS,	INCREG,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NCREG|NCSL,	RESC1,
+		"	sub.s A1,AL,AR\n", },
+
+{ MINUS,	INCREG,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		NCREG|NCSL,	RESC1,
+		"	sub.d A1,AL,AR\n", },
+
+{ UMINUS,	INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,
+		"	neg A1,AL\n", },
+
+{ UMINUS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SANY,	TANY,
+		NBREG|NAREG|NBSL,	RESC2,
+		"	subu A1,$zero,AL\n"
+		"	subu U1,$zero,UL\n"
+		"	sltu A2,$zero,A1\n"
+		"	subu U1,U1,A2\n", },
+
+{ UMINUS,	INCREG,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NCREG|NCSL,	RESC1,
+		"	neg.s A1,AL\n", },
+
+{ UMINUS,	INCREG,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		NCREG|NCSL,	RESC1,
+		"	neg.d A1,AL\n", },
+
+/* Simple 'op rd, rs, rt' or 'op rt, rs, imm' operations */
+
+{ OPSIMP,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSR|NBSL,	RESC1,
+      		"	O A1,AL,AR\n"
+      		"	O U1,UL,UR\n", },
+    
+{ OPSIMP,	INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR,
+		NAREG|NASR|NASL,	RESC1,
+		"	O A1,AL,AR\n", },
+
+{ OPSIMP,	INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR,
+	SPCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	Oi A1,AL,AR\n", },
+
+/*
+ * Shift instructions
+ */
+
+{ RS,	INAREG,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SCON,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	sra A1,AL,AR	# shift right by constant\n", },
+
+{ RS,	INAREG,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+	SCON,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	srl A1,AL,AR	# shift right by constant\n", },
+
+{ LS,	INAREG,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SCON,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	sll A1,AL,AR	# shift left by constant\n", },
+    
+{ RS,	INAREG,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	srav A1,AL,AR	# shift right by register\n", },
+
+{ RS,	INAREG,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	srlv A1,AL,AR	# shift right by register\n", },
+
+{ LS,	INAREG,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	sllv A1,AL,AR	# shift left by register\n", },	
+
+{ RS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCON,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NBREG,	RESC1,
+		"ZO", },
+
+{ LS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCON,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NBREG,	RESC1,
+		"ZO", },
+
+{ RS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NSPECIAL|NBREG,	RESC1,
+		"ZE", },
+
+{ LS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NSPECIAL|NBREG,	RESC1,
+		"ZE", },
+
+/*
+ * Rule for unary one's complement
+ */
+
+{ COMPL,        INAREG,
+        SAREG,  TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SANY,   TANY,
+                NAREG|NASL,   RESC1,
+                "	nor A1,$zero,AL	# complement\n", },
+    
+{ COMPL,        INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+        SANY,   TANY,
+                NBREG|NBSL,   RESC1,
+                "	nor A1,$zero,AL	# complement\n"
+                "	nor U1,$zero,UL\n", },
+    
+/*
+ * The next rules takes care of assignments. "=".
+ */
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG|SNAME,	TWORD|TPOINT,
+	SAREG,		TWORD|TPOINT,
+		0,	RDEST,
+		"	sw AR,AL		# store (u)int/(u)long\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG|SNAME,	TSHORT|TUSHORT,
+	SAREG,		TSHORT|TUSHORT,
+		0,	RDEST,
+        	"	sh AR,AL		# store (u)short\n"
+		"	nop\n", },	
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG|SNAME,	TCHAR|TUCHAR,
+	SAREG,		TCHAR|TUCHAR,
+		0,	RDEST,
+        	"	sb AR,AL		# store (u)char\n"
+		"	nop\n", },	
+
+{ ASSIGN,	FOREFF|INBREG,
+	SOREG|SNAME,	TLONGLONG|TULONGLONG,
+	SBREG,		TLONGLONG|TULONGLONG,
+		0,	RDEST,
+      		"	sw UR,UL		# store (u)longlong\n"
+		"	nop\n"
+      		"	sw AR,AL\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SBREG,		TLONGLONG|TULONGLONG,
+		0,	RDEST,
+      		"	move UL,UR		# register move\n"
+      		"	move AL,AR\n", },
+    
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TANY,
+	SAREG,	TANY,
+		0,	RDEST,
+        	"	move AL,AR		# register move\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		0,	RDEST,
+        	"	mov.s AL,AR		# register move\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+        	"	mov.d AL,AR		# register move\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SNAME|SOREG,	TFLOAT,
+	SCREG,		TFLOAT,
+		0,	RDEST,
+		"	s.s AR,AL		# store floating-point reg to oreg/sname\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SNAME|SOREG,	TDOUBLE|TLDOUBLE,
+	SCREG,		TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"	s.d AR,AL		# store double floating-point reg to oreg/sname\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,		TANY,
+	SOREG|SNAME,	TANY,
+		3*NAREG,	RDEST,
+		"	lw A1,AR		# bit-field assignment\n"
+		"	li A3,M\n"
+		"	lw A2,AL\n"
+		"	sll A1,A1,H\n"
+		"	and A1,A1,A3\n"
+		"	nor A3,$zero,A3\n"
+		"	and A2,A2,A3\n"
+		"	or A2,A2,A1\n"
+		"	sw A2,AL\n"
+		"F	lw AD,AR\n"
+		"F	nop\n"
+		"F	sll AD,AD,32-S\n"
+		"F	sra AD,AD,32-S\n", },
+
+/* XXX we can optimise this away */
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,		TANY,
+	SCON,		TANY,
+		3*NAREG,	RDEST,
+		"	li A1,AR		# bit-field assignment\n"
+		"	lw A2,AL\n"
+		"	li A3,M\n"
+		"	sll A1,A1,H\n"
+		"	and A1,A1,A3\n"
+		"	nor A3,$zero,A3\n"
+		"	and A2,A2,A3\n"
+		"	or A2,A2,A1\n"
+		"	sw A2,AL\n"
+		"F	li AD,AR\n"
+		"F	sll AD,AD,32-S\n"
+		"F	sra AD,AD,32-S\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,		TANY,
+	SAREG,		TANY,
+		3*NAREG,	RDEST,
+		"	move A1,AR		# bit-field assignment\n"
+		"	lw A2,AL\n"
+		"	li A3,M\n"
+		"	sll A1,A1,H\n"
+		"	and A1,A1,A3\n"
+		"	nor A3,$zero,A3\n"
+		"	and A2,A2,A3\n"
+		"	or A2,A2,A1\n"
+		"	sw A2,AL\n"
+		"F	move AR,AD\n"
+		"F	sll AD,AD,32-S\n"
+		"F	sra AD,AD,32-S\n", },
+
+{ STASG,        INAREG|FOREFF,
+        SOREG|SNAME,	TANY,
+        SAREG,  	TPTRTO|TANY,
+                NSPECIAL,       RDEST,
+                "ZQ", },
+
+/*
+ * Compare instructions
+ */
+
+{ EQ,	FORCC,
+        SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+                0,      RESCC,
+                "	beq AL,AR,LC\n"
+		"	nop\n", },
+
+{ NE,	FORCC,
+        SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+                0,      RESCC,
+                "	bne AL,AR,LC\n"
+		"	nop\n", },
+
+{ OPLOG,	FORCC,
+        SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SZERO,		TANY,
+                0,      RESCC,
+                "	O AL,LC\n"
+		"	nop\n", },
+
+{ OPLOG,	FORCC,
+        SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+                NAREG|NASL,     RESCC,
+		"	sub A1,AL,AR\n"
+                "	O A1,LC\n"
+		"	nop\n", },
+
+{ OPLOG,	FORCC,
+        SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+        SSCON,		TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+                NAREG|NASL,     RESCC,
+		"	sub A1,AL,AR\n"
+                "	O A1,LC\n"
+		"	nop\n", },
+
+{ OPLOG,	FORCC,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SBREG,		TLONGLONG|TULONGLONG,
+		NAREG,	RESCC,
+		"ZD", },
+
+{ OPLOG,	FORCC,
+	SCREG,	TFLOAT|TDOUBLE|TLDOUBLE,
+	SCREG,	TFLOAT|TDOUBLE|TLDOUBLE,
+		0,	RESCC,
+		"ZG", },
+
+/*
+ * Convert LTYPE to reg.
+ */
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TCHAR,
+		NAREG,	RESC1,
+		"	lb A1,AL	# load char to reg\n"
+		"	nop\n", },
+	
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TUCHAR,
+		NAREG,	RESC1,
+		"	lbu A1,AL	# load uchar to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TSHORT,
+		NAREG,	RESC1,
+		"	lh A1,AL	# load short to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TUSHORT,
+		NAREG,	RESC1,
+		"	lhu A1,AL	# load ushort to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TWORD|TPOINT,
+		NAREG,	RESC1,
+		"	lw A1,AL	# load (u)int/(u)long to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TLONGLONG|TULONGLONG,
+		NBREG,	RESC1,
+		"	lw U1,UL	# load (u)longlong to reg\n"
+		"	nop\n"
+		"	lw A1,AL\n"
+      		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SCON,	TPOINT,
+		NAREG,	RESC1,
+		"	la A1,AL	# load constant address to reg\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SZERO,	TANY,
+		NAREG,	RESC1,
+		"	move A1,$zero	# load 0 to reg\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SCON,	TANY,
+		NAREG,	RESC1,
+		"	li A1,AL	# load constant to reg\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SZERO,	TANY,
+		NBREG,	RESC1,
+		"	move A1,$zero	# load 0 to reg\n"
+		"	move U1,$zero\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SCON,	TANY,
+		NBREG,	RESC1,
+		"	li A1,AL	# load constant to reg\n"
+		"	li U1,UL\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SANY,	TANY,
+		NAREG,	RESC1,
+		"	move A1,AL\n", },
+
+{ OPLTYPE,	INCREG,
+	SANY,	TANY,
+	SZERO,	TFLOAT,
+		NCREG,	RESC1,
+		"	mtc1 $zero,A1	# load 0 to float reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INCREG,
+	SANY,	TANY,
+	SZERO,	TDOUBLE|TLDOUBLE,
+		NCREG,	RESC1,
+		"	mtc1 $zero,A1	# load 0 to (l)double reg\n"
+		"	mtc1 $zero,U1\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INCREG,
+	SANY,	TANY,
+	SOREG|SNAME,	TFLOAT,
+		NCREG,	RESC1,
+		"	l.s A1,AL	# load into floating-point reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INCREG,
+	SANY,	TANY,
+	OREG|SNAME,	TDOUBLE|TLDOUBLE,
+		NCREG,	RESC1,
+		"	l.d A1,AL	# load into double floating-point reg\n"
+		"	nop\n", },
+    
+/*
+ * Jumps.
+ */
+{ GOTO, 	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	j LL		# goto label\n"
+		"	nop\n"
+		"	nop\n", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,         FOREFF,
+        SCON,		TANY,
+        SANY,           TANY,
+                0,      0,
+                "	subu $sp,$sp,16	# call (args, no result) to scon/sname\n"
+                "	jal CL\n"
+		"	nop\n"
+		"ZC", },
+
+{ UCALL,        FOREFF,
+        SCON,		TANY,
+        SANY,           TANY,
+                0,      0,
+                "	jal CL			# call (no args, no result) to scon/sname\n"
+		"	nop\n", },
+
+{ CALL,         INAREG,
+        SCON,		TANY,
+        SAREG,          TANY,
+                NAREG,     RESC1,  /* should be 0 */
+                "	subu $sp,$sp,16	# call (args, result in v0) to scon/sname\n"
+		"	jal CL\n"
+		"	nop\n"
+		"ZC", },
+
+{ UCALL,        INAREG,
+        SCON,		TANY,
+        SAREG,          TANY,
+                NAREG,     RESC1,  /* should be 0 */
+                "	jal CL   # call (no args, result in v0) to scon/sname\n"
+		"	nop\n",
+ },
+
+{ CALL,         INBREG,
+        SCON,		TANY,
+        SBREG,          TANY,
+                NBREG,     RESC1,  /* should be 0 */
+                "	subu $sp,$sp,16	# call (args, result in v0:v1) to scon/sname\n"
+		"	jal CL\n"
+		"	nop\n"
+		"ZC", },
+
+{ UCALL,        INBREG,
+        SCON,		TANY,
+        SBREG,          TANY,
+                NBREG,     RESC1,  /* should be 0 */
+                "	jal CL   # call (no args, result in v0:v1) to scon/sname\n"
+		"	nop\n",
+ },
+
+{ CALL,         INCREG,
+        SCON,		TANY,
+        SCREG,          TANY,
+                NCREG,     RESC1,  /* should be 0 */
+                "	subu $sp,$sp,16	# call (args, result in f0:f1) to scon/sname\n"
+		"	jal CL\n"
+		"	nop\n"
+		"ZC", },
+
+{ UCALL,        INCREG,
+        SCON,		TANY,
+        SCREG,          TANY,
+                NCREG,     RESC1,  /* should be 0 */
+                "	jal CL   # call (no args, result in v0:v1) to scon/sname\n"
+		"	nop\n",
+ },
+
+{ CALL,         FOREFF,
+        SAREG,		TANY,
+        SANY,		TANY,
+                0,      0,
+                "	subu $sp,$sp,16	# call (args, no result) to reg\n"
+		"	move $25,AL\n"
+                "	jal $25\n"
+		"	nop\n"
+		"ZC", },
+
+{ UCALL,        FOREFF,
+        SAREG,		TANY,
+        SANY,		TANY,
+                0,      0,
+		"	move $25,AL\n"
+                "	jal $25			# call (no args, no result) to reg\n"
+		"	nop\n", },
+
+{ CALL,         INAREG,
+        SAREG,		TANY,
+        SAREG,		TANY,
+                NAREG,     RESC1,  /* should be 0 */
+                "	subu $sp,$sp,16	# call (args, result) to reg\n"
+		"	move $25,AL\n"
+                "	jal $25\n"
+		"	nop\n"
+		"ZC", },
+
+{ UCALL,        INAREG,
+        SAREG,		TANY,
+        SAREG,		TANY,
+                NAREG,     RESC1,  /* should be 0 */
+		"	move $25,AL\n"
+                "	jal $25		# call (no args, result) to reg\n"
+		"	nop\n", },
+
+{ CALL,         INBREG,
+        SAREG,		TANY,
+        SBREG,		TANY,
+                NBREG,     RESC1,  /* should be 0 */
+                "	subu $sp,$sp,16	# call (args, result) to reg\n"
+		"	move $25,AL\n"
+                "	jal $25\n"
+		"	nop\n"
+		"ZC", },
+
+{ UCALL,        INBREG,
+        SAREG,		TANY,
+        SBREG,		TANY,
+                NBREG,     RESC1,  /* should be 0 */
+		"	move $25,AL\n"
+                "	jal $25			# call (no args, result) to reg\n"
+		"	nop\n", },
+
+{ CALL,         INCREG,
+        SAREG,		TANY,
+        SCREG,		TANY,
+                NCREG,     RESC1,  /* should be 0 */
+                "	subu $sp,$sp,16	# call (args, result) to reg\n"
+		"	move $25,AL\n"
+                "	jal $25\n"
+		"	nop\n"
+		"ZC", },
+
+{ UCALL,        INCREG,
+        SCREG,		TANY,
+        SCREG,		TANY,
+                NCREG,     RESC1,  /* should be 0 */
+		"	move $25,AL\n"
+                "	jal $25			# call (no args, result) to reg\n"
+		"	nop\n", },
+
+
+/* struct return */
+{ USTCALL,      FOREFF,
+	SCON|SNAME,	TANY,
+	SANY,   	TANY,
+		0,	0,
+		"	jal CL\n"
+		"	nop\n", },
+
+{ USTCALL,      FOREFF,
+	SAREG,		TANY,
+	SANY,   	TANY,
+		0,	0,
+		"	move $25,AL\n"
+                "	jal $25\n"
+		"	nop\n", },
+
+{ USTCALL,      INAREG,
+	SCON|SNAME,	TANY,
+	SANY,   	TANY,
+		NAREG|NASL,	RESC1,
+		"	jal CL\n"
+		"	nop\n", },
+
+{ USTCALL,      INAREG,
+	SAREG,		TANY,
+	SANY,   	TANY,
+		NAREG|NASL,	RESC1,
+		"	move $25,AL\n"
+                "	jal $25\n"
+		"	nop\n", },
+
+{ STCALL,      FOREFF,
+	SCON|SNAME,	TANY,
+	SANY,   	TANY,
+		0,	0,
+                "	subu $sp,$sp,16\n"
+		"	jal CL\n"
+		"	nop\n"
+		"ZC", },
+
+{ STCALL,      FOREFF,
+	SAREG,	TANY,
+	SANY,   	TANY,
+		0,	0,
+                "	subu $sp,$sp,16\n"
+		"	move $25,AL\n"
+                "	jal $25\n"
+		"	nop\n"
+		"ZC", },
+
+{ STCALL,      INAREG,
+	SCON|SNAME,	TANY,
+	SANY,   	TANY,
+		NAREG|NASL,	RESC1,
+                "	subu $sp,$sp,16\n"
+		"	jal CL\n"
+		"	nop\n"
+		"ZC", },
+
+{ STCALL,      INAREG,
+	SAREG,	TANY,
+	SANY,   	TANY,
+		0,	0,
+                "	subu $sp,$sp,16\n"
+		"	move $25,AL\n"
+                "	jal $25\n"
+		"	nop\n"
+		"ZC", },
+
+
+/*
+ *  Function arguments
+ */
+
+#if 0
+
+/* intentionally write out the register for (u)short/(u)char */
+{ FUNARG,       FOREFF,
+        SAREG,  TWORD|TPOINT|TUSHORT|TSHORT|TUCHAR|TCHAR,
+        SANY,   TWORD|TPOINT|TUSHORT|TSHORT|TUCHAR|TCHAR,
+                0,      0,
+                "	subu $sp,$sp,4		# save function arg to stack\n"
+		"	sw AL,($sp)\n"
+		"	#nop\n", },
+
+{ FUNARG,	FOREFF,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SANY,	TLONGLONG|TULONGLONG,
+		0,	0,
+		"	addi $sp,$sp,-8		# save function arg to stack (endian problem here?\n"
+		"	sw UL,4($sp)\n"
+		"	sw AL,($sp)\n"
+		"	#nop\n", },
+
+{ FUNARG,	FOREFF,
+	SCREG,	TFLOAT,
+	SANY,	TFLOAT,
+		0,	0,
+		"	addi $sp,$sp,-4		# save function arg to stack\n"
+		"	s.s AL,($sp)\n"
+		"	#nop\n", },
+
+{ FUNARG,	FOREFF,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SANY,	TDOUBLE|TLDOUBLE,
+		0,	0,
+		"	addi $sp,$sp,-8		# save function arg to stack\n"
+		"	s.d AL,($sp)\n"
+		"	#nop\n", },
+
+#endif
+
+{ STARG,	FOREFF,
+	SAREG,		TANY,
+	SANY,		TSTRUCT,
+		NSPECIAL,	0,
+		"ZH", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL, INAREG,
+	SANY,	TPOINT|TWORD,
+	SOREG,	TPOINT|TWORD,
+    		NAREG,     RESC1,
+        	"	lw A1,AL		# word load\n"
+		"	nop\n", },
+
+{ UMUL, INAREG,
+	SANY,	TSHORT|TUSHORT,
+	SOREG,	TSHORT|TUSHORT,
+    		NAREG,     RESC1,
+        	"	lh A1,AL		# (u)short load\n"
+		"	nop\n", },
+
+{ UMUL, INAREG,
+	SANY,	TCHAR|TUCHAR,
+	SOREG,	TCHAR|TUCHAR,
+    		NAREG,     RESC1,
+        	"	lb A1,AL		# (u)char load\n"
+		"	nop\n", },
+
+{ UMUL,	INBREG,
+	SANY,	TLONGLONG|TULONGLONG,
+	SOREG,	TLONGLONG|TULONGLONG,
+		NBREG,	RESC1,
+		"	lw A1,AL		# (u)longlong load - endian problem here?\n"
+		"	nop\n"
+		"	lw U1,UL\n"
+		"	nop\n", },
+
+{ UMUL,	INCREG,
+	SANY,	TFLOAT,
+	SOREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	l.s A1,AL		# float load\n"
+		"	nop\n", },
+
+{ UMUL,	INCREG,
+	SANY,	TDOUBLE|TLDOUBLE,
+	SOREG,	TDOUBLE|TLDOUBLE,
+		NCREG,	RESC1,
+		"	l.d A1,AL		# float load\n"
+		"	nop\n", },
+
+#if 0
+{ UMUL,	INCREG,
+	SANY,	TDOUBLE|TLDOUBLE,
+	SAREG,	TPOINT,
+		NCREG,	RESC1,
+		"	l.d A1,(AL)\n"
+		"	nop\n", },
+    
+{ UMUL, INAREG,
+	SANY,	TPOINT|TWORD,
+	SNAME,	TPOINT|TWORD,
+    		NAREG,     RESC1,
+        	"	la A1,AL		# sname word load\n"
+		"	lw A1,(A1)\n"
+		"	nop\n", },
+
+{ UMUL, INAREG,
+	SANY,	TSHORT|TUSHORT,
+	SNAME,	TSHORT|TUSHORT,
+    		NAREG,     RESC1,
+        	"	la A1,AL		# sname (u)short load\n"
+		"	lh A1,(A1)\n"
+		"	nop\n", },
+
+{ UMUL, INAREG,
+	SANY,	TCHAR|TUCHAR,
+	SNAME,	TCHAR|TUCHAR,
+    		NAREG,     RESC1,
+        	"	la A1,AL		# sname (u)char load\n"
+		"	lb A1,(A1)\n"
+		"	nop\n", },
+
+{ UMUL, INBREG,
+	SANY,	TLONGLONG|TULONGLONG,
+	SNAME,	TLONGLONG|TULONGLONG,
+		NBREG|NAREG,	RESC1,
+		"	la A2,AL		# sname (u)long long load - endian problems here?\n"
+		"	lw A1,(A1)\n"
+		"	nop\n"
+		"	lw U1,4(A1)\n"
+		"	nop\n", },
+#endif
+
+{ UMUL, INAREG,
+	SANY,	TPOINT|TWORD,
+	SAREG,	TPOINT|TWORD,
+    		NAREG,     RESC1,
+        	"	lw A1,(AL)		# word load\n"
+		"	nop\n", },
+
+#if 0
+{ UMUL, INAREG,
+	SANY,	TSHORT|TUSHORT,
+	SAREG,	TPTRTO|TSHORT|TUSHORT,
+    		NAREG,     RESC1,
+        	"	lh A1,(AL)		# (u)short load\n"
+		"	nop\n", },
+
+{ UMUL, INAREG,
+	SANY,	TCHAR|TUCHAR,
+	SAREG,	TPTRTO|TCHAR|TUCHAR,
+    		NAREG|NASL,     RESC1,
+        	"	lb A1,(AL)		# (u)char load\n"
+		"	nop\n", },
+
+{ UMUL, INBREG,
+	SANY,	TLONGLONG|TULONGLONG,
+	SAREG,	TPTRTO|TLONGLONG|TULONGLONG,
+		NBREG,	RESC1,
+		"	lw A1,(AL)		# (u)long long load - endianness problems?\n"
+		"	nop\n"
+		"	lw U1,4(AL)"
+		"	nop\n", },
+#endif
+
+#define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ FLD, DF(FLD), },
+
+{ FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	"help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
Index: uspace/app/pcc/arch/mips32
===================================================================
--- uspace/app/pcc/arch/mips32	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/mips32	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1 @@
+mips
Index: uspace/app/pcc/arch/nova/README
===================================================================
--- uspace/app/pcc/arch/nova/README	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/nova/README	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,120 @@
+Calling conventions, stack frame and zero page:
+
+The variables that normally are placed on the stack or in registers in C
+are instead allocated in the zero page and saved on a (fictive) stack
+when calling functions.  Some locations have predefined functions though.
+Arrays allocated as automatics are stored on the stack with a pointer
+in zero page to its destination.
+
+0-7	Unused
+10	Stack pointer
+11	Frame pointer
+12-14	Unused
+15	Used by prolog
+16	Prolog address, written in crt0
+17	Epilog address, written in crt0
+20-27	Auto-increment, scratch
+30-37	Auto-decrement, scratch
+40-47	Unused
+50-57	Scratch/Arguments
+60-77	Permanent, save before use.
+100-377	Addresses for subroutines, written by the assembler
+
+The normal registers (AC0-AC3) are all considered scratch registers.
+
+Register classes are assigned as:
+	AC0-AC3: AREGs.
+	AC2-AC3: BREGs.
+	50-77:	 CREGs.
+	...and eventually register pairs as DREGs.
+
+In byte code the low half of a word is the first byte (little-endian).
+This is bit 8-15 in Nova syntax.
+
+The stack is growing towards lower adresses (as opposed to the Eclipse stack).
+Stack layout:
+
+	! arg1	!
+	! arg0	!
+ fp ->	! old pc!
+	! old fp!
+ pc ->	! saved !
+
+A reference to a struct member in assembler, a = b->c; b is in ZP 50
++ is zeropage-addressing
+* is fp-adressing
+
+# offset 0
++	lda 0,@50	# load value from indirect ZP 50 into ac0
+*	lda 2,,3	# load value from (ac3) into ac2
+*	lda 0,,2	# load value from (ac2) into ac0
+
+# offset 12
++	lda 2,50	# load value from ZP 50 into ac2
++	lda 0,12,2	# load value from (ac2+12) into ac0
+*	lda 2,,3	# load value from (ac3) into ac2
+*	lda 0,12,2	# load value from 12(ac2) into ac0
+
+# offset 517
++	lda 2,50	# load value from ZP 50 into ac2
++	lda 0,.L42-.,1	# load offset from .L42 PC-indexed
++	addz 0,2,skp	# add offset to ac2 and skip
++.L42:	.word 517	# offset value
++	lda 0,,2	# load value from (ac2) into ac0
+
+The prolog/epilog implementation; it is implemented as subroutines.
+
+.L42:	.word 13	# number of words to save
+func:
+	sta 3,@40	# save return address on stack
+	lda 2,.L42-.,1	# get save word count
+	jsr @45		# go to prolog
+	...
+	lda 2,.L42-.,1	# get restore word count
+	jmp @46		# jump to epilog
+
+# words to save in 2, return address in 3
+prolog:
+	sta 2,45	# save # of words to move at scratch
+	lda 0,41	# get old fp
+	lda 1,40	# get sp
+	sta 1,41	# save new fp
+	dsz 40		# decrement stack, will never be 0
+	sta 0,@40	# save old fp
+	dsz 40
+
+	lda 0,off57	# fetch address of regs to save - 1
+	sta 0,20	# store address at autoincr
+1:	lda 0,@20	# get word to copy
+	sta 0,@40	# push on stack
+	dsz 40		# manually decrement sp
+	dsz 45		# copied all words?
+	jmp 1b,1	# no, continue
+	jmp 0,3		# return
+
+epilog:
+	sta 2,45	# save # of words to move at scratch
+
+	lda 3,off57	# fetch address of regs to save
+	sta 3,20	# store at autoincr
+	lda 3,41	# fetch fp
+	sta 3,30	# store at autodecr
+	lda 3,@30	# get old fp
+
+1:	lda 2,@30	# fetch word from stack
+	sta 2,@20	# store at orig place
+	dsz 45		# enough?
+	jmp 1b,1	# no, continue
+
+	lda 2,41	# get new fp
+	sta 2,40	# restore stack
+	sta 3,41	# restore old fp
+	jmp @40		# Return
+
+Assembler syntax and functions.
+
+The assembler syntax mimics the DG assembler.
+Load and store to addresses is written "lda 0,foo" to load from address foo.
+If foo is not in zero page then the assembler will put the lda in the
+text area close to the instruction and do an indirect pc-relative load.
+
Index: uspace/app/pcc/arch/nova/code.c
===================================================================
--- uspace/app/pcc/arch/nova/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/nova/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,193 @@
+/*	$Id: code.c,v 1.5 2008/01/01 17:31:00 ragge Exp $	*/
+/*
+ * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass1.h"
+
+/*
+ * cause the alignment to become a multiple of n
+ * never called for text segment.
+ */
+void
+defalign(int n)
+{
+	/* alignment are always correct */
+}
+
+/*
+ * define the current location as the name p->soname
+ * never called for text segment.
+ */
+void
+defnam(struct symtab *p)
+{
+	char *c = p->soname;
+
+	if (p->sclass == EXTDEF)
+		printf("	.globl %s\n", c);
+	printf("%s:\n", c);
+}
+
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode()
+{
+	NODE *p, *q;
+	int sz;
+
+	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+		return;
+cerror("efcode");
+	/* address of return struct is in eax */
+	/* create a call to memcpy() */
+	/* will get the result in eax */
+	p = block(REG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+//	p->n_rval = EAX;
+	q = block(OREG, NIL, NIL, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+//	q->n_rval = EBP;
+	q->n_lval = 8; /* return buffer offset */
+	p = block(CM, q, p, INT, 0, MKSUE(INT));
+	sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR;
+	p = block(CM, p, bcon(sz), INT, 0, MKSUE(INT));
+	p->n_right->n_name = "";
+	p = block(CALL, bcon(0), p, CHAR+PTR, 0, MKSUE(CHAR+PTR));
+	p->n_left->n_name = "memcpy";
+	p = clocal(p);
+	send_passt(IP_NODE, p);
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **a, int n)
+{
+	int i;
+
+	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+		return;
+cerror("bfcode");
+	/* Function returns struct, adjust arg offset */
+	for (i = 0; i < n; i++)
+		a[i]->soffset += SZPOINT(INT);
+}
+
+
+/*
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+	SETOFF(autooff, SZINT);
+}
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag )
+{
+}
+
+void
+bjobcode()
+{
+}
+
+/*
+ * Print character t at position i in one string, until t == -1.
+ * Locctr & label is already defined.
+ */
+void
+bycode(int t, int i)
+{
+	static	int	lastoctal = 0;
+
+	/* put byte i+1 in a string */
+
+	if (t < 0) {
+		if (i != 0)
+			puts("\"");
+	} else {
+		if (i == 0)
+			printf("\t.ascii \"");
+		if (t == '\\' || t == '"') {
+			lastoctal = 0;
+			putchar('\\');
+			putchar(t);
+		} else if (t < 040 || t >= 0177) {
+			lastoctal++;
+			printf("\\%o",t);
+		} else if (lastoctal && '0' <= t && t <= '9') {
+			lastoctal = 0;
+			printf("\"\n\t.ascii \"%c", t);
+		} else {	
+			lastoctal = 0;
+			putchar(t);
+		}
+	}
+}
+
+/*
+ * 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;
+}
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+	return p;
+}
Index: uspace/app/pcc/arch/nova/local.c
===================================================================
--- uspace/app/pcc/arch/nova/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/nova/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,650 @@
+/*	$Id: local.c,v 1.8 2011/01/21 21:47: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.
+ */
+
+
+# include "pass1.h"
+
+/*	this file contains code which is dependent on the target machine */
+
+NODE *
+clocal(NODE *p)
+{
+	struct symtab *q;
+	NODE *r, *l;
+	int o;
+
+	switch( o = p->n_op ){
+	case NAME:
+		/* handle variables */
+		if ((q = p->n_sp) == NULL)
+			return p; /* Nothing to care about */
+		switch (q->sclass) {
+		case AUTO:
+			/* fake up a structure reference */
+			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+			r->n_lval = 0;
+			r->n_rval = FPREG;
+			p = stref(block(STREF, r, p, 0, 0, 0));
+			break;
+		default:
+			break;
+		}
+		break;
+
+	case PMCONV:
+	case PVCONV:
+                if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
+                nfree(p);
+                return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
+
+	case PCONV:
+		l = p->n_left;
+		/* if conversion to another pointer type, just remove */
+		if (p->n_type > BTMASK && l->n_type > BTMASK)
+			goto delp;
+		break;
+
+	delp:	l->n_type = p->n_type;
+		l->n_qual = p->n_qual;
+		l->n_df = p->n_df;
+		l->n_sue = p->n_sue;
+		nfree(p);
+		p = l;
+		break;
+	}
+
+#if 0
+	register struct symtab *q;
+	register NODE *r, *l;
+	register int o;
+	register int m;
+	TWORD t;
+
+//printf("in:\n");
+//fwalk(p, eprint, 0);
+	switch( o = p->n_op ){
+
+	case NAME:
+		if ((q = p->n_sp) == NULL)
+			return p; /* Nothing to care about */
+
+		switch (q->sclass) {
+
+		case PARAM:
+		case AUTO:
+			/* fake up a structure reference */
+			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+			r->n_lval = 0;
+			r->n_rval = FPREG;
+			p = stref(block(STREF, r, p, 0, 0, 0));
+			break;
+
+		case STATIC:
+			if (q->slevel == 0)
+				break;
+			p->n_lval = 0;
+			p->n_sp = q;
+			break;
+
+		case REGISTER:
+			p->n_op = REG;
+			p->n_lval = 0;
+			p->n_rval = q->soffset;
+			break;
+
+			}
+		break;
+
+	case STCALL:
+	case CALL:
+		/* Fix function call arguments. On x86, just add funarg */
+		for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+			if (r->n_right->n_op != STARG &&
+			    r->n_right->n_op != FUNARG)
+				r->n_right = block(FUNARG, r->n_right, NIL, 
+				    r->n_right->n_type, r->n_right->n_df,
+				    r->n_right->n_sue);
+		}
+		if (r->n_op != STARG && r->n_op != FUNARG) {
+			l = talloc();
+			*l = *r;
+			r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type;
+		}
+		break;
+		
+	case CBRANCH:
+		l = p->n_left;
+
+		/*
+		 * Remove unnecessary conversion ops.
+		 */
+		if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
+			if (coptype(l->n_op) != BITYPE)
+				break;
+			if (l->n_right->n_op == ICON) {
+				r = l->n_left->n_left;
+				if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
+					break;
+				/* Type must be correct */
+				t = r->n_type;
+				nfree(l->n_left);
+				l->n_left = r;
+				l->n_type = t;
+				l->n_right->n_type = t;
+			}
+		}
+		break;
+
+	case PCONV:
+		/* Remove redundant PCONV's. Be careful */
+		l = p->n_left;
+		if (l->n_op == ICON) {
+			l->n_lval = (unsigned)l->n_lval;
+			goto delp;
+		}
+		if (l->n_type < INT || l->n_type == LONGLONG || 
+		    l->n_type == ULONGLONG) {
+			/* float etc? */
+			p->n_left = block(SCONV, l, NIL,
+			    UNSIGNED, 0, MKSUE(UNSIGNED));
+			break;
+		}
+		/* if left is SCONV, cannot remove */
+		if (l->n_op == SCONV)
+			break;
+		/* if conversion to another pointer type, just remove */
+		if (p->n_type > BTMASK && l->n_type > BTMASK)
+			goto delp;
+		break;
+
+	delp:	l->n_type = p->n_type;
+		l->n_qual = p->n_qual;
+		l->n_df = p->n_df;
+		l->n_sue = p->n_sue;
+		nfree(p);
+		p = l;
+		break;
+
+	case SCONV:
+		l = p->n_left;
+
+		if (p->n_type == l->n_type) {
+			nfree(p);
+			return l;
+		}
+
+		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+		    btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
+			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+			    l->n_type != FLOAT && l->n_type != DOUBLE &&
+			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+				if (l->n_op == NAME || l->n_op == UMUL ||
+				    l->n_op == TEMP) {
+					l->n_type = p->n_type;
+					nfree(p);
+					return l;
+				}
+			}
+		}
+
+		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+		    coptype(l->n_op) == BITYPE) {
+			l->n_type = p->n_type;
+			nfree(p);
+			return l;
+		}
+
+		o = l->n_op;
+		m = p->n_type;
+
+		if (o == ICON) {
+			CONSZ val = l->n_lval;
+
+			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
+			    switch (m) {
+			case CHAR:
+				l->n_lval = (char)val;
+				break;
+			case UCHAR:
+				l->n_lval = val & 0377;
+				break;
+			case SHORT:
+				l->n_lval = (short)val;
+				break;
+			case USHORT:
+				l->n_lval = val & 0177777;
+				break;
+			case ULONG:
+			case UNSIGNED:
+				l->n_lval = val & 0xffffffff;
+				break;
+			case LONG:
+			case INT:
+				l->n_lval = (int)val;
+				break;
+			case LONGLONG:
+				l->n_lval = (long long)val;
+				break;
+			case ULONGLONG:
+				l->n_lval = val;
+				break;
+			case VOID:
+				break;
+			case LDOUBLE:
+			case DOUBLE:
+			case FLOAT:
+				l->n_op = FCON;
+				l->n_dcon = val;
+				break;
+			default:
+				cerror("unknown type %d", m);
+			}
+			l->n_type = m;
+			l->n_sue = MKSUE(m);
+			nfree(p);
+			return l;
+		}
+		if (DEUNSIGN(p->n_type) == SHORT &&
+		    DEUNSIGN(l->n_type) == SHORT) {
+			nfree(p);
+			p = l;
+		}
+		if ((p->n_type == CHAR || p->n_type == UCHAR ||
+		    p->n_type == SHORT || p->n_type == USHORT) &&
+		    (l->n_type == FLOAT || l->n_type == DOUBLE ||
+		    l->n_type == LDOUBLE)) {
+			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
+			p->n_left->n_type = INT;
+			return p;
+		}
+		break;
+
+	case MOD:
+	case DIV:
+		if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
+			break;
+		if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
+			break;
+		/* make it an int division by inserting conversions */
+		p->n_left = block(SCONV, p->n_left, NIL, INT, 0, MKSUE(INT));
+		p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKSUE(INT));
+		p = block(SCONV, p, NIL, p->n_type, 0, MKSUE(p->n_type));
+		p->n_left->n_type = INT;
+		break;
+
+	case PMCONV:
+	case PVCONV:
+                if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
+                nfree(p);
+                return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
+
+	case FORCE:
+		/* put return value in return reg */
+		p->n_op = ASSIGN;
+		p->n_right = p->n_left;
+		p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
+		p->n_left->n_rval = RETREG(p->n_type);
+		break;
+
+	case LS:
+	case RS:
+		/* shift count must be in a char
+		 * unless longlong, where it must be int */
+		if (p->n_right->n_op == ICON)
+			break; /* do not do anything */
+		if (p->n_type == LONGLONG || p->n_type == ULONGLONG) {
+			if (p->n_right->n_type != INT)
+				p->n_right = block(SCONV, p->n_right, NIL,
+				    INT, 0, MKSUE(INT));
+			break;
+		}
+		if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
+			break;
+		p->n_right = block(SCONV, p->n_right, NIL,
+		    CHAR, 0, MKSUE(CHAR));
+		break;
+	}
+//printf("ut:\n");
+//fwalk(p, eprint, 0);
+
+#endif
+
+	return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+	struct symtab *sp;
+	int o = p->n_op, i;
+
+	if (o != FCON) 
+		return;
+
+	sp = inlalloc(sizeof(struct symtab));
+	sp->sclass = STATIC;
+	sp->ssue = MKSUE(p->n_type);
+	sp->slevel = 1; /* fake numeric label */
+	sp->soffset = getlab();
+	sp->sflags = 0;
+	sp->stype = p->n_type;
+	sp->squal = (CON >> TSHIFT);
+
+	defloc(sp);
+	ninval(0, sp->ssue->suesize, p);
+
+	p->n_op = NAME;
+	p->n_lval = 0;
+	p->n_sp = sp;
+
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+	return(1);  /* all names can have & taken on them */
+}
+
+/*
+ * at the end of the arguments of a ftn, set the automatic offset
+ */
+void
+cendarg()
+{
+	autooff = AUTOINIT;
+}
+
+/*
+ * Return 1 if a variable of type type is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+	return 1; /* try to put anything in a register */
+}
+
+/*
+ * return a node, for structure references, which is suitable for
+ * being added to a pointer of type t, in order to be off bits offset
+ * into a structure
+ * t, d, and s are the type, dimension offset, and sizeoffset
+ * For nova, return the type-specific index number which calculation
+ * is based on its size. For example, char a[3] would return 3.
+ * Be careful about only handling first-level pointers, the following
+ * indirections must be fullword.
+ */
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
+{
+	register NODE *p;
+
+	if (xdebug)
+		printf("offcon: OFFSZ %ld type %x dim %p siz %d\n",
+		    off, t, d, sue->suesize);
+
+	p = bcon(0);
+	p->n_lval = off/SZINT;	/* Default */
+	if (ISPTR(DECREF(t)))
+		return p;
+	if (t == VOID || t == CHAR || t == UCHAR)
+		p->n_lval = off/SZCHAR; /* pointer to char */
+	return(p);
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a NAME node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+	NODE *sp;
+
+cerror("spalloc");
+	if ((off % SZINT) == 0)
+		p =  buildtree(MUL, p, bcon(off/SZINT));
+	else if ((off % SZSHORT) == 0) {
+		p = buildtree(MUL, p, bcon(off/SZSHORT));
+		p = buildtree(PLUS, p, bcon(1));
+		p = buildtree(RS, p, bcon(1));
+	} else if ((off % SZCHAR) == 0) {
+		p = buildtree(MUL, p, bcon(off/SZCHAR));
+		p = buildtree(PLUS, p, bcon(3));
+		p = buildtree(RS, p, bcon(2));
+	} else
+		cerror("roundsp");
+
+	/* save the address of sp */
+	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	t->n_type = sp->n_type;
+	ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+	/* add the size to sp */
+	sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	ecomp(buildtree(PLUSEQ, sp, p));
+}
+
+/*
+ * print out a constant node
+ * mat be associated with a label
+ */
+void
+ninval(NODE *p)
+{
+	struct symtab *q;
+	TWORD t;
+
+	p = p->n_left;
+	t = p->n_type;
+	if (t > BTMASK)
+		t = INT; /* pointer */
+
+	if (p->n_op != ICON)
+		cerror("ninval: init node not constant");
+
+	switch (t) {
+	case LONG:
+	case ULONG:
+		inval(p->n_lval & 0xffff);
+		inval(p->n_lval >> 16);
+		break;
+	case INT:
+	case UNSIGNED:
+		printf("\t.word 0%o", (short)p->n_lval);
+		if ((q = p->n_sp) != NULL) {
+			if ((q->sclass == STATIC && q->slevel > 0)) {
+				printf("+" LABFMT, q->soffset);
+			} else
+				printf("+%s", exname(q->soname));
+		}
+		printf("\n");
+		break;
+	default:
+		cerror("ninval");
+	}
+}
+
+/*
+ * print out an integer.
+ */
+void
+inval(CONSZ word)
+{
+	word &= 0xffff;
+	printf("	.word 0%o\n", (int)word);
+}
+
+/* output code to initialize a floating point value */
+/* the proper alignment has been obtained */
+void
+finval(NODE *p)
+{
+	union { float f; double d; long double l; int i[3]; } u;
+
+cerror("finval");
+	switch (p->n_type) {
+	case LDOUBLE:
+		u.i[2] = 0;
+		u.l = (long double)p->n_dcon;
+		printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+		break;
+	case DOUBLE:
+		u.d = (double)p->n_dcon;
+		printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+		break;
+	case FLOAT:
+		u.f = (float)p->n_dcon;
+		printf("\t.long\t0x%x\n", u.i[0]);
+		break;
+	}
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+	if (p == NULL)
+		return "";
+	return p;
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+	switch (BTYPE(type)) {
+	case LONGLONG:
+		MODTYPE(type,LONG);
+		break;
+
+	case ULONGLONG:
+		MODTYPE(type,ULONG);
+		break;
+	case SHORT:
+		MODTYPE(type,INT);
+		break;
+	case USHORT:
+		MODTYPE(type,UNSIGNED);
+		break;
+	}
+	return (type);
+}
+
+/* curid is a variable which is defined but
+ * is not initialized (and not a function );
+ * This routine returns the storage class for an uninitialized declaration
+ */
+int
+noinit()
+{
+	return(EXTERN);
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+/* make a common declaration for id, if reasonable */
+void
+commdec(struct symtab *q)
+{
+	int off;
+
+	off = tsize(q->stype, q->sdf, q->ssue);
+	off = (off+(SZCHAR-1))/SZCHAR;
+	printf("	.comm %s,0%o\n", exname(q->soname), off);
+}
+
+/* make a local common declaration for id, if reasonable */
+void
+lcommdec(struct symtab *q)
+{
+	int off;
+
+	off = tsize(q->stype, q->sdf, q->ssue);
+	off = (off+(SZCHAR-1))/SZCHAR;
+	if (q->slevel == 0)
+		printf("	.lcomm %s,0%o\n", exname(q->soname), off);
+	else
+		printf("	.lcomm " LABFMT ",0%o\n", q->soffset, off);
+}
+
+/*
+ * print a (non-prog) label.
+ */
+void
+deflab1(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+static char *loctbl[] = { "text", "data", "section .rodata", "section .rodata" };
+
+void
+setloc1(int locc)
+{
+	if (locc == lastloc)
+		return;
+	lastloc = locc;
+	printf("	.%s\n", loctbl[locc]);
+}
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+	return 0;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
Index: uspace/app/pcc/arch/nova/local2.c
===================================================================
--- uspace/app/pcc/arch/nova/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/nova/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,580 @@
+/*	$Id: local2.c,v 1.7 2008/11/01 08:29:37 mickey Exp $	*/
+/*
+ * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+# include <ctype.h>
+# include <string.h>
+
+void acon(NODE *p);
+int argsize(NODE *p);
+
+void
+deflab(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+static int prolnum;
+static struct ldq {
+	struct ldq *next;
+	int val;
+	int lab;
+	char *name;
+} *ldq;
+
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+	int i, j;
+
+	for (j = i = 0; i < MAXREGS; i++)
+		if (TESTBIT(ipp->ipp_regs, i))
+			j++;
+
+	printf(".LP%d:	.word 0%o\n", prolnum, j);
+	if (ipp->ipp_vis)
+		printf("	.globl %s\n", ipp->ipp_name);
+	printf("%s:\n", ipp->ipp_name);
+	printf("	sta 3,@40\n");	/* save ret pc on stack */
+	printf("	lda 2,.LP%d-.,1\n", prolnum);
+	printf("	jsr @45\n");
+	prolnum++;
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+	int i, j;
+
+	if (ipp->ipp_ip.ip_lbl == 0)
+		return; /* no code needs to be generated */
+
+	/* return from function code */
+	for (j = i = 0; i < MAXREGS; i++)
+		if (TESTBIT(ipp->ipp_regs, i))
+			j++;
+	printf("	lda 2,.LP%d-.,1\n", prolnum);
+	printf("	jmp @46\n");
+	printf(".LP%d:	.word 0%o\n", prolnum, j);
+	prolnum++;
+	while (ldq) {
+		printf(".LP%d:	.word 0%o", ldq->lab, ldq->val);
+		if (ldq->name && *ldq->name)
+			printf("+%s", ldq->name);
+		printf("\n");
+		ldq = ldq->next;
+	}
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+	char *str = 0;
+
+	switch (o) {
+	case PLUS:
+		str = "add";
+		break;
+	case MINUS:
+		str = "sub";
+		break;
+	case AND:
+		str = "and";
+		break;
+	case OR:
+		cerror("hopcode OR");
+		break;
+	case ER:
+		cerror("hopcode xor");
+		str = "xor";
+		break;
+	default:
+		comperr("hopcode2: %d", o);
+		str = 0; /* XXX gcc */
+	}
+	printf("%s%c", str, f);
+}
+
+#if 0
+/*
+ * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(p) NODE *p;
+{
+	switch(p->n_type) {
+		case CHAR:
+		case UCHAR:
+			return(1);
+
+		case SHORT:
+		case USHORT:
+			return(SZSHORT/SZCHAR);
+
+		case DOUBLE:
+			return(SZDOUBLE/SZCHAR);
+
+		case INT:
+		case UNSIGNED:
+		case LONG:
+		case ULONG:
+			return(SZINT/SZCHAR);
+
+		case LONGLONG:
+		case ULONGLONG:
+			return SZLONGLONG/SZCHAR;
+
+		default:
+			if (!ISPTR(p->n_type))
+				comperr("tlen type %d not pointer");
+			return SZPOINT(p->n_type)/SZCHAR;
+		}
+}
+#endif
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+	return 0;
+}
+
+#if 0
+/*
+ * Assign to a bitfield.
+ * Clumsy at least, but what to do?
+ */
+static void
+bfasg(NODE *p)
+{
+	NODE *fn = p->n_left;
+	int shift = UPKFOFF(fn->n_rval);
+	int fsz = UPKFSZ(fn->n_rval);
+	int andval, tch = 0;
+
+	/* get instruction size */
+	switch (p->n_type) {
+	case CHAR: case UCHAR: tch = 'b'; break;
+	case SHORT: case USHORT: tch = 'w'; break;
+	case INT: case UNSIGNED: tch = 'l'; break;
+	default: comperr("bfasg");
+	}
+
+	/* put src into a temporary reg */
+	fprintf(stdout, "	mov%c ", tch);
+	adrput(stdout, getlr(p, 'R'));
+	fprintf(stdout, ",");
+	adrput(stdout, getlr(p, '1'));
+	fprintf(stdout, "\n");
+
+	/* AND away the bits from dest */
+	andval = ~(((1 << fsz) - 1) << shift);
+	fprintf(stdout, "	and%c $%d,", tch, andval);
+	adrput(stdout, fn->n_left);
+	fprintf(stdout, "\n");
+
+	/* AND away unwanted bits from src */
+	andval = ((1 << fsz) - 1);
+	fprintf(stdout, "	and%c $%d,", tch, andval);
+	adrput(stdout, getlr(p, '1'));
+	fprintf(stdout, "\n");
+
+	/* SHIFT left src number of bits */
+	if (shift) {
+		fprintf(stdout, "	sal%c $%d,", tch, shift);
+		adrput(stdout, getlr(p, '1'));
+		fprintf(stdout, "\n");
+	}
+
+	/* OR in src to dest */
+	fprintf(stdout, "	or%c ", tch);
+	adrput(stdout, getlr(p, '1'));
+	fprintf(stdout, ",");
+	adrput(stdout, fn->n_left);
+	fprintf(stdout, "\n");
+}
+#endif
+
+#if 0
+/*
+ * Push a structure on stack as argument.
+ * the scratch registers are already free here
+ */
+static void
+starg(NODE *p)
+{
+	FILE *fp = stdout;
+
+	fprintf(fp, "	subl $%d,%%esp\n", p->n_stsize);
+	fprintf(fp, "	pushl $%d\n", p->n_stsize);
+	expand(p, 0, "	pushl AL\n");
+	expand(p, 0, "	leal 8(%esp),A1\n");
+	expand(p, 0, "	pushl A1\n");
+	fprintf(fp, "	call memcpy\n");
+	fprintf(fp, "	addl $12,%%esp\n");
+}
+#endif
+
+void
+zzzcode(NODE *p, int c)
+{
+	struct ldq *ld;
+
+	switch (c) {
+	case 'A': /* print out a skip ending if any numbers in queue */
+		if (ldq == NULL)
+			return;
+		printf(",skp\n.LP%d:	.word 0%o", ldq->lab, ldq->val);
+		if (ldq->name && *ldq->name)
+			printf("+%s", ldq->name);
+		printf("\n");
+		ldq = ldq->next;
+		break;
+
+	case 'B': /* print a label for later load */
+		ld = tmpalloc(sizeof(struct ldq));
+		ld->val = p->n_lval;
+		ld->name = p->n_name;
+		ld->lab = prolnum++;
+		ld->next = ldq;
+		ldq = ld;
+		printf(".LP%d-.", ld->lab);
+		break;
+
+	case 'C': /* fix reference to external variable via indirection */
+		zzzcode(p->n_left, 'B');
+		break;
+
+	case 'D': /* fix reference to external variable via indirection */
+		zzzcode(p, 'B');
+		break;
+
+	default:
+		comperr("zzzcode %c", c);
+	}
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+	return(1);
+}
+
+int canaddr(NODE *);
+int
+canaddr(NODE *p)
+{
+	int o = p->n_op;
+
+	if (o==NAME || o==REG || o==ICON || o==OREG ||
+	    (o==UMUL && shumul(p->n_left, SOREG)))
+		return(1);
+	return(0);
+}
+
+/*
+ * Does the bitfield shape match?
+ */
+int
+flshape(NODE *p)
+{
+	int o = p->n_op;
+
+cerror("flshape");
+	if (o == OREG || o == REG || o == NAME)
+		return SRDIR; /* Direct match */
+	if (o == UMUL && shumul(p->n_left, 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);
+}
+
+/*
+ * Conput should only be used by e2print on Nova.
+ */
+void
+conput(FILE *fp, NODE *p)
+{
+	int val = p->n_lval;
+
+	switch (p->n_op) {
+	case ICON:
+		if (p->n_name[0] != '\0') {
+			fprintf(fp, "%s", p->n_name);
+			if (val)
+				fprintf(fp, "+%d", val);
+		} else
+			fprintf(fp, "%d", val);
+		return;
+
+	default:
+		comperr("illegal conput, p %p", p);
+	}
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+	comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+comperr("upput");
+#if 0
+	size /= SZCHAR;
+	switch (p->n_op) {
+	case REG:
+		fprintf(stdout, "%%%s", &rnames[p->n_rval][3]);
+		break;
+
+	case NAME:
+	case OREG:
+		p->n_lval += size;
+		adrput(stdout, p);
+		p->n_lval -= size;
+		break;
+	case ICON:
+		fprintf(stdout, "$" CONFMT, p->n_lval >> 32);
+		break;
+	default:
+		comperr("upput bad op %d size %d", p->n_op, size);
+	}
+#endif
+}
+
+void
+adrput(FILE *io, NODE *p)
+{
+	/* output an address, with offsets, from p */
+
+	if (p->n_op == FLD)
+		p = p->n_left;
+
+	switch (p->n_op) {
+
+	case NAME:
+		if (p->n_name[0] != '\0')
+			fputs(p->n_name, io);
+		if (p->n_lval != 0)
+			fprintf(io, "+" CONFMT, p->n_lval);
+		return;
+
+	case OREG:
+		printf("%d,%s", (int)p->n_lval, rnames[p->n_rval]);
+		return;
+
+	case ICON:
+		/* addressable value of the constant */
+		fputc('$', io);
+		conput(io, p);
+		return;
+
+	case MOVE:
+	case REG:
+		switch (p->n_type) {
+		case LONGLONG:
+		case ULONGLONG:
+			fprintf(io, "%%%c%c%c", rnames[p->n_rval][0],
+			    rnames[p->n_rval][1], rnames[p->n_rval][2]);
+			break;
+		case SHORT:
+		case USHORT:
+			fprintf(io, "%%%s", &rnames[p->n_rval][2]);
+			break;
+		default:
+			fprintf(io, "%s", rnames[p->n_rval]);
+		}
+		return;
+
+	default:
+		comperr("illegal address, op %d, node %p", p->n_op, p);
+		return;
+
+	}
+}
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+	comperr("cbgen");
+}
+
+void
+myreader(struct interpass *ipole)
+{
+	if (x2debug)
+		printip(ipole);
+}
+
+void
+mycanon(NODE *p)
+{
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+	comperr("rmove");
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ * Return true if we always can find a color.
+ */
+int
+COLORMAP(int c, int *r)
+{
+	int num;
+
+	switch (c) {
+	case CLASSA:
+		num = r[CLASSB] + r[CLASSA];
+		return num < 4;
+	case CLASSB:
+		num = r[CLASSB] + r[CLASSA];
+		return num < 2;
+	case CLASSC:
+		return r[CLASSC] < CREGCNT;
+	case CLASSD:
+		return r[CLASSD] < DREGCNT;
+	}
+	return 0; /* XXX gcc */
+}
+
+char *rnames[] = {
+	"0", "1", "2", "3",
+	"050", "051", "052", "053", "054", "055", "056", "057",
+	"060", "061", "062", "063", "064", "065", "066", "067",
+	"070", "071", "072", "073", "074", "075", "076", "077",
+	"041", "040"
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+	return CLASSA;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+	return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+	return 0;
+}
Index: uspace/app/pcc/arch/nova/macdefs.h
===================================================================
--- uspace/app/pcc/arch/nova/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/nova/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,189 @@
+/*	$Id: macdefs.h,v 1.2 2007/11/16 22:27:42 gmcgarry Exp $	*/
+/*
+ * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent defines for Data General Nova.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ */
+#define makecc(val,i)	lastcon = (lastcon<<8)|(val);
+
+#define ARGINIT		16	/* adjusted in MD code */
+#define AUTOINIT	16	/* adjusted in MD code */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR		8
+#define SZINT		16
+#define SZFLOAT		32
+#define SZDOUBLE	64
+#define SZLDOUBLE	64
+#define SZLONG		32
+#define SZSHORT		16
+#define SZLONGLONG	32
+#define SZPOINT(t)	16	/* Actually 15 */
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR		8
+#define ALINT		16
+#define ALFLOAT		16
+#define ALDOUBLE	16
+#define ALLDOUBLE	16
+#define ALLONG		16
+#define ALLONGLONG	16
+#define ALSHORT		16
+#define ALPOINT		16
+#define ALSTRUCT	16
+#define ALSTACK		16 
+
+/*
+ * Min/max values.
+ */
+#define	MIN_CHAR	-128
+#define	MAX_CHAR	127
+#define	MAX_UCHAR	255
+#define	MIN_SHORT	-32768
+#define	MAX_SHORT	32767
+#define	MAX_USHORT	65535
+#define	MIN_INT		MIN_SHORT
+#define	MAX_INT		MAX_SHORT
+#define	MAX_UNSIGNED	MAX_USHORT
+#define	MIN_LONG	0x80000000L
+#define	MAX_LONG	0x7fffffffL
+#define	MAX_ULONG	0xffffffffUL
+#define	MIN_LONGLONG	MIN_LONG
+#define	MAX_LONGLONG	MAX_LONG
+#define	MAX_ULONGLONG	MAX_ULONG
+
+/* Default char is unsigned */
+#define	CHAR_UNSIGNED
+
+/*
+ * Use large-enough types.
+ */
+typedef	long CONSZ;
+typedef	unsigned long U_CONSZ;
+typedef long OFFSZ;
+
+#define CONFMT	"%ld"		/* format for printing constants */
+#define LABFMT	".L%d"		/* format for printing labels */
+#define	STABLBL	".LL%d"		/* format for stab (debugging) labels */
+#ifdef FORTRAN
+#define XL 8
+#define	FLABELFMT "%s:\n"
+#define USETEXT ".text"
+#define USECONST ".data\t0" 	/* XXX - fix */
+#define USEBSS  ".data\t1" 	/* XXX - fix */
+#define USEINIT ".data\t2" 	/* XXX - fix */
+#define MAXREGVAR 3             /* XXX - fix */
+#define BLANKCOMMON "_BLNK_"
+#define MSKIREG  (M(TYSHORT)|M(TYLONG))
+#define TYIREG TYLONG
+#define FSZLENG  FSZLONG
+#define FUDGEOFFSET 1
+#define	AUTOREG	EBP
+#define	ARGREG	EBP
+#define ARGOFFSET 4
+#endif
+
+#define BACKAUTO 		/* stack grows negatively for automatics */
+#define BACKTEMP 		/* stack grows negatively for temporaries */
+
+#undef	FIELDOPS		/* no bit-field instructions */
+#define	RTOLBYTES		/* bytes are numbered right to left */
+
+#define ENUMSIZE(high,low) INT	/* enums are always stored in full int */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)	((x)&01)
+#define wdal(k)		(BYTEOFF(k)==0)
+#define BITOOR(x)	(x)	/* bit offset to oreg offset XXX die! */
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+#define genfcall(a,b)	gencall(a,b)
+
+#define	szty(t)	(((t) == DOUBLE || (t) == LDOUBLE) ? 4 : \
+	((t) == LONGLONG || (t) == ULONGLONG || \
+	 (t) == LONG || (t) == ULONG) ? 2 : 1)
+
+/*
+ * The Nova has three register classes.  Note that the space used in 
+ * zero page is considered registers.
+ * Register 28 and 29 are FP and SP.
+ *
+ * The classes used on Nova are:
+ *	A - AC0-AC3 (as non-index registers)	: reg 0-3
+ *	B - AC2-AC3 (as index registers)	: reg 2-3
+ *	C - address 50-77 in memory		: reg 4-27
+ */
+#define	MAXREGS	30	/* 0-29 */
+
+#define	RSTATUS	\
+	SAREG|TEMPREG, SAREG|TEMPREG, SAREG|SBREG|TEMPREG, SAREG|SBREG|TEMPREG,\
+	SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG,	\
+	SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG, SCREG|TEMPREG,	\
+	SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG,	\
+	SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG,	\
+	SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG,	\
+	SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG, SCREG|PERMREG,	\
+	0,	0
+
+#define	ROVERLAP \
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 },	\
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 },	\
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 },	\
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 },
+
+
+/* Return a register class based on the type of the node */
+/* all types in all classes */
+#define PCLASS(p) (SAREG|SBREG|SCREG)
+
+#define	NUMCLASS 	4	/* highest number of reg classes used */
+				/* XXX - must be 4 */
+
+int COLORMAP(int c, int *r);
+#define	GCLASS(x) (x < 4 ? CLASSA : CLASSC)
+#define DECRA(x,y)	(((x) >> (y*6)) & 63)	/* decode encoded regs */
+#define	ENCRD(x)	(x)		/* Encode dest reg in n_reg */
+#define ENCRA1(x)	((x) << 6)	/* A1 */
+#define ENCRA2(x)	((x) << 12)	/* A2 */
+#define ENCRA(x,y)	((x) << (6+y*6))	/* encode regs in int */
+#define	RETREG(x)	(0) /* ? Sanity */
+
+/* XXX - to die */
+#define FPREG	28	/* frame pointer */
+#define STKREG	29	/* stack pointer */
Index: uspace/app/pcc/arch/nova/order.c
===================================================================
--- uspace/app/pcc/arch/nova/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/nova/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,186 @@
+/*	$Id: order.c,v 1.4 2008/09/27 07:35:23 ragge Exp $	*/
+/*
+ * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/* is it legal to make an OREG or NAME entry which has an
+ * offset of off, (from a register of r), if the
+ * resulting thing had type t */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+	if (r != 2 && r != 3)
+		return 1; /* can only index ac2 and ac3 */
+	if (t == CHAR || t == UCHAR) {
+		if (off < -256 || off > 254)
+			return 1;
+	} else if (off < -128 || off > 127)
+		return 1;
+	return(0);  /* YES */
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ * Be careful about register classes, this is a place where classes change.
+ */
+void
+offstar(NODE *p, int shape)
+{
+	NODE *r;
+
+	if (x2debug)
+		printf("offstar(%p)\n", p);
+
+	if (isreg(p))
+		return; /* Is already OREG */
+
+	r = p->n_right;
+	if( p->n_op == PLUS || p->n_op == MINUS ){
+		if( r->n_op == ICON ){
+			if (isreg(p->n_left) == 0 ||
+			    (p->n_left->n_op == REG &&
+			    p->n_left->n_rval != 2 && p->n_left->n_rval != 3))
+				(void)geninsn(p->n_left, INBREG);
+			/* Converted in ormake() */
+			return;
+		}
+	}
+	(void)geninsn(p, INBREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *q)
+{
+	if (x2debug)
+		printf("myormake(%p)\n", q);
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int order)
+{
+
+	if (x2debug)
+		printf("shumul(%p)\n", p);
+
+	/* Turns currently anything into OREG on x86 */
+	if (shape & SOREG)
+		return SROREG;
+	return SRNOPE;
+}
+
+/*
+ * Rewrite increment/decrement operation.
+ */
+int
+setincr(NODE *p)
+{
+	if (x2debug)
+		printf("setincr(%p)\n", p);
+
+	return(0);
+}
+
+/*
+ * Rewrite operations on binary operators (like +, -, etc...).
+ * Called as a result of table lookup.
+ */
+int
+setbin(NODE *p)
+{
+
+	if (x2debug)
+		printf("setbin(%p)\n", p);
+	return 0;
+
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+	if (x2debug)
+		printf("setasg(%p)\n", p);
+	return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+	return 0;
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+	comperr("nspecial entry %d", q - table);
+	return 0; /* XXX gcc */
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+	return 0;
+}
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+	static int r[1] = { -1 }; /* Terminate with -1 */
+
+	return &r[0];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+	return 1;
+}
Index: uspace/app/pcc/arch/nova/table.c
===================================================================
--- uspace/app/pcc/arch/nova/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/nova/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1514 @@
+/*	$Id: table.c,v 1.1 2006/07/30 09:30:48 ragge Exp $	*/
+/*
+ * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+# include "pass2.h"
+
+# define ANYSIGNED TINT|TLONG|TSHORT|TCHAR
+# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TUWORD TUNSIGNED|TULONG
+# define TSWORD TINT|TLONG
+# define TWORD TUWORD|TSWORD
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		0,	RDEST,
+		"	mov AR,ALZA\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SNAME,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		0,	RDEST,
+		"	sta AR,ZC,1\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		0,	RDEST,
+		"	sta AR,AL\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SONE,	TWORD,
+		NAREG,	RESC1,
+		"	subzl A1,A1ZA\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SCON,	TWORD,
+		NAREG,	RESC1,
+		"	lda A1,ZB,1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SZERO,	TWORD,
+		NAREG,	RESC1,
+		"	sub A1,A1ZA\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SNAME,	TWORD|TPOINT,
+		NAREG,	RESC1,
+		"	lda A1,ZD,1\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SNAME,	TWORD|TPOINT,
+		NBREG,	RESC1,
+		"	lda A1,ZD,1\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SCREG,	TWORD|TPOINT,
+		NBREG,	RESC1,
+		"	lda A1,AR\n", },
+
+{ PLUS,	INBREG|INAREG,
+	SAREG|SBREG,	TWORD|TPOINT,
+	SONE,		TANY,
+		0,	RLEFT,
+		"	inc AL,AL\n", },
+
+{ OPSIMP,	INBREG|INAREG|FOREFF,
+	SAREG|SBREG,	TWORD|TPOINT,
+	SAREG|SBREG,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	O AR,AL\n", },
+
+{ UMUL,	INAREG,
+	SANY,	TPOINT|TWORD,
+	SOREG,	TPOINT|TWORD,
+		NAREG|NASL,	RESC1,
+		"	lda A1,AL\n", },
+
+#if 0
+
+/* PCONVs are usually not necessary */
+{ PCONV,	INAREG,
+	SAREG,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		0,	RLEFT,
+		"", },
+
+/*
+ * A bunch conversions of integral<->integral types
+ * There are lots of them, first in table conversions to itself
+ * and then conversions from each type to the others.
+ */
+
+/* itself to itself, including pointers */
+
+/* convert (u)char to (u)char. */
+{ SCONV,	INCH,
+	SHCH,	TCHAR|TUCHAR,
+	SHCH,	TCHAR|TUCHAR,
+		0,	RLEFT,
+		"", },
+
+/* convert pointers to int. */
+{ SCONV,	ININT,
+	SHINT,	TPOINT|TWORD,
+	SANY,	TWORD,
+		0,	RLEFT,
+		"", },
+
+/* convert (u)longlong to (u)longlong. */
+{ SCONV,	INLL,
+	SHLL,	TLL,
+	SHLL,	TLL,
+		0,	RLEFT,
+		"", },
+
+/* convert double <-> float. nothing to do here */
+{ SCONV,	INFL,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"", },
+
+/* convert pointers to pointers. */
+{ SCONV,	ININT,
+	SHINT,	TPOINT,
+	SANY,	TPOINT,
+		0,	RLEFT,
+		"", },
+
+/* char to something */
+
+/* convert char to (unsigned) short. */
+{ SCONV,	ININT,
+	SBREG|SOREG|SNAME,	TCHAR,
+	SAREG,	TSHORT|TUSHORT,
+		NASL|NAREG,	RESC1,
+		"	movsbw AL,A1\n", },
+
+/* convert unsigned char to (u)short. */
+{ SCONV,	ININT,
+	SHCH|SOREG|SNAME,	TUCHAR,
+	SAREG,	TSHORT|TUSHORT,
+		NASL|NAREG,	RESC1,
+		"	movzbw AL,A1\n", },
+
+/* convert signed char to int (or pointer). */
+{ SCONV,	ININT,
+	SHCH|SOREG|SNAME,	TCHAR,
+	SAREG,	TWORD|TPOINT,
+		NASL|NAREG,	RESC1,
+		"	movsbl AL,A1\n", },
+
+/* convert unsigned char to (u)int. */
+{ SCONV,	ININT,
+	SHCH|SOREG|SNAME,	TUCHAR,
+	SAREG,	TWORD,
+		NASL|NAREG,	RESC1,
+		"	movzbl AL,A1\n", },
+
+/* convert char to (u)long long */
+{ SCONV,	INLL,
+	SHCH|SOREG|SNAME,	TCHAR,
+	SANY,	TLL,
+		NSPECIAL|NAREG|NASL,	RESC1,
+		"	movsbl AL,%eax\n	cltd\n", },
+
+/* convert unsigned char to (u)long long */
+{ SCONV,	INLL,
+	SHCH|SOREG|SNAME,	TUCHAR,
+	SANY,			TLL,
+		NCREG|NCSL,	RESC1,
+		"	movzbl AL,A1\n	xorl U1,U1\n", },
+
+/* convert char (in register) to double XXX - use NTEMP */
+{ SCONV,	INFL,
+	SHCH|SOREG|SNAME,	TCHAR,
+	SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
+		NAREG|NASL|NDREG,	RESC2,
+		"	movsbl AL,A1\n	pushl A1\n"
+		"	fildl (%esp)\n	addl $4,%esp\n", },
+
+/* convert (u)char (in register) to double XXX - use NTEMP */
+{ SCONV,	INFL,
+	SHCH|SOREG|SNAME,	TUCHAR,
+	SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
+		NAREG|NASL|NDREG,	RESC2,
+		"	movzbl AL,A1\n	pushl A1\n"
+		"	fildl (%esp)\n	addl $4,%esp\n", },
+
+/* short to something */
+
+/* convert short (in memory) to char */
+{ SCONV,	INCH,
+	SNAME|SOREG,	TSHORT|TUSHORT,
+	SHCH,		TCHAR|TUCHAR,
+		NBREG|NBSL,	RESC1,
+		"	movb AL,A1\n", },
+
+/* convert short (in reg) to char. */
+{ SCONV,	INCH,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL|NBREG|NBSL,	RESC1,
+		"ZM", },
+
+/* convert short to (u)int. */
+{ SCONV,	ININT,
+	SAREG|SOREG|SNAME,	TSHORT,
+	SAREG,	TWORD,
+		NASL|NAREG,	RESC1,
+		"	movswl AL,A1\n", },
+
+/* convert unsigned short to (u)int. */
+{ SCONV,	ININT,
+	SAREG|SOREG|SNAME,	TUSHORT,
+	SAREG,	TWORD,
+		NASL|NAREG,	RESC1,
+		"	movzwl AL,A1\n", },
+
+/* convert short to (u)long long */
+{ SCONV,	INLL,
+	SAREG|SOREG|SNAME,	TSHORT,
+	SHLL,			TLL,
+		NSPECIAL|NCREG|NCSL,	RESC1,
+		"	movswl AL,%eax\n	cltd\n", },
+
+/* convert unsigned short to (u)long long */
+{ SCONV,	INLL,
+	SAREG|SOREG|SNAME,	TUSHORT,
+	SHLL,			TLL,
+		NCREG|NCSL,	RESC1,
+		"	movzwl AL,A1\n	xorl U1,U1\n", },
+
+/* convert short (in memory) to float/double */
+{ SCONV,	INFL,
+	SOREG|SNAME,	TSHORT,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NDREG,	RESC1,
+		"	fild AL\n", },
+
+/* convert short (in register) to float/double */
+{ SCONV,	INFL,
+	SAREG,	TSHORT,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NTEMP|NDREG,	RESC1,
+		"	pushw AL\n	fild (%esp)\n	addl $2,%esp\n", },
+
+/* convert unsigned short to double XXX - use NTEMP */
+{ SCONV,	INFL,
+	SAREG|SOREG|SNAME,	TUSHORT,
+	SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
+		NAREG|NASL|NDREG|NTEMP,	RESC2,
+		"	movzwl AL,A1\n	pushl A1\n"
+		"	fildl (%esp)\n	addl $4,%esp\n", },
+
+/* int to something */
+
+/* convert int to char. This is done when register is loaded */
+{ SCONV,	INCH,
+	SAREG,	TWORD,
+	SANY,	TCHAR|TUCHAR,
+		NSPECIAL|NBREG|NBSL,	RESC1,
+		"ZM", },
+
+/* convert int to short. Nothing to do */
+{ SCONV,	INAREG,
+	SAREG,	TWORD,
+	SANY,	TSHORT|TUSHORT,
+		0,	RLEFT,
+		"", },
+
+/* convert int to long long */
+{ SCONV,	INLL,
+	SAREG,	TWORD|TPOINT,
+	SCREG,	TLONGLONG,
+		NSPECIAL|NCREG|NCSL,	RESC1,
+		"	cltd\n", },
+
+/* convert int to unsigned long long */
+{ SCONV,	INLL,
+	SAREG|SOREG|SNAME,	TWORD|TPOINT,
+	SHLL,	TULONGLONG,
+		NCSL|NCREG,	RESC1,
+		"	movl AL,A1\n	xorl U1,U1\n", },
+
+/* convert int (in memory) to double */
+{ SCONV,	INFL,
+	SOREG|SNAME,	TWORD,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NDREG,	RESC1,
+		"	fildl AL\n", },
+
+/* convert int (in register) to double */
+{ SCONV,	INFL,
+	SAREG,	TWORD,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NTEMP|NDREG,	RESC1,
+		"	pushl AL\n	fildl (%esp)\n	addl $4,%esp\n", },
+
+/* long long to something */
+
+/* convert (u)long long to (u)char (mem->reg) */
+{ SCONV,	INCH,
+	SOREG|SNAME,	TLL,
+	SANY,	TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	movb AL,A1\n", },
+
+/* convert (u)long long to (u)char (reg->reg, hopefully nothing) */
+{ SCONV,	INCH,
+	SHLL,	TLL,
+	SANY,	TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"ZS", },
+
+/* convert (u)long long to (u)short (mem->reg) */
+{ SCONV,	INAREG,
+	SOREG|SNAME,	TLL,
+	SAREG,	TSHORT|TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	movw AL,A1\n", },
+
+/* convert (u)long long to (u)short (reg->reg, hopefully nothing) */
+{ SCONV,	INAREG,
+	SHLL|SOREG|SNAME,	TLL,
+	SAREG,	TSHORT|TUSHORT,
+		NAREG|NASL,	RESC1,
+		"ZS", },
+
+/* convert long long to int (mem->reg) */
+{ SCONV,	INAREG,
+	SOREG|SNAME,	TLL,
+	SAREG,	TWORD|TPOINT,
+		NAREG|NASL,	RESC1,
+		"	movl AL,A1\n", },
+
+/* convert long long to int (reg->reg, hopefully nothing) */
+{ SCONV,	INAREG,
+	SHLL|SOREG|SNAME,	TLL,
+	SAREG,	TWORD|TPOINT,
+		NAREG|NASL,	RESC1,
+		"ZS", },
+
+/* convert long long (in memory) to floating */
+{ SCONV,	INFL,
+	SOREG|SNAME,	TLONGLONG,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NDREG,	RESC1,
+		"	fildq AL\n", },
+
+/* convert long long (in register) to floating */
+{ SCONV,	INFL,
+	SHLL,	TLONGLONG,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NTEMP|NDREG,	RESC1,
+		"	pushl UL\n	pushl AL\n"
+		"	fildq (%esp)\n	addl $8,%esp\n", },
+
+/* convert unsigned long long to floating */
+{ SCONV,	INFL,
+	SCREG,	TULONGLONG,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NDREG,	RESC1,
+		"ZJ", },
+
+/* float to something */
+
+#if 0 /* go via int by adding an extra sconv in clocal() */
+/* convert float/double to (u) char. XXX should use NTEMP here */
+{ SCONV,	INCH,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SHCH,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NBREG,	RESC1,
+		"	subl $4,%esp\n	fistpl (%esp)\n	popl A1\n", },
+
+/* convert float/double to (u) int/short/char. XXX should use NTEMP here */
+{ SCONV,	INCH,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SHCH,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NCREG,	RESC1,
+		"	subl $4,%esp\n	fistpl (%esp)\n	popl A1\n", },
+#endif
+
+/* convert float/double to (u)int. XXX should use NTEMP here */
+{ SCONV,	INAREG,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SAREG,	TWORD,
+		NAREG,	RESC1,
+		"	subl $4,%esp\n	fistpl (%esp)\n	popl A1\n", },
+
+/* convert float/double (in register) to (unsigned) long long */
+/* XXX - unsigned is not handled correct */
+{ SCONV,	INLL,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SHLL,	TLONGLONG|TULONGLONG,
+		NCREG,	RESC1,
+		"	subl $8,%esp\n	fistpq (%esp)\n"
+		"	popl A1\n	popl U1\n", },
+
+/* slut sconv */
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,		FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	call CL\nZC", },
+
+{ UCALL,	FOREFF,
+	SCON,	TANY,
+	SAREG,	TWORD|TPOINT,
+		0,	0,
+		"	call CL\n", },
+
+{ CALL,	INAREG,
+	SCON,	TANY,
+	SAREG,	TWORD|TPOINT,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	call CL\nZC", },
+
+{ UCALL,	INAREG,
+	SCON,	TANY,
+	SAREG,	TWORD|TPOINT,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	call CL\n", },
+
+{ CALL,	INBREG,
+	SCON,	TANY,
+	SBREG,	TCHAR|TUCHAR,
+		NBREG,	RESC1,	/* should be 0 */
+		"	call CL\nZC", },
+
+{ UCALL,	INBREG,
+	SCON,	TANY,
+	SBREG,	TCHAR|TUCHAR,
+		NBREG,	RESC1,	/* should be 0 */
+		"	call CL\n", },
+
+{ CALL,		INCREG,
+	SCON,	TANY,
+	SCREG,	TANY,
+		NCREG|NCSL,	RESC1,	/* should be 0 */
+		"	call CL\nZC", },
+
+{ UCALL,	INCREG,
+	SCON,	TANY,
+	SCREG,	TANY,
+		NCREG|NCSL,	RESC1,	/* should be 0 */
+		"	call CL\n", },
+
+{ CALL,	INDREG,
+	SCON,	TANY,
+	SDREG,	TANY,
+		NDREG|NDSL,	RESC1,	/* should be 0 */
+		"	call CL\nZC", },
+
+{ UCALL,	INDREG,
+	SCON,	TANY,
+	SDREG,	TANY,
+		NDREG|NDSL,	RESC1,	/* should be 0 */
+		"	call CL\nZC", },
+
+{ CALL,		FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	call *AL\nZC", },
+
+{ UCALL,	FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	call *AL\nZC", },
+
+{ CALL,		INAREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ UCALL,	INAREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ CALL,		INBREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NBREG|NBSL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ UCALL,	INBREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NBREG|NBSL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ CALL,		INCREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NCREG|NCSL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ UCALL,	INCREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NCREG|NCSL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ CALL,		INDREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NDREG|NDSL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+{ UCALL,	INDREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NDREG|NDSL,	RESC1,	/* should be 0 */
+		"	call *AL\nZC", },
+
+/* struct return */
+{ USTCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	0,
+		"ZP	call CL\nZC", },
+
+{ USTCALL,	INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"ZP	call CL\nZC", },
+
+{ USTCALL,	INAREG,
+	SNAME|SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"ZP	call *AL\nZC", },
+
+{ STCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	0,
+		"ZP	call CL\nZC", },
+
+{ STCALL,	INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"ZP	call CL\nZC", },
+
+{ STCALL,	INAREG,
+	SNAME|SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"ZP	call *AL\nZC", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+/* Special treatment for long long */
+{ PLUS,		INLL|FOREFF,
+	SHLL,		TLL,
+	SHLL|SNAME|SOREG,	TLL,
+		0,	RLEFT,
+		"	addl AR,AL\n	adcl UR,UL\n", },
+
+/* Special treatment for long long  XXX - fix commutative check */
+{ PLUS,		INLL|FOREFF,
+	SHLL|SNAME|SOREG,	TLL,
+	SHLL,			TLL,
+		0,	RRIGHT,
+		"	addl AL,AR\n	adcl UL,UR\n", },
+
+{ PLUS,		INFL,
+	SHFL,		TDOUBLE,
+	SNAME|SOREG,	TDOUBLE,
+		0,	RLEFT,
+		"	faddl AR\n", },
+
+{ PLUS,		INFL|FOREFF,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"	faddp\n", },
+
+{ PLUS,		INAREG,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SONE,	TANY,
+		0,	RLEFT,
+		"	incl AL\n", },
+
+{ PLUS,		INAREG,
+	SAREG,	TWORD|TPOINT,
+	SCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	leal CR(AL),A1\n", },
+
+{ PLUS,		INCH,
+	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
+	SONE,	TANY,
+		0,	RLEFT,
+		"	incb AL\n", },
+
+{ PLUS,		INAREG,
+	SAREG,	TWORD,
+	SAREG,	TWORD,
+		NAREG|NASL|NASR,	RESC1,
+		"	leal (AL,AR),A1\n", },
+
+
+/* address as register offset, negative */
+{ MINUS,	INAREG,
+	SAREG,	TWORD|TPOINT,
+	SPCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	leal -CR(AL),A1\n", },
+
+{ MINUS,	INLL|FOREFF,
+	SHLL,	TLL,
+	SHLL|SNAME|SOREG,	TLL,
+		0,	RLEFT,
+		"	subl AR,AL\n	sbbl UR,UL\n", },
+
+{ MINUS,	INFL,
+	SHFL,	TDOUBLE,
+	SNAME|SOREG,	TDOUBLE,
+		0,	RLEFT,
+		"	fsubl AR\n", },
+
+{ MINUS,	INFL|FOREFF,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"	fsubZAp\n", },
+
+/* Simple r/m->reg ops */
+{ OPSIMP,	INAREG|FOREFF,
+	SAREG,			TWORD|TPOINT,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	Ol AR,AL\n", },
+
+{ OPSIMP,	INAREG|FOREFF,
+	SHINT,		TSHORT|TUSHORT,
+	SHINT|SNAME|SOREG,	TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	Ow AR,AL\n", },
+
+{ OPSIMP,	INCH|FOREFF,
+	SHCH,		TCHAR|TUCHAR,
+	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
+		0,	RLEFT,
+		"	Ob AR,AL\n", },
+
+{ OPSIMP,	INAREG|FOREFF,
+	SAREG,	TWORD|TPOINT,
+	SCON,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	Ol AR,AL\n", },
+
+{ OPSIMP,	INAREG|FOREFF,
+	SHINT|SNAME|SOREG,	TSHORT|TUSHORT,
+	SCON,	TANY,
+		0,	RLEFT,
+		"	Ow AR,AL\n", },
+
+{ OPSIMP,	INCH|FOREFF,
+	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
+	SCON,	TANY,
+		0,	RLEFT,
+		"	Ob AR,AL\n", },
+
+{ OPSIMP,	INLL|FOREFF,
+	SHLL,	TLL,
+	SHLL|SNAME|SOREG,	TLL,
+		0,	RLEFT,
+		"	Ol AR,AL\n	Ol UR,UL\n", },
+
+
+/*
+ * The next rules handle all shift operators.
+ */
+/* (u)longlong left shift is emulated */
+{ LS,	INCREG,
+	SCREG|SNAME|SOREG|SCON, TLL,
+	SAREG|SNAME|SOREG|SCON, TINT, /* will be int */
+		NSPECIAL|NCREG|NCSL|NCSR,	RESC1,
+		"ZO", },
+
+{ LS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TWORD,
+	SHCH,		TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	sall AR,AL\n", },
+
+{ LS,	INAREG|FOREFF,
+	SAREG,	TWORD,
+	SCON,	TANY,
+		0,	RLEFT,
+		"	sall AR,AL\n", },
+
+{ LS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	shlw AR,AL\n", },
+
+{ LS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SCON,	TANY,
+		0,	RLEFT,
+		"	shlw AR,AL\n", },
+
+{ LS,	INCH|FOREFF,
+	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	salb AR,AL\n", },
+
+{ LS,	INCH|FOREFF,
+	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
+	SCON,			TANY,
+		0,	RLEFT,
+		"	salb AR,AL\n", },
+
+/* (u)longlong right shift is emulated */
+{ RS,	INCREG,
+	SCREG|SNAME|SOREG|SCON, TLL,
+	SAREG|SNAME|SOREG|SCON, TINT, /* will be int */
+		NSPECIAL|NCREG|NCSL|NCSR,	RESC1,
+		"ZO", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSWORD,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	sarl AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSWORD,
+	SCON,			TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+		0,		RLEFT,
+		"	sarl AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TUWORD,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	shrl AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TUWORD,
+	SCON,			TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+		0,		RLEFT,
+		"	shrl AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	sarw AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT,
+	SCON,			TANY,
+		0,		RLEFT,
+		"	sarw AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TUSHORT,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	shrw AR,AL\n", },
+
+{ RS,	INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TUSHORT,
+	SCON,			TANY,
+		0,		RLEFT,
+		"	shrw AR,AL\n", },
+
+{ RS,	INCH|FOREFF,
+	SHCH|SNAME|SOREG,	TCHAR,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	sarb AR,AL\n", },
+
+{ RS,	INCH|FOREFF,
+	SHCH|SNAME|SOREG,	TCHAR,
+	SCON,			TANY,
+		0,		RLEFT,
+		"	sarb AR,AL\n", },
+
+{ RS,	INCH|FOREFF,
+	SHCH|SNAME|SOREG,	TUCHAR,
+	SHCH,			TCHAR|TUCHAR,
+		NSPECIAL,	RLEFT,
+		"	shrb AR,AL\n", },
+
+{ RS,	INCH|FOREFF,
+	SHCH|SNAME|SOREG,	TUCHAR,
+	SCON,			TANY,
+		0,		RLEFT,
+		"	shrb AR,AL\n", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+{ ASSIGN,	FOREFF,
+	SHLL|SNAME|SOREG,	TLL,
+	SCON,		TANY,
+		0,	0,
+		"	movl AR,AL\n	movl UR,UL\n", },
+
+{ ASSIGN,	FOREFF|INLL,
+	SHLL,		TLL,
+	SCON,		TANY,
+		0,	RDEST,
+		"	movl AR,AL\n	movl UR,UL\n", },
+
+{ ASSIGN,	FOREFF,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SCON,		TANY,
+		0,	0,
+		"	movl AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TWORD|TPOINT,
+	SCON,		TANY,
+		0,	RDEST,
+		"	movl AR,AL\n", },
+
+{ ASSIGN,	FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SCON,		TANY,
+		0,	0,
+		"	movw AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SCON,		TANY,
+		0,	RDEST,
+		"	movw AR,AL\n", },
+
+{ ASSIGN,	FOREFF,
+	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
+	SCON,		TANY,
+		0,	0,
+		"	movb AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INCH,
+	SHCH,		TCHAR|TUCHAR,
+	SCON,		TANY,
+		0,	RDEST,
+		"	movb AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INLL,
+	SHLL|SNAME|SOREG,	TLL,
+	SHLL,			TLL,
+		0,	RDEST,
+		"	movl AR,AL\n	movl UR,UL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SAREG,		TWORD|TPOINT,
+		0,	RDEST,
+		"	movl AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,			TWORD|TPOINT,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+		0,	RDEST,
+		"	movl AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+	SAREG,		TSHORT|TUSHORT,
+		0,	RDEST,
+		"	movw AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INCH,
+	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
+	SHCH,		TCHAR|TUCHAR|TWORD,
+		0,	RDEST,
+		"	movb AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,		TANY,
+	SAREG,	TANY,
+		NAREG,	RDEST,
+		"ZE", },
+
+{ ASSIGN,	FOREFF,
+	SFLD,		TANY,
+	SAREG|SNAME|SOREG|SCON,	TANY,
+		NAREG,	0,
+		"ZE", },
+
+{ ASSIGN,	INDREG|FOREFF,
+	SHFL,	TFLOAT|TDOUBLE|TLDOUBLE,
+	SHFL,	TFLOAT|TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"", }, /* This will always be in the correct register */
+
+/* order of table entries is very important here! */
+{ ASSIGN,	INFL,
+	SNAME|SOREG,	TLDOUBLE,
+	SHFL,	TFLOAT|TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"	fstt AL\n", },
+
+{ ASSIGN,	FOREFF,
+	SNAME|SOREG,	TLDOUBLE,
+	SHFL,	TFLOAT|TDOUBLE|TLDOUBLE,
+		0,	0,
+		"	fstpt AL\n", },
+
+{ ASSIGN,	INFL,
+	SNAME|SOREG,	TDOUBLE,
+	SHFL,	TFLOAT|TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"	fstl AL\n", },
+
+{ ASSIGN,	FOREFF,
+	SNAME|SOREG,	TDOUBLE,
+	SHFL,	TFLOAT|TDOUBLE|TLDOUBLE,
+		0,	0,
+		"	fstpl AL\n", },
+
+{ ASSIGN,	INFL,
+	SNAME|SOREG,	TFLOAT,
+	SHFL,	TFLOAT|TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"	fsts AL\n", },
+
+{ ASSIGN,	FOREFF,
+	SNAME|SOREG,	TFLOAT,
+	SHFL,	TFLOAT|TDOUBLE|TLDOUBLE,
+		0,	0,
+		"	fstps AL\n", },
+/* end very important order */
+
+{ ASSIGN,	INFL|FOREFF,
+	SHFL,		TLDOUBLE,
+	SHFL|SOREG|SNAME,	TLDOUBLE,
+		0,	RDEST,
+		"	fldt AR\n", },
+
+{ ASSIGN,	INFL|FOREFF,
+	SHFL,		TDOUBLE,
+	SHFL|SOREG|SNAME,	TDOUBLE,
+		0,	RDEST,
+		"	fldl AR\n", },
+
+{ ASSIGN,	INFL|FOREFF,
+	SHFL,		TFLOAT,
+	SHFL|SOREG|SNAME,	TFLOAT,
+		0,	RDEST,
+		"	flds AR\n", },
+
+/* Do not generate memcpy if return from funcall */
+#if 0
+{ STASG,	INAREG|FOREFF,
+	SOREG|SNAME|SAREG,	TPTRTO|TSTRUCT,
+	SFUNCALL,	TPTRTO|TSTRUCT,
+		0,	RRIGHT,
+		"", },
+#endif
+
+{ STASG,	INAREG|FOREFF,
+	SOREG|SNAME,	TANY,
+	SAREG|SOREG|SNAME,	TPTRTO|TANY,
+		NSPECIAL,	RRIGHT,
+		"ZQ", },
+
+/*
+ * DIV/MOD/MUL 
+ */
+/* long long div is emulated */
+{ DIV,	INCREG,
+	SCREG|SNAME|SOREG|SCON, TLL,
+	SCREG|SNAME|SOREG|SCON, TLL,
+		NSPECIAL|NCREG|NCSL|NCSR,	RESC1,
+		"ZO", },
+
+{ DIV,	INAREG,
+	SAREG,			TSWORD,
+	SAREG|SNAME|SOREG,	TWORD,
+		NSPECIAL,	RDEST,
+		"	cltd\n	idivl AR\n", },
+
+{ DIV,	INAREG,
+	SAREG,			TUWORD|TPOINT,
+	SAREG|SNAME|SOREG,	TUWORD|TPOINT,
+		NSPECIAL,	RDEST,
+		"	xorl %edx,%edx\n	divl AR\n", },
+
+{ DIV,	INAREG,
+	SAREG,			TUSHORT,
+	SAREG|SNAME|SOREG,	TUSHORT,
+		NSPECIAL,	RDEST,
+		"	xorl %edx,%edx\n	divw AR\n", },
+
+{ DIV,	INCH,
+	SHCH,			TUCHAR,
+	SHCH|SNAME|SOREG,	TUCHAR,
+		NSPECIAL,	RDEST,
+		"	xorb %ah,%ah\n	divb AR\n", },
+
+{ DIV,	INFL,
+	SHFL,		TDOUBLE,
+	SNAME|SOREG,	TDOUBLE,
+		0,	RLEFT,
+		"	fdivl AR\n", },
+
+{ DIV,	INFL,
+	SHFL,		TLDOUBLE|TDOUBLE|TFLOAT,
+	SHFL,		TLDOUBLE|TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"	fdivZAp\n", },
+
+/* (u)longlong mod is emulated */
+{ MOD,	INCREG,
+	SCREG|SNAME|SOREG|SCON, TLL,
+	SCREG|SNAME|SOREG|SCON, TLL,
+		NSPECIAL|NCREG|NCSL|NCSR,	RESC1,
+		"ZO", },
+
+{ MOD,	INAREG,
+	SAREG,			TSWORD,
+	SAREG|SNAME|SOREG,	TSWORD,
+		NAREG|NSPECIAL,	RESC1,
+		"	cltd\n	idivl AR\n", },
+
+{ MOD,	INAREG,
+	SAREG,			TUWORD|TPOINT,
+	SAREG|SNAME|SOREG,	TUWORD|TPOINT,
+		NAREG|NSPECIAL,	RESC1,
+		"	xorl %edx,%edx\n	divl AR\n", },
+
+{ MOD,	INAREG,
+	SAREG,			TUSHORT,
+	SAREG|SNAME|SOREG,	TUSHORT,
+		NAREG|NSPECIAL,	RESC1,
+		"	xorl %edx,%edx\n	divw AR\n", },
+
+{ MOD,	INCH,
+	SHCH,			TUCHAR,
+	SHCH|SNAME|SOREG,	TUCHAR,
+		NBREG|NSPECIAL,	RESC1,
+		"	xorb %ah,%ah\n	divb AR\n", },
+
+/* (u)longlong mul is emulated */
+{ MUL,	INCREG,
+	SCREG|SNAME|SOREG|SCON, TLL,
+	SCREG|SNAME|SOREG|SCON, TLL,
+		NSPECIAL|NCREG|NCSL|NCSR,	RESC1,
+		"ZO", },
+
+{ MUL,	INAREG,
+	SAREG,				TWORD|TPOINT,
+	SAREG|SNAME|SOREG|SCON,		TWORD|TPOINT,
+		0,	RLEFT,
+		"	imull AR,AL\n", },
+
+{ MUL,	INAREG,
+	SAREG,			TSHORT|TUSHORT,
+	SAREG|SNAME|SOREG,	TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	imulw AR,AL\n", },
+
+{ MUL,	INCH,
+	SHCH,			TCHAR|TUCHAR,
+	SHCH|SNAME|SOREG,	TCHAR|TUCHAR,
+		NSPECIAL,	RDEST,
+		"	imulb AR\n", },
+
+{ MUL,	INFL,
+	SHFL,		TDOUBLE,
+	SNAME|SOREG,	TDOUBLE,
+		0,	RLEFT,
+		"	fmull AR\n", },
+
+{ MUL,	INFL,
+	SHFL,		TLDOUBLE|TDOUBLE|TFLOAT,
+	SHFL,		TLDOUBLE|TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"	fmulp\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL,	INLL,
+	SANY,	TANY,
+	SOREG,	TLL,
+		NCREG|NCSL,	RESC1,
+		"	movl UL,U1\n	movl AL,A1\n", },
+
+{ UMUL,	INAREG,
+	SANY,	TPOINT|TWORD,
+	SOREG,	TPOINT|TWORD,
+		NAREG|NASL,	RESC1,
+		"	movl AL,A1\n", },
+
+{ UMUL,	INCH,
+	SANY,	TANY,
+	SOREG,	TCHAR|TUCHAR,
+		NBREG|NBSL,	RESC1,
+		"	movb AL,A1\n", },
+
+{ UMUL,	INAREG,
+	SANY,	TANY,
+	SOREG,	TSHORT|TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	movw AL,A1\n", },
+
+{ UMUL,	INFL,
+	SANY,	TANY,
+	SOREG,	TLDOUBLE,
+		NDREG|NDSL,	RESC1,
+		"	fldt AL\n", },
+
+{ UMUL,	INFL,
+	SANY,	TANY,
+	SOREG,	TDOUBLE,
+		NDREG|NDSL,	RESC1,
+		"	fldl AL\n", },
+
+{ UMUL,	INFL,
+	SANY,	TANY,
+	SOREG,	TFLOAT,
+		NDREG|NDSL,	RESC1,
+		"	flds AL\n", },
+
+/*
+ * Logical/branching operators
+ */
+
+/* Comparisions, take care of everything */
+{ OPLOG,	FORCC,
+	SHLL|SOREG|SNAME,	TLL,
+	SHLL,			TLL,
+		0,	0,
+		"ZD", },
+
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME,	TWORD|TPOINT,
+	SCON|SAREG,	TWORD|TPOINT,
+		0, 	RESCC,
+		"	cmpl AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SCON|SAREG,	TWORD|TPOINT,
+	SAREG|SOREG|SNAME,	TWORD|TPOINT,
+		0, 	RESCC,
+		"	cmpl AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME,	TSHORT|TUSHORT,
+	SCON|SAREG,	TANY,
+		0, 	RESCC,
+		"	cmpw AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SBREG|SOREG|SNAME,	TCHAR|TUCHAR,
+	SCON|SBREG,	TANY,
+		0, 	RESCC,
+		"	cmpb AR,AL\n", },
+
+{ OPLOG,	FORCC,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NSPECIAL, 	0,
+		"ZG", },
+
+{ OPLOG,	FORCC,
+	SOREG|SNAME,	TDOUBLE|TFLOAT,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+		NSPECIAL, 	0,
+		"ZG", },
+
+#if 0
+/* Ppro and later only */
+{ OPLOG,	FORCC,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SDREG,	TLDOUBLE|TDOUBLE|TFLOAT,
+		0, 	RESCC,
+		"ZA	fucomip %st,%st(1)\n", },
+#endif
+
+{ OPLOG,	FORCC,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"diediedie!", },
+
+/* AND/OR/ER/NOT */
+{ AND,	INAREG|FOREFF,
+	SAREG|SOREG|SNAME,	TWORD,
+	SCON|SAREG,		TWORD,
+		0,	RLEFT,
+		"	andl AR,AL\n", },
+
+{ AND,	INCREG|FOREFF,
+	SCREG,			TLL,
+	SCREG|SOREG|SNAME,	TLL,
+		0,	RLEFT,
+		"	andl AR,AL\n	andl UR,UL\n", },
+
+{ AND,	INAREG|FOREFF,
+	SAREG,			TWORD,
+	SAREG|SOREG|SNAME,	TWORD,
+		0,	RLEFT,
+		"	andl AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,  
+	SAREG|SOREG|SNAME,	TSHORT|TUSHORT,
+	SCON|SAREG,		TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	andw AR,AL\n", },
+
+{ AND,	INAREG|FOREFF,  
+	SAREG,			TSHORT|TUSHORT,
+	SAREG|SOREG|SNAME,	TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	andw AR,AL\n", },
+
+{ AND,	INBREG|FOREFF,
+	SBREG|SOREG|SNAME,	TCHAR|TUCHAR,
+	SCON|SBREG,		TCHAR|TUCHAR,
+		0,	RLEFT,
+		"	andb AR,AL\n", },
+
+{ AND,	INBREG|FOREFF,
+	SBREG,			TCHAR|TUCHAR,
+	SBREG|SOREG|SNAME,	TCHAR|TUCHAR,
+		0,	RLEFT,
+		"	andb AR,AL\n", },
+/* AND/OR/ER/NOT */
+
+/*
+ * Jumps.
+ */
+{ GOTO, 	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	jmp LL\n", },
+
+#ifdef GCC_COMPAT
+{ GOTO, 	FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	jmp *AL\n", },
+#endif
+
+/*
+ * Convert LTYPE to reg.
+ */
+{ OPLTYPE,	INLL,
+	SANY,	TANY,
+	SCREG|SCON|SOREG|SNAME,	TLL,
+		NCREG,	RESC1,
+		"	movl UL,U1\n	movl AL,A1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SAREG|SCON|SOREG|SNAME,	TWORD|TPOINT,
+		NAREG|NASL,	RESC1,
+		"	movl AL,A1\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SBREG|SOREG|SNAME|SCON,	TCHAR|TUCHAR,
+		NBREG,	RESC1,
+		"	movb AL,A1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SAREG|SOREG|SNAME|SCON,	TSHORT|TUSHORT,
+		NAREG,	RESC1,
+		"	movw AL,A1\n", },
+
+{ OPLTYPE,	INDREG,
+	SANY,		TLDOUBLE,
+	SOREG|SNAME,	TLDOUBLE,
+		NDREG,	RESC1,
+		"	fldt AL\n", },
+
+{ OPLTYPE,	INDREG,
+	SANY,		TDOUBLE,
+	SOREG|SNAME,	TDOUBLE,
+		NDREG,	RESC1,
+		"	fldl AL\n", },
+
+{ OPLTYPE,	INDREG,
+	SANY,		TFLOAT,
+	SOREG|SNAME,	TFLOAT,
+		NDREG,	RESC1,
+		"	flds AL\n", },
+
+/* Only used in ?: constructs. The stack already contains correct value */
+{ OPLTYPE,	INDREG,
+	SANY,	TFLOAT|TDOUBLE|TLDOUBLE,
+	SDREG,	TFLOAT|TDOUBLE|TLDOUBLE,
+		NDREG,	RESC1,
+		"", },
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS,	INCREG|FOREFF,
+	SCREG,	TLL,
+	SCREG,	TLL,
+		0,	RLEFT,
+		"	negl AL\n	adcl $0,UL\n	negl UL\n", },
+
+{ UMINUS,	INAREG|FOREFF,
+	SAREG,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	negl AL\n", },
+
+{ UMINUS,	INAREG|FOREFF,
+	SAREG,	TSHORT|TUSHORT,
+	SAREG,	TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	negw AL\n", },
+
+{ UMINUS,	INBREG|FOREFF,
+	SBREG,	TCHAR|TUCHAR,
+	SBREG,	TCHAR|TUCHAR,
+		0,	RLEFT,
+		"	negb AL\n", },
+
+{ UMINUS,	INFL|FOREFF,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
+		0,	RLEFT,
+		"	fchs\n", },
+
+{ COMPL,	INCREG,
+	SCREG,	TLL,
+	SANY,	TANY,
+		0,	RLEFT,
+		"	notl AL\n	notl UL\n", },
+
+{ COMPL,	INAREG,
+	SAREG,	TWORD,
+	SANY,	TANY,
+		0,	RLEFT,
+		"	notl AL\n", },
+
+{ COMPL,	INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SANY,	TANY,
+		0,	RLEFT,
+		"	notw AL\n", },
+
+{ COMPL,	INBREG,
+	SBREG,	TCHAR|TUCHAR,
+	SANY,	TANY,
+		0,	RLEFT,
+		"	notb AL\n", },
+
+/*
+ * Arguments to functions.
+ */
+{ FUNARG,	FOREFF,
+	SCON|SCREG|SNAME|SOREG,	TLL,
+	SANY,	TLL,
+		0,	RNULL,
+		"	pushl UL\n	pushl AL\n", },
+
+{ FUNARG,	FOREFF,
+	SCON|SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SANY,	TWORD|TPOINT,
+		0,	RNULL,
+		"	pushl AL\n", },
+
+{ FUNARG,	FOREFF,
+	SCON,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SANY,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		0,	RNULL,
+		"	pushl AL\n", },
+
+{ FUNARG,	FOREFF,
+	SAREG|SNAME|SOREG,	TSHORT,
+	SANY,	TSHORT,
+		NAREG,	0,
+		"	movswl AL,ZN\n	pushl ZN\n", },
+
+{ FUNARG,	FOREFF,
+	SAREG|SNAME|SOREG,	TUSHORT,
+	SANY,	TUSHORT,
+		NAREG,	0,
+		"	movzwl AL,ZN\n	pushl ZN\n", },
+
+{ FUNARG,	FOREFF,
+	SHCH|SNAME|SOREG,	TCHAR,
+	SANY,			TCHAR,
+		NAREG,	0,
+		"	movsbl AL,A1\n	pushl A1\n", },
+
+{ FUNARG,	FOREFF,
+	SHCH|SNAME|SOREG,	TUCHAR,
+	SANY,	TUCHAR,
+		NAREG,	0,
+		"	movzbl AL,A1\n	pushl A1\n", },
+
+{ FUNARG,	FOREFF,
+	SNAME|SOREG,	TDOUBLE,
+	SANY,	TDOUBLE,
+		0,	0,
+		"	pushl UL\n	pushl AL\n", },
+
+{ FUNARG,	FOREFF,
+	SDREG,	TDOUBLE,
+	SANY,		TDOUBLE,
+		0,	0,
+		"	subl $8,%esp\n	fstpl (%esp)\n", },
+
+{ FUNARG,	FOREFF,
+	SNAME|SOREG,	TFLOAT,
+	SANY,		TFLOAT,
+		0,	0,
+		"	pushl AL\n", },
+
+{ FUNARG,	FOREFF,
+	SDREG,	TFLOAT,
+	SANY,		TFLOAT,
+		0,	0,
+		"	subl $4,%esp\n	fstps (%esp)\n", },
+
+{ FUNARG,	FOREFF,
+	SDREG,	TLDOUBLE,
+	SANY,		TLDOUBLE,
+		0,	0,
+		"	subl $12,%esp\n	fstpt (%esp)\n", },
+
+{ STARG,	FOREFF,
+	SAREG|SOREG|SNAME|SCON,	TANY,
+	SANY,	TSTRUCT,
+		NSPECIAL|NAREG,	0,
+		"ZF", },
+
+#endif
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+{ INIT, DF(INIT), },
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	"help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
Index: uspace/app/pcc/arch/pdp10/README
===================================================================
--- uspace/app/pcc/arch/pdp10/README	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/pdp10/README	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,20 @@
+
+
+PDP10 C calling convention
+--------------------------
+Register 1-7 are argument registers.  Types of sizes up to 36 bits are
+given in one register, two otherwise.  CHAR and SHORT are given as INTs.
+
+If the argument that would end up in register 7 requires two registers,
+it is saved on the stack instead and no more registers would end up
+on the stack.
+
+struct return: a hidden argument containing the address of the struct
+is stored as the first argument _on_the_stack_, never in register.
+
+struct argument: always saved on stack, and terminates the list 
+of arguments that are kept in registers.
+
+In case of debugging all arguments are saved on stack in the function.
+
+All variadic arguments are always saved on the stack.
Index: uspace/app/pcc/arch/pdp10/code.c
===================================================================
--- uspace/app/pcc/arch/pdp10/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/pdp10/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,223 @@
+/*	$Id: code.c,v 1.39 2008/07/29 13:25: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.
+ */
+
+
+# include "pass1.h"
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+	char *nextsect = NULL;	/* notyet */
+	static char *loctbl[] = { "text", "data", "section .rodata" };
+	static int lastloc = -1;
+	TWORD t;
+	int s;
+
+	if (sp == NULL) {
+		lastloc = -1;
+		return;
+	}
+	t = sp->stype;
+	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+	if (nextsect) {
+		printf("	.section %s\n", nextsect);
+		nextsect = NULL;
+		s = -1;
+	} else if (s != lastloc)
+		printf("	.%s\n", loctbl[s]);
+	lastloc = s;
+	if (sp->sclass == EXTDEF)
+		printf("	.globl %s\n", sp->soname);
+	if (sp->slevel == 0)
+		printf("%s:\n", sp->soname);
+	else
+		printf(LABFMT ":\n", sp->soffset);
+}
+
+/*
+ * code for the end of a function
+ */
+void
+efcode()
+{
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in stab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **sp, int cnt)
+{
+	NODE *p, *q;
+	int i, n;
+
+	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+		uerror("no struct return yet");
+	}
+	/* recalculate the arg offset and create TEMP moves */
+	for (n = 1, i = 0; i < cnt; i++) {
+		if (n < 8) {
+			p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->ssue);
+			q = block(REG, NIL, NIL,
+			    sp[i]->stype, sp[i]->sdf, sp[i]->ssue);
+			q->n_rval = n;
+			p = buildtree(ASSIGN, p, q);
+			sp[i]->soffset = regno(p->n_left);
+			sp[i]->sflags |= STNODE;
+			ecomp(p);
+		} else {
+			sp[i]->soffset += SZINT * n;
+			if (xtemps) {
+				/* put stack args in temps if optimizing */
+				p = tempnode(0, sp[i]->stype,
+				    sp[i]->sdf, sp[i]->ssue);
+				p = buildtree(ASSIGN, p, nametree(sp[i]));
+				sp[i]->soffset = regno(p->n_left);
+				sp[i]->sflags |= STNODE;
+				ecomp(p);
+			}
+		}
+		n += szty(sp[i]->stype);
+	}
+}
+
+
+/*
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+	SETOFF(autooff, SZINT);
+}
+
+void
+bjobcode()
+{
+}
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag )
+{
+}
+
+/*
+ * Make a register node, helper for funcode.
+ */
+static NODE *
+mkreg(NODE *p, int n)
+{
+	NODE *r;
+
+	r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue);
+	if (szty(p->n_type) == 2)
+		n += 16;
+	r->n_rval = n;
+	return r;
+}
+
+static int regnum;
+/*
+ * Move args to registers and emit expressions bottom-up.
+ */
+static void
+fixargs(NODE *p)
+{
+	NODE *r;
+
+	if (p->n_op == CM) {
+		fixargs(p->n_left);
+		r = p->n_right;
+		if (r->n_op == STARG)
+			regnum = 9; /* end of register list */
+		else if (regnum + szty(r->n_type) > 8)
+			p->n_right = block(FUNARG, r, NIL, r->n_type,
+			    r->n_df, r->n_sue);
+		else
+			p->n_right = buildtree(ASSIGN, mkreg(r, regnum), r);
+	} else {
+		if (p->n_op == STARG) {
+			regnum = 9; /* end of register list */
+		} else {
+			r = talloc();
+			*r = *p;
+			r = buildtree(ASSIGN, mkreg(r, regnum), r);
+			*p = *r;
+			nfree(r);
+		}
+		r = p;
+	}
+	regnum += szty(r->n_type);
+}
+
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+
+	regnum = 1;
+
+	fixargs(p->n_right);
+	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/pdp10/local.c
===================================================================
--- uspace/app/pcc/arch/pdp10/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/pdp10/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,878 @@
+/*	$Id: local.c,v 1.72 2011/01/21 21:47: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.
+ */
+
+
+# include "pass1.h"
+
+/*	this file contains code which is dependent on the target machine */
+
+static int pointp(TWORD t);
+static struct symtab *newfun(char *name, TWORD type);
+
+#define	PTRNORMAL	1
+#define	PTRCHAR		2
+#define	PTRSHORT	3
+static int xptype(TWORD t);
+
+NODE *
+clocal(NODE *p)
+{
+	/* this is called to do local transformations on
+	   an expression tree preparitory to its being
+	   written out in intermediate code.
+	*/
+
+	/* the major essential job is rewriting the
+	   automatic variables and arguments in terms of
+	   REG and OREG nodes */
+	/* conversion ops which are not necessary are also clobbered here */
+	/* in addition, any special features (such as rewriting
+	   exclusive or) are easily handled here as well */
+
+	register struct symtab *q;
+	register NODE *r, *l, *oop;
+	register int o;
+	register int m, ml;
+	int siz;
+
+#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:
+			/* First 7 parameters are in registers */
+			/* XXX last may be double */
+			if (q->soffset/SZINT < 7) {
+				p->n_op = REG;
+				p->n_rval = q->soffset/SZINT;
+				break;
+			} else
+				q->soffset -= 7*SZINT;
+				
+		case AUTO:
+			/* fake up a structure reference */
+			if (q->stype == CHAR || q->stype == UCHAR ||
+			    q->stype == SHORT || q->stype == USHORT)
+				r = block(REG, NIL, NIL, PTR+q->stype, 0, 0);
+			else
+				r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+			r->n_lval = 0;
+			r->n_rval = FPREG;
+			p = stref(block(STREF, r, p, 0, 0, 0));
+			break;
+
+		case STATIC:
+			if (q->slevel == 0)
+				break;
+			p->n_lval = 0;
+			break;
+
+		case REGISTER:
+			p->n_op = REG;
+			p->n_lval = 0;
+			p->n_rval = q->soffset;
+			break;
+
+			}
+		break;
+
+	case CALL:
+		/* avoid recursive calls */
+		r = tempnode(0, p->n_type, p->n_df, p->n_sue);
+		l = tempnode(regno(r), p->n_type, p->n_df, p->n_sue);
+		ecomp(buildtree(ASSIGN, r, p));
+		p = l;
+		break;
+
+	case PCONV:
+		l = p->n_left;
+		/*
+		 * Handle frame pointer directly without conversion,
+		 * for efficiency.
+		 */
+		if (l->n_op == REG && l->n_rval == 0) {
+rmpc:			l->n_type = p->n_type;
+			l->n_df = p->n_df;
+			l->n_sue = p->n_sue;
+			nfree(p);
+			return l;
+		}
+		/* Convert ICON with name to new type */
+		if (l->n_op == ICON && l->n_sp != NULL &&
+		    l->n_type == INCREF(STRTY) && 
+		    (p->n_type == INCREF(CHAR) ||
+		    p->n_type == INCREF(UCHAR) ||
+		    p->n_type == INCREF(SHORT) ||
+		    p->n_type == INCREF(USHORT))) {
+			l->n_lval *= (BTYPE(p->n_type) == CHAR ||
+			    BTYPE(p->n_type) == UCHAR ? 4 : 2);
+			goto rmpc;
+		}
+		/* Convert only address constants, never convert other */
+		if (l->n_op == ICON) {
+			if (l->n_sp == NULL)
+				goto rmpc;
+			if (p->n_type == INCREF(CHAR) ||
+			    p->n_type == INCREF(UCHAR) ||
+			    p->n_type == INCREF(VOID))
+				l->n_lval = (l->n_lval & 07777777777) |
+				    0700000000000LL;
+			else if (p->n_type == INCREF(SHORT) ||
+			    p->n_type == INCREF(USHORT))
+				l->n_lval = (l->n_lval & 07777777777) |
+				    0750000000000LL;
+			else
+				l->n_lval = l->n_lval & 07777777777;
+			goto rmpc;
+		}
+
+		/* Remove more conversions of identical pointers */
+		/* Be careful! optim() may do bad things */
+		if (ISPTR(DECREF(p->n_type))) {
+			if (ISPTR(DECREF(l->n_type))) {
+				if ((coptype(l->n_op) == UTYPE ||
+				    coptype(l->n_op) == BITYPE) &&
+				    (l->n_left->n_op == REG))
+					l->n_left->n_type = p->n_type;
+				goto rmpc;
+			}
+		}
+
+		/* Change PCONV from int to double pointer to right shift */
+		if (ISPTR(p->n_type) && ISPTR(DECREF(p->n_type)) &&
+		    (l->n_type == INT || l->n_type == UNSIGNED)) {
+			p->n_op = RS;
+			p->n_right = bcon(2);
+			break;
+		}
+		
+		/* Check for cast integral -> pointer */
+		if (BTYPE(l->n_type) == l->n_type)
+			break;
+
+		/* Remove conversions to identical pointers */
+		switch (xptype(p->n_type)) {
+		case PTRNORMAL:
+			if (xptype(l->n_type) == PTRNORMAL)
+				goto rmpc;
+			break;
+
+		case PTRSHORT:
+			if (xptype(l->n_type) == PTRSHORT)
+				goto rmpc;
+			break;
+
+		case PTRCHAR:
+			if (xptype(l->n_type) == PTRCHAR)
+				goto rmpc;
+			break;
+		}
+
+		break;
+
+	case SCONV:
+		l = p->n_left;
+
+		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+		    btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
+			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+			     l->n_type != FLOAT && l->n_type != DOUBLE) {
+				nfree(p);
+				return l;
+			}
+		}
+		/* cast to (void) XXX should be removed in MI code */
+		if (p->n_type == VOID) {
+			nfree(p);
+			return l;
+		}
+		m = p->n_type;
+		ml = l->n_type;
+		if (m == ml) {
+			nfree(p);
+			return l;
+		}
+		o = l->n_op;
+		if (ml == FLOAT || ml == DOUBLE) {
+			if (o != FCON)
+				break;
+			ml = ISUNSIGNED(m) ? UNSIGNED : INT; /* LONG? */
+			r = xbcon(ml == INT ? (int)p->n_left->n_dcon :
+			                      (unsigned)p->n_left->n_dcon,
+			          NULL, ml);
+			nfree(p->n_left);
+			p->n_left = r;
+			o = ICON;
+			if (m == ml) {
+				r = p->n_left;
+				nfree(p);
+				return r;
+			}
+		}
+		if (o == ICON) {
+			CONSZ val = l->n_lval;
+
+			switch (m) {
+			case CHAR:
+				l->n_lval = val & 0777;
+				if (val & 0400)
+					l->n_lval |= ~((CONSZ)0777);
+				break;
+			case UCHAR:
+				l->n_lval = val & 0777;
+				break;
+			case USHORT:
+				l->n_lval = val & 0777777;
+				break;
+			case SHORT:
+				l->n_lval = val & 0777777;
+				if (val & 0400000)
+					l->n_lval |= ~((CONSZ)0777777);
+				break;
+			case UNSIGNED:
+				l->n_lval = val & 0777777777777LL;
+				break;
+			case INT:
+				l->n_lval = val & 0777777777777LL;
+				if (val & 0400000000000LL)
+					l->n_lval |= ~(0777777777777LL);
+				break;
+			case LONGLONG:	/* XXX */
+			case ULONGLONG:
+				l->n_lval = val;
+				break;
+			case VOID:
+				break;
+			case DOUBLE:
+			case FLOAT:
+				l->n_op = FCON;
+				l->n_dcon = 0;
+				break;
+			default:
+				cerror("unknown type %d", m);
+			}
+			l->n_type = m;
+			l->n_sue = MKSUE(m);
+			nfree(p);
+			return l;
+		}
+		break;
+
+	case PMCONV:
+	case PVCONV:
+/*                if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0); */
+                nfree(p);
+                return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
+
+	case RS:
+	case RSEQ:
+		/* convert >> to << with negative shift count */
+		/* Beware! constant shifts will be converted back in optim() */
+
+		if (p->n_right->n_op != UMINUS) {
+			p->n_right = buildtree(UMINUS, p->n_right, NIL);
+		} else {
+			r = p->n_right;
+			p->n_right = p->n_right->n_left;
+			nfree(r);
+		}
+		if (p->n_op == RS)
+			p->n_op = LS;
+		else
+			p->n_op = LSEQ;
+		break;
+
+	case UMUL: /* Convert structure assignment to memcpy() */
+		if (p->n_left->n_op == PLUS &&
+		    p->n_left->n_left->n_op == PCONV &&
+		    p->n_left->n_right->n_op == ICON &&
+		    (p->n_type == CHAR || p->n_type == UCHAR ||
+		    p->n_type == SHORT || p->n_type == USHORT)) {
+			/* Can remove the left SCONV */
+			l = p->n_left->n_left;
+			p->n_left->n_left = l->n_left;
+			nfree(l);
+			break;
+
+		}
+		if (p->n_left->n_op != STASG)
+			break;
+		oop = p;
+		p = p->n_left;
+		siz = p->n_sue->suesize/SZCHAR;
+		l = p->n_left;
+		r = p->n_right;
+		if (l->n_type == STRTY || l->n_type == UNIONTY) {
+			if (l->n_op == UMUL) {
+				p->n_left = l->n_left;
+				nfree(l);
+				l = p->n_left;
+			} else {
+				l = block(ADDROF, l, NIL, INCREF(l->n_type),
+				    0, MKSUE(INT));
+			}
+		}
+		if ((l->n_type != (STRTY+PTR) && l->n_type != (UNIONTY+PTR)) ||
+		    (r->n_type != (STRTY+PTR) && r->n_type != (UNIONTY+PTR)))
+			cerror("bad stasg, l = %o, r = %o", l->n_type, r->n_type);
+		q = newfun("__structcpy", p->n_type);
+
+		/* structure pointer block */
+		l = block(CM, l, r, INT, 0, MKSUE(INT));
+		/* Size block */
+		r = block(CM, l, bcon(siz), INT, 0, MKSUE(INT));
+
+		l = xbcon(0, q, q->stype);
+		p->n_left = l;
+		p->n_right = r;
+		p->n_op = CALL;
+		oop->n_left = p;
+		return oop;
+
+	case FORCE:
+		p->n_op = ASSIGN;
+		p->n_right = p->n_left;
+		p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
+		p->n_left->n_rval = RETREG(p->n_type);
+		break;
+
+	}
+
+	return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+	NODE *r;
+
+	switch (p->n_op) {
+	case ULT: /* exor sign bit to avoid unsigned comparitions */
+	case ULE:
+	case UGT:
+	case UGE:
+		if (ISLONGLONG(p->n_left->n_type)) {
+			/* XXX */
+			r = xbcon(0x8000000000000000ULL, NULL, LONGLONG);
+		} else
+			r = xbcon(0400000000000LL, NULL, INT);
+		p->n_left = buildtree(ER, p->n_left, r);
+		if (ISUNSIGNED(p->n_left->n_type))
+			p->n_left->n_type = DEUNSIGN(p->n_left->n_type);
+
+		if (ISLONGLONG(p->n_right->n_type)) {
+			/* XXX */
+			r = xbcon(0x8000000000000000ULL, NULL, LONGLONG);
+		} else
+			r = xbcon(0400000000000LL, NULL, INT);
+		p->n_right = buildtree(ER, p->n_right, r);
+		if (ISUNSIGNED(p->n_right->n_type))
+			p->n_right->n_type = DEUNSIGN(p->n_right->n_type);
+
+		p->n_op -= (ULT-LT);
+		break;
+	case FCON:
+		cerror("fix float constants");
+	}
+}
+
+
+struct symtab *
+newfun(char *name, TWORD type)
+{
+	struct symtab *sp;
+
+	sp = lookup(name, 0);
+	if (sp->stype == VOID) {
+		sp->stype = INCREF(type | FTN);
+		sp->sclass = EXTERN;
+		sp->soffset = 0;
+	}
+#ifdef notdef
+	else if (!ISFTN(DECREF(sp->stype)))
+		uerror("reserved name '%s' used illegally", name);
+#endif
+	return sp;
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+	return(1);  /* all names can have & taken on them */
+}
+
+/*
+ * at the end of the arguments of a ftn, set the automatic offset
+ */
+void
+cendarg()
+{
+	autooff = AUTOINIT;
+}
+
+/*
+ * is an automatic variable of type t OK for a register variable
+ * Everything is trusted to be in register here.
+ */
+int
+cisreg(TWORD t)
+{
+	return(1);
+}
+
+int
+xptype(TWORD t)
+{
+	int tt = BTYPE(t);
+	int e, rv;
+
+	if (!ISPTR(t))
+		cerror("not a pointer");
+
+	e = t & ~BTMASK;
+	rv = e;
+	while (e) {
+		rv = e;
+		if (DECREF(e) == 0)
+			break;
+		e = DECREF(e);
+	}
+	if (ISFTN(rv))
+		return PTRNORMAL;
+
+	switch (tt) {
+	case INT:
+	case LONG:
+	case LONGLONG:
+	case FLOAT:
+	case DOUBLE:
+	case STRTY:
+	case UNIONTY:
+	case UNSIGNED:
+	case ULONG:
+	case ULONGLONG:
+		return PTRNORMAL;
+	case VOID:
+	case CHAR:
+	case UCHAR:
+		if (DECREF(t) == tt || ISARY(rv))
+			return PTRCHAR;
+		return PTRNORMAL;
+	case SHORT:
+	case USHORT:
+		if (DECREF(t) == tt || ISARY(rv))
+			return PTRSHORT;
+		return PTRNORMAL;
+	default:
+		break;
+	}
+	cerror("unknown type");
+	return PTRNORMAL; /* XXX */
+}
+
+/*
+ * Help routine to the one below; return true if it's not a word pointer.
+ */
+static int
+pointp(TWORD t)
+{
+	int rv = 0;
+
+	if (ISPTR(t) && ((t & TMASK1) == 0))
+		return 1;
+
+	t &= ~BTMASK;
+	while (t) {
+		rv = ISARY(t);
+		t = DECREF(t);
+	}
+	return rv;
+}
+
+/*
+ * return a node, for structure references, which is suitable for
+ * being added to a pointer of type t, in order to be off bits offset
+ * into a structure
+ * t, d, and s are the type, dimension offset, and sizeoffset
+ * For pdp10, return the type-specific index number which calculation
+ * is based on its size. For example, short a[3] would return 3.
+ * Be careful about only handling first-level pointers, the following
+ * indirections must be fullword.
+ */
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
+{
+	register NODE *p;
+
+	if (xdebug)
+		printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
+		    off, t, d, sue->suesize);
+
+	p = bcon(0);
+	p->n_lval = off/SZINT;	/* Default */
+	if (ISPTR(DECREF(t)))
+		return p;	/* Pointer/pointer reference */
+	switch (BTMASK & t) {
+	case INT:
+	case UNSIGNED:
+	case LONG:
+	case ULONG:
+	case STRTY:
+	case UNIONTY:
+	case LONGLONG:
+	case ULONGLONG:
+	case FLOAT:
+	case DOUBLE:
+		break;
+
+	case SHORT:
+	case USHORT:
+		if (pointp(t))
+			p->n_lval = off/SZSHORT;
+		break;
+
+	case VOID: /* void pointers */
+	case CHAR:
+	case UCHAR:
+		if (pointp(t))
+			p->n_lval = off/SZCHAR;
+		break;
+
+	default:
+		cerror("offcon, off %llo size %d type %x", off, sue->suesize, t);
+	}
+	if (xdebug)
+		printf("offcon return 0%llo\n", p->n_lval);
+	return(p);
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a NAME node where to write
+ * the allocated address.
+ * Be aware that a pointer conversion may be needed when saving 
+ * to node t!
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+	NODE *sp;
+
+	if ((off % SZINT) == 0)
+		p =  buildtree(MUL, p, bcon(off/SZINT));
+	else if ((off % SZSHORT) == 0) {
+		p = buildtree(MUL, p, bcon(off/SZSHORT));
+		p = buildtree(PLUS, p, bcon(1));
+		p = buildtree(RS, p, bcon(1));
+	} else if ((off % SZCHAR) == 0) {
+		p = buildtree(MUL, p, bcon(off/SZCHAR));
+		p = buildtree(PLUS, p, bcon(3));
+		p = buildtree(RS, p, bcon(2));
+	} else
+		cerror("roundsp");
+
+	/* save the address of sp */
+	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	/* Cast sp to destination type (may be redundant) */
+	sp = buildtree(CAST,
+	    block(NAME, NIL, NIL, t->n_type, t->n_df, t->n_sue), sp);
+	nfree(sp->n_left);
+	nfree(sp);
+	sp = sp->n_right;
+	ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+	/* add the size to sp */
+	sp = block(REG, NIL, NIL, p->n_type, 0, 0);
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	ecomp(buildtree(PLUSEQ, sp, p));
+}
+
+#if 0
+static int inwd;	/* current bit offsed in word */
+static CONSZ word;	/* word being built from fields */
+
+/*
+ * Generate initialization code for assigning a constant c
+ * to a field of width sz
+ * we assume that the proper alignment has been obtained
+ * inoff is updated to have the proper final value
+ * we also assume sz  < SZINT
+ */
+void
+incode(NODE *p, int sz)
+{
+	char *s;
+
+	inoff += sz;
+	if ((sz + inwd) > SZINT)
+		cerror("incode: field > int");
+
+	word |= ((p->n_lval & ((1 << sz) - 1)) << (36 - inwd - sz));
+
+	inwd += sz;
+	if (inoff % SZINT == 0) {
+		s = isinlining ? permalloc(30) : tmpalloc(30);
+		sprintf(s, "	.long 0%llo", word);
+		send_passt(IP_ASM, s);
+		word = inwd = 0;
+	}
+	tfree(p);
+}
+
+/* output code to initialize space of size sz to the value d */
+/* the proper alignment has been obtained */
+/* inoff is updated to have the proper final value */
+/* on the target machine, write it out in octal! */
+void
+fincode(NODE *p, int sz)
+{
+	double d = p->n_dcon;
+
+	if(!nerrors)
+		printf("	%s	0%c%.20e\n",
+		    sz == SZDOUBLE ? ".double" : ".float",
+		sz == SZDOUBLE ? 'd' : 'f', d);
+	inoff += sz;
+}
+
+void
+cinit(NODE *p, int sz)
+{
+	NODE *l;
+
+	/*
+	 * as a favor (?) to people who want to write
+	 *     int i = 9600/134.5;
+	 * we will, under the proper circumstances, do
+	 * a coercion here.
+	 */
+	switch (p->n_type) {
+	case INT:
+	case UNSIGNED:
+		l = p->n_left;
+		if (l->n_op != SCONV || l->n_left->n_op != FCON)
+			break;
+		nfree(l);
+		l = l->n_left;
+		l->n_lval = (long)(l->n_dcon);
+		l->n_sp = NULL;
+		l->n_op = ICON;
+		l->n_type = INT;
+		p->n_left = l;
+		break;
+	}
+	/* arrange for the initialization of p into a space of size sz */
+	/* the proper alignment has been opbtained */
+	/* inoff is updated to have the proper final value */
+	ecode( p );
+	inoff += sz;
+}
+
+/*
+ * define n bits of zeros in a vfd
+ */
+void
+vfdzero(int n)
+{
+	char *s;
+
+	inoff += n;
+	inwd += n;
+	if (inoff%ALINT ==0) {
+		s = isinlining ? permalloc(30) : tmpalloc(30);
+		sprintf(s, "	.long 0%llo", word);
+		send_passt(IP_ASM, s);
+		word = inwd = 0;
+	}
+}
+#endif
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+	if (p == NULL)
+		return "";
+	return p;
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+	switch (BTYPE(type)) {
+	case LONG:
+		MODTYPE(type,INT);
+		break;
+	case ULONG:
+		MODTYPE(type,UNSIGNED);
+		break;
+	case LDOUBLE:
+		MODTYPE(type,DOUBLE);
+		break;
+	}
+	return (type);
+}
+
+/*
+ * Print out a string of characters.
+ * Assume that the assembler understands C-style escape
+ * sequences.
+ */
+void
+instring(struct symtab *sp)
+{
+	char *s, *str;
+
+	defloc(sp);
+	str = sp->sname;
+
+	/* 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");
+}
+
+/* curid is a variable which is defined but
+ * is not initialized (and not a function );
+ * This routine returns the stroage class for an uninitialized declaration
+ */
+int
+noinit()
+{
+	return(EXTERN);
+}
+
+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;
+ 
+	off = tsize(sp->stype, sp->sdf, sp->ssue);
+	off = (off+(SZINT-1))/SZINT;
+	printf("        .%scomm ", sp->sclass == STATIC ? "l" : "");
+	if (sp->slevel == 0)
+		printf("%s,0%o\n", exname(sp->soname), off);
+	else
+		printf(LABFMT ",0%o\n", sp->soffset, off);
+}
+
+/*
+ * set fsz bits in sequence to zero.
+ */
+void
+zbits(OFFSZ off, int fsz)
+{
+	cerror("zbits");
+}
+
+/*
+ * 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);
+	cerror("infld");
+}
+
+/*
+ * 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)
+{
+	cerror("ninval");
+}
+
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+	return 0;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
+
Index: uspace/app/pcc/arch/pdp10/local2.c
===================================================================
--- uspace/app/pcc/arch/pdp10/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/pdp10/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1321 @@
+/*	$Id: local2.c,v 1.102 2008/11/22 16:12:25 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>
+
+# define putstr(s)	fputs((s), stdout)
+
+void acon(FILE *, NODE *p);
+int argsize(NODE *p);
+void genargs(NODE *p);
+
+static int offlab;
+int offarg;
+static int addto;
+static int regoff[16];
+
+void
+deflab(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+	int i, j;
+
+	if (ipp->ipp_vis)
+		printf("	.globl %s\n", ipp->ipp_name);
+	printf("%s:\n", ipp->ipp_name);
+	addto = p2maxautooff;
+	if (addto >= AUTOINIT/SZCHAR)
+		addto -= AUTOINIT/SZCHAR;
+	addto /= SZINT/SZCHAR;	/* use words here */
+	printf("	push %s,%s\n",rnames[STKREG], rnames[FPREG]);
+	printf("	move %s,%s\n", rnames[FPREG],rnames[STKREG]);
+
+	for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
+		if (i & 1)
+			regoff[j] = addto++;
+	}
+	if (addto)
+		printf("	addi %s,0%o\n", rnames[STKREG], addto);
+
+	for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
+		if (i & 1)
+			printf("	movem %s,%d(%s)\n",
+			    rnames[j], regoff[j], rnames[STKREG]);
+	}
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+	int i, j;
+
+	if (ipp->ipp_ip.ip_lbl == 0)
+		return; /* no code needs to be generated */
+	for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) {
+		if (i & 1)
+			printf("	move %s,%d(%s)\n",
+			    rnames[j], regoff[j], rnames[STKREG]);
+	}
+	printf("	move %s,%s\n", rnames[STKREG], rnames[FPREG]);
+	printf("	pop %s,%s\n", rnames[STKREG], rnames[FPREG]);
+	printf("	popj %s,\n", rnames[STKREG]);
+}
+
+#if 0
+void
+prologue(int regs, int autos)
+{
+	int i, addto;
+
+	offlab = getlab2();
+	if (regs < 0 || autos < 0) {
+		/*
+		 * non-optimized code, jump to epilogue for code generation.
+		 */
+		ftlab1 = getlab2();
+		ftlab2 = getlab2();
+		printf("	jrst L%d\n", ftlab1);
+		printf("L%d:\n", ftlab2);
+	} else {
+		/*
+		 * We here know what register to save and how much to 
+		 * add to the stack.
+		 */
+		autos = autos + (SZINT-1);
+		addto = (autos - AUTOINIT)/SZINT + (MAXRVAR-regs);
+		if (addto || gflag) {
+			printf("	push %s,%s\n",rnames[017], rnames[016]);
+			printf("	move %s,%s\n", rnames[016],rnames[017]);
+			for (i = regs; i < MAXRVAR; i++) {
+				int db = ((i+1) < MAXRVAR);
+				printf("	%smovem %s,0%o(%s)\n",
+				    db ? "d" : "",
+				    rnames[i+1], i+1-regs, rnames[016]);
+				if (db)
+					i++;
+			}
+			if (addto)
+				printf("	addi %s,0%o\n", rnames[017], addto);
+		} else
+			offarg = 1;
+	}
+}
+
+/*
+ * End of block.
+ */
+void
+eoftn(int regs, int autos, int retlab)
+{
+	register OFFSZ spoff;	/* offset from stack pointer */
+	int i;
+
+	spoff = autos + (SZINT-1);
+	if (spoff >= AUTOINIT)
+		spoff -= AUTOINIT;
+	spoff /= SZINT;
+	/* return from function code */
+	printf("L%d:\n", retlab);
+	if (gflag || isoptim == 0 || autos != AUTOINIT || regs != MAXRVAR) {
+		for (i = regs; i < MAXRVAR; i++) {
+			int db = ((i+1) < MAXRVAR);
+			printf("	%smove %s,0%o(%s)\n", db ? "d" : "",
+			    rnames[i+1], i+1-regs, rnames[016]);
+			if (db)
+				i++;
+		}
+		printf("	move %s,%s\n", rnames[017], rnames[016]);
+		printf("	pop %s,%s\n", rnames[017], rnames[016]);
+	}
+	printf("	popj %s,\n", rnames[017]);
+
+	/* Prolog code */
+	if (isoptim == 0) {
+		printf("L%d:\n", ftlab1);
+		printf("	push %s,%s\n", rnames[017], rnames[016]);
+		printf("	move %s,%s\n", rnames[016], rnames[017]);
+		for (i = regs; i < MAXRVAR; i++) {
+			int db = ((i+1) < MAXRVAR);
+			printf("	%smovem %s,0%o(%s)\n", db ? "d" : "",
+			    rnames[i+1], i+1-regs, rnames[016]);
+			spoff++;
+			if (db)
+				i++, spoff++;
+		}
+		if (spoff)
+			printf("	addi %s,0%llo\n", rnames[017], spoff);
+		printf("	jrst L%d\n", ftlab2);
+	}
+	printf("	.set " LABFMT ",0%o\n", offlab, MAXRVAR-regs);
+	offarg = isoptim = 0;
+}
+#endif
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ *	R - Register
+ *	M - Memory
+ *	C - Constant
+ */
+void
+hopcode(int f, int o)
+{
+	cerror("hopcode: f %d %d", f, o);
+}
+
+char *
+rnames[] = {  /* keyed to register number tokens */
+	"%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7",
+	"%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
+	"%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7",
+	"%10", "%11", "%12", "%13", "%14", "%15",
+};
+
+int
+tlen(p) NODE *p;
+{
+	switch(p->n_type) {
+		case CHAR:
+		case UCHAR:
+			return(1);
+
+		case SHORT:
+		case USHORT:
+			return(SZSHORT/SZCHAR);
+
+		case DOUBLE:
+			return(SZDOUBLE/SZCHAR);
+
+		case INT:
+		case UNSIGNED:
+		case LONG:
+		case ULONG:
+			return(SZINT/SZCHAR);
+
+		case LONGLONG:
+		case ULONGLONG:
+			return SZLONGLONG/SZCHAR;
+
+		default:
+			if (!ISPTR(p->n_type))
+				cerror("tlen type %d not pointer");
+			return SZPOINT(0)/SZCHAR;
+		}
+}
+
+static char *
+binskip[] = {
+	"e",	/* jumpe */
+	"n",	/* jumpn */
+	"le",	/* jumple */
+	"l",	/* jumpl */
+	"ge",	/* jumpge */
+	"g",	/* jumpg */
+};
+
+/*
+ * Extract the higher 36 bits from a longlong.
+ */
+static CONSZ
+gethval(CONSZ lval)
+{
+	CONSZ hval = (lval >> 35) & 03777777777LL;
+
+	if ((hval & 03000000000LL) == 03000000000LL) {
+		hval |= 0777000000000LL;
+	} else if ((hval & 03000000000LL) == 02000000000LL) {
+		hval &= 01777777777LL;
+		hval |= 0400000000000LL;
+	}
+	return hval;
+}
+
+/*
+ * Do a binary comparision, and jump accordingly.
+ */
+static void
+twocomp(NODE *p)
+{
+	int o = p->n_op;
+	extern int negrel[];
+	int isscon = 0, iscon = p->n_right->n_op == ICON;
+
+	if (o < EQ || o > GT)
+		cerror("bad binary conditional branch: %s", opst[o]);
+
+	if (iscon && p->n_right->n_name[0] != 0) {
+		printf("	cam%s ", binskip[negrel[o-EQ]-EQ]);
+		adrput(stdout, getlr(p, 'L'));
+		putchar(',');
+		printf("[ .long ");
+		adrput(stdout, getlr(p, 'R'));
+		putchar(']');
+		printf("\n	jrst L%d\n", p->n_label);
+		return;
+	}
+	if (iscon)
+		isscon = p->n_right->n_lval >= 0 &&
+		    p->n_right->n_lval < 01000000;
+
+	printf("	ca%c%s ", iscon && isscon ? 'i' : 'm',
+	    binskip[negrel[o-EQ]-EQ]);
+	adrput(stdout, getlr(p, 'L'));
+	putchar(',');
+	if (iscon && (isscon == 0)) {
+		printf("[ .long ");
+		adrput(stdout, getlr(p, 'R'));
+		putchar(']');
+	} else
+		adrput(stdout, getlr(p, 'R'));
+	printf("\n	jrst L%d\n", p->n_label);
+}
+
+/*
+ * Compare byte/word pointers.
+ * XXX - do not work for highest bit set in address
+ */
+static void
+ptrcomp(NODE *p)
+{
+	printf("	rot "); adrput(stdout, getlr(p, 'L')); printf(",6\n");
+	printf("	rot "); adrput(stdout, getlr(p, 'R')); printf(",6\n");
+	twocomp(p);
+}
+
+/*
+ * Do a binary comparision of two long long, and jump accordingly.
+ * XXX - can optimize for constants.
+ */
+static void     
+twollcomp(NODE *p)
+{       
+	int o = p->n_op;
+	int iscon = p->n_right->n_op == ICON;
+	int m = 0; /* XXX gcc */
+
+	if (o < EQ || o > GT)
+		cerror("bad long long conditional branch: %s", opst[o]);
+
+	/* Special strategy for equal/not equal */
+	if (o == EQ || o == NE) {
+		if (o == EQ)
+			m = getlab2();
+		printf("	came ");
+		upput(getlr(p, 'L'), SZLONG);
+		putchar(',');
+		if (iscon)
+			printf("[ .long ");
+		upput(getlr(p, 'R'), SZLONG);
+		if (iscon)
+			putchar(']');
+		printf("\n	jrst L%d\n", o == EQ ? m : p->n_label);
+		printf("	cam%c ", o == EQ ? 'n' : 'e');
+		adrput(stdout, getlr(p, 'L'));
+		putchar(',');
+		if (iscon)
+			printf("[ .long ");
+		adrput(stdout, getlr(p, 'R'));
+		if (iscon)
+			putchar(']');
+		printf("\n	jrst L%d\n", p->n_label);
+		if (o == EQ)
+			printf("L%d:\n", m);
+		return;
+	}
+	/* First test highword */
+	printf("	cam%ce ", o == GT || o == GE ? 'l' : 'g');
+	adrput(stdout, getlr(p, 'L'));
+	putchar(',');
+	if (iscon)
+		printf("[ .long ");
+	adrput(stdout, getlr(p, 'R'));
+	if (iscon)
+		putchar(']');
+	printf("\n	jrst L%d\n", p->n_label);
+
+	/* Test equality */
+	printf("	came ");
+	adrput(stdout, getlr(p, 'L'));
+	putchar(',');
+	if (iscon)
+		printf("[ .long ");
+	adrput(stdout, getlr(p, 'R'));
+	if (iscon)
+		putchar(']');
+	printf("\n	jrst L%d\n", m = getlab2());
+
+	/* Test lowword. Only works with pdp10 format for longlongs */
+	printf("	cam%c%c ", o == GT || o == GE ? 'l' : 'g',
+	    o == LT || o == GT ? 'e' : ' ');
+	upput(getlr(p, 'L'), SZLONG);
+	putchar(',');
+	if (iscon)  
+		printf("[ .long ");
+	upput(getlr(p, 'R'), SZLONG);
+	if (iscon)
+		putchar(']');
+	printf("\n	jrst L%d\n", p->n_label);
+	printf("L%d:\n", m);
+}
+
+/*
+ * Print the correct instruction for constants.
+ */
+static void
+constput(NODE *p)
+{
+	CONSZ val = p->n_right->n_lval;
+	int reg = p->n_left->n_rval;
+
+	/* Only numeric constant */
+	if (p->n_right->n_name[0] == '\0') {
+		if (val == 0) {
+			printf("movei %s,0", rnames[reg]);
+		} else if ((val & 0777777000000LL) == 0) {
+			printf("movei %s,0%llo", rnames[reg], val);
+		} else if ((val & 0777777) == 0) {
+			printf("hrlzi %s,0%llo", rnames[reg], val >> 18);
+		} else {
+			printf("move %s,[ .long 0%llo]", rnames[reg],
+			    szty(p->n_right->n_type) > 1 ? val :
+			    val & 0777777777777LL);
+		}
+		/* Can have more tests here, hrloi etc */
+		return;
+	} else {
+		printf("xmovei %s,%s", rnames[reg], p->n_right->n_name);
+		if (val)
+			printf("+" CONFMT, val);
+	}
+}
+
+/*
+ * Return true if the constant can be bundled in an instruction (immediate).
+ */
+static int
+oneinstr(NODE *p)
+{
+	if (p->n_name[0] != '\0')
+		return 0;
+	if ((p->n_lval & 0777777000000ULL) != 0)
+		return 0;
+	return 1;
+}
+
+/*
+ * Emit a halfword or byte instruction, from OREG to REG.
+ * Sign extension must also be done here.
+ */
+static void
+emitshort(NODE *p)
+{
+	CONSZ off = p->n_lval;
+	TWORD type = p->n_type;
+	int reg = p->n_rval;
+	int issigned = !ISUNSIGNED(type);
+	int ischar = type == CHAR || type == UCHAR;
+	int reg1 = getlr(p, '1')->n_rval;
+
+	if (off < 0) { /* argument, use move instead */
+		printf("	move ");
+	} else if (off == 0 && p->n_name[0] == 0) {
+		printf("	ldb %s,%s\n", rnames[reg1], rnames[reg]);
+		/* XXX must sign extend here even if not necessary */
+		switch (type) {
+		case CHAR:
+			printf("	lsh %s,033\n", rnames[reg1]);
+			printf("	ash %s,-033\n", rnames[reg1]);
+			break;
+		case SHORT:
+			printf("	hrre %s,%s\n",
+			    rnames[reg1], rnames[reg1]);
+			break;
+		}
+		return;
+	} else if (ischar) {
+		if (off >= 0700000000000LL && p->n_name[0] != '\0') {
+			cerror("emitsh");
+			/* reg contains index integer */
+//			if (!istreg(reg))
+//				cerror("emitshort !istreg");
+			printf("	adjbp %s,[ .long 0%llo+%s ]\n",
+			    rnames[reg], off, p->n_name);
+			printf("	ldb ");
+			adrput(stdout, getlr(p, '1'));
+			printf(",%s\n", rnames[reg]);
+			goto signe;
+		}
+		printf("	ldb ");
+		adrput(stdout, getlr(p, '1'));
+		if (off)
+			printf(",[ .long 0%02o11%02o%06o ]\n",
+			    (int)(27-(9*(off&3))), reg, (int)off/4);
+		else
+			printf(",%s\n", rnames[reg]);
+signe:		if (issigned) {
+			printf("	lsh ");
+			adrput(stdout, getlr(p, '1'));
+			printf(",033\n	ash ");
+			adrput(stdout, getlr(p, '1'));
+			printf(",-033\n");
+		}
+		return;
+	} else {
+		printf("	h%cr%c ", off & 1 ? 'r' : 'l',
+		    issigned ? 'e' : 'z');
+	}
+	p->n_lval /= (ischar ? 4 : 2);
+	adrput(stdout, getlr(p, '1'));
+	putchar(',');
+	adrput(stdout, getlr(p, 'L'));
+	putchar('\n');
+}
+
+/*
+ * Store a short from a register. Destination is a OREG.
+ */
+static void
+storeshort(NODE *p)
+{
+	NODE *l = p->n_left;
+	CONSZ off = l->n_lval;
+	int reg = l->n_rval;
+	int ischar = BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR;
+
+	if (l->n_op == NAME) {
+		if (ischar) {
+			printf("	dpb ");
+			adrput(stdout, getlr(p, 'R'));
+			printf(",[ .long 0%02o%010o+%s ]\n",
+			    070+((int)off&3), (int)(off/4), l->n_name);
+			return;
+		}
+		printf("	hr%cm ", off & 1 ? 'r' : 'l');
+		l->n_lval /= 2;
+		adrput(stdout, getlr(p, 'R'));
+		putchar(',');   
+		adrput(stdout, getlr(p, 'L'));
+		putchar('\n');
+		return;
+	}
+
+	if (off || reg == FPREG) { /* Can emit halfword instructions */
+		if (off < 0) { /* argument, use move instead */
+			printf("	movem ");
+		} else if (ischar) {
+			printf("	dpb ");
+			adrput(stdout, getlr(p, '1'));
+			printf(",[ .long 0%02o11%02o%06o ]\n",
+			    (int)(27-(9*(off&3))), reg, (int)off/4);
+			return;
+		} else {
+			printf("	hr%cm ", off & 1 ? 'r' : 'l');
+		}
+		l->n_lval /= 2;
+		adrput(stdout, getlr(p, 'R'));
+		putchar(',');
+		adrput(stdout, getlr(p, 'L'));
+	} else {
+		printf("	dpb ");
+		adrput(stdout, getlr(p, 'R'));
+		putchar(',');
+		l = getlr(p, 'L');
+		l->n_op = REG;
+		adrput(stdout, l);
+		l->n_op = OREG;
+	}
+	putchar('\n');
+}
+
+/*
+ * Multiply a register with a constant.
+ */
+static void     
+imuli(NODE *p)
+{
+	NODE *r = p->n_right;
+
+	if (r->n_lval >= 0 && r->n_lval <= 0777777) {
+		printf("	imuli ");
+		adrput(stdout, getlr(p, 'L'));
+		printf(",0%llo\n", r->n_lval);
+	} else {
+		printf("	imul ");
+		adrput(stdout, getlr(p, 'L'));
+		printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL);
+	}
+}
+
+/*
+ * Divide a register with a constant.
+ */
+static void     
+idivi(NODE *p)
+{
+	NODE *r = p->n_right;
+
+	if (r->n_lval >= 0 && r->n_lval <= 0777777) {
+		printf("	idivi ");
+		adrput(stdout, getlr(p, '1'));
+		printf(",0%llo\n", r->n_lval);
+	} else {
+		printf("	idiv ");
+		adrput(stdout, getlr(p, '1'));
+		printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL);
+	}
+}
+
+/*
+ * move a constant into a register.
+ */
+static void
+xmovei(NODE *p)
+{
+	/*
+	 * Trick: If this is an unnamed constant, just move it directly,
+	 * otherwise use xmovei to get section number.
+	 */
+	if (p->n_name[0] == '\0' || p->n_lval > 0777777) {
+		printf("	");
+		zzzcode(p, 'D');
+		putchar(' ');
+		adrput(stdout, getlr(p, '1'));
+		putchar(',');
+		zzzcode(p, 'E');
+	} else {
+		printf("	xmovei ");
+		adrput(stdout, getlr(p, '1'));
+		printf(",%s", p->n_name);
+		if (p->n_lval != 0)
+			printf("+0%llo", p->n_lval);
+	}
+	putchar('\n');
+}
+
+static void
+printcon(NODE *p) 
+{
+	CONSZ cz;
+
+	p = p->n_left;
+	if (p->n_lval >= 0700000000000LL) {
+		/* converted to pointer in clocal() */
+		conput(0, p);
+		return;
+	}
+	if (p->n_lval == 0 && p->n_name[0] == '\0') {
+		putchar('0');
+		return;
+	}
+	if (BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR)
+		cz = (p->n_lval/4) | ((p->n_lval & 3) << 30);
+	else
+		cz = (p->n_lval/2) | (((p->n_lval & 1) + 5) << 30);
+	cz |= 0700000000000LL;
+	printf("0%llo", cz);
+	if (p->n_name[0] != '\0')
+		printf("+%s", p->n_name);
+}
+
+static void
+putcond(NODE *p)
+{               
+	char *c = 0; /* XXX gcc */
+
+	switch (p->n_op) {
+	case EQ: c = "e"; break;
+	case NE: c = "n"; break;
+	case LE: c = "le"; break;
+	case LT: c = "l"; break;
+	case GT: c = "g"; break;
+	case GE: c = "ge"; break;
+	default:
+		cerror("putcond");
+	}
+	printf("%s", c);
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+	NODE *l;
+	CONSZ hval;
+
+	switch (c) {
+	case 'A': /* ildb right arg */
+		adrput(stdout, p->n_left->n_left);
+		break;
+
+	case 'B': /* remove from stack after subroutine call */
+		if (p->n_qual)
+			printf("	subi %%17,0%o\n", p->n_qual);
+		break;
+
+	case 'C':
+		constput(p);
+		break;
+
+	case 'D': /* Find out which type of const load insn to use */
+		if (p->n_op != ICON)
+			cerror("zzzcode not ICON");
+		if (p->n_name[0] == '\0') {
+			if ((p->n_lval <= 0777777) && (p->n_lval > 0))
+				printf("movei");
+			else if ((p->n_lval & 0777777) == 0)
+				printf("hrlzi");
+			else
+				printf("move");
+		} else
+			printf("move");
+		break;
+
+	case 'E': /* Print correct constant expression */
+		if (p->n_name[0] == '\0') {
+			if ((p->n_lval <= 0777777) && (p->n_lval > 0)){
+				printf("0%llo", p->n_lval);
+			} else if ((p->n_lval & 0777777) == 0) {
+				printf("0%llo", p->n_lval >> 18);
+			} else {
+				if (p->n_lval < 0)
+					printf("[ .long -0%llo]", -p->n_lval);
+				else
+					printf("[ .long 0%llo]", p->n_lval);
+			}
+		} else {
+			if (p->n_lval == 0)
+				printf("[ .long %s]", p->n_name);
+			else
+				printf("[ .long %s+0%llo]",
+				    p->n_name, p->n_lval);
+		}
+		break;
+
+	case 'G': /* structure argument */
+		printf("	addl %%17,0%o\n", p->n_stsize/(SZINT/SZCHAR));
+		printf("	foo...\n");
+		break;
+
+	case 'P':
+		p = getlr(p, 'R');
+		/* FALLTHROUGH */
+	case 'O':
+		/*
+		 * Print long long expression.
+		 */
+		hval = gethval(p->n_lval);
+		printf("[ .long 0%llo,0%llo", hval,
+		    (p->n_lval & 0377777777777LL) | (hval & 0400000000000LL));
+		if (p->n_name[0] != '\0')
+			printf("+%s", p->n_name);
+		printf(" ]");
+		break;
+
+	case 'F': /* Print an "opsimp" instruction based on its const type */
+		hopcode(oneinstr(p->n_right) ? 'C' : 'R', p->n_op);
+		break;
+
+	case 'H': /* Print a small constant */
+		p = p->n_right;
+		printf("0%llo", p->n_lval & 0777777);
+		break;
+
+	case 'Q': /* two-param long long comparisions */
+		twollcomp(p);
+		break;
+
+	case 'R': /* two-param conditionals */
+		twocomp(p);
+		break;
+
+	case 'U':
+		emitshort(p);
+		break;
+		
+	case 'V':
+		storeshort(p);
+		break;
+
+	case 'Z':
+		ptrcomp(p);
+		break;
+
+	case 'a':
+		imuli(p);
+		break;
+
+	case 'b':
+		idivi(p);
+		break;
+
+	case 'c':
+		xmovei(p);
+		break;
+
+	case 'd':
+		printcon(p);
+		break;
+
+	case 'e':
+		putcond(p);
+		break;
+
+	case 'g':
+		if (p->n_right->n_op != OREG || p->n_right->n_lval != 0)
+			comperr("bad Zg oreg");
+		printf("%s", rnames[p->n_right->n_rval]);
+		break;
+
+#if 0
+	case '1': /* double upput */
+		p = getlr(p, '1');
+		p->n_rval += 2;
+		adrput(stdout, p);
+		p->n_rval -= 2;
+		break;
+#endif
+
+	case 'i': /* Write instruction for short load from name */
+		l = getlr(p, 'L');
+		printf("	h%cr%c %s,%s+" CONFMT "\n",
+		    l->n_lval & 1 ? 'r' : 'l',
+		    ISUNSIGNED(p->n_type) ? 'z' : 'e',
+		    rnames[getlr(p, '1')->n_rval],
+		    l->n_name, l->n_lval >> 1);
+		break;
+
+	default:
+		cerror("zzzcode %c", c);
+	}
+}
+
+/* set up temporary registers */
+void
+setregs()
+{
+	fregs = 7;	/* 7 free regs on PDP10 (1-7) */
+}
+
+/*ARGSUSED*/
+int
+rewfld(NODE *p)
+{
+	return(1);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+	return 0;
+}
+
+int
+flshape(NODE *p)
+{
+	register int o = p->n_op;
+
+	return (o == REG || o == NAME || o == ICON ||
+		(o == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1)));
+}
+
+/* INTEMP shapes must not contain any temporary registers */
+int
+shtemp(NODE *p)
+{
+	return(0);
+}
+
+int
+shumul(NODE *p, int order)
+{
+	register int o;
+
+	if (x2debug) {
+		int val;
+		printf("shumul(%p)\n", p);
+		eprint(p, 0, &val, &val);
+	}
+
+	o = p->n_op;
+#if 0
+	if (o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON)
+		return(STARNM);
+#endif
+
+#if 0
+	if ((o == INCR) &&
+	    (p->n_left->n_op == REG && p->n_right->n_op == ICON) &&
+	    p->n_right->n_name[0] == '\0') {
+		switch (p->n_type) {
+			case CHAR|PTR:
+			case UCHAR|PTR:
+				o = 1;
+				break;
+
+			case SHORT|PTR:
+			case USHORT|PTR:
+				o = 2;
+				break;
+
+			case INT|PTR:
+			case UNSIGNED|PTR:
+			case LONG|PTR:
+			case ULONG|PTR:
+			case FLOAT|PTR:
+				o = 4;
+				break;
+
+			case DOUBLE|PTR:
+			case LONGLONG|PTR:
+			case ULONGLONG|PTR:
+				o = 8;
+				break;
+
+			default:
+				if (ISPTR(p->n_type) &&
+				     ISPTR(DECREF(p->n_type))) {
+					o = 4;
+					break;
+				} else
+					return(0);
+		}
+		return( 0);
+	}
+#endif
+	return( SRNOPE );
+}
+
+void
+adrcon(CONSZ val)
+{
+	cerror("adrcon: val %llo\n", val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+	switch (p->n_op) {
+	case ICON:
+		if (p->n_lval != 0) {
+			acon(stdout, p);
+			if (p->n_name[0] != '\0')
+				putchar('+');
+		}
+		if (p->n_name[0] != '\0')
+			printf("%s", p->n_name);
+		if (p->n_name[0] == '\0' && p->n_lval == 0)
+			putchar('0');
+		return;
+
+	case REG:
+		putstr(rnames[p->n_rval]);
+		return;
+
+	default:
+		cerror("illegal conput");
+	}
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+	cerror("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+
+	size /= SZLONG;
+	switch (p->n_op) {
+	case REG:
+		putstr(rnames[p->n_rval + size]);
+		break;
+
+	case NAME:
+	case OREG:
+		p->n_lval += size;
+		adrput(stdout, p);
+		p->n_lval -= size;
+		break;
+	case ICON:
+		printf(CONFMT, p->n_lval >> (36 * size));
+		break;
+	default:
+		cerror("upput bad op %d size %d", p->n_op, size);
+	}
+}
+
+void
+adrput(FILE *fp, NODE *p)
+{
+	int r;
+	/* output an address, with offsets, from p */
+
+	if (p->n_op == FLD)
+		p = p->n_left;
+
+	switch (p->n_op) {
+
+	case NAME:
+		if (p->n_name[0] != '\0')
+			fputs(p->n_name, fp);
+		if (p->n_lval != 0)
+			fprintf(fp, "+" CONFMT, p->n_lval & 0777777777777LL);
+		return;
+
+	case OREG:
+		r = p->n_rval;
+#if 0
+		if (R2TEST(r)) { /* double indexing */
+			register int flags;
+
+			flags = R2UPK3(r);
+			if (flags & 1)
+				putc('*', fp);
+			if (flags & 4)
+				putc('-', fp);
+			if (p->n_lval != 0 || p->n_name[0] != '\0')
+				acon(p);
+			if (R2UPK1(r) != 100)
+				printf("(%s)", rnames[R2UPK1(r)]);
+			if (flags & 2)
+				putchar('+');
+			printf("[%s]", rnames[R2UPK2(r)]);
+			return;
+		}
+#endif
+		if (R2TEST(r))
+			cerror("adrput: unwanted double indexing: r %o", r);
+		if (p->n_rval != FPREG && p->n_lval < 0 && p->n_name[0]) {
+			fprintf(fp, "%s", p->n_name);
+			acon(fp, p);
+			fprintf(fp, "(%s)", rnames[p->n_rval]);
+			return;
+		}
+		if (p->n_lval < 0 && p->n_rval == FPREG && offarg) {
+			p->n_lval -= offarg-2; acon(fp, p); p->n_lval += offarg-2;
+		} else if (p->n_lval != 0)
+			acon(fp, p);
+		if (p->n_name[0] != '\0')
+			fprintf(fp, "%s%s", p->n_lval ? "+" : "", p->n_name);
+		if (p->n_lval > 0 && p->n_rval == FPREG && offlab)
+			fprintf(fp, "+" LABFMT, offlab);
+		if (p->n_lval < 0 && p->n_rval == FPREG && offarg)
+			fprintf(fp, "(017)");
+		else
+			fprintf(fp, "(%s)", rnames[p->n_rval]);
+		return;
+	case ICON:
+		/* addressable value of the constant */
+		if (p->n_lval > 0) {
+			acon(fp, p);
+			if (p->n_name[0] != '\0')
+				putc('+', fp);
+		}
+		if (p->n_name[0] != '\0')
+			fprintf(fp, "%s", p->n_name);
+		if (p->n_lval < 0) 
+			acon(fp, p);
+		if (p->n_name[0] == '\0' && p->n_lval == 0)
+			putc('0', fp);
+		return;
+
+	case REG:
+		fputs(rnames[p->n_rval], fp);
+		return;
+
+	default:
+		cerror("illegal address, op %d", p->n_op);
+		return;
+
+	}
+}
+
+/*
+ * print out a constant
+*/
+void
+acon(FILE *fp, NODE *p)
+{
+	if (p->n_lval < 0 && p->n_lval > -0777777777777ULL)
+		fprintf(fp, "-" CONFMT, -p->n_lval);
+	else
+		fprintf(fp, CONFMT, p->n_lval);
+}
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o,int lab)
+{
+}
+
+/*
+ * Do some local optimizations that must be done after optim is called.
+ */
+static void
+optim2(NODE *p, void *arg)
+{
+	int op = p->n_op;
+	int m, ml;
+	NODE *l;
+
+	/* Remove redundant PCONV's */
+	if (op == PCONV) {
+		l = p->n_left;
+		m = BTYPE(p->n_type);
+		ml = BTYPE(l->n_type);
+		if ((m == INT || m == LONG || m == LONGLONG || m == FLOAT ||
+		    m == DOUBLE || m == STRTY || m == UNIONTY ||
+		    m == UNSIGNED || m == ULONG || m == ULONGLONG) &&
+		    (ml == INT || ml == LONG || ml == LONGLONG || ml == FLOAT ||
+		    ml == DOUBLE || ml == STRTY || ml == UNIONTY || 
+		    ml == UNSIGNED || ml == ULONG ||
+		    ml == ULONGLONG) && ISPTR(l->n_type)) {
+			*p = *l;
+			nfree(l);
+			op = p->n_op;
+		} else
+		if (ISPTR(DECREF(p->n_type)) &&
+		    (l->n_type == INCREF(STRTY))) {
+			*p = *l;
+			nfree(l);
+			op = p->n_op;
+		} else
+		if (ISPTR(DECREF(l->n_type)) &&
+		    (p->n_type == INCREF(INT) ||
+		    p->n_type == INCREF(STRTY) ||
+		    p->n_type == INCREF(UNSIGNED))) {
+			*p = *l;
+			nfree(l);
+			op = p->n_op;
+		}
+
+	}
+	/* Add constands, similar to the one in optim() */
+	if (op == PLUS && p->n_right->n_op == ICON) {
+		l = p->n_left;
+		if (l->n_op == PLUS && l->n_right->n_op == ICON &&
+		    (p->n_right->n_name[0] == '\0' ||
+		     l->n_right->n_name[0] == '\0')) {
+			l->n_right->n_lval += p->n_right->n_lval;
+			if (l->n_right->n_name[0] == '\0')
+				l->n_right->n_name = p->n_right->n_name;
+			nfree(p->n_right);
+			*p = *l;
+			nfree(l);
+		}
+	}
+
+	/* Convert "PTR undef" (void *) to "PTR uchar" */
+	/* XXX - should be done in MI code */
+	if (BTYPE(p->n_type) == VOID)
+		p->n_type = (p->n_type & ~BTMASK) | UCHAR;
+	if (op == ICON) {
+		if ((p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR))
+		    && p->n_lval == 0 && p->n_name[0] != '\0')
+			p->n_lval = 0700000000000LL;
+		if ((p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT))
+		    && p->n_lval == 0 && p->n_name[0] != '\0')
+			p->n_lval = 0750000000000LL;
+	}
+	if (op == MINUS) {
+		if ((p->n_left->n_type == (PTR|CHAR) ||
+		    p->n_left->n_type == (PTR|UCHAR)) &&
+		    (p->n_right->n_type == (PTR|CHAR) ||
+		    p->n_right->n_type == (PTR|UCHAR))) {
+			l = talloc();
+			l->n_op = SCONV;
+			l->n_type = INT;
+			l->n_left = p->n_right;
+			p->n_right = l;
+			l = talloc();
+			l->n_op = SCONV;
+			l->n_type = INT;
+			l->n_left = p->n_left;
+			p->n_left = l;
+		}
+	}
+}
+
+void
+myreader(struct interpass *ipole)
+{
+	struct interpass *ip;
+
+	DLIST_FOREACH(ip, ipole, qelem) {
+		if (ip->type != IP_NODE)
+			continue;
+		walkf(ip->ip_node, optim2, 0);
+	}
+
+	if (x2debug) {
+		printf("myreader final tree:\n");
+		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);
+}
+
+/*
+ * Remove last goto.
+ */
+void
+myoptim(struct interpass *ip)
+{
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+	return (szty(t) == 2 ? CLASSB : CLASSA);
+}
+
+static int
+argsiz(NODE *p)
+{
+	TWORD t = p->n_type;
+
+	if (t == STRTY || t == UNIONTY)
+		return p->n_stsize/(SZINT/SZCHAR);
+	return szty(t);
+}
+
+/*
+ * 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)
+		if (p->n_right->n_op != ASSIGN)
+                	size += argsiz(p->n_right);
+	if (p->n_op != ASSIGN)
+        	size += argsiz(p);
+        op->n_qual = size; /* XXX */
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+	printf("	%smove %s,%s\n",
+	    (s > 017 ? "d" : ""), rnames[d], rnames[s]);
+}
+
+/*
+ * 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:
+		/* there are 13 classa, so min 6 classb are needed to block */
+		num = r[CLASSB] * 2;
+		num += r[CLASSA];
+		return num < 13;
+	case CLASSB:
+		/* 7 classa may block all classb */
+		num = r[CLASSB] + r[CLASSA];
+		return num < 7;
+	}
+	comperr("COLORMAP");
+	return 0; /* XXX gcc */
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+	return 0;
+}
Index: uspace/app/pcc/arch/pdp10/macdefs.h
===================================================================
--- uspace/app/pcc/arch/pdp10/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/pdp10/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,247 @@
+/*	$Id: macdefs.h,v 1.30 2009/01/24 21:43:49 gmcgarry Exp $	*/
+/*
+ * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent defines for both passes.
+ */
+
+/*
+ * Convert (multi-)character constant to integer.
+ * Assume: If only one value; store at left side (char size), otherwise 
+ * treat it as an integer.
+ */
+#define makecc(val,i) {			\
+	if (i == 0) { lastcon = val;	\
+	} else if (i == 1) { lastcon = (lastcon << 9) | val; lastcon <<= 18; \
+	} else { lastcon |= (val << (27 - (i * 9))); } }
+
+#define ARGINIT		36	/* # bits below fp where arguments start */
+#define AUTOINIT	36	/* # bits above fp where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR		9
+#define SZBOOL		36
+#define SZINT		36
+#define SZFLOAT		36
+#define SZDOUBLE	72
+#define SZLDOUBLE	72
+#define SZLONG		36
+#define SZSHORT		18
+#define SZPOINT(x)	36
+#define SZLONGLONG	72
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR		9
+#define ALBOOL		36
+#define ALINT		36
+#define ALFLOAT		36
+#define ALDOUBLE	36
+#define ALLDOUBLE	36
+#define ALLONG		36
+#define ALLONGLONG	36
+#define ALSHORT		18
+#define ALPOINT		36
+#define ALSTRUCT	36
+#define ALSTACK		36 
+
+/*
+ * Max values.
+ */
+#define	MIN_CHAR	-256
+#define	MAX_CHAR	255
+#define	MAX_UCHAR	511
+#define	MIN_SHORT	-131072
+#define	MAX_SHORT	131071
+#define	MAX_USHORT	262143
+#define	MIN_INT		(-0377777777777LL-1)
+#define	MAX_INT		0377777777777LL
+#define	MAX_UNSIGNED	0777777777777ULL
+#define	MIN_LONG	(-0377777777777LL-1)
+#define	MAX_LONG	0377777777777LL
+#define	MAX_ULONG	0777777777777ULL
+#define	MIN_LONGLONG	(000777777777777777777777LL-1)	/* XXX cross */
+#define	MAX_LONGLONG	000777777777777777777777LL	/* XXX cross */
+#define	MAX_ULONGLONG	001777777777777777777777ULL	/* XXX cross */
+
+/* Default char is unsigned */
+#define TARGET_STDARGS
+#define	CHAR_UNSIGNED
+#define	BOOL_TYPE	INT
+
+/*
+ * Use large-enough types.
+ */
+typedef	long long CONSZ;
+typedef	unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT	"0%llo"		/* format for printing constants */
+#define LABFMT	".L%d"		/* format for printing labels */
+#define STABLBL ".LL%d"		/* format for stab (debugging) labels */
+
+#undef BACKAUTO 		/* stack grows negatively for automatics */
+#undef BACKTEMP 		/* stack grows negatively for temporaries */
+
+#undef	FIELDOPS		/* no bit-field instructions */
+#undef	RTOLBYTES		/* bytes are numbered left to right */
+
+#define ENUMSIZE(high,low) INT	/* enums are always stored in full int */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)	((x)&03)
+#define wdal(k)		(BYTEOFF(k)==0)
+#define BITOOR(x)	((x)/36)		/* bit offset to oreg offset */
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+#define genfcall(a,b)	gencall(a,b)
+
+#define	szty(t)	(((t) == DOUBLE || (t) == FLOAT || \
+	(t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1)
+
+#define	shltype(o, p) \
+	((o) == REG || (o) == NAME || (o) == ICON || \
+	 (o) == OREG || ((o) == UMUL && shumul((p)->n_left, SOREG)))
+
+#undef	SPECIAL_INTEGERS
+
+/*
+ * Special shapes used in code generation.
+ */
+#define	SUSHCON	(SPECIAL|6)	/* unsigned short constant */
+#define	SNSHCON	(SPECIAL|7)	/* negative short constant */
+#define	SILDB	(SPECIAL|8)	/* use ildb here */
+
+/*
+ * Register allocator definitions.
+ *
+ * The pdp10 has 16 general-purpose registers, but the two
+ * highest are used as sp and fp.  Register 0 has special 
+ * constraints in its possible use as index register.
+ * All regs can be used as pairs, named by the lowest number.
+ * In here we call the registers Rn and the pairs XRn, in assembler
+ * just its number prefixed with %.
+ * 
+ * R1/XR1 are return registers.
+ *
+ * R0 is currently not used.
+ */
+
+#define	MAXREGS		29 /* 16 + 13 regs */
+#define	NUMCLASS	2
+
+#define R0	00
+#define R1	01
+#define R2	02
+#define R3	03
+#define R4	04
+#define R5	05
+#define R6	06
+#define R7	07
+#define R10	010
+#define R11	011
+#define R12	012
+#define R13	013
+#define R14	014
+#define R15	015
+#define R16	016
+#define R17	017
+#define FPREG	R16		/* frame pointer */
+#define STKREG	R17		/* stack pointer */
+
+
+#define XR0	020
+#define XR1	021
+#define XR2	022
+#define XR3	023
+#define XR4	024
+#define XR5	025
+#define XR6	026
+#define XR7	027
+#define XR10	030
+#define XR11	031
+#define XR12	032
+#define XR13	033
+#define XR14	034
+
+
+#define RSTATUS \
+	0, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,			\
+	SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,	\
+	SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,	\
+	SAREG|PERMREG, SAREG|PERMREG, 0, 0,				\
+	SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,		\
+	SBREG, SBREG, SBREG, SBREG, SBREG,
+
+#define ROVERLAP \
+        { XR0, -1 },			\
+        { XR0, XR1, -1 },		\
+        { XR1, XR2, -1 },		\
+        { XR2, XR3, -1 },		\
+        { XR3, XR4, -1 },		\
+        { XR4, XR5, -1 },		\
+        { XR5, XR6, -1 },		\
+        { XR6, XR7, -1 },		\
+        { XR7, XR10, -1 },		\
+        { XR10, XR11, -1 },		\
+        { XR11, XR12, -1 },		\
+        { XR12, XR13, -1 },		\
+        { XR13, XR14, -1 },		\
+        { XR14, -1 },			\
+        { -1 },				\
+        { -1 },				\
+        { R0, R1, XR1, -1 },		\
+        { R1, R2, XR0, XR2, -1 },	\
+        { R2, R3, XR1, XR3, -1 },	\
+        { R3, R4, XR2, XR4, -1 },	\
+        { R4, R5, XR3, XR5, -1 },	\
+        { R5, R6, XR4, XR6, -1 },	\
+        { R6, R7, XR5, XR7, -1 },	\
+        { R7, R10, XR6, XR10, -1 },	\
+        { R10, R11, XR7, XR11, -1 },	\
+        { R11, R12, XR10, XR12, -1 },	\
+        { R12, R13, XR11, XR13, -1 },	\
+        { R13, R14, XR12, XR14, -1 },	\
+        { R14, R15, XR13, -1 },
+
+/* Return a register class based on the type of the node */
+#define PCLASS(p) (szty(p->n_type) == 2 ? SBREG : SAREG)
+#define RETREG(x) (szty(x) == 2 ? XR1 : R1)
+#define DECRA(x,y)      (((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define ENCRD(x)        (x)             /* Encode dest reg in n_reg */
+#define ENCRA1(x)       ((x) << 6)      /* A1 */
+#define ENCRA2(x)       ((x) << 12)     /* A2 */
+#define ENCRA(x,y)      ((x) << (6+y*6))        /* encode regs in int */
+#define GCLASS(x)	(x < 16 ? CLASSA : CLASSB)
+int COLORMAP(int c, int *r);
Index: uspace/app/pcc/arch/pdp10/order.c
===================================================================
--- uspace/app/pcc/arch/pdp10/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/pdp10/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,202 @@
+/*	$Id: order.c,v 1.63 2008/01/15 21:47:06 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"
+
+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 */
+}
+
+int radebug = 0;
+
+void
+offstar(NODE *p, int shape)
+{
+	NODE *q;
+
+	if (x2debug)
+		printf("offstar(%p)\n", p);
+
+	if( p->n_op == PLUS || p->n_op == MINUS ){
+		if( p->n_right->n_op == ICON ){
+			q = p->n_left;
+			if (q->n_op != REG)
+				geninsn(q, INAREG);
+			p->n_su = -1;
+		}
+	}
+	geninsn(p, INAREG);
+}
+
+/*
+ * findops() failed, see if we can rewrite it to match.
+ */
+int
+setbin(NODE *p)
+{
+	TWORD ty;
+	NODE *r, *s;
+
+	ty = p->n_type;
+	switch (p->n_op) {
+	case MINUS:
+		switch (ty) {
+		case PTR+CHAR:
+		case PTR+UCHAR:
+		case PTR+SHORT:
+		case PTR+USHORT:
+			/*
+			 * Must negate the right side and change op to PLUS.
+			 */
+			r = p->n_right;
+			if (r->n_op == ICON) {
+				r->n_lval = -r->n_lval;
+			} else {
+				s = talloc();
+				s->n_type = r->n_type;
+				s->n_op = UMINUS;
+				s->n_left = r;
+				p->n_right = s;
+			}
+			p->n_op = PLUS;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/* setup for assignment operator */
+int
+setasg(NODE *p, int cookie)
+{
+	return(0);
+}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+	return 0;
+}
+
+int
+special(NODE *p, int shape)
+{
+	switch (shape) {
+	case SUSHCON:
+		if (p->n_op == ICON && p->n_name[0] == '\0' &&
+		    (p->n_lval > 0 && p->n_lval <= 0777777))
+			return 1;
+		break;
+
+	case SNSHCON:
+		if (p->n_op == ICON && p->n_name[0] == '\0' &&
+		    (p->n_lval < 0 && p->n_lval > -01000000))
+			return 1;
+		break;
+	case SILDB:
+		if (p->n_op == ASSIGN && p->n_left->n_op == REG &&
+		    p->n_right->n_op == PLUS &&
+		    p->n_right->n_left->n_op == REG &&
+		    p->n_right->n_right->n_op == ICON && 
+		    p->n_right->n_right->n_lval == 1 &&
+		    p->n_right->n_left->n_rval == p->n_left->n_rval)
+			return 1;
+		break;
+	}
+	return 0;
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+	return 0; /* nothing differs on x86 */
+}
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+	return 0; /* XXX gcc */
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *p)
+{
+	if (x2debug)
+		printf("myormake(%p)\n", p);
+}
+
+/*
+ * set registers in calling conventions live.
+ */
+int *
+livecall(NODE *p)
+{
+	static int r[8], *s = r;
+
+	*s = -1;
+	if (p->n_op == UCALL || p->n_op == UFORTCALL || p->n_op == USTCALL ||
+	    p->n_op == FORTCALL)
+		return s;
+	for (p = p->n_right; p->n_op == CM; p = p->n_left) {
+		if (p->n_right->n_op == ASSIGN &&
+		    p->n_right->n_left->n_op == REG)
+			*s++ = p->n_right->n_left->n_rval;
+	}
+	if (p->n_op == ASSIGN &&
+	    p->n_left->n_op == REG)
+		*s++ = p->n_left->n_rval;
+	*s = -1;
+	return r;
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+	return 1;
+}
Index: uspace/app/pcc/arch/pdp10/table.c
===================================================================
--- uspace/app/pcc/arch/pdp10/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/pdp10/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1136 @@
+/*	$Id: table.c,v 1.97 2008/02/10 19:25:44 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
+
+struct optab table[] = {
+{ -1, FORREW,SANY,TANY,SANY,TANY,REWRITE,-1,"", },
+/*
+ * A bunch of pointer conversions.
+ * First pointer to integer.
+ */
+/* Convert char pointer to int */
+{ SCONV,	INAREG,
+	SAREG|SAREG,	TPTRTO|TCHAR|TUCHAR,
+	SANY,	TWORD,
+		NAREG,	RLEFT,
+		"	lsh AL,2\n"
+		"	move A1,AL\n"
+		"	lsh A1,-040\n"
+		"	trz A1,074\n"
+		"	ior AL,A1\n"
+		"	tlz AL,0740000\n", },
+
+/* Convert short pointer to int */
+{ SCONV,	INAREG,
+	SAREG|SAREG,	TPTRTO|TSHORT|TUSHORT,
+	SANY,	TWORD,
+		NAREG,	RLEFT,
+		"	lsh AL,2\n"
+		"	move A1,AL\n"
+		"	lsh A1,-041\n"
+		"	trz A1,2\n"
+		"	ior AL,A1\n"
+		"	tlz AL,0740000\n", },
+
+/* Convert int/unsigned/long/ulong/struct/union/func ptr to int */
+{ SCONV,	INAREG,
+	SAREG|SAREG,	TPTRTO|TWORD|TSTRUCT|TPOINT,
+	SANY,		TWORD,
+		0,	RLEFT,
+		"	lsh AL,2\n", },
+
+/*
+ * Convert int/long to pointers.
+ */
+/* Convert int to char pointer */
+{ PCONV,	INAREG,
+	SAREG,	TWORD,
+	SANY,	TPTRTO|TCHAR|TUCHAR,
+		NAREG,	RLEFT,
+		"	move A1,AL\n"
+		"	lsh A1,036\n"
+		"	tlo A1,0700000\n"
+		"	tlz A1,0040000\n"
+		"	lsh AL,-2\n"
+		"	ior AL,A1\n", },
+
+/* Convert int/long to short pointer */
+{ PCONV,	INAREG,
+	SAREG,	TWORD,
+	SANY,	TPTRTO|TSHORT|TUSHORT,
+		NAREG,	RLEFT,
+		"	move A1,AL\n"
+		"	lsh AL,-2\n"
+		"	tlo AL,0750000\n"
+		"	lsh A1,035\n"
+		"	tlz A1,0760000\n"
+		"	add AL,A1\n", },
+
+/* Convert int/long to int/struct/multiple ptr */
+{ PCONV,	INAREG,
+	SAREG,	TWORD,
+	SANY,	TPOINT|TWORD|TSTRUCT,
+		0,	RLEFT,
+		"	lsh AL,-2\n", },
+
+/*
+ * Pointer to pointer conversions.
+ */
+/* Convert char ptr to short ptr */
+{ PCONV,	INAREG,
+	SAREG,	TPTRTO|TCHAR|TUCHAR,
+	SANY,	TPTRTO|TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	tlo AL,050000\n"
+		"	tlne AL,020000\n"
+		"	tlz AL,010000\n", },
+
+/* Convert char/short pointer to int/struct/multiple ptr */
+{ PCONV,	INAREG,
+	SAREG,	TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SANY,	TPOINT|TWORD|TSTRUCT,
+		0,	RLEFT,
+		"	tlz AL,0770000\n", },
+
+/* Convert short pointer to char ptr */
+{ PCONV,	INAREG,
+	SAREG,	TPTRTO|TSHORT|TUSHORT,
+	SANY,	TPTRTO|TCHAR|TUCHAR,
+		0,	RLEFT,
+		"	tlz AL,050000\n", },
+
+/* Convert int/struct/foo pointer to char ptr */
+{ PCONV,	INAREG,
+	SAREG,	TPOINT|TWORD|TSTRUCT,
+	SANY,	TPTRTO|TCHAR|TUCHAR,
+		0,	RLEFT,
+		"	tlo AL,0700000\n", },
+
+/* Convert int/struct/foo pointer to short ptr */
+{ PCONV,	INAREG,
+	SAREG,	TPTRTO|TWORD|TSTRUCT,
+	SANY,	TPTRTO|TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	tlo AL,0750000\n", },
+
+/*
+ * A bunch conversions of integral<->integral types
+ */
+
+/* convert short/char to int. This is done when register is loaded */
+{ SCONV,	INAREG,
+	SAREG,	TSHORT|TUSHORT|TCHAR|TUCHAR|TWORD,
+	SANY,	TWORD,
+		0,	RLEFT,
+		"", },
+
+/* convert int to short/char. This is done when register is loaded */
+{ SCONV,	INAREG,
+	SAREG,	TWORD,
+	SANY,	TSHORT|TUSHORT|TCHAR|TUCHAR|TWORD,
+		0,	RLEFT,
+		"", },
+
+/* convert int/long to unsigned long long */
+{ SCONV,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+	SANY,	TULONGLONG,
+		NAREG|NASL,	RESC1,
+		"	move U1,AL\n"
+		"	setz A1,\n"
+		"	tlze U1,0400000\n"
+		"	tro A1,01\n" , },
+
+/* convert int/long to long long */
+{ SCONV,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+	SANY,	TLONGLONG,
+		NAREG|NASL,	RESC1,
+		"	move U1,AL\n"
+		"	move A1,U1\n"
+		"	ash A1,-043\n", },
+
+/* convert uchar/ushort to (unsigned) long long */
+{ SCONV,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TUCHAR|TUSHORT,
+	SANY,				TLL,
+		NAREG|NASL,	RESC1,
+		"	move U1,AL\n"
+		"	setz A1,\n", },
+
+/* convert long long to int/long */
+{ SCONV,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TLL,
+	SANY,	TWORD,
+		NAREG|NASL,	RESC1,
+		"	move A1,UL\n", },
+
+/* convert long long to unsigned char - XXX - signed char */
+{ SCONV,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TLL,
+	SANY,	TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	move A1,UL\n"
+		"	andi A1,0777\n", },
+
+/* convert long long to short - XXX - signed short */
+{ SCONV,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TLL,
+	SANY,	TSHORT|TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	move A1,UL\n"
+		"	hrrz A1,A1\n", },
+
+/* floating point conversions */
+{ SCONV,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TDOUBLE|TFLOAT,
+	SANY,	TWORD,
+		NAREG|NASL,	RESC1,
+		"	fix A1,AL\n", },
+
+{ SCONV,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+	SANY,	TFLOAT,
+		NAREG|NASL,	RESC1,
+		"	fltr A1,AL\n", },
+
+{ SCONV,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+	SANY,	TDOUBLE,
+		NAREG|NASL,	RESC1,
+		"	fltr A1,AL\n	setz U1,\n", },
+
+{ SCONV,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TDOUBLE,
+	SANY,	TFLOAT,
+		NAREG|NASL,	RESC1,
+		"	move A1,AL\n", },
+
+{ SCONV,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TFLOAT,
+	SANY,	TDOUBLE,
+		NAREG|NASL,	RESC1,
+		"	move A1,AL\n	setz U1,\n", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ UCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,	/* should be 0 */
+		"	pushj 017,AL\nZB", },
+
+{ CALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,	/* should be 0 */
+		"	pushj 017,AL\nZB", },
+
+{ UCALL,	INAREG,
+	SCON,	TANY,
+	SANY,	TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TPOINT,
+		NAREG,	RESC1,	/* should be 0 */
+		"	pushj 017,AL\nZB", },
+
+{ CALL,		INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	pushj 017,AL\nZB", },
+
+{ UCALL,	INAREG,
+	SAREG|SAREG,	TANY,
+	SANY,	TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	pushj 017,(AL)\nZB", },
+
+{ UCALL,	INAREG,
+	SNAME|SOREG,	TANY,
+	SANY,	TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT,
+		NAREG,	RESC1,	/* should be 0 */
+		"	pushj 017,@AL\nZB", },
+
+#ifdef notyet
+/*
+ * INCR can be slightly optimized.
+ */
+{ INCR,		INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO,
+	SONE,	TANY,
+		NAREG,	RESC1,
+		"	move A1,AL\n"
+		"	ibp AL\n", },
+
+/* Fix check of return value */
+{ INCR,		FOREFF,
+	SAREG|SAREG|SNAME|SOREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO,
+	SONE,	TANY,
+		0,	0,
+		"	ibp AL\n", },
+#endif
+
+/*
+ * PLUS operators.
+ */
+/* Add a value to a char/short pointer */
+{ PLUS,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG|SNAME|SOREG,	TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SAREG|SAREG,			TWORD,
+		0,	RRIGHT,
+		"	adjbp AR,AL\n", },
+
+/* No more search for char/short pointer addition */
+{ PLUS,	INAREG|INAREG|FOREFF,
+	SANY,	TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SANY,	TANY,
+		REWRITE, 0,
+		"DIEDIEDIE!\n", },
+
+/* Add char/short/int to register */
+{ PLUS,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,			TWORD,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+		0,	RLEFT,
+		"	add AL,AR\n", },
+
+/* Add char/short/int to memory */
+{ PLUS,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+	SAREG|SAREG,			TWORD,
+		0,	RLEFT,
+		"	addm AR,AL\n", },
+
+/* Add a small constant to a register */
+{ PLUS,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD|TPOINT,
+	SUSHCON,	TWORD,
+		0,	RLEFT,
+		"	addi AL,AR\n", },
+
+/* Add a larger constant to a register */
+{ PLUS,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD|TPOINT,
+	SCON,	TWORD,
+		0,	RLEFT,
+		"	add AL,[ .long AR ]\n", },
+
+/* Add long long to register */
+{ PLUS,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,			TLL,
+	SAREG|SAREG|SNAME|SOREG,	TLL,
+		0,	RLEFT,
+		"	dadd AL,AR\n", },
+
+/* Add int (or int pointer) to register */
+{ PLUS,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,			TWORD|TPOINT,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+		0,	RLEFT,
+		"	add AL,AR # foo \n", },
+
+/* char/short are allowed to be added if they are in registers */
+{ PLUS,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+		0,	RLEFT,
+		"	add AL,AR\n", },
+
+/* get address of an memory position into a register */
+{ PLUS,	INAREG|INAREG,
+	SAREG|SAREG,	TWORD|TPTRTO,
+	SCON,		TANY,
+		NAREG,	RESC1,
+		"	xmovei A1,AR(AL)\n", },
+
+/* Safety belt for plus */
+{ PLUS,	FORREW|FOREFF|INAREG|INAREG,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"DIEDIEDIE", },
+
+/*
+ * MINUS operators.
+ */
+/* Rewrite subtracts from char/short pointers (to negative adds) */
+{ MINUS,	FORREW|FOREFF|INAREG|INAREG,
+	SANY,	TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO,
+	SANY,	TANY,
+		REWRITE,	0,
+		"DIEDIEDIE", },
+
+/* Subtract char/short/int word in memory from reg */
+{ MINUS,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,			TWORD|TPOINT,
+	SAREG|SAREG|SNAME|SOREG,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	sub AL,AR\n", },
+
+/* Subtract a small constant from reg */
+{ MINUS,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,	TWORD|TPOINT,
+	SUSHCON,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	subi AL,AR\n", },
+
+/* Subtract a large constant from reg */
+{ MINUS,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,	TWORD|TPOINT,
+	SCON,	TWORD|TPOINT,
+		0,	RLEFT,
+		"	sub AL,[ .long AR ]\n", },
+
+/* Subtract char/short/int word in memory from reg, save in memory */
+{ MINUS,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,			TWORD,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+		0,	RRIGHT,
+		"	subm AL,AR\n", },
+
+/* Subtract long long from register */
+{ MINUS,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,			TLL,
+	SAREG|SAREG|SNAME|SOREG,	TLL,
+		0,	RLEFT,
+		"	dsub AL,AR\n", },
+
+/* char/short are allowed to be subtracted if they are in registers */
+{ MINUS,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+		0,	RLEFT,
+		"	sub AL,AR\n", },
+
+/* Safety belt for plus */
+{ MINUS,	FORREW|FOREFF|INAREG|INAREG,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"DIEDIEDIE", },
+
+/*
+ * AND/OR/ER operators.
+ * Simpler that the ops above in that they only work on integral types.
+ */
+/* And char/short/int with integer memory */
+{ AND,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,			TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+		0,	RLEFT,
+		"	and AL,AR\n", },
+
+/* And char/short/int with register */
+{ AND,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,			TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SAREG|SAREG,			TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+		0,	RLEFT,
+		"	and AL,AR\n", },
+
+/* And char/short/int with small constant */
+{ AND,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SUSHCON,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+		0,	RLEFT,
+		"	andi AL,AR\n", },
+
+/* And char/short/int with large constant */
+{ AND,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SCON,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+		0,	RLEFT,
+		"	and AL,[ .long AR ]\n", },
+
+/* long long AND */
+{ AND,	INAREG|FOREFF,
+	SAREG|SAREG,			TLL,
+	SAREG|SAREG|SNAME|SOREG,	TLL,
+		0,	RLEFT,
+		"	and AL,AR\n"
+		"	and UL,UR\n", },
+
+/* Safety belt for AND */
+{ AND,	FORREW|FOREFF|INAREG|INAREG,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"DIEDIEDIE", },
+
+
+/* OR char/short/int with integer memory */
+{ OR,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,			TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+		0,	RLEFT,
+		"	ior AL,AR\n", },
+
+/* OR char/short/int with register */
+{ OR,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,			TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SAREG|SAREG,			TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+		0,	RLEFT,
+		"	ior AL,AR\n", },
+
+/* OR char/short/int with small constant */
+{ OR,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SUSHCON,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+		0,	RLEFT,
+		"	iori AL,AR\n", },
+
+/* OR char/short/int with large constant */
+{ OR,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SCON,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+		0,	RLEFT,
+		"	ior AL,[ .long AR ]\n", },
+
+/* long long OR */
+{ OR,	INAREG|FOREFF,
+	SAREG|SAREG,			TLL,
+	SAREG|SAREG|SNAME|SOREG,	TLL,
+		0,	RLEFT,
+		"	ior AL,AR\n"
+		"	ior UL,UR\n", },
+
+/* Safety belt for OR */
+{ OR,	FORREW|FOREFF|INAREG|INAREG,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"DIEDIEDIE", },
+
+
+/* ER char/short/int with integer memory */
+{ ER,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,			TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+		0,	RLEFT,
+		"	xor AL,AR\n", },
+
+/* ER char/short/int with register */
+{ ER,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,			TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SAREG|SAREG,			TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+		0,	RLEFT,
+		"	xor AL,AR\n", },
+
+/* ER char/short/int with small constant */
+{ ER,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SUSHCON,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+		0,	RLEFT,
+		"	xori AL,AR\n", },
+
+/* ER char/short/int with large constant */
+{ ER,	FOREFF|INAREG|INAREG,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+	SCON,	TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD,
+		0,	RLEFT,
+		"	xor AL,[ .long AR ]\n", },
+
+/* long long ER */
+{ ER,	INAREG|FOREFF,
+	SAREG|SAREG,			TLL,
+	SAREG|SAREG|SNAME|SOREG,	TLL,
+		0,	RLEFT,
+		"	xor AL,AR\n"
+		"	xor UL,UR\n", },
+
+/* Safety belt for ER */
+{ ER,	FORREW|FOREFF|INAREG|INAREG,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"DIEDIEDIE", },
+
+/*
+ * The next rules handle all shift operators.
+ */
+{ LS,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SAREG|SAREG,	TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	lsh AL,(AR)\n", },
+
+{ LS,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SNAME|SOREG,	TWORD,
+		0,	RLEFT,
+		"	lsh AL,@AR\n", },
+
+{ LS,       INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TLL,
+	SCON,		TANY,
+		0,	RLEFT,
+		"	ashc AL,ZH\n", },
+
+{ LS,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TLL,
+	SAREG|SAREG /* |SNAME|SOREG */,	TANY,
+		0,	RLEFT,
+		"	ashc AL,(AR)\n", },
+
+{ RS,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TSWORD,
+	SCON,		TWORD,
+		0,	RLEFT,
+		"	ash AL,-ZH\n", },
+
+{ RS,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TUWORD,
+	SCON,		TWORD,
+		0,	RLEFT,
+		"	lsh AL,-ZH\n", },
+
+/* Safety belt for LS/RS */
+{ LS,	FORREW|FOREFF|INAREG|INAREG,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"DIEDIEDIE", },
+
+{ RS,	FORREW|FOREFF|INAREG|INAREG,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"DIEDIEDIE", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+/* Match zeroed registers first */
+{ ASSIGN,	INAREG|FOREFF,
+	SAREG,	TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT,
+	SZERO,	TANY,
+		0,	RDEST,
+		"	setz AL,\n", },
+
+{ ASSIGN,	FOREFF,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SZERO,	TANY,
+		0,	0,
+		"	setzm AL\n", },
+
+{ ASSIGN,	INAREG|FOREFF,
+	SAREG|SAREG,	TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT,
+	SMONE,	TANY,
+		0,	RDEST,
+		"	setom AL\n", },
+
+{ ASSIGN,	FOREFF,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SMONE,	TANY,
+		0,	0,
+		"	setom AL\n", },
+
+{ ASSIGN,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,		TWORD|TPOINT,
+	SCON,		TWORD|TPOINT,
+		0,	RDEST,
+		"	ZC\n", },
+
+{ ASSIGN,	INAREG|INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT|TFLOAT,
+	SAREG|SAREG,		TUCHAR|TUSHORT|TWORD|TPOINT|TFLOAT,
+		0,	RDEST,
+		"	movem AR,AL\n", },
+
+{ ASSIGN,	INAREG|INAREG|FOREFF,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT|TFLOAT,
+	SAREG|SAREG,		TSHORT,
+		0,	RDEST,
+		"	hrrem AR,AL\n", },
+
+{ ASSIGN,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT,
+	SAREG|SAREG|SNAME|SOREG,	TWORD|TPOINT,
+		0,	RDEST,
+		"	move AL,AR\n", },
+
+{ ASSIGN,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TUCHAR|TUSHORT|TCHAR|TSHORT,
+	SAREG|SAREG,	TUCHAR|TUSHORT|TCHAR|TSHORT,
+		0,	RDEST,
+		"	move AL,AR\n", },
+
+{ ASSIGN,	INBREG|FOREFF,
+	SBREG|SNAME|SOREG,	TLL|TDOUBLE,
+	SBREG,		TLL|TDOUBLE,
+		0,	RDEST,
+		"	dmovem AR,AL\n", },
+
+{ ASSIGN,	INAREG|INAREG|FOREFF,
+	SOREG|SNAME,	TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG|SAREG,	TANY,
+		0,	RDEST,
+		"ZV", },
+
+{ ASSIGN,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TUSHORT|TUCHAR,
+	SOREG,		TANY,
+		0,	RDEST,
+		"	ldb AL,Zg\n", },
+
+{ ASSIGN,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SSCON,		TANY,
+		0,	RDEST,
+		"	movei AL,AR\n", },
+
+{ ASSIGN,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SCON,		TANY,
+		0,	RDEST,
+		"	move AL,[ .long AR]\n", },
+
+/*
+ * DIV/MOD/MUL 
+ * These can be done way more efficient.
+ */
+/* long long div. XXX - work only with unsigned */
+{ DIV,	INBREG,
+	SBREG|SNAME|SOREG,	TLL,
+	SBREG|SNAME|SOREG,	TLL,
+		(2*NBREG)|NBSL,	RESC1,
+		"	dmove A2,AL ; dmove A1,[ .long 0,0 ]\n"
+		"	ddiv A1,AR\n", },
+
+/* long long div. with constant. XXX - work only with unsigned */
+{ DIV,	INBREG,
+	SBREG|SNAME|SOREG,	TLL,
+	SCON,	TLL,
+		(2*NBREG)|NBSL,	RESC1,
+		"	dmove A2,AL ; dmove A1,[ .long 0,0 ]\n"
+		"	ddiv A1,ZP\n", },
+
+/* Simple divide. XXX - fix so next reg can be free */
+{ DIV,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SAREG|SAREG,	TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+		0,	RRIGHT,
+		"	idivm AL,AR\n", },
+
+/* Safety belt for DIV */
+{ DIV,	FORREW|FOREFF|INAREG|INAREG,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"DIEDIEDIE", },
+
+/* long long MOD */
+{ MOD,	INBREG,
+	SBREG|SNAME|SOREG,	TLL,
+	SBREG|SNAME|SOREG,	TLL,
+		2*NBREG|NBSL,	RESC2,
+		"	dmove A2,AL ; dmove A1,[ .long 0,0 ]\n"
+		"	ddiv A1,AR\n", },
+
+/* integer MOD */
+{ MOD,	INAREG,
+	SAREG|SNAME|SOREG,	TWORD,
+	SAREG|SNAME|SOREG,	TWORD,
+		2*NAREG|NASL,	RESC2,
+		"	move A2,AL\n"
+		"	setz A1,\n"
+		"	idiv A1,AR\n", },
+
+/* integer MOD for char/short */
+{ MOD,	INAREG,
+	SAREG,	TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SAREG,	TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+		2*NAREG|NASL,	RESC2,
+		"	move A2,AL\n"
+		"	setz A1,\n"
+		"	idiv A1,AR\n", },
+
+/* Safety belt for MOD */
+{ MOD,	FOREFF,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"DIEDIEDIE", },
+
+/* long long MUL */
+{ MUL,	INBREG,
+	SBREG|SNAME|SOREG,	TLL,
+	SBREG|SNAME|SOREG,	TLL,
+		2*NBREG|NBSL,	RESC2,
+		"	dmove A1,AL\n"
+		"	dmul A1,AR\n", },
+
+/* integer multiply to memory*/
+{ MUL,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+	SAREG|SAREG,			TWORD,
+		0,		RLEFT,
+		"	imulm AR,AL\n", },
+
+/* integer multiply */
+{ MUL,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,			TWORD,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+		0,		RLEFT,
+		"	imul AL,AR\n", },
+
+/* integer multiply for char/short */
+{ MUL,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SAREG|SAREG,	TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT,
+		0,		RLEFT,
+		"	imul AL,AR\n", },
+
+/* integer multiply with small constant */
+{ MUL,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TWORD,
+	SUSHCON,	TWORD,
+		0,		RLEFT,
+		"	imuli AL,AR\n", },
+
+/* integer multiply with large constant */
+{ MUL,	INAREG|INAREG|FOREFF,
+	SAREG|SAREG,	TWORD,
+	SCON,		TWORD,
+		0,		RLEFT,
+		"	imul AL,[ .long AR ]\n", },
+
+/* Safety belt for MUL */
+{ MUL,	FORREW|FOREFF|INAREG|INAREG,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"DIEDIEDIE", },
+
+/* read an indirect long long value into register */
+{ UMUL,	INAREG,
+	SAREG|SAREG,	TPTRTO|TLL|TWORD,
+	SANY,		TLL,
+		NAREG|NASL,	RESC1,
+		"	dmove A1,(AL)\n", },
+
+/* read an indirect integer value into register */
+{ UMUL,	INAREG,
+	SAREG|SAREG,	TWORD|TPOINT,
+	SANY,		TWORD|TPOINT,
+		NAREG|NASL,	RESC1,
+		"	move A1,(AL)\n", },
+
+/* read an indirect value into register */
+{ UMUL,	INAREG,
+	SOREG,	TWORD|TPOINT,
+	SANY,	TWORD|TPOINT,
+		NAREG,	RESC1,
+		"	move A1,@AL\n", },
+
+/* read an indirect value into register */
+{ UMUL,	INAREG,
+	SAREG|SAREG|SOREG,	TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO,
+	SANY,	TCHAR|TUCHAR|TSHORT|TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	ldb A1,AL\n", },
+
+#ifdef notyet
+/* Match tree shape for ildb */
+{ UMUL,	INAREG,
+	SANY,	TANY,
+	SILDB,	TUCHAR|TCHAR|TPTRTO,
+		NAREG,	RESC1,
+		"	ildb A1,ZA\n", },
+#endif
+
+/* Match char/short pointers first, requires special handling */
+{ OPLOG,	FORCC,
+	SAREG|SAREG,	TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SAREG|SAREG,	TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT,
+		0, 	RESCC,
+		"ZZ", },
+
+/* Can check anything by just comparing if EQ/NE */
+{ OPLOG,	FORCC,
+	SAREG|SAREG,	TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SZERO,	TANY,
+		0, 	RESCC,
+		"	jumpZe AL,LC # bu\n", },
+
+{ EQ,		FORCC,
+	SAREG|SAREG,	TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SAREG|SAREG|SOREG|SNAME|SCON,	TWORD|TPOINT,
+		0, 	RESCC,
+		"ZR", },
+
+{ NE,		FORCC,
+	SAREG|SAREG,	TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SAREG|SAREG|SOREG|SNAME|SCON,	TWORD|TPOINT,
+		0, 	RESCC,
+		"ZR", },
+
+{ OPLOG,	FORCC,
+	SAREG|SAREG,	TWORD,
+	SAREG|SAREG|SOREG|SNAME|SCON,	TSWORD,
+		0, 	RESCC,
+		"ZR", },
+
+{ OPLOG,	FORCC,
+	SAREG|SAREG,	TCHAR|TUCHAR,
+	SCON,		TANY,
+		0, 	RESCC,
+		"ZR", },
+
+{ OPLOG,	FORCC,
+	SAREG|SAREG,	TWORD|TPOINT|TFLOAT,
+	SAREG|SAREG|SOREG|SNAME|SCON,	TWORD|TPOINT|TFLOAT,
+		0, 	RESCC,
+		"ZR", },
+
+{ OPLOG,	FORCC,
+	SAREG|SAREG,	TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SAREG|SAREG,	TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT,
+		0, 	RESCC,
+		"ZR", },
+
+{ OPLOG,	FORCC,  
+	SAREG|SAREG,	TLL|TDOUBLE, /* XXX - does double work here? */
+	SAREG|SAREG|SOREG|SNAME,	TLL|TDOUBLE,
+		0,	RESCC,
+		"ZQ", },
+
+/*
+ * Jumps.
+ */
+{ GOTO, 	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	jrst LL\n", },
+
+/*
+ * Convert LTYPE to reg.
+ */
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SMONE,	TLL,
+		NBREG,	RESC1,
+		"	seto A1,\n	seto U1,\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SMONE,	TANY,
+		NAREG,	RESC1,
+		"	seto A1,\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SZERO,	TLL,
+		NBREG,	RESC1,
+		"	setz A1,\n	setz U1,\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SZERO,	TANY,
+		NAREG,	RESC1,
+		"	setz A1,\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,		TANY,
+	SUSHCON,	TLL,
+		NBREG,	RESC1,
+		"	setz A1,\n	movei U1,AR\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SUSHCON,	ANYFIXED,
+		NAREG,	RESC1,
+		"	movei A1,AR\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	ANYFIXED,
+	SNSHCON,	ANYFIXED,
+		NAREG,	RESC1,
+		"	hrroi A1,AR\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	ANYFIXED,
+	SCON,	ANYFIXED,
+		NAREG|NASR,	RESC1,
+		"	ZD A1,ZE	# suspekt\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TWORD|TPOINT|TFLOAT,
+	SAREG|SAREG|SOREG|SNAME,	TWORD|TPOINT|TFLOAT,
+		NAREG|NASR,	RESC1,
+		"	move A1,AR\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,	TLL,
+	SCON,	TLL,
+		NBREG,	RESC1,
+		"	dmove A1,ZO\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,	TLL|TDOUBLE,
+	SANY,	TLL|TDOUBLE,
+		NBREG|NBSR,	RESC1,
+		"	dmove A1,AR\n", },
+
+{ OPLTYPE,	INAREG,
+	SOREG,		TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SOREG,		TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NASR,	RESC1,
+		"ZU", },
+
+{ OPLTYPE,	INAREG,
+	SNAME,	TUCHAR,
+	SNAME,	TUCHAR,
+		NAREG|NASR,	RESC1,
+		"	ldb A1,[ .long AL ]\n" },
+
+{ OPLTYPE,	INAREG,
+	SNAME,	TCHAR,
+	SNAME,	TCHAR,
+		NAREG|NASR,	RESC1,
+		"	ldb A1,[ .long AL ]\n"
+		"	ash A1,033\n"
+		"	ash A1,-033\n", },
+		
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SNAME,	TSHORT|TUSHORT,
+		NAREG|NASR,	RESC1,
+		"Zi", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TWORD|TPOINT,
+	SCON,	TWORD|TPOINT,
+		NAREG|NASR,	RESC1,
+		"Zc", },
+
+{ OPLTYPE,	INAREG,
+	SAREG|SAREG,	TUSHORT|TUCHAR,
+	SAREG|SAREG,	TUSHORT|TUCHAR|TWORD,
+		NAREG,	RESC1,
+		"	move A1,AL\n", },
+
+/*
+ * Negate a word.
+ */
+{ UMINUS,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+	SANY,	TWORD,
+		NAREG|NASL,	RESC1,
+		"	movn A1,AL\n", },
+
+{ UMINUS,	INAREG,
+	SAREG|SAREG,	TWORD,
+	SANY,	TCHAR|TUCHAR|TSHORT|TUSHORT,
+		0,	RLEFT,
+		"	movn AL,AL\n", },
+
+{ UMINUS,	INAREG,
+	SAREG|SNAME|SOREG,	TLL,
+	SANY,	TLL,
+		NAREG|NASR,	RESC1,
+		"	dmovn A1,AL\n", },
+
+{ COMPL,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TLL,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,
+		"	setcm A1,AL\n"
+		"	setcm U1,UL\n", },
+
+{ COMPL,	INAREG,
+	SAREG|SAREG|SNAME|SOREG,	TWORD,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,
+		"	setcm A1,AL\n", },
+
+{ COMPL,	INAREG,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SANY,	TCHAR|TUCHAR|TSHORT|TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	setcm A1,AL\n", },
+
+/*
+ * Arguments to functions.
+ */
+{ FUNARG,	FOREFF,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT|TFLOAT,
+	SANY,	TANY,
+		0,	RNULL,
+		"	push 017,AL\n", },
+
+{ FUNARG,	FOREFF,
+	SAREG|SAREG,	TCHAR|TUCHAR|TSHORT|TUSHORT,
+	SANY,	TANY,
+		0,	RNULL,
+		"	push 017,AL\n", },
+
+{ FUNARG,	FOREFF,
+	SCON,	TCHAR|TUCHAR|TSHORT|TUSHORT|TPOINT|TWORD,
+	SANY,	TANY,
+		0,	RNULL,
+		"	push 017,[ .long AL]\n", },
+
+{ FUNARG,	FOREFF,
+	SBREG,	TLL|TDOUBLE,
+	SANY,		TANY,
+		0,	RNULL,
+		"	push 017,AL\n	push 017,UL\n", },
+
+{ STARG,	FOREFF,
+	SAREG|SOREG|SNAME|SCON, TANY, 
+	SANY,   TSTRUCT,
+		0, 0, 
+		"ZG", },
+
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ OPLEAF, DF(NAME), },
+
+{ OPUNARY, DF(UMINUS), },
+
+{ FREE, FREE, FREE,	FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
Index: uspace/app/pcc/arch/pdp11/code.c
===================================================================
--- uspace/app/pcc/arch/pdp11/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/pdp11/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,197 @@
+/*	$Id: code.c,v 1.3 2009/02/08 16:41:35 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)
+{
+	static char *loctbl[] = { "text", "data", "data" };
+	TWORD t;
+	char *n;
+	int s;
+
+	if (sp == NULL) {
+		lastloc = -1;
+		return;
+	}
+	t = sp->stype;
+	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+	if (s != lastloc)
+		printf("	.%s\n", loctbl[s]);
+	lastloc = s;
+	while (ISARY(t))
+		t = DECREF(t);
+	n = sp->soname ? sp->soname : exname(sp->sname);
+	if (sp->sclass == EXTDEF)
+		printf("	.globl %s\n", n);
+	if (ISFTN(sp->stype) || talign(sp->stype, sp->ssue) > ALCHAR)
+		printf(".even\n");
+	if (sp->slevel == 0) {
+		printf("%s:\n", n);
+	} else {
+		printf(LABFMT ":\n", sp->soffset);
+	}
+}
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode()
+{
+	NODE *p, *q;
+
+	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+		return;
+	/* Create struct assignment */
+	q = block(OREG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
+	q->n_rval = R5;
+	q->n_lval = 8; /* return buffer offset */
+	q = buildtree(UMUL, q, NIL);
+	p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
+	p = buildtree(UMUL, p, NIL);
+	p = buildtree(ASSIGN, q, p);
+	ecomp(p);
+}
+
+/*
+ * code for the beginning of a function; a is an array of
+ * indices in symtab for the arguments; n is the number
+ */
+void
+bfcode(struct symtab **sp, int cnt)
+{
+	struct symtab *sp2;
+	NODE *n;
+	int i;
+
+	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+		/* Function returns struct, adjust arg offset */
+		for (i = 0; i < cnt; i++) 
+			sp[i]->soffset += SZPOINT(INT);
+	}
+
+	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;
+		sp2 = sp[i];
+		n = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->ssue);
+		n = buildtree(ASSIGN, n, nametree(sp2));
+		sp[i]->soffset = regno(n->n_left);
+		sp[i]->sflags |= STNODE;
+		ecomp(n);
+	}
+}
+
+
+/*
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+	SETOFF(autooff, SZINT);
+}
+
+/* called just before final exit */
+/* flag is 1 if errors, 0 if none */
+void
+ejobcode(int flag )
+{
+}
+
+void
+bjobcode()
+{
+}
+
+/*
+ * 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)
+{
+	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_sue);
+	}
+	if (r->n_op != STARG) {
+		l = talloc();
+		*l = *r;
+		r->n_op = FUNARG;
+		r->n_left = l;
+		r->n_type = l->n_type;
+	}
+	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/pdp11/local.c
===================================================================
--- uspace/app/pcc/arch/pdp11/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/pdp11/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,658 @@
+/*	$Id: local.c,v 1.7 2011/01/21 21:47: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.
+ */
+
+
+#include "pass1.h"
+
+/*	this file contains code which is dependent on the target machine */
+
+/* clocal() is called to do local transformations on
+ * an expression tree preparitory to its being
+ * written out in intermediate code.
+ *
+ * the major essential job is rewriting the
+ * automatic variables and arguments in terms of
+ * REG and OREG nodes
+ * conversion ops which are not necessary are also clobbered here
+ * in addition, any special features (such as rewriting
+ * exclusive or) are easily handled here as well
+ */
+NODE *
+clocal(NODE *p)
+{
+
+	register struct symtab *q;
+	register NODE *r, *l;
+	register int o;
+	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 STATIC:
+			if (q->slevel == 0)
+				break;
+			p->n_lval = 0;
+			break;
+
+		case REGISTER:
+			p->n_op = REG;
+			p->n_lval = 0;
+			p->n_rval = q->soffset;
+			break;
+
+		case EXTERN:
+		case EXTDEF:
+			break;
+		}
+		break;
+
+	case PCONV:
+		/* Remove redundant PCONV's. Be careful */
+		l = p->n_left;
+		if (l->n_op == ICON) {
+			l->n_lval = (unsigned)l->n_lval;
+			goto delp;
+		}
+		if (l->n_type < INT || l->n_type == LONGLONG || 
+		    l->n_type == ULONGLONG) {
+			/* float etc? */
+			p->n_left = block(SCONV, l, NIL,
+			    UNSIGNED, 0, MKSUE(UNSIGNED));
+			break;
+		}
+		/* if left is SCONV, cannot remove */
+		if (l->n_op == SCONV)
+			break;
+
+		/* avoid ADDROF TEMP */
+		if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
+			break;
+
+		/* if conversion to another pointer type, just remove */
+		if (p->n_type > BTMASK && l->n_type > BTMASK)
+			goto delp;
+		break;
+
+	delp:	l->n_type = p->n_type;
+		l->n_qual = p->n_qual;
+		l->n_df = p->n_df;
+		l->n_sue = p->n_sue;
+		nfree(p);
+		p = l;
+		break;
+		
+	case SCONV:
+		l = p->n_left;
+
+#if 0
+		if (p->n_type == l->n_type) {
+			nfree(p);
+			return l;
+		}
+
+		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+		    btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
+			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
+			    l->n_type != FLOAT && l->n_type != DOUBLE &&
+			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
+				if (l->n_op == NAME || l->n_op == UMUL ||
+				    l->n_op == TEMP) {
+					l->n_type = p->n_type;
+					nfree(p);
+					return l;
+				}
+			}
+		}
+
+		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
+		    coptype(l->n_op) == BITYPE) {
+			l->n_type = p->n_type;
+			nfree(p);
+			return l;
+		}
+#endif
+		o = l->n_op;
+		m = p->n_type;
+
+		if (o == ICON) {
+			CONSZ val = l->n_lval;
+
+			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
+			    switch (m) {
+			case BOOL:
+				l->n_lval = l->n_lval != 0;
+				break;
+			case CHAR:
+				l->n_lval = (char)val;
+				break;
+			case UCHAR:
+				l->n_lval = val & 0377;
+				break;
+			case INT:
+				l->n_lval = (short)val;
+				break;
+			case UNSIGNED:
+				l->n_lval = val & 0177777;
+				break;
+			case ULONG:
+				l->n_lval = val & 0xffffffff;
+				break;
+			case LONG:
+				l->n_lval = (long)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 = FLOAT_CAST(val, l->n_type);
+				break;
+			default:
+				cerror("unknown type %d", m);
+			}
+			l->n_type = m;
+			l->n_sue = MKSUE(m);
+			nfree(p);
+			return l;
+		} else if (l->n_op == FCON) {
+			l->n_lval = FLOAT_VAL(l->n_dcon);
+			l->n_sp = NULL;
+			l->n_op = ICON;
+			l->n_type = m;
+			l->n_sue = MKSUE(m);
+			nfree(p);
+			return clocal(l);
+		}
+		if (DEUNSIGN(p->n_type) == INT &&
+		    DEUNSIGN(l->n_type) == INT) {
+			nfree(p);
+			p = l;
+		}
+		break;
+
+	case CBRANCH:
+		l = p->n_left;
+		if (coptype(l->n_op) != BITYPE)
+			break;
+		if (l->n_left->n_op != SCONV || l->n_right->n_op != ICON)
+			break;
+		if ((r = l->n_left->n_left)->n_type > INT)
+			break;
+		/* compare with constant without casting */
+		nfree(l->n_left);
+		l->n_left = r;
+		l->n_right->n_type = l->n_left->n_type;
+		break;
+
+	case STASG: /* struct assignment, modify left */
+		l = p->n_left;
+		if (l->n_type == STRTY)
+			p->n_left = buildtree(ADDROF, l, NIL);
+		break;
+
+	case PMCONV:
+	case PVCONV:
+		r = p;
+		p = buildtree(o == PMCONV ? MUL : DIV, p->n_left, p->n_right);
+		nfree(r);
+		break;
+
+	case FORCE:
+		/* put return value in return reg */
+		p->n_op = ASSIGN;
+		p->n_right = p->n_left;
+		p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
+		p->n_left->n_rval = p->n_left->n_type == BOOL ? 
+		    RETREG(CHAR) : RETREG(p->n_type);
+		break;
+
+	}
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal end: %p\n", p);
+		fwalk(p, eprint, 0);
+	}
+#endif
+	return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+	struct symtab *sp;
+
+	if (p->n_op != FCON)
+		return;
+
+	sp = inlalloc(sizeof(struct symtab));
+	sp->sclass = STATIC;
+	sp->ssue = MKSUE(p->n_type);
+	sp->slevel = 1; /* fake numeric label */
+	sp->soffset = getlab();
+	sp->sflags = 0;
+	sp->stype = p->n_type;
+	sp->squal = (CON >> TSHIFT);
+
+	defloc(sp);
+	ninval(0, sp->ssue->suesize, p);
+
+	p->n_op = NAME;
+	p->n_lval = 0;
+	p->n_sp = sp;
+}
+
+/*ARGSUSED*/
+int
+andable(NODE *p)
+{
+	return(1);	/* all names can have & taken on them */
+}
+
+/*
+ * at the end of the arguments of a ftn, set the automatic offset
+ */
+void
+cendarg()
+{
+	autooff = AUTOINIT;
+}
+
+/*
+ * Return 1 if a variable of type type is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+	if (t == FLOAT || t == DOUBLE || t == LDOUBLE ||
+	    t == LONGLONG || t == ULONGLONG)
+		return 0; /* not yet */
+	return 1;
+}
+
+/*
+ * return a node, for structure references, which is suitable for
+ * being added to a pointer of type t, in order to be off bits offset
+ * into a structure
+ * t, d, and s are the type, dimension offset, and sizeoffset
+ * For pdp10, return the type-specific index number which calculation
+ * is based on its size. For example, short a[3] would return 3.
+ * Be careful about only handling first-level pointers, the following
+ * indirections must be fullword.
+ */
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
+{
+	register NODE *p;
+
+	if (xdebug)
+		printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
+		    off, t, d, sue->suesize);
+
+	p = bcon(0);
+	p->n_lval = off/SZCHAR;	/* Default */
+	return(p);
+}
+
+/*
+ * Allocate off bits on the stack.  p is a tree that when evaluated
+ * is the multiply count for off, t is a storeable node where to write
+ * the allocated address.
+ */
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+	NODE *sp;
+
+	p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
+
+	/* sub the size from sp */
+	sp = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	ecomp(buildtree(MINUSEQ, sp, p));
+
+	/* save the address of sp */
+	sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
+	sp->n_lval = 0;
+	sp->n_rval = STKREG;
+	t->n_type = sp->n_type;
+	ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
+
+}
+
+/*
+ * Print out a string of characters.
+ * Assume that the assembler understands C-style escape
+ * sequences.
+ */
+void
+instring(struct symtab *sp)
+{
+	char *s;
+	int val, cnt;
+
+	defloc(sp);
+
+	for (cnt = 0, s = sp->sname; *s != 0; ) {
+		if (cnt++ == 0)
+			printf(".byte ");
+		if (*s++ == '\\')
+			val = esccon(&s);
+		else
+			val = s[-1];
+		printf("%o", val & 0377);
+		if (cnt > 15) {
+			cnt = 0;
+			printf("\n");
+		} else
+			printf(",");
+	}
+	printf("%s0\n", cnt ? "" : ".byte ");
+}
+
+static int inbits, inval;
+
+/*
+ * set fsz bits in sequence to zero.
+ */
+void
+zbits(OFFSZ off, int fsz)
+{
+	int m;
+
+	if (idebug)
+		printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
+	if ((m = (inbits % SZCHAR))) {
+		m = SZCHAR - m;
+		if (fsz < m) {
+			inbits += fsz;
+			return;
+		} else {
+			fsz -= m;
+			printf("\t.byte %d\n", inval);
+			inval = inbits = 0;
+		}
+	}
+	if (fsz >= SZCHAR) {
+		printf(".=.+%o\n", fsz/SZCHAR);
+		fsz -= (fsz/SZCHAR) * SZCHAR;
+	}
+	if (fsz) {
+		inval = 0;
+		inbits = fsz;
+	}
+}
+
+/*
+ * Initialize a bitfield.
+ */
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+	if (idebug)
+		printf("infld off %lld, fsz %d, val %lld inbits %d\n",
+		    off, fsz, val, inbits);
+	val &= ((CONSZ)1 << fsz)-1;
+	while (fsz + inbits >= SZCHAR) {
+		inval |= (val << inbits);
+		printf("\t.byte %d\n", inval & 255);
+		fsz -= (SZCHAR - inbits);
+		val >>= (SZCHAR - inbits);
+		inval = inbits = 0;
+	}
+	if (fsz) {
+		inval |= (val << inbits);
+		inbits += fsz;
+	}
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ */
+void
+ninval(CONSZ off, int fsz, NODE *p)
+{
+#ifdef __pdp11__
+	union { float f; double d; short s[4]; int i[2]; } u;
+#endif
+	struct symtab *q;
+	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 (p->n_op != ICON && p->n_op != FCON)
+		cerror("ninval: init node not constant");
+
+	if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
+		uerror("element not constant");
+
+	switch (t) {
+	case LONGLONG:
+	case ULONGLONG:
+		i = (p->n_lval >> 32);
+		p->n_lval &= 0xffffffff;
+		p->n_type = INT;
+		ninval(off, 32, p);
+		p->n_lval = i;
+		ninval(off+32, 32, p);
+		break;
+	case LONG:
+	case ULONG:
+		printf("%o ; %o\n", (int)((p->n_lval >> 16) & 0177777),
+		    (int)(p->n_lval & 0177777));
+		break;
+	case INT:
+	case UNSIGNED:
+		printf("%o", (int)(p->n_lval & 0177777));
+		if ((q = p->n_sp) != NULL) {
+			if ((q->sclass == STATIC && q->slevel > 0)) {
+				printf("+" LABFMT, q->soffset);
+			} else {
+				printf("+%s", q->soname ? q->soname : exname(q->sname));
+			}
+		}
+		printf("\n");
+		break;
+	case BOOL:
+		if (p->n_lval > 1)
+			p->n_lval = p->n_lval != 0;
+		/* FALLTHROUGH */
+	case CHAR:
+	case UCHAR:
+		printf("\t.byte %o\n", (int)p->n_lval & 0xff);
+		break;
+#ifdef __pdp11__
+	case FLOAT:
+		u.f = (float)p->n_dcon;
+		printf("%o ; %o\n", u.i[0], u.i[1]);
+		break;
+	case LDOUBLE:
+	case DOUBLE:
+		u.d = (double)p->n_dcon;
+		printf("%o ; %o ; %o ; %o\n", u.i[0], u.i[1], u.i[2], u.i[3]);
+		break;
+#else
+	/* cross-compiling */
+	case FLOAT:
+		printf("%o ; %o\n", p->n_dcon.fd1, p->n_dcon.fd2);
+		break;
+	case LDOUBLE:
+	case DOUBLE:
+		printf("%o ; %o ; %o ; %o\n", p->n_dcon.fd1, p->n_dcon.fd2,
+		    p->n_dcon.fd3, p->n_dcon.fd4);
+		break;
+#endif
+	default:
+		cerror("ninval");
+	}
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+#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);
+
+}
+
+/*
+ * map types which are not defined on the local machine
+ */
+TWORD
+ctype(TWORD type)
+{
+	switch (BTYPE(type)) {
+	case SHORT:
+		MODTYPE(type,INT);
+		break;
+
+	case USHORT:
+		MODTYPE(type,UNSIGNED);
+		break;
+
+	case LDOUBLE:
+		MODTYPE(type,DOUBLE);
+		break;
+
+	}
+	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)
+{
+	extern int lastloc;
+	char *n;
+	int off;
+
+	off = tsize(sp->stype, sp->sdf, sp->ssue);
+	off = (off+(SZCHAR-1))/SZCHAR;
+	n = sp->soname ? sp->soname : exname(sp->sname);
+	if (sp->sclass == STATIC) {
+		printf(".bss\n");
+		if (sp->slevel == 0)
+			printf("%s:", n);
+		else
+			printf(LABFMT ":", sp->soffset);
+		printf("	.=.+%o\n", off);
+		lastloc = -1;
+		return;
+	}
+	printf(".comm ");
+	if (sp->slevel == 0)
+		printf("%s,0%o\n", n, off);
+	else
+		printf(LABFMT ",0%o\n", sp->soffset, off);
+}
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+	return 0;
+}
+
+/*
+ * Called when a identifier has been declared.
+ */
+void
+fixdef(struct symtab *sp)
+{
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
Index: uspace/app/pcc/arch/pdp11/local2.c
===================================================================
--- uspace/app/pcc/arch/pdp11/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/pdp11/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,845 @@
+/*	$Id: local2.c,v 1.8 2009/07/29 12:34:19 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>
+
+static int spcoff;
+static int argsiz(NODE *p);
+
+void
+deflab(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+	int addto;
+
+#ifdef LANG_F77
+	if (ipp->ipp_vis)
+		printf("	.globl %s\n", ipp->ipp_name);
+	printf("%s:\n", ipp->ipp_name);
+#endif
+	printf("jsr	r5,csv\n");
+	addto = p2maxautooff;
+	if (addto >= AUTOINIT/SZCHAR)
+		addto -= AUTOINIT/SZCHAR;
+	if (addto & 1)
+		addto++;
+	if (addto == 2)
+		printf("tst	-(sp)\n");
+	else if (addto == 4)
+		printf("cmp	-(sp),-(sp)\n");
+	else if (addto > 4)
+		printf("sub	$%o,sp\n", addto);
+	spcoff = 0;
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+	if (spcoff)
+		comperr("spcoff == %d", spcoff);
+	if (ipp->ipp_ip.ip_lbl == 0)
+		return; /* no code needs to be generated */
+	printf("jmp	cret\n");
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+	char *str;
+
+	switch (o) {
+	case PLUS:
+		str = "add";
+		break;
+	case MINUS:
+		str = "sub";
+		break;
+	case AND:
+		str = "and";
+		break;
+	case OR:
+		str = "or";
+		break;
+	case ER:
+		str = "xor";
+		break;
+	default:
+		comperr("hopcode2: %d", o);
+		str = 0; /* XXX gcc */
+	}
+	printf("%s%c", str, f);
+}
+
+/*
+ * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
+ */
+int
+tlen(p) NODE *p;
+{
+	switch(p->n_type) {
+		case CHAR:
+		case UCHAR:
+			return(1);
+
+		case SHORT:
+		case USHORT:
+			return(SZSHORT/SZCHAR);
+
+		case DOUBLE:
+			return(SZDOUBLE/SZCHAR);
+
+		case INT:
+		case UNSIGNED:
+		case LONG:
+		case ULONG:
+			return(SZINT/SZCHAR);
+
+		case LONGLONG:
+		case ULONGLONG:
+			return SZLONGLONG/SZCHAR;
+
+		default:
+			if (!ISPTR(p->n_type))
+				comperr("tlen type %d not pointer");
+			return SZPOINT(p->n_type)/SZCHAR;
+		}
+}
+
+/*
+ * Emit code to compare two long numbers.
+ */
+static void
+twolcomp(NODE *p)
+{
+	int o = p->n_op;
+	int s = getlab2();
+	int e = p->n_label;
+	int cb1, cb2;
+
+	if (o >= ULE)
+		o -= (ULE-LE);
+	switch (o) {
+	case NE:
+		cb1 = 0;
+		cb2 = NE;
+		break;
+	case EQ:
+		cb1 = NE;
+		cb2 = 0;
+		break;
+	case LE:
+	case LT:
+		cb1 = GT;
+		cb2 = LT;
+		break;
+	case GE:
+	case GT:
+		cb1 = LT;
+		cb2 = GT;
+		break;
+
+	default:
+		cb1 = cb2 = 0; /* XXX gcc */
+	}
+	if (p->n_op >= ULE)
+		cb1 += 2, cb2 += 2;
+	expand(p, 0, "cmp	AR,AL\n");
+	if (cb1) cbgen(cb1, s);
+	if (cb2) cbgen(cb2, e);
+        expand(p, 0, "cmp	UR,UL\n");
+        cbgen(p->n_op, e);
+        deflab(s);
+}
+
+
+/*
+ * Generate compare code for long instructions when right node is 0.
+ */
+static void
+lcomp(NODE *p)
+{
+	switch (p->n_op) {
+	case EQ:
+		expand(p, FORCC, "tst	AL\n");
+		printf("jne	1f\n");
+		expand(p, FORCC, "tst	UL\n");
+		cbgen(EQ, p->n_label);
+		printf("1:\n");
+		break;
+	case NE:
+		expand(p, FORCC, "tst	AL\n");
+		cbgen(NE, p->n_label);
+		expand(p, FORCC, "tst	UL\n");
+		cbgen(NE, p->n_label);
+		break;
+	case GE:
+		expand(p, FORCC, "tst	AL\n");
+		cbgen(GE, p->n_label);
+		break;
+	default:
+		comperr("lcomp %p", p);
+	} 
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+	switch (c) {
+	case 'A': /* print out - if not first arg */
+		if (spcoff || (p->n_type == FLOAT || p->n_type == DOUBLE))
+			printf("-");
+		spcoff += argsiz(p);
+		break;
+
+	case 'B': /* arg is pointer to block */
+		expand(p->n_left, FOREFF, "mov	AL,ZA(sp)\n");
+		expand(p->n_left, FOREFF, "sub	CR,(sp)\n");
+		break;
+		
+	case 'C': /* subtract stack after call */
+		spcoff -= p->n_qual;
+		if (spcoff == 0 && !(p->n_flags & NLOCAL1))
+			p->n_qual -= 2;
+		if (p->n_qual == 2)
+			printf("tst	(sp)+\n");
+		else if (p->n_qual == 4)
+			printf("cmp	(sp)+,(sp)+\n");
+		else if (p->n_qual > 2)
+			printf("add	$%o,sp\n", (int)p->n_qual);
+		break;
+
+	case 'D': /* long comparisions */
+		lcomp(p);
+		break;
+
+	case 'E': /* long move */
+		rmove(p->n_right->n_reg, p->n_left->n_reg, p->n_type);
+		break;
+
+	case 'F': /* long comparision */
+		twolcomp(p);
+		break;
+
+	case 'G': /* printout a subnode for post-inc */
+		adrput(stdout, p->n_left->n_left);
+		break;
+
+	case 'H': /* arg with post-inc */
+		expand(p->n_left->n_left, FOREFF, "mov	AL,ZA(sp)\n");
+		expand(p->n_left->n_left, FOREFF, "inc	AL\n");
+		break;
+
+	case 'Q': /* struct assignment, no rv */
+		printf("mov	$%o,", p->n_stsize/2);
+		expand(p, INAREG, "A1\n");
+		printf("1:\n");
+		expand(p, INAREG, "mov	(AR)+,(AL)+\n");
+		expand(p, INAREG, "dec	A1\n");
+		printf("jne	1b\n");
+		break;
+
+	case 'R': /* struct assignment with rv */
+		printf("mov	$%o,", p->n_stsize/2);
+		expand(p, INAREG, "A1\n");
+		expand(p, INAREG, "mov	AR,A2\n");
+		printf("1:\n");
+		expand(p, INAREG, "mov	(A2)+,(AL)+\n");
+		expand(p, INAREG, "dec	A1\n");
+		printf("jne	1b\n");
+		break;
+
+	case '1': /* lower part of double regs */
+		p = getlr(p, '1');
+		printf("r%c", rnames[p->n_rval][1]);
+		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, STARNM|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
+}
+
+static void
+negcon(FILE *fp, int con)
+{
+	if (con < 0)
+		fprintf(fp, "-"), con = -con;
+	fprintf(fp, "%o", con & 0177777);
+}
+
+void
+adrcon(CONSZ val)
+{
+	printf("$" CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+	int val = p->n_lval;
+
+	switch (p->n_op) {
+	case ICON:
+		printf("$");
+		if (p->n_name[0] != '\0') {
+			fprintf(fp, "%s", p->n_name);
+			if (val)
+				fprintf(fp, "+%o", val & 0177777);
+		} else if (p->n_type == LONG || p->n_type == ULONG)
+			negcon(fp, val >> 16);
+		else
+			negcon(fp, val);
+		return;
+
+	default:
+		comperr("illegal conput, p %p", p);
+	}
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+	comperr("insput");
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+	size /= SZINT;
+	switch (p->n_op) {
+	case NAME:
+	case OREG:
+		p->n_lval += size;
+		adrput(stdout, p);
+		p->n_lval -= size;
+		break;
+	case REG:
+		printf("r%c", rnames[p->n_rval][2]);
+		break;
+	case ICON:
+		/* On PDP11 upper value is low 16 bits */
+		printf("$");
+		negcon(stdout, p->n_lval & 0177777);
+		break;
+	default:
+		comperr("upput bad op %d size %d", p->n_op, size);
+	}
+}
+
+/*
+ * output an address, with offsets, from p
+ */
+void
+adrput(FILE *io, NODE *p)
+{
+	int r;
+
+	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, "+%o", (int)(p->n_lval&0177777));
+		} else
+			negcon(io, 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 (R2TEST(r) && R2UPK3(r) == 0)
+			printf("*");
+		if (p->n_lval)
+			negcon(io, p->n_lval);
+		if (R2TEST(r)) {
+			fprintf(io, "(%s)", rnames[R2UPK1(r)]);
+			if (R2UPK3(r) == 1)
+				fprintf(io, "+");
+		} else
+			fprintf(io, "(%s)", rnames[p->n_rval]);
+		return;
+	case ICON:
+		/* addressable value of the constant */
+		conput(io, p);
+		return;
+
+	case REG:
+		switch (p->n_type) {
+		case LONG:
+		case ULONG:
+			fprintf(io, "r%c", rnames[p->n_rval][1]);
+			break;
+		default:
+			fprintf(io, "%s", rnames[p->n_rval]);
+		}
+		return;
+
+	case UMUL:
+		if (tshape(p, STARNM)) {
+			printf("*");
+			adrput(io, p->n_left);
+			break;
+		}
+		/* FALLTHROUGH */
+	default:
+		comperr("illegal address, op %d, node %p", p->n_op, p);
+		return;
+
+	}
+}
+
+static char *
+ccbranches[] = {
+	"jeq",		/* jumpe */
+	"jne",		/* jumpn */
+	"jle",		/* jumple */
+	"jlt",		/* jumpl */
+	"jge",		/* jumpge */
+	"jgt",		/* jumpg */
+	"jlos",		/* jumple (jlequ) */
+	"jlo",		/* jumpl (jlssu) */
+	"jhis",		/* jumpge (jgequ) */
+	"jhi",		/* 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);
+}
+
+#define	IS1CON(p) ((p)->n_op == ICON && (p)->n_lval == 1)
+
+/*
+ * Move postfix operators to the next statement, unless they are 
+ * within a function call or a branch.
+ */
+static void
+cvtree(NODE *p, struct interpass *ip2)
+{
+	struct interpass *ip;
+	NODE *q;
+
+	if (callop(p->n_op) || p->n_op == CBRANCH)
+		return;
+
+	if ((p->n_op == PLUS || p->n_op == MINUS) &&
+	    IS1CON(p->n_right) && (q = p->n_left)->n_op == ASSIGN &&
+	    treecmp(q->n_left, q->n_right->n_left) &&
+	    IS1CON(q->n_right->n_right)) {
+		if ((p->n_op == PLUS && q->n_right->n_op == MINUS) ||
+		    (p->n_op == MINUS && q->n_right->n_op == PLUS)) {
+			nfree(p->n_right);
+			*p = *q->n_left;
+			if (optype(p->n_op) != LTYPE)
+				p->n_left = tcopy(p->n_left);
+			ip = ipnode(q);
+			DLIST_INSERT_AFTER(ip2, ip, qelem);
+			return;
+		}
+	}
+	if (optype(p->n_op) == BITYPE)
+		cvtree(p->n_right, ip2);
+	if (optype(p->n_op) != LTYPE)
+		cvtree(p->n_left, ip2);
+}
+
+/*
+ * Convert AND to BIC.
+ */
+static void
+fixops(NODE *p, void *arg)
+{
+	static int fltwritten;
+
+	if (!fltwritten && (p->n_type == FLOAT || p->n_type == DOUBLE)) {
+		printf(".globl	fltused\n");
+		fltwritten = 1;
+	}
+	switch (p->n_op) {
+	case AND:
+		if (p->n_right->n_op == ICON) {
+			p->n_right->n_lval = ((~p->n_right->n_lval) & 0177777);
+		} else if (p->n_right->n_op == COMPL) {
+			NODE *q = p->n_right->n_left;
+			nfree(p->n_right);
+			p->n_right = q;
+		} else
+			p->n_right = mkunode(COMPL, p->n_right, 0, p->n_type);
+		break;
+	case RS:
+		p->n_right = mkunode(UMINUS, p->n_right, 0, p->n_right->n_type);
+		p->n_op = LS;
+		break;
+	case EQ:
+	case NE: /* Hack not to clear bits if FORCC */
+		if (p->n_left->n_op == AND)
+			fixops(p->n_left, 0); /* Convert an extra time */
+		break;
+	}
+}
+
+void
+myreader(struct interpass *ipole)
+{
+	struct interpass *ip;
+
+#ifdef PCC_DEBUG
+	if (x2debug) {
+		printf("myreader before\n");
+		printip(ipole);
+	}
+#endif
+	DLIST_FOREACH(ip, ipole, qelem) {
+		if (ip->type != IP_NODE)
+			continue;
+		walkf(ip->ip_node, fixops, 0);
+		canon(ip->ip_node); /* call it early */
+	}
+#ifdef PCC_DEBUG
+	if (x2debug) {
+		printf("myreader middle\n");
+		printip(ipole);
+	}
+#endif
+	DLIST_FOREACH(ip, ipole, qelem) {
+		if (ip->type == IP_NODE)
+			cvtree(ip->ip_node, ip);
+	}
+#ifdef PCC_DEBUG
+	if (x2debug) {
+		printf("myreader after\n");
+		printip(ipole);
+	}
+#endif
+}
+
+/*
+ * Remove SCONVs where the left node is an OREG with a smaller type.
+ */
+static void
+delsconv(NODE *p, void *arg)
+{
+#if 0
+	NODE *l;
+
+	if (p->n_op != SCONV || (l = p->n_left)->n_op != OREG)
+		return;
+	if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == LONG) {
+		p->n_op = OREG;
+		p->n_lval = l->n_lval; /* high word */
+		p->n_rval = l->n_rval;
+		nfree(l);
+	}
+#endif
+	/* Could do this for char etc. also */
+}
+
+void
+mycanon(NODE *p)
+{
+	walkf(p, delsconv, 0);
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+	if (t < LONG || t > BTMASK) {
+		printf("mov%s	%s,%s\n", t < SHORT ? "b" : "",
+		    rnames[s],rnames[d]); /* XXX char should be full reg? */
+	} else if (t == LONG || t == ULONG) {
+		/* avoid trashing double regs */
+		if (d > s)
+			printf("mov     r%c,r%c\nmov    r%c,r%c\n",
+			    rnames[s][2],rnames[d][2],
+			    rnames[s][1],rnames[d][1]);
+		else
+			printf("mov	r%c,r%c\nmov	r%c,r%c\n",
+			    rnames[s][1],rnames[d][1],
+			    rnames[s][2],rnames[d][2]);
+	} else if (t == FLOAT || t == DOUBLE) {
+		printf("movf	%s,%s\n", rnames[s],rnames[d]);
+	} else
+		comperr("bad float rmove: %d %d %x", s, d, t);
+
+}
+
+/*
+ * 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)
+{
+	switch (c) {
+	case CLASSA:
+		return (r[CLASSB] * 2 + r[CLASSA]) < 5;
+	case CLASSB:
+		if (r[CLASSB] > 1) return 0;
+		if (r[CLASSB] == 1 && r[CLASSA] > 0) return 0;
+		if (r[CLASSA] > 2) return 0;
+		return 1;
+	case CLASSC:
+		return r[CLASSC] < 8;
+	}
+	return 0;
+}
+
+char *rnames[] = {
+	"r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc",
+	"r01", "r12", "r23", "r34", "XXX", "XXX", "XXX", "XXX",
+	"fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "XXX", "XXX",
+};
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+	if (t < LONG || t > BTMASK)
+		return CLASSA;
+	if (t == LONG || t == ULONG)
+		return CLASSB;
+	if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
+		return CLASSC;
+	comperr("gclass");
+	return CLASSD;
+}
+
+static int
+argsiz(NODE *p)  
+{
+	TWORD t = p->n_type;
+
+	if (t == LONG || t == ULONG || t == FLOAT)
+		return 4;
+	if (t == DOUBLE)
+		return 8;
+	if (t == STRTY || t == UNIONTY)
+		return p->n_stsize;
+	return 2;
+}
+
+/*
+ * Argument specialties.
+ */
+void
+lastcall(NODE *p)
+{
+	NODE *op = p;
+	int size = 0;
+
+	/*
+	 * Calculate arg sizes.
+	 * Mark first arg not to have - before it.
+	 */
+	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) {
+		p->n_right->n_qual = 0;
+		size += argsiz(p->n_right);
+	}
+	p->n_qual = 0;
+	size += argsiz(p);
+	p = op->n_right;
+
+	if (p->n_op == CM)
+		p = p->n_right;
+	if (p->n_type == FLOAT || p->n_type == DOUBLE ||
+	    p->n_type == STRTY || p->n_type == UNIONTY)
+		op->n_flags |= NLOCAL1;	/* Does not use stack slot */
+	else
+		op->n_flags &= ~NLOCAL1;
+	op->n_qual = size; /* XXX */
+}
+
+static int
+is1con(NODE *p)
+{
+	if (p->n_op == ICON && p->n_lval == 1)
+		return 1;
+	return 0;
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+	CONSZ s;
+
+	switch (shape) {
+	case SANDSCON:
+		s = ~p->n_lval;
+		if (s < 65536 || s > -65537)
+			return SRDIR;
+		break;
+	case SINCB: /* Check if subject for post-inc */
+		if (p->n_op == ASSIGN && p->n_right->n_op == PLUS &&
+		    treecmp(p->n_left, p->n_right->n_left) &&
+		    is1con(p->n_right->n_right))
+			return SRDIR;
+		break;
+	case SARGSUB:
+		if (p->n_op == MINUS && p->n_right->n_op == ICON &&
+		    p->n_left->n_op == REG)
+			return SRDIR;
+		break;
+	case SARGINC:
+		if (p->n_op == MINUS && is1con(p->n_right))
+			return special(p->n_left, SINCB);
+		break;
+	}
+	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)
+{
+	return 0;
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+	return 0;
+}
+
Index: uspace/app/pcc/arch/pdp11/macdefs.h
===================================================================
--- uspace/app/pcc/arch/pdp11/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/pdp11/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,237 @@
+/*	$Id: macdefs.h,v 1.4 2009/01/24 21:43:49 gmcgarry 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 = i ? (val<<8)|lastcon : val
+
+#define ARGINIT		32	/* # bits above r5 where arguments start */
+#define AUTOINIT	64	/* # bits below r5 where automatics start */
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR		8
+#define SZBOOL		8
+#define SZINT		16
+#define SZFLOAT		32
+#define SZDOUBLE	64
+#define SZLDOUBLE	64
+#define SZLONG		32
+#define SZSHORT		16
+#define SZLONGLONG	64
+#define SZPOINT(t)	16
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR		8
+#define ALBOOL		8
+#define ALINT		16
+#define ALFLOAT		16
+#define ALDOUBLE	16
+#define ALLDOUBLE	16
+#define ALLONG		16
+#define ALLONGLONG	16
+#define ALSHORT		16
+#define ALPOINT		16
+#define ALSTRUCT	16
+#define ALSTACK		16 
+
+/*
+ * Min/max values.
+ */
+#define	MIN_CHAR	-128
+#define	MAX_CHAR	127
+#define	MAX_UCHAR	255
+#define	MIN_SHORT	-32768
+#define	MAX_SHORT	32767
+#define	MAX_USHORT	65535
+#define	MIN_INT		(-0x7fff-1)
+#define	MAX_INT		0x7fff
+#define	MAX_UNSIGNED	0xffff
+#define	MIN_LONG	(-0x7fffffff-1)
+#define	MAX_LONG	0x7fffffff
+#define	MAX_ULONG	0xffffffff
+#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 */
+#define LABFMT	"L%d"		/* format for printing labels */
+#ifdef LANG_F77
+#define BLANKCOMMON "_BLNK_"
+#define MSKIREG  (M(TYSHORT)|M(TYLONG))
+#define TYIREG TYLONG
+#define FSZLENG  FSZLONG
+#define	AUTOREG	EBP
+#define	ARGREG	EBP
+#define ARGOFFSET 8
+#endif
+
+#define BACKAUTO 		/* stack grows negatively for automatics */
+#define BACKTEMP 		/* stack grows negatively for temporaries */
+
+#undef	FIELDOPS		/* no bit-field instructions */
+#define	RTOLBYTES		/* bytes are numbered right to left */
+
+#define ENUMSIZE(high,low) INT	/* enums are always stored in full int */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)	((x)&01)
+#define wdal(k)		(BYTEOFF(k)==0)
+#define BITOOR(x)	(x)	/* bit offset to oreg offset XXX die! */
+
+#define STOARG(p)
+#define STOFARG(p)
+#define STOSTARG(p)
+#define genfcall(a,b)	gencall(a,b)
+
+#define	FINDMOPS	/* pdp11 has instructions that modifies memory */
+
+#define szty(t) ((t) == DOUBLE || (t) == LONGLONG || (t) == ULONGLONG ? 4 : \
+	(t) == FLOAT || (t) == LONG || (t) == ULONG ? 2 : 1)
+
+/*
+ * The pdp11 has 3 register classes, 16-bit, 32-bit and floats.
+ * Class membership and overlaps are defined in the macros RSTATUS
+ * and ROVERLAP below.
+ *
+ * The classes used on pdp11 are:
+ *	A - 16-bit
+ *	B - 32-bit (concatenated 16-bit)
+ *	C - floating point
+ */
+#define	R0	000	/* Scratch and return register */
+#define	R1	001	/* Scratch and secondary return register */
+#define	R2	002	/* Scratch register */
+#define	R3	003	/* Scratch register */
+#define	R4	004	/* Scratch register */
+#define	R5	005	/* Frame pointer */
+#define	SP	006	/* Stack pointer */
+#define	PC	007	/* Program counter */
+
+#define	R01	010
+#define	R12	011
+#define	R23	012
+#define	R34	013
+
+#define	FR0	020
+#define	FR1	021
+#define	FR2	022
+#define	FR3	023
+#define	FR4	024
+#define	FR5	025
+#define	FR6	026
+#define	FR7	027
+
+#define	MAXREGS	030	/* 24 registers */
+
+#define	RSTATUS	\
+	SAREG|TEMPREG, SAREG|TEMPREG, SAREG, SAREG, SAREG, 0, 0, 0, \
+	SBREG, SBREG, SBREG, SBREG, 0, 0, 0, 0,		\
+	SCREG, SCREG, SCREG, SCREG, 0, 0, 0, 0
+
+#define	ROVERLAP \
+	/* 8 basic registers */\
+	{ R01, -1 },		\
+	{ R01, R12, -1 },	\
+	{ R12, R23, -1 },	\
+	{ R23, R34, -1 },	\
+	{ R34, -1 },		\
+	{ -1 },			\
+	{ -1 },			\
+	{ -1 },			\
+\
+	/* 4 long registers */\
+	{ R0, R1, R12, -1 },		\
+	{ R1, R2, R01, R23, -1 },		\
+	{ R2, R3, R12, R34, -1 },		\
+	{ R3, R4, R23, -1 },		\
+	{ -1 },			\
+	{ -1 },			\
+	{ -1 },			\
+	{ -1 },			\
+\
+	/* The fp registers do not overlap with anything */\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },\
+	{ -1 },
+
+
+/* Return a register class based on the type of the node */
+
+#define PCLASS(p) (p->n_type < LONG || p->n_type > BTMASK ? SAREG : \
+		  (p->n_type == LONG || p->n_type == ULONG ? SBREG : SCREG))
+
+#define	NUMCLASS 	3	/* highest number of reg classes used */
+
+int COLORMAP(int c, int *r);
+#define	GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : CLASSC)
+#define DECRA(x,y)	(((x) >> (y*5)) & 31)	/* decode encoded regs */
+#define	ENCRD(x)	(x)		/* Encode dest reg in n_reg */
+#define ENCRA1(x)	((x) << 5)	/* A1 */
+#define ENCRA2(x)	((x) << 10)	/* A2 */
+#define ENCRA(x,y)	((x) << (5+y*5))	/* encode regs in int */
+#define	RETREG(x)	((x) == LONG || (x) == ULONG ? R01 : \
+	(x) == FLOAT || (x) == DOUBLE ? FR0 : R0)
+
+//#define R2REGS	1	/* permit double indexing */
+
+/* XXX - to die */
+#define FPREG	R5	/* frame pointer */
+#define STKREG	SP	/* stack pointer */
+
+/* A bunch of specials to make life easier for pdp11 */
+#define	SANDSCON	(MAXSPECIAL+1)
+#define	SINCB		(MAXSPECIAL+2)	/* post-increment */
+#define	SINCW		(MAXSPECIAL+3)	/* post-increment */
+#define	SARGSUB		(MAXSPECIAL+4)	/* arg pointer to array */
+#define	SARGINC		(MAXSPECIAL+5)	/* post-increment arg */
Index: uspace/app/pcc/arch/pdp11/order.c
===================================================================
--- uspace/app/pcc/arch/pdp11/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/pdp11/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,249 @@
+/*	$Id: order.c,v 1.3 2008/10/04 08:43:17 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 */
+}
+
+static int
+inctree(NODE *p)
+{
+	if (p->n_op == MINUS && p->n_left->n_op == ASSIGN && 
+	    p->n_left->n_right->n_op == PLUS &&
+	    treecmp(p->n_left->n_left, p->n_left->n_right->n_left) &&
+	    p->n_right->n_op == ICON && p->n_right->n_lval == 1 &&
+	    p->n_left->n_right->n_right->n_op == ICON &&
+	    p->n_left->n_right->n_right->n_lval == 1) {
+		/* post-increment by 1; (r0)+ */
+		if (isreg(p->n_left->n_left)) /* Ignore if index not in reg */
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * 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)
+{
+	if (x2debug)
+		printf("offstar(%p)\n", p);
+
+	if (isreg(p))
+		return; /* Is already OREG */
+
+	if (p->n_op == UMUL)
+		p = p->n_left; /* double indexed umul */
+
+	if (inctree(p)) /* Do post-inc conversion */
+		return;
+
+	if( p->n_op == PLUS || p->n_op == MINUS ){
+		if (p->n_right->n_op == ICON) {
+			if (isreg(p->n_left) == 0)
+				(void)geninsn(p->n_left, INAREG);
+			/* Converted in ormake() */
+			return;
+		}
+	}
+	(void)geninsn(p, INAREG);
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *p)
+{
+	NODE *q = p->n_left;
+
+	if (x2debug) {
+		printf("myormake(%p)\n", p);
+		fwalk(p, e2print, 0);
+	}
+	if (inctree(q)) {
+		if (q->n_left->n_left->n_op == TEMP)
+			return;
+		p->n_op = OREG;
+		p->n_lval = 0; /* Add support for index offset */
+		p->n_rval = R2PACK(regno(q->n_left->n_left), 0, 1);
+		tfree(q);
+		return;
+	}
+	if (q->n_op != OREG)
+		return;
+	p->n_op = OREG;
+	p->n_lval = q->n_lval;
+	p->n_rval = R2PACK(q->n_rval, 0, 0);
+	nfree(q);
+}
+
+/*
+ * Shape matches for UMUL.  Cooperates with offstar().
+ */
+int
+shumul(NODE *p, int shape)
+{
+
+	if (x2debug)
+		printf("shumul(%p)\n", p);
+
+	if (p->n_op == NAME && (shape & STARNM))
+		return SRDIR;
+	if (shape & SOREG)
+		return SROREG;	/* Calls offstar */
+	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 MUL:
+		if (q->visit == INAREG) {
+			static struct rspecial s[] = { { NLEFT, R1 }, { 0 } };
+			return s;
+		} else if (q->visit == INBREG) {
+			static struct rspecial s[] = { { NRES, R01 }, { 0 } };
+			return s;
+		}
+		break;
+
+	case DIV:
+		if (q->visit == INAREG && q->ltype == TUNSIGNED) {
+			static struct rspecial s[] = {
+			   { NLEFT, R0 }, { NRIGHT, R1 }, { NRES, R0 }, { 0 } };
+			return s;
+		} else if (q->visit == INAREG) {
+			static struct rspecial s[] = {
+			    { NRES, R0 }, { 0 } };
+			return s;
+		} else if (q->visit == INBREG) {
+			static struct rspecial s[] = { { NRES, R01 }, { 0 } };
+			return s;
+		}
+		break;
+
+	case MOD:
+		if (q->visit == INAREG && q->ltype == TUNSIGNED) {
+			static struct rspecial s[] = {
+			   { NLEFT, R0 }, { NRIGHT, R1 }, { NRES, R0 }, { 0 } };
+			return s;
+		} else if (q->visit == INBREG) {
+			static struct rspecial s[] = { { NRES, R01 }, { 0 } };
+			return s;
+		}
+		break;
+
+	case SCONV:
+		if (q->lshape == SAREG) {
+			static struct rspecial s[] = {
+			    { NLEFT, R1 }, { NRES, R01 }, { 0 } };
+			return s;
+		}
+		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[] = { -1 };
+
+	return r;
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+	return 1;
+}
Index: uspace/app/pcc/arch/pdp11/table.c
===================================================================
--- uspace/app/pcc/arch/pdp11/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/pdp11/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,843 @@
+/*	$Id: table.c,v 1.5 2008/10/19 15:25:25 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
+# define TSWORD TINT
+# define TWORD TUWORD|TSWORD
+# define ANYSH	SCON|SAREG|SOREG|SNAME
+# define ARONS	SAREG|SOREG|SNAME|STARNM
+
+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,
+		"", },
+
+/* convert char to int or unsigned */
+{ SCONV,	INAREG,
+	SAREG,	TCHAR,
+	SAREG,	TINT|TUNSIGNED,
+		NAREG|NASL,	RESC1,
+		"", }, /* chars are stored as ints in registers */
+
+{ SCONV,	INAREG,
+	SOREG|SCON|SNAME,	TCHAR,
+	SAREG,	TINT,
+		NAREG|NASL,	RESC1,
+		"movb	AL,A1\n", },
+
+/* convert uchar to int or unsigned */
+{ SCONV,	INAREG,
+	SAREG|SOREG|SCON|SNAME,	TUCHAR,
+	SAREG,	TINT|TUNSIGNED,
+		NAREG,	RESC1,
+		"clr	A1\nbisb	AL,A1\n", },
+
+/* convert (u)int to (u)char.  Nothing to do. */
+{ SCONV,	INAREG,
+	SAREG,	TWORD,
+	SANY,	TCHAR|TUCHAR,
+		0,	RLEFT,
+		"", },
+
+/* convert (u)int to (u)int */
+{ SCONV,	INAREG,
+	SAREG,	TWORD,
+	SANY,	TWORD,
+		0,	RLEFT,
+		"", },
+
+/* convert pointer to (u)int */
+{ SCONV,	INAREG,
+	SAREG,	TPOINT,
+	SANY,	TWORD,
+		0,	RLEFT,
+		"", },
+
+/* convert int to long from memory */
+{ SCONV,	INBREG,
+	SNAME|SOREG,	TINT,
+	SANY,	TLONG,
+		NBREG,	RESC1,
+		"mov	AL,U1\nsxt	A1\n", },
+
+/* int -> (u)long. XXX - only in r0 and r1 */
+{ SCONV,	INBREG,
+	SAREG,	TINT,
+	SANY,	TLONG|TULONG,
+		NSPECIAL|NBREG|NBSL,	RESC1,
+		"tst	AL\nsxt	r0\n", },
+
+/* unsigned -> (u)long. XXX - only in r0 and r1 */
+{ SCONV,	INBREG,
+	SAREG,	TUNSIGNED,
+	SANY,	TLONG|TULONG,
+		NSPECIAL|NBREG|NBSL,	RESC1,
+		"clr	r0\n", },
+
+/* uint -> double */
+{ SCONV,	INCREG,
+	SAREG|SNAME|SOREG|SCON,	TUNSIGNED,
+	SANY,			TFLOAT|TDOUBLE,
+		NCREG|NCSL,	RESC1,
+		"mov	AL,-(sp)\nclr	-(sp)\n"
+		"setl\nmovif	(sp)+,A1\nseti\n", },
+
+/* long -> int */
+{ SCONV,	INAREG,
+	SBREG|SOREG|SNAME,	TLONG|TULONG,
+	SAREG,			TWORD,
+		NAREG|NASL,	RESC1,
+		"mov	UL,A1\n", },
+
+
+/* (u)long -> (u)long, nothing */
+{ SCONV,	INBREG,
+	SBREG,	TLONG|TULONG,
+	SANY,	TLONG|TULONG,
+		NBREG|NBSL,	RESC1,
+		"", },
+
+/* long -> double */
+{ SCONV,	INCREG,
+	SBREG|SNAME|SOREG|SCON,	TLONG,
+	SANY,		TFLOAT|TDOUBLE,
+		NCREG|NCSL,	RESC1,
+		"mov	UL,-(sp)\nmov	AL,-(sp)\n"
+		"setl\nmovif	(sp)+,A1\nseti\n", },
+
+/*
+ * Subroutine calls.
+ */
+{ CALL,		INBREG,
+	SCON,	TANY,
+	SBREG,	TLONG|TULONG,
+		NBREG|NBSL,	RESC1,
+		"jsr	pc,*CL\nZC", },
+
+{ UCALL,	INBREG,
+	SCON,	TANY,
+	SBREG,	TLONG|TULONG,
+		NBREG|NBSL,	RESC1,
+		"jsr	pc,*CL\n", },
+
+{ CALL,		FOREFF,
+	SCON|SNAME|SOREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"jsr	pc,*AL\nZC", },
+
+{ UCALL,	FOREFF,
+	SCON|SNAME|SOREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"jsr	pc,*AL\n", },
+
+{ CALL,		INAREG,
+	SCON|SOREG|SNAME,	TANY,
+	SAREG,	TWORD|TPOINT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"jsr	pc,*AL\nZC", },
+
+{ UCALL,	INAREG,
+	SCON|SOREG|SNAME,	TANY,
+	SAREG,	TWORD|TPOINT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"jsr	pc,*AL\n", },
+
+{ CALL,		FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"jsr	pc,(AL)\nZC", },
+
+{ UCALL,	FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"jsr	pc,(AL)\n", },
+
+{ CALL,		INAREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"jsr	pc,(AL)\nZC", },
+
+{ UCALL,	INAREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"jsr	pc,(AL)\n", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+/* Add one to anything left but use only for side effects */
+{ PLUS,		FOREFF|INAREG|FORCC,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SONE,			TANY,
+		0,	RLEFT|RESCC,
+		"inc	AL\n", },
+
+/* add one for char to reg, special handling */
+{ PLUS,		FOREFF|INAREG|FORCC,
+	SAREG,	TCHAR|TUCHAR,
+	SONE,		TANY,
+		0,	RLEFT|RESCC,
+		"inc	AL\n", },
+
+/* add one for char to memory */
+{ PLUS,		FOREFF|FORCC,
+	SNAME|SOREG|STARNM,	TCHAR|TUCHAR,
+	SONE,			TANY,
+		0,	RLEFT|RESCC,
+		"incb	AL\n", },
+
+{ PLUS,		INBREG|FOREFF,
+	SBREG,			TLONG,
+	SBREG|SNAME|SOREG|SCON,	TLONG,
+		0,	RLEFT,
+		"add	AR,AL\nadd	UR,UL\nadc	AL\n", },
+
+/* Add to reg left and reclaim reg */
+{ PLUS,		INAREG|FOREFF|FORCC,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SAREG|SNAME|SOREG|SCON,	TWORD|TPOINT,
+		0,	RLEFT|RESCC,
+		"add	AR,AL\n", },
+
+/* Add to anything left but use only for side effects */
+{ PLUS,		FOREFF|FORCC,
+	SNAME|SOREG,	TWORD|TPOINT,
+	SAREG|SNAME|SOREG|SCON,	TWORD|TPOINT,
+		0,	RLEFT|RESCC,
+		"add	AR,AL\n", },
+
+{ PLUS,		INAREG|FOREFF|FORCC,
+	SAREG,			TCHAR|TUCHAR,
+	SAREG|SNAME|SOREG|SCON,	TCHAR|TUCHAR,
+		0,	RLEFT|RESCC,
+		"add	AR,AL\n", },
+
+/* Post-increment read, byte */
+{ MINUS,	INAREG,
+	SINCB,	TCHAR|TUCHAR,
+	SONE,	TANY,
+		NAREG,	RESC1,
+		"movb	ZG,A1\nincb	ZG\n", },
+
+/* Post-increment read, int */
+{ MINUS,	INAREG,
+	SINCB,	TWORD|TPOINT,
+	SONE,	TANY,
+		NAREG,	RESC1,
+		"mov	ZG,A1\ninc	ZG\n", },
+
+{ MINUS,		INBREG|FOREFF,
+	SBREG,			TLONG|TULONG,
+	SBREG|SNAME|SOREG|SCON,	TLONG|TULONG,
+		0,	RLEFT,
+		"sub	AR,AL\nsub	UR,UL\nsbc	AL\n", },
+
+/* Sub one from anything left */
+{ MINUS,	FOREFF|INAREG|FORCC,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SONE,			TANY,
+		0,	RLEFT|RESCC,
+		"dec	AL\n", },
+
+{ MINUS,		INAREG|FOREFF,
+	SAREG,			TWORD|TPOINT,
+	SAREG|SNAME|SOREG|SCON,	TWORD|TPOINT,
+		0,	RLEFT,
+		"sub	AR,AL\n", },
+
+/* Sub from anything left but use only for side effects */
+{ MINUS,	FOREFF|INAREG|FORCC,
+	SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SAREG|SNAME|SOREG|SCON,	TWORD|TPOINT,
+		0,	RLEFT|RESCC,
+		"sub	AR,AL\n", },
+
+/* Sub one left but use only for side effects */
+{ MINUS,	FOREFF|FORCC,
+	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
+	SONE,			TANY,
+		0,	RLEFT|RESCC,
+		"decb	AL\n", },
+
+/* Sub from anything left but use only for side effects */
+{ MINUS,		FOREFF|FORCC,
+	SAREG|SNAME|SOREG,	TCHAR|TUCHAR,
+	SAREG|SNAME|SOREG|SCON,	TCHAR|TUCHAR|TWORD|TPOINT,
+		0,	RLEFT|RESCC,
+		"subb	AR,AL\n", },
+
+/*
+ * The next rules handle all shift operators.
+ */
+{ LS,	INBREG|FOREFF,
+	SBREG,	TLONG|TULONG,
+	SANY,	TANY,
+		0,	RLEFT,
+		"ashc	AR,AL\n", },
+
+{ LS,	INAREG|FOREFF,
+	SAREG,	TWORD,
+	SONE,	TANY,
+		0,	RLEFT,
+		"asl	AL\n", },
+
+{ LS,	INAREG|FOREFF,
+	SAREG,	TWORD,
+	ANYSH,	TWORD,
+		0,	RLEFT,
+		"ash	AR,AL\n", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+
+/* First optimizations, in lack of weight it uses first found */
+/* Start with class A registers */
+
+/* Clear word at address */
+{ ASSIGN,	FOREFF|FORCC,
+	ARONS,	TWORD|TPOINT,
+	SZERO,		TANY,
+		0,	RESCC,
+		"clr	AL\n", },
+
+/* Clear word at reg */
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TWORD|TPOINT,
+	SZERO,		TANY,
+		0,	RDEST,
+		"clr	AL\n", },
+
+/* Clear byte at address.  No reg here. */
+{ ASSIGN,	FOREFF,
+	SNAME|SOREG|STARNM,	TCHAR|TUCHAR,
+	SZERO,		TANY,
+		0,	RDEST,
+		"clrb	AL\n", },
+
+/* Clear byte in reg. must clear the whole register. */
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TCHAR|TUCHAR,
+	SZERO,	TANY,
+		0,	RDEST,
+		"clr	AL\n", },
+
+/* The next is class B regs */
+
+/* Clear long at address or in reg */
+{ ASSIGN,	FOREFF|INBREG,
+	SNAME|SOREG|SBREG,	TLONG|TULONG,
+	SZERO,			TANY,
+		0,	RDEST,
+		"clr	AL\nclr	UL\n", },
+
+/* Save 2 bytes if high-order bits are zero */
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,	TLONG|TULONG,
+	SSCON,	TLONG,
+		0,	RDEST,
+		"mov	UR,UL\nsxt	AL\n", },
+
+/* Must have multiple rules for long otherwise regs may be trashed */
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,			TLONG|TULONG,
+	SCON|SNAME|SOREG,	TLONG|TULONG,
+		0,	RDEST,
+		"mov	AR,AL\nmov	UR,UL\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SNAME|SOREG,	TLONG|TULONG,
+	SBREG,			TLONG|TULONG,
+		0,	RDEST,
+		"mov	AR,AL\nmov	UR,UL\n", },
+
+{ ASSIGN,	FOREFF,
+	SNAME|SOREG,	TLONG|TULONG,
+	SCON|SNAME|SOREG,	TLONG|TULONG,
+		0,	0,
+		"mov	AR,AL\nmov	UR,UL\n", },
+
+{ ASSIGN,	INBREG|FOREFF,
+	SBREG,	TLONG|TULONG,
+	SBREG,	TLONG|TULONG,
+		0,	RDEST,
+		"ZE\n", },
+
+{ ASSIGN,	FOREFF|INAREG|FORCC,
+	SAREG,			TWORD|TPOINT,
+	SAREG|SNAME|SOREG|SCON,	TWORD|TPOINT,
+		0,	RDEST|RESCC,
+		"mov	AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG|FORCC,
+	ARONS,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		0,	RDEST|RESCC,
+		"mov	AR,AL\n", },
+
+{ ASSIGN,	FOREFF|FORCC,
+	SNAME|SOREG,		TWORD|TPOINT,
+	SNAME|SOREG|SCON,	TWORD|TPOINT,
+		0,	RESCC,
+		"mov	AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG|FORCC,
+	SAREG,		TCHAR|TUCHAR,
+	ARONS|SCON,	TCHAR|TUCHAR,
+		0,	RDEST|RESCC,
+		"movb	AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG|FORCC,
+	ARONS,	TCHAR|TUCHAR,
+	SAREG,	TCHAR|TUCHAR,
+		0,	RDEST|RESCC,
+		"movb	AR,AL\n", },
+
+{ ASSIGN,	FOREFF|FORCC,
+	SNAME|SOREG|STARNM,		TCHAR|TUCHAR,
+	SNAME|SOREG|SCON|STARNM,	TCHAR|TUCHAR,
+		0,	RDEST|RESCC,
+		"movb	AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SCREG,		TDOUBLE,
+	SNAME|SOREG|SCON,	TDOUBLE,
+		0,	RDEST,
+		"movf	AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SCREG,		TFLOAT,
+	SNAME|SOREG|SCON,	TFLOAT,
+		0,	RDEST,
+		"movof	AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SNAME|SOREG|SCREG,	TDOUBLE,
+	SCREG,			TDOUBLE,
+		0,	RDEST,
+		"movf	AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SNAME|SOREG|SCREG,	TFLOAT,
+	SCREG,			TFLOAT,
+		0,	RDEST,
+		"movfo	AR,AL\n", },
+
+/*
+ * DIV/MOD/MUL 
+ */
+/* XXX - mul may use any odd register, only r1 for now */
+{ MUL,	INAREG,
+	SAREG,				TWORD|TPOINT,
+	SAREG|SNAME|SOREG|SCON,		TWORD|TPOINT,
+		NSPECIAL,	RLEFT,
+		"mul	AR,AL\n", },
+
+{ MUL,	INBREG,
+	SBREG|SNAME|SCON|SOREG,		TLONG|TULONG,
+	SBREG|SNAME|SCON|SOREG,		TLONG|TULONG,
+		NSPECIAL|NBREG|NBSL|NBSR,		RESC1,
+		"mov	UR,-(sp)\nmov	AR,-(sp)\n"
+		"mov	UL,-(sp)\nmov	AL,-(sp)\n"
+		"jsr	pc,lmul\nadd	$10,sp\n", },
+
+{ MUL,	INCREG,
+	SCREG,				TFLOAT|TDOUBLE,
+	SCREG|SNAME|SOREG,		TFLOAT|TDOUBLE,
+		0,	RLEFT,
+		"mulf	AR,AL\n", },
+
+/* need extra move to be sure N flag is correct for sxt */
+{ DIV,	INAREG,
+	ANYSH,		TINT|TPOINT,
+	ANYSH,		TINT|TPOINT,
+		NSPECIAL,	RDEST,
+		"mov	AL,r1\nsxt	r0\ndiv	AR,r0\n", },
+
+/* udiv uses args in registers */
+{ DIV,	INAREG,
+	SAREG,		TUNSIGNED,
+	SAREG,		TUNSIGNED,
+		NSPECIAL|NAREG|NASL|NASR,		RESC1,
+		"jsr	pc,udiv\n", },
+
+{ DIV,	INBREG,
+	SBREG|SNAME|SCON|SOREG,		TLONG|TULONG,
+	SBREG|SNAME|SCON|SOREG,		TLONG|TULONG,
+		NSPECIAL|NBREG|NBSL|NBSR,		RESC1,
+		"mov	UR,-(sp)\nmov	AR,-(sp)\n"
+		"mov	UL,-(sp)\nmov	AL,-(sp)\n"
+		"jsr	pc,ldiv\nadd	$10,sp\n", },
+
+{ DIV,	INCREG,
+	SCREG,			TFLOAT|TDOUBLE,
+	SCREG|SNAME|SOREG,	TFLOAT|TDOUBLE,
+		0,	RLEFT,
+		"divf	AR,AL\n", },
+
+/* XXX merge the two below to one */
+{ MOD,	INBREG,
+	SBREG|SNAME|SCON|SOREG,		TLONG,
+	SBREG|SNAME|SCON|SOREG,		TLONG,
+		NSPECIAL|NBREG|NBSL|NBSR,		RESC1,
+		"mov	UR,-(sp)\nmov	AR,-(sp)\n"
+		"mov	UL,-(sp)\nmov	AL,-(sp)\n"
+		"jsr	pc,lrem\nadd	$10,sp\n", },
+
+{ MOD,	INBREG,
+	SBREG|SNAME|SCON|SOREG,		TULONG,
+	SBREG|SNAME|SCON|SOREG,		TULONG,
+		NSPECIAL|NBREG|NBSL|NBSR,		RESC1,
+		"mov	UR,-(sp)\nmov	AR,-(sp)\n"
+		"mov	UL,-(sp)\nmov	AL,-(sp)\n"
+		"jsr	pc,ulrem\nadd	$10,sp\n", },
+
+/* urem uses args in registers */
+{ MOD,	INAREG,
+	SAREG,		TUNSIGNED,
+	SAREG,		TUNSIGNED,
+		NSPECIAL|NAREG|NASL|NASR,		RESC1,
+		"jsr	pc,urem\n", },
+
+/*
+ * Indirection operators.
+ */
+{ UMUL,	INBREG,
+	SANY,	TPOINT|TWORD,
+	SOREG,	TLONG|TULONG,
+		NBREG,	RESC1, /* |NBSL - may overwrite index reg */
+		"mov	AR,A1\nmov	UR,U1\n", },
+
+{ UMUL,	INAREG,
+	SANY,	TPOINT|TWORD,
+	SOREG,	TPOINT|TWORD,
+		NAREG|NASL,	RESC1,
+		"mov	AR,A1\n", },
+
+{ UMUL,	INAREG,
+	SANY,	TANY,
+	SOREG,	TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"movb	AR,A1\n", },
+
+/*
+ * Logical/branching operators
+ */
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME|SCON,	TWORD|TPOINT,
+	SZERO,	TANY,
+		0, 	RESCC,
+		"tst	AL\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME|SCON,	TCHAR|TUCHAR,
+	SZERO,	TANY,
+		0, 	RESCC,
+		"tstb	AL\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME|SCON,	TWORD|TPOINT,
+	SAREG|SOREG|SNAME|SCON,	TWORD|TPOINT,
+		0, 	RESCC,
+		"cmp	AL,AR\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|SOREG|SNAME|SCON,	TCHAR|TUCHAR,
+	SAREG|SOREG|SNAME|SCON,	TCHAR|TUCHAR,
+		0, 	RESCC,
+		"cmpb	AL,AR\n", },
+
+{ OPLOG,	FORCC,
+	SBREG|SOREG|SNAME|SCON,	TLONG|TULONG,
+	SZERO,	TANY,
+		0,	RNULL,
+		"ZD", },
+
+{ OPLOG,	FORCC,
+	SBREG|SOREG|SNAME,	TLONG|TULONG,
+	SBREG|SOREG|SNAME,	TLONG|TULONG,
+		0,	RNULL,
+		"ZF", },
+
+/* AND/OR/ER/NOT */
+/* Optimize if high order bits are zero */
+{ AND,	FOREFF|INBREG|FORCC,
+	SOREG|SNAME|SBREG,	TLONG|TULONG,
+	SANDSCON,		TLONG|TULONG,
+		0,	RLEFT|RESCC,
+		"clr	AL\nbic	UR,UL\n", },
+
+{ AND,	INBREG|FORCC,
+	SBREG,			TLONG|TULONG,
+	SCON|SBREG|SOREG|SNAME,	TLONG|TULONG,
+		0,	RLEFT|RESCC,
+		"bic	AR,AL\nbic	UR,UL\n", },
+
+/* set status bits */
+{ AND,	FORCC,
+	ARONS|SCON,	TWORD|TPOINT,
+	ARONS|SCON,	TWORD|TPOINT,
+		0,	RESCC,
+		"bit	AR,AL\n", },
+
+/* AND with int */
+{ AND,	INAREG|FORCC|FOREFF,
+	SAREG|SNAME|SOREG,	TWORD,
+	SCON|SAREG|SOREG|SNAME,	TWORD,
+		0,	RLEFT|RESCC,
+		"bic	AR,AL\n", },
+
+/* AND with char */
+{ AND,	INAREG|FORCC,
+	SAREG|SOREG|SNAME,	TCHAR|TUCHAR,
+	ARONS|SCON,		TCHAR|TUCHAR,
+		0,	RLEFT|RESCC,
+		"bicb	AR,AL\n", },
+
+{ OR,	INBREG|FORCC,
+	SBREG,			TLONG|TULONG,
+	SCON|SBREG|SOREG|SNAME,	TLONG|TULONG,
+		0,	RLEFT|RESCC,
+		"bis	AR,AL\nbis	UR,UL\n", },
+
+/* OR with int */
+{ OR,	FOREFF|INAREG|FORCC,
+	ARONS,		TWORD,
+	ARONS|SCON,	TWORD,
+		0,	RLEFT|RESCC,
+		"bis	AR,AL\n", },
+
+/* OR with char */
+{ OR,	INAREG|FORCC,
+	SAREG|SOREG|SNAME,	TCHAR|TUCHAR,
+	ARONS|SCON,		TCHAR|TUCHAR,
+		0,	RLEFT|RESCC,
+		"bisb	AR,AL\n", },
+
+/* XOR with int (extended insn)  */
+{ ER,	INAREG|FORCC,
+	ARONS,	TWORD,
+	SAREG,	TWORD,
+		0,	RLEFT|RESCC,
+		"xor	AR,AL\n", },
+
+/* XOR with char (extended insn)  */
+{ ER,	INAREG|FORCC,
+	SAREG,	TCHAR|TUCHAR,
+	SAREG,	TCHAR|TUCHAR,
+		0,	RLEFT|RESCC,
+		"xor	AR,AL\n", },
+
+/*
+ * Jumps.
+ */
+{ GOTO, 	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"jbr	LL\n", },
+
+/*
+ * Convert LTYPE to reg.
+ */
+/* Two bytes less if high half of constant is zero */
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SSCON,	TLONG|TULONG,
+		NBREG,	RESC1,
+		"mov	UL,U1\nsxt	A1\n", },
+
+/* XXX - avoid OREG index register to be overwritten */
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SCON|SBREG|SNAME|SOREG,	TLONG|TULONG,
+		NBREG,	RESC1,
+		"mov	AL,A1\nmov	UL,U1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SAREG|SCON|SOREG|SNAME,	TWORD|TPOINT,
+		NAREG|NASR,	RESC1,
+		"mov	AL,A1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SAREG|SCON|SOREG|SNAME,	TCHAR,
+		NAREG,		RESC1,
+		"movb	AR,A1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SAREG|SCON|SOREG|SNAME,	TUCHAR,
+		NAREG,		RESC1,
+		"clr	A1\nbisb	AL,A1\n", },
+
+{ OPLTYPE,	INCREG,
+	SANY,	TANY,
+	SCREG|SCON|SOREG|SNAME,	TDOUBLE,
+		NCREG,		RESC1,
+		"movf	AL,A1\n", },
+
+{ OPLTYPE,	INCREG,
+	SANY,	TANY,
+	SCREG|SCON|SOREG|SNAME,	TFLOAT,
+		NCREG,		RESC1,
+		"movof	AL,A1\n", },
+
+/*
+ * Negate a word.
+ */
+{ UMINUS,	INAREG|FOREFF,
+	SAREG,	TWORD|TPOINT|TCHAR|TUCHAR,
+	SANY,	TANY,
+		0,	RLEFT,
+		"neg	AL\n", },
+
+{ UMINUS,	INBREG|FOREFF,
+	SBREG|SOREG|SNAME,	TLONG,
+	SANY,			TANY,
+		0,	RLEFT,
+		"neg	AL\nneg	UL\nsbc	AL\n", },
+
+
+{ COMPL,	INBREG,
+	SBREG,	TLONG|TULONG,
+	SANY,	TANY,
+		0,	RLEFT,
+		"com	AL\ncom	UL\n", },
+
+{ COMPL,	INAREG,
+	SAREG,	TWORD,
+	SANY,	TANY,
+		0,	RLEFT,
+		"com	AL\n", },
+
+/*
+ * Arguments to functions.
+ */
+{ FUNARG,	FOREFF,
+	SCON|SBREG|SNAME|SOREG,	TLONG|TULONG,
+	SANY,	TLONG|TULONG,
+		0,	RNULL,
+		"mov	UL,ZA(sp)\nmov	AL,-(sp)\n", },
+
+{ FUNARG,	FOREFF,
+	SZERO,	TANY,
+	SANY,	TANY,
+		0,	RNULL,
+		"clr	ZA(sp)\n", },
+
+{ FUNARG,	FOREFF,
+	SARGSUB,	TWORD|TPOINT,
+	SANY,		TWORD|TPOINT,
+		0,	RNULL,
+		"ZB", },
+
+{ FUNARG,	FOREFF,
+	SARGINC,	TWORD|TPOINT,
+	SANY,		TWORD|TPOINT,
+		0,	RNULL,
+		"ZH", },
+
+{ FUNARG,	FOREFF,
+	SCON|SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SANY,	TWORD|TPOINT,
+		0,	RNULL,
+		"mov	AL,ZA(sp)\n", },
+
+{ FUNARG,	FOREFF,
+	SCON,	TCHAR|TUCHAR,
+	SANY,	TANY,
+		0,	RNULL,
+		"mov	AL,ZA(sp)\n", },
+
+{ FUNARG,	FOREFF,
+	SNAME|SOREG,	TCHAR,
+	SANY,		TCHAR,
+		NAREG,	RNULL,
+		"movb	AL,A1\nmov	A1,ZA(sp)\n", },
+
+{ FUNARG,	FOREFF,
+	SNAME|SOREG,	TUCHAR,
+	SANY,		TUCHAR,
+		NAREG,	RNULL,
+		"clr	ZA(sp)\nbisb	AL,(sp)\n", },
+
+{ FUNARG,	FOREFF,
+	SAREG,	TUCHAR|TCHAR,
+	SANY,	TUCHAR|TCHAR,
+		0,	RNULL,
+		"mov	AL,ZA(sp)\n", },
+
+{ FUNARG,	FOREFF,
+	SCREG,	TFLOAT|TDOUBLE,
+	SANY,		TANY,
+		0,	RNULL,
+		"movf	AL,ZA(sp)\n", },
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	"help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
Index: uspace/app/pcc/arch/powerpc/README
===================================================================
--- uspace/app/pcc/arch/powerpc/README	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/powerpc/README	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,48 @@
+macdefs.h		; machine-dependent definitions
+code.c			; machine-dependent code for prologs, switches (pass 1)
+local.c			; machine-dependent code for prologs, switches (pass 1)
+local2.c		; misc routines and tables of register names (pass 2)
+order.c			; machine-dependent code-generation strategy (pass 2)
+table.c			; code templates (pass 2)
+
+On OS X, binaries are not ELF and all binaries are compiled PIC.  To use pcc
+on OS X while linking against the system libraries, use the -k option.
+
+Current issues:
+
+- no floating point (need mickey's patches to support >64 registers)
+- mod/div on longlong not supported
+- the stack frame is always 200 bytes - need to calculate size and patch
+  OREGs to temporaries and arguments [see discussion below]
+- function arguments are always saved to the stack [need to change MI code]
+- permanent registers >R13 are not saved [need to change MI code]
+- structure arguments don't work
+- return of structure doesn't work
+- function pointers don't work for PIC
+- constant structure assignment doesn't work properly for PIC
+- no built-in vararg support [shouldn't be too hard to add]
+
+The way most modern CPUs create the stack is to allocate the frame
+to contain room for the temporaries, to save the permanent registers
+and to store the arguments to functions invoked from within the function.
+To achieve this, all the information must be known when the prologue
+is generated.  Currently we only know the size of the temporaries -
+we don't know the size of the argument space for each function that
+gets invoked from this function.  Even if we did know this information,
+we create ops to save the register arguments (R3-R10), early in pass1
+and don't know the position of the stack pointer, and the size of the
+argument space required to "step over".
+
+One solution is to have two pointers to the stack.  One for the top
+of the stack and the other pointing just below the temporaries but above
+the argument space.  Then our function arguments and the permanent registers can
+be saved fixed-relative to this register.  If we don't know the size of
+argument space, we cannot "dynamically" alter the stack (like we do with mips),
+since the powerpc ABI specifies that the "lowest" address
+in the stack frame is the saved stack pointer (pointing to the previous
+stack frame).  While this is a nice feature for tracking back through the
+stack frames (which mips has always had problems with), it makes it
+next-to-impossible to increase the strack frame dynamically.
+
+I guess the best approach is to determine the size of the argument stack
+and have a second frame pointer.
Index: uspace/app/pcc/arch/powerpc/code.c
===================================================================
--- uspace/app/pcc/arch/powerpc/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/powerpc/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1541 @@
+/*	$Id: code.c,v 1.23 2010/11/26 17:06:31 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 <assert.h>
+#include <stdlib.h>
+
+#include "pass1.h"
+#include "pass2.h"
+
+static void genswitch_bintree(int num, TWORD ty, struct swents **p, int n);
+
+#if 0
+static void genswitch_table(int num, struct swents **p, int n);
+static void genswitch_mrst(int num, struct swents **p, int n);
+#endif
+
+int lastloc = -1;
+static int rvnr;
+
+/*
+ * Define everything needed to print out some data (or text).
+ * This means segment, alignment, visibility, etc.
+ */
+void
+defloc(struct symtab *sp)
+{
+#if defined(ELFABI)
+	static char *loctbl[] = { "text", "data", "rodata" };
+#elif defined(MACHOABI)
+	static char *loctbl[] = { "text", "data", "const_data" };
+#endif
+	TWORD t;
+	char *name;
+	int s, n;
+
+	if (sp == NULL) {
+		lastloc = -1;
+		return;
+	}
+	t = sp->stype;
+	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+	if (s != lastloc)
+		printf("	.%s\n", loctbl[s]);
+	lastloc = s;
+
+	if (s == PROG)
+		n = 2;
+	else if ((n = ispow2(talign(t, sp->sap) / SZCHAR)) == -1)
+		cerror("defalign: n != 2^i");
+	printf("	.p2align %d\n", n);
+
+	name = sp->soname ? sp->soname : exname(sp->sname);
+	if (sp->sclass == EXTDEF)
+		printf("	.globl %s\n", name);
+	if (sp->slevel == 0)
+		printf("%s:\n", name);
+	else
+		printf(LABFMT ":\n", sp->soffset);
+}
+
+/* Put a symbol in a temporary
+ * used by bfcode() and its helpers
+ */
+static void
+putintemp(struct symtab *sym)
+{
+        NODE *p;
+
+        p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+        p = buildtree(ASSIGN, p, nametree(sym));
+        sym->soffset = regno(p->n_left);
+        sym->sflags |= STNODE;
+        ecomp(p);
+}
+
+/* setup a 64-bit parameter (double/ldouble/longlong)
+ * used by bfcode() */
+static void
+param_64bit(struct symtab *sym, int *argofsp, int dotemps)
+{
+        int argofs = *argofsp;
+        NODE *p, *q;
+        int navail;
+
+#if ALLONGLONG == 64
+        /* alignment */
+        ++argofs;
+        argofs &= ~1;
+#endif
+
+        navail = NARGREGS - argofs;
+
+        if (navail < 2) {
+		/* half in and half out of the registers */
+		q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		regno(q) = R3 + argofs;
+		p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		regno(p) = FPREG;
+		p = block(PLUS, p, bcon(sym->soffset/SZCHAR), PTR+INT, 0, MKAP(INT));
+		p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
+        } else {
+	        q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
+		regno(q) = R3R4 + argofs;
+		if (dotemps) {
+			p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+			sym->soffset = regno(p);
+			sym->sflags |= STNODE;
+		} else {
+			p = nametree(sym);
+		}
+	}
+        p = buildtree(ASSIGN, p, q);
+        ecomp(p);
+        *argofsp = argofs + 2;
+}
+
+/* setup a 32-bit param on the stack
+ * used by bfcode() */
+static void
+param_32bit(struct symtab *sym, int *argofsp, int dotemps)
+{
+        NODE *p, *q;
+
+        q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
+        regno(q) = R3 + (*argofsp)++;
+        if (dotemps) {
+                p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+                sym->soffset = regno(p);
+                sym->sflags |= STNODE;
+        } else {
+                p = nametree(sym);
+        }
+        p = buildtree(ASSIGN, p, q);
+        ecomp(p);
+}
+
+/* setup a double param on the stack
+ * used by bfcode() */
+static void
+param_double(struct symtab *sym, int *argofsp, int dotemps)
+{
+        NODE *p, *q, *t;
+        int tmpnr;
+
+        /*
+         * we have to dump the double from the general register
+         * into a temp, since the register allocator doesn't like
+         * floats to be in CLASSA.  This may not work for -xtemps.
+         */
+
+	if (xtemps) {
+	        q = block(REG, NIL, NIL, ULONGLONG, 0, MKAP(ULONGLONG));
+		regno(q) = R3R4 + *argofsp;
+		p = block(REG, NIL, NIL, PTR+ULONGLONG, 0, MKAP(ULONGLONG));
+		regno(p) = SPREG;
+		p = block(PLUS, p, bcon(-8), INT, 0, MKAP(INT));
+		p = block(UMUL, p, NIL, ULONGLONG, 0, MKAP(ULONGLONG));
+		p = buildtree(ASSIGN, p, q);
+		ecomp(p);
+	
+	        t = tempnode(0, sym->stype, sym->sdf, sym->sap);
+		tmpnr = regno(t);
+		p = block(REG, NIL, NIL,
+		    INCREF(sym->stype), sym->sdf, sym->sap);
+		regno(p) = SPREG;
+		p = block(PLUS, p, bcon(-8), INT, 0, MKAP(INT));
+		p = block(UMUL, p, NIL, sym->stype, sym->sdf, sym->sap);
+		p = buildtree(ASSIGN, t, p);
+		ecomp(p);
+	} else {
+		/* bounce straight into temp */
+		p = block(REG, NIL, NIL, ULONGLONG, 0, MKAP(ULONGLONG));
+		regno(p) = R3R4 + *argofsp;
+		t = tempnode(0, ULONGLONG, 0, MKAP(ULONGLONG));
+		tmpnr = regno(t);
+		p = buildtree(ASSIGN, t, p);
+		ecomp(p);
+	}
+
+	(*argofsp) += 2;
+	
+	sym->soffset = tmpnr;
+	sym->sflags |= STNODE;
+}
+
+/* setup a float param on the stack
+ * used by bfcode() */
+static void
+param_float(struct symtab *sym, int *argofsp, int dotemps)
+{
+        NODE *p, *q, *t;
+        int tmpnr;
+
+        /*
+         * we have to dump the float from the general register
+         * into a temp, since the register allocator doesn't like
+         * floats to be in CLASSA.  This may not work for -xtemps.
+         */
+
+	if (xtemps) {
+		/* bounce onto TOS */
+		q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		regno(q) = R3 + (*argofsp);
+		p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		regno(p) = SPREG;
+		p = block(PLUS, p, bcon(-4), INT, 0, MKAP(INT));
+		p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
+		p = buildtree(ASSIGN, p, q);
+		ecomp(p);
+
+		t = tempnode(0, sym->stype, sym->sdf, sym->sap);
+		tmpnr = regno(t);
+		p = block(REG, NIL, NIL, INCREF(sym->stype),
+		    sym->sdf, sym->sap);
+		regno(p) = SPREG;
+		p = block(PLUS, p, bcon(-4), INT, 0, MKAP(INT));
+		p = block(UMUL, p, NIL, sym->stype, sym->sdf, sym->sap);
+		p = buildtree(ASSIGN, t, p);
+		ecomp(p);
+	} else {
+		/* bounce straight into temp */
+		p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		regno(p) = R3 + (*argofsp);
+		t = tempnode(0, INT, 0, MKAP(INT));
+		tmpnr = regno(t);
+		p = buildtree(ASSIGN, t, p);
+		ecomp(p);
+	}
+
+	(*argofsp)++;
+
+	sym->soffset = tmpnr;
+	sym->sflags |= STNODE;
+}
+
+/* setup the hidden pointer to struct return parameter
+ * used by bfcode() */
+static void
+param_retstruct(void)
+{
+	NODE *p, *q;
+
+	p = tempnode(0, INCREF(cftnsp->stype), 0, cftnsp->sap);
+	rvnr = regno(p);
+	q = block(REG, NIL, NIL, INCREF(cftnsp->stype),
+	    cftnsp->sdf, cftnsp->sap);
+	regno(q) = R3;
+	p = buildtree(ASSIGN, p, q);
+	ecomp(p);
+}
+
+
+/* setup struct parameter
+ * push the registers out to memory
+ * used by bfcode() */
+static void
+param_struct(struct symtab *sym, int *argofsp)
+{
+        int argofs = *argofsp;
+        NODE *p, *q;
+        int navail;
+        int sz;
+        int off;
+        int num;
+        int i;
+
+        navail = NARGREGS - argofs;
+        sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT;
+        off = ARGINIT/SZINT + argofs;
+        num = sz > navail ? navail : sz;
+        for (i = 0; i < num; i++) {
+                q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+                regno(q) = R3 + argofs++;
+                p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+                regno(p) = SPREG;
+                p = block(PLUS, p, bcon(4*off++), INT, 0, MKAP(INT));
+                p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
+                p = buildtree(ASSIGN, p, q);
+                ecomp(p);
+        }
+
+        *argofsp = argofs;
+}
+
+/*
+ * code for the beginning of a function
+ * sp is an array of indices in symtab for the arguments
+ * cnt is the number of arguments
+ */
+void
+bfcode(struct symtab **sp, int cnt)
+{
+#ifdef USE_GOTNR
+	extern int gotnr;
+#endif
+
+	struct symtab *sp2;
+	union arglist *usym;
+	int saveallargs = 0;
+	int i, argofs = 0;
+
+        /*
+         * Detect if this function has ellipses and save all
+         * argument registers onto stack.
+         */
+        usym = cftnsp->sdf->dfun;
+        while (usym && usym->type != TNULL) {
+                if (usym->type == TELLIPSIS) {
+                        saveallargs = 1;
+                        break;
+                }
+                ++usym;
+        }
+
+	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
+		param_retstruct();
+		++argofs;
+	}
+
+#ifdef USE_GOTNR
+	if (kflag) {
+		/* put GOT register into temporary */
+		NODE *q, *p;
+		q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		regno(q) = GOTREG;
+		p = tempnode(0, INT, 0, MKAP(INT));
+		gotnr = regno(p);
+		ecomp(buildtree(ASSIGN, p, q));
+	}
+#endif
+
+        /* recalculate the arg offset and create TEMP moves */
+        for (i = 0; i < cnt; i++) {
+
+		if (sp[i] == NULL)
+			continue;
+
+                if ((argofs >= NARGREGS) && !xtemps)
+                        break;
+
+                if (argofs >= NARGREGS) {
+                        putintemp(sp[i]);
+                } else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) {
+                        param_struct(sp[i], &argofs);
+                } else if (DEUNSIGN(sp[i]->stype) == LONGLONG) {
+                        param_64bit(sp[i], &argofs, xtemps && !saveallargs);
+                } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) {
+			if (features(FEATURE_HARDFLOAT))
+	                        param_double(sp[i], &argofs,
+				    xtemps && !saveallargs);
+			else
+	                        param_64bit(sp[i], &argofs,
+				    xtemps && !saveallargs);
+                } else if (sp[i]->stype == FLOAT) {
+			if (features(FEATURE_HARDFLOAT))
+	                        param_float(sp[i], &argofs,
+				    xtemps && !saveallargs);
+			else
+                        	param_32bit(sp[i], &argofs,
+				    xtemps && !saveallargs);
+                } else {
+                        param_32bit(sp[i], &argofs, xtemps && !saveallargs);
+		}
+        }
+
+        /* if saveallargs, save the rest of the args onto the stack */
+        while (saveallargs && argofs < NARGREGS) {
+      		NODE *p, *q;
+		/* int off = (ARGINIT+FIXEDSTACKSIZE*SZCHAR)/SZINT + argofs; */
+		int off = ARGINIT/SZINT + argofs;
+		q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		regno(q) = R3 + argofs++;
+		p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		regno(p) = FPREG;
+		p = block(PLUS, p, bcon(4*off), INT, 0, MKAP(INT));
+		p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
+		p = buildtree(ASSIGN, p, q);
+		ecomp(p);
+	}
+
+	/* profiling */
+	if (pflag) {
+		NODE *p;
+
+#if defined(ELFABI)
+
+		sp2 = lookup("_mcount", 0);
+		sp2->stype = EXTERN;
+		p = nametree(sp2);
+		p->n_sp->sclass = EXTERN;
+		p = clocal(p);
+		p = buildtree(ADDROF, p, NIL);
+		p = block(UCALL, p, NIL, INT, 0, MKAP(INT));
+		ecomp(funcode(p));
+
+
+#elif defined(MACHOABI)
+
+		NODE *q;
+		int tmpnr;
+
+                q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+                regno(q) = R0;
+		p = tempnode(0, INT, 0, MKAP(INT));
+		tmpnr = regno(p);
+		p = buildtree(ASSIGN, p, q);
+		ecomp(p);
+
+		q = tempnode(tmpnr, INT, 0, MKAP(INT));
+
+		sp2 = lookup("mcount", 0);
+		sp2->stype = EXTERN;
+		p = nametree(sp2);
+		p->n_sp->sclass = EXTERN;
+		p = clocal(p);
+		p = buildtree(ADDROF, p, NIL);
+		p = block(CALL, p, q, INT, 0, MKAP(INT));
+		ecomp(funcode(p));
+
+#endif
+	}
+}
+
+/*
+ * code for the end of a function
+ * deals with struct return here
+ */
+void
+efcode()
+{
+        NODE *p, *q;
+        int tempnr;
+        int ty;
+
+#ifdef USE_GOTNR
+	extern int gotnr;
+	gotnr = 0;
+#endif
+
+        if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+                return;
+
+        ty = cftnsp->stype - FTN;
+
+        q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
+        regno(q) = R3;
+        p = tempnode(0, INCREF(ty), 0, cftnsp->sap);
+        tempnr = regno(p);
+        p = buildtree(ASSIGN, p, q);
+        ecomp(p);
+
+        q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap);
+        q = buildtree(UMUL, q, NIL);
+
+        p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
+        p = buildtree(UMUL, p, NIL);
+
+        p = buildtree(ASSIGN, p, q);
+        ecomp(p);
+
+        q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
+        p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
+        regno(p) = R3;
+        p = buildtree(ASSIGN, p, q);
+        ecomp(p);
+}
+
+/*
+ * by now, the automatics and register variables are allocated
+ */
+void
+bccode()
+{
+	SETOFF(autooff, SZINT);
+}
+
+struct stub stublist;
+struct stub nlplist;
+
+/* 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 __TEXT, __picsymbolstub1,symbol_stubs,pure_instructions,32\n");
+			printf("\t.align 5\n");
+			printf("L%s$stub:\n", p->name);
+			if (strcmp(p->name, "mcount") == 0)
+				printf("\t.indirect_symbol %s\n", p->name);
+			else
+				printf("\t.indirect_symbol %s\n", p->name);
+			printf("\tmflr r0\n");
+			printf("\tbcl 20,31,L%s$spb\n", p->name);
+			printf("L%s$spb:\n", p->name);
+			printf("\tmflr r11\n");
+			printf("\taddis r11,r11,ha16(L%s$lazy_ptr-L%s$spb)\n",
+			    p->name, p->name);
+			printf("\tmtlr r0\n");
+			printf("\tlwzu r12,lo16(L%s$lazy_ptr-L%s$spb)(r11)\n",
+			    p->name, p->name);
+			printf("\tmtctr r12\n");
+			printf("\tbctr\n");
+			printf("\t.lazy_symbol_pointer\n");
+			printf("L%s$lazy_ptr:\n", p->name);
+			if (strcmp(p->name, "mcount") == 0)
+				printf("\t.indirect_symbol %s\n", p->name);
+			else
+				printf("\t.indirect_symbol %s\n", p->name);
+			printf("\t.long	dyld_stub_binding_helper\n");
+			printf("\t.subsections_via_symbols\n");
+		}
+
+		printf("\t.non_lazy_symbol_pointer\n");
+		DLIST_FOREACH(p, &nlplist, link) {
+			printf("L%s$non_lazy_ptr:\n", p->name);
+			if (strcmp(p->name, "mcount") == 0)
+				printf("\t.indirect_symbol %s\n", p->name);
+			else
+				printf("\t.indirect_symbol %s\n", p->name);
+			printf("\t.long 0\n");
+	        }
+
+	}
+#endif
+
+#ifndef os_darwin
+#define _MKSTR(x) #x
+#define MKSTR(x) _MKSTR(x) 
+#define OS MKSTR(TARGOS)
+        printf("\t.ident \"PCC: %s (%s)\"\n", PACKAGE_STRING, OS);
+#endif
+
+}
+
+void
+bjobcode()
+{
+	DLIST_INIT(&stublist, link);
+	DLIST_INIT(&nlplist, link);
+}
+
+#ifdef notdef
+/*
+ * Print character t at position i in one string, until t == -1.
+ * Locctr & label is already defined.
+ */
+void
+bycode(int t, int i)
+{
+	static	int	lastoctal = 0;
+
+	/* put byte i+1 in a string */
+
+	if (t < 0) {
+		if (i != 0)
+			puts("\"");
+	} else {
+		if (i == 0)
+			printf("\t.ascii \"");
+		if (t == '\\' || t == '"') {
+			lastoctal = 0;
+			putchar('\\');
+			putchar(t);
+		} else if (t < 040 || t >= 0177) {
+			lastoctal++;
+			printf("\\%o",t);
+		} else if (lastoctal && '0' <= t && t <= '9') {
+			lastoctal = 0;
+			printf("\"\n\t.ascii \"%c", t);
+		} else {	
+			lastoctal = 0;
+			putchar(t);
+		}
+	}
+}
+#endif
+
+/*
+ * return the alignment of field of type t
+ */
+int
+fldal(unsigned int t)
+{
+	uerror("fldal: 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)
+{
+	if (num < 0) {
+		genswitch_bintree(num, type, p, n);
+		return 1;
+	}
+
+	return 0;
+
+#if 0
+	if (0)
+	genswitch_table(num, p, n);
+	if (0)
+	genswitch_bintree(num, p, n);
+	genswitch_mrst(num, p, n);
+#endif
+}
+
+static void bintree_rec(TWORD ty, int num,
+	struct swents **p, int n, int s, int e);
+
+static void
+genswitch_bintree(int num, TWORD ty, struct swents **p, int n)
+{
+	int lab = getlab();
+
+	if (p[0]->slab == 0)
+		p[0]->slab = lab;
+
+	bintree_rec(ty, num, p, n, 1, n);
+
+	plabel(lab);
+}
+
+static void
+bintree_rec(TWORD ty, int num, struct swents **p, int n, int s, int e)
+{
+	NODE *r;
+	int rlabel;
+	int h;
+
+	if (s == e) {
+		r = tempnode(num, ty, 0, MKAP(ty));
+		r = buildtree(NE, r, bcon(p[s]->sval));
+		cbranch(buildtree(NOT, r, NIL), bcon(p[s]->slab));
+		branch(p[0]->slab);
+		return;
+	}
+
+	rlabel = getlab();
+
+	h = s + (e - s) / 2;
+
+	r = tempnode(num, ty, 0, MKAP(ty));
+	r = buildtree(GT, r, bcon(p[h]->sval));
+	cbranch(r, bcon(rlabel));
+	bintree_rec(ty, num, p, n, s, h);
+	plabel(rlabel);
+	bintree_rec(ty, num, p, n, h+1, e);
+}
+
+
+#if 0
+
+static void
+genswitch_table(int num, struct swents **p, int n)
+{
+	NODE *r, *t;
+	int tval;
+	int minval, maxval, range;
+	int deflabel, tbllabel;
+	int i, j;
+
+	minval = p[1]->sval;
+	maxval = p[n]->sval;
+
+	range = maxval - minval + 1;
+
+	if (n < 10 || range > 3 * n) {
+		/* too small or too sparse for jump table */
+		genswitch_simple(num, p, n);
+		return;
+	}
+
+	r = tempnode(num, UNSIGNED, 0, MKAP(UNSIGNED));
+	r = buildtree(MINUS, r, bcon(minval));
+	t = tempnode(0, UNSIGNED, 0, MKAP(UNSIGNED));
+	tval = regno(t);
+	r = buildtree(ASSIGN, t, r);
+	ecomp(r);
+
+	deflabel = p[0]->slab;
+	if (deflabel == 0)
+		deflabel = getlab();
+
+	t = tempnode(tval, UNSIGNED, 0, MKAP(UNSIGNED));
+	cbranch(buildtree(GT, t, bcon(maxval-minval)), bcon(deflabel));
+
+	tbllabel = getlab();
+	struct symtab *strtbl = lookup("__switch_table", SLBLNAME|STEMP);
+	strtbl->soffset = tbllabel;
+	strtbl->sclass = ILABEL;
+	strtbl->stype = INCREF(UCHAR);
+
+	t = block(NAME, NIL, NIL, UNSIGNED, 0, MKAP(UNSIGNED));
+	t->n_sp = strtbl;
+	t = buildtree(ADDROF, t, NIL);
+	r = tempnode(tval, UNSIGNED, 0, MKAP(INT));
+	r = buildtree(PLUS, t, r);
+	t = tempnode(0, INCREF(UNSIGNED), 0, MKAP(UNSIGNED));
+	r = buildtree(ASSIGN, t, r);
+	ecomp(r);
+
+	r = tempnode(regno(t), INCREF(UNSIGNED), 0, MKAP(UNSIGNED));
+	r = buildtree(UMUL, r, NIL);
+	t = block(NAME, NIL, NIL, UCHAR, 0, MKAP(UCHAR));
+	t->n_sp = strtbl;
+	t = buildtree(ADDROF, t, NIL);
+	r = buildtree(PLUS, t, r);
+	r = block(GOTO, r, NIL, 0, 0, 0);
+	ecomp(r);
+
+	plabel(tbllabel);
+	for (i = minval, j=1; i <= maxval; i++) {
+		char *entry = tmpalloc(20);
+		int lab = deflabel;
+		//printf("; minval=%d, maxval=%d, i=%d, j=%d p[j]=%lld\n", minval, maxval, i, j, p[j]->sval);
+		if (p[j]->sval == i) {
+			lab = p[j]->slab;
+			j++;
+		}
+		snprintf(entry, 20, ".long " LABFMT "-" LABFMT, lab, tbllabel);
+		send_passt(IP_ASM, entry);
+	}
+
+	if (p[0]->slab <= 0)
+		plabel(deflabel);
+}
+
+#define DPRINTF(x)	if (xdebug) printf x
+//#define DPRINTF(x)	do { } while(0)
+
+#define MIN_TABLE_SIZE	8
+
+/*
+ *  Multi-way Radix Search Tree (MRST)
+ */
+
+static void mrst_rec(int num, struct swents **p, int n, int *state, int lab);
+static unsigned long mrst_find_window(struct swents **p, int n, int *state, int lab, int *len, int *lowbit);
+void mrst_put_entry_and_recurse(int num, struct swents **p, int n, int *state, int tbllabel, int lab, unsigned long j, unsigned long tblsize, unsigned long Wmax, int lowbit);
+
+static void
+genswitch_mrst(int num, struct swents **p, int n)
+{
+	int *state;
+	int i;
+	int putlabel = 0;
+
+	if (n < 10) {
+		/* too small for MRST */
+		genswitch_simple(num, p, n);
+		return;
+	}
+
+	state = tmpalloc((n+1)*sizeof(int));
+	for (i = 0; i <= n; i++)
+		state[i] = 0;
+
+	if (p[0]->slab == 0) {
+		p[0]->slab = getlab();
+		putlabel = 1;
+	}
+
+	mrst_rec(num, p, n, state, 0);
+
+	if (putlabel)
+		plabel(p[0]->slab);
+}
+
+
+/*
+ *  Look through the cases and generate a table or
+ *  list of simple comparisons.  If generating a table,
+ *  invoke mrst_put_entry_and_recurse() to put
+ *  an entry in the table and recurse.
+ */
+static void
+mrst_rec(int num, struct swents **p, int n, int *state, int lab)
+{
+	int len, lowbit;
+	unsigned long Wmax;
+	unsigned int tblsize;
+	NODE *t;
+	NODE *r;
+	int tval;
+	int i;
+
+	DPRINTF(("mrst_rec: num=%d, n=%d, lab=%d\n", num, n, lab));
+
+	/* find best window to cover set*/
+	Wmax = mrst_find_window(p, n, state, lab, &len, &lowbit);
+	tblsize = (1 << len);
+	assert(len > 0 && tblsize > 0);
+
+	DPRINTF(("mrst_rec: Wmax=%lu, lowbit=%d, tblsize=%u\n",
+		Wmax, lowbit, tblsize));
+
+	if (lab)
+		plabel(lab);
+
+	if (tblsize <= MIN_TABLE_SIZE) {
+		DPRINTF(("msrt_rec: break the recursion\n"));
+		for (i = 1; i <= n; i++) {
+			if (state[i] == lab) {
+				t = tempnode(num, UNSIGNED, 0, MKAP(UNSIGNED));
+				cbranch(buildtree(EQ, t, bcon(p[i]->sval)),
+				    bcon(p[i]->slab));
+			}
+		}
+		branch(p[0]->slab);
+		return;
+	}
+
+	DPRINTF(("generating table with %d elements\n", tblsize));
+
+	// AND with Wmax
+	t = tempnode(num, UNSIGNED, 0, MKAP(UNSIGNED));
+	r = buildtree(AND, t, bcon(Wmax));
+
+	// RS lowbits
+	r = buildtree(RS, r, bcon(lowbit));
+
+	t = tempnode(0, UNSIGNED, 0, MKAP(UNSIGNED));
+	tval = regno(t);
+	r = buildtree(ASSIGN, t, r);
+	ecomp(r);
+
+	int tbllabel = getlab();
+	struct symtab *strtbl = lookup("__switch_table", SLBLNAME|STEMP);
+	strtbl->sclass = STATIC;
+	strtbl->sap = MKAP(UCHAR);
+	strtbl->slevel = 1;
+	strtbl->soffset = tbllabel;
+	strtbl->stype = INCREF(UCHAR);
+	strtbl->squal = (CON >> TSHIFT);
+
+	t = block(NAME, NIL, NIL, UNSIGNED, 0, MKAP(UNSIGNED));
+	t->n_sp = strtbl;
+	t = buildtree(ADDROF, t, NIL);
+	r = tempnode(tval, UNSIGNED, 0, MKAP(INT));
+	r = buildtree(PLUS, t, r);
+	t = tempnode(0, INCREF(UNSIGNED), 0, MKAP(UNSIGNED));
+	r = buildtree(ASSIGN, t, r);
+	ecomp(r);
+
+	r = tempnode(regno(t), INCREF(UNSIGNED), 0, MKAP(UNSIGNED));
+	r = buildtree(UMUL, r, NIL);
+	t = block(NAME, NIL, NIL, UCHAR, 0, MKAP(UCHAR));
+	t->n_sp = strtbl;
+	t = buildtree(ADDROF, t, NIL);
+	r = buildtree(PLUS, t, r);
+	r = block(GOTO, r, NIL, 0, 0, 0);
+	ecomp(r);
+
+	plabel(tbllabel);
+	
+	mrst_put_entry_and_recurse(num, p, n, state, tbllabel, lab,
+		0, tblsize, Wmax, lowbit);
+}
+
+
+/*
+ * Put an entry into the table and recurse to the next entry
+ * in the table.  On the way back through the recursion, invoke
+ * mrst_rec() to check to see if we should generate another
+ * table.
+ */
+void
+mrst_put_entry_and_recurse(int num, struct swents **p, int n, int *state,
+	int tbllabel, int labval,
+	unsigned long j, unsigned long tblsize, unsigned long Wmax, int lowbit)
+{
+	int i;
+	int found = 0;
+	int lab = getlab();
+
+	/*
+	 *  Look for labels which map to this table entry.
+	 *  Mark each one in "state" that they fall inside this table.
+	 */
+	for (i = 1; i <= n; i++) {
+		unsigned int val = (p[i]->sval & Wmax) >> lowbit;
+		if (val == j && state[i] == labval) {
+			found = 1;
+			state[i] = lab;
+		}
+	}
+
+	/* couldn't find any labels?  goto the default label */
+	if (!found)
+		lab = p[0]->slab;
+
+	/* generate the table entry */
+	char *entry = tmpalloc(20);
+	snprintf(entry, 20, ".long " LABFMT "-" LABFMT, lab, tbllabel);
+	send_passt(IP_ASM, entry);
+
+	DPRINTF(("mrst_put_entry: table=%d, pos=%lu/%lu, label=%d\n",
+	    tbllabel, j, tblsize, lab));
+
+	/* go to the next table entry */
+	if (j+1 < tblsize) {
+		mrst_put_entry_and_recurse(num, p, n, state, tbllabel, labval,
+			j+1, tblsize, Wmax, lowbit);
+	}
+
+	/* if we are going to the default label, bail now */
+	if (!found)
+		return;
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("state: ");
+		for (i = 1; i <= n; i++)
+			printf("%d ", state[i]);
+		printf("\n");
+	}
+#endif
+
+	/* build another table */
+	mrst_rec(num, p, n, state, lab);
+}
+
+/*
+ * counts the number of entries in a table of size (1 << L) which would
+ * be used given the cases and the mask (W, lowbit).
+ */
+static unsigned int
+mrst_cardinality(struct swents **p, int n, int *state, int step, unsigned long W, int L, int lowbit)
+{
+	unsigned int count = 0;
+	int i;
+
+	if (W == 0)
+		return 0;
+
+	int *vals = (int *)calloc(1 << L, sizeof(int));
+	assert(vals);
+
+	DPRINTF(("mrst_cardinality: "));
+	for (i = 1; i <= n; i++) {
+		int idx;
+		if (state[i] != step)
+			continue;
+		idx = (p[i]->sval & W) >> lowbit;
+		DPRINTF(("%llu->%d, ", p[i]->sval, idx));
+		if (!vals[idx]) {
+			count++;
+		}
+		vals[idx] = 1;
+	}
+	DPRINTF((": found %d entries\n", count));
+	free(vals);
+
+	return count;
+}
+
+/*
+ *  Find the maximum window (table size) which would best cover
+ *  the set of labels.  Algorithm explained in:
+ *
+ *  Ulfar Erlingsson, Mukkai Krishnamoorthy and T.V. Raman.
+ *  Efficient Multiway Radix Search Trees.
+ *  Information Processing Letters 60:3 115-120 (November 1996)
+ */
+
+static unsigned long
+mrst_find_window(struct swents **p, int n, int *state, int lab, int *len, int *lowbit)
+{
+	unsigned int tblsize;
+	unsigned long W = 0;
+	unsigned long Wmax = 0;
+	unsigned long Wleft = (1 << (SZLONG-1));
+	unsigned int C = 0;
+	unsigned int Cmax = 0;
+	int L = 0;
+	int Lmax = 0;
+	int lowmax = 0;
+	int no_b = SZLONG-1;
+	unsigned long b = (1 << (SZLONG-1));
+
+	DPRINTF(("mrst_find_window: n=%d, lab=%d\n", n, lab));
+
+	for (; b > 0; b >>= 1, no_b--) {
+
+		// select the next bit
+		W |= b;
+		L += 1;
+
+		tblsize = 1 << L;
+		assert(tblsize > 0);
+
+		DPRINTF(("no_b=%d, b=0x%lx, Wleft=0x%lx, W=0x%lx, Wmax=0x%lx, L=%d, Lmax=%d, Cmax=%u, lowmax=%d, tblsize=%u\n", no_b, b, Wleft, W, Wmax, L, Lmax, Cmax, lowmax, tblsize));
+
+		C = mrst_cardinality(p, n, state, lab, W, L, no_b);
+		DPRINTF((" -> cardinality is %d\n", C));
+
+		if (2*C >= tblsize) {
+			DPRINTF(("(found good match, keep adding to table)\n"));
+			Wmax = W;
+			Lmax = L;
+			lowmax = no_b;
+			Cmax = C;
+		} else {
+			DPRINTF(("(too sparse)\n"));
+			assert((W & Wleft) != 0);
+
+			/* flip the MSB and see if we get a better match */
+			W ^= Wleft;
+			Wleft >>= 1;
+			L -= 1;
+
+			DPRINTF((" --> trying W=0x%lx and L=%d and Cmax=%u\n", W, L, Cmax));
+			C = mrst_cardinality(p, n, state, lab, W, L, no_b);
+			DPRINTF((" --> C=%u\n", C));
+			if (C > Cmax) {
+				Wmax = W;
+				Lmax = L;
+				lowmax = no_b;
+				Cmax = C;
+				DPRINTF((" --> better!\n"));
+			} else {
+				DPRINTF((" --> no better\n"));
+			}
+		}
+
+	}
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		int i;
+		int hibit = lowmax + Lmax;
+		printf("msrt_find_window: Wmax=0x%lx, lowbit=%d, result=", Wmax, lowmax);
+		for (i = 31; i >= 0; i--) {
+			int mask = (1 << i);
+			if (i == hibit)
+				printf("[");
+			if (Wmax & mask)
+				printf("1");
+			else
+				printf("0");
+			if (i == lowmax)
+				printf("]");
+		}
+		printf("\n");
+	}
+#endif
+
+	assert(Lmax > 0);
+	*len = Lmax;
+	*lowbit = lowmax;
+
+	DPRINTF(("msrt_find_window: returning Wmax=%lu, len=%d, lowbit=%d [tblsize=%u, entries=%u]\n", Wmax, Lmax, lowmax, tblsize, C));
+
+	return Wmax;
+}
+#endif
+
+/*
+ * Straighten a chain of CM ops so that the CM nodes
+ * only appear on the left node.
+ *
+ *          CM               CM
+ *        CM  CM           CM  b
+ *       x y  a b        CM  a
+ *                      x  y
+ *
+ *           CM             CM
+ *        CM    CM        CM c
+ *      CM z  CM  c      CM b
+ *     x y    a b      CM a
+ *                   CM z
+ *                  x y
+ */
+static NODE *
+straighten(NODE *p)
+{
+        NODE *r = p->n_right;
+
+        if (p->n_op != CM || r->n_op != CM)
+                return p;
+
+        p->n_right = r->n_left;
+        r->n_left = straighten(p);
+
+        return r;
+}
+
+static NODE *
+reverse1(NODE *p, NODE *a)
+{
+	NODE *l = p->n_left;
+	NODE *r = p->n_right;
+
+	a->n_right = r;
+	p->n_left = a;
+
+	if (l->n_op == CM) {
+		return reverse1(l, p);
+	} else {
+		p->n_right = l;
+		return p;
+	}
+}
+
+/*
+ * Reverse a chain of CM ops
+ */
+static NODE *
+reverse(NODE *p)
+{
+	NODE *l = p->n_left;
+	NODE *r = p->n_right;
+
+	p->n_left = r;
+
+	if (l->n_op == CM)
+		return reverse1(l, p);
+
+	p->n_right = l;
+
+	return p;
+}
+
+/* push arg onto the stack */
+/* called by moveargs() */
+static NODE *
+pusharg(NODE *p, int *regp)
+{
+        NODE *q;
+        int sz;
+	int off;
+
+        /* convert to register size, if smaller */
+        sz = tsize(p->n_type, p->n_df, p->n_ap);
+        if (sz < SZINT)
+                p = block(SCONV, p, NIL, INT, 0, MKAP(INT));
+
+        q = block(REG, NIL, NIL, INCREF(p->n_type), p->n_df, p->n_ap);
+        regno(q) = SPREG;
+
+	off = ARGINIT/SZCHAR + 4 * (*regp - R3);
+	q = block(PLUS, q, bcon(off), INT, 0, MKAP(INT));
+        q = block(UMUL, q, NIL, p->n_type, p->n_df, p->n_ap);
+	(*regp) += szty(p->n_type);
+
+        return buildtree(ASSIGN, q, p);
+}
+
+/* setup call stack with 32-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_32bit(NODE *p, int *regp)
+{
+	int reg = *regp;
+	NODE *q;
+
+	q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+	regno(q) = reg++;
+	q = buildtree(ASSIGN, q, p);
+
+	*regp = reg;
+	return q;
+}
+
+/* setup call stack with 64-bit argument */
+/* called from moveargs() */
+static NODE *
+movearg_64bit(NODE *p, int *regp)
+{
+        int reg = *regp;
+        NODE *q, *r;
+
+#if ALLONGLONG == 64
+        /* alignment */
+        ++reg;
+        reg &= ~1;
+#endif
+
+        if (reg > R10) {
+                *regp = reg;
+                q = pusharg(p, regp);
+	} else if (reg == R10) {
+		/* half in and half out of the registers */
+		r = tcopy(p);
+		if (!features(FEATURE_BIGENDIAN)) {
+			q = block(SCONV, p, NIL, INT, 0, MKAP(INT));
+			q = movearg_32bit(q, regp);	/* little-endian */
+			r = buildtree(RS, r, bcon(32));
+			r = block(SCONV, r, NIL, INT, 0, MKAP(INT));
+			r = pusharg(r, regp); /* little-endian */
+		} else {
+			q = buildtree(RS, p, bcon(32));
+			q = block(SCONV, q, NIL, INT, 0, MKAP(INT));
+			q = movearg_32bit(q, regp);	/* big-endian */
+			r = block(SCONV, r, NIL, INT, 0, MKAP(INT));
+			r = pusharg(r, regp); /* big-endian */
+		}
+		q = straighten(block(CM, q, r, p->n_type, p->n_df, p->n_ap));
+        } else {
+                q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+                regno(q) = R3R4 + (reg - R3);
+                q = buildtree(ASSIGN, q, p);
+                *regp = reg + 2;
+        }
+
+        return q;
+}
+
+/* setup call stack with float argument */
+/* called from moveargs() */
+static NODE *
+movearg_float(NODE *p, int *fregp, int *regp)
+{
+#if defined(MACHOABI)
+	NODE *q, *r;
+	TWORD ty = INCREF(p->n_type);
+	int tmpnr;
+#endif
+
+	p = movearg_32bit(p, fregp);
+
+	/*
+	 * On OS/X, floats are passed in the floating-point registers
+	 * and in the general registers for compatibily with libraries
+	 * compiled to handle soft-float.
+	 */
+
+#if defined(MACHOABI)
+
+	if (xtemps) {
+		/* bounce into TOS */
+		r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap);
+		regno(r) = SPREG;
+		r = block(PLUS, r, bcon(-4), INT, 0, MKAP(INT));
+		r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap);
+		r = buildtree(ASSIGN, r, p);
+		ecomp(r);
+
+		/* bounce into temp */
+		r = block(REG, NIL, NIL, PTR+INT, 0, MKAP(INT));
+		regno(r) = SPREG;
+		r = block(PLUS, r, bcon(-4), INT, 0, MKAP(INT));
+		r = block(UMUL, r, NIL, INT, 0, MKAP(INT));
+		q = tempnode(0, INT, 0, MKAP(INT));
+		tmpnr = regno(q);
+		r = buildtree(ASSIGN, q, r);
+		ecomp(r);
+	} else {
+		/* copy directly into temp */
+		q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+		tmpnr = regno(q);
+		r = buildtree(ASSIGN, q, p);
+		ecomp(r);
+	}
+
+	/* copy from temp to register parameter */
+	r = tempnode(tmpnr, INT, 0, MKAP(INT));
+	q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+	regno(q) = (*regp)++;
+	p = buildtree(ASSIGN, q, r);
+
+#endif
+	return p;
+
+}
+
+/* setup call stack with float/double argument */
+/* called from moveargs() */
+static NODE *
+movearg_double(NODE *p, int *fregp, int *regp)
+{
+#if defined(MACHOABI)
+	NODE *q, *r;
+	TWORD ty = INCREF(p->n_type);
+	int tmpnr;
+#endif
+
+	/* this does the move to a single register for us */
+	p = movearg_32bit(p, fregp);
+
+	/*
+	 * On OS/X, doubles are passed in the floating-point registers
+	 * and in the general registers for compatibily with libraries
+	 * compiled to handle soft-float.
+	 */
+
+#if defined(MACHOABI)
+
+	if (xtemps) {
+		/* bounce on TOS */
+		r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap);
+		regno(r) = SPREG;
+		r = block(PLUS, r, bcon(-8), ty, p->n_df, p->n_ap);
+		r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap);
+		r = buildtree(ASSIGN, r, p);
+		ecomp(r);
+
+		/* bounce into temp */
+		r = block(REG, NIL, NIL, PTR+LONGLONG, 0, MKAP(LONGLONG));
+		regno(r) = SPREG;
+		r = block(PLUS, r, bcon(-8), PTR+LONGLONG, 0, MKAP(LONGLONG));
+		r = block(UMUL, r, NIL, LONGLONG, 0, MKAP(LONGLONG));
+		q = tempnode(0, LONGLONG, 0, MKAP(LONGLONG));
+		tmpnr = regno(q);
+		r = buildtree(ASSIGN, q, r);
+		ecomp(r);
+	} else {
+		/* copy directly into temp */
+		q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+		tmpnr = regno(q);
+		r = buildtree(ASSIGN, q, p);
+		ecomp(r);
+	}
+
+	/* copy from temp to register parameter */
+	r = tempnode(tmpnr, LONGLONG, 0, MKAP(LONGLONG));
+	q = block(REG, NIL, NIL, LONGLONG, 0, MKAP(LONGLONG));
+	regno(q) = R3R4 - R3 + (*regp);
+	p = buildtree(ASSIGN, q, r);
+
+	(*regp) += 2;
+
+#endif
+	
+	return p;
+}
+
+/* setup call stack with a structure */
+/* called from moveargs() */
+static NODE *
+movearg_struct(NODE *p, int *regp)
+{
+        int reg = *regp;
+        NODE *l, *q, *t, *r;
+        int tmpnr;
+        int navail;
+        int num;
+        int sz;
+        int ty;
+        int i;
+
+	assert(p->n_op == STARG);
+
+        navail = NARGREGS - (reg - R3);
+        navail = navail < 0 ? 0 : navail;
+        sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT;
+        num = sz > navail ? navail : sz;
+
+	/* remove STARG node */
+        l = p->n_left;
+        nfree(p);
+        ty = l->n_type;
+
+	/*
+	 * put it into a TEMP, rather than tcopy(), since the tree
+	 * in p may have side-affects
+	 */
+	t = tempnode(0, ty, l->n_df, l->n_ap);
+	tmpnr = regno(t);
+	q = buildtree(ASSIGN, t, l);
+
+        /* copy structure into registers */
+        for (i = 0; i < num; i++) {
+		t = tempnode(tmpnr, ty, 0, MKAP(PTR+ty));
+		t = block(SCONV, t, NIL, PTR+INT, 0, MKAP(PTR+INT));
+		t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKAP(PTR+INT));
+		t = buildtree(UMUL, t, NIL);
+
+		r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		regno(r) = reg++;
+		r = buildtree(ASSIGN, r, t);
+
+		q = block(CM, q, r, INT, 0, MKAP(INT));
+        }
+
+	/* put the rest of the structure on the stack */
+        for (i = num; i < sz; i++) {
+                t = tempnode(tmpnr, ty, 0, MKAP(PTR+ty));
+                t = block(SCONV, t, NIL, PTR+INT, 0, MKAP(PTR+INT));
+                t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKAP(PTR+INT));
+                t = buildtree(UMUL, t, NIL);
+		r = pusharg(t, &reg);
+		q = block(CM, q, r, INT, 0, MKAP(INT));
+        }
+
+	q = reverse(q);
+
+        *regp = reg;
+        return q;
+}
+
+
+static NODE *
+moveargs(NODE *p, int *regp, int *fregp)
+{
+        NODE *r, **rp;
+        int reg, freg;
+
+        if (p->n_op == CM) {
+                p->n_left = moveargs(p->n_left, regp, fregp);
+                r = p->n_right;
+                rp = &p->n_right;
+        } else {
+                r = p;
+                rp = &p;
+        }
+
+        reg = *regp;
+	freg = *fregp;
+
+#define	ISFLOAT(p)	(p->n_type == FLOAT || \
+			p->n_type == DOUBLE || \
+			p->n_type == LDOUBLE)
+
+        if (reg > R10 && r->n_op != STARG) {
+                *rp = pusharg(r, regp);
+	} else if (r->n_op == STARG) {
+		*rp = movearg_struct(r, regp);
+        } else if (DEUNSIGN(r->n_type) == LONGLONG) {
+                *rp = movearg_64bit(r, regp);
+	} else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
+		if (features(FEATURE_HARDFLOAT))
+			*rp = movearg_double(r, fregp, regp);
+		else
+                	*rp = movearg_64bit(r, regp);
+	} else if (r->n_type == FLOAT) {
+		if (features(FEATURE_HARDFLOAT))
+			*rp = movearg_float(r, fregp, regp);
+		else
+                	*rp = movearg_32bit(r, regp);
+        } else {
+                *rp = movearg_32bit(r, regp);
+        }
+
+	return straighten(p);
+}
+
+/*
+ * Fixup arguments to pass pointer-to-struct as first argument.
+ *
+ * called from funcode().
+ */
+static NODE *
+retstruct(NODE *p)
+{
+	struct symtab s;
+	NODE *l, *r, *t, *q;
+	TWORD ty;
+
+	l = p->n_left;
+	r = p->n_right;
+
+	ty = DECREF(l->n_type) - FTN;
+
+	s.sclass = AUTO;
+	s.stype = ty;
+	s.sdf = l->n_df;
+	s.sap = l->n_ap;
+	oalloc(&s, &autooff);
+	q = block(REG, NIL, NIL, INCREF(ty), l->n_df, l->n_ap);
+	regno(q) = FPREG;
+	q = block(MINUS, q, bcon(autooff/SZCHAR), INCREF(ty),
+	    l->n_df, l->n_ap);
+
+	/* insert hidden assignment at beginning of list */
+	if (r->n_op != CM) {
+		p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_ap);
+	} else {
+		for (t = r; t->n_left->n_op == CM; t = t->n_left)
+			;
+		t->n_left = block(CM, q, t->n_left, INCREF(ty),
+		    l->n_df, l->n_ap);
+	}
+
+	return p;
+}
+
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+	int regnum = R3;
+	int fregnum = F1;
+
+        if (DECREF(p->n_left->n_type) == STRTY+FTN ||
+            DECREF(p->n_left->n_type) == UNIONTY+FTN)
+		p = retstruct(p);
+
+	p->n_right = moveargs(p->n_right, &regnum, &fregnum);
+
+	if (p->n_right == NULL)
+		p->n_op += (UCALL - CALL);
+
+	return p;
+}
Index: uspace/app/pcc/arch/powerpc/local.c
===================================================================
--- uspace/app/pcc/arch/powerpc/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/powerpc/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1512 @@
+/*	$Id: local.c,v 1.28 2011/01/21 21:47:59 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 <assert.h>
+#include "pass1.h"
+
+#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
+
+extern int kflag;
+
+static void simmod(NODE *p);
+
+/*	this file contains code which is dependent on the target machine */
+
+#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
+
+
+/*
+ * Make a symtab entry for PIC use.
+ */
+static struct symtab *
+picsymtab(char *p, char *s, char *s2)
+{
+	struct symtab *sp = IALLOC(sizeof(struct symtab));
+	size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
+
+	sp->sname = sp->soname = IALLOC(len);
+	strlcpy(sp->soname, p, len);
+	strlcat(sp->soname, s, len);
+	strlcat(sp->soname, s2, len);
+	sp->sclass = EXTERN;
+	sp->sflags = sp->slevel = 0;
+
+	return sp;
+}
+
+int gotnr;  /* tempnum for GOT register */
+
+/*
+ * Create a reference for an extern variable.
+ */
+static NODE *
+picext(NODE *p)
+{
+	NODE *q;
+	struct symtab *sp;
+	char *name;
+
+	name = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname);
+
+	if (strncmp(name, "__builtin", 9) == 0)
+		return p;
+
+#if defined(ELFABI)
+
+	sp = picsymtab("", name, "@got(31)");
+	q = xbcon(0, sp, PTR+VOID);
+	q = block(UMUL, q, 0, PTR+VOID, 0, MKAP(VOID));
+
+#elif defined(MACHOABI)
+
+	char buf2[64];
+	NODE *r;
+	char *fname;
+
+	fname = cftnsp->soname ? cftnsp->soname : cftnsp->sname;
+
+	if (p->n_sp->sclass == EXTDEF) {
+		snprintf(buf2, 64, "-L%s$pb", fname);
+		sp = picsymtab("", name, buf2);
+	} else {
+		snprintf(buf2, 64, "$non_lazy_ptr-L%s$pb", fname);
+		sp = picsymtab("L", name, buf2);
+		addstub(&nlplist, name);
+	}
+#if USE_GOTNR
+	q = tempnode(gotnr, PTR+VOID, 0, MKAP(VOID));
+#else
+	q = block(REG, NIL, NIL, PTR+VOID, 0, MKAP(VOID));
+	regno(q) = GOTREG;
+#endif
+	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));
+
+#endif
+
+	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;
+}
+
+/*
+ * Create a reference for a static variable
+ */
+
+static NODE *
+picstatic(NODE *p)
+{
+	NODE *q;
+	struct symtab *sp;
+
+#if defined(ELFABI)
+	char *n;
+
+	if (p->n_sp->slevel > 0) {
+		char buf[64];
+		snprintf(buf, 64, LABFMT, (int)p->n_sp->soffset);
+		sp = picsymtab("", buf, "@got(31)");
+	} else  {
+		n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname;
+		sp = picsymtab("", exname(n), "@got(31)");
+	}
+	sp->sclass = STATIC;
+	sp->stype = p->n_sp->stype;
+	q = xbcon(0, sp, PTR+VOID);
+	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
+	q->n_sp = p->n_sp;
+	nfree(p);
+
+#elif defined(MACHOABI)
+
+	char buf2[64];
+	NODE *r;
+
+	snprintf(buf2, 64, "-L%s$pb",
+	    cftnsp->soname ? cftnsp->soname : cftnsp->sname);
+
+	if (p->n_sp->slevel > 0) {
+		char buf1[64];
+		snprintf(buf1, 64, LABFMT, (int)p->n_sp->soffset);
+		sp = picsymtab("", buf1, buf2);
+	} else  {
+		char *name = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname);
+		sp = picsymtab("", name, buf2);
+	}
+	sp->sclass = STATIC;
+	sp->stype = p->n_sp->stype;
+#if USE_GOTNR
+	q = tempnode(gotnr, PTR+VOID, 0, MKAP(VOID));
+#else
+	q = block(REG, NIL, NIL, PTR+VOID, 0, MKAP(VOID));
+	regno(q) = GOTREG;
+#endif
+	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);
+
+#endif
+
+	return q;
+}
+
+static NODE *
+convert_ulltof(NODE *p)
+{
+	NODE *q, *r, *l, *t;
+	int ty;
+	int tmpnr;
+
+	ty = p->n_type;
+	l = p->n_left;
+	nfree(p);
+
+	q = tempnode(0, ULONGLONG, 0, MKAP(ULONGLONG));
+	tmpnr = regno(q);
+	t = buildtree(ASSIGN, q, l);
+	ecomp(t);
+
+#if 0
+	q = tempnode(tmpnr, ULONGLONG, 0, MKAP(ULONGLONG));
+	q = block(SCONV, q, NIL, LONGLONG, 0, MKAP(LONGLONG));
+#endif
+	q = tempnode(tmpnr, LONGLONG, 0, MKAP(LONGLONG));
+	r = block(SCONV, q, NIL, ty, 0, MKAP(ty));
+
+	q = tempnode(tmpnr, ULONGLONG, 0, MKAP(ULONGLONG));
+	q = block(RS, q, bcon(1), ULONGLONG, 0, MKAP(ULONGLONG));
+	q = block(SCONV, q, NIL, LONGLONG, 0, MKAP(LONGLONG));
+	q = block(SCONV, q, NIL, ty, 0, MKAP(ty));
+	t = block(FCON, NIL, NIL, ty, 0, MKAP(ty));
+	t->n_dcon = 2;
+	l = block(MUL, q, t, ty, 0, MKAP(ty));
+
+	r = buildtree(COLON, l, r);
+
+	q = tempnode(tmpnr, ULONGLONG, 0, MKAP(ULONGLONG));
+	q = block(SCONV, q, NIL, LONGLONG, 0, MKAP(LONGLONG));
+	l = block(LE, q, xbcon(0, NULL, LONGLONG), INT, 0, MKAP(INT));
+
+	return clocal(buildtree(QUEST, l, r));
+
+}
+
+
+/* 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)
+{
+
+	struct symtab *q;
+	NODE *r, *l;
+	int o;
+	int m;
+	TWORD t;
+	int isptrvoid = 0;
+	int tmpnr;
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal: %p\n", p);
+		fwalk(p, eprint, 0);
+	}
+#endif
+	switch (o = p->n_op) {
+
+	case ADDROF:
+#ifdef PCC_DEBUG
+		if (xdebug) {
+			printf("clocal(): ADDROF\n");
+			printf("type: 0x%x\n", p->n_type);
+		}
+#endif
+		/* XXX cannot takes addresses of PARAMs */
+
+		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 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:
+			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:
+			if (kflag == 0)
+				break;
+			if (blevel > 0)
+				p = picext(p);
+			break;
+		}
+		break;
+
+	case UCALL:
+	case CALL:
+	case USTCALL:
+	case STCALL:
+                if (p->n_type == VOID)
+                        break;
+                /*
+                 * if the function returns void*, ecode() invokes
+                 * delvoid() to convert it to uchar*.
+                 * We just let this happen on the ASSIGN to the temp,
+                 * and cast the pointer back to void* on access
+                 * from the temp.
+                 */
+                if (p->n_type == PTR+VOID)
+                        isptrvoid = 1;
+                r = tempnode(0, p->n_type, p->n_df, p->n_ap);
+                tmpnr = regno(r);
+		r = buildtree(ASSIGN, r, p);
+
+                p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
+                if (isptrvoid) {
+                        p = block(PCONV, p, NIL, PTR+VOID,
+                            p->n_df, MKAP(PTR+VOID));
+                }
+#if 1
+                p = buildtree(COMOP, r, p);
+#else
+		/* XXX this doesn't work if the call is already in a COMOP */
+		r = clocal(r);
+		ecomp(r);
+#endif
+                break;
+		
+	case CBRANCH:
+		l = p->n_left;
+
+		/*
+		 * Remove unnecessary conversion ops.
+		 */
+		if (clogop(l->n_op) && l->n_left->n_op == SCONV) {
+			if (coptype(l->n_op) != BITYPE)
+				break;
+			if (l->n_right->n_op == ICON) {
+				r = l->n_left->n_left;
+				if (r->n_type >= FLOAT && r->n_type <= LDOUBLE)
+					break;
+				/* Type must be correct */
+				t = r->n_type;
+				nfree(l->n_left);
+				l->n_left = r;
+				l->n_type = t;
+				l->n_right->n_type = t;
+			}
+		}
+		break;
+
+	case PCONV:
+		/* Remove redundant PCONV's. Be careful */
+		l = p->n_left;
+		if (l->n_op == ICON) {
+			l->n_lval = (unsigned)l->n_lval;
+			goto delp;
+		}
+		if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
+			/* 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:
+		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_type = p->n_type;
+			nfree(p);
+			return l;
+		}
+
+		/*
+		 * if converting ULONGLONG to FLOAT/(L)DOUBLE,
+		 * replace ___floatunsdidf() with ___floatdidf()
+		 */
+		if (l->n_type == ULONGLONG && p->n_type >= FLOAT &&
+		    p->n_type <= LDOUBLE) {
+			return convert_ulltof(p);
+		}
+
+		o = l->n_op;
+		m = p->n_type;
+
+		if (o == ICON) {
+			CONSZ val = l->n_lval;
+
+			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
+			    switch (m) {
+			case BOOL:
+				l->n_lval = l->n_lval != 0;
+				break;
+			case CHAR:
+				l->n_lval = (char)val;
+				break;
+			case UCHAR:
+				l->n_lval = val & 0377;
+				break;
+			case SHORT:
+				l->n_lval = (short)val;
+				break;
+			case USHORT:
+				l->n_lval = val & 0177777;
+				break;
+			case ULONG:
+			case UNSIGNED:
+				l->n_lval = val & 0xffffffff;
+				break;
+			case 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 (o == FCON) {
+			l->n_lval = 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 ((DEUNSIGN(p->n_type) == CHAR ||
+		    DEUNSIGN(p->n_type) == SHORT) &&
+		    (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;
+		}
+		if ((DEUNSIGN(l->n_type) == CHAR ||
+		    DEUNSIGN(l->n_type) == SHORT) &&
+		    (p->n_type == FLOAT || p->n_type == DOUBLE ||
+		    p->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:
+		simmod(p);
+		break;
+
+	case DIV:
+		if (o == DIV && 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:
+                
+                nfree(p);
+                return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right));
+
+	case STNAME:
+		if ((q = p->n_sp) == NULL)
+			return p;
+		if (q->sclass != STNAME)
+			return p;
+		t = p->n_type;
+		p = block(ADDROF, p, NIL, INCREF(t), p->n_df, p->n_ap);
+		p = block(UMUL, p, NIL, t, p->n_df, p->n_ap);
+		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(BOOL_TYPE) : RETREG(p->n_type);
+		break;
+
+	case LS:
+	case RS:
+		if (p->n_right->n_op == ICON)
+			break; /* do not do anything */
+		if (DEUNSIGN(p->n_right->n_type) == INT)
+			break;
+		p->n_right = block(SCONV, p->n_right, NIL, INT, 0, MKAP(INT));
+		break;
+	}
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal end: %p\n", p);
+		fwalk(p, eprint, 0);
+	}
+#endif
+	return(p);
+}
+
+/*
+ * Change CALL references to either direct (static) or PLT.
+ */
+static void
+fixnames(NODE *p, void *arg)
+{
+        struct symtab *sp;
+        struct 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 defined(ELFABI)
+
+        if (q->n_op == ICON) {
+                sp = q->n_sp;
+
+#elif defined(MACHOABI)
+
+#ifdef USE_GOTNR
+	if (q->n_op == PLUS && q->n_left->n_op == TEMP &&
+#else
+	if (q->n_op == PLUS && q->n_left->n_op == REG &&
+#endif
+	    q->n_right->n_op == ICON) {
+                sp = q->n_right->n_sp;
+#endif
+
+                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(31)")) == NULL)
+                        cerror("fixnames2");
+                if (isu) {
+                        strcpy(c, "@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;
+
+		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
+        }
+}
+
+void
+myp2tree(NODE *p)
+{
+	int o = p->n_op;
+	struct symtab *sp;
+
+	if (kflag)
+		walkf(p, fixnames, 0);
+	if (o != FCON) 
+		return;
+
+	/* Write float constants to memory */
+	/* Should be voluntary per architecture */
+ 
+	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, tsize(sp->stype, sp->sdf, sp->sap), 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()
+{
+#ifdef PCC_DEBUG
+	if (xdebug)
+		printf("cendarg: autooff=%d (was %d)\n", AUTOINIT, autooff);
+#endif
+	autooff = AUTOINIT;
+}
+
+/*
+ * Return 1 if a variable of type type is OK to put in register.
+ */
+int
+cisreg(TWORD t)
+{
+	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
+ * 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;
+
+#ifdef PCC_DEBUG
+	if (xdebug)
+		printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
+		    off, t, d, (int)tsize(t, d, ap));
+#endif
+
+	p = bcon(0);
+	p->n_lval = off/SZCHAR;	/* Default */
+	return(p);
+}
+
+/*
+ * Allocate bits on the stack.
+ * 'off' is the number of bits to allocate
+ * '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 *q, *r;
+	int nbytes = off / SZCHAR;
+	int stacksize = 24+40; /* this should be p2stacksize */
+
+	/*
+	 * After we subtract the requisite bytes
+	 * off the stack, we need to step back over
+	 * the 40 bytes for the arguments registers
+	 * *and* any other parameters which will get
+	 * saved to the stack.  Unfortunately, we
+	 * don't have that information in pass1 and
+	 * the parameters will stomp on the allocated
+	 * space for alloca().
+	 *
+	 * No fix yet.
+	 */
+	werror("parameters may stomp on alloca()");
+
+	/* compute size */
+	p = buildtree(MUL, p, bcon(nbytes));
+	p = buildtree(PLUS, p, bcon(ALSTACK/SZCHAR));
+
+	/* load the top-of-stack */
+	q = block(REG, NIL, NIL, PTR+INT, 0, MKAP(INT));
+	regno(q) = SPREG;
+	q = block(UMUL, q, NIL, INT, 0, MKAP(INT));
+
+	/* save old top-of-stack value to new top-of-stack position */
+	r = block(REG, NIL, NIL, PTR+INT, 0, MKAP(INT));
+	regno(r) = SPREG;
+	r = block(MINUSEQ, r, p, INT, 0, MKAP(INT));
+	r = block(UMUL, r, NIL, INT, 0, MKAP(INT));
+	ecomp(buildtree(ASSIGN, r, q));
+
+	r = block(REG, NIL, NIL, PTR+INT, 0, MKAP(INT));
+	regno(r) = SPREG;
+
+	/* skip over the arguments space and align to 16 bytes */
+	r = block(PLUS, r, bcon(stacksize + 15), INT, 0, MKAP(INT));
+	r = block(RS, r, bcon(4), INT, 0, MKAP(INT));
+	r = block(LS, r, bcon(4), INT, 0, MKAP(INT));
+
+	t->n_type = p->n_type;
+	ecomp(buildtree(ASSIGN, t, r));
+}
+
+/*
+ * Print out a string of characters.
+ * Unfortunately, this code assumes that the assembler understands
+ * C-style escape sequences. (which it doesn't!)
+ * Location is already set.
+ */
+void
+instring(struct symtab *sp)
+{
+	char *s, *str = sp->sname;
+
+#if defined(ELFABI)
+
+	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 > 64) {
+			fwrite(str, 1, s - str, stdout);
+			printf("\"\n\t.ascii \"");
+			str = s;
+		}
+	}
+	fwrite(str, 1, s - str, stdout);
+	printf("\\0\"\n");
+}
+
+static int inbits, inval;
+
+/*
+ * set fsz bits in sequence to zero.
+ */
+void
+zbits(OFFSZ off, int fsz)
+{
+	int m;
+
+	if (idebug)
+		printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
+
+#if 0
+	/* little-endian */
+	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;
+		}
+	}
+#endif
+	/* big-endian */
+	if (inbits) {
+		m = SZCHAR - inbits;
+		if (fsz < m) {
+			inbits += fsz;
+			inval <<= fsz;
+		} else {
+			printf("\t.byte %d\n", inval << m);
+			fsz -= m;
+			inval = inbits = 0;
+		}
+	}
+
+	if (fsz >= SZCHAR) {
+		printf("\t.space %d\n", fsz/SZCHAR);
+		fsz -= (fsz/SZCHAR) * SZCHAR;
+	}
+	if (fsz) {
+		inval = 0;
+		inbits = fsz;
+	}
+}
+
+/*
+ * Initialize a bitfield.
+ */
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+	if (idebug)
+		printf("infld off %lld, fsz %d, val %lld inbits %d\n",
+		    off, fsz, val, inbits);
+
+	val &= (1 << fsz)-1;
+
+#if 0
+	/* little-endian */
+	while (fsz + inbits >= SZCHAR) {
+		inval |= (val << inbits);
+		printf("\t.byte %d\n", inval & 255);
+		fsz -= (SZCHAR - inbits);
+		val >>= (SZCHAR - inbits);
+		inval = inbits = 0;
+	}
+	if (fsz) {
+		inval |= (val << inbits);
+		inbits += fsz;
+	}
+#endif
+
+	/* big-endian */
+	inval <<= fsz;
+	inval |= val;
+	inbits += fsz;
+	while (inbits >= SZCHAR) {
+		int pval = inval >> (inbits - SZCHAR);
+		printf("\t.byte %d\n", pval & 255);
+		inbits -= SZCHAR;
+	}
+}
+
+/*
+ * print out a constant node, may be associated with a label.
+ * Do not free the node after use.
+ * off is bit offset from the beginning of the aggregate
+ * fsz is the number of bits this is referring to
+ */
+void
+ninval(CONSZ off, int fsz, NODE *p)
+{
+	union { float f; double d; long double l; int i[3]; } u;
+	struct symtab *q;
+	char *c;
+	TWORD t;
+	int i;
+
+	t = p->n_type;
+	if (t > BTMASK)
+		t = INT; /* pointer */
+
+	while (p->n_op == SCONV || p->n_op == PCONV) {
+		NODE *l = p->n_left;
+		l->n_type = p->n_type;
+		p = l;
+	}
+
+	if (kflag && (p->n_op == PLUS || p->n_op == UMUL)) {
+		if (p->n_op == UMUL)
+			p = p->n_left;
+		p = p->n_right;
+		q = p->n_sp;
+
+#if defined(ELFABI)
+
+		if (q->soname && (c = strstr(q->soname, "@got(31)")) != 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: node %p [%s]",
+		     p, cftnsp->soname);
+
+	if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
+		uerror("element not constant");
+
+	switch (t) {
+	case LONGLONG:
+	case ULONGLONG:
+#if 0
+		/* little-endian */
+		i = (p->n_lval >> 32);
+		p->n_lval &= 0xffffffff;
+		p->n_type = INT;
+		ninval(off, 32, p);
+		p->n_lval = i;
+		ninval(off+32, 32, p);
+#endif
+		/* big-endian */
+		i = (p->n_lval & 0xffffffff);
+		p->n_lval >>= 32;
+		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 = q->soname ? q->soname : exname(q->sname);
+				printf("+%s", name);
+			}
+		}
+		printf("\n");
+		break;
+	case SHORT:
+	case USHORT:
+		printf("\t.short %d\n", (int)p->n_lval & 0xffff);
+		break;
+	case BOOL:
+		if (p->n_lval > 1)
+			p->n_lval = p->n_lval != 0;
+		/* FALLTHROUGH */
+	case CHAR:
+	case UCHAR:
+		printf("\t.byte %d\n", (int)p->n_lval & 0xff);
+		break;
+	case LDOUBLE:
+		u.i[2] = 0;
+		u.l = (long double)p->n_dcon;
+#if 0
+		/* little-endian */
+		printf("\t.long 0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+#endif
+		/* big-endian */
+		printf("\t.long 0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+		break;
+	case DOUBLE:
+		u.d = (double)p->n_dcon;
+		printf("\t.long 0x%x\n\t.long 0x%x\n", u.i[0], u.i[1]);
+		break;
+	case FLOAT:
+		u.f = (float)p->n_dcon;
+		printf("\t.long 0x%x\n", u.i[0]);
+		break;
+	default:
+		cerror("ninval");
+	}
+}
+
+/* make a name look like an external name in the local machine */
+char *
+exname(char *p)
+{
+#if defined(ELFABI)
+
+	return (p == NULL ? "" : p);
+
+#elif 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);
+
+#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) 
+{
+#ifdef PCC_DEBUG
+	if (xdebug)
+		printf("calldec:\n");
+#endif
+}
+
+void
+extdec(struct symtab *q)
+{
+#ifdef PCC_DEBUG
+	if (xdebug)
+		printf("extdec:\n");
+#endif
+}
+
+/* make a common declaration for id, if reasonable */
+void
+defzero(struct symtab *sp)
+{
+	char *n;
+	int off;
+
+	off = tsize(sp->stype, sp->sdf, sp->sap);
+	off = (off+(SZCHAR-1))/SZCHAR;
+	printf("\t.%scomm ", sp->sclass == STATIC ? "l" : "");
+	n = sp->soname ? sp->soname : exname(sp->sname);
+	if (sp->slevel == 0)
+		printf("%s,%d\n", n, off);
+	else
+		printf(LABFMT ",%d\n", sp->soffset, off);
+}
+
+
+#ifdef notdef
+/* make a common declaration for id, if reasonable */
+void
+commdec(struct symtab *q)
+{
+	int off;
+
+	off = tsize(q->stype, q->sdf, q->ssue);
+	off = (off+(SZCHAR-1))/SZCHAR;
+	printf("\t.comm %s,0%o\n", q->soname ? q->soname : exname(q->sname), off);
+}
+
+/* make a local common declaration for id, if reasonable */
+void
+lcommdec(struct symtab *q)
+{
+	int off;
+
+	off = tsize(q->stype, q->sdf, q->ssue);
+	off = (off+(SZCHAR-1))/SZCHAR;
+	if (q->slevel == 0)
+		printf("\t.lcomm %s,%d\n", q->soname ? q->soname : exname(q->sname), off);
+	else
+		printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off);
+}
+
+/*
+ * print a (non-prog) label.
+ */
+void
+deflab1(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+#if defined(ELFABI)
+
+static char *loctbl[] = { "text", "data", "section .rodata,",
+    "section .rodata" };
+
+#elif defined(MACHOABI)
+
+static char *loctbl[] = { "text", "data", "section .rodata,", "cstring" };
+
+#endif
+
+void
+setloc1(int locc)
+{
+#ifdef PCC_DEBUG
+	if (xdebug)
+		printf("setloc1: locc=%d, lastloc=%d\n", locc, lastloc);
+#endif
+
+	if (locc == lastloc)
+		return;
+	lastloc = locc;
+	printf("	.%s\n", loctbl[locc]);
+}
+#endif
+
+/* simulate and optimise the MOD opcode */
+static void
+simmod(NODE *p)
+{
+	NODE *r = p->n_right;
+
+	assert(p->n_op == MOD);
+
+	if (!ISUNSIGNED(p->n_type))
+		return;
+
+#define ISPOW2(n) ((n) && (((n)&((n)-1)) == 0))
+
+	/* if the right is a constant power of two, then replace with AND */
+	if (r->n_op == ICON && ISPOW2(r->n_lval)) {
+		p->n_op = AND;
+		r->n_lval--;
+		return;
+	}
+
+#undef ISPOW2
+
+	/* other optimizations can go here */
+}
+
+static int constructor;
+static int destructor;
+
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+	if (strcmp(str, "tls") == 0) {
+		uerror("thread-local storage not supported for this target");
+		return 1;
+	}
+	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;
+	}
+
+	return 0;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+	/* may have sanity checks here */
+	if ((constructor || destructor) && (sp->sclass != PARAM)) {
+#ifdef 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");
+		}
+		printf("\t.p2align 2\n");
+		printf("\t.long %s\n", exname(sp->sname));
+		printf("\t.text\n");
+		constructor = destructor = 0;
+#endif
+	}
+}
+
+/*
+ * There is very little different here to the standard builtins.
+ * It basically handles promotion of types smaller than INT.
+ */
+
+NODE *
+powerpc_builtin_stdarg_start(NODE *f, NODE *a, TWORD t)
+{
+        NODE *p, *q;
+        int sz = 1;
+
+        /* check num args and type */
+        if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+            !ISPTR(a->n_left->n_type))
+                goto bad;
+
+        /* must first deal with argument size; use int size */
+        p = a->n_right;
+        if (p->n_type < INT) {
+                /* round up to word */
+                sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap);
+        }
+
+        p = buildtree(ADDROF, p, NIL);  /* address of last arg */
+        p = optim(buildtree(PLUS, p, bcon(sz)));
+        q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
+        q = buildtree(CAST, q, p);
+        p = q->n_right;
+        nfree(q->n_left);
+        nfree(q);
+        p = buildtree(ASSIGN, a->n_left, p);
+        tfree(f);
+        nfree(a);
+
+        return p;
+
+bad:
+        uerror("bad argument to __builtin_stdarg_start");
+        return bcon(0);
+}
+
+NODE *
+powerpc_builtin_va_arg(NODE *f, NODE *a, TWORD t)
+{
+        NODE *p, *q, *r;
+        int sz, tmpnr;
+
+        /* check num args and type */
+        if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
+            !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
+                goto bad;
+
+        r = a->n_right;
+
+        /* get type size */
+        sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR;
+        if (sz < SZINT/SZCHAR) {
+                werror("%s%s promoted to int when passed through ...",
+                        ISUNSIGNED(r->n_type) ? "unsigned " : "",
+                        DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
+                sz = SZINT/SZCHAR;
+		r->n_type = INT;
+		r->n_ap = MKAP(INT);
+        }
+
+        p = tcopy(a->n_left);
+
+#if defined(ELFABI)
+
+        /* alignment */
+        if (SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
+                p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1));
+                p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_ap);
+        }
+
+#endif
+
+        /* create a copy to a temp node */
+        q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+        tmpnr = regno(q);
+        p = buildtree(ASSIGN, q, p);
+
+        q = tempnode(tmpnr, p->n_type, p->n_df, p->n_ap);
+        q = buildtree(PLUS, q, bcon(sz));
+        q = buildtree(ASSIGN, a->n_left, q);
+
+        q = buildtree(COMOP, p, q);
+
+        nfree(a->n_right);
+        nfree(a);
+        nfree(f);
+
+        p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap);
+        p = buildtree(UMUL, p, NIL);
+        p = buildtree(COMOP, q, p);
+
+        return p;
+
+bad:
+        uerror("bad argument to __builtin_va_arg");
+        return bcon(0);
+}
+
+NODE *
+powerpc_builtin_va_end(NODE *f, NODE *a, TWORD t)
+{
+        tfree(f);
+        tfree(a);
+ 
+        return bcon(0);
+}
+
+NODE *
+powerpc_builtin_va_copy(NODE *f, NODE *a, TWORD t)
+{
+        if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
+                goto bad;
+        tfree(f);
+        f = buildtree(ASSIGN, a->n_left, a->n_right);
+        nfree(a);
+        return f;
+
+bad:
+        uerror("bad argument to __buildtin_va_copy");
+        return bcon(0);
+}
+
+NODE *
+powerpc_builtin_return_address(NODE *f, NODE *a, TWORD t)
+{
+	int nframes;
+	int i = 0;
+
+	if (a == NULL || a->n_op != ICON)
+		goto bad;
+
+	nframes = a->n_lval;
+
+	tfree(f);
+	tfree(a);
+
+	f = block(REG, NIL, NIL, PTR+VOID, 0, MKAP(VOID));
+	regno(f) = SPREG;
+
+	do {
+		f = block(UMUL, f, NIL, PTR+VOID, 0, MKAP(VOID));
+	} while (i++ < nframes);
+
+	f = block(PLUS, f, bcon(8), 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 *
+powerpc_builtin_frame_address(NODE *f, NODE *a, TWORD t)
+{
+	int nframes;
+	int i = 0;
+
+	if (a == NULL || a->n_op != ICON)
+		goto bad;
+
+	nframes = a->n_lval;
+
+	tfree(f);
+	tfree(a);
+
+	if (nframes == 0) {
+		f = block(REG, NIL, NIL, PTR+VOID, 0, MKAP(VOID));
+		regno(f) = FPREG;
+	} else {
+		f = block(REG, NIL, NIL, PTR+VOID, 0, MKAP(VOID));
+		regno(f) = SPREG;
+		do {
+			f = block(UMUL, f, NIL, PTR+VOID, 0, MKAP(VOID));
+		} while (i++ < nframes);
+		f = block(PLUS, f, bcon(24), INCREF(PTR+VOID), 0, MKAP(VOID));
+		f = buildtree(UMUL, f, NIL);
+	}
+
+	return f;
+bad:
+        uerror("bad argument to __builtin_frame_address");
+        return bcon(0);
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
Index: uspace/app/pcc/arch/powerpc/local2.c
===================================================================
--- uspace/app/pcc/arch/powerpc/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/powerpc/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1517 @@
+/*	$Id: local2.c,v 1.25 2010/11/26 17:06:31 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"	/* for cftnsp */
+#include "pass2.h"
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(MACHOABI)
+#define EXPREFIX	"_"
+#else
+#define EXPREFIX	""
+#endif
+
+#define LOWREG		0
+#define HIREG		1
+
+char *rnames[] = {
+	REGPREFIX "r0", REGPREFIX "r1",
+	REGPREFIX "r2", REGPREFIX "r3",
+	REGPREFIX "r4", REGPREFIX "r5",
+	REGPREFIX "r6", REGPREFIX "r7",
+	REGPREFIX "r8", REGPREFIX "r9",
+	REGPREFIX "r10", REGPREFIX "r11",
+	REGPREFIX "r12", REGPREFIX "r13",
+	REGPREFIX "r14", REGPREFIX "r15",
+	REGPREFIX "r16", REGPREFIX "r17",
+	REGPREFIX "r18", REGPREFIX "r19",
+	REGPREFIX "r20", REGPREFIX "r21",
+	REGPREFIX "r22", REGPREFIX "r23",
+	REGPREFIX "r24", REGPREFIX "r25",
+	REGPREFIX "r26", REGPREFIX "r27",
+	REGPREFIX "r28", REGPREFIX "r29",
+	REGPREFIX "r30", REGPREFIX "r31",
+	"r4\0r3\0", "r5\0r4\0", "r6\0r5\0", "r7\0r6\0",
+	"r8\0r7\0", "r9\0r8\0", "r10r9\0", "r15r14", "r17r16",
+	"r19r18", "r21r20", "r23r22", "r25r24", "r27r26",
+	"r29r28", "r31r30",
+	REGPREFIX "f0", REGPREFIX "f1",
+	REGPREFIX "f2", REGPREFIX "f3",
+	REGPREFIX "f4", REGPREFIX "f5",
+	REGPREFIX "f6", REGPREFIX "f7",
+	REGPREFIX "f8", REGPREFIX "f9",
+	REGPREFIX "f10", REGPREFIX "f11",
+	REGPREFIX "f12", REGPREFIX "f13",
+	REGPREFIX "f14", REGPREFIX "f15",
+	REGPREFIX "f16", REGPREFIX "f17",
+	REGPREFIX "f18", REGPREFIX "f19",
+	REGPREFIX "f20", REGPREFIX "f21",
+	REGPREFIX "f22", REGPREFIX "f23",
+	REGPREFIX "f24", REGPREFIX "f25",
+	REGPREFIX "f26", REGPREFIX "f27",
+	REGPREFIX "f28", REGPREFIX "f29",
+	REGPREFIX "f30", REGPREFIX "f31",
+};
+
+static int argsize(NODE *p);
+
+static int p2calls;
+static int p2temps;		/* TEMPs which aren't autos yet */
+static int p2framesize;
+static int p2maxstacksize;
+
+void
+deflab(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+static TWORD ftype;
+
+/*
+ * Print out the prolog assembler.
+ */
+void
+prologue(struct interpass_prolog *ipp)
+{
+	int addto;
+
+#ifdef PCC_DEBUG
+	if (x2debug)
+		printf("prologue: type=%d, lineno=%d, name=%s, vis=%d, ipptype=%d, regs=0x%lx, autos=%d, tmpnum=%d, lblnum=%d\n",
+			ipp->ipp_ip.type,
+			ipp->ipp_ip.lineno,
+			ipp->ipp_name,
+			ipp->ipp_vis,
+			ipp->ipp_type,
+			ipp->ipp_regs[0],
+			ipp->ipp_autos,
+			ipp->ip_tmpnum,
+			ipp->ip_lblnum);
+#endif
+
+	ftype = ipp->ipp_type;
+
+	addto = p2framesize;
+
+	if (p2calls != 0 || kflag) {
+		/* get return address (not required for leaf function) */
+		printf("\tmflr %s\n", rnames[R0]);
+		printf("\tstw %s,8(%s)\n", rnames[R0], rnames[R1]);
+	}
+	/* save registers R30 and R31 */
+	printf("\tstmw %s,-8(%s)\n", rnames[R30], rnames[R1]);
+#ifdef FPREG
+	printf("\tmr %s,%s\n", rnames[FPREG], rnames[R1]);
+#endif
+	/* create the new stack frame */
+	if (addto > 32767) {
+		printf("\tlis %s,%d\n", rnames[R0], (-addto) >> 16);
+		printf("\tori %s,%s,%d\n", rnames[R0],
+		    rnames[R0], (-addto) & 0xffff);
+		printf("\tstwux %s,%s,%s\n", rnames[R1],
+		    rnames[R1], rnames[R0]);
+	} else {
+		printf("\tstwu %s,-%d(%s)\n", rnames[R1], addto, rnames[R1]);
+	}
+
+	if (kflag) {
+#if defined(ELFABI)
+		printf("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n");
+		printf("\tmflr %s\n", rnames[GOTREG]);
+#elif defined(MACHOABI)
+		printf("\tbcl 20,31,L%s$pb\n", ipp->ipp_name + 1);
+		printf("L%s$pb:\n", ipp->ipp_name + 1);
+		printf("\tmflr %s\n", rnames[GOTREG]);
+#endif
+	}
+
+}
+
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+
+#ifdef PCC_DEBUG
+	if (x2debug)
+		printf("eoftn:\n");
+#endif
+
+	if (ipp->ipp_ip.ip_lbl == 0)
+		return; /* no code needs to be generated */
+
+	/* struct return needs special treatment */
+	if (ftype == STRTY || ftype == UNIONTY) 
+		cerror("eoftn");
+
+	/* unwind stack frame */
+	printf("\tlwz %s,0(%s)\n", rnames[R1], rnames[R1]);
+	if (p2calls != 0 || kflag) {
+		printf("\tlwz %s,8(%s)\n", rnames[R0], rnames[R1]);
+		printf("\tmtlr %s\n", rnames[R0]);
+	}
+	printf("\tlmw %s,-8(%s)\n", rnames[R30], rnames[R1]);
+	printf("\tblr\n");
+}
+
+/*
+ * add/sub/...
+ *
+ * Param given:
+ */
+void
+hopcode(int f, int o)
+{
+	char *str;
+
+	switch (o) {
+	case PLUS:
+		str = "addw";
+		break;
+	case MINUS:
+		str = "subw";
+		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(NODE *p)
+{
+	switch(p->n_type) {
+		case CHAR:
+		case UCHAR:
+			return(1);
+
+		case SHORT:
+		case USHORT:
+			return(SZSHORT/SZCHAR);
+
+		case DOUBLE:
+			return(SZDOUBLE/SZCHAR);
+
+		case INT:
+		case UNSIGNED:
+		case LONG:
+		case ULONG:
+			return(SZINT/SZCHAR);
+
+		case LONGLONG:
+		case ULONGLONG:
+			return SZLONGLONG/SZCHAR;
+
+		default:
+			if (!ISPTR(p->n_type))
+				comperr("tlen type %d not pointer");
+			return SZPOINT(p->n_type)/SZCHAR;
+		}
+}
+
+/*
+ * Emit code to compare two longlong numbers.
+ */
+static void
+twollcomp(NODE *p)
+{
+	int o = p->n_op;
+	int s = getlab2();
+	int e = p->n_label;
+	int cb1, cb2;
+
+	if (o >= ULE)
+		o -= (ULE-LE);
+	switch (o) {
+	case NE:
+		cb1 = 0;
+		cb2 = NE;
+		break;
+	case EQ:
+		cb1 = NE;
+		cb2 = 0;
+		break;
+	case LE:
+	case LT:
+		cb1 = GT;
+		cb2 = LT;
+		break;
+	case GE:
+	case GT:
+		cb1 = LT;
+		cb2 = GT;
+		break;
+	
+	default:
+		cb1 = cb2 = 0; /* XXX gcc */
+	}
+	if (p->n_op >= ULE)
+		cb1 += 4, cb2 += 4;
+	if (p->n_op >= ULE)
+		expand(p, 0, "\tcmplw UL,UR" COM "compare 64-bit values (upper)\n");
+	else
+		expand(p, 0, "\tcmpw UL,UR" COM "compare 64-bit values (upper)\n");
+	if (cb1) cbgen(cb1, s);
+	if (cb2) cbgen(cb2, e);
+	if (p->n_op >= ULE)
+		expand(p, 0, "\tcmplw AL,AR" COM "(and lower)\n");
+	else
+		expand(p, 0, "\tcmpw AL,AR" COM "(and lower)\n");
+	cbgen(p->n_op, e);
+	deflab(s);
+}
+
+static void
+shiftop(NODE *p)
+{
+	NODE *r = p->n_right;
+	TWORD ty = p->n_type;
+
+	if (p->n_op == LS && r->n_op == ICON && r->n_lval < 32) {
+		expand(p, INBREG, "\tsrwi A1,AL,32-AR" COM "64-bit left-shift\n");
+		expand(p, INBREG, "\tslwi U1,UL,AR\n");
+		expand(p, INBREG, "\tor U1,U1,A1\n");
+		expand(p, INBREG, "\tslwi A1,AL,AR\n");
+	} else if (p->n_op == LS && r->n_op == ICON && r->n_lval < 64) {
+		expand(p, INBREG, "\tli A1,0" COM "64-bit left-shift\n");
+		if (r->n_lval == 32)
+			expand(p, INBREG, "\tmr U1,AL\n");
+		else
+			expand(p, INBREG, "\tslwi U1,AL,AR-32\n");
+	} else if (p->n_op == LS && r->n_op == ICON) {
+		expand(p, INBREG, "\tli A1,0" COM "64-bit left-shift\n");
+		expand(p, INBREG, "\tli U1,0\n");
+	} else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 32) {
+		expand(p, INBREG, "\tslwi U1,UL,32-AR" COM "64-bit right-shift\n");
+		expand(p, INBREG, "\tsrwi A1,AL,AR\n");
+		expand(p, INBREG, "\tor A1,A1,U1\n");
+		if (ty == LONGLONG)
+			expand(p, INBREG, "\tsrawi U1,UL,AR\n");
+		else
+			expand(p, INBREG, "\tsrwi U1,UL,AR\n");
+	} else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 64) {
+		if (ty == LONGLONG)
+			expand(p, INBREG, "\tli U1,-1" COM "64-bit right-shift\n");
+		else
+			expand(p, INBREG, "\tli U1,0" COM "64-bit right-shift\n");
+		if (r->n_lval == 32)
+			expand(p, INBREG, "\tmr A1,UL\n");
+		else if (ty == LONGLONG)
+			expand(p, INBREG, "\tsrawi A1,UL,AR-32\n");
+		else
+			expand(p, INBREG, "\tsrwi A1,UL,AR-32\n");
+	} else if (p->n_op == RS && r->n_op == ICON) {
+		expand(p, INBREG, "\tli A1,0" COM "64-bit right-shift\n");
+		expand(p, INBREG, "\tli U1,0\n");
+	}
+}
+
+/*
+ * Structure assignment.
+ */
+static void
+stasg(NODE *p)
+{
+	NODE *l = p->n_left;
+	int val = l->n_lval;
+
+        /* R3 = dest, R4 = src, R5 = len */
+        printf("\tli %s,%d\n", rnames[R5], p->n_stsize);
+        if (l->n_op == OREG) {
+                printf("\taddi %s,%s,%d\n", rnames[R3], rnames[regno(l)], val);
+        } else if (l->n_op == NAME) {
+#if defined(ELFABI)
+                printf("\tli %s,", rnames[R3]);
+                adrput(stdout, l);
+		printf("@ha\n");
+                printf("\taddi %s,%s,", rnames[R3], rnames[R3]);
+                adrput(stdout, l);
+		printf("@l\n");
+#elif defined(MACHOABI)
+                printf("\tli %s,ha16(", rnames[R3]);
+                adrput(stdout, l);
+		printf(")\n");
+                printf("\taddi %s,%s,lo16(", rnames[R3], rnames[R3]);
+                adrput(stdout, l);
+		printf(")\n");
+#endif
+        }
+	if (kflag) {
+#if defined(ELFABI)
+	        printf("\tbl %s@got(30)\n", EXPREFIX "memcpy");
+#elif defined(MACHOABI)
+	        printf("\tbl L%s$stub\n", EXPREFIX "memcpy");
+		addstub(&stublist, EXPREFIX "memcpy");
+#endif
+	} else {
+	        printf("\tbl %s\n", EXPREFIX "memcpy");
+	}
+}
+
+static void
+fpemul(NODE *p)
+{
+	NODE *l = p->n_left;
+	char *ch = NULL;
+
+	if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3";
+	else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3";
+	else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3";
+
+	else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3";
+	else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3";
+	else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3";
+
+	else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3";
+	else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3";
+	else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3";
+
+	else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3";
+	else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3";
+	else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3";
+
+	else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2";
+	else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2";
+	else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2";
+
+	else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2";
+	else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2";
+	else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2";
+
+	else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2";
+	else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2";
+	else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2";
+
+	else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2";
+	else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2";
+	else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2";
+
+	else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2";
+	else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2";
+	else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2";
+
+	else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2";
+	else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2";
+	else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2";
+
+	else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2";
+	else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2";
+	else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2";
+
+	else if (p->n_op == SCONV && p->n_type == FLOAT) {
+		if (l->n_type == DOUBLE) ch = "truncdfsf2";
+		else if (l->n_type == LDOUBLE) ch = "truncdfsf2";
+		else if (l->n_type == ULONGLONG) ch = "floatunsdisf";
+		else if (l->n_type == LONGLONG) ch = "floatdisf";
+		else if (l->n_type == LONG) ch = "floatsisf";
+		else if (l->n_type == ULONG) ch = "floatunsisf";
+		else if (l->n_type == INT) ch = "floatsisf";
+		else if (l->n_type == UNSIGNED) ch = "floatunsisf";
+	} else if (p->n_op == SCONV && p->n_type == DOUBLE) {
+		if (l->n_type == FLOAT) ch = "extendsfdf2";
+		else if (l->n_type == LDOUBLE) ch = "truncdfdf2";
+		else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+		else if (l->n_type == LONGLONG) ch = "floatdidf";
+		else if (l->n_type == LONG) ch = "floatsidf";
+		else if (l->n_type == ULONG) ch = "floatunssidf";
+		else if (l->n_type == INT) ch = "floatsidf";
+		else if (l->n_type == UNSIGNED) ch = "floatunssidf";
+	} else if (p->n_op == SCONV && p->n_type == LDOUBLE) {
+		if (l->n_type == FLOAT) ch = "extendsfdf2";
+		else if (l->n_type == DOUBLE) ch = "extenddfdf2";
+		else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
+		else if (l->n_type == LONGLONG) ch = "floatdidf";
+		else if (l->n_type == LONG) ch = "floatsidf";
+		else if (l->n_type == ULONG) ch = "floatunssidf";
+		else if (l->n_type == INT) ch = "floatsidf";
+		else if (l->n_type == UNSIGNED) ch = "floatunsidf";
+	} else if (p->n_op == SCONV && p->n_type == ULONGLONG) {
+		if (l->n_type == FLOAT) ch = "fixunssfdi";
+		else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
+		else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
+	} else if (p->n_op == SCONV && p->n_type == LONGLONG) {
+		if (l->n_type == FLOAT) ch = "fixsfdi";
+		else if (l->n_type == DOUBLE) ch = "fixdfdi";
+		else if (l->n_type == LDOUBLE) ch = "fixdfdi";
+	} else if (p->n_op == SCONV && p->n_type == LONG) {
+		if (l->n_type == FLOAT) ch = "fixsfdi";
+		else if (l->n_type == DOUBLE) ch = "fixdfdi";
+		else if (l->n_type == LDOUBLE) ch = "fixdfdi";
+	} else if (p->n_op == SCONV && p->n_type == ULONG) {
+		if (l->n_type == FLOAT) ch = "fixunssfdi";
+		else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
+		else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
+	} else if (p->n_op == SCONV && p->n_type == INT) {
+		if (l->n_type == FLOAT) ch = "fixsfsi";
+		else if (l->n_type == DOUBLE) ch = "fixdfsi";
+		else if (l->n_type == LDOUBLE) ch = "fixdfsi";
+	} else if (p->n_op == SCONV && p->n_type == UNSIGNED) {
+		if (l->n_type == FLOAT) ch = "fixunssfsi";
+		else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
+		else if (l->n_type == LDOUBLE) ch = "fixunsdfsi";
+	}
+
+	if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op);
+
+	if (kflag) {
+#if defined(ELFABI)
+		printf("\tbl __%s%s@got(30)" COM "soft-float\n", EXPREFIX, ch);
+#elif defined(MACHOABI)
+		char buf[32];
+		printf("\tbl L__%s%s$stub" COM "soft-float\n", EXPREFIX, ch);
+		snprintf(buf, 32, "__%s%s", EXPREFIX, ch);
+		addstub(&stublist, buf);
+#endif
+	} else {
+		printf("\tbl __%s%s" COM "soft-float\n", EXPREFIX, ch);
+	}
+
+	if (p->n_op >= EQ && p->n_op <= GT)
+		printf("\tcmpwi %s,0\n", rnames[R3]);
+}
+
+/*
+ * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
+ */
+
+static void
+emul(NODE *p)
+{
+	char *ch = NULL;
+
+        if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3";
+        else if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG ||
+            DEUNSIGN(p->n_type) == INT))
+                ch = "ashlsi3";
+
+        else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3";
+        else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == INT))
+                ch = "lshrsi3";
+
+        else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3";
+        else if (p->n_op == RS && (p->n_type == LONG || p->n_type == INT))
+                ch = "ashrsi3";
+        
+        else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3";
+        else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == INT))
+                ch = "divsi3";
+
+        else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3";
+        else if (p->n_op == DIV && (p->n_type == ULONG ||
+            p->n_type == UNSIGNED))
+                ch = "udivsi3";
+
+        else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3";
+        else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == INT))
+                ch = "modsi3";
+
+        else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3";
+        else if (p->n_op == MOD && (p->n_type == ULONG ||
+            p->n_type == UNSIGNED))
+                ch = "umodsi3";
+
+        else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3";
+        else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == INT))
+                ch = "mulsi3";
+
+        else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2";
+        else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2";
+
+	else ch = 0, comperr("ZE");
+	if (kflag) {
+#if defined(ELFABI)
+		printf("\tbl __%s%s@got(30)" COM "emulated op\n", EXPREFIX, ch);
+#elif defined(MACHOABI)
+		char buf[32];
+		printf("\tbl L__%s%s$stub" COM "emulated op\n", EXPREFIX, ch);
+		snprintf(buf, 32, "__%s%s", EXPREFIX, ch);
+		addstub(&stublist, buf);
+#endif
+	} else {
+		printf("\tbl __%s%s" COM "emulated operation\n", EXPREFIX, ch);
+	}
+}
+
+/*
+ *  Floating-point conversions (int -> float/double & float/double -> int)
+ */
+
+static void
+ftoi(NODE *p)
+{
+	NODE *l = p->n_left;
+
+	printf(COM "start conversion float/(l)double to int\n");
+
+	if (l->n_op != OREG) {
+		expand(p, 0, "\tstw AL,-4");
+		printf("(%s)\n", rnames[SPREG]);
+		if (l->n_type == FLOAT)
+			expand(p, 0, "\tlfs A2,");
+		else
+			expand(p, 0, "\tlfd A2,\n");
+		printf("-4(%s)\n", rnames[SPREG]);
+	} else {
+		if (l->n_type == FLOAT)
+			expand(p, 0, "\tlfs A2,AL\n");
+		else
+			expand(p, 0, "\tlfd A2,AL\n");
+	}
+
+	expand(p, 0, "\tfctiwz A2,A2\n");
+	expand(p, 0, "\tstfd A2,");
+	printf("-8(%s)\n", rnames[SPREG]);
+	expand(p, 0, "\tlwz A1,");
+	printf("-4(%s)\n", rnames[SPREG]);
+
+	printf(COM "end conversion\n");
+}
+
+static void
+ftou(NODE *p)
+{
+	static int lab = 0;
+	NODE *l = p->n_left;
+	int lab1 = getlab2();
+	int lab2 = getlab2();
+
+	printf(COM "start conversion of float/(l)double to unsigned\n");
+
+	if (lab == 0) {
+		lab = getlab2();
+		expand(p, 0, "\t.data\n");
+		printf(LABFMT ":\t.long 0x41e00000\n\t.long 0\n", lab);
+		expand(p, 0, "\t.text\n");
+	}
+
+	if (l->n_op != OREG) {
+		expand(p, 0, "\tstw AL,");
+		printf("-4(%s)\n", rnames[SPREG]);
+		if (l->n_type == FLOAT)
+			expand(p, 0, "\tlfs A3,");
+		else
+			expand(p, 0, "\tlfd A3,");
+		printf("-4(%s)\n", rnames[SPREG]);
+		
+	} else {
+		if (l->n_type == FLOAT)
+			expand(p, 0, "\tlfs A3,AL\n");
+		else
+			expand(p, 0, "\tlfd A3,AL\n");
+	}
+
+#if 0
+	if (kflag) {
+		expand(p, 0, "\taddis A1,");
+		printf("%s,ha16(", rnames[R31]);
+		printf(LABFMT, lab);
+		printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+       		expand(p, 0, "\tlfd A2,lo16(");
+		printf(LABFMT, lab);
+		printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+		expand(p, 0, "(A1)\n");
+	} else {
+               	expand(p, 0, "\tlfd A2,");
+		printf(LABFMT "\n", lab);
+	}
+#endif
+
+#if defined(ELFABI)
+
+	expand(p, 0, "\taddis A1,");
+	printf("%s," LABFMT "@ha\n", rnames[R31], lab);
+       	expand(p, 0, "\tlfd A2,");
+	printf(LABFMT "@l", lab);
+	expand(p, 0, "(A1)\n");
+
+#elif defined(MACHOABI)
+
+	expand(p, 0, "\taddis A1,");
+	printf("%s,ha16(", rnames[R31]);
+	printf(LABFMT, lab);
+	if (kflag)
+		printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+	printf(")\n");
+       	expand(p, 0, "\tlfd A2,lo16(");
+	printf(LABFMT, lab);
+	if (kflag)
+		printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+	expand(p, 0, ")(A1)\n");
+
+#endif
+
+	expand(p, 0, "\tfcmpu cr7,A3,A2\n");
+	printf("\tcror 30,29,30\n");
+	printf("\tbeq cr7,"LABFMT "\n", lab1);
+
+	expand(p, 0, "\tfctiwz A2,A3\n");
+	expand(p, 0, "\tstfd A2,");
+	printf("-8(%s)\n", rnames[SPREG]);
+	expand(p, 0, "\tlwz A1,");
+	printf("-4(%s)\n", rnames[SPREG]);
+	printf("\tba " LABFMT "\n", lab2);
+
+	deflab(lab1);
+
+        expand(p, 0, "\tfsub A2,A3,A2\n");
+        expand(p, 0, "\tfctiwz A2,A2\n");
+	expand(p, 0, "\tstfd A2,");
+	printf("-8(%s)\n", rnames[SPREG]);
+	expand(p, 0, "\tlwz A1,");
+	printf("-4(%s)\n", rnames[SPREG]);
+        expand(p, 0, "\txoris A1,A1,0x8000\n");
+
+	deflab(lab2);
+
+	printf(COM "end conversion\n");
+}
+
+static void
+itof(NODE *p)
+{
+	static int labu = 0;
+	static int labi = 0;
+	int lab;
+	NODE *l = p->n_left;
+
+	printf(COM "start conversion (u)int to float/(l)double\n");
+
+	if (labi == 0 && l->n_type == INT) {
+		labi = getlab2();
+		expand(p, 0, "\t.data\n");
+		printf(LABFMT ":\t.long 0x43300000\n\t.long 0x80000000\n", labi);
+		expand(p, 0, "\t.text\n");
+	} else if (labu == 0 && l->n_type == UNSIGNED) {
+		labu = getlab2();
+		expand(p, 0, "\t.data\n");
+		printf(LABFMT ":\t.long 0x43300000\n\t.long 0x00000000\n", labu);
+		expand(p, 0, "\t.text\n");
+	}
+
+	if (l->n_type == INT) {
+		expand(p, 0, "\txoris A1,AL,0x8000\n");
+		lab = labi;
+	} else {
+		lab = labu;
+	}
+	expand(p, 0, "\tstw A1,");
+	printf("-4(%s)\n", rnames[SPREG]);
+        expand(p, 0, "\tlis A1,0x4330\n");
+        expand(p, 0, "\tstw A1,");
+	printf("-8(%s)\n", rnames[SPREG]);
+        expand(p, 0, "\tlfd A3,");
+	printf("-8(%s)\n", rnames[SPREG]);
+
+#if 0
+	if (kflag) {
+		expand(p, 0, "\taddis A1,");
+		printf("%s,ha16(", rnames[R31]);
+		printf(LABFMT, lab);
+		printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+       		expand(p, 0, "\tlfd A2,lo16(");
+		printf(LABFMT, lab);
+		printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+		expand(p, 0, "(A1)\n");
+	} else {
+               	expand(p, 0, "\tlfd A2,");
+		printf(LABFMT "\n", lab);
+	}
+#endif
+
+#if defined(ELFABI)
+
+	expand(p, 0, "\taddis A1,");
+	printf("%s," LABFMT "@ha\n", rnames[R31], lab);
+       	expand(p, 0, "\tlfd A2,");
+	printf(LABFMT "@l", lab);
+	expand(p, 0, "(A1)\n");
+
+#elif defined(MACHOABI)
+
+	expand(p, 0, "\taddis A1,");
+	printf("%s,ha16(", rnames[R31]);
+	printf(LABFMT, lab);
+	if (kflag)
+		printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+	printf(")\n");
+       	expand(p, 0, "\tlfd A2,lo16(");
+	printf(LABFMT, lab);
+	if (kflag)
+		printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname));
+	expand(p, 0, ")(A1)\n");
+
+#endif
+
+	expand(p, 0, "\tfsub A3,A3,A2\n");
+	if (p->n_type == FLOAT)
+		expand(p, 0, "\tfrsp A3,A3\n");
+
+	printf(COM "end conversion\n");
+}
+
+
+static void
+fpconv(NODE *p)
+{
+	NODE *l = p->n_left;
+
+#ifdef PCC_DEBUG
+	if (p->n_op != SCONV)
+		cerror("fpconv 1");
+#endif
+
+	if (DEUNSIGN(l->n_type) == INT)
+		itof(p);
+	else if (p->n_type == INT)
+		ftoi(p);
+	else if (p->n_type == UNSIGNED)
+		ftou(p);
+	else
+		cerror("unhandled floating-point conversion");
+
+}
+
+void
+zzzcode(NODE *p, int c)
+{
+	switch (c) {
+
+	case 'C': /* floating-point conversions */
+		fpconv(p);
+		break;
+
+	case 'D': /* long long comparision */
+		twollcomp(p);
+		break;
+
+	case 'E': /* print out emulated ops */
+		emul(p);
+		break;
+
+	case 'F': /* print out emulate floating-point ops */
+		fpemul(p);
+		break;
+
+	case 'O': /* 64-bit left and right shift operators */
+		shiftop(p);
+		break;
+
+	case 'Q': /* emit struct assign */
+		stasg(p);
+		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;
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+	CONSZ val;
+	int shft;
+
+	if (p->n_op == ASSIGN)
+		p = p->n_left;
+
+	if (features(FEATURE_BIGENDIAN))
+		shft = SZINT - UPKFSZ(p->n_rval) - UPKFOFF(p->n_rval);
+	else
+		shft = UPKFOFF(p->n_rval);
+
+	switch (**cp) {
+	case 'S':
+		printf("%d", UPKFSZ(p->n_rval));
+		break;
+	case 'H':
+		printf("%d", shft);
+		break;
+	case 'M':
+	case 'N':
+		val = (CONSZ)1 << UPKFSZ(p->n_rval);
+		--val;
+		val <<= shft;
+		printf(CONFMT, (**cp == 'M' ? val : ~val)  & 0xffffffff);
+		break;
+	default:
+		comperr("fldexpand");
+	}
+	return 1;
+}
+
+/*
+ * 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)
+{
+	printf("; shtemp\n");
+	return 0;
+#if 0
+	int r;
+
+	if (p->n_op == STARG )
+		p = p->n_left;
+
+	switch (p->n_op) {
+	case REG:
+		return (!istreg(regno(p)));
+
+	case OREG:
+		r = regno(p);
+		if (R2TEST(r)) {
+			if (istreg(R2UPK1(r)))
+				return(0);
+			r = R2UPK2(r);
+		}
+		return (!istreg(r));
+
+	case UMUL:
+		p = p->n_left;
+		return (p->n_op != UMUL && shtemp(p));
+	}
+
+	if (optype(p->n_op) != LTYPE)
+		return(0);
+	return(1);
+#endif
+}
+
+void
+adrcon(CONSZ val)
+{
+	printf( CONFMT, val);
+}
+
+void
+conput(FILE *fp, NODE *p)
+{
+	int val = p->n_lval;
+
+	switch (p->n_op) {
+	case ICON:
+		if (p->n_name[0] != '\0') {
+			fprintf(fp, "%s", p->n_name);
+			if (val)
+				fprintf(fp, "+%d", val);
+		} else {
+			if (GCLASS(p->n_type) == CLASSB)
+				fprintf(fp, CONFMT, p->n_lval >> 32);
+			else
+				fprintf(fp, "%d", val);
+		}
+		return;
+
+	default:
+		comperr("illegal conput, p %p", p);
+	}
+}
+
+/*ARGSUSED*/
+void
+insput(NODE *p)
+{
+	comperr("insput");
+}
+
+/*
+ * Print lower or upper name of 64-bit register.
+ */
+static void
+reg64name(int reg, int hi)
+{
+	int idx;
+	int off = 0;
+
+	idx = (reg > R14R15 ? (2*(reg - R14R15) + R14) : (reg - R3R4 + R3));
+
+	if ((hi == HIREG && !features(FEATURE_BIGENDIAN)) ||
+	    (hi == LOWREG && features(FEATURE_BIGENDIAN)))
+		off = 1;
+		
+	fprintf(stdout, "%s" , rnames[idx + off]);
+}
+
+/*
+ * Write out the upper address, like the upper register of a 2-register
+ * reference, or the next memory location.
+ */
+void
+upput(NODE *p, int size)
+{
+	size /= SZCHAR;
+	switch (p->n_op) {
+	case REG:
+		reg64name(regno(p), HIREG);
+		break;
+
+	case NAME:
+	case OREG:
+		if (features(FEATURE_BIGENDIAN))
+			fprintf(stdout, "%d", (int)p->n_lval);
+		else
+			fprintf(stdout, "%d", (int)(p->n_lval + 4));
+		fprintf(stdout, "(%s)", rnames[regno(p)]);
+		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)
+{
+	/* 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:
+		if (DEUNSIGN(p->n_type) == LONGLONG &&
+		    features(FEATURE_BIGENDIAN))
+			fprintf(io, "%d", (int)(p->n_lval + 4));
+		else
+			fprintf(io, "%d", (int)p->n_lval);
+		fprintf(io, "(%s)", rnames[regno(p)]);
+		return;
+
+	case ICON:
+		/* addressable value of the constant */
+		conput(io, p);
+		return;
+
+	case REG:
+		if (GCLASS(regno(p)) == CLASSB)
+			reg64name(regno(p), LOWREG);
+		else
+			fprintf(io, "%s", rnames[regno(p)]);
+#if 0
+		switch (p->n_type) {
+		case DOUBLE:
+		case LDOUBLE:
+			if (features(FEATURE_HARDFLOAT)) {
+				fprintf(io, "%s", rnames[regno(p)]);
+				break;
+			}
+			/* FALL-THROUGH */
+		case LONGLONG:
+		case ULONGLONG:
+			reg64name(regno(p), LOWREG);
+			break;
+		default:
+			fprintf(io, "%s", rnames[regno(p)]);
+		}
+#endif
+		return;
+
+	default:
+		comperr("illegal address, op %d, node %p", p->n_op, p);
+		return;
+
+	}
+}
+
+/*
+ * these mnemonics match the order of the preprocessor decls
+ * EQ, NE, LE, LT, GE, GT, ULE, ULT, UGE, UGT
+ */
+
+static char *
+ccbranches[] = {
+	"beq",		/* branch if equal */
+	"bne",		/* branch if not-equal */
+	"ble",		/* branch if less-than-or-equal */
+	"blt",		/* branch if less-than */
+	"bge",		/* branch if greater-than-or-equal */
+	"bgt",		/* branch if greater-than */
+	/* what should these be ? */
+	"ble",		/* branch if less-than-or-equal */
+	"blt",		/* branch if less-than */
+	"bge",		/* branch if greater-than-or-equal */
+	"bgt",		/* branch if greater-than */
+
+};
+
+
+/*   printf conditional and unconditional branches */
+void
+cbgen(int o, int lab)
+{
+	if (o < EQ || o > UGT)
+		comperr("bad conditional branch: %s", opst[o]);
+	printf("\t%s " LABFMT "\n", ccbranches[o-EQ], lab);
+}
+
+static int
+argsize(NODE *p)
+{
+	TWORD t = p->n_type;
+
+	if (t < LONGLONG || t == FLOAT || t > BTMASK)
+		return 4;
+	if (t == LONGLONG || t == ULONGLONG)
+		return 8;
+	if (t == DOUBLE || t == LDOUBLE)
+		return 8;
+	if (t == STRTY || t == UNIONTY)
+		return p->n_stsize;
+	comperr("argsize");
+	return 0;
+}
+
+static int
+calc_args_size(NODE *p)
+{
+	int n = 0;
+        
+        if (p->n_op == CM) {
+                n += calc_args_size(p->n_left);
+                n += calc_args_size(p->n_right);
+                return n;
+        }
+
+        n += argsize(p);
+
+        return n;
+}
+
+
+static void
+fixcalls(NODE *p, void *arg)
+{
+	int n = 0;
+
+	switch (p->n_op) {
+	case STCALL:
+	case CALL:
+		n = calc_args_size(p->n_right);
+		if (n > p2maxstacksize)
+			p2maxstacksize = n;
+		/* FALLTHROUGH */
+	case USTCALL:
+	case UCALL:
+		++p2calls;
+		break;
+	case TEMP:
+		p2temps += argsize(p);
+		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, SPREG, t);
+			nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t));
+			p->n_left = mklnode(OREG, off, SPREG, t);
+                	DLIST_INSERT_BEFORE(ip, nip, qelem);
+		}
+		return l|r;
+
+	case UTYPE:
+		l = storefloat(ip, p->n_left);
+		if (callop(p->n_op))
+			l = 1;
+		return l;
+	default:
+		return 0;
+	}
+}
+
+void
+myreader(struct interpass *ipole)
+{
+	struct interpass *ip;
+
+	p2calls = 0;
+	p2temps = 0;
+	p2maxstacksize = 0;
+
+	DLIST_FOREACH(ip, ipole, qelem) {
+		if (ip->type != IP_NODE)
+			continue;
+		walkf(ip->ip_node, fixcalls, 0);
+		storefloat(ip, ip->ip_node);
+	}
+
+	if (p2maxstacksize < NARGREGS*SZINT/SZCHAR)
+		p2maxstacksize = NARGREGS*SZINT/SZCHAR;
+
+	p2framesize = ARGINIT/SZCHAR;		/* stack ptr / return addr */
+	p2framesize += 8;			/* for R31 and R30 */
+	p2framesize += p2maxautooff;		/* autos */
+	p2framesize += p2temps;			/* TEMPs that aren't autos */
+	if (p2calls != 0)
+		p2framesize += p2maxstacksize;	/* arguments to functions */
+	p2framesize += (ALSTACK/SZCHAR - 1);	/* round to 16-byte boundary */
+	p2framesize &= ~(ALSTACK/SZCHAR - 1);
+
+#if 0
+	printf("!!! MYREADER\n");
+	printf("!!! p2maxautooff = %d\n", p2maxautooff);
+	printf("!!! p2autooff = %d\n", p2autooff);
+	printf("!!! p2temps = %d\n", p2temps);
+	printf("!!! p2calls = %d\n", p2calls);
+	printf("!!! p2maxstacksize = %d\n", p2maxstacksize);
+#endif
+
+	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)
+{
+#ifdef PCC_DEBUG
+	if (x2debug) {
+		printf("myoptim\n");
+	}
+#endif
+}
+
+/*
+ * Move data between registers.  While basic registers aren't a problem,
+ * we have to handle the special case of overlapping composite registers.
+ * It might just be easier to modify the register allocator so that
+ * moves between overlapping registers isn't possible.
+ */
+void
+rmove(int s, int d, TWORD t)
+{
+	switch (t) {
+	case LDOUBLE:
+	case DOUBLE:
+		if (features(FEATURE_HARDFLOAT)) {
+			printf("\tfmr %s,%s" COM "rmove\n",
+			    rnames[d], rnames[s]);
+			break;
+		}
+		/* FALL-THROUGH */
+	case LONGLONG:
+	case ULONGLONG:
+		if (s == d+1) {
+			/* dh = sl, copy low word first */
+			printf("\tmr ");
+			reg64name(d, LOWREG);
+			printf(",");
+			reg64name(s, LOWREG);
+			printf("\n");
+			printf("\tmr ");
+			reg64name(d, HIREG);
+			printf(",");
+			reg64name(s, HIREG);
+			printf("\n");
+		} else {
+			/* copy high word first */
+			printf("\tmr ");
+			reg64name(d, HIREG);
+			printf(",");
+			reg64name(s, HIREG);
+			printf("\n");
+			printf("\tmr ");
+			reg64name(d, LOWREG);
+			printf(",");
+			reg64name(s, LOWREG);
+			printf("\n");
+		}
+		break;
+	case FLOAT:
+		if (features(FEATURE_HARDFLOAT)) {
+			printf("\tfmr %s,%s" COM "rmove\n",
+			    rnames[d], rnames[s]);
+			break;
+		}
+		/* FALL-THROUGH */
+	default:
+		printf("\tmr %s,%s" COM "rmove\n", rnames[d], rnames[s]);
+	}
+}
+
+/*
+ * For class c, find worst-case displacement of the number of
+ * registers in the array r[] indexed by class.
+ *
+ * On PowerPC, we have:
+ *
+ * 32 32-bit registers (2 reserved)
+ * 16 64-bit pseudo registers
+ * 32 floating-point registers
+ */
+int
+COLORMAP(int c, int *r)
+{
+	int num = 0;
+
+        switch (c) {
+        case CLASSA:
+                num += r[CLASSA];
+                num += 2*r[CLASSB];
+                return num < 30;
+        case CLASSB:
+                num += 2*r[CLASSB];
+                num += r[CLASSA];
+                return num < 16;
+	case CLASSC:
+		return num < 32;
+        case CLASSD:
+                return r[CLASSD] < DREGCNT;
+        }
+        return 0; /* XXX gcc */
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+	if (t == LONGLONG || t == ULONGLONG)
+		return CLASSB;
+	if (t == FLOAT || t == DOUBLE || t == LDOUBLE) {
+		if (features(FEATURE_HARDFLOAT))
+			return CLASSC;
+		if (t == FLOAT)
+			return CLASSA;
+		else
+			return CLASSB;
+	}
+	return CLASSA;
+}
+
+int
+retreg(int t)
+{
+	int c = gclass(t);
+	if (c == CLASSB)
+		return R3R4;
+	else if (c == CLASSC)
+		return F1;
+	return R3;
+}
+
+/*
+ * Calculate argument sizes.
+ */
+void
+lastcall(NODE *p)
+{
+	NODE *op = p;
+	int size = 0;
+
+#ifdef PCC_DEBUG
+	if (x2debug)
+		printf("lastcall:\n");
+#endif
+
+	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 += argsize(p->n_right);
+	size += argsize(p);
+	op->n_qual = size; /* XXX */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+	int o = p->n_op;
+
+	switch (shape) {
+	case SFUNCALL:
+		if (o == STCALL || o == USTCALL)
+			return SRREG;
+		break;
+	case SPCON:
+		if (o == ICON && p->n_name[0] == 0 && (p->n_lval & ~0x7fff) == 0)
+			return SRDIR;
+		break;
+	}
+	return SRNOPE;
+}
+
+static int fset = FEATURE_BIGENDIAN | FEATURE_HARDFLOAT;
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+	if (strcasecmp(str, "big-endian") == 0) {
+		fset |= FEATURE_BIGENDIAN;
+	} else if (strcasecmp(str, "little-endian") == 0) {
+		fset &= ~FEATURE_BIGENDIAN;
+	} else if (strcasecmp(str, "soft-float") == 0) {
+		fset &= ~FEATURE_HARDFLOAT;
+	} else if (strcasecmp(str, "hard-float") == 0) {
+		fset |= FEATURE_HARDFLOAT;
+	} else {
+		fprintf(stderr, "unknown m option '%s'\n", str);
+		exit(1);
+	}
+}
+
+int
+features(int mask)
+{
+	return ((fset & mask) == mask);
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+	return 0;
+}
Index: uspace/app/pcc/arch/powerpc/macdefs.h
===================================================================
--- uspace/app/pcc/arch/powerpc/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/powerpc/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,407 @@
+/*	$Id: macdefs.h,v 1.11 2010/11/26 17:06:31 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);
+
+/*
+ * Storage space requirements
+ */
+#define SZCHAR		8
+#define SZBOOL		32
+#define SZINT		32
+#define SZFLOAT		32
+#define SZDOUBLE	64
+#ifdef ELFABI
+#define SZLDOUBLE	96
+#else
+#define SZLDOUBLE	128
+#endif
+#define SZLONG		32
+#define SZSHORT		16
+#define SZLONGLONG	64
+#define SZPOINT(t)	32
+
+/*
+ * Alignment constraints
+ */
+#define ALCHAR		8
+#define ALBOOL		32
+#define ALINT		32
+#define ALFLOAT		32
+#define ALDOUBLE	32
+#ifdef ELFABI
+#define ALLDOUBLE	32
+#else
+#define ALLDOUBLE	128
+#endif
+#define ALLONG		32
+#ifdef ELFABI
+#define ALLONGLONG	64
+#else
+#define ALLONGLONG	32
+#endif
+#define ALSHORT		16
+#define ALPOINT		32
+#define ALSTRUCT	32
+#define ALSTACK		(16*SZCHAR)
+
+/*
+ * Min/max values.
+ */
+#define	MIN_CHAR	-128
+#define	MAX_CHAR	127
+#define	MAX_UCHAR	255
+#define	MIN_SHORT	-32768
+#define	MAX_SHORT	32767
+#define	MAX_USHORT	65535
+#define	MIN_INT		-1
+#define	MAX_INT		0x7fffffff
+#define	MAX_UNSIGNED	0xffffffff
+#define	MIN_LONG	MIN_INT
+#define	MAX_LONG	MAX_INT
+#define	MAX_ULONG	MAX_UNSIGNED
+#define	MIN_LONGLONG	0x8000000000000000LL
+#define	MAX_LONGLONG	0x7fffffffffffffffLL
+#define	MAX_ULONGLONG	0xffffffffffffffffULL
+
+#define CHAR_UNSIGNED
+#define	BOOL_TYPE	INT	/* 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 REGPREFIX	"%"	/* format for printing registers */
+#elif defined(MACHOABI)
+#define LABFMT	"L%d"		/* format for printing labels */
+#define REGPREFIX
+#else
+#error undefined ABI
+#endif
+#define	STABLBL	"LL%d"		/* format for stab (debugging) labels */
+
+#ifdef MACHOABI
+#define STAB_LINE_ABSOLUTE	/* S_LINE fields use absolute addresses */
+#endif
+
+#undef	FIELDOPS		/* no bit-field instructions */
+
+#define ENUMSIZE(high,low) INT	/* enums are always stored in full int */
+
+/* Definitions mostly used in pass2 */
+
+#define BYTEOFF(x)	((x)&03)
+#define BITOOR(x)	(x)	/* bit offset to oreg offset XXX die! */
+
+#define	szty(t)	(((t) == DOUBLE || (t) == LDOUBLE || \
+	DEUNSIGN(t) == LONGLONG) ? 2 : 1)
+
+/*
+ * The PPC register definition are taken from apple docs.
+ *
+ * The classes used are:
+ *	A - general registers
+ *	B - 64-bit register pairs
+ *	C - floating-point registers
+ */
+
+#define R0	0	/* scratch register */
+#define R1	1	/* stack base pointer */
+#define R2	2
+#define R3	3	/* return register / argument 0 */
+#define R4	4	/* return register (for longlong) / argument 1 */
+#define R5	5	/* scratch register / argument 2 */
+#define R6	6	/* scratch register / argument 3 */
+#define R7	7	/* scratch register / argument 4 */
+#define R8	8	/* scratch register / argument 5 */
+#define R9	9	/* scratch register / argument 6 */
+#define R10	10	/* scratch register / argument 7 */
+#define R11	11	/* scratch register */
+#define R12	12	/* scratch register */
+#define R13	13
+#define R14	14
+#define R15	15
+#define R16	16
+#define R17	17
+#define R18	18
+#define R19	19
+#define R20	20
+#define R21	21
+#define R22	22
+#define R23	23
+#define R24	24
+#define R25	25
+#define R26	26
+#define R27	27
+#define R28	28
+#define R29	29
+#define R30	30
+#define R31	31
+
+#define R3R4	32
+#define R4R5	33
+#define R5R6	34
+#define R6R7	35
+#define R7R8	36
+#define R8R9	37
+#define R9R10	38
+#define R14R15	39
+#define R16R17	40
+#define R18R19	41
+#define R20R21	42
+#define R22R23	43
+#define R24R25	44
+#define R26R27	45
+#define R28R29	46
+#define R30R31	47
+
+#define F0	48	/* scratch register */
+#define F1	49	/* return value 0 / argument 0 */
+#define F2	50	/* return value 1 / argument 1 */
+#define F3	51	/* return value 2 / argument 2 */
+#define F4	52	/* return value 3 / argument 3 */
+#define F5	53	/* argument 4 */
+#define F6	54	/* argument 5 */
+#define F7	55	/* argument 6 */
+#define F8	56	/* argument 7 */
+#define F9	57	/* argument 8 */
+#define F10	58	/* argument 9 */
+#define F11	59	/* argument 10 */
+#define F12	60	/* argument 11 */
+#define F13	61	/* argument 12 */
+#define F14	62
+#define F15	63
+#define F16	64
+#define F17	65
+#define F18	66
+#define F19	67
+#define F20	68
+#define F21	69
+#define F22	70
+#define F23	71
+#define F24	72
+#define F25	73
+#define F26	74
+#define F27	75
+#define F28	76
+#define F29	77
+#define F30	78
+#define F31	79
+
+#define NUMCLASS 3
+#define	MAXREGS	64		/* XXX cannot have more than 64 */
+
+#define RSTATUS 				\
+	0,			/* R0 */	\
+	0,			/* R1 */	\
+	SAREG|TEMPREG,		/* R2 */	\
+	SAREG|TEMPREG,		/* R3 */	\
+	SAREG|TEMPREG,		/* R4 */	\
+	SAREG|TEMPREG,		/* R5 */	\
+	SAREG|TEMPREG,		/* R6 */	\
+	SAREG|TEMPREG,		/* R7 */	\
+	SAREG|TEMPREG,		/* R8 */	\
+	SAREG|TEMPREG,		/* R9 */	\
+	SAREG|TEMPREG,		/* R10 */	\
+	SAREG|TEMPREG,		/* R11 */	\
+	SAREG|TEMPREG,		/* R12 */	\
+	SAREG,			/* R13 */	\
+	SAREG,			/* R14 */	\
+	SAREG,			/* R15 */	\
+	SAREG,			/* R16 */	\
+	SAREG,			/* R17 */	\
+	SAREG,			/* R18 */	\
+	SAREG,			/* R19 */	\
+	SAREG,			/* R20 */	\
+	SAREG,			/* R21 */	\
+	SAREG,			/* R22 */	\
+	SAREG,			/* R23 */	\
+	SAREG,			/* R24 */	\
+	SAREG,			/* R25 */	\
+	SAREG,			/* R26 */	\
+	SAREG,			/* R27 */	\
+	SAREG,			/* R28 */	\
+	SAREG,			/* R29 */	\
+	SAREG,			/* R30 */	\
+	SAREG,			/* R31 */	\
+	\
+        SBREG|TEMPREG,		/* R3R4 */	\
+	SBREG|TEMPREG,		/* R4R5 */	\
+	SBREG|TEMPREG,		/* R5R6 */	\
+	SBREG|TEMPREG,		/* R6R7 */	\
+        SBREG|TEMPREG,		/* R7R8 */	\
+	SBREG|TEMPREG,		/* R8R9 */	\
+	SBREG|TEMPREG,		/* R9R10 */	\
+	\
+	SBREG,			/* R14R15 */	\
+	SBREG,			/* R16R17 */	\
+	SBREG,			/* R18R19 */	\
+	SBREG,			/* R20R21 */	\
+	SBREG,			/* R22R23 */	\
+	SBREG,			/* R24R25 */	\
+	SBREG,			/* R26R2k */	\
+	SBREG,			/* R28R29 */	\
+	SBREG, 			/* R30R31 */	\
+	\
+	SCREG|TEMPREG,		/* F0 */	\
+	SCREG|TEMPREG,		/* F1 */	\
+	SCREG|TEMPREG,		/* F2 */	\
+	SCREG|TEMPREG,		/* F3 */	\
+	SCREG|TEMPREG,		/* F4 */	\
+	SCREG|TEMPREG,		/* F5 */	\
+	SCREG|TEMPREG,		/* F6 */	\
+	SCREG|TEMPREG,		/* F7 */	\
+	SCREG|TEMPREG,		/* F8 */	\
+	SCREG|TEMPREG,		/* F9 */	\
+	SCREG|TEMPREG,		/* F10 */	\
+	SCREG|TEMPREG,		/* F11 */	\
+	SCREG|TEMPREG,		/* F12 */	\
+	SCREG|TEMPREG,		/* F13 */	\
+	SCREG,			/* F14 */	\
+	SCREG,			/* F15 */	\
+
+#define ROVERLAP \
+	{ -1 }, { -1 }, { -1 },			\
+	{ R3R4,       -1 }, { R3R4, R4R5, -1 },	\
+	{ R4R5, R5R6, -1 }, { R5R6, R6R7, -1 },	\
+	{ R6R7, R7R8, -1 }, { R7R8, R8R9, -1 },	\
+	{ R8R9, R9R10, -1 }, { R9R10, -1 },	\
+	{ -1 }, { -1 }, { -1 },			\
+	{ R14R15, -1 }, { R14R15, -1 }, 	\
+	{ R16R17, -1 }, { R16R17, -1 },		\
+	{ R18R19, -1 }, { R18R19, -1 }, 	\
+	{ R20R21, -1 }, { R20R21, -1 },		\
+	{ R22R23, -1 }, { R22R23, -1 }, 	\
+	{ R24R25, -1 }, { R24R25, -1 },		\
+	{ R26R27, -1 }, { R26R27, -1 }, 	\
+	{ R28R29, -1 }, { R28R29, -1 },		\
+	{ R30R31, -1 }, { R30R31, -1 }, 	\
+	\
+	{ R3, R4,       R4R5, -1 }, { R4, R5, R3R4, R5R6, -1 },	\
+	{ R5, R6, R4R5, R6R7, -1 }, { R6, R7, R5R6, R7R8, -1 },	\
+	{ R7, R8, R6R7, R8R9, -1 }, { R8, R9, R7R8, R8R9, -1 }, \
+	{ R9, R10, R8R9,      -1 }, 	\
+	{ R14, R15, -1 }, { R16, R17, -1 },	\
+	{ R18, R19, -1 }, { R20, R21, -1 }, 	\
+	{ R22, R23, -1 }, { R24, R25, -1 },	\
+	{ R26, R27, -1 }, { R28, R29, -1 }, 	\
+	{ R30, R31, -1 },		\
+	\
+	{ -1 }, { -1 }, { -1 }, { -1 },		\
+	{ -1 }, { -1 }, { -1 }, { -1 },		\
+	{ -1 }, { -1 }, { -1 }, { -1 },		\
+	{ -1 }, { -1 }, { -1 }, { -1 },		\
+
+/*
+ * According to the ABI documents, there isn't really a frame pointer;
+ * all references to data on the stack (autos and parameters) are
+ * indexed relative to the stack pointer.  However, pcc isn't really
+ * capable of running in this manner, and expects a frame pointer.
+ */
+#define SPREG   R1	/* stack pointer */
+#define FPREG   R30	/* frame pointer */
+#define GOTREG	R31	/* global offset table (PIC) */
+
+#ifdef FPREG
+#define ARGINIT		(24*8)	/* # bits above fp where arguments start */
+#define AUTOINIT	(8*8)	/* # bits above fp where automatics start */
+#define BACKAUTO 		/* stack grows negatively for automatics */
+#define BACKTEMP 		/* stack grows negatively for temporaries */
+#else
+#define ARGINIT		(24*8)	/* # bits above fp where arguments start */
+#define AUTOINIT	(56*8)	/* # bits above fp where automatics start */
+#endif
+
+/* Return a register class based on the type of the node */
+#define PCLASS(p)	(1 << gclass((p)->n_type))
+
+#define GCLASS(x)	((x) < 32 ? CLASSA : ((x) < 48 ? CLASSB : CLASSC))
+#define DECRA(x,y)	(((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define ENCRA(x,y)	((x) << (6+y*6))        /* encode regs in int */
+#define ENCRD(x)	(x)		/* Encode dest reg in n_reg */
+#define RETREG(x)	retreg(x)
+
+int COLORMAP(int c, int *r);
+int retreg(int ty);
+
+#define	SHSTR		(MAXSPECIAL+1)	/* short struct */
+#define	SFUNCALL	(MAXSPECIAL+2)	/* struct assign after function call */
+#define SPCON		(MAXSPECIAL+3)  /* positive constant */
+
+int features(int f);
+#define FEATURE_BIGENDIAN	0x00010000
+#define FEATURE_PIC		0x00020000
+#define FEATURE_HARDFLOAT	0x00040000
+
+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);
+
+#define TARGET_STDARGS
+#define TARGET_BUILTINS							\
+	{ "__builtin_stdarg_start", powerpc_builtin_stdarg_start },	\
+	{ "__builtin_va_arg", powerpc_builtin_va_arg },			\
+	{ "__builtin_va_end", powerpc_builtin_va_end },			\
+	{ "__builtin_va_copy", powerpc_builtin_va_copy },		\
+	{ "__builtin_frame_address", powerpc_builtin_frame_address },	\
+	{ "__builtin_return_address", powerpc_builtin_return_address },
+
+#define NODE struct node
+struct node;
+NODE *powerpc_builtin_stdarg_start(NODE *f, NODE *a, unsigned int);
+NODE *powerpc_builtin_va_arg(NODE *f, NODE *a, unsigned int);
+NODE *powerpc_builtin_va_end(NODE *f, NODE *a, unsigned int);
+NODE *powerpc_builtin_va_copy(NODE *f, NODE *a, unsigned int);
+NODE *powerpc_builtin_frame_address(NODE *f, NODE *a, unsigned int);
+NODE *powerpc_builtin_return_address(NODE *f, NODE *a, unsigned int);
+#undef NODE
+
+#define NARGREGS	8
+
+#ifdef ELFABI
+#define COM     "       # "
+#else
+#define COM     "       ; "
+#endif
Index: uspace/app/pcc/arch/powerpc/order.c
===================================================================
--- uspace/app/pcc/arch/powerpc/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/powerpc/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,408 @@
+/*	$Id: order.c,v 1.8 2009/01/07 11:44:03 gmcgarry 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 <assert.h>
+
+# include "pass2.h"
+
+#include <string.h>
+
+int canaddr(NODE *);
+
+/*
+ * Check size of offset in OREG.  Called by oregok() to see if an
+ * OREG can be generated.
+ *
+ * returns 0 if it can, 1 otherwise.
+ */
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+#if 0
+	if (off >= 32767 || off <= -32768)
+		printf("; notoff %lld TOO BIG!\n", off);
+#endif
+	if (cp && cp[0]) return 1;
+	return (off >= 32768 || off <= -32769);
+}
+
+/*
+ * Generate instructions for an OREG.
+ * Called by swmatch().
+ */
+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;
+		}
+	}
+	(void)geninsn(p, INAREG);
+}
+
+/*
+ * Unable to convert to OREG (notoff() returned failure).  Output
+ * suitable instructions to replace OREG.
+ */
+void
+myormake(NODE *q)
+{
+	NODE *p;
+
+	if (x2debug)
+		printf("myormake(%p)\n", q);
+
+        p = q->n_left;
+
+	/*
+	 * This handles failed OREGs conversions, due to the offset
+	 * being too large for an OREG.
+	 */
+	if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_right->n_op == ICON) {
+		if (isreg(p->n_left) == 0)
+			(void)geninsn(p->n_left, INAREG);
+		if (isreg(p->n_right) == 0)
+			(void)geninsn(p->n_right, INAREG);
+		(void)geninsn(p, INAREG);
+	} else if (p->n_op == REG) {
+		q->n_op = OREG;
+		q->n_lval = p->n_lval;
+		q->n_rval = p->n_rval;
+		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)
+{
+	if (x2debug)
+		printf("nspecial: op=%d, visit=0x%x: %s", q->op, q->visit, q->cstring);
+
+	switch (q->op) {
+
+	/* soft-float stuff */
+        case RS:
+        case LS:
+                if (q->lshape == SBREG) {
+                        static struct rspecial s[] = {
+                                { NLEFT, R3R4 },
+                                { NRIGHT, R5 },
+                                { NRES, R3R4 },
+                                { 0 },
+                        };
+                        return s;
+                } else if (q->lshape == SAREG) {
+                        static struct rspecial s[] = {
+                                { NLEFT, R3 },
+                                { NRIGHT, R4 },
+                                { NRES, R3 },
+                                { 0 },
+                        };
+                        return s;
+                }
+
+		cerror("nspecial LS/RS");
+		break;
+
+	case UMINUS:
+	case SCONV:
+		if (q->lshape == SBREG && q->rshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R3R4 },
+				{ NRES, R3 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SAREG && q->rshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R3 },
+				{ NRES, R3R4 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SAREG && q->rshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R3 },
+				{ NRES, R3 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SBREG && q->rshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R3R4 },
+				{ NRES, R3R4 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SCREG && q->rshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, F1 },
+				{ NEVER, F0 }, /* stomped on */
+				{ NRES, R3R4 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SBREG && q->rshape == SCREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R3R4 },
+				{ NEVER, F0 }, /* stomped on */
+				{ NRES, F1 },
+				{ 0 }
+			};
+			return s;
+		} else {
+			static struct rspecial s[] = {
+				{ NOLEFT, R0 },
+				{ 0 } };
+			return s;
+		}
+
+		break;
+
+	case OPLOG:
+		if (q->lshape == SBREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R3R4 },
+				{ NRIGHT, R5R6 },
+				{ NRES, R3 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NLEFT, R3 },
+				{ NRIGHT, R4 },
+				{ NRES, R3 },
+				{ 0 }
+			};
+			return s;
+		}
+
+		cerror("nspecial oplog");
+		break;
+
+	case PLUS:
+	case MINUS:
+	case MUL:
+	case DIV:
+	case MOD:
+		if (q->lshape == SBREG && 
+		    (q->ltype & (TDOUBLE|TLDOUBLE|TLONGLONG|TULONGLONG))) {
+			static struct rspecial s[] = {
+				{ NLEFT, R3R4 },
+				{ NRIGHT, R5R6 },
+				{ NRES, R3R4 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SAREG && q->ltype & TFLOAT) {
+			static struct rspecial s[] = {
+				{ NLEFT, R3 },
+				{ NRIGHT, R4 },
+				{ NRES, R3 },
+				{ 0 }
+			};
+			return s;
+		} else if (q->lshape == SAREG) {
+			static struct rspecial s[] = {
+				{ NOLEFT, R0 },
+				{ 0 } };
+			return s;
+		}
+
+		cerror("nspecial mul");
+		break;
+
+	case STASG:
+		{
+			static struct rspecial s[] = {
+				{ NEVER, R3 },
+				{ NRIGHT, R4 },
+				{ NEVER, R5 },
+				{ 0 } };
+			return s;
+		}
+		break;
+
+	case OPLTYPE:
+		{
+			if (q->visit & SAREG) {
+				static struct rspecial s[] = {
+					{ NEVER, R0 },
+					{ 0 } };
+				return s;
+			}
+		}
+		break;
+
+	case ASSIGN:
+		if (q->lshape & SNAME) {
+			static struct rspecial s[] = {
+				{ NEVER, R0 },
+				{ 0 } };
+			return s;
+		} else if (q->rshape & SNAME) {
+			static struct rspecial s[] = {
+				{ NOLEFT, R0 },
+				{ 0 } };
+			return s;
+		} else if (q->lshape & SOREG) {
+			static struct rspecial s[] = {
+				{ NOLEFT, R0 },
+				{ 0 } };
+			return s;
+		} else if (q->rshape & SOREG) {
+			static struct rspecial s[] = {
+				{ NORIGHT, R0 },
+				{ 0 } };
+			return s;
+		}
+		/* fallthough */
+
+	case UMUL:
+	case AND:
+	case OR:
+	case ER:
+		{
+			static struct rspecial s[] = {
+				{ NOLEFT, R0 },
+				{ 0 } };
+			return s;
+		}
+
+	default:
+		break;
+	}
+
+	comperr("nspecial entry %d: %s", q - table, q->cstring);
+	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 "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+	static int r[] = { R10, R9, R8, R7, R6, R5, R4, R3, R30, R31, -1 };
+	int num = 1;
+
+        if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+                return &r[8-0];
+
+        for (p = p->n_right; p->n_op == CM; p = p->n_left)
+                num += szty(p->n_right->n_type);
+        num += szty(p->n_right->n_type);
+
+        num = (num > 8 ? 8 : num);
+
+        return &r[8 - num];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+	if ((op->visit & FEATURE_PIC) != 0)
+		return (kflag != 0);
+	return features(op->visit & 0xffff0000);
+}
Index: uspace/app/pcc/arch/powerpc/table.c
===================================================================
--- uspace/app/pcc/arch/powerpc/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/powerpc/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1806 @@
+/*	$Id: table.c,v 1.18 2010/11/26 17:06:31 ragge Exp $	*/
+/*-
+ * Copyright (c) 2007 Gregory McGarry <g.mcgarry@ieee.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * A template has five logical sections:
+ *
+ *	1) subtree (operator); goal to achieve (cookie)
+ *	2) left node descendent of operator (node class; type)
+ *	3) right node descendent of operator (node class; type)
+ *	4) resource requirements (number of scratch registers);
+ *	   subtree rewriting rule
+ *	5) emitted instructions
+ */
+
+#include "pass2.h"
+
+#define TUWORD	TUNSIGNED|TULONG
+#define TSWORD	TINT|TLONG
+#define TWORD	TUWORD|TSWORD
+
+#if defined(ELFABI)
+#define HA16(x)	# x "@ha"
+#define LO16(x)	# x "@l"
+#elif defined(MACHOABI)
+#define HA16(x)	"ha16(" # x ")"
+#define LO16(x)	"lo16(" # x ")"
+#else
+#error undefined ABI
+#endif
+
+struct optab table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+/* PCONVs are not necessary */
+{ PCONV,	INAREG,
+	SAREG,	TWORD|TPOINT,
+	SAREG,	TWORD|TPOINT,
+		0,	RLEFT,
+		COM "pointer conversion\n", },
+
+/*
+ * Conversions of integral types
+ */
+
+{ SCONV,	INAREG,
+	SAREG,	TCHAR|TUCHAR,
+	SAREG,	TCHAR|TUCHAR,
+		0,	RLEFT,
+		COM "convert between (u)char and (u)char\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SAREG,	TSHORT|TUSHORT,
+		0,	RLEFT,
+		COM "convert between (u)short and (u)short\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TPOINT|TWORD,
+	SAREG,	TWORD,
+		0,	RLEFT,
+		COM "convert a pointer/word to an int\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TPOINT,
+	SAREG,	TPOINT,
+		0,	RLEFT,
+		COM "convert pointers\n", },
+
+{ SCONV,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		0,	RLEFT,
+		COM "convert (u)longlong to (u)longlong\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TCHAR,
+	SAREG,	TSHORT|TSWORD,
+		NASL|NAREG,	RESC1,
+		"	extsb A1,AL" COM "convert char to short/int\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUCHAR,
+	SAREG,	TSHORT|TSWORD,
+		0,	RLEFT,
+		COM "convert uchar to short/int\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUCHAR,
+	SAREG,	TUSHORT|TUWORD,
+		0,	RLEFT,
+		COM "convert uchar to ushort/unsigned\n", },
+
+/* XXX is this necessary? */
+{ SCONV,	INAREG,
+	SAREG,	TCHAR,
+	SAREG,	TUSHORT|TUWORD,
+		NSPECIAL|NAREG|NASL,	RESC1,
+		"	extsb A1,AL" COM "convert char to ushort/unsigned\n", },
+
+{ SCONV,	INBREG | FEATURE_BIGENDIAN,
+	SAREG,	TUCHAR|TUSHORT|TUNSIGNED,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG,		RESC1,
+		"	mr U1,AL" COM "convert uchar/ushort/uint to (u)longlong\n"
+		"	li A1,0\n", },
+
+{ SCONV,	INBREG,
+	SAREG,	TUCHAR|TUSHORT|TUNSIGNED,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG,		RESC1,
+		"	mr A1,AL" COM "convert uchar/ushort/uint to (u)longlong\n"
+		"	li U1,0\n", },
+
+{ SCONV,	INBREG | FEATURE_BIGENDIAN,
+	SAREG,	TCHAR|TSHORT|TSWORD,
+	SBREG,	TULONGLONG|TLONGLONG,
+		NBREG,		RESC1,
+		"	mr U1,AL" COM "convert char/short/int to ulonglong\n"
+		"	srawi A1,AL,31\n", },
+
+{ SCONV,	INBREG,
+	SAREG,	TCHAR|TSHORT|TSWORD,
+	SBREG,	TULONGLONG|TLONGLONG,
+		NBREG,		RESC1,
+		"	mr A1,AL" COM "convert char/short/int to ulonglong\n"
+		"	srawi U1,AL,31\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSHORT|TUSHORT,
+	SAREG,	TCHAR|TUCHAR,
+		NSPECIAL|NAREG|NASL,	RESC1,
+		"	andi. A1,AL,255" COM "convert (u)short to (u)char\n", },
+
+/* XXX is this really necessary? */
+{ SCONV,	INAREG,
+	SAREG,	TSHORT,
+	SAREG,	TWORD,
+		NAREG|NASL,	RESC1,
+		"	extsh A1,AL" COM "convert short to int\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUSHORT,
+	SAREG,	TWORD,
+		NSPECIAL|NAREG|NASL,	RESC1,
+		COM "convert ushort to word\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TWORD,
+	SAREG,	TCHAR|TUCHAR,
+		NAREG|NASL|NSPECIAL,	RESC1,
+		"	andi. A1,AL,255" COM "convert (u)int to (u)char\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TWORD,
+	SAREG,	TSHORT|TUSHORT,
+		NAREG|NASL|NSPECIAL,	RESC1,
+		"	andi. A1,AL,65535" COM "convert (u)int to (u)short\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TCHAR|TUCHAR,
+		NAREG|NSPECIAL,	RESC1,
+		"	andi. A1,AL,255" COM "(u)longlong to (u)char\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TSHORT|TUSHORT,
+		NAREG|NSPECIAL,	RESC1,
+		"	andi. A1,AL,65535" COM "(u)longlong to (u)short\n", },
+
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TWORD,
+		NAREG,		RESC1,
+		"	mr A1,AL" COM "convert (u)longlong to (u)int/long\n", },
+
+/* conversions on load from memory */
+
+{ SCONV,	INAREG,
+	SOREG,	TCHAR,
+	SAREG,	TWORD,
+		NASL|NAREG|NSPECIAL,	RESC1,
+		"	lbz A1,AL" COM "convert char to int/long\n"
+		"	extsb A1,A1\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TUCHAR,
+	SAREG,	TWORD,
+		NASL|NAREG|NSPECIAL,	RESC1,
+		"	lbz A1,AL" COM "convert uchar to int/long\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TSHORT,
+	SAREG,	TWORD,
+		NASL|NAREG|NSPECIAL,	RESC1,
+		"	lha A1,AL" COM "convert short to int/long\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TUSHORT,
+	SAREG,	TWORD,
+		NASL|NAREG|NSPECIAL,	RESC1,
+		"	lhz A1,AL" COM "convert ushort to int/long\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TCHAR|TUCHAR,
+		NAREG|NSPECIAL,	RESC1,
+		"	lwz A1,AL" COM "(u)longlong to (u)char\n"
+		"	andi. A1,A1,255\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TSHORT|TUSHORT,
+		NAREG|NSPECIAL,	RESC1,
+		"	lwz A1,AL" COM "(u)longlong to (u)short\n"
+		"	andi. A1,A1,65535\n", },
+
+{ SCONV,	INAREG,
+	SOREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TWORD,
+		NAREG|NSPECIAL,	RESC1,
+		"	lwz A1,AL" COM "(u)longlong to (u)int\n", },
+
+/*
+ * floating-point conversions
+ *
+ * There doesn't appear to be an instruction to move values between
+ * the floating-point registers and the general-purpose registers.
+ * So values are bounced into memory...
+ */
+
+{ SCONV,	INCREG | FEATURE_HARDFLOAT,
+	SCREG,	TFLOAT,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		0,	RLEFT,
+		COM "convert float to (l)double\n", },
+
+/* soft-float */
+{ SCONV,	INBREG,
+	SAREG,	TFLOAT,
+	SBREG,	TDOUBLE|TLDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+{ SCONV,	INCREG | FEATURE_HARDFLOAT,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	frsp A1,AL" COM "convert (l)double to float\n", },
+
+/* soft-float */
+{ SCONV,	INAREG,
+	SBREG,	TDOUBLE|TLDOUBLE,
+	SAREG,	TFLOAT,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+
+{ SCONV,	INCREG | FEATURE_HARDFLOAT,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		0,	RLEFT,
+		COM "convert (l)double to (l)double\n", },
+
+/* soft-float */
+{ SCONV,	INBREG,
+	SBREG,	TDOUBLE|TLDOUBLE,
+	SBREG,	TDOUBLE|TLDOUBLE,
+		0,	RLEFT,
+		COM "convert (l)double to (l)double (soft-float)\n", },
+
+{ SCONV,	INCREG | FEATURE_HARDFLOAT,
+	SAREG,	TWORD,
+	SCREG,	TFLOAT|TDOUBLE|TLDOUBLE,
+		2*NCREG|NAREG,	RESC3,
+		"ZC", },
+
+/* soft-float */
+{ SCONV,	INAREG,
+	SAREG,	TWORD,
+	SAREG,	TFLOAT,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+
+/* soft-float */
+{ SCONV,	INBREG,
+	SAREG,	TWORD,
+	SBREG,	TDOUBLE|TLDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+{ SCONV,	INAREG | FEATURE_HARDFLOAT,
+	SOREG,	TFLOAT|TDOUBLE|TLDOUBLE,
+	SAREG,	TWORD,
+		2*NCREG|NAREG,	RESC1,
+		"ZC", },
+
+/* soft-float */
+{ SCONV,	INAREG,
+	SAREG,	TFLOAT,
+	SAREG,	TWORD,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+
+/* soft-float */
+{ SCONV,	INAREG,
+	SBREG,	TDOUBLE|TLDOUBLE,
+	SAREG,	TWORD,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+	
+{ SCONV,	INCREG | FEATURE_HARDFLOAT,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCREG,	TFLOAT|TDOUBLE|TLDOUBLE,
+		NSPECIAL|NCREG,	RESC1,
+		"ZF", },
+
+/* soft-float */
+{ SCONV,	INAREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TFLOAT,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+
+/* soft-float */
+{ SCONV,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TDOUBLE|TLDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+{ SCONV,	INBREG | FEATURE_HARDFLOAT,
+	SCREG,	TFLOAT|TDOUBLE|TLDOUBLE,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+/* soft-float */
+{ SCONV,	INBREG,
+	SAREG,	TFLOAT,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+/* soft-float */
+{ SCONV,	INBREG,
+	SBREG,	TDOUBLE|TLDOUBLE,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,		FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	bl CL" COM "call (args, no result) to scon\n", },
+
+{ UCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	bl CL" COM "call (no args, no result) to scon\n", },
+
+{ CALL,		INAREG,
+	SCON,	TANY,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (args, result) to scon\n", },
+
+{ UCALL,	INAREG,
+	SCON,	TANY,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (no args, result) to scon\n", },
+
+{ CALL,		INBREG,
+	SCON,	TANY,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (args, result) to scon\n", },
+
+{ UCALL,	INBREG,
+	SCON,	TANY,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (no args, result) to scon\n", },
+
+{ CALL,		INCREG | FEATURE_HARDFLOAT,
+	SCON,	TANY,
+	SCREG,	TFLOAT|TDOUBLE|TLDOUBLE,
+		NCREG|NCSL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (args, result) to scon\n", },
+
+{ UCALL,	INCREG | FEATURE_HARDFLOAT,
+	SCON,	TANY,
+	SCREG,	TFLOAT|TDOUBLE|TLDOUBLE,
+		NCREG|NCSL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (no args, result) to scon\n", },
+
+{ CALL,		INAREG,
+	SCON,	TANY,
+	SAREG,	TFLOAT,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (args, result) to scon\n", },
+
+{ UCALL,	INAREG,
+	SCON,	TANY,
+	SAREG,	TFLOAT,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (no args, result) to scon\n", },
+
+{ CALL,		INBREG,
+	SCON,	TANY,
+	SBREG,	TDOUBLE|TLDOUBLE,
+		NBREG|NBSL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (args, result) to scon\n", },
+
+{ UCALL,	INBREG,
+	SCON,	TANY,
+	SBREG,	TDOUBLE|TLDOUBLE,
+		NBREG|NBSL,	RESC1,	/* should be 0 */
+		"	bl CL" COM "call (no args, result) to scon\n", },
+
+
+
+{ CALL,		FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	mtctr AL" COM "call (args, no result) to reg\n"
+		"	bctrl\n", },
+
+{ UCALL,	FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	mtctr AL" COM "call (no args, no result) to reg\n"
+		"	bctrl\n", },
+
+{ CALL,		INAREG,
+	SAREG,	TANY,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG,	RESC1,
+		"	mtctr AL" COM "call (args, result) to reg\n"
+		"	bctrl\n", },
+
+{ UCALL,	INAREG,
+	SAREG,	TANY,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG,	RESC1,
+		"	mtctr AL" COM "call (no args, result) to reg\n"
+		"	bctrl\n", },
+
+/* struct return */
+{ USTCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	bl CL\n", },
+
+{ USTCALL,	INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	bl CL\n", },
+
+{ USTCALL,	INAREG,
+	SAREG,	TANY,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG,	RESC1,
+		"	mtctr AL"
+		"	bctrl\n", },
+
+{ STCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	bl CL\n", },
+
+{ STCALL,	INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	bl CL\n", },
+
+{ STCALL,	INAREG,
+	SAREG,	TANY,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	mtctr AL"
+		"	bctrl\n", },
+
+/*
+ * The next rules handle all binop-style operators.
+ */
+
+/* XXX AL cannot be R0 */
+{ PLUS,		INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SSCON,	TANY,
+		NAREG|NASL|NSPECIAL,	RESC1,
+		"	addi A1,AL,AR" COM "addition of constant\n", },
+
+/* XXX AL cannot be R0 */
+{ PLUS,		INAREG|FORCC,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SSCON,	TANY,
+		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
+		"	addic. A1,AL,AR" COM "addition of constant\n", },
+
+{ PLUS,		INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SSCON,	TANY,
+		NBREG|NBSL,	RESC1,
+		"	addic A1,AL,AR" COM "64-bit addition of constant\n"
+		"	addze U1,UL\n", },
+
+{ PLUS,		INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL|NSPECIAL,	RESC1,
+		"	add A1,AL,AR\n", },
+
+{ PLUS,		INAREG|FORCC,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
+		"	add. A1,AL,AR\n", },
+
+{ PLUS,		INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,
+		"	addc A1,AL,AR" COM "64-bit add\n"
+		"	adde U1,UL,UR\n", },
+
+{ PLUS,		INCREG | FEATURE_HARDFLOAT,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NCREG,		RESC1,
+		"	fadds A1,AL,AR" COM "float add\n", },
+
+{ PLUS,		INAREG,
+	SAREG,	TFLOAT,
+	SAREG,	TFLOAT,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+
+{ PLUS,		INCREG | FEATURE_HARDFLOAT,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		NCREG|NCSL,	RESC1,
+		"	fadd A1,AL,AR" COM "(l)double add\n", },
+
+/* soft-float */
+{ PLUS,		INBREG,
+	SBREG,	TDOUBLE|TLDOUBLE,
+	SBREG,	TDOUBLE|TLDOUBLE,
+		NSPECIAL|NBREG|NBSL,	RESC1,
+		"ZF", },
+
+{ MINUS,	INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SSCON,	TANY,
+		NAREG|NASL|NSPECIAL,	RESC1,
+		"	addi A1,AL,-AR\n", },
+
+{ MINUS,	INAREG|FORCC,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SSCON,	TANY,
+		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
+		"	addic. A1,AL,-AR\n", },
+
+{ MINUS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SSCON,	TANY,
+		NBREG|NBSL,	RESC1,
+		"	addic A1,AL,-AR\n"
+		"	addme U1,UL\n", },
+
+{ MINUS,	INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL|NSPECIAL,	RESC1,
+		"	subf A1,AR,AL\n", },
+
+{ MINUS,	INAREG|FORCC,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
+		"	subf. A1,AR,AL\n", },
+
+{ MINUS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,
+		"	subfc A1,AR,AL" COM "64-bit subtraction\n"
+		"	subfe U1,UR,UL\n", },
+
+{ MINUS,	INCREG | FEATURE_HARDFLOAT,
+	SCREG,	TFLOAT,
+	SCREG,	TFLOAT,
+		NCREG,	RESC1,
+		"	fsubs A1,AL,AR\n", },
+
+{ MINUS,	INAREG,
+	SAREG,	TFLOAT,
+	SAREG,	TFLOAT,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+
+{ MINUS,		INCREG | FEATURE_HARDFLOAT,
+	SCREG,	TDOUBLE|TLDOUBLE,
+	SCREG,	TDOUBLE|TLDOUBLE,
+		NCREG|NCSL,	RESC1,
+		"	fsub A1,AL,AR" COM "(l)double sub\n", },
+
+/* soft-float */
+{ MINUS,		INBREG,
+	SBREG,	TDOUBLE|TLDOUBLE,
+	SBREG,	TDOUBLE|TLDOUBLE,
+		NSPECIAL|NBREG|NBSL,	RESC1,
+		"ZF", },
+
+
+/*
+ * The next rules handle all shift operators.
+ */
+
+{ LS,	INAREG,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	slw A1,AL,AR" COM "left shift\n", },
+
+{ LS,	INAREG|FORCC,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	slw. A1,AL,AR" COM "left shift\n", },
+
+{ LS,	INAREG,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	slwi A1,AL,AR" COM "left shift by constant\n", },
+
+{ LS,	INAREG|FORCC,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	slwi. A1,AL,AR" COM "left shift by constant\n", },
+
+{ LS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCON,	TANY,
+		NBREG,	RESC1,
+		"ZO", },
+
+{ LS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TANY,
+		NSPECIAL|NBREG,	RESC1,
+		"ZE", },
+
+{ RS,	INAREG,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	srw A1,AL,AR" COM "right shift\n", },
+
+{ RS,	INAREG,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	sraw A1,AL,AR" COM "arithmetic right shift\n", },
+
+{ RS,	INAREG|FORCC,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	srw. A1,AL,AR" COM "right shift\n", },
+
+{ RS,	INAREG|FORCC,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	sraw. A1,AL,AR" COM "arithmetic right shift\n", },
+
+{ RS,	INAREG,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+	SCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	srwi A1,AL,AR" COM "right shift by constant\n", },
+
+{ RS,	INAREG,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	srawi A1,AL,AR" COM "arithmetic right shift by constant\n", },
+
+{ RS,	INAREG|FORCC,
+	SAREG,	TUWORD|TUSHORT|TUCHAR,
+	SCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	srwi. A1,AL,AR" COM "right shift by constant\n", },
+
+{ RS,	INAREG|FORCC,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	srawi. A1,AL,AR" COM "right shift by constant\n", },
+
+{ RS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SCON,	TANY,
+		NBREG,	RESC1,
+		"ZO" },
+
+{ RS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SAREG,	TANY,
+		NSPECIAL|NBREG,	RESC1,
+		"ZE", },
+
+/*
+ * The next rules takes care of assignments. "=".
+ */
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SSCON,		TANY,
+		0,	RDEST,
+		"	li AL,AR\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SSCON,		TANY,
+		0,	RDEST,
+		"	li AL,AR\n"
+		"	li UL,UR\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SCON,		TANY,
+		0,	RDEST,
+		"	lis AL," HA16(AR) "\n"
+		"	addi AL,AL," LO16(AR) "\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SCON,		TANY,
+		0,	RDEST,
+		"	lis AL," HA16(AR) "\n"
+		"	addi AL,AL," LO16(AR) "\n"
+		"	lis UL," HA16(UR) "\n"
+		"	addi UL,UL," LO16(UR) "\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TWORD|TPOINT,
+	SOREG,		TWORD|TPOINT,
+		NSPECIAL,	RDEST,
+		"	lwz AL,AR" COM "assign oreg to reg\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TWORD|TPOINT,
+	SNAME,		TWORD|TPOINT,
+		NSPECIAL,	RDEST,
+		"	lis AL," HA16(AR) COM "assign sname to reg\n"
+		"	lwz AL," LO16(AR) "(AL)\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SOREG,		TLONGLONG|TULONGLONG,
+		NSPECIAL,	RDEST,
+		"	lwz AL,AR" COM "assign llong to reg\n"
+		"	lwz UL,UR\n" },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SNAME,		TLONGLONG|TULONGLONG,
+		NSPECIAL,	RDEST,
+		"	lis AL," HA16(AR) COM "assign 64-bit sname to reg\n"
+		"	lwz AL," LO16(AR) "(AL)\n"
+		"	lis UL," HA16(UR) "\n"
+		"	lwz UL," LO16(UR) "(UL)\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SOREG,		TSWORD,
+		NSPECIAL,	RDEST,
+		"	lwz AL,AR" COM "load int/pointer into llong\n"
+		"	srawi UL,AR,31\n" },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SOREG,		TUNSIGNED|TPOINT,
+		NSPECIAL,	RDEST,
+		"	lwz AL,AR" COM "load uint/pointer into (u)llong\n"
+		"	li UL,0\n" },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TUCHAR,
+	SOREG,		TUCHAR,
+		NSPECIAL,	RDEST,
+		"	lbz AL,AR\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TUCHAR,
+	SNAME,		TUCHAR,
+		NSPECIAL,	RDEST,
+		"	lis AL," HA16(AR) COM "assign uchar sname to reg\n"
+		"	lbz AL," LO16(AR) "(AL)\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TCHAR,
+	SOREG,		TCHAR,
+		NSPECIAL,	RDEST,
+		"	lbz AL,AR\n"
+		"	extsb AL,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TCHAR,
+	SNAME,		TCHAR,
+		NSPECIAL,	RDEST,
+		"	lis AL," HA16(AR) COM "assign char sname to reg\n"
+		"	lbz AL," LO16(AR) "(AL)\n"
+		"	extsb AL,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TWORD|TPOINT,
+	SOREG,		TSHORT,
+		NSPECIAL,	RDEST,
+		"	lha AL,AR\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TWORD|TPOINT,
+	SOREG,		TUSHORT,
+		NSPECIAL,	RDEST,
+		"	lhz AL,AR\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TWORD,
+	SNAME,		TSHORT,
+		NSPECIAL,	RDEST,
+		"	lis AL," HA16(AR) "\n"
+		"	lha AL," LO16(AR) "(AL)\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TWORD,
+	SNAME,		TUSHORT,
+		NSPECIAL,	RDEST,
+		"	lis AL," HA16(AR) "\n"
+		"	lhz AL," LO16(AR) "(AL)\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,		TWORD|TPOINT,
+	SAREG,		TWORD|TPOINT,
+		NSPECIAL,	RDEST,
+		"	stw AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SNAME,		TWORD|TPOINT,
+	SAREG,		TWORD|TPOINT,
+		NAREG|NSPECIAL,	RDEST,
+		"	lis A1," HA16(AL) COM "assign reg to sname\n"
+		"	stw AR," LO16(AL) "(A1)\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SOREG,		TLONGLONG|TULONGLONG,
+	SBREG,		TLONGLONG|TULONGLONG,
+		NSPECIAL,	RDEST,
+		"	stw AR,AL" COM "store 64-bit value\n"
+		"	stw UR,UL\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SNAME,		TLONGLONG|TULONGLONG,
+	SBREG,		TLONGLONG|TULONGLONG,
+		NBREG|NSPECIAL,	RDEST,
+		"	lis A1," HA16(AL) COM "assign reg to 64-bit sname\n"
+		"	stw AR," LO16(AL) "(A1)\n"
+		"	lis U1," HA16(UL) "\n"
+		"	stw UR," LO16(UL) "(U1)\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,		TCHAR|TUCHAR,
+	SAREG,		TCHAR|TUCHAR,
+		NSPECIAL,	RDEST,
+		"	stb AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SNAME,		TCHAR|TUCHAR,
+	SAREG,		TCHAR|TUCHAR,
+		NAREG|NSPECIAL,	RDEST,
+		"	lis A1," HA16(AL) "\n"
+		"	stb AR," LO16(AL) "(A1)\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,		TSHORT|TUSHORT,
+	SAREG,		TSHORT|TUSHORT,
+		NSPECIAL,	RDEST,
+		"	sth AR,AL\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SNAME,		TSHORT|TUSHORT,
+	SAREG,		TSHORT|TUSHORT,
+		NAREG|NSPECIAL,	RDEST,
+		"	lis A1," HA16(AL) "\n"
+		"	sth AR," LO16(AL) "(A1)\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		0,	RDEST,
+		"	mr AL,AR" COM "assign AR to AL\n", },
+
+{ ASSIGN,      FOREFF|INBREG,
+        SBREG,	TLONGLONG|TULONGLONG,
+        SBREG,	TLONGLONG|TULONGLONG,
+                0,  RDEST,
+		"	mr AL,AR" COM "assign UR:AR to UL:AL\n"
+                "	mr UL,UR\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SFLD,		TANY,
+	SAREG,		TANY,
+		3*NAREG,	RDEST,
+		"	lis A3," HA16(M) COM "bit-field assignment\n"
+		"	addi A3,A3," LO16(M) "\n"
+		"	lwz A2,AL\n"
+		"	slwi A1,AR,H\n"
+		"	and A1,A1,A3\n"
+		"	not A3,A3\n"
+		"	and A2,A2,A3\n"
+		"	or A2,A2,A1\n"
+		"	stw A2,AL\n"
+		"F	mr AD,AR\n"
+		"F	slwi AD,AD,32-S\n"
+		"F	srwi AD,AD,32-S\n", },
+
+{ STASG,	INAREG|FOREFF,
+	SOREG|SNAME,	TANY,
+	SAREG,		TPTRTO|TANY,
+		NSPECIAL,	RDEST,
+		"ZQ", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_HARDFLOAT,
+	SOREG,		TFLOAT,
+	SCREG,		TFLOAT,
+		0,	RDEST,
+		"	stfs AR,AL" COM "store float\n", },
+
+/* soft-float */
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,		TFLOAT,
+	SAREG,		TFLOAT,
+		0,	RDEST,
+		"	stw AR,AL" COM "store float (soft-float)\n", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_HARDFLOAT,
+	SNAME,		TFLOAT,
+	SCREG,		TFLOAT,
+		NAREG,	RDEST,
+		"	lis A1," HA16(AL) "\n"
+		"	stfs AR," LO16(AL) "(A1)\n", },
+
+/* soft-float */
+{ ASSIGN,	FOREFF|INAREG,
+	SNAME,		TFLOAT,
+	SAREG,		TFLOAT,
+		NAREG,	RDEST,
+		"	lis A1," HA16(AL) "\n"
+		"	stw AR," LO16(AL) "(A1)\n", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_HARDFLOAT,
+	SCREG,		TFLOAT,
+	SOREG,		TFLOAT,
+		0,	RDEST,
+		"	lfs AL,AR" COM "load float\n", },
+
+/* soft-float */
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TFLOAT,
+	SOREG,		TFLOAT,
+		0,	RDEST,
+		"	lwz AL,AR" COM "load float (soft-float)\n", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_HARDFLOAT,
+	SCREG,		TFLOAT,
+	SNAME,		TFLOAT,
+		NAREG,	RDEST,
+		"	lis A1," HA16(AR) "\n"
+		"	lfs AL," LO16(AR) "(A1)\n", },
+
+/* soft-float */
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TFLOAT,
+	SNAME,		TFLOAT,
+		NAREG,	RDEST,
+		"	lis A1," HA16(AR) "\n"
+		"	lwz AL," LO16(AR) "(A1)\n", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_HARDFLOAT,
+	SCREG,		TFLOAT,
+	SCREG,		TFLOAT,
+		0,	RDEST,
+		"	fmr AL,AR" COM "assign AR to AL\n", },
+
+/* soft-float */
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,		TFLOAT,
+	SAREG,		TFLOAT,
+		0,	RDEST,
+		"	mr AL,AR" COM "assign AR to AL\n", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_HARDFLOAT,
+	SOREG,		TDOUBLE|TLDOUBLE,
+	SCREG,		TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"	stfd AR,AL" COM "store (l)double\n", },
+
+/* soft-float */
+{ ASSIGN,	FOREFF|INBREG,
+	SOREG,		TDOUBLE|TLDOUBLE,
+	SBREG,		TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"	stw AR,AL" COM "store (l)double (soft-float)\n"
+		"	stw UR,UL\n", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_HARDFLOAT,
+	SNAME,		TDOUBLE|TLDOUBLE,
+	SCREG,		TDOUBLE|TLDOUBLE,
+		NAREG,	RDEST,
+		"	lis A1," HA16(AL) "\n"
+		"	stfd AR," LO16(AL) "(A1)\n", },
+
+/* soft-float */
+{ ASSIGN,	FOREFF|INBREG,
+	SNAME,		TDOUBLE|TLDOUBLE,
+	SBREG,		TDOUBLE|TLDOUBLE,
+		NAREG,	RDEST,
+		"	lis A1," HA16(AL) "\n"
+		"	stw AR," LO16(AL) "(A1)\n"
+		"	lis A1," HA16(UL) "\n"
+		"	stw UR," LO16(UL) "(A1)\n", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_HARDFLOAT,
+	SCREG,		TDOUBLE|TLDOUBLE,
+	SOREG,		TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"	lfd AL,AR" COM "load (l)double\n", },
+
+/* soft-float */
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,		TDOUBLE|TLDOUBLE,
+	SOREG,		TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"	lwz AL,AR" COM "load (l)double (soft-float)\n"
+		"	lwz UL,UR\n", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_HARDFLOAT,
+	SCREG,		TDOUBLE|TLDOUBLE,
+	SNAME,		TDOUBLE|TLDOUBLE,
+		NAREG,	RDEST,
+		"	lis A1," HA16(AR) "\n"
+		"	lfd AL," LO16(AR) "(A1)\n", },
+
+/* soft-float */
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,		TDOUBLE|TLDOUBLE,
+	SNAME,		TDOUBLE|TLDOUBLE,
+		NAREG,	RDEST,
+		"	lis A1," HA16(AR) "\n"
+		"	lwz AL," LO16(AR) "(A1)\n"
+		"	lis A1," HA16(UR) "\n"
+		"	lwz UL," LO16(UR) "(A1)\n", },
+
+{ ASSIGN,	FOREFF|INCREG | FEATURE_HARDFLOAT,
+	SCREG,		TDOUBLE|TLDOUBLE,
+	SCREG,		TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"	fmr AL,AR" COM "assign AR to AL\n", },
+
+/* soft-float */
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,		TDOUBLE|TLDOUBLE,
+	SBREG,		TDOUBLE|TLDOUBLE,
+		0,	RDEST,
+		"	mr AL,AR" COM "assign AR to AL\n"
+		"	mr UL,UR\n", },
+
+/*
+ * DIV/MOD/MUL 
+ */
+
+{ DIV,	INAREG,
+	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
+	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	divwu A1,AL,AR\n", },
+
+{ DIV,	INAREG|FORCC,
+	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
+	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
+		NAREG|NASL,	RESC1|RESCC,
+		"	divwu. A1,AL,AR\n", },
+
+{ DIV,	INAREG,
+	SAREG,	TWORD|TSHORT|TCHAR,
+	SAREG,	TWORD|TSHORT|TCHAR,
+		NAREG|NASL,	RESC1,
+		"	divw A1,AL,AR\n", },
+
+{ DIV,	INAREG|FORCC,
+	SAREG,	TWORD|TSHORT|TCHAR,
+	SAREG,	TWORD|TSHORT|TCHAR,
+		NAREG|NASL,	RESC1|RESCC,
+		"	divw. A1,AL,AR\n", },
+
+{ DIV,	INBREG,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SBREG,		TLONGLONG|TULONGLONG,
+		NSPECIAL|NBREG,	RESC1,
+		"ZE", },
+
+{ DIV, INCREG | FEATURE_HARDFLOAT,
+	SCREG,		TFLOAT,
+	SCREG,		TFLOAT,
+		NCREG|NCSR,	RESC1,
+		"	fdivs A1,AL,AR" COM "float divide\n", },
+
+/* soft-float */
+{ DIV, INAREG,
+	SAREG,		TFLOAT,
+	SAREG,		TFLOAT,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+
+{ DIV, INCREG | FEATURE_HARDFLOAT,
+	SCREG,		TDOUBLE|TLDOUBLE,
+	SCREG,		TDOUBLE|TLDOUBLE,
+		NCREG|NCSR,	RESC1,
+		"	fdiv A1,AL,AR" COM "(l)double divide\n", },
+
+/* soft-float */
+{ DIV, INBREG,
+	SBREG,		TDOUBLE|TLDOUBLE,
+	SBREG,		TDOUBLE|TLDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+{ MOD,	INAREG,
+	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
+	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
+		NAREG,	RESC1,
+		"	divwu A1,AL,AR" COM "unsigned modulo\n"
+		"	mullw A1,A1,AR\n"
+		"	subf A1,A1,AL\n", },
+
+{ MOD,	INAREG,
+	SAREG,	TWORD|TSHORT|TCHAR,
+	SAREG,	TWORD|TSHORT|TCHAR,
+		NAREG,	RESC1,
+		"	divw A1,AL,AR" COM "signed modulo\n"
+		"	mullw A1,A1,AR\n"
+		"	subf A1,A1,AL\n", },
+
+{ MOD,	INBREG,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SBREG,		TLONGLONG|TULONGLONG,
+		NSPECIAL|NBREG,	RESC1,
+		"ZE", },
+
+{ MUL,	INAREG,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SSCON,		TANY,
+		NAREG|NASL,	RESC1,
+		"	mulli A1,AL,AR\n", },
+
+{ MUL,	INAREG|FORCC,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SSCON,		TANY,
+		NAREG|NASL,	RESC1|RESCC,
+		"	mulli. A1,AL,AR\n", },
+
+{ MUL,	INAREG,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	mullw A1,AL,AR\n", },
+
+{ MUL,	INAREG|FORCC,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1|RESCC,
+		"	mullw. A1,AL,AR\n", },
+
+{ MUL,	INBREG,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NBREG,	RESC1,
+		"	mullw A1,AL,AR\n"
+		"	mulhw U1,AL,AR\n", },
+
+{ MUL,	INBREG,
+	SBREG,		TLONGLONG|TULONGLONG,
+	SBREG,		TLONGLONG|TULONGLONG,
+		NBREG,	RESC1,
+		"	mullw A1,AL,AR\n"
+		"	mulhw U1,AL,AR\n", },
+
+{ MUL, INCREG | FEATURE_HARDFLOAT,
+	SCREG,		TFLOAT,
+	SCREG,		TFLOAT,
+		NCREG|NCSR,	RESC1,
+		"	fmuls A1,AL,AR" COM "float multiply\n", },
+
+/* soft-float */
+{ MUL, INAREG,
+	SAREG,		TFLOAT,
+	SAREG,		TFLOAT,
+		NSPECIAL|NAREG,	RESC1,
+		"ZF", },
+
+{ MUL, INCREG | FEATURE_HARDFLOAT,
+	SCREG,		TDOUBLE|TLDOUBLE,
+	SCREG,		TDOUBLE|TLDOUBLE,
+		NCREG|NCSR,	RESC1,
+		"	fmul A1,AL,AR" COM "(l)double multiply\n", },
+
+/* soft-float */
+{ MUL, INBREG,
+	SBREG,		TDOUBLE|TLDOUBLE,
+	SBREG,		TDOUBLE|TLDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"ZF", },
+
+/*
+ * Indirection operators.
+ */
+
+{ UMUL,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TWORD|TPOINT,
+		NAREG|NSPECIAL,	RESC1,
+		"	lwz A1,AL" COM "word load\n", },
+
+{ UMUL,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TCHAR,
+		NAREG|NSPECIAL,	RESC1,
+		"	lbz A1,AL" COM "char load\n"
+		"	extsb A1,A1\n", },
+
+{ UMUL,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TUCHAR,
+		NAREG|NSPECIAL,	RESC1,
+		"	lbz A1,AL" COM "uchar load\n", },
+
+{ UMUL,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TSHORT,
+		NAREG|NSPECIAL,	RESC1,
+		"	lha A1,AL" COM "short load\n", },
+
+{ UMUL,	INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TUSHORT,
+		NAREG|NSPECIAL,	RESC1,
+		"	lhz A1,AL" COM "ushort load\n", },
+
+{ UMUL, INBREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TLONGLONG|TULONGLONG,
+		NBREG,	RESC1,
+		"	lwz A1,AL" COM "64-bit load\n"
+		"	lwz U1,UL\n", },
+
+{ UMUL, INCREG | FEATURE_HARDFLOAT,
+	SANY,		TANY,
+	SOREG|SNAME,	TFLOAT,
+		NCREG,	RESC1,
+		"	lfs A1,AL" COM "float load\n", },
+
+{ UMUL, INAREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TFLOAT,
+		NAREG,	RESC1,
+		"	lwz A1,AL" COM "float load (soft-float)\n", },
+
+{ UMUL, INCREG | FEATURE_HARDFLOAT,
+	SANY,		TANY,
+	SOREG|SNAME,	TDOUBLE|TLDOUBLE,
+		NCREG,	RESC1,
+		"	lfd A1,AL" COM "(l)double load\n", },
+
+{ UMUL, INBREG,
+	SANY,		TANY,
+	SOREG|SNAME,	TDOUBLE|TLDOUBLE,
+		NSPECIAL|NBREG,	RESC1,
+		"	lwz A1,AL" COM "(l)double load (soft-float)\n"
+		"	lwz U1,UL\n", },
+
+#if 0
+{ UMUL, INAREG,
+	SANY,		TANY,
+	SAREG,		TWORD|TPOINT,
+		NAREG,	RESC1,
+		"	lwz A1,(AL)" COM "word load\n", },
+#endif
+
+/*
+ * Logical/branching operators
+ */
+
+/* compare with constant */
+{ OPLOG,	FORCC,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SSCON,	TANY,
+		0, 	RESCC,
+		"	cmpwi AL,AR\n", },
+
+/* compare with constant */
+{ OPLOG,	FORCC,
+	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
+	SSCON,	TANY,
+		0, 	RESCC,
+		"	cmplwi AL,AR\n", },
+
+/* compare with register */
+{ OPLOG,	FORCC,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+	SAREG,	TSWORD|TSHORT|TCHAR,
+		0, 	RESCC,
+		"	cmpw AL,AR\n", },
+
+/* compare with register */
+{ OPLOG,	FORCC,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		0, 	RESCC,
+		"	cmplw AL,AR\n", },
+
+/* compare with register */
+{ OPLOG,	FORCC,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		0, 	RESCC,
+		"ZD", },
+
+/* compare with register */
+{ OPLOG,	FORCC | FEATURE_HARDFLOAT,
+	SCREG,	TFLOAT|TDOUBLE|TLDOUBLE,
+	SCREG,	TFLOAT|TDOUBLE|TLDOUBLE,
+		0,	RESCC,
+		"	fcmpu 0,AL,AR\n", },
+
+/* soft-float */
+{ OPLOG,	FORCC,
+	SAREG,	TFLOAT,
+	SAREG,	TFLOAT,
+		NSPECIAL,	RESCC,
+		"ZF\n", },
+
+/* soft-float */
+{ OPLOG,	FORCC,
+	SBREG,	TDOUBLE|TLDOUBLE,
+	SBREG,	TDOUBLE|TLDOUBLE,
+		NSPECIAL,	RESCC,
+		"ZF", },
+
+{ OPLOG,	FORCC,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	0,
+		"diediedie!", },
+
+/* AND/OR/ER */
+{ AND,	INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
+		"	and A1,AL,AR\n", },
+
+{ AND,	INAREG|FORCC,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL|NSPECIAL,	RESC1,
+		"	and. A1,AL,AR\n", },
+
+/* AR must be positive */
+{ AND,	INAREG|FORCC,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SPCON,	TANY,
+		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
+		"	andi. A1,AL,AR\n", },
+
+{ AND,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,
+		"	and A1,AL,AR" COM "64-bit and\n"
+		"	and U1,UL,UR\n" },
+
+{ AND,	INBREG|FORCC,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SPCON,	TANY,
+		NBREG|NBSL,	RESC1|RESCC,
+		"	andi. A1,AL,AR" COM "64-bit and with constant\n"
+		"	li U1,0\n" },
+
+{ OR,	INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL|NSPECIAL,	RESC1,
+		"	or A1,AL,AR\n", },
+
+{ OR,	INAREG|FORCC,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
+		"	or. A1,AL,AR\n", },
+
+{ OR,	INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SPCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	ori A1,AL,AR\n", },
+
+{ OR,	INAREG|FORCC,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SPCON,	TANY,
+		NAREG|NASL,	RESC1|RESCC,
+		"	ori. A1,AL,AR\n", },
+
+{ OR,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,
+		"	or A1,AL,AR" COM "64-bit or\n"
+		"	or U1,UL,UR\n" },
+
+{ OR,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SPCON,	TANY,
+		NBREG|NBSL,	RESC1,
+		"	ori A1,AL,AR" COM "64-bit or with constant\n" },
+
+{ OR,	INBREG|FORCC,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SPCON,	TANY,
+		NBREG|NBSL,	RESC1|RESCC,
+		"	ori. A1,AL,AR" COM "64-bit or with constant\n" },
+
+{ ER,	INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL|NSPECIAL,	RESC1,
+		"	xor A1,AL,AR\n", },
+
+{ ER,	INAREG|FORCC,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
+		"	xor. A1,AL,AR\n", },
+
+{ ER,	INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SPCON,	TANY,
+		NAREG|NASL|NSPECIAL,	RESC1,
+		"	xori A1,AL,AR\n", },
+
+{ ER,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SBREG,	TLONGLONG|TULONGLONG,
+		NBREG|NBSL,	RESC1,
+		"	xor A1,AL,AR" COM "64-bit xor\n"
+		"	xor U1,UL,UR\n" },
+
+{ ER,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SPCON,	TANY,
+		NBREG|NBSL,	RESC1,
+		"	xori A1,AL,AR" COM "64-bit xor with constant\n" },
+
+/*
+ * Jumps.
+ */
+{ GOTO, 	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	b LL\n", },
+
+{ GOTO, 	FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	mtctr AL\n"
+		"	bctr\n", },
+
+/*
+ * Convert LTYPE to reg.
+ */
+
+#if defined(ELFABI)
+{ OPLTYPE,	INAREG | FEATURE_PIC,
+	SANY,		TANY,
+	SNAME,		TANY,
+		NAREG,	RESC1,
+		"	lwz A1,AL" COM "elfabi pic load\n", },
+#endif
+
+{ OPLTYPE,      INBREG,
+        SANY,   	TANY,
+        SOREG,		TLONGLONG|TULONGLONG,
+                NBREG,  RESC1,
+                "	lwz A1,AL" COM "load llong from memory\n"
+		"	lwz U1,UL\n", },
+
+{ OPLTYPE,      INBREG,
+        SANY,   	TANY,
+        SNAME,		TLONGLONG|TULONGLONG,
+                NBREG,  RESC1,
+		"	lis A1," HA16(AL) COM "load llong from sname\n"
+		"	lwz A1," LO16(AL) "(A1)\n"
+		"	lis U1," HA16(UL) "\n"
+		"	lwz U1," LO16(UL) "(U1)\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG,		TWORD|TPOINT,
+		NAREG,	RESC1,
+		"	lwz A1,AL" COM "load word from memory\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SNAME,		TWORD|TPOINT,
+		NAREG|NSPECIAL,	RESC1,
+		"	lis A1," HA16(AL) COM "load word from sname\n"
+		"	lwz A1," LO16(AL) "(A1)\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG,		TCHAR,
+		NAREG,	RESC1,
+		"	lbz A1,AL" COM "load char from memory\n"
+		"	extsb A1,A1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SNAME,		TCHAR,
+		NAREG|NSPECIAL,	RESC1,
+		"	lis A1," HA16(AL) COM "load char from sname\n"
+		"	lbz A1," LO16(AL) "(A1)\n"
+		"	extsb A1,A1\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG,		TUCHAR,
+		NAREG,	RESC1,
+		"	lbz A1,AL" COM "load uchar from memory\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SNAME,		TUCHAR,
+		NAREG|NSPECIAL,	RESC1,
+		"	lis A1," HA16(AL) COM "load uchar from sname\n"
+		"	lbz A1," LO16(AL) "(A1)\n", },
+
+/* load short from memory */
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG,		TSHORT,
+		NAREG,	RESC1,
+		"	lha A1,AL" COM "load short from memory\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG,		TUSHORT,
+		NAREG,	RESC1,
+		"	lhz A1,AL" COM "load ushort from memory\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SNAME,		TSHORT,
+		NAREG|NSPECIAL,	RESC1,
+		"	lis A1," HA16(AL) COM "load short from sname\n"
+		"	lha A1," LO16(AL) "(A1)\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SNAME,		TUSHORT,
+		NAREG|NSPECIAL,	RESC1,
+		"	lis A1," HA16(AL) COM "load ushort from sname\n"
+		"	lhz A1," LO16(AL) "(A1)\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SSCON,		TANY,
+		NAREG,	RESC1,
+		"	li A1,AL" COM "load 16-bit constant\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SSCON,	TANY,
+		NBREG,	RESC1,
+		"	li A1,AL" COM "load 16-bit constant\n"
+		"	li U1,UL\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SCON,	TANY,
+		NAREG|NASL,	RESC1,
+		"	lis A1," HA16(AL) COM "load constant into register\n"
+		"	addi A1,A1," LO16(AL) "\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,	TANY,
+	SCON,	TANY,
+		NBREG,	RESC1,
+		"	lis A1," HA16(AL) COM "load constant into register\n"
+		"	addi A1,A1," LO16(AL) "\n"
+		"	lis U1," HA16(UL) "\n"
+		"	addi U1,U1," LO16(UL) "\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SAREG,	TANY,
+		NAREG,	RESC1,
+		"	mr A1,AL" COM "load AL into A1\n" },
+
+{ OPLTYPE,      INBREG,
+        SANY,   TANY,
+        SBREG,	TANY,
+                NBREG,  RESC1,
+		"	mr A1,AL" COM "load UL:AL into U1:A1\n"
+                "       mr U1,UL\n", },
+
+{ OPLTYPE,      INCREG,
+        SANY,   TANY,
+        SCREG,	TFLOAT|TDOUBLE|TLDOUBLE,
+                NCREG,  RESC1,
+		"	fmr A1,AL" COM "load AL into A1\n", },
+
+{ OPLTYPE,	INCREG | FEATURE_HARDFLOAT,
+	SANY,		TANY,
+	SOREG,		TFLOAT,
+		NCREG,	RESC1,
+		"	lfs A1,AL" COM "load float\n", },
+
+/* soft-float */
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SOREG,		TFLOAT,
+		NAREG,	RESC1,
+		"	lwz A1,AL" COM "load float (soft-float)\n", },
+
+{ OPLTYPE,	INCREG | FEATURE_HARDFLOAT,
+	SANY,		TANY,
+	SNAME,		TFLOAT,
+		NCREG|NAREG,	RESC2,
+		"	lis A1," HA16(AL) COM "load sname\n"
+		"	lfs A2," LO16(AL) "(A1)\n", },
+
+/* soft-float */
+{ OPLTYPE,	INAREG,
+	SANY,		TANY,
+	SNAME,		TFLOAT,
+		NAREG,	RESC1,
+		"	lis A1," HA16(AL) COM "load sname (soft-float)\n"
+		"	lwz A1," LO16(AL) "(A1)\n", },
+
+{ OPLTYPE,	INCREG | FEATURE_HARDFLOAT,
+	SANY,		TANY,
+	SOREG,		TDOUBLE|TLDOUBLE,
+		NCREG,	RESC1,
+		"	lfd A1,AL" COM "load (l)double\n", },
+
+/* soft-float */
+{ OPLTYPE,	INBREG,
+	SANY,		TANY,
+	SOREG,		TDOUBLE|TLDOUBLE,
+		NBREG,	RESC1,
+		"	lwz A1,AL" COM "load (l)double (soft-float)\n"
+		"	lwz U1,UL\n", },
+
+{ OPLTYPE,	INCREG | FEATURE_HARDFLOAT,
+	SANY,		TANY,
+	SNAME,		TDOUBLE|TLDOUBLE,
+		NCREG|NAREG,	RESC2,
+		"	lis A1," HA16(AL) COM "load sname\n"
+		"	lfd A2," LO16(AL) "(A1)\n", },
+
+{ OPLTYPE,	INBREG,
+	SANY,		TANY,
+	SNAME,		TDOUBLE|TLDOUBLE,
+		NBREG,	RESC1,
+		"	lis A1," HA16(AL) COM "load sname (soft-float)\n"
+		"	lwz A1," LO16(AL) "(A1)\n"
+		"	lis U1," HA16(UL) "\n"
+		"	lwz U1," LO16(UL) "(U1)\n", },
+
+
+/*
+ * Negate a word.
+ */
+
+{ UMINUS,	INAREG,
+	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,
+		"	neg A1,AL\n", },
+
+{ UMINUS,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SANY,	TANY,
+		NBREG|NBSL,	RESC1,
+		"	subfic A1,AL,0\n"
+		"	subfze U1,UL\n", },
+
+{ UMINUS,	INCREG | FEATURE_HARDFLOAT,
+	SCREG,	TFLOAT|TDOUBLE|TLDOUBLE,
+	SANY,	TANY,
+		NCREG|NCSL,	RESC1,
+		"	fneg A1,AL\n", },
+
+{ UMINUS,	INAREG,
+	SAREG,	TFLOAT,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,
+		"	xoris A1,AL,0x8000" COM "(soft-float)\n", },
+
+{ UMINUS,	INBREG,
+	SBREG,	TDOUBLE|TLDOUBLE,
+	SANY,	TANY,
+		NBREG|NBSL,	RESC1,
+		"	xoris U1,UL,0x8000" COM "(soft-float)\n"
+		"	mr A1,AL\n", },
+
+{ COMPL,	INAREG,
+	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,
+		"	not A1,AL\n", },
+
+{ COMPL,	INBREG,
+	SBREG,	TLONGLONG|TULONGLONG,
+	SANY,	TANY,
+		NBREG|NBSL,	RESC1,
+		"	not A1,AL\n"
+		"	not U1,UL\n", },
+
+/*
+ * Arguments to functions.
+ */
+
+#if 0
+{ STARG,	FOREFF,
+	SAREG|SOREG|SNAME|SCON,	TANY,
+	SANY,	TSTRUCT,
+		NSPECIAL|NAREG,	0,
+		"ZF", },
+#endif
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ FLD, DF(FLD), },
+
+{ OPLEAF, DF(NAME), },
+
+/* { INIT, DF(INIT), }, */
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	"help; I'm in trouble\n" },
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
Index: uspace/app/pcc/arch/ppc32
===================================================================
--- uspace/app/pcc/arch/ppc32	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/ppc32	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1 @@
+powerpc
Index: uspace/app/pcc/arch/sparc64/code.c
===================================================================
--- uspace/app/pcc/arch/sparc64/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/sparc64/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2008 David Crawshaw <david@zentus.com>
+ * 
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "pass1.h"
+
+void
+defloc(struct symtab *sp)
+{
+	static char *loctbl[] = { "text", "data", "rodata" };
+	static int lastloc = -1;
+	TWORD t;
+	char *n;
+	int s;
+
+	if (sp == NULL)
+		return;
+
+	t = sp->stype;
+	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
+	if (s != lastloc)
+		printf("\n\t.section \".%s\"\n", loctbl[s]);
+	lastloc = s;
+	if (s == PROG)
+		return;
+
+	switch (DEUNSIGN(sp->stype)) {
+		case CHAR:	s = 1;
+		case SHORT:	s = 2;
+		case INT:
+		case UNSIGNED:	s = 4;
+		default:	s = 8;
+	}
+	printf("\t.align %d\n", s);
+
+	n = sp->soname ? sp->soname : sp->sname;
+	if (sp->sclass == EXTDEF)
+		printf("\t.global %s\n", n);
+	if (sp->slevel == 0) {
+		printf("\t.type %s,#object\n", n);
+		printf("\t.size %s," CONFMT "\n", n,
+			tsize(sp->stype, sp->sdf, sp->sap) / SZCHAR);
+		printf("%s:\n", n);
+	} else
+		printf(LABFMT ":\n", sp->soffset);
+}
+
+void
+efcode()
+{
+	/* XXX */
+}
+
+void
+bfcode(struct symtab **sp, int cnt)
+{
+	int i, off;
+	NODE *p, *q;
+	struct symtab *sym;
+
+	/* Process the first six arguments. */
+	for (i=0; i < cnt && i < 6; i++) {
+		sym = sp[i];
+		q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
+		q->n_rval = RETREG_PRE(sym->stype) + i;
+		p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+		sym->soffset = regno(p);
+		sym->sflags |= STNODE;
+		p = buildtree(ASSIGN, p, q);
+		ecomp(p);
+	}
+
+	/* Process the remaining arguments. */
+	for (off = V9RESERVE; i < cnt; i++) {
+		sym = sp[i];
+		p = tempnode(0, sym->stype, sym->sdf, sym->sap);
+		off = ALIGN(off, (tlen(p) - 1));
+		sym->soffset = off * SZCHAR;
+		off += tlen(p);
+		p = buildtree(ASSIGN, p, nametree(sym));
+		sym->soffset = regno(p->n_left);
+		sym->sflags |= STNODE;
+		ecomp(p);
+	}
+}
+
+void
+bccode()
+{
+	SETOFF(autooff, SZINT);
+}
+
+void
+ejobcode(int flag)
+{
+}
+
+void
+bjobcode()
+{
+}
+
+/*
+ * The first six 64-bit arguments are saved in the registers O0 to O5,
+ * which become I0 to I5 after the "save" instruction moves the register
+ * window. Arguments 7 and up must be saved on the stack to %sp+BIAS+176.
+ *
+ * For a pretty picture, see Figure 3-16 in the SPARC Compliance Def 2.4.
+ */
+static NODE *
+moveargs(NODE *p, int *regp, int *stacksize)
+{
+	NODE *r, *q;
+
+	if (p->n_op == CM) {
+		p->n_left = moveargs(p->n_left, regp, stacksize);
+		r = p->n_right;
+	} else {
+		r = p;
+	}
+
+	/* XXX more than six FP args can and should be passed in registers. */
+	if (*regp > 5 && r->n_op != STARG) {
+		/* We are storing the stack offset in n_rval. */
+		r = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap);
+		/* Make sure we are appropriately aligned. */
+		*stacksize = ALIGN(*stacksize, (tlen(r) - 1));
+		r->n_rval = *stacksize;
+		*stacksize += tlen(r);
+	} else if (r->n_op == STARG)
+		cerror("op STARG in moveargs");
+	else {
+		q = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_ap);
+
+		/*
+		 * The first six non-FP arguments go in the registers O0 - O5.
+		 * Float arguments are stored in %fp1, %fp3, ..., %fp29, %fp31.
+		 * Double arguments are stored in %fp0, %fp2, ..., %fp28, %fp30.
+		 * A non-fp argument still increments register, eg.
+		 *     test(int a, int b, float b)
+		 * takes %o0, %o1, %fp5.
+		 */
+		if (q->n_type == FLOAT)
+			q->n_rval = F0 + (*regp++ * 2) + 1;
+		else if (q->n_type == DOUBLE)
+			q->n_rval = D0 + *regp++;
+		else if (q->n_type == LDOUBLE)
+			cerror("long double support incomplete");
+		else
+			q->n_rval = O0 + (*regp)++;
+
+		r = buildtree(ASSIGN, q, r);
+	}
+
+	if (p->n_op == CM) {
+		p->n_right = r;
+		return p;
+	}
+
+	return r;
+}
+
+NODE *
+funcode(NODE *p)
+{
+	NODE *r, *l;
+	int reg = 0, stacksize = 0;
+
+	r = l = 0;
+
+	p->n_right = moveargs(p->n_right, &reg, &stacksize);
+
+	/*
+	 * This is a particularly gross and inefficient way to handle
+	 * argument overflows. First, we calculate how much stack space
+	 * we need in moveargs(). Then we assign it by moving %sp, make
+	 * the function call, and then move %sp back.
+	 *
+	 * What we should be doing is getting the maximum of all the needed
+	 * stacksize values to the prologue and doing it all in the "save"
+	 * instruction.
+	 */
+	if (stacksize != 0) {
+		stacksize = V9STEP(stacksize); /* 16-bit alignment. */
+
+		r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		r->n_lval = 0;
+		r->n_rval = SP;
+		r = block(MINUS, r, bcon(stacksize), INT, 0, MKAP(INT));
+
+		l = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		l->n_lval = 0;
+		l->n_rval = SP;
+		r = buildtree(ASSIGN, l, r);
+
+		p = buildtree(COMOP, r, p);
+
+		r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		r->n_lval = 0;
+		r->n_rval = SP;
+		r = block(PLUS, r, bcon(stacksize), INT, 0, MKAP(INT));
+
+		l = block(REG, NIL, NIL, INT, 0, MKAP(INT));
+		l->n_lval = 0;
+		l->n_rval = SP;
+		r = buildtree(ASSIGN, l, r);
+
+		p = buildtree(COMOP, p, r);
+
+	}
+	return p;
+}
+
+int
+fldal(unsigned int t)
+{
+	uerror("illegal field type");
+	return ALINT;
+}
+
+void
+fldty(struct symtab *p)
+{
+}
+
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+	return 0;
+}
Index: uspace/app/pcc/arch/sparc64/local.c
===================================================================
--- uspace/app/pcc/arch/sparc64/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/sparc64/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2008 David Crawshaw <david@zentus.com>
+ * 
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "pass1.h"
+
+NODE *
+clocal(NODE *p)
+{
+	struct symtab *sp;
+	int op;
+	NODE *r, *l;
+
+	op = p->n_op;
+	sp = p->n_sp;
+	l  = p->n_left;
+	r  = p->n_right;
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal in: %p, %s\n", p, copst(op));
+		fwalk(p, eprint, 0);
+	}
+#endif
+
+	switch (op) {
+
+	case NAME:
+		if (sp->sclass == PARAM || sp->sclass == AUTO) {
+			/*
+			 * Use a fake structure reference to
+			 * write out frame pointer offsets.
+			 */
+			l = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
+			l->n_lval = 0;
+			l->n_rval = FP;
+			r = p;
+			p = stref(block(STREF, l, r, 0, 0, 0));
+		}
+		break;
+	case PCONV: /* Remove what PCONVs we can. */
+		if (l->n_op == SCONV)
+			break;
+
+		if (l->n_op == ICON || (ISPTR(p->n_type) && ISPTR(l->n_type))) {
+			l->n_type = p->n_type;
+			l->n_qual = p->n_qual;
+			l->n_df = p->n_df;
+			l->n_ap = p->n_ap;
+			nfree(p);
+			p = l;
+		}
+		break;
+
+	case SCONV:
+        /* Remove redundant conversions. */
+		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
+		    btattr[p->n_type].atypsz == btattr[l->n_type].atypsz &&
+		    p->n_type != FLOAT && p->n_type != DOUBLE &&
+		    l->n_type != FLOAT && l->n_type != DOUBLE &&
+		    l->n_type != DOUBLE && p->n_type != LDOUBLE) {
+			if (l->n_op == NAME || l->n_op == UMUL ||
+			    l->n_op == TEMP) {
+				l->n_type = p->n_type;
+				nfree(p);
+				p = l;
+				break;
+			}
+		}
+
+        /* Convert floating point to int before to char or short. */
+        if ((l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE)
+            && (DEUNSIGN(p->n_type) == CHAR || DEUNSIGN(p->n_type) == SHORT)) {
+            p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
+            p->n_left->n_type = INT;
+            break;
+        }
+
+        /* Transform constants now. */
+		if (l->n_op != ICON)
+			break;
+
+		if (ISPTR(p->n_type)) {
+			l->n_type = p->n_type;
+			nfree(p);
+			p = l;
+			break;
+		}
+
+		switch (p->n_type) {
+		case BOOL:      l->n_lval = (l->n_lval != 0); break;
+		case CHAR:      l->n_lval = (char)l->n_lval; break;
+		case UCHAR:     l->n_lval = l->n_lval & 0377; break;
+		case SHORT:     l->n_lval = (short)l->n_lval; break;
+		case USHORT:    l->n_lval = l->n_lval & 0177777; break;
+		case UNSIGNED:  l->n_lval = l->n_lval & 0xffffffff; break;
+		case INT:       l->n_lval = (int)l->n_lval; break;
+		case ULONG:
+		case ULONGLONG: l->n_lval = l->n_lval; break;
+		case LONG:
+		case LONGLONG:	l->n_lval = (long long)l->n_lval; break;
+		case FLOAT:
+		case DOUBLE:
+		case LDOUBLE:
+			l->n_op = FCON;
+			l->n_dcon = l->n_lval;
+			break;
+		case VOID:
+			break;
+		default:
+			cerror("sconv type unknown %d", p->n_type);
+		}
+
+		l->n_type = p->n_type;
+		nfree(p);
+		p = l;
+		break;
+
+	case PMCONV:
+	case PVCONV:
+		if (r->n_op != ICON)
+			cerror("converting bad type");
+		nfree(p);
+		p = buildtree(op == PMCONV ? MUL : DIV, l, r);
+		break;
+
+	case FORCE:
+		/* Put attached value into the return register. */
+		p->n_op = ASSIGN;
+		p->n_right = p->n_left;
+		p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKAP(INT));
+		p->n_left->n_rval = RETREG_PRE(p->n_type);
+		break;
+	}
+
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("clocal out: %p, %s\n", p, copst(op));
+		fwalk(p, eprint, 0);
+	}
+#endif
+
+	return p;
+}
+
+void
+myp2tree(NODE *p)
+{
+	struct symtab *sp;
+
+	if (p->n_op != FCON)
+		return;
+
+	sp = tmpalloc(sizeof(struct symtab));
+	sp->sclass = STATIC;
+	sp->slevel = 1;
+	sp->soffset = getlab();
+	sp->sflags = 0;
+	sp->stype = p->n_type;
+	sp->squal = (CON >> TSHIFT);
+
+	defloc(sp);
+	ninval(0, btattr[p->n_type].atypsz, p);
+
+	p->n_op = NAME;
+	p->n_lval = 0;
+	p->n_sp = sp;
+}
+
+int
+andable(NODE *p)
+{
+	return 1;
+}
+
+void
+cendarg()
+{
+	autooff = AUTOINIT;
+}
+
+int
+cisreg(TWORD t)
+{
+	/* SPARCv9 registers are all 64-bits wide. */
+	return 1;
+}
+
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct attr *ap)
+{
+	return bcon(off / SZCHAR);
+}
+
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+}
+
+void
+instring(struct symtab *sp)
+{
+	char *s, *str;
+
+	defloc(sp);
+	str = sp->sname;
+
+	printf("\t.ascii \"");
+	for (s = str; *s != 0; ) {
+		if (*s++ == '\\')
+			esccon(&s);
+		if (s - str > 60) {
+			fwrite(str, 1, s - str, stdout);
+			printf("\"\n\t.ascii \"");
+			str = s;
+		}
+	}
+	fwrite(str, 1, s - str, stdout);
+	printf("\\0\"\n");
+}
+
+void
+zbits(OFFSZ off, int fsz)
+{
+}
+
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+}
+
+void
+ninval(CONSZ off, int fsz, NODE *p)
+{
+	TWORD t;
+	struct symtab *sp;
+	union { float f; double d; int i; long long l; } u;
+
+	t = p->n_type;
+	sp = p->n_sp;
+
+	if (ISPTR(t))
+		t = LONGLONG;
+
+	if (p->n_op != ICON && p->n_op != FCON)
+		cerror("ninval: not a constant");
+	if (p->n_op == ICON && sp != NULL && DEUNSIGN(t) != LONGLONG)
+		cerror("ninval: not constant");
+
+	switch (t) {
+		case CHAR:
+		case UCHAR:
+			printf("\t.byte %d\n", (int)p->n_lval & 0xff);
+			break;
+		case SHORT:
+		case USHORT:
+			printf("\t.half %d\n", (int)p->n_lval &0xffff);
+			break;
+		case BOOL:
+			p->n_lval = (p->n_lval != 0); /* FALLTHROUGH */
+		case INT:
+		case UNSIGNED:
+			printf("\t.long " CONFMT "\n", p->n_lval);
+			break;
+		case LONG:
+		case ULONG:
+		case LONGLONG:
+		case ULONGLONG:
+			printf("\t.xword %lld", p->n_lval);
+			if (sp != 0) {
+				if (sp->sclass == STATIC && sp->slevel > 0)
+					printf("+" LABFMT, sp->soffset);
+				else
+					printf("+%s", sp->soname ?
+					    sp->soname : exname(sp->sname));
+			}
+			printf("\n");
+			break;
+		case FLOAT:
+			u.f = (float)p->n_dcon;
+			printf("\t.long %d\n", u.i);
+			break;
+		case DOUBLE:
+			u.d = (double)p->n_dcon;
+			printf("\t.xword %lld\n", u.l);
+			break;
+	}
+}
+
+char *
+exname(char *p)
+{
+	return p ? p : "";
+}
+
+TWORD
+ctype(TWORD type)
+{
+	return type;
+}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+void
+defzero(struct symtab *sp)
+{
+	int off = (tsize(sp->stype, sp->sdf, sp->sap) + SZCHAR - 1) / SZCHAR;
+	printf("\t.comm ");
+	if (sp->slevel == 0)
+		printf("%s,%d\n", sp->soname ? sp->soname : exname(sp->sname), off);
+	else
+		printf(LABFMT ",%d\n", sp->soffset, off);
+}
+
+int
+mypragma(char *str)
+{
+	return 0;
+}
+
+void
+fixdef(struct symtab *sp)
+{
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
+
Index: uspace/app/pcc/arch/sparc64/local2.c
===================================================================
--- uspace/app/pcc/arch/sparc64/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/sparc64/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2008 David Crawshaw <david@zentus.com>
+ * 
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "pass1.h"
+#include "pass2.h"
+
+
+char *
+rnames[] = {
+	/* "\%g0", always zero, removed due to 31-element class limit */
+	        "\%g1", "\%g2", "\%g3", "\%g4", "\%g5", "\%g6", "\%g7",
+	"\%o0", "\%o1", "\%o2", "\%o3", "\%o4", "\%o5", "\%o6", "\%o7",
+	"\%l0", "\%l1", "\%l2", "\%l3", "\%l4", "\%l5", "\%l6", "\%l7",
+	"\%i0", "\%i1", "\%i2", "\%i3", "\%i4", "\%i5", "\%i6", "\%i7",
+
+	"\%f0",  "\%f1",  "\%f2",  "\%f3",  "\%f4",  "\%f5",  "\%f6",  "\%f7",
+	"\%f8",  "\%f9",  "\%f10", "\%f11", "\%f12", "\%f13", "\%f14", "\%f15",
+	"\%f16", "\%f17", "\%f18", "\%f19", "\%f20", "\%f21", "\%f22", "\%f23",
+	"\%f24", "\%f25", "\%f26", "\%f27", "\%f28", "\%f29", "\%f30",
+	/*, "\%f31" XXX removed due to 31-element class limit */
+
+	"\%f0",  "\%f2",  "\%f4",  "\%f6",  "\%f8",  "\%f10", "\%f12", "\%f14",
+	"\%f16", "\%f18", "\%f20", "\%f22", "\%f24", "\%f26", "\%f28", "\%f30",
+
+	"\%sp", "\%fp",
+};
+
+void
+deflab(int label)
+{
+	printf(LABFMT ":\n", label);
+}
+
+void
+prologue(struct interpass_prolog *ipp)
+{
+	int i, stack;
+
+	stack = V9RESERVE + V9STEP(p2maxautooff);
+
+	for (i = ipp->ipp_regs[0]; i; i >>= 1)
+		if (i & 1)
+			stack += 16;
+
+	/* TODO printf("\t.proc %d\n"); */
+	if (ipp->ipp_vis)
+		printf("\t.global %s\n", ipp->ipp_name);
+	printf("\t.align 4\n");
+	printf("%s:\n", ipp->ipp_name);
+	if (SIMM13(stack))
+		printf("\tsave %%sp,-%d,%%sp\n", stack);
+	else {
+		printf("\tsetx -%d,%%g4,%%g1\n", stack);
+		printf("\tsave %%sp,%%g1,%%sp\n");
+	}
+}
+
+void
+eoftn(struct interpass_prolog *ipp)
+{
+	printf("\tret\n");
+	printf("\trestore\n");
+	printf("\t.type %s,#function\n", ipp->ipp_name);
+	printf("\t.size %s,(.-%s)\n", ipp->ipp_name, ipp->ipp_name);
+}
+
+void
+hopcode(int f, int o)
+{
+	char *str;
+
+	switch (o) {
+		case EQ:        str = "brz"; break;
+		case NE:        str = "brnz"; break;
+		case ULE:
+		case LE:        str = "brlez"; break;
+		case ULT:
+		case LT:        str = "brlz";  break;
+		case UGE:
+		case GE:        str = "brgez"; break;
+		case UGT:
+		case GT:        str = "brgz";  break;
+		case PLUS:      str = "add"; break;
+		case MINUS:     str = "sub"; break;
+		case AND:       str = "and"; break;
+		case OR:        str = "or";  break;
+		case ER:        str = "xor"; break;
+		default:
+			comperr("unknown hopcode: %d (with %c)", o, f);
+			return;
+	}
+
+	printf("%s%c", str, f);
+}
+
+int
+tlen(NODE *p)
+{
+	switch (p->n_type) {
+		case CHAR:
+		case UCHAR:
+			return 1;
+		case SHORT:
+		case USHORT:
+			return (SZSHORT / SZCHAR);
+		case FLOAT:
+			return (SZFLOAT / SZCHAR);
+		case DOUBLE:
+			return (SZDOUBLE / SZCHAR);
+		case INT:
+		case UNSIGNED:
+			return (SZINT / SZCHAR);
+		case LONG:
+		case ULONG:
+		case LONGLONG:
+		case ULONGLONG:
+			return SZLONGLONG / SZCHAR;
+		default:
+			if (!ISPTR(p->n_type))
+				comperr("tlen type unknown: %d");
+			return SZPOINT(p->n_type) / SZCHAR;
+	}
+}
+
+void
+zzzcode(NODE * p, int c)
+{
+	char *str;
+	NODE *l, *r;
+	l = p->n_left;
+	r = p->n_right;
+
+	switch (c) {
+
+	case 'A':	/* Add const. */
+		if (ISPTR(l->n_type) && l->n_rval == FP)
+			r->n_lval += V9BIAS;
+
+		if (SIMM13(r->n_lval))
+			expand(p, 0, "\tadd AL,AR,A1\t\t! add const\n");
+		else
+			expand(p, 0, "\tsetx AR,A3,A2\t\t! add const\n"
+			             "\tadd AL,A2,A1\n");
+		break;
+	case 'B':	/* Subtract const. */
+		if (ISPTR(l->n_type) && l->n_rval == FP)
+			r->n_lval -= V9BIAS;
+
+		if (SIMM13(r->n_lval))
+			expand(p, 0, "\tsub AL,AR,A1\t\t! subtract const\n");
+		else
+			expand(p, 0, "\tsetx AR,A3,A2\t\t! subtract const\n"
+			             "\tsub AL,A2,A1\n");
+		break;
+	case 'C':	/* Load constant to register. */
+		if (ISPTR(p->n_type))
+			expand(p, 0,
+				"\tsethi %h44(AL),A1\t\t! load label\n"
+				"\tor A1,%m44(AL),A1\n"
+				"\tsllx A1,12,A1\n"
+				"\tor A1,%l44(AL),A1\n");
+		else if (SIMM13(p->n_lval))
+			expand(p, 0, "\tor %g0,AL,A1\t\t\t! load const\n");
+		else
+			expand(p, 0, "\tsetx AL,A2,A1\t\t! load const\n");
+		break;
+	case 'F':	/* Floating-point comparison, cf. hopcode(). */
+		switch (p->n_op) {
+			case EQ:        str = "fbe"; break;
+			case NE:        str = "fbne"; break;
+			case ULE:
+			case LE:        str = "fbule"; break;
+			case ULT:
+			case LT:        str = "fbul";  break;
+			case UGE:
+			case GE:        str = "fbuge"; break;
+			case UGT:
+			case GT:        str = "fbug";  break;
+			/* XXX
+			case PLUS:      str = "add"; break;
+			case MINUS:     str = "sub"; break;
+			case AND:       str = "and"; break;
+			case OR:        str = "or";  break;
+			case ER:        str = "xor"; break;*/
+			default:
+				comperr("unknown float code: %d", p->n_op);
+				return;
+		}
+		printf(str);
+		break;
+
+	case 'Q':	/* Structure assignment. */
+		/* TODO Check if p->n_stsize is small and use a few ldx's
+		        to move the struct instead of memcpy. The equiv.
+			could be done on all the architectures. */
+		if (l->n_rval != O0)
+			printf("\tmov %s,%s\n", rnames[l->n_rval], rnames[O0]);
+		if (SIMM13(p->n_stsize))
+			printf("\tor %%g0,%d,%%o2\n", p->n_stsize);
+		else
+			printf("\tsetx %d,%%g1,%%o2\n", p->n_stsize);
+		printf("\tcall memcpy\t\t\t! struct assign (dest, src, len)\n");
+		printf("\tnop\n");
+		break;
+	default:
+		cerror("unknown zzzcode call: %c", c);
+	}
+}
+
+int
+rewfld(NODE * p)
+{
+	return (1);
+}
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+	printf("XXX fldexpand called\n"); /* XXX */
+	return 1;
+}
+
+int
+flshape(NODE * p)
+{
+	return SRREG;
+}
+
+int
+shtemp(NODE * p)
+{
+	return 0;
+}
+
+
+void
+adrcon(CONSZ val)
+{
+}
+
+void
+conput(FILE * fp, NODE * p)
+{
+	if (p->n_op != ICON) {
+		comperr("conput got bad op: %s", copst(p->n_op));
+		return;
+	}
+
+	if (p->n_name[0] != '\0') {
+		fprintf(fp, "%s", p->n_name);
+		if (p->n_lval > 0)
+			fprintf(fp, "+");
+		if (p->n_lval)
+			fprintf(fp, CONFMT, p->n_lval);
+	} else
+		fprintf(fp, CONFMT, p->n_lval);
+}
+
+void
+insput(NODE * p)
+{
+	comperr("insput");
+}
+
+void
+upput(NODE *p, int size)
+{
+	comperr("upput");
+}
+
+void
+adrput(FILE * io, NODE * p)
+{
+	int64_t off;
+
+	if (p->n_op == FLD) {
+		printf("adrput a FLD\n");
+		p = p->n_left;
+	}
+
+	if (p->n_op == UMUL && p->n_right == 0)
+		p = p->n_left;
+
+	off = p->n_lval;
+
+	switch (p->n_op) {
+	case NAME:
+		if (p->n_name[0] != '\0')
+			fputs(p->n_name, io);
+		if (off > 0)
+			fprintf(io, "+");
+		if (off != 0)
+			fprintf(io, CONFMT, (long long int)off);
+		return;
+	case OREG:
+		fprintf(io, "%s", rnames[p->n_rval]);
+		if (p->n_rval == FP)
+			off += V9BIAS;
+		if (p->n_rval == SP)
+			off += V9BIAS + V9RESERVE;
+		if (off > 0)
+			fprintf(io, "+");
+		if (off)
+			fprintf(io, CONFMT, (CONSZ)off);
+		return;
+	case ICON:
+		/* addressable value of the constant */
+		conput(io, p);
+		return;
+	case REG:
+		fputs(rnames[p->n_rval], io);
+		return;
+	case FUNARG:
+		/* We do something odd and store the stack offset in n_rval. */
+		fprintf(io, "%d", V9BIAS + V9RESERVE + p->n_rval);
+		return;
+	default:
+		comperr("bad address, %s, node %p", copst(p->n_op), p);
+		return;
+	}
+}
+
+void
+cbgen(int o, int lab)
+{
+}
+
+void
+myreader(struct interpass * ipole)
+{
+}
+
+void
+mycanon(NODE * p)
+{
+}
+
+void
+myoptim(struct interpass * ipole)
+{
+}
+
+void
+rmove(int s, int d, TWORD t)
+{
+	printf("\t");
+
+	if (t == FLOAT)	      printf("fmovs");
+	else if (t == DOUBLE) printf("fmovd");
+	else                  printf("mov");
+
+	printf(" %s,%s\t\t\t! rmove()\n", rnames[s], rnames[d]);
+}
+
+int
+gclass(TWORD t)
+{
+	if (t == FLOAT)
+		return CLASSB;
+	if (t == DOUBLE)
+		return CLASSC;
+	return CLASSA;
+}
+
+void
+lastcall(NODE *p)
+{
+}
+
+int
+special(NODE *p, int shape)
+{
+	return SRNOPE;
+}
+
+void mflags(char *str)
+{
+}
+
+int
+COLORMAP(int c, int *r)
+{
+	int num=0;
+
+	switch (c) {
+		case CLASSA:
+			num += r[CLASSA];
+			return num < 32;
+		case CLASSB:
+			num += r[CLASSB];
+			num += 2*r[CLASSC];
+			return num < 32;;
+		case CLASSC:
+			num += r[CLASSC];
+			num += 2*r[CLASSB];
+			return num < 17;
+		case CLASSD:
+			return 0;
+		default:
+			comperr("COLORMAP: unknown class: %d", c);
+			return 0;
+	}
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+	return 0;
+}
Index: uspace/app/pcc/arch/sparc64/macdefs.h
===================================================================
--- uspace/app/pcc/arch/sparc64/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/sparc64/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2008 David Crawshaw <david@zentus.com>
+ * 
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*
+ * Many arithmetic instructions take 'reg_or_imm' in SPARCv9, where imm
+ * means we can use a signed 13-bit constant (simm13). This gives us a
+ * shortcut for small constants, instead of loading them into a register.
+ * Special handling is required because 13 bits lies between SSCON and SCON.
+ */
+#define SIMM13(val) (val < 4096 && val > -4097)
+
+/*
+ * The SPARCv9 ABI specifies a stack bias of 2047 bits. This means that the
+ * end of our call space is %fp+V9BIAS, working back towards %sp+V9BIAS+176.
+ */
+#define V9BIAS 2047
+
+/*
+ * The ABI requires that every frame reserve 176 bits for saving registers
+ * in the case of a spill. The stack size must be 16-bit aligned.
+ */
+#define V9RESERVE 176
+#define V9STEP(x) ALIGN(x, 0xf)
+#define ALIGN(x, y) ((x & y) ? (x + y) & ~y : x)
+
+
+#define makecc(val,i)	lastcon = (lastcon<<8)|((val<<24)>>24);
+
+#define ARGINIT		(7*8) /* XXX */
+#define AUTOINIT	(0)
+
+/* Type sizes */
+#define SZCHAR		8
+#define SZBOOL		32
+#define SZINT		32
+#define SZFLOAT		32
+#define SZDOUBLE	64
+#define SZLDOUBLE	64
+#define SZLONG		64
+#define SZSHORT		16
+#define SZLONGLONG	64
+#define SZPOINT(t)	64
+
+/* Type alignments */
+#define ALCHAR		8
+#define ALBOOL		32
+#define ALINT		32
+#define ALFLOAT		32
+#define ALDOUBLE	64
+#define ALLDOUBLE	64
+#define ALLONG		64
+#define ALLONGLONG	64
+#define ALSHORT		16
+#define ALPOINT		64
+#define ALSTRUCT	32
+#define ALSTACK		64
+
+/* Min/max values. */
+#define	MIN_CHAR	-128
+#define	MAX_CHAR	127
+#define	MAX_UCHAR	255
+#define	MIN_SHORT	-32768
+#define	MAX_SHORT	32767
+#define	MAX_USHORT	65535
+#define	MIN_INT		-1
+#define	MAX_INT		0x7fffffff
+#define	MAX_UNSIGNED	0xffffffff
+#define	MIN_LONGLONG	0x8000000000000000LL
+#define	MAX_LONGLONG	0x7fffffffffffffffLL
+#define	MAX_ULONGLONG	0xffffffffffffffffULL
+#define	MIN_LONG	MIN_LONGLONG
+#define	MAX_LONG	MAX_LONGLONG
+#define	MAX_ULONG	MAX_ULONGLONG
+
+#define BOOL_TYPE	INT
+
+typedef	long long CONSZ;
+typedef	unsigned long long U_CONSZ;
+typedef long long OFFSZ;
+
+#define CONFMT	"%lld"
+#define LABFMT  "L%d"
+#define STABLBL "LL%d"
+
+#define BACKAUTO 		/* Stack grows negatively for automatics. */
+#define BACKTEMP 		/* Stack grows negatively for temporaries. */
+
+#undef	FIELDOPS
+#define RTOLBYTES
+
+#define ENUMSIZE(high,low) INT
+#define BYTEOFF(x) 	((x)&03)
+#define BITOOR(x)	(x)
+
+#define	szty(t)	((ISPTR(t) || (t) == DOUBLE || \
+	         (t) == LONG || (t) == ULONG || \
+	         (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1)
+
+
+/* Register names. */
+
+#define MAXREGS (31 + 31 + 16 + 2)
+#define NUMCLASS 4
+
+//define G0 	-1
+#define G1 	0
+#define G2 	1
+#define G3 	2
+#define G4 	3
+#define G5 	4
+#define G6 	5
+#define G7 	6
+#define O0 	7
+#define O1 	8
+#define O2 	9
+#define O3 	10
+#define O4 	11
+#define O5 	12
+#define O6 	13
+#define O7 	14
+#define L0 	15
+#define L1 	16
+#define L2 	17
+#define L3 	18
+#define L4 	19
+#define L5 	20
+#define L6 	21
+#define L7 	22
+#define I0 	23
+#define I1 	24
+#define I2 	25
+#define I3 	26
+#define I4 	27
+#define I5 	28
+#define I6 	29
+#define I7 	30
+
+#define F0 	31
+#define F1 	32
+#define F2 	33
+#define F3 	34
+#define F4 	35
+#define F5 	36
+#define F6 	37
+#define F7 	38
+#define F8 	39
+#define F9 	40
+#define F10	41
+#define F11	42
+#define F12	43
+#define F13	44
+#define F14	45
+#define F15	46
+#define F16	47
+#define F17	48
+#define F18	49
+#define F19	50
+#define F20	51
+#define F21	52
+#define F22	53
+#define F23	54
+#define F24	55
+#define F25	56
+#define F26	57
+#define F27	58
+#define F28	59
+#define F29	60
+#define F30	61
+//define F31    XXX
+#define D0	62
+#define D1	63
+#define D2	64
+#define D3	65
+#define D4	66
+#define D5	67
+#define D6	68
+#define D7	69
+#define D8	70
+#define D9	71
+#define D10	72
+#define D11	73
+#define D12	74
+#define D13	75
+#define D14	76
+#define D15	77
+
+#define SP 	78
+#define FP 	79
+
+#define FPREG 	FP
+
+#define RETREG(x)	((x)==DOUBLE ? D0 : (x)==FLOAT ? F1 : O0)
+#define RETREG_PRE(x)	((x)==DOUBLE ? D0 : (x)==FLOAT ? F1 : I0)
+
+#define RSTATUS \
+	/* global */ \
+		               SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \
+		SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \
+	/* out */ \
+		SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+		SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+	/* local */ \
+		SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+		SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+	/* in */ \
+		SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+		SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \
+	/* 32-bit floating point */ \
+		SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \
+		SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \
+		SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \
+		SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, /*, SBREG */ \
+	/* 64-bit floating point */ \
+		SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \
+		SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \
+	/* sp */ SDREG, \
+	/* fp */ SDREG
+
+#define ROVERLAP \
+	        { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+	{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \
+/* 32-bit floating point */ \
+	{  D0, -1 }, {  D0, -1 }, {  D1, -1 }, {  D1, -1 }, \
+	{  D2, -1 }, {  D2, -1 }, {  D3, -1 }, {  D3, -1 }, \
+	{  D4, -1 }, {  D4, -1 }, {  D5, -1 }, {  D5, -1 }, \
+	{  D6, -1 }, {  D6, -1 }, {  D7, -1 }, {  D7, -1 }, \
+	{  D8, -1 }, {  D8, -1 }, {  D9, -1 }, {  D9, -1 }, \
+	{ D10, -1 }, { D10, -1 }, { D11, -1 }, { D11, -1 }, \
+	{ D12, -1 }, { D12, -1 }, { D13, -1 }, { D13, -1 }, \
+	{ D14, -1 }, { D14, -1 }, { D15, -1 }, /* { D15, -1 }, */ \
+/* 64-bit floating point */ \
+	{  F0,  F1, -1 }, {  F2,  F3, -1 }, {  F4,  F5, -1 }, \
+	{  F6,  F7, -1 }, {  F8,  F9, -1 }, { F10, F11, -1 }, \
+	{ F12, F13, -1 }, { F14, F15, -1 }, { F16, F17, -1 }, \
+	{ F18, F19, -1 }, { F20, F21, -1 }, { F22, F23, -1 }, \
+	{ F24, F25, -1 }, { F26, F27, -1 }, { F28, F29, -1 }, \
+	{ F30, /* F31, */ -1 }, \
+	{ -1 }, \
+	{ -1 }
+
+#define GCLASS(x) 	(x <= I7                ? CLASSA : \
+			(x <= F30               ? CLASSB : \
+			(x <= D15               ? CLASSC : \
+			(x == SP || x == FP     ? CLASSD : 0))))
+#define PCLASS(p)	(1 << gclass((p)->n_type))
+#define DECRA(x,y)	(((x) >> (y*7)) & 127)
+#define ENCRA(x,y)	((x) << (7+y*7))
+#define ENCRD(x)	(x)
+
+int COLORMAP(int c, int *r);
Index: uspace/app/pcc/arch/sparc64/order.c
===================================================================
--- uspace/app/pcc/arch/sparc64/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/sparc64/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2008 David Crawshaw <david@zentus.com>
+ * 
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "pass2.h"
+
+/* 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 !SIMM13(off);
+}
+
+/*
+ * Turn a UMUL-referenced node into OREG.
+ */
+void
+offstar(NODE *p, int shape)
+{
+	if (x2debug)
+		printf("offstar(%p)\n", p);
+
+	if (p->n_op == PLUS || p->n_op == MINUS) {
+		if (p->n_right->n_op == ICON && SIMM13(p->n_right->n_lval)) {
+			if (isreg(p->n_left) == 0)
+				(void)geninsn(p->n_left, INAREG);
+			/* Converted in ormake() */
+			return;
+		}
+	}
+	(void)geninsn(p, INAREG);
+}
+
+void
+myormake(NODE *q)
+{
+}
+
+int
+shumul(NODE *p, int shape)
+{
+	if (shape & SOREG)
+		return SROREG;
+	return SRNOPE;
+}
+
+int
+setbin(NODE *p)
+{
+	return 0;
+}
+
+int
+setasg(NODE *p, int cookie)
+{
+	return 0;
+}
+
+int
+setuni(NODE *p, int cookie)
+{
+	return 0;
+}
+
+struct rspecial *
+nspecial(struct optab *q)
+{
+	switch (q->op) {
+	case STASG: {
+		static struct rspecial s[] = {
+			{ NEVER, O0 },
+			{ NRIGHT, O1 },
+			{ NEVER, O2 },
+			{ 0 }
+		};
+		return s;
+	}
+	}
+
+	comperr("unknown nspecial %d: %s", q - table, q->cstring);
+	return 0; /* XXX */
+}
+
+int
+setorder(NODE *p)
+{
+	return 0;
+}
+
+int *
+livecall(NODE *p)
+{
+	static int ret[] = { O0, O1, O2, O3, O4, O5, O6, O7, -1 };
+	return ret;
+}
+
+int
+acceptable(struct optab *op)
+{
+	return 1;
+}
Index: uspace/app/pcc/arch/sparc64/table.c
===================================================================
--- uspace/app/pcc/arch/sparc64/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/sparc64/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,963 @@
+/*
+ * Copyright (c) 2008 David Crawshaw <david@zentus.com>
+ * 
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "pass2.h"
+
+#define TS64   TLONG|TLONGLONG
+#define TU64   TULONG|TULONGLONG|TPOINT
+#define T64    TS64|TU64
+
+struct optab table[] = {
+
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },      /* empty */
+
+{ PCONV,	INAREG,
+	SAREG,	T64|TINT,
+	SAREG,	T64,
+		0,	RLEFT,
+		"	! convert between word and pointer\n", },
+
+/* Conversions. */
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TUNSIGNED,
+	SAREG,	TINT,
+		NAREG|NASL,	RESC1,
+		"	sra AL,0,A1	\t\t! (u)int64/32 -> (u)int32\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TINT|TUNSIGNED,
+	SAREG,	TSHORT,
+		NAREG|NASL,	RESC1,
+		"	sll AL,16,A1	\t\t! (u)int64/32 -> int16\n"
+		"	sra AL,16,A1\n"
+		"	sra AL, 0,A1\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TINT|TUNSIGNED,
+	SAREG,	TUSHORT,
+		NAREG|NASL,	RESC1,
+		"	sll AL,16,A1	\t\t! (u)int64/32 -> uint16\n"
+		"	srl AL,16,A1\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TINT|TUNSIGNED|TSHORT|TUSHORT,
+	SAREG,	TCHAR,
+		NAREG|NASL,	RESC1,
+		"	sll AL,24,A1	\t\t! (u)int64/32/16 -> int8\n"
+		"	sra AL,24,A1\n"
+		"	sra AL, 0,A1\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TINT|TUNSIGNED|TSHORT|TUSHORT,
+	SAREG,	TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	and AL,0xff,A1	\t\t! (u)int64/32/16 -> uint8\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, /* TCHAR|TUCHAR added to handle char -> long (among others) */
+	SAREG,	T64,
+		0,	RLEFT,
+		"	              	\t\t! (u)int64...8 -> (u)int64\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG,	TINT,
+		0,	RLEFT,
+		"	              	\t\t! (u)int16/8 -> int32\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	T64|TINT|TSHORT|TCHAR,
+	SAREG,	TUNSIGNED,
+		0,	RLEFT,
+		"	srl AL, 0,A1	\t\t! int32/16/8 -> uint32\n", },
+
+{ SCONV,	INAREG,
+	SAREG,	TUSHORT|TUCHAR,
+	SAREG,	TUNSIGNED,
+		0,	RLEFT,
+		"	              	\t\t! uint16/8 -> uint32\n", },
+
+{ SCONV,	INBREG,
+	SBREG,	TINT|TUNSIGNED,
+	SBREG,	TFLOAT,
+		NBREG|NASL,	RESC1,
+		"	fitos AL,A1         \t\t! (u)int32 -> float\n", },
+
+{ SCONV,	INBREG,
+	SBREG,	T64,
+	SBREG,	TFLOAT,
+		NBREG|NASL,	RESC1,
+		"	fxtos AL,A1         \t\t! (u)int64 -> float\n", },
+
+{ SCONV,	INCREG,
+	SCREG,	TINT|TUNSIGNED,
+	SCREG,	TDOUBLE,
+		NCREG|NASL,	RESC1,
+		"	fitod AL,A1         \t\t! (u)int32 -> double\n", },
+
+{ SCONV,	INCREG,
+	SCREG,	T64,
+	SCREG,	TDOUBLE,
+		NCREG|NASL,	RESC1,
+		"	fxtod AL,A1         \t\t! (u)int64 -> double\n", },
+
+
+/* Floating-point conversions must be stored and loaded. */
+
+{ SCONV, 	INAREG,
+	SOREG, 	TFLOAT,
+	SAREG,	TINT,
+		NAREG|(2*NBREG),	RESC1,
+		" 	ld [AL],A2    \t\t! float -> int32\n"
+		"	nop\n"
+		"	fmovs A2,A3\n"
+		"	fstoi A2,A2\n"
+		"	st A2,[AL]\n"
+		"	nop\n"
+		"	ld [AL],A1\n"
+		"	nop\n"
+		"	st A3,[AL]\n"
+		"	nop\n", },
+
+{ SCONV, 	INAREG,
+	SOREG, 	TDOUBLE,
+	SAREG,	TINT,
+		NAREG|(2*NCREG),	RESC1,
+		" 	ld [AL],A2    \t\t! double -> int32\n"
+		"	nop\n"
+		"	fmovd A2,A3\n"
+		"	fdtoi A2,A2\n"
+		"	std A2,[AL]\n"
+		"	nop\n"
+		"	ldd [AL],A1\n"
+		"	nop\n"
+		"	std A3,[AL]\n"
+		"	nop\n", },
+
+{ SCONV,	INBREG,
+	SOREG,	T64|TUNSIGNED,
+	SBREG,	TFLOAT,
+		NBREG,	RESC1,
+		"	ld [AL],A1	\t\t! int64 -> float\n"
+		"	fxtos A1,A1\n", },
+
+{ SCONV,	INBREG,
+	SOREG,	TINT|TSHORT|TCHAR,
+	SBREG,	TFLOAT,
+		NBREG,	RESC1,
+		"	ld [AL],A1	\t\t! int32/16/8 -> float\n"
+		"	fitos A1,A1\n", }, // XXX need 'lds', 'ldh', etc
+
+{ SCONV,	INCREG,
+	SOREG,	T64|TUNSIGNED,
+	SCREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	ldd [AL],A1	\t\t! (u)int64 -> double\n"
+		"	fxtod A1,A1\n", },
+
+{ SCONV,	INCREG,
+	SOREG,	TINT|TSHORT|TCHAR,
+	SCREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	ld [AL],A1	\t\t! int32/16/8 -> double\n"
+		"	fitod A1,A1\n", }, // XXX need 'lds' 'ldh' 'ld', etc.
+
+{ SCONV,	INBREG,
+	SCREG,	TDOUBLE,
+	SBREG,	TFLOAT,
+		NBREG,	RESC1,
+		"	fdtos AL,A1 	\t\t! double -> float\n",},
+
+{ SCONV,	INCREG,
+	SBREG,	TFLOAT,
+	SCREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	fstod AL,A1 	\t\t! float -> double\n",},
+
+{ SCONV,    INAREG,
+	SBREG,  TFLOAT,
+	SAREG,  TINT,
+		NAREG|NBREG,    RESC1,
+		"	fstoi AL,A2     \t\t! float -> int\n"
+		"	st A2,[%fp+2047]\n"
+		"	nop\n"
+		"	ld [%fp+2047],A1\n"
+		"	nop\n",},
+
+{ SCONV,    INAREG,
+	SCREG,  TDOUBLE,
+	SAREG,  TINT,
+		NAREG|NCREG,    RESC1,
+		"	fdtoi AL,A2     \t\t! double -> int\n"
+		"	st A2,[%fp+2047]\n"
+		"	nop\n"
+		"	ld [%fp+2047],A1\n"
+        "	nop\n",},
+
+
+/* Multiplication and division */
+
+{ MUL,	INAREG,
+	SAREG,	TANY,
+	SAREG,	TANY,
+		NAREG|NASR|NASL,	RESC1,
+		"	mulx AL,AR,A1		! multiply\n", },
+
+{ MUL,	INBREG,
+	SBREG,	TFLOAT,
+	SBREG,	TFLOAT,
+		NBREG|NBSR|NBSL,	RESC1,
+		"	fmuls AL,AR,A1		! multiply float\n", },
+
+{ MUL,	INCREG,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG|NCSR|NCSL,	RESC1,
+		"	fmuld AL,AR,A1		! multiply double\n", },
+
+{ DIV,	INAREG,
+	SAREG,	TUNSIGNED|TUSHORT|TUCHAR|TU64,
+	SAREG,	TUNSIGNED|TUSHORT|TUCHAR|TU64,
+		NAREG|NASR|NASL,	RESC1,
+		"	udivx AL,AR,A1		! unsigned division\n", },
+
+{ DIV,	INAREG,
+	SAREG,	TINT|TSHORT|TCHAR|TS64,
+	SAREG,	TINT|TSHORT|TCHAR|TS64,
+		NAREG|NASR|NASL,	RESC1,
+		"	sdivx AL,AR,A1		! signed division\n", },
+
+{ DIV,	INBREG,
+	SBREG,	TFLOAT,
+	SBREG,	TFLOAT,
+		NBREG|NBSR|NBSL,	RESC1,
+		"	fdivs AL,AR,A1		! divide float\n", },
+
+{ DIV,	INCREG,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG|NCSR|NCSL,	RESC1,
+		"	fdivd AL,AR,A1		! divide double\n", },
+
+{ MOD,	INAREG,
+	SAREG,	TUNSIGNED|TUSHORT|TUCHAR|TU64,
+	SAREG,	TUNSIGNED|TUSHORT|TUCHAR|TU64,
+		NAREG, RESC1,
+		"	udivx AL,AR,A1		! unsigned modulo\n"
+		"	mulx A1,AR,A1\n"
+		"	sub AL,A1,A1\n", },
+
+{ MOD,	INAREG,
+	SAREG,	TINT|TSHORT|TCHAR|TS64,
+	SAREG,	TINT|TSHORT|TCHAR|TS64,
+		NAREG, RESC1,
+		"	sdivx AL,AR,A1		! signed modulo\n"
+		"	mulx A1,AR,A1\n"
+		"	sub AL,A1,A1\n", },
+
+{ PLUS,	INAREG,
+	SAREG,	TANY,
+	SAREG,	TANY,
+		NAREG|NASL,	RESC1,
+      		"	add AL,AR,A1\n", },
+
+{ PLUS,	INBREG,
+	SBREG,	TFLOAT,
+	SBREG,	TFLOAT,
+		NBREG|NBSL,	RESC1,
+      		"	fadds AL,AR,A1\n", },
+
+{ PLUS,	INCREG,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG|NCSL,	RESC1,
+      		"	faddd AL,AR,A1\n", },
+
+{ PLUS,	INAREG,
+	SAREG,	TANY,
+	SCON,	TANY,
+		(3*NAREG),	RESC1,
+		"ZA", },
+
+{ MINUS,	INAREG,
+	SAREG,	TANY,
+	SAREG,	TANY,
+		NAREG|NASL,	RESC1,
+		"	sub AL,AR,A1\n", },
+
+{ MINUS,	INBREG,
+	SBREG,	TANY,
+	SBREG,	TANY,
+		NBREG|NBSL|NBSR,	RESC1,
+      		"	fsubs AL,AR,A1\n", },
+
+{ MINUS,	INCREG,
+	SCREG,	TANY,
+	SCREG,	TANY,
+		NCREG|NCSL|NBSR,	RESC1,
+      		"	fsubd AL,AR,A1\n", },
+
+{ MINUS,	INAREG,
+	SAREG,	TANY,
+	SCON,	TANY,
+		(3*NAREG),	RESC1,
+		"ZB", },
+
+{ UMINUS,	INAREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,
+		"	sub %g0,AL,A1\n", },
+
+{ UMINUS,	INBREG,
+	SBREG,	TANY,
+	SANY,	TANY,
+		NBREG|NBSL,	RESC1,
+		"	fsubs %g0,AL,A1\n", },
+
+{ UMINUS,	INCREG,
+	SCREG,	TANY,
+	SANY,	TANY,
+		NCREG|NCSL,	RESC1,
+		"	fsubd %g0,AL,A1\n", },
+
+/* Shifts */
+
+{ RS,	INAREG,
+	SAREG,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG|SCON,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	srl AL,AR,A1			! shift right\n", },
+
+{ RS,	INAREG,
+	SAREG,	T64,
+	SAREG|SCON,	T64|TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	srlx AL,AR,A1			! shift right\n", },
+
+{ LS,	INAREG,
+	SAREG,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+	SAREG|SCON,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	sll AL,AR,A1			! shift left\n", },
+
+{ LS,	INAREG,
+	SAREG,	T64,
+	SAREG|SCON,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
+		NAREG|NASL,	RESC1,
+		"	sllx AL,AR,A1			! shift left\n", },
+
+{ COMPL,	INAREG,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,
+		"	not AL,A1			! complement\n", },
+
+/* Assignments */
+
+{ ASSIGN,	FOREFF|INAREG,			/* FIXME: Remove [,] here and add them in adrput instead. */
+	SAREG|SOREG,	TINT|TUNSIGNED,
+	SAREG,	TINT|TUNSIGNED,
+		0,	RDEST,
+		"	stw AR,[AL]		! store (u)int32\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,	TSHORT|TUSHORT,
+	SAREG,	TSHORT|TUSHORT,
+		0,	RDEST,
+        	"	sth AR,[AL]		! store (u)int16\n"
+		"	nop\n", },	
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,	TCHAR|TUCHAR,
+	SAREG,	TCHAR|TUCHAR,
+		0,	RDEST,
+        	"	stb AR,[AL]		! store (u)int8\n"
+		"	nop\n", },	
+
+{ ASSIGN,	FOREFF|INAREG,
+	SOREG,	T64,
+	SAREG,	T64,
+		0,	RDEST,
+		"	stx AR,[AL] 		! store (u)int64\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SOREG,	TFLOAT,
+	SBREG,	TFLOAT,
+		0,	RDEST,
+		"	st AR,[AL] 		! store float\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SOREG,	TINT,
+	SBREG,	TINT,
+		0,	RDEST,
+		"	st AR,[AL] 		! store int from fp address\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SOREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		0,	RDEST,
+		"	std AR,[AL] 		! store double\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SOREG,	TINT,
+	SCREG,	TINT,
+		0,	RDEST,
+		"	st AR,[AL] 		! store int from fp address\n"
+		"	nop\n", },
+
+
+{ ASSIGN,	FOREFF|INAREG,
+	SNAME,	TINT|TUNSIGNED,
+	SAREG,	TINT|TUNSIGNED,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store (u)int32 into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	stw AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SNAME,	TSHORT|TUSHORT,
+	SAREG,	TSHORT|TUSHORT,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store (u)int16 into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	sth AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SNAME,	TCHAR|TUCHAR,
+	SAREG,	TCHAR|TUCHAR,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store (u)int8 into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	stb AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SNAME,	T64,
+	SAREG,	T64,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store (u)int64 into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	stx AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SNAME,	TFLOAT|TINT,
+	SBREG,	TFLOAT|TINT,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store float into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	st AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SNAME,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store double into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	std AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SNAME,	TINT,
+	SCREG,	TINT,
+		NAREG,	RDEST,
+		"	sethi %h44(AL),A1	\t! store int into sname\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	st AR,[A1+%l44(AL)]\n"
+		"	nop\n", },
+
+{ ASSIGN,	FOREFF|INAREG,
+	SAREG,	TANY,
+	SAREG,	TANY,
+		0,	RDEST,
+		"	mov AR,AL			! register move\n", },
+
+{ ASSIGN,	FOREFF|INBREG,
+	SBREG,	TANY,
+	SBREG,	TANY,
+		0,	RDEST,
+		"	fmovs AR,AL			! move float\n", },
+
+{ ASSIGN,	FOREFF|INCREG,
+	SCREG,	TANY,
+	SCREG,	TANY,
+		0,	RDEST,
+		"	fmovd AR,AL			! move double\n", },
+
+/* Structure assignment. */
+
+{ STASG,	INAREG|FOREFF,
+	SOREG|SNAME,	TANY,
+	SAREG,		TPTRTO|TANY,
+		NSPECIAL,	RDEST,
+		"ZQ", },
+
+/* Comparisons. */
+
+{ EQ,	FORCC,
+        SAREG,	TANY,
+        SAREG,	TANY,
+                0,      RESCC,
+		"	cmp AL,AR			! eq\n"
+		"	be LC\n"
+		"	nop\n", },
+
+{ NE,	FORCC,
+        SAREG,	TANY,
+        SAREG,	TANY,
+                0,      RESCC,
+		"	cmp AL,AR			! ne\n"
+                "	bne LC\n"
+		"	nop\n", },
+
+{ OPLOG,	FORCC,
+	SAREG,	TANY,
+	SZERO,	TANY,
+		0,	RESCC,
+		"	O AL,LC\n"
+		"	nop\n", },
+
+{ OPLOG,	FORCC,
+	SAREG,	TANY,
+	SAREG,	TANY,
+		NAREG|NASL,	RESCC,
+		"	sub AL,AR,A1			! oplog\n"
+		"	O A1,LC\n"
+		"	nop\n", },
+
+{ OPLOG,	FORCC,
+	SAREG,	TANY,
+	SCCON,	TANY,
+		NAREG|NASL,	RESCC,
+		"	sub AL,AR,A1			! oplog sccon\n"
+		"	O A1,LC\n"
+		"	nop\n", },
+
+{ OPLOG,	FORCC,
+	SBREG,	TFLOAT,
+	SBREG,	TFLOAT,
+		NBREG, RESCC,
+		"	fcmps AL,AR			! oplog float\n"
+		"	ZF LC\n", },
+
+{ OPLOG,	FORCC,
+	SOREG,	TFLOAT,
+	SBREG,	TFLOAT,
+		NBREG, RESCC,
+		"	ld [AL], A1    			! oplog float oreg\n"
+		"	nop\n"
+		"	fcmps A1,AR\n"
+		"	ZF LC\n", },
+
+{ OPLOG,	FORCC,
+	SCREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG, RESCC,
+		"	fcmpd AL,AR			! oplog double\n"
+		"	ZF LC\n", },
+
+{ OPLOG,	FORCC,
+	SOREG,	TDOUBLE,
+	SCREG,	TDOUBLE,
+		NCREG, RESCC,
+		"	ldd [AL], A1   			! oplog double oreg\n"
+		"	nop\n"
+		"	fcmpd A1,AR\n"
+		"	ZF LC\n", },
+
+
+/* Load constants to register. */
+
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		T64,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t	! load const (u)int64 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ldx [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		TINT,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t	! load const int32 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ldsw [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		TUNSIGNED,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t! load const uint32 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	lduw [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		TSHORT,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t! load const int16 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ldsh [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		TUSHORT,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t	! load const uint16 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	lduh [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		TCHAR,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t\t! load const int8 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ldsb [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+{ OPLTYPE,	INAREG,
+	SCON,		TANY,
+	SNAME,		TUCHAR,
+		NAREG,	RESC1,
+		"	sethi %h44(AL),A1\t! load const uint8 to reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ldub [A1+%l44(AL)],A1\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INBREG,
+	SBREG,	TANY,
+	SNAME,	TANY,
+		NAREG|NBREG,	RESC2,
+		"	sethi %h44(AL),A1\t\t! load const to fp reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ld [A1+%l44(AL)],A2\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INCREG,
+	SCREG,	TANY,
+	SNAME,	TANY,
+		NAREG|NCREG,	RESC2,
+		"	sethi %h44(AL),A1\t\t! load const to fp reg\n"
+		"	or A1,%m44(AL),A1\n"
+		"	sllx A1,12,A1\n"
+		"	ldd [A1+%l44(AL)],A2\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SCON,	TANY,
+		(2*NAREG),	RESC1,
+		"ZC" },
+
+/* Convert LTYPE to reg. */
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	TCHAR,
+		NAREG,	RESC1,
+		"	ldsb [AL],A1		! load int8 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	TUCHAR,
+		NAREG,	RESC1,
+		"	ldub [AL],A1		! load uint8 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	TSHORT,
+		NAREG,	RESC1,
+		"	ldsh [AL],A1		! load int16 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	TUSHORT,
+		NAREG,	RESC1,
+		"	lduh [AL],A1		! load uint16 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	TINT,
+		NAREG,	RESC1,
+		"	ldsw [AL],A1		! load int32 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	TUNSIGNED,
+		NAREG,	RESC1,
+		"	lduw [AL],A1		! load uint32 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SAREG,	TANY,
+	SOREG,	T64,
+		NAREG,	RESC1,
+		"	ldx [AL],A1		! load (u)int64 to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INAREG,
+	SANY,	TANY,
+	SZERO,	TANY,
+		NAREG,	RESC1,
+		"	mov \%g0,A1\t		! load 0 to reg\n", },
+
+{ OPLTYPE,	INBREG,
+	SBREG,	TFLOAT,
+	SOREG,	TFLOAT,
+		NBREG,	RESC1,
+		"	ld [AL],A1  		! load float to reg\n"
+		"	nop\n", },
+
+{ OPLTYPE,	INCREG,
+	SCREG,	TDOUBLE,
+	SOREG,	TDOUBLE,
+		NCREG,	RESC1,
+		"	ldd [AL],A1  		! load double to reg\n"
+		"	nop\n", },
+
+/* Jumps. */
+
+{ GOTO, 	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	call LL		 	! goto LL\n"
+		"	nop\n", },
+
+{ UCALL,	FOREFF,
+	SCON,		TANY,
+	SANY,		TANY,
+		0,	0,
+		"	call CL			! void CL()\n"
+		"	nop\n", },
+
+{ UCALL,         INAREG,
+        SCON,		TANY,
+        SAREG,          TANY,
+                NAREG,     RESC1,
+		"	call CL			! = CL()\n"
+		" 	nop\n", },
+
+{ CALL,		FOREFF,
+	SCON,		TANY,
+	SANY,		TANY,
+		0,	0,
+		"	call CL			! void CL(constant)\n"
+		"	nop\n", },
+
+{ CALL,		INAREG,
+	SCON,		TANY,
+	SAREG,		TANY,
+		NAREG,		RESC1,
+		"	call CL			! = CL(constant)\n"
+		"	nop\n", },
+
+{ CALL,		INBREG,
+	SCON,		TANY,
+	SBREG,		TFLOAT,
+		NBREG,		RESC1,
+		"	call CL			! = CL(constant)\n"
+		"	nop\n", },
+
+{ CALL,		INCREG,
+	SCON,		TANY,
+	SCREG,		TDOUBLE,
+		NCREG,		RESC1,
+		"	call CL			! = CL(constant)\n"
+		"	nop\n", },
+
+{ CALL,         INAREG,
+        SAREG,		TANY,
+        SAREG,		TANY,
+                NAREG,     RESC1,
+		"	call AL			! = AL(args)\n"
+		"	nop\n", },
+
+{ CALL,		FOREFF,
+	SAREG,		TANY,
+	SANY,		TANY,
+		0,		0,
+		"	call AL			! void AL(args)\n"
+		"	nop\n", },
+
+{ UCALL,	FOREFF,
+	SAREG,		TANY,
+	SANY,		TANY,
+		0,	0,
+		"	call AL			! (*AL)()\n"
+		"	nop\n", },
+
+{ UCALL,	INAREG,
+	SAREG,		TANY,
+	SAREG,		TANY,
+		NAREG,		RESC1,
+		"	call AL			! = (*AL)()\n"
+		"	nop\n", },
+
+{ CALL,		INAREG,
+	SAREG,		TANY,
+	SAREG,		TANY,
+		NAREG,		RESC1,
+		"	call AL			! = (*AL)(args)\n"
+		"	nop\n", },
+
+/* Function arguments. */
+
+{ FUNARG,       FOREFF,
+        SAREG,  T64,
+        SANY,   TANY,
+                0,      0,
+                "	stx AL,[%sp+AR]   	\t! save func arg to stack\n"
+		"	nop\n", },
+
+{ FUNARG,       FOREFF,
+        SAREG,  TINT|TUNSIGNED,
+        SANY,   TANY,
+                0,      0,
+                "	stw AL,[%sp+AR]   	\t! save func arg to stack\n"
+		"	nop\n", },
+
+{ FUNARG,       FOREFF,
+        SAREG,  TSHORT|TUSHORT,
+        SANY,   TANY,
+                0,      0,
+                "	sth AL,[%sp+AR]   	\t! save func arg to stack\n"
+		"	nop\n", },
+
+{ FUNARG,       FOREFF,
+        SAREG,  TCHAR|TUCHAR,
+        SANY,   TANY,
+                0,      0,
+                "	stb AL,[%sp+AR]  	\t! save func arg to stack\n"
+		"	nop\n", },
+
+{ FUNARG,       FOREFF,
+        SBREG,  TFLOAT,
+        SANY,   TANY,
+                0,      0,
+                "	st AL,[%sp+AR]  	\t! save func arg to stack\n"
+		"	nop\n", },
+
+{ FUNARG,       FOREFF,
+        SCREG,  TDOUBLE,
+        SANY,   TANY,
+                0,      0,
+                "	std AL,[%sp+AR]  	\t! save func arg to stack\n"
+		"	nop\n", },
+
+
+/* Indirection. */
+
+{ OPSIMP,	INAREG,
+	SAREG,	TANY,
+	SAREG,	TANY,
+		NAREG|NASR|NASL,	RESC1,
+		"	O AL,AR,A1\n", },
+
+{ UMUL, INAREG,
+	SAREG,	T64,
+	SOREG,	T64,
+		NAREG,		RESC1,
+		"	ldx [AL],A1		! (u)int64 load\n"
+		"	nop\n", },
+{ UMUL, INAREG,
+	SAREG,	TINT,
+	SOREG,	TINT,
+		NAREG,		RESC1,
+		"	ldsw [AL],A1		! int32 load\n"
+		"	nop\n", },
+{ UMUL, INAREG,
+	SAREG,	TUNSIGNED,
+	SOREG,	TUNSIGNED,
+		NAREG,		RESC1,
+		"	lduw [AL],A1		! uint32 load\n"
+		"	nop\n", },
+{ UMUL, INAREG,
+	SAREG,	TCHAR,
+	SOREG,	TCHAR,
+		NAREG,		RESC1,
+		"	ldsb [AL],A1		! int8 load\n"
+		"	nop\n", },
+{ UMUL, INAREG,
+	SAREG,	TUCHAR,
+	SOREG,	TUCHAR,
+		NAREG,		RESC1,
+		"	ldub [AL],A1		! uint8 load\n"
+		"	nop\n", },
+{ UMUL, INAREG,
+	SAREG,	TSHORT,
+	SOREG,	TSHORT,
+		NAREG,		RESC1,
+		"	ldsh [AL],A1		! int16 load\n"
+		"	nop\n", },
+{ UMUL, INAREG,
+	SAREG,	TUSHORT,
+	SOREG,	TUSHORT,
+		NAREG,		RESC1,
+		"	lduh [AL],A1		! uint16 load\n"
+		"	nop\n", },
+
+{ UMUL, INBREG,
+	SAREG,	TFLOAT,
+	SOREG,	TFLOAT,
+		NBREG,		RESC1,
+		"	ld [AL],A1		! load float\n"
+		"	nop\n", },
+
+{ UMUL, INCREG,
+	SAREG,	TDOUBLE,
+	SOREG,	TDOUBLE,
+		NCREG,		RESC1,
+		"	ldd [AL],A1		! load double\n"
+		"	nop\n", },
+
+{ FREE,FREE,FREE,FREE,FREE,FREE,FREE,FREE, "ERR: printing free op\n" },
+
+};
+
+int tablesize = sizeof(table)/sizeof(table[0]);
Index: uspace/app/pcc/arch/vax/code.c
===================================================================
--- uspace/app/pcc/arch/vax/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/vax/code.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,330 @@
+/*	$Id: code.c,v 1.8 2009/02/08 16:55:08 ragge Exp $	*/
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass1.h"
+
+short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3};
+#define LOG2SZ 9
+
+void
+defalign(n) {
+	/* cause the alignment to become a multiple of n */
+	n /= SZCHAR;
+	if( lastloc != PROG && n > 1 ) printf( "	.align	%d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 );
+	}
+
+/*
+ * output something to define the current position as label n
+ */
+void
+deflab1(int n)
+{
+	printf(LABFMT ":\n", n);
+}
+
+void
+efcode(){
+	/* code for the end of a function */
+	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+		return;
+	cerror("efcode");
+
+#ifdef notyet
+	if( strftn ){  /* copy output (in R2) to caller */
+		register NODE *l, *r;
+		register struct symtab *p;
+		register TWORD t;
+		register int j;
+		int i;
+
+		p = &stab[curftn];
+		t = p->stype;
+		t = DECREF(t);
+
+		deflab( retlab );
+
+		i = getlab();	/* label for return area */
+		printf("	.data\n" );
+		printf("	.align	2\n" );
+		deflab1(i);
+		printf("\t.space  %d\n", tsize(t, p->dimoff, p->sizoff)/SZCHAR);
+		printf("	.text\n" );
+		psline();
+		printf("	movab	" LABFMT ",r1\n", i);
+
+		reached = 1;
+		l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
+		l->rval = 1;  /* R1 */
+		l->lval = 0;  /* no offset */
+		r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
+		r->rval = 0;  /* R0 */
+		r->lval = 0;
+		l = buildtree( UNARY MUL, l, NIL );
+		r = buildtree( UNARY MUL, r, NIL );
+		l = buildtree( ASSIGN, l, r );
+		l->op = FREE;
+		ecomp( l->left );
+		printf( "	movab	" LABFMT ",r0\n", i );
+		/* turn off strftn flag, so return sequence will be generated */
+		strftn = 0;
+		}
+	branch( retlab );
+	printf( "	.set	.R%d,0x%x\n", ftnno, ent_mask[reg_use] );
+	reg_use = 11;
+	p2bend();
+	fdefflag = 0;
+#endif
+	}
+
+void
+bfcode(struct symtab **a, int n)
+{
+	int i;
+
+	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
+		return;
+	/* Function returns struct, adjust arg offset */
+	for (i = 0; i < n; i++)
+		a[i]->soffset += SZPOINT(INT);
+}
+
+void
+bccode(){ /* called just before the first executable statment */
+		/* by now, the automatics and register variables are allocated */
+	SETOFF( autooff, SZINT );
+#if 0
+	/* set aside store area offset */
+	p2bbeg( autooff, regvar );
+	reg_use = (reg_use > regvar ? regvar : reg_use);
+#endif
+	}
+
+void
+ejobcode( flag ){
+	/* called just before final exit */
+	/* flag is 1 if errors, 0 if none */
+	}
+
+void
+bjobcode()
+{
+}
+
+#if 0
+aobeg(){
+	/* called before removing automatics from stab */
+	}
+
+aocode(p) struct symtab *p; {
+	/* called when automatic p removed from stab */
+	}
+
+aoend(){
+	/* called after removing all automatics from stab */
+	}
+#endif
+
+void
+defnam( p ) register struct symtab *p; {
+	/* define the current location as the name p->sname */
+	char *n;
+
+	n = p->soname ? p->soname : exname(p->sname);
+	if( p->sclass == EXTDEF ){
+		printf( "	.globl	%s\n", n );
+		}
+	printf( "%s:\n", n );
+
+	}
+
+void
+bycode( t, i ){
+	/* put byte i+1 in a string */
+
+	i &= 07;
+	if( t < 0 ){ /* end of the string */
+		if( i != 0 ) printf( "\n" );
+		}
+
+	else { /* stash byte t into string */
+		if( i == 0 ) printf( "	.byte	" );
+		else printf( "," );
+		printf( "0x%x", t );
+		if( i == 07 ) printf( "\n" );
+		}
+	}
+
+int
+fldal( t ) unsigned t; { /* return the alignment of field of type t */
+	uerror( "illegal field type" );
+	return( ALINT );
+	}
+
+void
+fldty( p ) struct symtab *p; { /* fix up type of field p */
+	;
+	}
+
+/*
+ * XXX - fix genswitch.
+ */
+int
+mygenswitch(int num, TWORD type, struct swents **p, int n)
+{
+	return 0;
+}
+
+#ifdef notyet
+struct sw heapsw[SWITSZ];	/* heap for switches */
+
+genswitch(p,n) register struct sw *p;{
+	/*	p points to an array of structures, each consisting
+		of a constant value and a label.
+		The first is >=0 if there is a default label;
+		its value is the label number
+		The entries p[1] to p[n] are the nontrivial cases
+		*/
+	register i;
+	register CONSZ j, range;
+	register dlab, swlab;
+
+	range = p[n].sval-p[1].sval;
+
+	if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */
+
+		swlab = getlab();
+		dlab = p->slab >= 0 ? p->slab : getlab();
+
+		/* already in r0 */
+		printf("	casel	r0,$%ld,$%ld\n", p[1].sval, range);
+		deflab1(swlab);
+		for( i=1,j=p[1].sval; i<=n; j++) {
+			printf("	.word	" LABFMT "-" LABFMT "\n",
+			    (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab),
+				swlab);
+			}
+
+		if( p->slab >= 0 ) branch( dlab );
+		else deflab1(dlab);
+		return;
+
+		}
+
+	if( n>8 ) {	/* heap switch */
+
+		heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab();
+		makeheap(p, n, 1);	/* build heap */
+
+		walkheap(1, n);	/* produce code */
+
+		if( p->slab >= 0 )
+			branch( dlab );
+		else
+			deflab1(dlab);
+		return;
+	}
+
+	/* debugging code */
+
+	/* out for the moment
+	if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) );
+	*/
+
+	/* simple switch code */
+
+	for( i=1; i<=n; ++i ){
+		/* already in r0 */
+
+		printf( "	cmpl	r0,$" );
+		printf( CONFMT, p[i].sval );
+		printf( "\n	jeql	" LBLFMT "\n", p[i].slab );
+		}
+
+	if( p->slab>=0 ) branch( p->slab );
+	}
+
+makeheap(p, m, n)
+register struct sw *p;
+{
+	register int q;
+
+	q = select(m);
+	heapsw[n] = p[q];
+	if( q>1 ) makeheap(p, q-1, 2*n);
+	if( q<m ) makeheap(p+q, m-q, 2*n+1);
+}
+
+select(m) {
+	register int l,i,k;
+
+	for(i=1; ; i*=2)
+		if( (i-1) > m ) break;
+	l = ((k = i/2 - 1) + 1)/2;
+	return( l + (m-k < l ? m-k : l));
+}
+
+walkheap(start, limit)
+{
+	int label;
+
+
+	if( start > limit ) return;
+	printf("	cmpl	r0,$%d\n",  heapsw[start].sval);
+	printf("	jeql	" LBLFMT "\n", heapsw[start].slab);
+	if( (2*start) > limit ) {
+		printf("	jbr 	" LBLFMT "\n", heapsw[0].slab);
+		return;
+	}
+	if( (2*start+1) <= limit ) {
+		label = getlab();
+		printf("	jgtr	" LBLFMT "\n", label);
+	} else
+		printf("	jgtr	" LBLFMT "\n", heapsw[0].slab);
+	walkheap( 2*start, limit);
+	if( (2*start+1) <= limit ) {
+		deflab1(label);
+		walkheap( 2*start+1, limit);
+	}
+}
+#endif
+/*
+ * Called with a function call with arguments as argument.
+ * This is done early in buildtree() and only done once.
+ */
+NODE *
+funcode(NODE *p)
+{
+	return p;
+}
Index: uspace/app/pcc/arch/vax/local.c
===================================================================
--- uspace/app/pcc/arch/vax/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/vax/local.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,511 @@
+/*	$Id: local.c,v 1.10 2011/01/21 21:47:59 ragge Exp $	*/
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ *	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.	IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass1.h"
+
+/*	this file contains code which is dependent on the target machine */
+
+#if 0
+NODE *
+cast( p, t ) register NODE *p; TWORD t; {
+	/* cast node p to type t */
+
+	p = buildtree( CAST, block( NAME, NIL, NIL, t, 0, (int)t ), p );
+	p->left->op = FREE;
+	p->op = FREE;
+	return( p->right );
+	}
+#endif
+
+NODE *
+clocal(p) NODE *p; {
+
+	/* this is called to do local transformations on
+	   an expression tree preparitory to its being
+	   written out in intermediate code.
+	*/
+
+	/* the major essential job is rewriting the
+	   automatic variables and arguments in terms of
+	   REG and OREG nodes */
+	/* conversion ops which are not necessary are also clobbered here */
+	/* in addition, any special features (such as rewriting
+	   exclusive or) are easily handled here as well */
+
+	register struct symtab *q;
+	register NODE *r;
+	register int o;
+	register int m, ml;
+
+	switch( o = p->n_op ){
+
+	case NAME:
+		if((q = p->n_sp) == 0 ) { /* already processed; ignore... */
+			return(p);
+			}
+		switch( q->sclass ){
+
+		case AUTO:
+		case PARAM:
+			/* fake up a structure reference */
+			r = block( REG, NIL, NIL, PTR+STRTY, 0, 0 );
+			r->n_lval = 0;
+			r->n_rval = (q->sclass==AUTO?STKREG:ARGREG);
+			p = stref( block( STREF, r, p, 0, 0, 0 ) );
+			break;
+
+		case STATIC:
+			if( q->slevel == 0 ) break;
+			p->n_lval = 0;
+			p->n_rval = -q->soffset;
+			break;
+
+		case REGISTER:
+			p->n_op = REG;
+			p->n_lval = 0;
+			p->n_rval = q->soffset;
+			break;
+
+			}
+		break;
+
+	case PCONV:
+		/* do pointer conversions for char and longs */
+		ml = p->n_left->n_type;
+		if( ( ml==CHAR || ml==UCHAR || ml==SHORT || ml==USHORT ) && p->n_left->n_op != ICON ) break;
+
+		/* pointers all have the same representation; the type is inherited */
+
+	inherit:
+		p->n_left->n_type = p->n_type;
+		p->n_left->n_df = p->n_df;
+		p->n_left->n_sue = p->n_sue;
+		r = p->n_left;
+		nfree(p);
+		return( r );
+
+	case SCONV:
+		m = (p->n_type == FLOAT || p->n_type == DOUBLE );
+		ml = (p->n_left->n_type == FLOAT || p->n_left->n_type == DOUBLE );
+		if( m != ml ) break;
+
+		/* now, look for conversions downwards */
+
+		m = p->n_type;
+		ml = p->n_left->n_type;
+		if( p->n_left->n_op == ICON ){ /* simulate the conversion here */
+			CONSZ val;
+			val = p->n_left->n_lval;
+			switch( m ){
+			case CHAR:
+				p->n_left->n_lval = (char) val;
+				break;
+			case UCHAR:
+				p->n_left->n_lval = val & 0XFF;
+				break;
+			case USHORT:
+				p->n_left->n_lval = val & 0XFFFFL;
+				break;
+			case SHORT:
+				p->n_left->n_lval = (short)val;
+				break;
+			case UNSIGNED:
+				p->n_left->n_lval = val & 0xFFFFFFFFL;
+				break;
+			case INT:
+				p->n_left->n_lval = (int)val;
+				break;
+				}
+			p->n_left->n_type = m;
+			}
+		else {
+			/* meaningful ones are conversion of int to char, int to short,
+			   and short to char, and unsigned version of them */
+			if( m==CHAR || m==UCHAR ){
+				if( ml!=CHAR && ml!= UCHAR ) break;
+				}
+			else if( m==SHORT || m==USHORT ){
+				if( ml!=CHAR && ml!=UCHAR && ml!=SHORT && ml!=USHORT ) break;
+				}
+			}
+
+		/* clobber conversion */
+		if( tlen(p) == tlen(p->n_left) ) goto inherit;
+		r = p->n_left;
+		nfree(p);
+		return( r );  /* conversion gets clobbered */
+
+	case PVCONV:
+	case PMCONV:
+		if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0);
+		r = buildtree( o==PMCONV?MUL:DIV, p->n_left, p->n_right);
+		nfree(p);
+		return r;
+
+	case RS:
+	case RSEQ:
+		/* convert >> to << with negative shift count */
+		/* only if type of left operand is not unsigned */
+		if( ISUNSIGNED(p->n_left->n_type) ) break;
+		p->n_right = buildtree( UMINUS, p->n_right, NIL );
+		if( p->n_op == RS ) p->n_op = LS;
+		else p->n_op = LSEQ;
+		break;
+
+	case FORCE:
+		p->n_op = ASSIGN;
+		p->n_right = p->n_left;
+		p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
+		p->n_left->n_rval = p->n_left->n_type == BOOL ? 
+		    RETREG(CHAR) : RETREG(p->n_type);
+		break;
+
+	case STCALL:
+	case CALL:
+		/* Fix function call arguments. On vax, just add funarg */
+		for (r = p->n_right; r->n_op == CM; r = r->n_left) {
+			if (r->n_right->n_op != STARG &&
+			    r->n_right->n_op != FUNARG)
+				r->n_right = block(FUNARG, r->n_right, NIL, 
+				    r->n_right->n_type, r->n_right->n_df,
+				    r->n_right->n_sue);
+		}
+		if (r->n_op != STARG && r->n_op != FUNARG) {
+			NODE *l = talloc();
+			*l = *r;
+			r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type;
+		}
+		break;
+	}
+
+	return(p);
+}
+
+void
+myp2tree(NODE *p)
+{
+	struct symtab *sp;
+	int o = p->n_op, i;
+
+	if (o != FCON) 
+		return;
+
+	sp = inlalloc(sizeof(struct symtab));
+	sp->sclass = STATIC;
+	sp->ssue = MKSUE(p->n_type);
+	sp->slevel = 1; /* fake numeric label */
+	sp->soffset = getlab();
+	sp->sflags = 0;
+	sp->stype = p->n_type;
+	sp->squal = (CON >> TSHIFT);
+
+	defloc(sp);
+	ninval(0, sp->ssue->suesize, p);
+
+	p->n_op = NAME;
+	p->n_lval = 0;
+	p->n_sp = sp;
+
+}
+
+/*
+ * Can we take & of a NAME?
+ */
+int
+andable(NODE *p)
+{
+
+	if ((p->n_type & ~BTMASK) == FTN)
+		return 1; /* functions are called by name */
+	return 0; /* Delay name reference to table, for PIC code generation */
+}
+ 
+void
+cendarg(){ /* at the end of the arguments of a ftn, set the automatic offset */
+	autooff = AUTOINIT;
+	}
+
+int
+cisreg( t ) TWORD t; { /* is an automatic variable of type t OK for a register variable */
+	return(1);	/* all are now */
+	}
+
+NODE *
+offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
+{
+
+	/* return a node, for structure references, which is suitable for
+	   being added to a pointer of type t, in order to be off bits offset
+	   into a structure */
+
+	register NODE *p;
+
+	/* t, d, and s are the type, dimension offset, and sizeoffset */
+	/* in general they  are necessary for offcon, but not on H'well */
+
+	p = bcon(0);
+	p->n_lval = off/SZCHAR;
+	return(p);
+
+	}
+
+void
+spalloc(NODE *t, NODE *p, OFFSZ off)
+{
+	cerror("spalloc");
+}
+
+static int inbits, inval;
+
+/*
+ * set fsz bits in sequence to zero.
+ */
+void
+zbits(OFFSZ off, int fsz)
+{
+	int m;
+
+	if (idebug)
+		printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
+	if ((m = (inbits % SZCHAR))) {
+		m = SZCHAR - m;
+		if (fsz < m) {
+			inbits += fsz;
+			return;
+		} else {
+			fsz -= m;
+			printf("\t.byte %d\n", inval);
+			inval = inbits = 0;
+		}
+	}
+	if (fsz >= SZCHAR) {
+		printf("\t.space %d\n", fsz/SZCHAR);
+		fsz -= (fsz/SZCHAR) * SZCHAR;
+	}
+	if (fsz) {
+		inval = 0;
+		inbits = fsz;
+	}
+}
+
+/*
+ * Initialize a bitfield.
+ */
+void
+infld(CONSZ off, int fsz, CONSZ val)
+{
+	if (idebug)
+		printf("infld off %lld, fsz %d, val %lld inbits %d\n",
+		    off, fsz, val, inbits);
+	val &= ((CONSZ)1 << fsz)-1;
+	while (fsz + inbits >= SZCHAR) {
+		inval |= (val << inbits);
+		printf("\t.byte %d\n", inval & 255);
+		fsz -= (SZCHAR - inbits);
+		val >>= (SZCHAR - inbits);
+		inval = inbits = 0;
+	}
+	if (fsz) {
+		inval |= (val << inbits);
+		inbits += fsz;
+	}
+}
+
+
+char *
+exname( p ) char *p; {
+	/* make a name look like an external name in the local machine */
+	/* vad is elf now */
+	if (p == NULL)
+		return "";
+	return( p );
+	}
+
+TWORD
+ctype(TWORD type ){ /* map types which are not defined on the local machine */
+	switch( BTYPE(type) ){
+
+	case LONG:
+		MODTYPE(type,INT);
+		break;
+
+	case ULONG:
+		MODTYPE(type,UNSIGNED);
+		break;
+
+	case LDOUBLE:	/* for now */
+		MODTYPE(type,DOUBLE);
+		}
+	return( type );
+	}
+
+void
+calldec(NODE *p, NODE *q) 
+{
+}
+
+void
+extdec(struct symtab *q)
+{
+}
+
+void
+commdec( struct symtab *q ){ /* make a common declaration for id, if reasonable */
+	OFFSZ off;
+
+	printf( "	.comm	%s,", q->soname ? q->soname : exname( q->sname ) );
+	off = tsize( q->stype, q->sdf, q->ssue );
+	printf( CONFMT, off/SZCHAR );
+	printf( "\n" );
+	}
+
+/* make a local common declaration for id, if reasonable */
+void
+lcommdec(struct symtab *q)
+{
+	int off;
+
+	off = tsize(q->stype, q->sdf, q->ssue);
+	off = (off+(SZCHAR-1))/SZCHAR;
+	if (q->slevel == 0)
+		printf("	.lcomm %s,0%o\n", q->soname ? q->soname : exname(q->sname), off);
+	else
+		printf("	.lcomm " LABFMT ",0%o\n", q->soffset, off);
+}
+
+
+static char *loctbl[] = { "text", "data", "section .rodata", "section .rodata" };
+
+void
+setloc1(int locc)
+{
+	if (locc == lastloc)
+		return;
+	lastloc = locc;
+	printf("	.%s\n", loctbl[locc]);
+}
+
+/*
+ * 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
+ * XXX - floating point constants may be wrong if cross-compiling.
+ */
+void
+ninval(CONSZ off, int fsz, NODE *p)
+{
+	union { float f; double d; long double l; int i[3]; } u;
+	struct symtab *q;
+	TWORD t;
+
+	t = p->n_type;
+	if (t > BTMASK)
+		t = INT; /* pointer */
+
+	if (p->n_op != ICON && p->n_op != FCON)
+		cerror("ninval: init node not constant");
+
+	if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
+		uerror("element not constant");
+
+	switch (t) {
+	case LONGLONG:
+	case ULONGLONG:
+		printf("\t.long 0x%x", (int)p->n_lval);
+		printf("\t.long 0x%x", (int)(p->n_lval >> 32));
+		break;
+	case INT:
+	case UNSIGNED:
+		printf("\t.long 0x%x", (int)p->n_lval);
+		if ((q = p->n_sp) != NULL) {
+			if ((q->sclass == STATIC && q->slevel > 0)) {
+				printf("+" LABFMT, q->soffset);
+			} else
+				printf("+%s", q->soname ? q->soname : exname(q->sname));
+		}
+		printf("\n");
+		break;
+	case SHORT:
+	case USHORT:
+		printf("\t.short 0x%x\n", (int)p->n_lval & 0xffff);
+		break;
+	case BOOL:
+		if (p->n_lval > 1)
+			p->n_lval = p->n_lval != 0;
+		/* FALLTHROUGH */
+	case CHAR:
+	case UCHAR:
+		printf("\t.byte %d\n", (int)p->n_lval & 0xff);
+		break;
+	case LDOUBLE:
+		u.i[2] = 0;
+		u.l = (long double)p->n_dcon;
+		printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]);
+		break;
+	case DOUBLE:
+		u.d = (double)p->n_dcon;
+		printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
+		break;
+	case FLOAT:
+		u.f = (float)p->n_dcon;
+		printf("\t.long\t0x%x\n", u.i[0]);
+		break;
+	default:
+		cerror("ninval");
+	}
+
+}
+/*
+ * Give target the opportunity of handling pragmas.
+ */
+int
+mypragma(char *str)
+{
+	return 0;
+}
+
+/*
+ * Called when a identifier has been declared, to give target last word.
+ */
+void
+fixdef(struct symtab *sp)
+{
+}
+
+void
+pass1_lastchance(struct interpass *ip)
+{
+}
Index: uspace/app/pcc/arch/vax/local2.c
===================================================================
--- uspace/app/pcc/arch/vax/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/vax/local2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1036 @@
+/*	$Id: local2.c,v 1.11 2008/11/22 16:12:25 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 "pass2.h"
+# include "ctype.h"
+/* a lot of the machine dependent parts of the second pass */
+
+static void prtype(NODE *n);
+static void acon(NODE *p);
+
+/*
+ * Print out the prolog assembler.
+ * addto and regoff are already calculated.
+ */
+void
+prologue(struct interpass_prolog *ipp)
+{
+	if (ipp->ipp_vis)
+		printf("	.globl %s\n", ipp->ipp_name);
+	printf("	.align 4\n");
+	printf("%s:\n", ipp->ipp_name);
+	printf("	.word 0x%x\n", ipp->ipp_regs[0]);
+	if (p2maxautooff)
+		printf("	subl2 $%d,%%sp\n", p2maxautooff);
+}
+
+/*
+ * Called after all instructions in a function are emitted.
+ * Generates code for epilog here.
+ */
+void
+eoftn(struct interpass_prolog *ipp)
+{
+	if (ipp->ipp_ip.ip_lbl == 0)
+		return; /* no code needs to be generated */
+	printf("	ret\n");
+}
+
+struct hoptab { int opmask; char * opstring; } ioptab[] = {
+
+	{ PLUS,	"add", },
+	{ MINUS,	"sub", },
+	{ MUL,	"mul", },
+	{ DIV,	"div", },
+	{ OR,	"bis", },
+	{ ER,	"xor", },
+	{ AND,	"bic", },
+	{ -1, ""     },
+};
+
+void
+hopcode( f, o ){
+	/* output the appropriate string from the above table */
+
+	register struct hoptab *q;
+
+	for( q = ioptab;  q->opmask>=0; ++q ){
+		if( q->opmask == o ){
+			printf( "%s", q->opstring );
+/* tbl
+			if( f == 'F' ) printf( "e" );
+			else if( f == 'D' ) printf( "d" );
+   tbl */
+/* tbl */
+			switch( f ) {
+				case 'L':
+				case 'W':
+				case 'B':
+				case 'D':
+				case 'F':
+					printf("%c", tolower(f));
+					break;
+
+				}
+/* tbl */
+			return;
+			}
+		}
+	cerror( "no hoptab for %s", opst[o] );
+	}
+
+char *
+rnames[] = {  /* keyed to register number tokens */
+
+	"r0", "r1", "r2", "r3", "r4", "r5",
+	"r6", "r7", "r8", "r9", "r10", "r11",
+	"ap", "fp", "sp", "pc",
+	/* The concatenated regs has the name of the lowest */
+	"r0", "r1", "r2", "r3", "r4", "r5",
+	"r6", "r7", "r8", "r9", "r10"
+	};
+
+int
+tlen(p) NODE *p;
+{
+	switch(p->n_type) {
+		case CHAR:
+		case UCHAR:
+			return(1);
+
+		case SHORT:
+		case USHORT:
+			return(2);
+
+		case DOUBLE:
+		case LDOUBLE:
+		case LONGLONG:
+		case ULONGLONG:
+			return(8);
+
+		default:
+			return(4);
+		}
+}
+
+static int
+mixtypes(NODE *p, NODE *q)
+{
+	TWORD tp, tq;
+
+	tp = p->n_type;
+	tq = q->n_type;
+
+	return( (tp==FLOAT || tp==DOUBLE) !=
+		(tq==FLOAT || tq==DOUBLE) );
+}
+
+void
+prtype(NODE *n)
+{
+	switch (n->n_type)
+		{
+		case DOUBLE:
+			printf("d");
+			return;
+
+		case FLOAT:
+			printf("f");
+			return;
+
+		case LONG:
+		case ULONG:
+		case INT:
+		case UNSIGNED:
+			printf("l");
+			return;
+
+		case SHORT:
+		case USHORT:
+			printf("w");
+			return;
+
+		case CHAR:
+		case UCHAR:
+			printf("b");
+			return;
+
+		default:
+			if ( !ISPTR( n->n_type ) ) cerror("zzzcode- bad type");
+			else {
+				printf("l");
+				return;
+				}
+		}
+}
+
+void
+zzzcode( p, c ) register NODE *p; {
+	int m;
+	int val;
+	switch( c ){
+
+	case 'N':  /* logical ops, turned into 0-1 */
+		/* use register given by register 1 */
+		cbgen( 0, m=getlab2());
+		deflab( p->n_label );
+		printf( "	clrl	%s\n", rnames[getlr( p, '1' )->n_rval] );
+		deflab( m );
+		return;
+
+	case 'A':
+		{
+		register NODE *l, *r;
+
+		if (xdebug) e2print(p, 0, &val, &val);
+		r = getlr(p, 'R');
+		if (optype(p->n_op) == LTYPE || p->n_op == UMUL) {
+			l = resc;
+			l->n_type = (r->n_type==FLOAT || r->n_type==DOUBLE ? DOUBLE : INT);
+		} else
+			l = getlr(p, 'L');
+		if (r->n_op == ICON  && r->n_name[0] == '\0') {
+			if (r->n_lval == 0) {
+				printf("clr");
+				prtype(l);
+				printf("	");
+				adrput(stdout, l);
+				return;
+			}
+			if (r->n_lval < 0 && r->n_lval >= -63) {
+				printf("mneg");
+				prtype(l);
+				r->n_lval = -r->n_lval;
+				goto ops;
+			}
+			r->n_type = (r->n_lval < 0 ?
+					(r->n_lval >= -128 ? CHAR
+					: (r->n_lval >= -32768 ? SHORT
+					: INT )) : r->n_type);
+			r->n_type = (r->n_lval >= 0 ?
+					(r->n_lval <= 63 ? INT
+					: ( r->n_lval <= 127 ? CHAR
+					: (r->n_lval <= 255 ? UCHAR
+					: (r->n_lval <= 32767 ? SHORT
+					: (r->n_lval <= 65535 ? USHORT
+					: INT ))))) : r->n_type );
+			}
+		if (l->n_op == REG && l->n_type != FLOAT && l->n_type != DOUBLE)
+			l->n_type = INT;
+		if (!mixtypes(l,r))
+			{
+			if (tlen(l) == tlen(r))
+				{
+				printf("mov");
+				prtype(l);
+				goto ops;
+				}
+			else if (tlen(l) > tlen(r) && ISUNSIGNED(r->n_type))
+				{
+				printf("movz");
+				}
+			else
+				{
+				printf("cvt");
+				}
+			}
+		else
+			{
+			printf("cvt");
+			}
+		prtype(r);
+		prtype(l);
+	ops:
+		printf("	");
+		adrput(stdout, r);
+		printf(",");
+		adrput(stdout, l);
+		return;
+		}
+
+	case 'C':	/* num words pushed on arg stack */
+		if (p->n_op == STCALL || p->n_op == USTCALL)
+			p->n_qual++;
+		printf("$%d", p->n_qual);
+		break;
+
+	case 'D':	/* INCR and DECR */
+		zzzcode(p->n_left, 'A');
+		printf("\n	");
+
+#if 0
+	case 'E':	/* INCR and DECR, FOREFF */
+		if (p->n_right->n_lval == 1)
+			{
+			printf("%s", (p->n_op == INCR ? "inc" : "dec") );
+			prtype(p->n_left);
+			printf("	");
+			adrput(stdout, p->n_left);
+			return;
+			}
+		printf("%s", (p->n_op == INCR ? "add" : "sub") );
+		prtype(p->n_left);
+		printf("2	");
+		adrput(stdout, p->n_right);
+		printf(",");
+		adrput(p->n_left);
+		return;
+#endif
+
+	case 'F':	/* register type of right operand */
+		{
+		register NODE *n;
+		extern int xdebug;
+		register int ty;
+
+		n = getlr( p, 'R' );
+		ty = n->n_type;
+
+		if (xdebug) printf("->%d<-", ty);
+
+		if ( ty==DOUBLE) printf("d");
+		else if ( ty==FLOAT ) printf("f");
+		else printf("l");
+		return;
+		}
+
+	case 'J': /* jump or ret? */
+		{
+			extern struct interpass_prolog *epp;
+			struct interpass *ip =
+			    DLIST_PREV((struct interpass *)epp, qelem);
+			if (ip->type != IP_DEFLAB ||
+			    ip->ip_lbl != getlr(p, 'L')->n_lval)
+				expand(p, FOREFF, "jbr	LL");
+			else
+				printf("ret");
+		}
+		break;
+
+	case 'L':	/* type of left operand */
+	case 'R':	/* type of right operand */
+		{
+		register NODE *n;
+		extern int xdebug;
+
+		n = getlr ( p, c);
+		if (xdebug) printf("->%d<-", n->n_type);
+
+		prtype(n);
+		return;
+		}
+
+	case 'Z':	/* complement mask for bit instr */
+		printf("$%Ld", ~p->n_right->n_lval);
+		return;
+
+	case 'U':	/* 32 - n, for unsigned right shifts */
+		printf("$" CONFMT, 32 - p->n_right->n_lval );
+		return;
+
+	case 'T':	/* rounded structure length for arguments */
+		{
+		int size;
+
+		size = p->n_stsize;
+		SETOFF( size, 4);
+		printf("$%d", size);
+		return;
+		}
+
+	case 'S':  /* structure assignment */
+		{
+			register NODE *l, *r;
+			register int size;
+
+			l = r = NULL; /* XXX gcc */
+			if( p->n_op == STASG ){
+				l = p->n_left;
+				r = p->n_right;
+
+				}
+			else if( p->n_op == STARG ){  /* store an arg into a temporary */
+				l = getlr( p, '3' );
+				r = p->n_left;
+				}
+			else cerror( "STASG bad" );
+
+			if( r->n_op == ICON ) r->n_op = NAME;
+			else if( r->n_op == REG ) r->n_op = OREG;
+			else if( r->n_op != OREG ) cerror( "STASG-r" );
+
+			size = p->n_stsize;
+
+			if( size <= 0 || size > 65535 )
+				cerror("structure size <0=0 or >65535");
+
+			switch(size) {
+				case 1:
+					printf("	movb	");
+					break;
+				case 2:
+					printf("	movw	");
+					break;
+				case 4:
+					printf("	movl	");
+					break;
+				case 8:
+					printf("	movq	");
+					break;
+				default:
+					printf("	movc3	$%d,", size);
+					break;
+			}
+			adrput(stdout, r);
+			printf(",");
+			adrput(stdout, l);
+			printf("\n");
+
+			if( r->n_op == NAME ) r->n_op = ICON;
+			else if( r->n_op == OREG ) r->n_op = REG;
+
+			}
+		break;
+
+	default:
+		comperr("illegal zzzcode '%c'", c);
+		}
+	}
+
+void
+rmove( int rt,int  rs, TWORD t ){
+	printf( "	%s	%s,%s\n",
+		(t==FLOAT ? "movf" : (t==DOUBLE ? "movd" : "movl")),
+		rnames[rs], rnames[rt] );
+	}
+
+#if 0
+setregs(){ /* set up temporary registers */
+	fregs = 6;	/* tbl- 6 free regs on VAX (0-5) */
+	;
+	}
+
+szty(t){ /* size, in registers, needed to hold thing of type t */
+	return( (t==DOUBLE||t==FLOAT) ? 2 : 1 );
+	}
+#endif
+
+int
+rewfld( p ) NODE *p; {
+	return(1);
+	}
+
+#if 0
+callreg(p) NODE *p; {
+	return( R0 );
+	}
+
+base( p ) register NODE *p; {
+	register int o = p->op;
+
+	if( (o==ICON && p->name[0] != '\0')) return( 100 ); /* ie no base reg */
+	if( o==REG ) return( p->rval );
+    if( (o==PLUS || o==MINUS) && p->left->op == REG && p->right->op==ICON)
+		return( p->left->rval );
+    if( o==OREG && !R2TEST(p->rval) && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) )
+		return( p->rval + 0200*1 );
+	if( o==INCR && p->left->op==REG ) return( p->left->rval + 0200*2 );
+	if( o==ASG MINUS && p->left->op==REG) return( p->left->rval + 0200*4 );
+	if( o==UNARY MUL && p->left->op==INCR && p->left->left->op==REG
+	  && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) )
+		return( p->left->left->rval + 0200*(1+2) );
+	return( -1 );
+	}
+
+offset( p, tyl ) register NODE *p; int tyl; {
+
+	if( tyl==1 && p->op==REG && (p->type==INT || p->type==UNSIGNED) ) return( p->rval );
+	if( (p->op==LS && p->left->op==REG && (p->left->type==INT || p->left->type==UNSIGNED) &&
+	      (p->right->op==ICON && p->right->name[0]=='\0')
+	      && (1<<p->right->lval)==tyl))
+		return( p->left->rval );
+	return( -1 );
+	}
+#endif
+
+#if 0
+void
+makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
+	register NODE *t;
+	NODE *f;
+
+	p->n_op = OREG;
+	f = p->n_left; 	/* have to free this subtree later */
+
+	/* init base */
+	switch (q->n_op) {
+		case ICON:
+		case REG:
+		case OREG:
+			t = q;
+			break;
+
+		case MINUS:
+			q->n_right->n_lval = -q->n_right->n_lval;
+		case PLUS:
+			t = q->n_right;
+			break;
+
+		case UMUL:
+			t = q->n_left->n_left;
+			break;
+
+		default:
+			cerror("illegal makeor2");
+			t = NULL; /* XXX gcc */
+	}
+
+	p->n_lval = t->n_lval;
+	p->n_name = t->n_name;
+
+	/* init offset */
+	p->n_rval = R2PACK( (b & 0177), o, (b>>7) );
+
+	tfree(f);
+	return;
+	}
+
+int
+canaddr( p ) NODE *p; {
+	register int o = p->n_op;
+
+	if( o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left, STARNM|SOREG)) ) return(1);
+	return(0);
+	}
+
+shltype( o, p ) register NODE *p; {
+	return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UMUL && shumul(p->n_left, STARNM|SOREG)) );
+	}
+#endif
+
+int
+fldexpand(NODE *p, int cookie, char **cp)
+{
+	return 0;
+}
+
+int
+flshape( p ) register NODE *p; {
+	return( p->n_op == REG || p->n_op == NAME || p->n_op == ICON ||
+		(p->n_op == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1)) );
+	}
+
+int
+shtemp( p ) register NODE *p; {
+	if( p->n_op == STARG ) p = p->n_left;
+	return( p->n_op==NAME || p->n_op ==ICON || p->n_op == OREG || (p->n_op==UMUL && shumul(p->n_left, STARNM|SOREG)) );
+	}
+
+int
+shumul( p, shape ) register NODE *p; int shape; {
+	register int o;
+	extern int xdebug;
+
+	if (xdebug) {
+		 printf("\nshumul:op=%d,lop=%d,rop=%d", p->n_op, p->n_left->n_op, p->n_right->n_op);
+		printf(" prname=%s,plty=%d, prlval=%lld\n", p->n_right->n_name, p->n_left->n_type, p->n_right->n_lval);
+		}
+
+
+	o = p->n_op;
+	if( o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON )
+		if (shape & STARNM)
+			return SRDIR;
+
+#ifdef notyet
+	if( ( o == INCR || o == ASG MINUS ) &&
+	    ( p->n_left->n_op == REG && p->n_right->n_op == ICON ) &&
+	    p->n_right->n_name[0] == '\0' )
+		{
+		switch (p->n_left->n_type)
+			{
+			case CHAR|PTR:
+			case UCHAR|PTR:
+				o = 1;
+				break;
+
+			case SHORT|PTR:
+			case USHORT|PTR:
+				o = 2;
+				break;
+
+			case INT|PTR:
+			case UNSIGNED|PTR:
+			case LONG|PTR:
+			case ULONG|PTR:
+			case FLOAT|PTR:
+				o = 4;
+				break;
+
+			case DOUBLE|PTR:
+				o = 8;
+				break;
+
+			default:
+				if ( ISPTR(p->n_left->n_type) ) {
+					o = 4;
+					break;
+					}
+				else return(0);
+			}
+		return( p->n_right->n_lval == o ? STARREG : 0);
+		}
+#endif
+
+	return( SRNOPE );
+	}
+
+void
+adrcon( val ) CONSZ val; {
+	printf( "$" );
+	printf( CONFMT, val );
+	}
+
+void
+conput(FILE *fp, NODE *p)
+{
+	switch( p->n_op ){
+
+	case ICON:
+		acon( p );
+		return;
+
+	case REG:
+		printf( "%s", rnames[p->n_rval] );
+		return;
+
+	default:
+		cerror( "illegal conput" );
+		}
+	}
+
+void
+insput( p ) register NODE *p; {
+	cerror( "insput" );
+	}
+
+void
+upput( p , size) register NODE *p; {
+	cerror( "upput" );
+	}
+
+void
+adrput(FILE *fp, NODE *p)
+{
+	register int r;
+	/* output an address, with offsets, from p */
+
+	if( p->n_op == FLD ){
+		p = p->n_left;
+		}
+	switch( p->n_op ){
+
+	case NAME:
+		acon( p );
+		return;
+
+	case ICON:
+		/* addressable value of the constant */
+		if (p->n_name[0] == '\0') /* uses xxxab */
+			printf("$");
+		acon(p);
+		return;
+
+	case REG:
+		printf( "%s", rnames[p->n_rval] );
+		return;
+
+	case OREG:
+		r = p->n_rval;
+		if( R2TEST(r) ){ /* double indexing */
+			register int flags;
+
+			flags = R2UPK3(r);
+			if( flags & 1 ) printf("*");
+			if( flags & 4 ) printf("-");
+			if( p->n_lval != 0 || p->n_name[0] != '\0' ) acon(p);
+			if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] );
+			if( flags & 2 ) printf("+");
+			printf( "[%s]", rnames[R2UPK2(r)] );
+			return;
+			}
+		if( r == AP ){  /* in the argument region */
+			if( p->n_lval <= 0 || p->n_name[0] != '\0' ) werror( "bad arg temp" );
+			printf( CONFMT, p->n_lval );
+			printf( "(ap)" );
+			return;
+			}
+		if( p->n_lval != 0 || p->n_name[0] != '\0') acon( p );
+		printf( "(%s)", rnames[p->n_rval] );
+		return;
+
+	case UMUL:
+		/* STARNM or STARREG found */
+		if( tshape(p, STARNM) ) {
+			printf( "*" );
+			adrput(0,  p->n_left);
+			}
+		else {	/* STARREG - really auto inc or dec */
+			register NODE *q;
+
+/* tbl
+			p = p->n_left;
+			p->n_left->n_op = OREG;
+			if( p->n_op == INCR ) {
+				adrput( p->n_left );
+				printf( "+" );
+				}
+			else {
+				printf( "-" );
+				adrput( p->n_left );
+				}
+   tbl */
+#ifdef notyet
+			printf("%c(%s)%c", (p->n_left->n_op==INCR ? '\0' : '-'),
+				rnames[p->n_left->n_left->n_rval], 
+				(p->n_left->n_op==INCR ? '+' : '\0') );
+#else
+			printf("%c(%s)%c", '-',
+				rnames[p->n_left->n_left->n_rval], 
+				'\0' );
+#endif
+			p->n_op = OREG;
+			p->n_rval = p->n_left->n_left->n_rval;
+			q = p->n_left;
+#ifdef notyet
+
+			p->n_lval = (p->n_left->n_op == INCR ? -p->n_left->n_right->n_lval : 0);
+#else
+			p->n_lval = 0;
+#endif
+			p->n_name[0] = '\0';
+			tfree(q);
+		}
+		return;
+
+	default:
+		cerror( "illegal address" );
+		return;
+	}
+
+}
+
+/*
+ * print out a constant
+ */
+void
+acon(NODE *p)
+{
+
+	if (p->n_name[0] == '\0') {
+		printf(CONFMT, p->n_lval);
+	} else if( p->n_lval == 0 ) {
+		printf("%s", p->n_name);
+	} else {
+		printf("%s+", p->n_name);
+		printf(CONFMT, p->n_lval);
+	}
+}
+
+#if 0
+genscall( p, cookie ) register NODE *p; {
+	/* structure valued call */
+	return( gencall( p, cookie ) );
+	}
+
+/* tbl */
+int gc_numbytes;
+/* tbl */
+
+gencall( p, cookie ) register NODE *p; {
+	/* generate the call given by p */
+	register NODE *p1, *ptemp;
+	register temp, temp1;
+	register m;
+
+	if( p->right ) temp = argsize( p->right );
+	else temp = 0;
+
+	if( p->op == STCALL || p->op == UNARY STCALL ){
+		/* set aside room for structure return */
+
+		if( p->stsize > temp ) temp1 = p->stsize;
+		else temp1 = temp;
+		}
+
+	if( temp > maxargs ) maxargs = temp;
+	SETOFF(temp1,4);
+
+	if( p->right ){ /* make temp node, put offset in, and generate args */
+		ptemp = talloc();
+		ptemp->op = OREG;
+		ptemp->lval = -1;
+		ptemp->rval = SP;
+		ptemp->name[0] = '\0';
+		ptemp->rall = NOPREF;
+		ptemp->su = 0;
+		genargs( p->right, ptemp );
+		nfree(ptemp);
+		}
+
+	p1 = p->left;
+	if( p1->op != ICON ){
+		if( p1->op != REG ){
+			if( p1->op != OREG || R2TEST(p1->rval) ){
+				if( p1->op != NAME ){
+					order( p1, INAREG );
+					}
+				}
+			}
+		}
+
+/*
+	if( p1->op == REG && p->rval == R5 ){
+		cerror( "call register overwrite" );
+		}
+ */
+/* tbl
+	setup gc_numbytes so reference to ZC works */
+
+	gc_numbytes = temp;
+/* tbl */
+
+	p->op = UNARY CALL;
+	m = match( p, INTAREG|INTBREG );
+/* tbl
+	switch( temp ) {
+	case 0:
+		break;
+	case 2:
+		printf( "	tst	(sp)+\n" );
+		break;
+	case 4:
+		printf( "	cmp	(sp)+,(sp)+\n" );
+		break;
+	default:
+		printf( "	add	$%d,sp\n", temp);
+		}
+   tbl */
+	return(m != MDONE);
+	}
+#endif
+
+static char *
+ccbranches[] = {
+	"jeql",
+	"jneq",
+	"jleq",
+	"jlss",
+	"jgeq",
+	"jgtr",
+	"jlequ",
+	"jlssu",
+	"jgequ",
+	"jgtru",
+};
+
+/*
+ * printf conditional and unconditional branches
+ */
+void
+cbgen(int o, int lab)
+{
+
+	if (o == 0) {
+		printf("	jbr     " LABFMT "\n", lab);
+	} else {
+		if (o > UGT)
+			comperr("bad conditional branch: %s", opst[o]);
+		printf("\t%s\t" LABFMT "\n", ccbranches[o-EQ], lab);
+	}
+}
+
+static void
+optim2(NODE *p, void *arg)
+{
+	/* do local tree transformations and optimizations */
+
+	register NODE *r;
+
+	switch( p->n_op ) {
+
+	case AND:
+		/* commute L and R to eliminate compliments and constants */
+		if( (p->n_left->n_op==ICON&&p->n_left->n_name[0]==0) || p->n_left->n_op==COMPL ) {
+			r = p->n_left;
+			p->n_left = p->n_right;
+			p->n_right = r;
+			}
+#if 0
+	case ASG AND:
+		/* change meaning of AND to ~R&L - bic on pdp11 */
+		r = p->n_right;
+		if( r->op==ICON && r->name[0]==0 ) { /* compliment constant */
+			r->lval = ~r->lval;
+			}
+		else if( r->op==COMPL ) { /* ~~A => A */
+			r->op = FREE;
+			p->right = r->left;
+			}
+		else { /* insert complement node */
+			p->right = talloc();
+			p->right->op = COMPL;
+			p->right->rall = NOPREF;
+			p->right->type = r->type;
+			p->right->left = r;
+			p->right->right = NULL;
+			}
+		break;
+#endif
+		}
+	}
+
+void
+myreader(struct interpass *ipole)
+{
+	struct interpass *ip;
+
+	DLIST_FOREACH(ip, ipole, qelem) {
+		if (ip->type != IP_NODE)
+			continue;
+		walkf(ip->ip_node, optim2, 0);
+	}
+}
+
+void
+mycanon(NODE *p)
+{
+}
+
+void
+myoptim(struct interpass *ip)
+{
+}
+
+/*
+ * Return argument size in regs.
+ */
+static int
+argsiz(NODE *p)
+{
+	TWORD t = p->n_type;
+
+	if (t == STRTY || t == UNIONTY)
+		return p->n_stsize/(SZINT/SZCHAR);
+	return szty(t);
+}
+
+/*
+ * Last chance to do something before calling a function.
+ */
+void
+lastcall(NODE *p)
+{
+	NODE *op = p;
+	int size = 0;
+
+	/* Calculate argument sizes */
+	p->n_qual = 0;
+	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
+		return;
+	for (p = p->n_right; p->n_op == CM; p = p->n_left)
+		size += argsiz(p->n_right);
+	size += argsiz(p);
+	op->n_qual = size; /* XXX */
+}
+
+/*
+ * Return a class suitable for a specific type.
+ */
+int
+gclass(TWORD t)
+{
+	return (szty(t) == 2 ? CLASSB : CLASSA);
+}
+
+/*
+ * 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:
+		/* there are 12 classa, so min 6 classb are needed to block */
+		num = r[CLASSB] * 2;
+		num += r[CLASSA];
+		return num < 12;
+	case CLASSB:
+		/* 6 classa may block all classb */
+		num = r[CLASSB] + r[CLASSA];
+		return num < 6;
+	}
+	comperr("COLORMAP");
+	return 0; /* XXX gcc */
+}
+
+/*
+ * Special shapes.
+ */
+int
+special(NODE *p, int shape)
+{
+	return SRNOPE;
+}
+
+/*
+ * Target-dependent command-line options.
+ */
+void
+mflags(char *str)
+{
+}
+/*
+ * Do something target-dependent for xasm arguments.
+ * Supposed to find target-specific constraints and rewrite them.
+ */
+int
+myxasm(struct interpass *ip, NODE *p)
+{
+	return 0;
+}
Index: uspace/app/pcc/arch/vax/macdefs.h
===================================================================
--- uspace/app/pcc/arch/vax/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/vax/macdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,259 @@
+/*	$Id: macdefs.h,v 1.5 2009/01/24 21:43:49 gmcgarry Exp $	*/
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# define makecc(val,i)  lastcon = (lastcon<<8)|((val<<24)>>24);  
+
+# define  ARGINIT 32 
+# define  AUTOINIT 0 
+# define  SZCHAR 8
+# define  SZBOOL 8
+# define  SZINT 32
+# define  SZFLOAT 32
+# define  SZDOUBLE 64
+# define  SZLDOUBLE 64	/* XXX use longer? */
+# define  SZLONG 32
+# define  SZLONGLONG 64
+# define  SZSHORT 16
+# define SZPOINT(t) 32
+# define ALCHAR 8
+# define ALBOOL 8
+# define ALINT 32
+# define ALFLOAT 32
+# define ALDOUBLE 32
+# define ALLDOUBLE 32
+# define ALLONG 32
+# define ALLONGLONG 32
+# define ALSHORT 16
+# define ALPOINT 32
+# define ALSTRUCT 8
+# define  ALSTACK 32 
+
+/*
+ * Min/max values.
+ */
+#define MIN_CHAR        -128
+#define MAX_CHAR        127
+#define MAX_UCHAR       255
+#define MIN_SHORT       -32768
+#define MAX_SHORT       32767
+#define MAX_USHORT      65535
+#define MIN_INT         (-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 */
+
+/*	size in which constants are converted */
+/*	should be long if feasable */
+
+typedef long long CONSZ;
+typedef unsigned long long U_CONSZ;
+
+# define CONFMT "%lld"
+# define LABFMT ".L%d"
+# define STABLBL ".LL%d"
+
+/*	size in which offsets are kept
+ *	should be large enough to cover address space in bits
+ */
+typedef long long OFFSZ;
+
+/* 	character set macro */
+
+# define  CCTRANS(x) x
+
+/* register cookie for stack poINTer */
+
+# define  STKREG 13
+# define ARGREG 12
+
+/*	maximum and minimum register variables */
+
+# define MAXRVAR 11
+# define MINRVAR 6
+
+/* show stack grows negatively */
+#define BACKAUTO
+#define BACKTEMP
+
+/* show field hardware support on VAX */
+#define FIELDOPS
+
+/* bytes are numbered from right to left */
+#define RTOLBYTES
+
+/* we want prtree included */
+# define STDPRTREE
+# ifndef FORT
+# define ONEPASS
+#endif
+
+# define ENUMSIZE(high,low) INT
+
+/*	VAX-11/780 Registers */
+
+	/* scratch registers */
+# define R0 0
+# define R1 1
+# define R2 2
+# define R3 3
+# define R4 4
+# define R5 5
+
+	/* register variables */
+# define R6 6
+# define R7 7
+# define R8 8
+# define R9 9
+# define R10 10
+# define R11 11
+
+	/* special purpose */
+# define AP 12		/* argument pointer */
+# define FP 13		/* frame pointer */
+# define SP 14	/* stack pointer */
+# define PC 15	/* program counter */
+
+	/* floating registers */
+
+	/* there are no floating point registers on the VAX */
+	/* but there are concatenated regs */
+	/* we call them XR? */
+#define	XR0	16
+#define	XR1	17
+#define	XR2	18
+#define	XR3	19
+#define	XR4	20
+#define	XR5	21
+#define	XR6	22
+#define	XR7	23
+#define	XR8	24
+#define	XR9	25
+#define	XR10	26
+
+
+
+
+extern int fregs;
+extern int maxargs;
+
+# define BYTEOFF(x) ((x)&03)
+# define wdal(k) (BYTEOFF(k)==0)
+# define BITOOR(x) ((x)>>3)  /* bit offset to oreg offset */
+
+# define REGSZ 16
+
+# define TMPREG FP
+
+//# define R2REGS   /* permit double indexing */
+
+# define STOARG(p)     /* just evaluate the arguments, and be done with it... */
+# define STOFARG(p)
+# define STOSTARG(p)
+# define genfcall(a,b) gencall(a,b)
+
+# define NESTCALL
+
+/*
+ * Register allocator stuff.
+ * The register allocator sees this as 16 general regs (AREGs)
+ * and 11 64-bit concatenated regs. (BREGs)
+ */
+#define MAXREGS 033     /* 27 registers */
+
+#define RSTATUS \
+        SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG,     \
+        SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, SAREG|PERMREG,	\
+        SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG,	\
+	0, 0, 0, 0, /* do not care about ap, fp, sp or pc */		\
+	SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG,		\
+	SBREG, SBREG, SBREG,
+
+#define ROVERLAP \
+	{ XR0, -1 },			\
+	{ XR0, XR1, -1 },		\
+	{ XR1, XR2, -1 },		\
+	{ XR2, XR3, -1 },		\
+	{ XR3, XR4, -1 },		\
+	{ XR4, XR5, -1 },		\
+	{ XR5, XR6, -1 },		\
+	{ XR6, XR7, -1 },		\
+	{ XR7, XR8, -1 },		\
+	{ XR8, XR9, -1 },		\
+	{ XR9, XR10, -1 },		\
+	{ XR10, -1 },			\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 },				\
+	{ -1 },				\
+	{ R0, R1, XR1, -1 },		\
+	{ R1, R2, XR0, XR2, -1 },	\
+	{ R2, R3, XR1, XR3, -1 },	\
+	{ R3, R4, XR2, XR4, -1 },	\
+	{ R4, R5, XR3, XR5, -1 },	\
+	{ R5, R6, XR4, XR6, -1 },	\
+	{ R6, R7, XR5, XR7, -1 },	\
+	{ R7, R8, XR6, XR8, -1 },	\
+	{ R8, R9, XR7, XR9, -1 },	\
+	{ R9, R10, XR8, XR10, -1 },	\
+	{ R10, R11, XR9, -1 },
+
+#define NUMCLASS        2       /* highest number of reg classes used */
+
+/* size, in registers, needed to hold thing of type t */
+#define	szty(t)	(((t) == DOUBLE || (t) == LDOUBLE || (t) == FLOAT || \
+	(t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1)
+#define FPREG	FP	/* frame pointer */
+
+#define DECRA(x,y)      (((x) >> (y*6)) & 63)   /* decode encoded regs */
+#define ENCRD(x)        (x)             /* Encode dest reg in n_reg */
+#define ENCRA1(x)       ((x) << 6)      /* A1 */
+#define ENCRA2(x)       ((x) << 12)     /* A2 */
+#define ENCRA(x,y)      ((x) << (6+y*6))        /* encode regs in int */
+
+#define PCLASS(p)	(szty(p->n_type) == 2 ? SBREG : SAREG)
+#define RETREG(x)	(szty(x) == 2 ? XR0 : R0)
+#define GCLASS(x)	(x < XR0 ? CLASSA : CLASSB)
+int COLORMAP(int c, int *r);
+
+#define	SNCON		(MAXSPECIAL+1)	/* named constand */
Index: uspace/app/pcc/arch/vax/order.c
===================================================================
--- uspace/app/pcc/arch/vax/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/vax/order.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,611 @@
+/*	$Id: order.c,v 1.4 2007/11/26 00:10:03 gmcgarry 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 "pass2.h"
+
+int canaddr(NODE *);
+
+int maxargs = { -1 };
+
+#if 0
+stoasg( p, o ) register NODE *p; {
+	/* should the assignment op p be stored,
+	   given that it lies as the right operand of o
+	   (or the left, if o==UNARY MUL) */
+/*
+	if( p->op == INCR || p->op == DECR ) return;
+	if( o==UNARY MUL && p->left->op == REG && !isbreg(p->left->rval) ) SETSTO(p,INAREG);
+ */
+	}
+#endif
+
+int
+deltest( p ) register NODE *p; {
+	/* should we delay the INCR or DECR operation p */
+	p = p->n_left;
+	return( p->n_op == REG || p->n_op == NAME || p->n_op == OREG );
+	}
+
+#if 0
+autoincr( p ) NODE *p; {
+	register NODE *q = p->left, *r;
+
+	if( q->op == INCR && (r=q->left)->op == REG &&
+	    ISPTR(q->type) && p->type == DECREF(q->type) &&
+	    tlen(p) == q->right->lval ) return(1);
+
+	return(0);
+	}
+
+mkadrs(p) register NODE *p; {
+	register o;
+
+	o = p->op;
+
+	if( asgop(o) ){
+		if( p->left->su >= p->right->su ){
+			if( p->left->op == UNARY MUL ){
+				SETSTO( p->left->left, INTEMP );
+				}
+			else if( p->left->op == FLD && p->left->left->op == UNARY MUL ){
+				SETSTO( p->left->left->left, INTEMP );
+				}
+			else { /* should be only structure assignment */
+				SETSTO( p->left, INTEMP );
+				}
+			}
+		else SETSTO( p->right, INTEMP );
+		}
+	else {
+		if( p->left->su > p->right->su ){
+			SETSTO( p->left, INTEMP );
+			}
+		else {
+			SETSTO( p->right, INTEMP );
+			}
+		}
+	}
+#endif
+
+int
+notoff(TWORD t, int r, CONSZ off, char *cp)
+{
+	/* is it legal to make an OREG or NAME entry which has an
+	 * offset of off, (from a register of r), if the
+	 * resulting thing had type t */
+
+/*	if( r == R0 ) return( 1 );  / * NO */
+	return(0);  /* YES */
+	}
+
+# define max(x,y) ((x)<(y)?(y):(x))
+
+#if 0
+sucomp( p ) register NODE *p; {
+
+	/* set the su field in the node to the sethi-ullman
+	   number, or local equivalent */
+
+	register o, ty, sul, sur, r;
+
+	o = p->op;
+	ty = optype( o );
+	p->su = szty( p->type );   /* 2 for float or double, else 1 */;
+
+	if( ty == LTYPE ){
+		if( o == OREG ){
+			r = p->rval;
+			/* oreg cost is (worst case) 1 + number of temp registers used */
+			if( R2TEST(r) ){
+				if( R2UPK1(r)!=100 && istreg(R2UPK1(r)) ) ++p->su;
+				if( istreg(R2UPK2(r)) ) ++p->su;
+				}
+			else {
+				if( istreg( r ) ) ++p->su;
+				}
+			}
+		if( p->su == szty(p->type) &&
+		   (p->op!=REG || !istreg(p->rval)) &&
+		   (p->type==INT || p->type==UNSIGNED || p->type==DOUBLE) )
+			p->su = 0;
+		return;
+		}
+
+	else if( ty == UTYPE ){
+		switch( o ) {
+		case UNARY CALL:
+		case UNARY STCALL:
+			p->su = fregs;  /* all regs needed */
+			return;
+
+		default:
+			p->su =  p->left->su + (szty( p->type ) > 1 ? 2 : 0) ;
+			return;
+			}
+		}
+
+
+	/* If rhs needs n, lhs needs m, regular su computation */
+
+	sul = p->left->su;
+	sur = p->right->su;
+
+	if( o == ASSIGN ){
+		/* computed by doing right, then left (if not in mem), then doing it */
+		p->su = max(sur,sul+1);
+		return;
+		}
+
+	if( o == CALL || o == STCALL ){
+		/* in effect, takes all free registers */
+		p->su = fregs;
+		return;
+		}
+
+	if( o == STASG ){
+		/* right, then left */
+		p->su = max( max( 1+sul, sur), fregs );
+		return;
+		}
+
+	if( asgop(o) ){
+		/* computed by doing right, doing left address, doing left, op, and store */
+		p->su = max(sur,sul+2);
+/*
+		if( o==ASG MUL || o==ASG DIV || o==ASG MOD) p->su = max(p->su,fregs);
+ */
+		return;
+		}
+
+	switch( o ){
+	case ANDAND:
+	case OROR:
+	case QUEST:
+	case COLON:
+	case COMOP:
+		p->su = max( max(sul,sur), 1);
+		return;
+
+	case PLUS:
+	case OR:
+	case ER:
+		/* commutative ops; put harder on left */
+		if( p->right->su > p->left->su && !istnode(p->left) ){
+			register NODE *temp;
+			temp = p->left;
+			p->left = p->right;
+			p->right = temp;
+			}
+		break;
+		}
+
+	/* binary op, computed by left, then right, then do op */
+	p->su = max(sul,szty(p->right->type)+sur);
+/*
+	if( o==MUL||o==DIV||o==MOD) p->su = max(p->su,fregs);
+ */
+
+	}
+
+int radebug = 0;
+
+rallo( p, down ) NODE *p; {
+	/* do register allocation */
+	register o, type, down1, down2, ty;
+
+	if( radebug ) printf( "rallo( %o, %d )\n", p, down );
+
+	down2 = NOPREF;
+	p->rall = down;
+	down1 = ( down &= ~MUSTDO );
+
+	ty = optype( o = p->op );
+	type = p->type;
+
+
+	if( type == DOUBLE || type == FLOAT ){
+		if( o == FORCE ) down1 = R0|MUSTDO;
+		}
+	else switch( o ) {
+	case ASSIGN:	
+		down1 = NOPREF;
+		down2 = down;
+		break;
+
+/*
+	case MUL:
+	case DIV:
+	case MOD:
+		down1 = R3|MUSTDO;
+		down2 = R5|MUSTDO;
+		break;
+
+	case ASG MUL:
+	case ASG DIV:
+	case ASG MOD:
+		p->left->rall = down1 = R3|MUSTDO;
+		if( p->left->op == UNARY MUL ){
+			rallo( p->left->left, R4|MUSTDO );
+			}
+		else if( p->left->op == FLD  && p->left->left->op == UNARY MUL ){
+			rallo( p->left->left->left, R4|MUSTDO );
+			}
+		else rallo( p->left, R3|MUSTDO );
+		rallo( p->right, R5|MUSTDO );
+		return;
+ */
+
+	case CALL:
+	case STASG:
+	case EQ:
+	case NE:
+	case GT:
+	case GE:
+	case LT:
+	case LE:
+	case NOT:
+	case ANDAND:
+	case OROR:
+		down1 = NOPREF;
+		break;
+
+	case FORCE:	
+		down1 = R0|MUSTDO;
+		break;
+
+		}
+
+	if( ty != LTYPE ) rallo( p->left, down1 );
+	if( ty == BITYPE ) rallo( p->right, down2 );
+
+	}
+#endif
+
+void
+offstar( p, s ) register NODE *p; {
+comperr("offstar");
+#if 0
+	if( p->n_op == PLUS ) {
+		if( p->n_left->n_su == fregs ) {
+			order( p->n_left, INAREG );
+			return;
+		} else if( p->n_right->n_su == fregs ) {
+			order( p->n_right, INAREG );
+			return;
+		}
+		if( p->n_left->n_op==LS && 
+		  (p->n_left->n_left->n_op!=REG || tlen(p->n_left->n_left)!=sizeof(int) ) ) {
+			order( p->n_left->n_left, INAREG );
+			return;
+		}
+		if( p->n_right->n_op==LS &&
+		  (p->n_right->n_left->n_op!=REG || tlen(p->n_right->n_left)!=sizeof(int) ) ) {
+			order( p->n_right->n_left, INAREG );
+			return;
+		}
+		if( p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR) ) {
+			if( p->n_left->n_op!=REG || tlen(p->n_left)!=sizeof(int) ) {
+				order( p->n_left, INAREG );
+				return;
+			}
+			else if( p->n_right->n_op!=REG || tlen(p->n_right)!=sizeof(int) ) {
+				order(p->n_right, INAREG);
+				return;
+			}
+		}
+	}
+	if( p->n_op == PLUS || p->n_op == MINUS ){
+		if( p->n_right->n_op == ICON ){
+			p = p->n_left;
+			order( p , INAREG);
+			return;
+			}
+		}
+
+	if( p->n_op == UMUL && !canaddr(p) ) {
+		offstar( p->n_left, 0 );
+		return;
+	}
+
+	order( p, INAREG );
+#endif
+	}
+
+int
+setbin( p ) register NODE *p; {
+
+#if 0
+	register int ro, rt;
+
+	rt = p->n_right->n_type;
+	ro = p->n_right->n_op;
+
+	if( canaddr( p->n_left ) && !canaddr( p->n_right ) ) { /* address rhs */
+		if( ro == UMUL ) {
+			offstar( p->n_right->n_left, 0 );
+			return(1);
+		} else {
+			order( p->n_right, INAREG|SOREG );
+			return(1);
+		}
+	}
+	if( !istnode( p->n_left) ) { /* try putting LHS into a reg */
+/*		order( p->n_left, logop(p->n_op)?(INAREG|INBREG|INTAREG|INTBREG|SOREG):(INTAREG|INTBREG|SOREG) );*/
+		order( p->n_left, INAREG|INTAREG|INBREG|INTBREG|SOREG );
+		return(1);
+		}
+	else if( ro == UNARY MUL && rt != CHAR && rt != UCHAR ){
+		offstar( p->n_right->n_left );
+		return(1);
+		}
+	else if( rt == CHAR || rt == UCHAR || rt == SHORT || rt == USHORT || (ro != REG &&
+			ro != NAME && ro != OREG && ro != ICON ) ){
+		order( p->n_right, INAREG|INBREG );
+		return(1);
+		}
+/*
+	else if( logop(p->n_op) && rt==USHORT ){  / * must get rhs into register */
+/*
+		order( p->n_right, INAREG );
+		return( 1 );
+		}
+ */
+#endif
+	return(0);
+	}
+
+#if 0
+int
+setstr( p ) register NODE *p; { /* structure assignment */
+	if( p->right->op != REG ){
+		order( p->right, INTAREG );
+		return(1);
+		}
+	p = p->left;
+	if( p->op != NAME && p->op != OREG ){
+		if( p->op != UNARY MUL ) cerror( "bad setstr" );
+		order( p->left, INTAREG );
+		return( 1 );
+		}
+	return( 0 );
+	}
+#endif
+
+int
+setasg( p, s ) register NODE *p; {
+
+#if 0
+	/* setup for assignment operator */
+
+	if( !canaddr(p->n_right) ) {
+		if( p->n_right->n_op == UNARY MUL )
+			offstar(p->n_right->n_left);
+		else
+			order( p->n_right, INAREG|INBREG|SOREG );
+		return(1);
+		}
+	if( p->n_left->n_op == UMUL ) {
+		offstar( p->n_left->n_left );
+		return(1);
+		}
+	if( p->left->op == FLD && p->left->left->op == UNARY MUL ){
+		offstar( p->left->left->left );
+		return(1);
+		}
+/* FLD patch */
+	if( p->left->op == FLD && !(p->right->type==INT || p->right->type==UNSIGNED)) {
+		order( p->right, INAREG);
+		return(1);
+		}
+/* end of FLD patch */
+#endif
+	return(0);
+	}
+
+/* setup for unary operator */
+int
+setuni(NODE *p, int cookie)
+{
+	return 0;
+}
+
+
+#if 0
+int
+setasop( p ) register NODE *p; {
+	/* setup for =ops */
+	register rt, ro;
+
+	rt = p->right->type;
+	ro = p->right->op;
+
+	if( ro == UNARY MUL && rt != CHAR ){
+		offstar( p->right->left );
+		return(1);
+		}
+	if( ( rt == CHAR || rt == SHORT || rt == UCHAR || rt == USHORT ||
+			( ro != REG && ro != ICON && ro != NAME && ro != OREG ) ) ){
+		order( p->right, INAREG|INBREG );
+		return(1);
+		}
+/*
+	if( (p->op == ASG LS || p->op == ASG RS) && ro != ICON && ro != REG ){
+		order( p->right, INAREG );
+		return(1);
+		}
+ */
+
+
+	p = p->left;
+	if( p->op == FLD ) p = p->left;
+
+	switch( p->op ){
+
+	case REG:
+	case ICON:
+	case NAME:
+	case OREG:
+		return(0);
+
+	case UNARY MUL:
+		if( p->left->op==OREG )
+			return(0);
+		else
+			offstar( p->left );
+		return(1);
+
+		}
+	cerror( "illegal setasop" );
+	}
+#endif
+
+void
+deflab(int l)
+{
+	printf(LABFMT ":\n", l);
+}
+
+#if 0
+genargs( p, ptemp ) register NODE *p, *ptemp; {
+	register NODE *pasg;
+	register align;
+	register size;
+	register TWORD type;
+
+	/* generate code for the arguments */
+
+	/*  first, do the arguments on the right */
+	while( p->op == CM ){
+		genargs( p->right, ptemp );
+		p->op = FREE;
+		p = p->left;
+		}
+
+	if( p->op == STARG ){ /* structure valued argument */
+
+		size = p->stsize;
+		align = p->stalign;
+
+ /*		ptemp->lval = (ptemp->lval/align)*align;  / * SETOFF for negative numbers */
+ 		ptemp->lval = 0;	/* all moves to (sp) */
+
+		p->op = STASG;
+		p->right = p->left;
+		p->left = tcopy( ptemp );
+
+		/* the following line is done only with the knowledge
+		that it will be undone by the STASG node, with the
+		offset (lval) field retained */
+
+		if( p->right->op == OREG ) p->right->op = REG;  /* only for temporaries */
+
+ 		order( p, FORARG );
+		ptemp->lval += size;
+		return;
+		}
+
+	/* ordinary case */
+
+	order( p, FORARG );
+	}
+
+argsize( p ) register NODE *p; {
+	register t;
+	t = 0;
+	if( p->op == CM ){
+		t = argsize( p->left );
+		p = p->right;
+		}
+	if( p->type == DOUBLE || p->type == FLOAT ){
+		SETOFF( t, 4 );
+		return( t+8 );
+		}
+	else if( p->op == STARG ){
+ 		SETOFF( t, 4 );  /* alignment */
+ 		return( t + ((p->stsize+3)/4)*4 );  /* size */
+		}
+	else {
+		SETOFF( t, 4 );
+		return( t+4 );
+		}
+	}
+#endif
+
+/*
+ * Special handling of some instruction register allocation.
+ */
+struct rspecial *
+nspecial(struct optab *q)
+{
+	comperr("nspecial");
+	return NULL;
+}
+
+/*
+ * Set evaluation order of a binary node if it differs from default.
+ */
+int
+setorder(NODE *p)
+{
+	return 0; /* nothing differs on vax */
+}
+
+/*
+ * Do the actual conversion of offstar-found OREGs into real OREGs.
+ */
+void
+myormake(NODE *q)
+{
+}
+/*
+ * Set registers "live" at function calls (like arguments in registers).
+ * This is for liveness analysis of registers.
+ */
+int *
+livecall(NODE *p)
+{
+	static int r[1] = { -1 }; /* Terminate with -1 */
+
+	return &r[0];
+}
+
+/*
+ * Signal whether the instruction is acceptable for this target.
+ */
+int
+acceptable(struct optab *op)
+{
+	return 1;
+}
Index: uspace/app/pcc/arch/vax/table.c
===================================================================
--- uspace/app/pcc/arch/vax/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/arch/vax/table.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,695 @@
+/*	$Id: table.c,v 1.3 2007/10/29 14:20:22 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 "pass2.h"
+
+# define WPTR TPTRTO|TINT|TLONG|TFLOAT|TDOUBLE|TPOINT|TUNSIGNED|TULONG
+# define AWD SNAME|SOREG|SCON|STARNM|STARREG
+/* tbl */
+# define ANYSIGNED TPOINT|TINT|TLONG|TSHORT|TCHAR
+# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR
+# define ANYFIXED ANYSIGNED|ANYUSIGNED
+# define TWORD TINT|TUNSIGNED|TPOINT|TLONG|TULONG
+/* tbl */
+# define TBREG TLONGLONG|TULONGLONG|TDOUBLE
+
+struct optab  table[] = {
+/* First entry must be an empty entry */
+{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
+
+{ PCONV,	INAREG|INAREG,
+	SAREG|AWD,	TCHAR|TSHORT,
+	SANY,	TPOINT,
+		NAREG|NASL,	RESC1,
+		"	cvtZLl	AL,A1\n", },
+
+{ PCONV,	INAREG|INAREG,
+	SAREG|AWD,	TUCHAR|TUSHORT,
+	SANY,	TPOINT,
+		NAREG|NASL,	RESC1,
+		"	movzZLl	AL,A1\n", },
+
+{ SCONV,	INBREG|FORCC,
+	SAREG,	TDOUBLE,
+	SANY,	TDOUBLE,
+		0,	RLEFT,
+		"", },
+
+{ SCONV,	INBREG|FORCC,
+	SAREG|AWD,	TANY,
+	SANY,	TFLOAT|TDOUBLE,
+		NAREG|NASL,	RESC1|RESCC,
+		"	cvtZLd	AL,A1\n", },
+
+{ SCONV,	INAREG|FORCC,
+	SAREG|AWD,	TFLOAT|TDOUBLE,
+	SANY,	ANYFIXED,
+		NAREG|NASL,	RESC1|RESCC,
+		"	cvtZLZF	AL,A1\n", },
+
+{ SCONV,	INAREG|FORCC,
+	SAREG|SNAME|SCON|STARNM,	TANY,
+	SANY,	ANYUSIGNED,
+		NAREG|NASL,	RESC1|RESCC,
+		"	movzZRl	AL,A1\n", },
+
+{ SCONV,	INAREG|FORCC,
+	SSOREG,	TANY,
+	SANY,	ANYUSIGNED,
+		NAREG|NASL,	RESC1|RESCC,
+		"	movzZRl	AL,A1\n", },
+
+{ SCONV,	INAREG|FORCC,
+	SAREG|SNAME|SCON|STARNM,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1|RESCC,
+		"	cvtZRl	AL,A1\n", },
+
+{ SCONV,	INAREG|FORCC,
+	SSOREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1|RESCC,
+		"	cvtZRl	AL,A1\n", },
+
+{ GOTO,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	ZJ\n", },
+
+{ GOTO,	FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		0,	RNOP,
+		"	jmp	(AL)\n", },
+
+{ STARG,	INTEMP,
+	SCON|SAREG,	TANY,
+	SANY,	TANY,
+		NTEMP+2*NAREG,	RESC3,
+		"ZS", },
+
+#if 0
+{ STASG,	FORARG,
+	SNAME|SOREG,	TANY,
+	SCON|SAREG,	TANY,
+		0,	RNULL,
+		"	subl2	ZT,sp\nZS", },
+#endif
+
+{ ADDROF,	INAREG,
+	SNAME,	TANY,
+	SAREG,	TANY,
+		NAREG,	RESC1,
+		"	movab	AL,A1\n", },
+
+{ STASG,	FOREFF,
+	SNAME|SOREG,	TANY,
+	SCON|SAREG,	TANY,
+		0,	RNOP,
+		"ZS", },
+
+{ STASG,	INAREG,
+	SNAME|SOREG,	TANY,
+	SCON,	TANY,
+		NAREG,	RESC1,
+		"ZS	movl	AR,A1\n", },
+
+{ STASG,	INAREG,
+	SNAME|SOREG,	TANY,
+	SAREG,	TANY,
+		0,	RRIGHT,
+		"	pushl	AR\nZS	movl	(sp)+,AR\n", },
+
+{ FLD,	INAREG|INAREG,
+	SANY,	TANY,
+	SFLD,	ANYSIGNED,
+		NAREG|NASR,	RESC1,
+		"	extv	H,S,AR,A1\n", },
+
+{ FLD,	INAREG|INAREG,
+	SANY,	TANY,
+	SFLD,	ANYUSIGNED,
+		NAREG|NASR,	RESC1,
+		"	extzv	H,S,AR,A1\n", },
+
+#if 0
+{ FLD,	FORARG,
+	SANY,	TANY,
+	SFLD,	ANYSIGNED,
+		0,	RNULL,
+		"	extv	H,S,AR,-(sp)\n", },
+
+{ FLD,	FORARG,
+	SANY,	TANY,
+	SFLD,	ANYUSIGNED,
+		0,	RNULL,
+		"	extzv	H,S,AR,-(sp)\n", },
+#endif
+
+{ OPLOG,	FORCC,
+	SAREG|AWD,	TWORD,
+	SAREG|AWD,	TWORD,
+		0,	RESCC,
+		"	cmpl	AL,AR\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|AWD,	TSHORT|TUSHORT,
+	SAREG|AWD,	TSHORT|TUSHORT,
+		0,	RESCC,
+		"	cmpw	AL,AR\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|AWD,	TCHAR|TUCHAR,
+	SAREG|AWD,	TCHAR|TUCHAR,
+		0,	RESCC,
+		"	cmpb	AL,AR\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|AWD,	TSHORT|TUSHORT,
+	SSCON,	TANY,
+		0,	RESCC,
+		"	cmpw	AL,AR\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|AWD,	TCHAR|TUCHAR,
+	SCCON,	TANY,
+		0,	RESCC,
+		"	cmpb	AL,AR\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|AWD,	TDOUBLE,
+	SAREG|AWD,	TDOUBLE,
+		0,	RESCC,
+		"	cmpd	AL,AR\n", },
+
+{ OPLOG,	FORCC,
+	SAREG|AWD,	TFLOAT|TDOUBLE,
+	SAREG|AWD,	TFLOAT|TDOUBLE,
+		0,	RESCC,
+		"	cmpf	AL,AR\n", },
+
+{ CCODES,	INAREG|INAREG,
+	SANY,	TANY,
+	SANY,	TANY,
+		NAREG,	RESC1,
+		"	movl	$1,A1\nZN", },
+
+/*
+ * Subroutine calls.
+ */
+
+{ CALL,		FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	calls	ZC,CL\n", },
+
+{ UCALL,	FOREFF,
+	SCON,	TANY,
+	SANY,	TANY,
+		0,	0,
+		"	calls	$0,CL\n", },
+
+{ CALL,		INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1, /* should be register 0 */
+		"	calls	ZC,CL\n", },
+
+{ UCALL,	INAREG,
+	SCON,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1, /* should be register 0 */
+		"	calls	$0,CL\n", },
+
+{ CALL,		INAREG|FOREFF,
+	SAREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	calls	ZC,(AL)\n", },
+
+{ UCALL,	INAREG|FOREFF,
+	SAREG,	TANY,
+	SANY,	TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE,
+		NAREG|NASL,	RESC1,	/* should be 0 */
+		"	calls	ZC,(AL)\n", },
+
+{ UCALL,	INAREG|FOREFF,
+	SNAME,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* really reg 0 */
+		"	calls	ZC,*AL\n", },
+
+{ UCALL,	INAREG|FOREFF,
+	SSOREG,	TANY,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1,	/* really reg 0 */
+		"	calls	ZC,*AL\n", },
+
+/*
+ * Function arguments
+ */
+{ FUNARG,	FOREFF,
+	SCON|SAREG|SNAME|SOREG,	TWORD|TPOINT,
+	SANY,	TWORD|TPOINT,
+		0,	RNULL,
+		"	pushl AL\n" },
+
+#if 0
+{ ASG RS,	INAREG|FOREFF|FORCC,
+	SAREG,	TWORD,
+	SCON,	TINT,
+		0,	RLEFT|RESCC,
+		"	extzv	AR,ZU,AL,AL\n", },
+
+{ ASG RS,	INAREG|FOREFF|FORCC,
+	SAREG,	TWORD,
+	SAREG,	ANYFIXED,
+		NAREG,	RLEFT|RESCC,
+		"	subl3	AR,$32,A1\n	extzv	AR,A1,AL,AL\n", },
+
+{ ASG RS,	INAREG|FOREFF|FORCC,
+	SAREG,	TWORD,
+	SAREG|AWD,	TWORD,
+		NAREG,	RLEFT|RESCC,
+		"	subl3	AR,$32,A1\n	extzv	AR,A1,AL,AL\n", },
+#endif
+
+{ RS,	INAREG|INAREG|FORCC,
+	SAREG,	TWORD,
+	SCON,	TINT,
+		NAREG|NASL,	RESC1|RESCC,
+		"	extzv	AR,ZU,AL,A1\n", },
+
+#if 0
+{ ASG LS,	INAREG|FOREFF|FORCC,
+	SAREG|AWD,	TWORD,
+	SAREG|AWD,	ANYSIGNED|ANYUSIGNED,
+		0,	RLEFT|RESCC,
+		"	ashl	AR,AL,AL\n", },
+#endif
+
+{ LS,	INAREG|INAREG|FORCC,
+	SAREG|AWD,	TWORD,
+	SAREG|AWD,	ANYSIGNED|ANYUSIGNED,
+		NAREG|NASL|NASR,	RESC1|RESCC,
+		"	ashl	AR,AL,A1\n", },
+
+#if 0
+{ INCR,	FOREFF,
+	SAREG|AWD,	TANY,
+	SANY,	TANY,
+		0,	RLEFT,
+		"	ZE\n", },
+
+{ DECR,	FOREFF,
+	SAREG|AWD,	TANY,
+	SCON,	TANY,
+		0,	RLEFT,
+		"	ZE\n", },
+
+{ INCR,	INAREG|INAREG,
+	SAREG|AWD,	TANY,
+	SCON,	TANY,
+		NAREG,	RESC1,
+		"	ZD\n", },
+
+{ DECR,	INAREG|INAREG,
+	SAREG|AWD,	TANY,
+	SCON,	TANY,
+		NAREG,	RESC1,
+		"	ZD\n", },
+#endif
+
+{ ASSIGN,	INBREG|FOREFF,
+	SBREG|AWD,	TBREG,
+	SBREG|AWD,	TBREG,
+		0,	RDEST,
+		"	movq AR,AL\n", },
+
+{ ASSIGN,	INAREG|FOREFF|FORCC,
+	SAREG|AWD,	TANY,
+	SAREG|AWD,	TANY,
+		0,	RDEST|RESCC,
+		"	ZA\n", },
+
+{ ASSIGN,	INAREG|FOREFF|FORCC,
+	SFLD,	TANY,
+	SAREG|AWD,	TWORD,
+		0,	RDEST|RESCC,
+		"	insv	AR,H,S,AL\n", },
+
+{ ASSIGN,	INAREG|FOREFF|FORCC,
+	SAREG|AWD,	TWORD,
+	SFLD,	ANYSIGNED,
+		0,	RDEST|RESCC,
+		"	extv	H,S,AR,AL\n", },
+
+{ ASSIGN,	INAREG|FOREFF|FORCC,
+	SAREG|AWD,	TWORD,
+	SFLD,	ANYUSIGNED,
+		0,	RDEST|RESCC,
+		"	extzv	H,S,AR,AL\n", },
+
+/* dummy UNARY MUL entry to get U* to possibly match OPLTYPE */
+{ UMUL,	FOREFF,
+	SCC,	TANY,
+	SCC,	TANY,
+		0,	RNULL,
+		"	HELP HELP HELP\n", },
+
+#if 0
+{ REG,	FORARG,
+	SANY,	TANY,
+	SAREG,	TDOUBLE|TFLOAT,
+		0,	RNULL,
+		"	movZR	AR,-(sp)\n", },
+#endif
+
+{ REG,	INTEMP,
+	SANY,	TANY,
+	SAREG,	TDOUBLE,
+		2*NTEMP,	RESC1,
+		"	movd	AR,A1\n", },
+
+{ REG,	INTEMP,
+	SANY,	TANY,
+	SAREG,	TANY,
+		NTEMP,	RESC1,
+		"	movZF	AR,A1\n", },
+
+{ OPLEAF,	FOREFF,
+	SANY,	TANY,
+	SAREG|AWD,	TANY,
+		0,	RLEFT,
+		"", },
+
+{ OPLTYPE,	INAREG|INAREG,
+	SANY,	TANY,
+	SANY,	TFLOAT|TDOUBLE,
+		2*NAREG|NASR,	RESC1,
+		"	ZA\n", },
+
+{ OPLTYPE,	INAREG|INAREG,
+	SANY,	TANY,
+	SANY,	TANY,
+		NAREG|NASR,	RESC1,
+		"	ZA\n", },
+
+{ OPLTYPE,	FORCC,
+	SANY,	TANY,
+	SANY,	TANY,
+		0,	RESCC,
+		"	tstZR	AR\n", },
+
+#if 0
+{ OPLTYPE,	FORARG,
+	SANY,	TANY,
+	SANY,	TWORD,
+		0,	RNULL,
+		"	pushl	AR\n", },
+
+{ OPLTYPE,	FORARG,
+	SANY,	TANY,
+	SANY,	TCHAR|TSHORT,
+		0,	RNULL,
+		"	cvtZRl	AR,-(sp)\n", },
+
+{ OPLTYPE,	FORARG,
+	SANY,	TANY,
+	SANY,	TUCHAR|TUSHORT,
+		0,	RNULL,
+		"	movzZRl	AR,-(sp)\n", },
+
+{ OPLTYPE,	FORARG,
+	SANY,	TANY,
+	SANY,	TDOUBLE,
+		0,	RNULL,
+		"	movd	AR,-(sp)\n", },
+
+{ OPLTYPE,	FORARG,
+	SANY,	TANY,
+	SANY,	TFLOAT,
+		0,	RNULL,
+		"	cvtfd	AR,-(sp)\n", },
+#endif
+
+{ UMINUS,	INAREG|FORCC,
+	SAREG|AWD,	TINT|TUNSIGNED|TLONG|TULONG|TDOUBLE,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1|RESCC,
+		"	mnegZL	AL,A1\n", },
+
+{ COMPL,	INAREG|FORCC,
+	SAREG|AWD,	TINT|TUNSIGNED,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1|RESCC,
+		"	mcomZL	AL,A1\n", },
+
+{ COMPL,	INAREG|FORCC,
+	SAREG|AWD,	ANYSIGNED|ANYUSIGNED,
+	SANY,	TANY,
+		NAREG|NASL,	RESC1|RESCC,
+		"	cvtZLl	AL,A1\n	mcoml	A1,A1\n", },
+
+{ AND,	FORCC,
+	SAREG|AWD,	TWORD,
+	SCON,	TWORD,
+		0,	RESCC,
+		"	bitl	ZZ,AL\n", },
+
+{ AND,	FORCC,
+	SAREG|AWD,	TSHORT|TUSHORT,
+	SSCON,	TWORD,
+		0,	RESCC,
+		"	bitw	ZZ,AL\n", },
+
+{ AND,	FORCC,
+	SAREG|AWD,	TCHAR|TUCHAR,
+	SCCON,	TWORD,
+		0,	RESCC,
+		"	bitb	ZZ,AL\n", },
+
+#if 0
+{ ASG AND,	INAREG|FOREFF|FORCC,
+	SAREG,	ANYFIXED,
+	SCON,	TWORD,
+		0,	RLEFT|RESCC,
+		"	bicl2	AR,AL\n", },
+
+{ ASG OPMUL,	INAREG|FOREFF|FORCC,
+	SAREG|AWD,	TINT|TUNSIGNED|TLONG|TULONG,
+	SAREG|AWD,	TINT|TUNSIGNED|TLONG|TULONG,
+		0,	RLEFT|RESCC,
+		"	OL2	AR,AL\n", },
+#endif
+
+{ OPMUL,	INAREG|INAREG|FORCC,
+	SAREG,	TINT|TUNSIGNED|TLONG|TULONG,
+	SAREG|AWD,	TINT|TUNSIGNED|TLONG|TULONG,
+		0,	RLEFT|RESCC,
+		"	OL2	AR,AL\n", },
+
+{ OPMUL,	INAREG|INAREG|FORCC,
+	SAREG|AWD,	TINT|TUNSIGNED|TLONG|TULONG,
+	SAREG|AWD,	TINT|TUNSIGNED|TLONG|TULONG,
+		NAREG|NASL|NASR,	RESC1|RESCC,
+		"	OL3	AR,AL,A1\n", },
+
+#if 0
+{ ASG MOD,	INAREG|INAREG|FOREFF|FORCC,
+	SAREG,	TINT|TUNSIGNED|TLONG|TULONG,
+	SAREG|AWD,	TINT|TUNSIGNED|TLONG|TULONG,
+		NAREG,	RLEFT|RESCC,
+		"	divl3	AR,AL,A1\n	mull2	AR,A1\n	subl2	A1,AL\n", },
+#endif
+
+{ MOD,	INAREG|INAREG,
+	SAREG|AWD,	TINT|TUNSIGNED|TLONG|TULONG,
+	SAREG|AWD,	TINT|TUNSIGNED|TLONG|TULONG,
+		NAREG,	RESC1,
+		"	divl3	AR,AL,A1\n	mull2	AR,A1\n	subl3	A1,AL,A1\n", },
+
+#if 0
+{ ASG PLUS,	INAREG|FOREFF|FORCC,
+	SAREG|AWD,	ANYSIGNED|ANYUSIGNED,
+	SONE,	TINT|TLONG,
+		0,	RLEFT|RESCC,
+		"	incZL	AL\n", },
+
+{ ASG MINUS,	INAREG|FOREFF|FORCC,
+	SAREG|AWD,	ANYSIGNED|ANYUSIGNED,
+	SONE,	TINT|TLONG,
+		0,	RLEFT|RESCC,
+		"	decZL	AL\n", },
+#endif
+
+{ PLUS,	INAREG|INAREG|FORCC,
+	SAREG,	ANYFIXED,
+	SONE,	TWORD,
+		0,	RLEFT|RESCC,
+		"	incZL	AL\n", },
+
+{ MINUS,	INAREG|INAREG|FORCC,
+	SAREG,	ANYFIXED,
+	SONE,	TWORD,
+		0,	RLEFT|RESCC,
+		"	decZL	AL\n", },
+
+#if 0
+{ ASG OPSIMP,	INAREG|FOREFF|FORCC,
+	SAREG|AWD,	TWORD,
+	SAREG|AWD,	TWORD,
+		0,	RLEFT|RESCC,
+		"	OL2	AR,AL\n", },
+
+{ ASG OPSIMP,	INAREG|FOREFF|FORCC,
+	AWD,	TSHORT|TUSHORT,
+	SAREG|AWD,	TSHORT|TUSHORT,
+		0,	RLEFT|RESCC,
+		"	OW2	AR,AL\n", },
+
+{ ASG OPSIMP,	INAREG|FOREFF|FORCC,
+	AWD,	TSHORT|TUSHORT,
+	SSCON,	TWORD,
+		0,	RLEFT|RESCC,
+		"	OW2	AR,AL\n", },
+
+{ ASG OPSIMP,	INAREG|FOREFF|FORCC,
+	AWD,	TCHAR|TUCHAR,
+	SAREG|AWD,	TCHAR|TUCHAR,
+		0,	RLEFT|RESCC,
+		"	OB2	AR,AL\n", },
+
+{ ASG OPSIMP,	INAREG|FOREFF|FORCC,
+	AWD,	TCHAR|TUCHAR,
+	SCCON,	TWORD,
+		0,	RLEFT|RESCC,
+		"	OB2	AR,AL\n", },
+#endif
+
+{ OPSIMP,	INAREG|INAREG|FORCC,
+	SAREG,	ANYFIXED,
+	SAREG|AWD,	TWORD,
+		0,	RLEFT|RESCC,
+		"	OL2	AR,AL\n", },
+
+{ OPSIMP,	INAREG|INAREG|FORCC,
+	SAREG|AWD,	TWORD,
+	SAREG|AWD,	TWORD,
+		NAREG|NASL|NASR,	RESC1|RESCC,
+		"	OL3	AR,AL,A1\n", },
+
+#if 0
+{ ASG OPFLOAT,	INAREG|FOREFF|FORCC,
+	SAREG|AWD,	TDOUBLE,
+	SAREG|AWD,	TDOUBLE,
+		0,	RLEFT|RESCC,
+		"	OD2	AR,AL\n", },
+
+{ ASG OPFLOAT,	INAREG|FOREFF|FORCC,
+	SAREG|AWD,	TFLOAT,
+	SAREG|AWD,	TFLOAT,
+		0,	RLEFT|RESCC,
+		"	OF2	AR,AL\n", },
+
+{ ASG OPFLOAT,	INAREG|FOREFF|FORCC,
+	SAREG|AWD,	TDOUBLE,
+	SAREG|AWD,	TFLOAT,
+		NAREG|NASR,	RLEFT|RESCC,
+		"	cvtfd	AR,A1\n	OD2	A1,AL\n", },
+
+{ ASG OPFLOAT,	INAREG|INAREG|FOREFF|FORCC,
+	SAREG|AWD,	TFLOAT,
+	SAREG|AWD,	TDOUBLE,
+		NAREG,	RLEFT|RESC1|RESCC,
+		"	cvtfd	AL,A1\n	OD2	AR,A1\n	cvtdf	A1,AL\n", },
+#endif
+
+{ OPFLOAT,	INAREG|INAREG|FORCC,
+	SAREG,	TDOUBLE,
+	SAREG|AWD,	TDOUBLE,
+		0,	RLEFT|RESCC,
+		"	OD2	AR,AL\n", },
+
+{ OPFLOAT,	INAREG|INAREG|FORCC,
+	SAREG|AWD,	TDOUBLE,
+	SAREG|AWD,	TDOUBLE,
+		NAREG|NASL|NASR,	RESC1|RESCC,
+		"	OD3	AR,AL,A1\n", },
+
+{ OPFLOAT,	INAREG|INAREG|FORCC,
+	SAREG|AWD,	TFLOAT,
+	SAREG|AWD,	TDOUBLE,
+		NAREG|NASL,	RESC1|RESCC,
+		"	cvtfd	AL,A1\n	OD2	AR,A1\n", },
+
+{ OPFLOAT,	INAREG|INAREG|FORCC,
+	SAREG|AWD,	TDOUBLE,
+	SAREG|AWD,	TFLOAT,
+		NAREG|NASR,	RESC1|RESCC,
+		"	cvtfd	AR,A1\n	OD3	A1,AL,A1\n", },
+
+{ OPFLOAT,	INAREG|INAREG|FORCC,
+	SAREG|AWD,	TFLOAT,
+	SAREG|AWD,	TFLOAT,
+		NAREG|NASL|NASR,	RESC1|RESCC,
+		"	OF3	AR,AL,A1\n	cvtfd	A1,A1\n", },
+
+	/* Default actions for hard trees ... */
+
+# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
+
+{ UMUL, DF( UMUL ), },
+
+{ ASSIGN, DF(ASSIGN), },
+
+{ STASG, DF(STASG), },
+
+{ OPLEAF, DF(NAME), },
+
+{ OPLOG,	FORCC,
+	SANY,	TANY,
+	SANY,	TANY,
+		REWRITE,	BITYPE,
+		"", },
+
+{ OPUNARY, DF(UMINUS), },
+
+{ OPANY, DF(BITYPE), },
+
+{ FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	"help; I'm in trouble\n" }
+};
Index: uspace/app/pcc/cc/Makefile.in
===================================================================
--- uspace/app/pcc/cc/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,39 @@
+#	$Id: Makefile.in,v 1.3 2008/01/06 17:18:55 ragge Exp $
+#
+# Makefile.in for top-level of pcc.
+#
+
+@SET_MAKE@
+VPATH=@srcdir@
+CC=@CC@
+CFLAGS=@CFLAGS@
+LDFLAGS=@LDFLAGS@
+CPPFLAGS=@CPPFLAGS@
+YACC=@YACC@
+LEX=@LEX@
+
+SUBDIR=cc cpp ccom
+
+all: ${SUBDIR}
+
+install:
+	cd cc && ${MAKE} install
+	cd cpp && ${MAKE} install
+	cd ccom && ${MAKE} install
+
+clean:
+	cd cc && ${MAKE} clean
+	cd cpp && ${MAKE} clean
+	cd ccom && ${MAKE} clean
+
+distclean:
+	cd cc && ${MAKE} distclean
+	cd cpp && ${MAKE} distclean
+	cd ccom && ${MAKE} distclean
+	/bin/rm -rf Makefile config.log stamp-h1 config.status \
+	configure.lineno config.h autom4te.cache
+
+${SUBDIR}: nonexistant
+	cd $@; $(MAKE) all $(MFLAGS)
+
+nonexistant:
Index: uspace/app/pcc/cc/cc/Makefile
===================================================================
--- uspace/app/pcc/cc/cc/Makefile	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cc/Makefile	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,50 @@
+#
+# Copyright (c) 2011 Jiri Zarevucky
+# 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 must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - 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.
+#
+
+USPACE_PREFIX = ../../../..
+MIPDIR = ../../mip
+ARCHDIR = ../../arch/$(PLATFORM)
+OSDIR = ../../os/helenos
+EXTRA_CFLAGS = -I$(MIPDIR) -I$(ARCHDIR) -I$(OSDIR) -w
+DEFS = -Dmach_$(PLATFORM) -D__helenos__
+BINARY = cc
+
+PRE_DEPEND = compat.c
+EXTRA_CLEAN = compat.c
+
+POSIX_COMPAT = y
+
+SOURCES = \
+	cc.c \
+	compat.c
+
+include $(USPACE_PREFIX)/Makefile.common
+
+compat.c: $(MIPDIR)/compat.c
+	ln -s -f $^ $@
+
Index: uspace/app/pcc/cc/cc/Makefile.in
===================================================================
--- uspace/app/pcc/cc/cc/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cc/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,70 @@
+#	$Id: Makefile.in,v 1.22 2009/11/14 16:27:23 ragge Exp $
+#
+# Makefile.in for the cc part of pcc.
+#
+VPATH=@srcdir@
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+top_builddir=@top_builddir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+includedir = @includedir@
+datarootdir = @datarootdir@
+mandir = @mandir@
+strip = @strip@
+CC = @CC@
+EXEEXT = @EXEEXT@
+TARGOS = @targos@
+TARGMACH = @targmach@
+TARGET = @target@
+VERSION = @PACKAGE_VERSION@
+PCCLIBDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/lib
+PCCINCDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/include
+CFLAGS = @CFLAGS@ @ADD_CFLAGS@
+CPPFLAGS = @CPPFLAGS@ -DLIBEXECDIR=\"${libexecdir}/\" \
+	@ADD_CPPFLAGS@ -DINCLUDEDIR=\"${includedir}/\" \
+	-DPCCINCDIR=\"${PCCINCDIR}/\" -DPCCLIBDIR=\"${PCCLIBDIR}/\" \
+	-Dos_${TARGOS} -DTARGMACH=${TARGMACH} -Dmach_${TARGMACH} \
+	-I${top_builddir} -I${top_srcdir}/os/${TARGOS} -I${MIPDIR} -I${MDIR}
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+
+OBJS=cc.o compat.o
+DEST=@BINPREFIX@pcc$(EXEEXT)
+
+MIPDIR=${top_srcdir}/mip
+MDIR=${top_srcdir}/arch/$(TARGMACH)
+
+all: ${DEST}
+
+${DEST}: $(OBJS)
+	$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@
+
+.c.o:
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $<
+
+compat.o: $(MIPDIR)/compat.c
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/compat.c
+
+install:
+	test -z "${DESTDIR}$(bindir)" || mkdir -p "${DESTDIR}$(bindir)"
+	${INSTALL_PROGRAM} ${DEST} ${DESTDIR}${bindir}
+	@if [ ${strip} = yes ]; then		\
+		strip ${DESTDIR}${bindir}/${DEST} ;	\
+		echo strip ${DESTDIR}${bindir}/${DEST} ;	\
+	fi
+	test -z "${DESTDIR}$(mandir)/man1" || mkdir -p "${DESTDIR}$(mandir)/man1"
+	${INSTALL} $(srcdir)/cc.1 ${DESTDIR}${mandir}/man1/${DEST}.1
+	test -z "${DESTDIR}$(PCCINCDIR)" || mkdir -p "${DESTDIR}$(PCCINCDIR)"
+	test -z "${DESTDIR}$(PCCLIBDIR)" || mkdir -p "${DESTDIR}$(PCCLIBDIR)"
+
+clean:
+	/bin/rm -f  $(OBJS) ${DEST}
+
+distclean: clean
+	/bin/rm -f  Makefile
Index: uspace/app/pcc/cc/cc/cc.1
===================================================================
--- uspace/app/pcc/cc/cc/cc.1	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cc/cc.1	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,335 @@
+.\"	$Id: cc.1,v 1.16 2010/04/05 14:24:06 reed Exp $
+.\"	$NetBSD$
+.\"	$OpenBSD$
+.\"
+.\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net>
+.\"
+.\" Permission to use, copy, modify, and/or distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM
+.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND
+.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+.\" THIS SOFTWARE.
+.\"
+.Dd September 14, 2007
+.Dt CC 1
+.Os
+.Sh NAME
+.Nm cc
+.Nd front-end to the C compiler
+.Sh SYNOPSIS
+.Nm
+.Op Fl cEgkLMPOStvXx
+.Op Fl fPIC
+.Op Fl fpic
+.Op Fl m Ns Ar option
+.Op Fl nostartfiles
+.Op Fl nostdinc
+.Op Fl nostdlib
+.Op Fl pg
+.Op Fl pthread
+.Op Fl static
+.Op Fl B Ar prefix
+.Op Fl D Ar macro[=value]
+.Op Fl d Ar option
+.Op Fl I Ar directory
+.Op Fl include Ar path
+.Op Fl isystem Ar path
+.Op Fl o Ar outfile
+.Op Fl Wl Ar flags
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility provides a front-end to the
+.Dq portable C compiler .
+Multiple files may be given on the command line.
+Unrecognized options are all sent directly to
+.Xr ld 1 .
+.Pp
+.\" Brief description of its syntax:
+Filenames that end with
+.Sy \&.c
+are passed via
+.Xr cpp 1
+\(->
+.Xr ccom 1
+\(->
+.Xr as 1
+\(->
+.Xr ld 1 .
+.Pp
+Filenames that end with
+.Sy \&.i
+are passed via
+.Xr ccom 1
+\(->
+.Xr as 1
+\(->
+.Xr ld 1 .
+.Pp
+Filenames that end with
+.Sy \&.s
+are passed via
+.Xr as 1
+\(->
+.Xr ld 1 .
+.Pp
+Filenames that end with
+.Sy \&.S
+are passed via
+.Xr cpp 1
+\(->
+.Xr as 1
+\(->
+.Xr ld 1 .
+.Pp
+Filenames that end with
+.Sy \&.o
+are passed directly to
+.Xr ld 1 .
+.Pp
+.\"
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl B Ar prefix
+Define alternate prefix path for
+.Xr cpp 1 ,
+.Xr ccom 1 ,
+.Xr as 1 ,
+or
+.Xr ld 1
+executables.
+.\" TODO: provide an example of -B
+.It Fl C
+Passed to the
+.Xr cpp 1
+preprocessor to not discard comments.
+.It Fl c
+Only compile or assemble and then stop.
+Do not link.
+The resulting object output is saved
+as a filename with a
+.Dq \&.o
+suffix unless
+.Fl o
+option is used.
+Note: cannot be combined with
+.Fl o
+if multiple files are given.
+.It Fl D Ar macro[=value]
+Passed to the
+.Xr cpp 1
+preprocessor to define
+.Ar macro .
+.It Fl d Ar option
+Passed to the
+.Xr as 1
+assembler.
+.\" TODO: what is as -dfoo for?
+.It Fl E
+Stop after preprocessing with
+.Xr cpp 1 .
+Do not compile, assemble, or link.
+Output is sent to standard output unless the
+.Fl o
+option is used.
+.It Fl fPIC
+Generate PIC code.
+.\" TODO: document about avoiding machine-specific maximum size?
+.It Fl fpic
+Tells C compiler to generate PIC code
+and tells assembler that PIC code has been generated.
+.\" TODO: document difference between PIC and pic
+.\" other -f GCC compatibility flags are ignored for now
+.It Fl g
+Send
+.Fl g
+flag to
+.Xr ccom 1
+to create debug output.
+This unsets the
+.Fl O
+option.
+.It Fl I Ar path
+Passed to the
+.Xr cpp 1
+preprocessor to add header search directory to override system defaults.
+.It Fl include Ar file
+Tells the
+.Xr cpp 1
+preprocessor to include the
+.Ar file
+during preprocessing.
+.It Fl isystem Ar path
+Defines
+.Ar path
+as a system header directory for the
+.Xr cpp 1
+preprocessor.
+.It Fl k
+Generate PIC code.
+See
+.Fl fpic
+option.
+.It Fl L
+TODO
+.It Fl M
+Pass
+.Fl M
+flag to
+.Xr cpp 1
+to generate dependencies for
+.Xr make 1 .
+.It Fl m Ns options
+Target-dependent option.
+.Bl -tag -width PowerPC
+.It ARM
+\-mlittle-endian \-mbig-endian \-mfpe=fpa \-mfpe=vpf \-msoft-float \-march=armv1 \-march=armv2 \-march=armv2a \-march=armv3 \-march=armv4 \-march=armv4t \-march=armv4tej \-march=armv5 \-march=armv6 \-march=armv6t2 \-march=armv6kz \-march=armv6k \-march=armv7
+.It HPPA
+.It i386
+.It MIPS
+\-mlittle-endian \-mbig-endian \-mhard-float \-msoft-float
+.It PDP-10
+.It PowerPC
+.It Sparc64
+.It VAX
+.El
+.It Fl nostartfiles
+Do not link with the system startup files (crt0.c, etc.)
+.It Fl nostdinc
+Do not use the system include paths (/usr/include, etc.)
+.It Fl nostdlib
+Do not link with the system C library (libc).
+.\" implies -nostartfiles ??
+.It Fl O
+Enable optimizations.
+Currently passes
+.Fl xdeljumps
+and
+.Fl xtemps
+to
+.Xr ccom 1 .
+Note: this is unset if the
+.Fl g
+option is used.
+.It Fl o Ar outfile
+Save result to
+.Ar outfile .
+.It Fl P
+TODO
+.\" TODO: what is this?
+.\" TODO: Looks like it does cpp only, but I couldn't get it to work for me.
+.It Fl pg
+Enable profiling on the generated executable.
+.It Fl pthread
+Defines
+.Sy _PTHREADS
+preprocessor directive for
+.Xr cpp 1 .
+Uses
+.Sy \-lpthread
+for the
+.Xr ld 1
+linker.
+.It Fl S
+Stop after compilation by
+.Xr ccom 1 .
+Do not assemble and do not link.
+The resulting assembler-language output is saved
+as a filename with a
+.Dq \&.s
+suffix unless the
+.Fl o
+option is used.
+Note: cannot be combined with
+.Fl o
+if multiple files are given.
+.It Fl static
+Do not use dynamic linkage.
+By default, it will link using the dynamic linker options
+and/or shared objects for the platform.
+.It Fl shared
+Create a shared object of the result.  Tells the linker not to 
+generate an executable.
+.It Fl t
+Passes
+.Fl t
+to
+.Xr cpp 1
+for traditional C preprocessor syntax.
+.It Fl U Ar macro
+Passes to the
+.Xr cpp 1
+preprocessor to remove the initial macro definition.
+.It Fl v
+Outputs the version of
+.Nm
+and shows what commands will be run with their command line arguments.
+.It Fl Wl Ar flags
+Options for the linker.
+.\" what is ignored? llist?
+.It Fl X
+Don't remove temporary files on exit.
+.It Fl x
+May be used to give separate optimization flags to ccom, see
+.Fl O
+for options.
+.It Fl x Ar c
+Gcc compatibility option; specify that the language in use is
+.Ar c .
+.El
+.Ss Predefined Macros
+A few
+macros are predefined by
+.Nm
+when sent to
+.Xr cpp 1 .
+.Bl -diag
+.\" TODO:
+.\" .It __ASSEMBLER__
+.\" Defined if suffix is .S -- why not with .s? what does this mean?
+.It __PCC__
+Set to the major version of
+.Xr pcc 1 .
+These macros can be used to select code based on
+.Xr pcc 1
+compatibility.
+See the
+.Fl v
+option.
+.It __PCC_MINOR__
+Set to the minor version.
+.It __PCC_MINORMINOR__
+Set to the minor-minor version \(em the number after the minor version.
+.It _PTHREADS
+Defined when
+.Fl pthread
+switch is used.
+.El
+.Pp
+Also system- and/or machine-dependent macros may also be predefined;
+for example:
+.Dv __NetBSD__ ,
+.Dv __ELF__ ,
+and
+.Dv __i386__ .
+.Sh SEE ALSO
+.Xr as 1 ,
+.Xr ccom 1 ,
+.Xr cpp 1 ,
+.Xr ld 1
+.Sh HISTORY
+The
+.Nm
+command comes from the original Portable C Compiler by S. C. Johnson,
+written in the late 70's.
+.Pp
+This product includes software developed or owned by Caldera
+International, Inc.
Index: uspace/app/pcc/cc/cc/cc.c
===================================================================
--- uspace/app/pcc/cc/cc/cc.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cc/cc.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1603 @@
+/*	$Id: cc.c,v 1.170.2.1 2011/03/15 19:25:36 ragge Exp $	*/
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Front-end to the C compiler.
+ *
+ * Brief description of its syntax:
+ * - Files that end with .c are passed via cpp->ccom->as->ld
+ * - Files that end with .i are passed via ccom->as->ld
+ * - Files that end with .s are passed as->ld
+ * - Files that end with .o are passed directly to ld
+ * - Multiple files may be given on the command line.
+ * - Unrecognized options are all sent directly to ld.
+ * -c or -S cannot be combined with -o if multiple files are given.
+ *
+ * This file should be rewritten readable.
+ */
+#include "config.h"
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_LIBGEN_H
+#include <libgen.h>
+#endif
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef WIN32
+#include <windows.h>
+#include <process.h>
+#include <io.h>
+#endif
+
+#include "compat.h"
+
+#include "ccconfig.h"
+#include "macdefs.h"
+/* C command */
+
+#define	MKS(x) _MKS(x)
+#define _MKS(x) #x
+
+/*
+ * Many specific definitions, should be declared elsewhere.
+ */
+
+#ifndef STDINC
+#define	STDINC	  	"/usr/include/"
+#endif
+
+#ifndef LIBDIR
+#define LIBDIR		"/usr/lib/"
+#endif
+
+#ifndef PREPROCESSOR
+#define PREPROCESSOR	"cpp"
+#endif
+
+#ifndef COMPILER
+#define COMPILER	"ccom"
+#endif
+
+#ifndef ASSEMBLER
+#define ASSEMBLER	"as"
+#endif
+
+#ifndef LINKER
+#define LINKER		"ld"
+#endif
+
+#define OS MKS(TARGOS)
+#define MACH MKS(TARGMACH)
+#ifndef PCCINCDIR
+#define PCCINCDIR	LIBDIR "pcc/" MACH "-" OS "/" PACKAGE_VERSION "/include"
+#endif
+#ifndef PCCLIBDIR
+#define PCCLIBDIR	LIBDIR "pcc/" MACH "-" OS "/" PACKAGE_VERSION "/lib"
+#endif
+
+#define MAXFIL 10000
+#define MAXLIB 10000
+#define MAXAV  10000
+#define MAXOPT 200
+char	*tmp3;
+char	*tmp4;
+char	*outfile, *ermfile;
+char *Bprefix(char *);
+char *copy(char *, int);
+char *setsuf(char *, char);
+int getsuf(char *);
+int main(int, char *[]);
+void error(char *, ...);
+void errorx(int, char *, ...);
+int callsys(char [], char *[]);
+int cunlink(char *);
+void dexit(int);
+void idexit(int);
+char *gettmp(void);
+void *ccmalloc(int size);
+#ifdef WIN32
+char *win32pathsubst(char *);
+char *win32commandline(char *, char *[]);
+#endif
+char	*av[MAXAV];
+char	*clist[MAXFIL];
+char    *olist[MAXFIL];
+char	*llist[MAXLIB];
+char	*aslist[MAXAV];
+char	*cpplist[MAXAV];
+char	alist[20];
+char	*xlist[100];
+int	xnum;
+char	*mlist[100];
+char	*flist[100];
+char	*wlist[100];
+char	*idirafter;
+int	nm;
+int	nf;
+int	nw;
+int	sspflag;
+int	dflag;
+int	pflag;
+int	sflag;
+int	cflag;
+int	eflag;
+int	gflag;
+int	rflag;
+int	vflag;
+int	tflag;
+int	Eflag;
+int	Oflag;
+int	kflag;	/* generate PIC/pic code */
+#define F_PIC	1
+#define F_pic	2
+int	Mflag;	/* dependencies only */
+int	pgflag;
+int	exfail;
+int	Xflag;
+int	Wallflag;
+int	Wflag;
+int	nostartfiles, Bstatic, shared;
+int	nostdinc, nostdlib;
+int	onlyas;
+int	pthreads;
+int	xcflag;
+int 	ascpp;
+
+char	*passp = LIBEXECDIR PREPROCESSOR;
+char	*pass0 = LIBEXECDIR COMPILER;
+char	*as = ASSEMBLER;
+char	*ld = LINKER;
+char	*Bflag;
+char *cppadd[] = CPPADD;
+#ifdef DYNLINKER
+char *dynlinker[] = DYNLINKER;
+#endif
+#ifdef CRT0FILE
+char *crt0file = CRT0FILE;
+#endif
+#ifdef CRT0FILE_PROFILE
+char *crt0file_profile = CRT0FILE_PROFILE;
+#endif
+#ifdef STARTFILES
+char *startfiles[] = STARTFILES;
+char *endfiles[] = ENDFILES;
+#endif
+#ifdef STARTFILES_T
+char *startfiles_T[] = STARTFILES_T;
+char *endfiles_T[] = ENDFILES_T;
+#endif
+#ifdef STARTFILES_S
+char *startfiles_S[] = STARTFILES_S;
+char *endfiles_S[] = ENDFILES_S;
+#endif
+#ifdef MULTITARGET
+char *mach = DEFMACH;
+struct cppmd {
+	char *mach;
+	char *cppmdadd[MAXCPPMDARGS];
+};
+
+struct cppmd cppmds[] = CPPMDADDS;
+#else
+char *cppmdadd[] = CPPMDADD;
+#endif
+#ifdef LIBCLIBS
+char *libclibs[] = LIBCLIBS;
+#else
+char *libclibs[] = { "-lc", NULL };
+#endif
+#ifdef LIBCLIBS_PROFILE
+char *libclibs_profile[] = LIBCLIBS_PROFILE;
+#else
+char *libclibs_profile[] = { "-lc_p", NULL };
+#endif
+#ifndef STARTLABEL
+#define STARTLABEL "__start"
+#endif
+char *incdir = STDINC;
+char *altincdir = INCLUDEDIR "pcc/";
+char *libdir = LIBDIR;
+char *pccincdir = PCCINCDIR;
+char *pcclibdir = PCCLIBDIR;
+#ifdef mach_amd64
+int amd64_i386;
+#endif
+
+/* handle gcc warning emulations */
+struct Wflags {
+	char *name;
+	int flags;
+#define	INWALL		1
+#define	NEGATIVE	2
+} Wflags[] = {
+	{ "-Wtruncate", 0 },
+	{ "-Wno-truncate", NEGATIVE },
+	{ "-Werror", 0 },
+	{ "-Wshadow", 0 },
+	{ "-Wno-shadow", NEGATIVE },
+	{ "-Wpointer-sign", INWALL },
+	{ "-Wno-pointer-sign", NEGATIVE },
+	{ "-Wsign-compare", 0 },
+	{ "-Wno-sign-compare", NEGATIVE },
+	{ "-Wunknown-pragmas", INWALL },
+	{ "-Wno-unknown-pragmas", NEGATIVE },
+	{ "-Wunreachable-code", 0 },
+	{ "-Wno-unreachable-code", NEGATIVE },
+	{ 0, 0 },
+};
+
+#define	SZWFL	(sizeof(Wflags)/sizeof(Wflags[0]))
+
+#ifndef USHORT
+/* copied from mip/manifest.h */
+#define	USHORT		5
+#define	INT		6
+#define	UNSIGNED	7
+#endif
+
+/*
+ * Wide char defines.
+ */
+ #if 0
+#if WCHAR_TYPE == USHORT
+#define	WCT "short unsigned int"
+#define WCM "65535U"
+#if WCHAR_SIZE != 2
+#error WCHAR_TYPE vs. WCHAR_SIZE mismatch
+#endif
+#elif WCHAR_TYPE == INT
+#define WCT "int"
+#define WCM "2147483647"
+#if WCHAR_SIZE != 4
+#error WCHAR_TYPE vs. WCHAR_SIZE mismatch
+#endif
+#elif WCHAR_TYPE == UNSIGNED
+#define WCT "unsigned int"
+#define WCM "4294967295U"
+#if WCHAR_SIZE != 4
+#error WCHAR_TYPE vs. WCHAR_SIZE mismatch
+#endif
+#else
+#error WCHAR_TYPE not defined or invalid
+#endif
+ #endif
+
+#define WCT "int"
+#define WCM "2147483647"
+
+
+#ifdef GCC_COMPAT
+#ifndef REGISTER_PREFIX
+#define REGISTER_PREFIX ""
+#endif
+#ifndef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX ""
+#endif
+#endif
+
+#ifndef PCC_PTRDIFF_TYPE
+#define PCC_PTRDIFF_TYPE "long int"
+#endif
+
+int
+main(int argc, char *argv[])
+{
+	struct Wflags *Wf;
+	char *t, *u;
+	char *assource;
+	char **pv, *ptemp[MAXOPT], **pvt;
+	int nc, nl, nas, ncpp, i, j, c, nxo, na;
+#ifdef MULTITARGET
+	int k;
+#endif
+
+#ifdef WIN32
+	/* have to prefix path early.  -B may override */
+	incdir = win32pathsubst(incdir);
+	altincdir = win32pathsubst(altincdir);
+	libdir = win32pathsubst(libdir);
+	pccincdir = win32pathsubst(pccincdir);
+	pcclibdir = win32pathsubst(pcclibdir);
+	passp = win32pathsubst(passp);
+	pass0 = win32pathsubst(pass0);
+#endif
+
+	i = nc = nl = nas = ncpp = nxo = 0;
+	pv = ptemp;
+	while(++i < argc) {
+		if (argv[i][0] == '-') {
+			switch (argv[i][1]) {
+			default:
+				goto passa;
+#ifdef notyet
+	/* must add library options first (-L/-l/...) */
+				error("unrecognized option `-%c'", argv[i][1]);
+				break;
+#endif
+
+			case '-': /* double -'s */
+				if (strcmp(argv[i], "--version") == 0) {
+					printf("%s\n", VERSSTR);
+					return 0;
+				} else if (strcmp(argv[i], "--param") == 0) {
+					/* NOTHING YET */;
+					i++; /* ignore arg */
+				} else
+					goto passa;
+				break;
+
+			case 'B': /* other search paths for binaries */
+				Bflag = &argv[i][2];
+				break;
+
+#ifdef MULTITARGET
+			case 'b':
+				t = &argv[i][2];
+				if (*t == '\0' && i + 1 < argc) {
+					t = argv[i+1];
+					i++;
+				}
+				if (strncmp(t, "?", 1) == 0) {
+					/* show machine targets */
+					printf("Available machine targets:");
+					for (j=0; cppmds[j].mach; j++)
+						printf(" %s",cppmds[j].mach);
+					printf("\n");
+					exit(0);
+				}
+				for (j=0; cppmds[j].mach; j++)
+					if (strcmp(t, cppmds[j].mach) == 0) {
+						mach = cppmds[j].mach;
+						break;
+					}
+				if (cppmds[j].mach == NULL)
+					errorx(1, "unknown target arch %s", t);
+				break;
+#endif
+
+			case 'X':
+				Xflag++;
+				break;
+			case 'W': /* Ignore (most of) W-flags */
+				if (strncmp(argv[i], "-Wl,", 4) == 0) {
+					/* options to the linker */
+					t = &argv[i][4];
+					while ((u = strchr(t, ','))) {
+						*u++ = 0;
+						llist[nl++] = t;
+						t = u;
+					}
+					llist[nl++] = t;
+				} else if (strncmp(argv[i], "-Wa,", 4) == 0) {
+					/* options to the assembler */
+					t = &argv[i][4];
+					while ((u = strchr(t, ','))) {
+						*u++ = 0;
+						aslist[nas++] = t;
+						t = u;
+					}
+					aslist[nas++] = t;
+				} else if (strncmp(argv[i], "-Wc,", 4) == 0) {
+					/* options to ccom */
+					t = &argv[i][4];
+					while ((u = strchr(t, ','))) {
+						*u++ = 0;
+						wlist[nw++] = t;
+						t = u;
+					}
+					wlist[nw++] = t;
+				} else if (strncmp(argv[i], "-Wp,", 4) == 0) {
+					/* preprocessor */
+					t = &argv[i][4];
+					while ((u = strchr(t, ','))) {
+						*u++ = 0;
+						cpplist[ncpp++] = t;
+						t = u;
+					}
+					cpplist[ncpp++] = t;
+				} else if (strcmp(argv[i], "-Wall") == 0) {
+					Wallflag = 1;
+				} else if (strcmp(argv[i], "-WW") == 0) {
+					Wflag = 1;
+				} else {
+					/* check and set if available */
+					for (Wf = Wflags; Wf->name; Wf++) {
+						if (strcmp(argv[i], Wf->name))
+							continue;
+						wlist[nw++] = Wf->name;
+					}
+				}
+				break;
+
+			case 'f': /* GCC compatibility flags */
+				if (strcmp(argv[i], "-fPIC") == 0)
+					kflag = F_PIC;
+				else if (strcmp(argv[i], "-fpic") == 0)
+					kflag = F_pic;
+				else if (strcmp(argv[i],
+				    "-fsigned-char") == 0)
+					flist[nf++] = argv[i];
+				else if (strcmp(argv[i],
+				    "-fno-signed-char") == 0)
+					flist[nf++] = argv[i];
+				else if (strcmp(argv[i],
+				    "-funsigned-char") == 0)
+					flist[nf++] = argv[i];
+				else if (strcmp(argv[i],
+				    "-fno-unsigned-char") == 0)
+					flist[nf++] = argv[i];
+				else if (strcmp(argv[i],
+				    "-fstack-protector") == 0) {
+					flist[nf++] = argv[i];
+					sspflag++;
+				} else if (strcmp(argv[i],
+				    "-fstack-protector-all") == 0) {
+					flist[nf++] = argv[i];
+					sspflag++;
+				} else if (strcmp(argv[i],
+				    "-fno-stack-protector") == 0) {
+					flist[nf++] = argv[i];
+					sspflag = 0;
+				} else if (strcmp(argv[i],
+				    "-fno-stack-protector-all") == 0) {
+					flist[nf++] = argv[i];
+					sspflag = 0;
+				}
+				/* silently ignore the rest */
+				break;
+
+			case 'g': /* create debug output */
+				gflag++;
+				break;
+
+			case 'i':
+				if (strcmp(argv[i], "-isystem") == 0) {
+					*pv++ = "-S";
+					*pv++ = argv[++i];
+				} else if (strcmp(argv[i], "-include") == 0) {
+					*pv++ = "-i";
+					*pv++ = argv[++i];
+				} else if (strcmp(argv[i], "-idirafter") == 0) {
+					idirafter = argv[++i];
+				} else
+					goto passa;
+				break;
+
+			case 'k': /* generate PIC code */
+				kflag = F_pic;
+				break;
+
+			case 'm': /* target-dependent options */
+#ifdef mach_amd64
+				/* need to call i386 ccom for this */
+				if (strcmp(argv[i], "-m32") == 0) {
+					pass0 = LIBEXECDIR "/ccom_i386";
+					amd64_i386 = 1;
+					break;
+				}
+#endif
+				mlist[nm++] = argv[i];
+				if (argv[i][2] == 0) {
+					/* separate second arg */
+					/* give also to linker */
+					llist[nl++] = argv[i++];
+					mlist[nm++] = argv[i];
+					llist[nl++] = argv[i];
+				}
+				break;
+
+			case 'n': /* handle -n flags */
+				if (strcmp(argv[i], "-nostdinc") == 0)
+					nostdinc++;
+				else if (strcmp(argv[i], "-nostdlib") == 0) {
+					nostdlib++;
+					nostartfiles++;
+				} else if (strcmp(argv[i], "-nostartfiles") == 0)
+					nostartfiles = 1;
+				else
+					goto passa;
+				break;
+
+			case 'p':
+				if (strcmp(argv[i], "-pg") == 0 ||
+				    strcmp(argv[i], "-p") == 0)
+					pgflag++;
+				else if (strcmp(argv[i], "-pthread") == 0)
+					pthreads++;
+				else if (strcmp(argv[i], "-pipe") == 0)
+					/* NOTHING YET */;
+				else if (strcmp(argv[i], "-pedantic") == 0)
+					/* NOTHING YET */;
+				else if (strcmp(argv[i],
+				    "-print-prog-name=ld") == 0) {
+					printf("%s\n", LINKER);
+					return 0;
+				} else
+					errorx(1, "unknown option %s", argv[i]);
+				break;
+
+			case 'r':
+				rflag = 1;
+				break;
+
+			case 'x':
+				t = &argv[i][2];
+				if (*t == 0)
+					t = argv[++i];
+				if (strcmp(t, "c") == 0)
+					xcflag = 1; /* default */
+				else if (strcmp(t, "assembler-with-cpp") == 0)
+					ascpp = 1;
+#ifdef notyet
+				else if (strcmp(t, "c++") == 0)
+					cxxflag++;
+#endif
+				else
+					xlist[xnum++] = argv[i];
+				break;
+			case 't':
+				tflag++;
+				break;
+			case 'S':
+				sflag++;
+				cflag++;
+				break;
+			case 'o':
+				if (outfile)
+					errorx(8, "too many -o");
+				outfile = argv[++i];
+				break;
+			case 'O':
+				if (argv[i][2] == '0')
+					Oflag = 0;
+				else
+					Oflag++;
+				break;
+			case 'E':
+				Eflag++;
+				break;
+			case 'P':
+				pflag++;
+				*pv++ = argv[i];
+			case 'c':
+				cflag++;
+				break;
+
+#if 0
+			case '2':
+				if(argv[i][2] == '\0')
+					pref = "/lib/crt2.o";
+				else {
+					pref = "/lib/crt20.o";
+				}
+				break;
+#endif
+			case 'C':
+				cpplist[ncpp++] = argv[i];
+				break;
+			case 'D':
+			case 'I':
+			case 'U':
+				*pv++ = argv[i];
+				if (argv[i][2] == 0)
+					*pv++ = argv[++i];
+				if (pv >= ptemp+MAXOPT) {
+					error("Too many DIU options");
+					--pv;
+				}
+				break;
+
+			case 'M':
+				Mflag++;
+				break;
+
+			case 'd':
+#ifdef os_darwin
+				if (strcmp(argv[i], "-dynamiclib") == 0) {
+					shared = 1;
+				} else
+#endif
+				if (strcmp(argv[i], "-d") == 0) {
+					dflag++;
+					strlcpy(alist, argv[i], sizeof (alist));
+				}
+				break;
+			case 'v':
+				printf("%s\n", VERSSTR);
+				vflag++;
+				break;
+
+			case 's':
+#ifndef os_darwin
+				if (strcmp(argv[i], "-shared") == 0) {
+					shared = 1;
+#ifndef os_win32
+					nostdlib = 1;
+#endif
+				} else
+#endif
+				if (strcmp(argv[i], "-static") == 0) {
+					Bstatic = 1;
+				} else if (strncmp(argv[i], "-std", 4) == 0) {
+					/* ignore gcc -std= */;
+				} else
+					goto passa;
+				break;
+			}
+		} else {
+		passa:
+			t = argv[i];
+			if (*argv[i] == '-' && argv[i][1] == 'L')
+				;
+			else if((c=getsuf(t))=='c' || c=='S' || c=='i' ||
+			    c=='s'|| Eflag || xcflag) {
+				clist[nc++] = t;
+				if (nc>=MAXFIL) {
+					error("Too many source files");
+					exit(1);
+				}
+			}
+
+			/* Check for duplicate .o files. */
+			for (j = getsuf(t) == 'o' ? 0 : nl; j < nl; j++) {
+				if (strcmp(llist[j], t) == 0)
+					break;
+			}
+			if ((c=getsuf(t))!='c' && c!='S' &&
+			    c!='s' && c!='i' && j==nl) {
+				llist[nl++] = t;
+				if (nl >= MAXLIB) {
+					error("Too many object/library files");
+					exit(1);
+				}
+				if (getsuf(t)=='o')
+					nxo++;
+			}
+		}
+	}
+	/* Sanity checking */
+	if (nc == 0 && nl == 0)
+		errorx(8, "no input files");
+	if (outfile && (cflag || sflag || Eflag) && nc > 1)
+		errorx(8, "-o given with -c || -E || -S and more than one file");
+	if (outfile && clist[0] && strcmp(outfile, clist[0]) == 0)
+		errorx(8, "output file will be clobbered");
+	if (nc==0)
+		goto nocom;
+	if (pflag==0) {
+		if (!sflag)
+			tmp3 = gettmp();
+		tmp4 = gettmp();
+	}
+	if (Bflag) {
+		altincdir = Bflag;
+		pccincdir = Bflag;
+		pcclibdir = Bflag;
+	}
+	if (signal(SIGINT, SIG_IGN) != SIG_IGN)	/* interrupt */
+		signal(SIGINT, idexit);
+	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)	/* terminate */
+		signal(SIGTERM, idexit);
+#ifdef MULTITARGET
+	pass0 = copy(LIBEXECDIR "/ccom_", k = strlen(mach));
+	strlcat(pass0, mach, sizeof(LIBEXECDIR "/ccom_") + k);
+#endif
+	pvt = pv;
+	for (i=0; i<nc; i++) {
+		/*
+		 * C preprocessor
+		 */
+		if (nc>1 && !Eflag)
+			printf("%s:\n", clist[i]);
+		onlyas = 0;
+		assource = tmp3;
+		if (getsuf(clist[i])=='S')
+			ascpp = 1;
+		if (getsuf(clist[i])=='i') {
+			if(Eflag)
+				continue;
+			goto com;
+		} else if (ascpp) {
+			onlyas = 1;
+		} else if (getsuf(clist[i])=='s') {
+			assource = clist[i];
+			goto assemble;
+		}
+		if (pflag)
+			tmp4 = setsuf(clist[i], 'i');
+		na = 0;
+		av[na++] = "cpp";
+		if (vflag)
+			av[na++] = "-v";
+		av[na++] = "-D__PCC__=" MKS(PCC_MAJOR);
+		av[na++] = "-D__PCC_MINOR__=" MKS(PCC_MINOR);
+		av[na++] = "-D__PCC_MINORMINOR__=" MKS(PCC_MINORMINOR);
+#ifndef os_win32
+#ifdef GCC_COMPAT
+		av[na++] = "-D__GNUC__=4";
+		av[na++] = "-D__GNUC_MINOR__=3";
+		av[na++] = "-D__GNUC_PATCHLEVEL__=1";
+		av[na++] = "-D__GNUC_STDC_INLINE__=1";
+#endif
+#endif
+		av[na++] = "-D__VERSION__=" MKS(VERSSTR);
+		av[na++] = "-D__SCHAR_MAX__=" MKS(MAX_CHAR);
+		av[na++] = "-D__SHRT_MAX__=" MKS(MAX_SHORT);
+		av[na++] = "-D__INT_MAX__=" MKS(MAX_INT);
+		av[na++] = "-D__LONG_MAX__=" MKS(MAX_LONG);
+		av[na++] = "-D__LONG_LONG_MAX__=" MKS(MAX_LONGLONG);
+#ifdef CHAR_UNSIGNED
+		av[na++] = "-D__CHAR_UNSIGNED__";
+#endif
+		if (ascpp)
+			av[na++] = "-D__ASSEMBLER__";
+		if (sspflag)
+			av[na++] = "-D__SSP__=1";
+		if (pthreads)
+			av[na++] = "-D_PTHREADS";
+		if (Mflag)
+			av[na++] = "-M";
+		if (Oflag)
+			av[na++] = "-D__OPTIMIZE__";
+#ifdef GCC_COMPAT
+		av[na++] = "-D__REGISTER_PREFIX__=" REGISTER_PREFIX;
+		av[na++] = "-D__USER_LABEL_PREFIX__=" USER_LABEL_PREFIX;
+		if (Oflag)
+			av[na++] = "-D__OPTIMIZE__";
+#endif
+		if (dflag)
+			av[na++] = alist;
+		for (j = 0; cppadd[j]; j++)
+			av[na++] = cppadd[j];
+		for (j = 0; j < ncpp; j++)
+			av[na++] = cpplist[j];
+		av[na++] = "-D__STDC_ISO_10646__=200009L";
+		av[na++] = "-D__WCHAR_TYPE__=" WCT;
+		av[na++] = "-D__SIZEOF_WCHAR_T__=" MKS(WCHAR_SIZE);
+		av[na++] = "-D__WCHAR_MAX__=" WCM;
+		av[na++] = "-D__WINT_TYPE__=unsigned int";
+		av[na++] = "-D__SIZE_TYPE__=unsigned long";
+		av[na++] = "-D__PTRDIFF_TYPE__=" PCC_PTRDIFF_TYPE;
+		av[na++] = "-D__SIZEOF_WINT_T__=4";
+#ifdef MULTITARGET
+		for (k = 0; cppmds[k].mach; k++) {
+			if (strcmp(cppmds[k].mach, mach) != 0)
+				continue;
+			for (j = 0; cppmds[k].cppmdadd[j]; j++)
+				av[na++] = cppmds[k].cppmdadd[j];
+			break;
+		}
+#else
+		for (j = 0; cppmdadd[j]; j++)
+			av[na++] = cppmdadd[j];
+#endif
+		if (tflag)
+			av[na++] = "-t";
+		for(pv=ptemp; pv <pvt; pv++)
+			av[na++] = *pv;
+		if (!nostdinc) {
+			av[na++] = "-S", av[na++] = altincdir;
+			av[na++] = "-S", av[na++] = incdir;
+			av[na++] = "-S", av[na++] = pccincdir;
+		}
+		if (idirafter) {
+			av[na++] = "-I";
+			av[na++] = idirafter;
+		}
+		av[na++] = clist[i];
+		if (!Eflag && !Mflag)
+			av[na++] = tmp4;
+		if ((Eflag || Mflag) && outfile)
+			 ermfile = av[na++] = outfile;
+		av[na++]=0;
+		if (callsys(passp, av)) {
+			exfail++;
+			eflag++;
+		}
+		if (Eflag || Mflag)
+			continue;
+		if (onlyas) {
+			assource = tmp4;
+			goto assemble;
+		}
+
+		/*
+		 * C compiler
+		 */
+	com:
+		na = 0;
+		av[na++]= "ccom";
+		if (Wallflag) {
+			/* Set only the same flags as gcc */
+			for (Wf = Wflags; Wf->name; Wf++) {
+				if (Wf->flags != INWALL)
+					continue;
+				av[na++] = Wf->name;
+			}
+		}
+		if (Wflag) {
+			/* set all positive flags */
+			for (Wf = Wflags; Wf->name; Wf++) {
+				if (Wf->flags == NEGATIVE)
+					continue;
+				av[na++] = Wf->name;
+			}
+		}
+		for (j = 0; j < nw; j++)
+			av[na++] = wlist[j];
+		for (j = 0; j < nf; j++)
+			av[na++] = flist[j];
+#if !defined(os_sunos) && !defined(mach_i386)
+		if (vflag)
+			av[na++] = "-v";
+#endif
+		if (pgflag)
+			av[na++] = "-p";
+		if (gflag)
+			av[na++] = "-g";
+#ifdef os_darwin
+		/* darwin always wants PIC compilation */
+		if (!Bstatic)
+			av[na++] = "-k";
+#elif defined(os_sunos) && defined(mach_i386)
+		if (kflag) {
+			av[na++] = "-K";
+			av[na++] = "pic";
+		}
+#else
+		if (kflag)
+			av[na++] = "-k";
+#endif
+		if (Oflag) {
+			av[na++] = "-xtemps";
+			av[na++] = "-xdeljumps";
+			av[na++] = "-xinline";
+		}
+		for (j = 0; j < xnum; j++)
+			av[na++] = xlist[j];
+		for (j = 0; j < nm; j++)
+			av[na++] = mlist[j];
+		if (getsuf(clist[i])=='i')
+			av[na++] = clist[i];
+		else
+			av[na++] = tmp4; /* created by cpp */
+		if (pflag || exfail)
+			{
+			cflag++;
+			continue;
+			}
+		if(sflag) {
+			if (outfile)
+				tmp3 = outfile;
+			else
+				tmp3 = setsuf(clist[i], 's');
+		}
+		ermfile = av[na++] = tmp3;
+#if 0
+		if (proflag) {
+			av[3] = "-XP";
+			av[4] = 0;
+		} else
+			av[3] = 0;
+#endif
+		av[na++] = NULL;
+		if (callsys(pass0, av)) {
+			cflag++;
+			eflag++;
+			continue;
+		}
+		if (sflag)
+			continue;
+
+		/*
+		 * Assembler
+		 */
+	assemble:
+		na = 0;
+		av[na++] = as;
+		for (j = 0; j < nas; j++)
+			av[na++] = aslist[j];
+#if defined(os_win32) && defined(USE_YASM)
+		av[na++] = "-p";
+		av[na++] = "gnu";
+		av[na++] = "-f";
+		av[na++] = "win32";
+#endif
+#if defined(os_sunos) && defined(mach_sparc64)
+		av[na++] = "-m64";
+#endif
+#if defined(os_darwin)
+		if (Bstatic)
+			av[na++] = "-static";
+#endif
+		if (vflag)
+			av[na++] = "-v";
+		if (kflag)
+			av[na++] = "-k";
+#ifdef mach_amd64
+		if (amd64_i386)
+			av[na++] = "--32";
+#endif
+		av[na++] = "-o";
+		if (outfile && cflag)
+			ermfile = av[na++] = outfile;
+		else if (cflag)
+			ermfile = av[na++] = olist[i] = setsuf(clist[i], 'o');
+		else
+			ermfile = av[na++] = olist[i] = gettmp();
+		av[na++] = assource;
+		if (dflag)
+			av[na++] = alist;
+		av[na++] = 0;
+		if (callsys(as, av)) {
+			cflag++;
+			eflag++;
+			cunlink(tmp4);
+			continue;
+		}
+		cunlink(tmp4);
+	}
+
+	if (Eflag || Mflag)
+		dexit(eflag);
+
+	/*
+	 * Linker
+	 */
+nocom:
+	if (cflag==0 && nc+nl != 0) {
+		j = 0;
+		av[j++] = ld;
+#ifndef MSLINKER
+		if (vflag)
+			av[j++] = "-v";
+#endif
+#if !defined(os_sunos) && !defined(os_win32) && !defined(os_darwin)
+		av[j++] = "-X";
+#endif
+		if (shared) {
+#ifdef os_darwin
+			av[j++] = "-dylib";
+#else
+			av[j++] = "-shared";
+#endif
+#ifdef os_win32
+			av[j++] = "-Bdynamic";
+#endif
+#ifndef os_sunos
+		} else {
+#ifndef os_win32
+#ifndef os_darwin
+			av[j++] = "-d";
+#endif
+			if (rflag) {
+				av[j++] = "-r";
+			} else {
+				av[j++] = "-e";
+				av[j++] = STARTLABEL;
+			}
+#endif
+#endif
+			if (Bstatic == 0) { /* Dynamic linkage */
+#ifdef DYNLINKER
+				for (i = 0; dynlinker[i]; i++)
+					av[j++] = dynlinker[i];
+#endif
+			} else {
+#ifdef os_darwin
+				av[j++] = "-static";
+#else
+				av[j++] = "-Bstatic";
+#endif
+			}
+		}
+		if (outfile) {
+#ifdef MSLINKER
+#define	OUTSTR	"/OUT:"
+			char *s = copy(OUTSTR, i = strlen(outfile));
+			strlcat(s, outfile, sizeof(OUTSTR) + i);
+			av[j++] = s;
+#else
+			av[j++] = "-o";
+			av[j++] = outfile;
+#endif
+		}
+#ifdef STARTFILES_S
+		if (shared) {
+			if (!nostartfiles) {
+				for (i = 0; startfiles_S[i]; i++)
+					av[j++] = Bprefix(startfiles_S[i]);
+			}
+		} else
+#endif
+		{
+			if (!nostartfiles) {
+#ifdef CRT0FILE_PROFILE
+				if (pgflag) {
+					av[j++] = Bprefix(crt0file_profile);
+				} else
+#endif
+				{
+#ifdef CRT0FILE
+					av[j++] = Bprefix(crt0file);
+#endif
+				}
+#ifdef STARTFILES_T
+				if (Bstatic) {
+					for (i = 0; startfiles_T[i]; i++)
+						av[j++] = Bprefix(startfiles_T[i]);
+				} else
+#endif
+				{
+#ifdef STARTFILES
+					for (i = 0; startfiles[i]; i++)
+						av[j++] = Bprefix(startfiles[i]);
+#endif
+				}
+			}
+		}
+		i = 0;
+		while (i<nc) {
+			av[j++] = olist[i++];
+			if (j >= MAXAV)
+				error("Too many ld options");
+		}
+		i = 0;
+		while(i<nl) {
+			av[j++] = llist[i++];
+			if (j >= MAXAV)
+				error("Too many ld options");
+		}
+#if !defined(os_darwin) && !defined(os_sunos)
+		/* darwin assembler doesn't want -g */
+		if (gflag)
+			av[j++] = "-g";
+#endif
+#if 0
+		if (gflag)
+			av[j++] = "-lg";
+#endif
+		if (pthreads)
+			av[j++] = "-lpthread";
+		if (!nostdlib) {
+#ifdef MSLINKER
+#define	LFLAG	"/LIBPATH:"
+#else
+#define	LFLAG	"-L"
+#endif
+			char *s = copy(LFLAG, i = strlen(pcclibdir));
+			strlcat(s, pcclibdir, sizeof(LFLAG) + i);
+			av[j++] = s;
+#ifdef os_win32
+			s = copy(LFLAG, i = strlen(libdir));
+			strlcat(s, libdir, sizeof(LFLAG) + i);
+			av[j++] = s;
+#endif
+			if (pgflag) {
+				for (i = 0; libclibs_profile[i]; i++)
+					av[j++] = Bprefix(libclibs_profile[i]);
+			} else {
+				for (i = 0; libclibs[i]; i++)
+					av[j++] = Bprefix(libclibs[i]);
+			}
+		}
+		if (!nostartfiles) {
+#ifdef STARTFILES_S
+			if (shared) {
+				for (i = 0; endfiles_S[i]; i++)
+					av[j++] = Bprefix(endfiles_S[i]);
+			} else 
+#endif
+			{
+#ifdef STARTFILES_T
+				if (Bstatic) {
+					for (i = 0; endfiles_T[i]; i++)
+						av[j++] = Bprefix(endfiles_T[i]);
+				} else
+#endif
+				{
+#ifdef STARTFILES
+					for (i = 0; endfiles[i]; i++)
+						av[j++] = Bprefix(endfiles[i]);
+#endif
+				}
+			}
+		}
+#ifdef __helenos__
+		av[j++] = "-T";
+		av[j++] = "/inc/_link.ld";
+#endif
+		
+		av[j++] = 0;
+		eflag |= callsys(ld, av);
+		if (nc==1 && nxo==1 && eflag==0)
+			cunlink(olist[0]);
+		else if (nc > 0 && eflag == 0) {
+			/* remove .o files XXX ugly */
+			for (i = 0; i < nc; i++)
+				cunlink(olist[i]);
+		}
+	}
+	dexit(eflag);
+	return 0;
+}
+
+/*
+ * exit and cleanup after interrupt.
+ */
+void
+idexit(int arg)
+{
+	dexit(100);
+}
+
+/*
+ * exit and cleanup.
+ */
+void
+dexit(int eval)
+{
+	if (!pflag && !Xflag) {
+		if (sflag==0)
+			cunlink(tmp3);
+		cunlink(tmp4);
+	}
+	if (exfail || eflag)
+		cunlink(ermfile);
+	if (eval == 100)
+		_exit(eval);
+	exit(eval);
+}
+
+static void
+ccerror(char *s, va_list ap)
+{
+	vfprintf(Eflag ? stderr : stdout, s, ap);
+	putc('\n', Eflag? stderr : stdout);
+	exfail++;
+	cflag++;
+	eflag++;
+}
+
+/*
+ * complain a bit.
+ */
+void
+error(char *s, ...)
+{
+	va_list ap;
+
+	va_start(ap, s);
+	ccerror(s, ap);
+	va_end(ap);
+}
+
+/*
+ * complain a bit and then exit.
+ */
+void
+errorx(int eval, char *s, ...)
+{
+	va_list ap;
+
+	va_start(ap, s);
+	ccerror(s, ap);
+	va_end(ap);
+	dexit(eval);
+}
+
+char *
+Bprefix(char *s)
+{
+	char *suffix;
+	char *str;
+	int i;
+
+#ifdef WIN32
+
+	/*  put here to save sprinkling it ~everywhere  */
+	s =  win32pathsubst(s);
+
+	if (Bflag == NULL)
+		return s;
+	suffix = strrchr(s, '/');
+	if (suffix == NULL)
+		suffix = strrchr(s, '\\');
+
+#else
+
+	if (Bflag == NULL || s[0] != '/')
+		return s;
+	suffix = strrchr(s, '/');
+
+#endif
+
+	if (suffix == NULL)
+		suffix = s;
+
+	str = copy(Bflag, i = strlen(suffix));
+	strlcat(str, suffix, strlen(Bflag) + i + 1);
+	return str;
+}
+
+int
+getsuf(char *s)
+{
+	register char *p;
+
+	if ((p = strrchr(s, '.')) && p[1] != '\0' && p[2] == '\0')
+		return p[1];
+	return(0);
+}
+
+/*
+ * Get basename of string s and change its suffix to ch.
+ */
+char *
+setsuf(char *s, char ch)
+{
+	char *p;
+
+	s = copy(basename(s), 2);
+	if ((p = strrchr(s, '.')) == NULL) {
+		p = s + strlen(s);
+		p[0] = '.';
+	}
+	p[1] = ch;
+	p[2] = '\0';
+	return(s);
+}
+
+#ifdef WIN32
+#define MAX_CMDLINE_LENGTH 32768
+int
+callsys(char *f, char *v[])
+{
+	char *cmd;
+	STARTUPINFO si;
+	PROCESS_INFORMATION pi;
+	DWORD exitCode;
+	BOOL ok;
+
+	cmd = win32commandline(f, v);
+	if (vflag)
+		printf("%s\n", cmd);
+
+	ZeroMemory(&si, sizeof(STARTUPINFO));
+	si.cb = sizeof(STARTUPINFO);
+	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
+
+	ok = CreateProcess(NULL,  // the executable program
+		cmd,   // the command line arguments
+		NULL,       // ignored
+		NULL,       // ignored
+		TRUE,       // inherit handles
+		HIGH_PRIORITY_CLASS,
+		NULL,       // ignored
+		NULL,       // ignored
+		&si,
+		&pi);
+
+	if (!ok) {
+		fprintf(stderr, "Can't find %s\n", f);
+		return 100;
+	}
+
+	WaitForSingleObject(pi.hProcess, INFINITE);
+	GetExitCodeProcess(pi.hProcess, &exitCode);
+	CloseHandle(pi.hProcess);
+	CloseHandle(pi.hThread);
+
+	return (exitCode != 0);
+}
+
+#elif defined(__helenos__)
+
+#include <task.h>
+
+int callsys(char *f, char *v[])
+{
+	size_t len;
+	char *path = NULL;
+	const char *s;
+	int t;
+	task_exit_t texit;
+	int retval;
+	
+	task_id_t tid;
+	
+	if (vflag) {
+		fprintf(stderr, "%s ", f);
+		for (t = 1; v[t]; t++)
+			fprintf(stderr, "%s ", v[t]);
+		fprintf(stderr, "\n");
+	}
+	
+	if (Bflag) {
+		len = strlen (Bflag) + 8;
+		path = malloc (len);
+		if (path == NULL) {
+			error("callsys: malloc failed");
+			exit(1);
+		}
+		if ((s = strrchr(f, '/'))) {
+			strlcpy(path, Bflag, len);
+			strlcat(path, s, len);
+			if (task_spawnv(&tid, path, v) == 0)
+				goto _wait;
+		}
+	}
+	
+	if (task_spawnv(&tid, f, v) == 0)
+		goto _wait;
+	
+	if ((s = strrchr(f, '/')) && task_spawnv (&tid, s + 1, v) == 0) 
+		goto _wait;
+	
+	errorx(8, "Can't find %s\n", f);
+	return 0;
+	
+_wait:
+	
+	
+	if (task_wait (tid, &texit, &retval) != 0) {
+		error("Couldn't wait on task");
+		return 0;
+	}
+	
+	return retval;
+}
+
+#else
+
+int
+callsys(char *f, char *v[])
+{
+	int t, status = 0;
+	pid_t p;
+	char *s;
+	char * volatile a = NULL;
+	volatile size_t len;
+
+	if (vflag) {
+		fprintf(stderr, "%s ", f);
+		for (t = 1; v[t]; t++)
+			fprintf(stderr, "%s ", v[t]);
+		fprintf(stderr, "\n");
+	}
+
+	if (Bflag) {
+		len = strlen(Bflag) + 8;
+		a = malloc(len);
+	}
+#ifdef HAVE_VFORK
+	if ((p = vfork()) == 0) {
+#else
+	if ((p = fork()) == 0) {
+#endif
+		if (Bflag) {
+			if (a == NULL) {
+				error("callsys: malloc failed");
+				exit(1);
+			}
+			if ((s = strrchr(f, '/'))) {
+				strlcpy(a, Bflag, len);
+				strlcat(a, s, len);
+				execv(a, v);
+			}
+		}
+		execvp(f, v);
+		if ((s = strrchr(f, '/')))
+			execvp(s+1, v);
+		fprintf(stderr, "Can't find %s\n", f);
+		_exit(100);
+	}
+	if (p == -1) {
+		fprintf(stderr, "fork() failed, try again\n");
+		return(100);
+	}
+	if (Bflag) {
+		free(a);
+	}
+	while (waitpid(p, &status, 0) == -1 && errno == EINTR)
+		;
+	if (WIFEXITED(status))
+		return (WEXITSTATUS(status));
+	if (WIFSIGNALED(status))
+		dexit(eflag ? eflag : 1);
+	errorx(8, "Fatal error in %s", f);
+
+	return 0;
+}
+#endif
+
+/*
+ * Make a copy of string as, mallocing extra bytes in the string.
+ */
+char *
+copy(char *s, int extra)
+{
+	int len = strlen(s)+1;
+	char *rv;
+
+	rv = ccmalloc(len+extra);
+	strlcpy(rv, s, len);
+	return rv;
+}
+
+int
+cunlink(char *f)
+{
+	if (f==0 || Xflag)
+		return(0);
+	return (unlink(f));
+}
+
+#ifdef WIN32
+char *
+gettmp(void)
+{
+#define BUFFSIZE 1000
+	DWORD pathSize;
+	char pathBuffer[BUFFSIZE];
+	char tempFilename[MAX_PATH];
+	UINT uniqueNum;
+
+	pathSize = GetTempPath(BUFFSIZE, pathBuffer);
+	if (pathSize < BUFFSIZE)
+		pathBuffer[pathSize] = 0;
+	else
+		pathBuffer[0] = 0;
+	uniqueNum = GetTempFileName(pathBuffer, "ctm", 0, tempFilename);
+	if (uniqueNum == 0) {
+		fprintf(stderr, "%s:\n", pathBuffer);
+		exit(8);
+	}
+	return copy(tempFilename, 0);
+}
+
+#else
+
+char *
+gettmp(void)
+{
+	char *sfn = copy("/tmp/ctm.XXXXXX", 0);
+	int fd = -1;
+
+	if ((fd = mkstemp(sfn)) == -1) {
+		fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
+		exit(8);
+	}
+	close(fd);
+	return sfn;
+}
+#endif
+
+void *
+ccmalloc(int size)
+{
+	void *rv;
+
+	if ((rv = malloc(size)) == NULL)
+		error("malloc failed");
+	return rv;
+}
+
+#ifdef WIN32
+
+char *
+win32pathsubst(char *s)
+{
+	char env[1024];
+	char *rv;
+	int len;
+
+	len = ExpandEnvironmentStrings(s, env, sizeof(env));
+	if (len <= 0)
+		return s;
+
+	while (env[len-1] == '/' || env[len-1] == '\\' || env[len-1] == '\0')
+		env[--len] = 0;
+
+	rv = ccmalloc(len+1);
+	strlcpy(rv, env, len+1);
+
+	return rv;
+}
+
+char *
+win32commandline(char *f, char *args[])
+{
+	char *cmd;
+	char *p;
+	int len;
+	int i, j, k;
+
+	len = strlen(f) + 3;
+
+	for (i = 1; args[i] != NULL; i++) {
+		for (j = 0; args[i][j] != '\0'; j++) {
+			len++;
+			if (args[i][j] == '\"') {
+				for (k = j-1; k >= 0 && args[i][k] == '\\'; k--)
+					len++;
+			}
+		}
+		for (k = j-1; k >= 0 && args[i][k] == '\\'; k--)
+			len++;
+		len += j + 3;
+	}
+
+	p = cmd = ccmalloc(len);
+	*p++ = '\"';
+	p += strlcpy(p, f, len-1);
+	*p++ = '\"';
+	*p++ = ' ';
+
+	for (i = 1; args[i] != NULL; i++) {
+		*p++ = '\"';
+		for (j = 0; args[i][j] != '\0'; j++) {
+			if (args[i][j] == '\"') {
+				for (k = j-1; k >= 0 && args[i][k] == '\\'; k--)
+					*p++ = '\\';
+				*p++ = '\\';
+			}
+			*p++ = args[i][j];
+		}
+		for (k = j-1; k >= 0 && args[i][k] == '\\'; k--)
+			*p++ = '\\';
+		*p++ = '\"';
+		*p++ = ' ';
+	}
+	p[-1] = '\0';
+
+	return cmd;
+}
+
+#endif
Index: uspace/app/pcc/cc/ccom/Makefile
===================================================================
--- uspace/app/pcc/cc/ccom/Makefile	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/Makefile	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,94 @@
+#
+# Copyright (c) 2011 Jiri Zarevucky
+# 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 must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - 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.
+#
+
+USPACE_PREFIX = ../../../..
+MIPDIR = ../../mip
+MDIR = ../../arch/$(PLATFORM)
+OSDIR = ../../os/helenos
+EXTRA_CFLAGS = -I$(MIPDIR) -I$(MDIR) -I$(OSDIR) -I. -w
+DEFS = -Dmach_$(PLATFORM) -D__helenos__ -DPCC_DEBUG -DGCC_COMPAT -Dfree=free
+BINARY = ccom
+
+PRE_DEPEND = cgram.c scan.c external.c external.h common.c compat.c
+EXTRA_CLEAN = cgram.c cgram.h scan.c external.c external.h common.c compat.c \
+	$(MIPDIR)/*.o $(MDIR)/*.o
+
+POSIX_COMPAT = y
+
+# FIXME: external.{c,h} must be generated for each target system
+
+SOURCES = \
+	external.c \
+	$(MDIR)/local.c \
+	$(MDIR)/local2.c \
+	$(MDIR)/code.c \
+	$(MDIR)/order.c \
+	$(MDIR)/table.c \
+	$(MIPDIR)/match.c \
+	$(MIPDIR)/reader.c \
+	$(MIPDIR)/optim2.c \
+	$(MIPDIR)/regs.c \
+	common.c \
+	compat.c \
+	cgram.c \
+	scan.c \
+	builtins.c \
+	gcc_compat.c \
+	init.c \
+	inline.c \
+	main.c \
+	optim.c \
+	pftn.c \
+	softfloat.c \
+	stabs.c \
+	symtabs.c \
+	trees.c
+
+include $(USPACE_PREFIX)/Makefile.common
+
+cgram.c: cgram.y
+	$(YACC) $(YFLAGS) -d $<
+	mv y.tab.c cgram.c
+	mv y.tab.h cgram.h
+
+scan.c: scan.l cgram.c
+	$(LEX) $(LFLAGS) $<
+	mv lex.yy.c scan.c
+
+compat.c: $(MIPDIR)/compat.c
+	ln -s -f $^ $@
+
+common.c: $(MIPDIR)/common.c
+	ln -s -f $^ $@
+
+external.c: arch/$(PLATFORM)/external.c
+	ln -s -f $^ $@
+
+external.h: arch/$(PLATFORM)/external.h
+	ln -s -f $^ $@
+
Index: uspace/app/pcc/cc/ccom/Makefile.in
===================================================================
--- uspace/app/pcc/cc/ccom/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,139 @@
+#	$Id: Makefile.in,v 1.32 2010/04/11 15:01:04 ragge Exp $
+#
+# Makefile.in for ccom
+#
+VPATH=@srcdir@
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+builddir=@builddir@
+top_builddir=@top_builddir@
+XFL=-DPCC_DEBUG
+CC = @CC@
+EXEEXT = @EXEEXT@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+_CFLAGS = @CFLAGS@
+CFLAGS = $(_CFLAGS) @ADD_CFLAGS@
+CPPFLAGS = @ADD_CPPFLAGS@ ${XFL} -Dos_${TARGOS} -Dmach_${TARGMACH} \
+	-D_ISOC99_SOURCE \
+	-I${srcdir} -I${builddir} -I${top_builddir} -I${MIPDIR} -I${MDIR} \
+	-I${top_srcdir}/os/${TARGOS} 
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+YACC = @YACC@
+TARGOS = @targos@
+TARGMACH = @targmach@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
+mandir = @mandir@
+strip = @strip@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+
+MDIR=$(top_srcdir)/arch/$(TARGMACH)
+MIPDIR=$(top_srcdir)/mip
+
+OBJS1=optim.o pftn.o scan.o trees.o cgram.o inline.o symtabs.o \
+	gcc_compat.o init.o local.o code.o stabs.o builtins.o
+
+OBJS2=match.o reader.o optim2.o regs.o local2.o order.o table.o
+
+OBJS=$(OBJS1) $(OBJS2) compat.o common.o main.o external.o
+
+DEST=@BINPREFIX@ccom$(EXEEXT)
+
+all: ${DEST}
+
+${DEST}: $(OBJS)
+	$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@
+
+.c.o:
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
+
+local.o: $(MDIR)/local.c external.h
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MDIR)/local.c
+
+local2.o: $(MDIR)/local2.c external.h
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MDIR)/local2.c
+
+code.o: $(MDIR)/code.c external.h
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MDIR)/code.c
+
+order.o: $(MDIR)/order.c external.h
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MDIR)/order.c
+
+table.o: $(MDIR)/table.c external.h
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MDIR)/table.c
+
+match.o: $(MIPDIR)/match.c external.h
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/match.c
+
+reader.o: $(MIPDIR)/reader.c external.h
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/reader.c
+
+optim2.o: $(MIPDIR)/optim2.c external.h
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/optim2.c
+
+regs.o: $(MIPDIR)/regs.c external.h
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/regs.c
+
+cgram.o: cgram.c external.h
+	$(CC) $(DEFS) $(CPPFLAGS) $(_CFLAGS) -c -o $@ cgram.c
+
+scan.o: scan.c external.h
+	$(CC) $(DEFS) $(CPPFLAGS) $(_CFLAGS) -c -o $@ scan.c
+
+common.o: $(MIPDIR)/common.c external.h
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/common.c
+
+compat.o: $(MIPDIR)/compat.c external.h
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/compat.c
+
+external.h external.c: ${MIPDIR}/mkext.c $(MDIR)/table.c
+	$(CC_FOR_BUILD) $(DEFS) $(CPPFLAGS) $(CFLAGS) -DMKEXT -o mkext \
+	${MIPDIR}/mkext.c $(MDIR)/table.c ${MIPDIR}/common.c
+	./mkext
+
+trees.c: ../../mip/pass2.h external.h
+
+inline.c: external.h
+init.c: external.h
+pftn.c: external.h
+gcc_compat.c: external.h
+symtabs.c: external.h
+stabs.c: external.h
+main.c: external.h
+
+pass1.h: external.h
+pass2.h: external.h
+
+cgram.c: cgram.y
+	$(YACC) $(YFLAGS) -d $<
+	mv y.tab.c cgram.c
+	mv y.tab.h cgram.h
+
+scan.c: scan.l cgram.c
+	$(LEX) $(LFLAGS) $<
+	mv lex.yy.c scan.c
+
+optim2.o reader.o optim.o : external.h
+
+pftn.o: cgram.c # creates cgram.h also
+
+install:
+	test -z "${DESTDIR}$(libexecdir)" || mkdir -p "${DESTDIR}$(libexecdir)"
+	${INSTALL_PROGRAM} ${DEST} ${DESTDIR}${libexecdir}
+	@if [ ${strip} = yes ]; then			\
+		strip ${DESTDIR}${libexecdir}/${DEST} ;		\
+		echo strip ${DESTDIR}${libexecdir}/${DEST} ;	\
+	fi
+	test -z "${DESTDIR}$(mandir)/man1" || mkdir -p "${DESTDIR}$(mandir)/man1"       
+	${INSTALL} $(srcdir)/ccom.1 ${DESTDIR}${mandir}/man1/$(DEST).1
+
+clean:
+	/bin/rm -f $(OBJS) $(DEST) scan.c cgram.[ch] mkext external.[ch]
+
+distclean: clean
+	/bin/rm -f Makefile
Index: uspace/app/pcc/cc/ccom/arch/abs32le/external.c
===================================================================
--- uspace/app/pcc/cc/ccom/arch/abs32le/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/abs32le/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,246 @@
+#include "pass2.h"
+
+// TODO: replace with file generated by ccom_mkext
+
+static int op0[] = { -1 };
+static int op1[] = { -1 };
+static int op2[] = { -1 };
+static int op3[] = { -1 };
+static int op4[] = { -1 };
+static int op5[] = { -1 };
+static int op6[] = { -1 };
+static int op7[] = { -1 };
+static int op8[] = { -1 };
+static int op9[] = { -1 };
+static int op10[] = { -1 };
+static int op11[] = { -1 };
+static int op12[] = { -1 };
+static int op13[] = { -1 };
+static int op14[] = { -1 };
+static int op15[] = { -1 };
+static int op16[] = { -1 };
+static int op17[] = { -1 };
+static int op18[] = { -1 };
+static int op19[] = { -1 };
+static int op20[] = { -1 };
+static int op21[] = { -1 };
+static int op22[] = { -1 };
+static int op23[] = { -1 };
+static int op24[] = { -1 };
+static int op25[] = { -1 };
+static int op26[] = { -1 };
+static int op27[] = { -1 };
+static int op28[] = { -1 };
+static int op29[] = { -1 };
+static int op30[] = { -1 };
+static int op31[] = { -1 };
+static int op32[] = { -1 };
+static int op33[] = { -1 };
+static int op34[] = { -1 };
+static int op35[] = { -1 };
+static int op36[] = { -1 };
+static int op37[] = { -1 };
+static int op38[] = { -1 };
+static int op39[] = { -1 };
+static int op40[] = { -1 };
+static int op41[] = { -1 };
+static int op42[] = { -1 };
+static int op43[] = { -1 };
+static int op44[] = { -1 };
+static int op45[] = { -1 };
+static int op46[] = { -1 };
+static int op47[] = { -1 };
+static int op48[] = { -1 };
+static int op49[] = { -1 };
+static int op50[] = { -1 };
+static int op51[] = { -1 };
+static int op52[] = { -1 };
+static int op53[] = { -1 };
+static int op54[] = { -1 };
+static int op55[] = { -1 };
+static int op56[] = { -1 };
+static int op57[] = { -1 };
+static int op58[] = { -1 };
+
+int *qtable[] = { 
+	op0,
+	op1,
+	op2,
+	op3,
+	op4,
+	op5,
+	op6,
+	op7,
+	op8,
+	op9,
+	op10,
+	op11,
+	op12,
+	op13,
+	op14,
+	op15,
+	op16,
+	op17,
+	op18,
+	op19,
+	op20,
+	op21,
+	op22,
+	op23,
+	op24,
+	op25,
+	op26,
+	op27,
+	op28,
+	op29,
+	op30,
+	op31,
+	op32,
+	op33,
+	op34,
+	op35,
+	op36,
+	op37,
+	op38,
+	op39,
+	op40,
+	op41,
+	op42,
+	op43,
+	op44,
+	op45,
+	op46,
+	op47,
+	op48,
+	op49,
+	op50,
+	op51,
+	op52,
+	op53,
+	op54,
+	op55,
+	op56,
+	op57,
+	op58,
+};
+int tempregs[] = { -1 };
+int permregs[] = { -1 };
+bittype validregs[] = {
+	0x7fffffffff,
+};
+static int amap[MAXREGS][NUMCLASS] = {
+	/* 0 */{ 0x0,0x0,0x0,0x0 },
+	/* 1 */{ 0x0,0x0,0x0,0x0 },
+	/* 2 */{ 0x0,0x0,0x0,0x0 },
+	/* 3 */{ 0x0,0x0,0x0,0x0 },
+	/* 4 */{ 0x0,0x0,0x0,0x0 },
+	/* 5 */{ 0x0,0x0,0x0,0x0 },
+	/* 6 */{ 0x0,0x0,0x0,0x0 },
+	/* 7 */{ 0x0,0x0,0x0,0x0 },
+	/* 8 */{ 0x0,0x0,0x0,0x0 },
+	/* 9 */{ 0x0,0x0,0x0,0x0 },
+	/* 10 */{ 0x0,0x0,0x0,0x0 },
+	/* 11 */{ 0x0,0x0,0x0,0x0 },
+	/* 12 */{ 0x0,0x0,0x0,0x0 },
+	/* 13 */{ 0x0,0x0,0x0,0x0 },
+	/* 14 */{ 0x0,0x0,0x0,0x0 },
+	/* 15 */{ 0x0,0x0,0x0,0x0 },
+	/* 16 */{ 0x0,0x0,0x0,0x0 },
+	/* 17 */{ 0x0,0x0,0x0,0x0 },
+	/* 18 */{ 0x0,0x0,0x0,0x0 },
+	/* 19 */{ 0x0,0x0,0x0,0x0 },
+	/* 20 */{ 0x0,0x0,0x0,0x0 },
+	/* 21 */{ 0x0,0x0,0x0,0x0 },
+	/* 22 */{ 0x0,0x0,0x0,0x0 },
+	/* 23 */{ 0x0,0x0,0x0,0x0 },
+	/* 24 */{ 0x0,0x0,0x0,0x0 },
+	/* 25 */{ 0x0,0x0,0x0,0x0 },
+	/* 26 */{ 0x0,0x0,0x0,0x0 },
+	/* 27 */{ 0x0,0x0,0x0,0x0 },
+	/* 28 */{ 0x0,0x0,0x0,0x0 },
+	/* 29 */{ 0x0,0x0,0x0,0x0 },
+	/* 30 */{ 0x0,0x0,0x0,0x0 },
+	/* 31 */{ 0x0,0x0,0x0,0x0 },
+	/* 32 */{ 0x0,0x0,0x0,0x0 },
+	/* 33 */{ 0x0,0x0,0x0,0x0 },
+	/* 34 */{ 0x0,0x0,0x0,0x0 },
+	/* 35 */{ 0x0,0x0,0x0,0x0 },
+	/* 36 */{ 0x0,0x0,0x0,0x0 },
+	/* 37 */{ 0x0,0x0,0x0,0x0 },
+	/* 38 */{ 0x0,0x0,0x0,0x0 }
+};
+int
+aliasmap(int class, int regnum)
+{
+	return amap[regnum][class-1];
+}
+static int rmap[NUMCLASS][15] = {
+	{ 0, 1, 2, 3, 4, 5, },
+	{ 8, 9, 10, 11, 12, 13, 14, 15, },
+	{ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, },
+	{ 31, 32, 33, 34, 35, 36, 37, 38, },
+};
+
+int
+color2reg(int color, int class)
+{
+	return rmap[class-1][color];
+}
+int regK[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+int
+classmask(int class)
+{
+	if(class == CLASSA) return 0x0;
+	if(class == CLASSB) return 0x0;
+	if(class == CLASSC) return 0x0;
+	if(class == CLASSD) return 0x0;
+	if(class == CLASSE) return 0x0;
+	if(class == CLASSF) return 0x0;
+	return 0x0;
+}
+static bittype ovlarr[MAXREGS][1] = {
+{ 0x1f0301,  },
+{ 0x1e10c02,  },
+{ 0xe223004,  },
+{ 0x3244c008,  },
+{ 0x54880010,  },
+{ 0x69100020,  },
+{ 0x40,  },
+{ 0x80,  },
+{ 0x1f0101,  },
+{ 0x1f0201,  },
+{ 0x1e10402,  },
+{ 0x1e10802,  },
+{ 0xe221004,  },
+{ 0xe222004,  },
+{ 0x32444008,  },
+{ 0x32448008,  },
+{ 0x1ff0f03,  },
+{ 0xe3f3305,  },
+{ 0x325fc309,  },
+{ 0x549f0311,  },
+{ 0x691f0321,  },
+{ 0xfe33c06,  },
+{ 0x33e5cc0a,  },
+{ 0x55e90c12,  },
+{ 0x69f10c22,  },
+{ 0x3e66f00c,  },
+{ 0x5eaa3014,  },
+{ 0x6f323024,  },
+{ 0x76ccc018,  },
+{ 0x7b54c028,  },
+{ 0x7d980030,  },
+{ 0x80000000,  },
+{ 0x1,  },
+{ 0x2,  },
+{ 0x4,  },
+{ 0x8,  },
+{ 0x10,  },
+{ 0x20,  },
+{ 0x40,  },
+};
+int
+interferes(int reg1, int reg2)
+{
+return (TESTBIT(ovlarr[reg1], reg2)) != 0;
+}
Index: uspace/app/pcc/cc/ccom/arch/abs32le/external.h
===================================================================
--- uspace/app/pcc/cc/ccom/arch/abs32le/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/abs32le/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,27 @@
+// TODO: replace with file generated by ccom_mkext
+
+#ifndef _EXTERNAL_H_
+#define _EXTERNAL_H_
+#define MAXOPLEN 0
+#define NUMBITS 32
+#define BIT2BYTE(bits) ((((bits)+NUMBITS-1)/NUMBITS)*(NUMBITS/8))
+#define BITSET(arr, bit) (arr[bit/NUMBITS] |= ((int)1 << (bit & (NUMBITS-1))))
+#define BITCLEAR(arr, bit) (arr[bit/NUMBITS] &= ~((int)1 << (bit & (NUMBITS-1))))
+#define TESTBIT(arr, bit) (arr[bit/NUMBITS] & ((int)1 << (bit & (NUMBITS-1))))
+typedef int bittype;
+extern int tempregs[], permregs[];
+#define NTEMPREG 0
+#define FREGS 0
+#define NPERMREG 0
+extern bittype validregs[];
+#define AREGCNT 0
+#define BREGCNT 0
+#define CREGCNT 0
+#define DREGCNT 0
+#define EREGCNT 0
+#define FREGCNT 0
+#define GREGCNT 0
+int aliasmap(int class, int regnum);
+int color2reg(int color, int class);
+int interferes(int reg1, int reg2);
+#endif /* _EXTERNAL_H_ */
Index: uspace/app/pcc/cc/ccom/arch/amd64/external.c
===================================================================
--- uspace/app/pcc/cc/ccom/arch/amd64/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/amd64/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,246 @@
+#include "pass2.h"
+
+// TODO: replace with file generated by ccom_mkext
+
+static int op0[] = { -1 };
+static int op1[] = { -1 };
+static int op2[] = { -1 };
+static int op3[] = { -1 };
+static int op4[] = { -1 };
+static int op5[] = { -1 };
+static int op6[] = { -1 };
+static int op7[] = { -1 };
+static int op8[] = { -1 };
+static int op9[] = { -1 };
+static int op10[] = { -1 };
+static int op11[] = { -1 };
+static int op12[] = { -1 };
+static int op13[] = { -1 };
+static int op14[] = { -1 };
+static int op15[] = { -1 };
+static int op16[] = { -1 };
+static int op17[] = { -1 };
+static int op18[] = { -1 };
+static int op19[] = { -1 };
+static int op20[] = { -1 };
+static int op21[] = { -1 };
+static int op22[] = { -1 };
+static int op23[] = { -1 };
+static int op24[] = { -1 };
+static int op25[] = { -1 };
+static int op26[] = { -1 };
+static int op27[] = { -1 };
+static int op28[] = { -1 };
+static int op29[] = { -1 };
+static int op30[] = { -1 };
+static int op31[] = { -1 };
+static int op32[] = { -1 };
+static int op33[] = { -1 };
+static int op34[] = { -1 };
+static int op35[] = { -1 };
+static int op36[] = { -1 };
+static int op37[] = { -1 };
+static int op38[] = { -1 };
+static int op39[] = { -1 };
+static int op40[] = { -1 };
+static int op41[] = { -1 };
+static int op42[] = { -1 };
+static int op43[] = { -1 };
+static int op44[] = { -1 };
+static int op45[] = { -1 };
+static int op46[] = { -1 };
+static int op47[] = { -1 };
+static int op48[] = { -1 };
+static int op49[] = { -1 };
+static int op50[] = { -1 };
+static int op51[] = { -1 };
+static int op52[] = { -1 };
+static int op53[] = { -1 };
+static int op54[] = { -1 };
+static int op55[] = { -1 };
+static int op56[] = { -1 };
+static int op57[] = { -1 };
+static int op58[] = { -1 };
+
+int *qtable[] = { 
+	op0,
+	op1,
+	op2,
+	op3,
+	op4,
+	op5,
+	op6,
+	op7,
+	op8,
+	op9,
+	op10,
+	op11,
+	op12,
+	op13,
+	op14,
+	op15,
+	op16,
+	op17,
+	op18,
+	op19,
+	op20,
+	op21,
+	op22,
+	op23,
+	op24,
+	op25,
+	op26,
+	op27,
+	op28,
+	op29,
+	op30,
+	op31,
+	op32,
+	op33,
+	op34,
+	op35,
+	op36,
+	op37,
+	op38,
+	op39,
+	op40,
+	op41,
+	op42,
+	op43,
+	op44,
+	op45,
+	op46,
+	op47,
+	op48,
+	op49,
+	op50,
+	op51,
+	op52,
+	op53,
+	op54,
+	op55,
+	op56,
+	op57,
+	op58,
+};
+int tempregs[] = { -1 };
+int permregs[] = { -1 };
+bittype validregs[] = {
+	0x7fffffffff,
+};
+static int amap[MAXREGS][NUMCLASS] = {
+	/* 0 */{ 0x0,0x0,0x0,0x0 },
+	/* 1 */{ 0x0,0x0,0x0,0x0 },
+	/* 2 */{ 0x0,0x0,0x0,0x0 },
+	/* 3 */{ 0x0,0x0,0x0,0x0 },
+	/* 4 */{ 0x0,0x0,0x0,0x0 },
+	/* 5 */{ 0x0,0x0,0x0,0x0 },
+	/* 6 */{ 0x0,0x0,0x0,0x0 },
+	/* 7 */{ 0x0,0x0,0x0,0x0 },
+	/* 8 */{ 0x0,0x0,0x0,0x0 },
+	/* 9 */{ 0x0,0x0,0x0,0x0 },
+	/* 10 */{ 0x0,0x0,0x0,0x0 },
+	/* 11 */{ 0x0,0x0,0x0,0x0 },
+	/* 12 */{ 0x0,0x0,0x0,0x0 },
+	/* 13 */{ 0x0,0x0,0x0,0x0 },
+	/* 14 */{ 0x0,0x0,0x0,0x0 },
+	/* 15 */{ 0x0,0x0,0x0,0x0 },
+	/* 16 */{ 0x0,0x0,0x0,0x0 },
+	/* 17 */{ 0x0,0x0,0x0,0x0 },
+	/* 18 */{ 0x0,0x0,0x0,0x0 },
+	/* 19 */{ 0x0,0x0,0x0,0x0 },
+	/* 20 */{ 0x0,0x0,0x0,0x0 },
+	/* 21 */{ 0x0,0x0,0x0,0x0 },
+	/* 22 */{ 0x0,0x0,0x0,0x0 },
+	/* 23 */{ 0x0,0x0,0x0,0x0 },
+	/* 24 */{ 0x0,0x0,0x0,0x0 },
+	/* 25 */{ 0x0,0x0,0x0,0x0 },
+	/* 26 */{ 0x0,0x0,0x0,0x0 },
+	/* 27 */{ 0x0,0x0,0x0,0x0 },
+	/* 28 */{ 0x0,0x0,0x0,0x0 },
+	/* 29 */{ 0x0,0x0,0x0,0x0 },
+	/* 30 */{ 0x0,0x0,0x0,0x0 },
+	/* 31 */{ 0x0,0x0,0x0,0x0 },
+	/* 32 */{ 0x0,0x0,0x0,0x0 },
+	/* 33 */{ 0x0,0x0,0x0,0x0 },
+	/* 34 */{ 0x0,0x0,0x0,0x0 },
+	/* 35 */{ 0x0,0x0,0x0,0x0 },
+	/* 36 */{ 0x0,0x0,0x0,0x0 },
+	/* 37 */{ 0x0,0x0,0x0,0x0 },
+	/* 38 */{ 0x0,0x0,0x0,0x0 }
+};
+int
+aliasmap(int class, int regnum)
+{
+	return amap[regnum][class-1];
+}
+static int rmap[NUMCLASS][15] = {
+	{ 0, 1, 2, 3, 4, 5, },
+	{ 8, 9, 10, 11, 12, 13, 14, 15, },
+	{ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, },
+	{ 31, 32, 33, 34, 35, 36, 37, 38, },
+};
+
+int
+color2reg(int color, int class)
+{
+	return rmap[class-1][color];
+}
+int regK[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+int
+classmask(int class)
+{
+	if(class == CLASSA) return 0x0;
+	if(class == CLASSB) return 0x0;
+	if(class == CLASSC) return 0x0;
+	if(class == CLASSD) return 0x0;
+	if(class == CLASSE) return 0x0;
+	if(class == CLASSF) return 0x0;
+	return 0x0;
+}
+static bittype ovlarr[MAXREGS][1] = {
+{ 0x1f0301,  },
+{ 0x1e10c02,  },
+{ 0xe223004,  },
+{ 0x3244c008,  },
+{ 0x54880010,  },
+{ 0x69100020,  },
+{ 0x40,  },
+{ 0x80,  },
+{ 0x1f0101,  },
+{ 0x1f0201,  },
+{ 0x1e10402,  },
+{ 0x1e10802,  },
+{ 0xe221004,  },
+{ 0xe222004,  },
+{ 0x32444008,  },
+{ 0x32448008,  },
+{ 0x1ff0f03,  },
+{ 0xe3f3305,  },
+{ 0x325fc309,  },
+{ 0x549f0311,  },
+{ 0x691f0321,  },
+{ 0xfe33c06,  },
+{ 0x33e5cc0a,  },
+{ 0x55e90c12,  },
+{ 0x69f10c22,  },
+{ 0x3e66f00c,  },
+{ 0x5eaa3014,  },
+{ 0x6f323024,  },
+{ 0x76ccc018,  },
+{ 0x7b54c028,  },
+{ 0x7d980030,  },
+{ 0x80000000,  },
+{ 0x1,  },
+{ 0x2,  },
+{ 0x4,  },
+{ 0x8,  },
+{ 0x10,  },
+{ 0x20,  },
+{ 0x40,  },
+};
+int
+interferes(int reg1, int reg2)
+{
+return (TESTBIT(ovlarr[reg1], reg2)) != 0;
+}
Index: uspace/app/pcc/cc/ccom/arch/amd64/external.h
===================================================================
--- uspace/app/pcc/cc/ccom/arch/amd64/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/amd64/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,27 @@
+// TODO: replace with file generated by ccom_mkext
+
+#ifndef _EXTERNAL_H_
+#define _EXTERNAL_H_
+#define MAXOPLEN 0
+#define NUMBITS 32
+#define BIT2BYTE(bits) ((((bits)+NUMBITS-1)/NUMBITS)*(NUMBITS/8))
+#define BITSET(arr, bit) (arr[bit/NUMBITS] |= ((int)1 << (bit & (NUMBITS-1))))
+#define BITCLEAR(arr, bit) (arr[bit/NUMBITS] &= ~((int)1 << (bit & (NUMBITS-1))))
+#define TESTBIT(arr, bit) (arr[bit/NUMBITS] & ((int)1 << (bit & (NUMBITS-1))))
+typedef int bittype;
+extern int tempregs[], permregs[];
+#define NTEMPREG 0
+#define FREGS 0
+#define NPERMREG 0
+extern bittype validregs[];
+#define AREGCNT 0
+#define BREGCNT 0
+#define CREGCNT 0
+#define DREGCNT 0
+#define EREGCNT 0
+#define FREGCNT 0
+#define GREGCNT 0
+int aliasmap(int class, int regnum);
+int color2reg(int color, int class);
+int interferes(int reg1, int reg2);
+#endif /* _EXTERNAL_H_ */
Index: uspace/app/pcc/cc/ccom/arch/arm32/external.c
===================================================================
--- uspace/app/pcc/cc/ccom/arch/arm32/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/arm32/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,246 @@
+#include "pass2.h"
+
+// TODO: replace with file generated by ccom_mkext
+
+static int op0[] = { -1 };
+static int op1[] = { -1 };
+static int op2[] = { -1 };
+static int op3[] = { -1 };
+static int op4[] = { -1 };
+static int op5[] = { -1 };
+static int op6[] = { -1 };
+static int op7[] = { -1 };
+static int op8[] = { -1 };
+static int op9[] = { -1 };
+static int op10[] = { -1 };
+static int op11[] = { -1 };
+static int op12[] = { -1 };
+static int op13[] = { -1 };
+static int op14[] = { -1 };
+static int op15[] = { -1 };
+static int op16[] = { -1 };
+static int op17[] = { -1 };
+static int op18[] = { -1 };
+static int op19[] = { -1 };
+static int op20[] = { -1 };
+static int op21[] = { -1 };
+static int op22[] = { -1 };
+static int op23[] = { -1 };
+static int op24[] = { -1 };
+static int op25[] = { -1 };
+static int op26[] = { -1 };
+static int op27[] = { -1 };
+static int op28[] = { -1 };
+static int op29[] = { -1 };
+static int op30[] = { -1 };
+static int op31[] = { -1 };
+static int op32[] = { -1 };
+static int op33[] = { -1 };
+static int op34[] = { -1 };
+static int op35[] = { -1 };
+static int op36[] = { -1 };
+static int op37[] = { -1 };
+static int op38[] = { -1 };
+static int op39[] = { -1 };
+static int op40[] = { -1 };
+static int op41[] = { -1 };
+static int op42[] = { -1 };
+static int op43[] = { -1 };
+static int op44[] = { -1 };
+static int op45[] = { -1 };
+static int op46[] = { -1 };
+static int op47[] = { -1 };
+static int op48[] = { -1 };
+static int op49[] = { -1 };
+static int op50[] = { -1 };
+static int op51[] = { -1 };
+static int op52[] = { -1 };
+static int op53[] = { -1 };
+static int op54[] = { -1 };
+static int op55[] = { -1 };
+static int op56[] = { -1 };
+static int op57[] = { -1 };
+static int op58[] = { -1 };
+
+int *qtable[] = { 
+	op0,
+	op1,
+	op2,
+	op3,
+	op4,
+	op5,
+	op6,
+	op7,
+	op8,
+	op9,
+	op10,
+	op11,
+	op12,
+	op13,
+	op14,
+	op15,
+	op16,
+	op17,
+	op18,
+	op19,
+	op20,
+	op21,
+	op22,
+	op23,
+	op24,
+	op25,
+	op26,
+	op27,
+	op28,
+	op29,
+	op30,
+	op31,
+	op32,
+	op33,
+	op34,
+	op35,
+	op36,
+	op37,
+	op38,
+	op39,
+	op40,
+	op41,
+	op42,
+	op43,
+	op44,
+	op45,
+	op46,
+	op47,
+	op48,
+	op49,
+	op50,
+	op51,
+	op52,
+	op53,
+	op54,
+	op55,
+	op56,
+	op57,
+	op58,
+};
+int tempregs[] = { -1 };
+int permregs[] = { -1 };
+bittype validregs[] = {
+	0x7fffffffff,
+};
+static int amap[MAXREGS][NUMCLASS] = {
+	/* 0 */{ 0x0,0x0,0x0,0x0 },
+	/* 1 */{ 0x0,0x0,0x0,0x0 },
+	/* 2 */{ 0x0,0x0,0x0,0x0 },
+	/* 3 */{ 0x0,0x0,0x0,0x0 },
+	/* 4 */{ 0x0,0x0,0x0,0x0 },
+	/* 5 */{ 0x0,0x0,0x0,0x0 },
+	/* 6 */{ 0x0,0x0,0x0,0x0 },
+	/* 7 */{ 0x0,0x0,0x0,0x0 },
+	/* 8 */{ 0x0,0x0,0x0,0x0 },
+	/* 9 */{ 0x0,0x0,0x0,0x0 },
+	/* 10 */{ 0x0,0x0,0x0,0x0 },
+	/* 11 */{ 0x0,0x0,0x0,0x0 },
+	/* 12 */{ 0x0,0x0,0x0,0x0 },
+	/* 13 */{ 0x0,0x0,0x0,0x0 },
+	/* 14 */{ 0x0,0x0,0x0,0x0 },
+	/* 15 */{ 0x0,0x0,0x0,0x0 },
+	/* 16 */{ 0x0,0x0,0x0,0x0 },
+	/* 17 */{ 0x0,0x0,0x0,0x0 },
+	/* 18 */{ 0x0,0x0,0x0,0x0 },
+	/* 19 */{ 0x0,0x0,0x0,0x0 },
+	/* 20 */{ 0x0,0x0,0x0,0x0 },
+	/* 21 */{ 0x0,0x0,0x0,0x0 },
+	/* 22 */{ 0x0,0x0,0x0,0x0 },
+	/* 23 */{ 0x0,0x0,0x0,0x0 },
+	/* 24 */{ 0x0,0x0,0x0,0x0 },
+	/* 25 */{ 0x0,0x0,0x0,0x0 },
+	/* 26 */{ 0x0,0x0,0x0,0x0 },
+	/* 27 */{ 0x0,0x0,0x0,0x0 },
+	/* 28 */{ 0x0,0x0,0x0,0x0 },
+	/* 29 */{ 0x0,0x0,0x0,0x0 },
+	/* 30 */{ 0x0,0x0,0x0,0x0 },
+	/* 31 */{ 0x0,0x0,0x0,0x0 },
+	/* 32 */{ 0x0,0x0,0x0,0x0 },
+	/* 33 */{ 0x0,0x0,0x0,0x0 },
+	/* 34 */{ 0x0,0x0,0x0,0x0 },
+	/* 35 */{ 0x0,0x0,0x0,0x0 },
+	/* 36 */{ 0x0,0x0,0x0,0x0 },
+	/* 37 */{ 0x0,0x0,0x0,0x0 },
+	/* 38 */{ 0x0,0x0,0x0,0x0 }
+};
+int
+aliasmap(int class, int regnum)
+{
+	return amap[regnum][class-1];
+}
+static int rmap[NUMCLASS][15] = {
+	{ 0, 1, 2, 3, 4, 5, },
+	{ 8, 9, 10, 11, 12, 13, 14, 15, },
+	{ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, },
+	{ 31, 32, 33, 34, 35, 36, 37, 38, },
+};
+
+int
+color2reg(int color, int class)
+{
+	return rmap[class-1][color];
+}
+int regK[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+int
+classmask(int class)
+{
+	if(class == CLASSA) return 0x0;
+	if(class == CLASSB) return 0x0;
+	if(class == CLASSC) return 0x0;
+	if(class == CLASSD) return 0x0;
+	if(class == CLASSE) return 0x0;
+	if(class == CLASSF) return 0x0;
+	return 0x0;
+}
+static bittype ovlarr[MAXREGS][1] = {
+{ 0x1f0301,  },
+{ 0x1e10c02,  },
+{ 0xe223004,  },
+{ 0x3244c008,  },
+{ 0x54880010,  },
+{ 0x69100020,  },
+{ 0x40,  },
+{ 0x80,  },
+{ 0x1f0101,  },
+{ 0x1f0201,  },
+{ 0x1e10402,  },
+{ 0x1e10802,  },
+{ 0xe221004,  },
+{ 0xe222004,  },
+{ 0x32444008,  },
+{ 0x32448008,  },
+{ 0x1ff0f03,  },
+{ 0xe3f3305,  },
+{ 0x325fc309,  },
+{ 0x549f0311,  },
+{ 0x691f0321,  },
+{ 0xfe33c06,  },
+{ 0x33e5cc0a,  },
+{ 0x55e90c12,  },
+{ 0x69f10c22,  },
+{ 0x3e66f00c,  },
+{ 0x5eaa3014,  },
+{ 0x6f323024,  },
+{ 0x76ccc018,  },
+{ 0x7b54c028,  },
+{ 0x7d980030,  },
+{ 0x80000000,  },
+{ 0x1,  },
+{ 0x2,  },
+{ 0x4,  },
+{ 0x8,  },
+{ 0x10,  },
+{ 0x20,  },
+{ 0x40,  },
+};
+int
+interferes(int reg1, int reg2)
+{
+return (TESTBIT(ovlarr[reg1], reg2)) != 0;
+}
Index: uspace/app/pcc/cc/ccom/arch/arm32/external.h
===================================================================
--- uspace/app/pcc/cc/ccom/arch/arm32/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/arm32/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,27 @@
+// TODO: replace with file generated by ccom_mkext
+
+#ifndef _EXTERNAL_H_
+#define _EXTERNAL_H_
+#define MAXOPLEN 0
+#define NUMBITS 32
+#define BIT2BYTE(bits) ((((bits)+NUMBITS-1)/NUMBITS)*(NUMBITS/8))
+#define BITSET(arr, bit) (arr[bit/NUMBITS] |= ((int)1 << (bit & (NUMBITS-1))))
+#define BITCLEAR(arr, bit) (arr[bit/NUMBITS] &= ~((int)1 << (bit & (NUMBITS-1))))
+#define TESTBIT(arr, bit) (arr[bit/NUMBITS] & ((int)1 << (bit & (NUMBITS-1))))
+typedef int bittype;
+extern int tempregs[], permregs[];
+#define NTEMPREG 0
+#define FREGS 0
+#define NPERMREG 0
+extern bittype validregs[];
+#define AREGCNT 0
+#define BREGCNT 0
+#define CREGCNT 0
+#define DREGCNT 0
+#define EREGCNT 0
+#define FREGCNT 0
+#define GREGCNT 0
+int aliasmap(int class, int regnum);
+int color2reg(int color, int class);
+int interferes(int reg1, int reg2);
+#endif /* _EXTERNAL_H_ */
Index: uspace/app/pcc/cc/ccom/arch/ia32/external.c
===================================================================
--- uspace/app/pcc/cc/ccom/arch/ia32/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/ia32/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,244 @@
+#include "pass2.h"
+static int op0[] = { -1 };
+static int op1[] = { -1 };
+static int op2[] = { 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 231, 233, -1 };
+static int op3[] = { -1 };
+static int op4[] = { 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 231, 233, -1 };
+static int op5[] = { 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 231, 233, -1 };
+static int op6[] = { 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 231, 233, -1 };
+static int op7[] = { 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 231, 233, -1 };
+static int op8[] = { 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 231, 233, -1 };
+static int op9[] = { 232, 233, -1 };
+static int op10[] = { 68, 69, 70, 71, 72, 73, 74, 75, 76, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 233, -1 };
+static int op11[] = { 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 96, 233, -1 };
+static int op12[] = { 151, 152, 153, 154, 155, 156, 157, 233, -1 };
+static int op13[] = { 158, 159, 160, 161, 162, 233, -1 };
+static int op14[] = { 163, 164, 165, 166, 167, 168, 233, -1 };
+static int op15[] = { 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 183, 184, 185, 186, 187, 188, 189, 233, -1 };
+static int op16[] = { 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 233, -1 };
+static int op17[] = { 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 233, -1 };
+static int op18[] = { 97, 98, 99, 100, 101, 102, 103, 233, -1 };
+static int op19[] = { 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 233, -1 };
+static int op20[] = { 210, 211, 212, 213, 232, 233, -1 };
+static int op21[] = { -1 };
+static int op22[] = { -1 };
+static int op23[] = { 169, 170, 171, 172, 173, 174, 175, 227, 232, 233, -1 };
+static int op24[] = { 205, 206, 207, 208, 209, 232, 233, -1 };
+static int op25[] = { 176, 177, 178, 179, 180, 181, 182, 233, -1 };
+static int op26[] = { 176, 177, 178, 179, 180, 181, 182, 233, -1 };
+static int op27[] = { 176, 177, 178, 179, 180, 181, 182, 233, -1 };
+static int op28[] = { 176, 177, 178, 179, 180, 181, 182, 233, -1 };
+static int op29[] = { 176, 177, 178, 179, 180, 181, 182, 233, -1 };
+static int op30[] = { 176, 177, 178, 179, 180, 181, 182, 233, -1 };
+static int op31[] = { 176, 177, 178, 179, 180, 181, 182, 233, -1 };
+static int op32[] = { 176, 177, 178, 179, 180, 181, 182, 233, -1 };
+static int op33[] = { 176, 177, 178, 179, 180, 181, 182, 233, -1 };
+static int op34[] = { 176, 177, 178, 179, 180, 181, 182, 233, -1 };
+static int op35[] = { 233, -1 };
+static int op36[] = { 230, 232, 233, -1 };
+static int op37[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 232, 233, -1 };
+static int op38[] = { 1, 232, 233, -1 };
+static int op39[] = { 233, -1 };
+static int op40[] = { 233, -1 };
+static int op41[] = { 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 233, -1 };
+static int op42[] = { 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 232, 233, -1 };
+static int op43[] = { 233, -1 };
+static int op44[] = { 232, 233, -1 };
+static int op45[] = { 65, 66, 67, 233, -1 };
+static int op46[] = { 62, 63, 64, 232, 233, -1 };
+static int op47[] = { 231, 233, -1 };
+static int op48[] = { 233, -1 };
+static int op49[] = { 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 228, -1 };
+static int op50[] = { 150, 229, -1 };
+static int op51[] = { 226, 232, 233, -1 };
+static int op52[] = { 232, 233, -1 };
+static int op53[] = { 233, -1 };
+static int op54[] = { 190, 232, 233, -1 };
+static int op55[] = { -1 };
+static int op56[] = { 233, -1 };
+static int op57[] = { 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 232, 233, -1 };
+static int op58[] = { 232, 233, -1 };
+
+int *qtable[] = { 
+	op0,
+	op1,
+	op2,
+	op3,
+	op4,
+	op5,
+	op6,
+	op7,
+	op8,
+	op9,
+	op10,
+	op11,
+	op12,
+	op13,
+	op14,
+	op15,
+	op16,
+	op17,
+	op18,
+	op19,
+	op20,
+	op21,
+	op22,
+	op23,
+	op24,
+	op25,
+	op26,
+	op27,
+	op28,
+	op29,
+	op30,
+	op31,
+	op32,
+	op33,
+	op34,
+	op35,
+	op36,
+	op37,
+	op38,
+	op39,
+	op40,
+	op41,
+	op42,
+	op43,
+	op44,
+	op45,
+	op46,
+	op47,
+	op48,
+	op49,
+	op50,
+	op51,
+	op52,
+	op53,
+	op54,
+	op55,
+	op56,
+	op57,
+	op58,
+};
+int tempregs[] = { 0, 1, 2, -1 };
+int permregs[] = { 3, 4, 5, -1 };
+bittype validregs[] = {
+	0xffffff3f,
+	0x0000007f,
+};
+static int amap[MAXREGS][NUMCLASS] = {
+	/* 0 */{ 0x1,0x3,0x1f,0x0 },
+	/* 1 */{ 0x2,0xc,0x1e1,0x0 },
+	/* 2 */{ 0x4,0x30,0xe22,0x0 },
+	/* 3 */{ 0x8,0xc0,0x3244,0x0 },
+	/* 4 */{ 0x10,0x0,0x5488,0x0 },
+	/* 5 */{ 0x20,0x0,0x6910,0x0 },
+	/* 6 */{ 0x0,0x0,0x0,0x0 },
+	/* 7 */{ 0x0,0x0,0x0,0x0 },
+	/* 8 */{ 0x1,0x1,0x1f,0x0 },
+	/* 9 */{ 0x1,0x2,0x1f,0x0 },
+	/* 10 */{ 0x2,0x4,0x1e1,0x0 },
+	/* 11 */{ 0x2,0x8,0x1e1,0x0 },
+	/* 12 */{ 0x4,0x10,0xe22,0x0 },
+	/* 13 */{ 0x4,0x20,0xe22,0x0 },
+	/* 14 */{ 0x8,0x40,0x3244,0x0 },
+	/* 15 */{ 0x8,0x80,0x3244,0x0 },
+	/* 16 */{ 0x3,0xf,0x1ff,0x0 },
+	/* 17 */{ 0x5,0x33,0xe3f,0x0 },
+	/* 18 */{ 0x9,0xc3,0x325f,0x0 },
+	/* 19 */{ 0x11,0x3,0x549f,0x0 },
+	/* 20 */{ 0x21,0x3,0x691f,0x0 },
+	/* 21 */{ 0x6,0x3c,0xfe3,0x0 },
+	/* 22 */{ 0xa,0xcc,0x33e5,0x0 },
+	/* 23 */{ 0x12,0xc,0x55e9,0x0 },
+	/* 24 */{ 0x22,0xc,0x69f1,0x0 },
+	/* 25 */{ 0xc,0xf0,0x3e66,0x0 },
+	/* 26 */{ 0x14,0x30,0x5eaa,0x0 },
+	/* 27 */{ 0x24,0x30,0x6f32,0x0 },
+	/* 28 */{ 0x18,0xc0,0x76cc,0x0 },
+	/* 29 */{ 0x28,0xc0,0x7b54,0x0 },
+	/* 30 */{ 0x30,0x0,0x7d98,0x0 },
+	/* 31 */{ 0x0,0x0,0x0,0x1 },
+	/* 32 */{ 0x0,0x0,0x0,0x2 },
+	/* 33 */{ 0x0,0x0,0x0,0x4 },
+	/* 34 */{ 0x0,0x0,0x0,0x8 },
+	/* 35 */{ 0x0,0x0,0x0,0x10 },
+	/* 36 */{ 0x0,0x0,0x0,0x20 },
+	/* 37 */{ 0x0,0x0,0x0,0x40 },
+	/* 38 */{ 0x0,0x0,0x0,0x80 },
+};
+int
+aliasmap(int class, int regnum)
+{
+	return amap[regnum][class-1];
+}
+static int rmap[NUMCLASS][15] = {
+	{ 0, 1, 2, 3, 4, 5, },
+	{ 8, 9, 10, 11, 12, 13, 14, 15, },
+	{ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, },
+	{ 31, 32, 33, 34, 35, 36, 37, 38, },
+};
+
+int
+color2reg(int color, int class)
+{
+	return rmap[class-1][color];
+}
+int regK[] = { 0, 6, 8, 15, 8, 0, 0, 0 };
+int
+classmask(int class)
+{
+	if(class == CLASSA) return 0x3f;
+	if(class == CLASSB) return 0xff;
+	if(class == CLASSC) return 0x7fff;
+	if(class == CLASSD) return 0xff;
+	if(class == CLASSE) return 0x0;
+	if(class == CLASSF) return 0x0;
+	return 0x0;
+}
+static bittype ovlarr[MAXREGS][2] = {
+{ 0x1f0301, 0x0,  },
+{ 0x1e10c02, 0x0,  },
+{ 0xe223004, 0x0,  },
+{ 0x3244c008, 0x0,  },
+{ 0x54880010, 0x0,  },
+{ 0x69100020, 0x0,  },
+{ 0x40, 0x0,  },
+{ 0x80, 0x0,  },
+{ 0x1f0101, 0x0,  },
+{ 0x1f0201, 0x0,  },
+{ 0x1e10402, 0x0,  },
+{ 0x1e10802, 0x0,  },
+{ 0xe221004, 0x0,  },
+{ 0xe222004, 0x0,  },
+{ 0x32444008, 0x0,  },
+{ 0x32448008, 0x0,  },
+{ 0x1ff0f03, 0x0,  },
+{ 0xe3f3305, 0x0,  },
+{ 0x325fc309, 0x0,  },
+{ 0x549f0311, 0x0,  },
+{ 0x691f0321, 0x0,  },
+{ 0xfe33c06, 0x0,  },
+{ 0x33e5cc0a, 0x0,  },
+{ 0x55e90c12, 0x0,  },
+{ 0x69f10c22, 0x0,  },
+{ 0x3e66f00c, 0x0,  },
+{ 0x5eaa3014, 0x0,  },
+{ 0x6f323024, 0x0,  },
+{ 0x76ccc018, 0x0,  },
+{ 0x7b54c028, 0x0,  },
+{ 0x7d980030, 0x0,  },
+{ 0x80000000, 0x0,  },
+{ 0x0, 0x1,  },
+{ 0x0, 0x2,  },
+{ 0x0, 0x4,  },
+{ 0x0, 0x8,  },
+{ 0x0, 0x10,  },
+{ 0x0, 0x20,  },
+{ 0x0, 0x40,  },
+};
+int
+interferes(int reg1, int reg2)
+{
+return (TESTBIT(ovlarr[reg1], reg2)) != 0;
+}
Index: uspace/app/pcc/cc/ccom/arch/ia32/external.h
===================================================================
--- uspace/app/pcc/cc/ccom/arch/ia32/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/ia32/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,25 @@
+#ifndef _EXTERNAL_H_
+#define _EXTERNAL_H_
+#define MAXOPLEN 42
+#define NUMBITS 32
+#define BIT2BYTE(bits) ((((bits)+NUMBITS-1)/NUMBITS)*(NUMBITS/8))
+#define BITSET(arr, bit) (arr[bit/NUMBITS] |= ((int)1 << (bit & (NUMBITS-1))))
+#define BITCLEAR(arr, bit) (arr[bit/NUMBITS] &= ~((int)1 << (bit & (NUMBITS-1))))
+#define TESTBIT(arr, bit) (arr[bit/NUMBITS] & ((int)1 << (bit & (NUMBITS-1))))
+typedef int bittype;
+extern int tempregs[], permregs[];
+#define NTEMPREG 4
+#define FREGS 3
+#define NPERMREG 4
+extern bittype validregs[];
+#define AREGCNT 6
+#define BREGCNT 8
+#define CREGCNT 15
+#define DREGCNT 8
+#define EREGCNT 0
+#define FREGCNT 0
+#define GREGCNT 0
+int aliasmap(int class, int regnum);
+int color2reg(int color, int class);
+int interferes(int reg1, int reg2);
+#endif /* _EXTERNAL_H_ */
Index: uspace/app/pcc/cc/ccom/arch/ia64/external.c
===================================================================
--- uspace/app/pcc/cc/ccom/arch/ia64/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/ia64/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,246 @@
+#include "pass2.h"
+
+// TODO: replace with file generated by ccom_mkext
+
+static int op0[] = { -1 };
+static int op1[] = { -1 };
+static int op2[] = { -1 };
+static int op3[] = { -1 };
+static int op4[] = { -1 };
+static int op5[] = { -1 };
+static int op6[] = { -1 };
+static int op7[] = { -1 };
+static int op8[] = { -1 };
+static int op9[] = { -1 };
+static int op10[] = { -1 };
+static int op11[] = { -1 };
+static int op12[] = { -1 };
+static int op13[] = { -1 };
+static int op14[] = { -1 };
+static int op15[] = { -1 };
+static int op16[] = { -1 };
+static int op17[] = { -1 };
+static int op18[] = { -1 };
+static int op19[] = { -1 };
+static int op20[] = { -1 };
+static int op21[] = { -1 };
+static int op22[] = { -1 };
+static int op23[] = { -1 };
+static int op24[] = { -1 };
+static int op25[] = { -1 };
+static int op26[] = { -1 };
+static int op27[] = { -1 };
+static int op28[] = { -1 };
+static int op29[] = { -1 };
+static int op30[] = { -1 };
+static int op31[] = { -1 };
+static int op32[] = { -1 };
+static int op33[] = { -1 };
+static int op34[] = { -1 };
+static int op35[] = { -1 };
+static int op36[] = { -1 };
+static int op37[] = { -1 };
+static int op38[] = { -1 };
+static int op39[] = { -1 };
+static int op40[] = { -1 };
+static int op41[] = { -1 };
+static int op42[] = { -1 };
+static int op43[] = { -1 };
+static int op44[] = { -1 };
+static int op45[] = { -1 };
+static int op46[] = { -1 };
+static int op47[] = { -1 };
+static int op48[] = { -1 };
+static int op49[] = { -1 };
+static int op50[] = { -1 };
+static int op51[] = { -1 };
+static int op52[] = { -1 };
+static int op53[] = { -1 };
+static int op54[] = { -1 };
+static int op55[] = { -1 };
+static int op56[] = { -1 };
+static int op57[] = { -1 };
+static int op58[] = { -1 };
+
+int *qtable[] = { 
+	op0,
+	op1,
+	op2,
+	op3,
+	op4,
+	op5,
+	op6,
+	op7,
+	op8,
+	op9,
+	op10,
+	op11,
+	op12,
+	op13,
+	op14,
+	op15,
+	op16,
+	op17,
+	op18,
+	op19,
+	op20,
+	op21,
+	op22,
+	op23,
+	op24,
+	op25,
+	op26,
+	op27,
+	op28,
+	op29,
+	op30,
+	op31,
+	op32,
+	op33,
+	op34,
+	op35,
+	op36,
+	op37,
+	op38,
+	op39,
+	op40,
+	op41,
+	op42,
+	op43,
+	op44,
+	op45,
+	op46,
+	op47,
+	op48,
+	op49,
+	op50,
+	op51,
+	op52,
+	op53,
+	op54,
+	op55,
+	op56,
+	op57,
+	op58,
+};
+int tempregs[] = { -1 };
+int permregs[] = { -1 };
+bittype validregs[] = {
+	0x7fffffffff,
+};
+static int amap[MAXREGS][NUMCLASS] = {
+	/* 0 */{ 0x0,0x0,0x0,0x0 },
+	/* 1 */{ 0x0,0x0,0x0,0x0 },
+	/* 2 */{ 0x0,0x0,0x0,0x0 },
+	/* 3 */{ 0x0,0x0,0x0,0x0 },
+	/* 4 */{ 0x0,0x0,0x0,0x0 },
+	/* 5 */{ 0x0,0x0,0x0,0x0 },
+	/* 6 */{ 0x0,0x0,0x0,0x0 },
+	/* 7 */{ 0x0,0x0,0x0,0x0 },
+	/* 8 */{ 0x0,0x0,0x0,0x0 },
+	/* 9 */{ 0x0,0x0,0x0,0x0 },
+	/* 10 */{ 0x0,0x0,0x0,0x0 },
+	/* 11 */{ 0x0,0x0,0x0,0x0 },
+	/* 12 */{ 0x0,0x0,0x0,0x0 },
+	/* 13 */{ 0x0,0x0,0x0,0x0 },
+	/* 14 */{ 0x0,0x0,0x0,0x0 },
+	/* 15 */{ 0x0,0x0,0x0,0x0 },
+	/* 16 */{ 0x0,0x0,0x0,0x0 },
+	/* 17 */{ 0x0,0x0,0x0,0x0 },
+	/* 18 */{ 0x0,0x0,0x0,0x0 },
+	/* 19 */{ 0x0,0x0,0x0,0x0 },
+	/* 20 */{ 0x0,0x0,0x0,0x0 },
+	/* 21 */{ 0x0,0x0,0x0,0x0 },
+	/* 22 */{ 0x0,0x0,0x0,0x0 },
+	/* 23 */{ 0x0,0x0,0x0,0x0 },
+	/* 24 */{ 0x0,0x0,0x0,0x0 },
+	/* 25 */{ 0x0,0x0,0x0,0x0 },
+	/* 26 */{ 0x0,0x0,0x0,0x0 },
+	/* 27 */{ 0x0,0x0,0x0,0x0 },
+	/* 28 */{ 0x0,0x0,0x0,0x0 },
+	/* 29 */{ 0x0,0x0,0x0,0x0 },
+	/* 30 */{ 0x0,0x0,0x0,0x0 },
+	/* 31 */{ 0x0,0x0,0x0,0x0 },
+	/* 32 */{ 0x0,0x0,0x0,0x0 },
+	/* 33 */{ 0x0,0x0,0x0,0x0 },
+	/* 34 */{ 0x0,0x0,0x0,0x0 },
+	/* 35 */{ 0x0,0x0,0x0,0x0 },
+	/* 36 */{ 0x0,0x0,0x0,0x0 },
+	/* 37 */{ 0x0,0x0,0x0,0x0 },
+	/* 38 */{ 0x0,0x0,0x0,0x0 }
+};
+int
+aliasmap(int class, int regnum)
+{
+	return amap[regnum][class-1];
+}
+static int rmap[NUMCLASS][15] = {
+	{ 0, 1, 2, 3, 4, 5, },
+	{ 8, 9, 10, 11, 12, 13, 14, 15, },
+	{ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, },
+	{ 31, 32, 33, 34, 35, 36, 37, 38, },
+};
+
+int
+color2reg(int color, int class)
+{
+	return rmap[class-1][color];
+}
+int regK[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+int
+classmask(int class)
+{
+	if(class == CLASSA) return 0x0;
+	if(class == CLASSB) return 0x0;
+	if(class == CLASSC) return 0x0;
+	if(class == CLASSD) return 0x0;
+	if(class == CLASSE) return 0x0;
+	if(class == CLASSF) return 0x0;
+	return 0x0;
+}
+static bittype ovlarr[MAXREGS][1] = {
+{ 0x1f0301,  },
+{ 0x1e10c02,  },
+{ 0xe223004,  },
+{ 0x3244c008,  },
+{ 0x54880010,  },
+{ 0x69100020,  },
+{ 0x40,  },
+{ 0x80,  },
+{ 0x1f0101,  },
+{ 0x1f0201,  },
+{ 0x1e10402,  },
+{ 0x1e10802,  },
+{ 0xe221004,  },
+{ 0xe222004,  },
+{ 0x32444008,  },
+{ 0x32448008,  },
+{ 0x1ff0f03,  },
+{ 0xe3f3305,  },
+{ 0x325fc309,  },
+{ 0x549f0311,  },
+{ 0x691f0321,  },
+{ 0xfe33c06,  },
+{ 0x33e5cc0a,  },
+{ 0x55e90c12,  },
+{ 0x69f10c22,  },
+{ 0x3e66f00c,  },
+{ 0x5eaa3014,  },
+{ 0x6f323024,  },
+{ 0x76ccc018,  },
+{ 0x7b54c028,  },
+{ 0x7d980030,  },
+{ 0x80000000,  },
+{ 0x1,  },
+{ 0x2,  },
+{ 0x4,  },
+{ 0x8,  },
+{ 0x10,  },
+{ 0x20,  },
+{ 0x40,  },
+};
+int
+interferes(int reg1, int reg2)
+{
+return (TESTBIT(ovlarr[reg1], reg2)) != 0;
+}
Index: uspace/app/pcc/cc/ccom/arch/ia64/external.h
===================================================================
--- uspace/app/pcc/cc/ccom/arch/ia64/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/ia64/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,27 @@
+// TODO: replace with file generated by ccom_mkext
+
+#ifndef _EXTERNAL_H_
+#define _EXTERNAL_H_
+#define MAXOPLEN 0
+#define NUMBITS 32
+#define BIT2BYTE(bits) ((((bits)+NUMBITS-1)/NUMBITS)*(NUMBITS/8))
+#define BITSET(arr, bit) (arr[bit/NUMBITS] |= ((int)1 << (bit & (NUMBITS-1))))
+#define BITCLEAR(arr, bit) (arr[bit/NUMBITS] &= ~((int)1 << (bit & (NUMBITS-1))))
+#define TESTBIT(arr, bit) (arr[bit/NUMBITS] & ((int)1 << (bit & (NUMBITS-1))))
+typedef int bittype;
+extern int tempregs[], permregs[];
+#define NTEMPREG 0
+#define FREGS 0
+#define NPERMREG 0
+extern bittype validregs[];
+#define AREGCNT 0
+#define BREGCNT 0
+#define CREGCNT 0
+#define DREGCNT 0
+#define EREGCNT 0
+#define FREGCNT 0
+#define GREGCNT 0
+int aliasmap(int class, int regnum);
+int color2reg(int color, int class);
+int interferes(int reg1, int reg2);
+#endif /* _EXTERNAL_H_ */
Index: uspace/app/pcc/cc/ccom/arch/mips32/external.c
===================================================================
--- uspace/app/pcc/cc/ccom/arch/mips32/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/mips32/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,246 @@
+#include "pass2.h"
+
+// TODO: replace with file generated by ccom_mkext
+
+static int op0[] = { -1 };
+static int op1[] = { -1 };
+static int op2[] = { -1 };
+static int op3[] = { -1 };
+static int op4[] = { -1 };
+static int op5[] = { -1 };
+static int op6[] = { -1 };
+static int op7[] = { -1 };
+static int op8[] = { -1 };
+static int op9[] = { -1 };
+static int op10[] = { -1 };
+static int op11[] = { -1 };
+static int op12[] = { -1 };
+static int op13[] = { -1 };
+static int op14[] = { -1 };
+static int op15[] = { -1 };
+static int op16[] = { -1 };
+static int op17[] = { -1 };
+static int op18[] = { -1 };
+static int op19[] = { -1 };
+static int op20[] = { -1 };
+static int op21[] = { -1 };
+static int op22[] = { -1 };
+static int op23[] = { -1 };
+static int op24[] = { -1 };
+static int op25[] = { -1 };
+static int op26[] = { -1 };
+static int op27[] = { -1 };
+static int op28[] = { -1 };
+static int op29[] = { -1 };
+static int op30[] = { -1 };
+static int op31[] = { -1 };
+static int op32[] = { -1 };
+static int op33[] = { -1 };
+static int op34[] = { -1 };
+static int op35[] = { -1 };
+static int op36[] = { -1 };
+static int op37[] = { -1 };
+static int op38[] = { -1 };
+static int op39[] = { -1 };
+static int op40[] = { -1 };
+static int op41[] = { -1 };
+static int op42[] = { -1 };
+static int op43[] = { -1 };
+static int op44[] = { -1 };
+static int op45[] = { -1 };
+static int op46[] = { -1 };
+static int op47[] = { -1 };
+static int op48[] = { -1 };
+static int op49[] = { -1 };
+static int op50[] = { -1 };
+static int op51[] = { -1 };
+static int op52[] = { -1 };
+static int op53[] = { -1 };
+static int op54[] = { -1 };
+static int op55[] = { -1 };
+static int op56[] = { -1 };
+static int op57[] = { -1 };
+static int op58[] = { -1 };
+
+int *qtable[] = { 
+	op0,
+	op1,
+	op2,
+	op3,
+	op4,
+	op5,
+	op6,
+	op7,
+	op8,
+	op9,
+	op10,
+	op11,
+	op12,
+	op13,
+	op14,
+	op15,
+	op16,
+	op17,
+	op18,
+	op19,
+	op20,
+	op21,
+	op22,
+	op23,
+	op24,
+	op25,
+	op26,
+	op27,
+	op28,
+	op29,
+	op30,
+	op31,
+	op32,
+	op33,
+	op34,
+	op35,
+	op36,
+	op37,
+	op38,
+	op39,
+	op40,
+	op41,
+	op42,
+	op43,
+	op44,
+	op45,
+	op46,
+	op47,
+	op48,
+	op49,
+	op50,
+	op51,
+	op52,
+	op53,
+	op54,
+	op55,
+	op56,
+	op57,
+	op58,
+};
+int tempregs[] = { -1 };
+int permregs[] = { -1 };
+bittype validregs[] = {
+	0x7fffffffff,
+};
+static int amap[MAXREGS][NUMCLASS] = {
+	/* 0 */{ 0x0,0x0,0x0,0x0 },
+	/* 1 */{ 0x0,0x0,0x0,0x0 },
+	/* 2 */{ 0x0,0x0,0x0,0x0 },
+	/* 3 */{ 0x0,0x0,0x0,0x0 },
+	/* 4 */{ 0x0,0x0,0x0,0x0 },
+	/* 5 */{ 0x0,0x0,0x0,0x0 },
+	/* 6 */{ 0x0,0x0,0x0,0x0 },
+	/* 7 */{ 0x0,0x0,0x0,0x0 },
+	/* 8 */{ 0x0,0x0,0x0,0x0 },
+	/* 9 */{ 0x0,0x0,0x0,0x0 },
+	/* 10 */{ 0x0,0x0,0x0,0x0 },
+	/* 11 */{ 0x0,0x0,0x0,0x0 },
+	/* 12 */{ 0x0,0x0,0x0,0x0 },
+	/* 13 */{ 0x0,0x0,0x0,0x0 },
+	/* 14 */{ 0x0,0x0,0x0,0x0 },
+	/* 15 */{ 0x0,0x0,0x0,0x0 },
+	/* 16 */{ 0x0,0x0,0x0,0x0 },
+	/* 17 */{ 0x0,0x0,0x0,0x0 },
+	/* 18 */{ 0x0,0x0,0x0,0x0 },
+	/* 19 */{ 0x0,0x0,0x0,0x0 },
+	/* 20 */{ 0x0,0x0,0x0,0x0 },
+	/* 21 */{ 0x0,0x0,0x0,0x0 },
+	/* 22 */{ 0x0,0x0,0x0,0x0 },
+	/* 23 */{ 0x0,0x0,0x0,0x0 },
+	/* 24 */{ 0x0,0x0,0x0,0x0 },
+	/* 25 */{ 0x0,0x0,0x0,0x0 },
+	/* 26 */{ 0x0,0x0,0x0,0x0 },
+	/* 27 */{ 0x0,0x0,0x0,0x0 },
+	/* 28 */{ 0x0,0x0,0x0,0x0 },
+	/* 29 */{ 0x0,0x0,0x0,0x0 },
+	/* 30 */{ 0x0,0x0,0x0,0x0 },
+	/* 31 */{ 0x0,0x0,0x0,0x0 },
+	/* 32 */{ 0x0,0x0,0x0,0x0 },
+	/* 33 */{ 0x0,0x0,0x0,0x0 },
+	/* 34 */{ 0x0,0x0,0x0,0x0 },
+	/* 35 */{ 0x0,0x0,0x0,0x0 },
+	/* 36 */{ 0x0,0x0,0x0,0x0 },
+	/* 37 */{ 0x0,0x0,0x0,0x0 },
+	/* 38 */{ 0x0,0x0,0x0,0x0 }
+};
+int
+aliasmap(int class, int regnum)
+{
+	return amap[regnum][class-1];
+}
+static int rmap[NUMCLASS][15] = {
+	{ 0, 1, 2, 3, 4, 5, },
+	{ 8, 9, 10, 11, 12, 13, 14, 15, },
+	{ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, },
+	{ 31, 32, 33, 34, 35, 36, 37, 38, },
+};
+
+int
+color2reg(int color, int class)
+{
+	return rmap[class-1][color];
+}
+int regK[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+int
+classmask(int class)
+{
+	if(class == CLASSA) return 0x0;
+	if(class == CLASSB) return 0x0;
+	if(class == CLASSC) return 0x0;
+	if(class == CLASSD) return 0x0;
+	if(class == CLASSE) return 0x0;
+	if(class == CLASSF) return 0x0;
+	return 0x0;
+}
+static bittype ovlarr[MAXREGS][1] = {
+{ 0x1f0301,  },
+{ 0x1e10c02,  },
+{ 0xe223004,  },
+{ 0x3244c008,  },
+{ 0x54880010,  },
+{ 0x69100020,  },
+{ 0x40,  },
+{ 0x80,  },
+{ 0x1f0101,  },
+{ 0x1f0201,  },
+{ 0x1e10402,  },
+{ 0x1e10802,  },
+{ 0xe221004,  },
+{ 0xe222004,  },
+{ 0x32444008,  },
+{ 0x32448008,  },
+{ 0x1ff0f03,  },
+{ 0xe3f3305,  },
+{ 0x325fc309,  },
+{ 0x549f0311,  },
+{ 0x691f0321,  },
+{ 0xfe33c06,  },
+{ 0x33e5cc0a,  },
+{ 0x55e90c12,  },
+{ 0x69f10c22,  },
+{ 0x3e66f00c,  },
+{ 0x5eaa3014,  },
+{ 0x6f323024,  },
+{ 0x76ccc018,  },
+{ 0x7b54c028,  },
+{ 0x7d980030,  },
+{ 0x80000000,  },
+{ 0x1,  },
+{ 0x2,  },
+{ 0x4,  },
+{ 0x8,  },
+{ 0x10,  },
+{ 0x20,  },
+{ 0x40,  },
+};
+int
+interferes(int reg1, int reg2)
+{
+return (TESTBIT(ovlarr[reg1], reg2)) != 0;
+}
Index: uspace/app/pcc/cc/ccom/arch/mips32/external.h
===================================================================
--- uspace/app/pcc/cc/ccom/arch/mips32/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/mips32/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,27 @@
+// TODO: replace with file generated by ccom_mkext
+
+#ifndef _EXTERNAL_H_
+#define _EXTERNAL_H_
+#define MAXOPLEN 0
+#define NUMBITS 32
+#define BIT2BYTE(bits) ((((bits)+NUMBITS-1)/NUMBITS)*(NUMBITS/8))
+#define BITSET(arr, bit) (arr[bit/NUMBITS] |= ((int)1 << (bit & (NUMBITS-1))))
+#define BITCLEAR(arr, bit) (arr[bit/NUMBITS] &= ~((int)1 << (bit & (NUMBITS-1))))
+#define TESTBIT(arr, bit) (arr[bit/NUMBITS] & ((int)1 << (bit & (NUMBITS-1))))
+typedef int bittype;
+extern int tempregs[], permregs[];
+#define NTEMPREG 0
+#define FREGS 0
+#define NPERMREG 0
+extern bittype validregs[];
+#define AREGCNT 0
+#define BREGCNT 0
+#define CREGCNT 0
+#define DREGCNT 0
+#define EREGCNT 0
+#define FREGCNT 0
+#define GREGCNT 0
+int aliasmap(int class, int regnum);
+int color2reg(int color, int class);
+int interferes(int reg1, int reg2);
+#endif /* _EXTERNAL_H_ */
Index: uspace/app/pcc/cc/ccom/arch/ppc32/external.c
===================================================================
--- uspace/app/pcc/cc/ccom/arch/ppc32/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/ppc32/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,246 @@
+#include "pass2.h"
+
+// TODO: replace with file generated by ccom_mkext
+
+static int op0[] = { -1 };
+static int op1[] = { -1 };
+static int op2[] = { -1 };
+static int op3[] = { -1 };
+static int op4[] = { -1 };
+static int op5[] = { -1 };
+static int op6[] = { -1 };
+static int op7[] = { -1 };
+static int op8[] = { -1 };
+static int op9[] = { -1 };
+static int op10[] = { -1 };
+static int op11[] = { -1 };
+static int op12[] = { -1 };
+static int op13[] = { -1 };
+static int op14[] = { -1 };
+static int op15[] = { -1 };
+static int op16[] = { -1 };
+static int op17[] = { -1 };
+static int op18[] = { -1 };
+static int op19[] = { -1 };
+static int op20[] = { -1 };
+static int op21[] = { -1 };
+static int op22[] = { -1 };
+static int op23[] = { -1 };
+static int op24[] = { -1 };
+static int op25[] = { -1 };
+static int op26[] = { -1 };
+static int op27[] = { -1 };
+static int op28[] = { -1 };
+static int op29[] = { -1 };
+static int op30[] = { -1 };
+static int op31[] = { -1 };
+static int op32[] = { -1 };
+static int op33[] = { -1 };
+static int op34[] = { -1 };
+static int op35[] = { -1 };
+static int op36[] = { -1 };
+static int op37[] = { -1 };
+static int op38[] = { -1 };
+static int op39[] = { -1 };
+static int op40[] = { -1 };
+static int op41[] = { -1 };
+static int op42[] = { -1 };
+static int op43[] = { -1 };
+static int op44[] = { -1 };
+static int op45[] = { -1 };
+static int op46[] = { -1 };
+static int op47[] = { -1 };
+static int op48[] = { -1 };
+static int op49[] = { -1 };
+static int op50[] = { -1 };
+static int op51[] = { -1 };
+static int op52[] = { -1 };
+static int op53[] = { -1 };
+static int op54[] = { -1 };
+static int op55[] = { -1 };
+static int op56[] = { -1 };
+static int op57[] = { -1 };
+static int op58[] = { -1 };
+
+int *qtable[] = { 
+	op0,
+	op1,
+	op2,
+	op3,
+	op4,
+	op5,
+	op6,
+	op7,
+	op8,
+	op9,
+	op10,
+	op11,
+	op12,
+	op13,
+	op14,
+	op15,
+	op16,
+	op17,
+	op18,
+	op19,
+	op20,
+	op21,
+	op22,
+	op23,
+	op24,
+	op25,
+	op26,
+	op27,
+	op28,
+	op29,
+	op30,
+	op31,
+	op32,
+	op33,
+	op34,
+	op35,
+	op36,
+	op37,
+	op38,
+	op39,
+	op40,
+	op41,
+	op42,
+	op43,
+	op44,
+	op45,
+	op46,
+	op47,
+	op48,
+	op49,
+	op50,
+	op51,
+	op52,
+	op53,
+	op54,
+	op55,
+	op56,
+	op57,
+	op58,
+};
+int tempregs[] = { -1 };
+int permregs[] = { -1 };
+bittype validregs[] = {
+	0x7fffffffff,
+};
+static int amap[MAXREGS][NUMCLASS] = {
+	/* 0 */{ 0x0,0x0,0x0,0x0 },
+	/* 1 */{ 0x0,0x0,0x0,0x0 },
+	/* 2 */{ 0x0,0x0,0x0,0x0 },
+	/* 3 */{ 0x0,0x0,0x0,0x0 },
+	/* 4 */{ 0x0,0x0,0x0,0x0 },
+	/* 5 */{ 0x0,0x0,0x0,0x0 },
+	/* 6 */{ 0x0,0x0,0x0,0x0 },
+	/* 7 */{ 0x0,0x0,0x0,0x0 },
+	/* 8 */{ 0x0,0x0,0x0,0x0 },
+	/* 9 */{ 0x0,0x0,0x0,0x0 },
+	/* 10 */{ 0x0,0x0,0x0,0x0 },
+	/* 11 */{ 0x0,0x0,0x0,0x0 },
+	/* 12 */{ 0x0,0x0,0x0,0x0 },
+	/* 13 */{ 0x0,0x0,0x0,0x0 },
+	/* 14 */{ 0x0,0x0,0x0,0x0 },
+	/* 15 */{ 0x0,0x0,0x0,0x0 },
+	/* 16 */{ 0x0,0x0,0x0,0x0 },
+	/* 17 */{ 0x0,0x0,0x0,0x0 },
+	/* 18 */{ 0x0,0x0,0x0,0x0 },
+	/* 19 */{ 0x0,0x0,0x0,0x0 },
+	/* 20 */{ 0x0,0x0,0x0,0x0 },
+	/* 21 */{ 0x0,0x0,0x0,0x0 },
+	/* 22 */{ 0x0,0x0,0x0,0x0 },
+	/* 23 */{ 0x0,0x0,0x0,0x0 },
+	/* 24 */{ 0x0,0x0,0x0,0x0 },
+	/* 25 */{ 0x0,0x0,0x0,0x0 },
+	/* 26 */{ 0x0,0x0,0x0,0x0 },
+	/* 27 */{ 0x0,0x0,0x0,0x0 },
+	/* 28 */{ 0x0,0x0,0x0,0x0 },
+	/* 29 */{ 0x0,0x0,0x0,0x0 },
+	/* 30 */{ 0x0,0x0,0x0,0x0 },
+	/* 31 */{ 0x0,0x0,0x0,0x0 },
+	/* 32 */{ 0x0,0x0,0x0,0x0 },
+	/* 33 */{ 0x0,0x0,0x0,0x0 },
+	/* 34 */{ 0x0,0x0,0x0,0x0 },
+	/* 35 */{ 0x0,0x0,0x0,0x0 },
+	/* 36 */{ 0x0,0x0,0x0,0x0 },
+	/* 37 */{ 0x0,0x0,0x0,0x0 },
+	/* 38 */{ 0x0,0x0,0x0,0x0 }
+};
+int
+aliasmap(int class, int regnum)
+{
+	return amap[regnum][class-1];
+}
+static int rmap[NUMCLASS][15] = {
+	{ 0, 1, 2, 3, 4, 5, },
+	{ 8, 9, 10, 11, 12, 13, 14, 15, },
+	{ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, },
+	{ 31, 32, 33, 34, 35, 36, 37, 38, },
+};
+
+int
+color2reg(int color, int class)
+{
+	return rmap[class-1][color];
+}
+int regK[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+int
+classmask(int class)
+{
+	if(class == CLASSA) return 0x0;
+	if(class == CLASSB) return 0x0;
+	if(class == CLASSC) return 0x0;
+	if(class == CLASSD) return 0x0;
+	if(class == CLASSE) return 0x0;
+	if(class == CLASSF) return 0x0;
+	return 0x0;
+}
+static bittype ovlarr[MAXREGS][1] = {
+{ 0x1f0301,  },
+{ 0x1e10c02,  },
+{ 0xe223004,  },
+{ 0x3244c008,  },
+{ 0x54880010,  },
+{ 0x69100020,  },
+{ 0x40,  },
+{ 0x80,  },
+{ 0x1f0101,  },
+{ 0x1f0201,  },
+{ 0x1e10402,  },
+{ 0x1e10802,  },
+{ 0xe221004,  },
+{ 0xe222004,  },
+{ 0x32444008,  },
+{ 0x32448008,  },
+{ 0x1ff0f03,  },
+{ 0xe3f3305,  },
+{ 0x325fc309,  },
+{ 0x549f0311,  },
+{ 0x691f0321,  },
+{ 0xfe33c06,  },
+{ 0x33e5cc0a,  },
+{ 0x55e90c12,  },
+{ 0x69f10c22,  },
+{ 0x3e66f00c,  },
+{ 0x5eaa3014,  },
+{ 0x6f323024,  },
+{ 0x76ccc018,  },
+{ 0x7b54c028,  },
+{ 0x7d980030,  },
+{ 0x80000000,  },
+{ 0x1,  },
+{ 0x2,  },
+{ 0x4,  },
+{ 0x8,  },
+{ 0x10,  },
+{ 0x20,  },
+{ 0x40,  },
+};
+int
+interferes(int reg1, int reg2)
+{
+return (TESTBIT(ovlarr[reg1], reg2)) != 0;
+}
Index: uspace/app/pcc/cc/ccom/arch/ppc32/external.h
===================================================================
--- uspace/app/pcc/cc/ccom/arch/ppc32/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/ppc32/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,27 @@
+// TODO: replace with file generated by ccom_mkext
+
+#ifndef _EXTERNAL_H_
+#define _EXTERNAL_H_
+#define MAXOPLEN 0
+#define NUMBITS 32
+#define BIT2BYTE(bits) ((((bits)+NUMBITS-1)/NUMBITS)*(NUMBITS/8))
+#define BITSET(arr, bit) (arr[bit/NUMBITS] |= ((int)1 << (bit & (NUMBITS-1))))
+#define BITCLEAR(arr, bit) (arr[bit/NUMBITS] &= ~((int)1 << (bit & (NUMBITS-1))))
+#define TESTBIT(arr, bit) (arr[bit/NUMBITS] & ((int)1 << (bit & (NUMBITS-1))))
+typedef int bittype;
+extern int tempregs[], permregs[];
+#define NTEMPREG 0
+#define FREGS 0
+#define NPERMREG 0
+extern bittype validregs[];
+#define AREGCNT 0
+#define BREGCNT 0
+#define CREGCNT 0
+#define DREGCNT 0
+#define EREGCNT 0
+#define FREGCNT 0
+#define GREGCNT 0
+int aliasmap(int class, int regnum);
+int color2reg(int color, int class);
+int interferes(int reg1, int reg2);
+#endif /* _EXTERNAL_H_ */
Index: uspace/app/pcc/cc/ccom/arch/sparc64/external.c
===================================================================
--- uspace/app/pcc/cc/ccom/arch/sparc64/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/sparc64/external.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,246 @@
+#include "pass2.h"
+
+// TODO: replace with file generated by ccom_mkext
+
+static int op0[] = { -1 };
+static int op1[] = { -1 };
+static int op2[] = { -1 };
+static int op3[] = { -1 };
+static int op4[] = { -1 };
+static int op5[] = { -1 };
+static int op6[] = { -1 };
+static int op7[] = { -1 };
+static int op8[] = { -1 };
+static int op9[] = { -1 };
+static int op10[] = { -1 };
+static int op11[] = { -1 };
+static int op12[] = { -1 };
+static int op13[] = { -1 };
+static int op14[] = { -1 };
+static int op15[] = { -1 };
+static int op16[] = { -1 };
+static int op17[] = { -1 };
+static int op18[] = { -1 };
+static int op19[] = { -1 };
+static int op20[] = { -1 };
+static int op21[] = { -1 };
+static int op22[] = { -1 };
+static int op23[] = { -1 };
+static int op24[] = { -1 };
+static int op25[] = { -1 };
+static int op26[] = { -1 };
+static int op27[] = { -1 };
+static int op28[] = { -1 };
+static int op29[] = { -1 };
+static int op30[] = { -1 };
+static int op31[] = { -1 };
+static int op32[] = { -1 };
+static int op33[] = { -1 };
+static int op34[] = { -1 };
+static int op35[] = { -1 };
+static int op36[] = { -1 };
+static int op37[] = { -1 };
+static int op38[] = { -1 };
+static int op39[] = { -1 };
+static int op40[] = { -1 };
+static int op41[] = { -1 };
+static int op42[] = { -1 };
+static int op43[] = { -1 };
+static int op44[] = { -1 };
+static int op45[] = { -1 };
+static int op46[] = { -1 };
+static int op47[] = { -1 };
+static int op48[] = { -1 };
+static int op49[] = { -1 };
+static int op50[] = { -1 };
+static int op51[] = { -1 };
+static int op52[] = { -1 };
+static int op53[] = { -1 };
+static int op54[] = { -1 };
+static int op55[] = { -1 };
+static int op56[] = { -1 };
+static int op57[] = { -1 };
+static int op58[] = { -1 };
+
+int *qtable[] = { 
+	op0,
+	op1,
+	op2,
+	op3,
+	op4,
+	op5,
+	op6,
+	op7,
+	op8,
+	op9,
+	op10,
+	op11,
+	op12,
+	op13,
+	op14,
+	op15,
+	op16,
+	op17,
+	op18,
+	op19,
+	op20,
+	op21,
+	op22,
+	op23,
+	op24,
+	op25,
+	op26,
+	op27,
+	op28,
+	op29,
+	op30,
+	op31,
+	op32,
+	op33,
+	op34,
+	op35,
+	op36,
+	op37,
+	op38,
+	op39,
+	op40,
+	op41,
+	op42,
+	op43,
+	op44,
+	op45,
+	op46,
+	op47,
+	op48,
+	op49,
+	op50,
+	op51,
+	op52,
+	op53,
+	op54,
+	op55,
+	op56,
+	op57,
+	op58,
+};
+int tempregs[] = { -1 };
+int permregs[] = { -1 };
+bittype validregs[] = {
+	0x7fffffffff,
+};
+static int amap[MAXREGS][NUMCLASS] = {
+	/* 0 */{ 0x0,0x0,0x0,0x0 },
+	/* 1 */{ 0x0,0x0,0x0,0x0 },
+	/* 2 */{ 0x0,0x0,0x0,0x0 },
+	/* 3 */{ 0x0,0x0,0x0,0x0 },
+	/* 4 */{ 0x0,0x0,0x0,0x0 },
+	/* 5 */{ 0x0,0x0,0x0,0x0 },
+	/* 6 */{ 0x0,0x0,0x0,0x0 },
+	/* 7 */{ 0x0,0x0,0x0,0x0 },
+	/* 8 */{ 0x0,0x0,0x0,0x0 },
+	/* 9 */{ 0x0,0x0,0x0,0x0 },
+	/* 10 */{ 0x0,0x0,0x0,0x0 },
+	/* 11 */{ 0x0,0x0,0x0,0x0 },
+	/* 12 */{ 0x0,0x0,0x0,0x0 },
+	/* 13 */{ 0x0,0x0,0x0,0x0 },
+	/* 14 */{ 0x0,0x0,0x0,0x0 },
+	/* 15 */{ 0x0,0x0,0x0,0x0 },
+	/* 16 */{ 0x0,0x0,0x0,0x0 },
+	/* 17 */{ 0x0,0x0,0x0,0x0 },
+	/* 18 */{ 0x0,0x0,0x0,0x0 },
+	/* 19 */{ 0x0,0x0,0x0,0x0 },
+	/* 20 */{ 0x0,0x0,0x0,0x0 },
+	/* 21 */{ 0x0,0x0,0x0,0x0 },
+	/* 22 */{ 0x0,0x0,0x0,0x0 },
+	/* 23 */{ 0x0,0x0,0x0,0x0 },
+	/* 24 */{ 0x0,0x0,0x0,0x0 },
+	/* 25 */{ 0x0,0x0,0x0,0x0 },
+	/* 26 */{ 0x0,0x0,0x0,0x0 },
+	/* 27 */{ 0x0,0x0,0x0,0x0 },
+	/* 28 */{ 0x0,0x0,0x0,0x0 },
+	/* 29 */{ 0x0,0x0,0x0,0x0 },
+	/* 30 */{ 0x0,0x0,0x0,0x0 },
+	/* 31 */{ 0x0,0x0,0x0,0x0 },
+	/* 32 */{ 0x0,0x0,0x0,0x0 },
+	/* 33 */{ 0x0,0x0,0x0,0x0 },
+	/* 34 */{ 0x0,0x0,0x0,0x0 },
+	/* 35 */{ 0x0,0x0,0x0,0x0 },
+	/* 36 */{ 0x0,0x0,0x0,0x0 },
+	/* 37 */{ 0x0,0x0,0x0,0x0 },
+	/* 38 */{ 0x0,0x0,0x0,0x0 }
+};
+int
+aliasmap(int class, int regnum)
+{
+	return amap[regnum][class-1];
+}
+static int rmap[NUMCLASS][15] = {
+	{ 0, 1, 2, 3, 4, 5, },
+	{ 8, 9, 10, 11, 12, 13, 14, 15, },
+	{ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, },
+	{ 31, 32, 33, 34, 35, 36, 37, 38, },
+};
+
+int
+color2reg(int color, int class)
+{
+	return rmap[class-1][color];
+}
+int regK[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+int
+classmask(int class)
+{
+	if(class == CLASSA) return 0x0;
+	if(class == CLASSB) return 0x0;
+	if(class == CLASSC) return 0x0;
+	if(class == CLASSD) return 0x0;
+	if(class == CLASSE) return 0x0;
+	if(class == CLASSF) return 0x0;
+	return 0x0;
+}
+static bittype ovlarr[MAXREGS][1] = {
+{ 0x1f0301,  },
+{ 0x1e10c02,  },
+{ 0xe223004,  },
+{ 0x3244c008,  },
+{ 0x54880010,  },
+{ 0x69100020,  },
+{ 0x40,  },
+{ 0x80,  },
+{ 0x1f0101,  },
+{ 0x1f0201,  },
+{ 0x1e10402,  },
+{ 0x1e10802,  },
+{ 0xe221004,  },
+{ 0xe222004,  },
+{ 0x32444008,  },
+{ 0x32448008,  },
+{ 0x1ff0f03,  },
+{ 0xe3f3305,  },
+{ 0x325fc309,  },
+{ 0x549f0311,  },
+{ 0x691f0321,  },
+{ 0xfe33c06,  },
+{ 0x33e5cc0a,  },
+{ 0x55e90c12,  },
+{ 0x69f10c22,  },
+{ 0x3e66f00c,  },
+{ 0x5eaa3014,  },
+{ 0x6f323024,  },
+{ 0x76ccc018,  },
+{ 0x7b54c028,  },
+{ 0x7d980030,  },
+{ 0x80000000,  },
+{ 0x1,  },
+{ 0x2,  },
+{ 0x4,  },
+{ 0x8,  },
+{ 0x10,  },
+{ 0x20,  },
+{ 0x40,  },
+};
+int
+interferes(int reg1, int reg2)
+{
+return (TESTBIT(ovlarr[reg1], reg2)) != 0;
+}
Index: uspace/app/pcc/cc/ccom/arch/sparc64/external.h
===================================================================
--- uspace/app/pcc/cc/ccom/arch/sparc64/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/arch/sparc64/external.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,27 @@
+// TODO: replace with file generated by ccom_mkext
+
+#ifndef _EXTERNAL_H_
+#define _EXTERNAL_H_
+#define MAXOPLEN 0
+#define NUMBITS 32
+#define BIT2BYTE(bits) ((((bits)+NUMBITS-1)/NUMBITS)*(NUMBITS/8))
+#define BITSET(arr, bit) (arr[bit/NUMBITS] |= ((int)1 << (bit & (NUMBITS-1))))
+#define BITCLEAR(arr, bit) (arr[bit/NUMBITS] &= ~((int)1 << (bit & (NUMBITS-1))))
+#define TESTBIT(arr, bit) (arr[bit/NUMBITS] & ((int)1 << (bit & (NUMBITS-1))))
+typedef int bittype;
+extern int tempregs[], permregs[];
+#define NTEMPREG 0
+#define FREGS 0
+#define NPERMREG 0
+extern bittype validregs[];
+#define AREGCNT 0
+#define BREGCNT 0
+#define CREGCNT 0
+#define DREGCNT 0
+#define EREGCNT 0
+#define FREGCNT 0
+#define GREGCNT 0
+int aliasmap(int class, int regnum);
+int color2reg(int color, int class);
+int interferes(int reg1, int reg2);
+#endif /* _EXTERNAL_H_ */
Index: uspace/app/pcc/cc/ccom/builtins.c
===================================================================
--- uspace/app/pcc/cc/ccom/builtins.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/builtins.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,638 @@
+/*	$Id: builtins.c,v 1.18.2.2 2011/03/29 15:56: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.
+ *
+ * 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"
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#ifndef NO_C_BUILTINS
+/*
+ * replace an alloca function with direct allocation on stack.
+ * return a destination temp node.
+ */
+static NODE *
+builtin_alloca(NODE *f, NODE *a, TWORD rt)
+{
+	struct symtab *sp;
+	NODE *t, *u;
+
+#ifdef notyet
+	if (xnobuiltins)
+		return NULL;
+#endif
+	sp = f->n_sp;
+
+	t = tempnode(0, VOID|PTR, 0, MKAP(INT) /* XXX */);
+	u = tempnode(regno(t), VOID|PTR, 0, MKAP(INT) /* XXX */);
+	spalloc(t, a, SZCHAR);
+	tfree(f);
+	return u;
+}
+
+/*
+ * See if there is a goto in the tree.
+ * XXX this function is a hack for a flaw in handling of 
+ * compound expressions and inline functions and should not be 
+ * needed.
+ */
+static int
+hasgoto(NODE *p)
+{
+	int o = coptype(p->n_op);
+
+	if (o == LTYPE)
+		return 0;
+	if (p->n_op == GOTO)
+		return 1;
+	if (o == UTYPE)
+		return hasgoto(p->n_left);
+	if (hasgoto(p->n_left))
+		return 1;
+	return hasgoto(p->n_right);
+}
+
+/*
+ * Determine if a value is known to be constant at compile-time and
+ * hence that PCC can perform constant-folding on expressions involving
+ * that value.
+ */
+static NODE *
+builtin_constant_p(NODE *f, NODE *a, TWORD rt)
+{
+	void putjops(NODE *p, void *arg);
+	int isconst;
+
+	tfree(f);
+	walkf(a, putjops, 0);
+	for (f = a; f->n_op == COMOP; f = f->n_right)
+		;
+	isconst = nncon(f);
+	tfree(a);
+	return bcon(isconst);
+}
+
+/*
+ * Hint to the compiler whether this expression will evaluate true or false.
+ * Just ignored for now.
+ */
+static NODE *
+builtin_expect(NODE *f, NODE *a, TWORD rt)
+{
+
+	tfree(f);
+	if (a && a->n_op == CM) {
+		tfree(a->n_right);
+		f = a->n_left;
+		nfree(a);
+		a = f;
+	}
+
+	return a;
+}
+
+/*
+ * Take integer absolute value.
+ * Simply does: ((((x)>>(8*sizeof(x)-1))^(x))-((x)>>(8*sizeof(x)-1)))
+ */
+static NODE *
+builtin_abs(NODE *f, NODE *a, TWORD rt)
+{
+	NODE *p, *q, *r, *t, *t2, *t3;
+	int tmp1, tmp2, shift;
+
+	if (a->n_type != INT)
+		a = cast(a, INT, 0);
+
+	tfree(f);
+
+	if (a->n_op == ICON) {
+		if (a->n_lval < 0)
+			a->n_lval = -a->n_lval;
+		p = a;
+	} else {
+		t = tempnode(0, a->n_type, a->n_df, a->n_ap);
+		tmp1 = regno(t);
+		p = buildtree(ASSIGN, t, a);
+
+		t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap);
+		shift = (int)tsize(a->n_type, a->n_df, a->n_ap) - 1;
+		q = buildtree(RS, t, bcon(shift));
+
+		t2 = tempnode(0, a->n_type, a->n_df, a->n_ap);
+		tmp2 = regno(t2);
+		q = buildtree(ASSIGN, t2, q);
+
+		t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap);
+		t2 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap);
+		t3 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap);
+		r = buildtree(MINUS, buildtree(ER, t, t2), t3);
+
+		p = buildtree(COMOP, p, buildtree(COMOP, q, r));
+	}
+
+	return p;
+}
+
+/*
+ * Get size of object, if possible.
+ * Currently does nothing,
+ */
+static NODE *
+builtin_object_size(NODE *f, NODE *a, TWORD rt)
+{
+	int v = icons(a->n_right);
+	if (v < 0 || v > 3)
+		uerror("arg2 must be between 0 and 3");
+
+	tfree(f);
+	f = buildtree(COMOP, a->n_left, xbcon(v < 2 ? -1 : 0, NULL, rt));
+	nfree(a);
+	return f;
+}
+
+#ifndef TARGET_STDARGS
+static NODE *
+builtin_stdarg_start(NODE *f, NODE *a, TWORD rt)
+{
+	NODE *p, *q;
+	int sz;
+
+	/* must first deal with argument size; use int size */
+	p = a->n_right;
+	if (p->n_type < INT) {
+		sz = (int)(SZINT/tsize(p->n_type, p->n_df, p->n_ap));
+	} else
+		sz = 1;
+
+	/* do the real job */
+	p = buildtree(ADDROF, p, NIL); /* address of last arg */
+#ifdef BACKAUTO
+	p = optim(buildtree(PLUS, p, bcon(sz))); /* add one to it (next arg) */
+#else
+	p = optim(buildtree(MINUS, p, bcon(sz))); /* add one to it (next arg) */
+#endif
+	q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); /* create cast node */
+	q = buildtree(CAST, q, p); /* cast to void * (for assignment) */
+	p = q->n_right;
+	nfree(q->n_left);
+	nfree(q);
+	p = buildtree(ASSIGN, a->n_left, p); /* assign to ap */
+	tfree(f);
+	nfree(a);
+	return p;
+}
+
+static NODE *
+builtin_va_arg(NODE *f, NODE *a, TWORD rt)
+{
+	NODE *p, *q, *r, *rv;
+	int sz, nodnum;
+
+	/* create a copy to a temp node of current ap */
+	p = ccopy(a->n_left);
+	q = tempnode(0, p->n_type, p->n_df, p->n_ap);
+	nodnum = regno(q);
+	rv = buildtree(ASSIGN, q, p);
+
+	r = a->n_right;
+	sz = (int)tsize(r->n_type, r->n_df, r->n_ap)/SZCHAR;
+	/* add one to ap */
+#ifdef BACKAUTO
+	rv = buildtree(COMOP, rv , buildtree(PLUSEQ, a->n_left, bcon(sz)));
+#else
+#error fix wrong eval order in builtin_va_arg
+	ecomp(buildtree(MINUSEQ, a->n_left, bcon(sz)));
+#endif
+
+	nfree(a->n_right);
+	nfree(a);
+	nfree(f);
+	r = tempnode(nodnum, INCREF(r->n_type), r->n_df, r->n_ap);
+	return buildtree(COMOP, rv, buildtree(UMUL, r, NIL));
+
+}
+
+static NODE *
+builtin_va_end(NODE *f, NODE *a, TWORD rt)
+{
+	tfree(f);
+	tfree(a);
+	return bcon(0); /* nothing */
+}
+
+static NODE *
+builtin_va_copy(NODE *f, NODE *a, TWORD rt)
+{
+	tfree(f);
+	f = buildtree(ASSIGN, a->n_left, a->n_right);
+	nfree(a);
+	return f;
+}
+#endif /* TARGET_STDARGS */
+
+/*
+ * For unimplemented "builtin" functions, try to invoke the
+ * non-builtin name
+ */
+static NODE *
+binhelp(NODE *f, NODE *a, TWORD rt, char *n)
+{
+	f->n_sp = lookup(addname(n), SNORMAL);
+	if (f->n_sp->sclass == SNULL) {
+		f->n_sp->sclass = EXTERN;
+		f->n_sp->stype = INCREF(rt)+(FTN-PTR);
+	}
+	f->n_type = f->n_sp->stype;
+	f = clocal(f);
+	return buildtree(CALL, f, a);
+}
+
+static NODE *
+builtin_unimp(NODE *f, NODE *a, TWORD rt)
+{
+	char *n = f->n_sp->sname;
+
+	if (strncmp("__builtin_", n, 10) == 0)
+		n += 10;
+	return binhelp(f, a, rt, n);
+}
+
+static NODE *
+builtin_unimp_f(NODE *f, NODE *a, TWORD rt)
+{
+	return binhelp(f, a, rt, f->n_sp->sname);
+}
+
+#ifndef TARGET_ISMATH
+/*
+ * Handle the builtin macros for the math functions is*
+ * To get something that is be somewhat generic assume that 
+ * isnan() is a real function and that cast of a NaN type 
+ * to double will still be a NaN.
+ */
+static NODE *
+mtisnan(NODE *p)
+{
+	NODE *q = block(NAME, NIL, NIL, INT, 0, MKAP(INT));
+
+	return binhelp(q, cast(ccopy(p), DOUBLE, 0), INT, "isnan");
+}
+
+static TWORD
+mtcheck(NODE *p)
+{
+	TWORD t1 = p->n_left->n_type, t2 = p->n_right->n_type;
+
+	if ((t1 >= FLOAT && t1 <= LDOUBLE) ||
+	    (t2 >= FLOAT && t2 <= LDOUBLE))
+		return MAX(t1, t2);
+	return 0;
+}
+
+static NODE *
+builtin_isunordered(NODE *f, NODE *a, TWORD rt)
+{
+	NODE *p;
+
+	if (mtcheck(a) == 0)
+		return bcon(0);
+
+	p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
+	tfree(f);
+	tfree(a);
+	return p;
+}
+static NODE *
+builtin_isany(NODE *f, NODE *a, TWORD rt, int cmpt)
+{
+	NODE *p, *q;
+	TWORD t;
+
+	if ((t = mtcheck(a)) == 0)
+		return bcon(0);
+	p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
+	p = buildtree(NOT, p, NIL);
+	q = buildtree(cmpt, cast(ccopy(a->n_left), t, 0),
+	    cast(ccopy(a->n_right), t, 0));
+	p = buildtree(ANDAND, p, q);
+	tfree(f);
+	tfree(a);
+	return p;
+}
+static NODE *
+builtin_isgreater(NODE *f, NODE *a, TWORD rt)
+{
+	return builtin_isany(f, a, rt, GT);
+}
+static NODE *
+builtin_isgreaterequal(NODE *f, NODE *a, TWORD rt)
+{
+	return builtin_isany(f, a, rt, GE);
+}
+static NODE *
+builtin_isless(NODE *f, NODE *a, TWORD rt)
+{
+	return builtin_isany(f, a, rt, LT);
+}
+static NODE *
+builtin_islessequal(NODE *f, NODE *a, TWORD rt)
+{
+	return builtin_isany(f, a, rt, LE);
+}
+static NODE *
+builtin_islessgreater(NODE *f, NODE *a, TWORD rt)
+{
+	NODE *p, *q, *r;
+	TWORD t;
+
+	if ((t = mtcheck(a)) == 0)
+		return bcon(0);
+	p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right));
+	p = buildtree(NOT, p, NIL);
+	q = buildtree(GT, cast(ccopy(a->n_left), t, 0),
+	    cast(ccopy(a->n_right), t, 0));
+	r = buildtree(LT, cast(ccopy(a->n_left), t, 0),
+	    cast(ccopy(a->n_right), t, 0));
+	q = buildtree(OROR, q, r);
+	p = buildtree(ANDAND, p, q);
+	tfree(f);
+	tfree(a);
+	return p;
+}
+#endif
+
+/*
+ * Math-specific builtins that expands to constants.
+ * Versins here is for IEEE FP, vax needs its own versions.
+ */
+#ifdef RTOLBYTES
+static char vFLOAT[] = { 0, 0, 0x80, 0x7f };
+static char vDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
+#ifdef LDBL_128
+static char vLDOUBLE[] = { 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f };
+#else /* LDBL_80 */
+static char vLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f };
+#endif
+static char nFLOAT[] = { 0, 0, 0xc0, 0x7f };
+static char nDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
+#ifdef LDBL_128
+static char nLDOUBLE[] = { 0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f };
+#else /* LDBL_80 */
+static char nLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f, 0, 0 };
+#endif
+#else
+static char vFLOAT[] = { 0x7f, 0x80, 0, 0 };
+static char vDOUBLE[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
+#ifdef LDBL_128
+static char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
+#else /* LDBL_80 */
+static char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0 };
+#endif
+static char nFLOAT[] = { 0x7f, 0xc0, 0, 0 };
+static char nDOUBLE[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
+#ifdef LDBL_128
+static char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 };
+#else /* LDBL_80 */
+static char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0 };
+#endif
+#endif
+
+#define VALX(typ,TYP) {						\
+	typ d;							\
+	int x;							\
+	x = MIN(sizeof(n ## TYP), sizeof(d));			\
+	memcpy(&d, v ## TYP, x);				\
+	nfree(f);						\
+	f = block(FCON, NIL, NIL, TYP, NULL, MKAP(TYP));	\
+	f->n_dcon = d;						\
+	return f;						\
+}
+
+static NODE *
+builtin_huge_valf(NODE *f, NODE *a, TWORD rt) VALX(float,FLOAT)
+static NODE *
+builtin_huge_val(NODE *f, NODE *a, TWORD rt) VALX(double,DOUBLE)
+static NODE *
+builtin_huge_vall(NODE *f, NODE *a, TWORD rt) VALX(long double,LDOUBLE)
+
+#define	builtin_inff	builtin_huge_valf
+#define	builtin_inf	builtin_huge_val
+#define	builtin_infl	builtin_huge_vall
+
+#define	NANX(typ,TYP) {							\
+	typ d;								\
+	int x;								\
+	if ((a->n_op == ICON && a->n_sp && a->n_sp->sname[0] == '\0') ||\
+	    (a->n_op == ADDROF && a->n_left->n_op == NAME && 		\
+	     a->n_left->n_sp && a->n_left->n_sp->sname[0] == '\0')) {	\
+		x = MIN(sizeof(n ## TYP), sizeof(d));			\
+		memcpy(&d, n ## TYP, x);				\
+		tfree(a); tfree(f);					\
+		f = block(FCON, NIL, NIL, TYP, NULL, MKAP(TYP));	\
+		f->n_dcon = d;						\
+		return f;						\
+	}								\
+	return buildtree(CALL, f, a);					\
+}
+
+/*
+ * Return NANs, if reasonable.
+ */
+static NODE *
+builtin_nanf(NODE *f, NODE *a, TWORD rt) NANX(float,FLOAT)
+static NODE *
+builtin_nan(NODE *f, NODE *a, TWORD rt) NANX(double,DOUBLE)
+static NODE *
+builtin_nanl(NODE *f, NODE *a, TWORD rt) NANX(long double,LDOUBLE)
+
+/*
+ * Target defines, to implement target versions of the generic builtins
+ */
+#ifndef TARGET_MEMCMP
+#define	builtin_memcmp builtin_unimp
+#endif
+#ifndef TARGET_MEMCPY
+#define	builtin_memcpy builtin_unimp
+#endif
+#ifndef TARGET_MEMSET
+#define	builtin_memset builtin_unimp
+#endif
+
+/* Reasonable type of size_t */
+#ifndef SIZET
+#if SZINT == SZSHORT
+#define	SIZET UNSIGNED
+#elif SZLONG > SZINT
+#define SIZET ULONG
+#else
+#define SIZET UNSIGNED
+#endif
+#endif
+
+static TWORD memcpyt[] = { VOID|PTR, VOID|PTR, SIZET, INT };
+static TWORD memsett[] = { VOID|PTR, INT, SIZET, INT };
+static TWORD allocat[] = { SIZET };
+static TWORD expectt[] = { LONG, LONG };
+static TWORD strcmpt[] = { CHAR|PTR, CHAR|PTR };
+static TWORD strcpyt[] = { CHAR|PTR, CHAR|PTR, INT };
+static TWORD strncpyt[] = { CHAR|PTR, CHAR|PTR, SIZET, INT };
+static TWORD strchrt[] = { CHAR|PTR, INT };
+static TWORD strcspnt[] = { CHAR|PTR, CHAR|PTR };
+static TWORD nant[] = { CHAR|PTR };
+static TWORD bitt[] = { UNSIGNED };
+static TWORD bitlt[] = { ULONG };
+static TWORD ffst[] = { INT };
+
+static const struct bitable {
+	char *name;
+	NODE *(*fun)(NODE *f, NODE *a, TWORD);
+	int narg;
+	TWORD *tp;
+	TWORD rt;
+} bitable[] = {
+	{ "__builtin___memcpy_chk", builtin_unimp, 4, memcpyt, VOID|PTR },
+	{ "__builtin___memmove_chk", builtin_unimp, 4, memcpyt, VOID|PTR },
+	{ "__builtin___memset_chk", builtin_unimp, 4, memsett, VOID|PTR },
+
+	{ "__builtin___strcat_chk", builtin_unimp, 3, strcpyt, CHAR|PTR },
+	{ "__builtin___strcpy_chk", builtin_unimp, 3, strcpyt, CHAR|PTR },
+	{ "__builtin___strncat_chk", builtin_unimp, 4, strncpyt,CHAR|PTR },
+	{ "__builtin___strncpy_chk", builtin_unimp, 4, strncpyt,CHAR|PTR },
+
+	{ "__builtin___printf_chk", builtin_unimp, -1, 0, INT },
+	{ "__builtin___fprintf_chk", builtin_unimp, -1, 0, INT },
+	{ "__builtin___sprintf_chk", builtin_unimp, -1, 0, INT },
+	{ "__builtin___snprintf_chk", builtin_unimp, -1, 0, INT },
+	{ "__builtin___vprintf_chk", builtin_unimp, -1, 0, INT },
+	{ "__builtin___vfprintf_chk", builtin_unimp, -1, 0, INT },
+	{ "__builtin___vsprintf_chk", builtin_unimp, -1, 0, INT },
+	{ "__builtin___vsnprintf_chk", builtin_unimp, -1, 0, INT },
+
+	{ "__builtin_alloca", builtin_alloca, 1, allocat },
+	{ "__builtin_abs", builtin_abs, 1 },
+	{ "__builtin_clz", builtin_unimp_f, 1, bitt, INT },
+	{ "__builtin_ctz", builtin_unimp_f, 1, bitt, INT },
+	{ "__builtin_clzl", builtin_unimp_f, 1, bitlt, INT },
+	{ "__builtin_ctzl", builtin_unimp_f, 1, bitlt, INT },
+	{ "__builtin_ffs", builtin_unimp, 1, ffst, INT },
+
+	{ "__builtin_constant_p", builtin_constant_p, 1 },
+	{ "__builtin_expect", builtin_expect, 2, expectt },
+	{ "__builtin_memcmp", builtin_memcmp, 3, memcpyt, INT },
+	{ "__builtin_memcpy", builtin_memcpy, 3, memcpyt, VOID|PTR },
+	{ "__builtin_memset", builtin_memset, 3, memsett, VOID|PTR },
+	{ "__builtin_huge_valf", builtin_huge_valf, 0 },
+	{ "__builtin_huge_val", builtin_huge_val, 0 },
+	{ "__builtin_huge_vall", builtin_huge_vall, 0 },
+	{ "__builtin_inff", builtin_inff, 0 },
+	{ "__builtin_inf", builtin_inf, 0 },
+	{ "__builtin_infl", builtin_infl, 0 },
+	{ "__builtin_isgreater", builtin_isgreater, 2, NULL, INT },
+	{ "__builtin_isgreaterequal", builtin_isgreaterequal, 2, NULL, INT },
+	{ "__builtin_isless", builtin_isless, 2, NULL, INT },
+	{ "__builtin_islessequal", builtin_islessequal, 2, NULL, INT },
+	{ "__builtin_islessgreater", builtin_islessgreater, 2, NULL, INT },
+	{ "__builtin_isunordered", builtin_isunordered, 2, NULL, INT },
+	{ "__builtin_nanf", builtin_nanf, 1, nant, FLOAT },
+	{ "__builtin_nan", builtin_nan, 1, nant, DOUBLE },
+	{ "__builtin_nanl", builtin_nanl, 1, nant, LDOUBLE },
+	{ "__builtin_object_size", builtin_object_size, 2, memsett, SIZET },
+	{ "__builtin_strcmp", builtin_unimp, 2, strcmpt, INT },
+	{ "__builtin_strcpy", builtin_unimp, 2, strcmpt, CHAR|PTR },
+	{ "__builtin_strchr", builtin_unimp, 2, strchrt, CHAR|PTR },
+	{ "__builtin_strlen", builtin_unimp, 1, strcmpt, SIZET },
+	{ "__builtin_strrchr", builtin_unimp, 2, strchrt, CHAR|PTR },
+	{ "__builtin_strncpy", builtin_unimp, 3, strncpyt, CHAR|PTR },
+	{ "__builtin_strncat", builtin_unimp, 3, strncpyt, CHAR|PTR },
+	{ "__builtin_strcspn", builtin_unimp, 2, strcspnt, SIZET },
+#ifndef TARGET_STDARGS
+	{ "__builtin_stdarg_start", builtin_stdarg_start, 2 },
+	{ "__builtin_va_start", builtin_stdarg_start, 2 },
+	{ "__builtin_va_arg", builtin_va_arg, 2 },
+	{ "__builtin_va_end", builtin_va_end, 1 },
+	{ "__builtin_va_copy", builtin_va_copy, 2 },
+#endif
+#ifdef TARGET_BUILTINS
+	TARGET_BUILTINS
+#endif
+};
+
+/*
+ * Check and cast arguments for builtins.
+ */
+static int
+acnt(NODE *a, int narg, TWORD *tp)
+{
+	NODE *q;
+	TWORD t;
+
+	if (a == NIL)
+		return narg;
+	for (; a->n_op == CM; a = a->n_left, narg--) {
+		if (tp == NULL)
+			continue;
+		q = a->n_right;
+		t = tp[narg-1];
+		if (q->n_type == t)
+			continue;
+		a->n_right = ccast(q, t, 0, NULL, MKAP(BTYPE(t)));
+	}
+
+	/* Last arg is ugly to deal with */
+	if (narg == 1 && tp != NULL) {
+		q = talloc();
+		*q = *a;
+		q = ccast(q, tp[0], 0, NULL, MKAP(BTYPE(tp[0])));
+		*a = *q;
+		nfree(q);
+	}
+	return narg != 1;
+}
+
+NODE *
+builtin_check(NODE *f, NODE *a)
+{
+	const struct bitable *bt;
+	int i;
+
+	for (i = 0; i < (int)(sizeof(bitable)/sizeof(bitable[0])); i++) {
+		bt = &bitable[i];
+		if (strcmp(bt->name, f->n_sp->sname))
+			continue;
+		if (bt->narg >= 0 && acnt(a, bt->narg, bt->tp)) {
+			uerror("wrong argument count to %s", bt->name);
+			return bcon(0);
+		}
+		return (*bt->fun)(f, a, bt->rt);
+	}
+	return NIL;
+}
+#endif
Index: uspace/app/pcc/cc/ccom/ccom.1
===================================================================
--- uspace/app/pcc/cc/ccom/ccom.1	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/ccom.1	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,192 @@
+.\"	$NetBSD$
+.\"	$Id: ccom.1,v 1.9 2010/04/05 13:13:57 reed Exp $
+.\"
+.\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net>
+.\" Permission to use, copy, modify, and/or distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM
+.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND
+.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+.\" THIS SOFTWARE.
+.Dd September 14, 2007
+.Dt CCOM 1
+.Os
+.Sh NAME
+.Nm ccom
+.Nd C compiler
+.Sh SYNOPSIS
+.Nm
+.Op Fl gs
+.Op Fl W Ar flags
+.Op Fl X Ar flags
+.Op Fl x Ar optimizations
+.Op Fl Z Ar flags
+.Op infile
+.Op outfile
+.Sh DESCRIPTION
+The
+.Nm
+utility provides a C compiler.
+The frontend is usually
+.Xr pcc 1 .
+It is
+.Em not
+intended to be run directly.
+.Pp
+.Nm
+reads the C source from
+.Ar infile
+or standard input and writes the assembler source
+to
+.Ar outfile
+or to standard output.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl g
+Enable debugging.
+.\" built into binary, explain stabs?
+.It Fl k
+Generate PIC code.
+.It Fl s
+Print statistics to standard error when complete.
+This includes:
+name table entries, name string size, permanent allocated memory,
+temporary allocated memory, lost memory, argument list unions,
+dimension/function unions, struct/union/enum blocks, inline node count,
+inline control blocks, and permanent symtab entries.
+.\" TODO: explain units for above?
+.It Fl v
+Display version.
+.It Fl W Ar flags
+Report warnings.
+(Do some basic checks.)
+.Em NOTE!
+.Em These are subject to change RSN!
+.Ar flags
+is one or more of the following:
+.Bl -tag -width Ds
+.It Sy error
+Report all warnings as errors.
+.It Sy implicit
+Implies
+.Sy implicit-function-declaration
+and
+.Sy implicit-int .
+.It Sy implicit-function-declaration
+Report if no prototype was declared for a function.
+.It Sy implicit-int
+TODO
+.It Sy missing-prototypes
+TODO
+.It Sy strict-prototypes
+TODO
+.It Sy W
+Enable all warnings.
+.El
+.\"
+.It Fl X Ar flags
+C specific debugging where
+.Ar flags
+is one or more of the following:
+.Bl -tag -width Ds
+.It Sy b
+Building of parse trees
+.It Sy d
+Declarations (using multiple
+.Sy d
+flags gives more output)
+.It Sy e
+Pass1 trees at exit
+.It Sy i
+Initializations
+.It Sy n
+Memory allocations
+.It Sy o
+Turn off optimisations
+.It Sy p
+Prototypes
+.It Sy s
+Inlining
+.It Sy t
+Type conversions
+.It Sy x
+Target-specific flag, used in machine-dependent code
+.El
+.\"
+.It Fl x Ar optimizations
+.Ar optimizations
+is one of the following:
+.\" TODO: reword this, since multiple terms don't go with one -x switch??
+.Bl -tag -width deljumps
+.It Sy deljumps
+Delete redundant jumps and dead code.
+.It Sy ssa
+Convert statements into SSA form for optimization.
+Not yet finished.
+.It Sy tailcall
+Currently not implemented.
+.It Sy temps
+Setting this flag allows variables to be put into registers, for further
+optimization by the register allocator.
+.El
+The
+.Fl x
+flag can be passed multiple times to set different options.
+.\"
+.It Fl Z Ar flags
+Code generator (pass2) specific debugging where
+.Ar flags
+is one or more of the following:
+.Bl -tag -width Ds
+.It Sy b
+Basic block and SSA building
+.It Sy c
+Code printout
+.It Sy e
+Trees when entering pass2
+.It Sy f
+Instruction matcher, may provide much output
+.It Sy n
+Memory allocation
+.It Sy o
+Instruction generator
+.It Sy r
+Register allocator
+.It Sy s
+Shape matching in instruction generator
+.It Sy t
+Type matching in instruction generator
+.It Sy u
+Sethi-Ullman computations
+.It Sy x
+Target-specific flag, used in machine-dependent code
+.El
+.El
+.Sh SEE ALSO
+.Xr as 1 ,
+.Xr cpp 1 ,
+.Xr pcc 1
+.Sh HISTORY
+The
+.Nm
+compiler is based on the original Portable C Compiler by S. C. Johnson,
+written in the late 70's.
+Even though much of the compiler has been rewritten, some of the
+basics still remain.
+About 50% of the frontend code and 80% of the backend code has been
+rewritten.
+Most is written by Anders Magnusson, with the exception of
+the data-flow analysis part and the SSA conversion code which is
+written by Peter A Jonsson, and the Mips port that were written as
+part of a project by undergraduate students at Lulea University of
+Technology.
+.Pp
+This product includes software developed or owned by Caldera
+International, Inc.
Index: uspace/app/pcc/cc/ccom/cgram.y
===================================================================
--- uspace/app/pcc/cc/ccom/cgram.y	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/cgram.y	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,2259 @@
+/*	$Id: cgram.y,v 1.319 2011/01/27 18:00:32 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.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Comments for this grammar file. Ragge 021123
+ *
+ * ANSI support required rewrite of the function header and declaration
+ * rules almost totally.
+ *
+ * The lex/yacc shared keywords are now split from the keywords used
+ * in the rest of the compiler, to simplify use of other frontends.
+ */
+
+/*
+ * At last count, there were 5 shift/reduce and no reduce/reduce conflicts
+ * Four are accounted for;
+ * One is "dangling else"
+ * Two is in attribute parsing
+ * One is in ({ }) parsing
+ */
+
+/*
+ * Token used in C lex/yacc communications.
+ */
+%token	C_STRING	/* a string constant */
+%token	C_ICON		/* an integer constant */
+%token	C_FCON		/* a floating point constant */
+%token	C_NAME		/* an identifier */
+%token	C_TYPENAME	/* a typedef'd name */
+%token	C_ANDAND	/* && */
+%token	C_OROR		/* || */
+%token	C_GOTO		/* unconditional goto */
+%token	C_RETURN	/* return from function */
+%token	C_TYPE		/* a type */
+%token	C_CLASS		/* a storage class */
+%token	C_ASOP		/* assignment ops */
+%token	C_RELOP		/* <=, <, >=, > */
+%token	C_EQUOP		/* ==, != */
+%token	C_DIVOP		/* /, % */
+%token	C_SHIFTOP	/* <<, >> */
+%token	C_INCOP		/* ++, -- */
+%token	C_UNOP		/* !, ~ */
+%token	C_STROP		/* ., -> */
+%token	C_STRUCT
+%token	C_IF
+%token	C_ELSE
+%token	C_SWITCH
+%token	C_BREAK
+%token	C_CONTINUE
+%token	C_WHILE	
+%token	C_DO
+%token	C_FOR
+%token	C_DEFAULT
+%token	C_CASE
+%token	C_SIZEOF
+%token	C_ALIGNOF
+%token	C_ENUM
+%token	C_ELLIPSIS
+%token	C_QUALIFIER
+%token	C_FUNSPEC
+%token	C_ASM
+%token	NOMATCH
+%token	C_TYPEOF	/* COMPAT_GCC */
+%token	C_ATTRIBUTE	/* COMPAT_GCC */
+%token	PCC_OFFSETOF
+
+/*
+ * Precedence
+ */
+%left ','
+%right '=' C_ASOP
+%right '?' ':'
+%left C_OROR
+%left C_ANDAND
+%left '|'
+%left '^'
+%left '&'
+%left C_EQUOP
+%left C_RELOP
+%left C_SHIFTOP
+%left '+' '-'
+%left '*' C_DIVOP
+%right C_UNOP
+%right C_INCOP C_SIZEOF
+%left '[' '(' C_STROP
+%{
+# include "pass1.h"
+# include <stdarg.h>
+# include <string.h>
+# include <stdlib.h>
+
+int fun_inline;	/* Reading an inline function */
+int oldstyle;	/* Current function being defined */
+static struct symtab *xnf;
+extern int enummer, tvaloff, inattr;
+extern struct rstack *rpole;
+static int widestr, alwinl;
+NODE *cftnod;
+static int attrwarn = 1;
+
+#define	NORETYP	SNOCREAT /* no return type, save in unused field in symtab */
+
+       NODE *bdty(int op, ...);
+static void fend(void);
+static void fundef(NODE *tp, NODE *p);
+static void olddecl(NODE *p, NODE *a);
+static struct symtab *init_declarator(NODE *tn, NODE *p, int assign, NODE *a);
+static void resetbc(int mask);
+static void swend(void);
+static void addcase(NODE *p);
+#ifdef GCC_COMPAT
+static void gcccase(NODE *p, NODE *);
+#endif
+static void adddef(void);
+static void savebc(void);
+static void swstart(int, TWORD);
+static void genswitch(int, TWORD, struct swents **, int);
+static char *mkpstr(char *str);
+static struct symtab *clbrace(NODE *);
+static NODE *cmop(NODE *l, NODE *r);
+static NODE *xcmop(NODE *out, NODE *in, NODE *str);
+static void mkxasm(char *str, NODE *p);
+static NODE *xasmop(char *str, NODE *p);
+static int maxstlen(char *str);
+static char *stradd(char *old, char *new);
+static NODE *biop(int op, NODE *l, NODE *r);
+static void flend(void);
+static char * simname(char *s);
+#ifdef GCC_COMPAT
+static NODE *tyof(NODE *);	/* COMPAT_GCC */
+static NODE *voidcon(void);	/* COMPAT_GCC */
+#endif
+static NODE *funargs(NODE *p);
+static void oldargs(NODE *p);
+static void uawarn(NODE *p, char *s);
+static int con_e(NODE *p);
+static void dainit(NODE *d, NODE *a);
+static NODE *tymfix(NODE *p);
+static NODE *namekill(NODE *p, int clr);
+static NODE *aryfix(NODE *p);
+
+#define	TYMFIX(inp) { \
+	NODE *pp = inp; \
+	inp = tymerge(pp->n_left, pp->n_right); \
+	nfree(pp->n_left); nfree(pp); }
+/*
+ * State for saving current switch state (when nested switches).
+ */
+struct savbc {
+	struct savbc *next;
+	int brklab;
+	int contlab;
+	int flostat;
+	int swx;
+} *savbc, *savctx;
+
+%}
+
+%union {
+	int intval;
+	NODE *nodep;
+	struct symtab *symp;
+	struct rstack *rp;
+	char *strp;
+}
+
+	/* define types */
+%start ext_def_list
+
+%type <intval> ifelprefix ifprefix whprefix forprefix doprefix switchpart
+		xbegin
+%type <nodep> e .e term enum_dcl struct_dcl cast_type declarator
+		elist type_sq cf_spec merge_attribs
+		parameter_declaration abstract_declarator initializer
+		parameter_type_list parameter_list addrlbl
+		declaration_specifiers designation
+		specifier_qualifier_list merge_specifiers
+		identifier_list arg_param_list type_qualifier_list
+		designator_list designator xasm oplist oper cnstr funtype
+		typeof attribute attribute_specifier /* COMPAT_GCC */
+		attribute_list attr_spec_list attr_var /* COMPAT_GCC */
+%type <strp>	string C_STRING
+%type <rp>	str_head
+%type <symp>	xnfdeclarator clbrace enum_head
+
+%type <intval>  C_STRUCT C_RELOP C_DIVOP C_SHIFTOP
+		C_ANDAND C_OROR C_STROP C_INCOP C_UNOP C_ASOP C_EQUOP
+
+%type <nodep>   C_TYPE C_QUALIFIER C_ICON C_FCON C_CLASS
+%type <strp>	C_NAME C_TYPENAME
+%%
+
+ext_def_list:	   ext_def_list external_def
+		| { ftnend(); }
+		;
+
+external_def:	   funtype kr_args compoundstmt { fend(); }
+		|  declaration  { blevel = 0; symclear(0); }
+		|  asmstatement ';'
+		|  ';'
+		|  error { blevel = 0; }
+		;
+
+funtype:	  /* no type given */ declarator {
+		    fundef(mkty(INT, 0, MKAP(INT)), $1);
+		    cftnsp->sflags |= NORETYP;
+		}
+		| declaration_specifiers declarator { fundef($1,$2); }
+		;
+
+kr_args:	  /* empty */
+		| arg_dcl_list
+		;
+
+/*
+ * Returns a node pointer or NULL, if no types at all given.
+ * Type trees are checked for correctness and merged into one
+ * type node in typenode().
+ */
+declaration_specifiers:
+		   merge_attribs { $$ = typenode($1); }
+		;
+
+merge_attribs:	   type_sq { $$ = $1; }
+		|  type_sq merge_attribs { $$ = cmop($2, $1); }
+		|  cf_spec { $$ = $1; }
+		|  cf_spec merge_attribs { $$ = cmop($2, $1); }
+		;
+
+type_sq:	   C_TYPE { $$ = $1; }
+		|  C_TYPENAME { 
+			struct symtab *sp = lookup($1, 0);
+			if (sp->stype == ENUMTY) {
+				sp->stype = strmemb(sp->sap)->stype;
+			}
+			$$ = mkty(sp->stype, sp->sdf, sp->sap);
+			$$->n_sp = sp;
+		}
+		|  struct_dcl { $$ = $1; }
+		|  enum_dcl { $$ = $1; }
+		|  C_QUALIFIER { $$ = $1; }
+		|  attribute_specifier { $$ = biop(ATTRIB, $1, 0); }
+		|  typeof { $$ = $1; }
+		;
+
+cf_spec:	   C_CLASS { $$ = $1; }
+		|  C_FUNSPEC { fun_inline = 1;  /* XXX - hack */
+			$$ = block(QUALIFIER, NIL, NIL, 0, 0, 0); }
+		;
+
+typeof:		   C_TYPEOF '(' term ')' { $$ = tyof(eve($3)); }
+		|  C_TYPEOF '(' cast_type ')' { TYMFIX($3); $$ = tyof($3); }
+		;
+
+attribute_specifier :
+		   C_ATTRIBUTE '(' '(' attribute_list ')' ')' { $$ = $4; }
+ /*COMPAT_GCC*/	;
+
+attribute_list:	   attribute
+		|  attribute ',' attribute_list { $$ = cmop($3, $1); }
+		;
+
+attribute:	   {
+#ifdef GCC_COMPAT
+			 $$ = voidcon();
+#endif
+		}
+		|  C_NAME { $$ = bdty(NAME, $1); }
+		|  C_NAME '(' elist ')' {
+			$$ = bdty($3 == NIL ? UCALL : CALL, bdty(NAME, $1), $3);
+		}
+		;
+
+/*
+ * Adds a pointer list to front of the declarators.
+ */
+declarator:	   '*' declarator { $$ = bdty(UMUL, $2); }
+		|  '*' type_qualifier_list declarator {
+			$$ = $2;
+			$$->n_left = $3;
+		}
+		|  C_NAME { $$ = bdty(NAME, $1); }
+		|  '(' attr_spec_list declarator ')' {
+			$$ = $3;
+			$$->n_ap = attr_add($$->n_ap, gcc_attr_parse($2));
+		}
+		|  '(' declarator ')' { $$ = $2; }
+		|  declarator '[' e ']' { $$ = biop(LB, $1, $3); }
+		|  declarator '[' C_CLASS e ']' {
+			if ($3->n_type != STATIC)
+				uerror("bad class keyword");
+			tfree($3); /* XXX - handle */
+			$$ = biop(LB, $1, $4);
+		}
+		|  declarator '[' ']' { $$ = biop(LB, $1, bcon(NOOFFSET)); }
+		|  declarator '[' '*' ']' { $$ = biop(LB, $1, bcon(NOOFFSET)); }
+		|  declarator '(' parameter_type_list ')' {
+			$$ = bdty(CALL, $1, $3);
+		}
+		|  declarator '(' identifier_list ')' {
+			$$ = bdty(CALL, $1, $3);
+			oldstyle = 1;
+		}
+		|  declarator '(' ')' { $$ = bdty(UCALL, $1); }
+		;
+
+type_qualifier_list:
+		   C_QUALIFIER { $$ = $1; $$->n_op = UMUL; }
+		|  type_qualifier_list C_QUALIFIER {
+			$$ = $1;
+			$$->n_qual |= $2->n_qual;
+			nfree($2);
+		}
+		|  attribute_specifier {
+			$$ = block(UMUL, NIL, NIL, 0, 0, gcc_attr_parse($1));
+		}
+		|  type_qualifier_list attribute_specifier {
+			$1->n_ap = attr_add($1->n_ap, gcc_attr_parse($2));
+		}
+		;
+
+identifier_list:   C_NAME { $$ = bdty(NAME, $1); oldargs($$); }
+		|  identifier_list ',' C_NAME {
+			$$ = cmop($1, bdty(NAME, $3));
+			oldargs($$->n_right);
+		}
+		;
+
+/*
+ * Returns as parameter_list, but can add an additional ELLIPSIS node.
+ */
+parameter_type_list:
+		   parameter_list { $$ = $1; }
+		|  parameter_list ',' C_ELLIPSIS {
+			$$ = cmop($1, biop(ELLIPSIS, NIL, NIL));
+		}
+		;
+
+/*
+ * Returns a linked lists of nodes of op CM with parameters on
+ * its right and additional CM nodes of its left pointer.
+ * No CM nodes if only one parameter.
+ */
+parameter_list:	   parameter_declaration { $$ = $1; }
+		|  parameter_list ',' parameter_declaration {
+			$$ = cmop($1, $3);
+		}
+		;
+
+/*
+ * Returns a node pointer to the declaration.
+ */
+parameter_declaration:
+		   declaration_specifiers declarator attr_var {
+			if ($1->n_lval != SNULL && $1->n_lval != REGISTER)
+				uerror("illegal parameter class");
+			$$ = block(TYMERGE, $1, $2, INT, 0, gcc_attr_parse($3));
+		}
+		|  declaration_specifiers abstract_declarator { 
+			$$ = block(TYMERGE, $1, $2, INT, 0, 0);
+		}
+		|  declaration_specifiers {
+			$$ = block(TYMERGE, $1, bdty(NAME, NULL), INT, 0, 0);
+		}
+		;
+
+abstract_declarator:
+		   '*' { $$ = bdty(UMUL, bdty(NAME, NULL)); }
+		|  '*' type_qualifier_list {
+			$$ = $2;
+			$$->n_left = bdty(NAME, NULL);
+		}
+		|  '*' abstract_declarator { $$ = bdty(UMUL, $2); }
+		|  '*' type_qualifier_list abstract_declarator {
+			$$ = $2;
+			$$->n_left = $3;
+		}
+		|  '(' abstract_declarator ')' { $$ = $2; }
+		|  '[' ']' attr_var {
+			$$ = block(LB, bdty(NAME, NULL), bcon(NOOFFSET),
+			    INT, 0, gcc_attr_parse($3));
+		}
+		|  '[' e ']' attr_var {
+			$$ = block(LB, bdty(NAME, NULL), $2,
+			    INT, 0, gcc_attr_parse($4));
+		}
+		|  abstract_declarator '[' ']' attr_var {
+			$$ = block(LB, $1, bcon(NOOFFSET),
+			    INT, 0, gcc_attr_parse($4));
+		}
+		|  abstract_declarator '[' e ']' attr_var {
+			$$ = block(LB, $1, $3, INT, 0, gcc_attr_parse($5));
+		}
+		|  '(' ')' { $$ = bdty(UCALL, bdty(NAME, NULL)); }
+		|  '(' ib2 parameter_type_list ')' {
+			$$ = bdty(CALL, bdty(NAME, NULL), $3);
+		}
+		|  abstract_declarator '(' ')' {
+			$$ = bdty(UCALL, $1);
+		}
+		|  abstract_declarator '(' ib2 parameter_type_list ')' {
+			$$ = bdty(CALL, $1, $4);
+		}
+		;
+
+ib2:		  { }
+		;
+/*
+ * K&R arg declaration, between ) and {
+ */
+arg_dcl_list:	   arg_declaration
+		|  arg_dcl_list arg_declaration
+		;
+
+
+arg_declaration:   declaration_specifiers arg_param_list ';' {
+			nfree($1);
+		}
+		;
+
+arg_param_list:	   declarator attr_var {
+			olddecl(block(TYMERGE, ccopy($<nodep>0), $1,
+			    INT, 0, 0), $2);
+		}
+		|  arg_param_list ',' declarator attr_var {
+			olddecl(block(TYMERGE, ccopy($<nodep>0), $3,
+			    INT, 0, 0), $4);
+		}
+		;
+
+/*
+ * Declarations in beginning of blocks.
+ */
+block_item_list:   block_item
+		|  block_item_list block_item
+		;
+
+block_item:	   declaration
+		|  statement
+		;
+
+/*
+ * Here starts the old YACC code.
+ */
+
+/*
+ * Variables are declared in init_declarator.
+ */
+declaration:	   declaration_specifiers ';' { tfree($1); fun_inline = 0; }
+		|  declaration_specifiers init_declarator_list ';' {
+			tfree($1);
+			fun_inline = 0;
+		}
+		;
+
+/*
+ * Normal declaration of variables. curtype contains the current type node.
+ * Returns nothing, variables are declared in init_declarator.
+ */
+init_declarator_list:
+		   init_declarator { symclear(blevel); }
+		|  init_declarator_list ',' attr_var { $<nodep>$ = $<nodep>0; } init_declarator {
+			uawarn($3, "init_declarator");
+			symclear(blevel);
+		}
+		;
+
+enum_dcl:	   enum_head '{' moe_list optcomma '}' { $$ = enumdcl($1); }
+		|  C_ENUM C_NAME {  $$ = enumref($2); }
+		;
+
+enum_head:	   C_ENUM { $$ = enumhd(NULL); }
+		|  C_ENUM C_NAME {  $$ = enumhd($2); }
+		;
+
+moe_list:	   moe
+		|  moe_list ',' moe
+		;
+
+moe:		   C_NAME {  moedef($1); }
+		|  C_TYPENAME {  moedef($1); }
+		|  C_NAME '=' e { enummer = con_e($3); moedef($1); }
+		|  C_TYPENAME '=' e { enummer = con_e($3); moedef($1); }
+		;
+
+struct_dcl:	   str_head '{' struct_dcl_list '}' {
+			NODE *p;
+
+			$$ = dclstruct($1);
+			if (pragma_allpacked) {
+				p = bdty(CALL, bdty(NAME, "packed"),
+				    bcon(pragma_allpacked));
+				$$ = cmop(biop(ATTRIB, p, 0), $$);
+			}
+		}
+		|  C_STRUCT attr_var C_NAME { 
+			$$ = rstruct($3,$1);
+			uawarn($2, "struct_dcl");
+		}
+ /*COMPAT_GCC*/	|  str_head '{' '}' { $$ = dclstruct($1); }
+		;
+
+attr_var:	   {	
+			NODE *q, *p;
+
+			p = pragma_aligned ? bdty(CALL, bdty(NAME, "aligned"),
+			    bcon(pragma_aligned)) : NIL;
+			if (pragma_packed) {
+				q = bdty(NAME, "packed");
+				p = (p == NIL ? q : cmop(p, q));
+			}
+			pragma_aligned = pragma_packed = 0;
+			$$ = p;
+		}
+ /*COMPAT_GCC*/	|  attr_spec_list
+		;
+
+attr_spec_list:	   attribute_specifier 
+		|  attr_spec_list attribute_specifier { $$ = cmop($1, $2); }
+		;
+
+str_head:	   C_STRUCT attr_var {  $$ = bstruct(NULL, $1, $2);  }
+		|  C_STRUCT attr_var C_NAME {  $$ = bstruct($3, $1, $2);  }
+		;
+
+struct_dcl_list:   struct_declaration
+		|  struct_dcl_list struct_declaration
+		;
+
+struct_declaration:
+		   specifier_qualifier_list struct_declarator_list optsemi {
+			tfree($1);
+		}
+		;
+
+optsemi:	   ';' { }
+		|  optsemi ';' { werror("extra ; in struct"); }
+		;
+
+specifier_qualifier_list:
+		   merge_specifiers { $$ = typenode($1); }
+		;
+
+merge_specifiers:  type_sq merge_specifiers { $$ = cmop($2, $1); }
+		|  type_sq { $$ = $1; }
+		;
+
+struct_declarator_list:
+		   struct_declarator { symclear(blevel); }
+		|  struct_declarator_list ',' { $<nodep>$=$<nodep>0; } 
+			struct_declarator { symclear(blevel); }
+		;
+
+struct_declarator: declarator attr_var {
+			NODE *p;
+
+			$1 = aryfix($1);
+			p = tymerge($<nodep>0, tymfix($1));
+			if ($2)
+				p->n_ap = attr_add(p->n_ap, gcc_attr_parse($2));
+			soumemb(p, (char *)$1->n_sp, 0);
+			tfree(p);
+		}
+		|  ':' e {
+			int ie = con_e($2);
+			if (fldchk(ie))
+				ie = 1;
+			falloc(NULL, ie, $<nodep>0);
+		}
+		|  declarator ':' e {
+			int ie = con_e($3);
+			if (fldchk(ie))
+				ie = 1;
+			if ($1->n_op == NAME) {
+				/* XXX - tymfix() may alter $1 */
+				tymerge($<nodep>0, tymfix($1));
+				soumemb($1, (char *)$1->n_sp, FIELD | ie);
+				nfree($1);
+			} else
+				uerror("illegal declarator");
+		}
+		|  declarator ':' e attr_spec_list {
+			int ie = con_e($3);
+			if (fldchk(ie))
+				ie = 1;
+			if ($1->n_op == NAME) {
+				/* XXX - tymfix() may alter $1 */
+				tymerge($<nodep>0, tymfix($1));
+				if ($4)
+					$1->n_ap = attr_add($1->n_ap,
+					    gcc_attr_parse($4));
+				soumemb($1, (char *)$1->n_sp, FIELD | ie);
+				nfree($1);
+			} else
+				uerror("illegal declarator");
+		}
+		| /* unnamed member */ {
+			NODE *p = $<nodep>0;
+			char *c = permalloc(10);
+
+			if (p->n_type != STRTY && p->n_type != UNIONTY)
+				uerror("bad unnamed member type");
+			snprintf(c, 10, "*%dFAKE", getlab());
+			soumemb(p, c, 0);
+		}
+		;
+
+		/* always preceeded by attributes */
+xnfdeclarator:	   declarator attr_var {
+			$$ = xnf = init_declarator($<nodep>0, $1, 1, $2);
+		}
+		|  declarator C_ASM '(' string ')' {
+			pragma_renamed = newstring($4, strlen($4));
+			$$ = xnf = init_declarator($<nodep>0, $1, 1, NULL);
+		}
+		;
+
+/*
+ * Handles declarations and assignments.
+ * Returns nothing.
+ */
+init_declarator:   declarator attr_var { init_declarator($<nodep>0, $1, 0, $2);}
+		|  declarator C_ASM '(' string ')' attr_var {
+#ifdef GCC_COMPAT
+			pragma_renamed = newstring($4, strlen($4));
+			init_declarator($<nodep>0, $1, 0, $6);
+#else
+			werror("gcc extension");
+			init_declarator($<nodep>0, $1, 0, $6);
+#endif
+		}
+		|  xnfdeclarator '=' e { simpleinit($1, eve($3)); xnf = NULL; }
+		|  xnfdeclarator '=' begbr init_list optcomma '}' {
+			endinit();
+			xnf = NULL;
+		}
+ /*COMPAT_GCC*/	|  xnfdeclarator '=' begbr '}' { endinit(); xnf = NULL; }
+		|  xnfdeclarator '=' addrlbl { simpleinit($1, $3); xnf = NULL; }
+		;
+
+begbr:		   '{' { beginit($<symp>-1); }
+		;
+
+initializer:	   e %prec ',' {  $$ = eve($1); }
+		|  addrlbl {  $$ = $1; }
+		|  ibrace init_list optcomma '}' { $$ = NULL; }
+		|  ibrace '}' { asginit(bcon(0)); $$ = NULL; }
+		;
+
+init_list:	   designation initializer { dainit($1, $2); }
+		|  init_list ','  designation initializer { dainit($3, $4); }
+		;
+
+designation:	   designator_list '=' { desinit($1); $$ = NIL; }
+		|  '[' e C_ELLIPSIS e ']' '=' { $$ = biop(CM, $2, $4); }
+		|  { $$ = NIL; }
+		;
+
+designator_list:   designator { $$ = $1; }
+		|  designator_list designator { $$ = $2; $$->n_left = $1; }
+		;
+
+designator:	   '[' e ']' {
+			int ie = con_e($2);
+			if (ie < 0) {
+				uerror("designator must be non-negative");
+				ie = 0;
+			}
+			$$ = biop(LB, NIL, bcon(ie));
+		}
+		|  C_STROP C_TYPENAME {
+			if ($1 != DOT)
+				uerror("invalid designator");
+			$$ = bdty(NAME, $2);
+		}
+		|  C_STROP C_NAME {
+			if ($1 != DOT)
+				uerror("invalid designator");
+			$$ = bdty(NAME, $2);
+		}
+		;
+
+optcomma	:	/* VOID */
+		|  ','
+		;
+
+ibrace:		   '{' {  ilbrace(); }
+		;
+
+/*	STATEMENTS	*/
+
+compoundstmt:	   begin block_item_list '}' { flend(); }
+		|  begin '}' { flend(); }
+		;
+
+begin:		  '{' {
+			struct savbc *bc = tmpalloc(sizeof(struct savbc));
+			if (blevel == 1) {
+#ifdef STABS
+				if (gflag)
+					stabs_line(lineno);
+#endif
+				dclargs();
+			}
+#ifdef STABS
+			if (gflag && blevel > 1)
+				stabs_lbrac(blevel+1);
+#endif
+			++blevel;
+			oldstyle = 0;
+			bc->contlab = autooff;
+			bc->next = savctx;
+			savctx = bc;
+			bccode();
+			if (!isinlining && sspflag && blevel == 2)
+				sspstart();
+		}
+		;
+
+statement:	   e ';' { ecomp(eve($1)); symclear(blevel); }
+		|  compoundstmt
+		|  ifprefix statement { plabel($1); reached = 1; }
+		|  ifelprefix statement {
+			if ($1 != NOLAB) {
+				plabel( $1);
+				reached = 1;
+			}
+		}
+		|  whprefix statement {
+			branch(contlab);
+			plabel( brklab );
+			if( (flostat&FBRK) || !(flostat&FLOOP))
+				reached = 1;
+			else
+				reached = 0;
+			resetbc(0);
+		}
+		|  doprefix statement C_WHILE '(' e ')' ';' {
+			plabel(contlab);
+			if (flostat & FCONT)
+				reached = 1;
+			if (reached)
+				cbranch(buildtree(NE, eve($5), bcon(0)),
+				    bcon($1));
+			else
+				tfree(eve($5));
+			plabel( brklab);
+			reached = 1;
+			resetbc(0);
+		}
+		|  forprefix .e ')' statement
+			{  plabel( contlab );
+			    if( flostat&FCONT ) reached = 1;
+			    if( $2 ) ecomp( $2 );
+			    branch($1);
+			    plabel( brklab );
+			    if( (flostat&FBRK) || !(flostat&FLOOP) ) reached = 1;
+			    else reached = 0;
+			    resetbc(0);
+			    }
+		| switchpart statement
+			{ if( reached ) branch( brklab );
+			    plabel( $1 );
+			    swend();
+			    plabel( brklab);
+			    if( (flostat&FBRK) || !(flostat&FDEF) ) reached = 1;
+			    resetbc(FCONT);
+			    }
+		|  C_BREAK  ';' {
+			if (brklab == NOLAB)
+				uerror("illegal break");
+			else if (reached)
+				branch(brklab);
+			flostat |= FBRK;
+			reached = 0;
+		}
+		|  C_CONTINUE  ';' {
+			if (contlab == NOLAB)
+				uerror("illegal continue");
+			else
+				branch(contlab);
+			flostat |= FCONT;
+			goto rch;
+		}
+		|  C_RETURN  ';' {
+			branch(retlab);
+			if (cftnsp->stype != VOID && 
+			    (cftnsp->sflags & NORETYP) == 0 &&
+			    cftnsp->stype != VOID+FTN)
+				uerror("return value required");
+			rch:
+			if (!reached)
+				warner(Wunreachable_code, NULL);
+			reached = 0;
+		}
+		|  C_RETURN e  ';' {
+			NODE *p, *q;
+
+			p = nametree(cftnsp);
+			p->n_type = DECREF(p->n_type);
+			q = eve($2);
+#ifndef NO_COMPLEX
+			if (ANYCX(q) || ANYCX(p))
+				q = cxret(q, p);
+#endif
+			p = buildtree(RETURN, p, q);
+			if (p->n_type == VOID) {
+				ecomp(p->n_right);
+			} else {
+				if (cftnod == NIL)
+					cftnod = tempnode(0, p->n_type,
+					    p->n_df, p->n_ap);
+				ecomp(buildtree(ASSIGN,
+				    ccopy(cftnod), p->n_right));
+			}
+			tfree(p->n_left);
+			nfree(p);
+			branch(retlab);
+			reached = 0;
+		}
+		|  C_GOTO C_NAME ';' { gotolabel($2); goto rch; }
+		|  C_GOTO '*' e ';' { ecomp(biop(GOTO, eve($3), NIL)); }
+		|  asmstatement ';'
+		|   ';'
+		|  error  ';'
+		|  error '}'
+		|  label statement
+		;
+
+asmstatement:	   C_ASM mvol '(' string ')' { send_passt(IP_ASM, mkpstr($4)); }
+		|  C_ASM mvol '(' string xasm ')' { mkxasm($4, $5); }
+		;
+
+mvol:		   /* empty */
+		|  C_QUALIFIER { nfree($1); }
+		;
+
+xasm:		   ':' oplist { $$ = xcmop($2, NIL, NIL); }
+		|  ':' oplist ':' oplist { $$ = xcmop($2, $4, NIL); }
+		|  ':' oplist ':' oplist ':' cnstr { $$ = xcmop($2, $4, $6); }
+		;
+
+oplist:		   /* nothing */ { $$ = NIL; }
+		|  oper { $$ = $1; }
+		;
+
+oper:		   string '(' e ')' { $$ = xasmop($1, eve($3)); }
+		|  oper ',' string '(' e ')' {
+			$$ = cmop($1, xasmop($3, eve($5)));
+		}
+		;
+
+cnstr:		   string { $$ = xasmop($1, bcon(0)); }
+		|  cnstr ',' string { $$ = cmop($1, xasmop($3, bcon(0))); }
+                ;
+
+label:		   C_NAME ':' attr_var { deflabel($1, $3); reached = 1; }
+		|  C_TYPENAME ':' attr_var { deflabel($1, $3); reached = 1; }
+		|  C_CASE e ':' { addcase(eve($2)); reached = 1; }
+/* COMPAT_GCC */|  C_CASE e C_ELLIPSIS e ':' {
+#ifdef GCC_COMPAT
+			gcccase(eve($2), eve($4)); reached = 1;
+#endif
+		}
+		|  C_DEFAULT ':' { reached = 1; adddef(); flostat |= FDEF; }
+		;
+
+doprefix:	C_DO {
+			savebc();
+			brklab = getlab();
+			contlab = getlab();
+			plabel(  $$ = getlab());
+			reached = 1;
+		}
+		;
+ifprefix:	C_IF '(' e ')' {
+			cbranch(buildtree(NOT, eve($3), NIL), bcon($$ = getlab()));
+			reached = 1;
+		}
+		;
+ifelprefix:	  ifprefix statement C_ELSE {
+			if (reached)
+				branch($$ = getlab());
+			else
+				$$ = NOLAB;
+			plabel( $1);
+			reached = 1;
+		}
+		;
+
+whprefix:	  C_WHILE  '('  e  ')' {
+			savebc();
+			$3 = eve($3);
+			if ($3->n_op == ICON && $3->n_lval != 0)
+				flostat = FLOOP;
+			plabel( contlab = getlab());
+			reached = 1;
+			brklab = getlab();
+			if (flostat == FLOOP)
+				tfree($3);
+			else
+				cbranch(buildtree(NOT, $3, NIL), bcon(brklab));
+		}
+		;
+forprefix:	  C_FOR  '('  .e  ';' .e  ';' {
+			if ($3)
+				ecomp($3);
+			savebc();
+			contlab = getlab();
+			brklab = getlab();
+			plabel( $$ = getlab());
+			reached = 1;
+			if ($5)
+				cbranch(buildtree(NOT, $5, NIL), bcon(brklab));
+			else
+				flostat |= FLOOP;
+		}
+		|  C_FOR '(' { ++blevel; } declaration .e ';' {
+			blevel--;
+			savebc();
+			contlab = getlab();
+			brklab = getlab();
+			plabel( $$ = getlab());
+			reached = 1;
+			if ($5)
+				cbranch(buildtree(NOT, $5, NIL), bcon(brklab));
+			else
+				flostat |= FLOOP;
+		}
+		;
+
+switchpart:	   C_SWITCH  '('  e ')' {
+			NODE *p;
+			int num;
+			TWORD t;
+
+			savebc();
+			brklab = getlab();
+			$3 = eve($3);
+			if (($3->n_type != BOOL && $3->n_type > ULONGLONG) ||
+			    $3->n_type < CHAR) {
+				uerror("switch expression must have integer "
+				       "type");
+				t = INT;
+			} else {
+				$3 = intprom($3);
+				t = $3->n_type;
+			}
+			p = tempnode(0, t, 0, MKAP(t));
+			num = regno(p);
+			ecomp(buildtree(ASSIGN, p, $3));
+			branch( $$ = getlab());
+			swstart(num, t);
+			reached = 0;
+		}
+		;
+/*	EXPRESSIONS	*/
+.e:		   e { $$ = eve($1); }
+		| 	{ $$=0; }
+		;
+
+elist:		   { $$ = NIL; }
+		|  e %prec ','
+		|  elist  ','  e { $$ = biop(CM, $1, $3); }
+		|  elist  ','  cast_type { /* hack for stdarg */
+			TYMFIX($3);
+			$3->n_op = TYPE;
+			$$ = biop(CM, $1, $3);
+		}
+		;
+
+/*
+ * Precedence order of operators.
+ */
+e:		   e ',' e { $$ = biop(COMOP, $1, $3); }
+		|  e '=' e {  $$ = biop(ASSIGN, $1, $3); }
+		|  e C_ASOP e {  $$ = biop($2, $1, $3); }
+		|  e '?' e ':' e {
+			$$=biop(QUEST, $1, biop(COLON, $3, $5));
+		}
+		|  e '?' ':' e {
+			NODE *p = tempnode(0, $1->n_type, $1->n_df, $1->n_ap);
+			$$ = biop(COLON, ccopy(p), $4);
+			$$=biop(QUEST, biop(ASSIGN, p, $1), $$);
+		}
+		|  e C_OROR e { $$ = biop($2, $1, $3); }
+		|  e C_ANDAND e { $$ = biop($2, $1, $3); }
+		|  e '|' e { $$ = biop(OR, $1, $3); }
+		|  e '^' e { $$ = biop(ER, $1, $3); }
+		|  e '&' e { $$ = biop(AND, $1, $3); }
+		|  e C_EQUOP  e { $$ = biop($2, $1, $3); }
+		|  e C_RELOP e { $$ = biop($2, $1, $3); }
+		|  e C_SHIFTOP e { $$ = biop($2, $1, $3); }
+		|  e '+' e { $$ = biop(PLUS, $1, $3); }
+		|  e '-' e { $$ = biop(MINUS, $1, $3); }
+		|  e C_DIVOP e { $$ = biop($2, $1, $3); }
+		|  e '*' e { $$ = biop(MUL, $1, $3); }
+		|  e '=' addrlbl { $$ = biop(ASSIGN, $1, $3); }
+		|  term
+		;
+
+xbegin:		   begin {
+			$$ = getlab(); getlab(); getlab();
+			branch($$); plabel(($$)+1); }
+		;
+
+addrlbl:	  C_ANDAND C_NAME {
+#ifdef GCC_COMPAT
+			struct symtab *s = lookup($2, SLBLNAME);
+			if (s->soffset == 0)
+				s->soffset = -getlab();
+			$$ = buildtree(ADDROF, nametree(s), NIL);
+#else
+			uerror("gcc extension");
+#endif
+		}
+		;
+
+term:		   term C_INCOP {  $$ = biop($2, $1, bcon(1)); }
+		|  '*' term { $$ = biop(UMUL, $2, NIL); }
+		|  '&' term { $$ = biop(ADDROF, $2, NIL); }
+		|  '-' term { $$ = biop(UMINUS, $2, NIL ); }
+		|  '+' term { $$ = biop(PLUS, $2, bcon(0)); }
+		|  C_UNOP term { $$ = biop($1, $2, NIL); }
+		|  C_INCOP term {
+			$$ = biop($1 == INCR ? PLUSEQ : MINUSEQ, $2, bcon(1));
+		}
+		|  C_SIZEOF xa term { $$ = biop(SZOF, $3, bcon(0)); inattr = $<intval>2; }
+		|  '(' cast_type ')' term  %prec C_INCOP {
+			TYMFIX($2);
+			$$ = biop(CAST, $2, $4);
+		}
+		|  C_SIZEOF xa '(' cast_type ')'  %prec C_SIZEOF {
+			$$ = biop(SZOF, $4, bcon(1));
+			inattr = $<intval>2;
+		}
+		|  C_ALIGNOF xa '(' cast_type ')' {
+			TYMFIX($4);
+			int al = talign($4->n_type, $4->n_ap);
+			$$ = bcon(al/SZCHAR);
+			inattr = $<intval>2;
+			tfree($4);
+		}
+		| '(' cast_type ')' clbrace init_list optcomma '}' {
+			endinit();
+			$$ = bdty(NAME, $4);
+			$$->n_op = CLOP;
+		}
+		| '(' cast_type ')' clbrace '}' {
+			endinit();
+			$$ = bdty(NAME, $4);
+			$$->n_op = CLOP;
+		}
+		|  term '[' e ']' { $$ = biop(LB, $1, $3); }
+		|  C_NAME  '(' elist ')' {
+			$$ = biop($3 ? CALL : UCALL, bdty(NAME, $1), $3);
+		}
+		|  term  '(' elist ')' { $$ = biop($3 ? CALL : UCALL, $1, $3); }
+		|  term C_STROP C_NAME { $$ = biop($2, $1, bdty(NAME, $3)); }
+		|  term C_STROP C_TYPENAME { $$ = biop($2, $1, bdty(NAME, $3));}
+		|  C_NAME %prec C_SIZEOF /* below ( */{ $$ = bdty(NAME, $1); }
+		|  PCC_OFFSETOF  '(' cast_type ',' term ')' {
+			TYMFIX($3);
+			$3->n_type = INCREF($3->n_type);
+			$3 = biop(CAST, $3, bcon(0));
+			if ($5->n_op == NAME) {
+				$$ = biop(STREF, $3, $5);
+			} else {
+				NODE *p = $5;
+				while (p->n_left->n_op != NAME)
+					p = p->n_left;
+				p->n_left = biop(STREF, $3, p->n_left);
+				$$ = $5;
+			}
+			$$ = biop(ADDROF, $$, NIL);
+			$3 = block(NAME, NIL, NIL, ENUNSIGN(INTPTR), 0,
+			    MKAP(ENUNSIGN(INTPTR)));
+			$$ = biop(CAST, $3, $$);
+		}
+		|  C_ICON { $$ = $1; }
+		|  C_FCON { $$ = $1; }
+		|  string { $$ = bdty(STRING, $1, widestr); }
+		|   '('  e  ')' { $$=$2; }
+		|  '(' xbegin block_item_list e ';' '}' ')' {
+			/* XXX - check recursive ({ }) statements */
+			branch(($2)+2);
+			plabel($2);
+			$$ = buildtree(COMOP,
+			    biop(GOTO, bcon(($2)+1), NIL), eve($4));
+			flend();
+		}
+		|  '(' xbegin block_item_list '}' ')' { 
+			/* XXX - check recursive ({ }) statements */
+			branch(($2)+2);
+			plabel($2);
+			$$ = buildtree(COMOP,
+			    biop(GOTO, bcon(($2)+1), NIL), voidcon());
+			flend();
+		}
+		;
+
+xa:		  { $<intval>$ = inattr; inattr = 0; }
+		;
+
+clbrace:	   '{'	{ NODE *q = $<nodep>-1; TYMFIX(q); $$ = clbrace(q); }
+		;
+
+string:		   C_STRING { widestr = 0; $$ = stradd("", $1); }
+		|  string C_STRING { $$ = stradd($1, $2); }
+		;
+
+cast_type:	   specifier_qualifier_list {
+			$$ = biop(TYMERGE, $1, bdty(NAME, NULL));
+		}
+		|  specifier_qualifier_list abstract_declarator {
+			$$ = biop(TYMERGE, $1, aryfix($2));
+		}
+		;
+
+%%
+
+NODE *
+mkty(TWORD t, union dimfun *d, struct attr *sue)
+{
+	return block(TYPE, NIL, NIL, t, d, sue);
+}
+
+NODE *
+bdty(int op, ...)
+{
+	va_list ap;
+	int val;
+	register NODE *q;
+
+	va_start(ap, op);
+	q = biop(op, NIL, NIL);
+
+	switch (op) {
+	case UMUL:
+	case UCALL:
+		q->n_left = va_arg(ap, NODE *);
+		q->n_rval = 0;
+		break;
+
+	case CALL:
+		q->n_left = va_arg(ap, NODE *);
+		q->n_right = va_arg(ap, NODE *);
+		break;
+
+	case LB:
+		q->n_left = va_arg(ap, NODE *);
+		if ((val = va_arg(ap, int)) <= 0) {
+			uerror("array size must be positive");
+			val = 1;
+		}
+		q->n_right = bcon(val);
+		break;
+
+	case NAME:
+		q->n_sp = va_arg(ap, struct symtab *); /* XXX survive tymerge */
+		break;
+
+	case STRING:
+		q->n_name = va_arg(ap, char *);
+		q->n_lval = va_arg(ap, int);
+		break;
+
+	default:
+		cerror("bad bdty");
+	}
+	va_end(ap);
+
+	return q;
+}
+
+static void
+flend(void)
+{
+	if (!isinlining && sspflag && blevel == 2)
+		sspend();
+#ifdef STABS
+	if (gflag && blevel > 2)
+		stabs_rbrac(blevel);
+#endif
+	--blevel;
+	if( blevel == 1 )
+		blevel = 0;
+	symclear(blevel); /* Clean ut the symbol table */
+	if (autooff > maxautooff)
+		maxautooff = autooff;
+	autooff = savctx->contlab;
+	savctx = savctx->next;
+}
+
+static void
+savebc(void)
+{
+	struct savbc *bc = tmpalloc(sizeof(struct savbc));
+
+	bc->brklab = brklab;
+	bc->contlab = contlab;
+	bc->flostat = flostat;
+	bc->next = savbc;
+	savbc = bc;
+	flostat = 0;
+}
+
+static void
+resetbc(int mask)
+{
+	flostat = savbc->flostat | (flostat&mask);
+	contlab = savbc->contlab;
+	brklab = savbc->brklab;
+	savbc = savbc->next;
+}
+
+struct swdef {
+	struct swdef *next;	/* Next in list */
+	int deflbl;		/* Label for "default" */
+	struct swents *ents;	/* Linked sorted list of case entries */
+	int nents;		/* # of entries in list */
+	int num;		/* Node value will end up in */
+	TWORD type;		/* Type of switch expression */
+} *swpole;
+
+/*
+ * add case to switch
+ */
+static void
+addcase(NODE *p)
+{
+	struct swents **put, *w, *sw = tmpalloc(sizeof(struct swents));
+	CONSZ val;
+
+	p = optim(p);  /* change enum to ints */
+	if (p->n_op != ICON || p->n_sp != NULL) {
+		uerror( "non-constant case expression");
+		return;
+	}
+	if (swpole == NULL) {
+		uerror("case not in switch");
+		return;
+	}
+
+	if (DEUNSIGN(swpole->type) != DEUNSIGN(p->n_type)) {
+		val = p->n_lval;
+		p = makety(p, swpole->type, 0, 0, MKAP(swpole->type));
+		if (p->n_op != ICON)
+			cerror("could not cast case value to type of switch "
+			       "expression");
+		if (p->n_lval != val)
+			werror("case expression truncated");
+	}
+	sw->sval = p->n_lval;
+	tfree(p);
+	put = &swpole->ents;
+	if (ISUNSIGNED(swpole->type)) {
+		for (w = swpole->ents;
+		     w != NULL && (U_CONSZ)w->sval < (U_CONSZ)sw->sval;
+		     w = w->next)
+			put = &w->next;
+	} else {
+		for (w = swpole->ents; w != NULL && w->sval < sw->sval;
+		     w = w->next)
+			put = &w->next;
+	}
+	if (w != NULL && w->sval == sw->sval) {
+		uerror("duplicate case in switch");
+		return;
+	}
+	plabel(sw->slab = getlab());
+	*put = sw;
+	sw->next = w;
+	swpole->nents++;
+}
+
+#ifdef GCC_COMPAT
+void
+gcccase(NODE *ln, NODE *hn)
+{
+	CONSZ i, l, h;
+
+	l = icons(optim(ln));
+	h = icons(optim(hn));
+
+	if (h < l)
+		i = l, l = h, h = i;
+
+	for (i = l; i <= h; i++)
+		addcase(xbcon(i, NULL, hn->n_type));
+}
+#endif
+
+/*
+ * add default case to switch
+ */
+static void
+adddef(void)
+{
+	if (swpole == NULL)
+		uerror("default not inside switch");
+	else if (swpole->deflbl != 0)
+		uerror("duplicate default in switch");
+	else
+		plabel( swpole->deflbl = getlab());
+}
+
+static void
+swstart(int num, TWORD type)
+{
+	struct swdef *sw = tmpalloc(sizeof(struct swdef));
+
+	sw->deflbl = sw->nents = 0;
+	sw->ents = NULL;
+	sw->next = swpole;
+	sw->num = num;
+	sw->type = type;
+	swpole = sw;
+}
+
+/*
+ * end a switch block
+ */
+static void
+swend(void)
+{
+	struct swents *sw, **swp;
+	int i;
+
+	sw = tmpalloc(sizeof(struct swents));
+	swp = tmpalloc(sizeof(struct swents *) * (swpole->nents+1));
+
+	sw->slab = swpole->deflbl;
+	swp[0] = sw;
+
+	for (i = 1; i <= swpole->nents; i++) {
+		swp[i] = swpole->ents;
+		swpole->ents = swpole->ents->next;
+	}
+	genswitch(swpole->num, swpole->type, swp, swpole->nents);
+
+	swpole = swpole->next;
+}
+
+/*
+ * num: tempnode the value of the switch expression is in
+ * type: type of the switch expression
+ *
+ * p points to an array of structures, each consisting
+ * of a constant value and a label.
+ * The first is >=0 if there is a default label;
+ * its value is the label number
+ * The entries p[1] to p[n] are the nontrivial cases
+ * n is the number of case statements (length of list)
+ */
+static void
+genswitch(int num, TWORD type, struct swents **p, int n)
+{
+	NODE *r, *q;
+	int i;
+
+	if (mygenswitch(num, type, p, n))
+		return;
+
+	/* simple switch code */
+	for (i = 1; i <= n; ++i) {
+		/* already in 1 */
+		r = tempnode(num, type, 0, MKAP(type));
+		q = xbcon(p[i]->sval, NULL, type);
+		r = buildtree(NE, r, clocal(q));
+		cbranch(buildtree(NOT, r, NIL), bcon(p[i]->slab));
+	}
+	if (p[0]->slab > 0)
+		branch(p[0]->slab);
+}
+
+/*
+ * Declare a variable or prototype.
+ */
+static struct symtab *
+init_declarator(NODE *tn, NODE *p, int assign, NODE *a)
+{
+	int class = tn->n_lval;
+	struct symtab *sp;
+
+	p = aryfix(p);
+	p = tymerge(tn, p);
+	if (a) {
+		struct attr *ap = gcc_attr_parse(a);
+		p->n_ap = attr_add(p->n_ap, ap);
+	}
+
+	p->n_sp = sp = lookup((char *)p->n_sp, 0); /* XXX */
+
+	if (fun_inline && ISFTN(p->n_type))
+		sp->sflags |= SINLINE;
+
+	if (ISFTN(p->n_type) == 0) {
+		if (assign) {
+			defid(p, class);
+			sp = p->n_sp;
+			sp->sflags |= SASG;
+			if (sp->sflags & SDYNARRAY)
+				uerror("can't initialize dynamic arrays");
+			lcommdel(sp);
+		} else
+			nidcl(p, class);
+	} else {
+		extern NODE *parlink;
+		if (assign)
+			uerror("cannot initialise function");
+		defid(p, uclass(class));
+		sp = p->n_sp;
+		if (parlink) {
+			/* dynamic sized arrays in prototypes */
+			tfree(parlink); /* Free delayed tree */
+			parlink = NIL;
+		}
+	}
+	tfree(p);
+	return sp;
+}
+
+/*
+ * Declare old-stype function arguments.
+ */
+static void
+oldargs(NODE *p)
+{
+	blevel++;
+	p->n_op = TYPE;
+	p->n_type = FARG;
+	p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */
+	defid(p, PARAM);
+	blevel--;
+}
+
+/*
+ * Set NAME nodes to a null name and index of LB nodes to NOOFFSET
+ * unless clr is one, in that case preserve variable name.
+ */
+static NODE *
+namekill(NODE *p, int clr)
+{
+	NODE *q;
+	int o = p->n_op;
+
+	switch (coptype(o)) {
+	case LTYPE:
+		if (o == NAME) {
+			if (clr)
+				p->n_sp = NULL;
+			else
+				p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */
+		}
+		break;
+
+	case UTYPE:
+		p->n_left = namekill(p->n_left, clr);
+		break;
+
+        case BITYPE:
+                p->n_left = namekill(p->n_left, clr);
+		if (o == LB) {
+			if (clr) {
+				tfree(p->n_right);
+				p->n_right = bcon(NOOFFSET);
+			} else
+				p->n_right = eve(p->n_right);
+		} else if (o == CALL)
+			p->n_right = namekill(p->n_right, 1);
+		else
+			p->n_right = namekill(p->n_right, clr);
+		if (o == TYMERGE) {
+			q = tymerge(p->n_left, p->n_right);
+			q->n_ap = attr_add(q->n_ap, p->n_ap);
+			tfree(p->n_left);
+			nfree(p);
+			p = q;
+		}
+		break;
+	}
+	return p;
+}
+
+/*
+ * Declare function arguments.
+ */
+static NODE *
+funargs(NODE *p)
+{
+	extern NODE *arrstk[10];
+
+	if (p->n_op == ELLIPSIS)
+		return p;
+
+	p = namekill(p, 0);
+	if (ISFTN(p->n_type))
+		p->n_type = INCREF(p->n_type);
+	if (ISARY(p->n_type)) {
+		p->n_type += (PTR-ARY);
+		if (p->n_df->ddim == -1)
+			tfree(arrstk[0]), arrstk[0] = NIL;
+		p->n_df++;
+	}
+	if (p->n_type == VOID && p->n_sp->sname == NULL)
+		return p; /* sanitycheck later */
+	else if (p->n_sp->sname == NULL)
+		uerror("argument missing");
+	else
+		defid(p, PARAM);
+	return p;
+}
+
+static NODE *
+listfw(NODE *p, NODE * (*f)(NODE *))
+{
+        if (p->n_op == CM) {
+                p->n_left = listfw(p->n_left, f);
+                p->n_right = (*f)(p->n_right);
+        } else
+                p = (*f)(p);
+	return p;
+}
+
+
+/*
+ * Declare a function.
+ */
+static void
+fundef(NODE *tp, NODE *p)
+{
+	extern int prolab;
+	struct symtab *s;
+	NODE *q, *typ;
+	int class = tp->n_lval, oclass, ctval;
+	char *c;
+
+	/*
+	 * We discard all names except for those needed for
+	 * parameter declaration. While doing that, also change
+	 * non-constant array sizes to unknown.
+	 */
+	ctval = tvaloff;
+	for (q = p; coptype(q->n_op) != LTYPE &&
+	    q->n_left->n_op != NAME; q = q->n_left) {
+		if (q->n_op == CALL)
+			q->n_right = namekill(q->n_right, 1);
+	}
+	if (q->n_op != CALL && q->n_op != UCALL) {
+		uerror("invalid function definition");
+		p = bdty(UCALL, p);
+	} else if (q->n_op == CALL) {
+		blevel = 1;
+		argoff = ARGINIT;
+		if (oldstyle == 0)
+			q->n_right = listfw(q->n_right, funargs);
+		ftnarg(q);
+		blevel = 0;
+	}
+
+	p = typ = tymerge(tp, p);
+	s = typ->n_sp = lookup((char *)typ->n_sp, 0); /* XXX */
+
+	oclass = s->sclass;
+	if (class == STATIC && oclass == EXTERN)
+		werror("%s was first declared extern, then static", s->sname);
+
+	if (fun_inline) {
+		/* special syntax for inline functions */
+		if (! strcmp(s->sname,"main")) 
+			uerror("cannot inline main()");
+
+		s->sflags |= SINLINE;
+		inline_start(s);
+		if (class == EXTERN)
+			class = EXTDEF;
+	} else if (class == EXTERN)
+		class = SNULL; /* same result */
+
+	cftnsp = s;
+	defid(p, class);
+#ifdef GCC_COMPAT
+	if (attr_find(p->n_ap, GCC_ATYP_ALW_INL)) {
+		/* Temporary turn on temps to make always_inline work */
+		alwinl = 1;
+		if (xtemps == 0) alwinl |= 2;
+		xtemps = 1;
+	}
+#endif
+	prolab = getlab();
+	if ((c = cftnsp->soname) == NULL)
+		c = addname(exname(cftnsp->sname));
+	send_passt(IP_PROLOG, -1, c, cftnsp->stype,
+	    cftnsp->sclass == EXTDEF, prolab, ctval);
+	blevel++;
+#ifdef STABS
+	if (gflag)
+		stabs_func(s);
+#endif
+	tfree(tp);
+	tfree(p);
+
+}
+
+static void
+fend(void)
+{
+	if (blevel)
+		cerror("function level error");
+	ftnend();
+	fun_inline = 0;
+	if (alwinl & 2) xtemps = 0;
+	alwinl = 0;
+	cftnsp = NULL;
+}
+
+NODE *
+structref(NODE *p, int f, char *name)
+{
+	NODE *r;
+
+	if (f == DOT)
+		p = buildtree(ADDROF, p, NIL);
+	r = biop(NAME, NIL, NIL);
+	r->n_name = name;
+	r = buildtree(STREF, p, r);
+	return r;
+}
+
+static void
+olddecl(NODE *p, NODE *a)
+{
+	struct symtab *s;
+
+	p = namekill(p, 0);
+	s = p->n_sp;
+	if (s->slevel != 1 || s->stype == UNDEF)
+		uerror("parameter '%s' not defined", s->sname);
+	else if (s->stype != FARG)
+		uerror("parameter '%s' redefined", s->sname);
+
+	s->stype = p->n_type;
+	s->sdf = p->n_df;
+	s->sap = p->n_ap;
+	if (ISARY(s->stype)) {
+		s->stype += (PTR-ARY);
+		s->sdf++;
+	}
+	if (a)
+		attr_add(s->sap, gcc_attr_parse(a));
+	nfree(p);
+}
+
+void
+branch(int lbl)
+{
+	int r = reached++;
+	ecomp(biop(GOTO, bcon(lbl), NIL));
+	reached = r;
+}
+
+/*
+ * Create a printable string based on an encoded string.
+ */
+static char *
+mkpstr(char *str)
+{
+	char *s, *os;
+	int v, l = strlen(str)+3; /* \t + \n + \0 */
+
+	os = s = inlalloc(l);
+	*s++ = '\t';
+	for (; *str; ) {
+		if (*str++ == '\\')
+			v = esccon(&str);
+		else
+			v = str[-1];
+		*s++ = v;
+	}
+	*s++ = '\n';
+	*s = 0;
+	return os;
+}
+
+/*
+ * Estimate the max length a string will have in its internal 
+ * representation based on number of \ characters.
+ */
+static int
+maxstlen(char *str)
+{
+	int i;
+
+	for (i = 0; *str; str++, i++)
+		if (*str == '\\' || *str < 32 || *str > 0176)
+			i += 3;
+	return i;
+}
+
+static char *
+voct(char *d, unsigned int v)
+{
+	v &= (1 << SZCHAR) - 1;
+	*d++ = '\\';
+	*d++ = v/64 + '0'; v &= 077;
+	*d++ = v/8 + '0'; v &= 7;
+	*d++ = v + '0';
+	return d;
+}
+	
+
+/*
+ * Convert a string to internal format.  The resulting string may be no
+ * more than len characters long.
+ */
+static void
+fixstr(char *d, char *s, int len)
+{
+	unsigned int v;
+
+	while (*s) {
+		if (len <= 0)
+			cerror("fixstr");
+		if (*s == '\\') {
+			s++;
+			v = esccon(&s);
+			d = voct(d, v);
+			len -= 4;
+		} else if (*s < ' ' || *s > 0176) {
+			d = voct(d, *s++);
+			len -= 4;
+		} else
+			*d++ = *s++, len--;
+	}
+	*d = 0;
+}
+
+/*
+ * Add "raw" string new to cleaned string old.
+ */
+static char *
+stradd(char *old, char *new)
+{
+	char *rv;
+	int len;
+
+	if (*new == 'L' && new[1] == '\"')
+		widestr = 1, new++;
+	if (*new == '\"') {
+		new++;			 /* remove first " */
+		new[strlen(new) - 1] = 0;/* remove last " */
+	}
+	len = strlen(old) + maxstlen(new) + 1;
+	rv = tmpalloc(len);
+	strlcpy(rv, old, len);
+	fixstr(rv + strlen(old), new, maxstlen(new) + 1);
+	return rv;
+}
+
+/*
+ * Fake a symtab entry for compound literals.
+ */
+static struct symtab *
+clbrace(NODE *p)
+{
+	struct symtab *sp;
+
+	sp = getsymtab(simname("cl"), STEMP);
+	sp->stype = p->n_type;
+	sp->squal = p->n_qual;
+	sp->sdf = p->n_df;
+	sp->sap = p->n_ap;
+	tfree(p);
+	if (blevel == 0 && xnf != NULL) {
+		sp->sclass = STATIC;
+		sp->slevel = 2;
+		sp->soffset = getlab();
+	} else {
+		sp->sclass = blevel ? AUTO : STATIC;
+		if (!ISARY(sp->stype) || sp->sdf->ddim != NOOFFSET) {
+			sp->soffset = NOOFFSET;
+			oalloc(sp, &autooff);
+		}
+	}
+	beginit(sp);
+	return sp;
+}
+
+char *
+simname(char *s)
+{
+	int len = strlen(s) + 10 + 1;
+	char *w = tmpalloc(len);
+
+	snprintf(w, len, "%s%d", s, getlab());
+	return w;
+}
+
+NODE *
+biop(int op, NODE *l, NODE *r)
+{
+	return block(op, l, r, INT, 0, MKAP(INT));
+}
+
+static NODE *
+cmop(NODE *l, NODE *r)
+{
+	return biop(CM, l, r);
+}
+
+static NODE *
+voidcon(void)
+{
+	return block(ICON, NIL, NIL, STRTY, 0, MKAP(VOID));
+}
+
+/* Support for extended assembler a' la' gcc style follows below */
+
+static NODE *
+xmrg(NODE *out, NODE *in)
+{
+	NODE *p = in;
+
+	if (p->n_op == XARG) {
+		in = cmop(out, p);
+	} else {
+		while (p->n_left->n_op == CM)
+			p = p->n_left;
+		p->n_left = cmop(out, p->n_left);
+	}
+	return in;
+}
+
+/*
+ * Put together in and out node lists in one list, and balance it with
+ * the constraints on the right side of a CM node.
+ */
+static NODE *
+xcmop(NODE *out, NODE *in, NODE *str)
+{
+	NODE *p, *q;
+
+	if (out) {
+		/* D out-list sanity check */
+		for (p = out; p->n_op == CM; p = p->n_left) {
+			q = p->n_right;
+			if (q->n_name[0] != '=' && q->n_name[0] != '+')
+				uerror("output missing =");
+		}
+		if (p->n_name[0] != '=' && p->n_name[0] != '+')
+			uerror("output missing =");
+		if (in == NIL)
+			p = out;
+		else
+			p = xmrg(out, in);
+	} else if (in) {
+		p = in;
+	} else
+		p = voidcon();
+
+	if (str == NIL)
+		str = voidcon();
+	return cmop(p, str);
+}
+
+/*
+ * Generate a XARG node based on a string and an expression.
+ */
+static NODE *
+xasmop(char *str, NODE *p)
+{
+
+	p = biop(XARG, p, NIL);
+	p->n_name = isinlining ? newstring(str, strlen(str)+1) : str;
+	return p;
+}
+
+/*
+ * Generate a XASM node based on a string and an expression.
+ */
+static void
+mkxasm(char *str, NODE *p)
+{
+	NODE *q;
+
+	q = biop(XASM, p->n_left, p->n_right);
+	q->n_name = isinlining ? newstring(str, strlen(str)+1) : str;
+	nfree(p);
+	ecomp(q);
+}
+
+#ifdef GCC_COMPAT
+static NODE *
+tyof(NODE *p)
+{
+	static struct symtab spp;
+	NODE *q = block(TYPE, NIL, NIL, p->n_type, p->n_df, p->n_ap);
+	q->n_qual = p->n_qual;
+	q->n_sp = &spp; /* for typenode */
+	tfree(p);
+	return q;
+}
+#endif
+
+/*
+ * Traverse an unhandled expression tree bottom-up and call buildtree()
+ * or equivalent as needed.
+ */
+NODE *
+eve(NODE *p)
+{
+	struct symtab *sp;
+	NODE *r, *p1, *p2;
+	int x;
+
+	p1 = p->n_left;
+	p2 = p->n_right;
+	switch (p->n_op) {
+	case NAME:
+		sp = lookup((char *)p->n_sp, 0);
+		if (sp->sflags & SINLINE)
+			inline_ref(sp);
+		r = nametree(sp);
+		if (sp->sflags & SDYNARRAY)
+			r = buildtree(UMUL, r, NIL);
+#ifdef GCC_COMPAT
+		if (attr_find(sp->sap, GCC_ATYP_DEPRECATED))
+			werror("`%s' is deprecated", sp->sname);
+#endif
+		break;
+
+	case DOT:
+	case STREF:
+		r = structref(eve(p1), p->n_op, (char *)p2->n_sp);
+		nfree(p2);
+		break;
+
+	case CAST:
+		p1 = buildtree(CAST, p1, eve(p2));
+		nfree(p1->n_left);
+		r = p1->n_right;
+		nfree(p1);
+		break;
+
+
+	case SZOF:
+		x = xinline; xinline = 0; /* XXX hack */
+		if (p2->n_lval == 0)
+			p1 = eve(p1);
+		else
+			TYMFIX(p1);
+		nfree(p2);
+		r = doszof(p1);
+		xinline = x;
+		break;
+
+	case LB:
+		p1 = eve(p->n_left);
+		r = buildtree(UMUL, buildtree(PLUS, p1, eve(p2)), NIL);
+		break;
+
+	case COMPL:
+#ifndef NO_COMPLEX
+		p1 = eve(p1);
+		if (ANYCX(p1))
+			r = cxconj(p1);
+		else
+			r = buildtree(COMPL, p1, NIL);
+		break;
+#endif
+	case UMINUS:
+	case NOT:
+	case UMUL:
+		r = buildtree(p->n_op, eve(p->n_left), NIL);
+		break;
+
+	case ADDROF:
+		r = eve(p1);
+		if (ISFTN(p->n_type)/* || ISARY(p->n_type) */){
+#ifdef notdef
+			werror( "& before array or function: ignored" );
+#endif
+		} else
+			r = buildtree(ADDROF, r, NIL);
+		break;
+
+	case CALL:
+		p2 = eve(p2);
+		/* FALLTHROUGH */
+	case UCALL:
+		if (p1->n_op == NAME) {
+			sp = lookup((char *)p1->n_sp, 0);
+			if (sp->stype == UNDEF) {
+				p1->n_type = FTN|INT;
+				p1->n_sp = sp;
+				p1->n_ap = MKAP(INT);
+				defid(p1, EXTERN);
+			}
+			nfree(p1);
+#ifdef GCC_COMPAT
+			if (attr_find(sp->sap, GCC_ATYP_DEPRECATED))
+				werror("`%s' is deprecated", sp->sname);
+#endif
+			r = doacall(sp, nametree(sp), p2);
+		} else
+			r = doacall(NULL, eve(p1), p2);
+		break;
+
+#ifndef NO_COMPLEX
+	case XREAL:
+	case XIMAG:
+		p1 = eve(p1);
+		r = cxelem(p->n_op, p1);
+		break;
+#endif
+
+	case MUL:
+	case DIV:
+	case PLUS:
+	case MINUS:
+	case ASSIGN:
+	case EQ:
+	case NE:
+#ifndef NO_COMPLEX
+		p1 = eve(p1);
+		p2 = eve(p2);
+		if (ANYCX(p1) || ANYCX(p2)) {
+			r = cxop(p->n_op, p1, p2);
+		} else if (ISITY(p1->n_type) || ISITY(p2->n_type)) {
+			r = imop(p->n_op, p1, p2);
+		} else
+			r = buildtree(p->n_op, p1, p2);
+		break;
+#endif
+	case MOD:
+	case INCR:
+	case DECR:
+	case CM:
+	case GT:
+	case GE:
+	case LT:
+	case LE:
+	case RS:
+	case LS:
+	case RSEQ:
+	case LSEQ:
+	case AND:
+	case OR:
+	case ER:
+	case OROR:
+	case ANDAND:
+	case EREQ:
+	case OREQ:
+	case ANDEQ:
+	case MINUSEQ:
+	case PLUSEQ:
+	case MULEQ:
+	case DIVEQ:
+	case MODEQ:
+	case QUEST:
+	case COLON:
+		p1 = eve(p1);
+		r = buildtree(p->n_op, p1, eve(p2));
+		break;
+
+	case STRING:
+		r = strend(p->n_lval, p->n_name);
+		break;
+
+	case COMOP:
+		if (p1->n_op == GOTO) {
+			/* inside ({ }), eve already called */
+			r = buildtree(p->n_op, p1, p2);
+		} else {
+			p1 = eve(p1);
+			r = buildtree(p->n_op, p1, eve(p2));
+		}
+		break;
+
+	case TYPE:
+	case ICON:
+	case FCON:
+	case TEMP:
+		return p;
+
+	case CLOP:
+		r = nametree(p->n_sp);
+		break;
+
+	default:
+#ifdef PCC_DEBUG
+		fwalk(p, eprint, 0);
+#endif
+		cerror("eve");
+		r = NIL;
+	}
+	nfree(p);
+	return r;
+}
+
+int
+con_e(NODE *p)
+{
+	return icons(eve(p));
+}
+
+void
+uawarn(NODE *p, char *s)
+{
+	if (p == 0)
+		return;
+	if (attrwarn)
+		werror("unhandled %s attribute", s);
+	tfree(p);
+}
+
+static void
+dainit(NODE *d, NODE *a)
+{
+	if (d == NULL) {
+		asginit(a);
+	} else if (d->n_op == CM) {
+		int is = con_e(d->n_left);
+		int ie = con_e(d->n_right);
+		int i;
+
+		nfree(d);
+		if (ie < is)
+			uerror("negative initializer range");
+		desinit(biop(LB, NIL, bcon(is)));
+		for (i = is; i < ie; i++)
+			asginit(ccopy(a));
+		asginit(a);
+	} else {
+		cerror("dainit");
+	}
+}
+
+/*
+ * Traverse down and tymerge() where appropriate.
+ */
+static NODE *
+tymfix(NODE *p)
+{
+	NODE *q;
+	int o = coptype(p->n_op);
+
+	switch (o) {
+	case LTYPE:
+		break;
+	case UTYPE:
+		p->n_left = tymfix(p->n_left);
+		break;
+	case BITYPE:
+		p->n_left = tymfix(p->n_left);
+		p->n_right = tymfix(p->n_right);
+		if (p->n_op == TYMERGE) {
+			q = tymerge(p->n_left, p->n_right);
+			q->n_ap = attr_add(q->n_ap, p->n_ap);
+			tfree(p->n_left);
+			nfree(p);
+			p = q;
+		}
+		break;
+	}
+	return p;
+}
+
+static NODE *
+aryfix(NODE *p)
+{
+	NODE *q;
+
+	for (q = p; q->n_op != NAME; q = q->n_left) {
+		if (q->n_op == LB) {
+			q->n_right = optim(eve(q->n_right));
+			if ((blevel == 0 || rpole != NULL) &&
+			    !nncon(q->n_right))
+				uerror("array size not constant"); 
+			/*
+			 * Checks according to 6.7.5.2 clause 1:
+			 * "...the expression shall have an integer type."
+			 * "If the expression is a constant expression,	 
+			 * it shall have a value greater than zero."
+			 */
+			if (!ISINTEGER(q->n_right->n_type))
+				werror("array size is not an integer");
+			else if (q->n_right->n_op == ICON &&
+			    q->n_right->n_lval < 0 &&
+			    q->n_right->n_lval != NOOFFSET) {
+					uerror("array size cannot be negative");
+					q->n_right->n_lval = 1;
+			}
+		} else if (q->n_op == CALL)
+			q->n_right = namekill(q->n_right, 1);
+	}
+	return p;
+}
Index: uspace/app/pcc/cc/ccom/gcc_compat.c
===================================================================
--- uspace/app/pcc/cc/ccom/gcc_compat.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/gcc_compat.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,574 @@
+/*      $Id: gcc_compat.c,v 1.77 2011/02/01 14:20:02 ragge Exp $     */
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Routines to support some of the gcc extensions to C.
+ */
+#ifdef GCC_COMPAT
+
+#include "pass1.h"
+#include "cgram.h"
+
+#include <string.h>
+
+static struct kw {
+	char *name, *ptr;
+	int rv;
+} kw[] = {
+/*
+ * Do NOT change the order of these entries unless you know 
+ * what you're doing!
+ */
+/* 0 */	{ "__asm", NULL, C_ASM },
+/* 1 */	{ "__signed", NULL, 0 },
+/* 2 */	{ "__inline", NULL, C_FUNSPEC },
+/* 3 */	{ "__const", NULL, 0 },
+/* 4 */	{ "__asm__", NULL, C_ASM },
+/* 5 */	{ "__inline__", NULL, C_FUNSPEC },
+/* 6 */	{ "__thread", NULL, 0 },
+/* 7 */	{ "__FUNCTION__", NULL, 0 },
+/* 8 */	{ "__volatile", NULL, 0 },
+/* 9 */	{ "__volatile__", NULL, 0 },
+/* 10 */{ "__restrict", NULL, -1 },
+/* 11 */{ "__typeof__", NULL, C_TYPEOF },
+/* 12 */{ "typeof", NULL, C_TYPEOF },
+/* 13 */{ "__extension__", NULL, -1 },
+/* 14 */{ "__signed__", NULL, 0 },
+/* 15 */{ "__attribute__", NULL, 0 },
+/* 16 */{ "__attribute", NULL, 0 },
+/* 17 */{ "__real__", NULL, 0 },
+/* 18 */{ "__imag__", NULL, 0 },
+/* 19 */{ "__builtin_offsetof", NULL, PCC_OFFSETOF },
+/* 20 */{ "__PRETTY_FUNCTION__", NULL, 0 },
+/* 21 */{ "__alignof__", NULL, C_ALIGNOF },
+/* 22 */{ "__typeof", NULL, C_TYPEOF },
+/* 23 */{ "__alignof", NULL, C_ALIGNOF },
+/* 24 */{ "__restrict__", NULL, -1 },
+	{ NULL, NULL, 0 },
+};
+
+/* g77 stuff */
+#if SZFLOAT == SZLONG
+#define G77_INTEGER LONG
+#define G77_UINTEGER ULONG
+#elif SZFLOAT == SZINT
+#define G77_INTEGER INT
+#define G77_UINTEGER UNSIGNED
+#else
+#error fix g77 stuff
+#endif
+#if SZFLOAT*2 == SZLONG
+#define G77_LONGINT LONG
+#define G77_ULONGINT ULONG
+#elif SZFLOAT*2 == SZLONGLONG
+#define G77_LONGINT LONGLONG
+#define G77_ULONGINT ULONGLONG
+#else
+#error fix g77 long stuff
+#endif
+
+static TWORD g77t[] = { G77_INTEGER, G77_UINTEGER, G77_LONGINT, G77_ULONGINT };
+static char *g77n[] = { "__g77_integer", "__g77_uinteger",
+	"__g77_longint", "__g77_ulongint" };
+
+void
+gcc_init()
+{
+	struct kw *kwp;
+	NODE *p;
+	TWORD t;
+	int i;
+
+	for (kwp = kw; kwp->name; kwp++)
+		kwp->ptr = addname(kwp->name);
+
+	for (i = 0; i < 4; i++) {
+		struct symtab *sp;
+		t = ctype(g77t[i]);
+		p = block(NAME, NIL, NIL, t, NULL, MKAP(t));
+		sp = lookup(addname(g77n[i]), 0);
+		p->n_sp = sp;
+		defid(p, TYPEDEF);
+		nfree(p);
+	}
+
+}
+
+#define	TS	"\n#pragma tls\n# %d\n"
+#define	TLLEN	sizeof(TS)+10
+/*
+ * See if a string matches a gcc keyword.
+ */
+int
+gcc_keyword(char *str, NODE **n)
+{
+	extern int inattr, parlvl, parbal;
+	YYSTYPE *yyl = (YYSTYPE *)n; /* XXX should pass yylval */
+	char tlbuf[TLLEN], *tw;
+	struct kw *kwp;
+	int i;
+
+	/* XXX hack, should pass everything in expressions */
+	if (str == kw[21].ptr)
+		return kw[21].rv;
+
+	if (inattr)
+		return 0;
+
+	for (i = 0, kwp = kw; kwp->name; kwp++, i++)
+		if (str == kwp->ptr)
+			break;
+	if (kwp->name == NULL)
+		return 0;
+	if (kwp->rv)
+		return kwp->rv;
+	switch (i) {
+	case 1:  /* __signed */
+	case 14: /* __signed__ */
+		*n = mkty((TWORD)SIGNED, 0, MKAP(SIGNED));
+		return C_TYPE;
+	case 3: /* __const */
+		*n = block(QUALIFIER, NIL, NIL, CON, 0, 0);
+		(*n)->n_qual = CON;
+		return C_QUALIFIER;
+	case 6: /* __thread */
+		snprintf(tlbuf, TLLEN, TS, lineno);
+		tw = &tlbuf[strlen(tlbuf)];
+		while (tw > tlbuf)
+			cunput(*--tw);
+		return -1;
+	case 7: /* __FUNCTION__ */
+	case 20: /* __PRETTY_FUNCTION__ */
+		if (cftnsp == NULL) {
+			uerror("%s outside function", kwp->name);
+			yylval.strp = "";
+		} else
+			yylval.strp = cftnsp->sname; /* XXX - not C99 */
+		return C_STRING;
+	case 8: /* __volatile */
+	case 9: /* __volatile__ */
+		*n = block(QUALIFIER, NIL, NIL, VOL, 0, 0);
+		(*n)->n_qual = VOL;
+		return C_QUALIFIER;
+	case 15: /* __attribute__ */
+	case 16: /* __attribute */
+		inattr = 1;
+		parlvl = parbal;
+		return C_ATTRIBUTE;
+	case 17: /* __real__ */
+		yyl->intval = XREAL;
+		return C_UNOP;
+	case 18: /* __imag__ */
+		yyl->intval = XIMAG;
+		return C_UNOP;
+	}
+	cerror("gcc_keyword");
+	return 0;
+}
+
+#ifndef TARGET_ATTR
+#define	TARGET_ATTR(p, sue)		0
+#endif
+#ifndef	ALMAX
+#define	ALMAX (ALLDOUBLE > ALLONGLONG ? ALLDOUBLE : ALLONGLONG)
+#endif
+
+/* allowed number of args */
+#define	A_0ARG	0x01
+#define	A_1ARG	0x02
+#define	A_2ARG	0x04
+#define	A_3ARG	0x08
+/* arg # is a name */
+#define	A1_NAME	0x10
+#define	A2_NAME	0x20
+#define	A3_NAME	0x40
+#define	A_MANY	0x80
+/* arg # is "string" */
+#define	A1_STR	0x100
+#define	A2_STR	0x200
+#define	A3_STR	0x400
+
+#ifdef __MSC__
+#define	CS(x)
+#else
+#define CS(x) [x] =
+#endif
+
+struct atax {
+	int typ;
+	char *name;
+} atax[GCC_ATYP_MAX] = {
+	CS(ATTR_NONE)		{ 0, NULL },
+	CS(ATTR_COMPLEX)	{ 0, NULL },
+	CS(ATTR_BASETYP)	{ 0, NULL },
+	CS(ATTR_QUALTYP)	{ 0, NULL },
+	CS(ATTR_STRUCT)		{ 0, NULL },
+	CS(GCC_ATYP_ALIGNED)	{ A_0ARG|A_1ARG, "aligned" },
+	CS(GCC_ATYP_PACKED)	{ A_0ARG|A_1ARG, "packed" },
+	CS(GCC_ATYP_SECTION)	{ A_1ARG|A1_STR, "section" },
+	CS(GCC_ATYP_TRANSP_UNION) { A_0ARG, "transparent_union" },
+	CS(GCC_ATYP_UNUSED)	{ A_0ARG, "unused" },
+	CS(GCC_ATYP_DEPRECATED)	{ A_0ARG, "deprecated" },
+	CS(GCC_ATYP_MAYALIAS)	{ A_0ARG, "may_alias" },
+	CS(GCC_ATYP_MODE)	{ A_1ARG|A1_NAME, "mode" },
+	CS(GCC_ATYP_NORETURN)	{ A_0ARG, "noreturn" },
+	CS(GCC_ATYP_FORMAT)	{ A_3ARG|A1_NAME, "format" },
+	CS(GCC_ATYP_NONNULL)	{ A_MANY, "nonnull" },
+	CS(GCC_ATYP_SENTINEL)	{ A_0ARG|A_1ARG, "sentinel" },
+	CS(GCC_ATYP_WEAK)	{ A_0ARG, "weak" },
+	CS(GCC_ATYP_FORMATARG)	{ A_1ARG, "format_arg" },
+	CS(GCC_ATYP_GNU_INLINE)	{ A_0ARG, "gnu_inline" },
+	CS(GCC_ATYP_MALLOC)	{ A_0ARG, "malloc" },
+	CS(GCC_ATYP_NOTHROW)	{ A_0ARG, "nothrow" },
+	CS(GCC_ATYP_CONST)	{ A_0ARG, "const" },
+	CS(GCC_ATYP_PURE)	{ A_0ARG, "pure" },
+	CS(GCC_ATYP_CONSTRUCTOR) { A_0ARG, "constructor" },
+	CS(GCC_ATYP_DESTRUCTOR)	{ A_0ARG, "destructor" },
+	CS(GCC_ATYP_VISIBILITY)	{ A_1ARG|A1_STR, "visibility" },
+	CS(GCC_ATYP_STDCALL)	{ A_0ARG, "stdcall" },
+	CS(GCC_ATYP_CDECL)	{ A_0ARG, "cdecl" },
+	CS(GCC_ATYP_WARN_UNUSED_RESULT) { A_0ARG, "warn_unused_result" },
+	CS(GCC_ATYP_USED)	{ A_0ARG, "used" },
+	CS(GCC_ATYP_NO_INSTR_FUN) { A_0ARG, "no_instrument_function" },
+	CS(GCC_ATYP_NOINLINE)	{ A_0ARG, "noinline" },
+	CS(GCC_ATYP_ALIAS)	{ A_1ARG|A1_STR, "alias" },
+	CS(GCC_ATYP_WEAKREF)	{ A_0ARG|A_1ARG|A1_STR, "weakref" },
+	CS(GCC_ATYP_ALLOCSZ)	{ A_1ARG|A_2ARG, "alloc_size" },
+	CS(GCC_ATYP_ALW_INL)	{ A_0ARG, "always_inline" },
+	CS(GCC_ATYP_TLSMODEL)	{ A_1ARG|A1_STR, "tls_model" },
+	CS(GCC_ATYP_ALIASWEAK)	{ A_1ARG|A1_STR, "aliasweak" },
+
+	CS(GCC_ATYP_BOUNDED)	{ A_3ARG|A_MANY|A1_NAME, "bounded" },
+};
+
+#if SZPOINT(CHAR) == SZLONGLONG
+#define	GPT	LONGLONG
+#else
+#define	GPT	INT
+#endif
+
+struct atax mods[] = {
+	{ 0, NULL },
+	{ INT, "SI" },
+	{ INT, "word" },
+	{ GPT, "pointer" },
+	{ CHAR, "byte" },
+	{ CHAR, "QI" },
+	{ SHORT, "HI" },
+	{ LONGLONG, "DI" },
+	{ FLOAT, "SF" },
+	{ DOUBLE, "DF" },
+	{ LDOUBLE, "XF" },
+	{ FCOMPLEX, "SC" },
+	{ COMPLEX, "DC" },
+	{ LCOMPLEX, "XC" },
+#ifdef TARGET_MODS
+	TARGET_MODS
+#endif
+};
+#define	ATSZ	(sizeof(mods)/sizeof(mods[0]))
+
+static int
+amatch(char *s, struct atax *at, int mx)
+{
+	int i, len;
+
+	if (s[0] == '_' && s[1] == '_')
+		s += 2;
+	len = strlen(s);
+	if (len > 2 && s[len-1] == '_' && s[len-2] == '_')
+		len -= 2;
+	for (i = 0; i < mx; i++) {
+		char *t = at[i].name;
+		if (t != NULL && strncmp(s, t, len) == 0 && t[len] == 0)
+			return i;
+	}
+	return 0;
+}
+
+static void
+setaarg(int str, union aarg *aa, NODE *p)
+{
+	if (str) {
+		if (((str & (A1_STR|A2_STR|A3_STR)) && p->n_op != STRING) ||
+		    ((str & (A1_NAME|A2_NAME|A3_NAME)) && p->n_op != NAME))
+			uerror("bad arg to attribute");
+		if (p->n_op == STRING) {
+			aa->sarg = newstring(p->n_name, strlen(p->n_name)+1);
+		} else
+			aa->sarg = (char *)p->n_sp;
+		nfree(p);
+	} else
+		aa->iarg = (int)icons(eve(p));
+}
+
+/*
+ * Parse attributes from an argument list.
+ */
+static struct attr *
+gcc_attribs(NODE *p)
+{
+	NODE *q, *r;
+	struct attr *ap;
+	char *name = NULL, *c;
+	int cw, attr, narg, i;
+
+	if (p->n_op == NAME) {
+		name = (char *)p->n_sp;
+	} else if (p->n_op == CALL || p->n_op == UCALL) {
+		name = (char *)p->n_left->n_sp;
+	} else if (p->n_op == ICON && p->n_type == STRTY) {
+		return NULL;
+	} else
+		cerror("bad variable attribute");
+
+	if ((attr = amatch(name, atax, GCC_ATYP_MAX)) == 0) {
+		werror("unsupported attribute '%s'", name);
+		ap = NULL;
+		goto out;
+	}
+	narg = 0;
+	if (p->n_op == CALL)
+		for (narg = 1, q = p->n_right; q->n_op == CM; q = q->n_left)
+			narg++;
+
+	cw = atax[attr].typ;
+	if (!(cw & A_MANY) && ((narg > 3) || ((cw & (1 << narg)) == 0))) {
+		uerror("wrong attribute arg count");
+		return NULL;
+	}
+	ap = attr_new(attr, 3); /* XXX should be narg */
+	q = p->n_right;
+
+	switch (narg) {
+	default:
+		/* XXX */
+		while (narg-- > 3) {
+			r = q;
+			q = q->n_left;
+			tfree(r->n_right);
+			nfree(r);
+		}
+		/* FALLTHROUGH */
+	case 3:
+		setaarg(cw & (A3_NAME|A3_STR), &ap->aa[2], q->n_right);
+		r = q;
+		q = q->n_left;
+		nfree(r);
+		/* FALLTHROUGH */
+	case 2:
+		setaarg(cw & (A2_NAME|A2_STR), &ap->aa[1], q->n_right);
+		r = q;
+		q = q->n_left;
+		nfree(r);
+		/* FALLTHROUGH */
+	case 1:
+		setaarg(cw & (A1_NAME|A1_STR), &ap->aa[0], q);
+		p->n_op = UCALL;
+		/* FALLTHROUGH */
+	case 0:
+		break;
+	}
+
+	/* some attributes must be massaged special */
+	switch (attr) {
+	case GCC_ATYP_ALIGNED:
+		if (narg == 0)
+			ap->aa[0].iarg = ALMAX;
+		else
+			ap->aa[0].iarg *= SZCHAR;
+		break;
+	case GCC_ATYP_PACKED:
+		if (narg == 0)
+			ap->aa[0].iarg = 1; /* bitwise align */
+		else
+			ap->aa[0].iarg *= SZCHAR;
+		break;
+
+	case GCC_ATYP_MODE:
+		if ((i = amatch(ap->aa[0].sarg, mods, ATSZ)) == 0)
+			werror("unknown mode arg %s", ap->aa[0].sarg);
+		ap->aa[0].iarg = ctype(mods[i].typ);
+		break;
+
+	case GCC_ATYP_VISIBILITY:
+		c = ap->aa[0].sarg;
+		if (strcmp(c, "default") && strcmp(c, "hidden") &&
+		    strcmp(c, "internal") && strcmp(c, "protected"))
+			werror("unknown visibility %s", c);
+		break;
+
+	case GCC_ATYP_TLSMODEL:
+		c = ap->aa[0].sarg;
+		if (strcmp(c, "global-dynamic") && strcmp(c, "local-dynamic") &&
+		    strcmp(c, "initial-exec") && strcmp(c, "local-exec"))
+			werror("unknown tls model %s", c);
+		break;
+
+	default:
+		break;
+	}
+out:
+	return ap;
+}
+
+/*
+ * Extract attributes from a node tree and return attribute entries 
+ * based on its contents.
+ */
+struct attr *
+gcc_attr_parse(NODE *p)
+{
+	struct attr *b, *c;
+
+	if (p == NIL)
+		return NULL;
+
+	if (p->n_op != CM) {
+		b = gcc_attribs(p);
+		tfree(p);
+	} else {
+		b = gcc_attr_parse(p->n_left);
+		c = gcc_attr_parse(p->n_right);
+		nfree(p);
+		b = b ? attr_add(b, c) : c;
+	}
+	return b;
+}
+
+/*
+ * Fixup struct/unions depending on attributes.
+ */
+void
+gcc_tcattrfix(NODE *p)
+{
+	struct symtab *sp;
+	struct attr *ap;
+	int sz, coff, csz, al;
+
+	if ((ap = attr_find(p->n_ap, GCC_ATYP_PACKED)) == NULL)
+		return; /* nothing to fix */
+
+	al = ap->iarg(0);
+
+	/* Must repack struct */
+	coff = csz = 0;
+	for (sp = strmemb(ap); sp; sp = sp->snext) {
+		if (sp->sclass & FIELD)
+			sz = sp->sclass&FLDSIZ;
+		else
+			sz = (int)tsize(sp->stype, sp->sdf, sp->sap);
+		SETOFF(sz, al);
+		sp->soffset = coff;
+		coff += sz;
+		if (coff > csz)
+			csz = coff;
+		if (p->n_type == UNIONTY)
+			coff = 0;
+	}
+	SETOFF(csz, al); /* Roundup to whatever */
+
+	ap = attr_find(p->n_ap, ATTR_BASETYP);
+	ap->atypsz = csz;
+	ap->aalign = al;
+}
+
+/*
+ * gcc-specific pragmas.
+ */
+int
+pragmas_gcc(char *t)
+{
+	int ign, warn, err, i, u;
+	extern bittype warnary[], werrary[];
+	extern char *flagstr[], *pragstore;
+
+	if (strcmp((t = pragtok(NULL)), "diagnostic") == 0) {
+		ign = warn = err = 0;
+		if (strcmp((t = pragtok(NULL)), "ignored") == 0)
+			ign = 1;
+		else if (strcmp(t, "warning") == 0)
+			warn = 1;
+		else if (strcmp(t, "error") == 0)
+			err = 1;
+		else
+			return 1;
+		if (eat('\"') || eat('-'))
+			return 1;
+		for (t = pragstore; *t && *t != '\"'; t++)
+			;
+		u = *t;
+		*t = 0;
+		for (i = 0; i < NUMW; i++) {
+			if (strcmp(flagstr[i], pragstore+1) != 0)
+				continue;
+			if (err) {
+				BITSET(warnary, i);
+				BITSET(werrary, i);
+			} else if (warn) {
+				BITSET(warnary, i);
+				BITCLEAR(werrary, i);
+			} else {
+				BITCLEAR(warnary, i);
+				BITCLEAR(werrary, i);
+			}
+			return 0;
+		}
+		*t = u;
+	} else if (strcmp(t, "poison") == 0) {
+		/* currently ignore */;
+	} else if (strcmp(t, "visibility") == 0) {
+		/* currently ignore */;
+	} else
+		werror("gcc pragma unsupported");
+	return 0;
+}
+
+#ifdef PCC_DEBUG
+void
+dump_attr(struct attr *ap)
+{
+	printf("attributes; ");
+	for (; ap; ap = ap->next) {
+		if (ap->atype >= GCC_ATYP_MAX) {
+			printf("bad type %d, ", ap->atype);
+		} else if (atax[ap->atype].name == 0) {
+			char *c = ap->atype == ATTR_COMPLEX ? "complex" :
+			    ap->atype == ATTR_BASETYP ? "basetyp" :
+			    ap->atype == ATTR_STRUCT ? "struct" : "badtype";
+			printf("%s, ", c);
+		} else {
+			printf("%s: ", atax[ap->atype].name);
+			printf("%d %d %d, ", ap->iarg(0),
+			    ap->iarg(1), ap->iarg(2));
+		}
+	}
+	printf("\n");
+}
+#endif
+#endif
Index: uspace/app/pcc/cc/ccom/init.c
===================================================================
--- uspace/app/pcc/cc/ccom/init.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/init.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1060 @@
+/*	$Id: init.c,v 1.62 2011/02/19 17:23:39 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004, 2007 Anders Magnusson (ragge@ludd.ltu.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pass1.h"
+#include <string.h>
+
+/*
+ * The following machine-dependent routines may be called during
+ * initialization:
+ * 
+ * zbits(OFFSZ, int)	- sets int bits of zero at position OFFSZ.
+ * infld(CONSZ off, int fsz, CONSZ val)
+ *			- sets the bitfield val starting at off and size fsz.
+ * ninval(CONSZ off, int fsz, NODE *)
+ *			- prints an integer constant which may have
+ *			  a label associated with it, located at off and
+ *			  size fsz.
+ *
+ * Initialization may be of different kind:
+ * - Initialization at compile-time, all values are constants and laid
+ *   out in memory. Static or extern variables outside functions.
+ * - Initialization at run-time, written to their values as code.
+ *
+ * Currently run-time-initialized variables are only initialized by using
+ * move instructions.  An optimization might be to detect that it is
+ * initialized with constants and therefore copied from readonly memory.
+ */
+
+/*
+ * The base element(s) of an initialized variable is kept in a linked 
+ * list, allocated while initialized.
+ *
+ * When a scalar is found, entries are popped of the instk until it's
+ * possible to find an entry for a new scalar; then onstk() is called 
+ * to get the correct type and size of that scalar.
+ *
+ * If a right brace is found, pop the stack until a matching left brace
+ * were found while filling the elements with zeros.  This left brace is
+ * also marking where the current level is for designated initializations.
+ *
+ * Position entries are increased when traversing back down into the stack.
+ */
+
+/*
+ * Good-to-know entries from symtab:
+ *	soffset - # of bits from beginning of this structure.
+ */
+
+/*
+ * TO FIX:
+ * - Alignment of structs on like i386 char members.
+ */
+
+int idebug;
+
+/*
+ * Struct used in array initialisation.
+ */
+static struct instk {
+	struct	instk *in_prev; /* linked list */
+	struct	symtab *in_lnk;	/* member in structure initializations */
+	struct	symtab *in_sym; /* symtab index */
+	union	dimfun *in_df;	/* dimenston of array */
+	TWORD	in_t;		/* type for this level */
+	int	in_n;		/* number of arrays seen so far */
+	int	in_fl;	/* flag which says if this level is controlled by {} */
+} *pstk, pbase;
+
+static struct symtab *csym;
+
+#ifdef PCC_DEBUG
+static void prtstk(struct instk *in);
+#endif
+
+/*
+ * Linked lists for initializations.
+ */
+struct ilist {
+	struct ilist *next;
+	CONSZ off;	/* bit offset of this entry */
+	int fsz;	/* bit size of this entry */
+	NODE *n;	/* node containing this data info */
+};
+
+struct llist {
+	SLIST_ENTRY(llist) next;
+	CONSZ begsz;	/* bit offset of this entry */
+	struct ilist *il;
+};
+static SLIST_HEAD(llh, llist) lpole;
+static CONSZ basesz;
+static int numents; /* # of array entries allocated */
+
+static struct initctx {
+	struct initctx *prev;
+	struct instk *pstk;
+	struct symtab *psym;
+	struct llh lpole;
+	CONSZ basesz;
+	int numents;
+} *inilnk;
+
+static struct ilist *
+getil(struct ilist *next, CONSZ b, int sz, NODE *n)
+{
+	struct ilist *il = tmpalloc(sizeof(struct ilist));
+
+	il->off = b;
+	il->fsz = sz;
+	il->n = n;
+	il->next = next;
+	return il;
+}
+
+/*
+ * Allocate a new struct defining a block of initializers appended to the
+ * end of the llist. Return that entry.
+ */
+static struct llist *
+getll(void)
+{
+	struct llist *ll;
+
+	ll = tmpalloc(sizeof(struct llist));
+	ll->begsz = numents * basesz;
+	ll->il = NULL;
+	SLIST_INSERT_LAST(&lpole, ll, next);
+	numents++;
+	return ll;
+}
+
+/*
+ * Return structure containing off bitnumber.
+ * Allocate more entries, if needed.
+ */
+static struct llist *
+setll(OFFSZ off)
+{
+	struct llist *ll = NULL;
+
+	/* Ensure that we have enough entries */
+	while (off >= basesz * numents)
+		 ll = getll();
+
+	if (ll != NULL && ll->begsz <= off && ll->begsz + basesz > off)
+		return ll;
+
+	SLIST_FOREACH(ll, &lpole, next)
+		if (ll->begsz <= off && ll->begsz + basesz > off)
+			break;
+	return ll; /* ``cannot fail'' */
+}
+
+/*
+ * beginning of initialization; allocate space to store initialized data.
+ * remember storage class for writeout in endinit().
+ * p is the newly declarated type.
+ */
+void
+beginit(struct symtab *sp)
+{
+	struct initctx *ict;
+	struct instk *is = &pbase;
+
+#ifdef PCC_DEBUG
+	if (idebug)
+		printf("beginit(%p), sclass %s\n", sp, scnames(sp->sclass));
+#endif
+
+	if (pstk) {
+#ifdef PCC_DEBUG
+		if (idebug)
+			printf("beginit: saving ctx pstk %p\n", pstk);
+#endif
+		/* save old context */
+		ict = tmpalloc(sizeof(struct initctx));
+		ict->prev = inilnk;
+		inilnk = ict;
+		ict->pstk = pstk;
+		ict->psym = csym;
+		ict->lpole = lpole;
+		ict->basesz = basesz;
+		ict->numents = numents;
+		is = tmpalloc(sizeof(struct instk));
+	}
+	csym = sp;
+
+	numents = 0; /* no entries in array list */
+	if (ISARY(sp->stype)) {
+		basesz = tsize(DECREF(sp->stype), sp->sdf+1, sp->sap);
+		if (basesz == 0) {
+			uerror("array has incomplete type");
+			basesz = SZINT;
+		}
+	} else
+		basesz = tsize(DECREF(sp->stype), sp->sdf, sp->sap);
+	SLIST_INIT(&lpole);
+
+	/* first element */
+	if (ISSOU(sp->stype)) {
+		is->in_lnk = strmemb(sp->sap);
+	} else
+		is->in_lnk = NULL;
+	is->in_n = 0;
+	is->in_t = sp->stype;
+	is->in_sym = sp;
+	is->in_df = sp->sdf;
+	is->in_fl = 0;
+	is->in_prev = NULL;
+	pstk = is;
+}
+
+/*
+ * Push a new entry on the initializer stack.
+ * The new entry will be "decremented" to the new sub-type of the previous
+ * entry when called.
+ * Popping of entries is done elsewhere.
+ */
+static void
+stkpush(void)
+{
+	struct instk *is;
+	struct symtab *sq, *sp;
+	TWORD t;
+
+	if (pstk == NULL) {
+		sp = csym;
+		t = 0;
+	} else {
+		t = pstk->in_t;
+		sp = pstk->in_sym;
+	}
+
+#ifdef PCC_DEBUG
+	if (idebug) {
+		printf("stkpush: '%s' %s ", sp->sname, scnames(sp->sclass));
+		tprint(stdout, t, 0);
+	}
+#endif
+
+	/*
+	 * Figure out what the next initializer will be, and push it on 
+	 * the stack.  If this is an array, just decrement type, if it
+	 * is a struct or union, extract the next element.
+	 */
+	is = tmpalloc(sizeof(struct instk));
+	is->in_fl = 0;
+	is->in_n = 0;
+	if (pstk == NULL) {
+		/* stack empty */
+		is->in_lnk = ISSOU(sp->stype) ? strmemb(sp->sap) : NULL;
+		is->in_t = sp->stype;
+		is->in_sym = sp;
+		is->in_df = sp->sdf;
+	} else if (ISSOU(t)) {
+		sq = pstk->in_lnk;
+		if (sq == NULL) {
+			uerror("excess of initializing elements");
+		} else {
+			is->in_lnk = ISSOU(sq->stype) ? strmemb(sq->sap) : NULL;
+			is->in_t = sq->stype;
+			is->in_sym = sq;
+			is->in_df = sq->sdf;
+		}
+	} else if (ISARY(t)) {
+		is->in_lnk = ISSOU(DECREF(t)) ? strmemb(pstk->in_sym->sap) : 0;
+		is->in_t = DECREF(t);
+		is->in_sym = sp;
+		if (pstk->in_df->ddim != NOOFFSET && pstk->in_df->ddim &&
+		    pstk->in_n >= pstk->in_df->ddim) {
+			werror("excess of initializing elements");
+			pstk->in_n--;
+		}
+		is->in_df = pstk->in_df+1;
+	} else
+		uerror("too many left braces");
+	is->in_prev = pstk;
+	pstk = is;
+
+#ifdef PCC_DEBUG
+	if (idebug) {
+		printf(" newtype ");
+		tprint(stdout, is->in_t, 0);
+		printf("\n");
+	}
+#endif
+}
+
+/*
+ * pop down to either next level that can handle a new initializer or
+ * to the next braced level.
+ */
+static void
+stkpop(void)
+{
+#ifdef PCC_DEBUG
+	if (idebug)
+		printf("stkpop\n");
+#endif
+	for (; pstk; pstk = pstk->in_prev) {
+		if (pstk->in_t == STRTY && pstk->in_lnk != NULL) {
+			pstk->in_lnk = pstk->in_lnk->snext;
+			if (pstk->in_lnk != NULL)
+				break;
+		}
+		if (ISSOU(pstk->in_t) && pstk->in_fl)
+			break; /* need } */
+		if (ISARY(pstk->in_t)) {
+			pstk->in_n++;
+			if (pstk->in_fl)
+				break;
+			if (pstk->in_df->ddim == NOOFFSET ||
+			    pstk->in_n < pstk->in_df->ddim)
+				break; /* ger more elements */
+		}
+	}
+#ifdef PCC_DEBUG
+	if (idebug > 1)
+		prtstk(pstk);
+#endif
+}
+
+/*
+ * Count how many elements an array may consist of.
+ */
+static int
+acalc(struct instk *is, int n)
+{
+	if (is == NULL || !ISARY(is->in_t))
+		return 0;
+	return acalc(is->in_prev, n * is->in_df->ddim) + n * is->in_n;
+}
+
+/*
+ * Find current bit offset of the top element on the stack from
+ * the beginning of the aggregate.
+ */
+static CONSZ
+findoff(void)
+{
+	struct instk *is;
+	OFFSZ off;
+
+#ifdef PCC_DEBUG
+	if (ISARY(pstk->in_t))
+		cerror("findoff on bad type %x", pstk->in_t);
+#endif
+
+	/*
+	 * Offset calculations. If:
+	 * - previous type is STRTY, soffset has in-struct offset.
+	 * - this type is ARY, offset is ninit*stsize.
+	 */
+	for (off = 0, is = pstk; is; is = is->in_prev) {
+		if (is->in_prev && is->in_prev->in_t == STRTY)
+			off += is->in_sym->soffset;
+		if (ISARY(is->in_t)) {
+			/* suesize is the basic type, so adjust */
+			TWORD t = is->in_t;
+			OFFSZ o;
+			while (ISARY(t))
+				t = DECREF(t);
+			if (ISPTR(t)) {
+				o = SZPOINT(t); /* XXX use tsize() */
+			} else {
+				o = tsize(t, is->in_sym->sdf, is->in_sym->sap);
+			}
+			off += o * acalc(is, 1);
+			while (is->in_prev && ISARY(is->in_prev->in_t)) {
+				if (is->in_prev->in_prev &&
+				    is->in_prev->in_prev->in_t == STRTY)
+					off += is->in_sym->soffset;
+				is = is->in_prev;
+			}
+		}
+	}
+#ifdef PCC_DEBUG
+	if (idebug>1) {
+		printf("findoff: off %lld\n", off);
+		prtstk(pstk);
+	}
+#endif
+	return off;
+}
+
+/*
+ * Insert the node p with size fsz at position off.
+ * Bit fields are already dealt with, so a node of correct type
+ * with correct alignment and correct bit offset is given.
+ */
+static void
+nsetval(CONSZ off, int fsz, NODE *p)
+{
+	struct llist *ll;
+	struct ilist *il;
+
+	if (idebug>1)
+		printf("setval: off %lld fsz %d p %p\n", off, fsz, p);
+
+	if (fsz == 0)
+		return;
+
+	ll = setll(off);
+	off -= ll->begsz;
+	if (ll->il == NULL) {
+		ll->il = getil(NULL, off, fsz, p);
+	} else {
+		il = ll->il;
+		if (il->off > off) {
+			ll->il = getil(ll->il, off, fsz, p);
+		} else {
+			for (il = ll->il; il->next; il = il->next)
+				if (il->off <= off && il->next->off > off)
+					break;
+			if (il->off == off) {
+				/* replace */
+				nfree(il->n);
+				il->n = p;
+			} else
+				il->next = getil(il->next, off, fsz, p);
+		}
+	}
+}
+
+/*
+ * take care of generating a value for the initializer p
+ * inoff has the current offset (last bit written)
+ * in the current word being generated
+ * Returns the offset.
+ */
+CONSZ
+scalinit(NODE *p)
+{
+	CONSZ woff;
+	NODE *q;
+	int fsz;
+
+#ifdef PCC_DEBUG
+	if (idebug > 2) {
+		printf("scalinit(%p)\n", p);
+		fwalk(p, eprint, 0);
+		prtstk(pstk);
+	}
+#endif
+
+	if (nerrors)
+		return 0;
+
+	p = optim(p);
+
+#ifdef notdef /* leave to the target to decide if useable */
+	if (csym->sclass != AUTO && p->n_op != ICON &&
+	    p->n_op != FCON && p->n_op != NAME)
+		cerror("scalinit not leaf");
+#endif
+
+	/* Out of elements? */
+	if (pstk == NULL) {
+		uerror("excess of initializing elements");
+		return 0;
+	}
+
+	/*
+	 * Get to the simple type if needed.
+	 */
+	while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) {
+		stkpush();
+		/* If we are doing auto struct init */
+		if (ISSOU(pstk->in_t) && ISSOU(p->n_type) &&
+		    suemeq(pstk->in_sym->sap, p->n_ap))
+			break;
+	}
+
+	if (ISSOU(pstk->in_t) == 0) {
+		/* let buildtree do typechecking (and casting) */
+		q = block(NAME, NIL,NIL, pstk->in_t, pstk->in_df,
+		    pstk->in_sym->sap);
+		p = buildtree(ASSIGN, q, p);
+		nfree(p->n_left);
+		q = optim(p->n_right);
+		nfree(p);
+	} else
+		q = p;
+
+	woff = findoff();
+
+	/* bitfield sizes are special */
+	if (pstk->in_sym->sclass & FIELD)
+		fsz = -(pstk->in_sym->sclass & FLDSIZ);
+	else
+		fsz = (int)tsize(pstk->in_t, pstk->in_sym->sdf,
+		    pstk->in_sym->sap);
+
+	nsetval(woff, fsz, q);
+
+	stkpop();
+#ifdef PCC_DEBUG
+	if (idebug > 2) {
+		printf("scalinit e(%p)\n", q);
+	}
+#endif
+	return woff;
+}
+
+/*
+ * Generate code to insert a value into a bitfield.
+ */
+static void
+insbf(OFFSZ off, int fsz, int val)
+{
+	struct symtab sym;
+	NODE *p, *r;
+	TWORD typ;
+
+#ifdef PCC_DEBUG
+	if (idebug > 1)
+		printf("insbf: off %lld fsz %d val %d\n", off, fsz, val);
+#endif
+
+	if (fsz == 0)
+		return;
+
+	/* small opt: do char instead of bf asg */
+	if ((off & (ALCHAR-1)) == 0 && fsz == SZCHAR)
+		typ = CHAR;
+	else
+		typ = INT;
+	/* Fake a struct reference */
+	p = buildtree(ADDROF, nametree(csym), NIL);
+	sym.stype = typ;
+	sym.squal = 0;
+	sym.sdf = 0;
+	sym.sap = MKAP(typ);
+	sym.soffset = (int)off;
+	sym.sclass = (char)(typ == INT ? FIELD | fsz : MOU);
+	r = xbcon(0, &sym, typ);
+	p = block(STREF, p, r, INT, 0, MKAP(INT));
+	ecode(buildtree(ASSIGN, stref(p), bcon(val)));
+}
+
+/*
+ * Clear a bitfield, starting at off and size fsz.
+ */
+static void
+clearbf(OFFSZ off, OFFSZ fsz)
+{
+	/* Pad up to the next even initializer */
+	if ((off & (ALCHAR-1)) || (fsz < SZCHAR)) {
+		int ba = (int)(((off + (SZCHAR-1)) & ~(SZCHAR-1)) - off);
+		if (ba > fsz)
+			ba = (int)fsz;
+		insbf(off, ba, 0);
+		off += ba;
+		fsz -= ba;
+	}
+	while (fsz >= SZCHAR) {
+		insbf(off, SZCHAR, 0);
+		off += SZCHAR;
+		fsz -= SZCHAR;
+	}
+	if (fsz)
+		insbf(off, fsz, 0);
+}
+
+/*
+ * final step of initialization.
+ * print out init nodes and generate copy code (if needed).
+ */
+void
+endinit(void)
+{
+	struct llist *ll;
+	struct ilist *il;
+	int fsz;
+	OFFSZ lastoff, tbit;
+
+#ifdef PCC_DEBUG
+	if (idebug)
+		printf("endinit()\n");
+#endif
+
+	if (csym->sclass != AUTO)
+		defloc(csym);
+
+	/* Calculate total block size */
+	if (ISARY(csym->stype) && csym->sdf->ddim == NOOFFSET) {
+		tbit = numents*basesz; /* open-ended arrays */
+		csym->sdf->ddim = numents;
+		if (csym->sclass == AUTO) { /* Get stack space */
+			csym->soffset = NOOFFSET;
+			oalloc(csym, &autooff);
+		}
+	} else
+		tbit = tsize(csym->stype, csym->sdf, csym->sap);
+
+	/* Traverse all entries and print'em out */
+	lastoff = 0;
+	SLIST_FOREACH(ll, &lpole, next) {
+		for (il = ll->il; il; il = il->next) {
+#ifdef PCC_DEBUG
+			if (idebug > 1) {
+				printf("off %lld size %d val %lld type ",
+				    ll->begsz+il->off, il->fsz, il->n->n_lval);
+				tprint(stdout, il->n->n_type, 0);
+				printf("\n");
+			}
+#endif
+			fsz = il->fsz;
+			if (csym->sclass == AUTO) {
+				struct symtab sym;
+				NODE *p, *r, *n;
+
+				if (ll->begsz + il->off > lastoff)
+					clearbf(lastoff,
+					    (ll->begsz + il->off) - lastoff);
+
+				/* Fake a struct reference */
+				p = buildtree(ADDROF, nametree(csym), NIL);
+				n = il->n;
+				sym.stype = n->n_type;
+				sym.squal = n->n_qual;
+				sym.sdf = n->n_df;
+				sym.sap = n->n_ap;
+				sym.soffset = (int)(ll->begsz + il->off);
+				sym.sclass = (char)(fsz < 0 ? FIELD | -fsz : 0);
+				r = xbcon(0, &sym, INT);
+				p = block(STREF, p, r, INT, 0, MKAP(INT));
+				ecomp(buildtree(ASSIGN, stref(p), il->n));
+				if (fsz < 0)
+					fsz = -fsz;
+
+			} else {
+				if (ll->begsz + il->off > lastoff)
+					zbits(lastoff,
+					    (ll->begsz + il->off) - lastoff);
+				if (fsz < 0) {
+					fsz = -fsz;
+					infld(il->off, fsz, il->n->n_lval);
+				} else
+					ninval(il->off, fsz, il->n);
+				tfree(il->n);
+			}
+			lastoff = ll->begsz + il->off + fsz;
+		}
+	}
+	if (csym->sclass == AUTO) {
+		clearbf(lastoff, tbit-lastoff);
+	} else
+		zbits(lastoff, tbit-lastoff);
+	
+	endictx();
+}
+
+void
+endictx(void)
+{
+	struct initctx *ict = inilnk;
+
+	if (ict == NULL)
+		return;
+
+	pstk = ict->pstk;
+	csym = ict->psym;
+	lpole = ict->lpole;
+	basesz = ict->basesz;
+	numents = ict->numents;
+	inilnk = inilnk->prev;
+#ifdef PCC_DEBUG
+	if (idebug)
+		printf("endinit: restoring ctx pstk %p\n", pstk);
+#endif
+}
+
+/*
+ * process an initializer's left brace
+ */
+void
+ilbrace()
+{
+
+#ifdef PCC_DEBUG
+	if (idebug)
+		printf("ilbrace()\n");
+#endif
+
+	if (pstk == NULL)
+		return;
+
+	stkpush();
+	pstk->in_fl = 1; /* mark lbrace */
+#ifdef PCC_DEBUG
+	if (idebug > 1)
+		prtstk(pstk);
+#endif
+}
+
+/*
+ * called when a '}' is seen
+ */
+void
+irbrace()
+{
+#ifdef PCC_DEBUG
+	if (idebug)
+		printf("irbrace()\n");
+	if (idebug > 2)
+		prtstk(pstk);
+#endif
+
+	if (pstk == NULL)
+		return;
+
+	/* Got right brace, search for corresponding in the stack */
+	for (; pstk->in_prev != NULL; pstk = pstk->in_prev) {
+		if(!pstk->in_fl)
+			continue;
+
+		/* we have one now */
+
+		pstk->in_fl = 0;  /* cancel { */
+		if (ISARY(pstk->in_t))
+			pstk->in_n = pstk->in_df->ddim;
+		else if (pstk->in_t == STRTY) {
+			while (pstk->in_lnk != NULL &&
+			    pstk->in_lnk->snext != NULL)
+				pstk->in_lnk = pstk->in_lnk->snext;
+		}
+		stkpop();
+		return;
+	}
+}
+
+/*
+ * Create a new init stack based on given elements.
+ */
+static void
+mkstack(NODE *p)
+{
+
+#ifdef PCC_DEBUG
+	if (idebug) {
+		printf("mkstack: %p\n", p);
+		if (idebug > 1 && p)
+			fwalk(p, eprint, 0);
+	}
+#endif
+
+	if (p == NULL)
+		return;
+	mkstack(p->n_left);
+
+	switch (p->n_op) {
+	case LB: /* Array index */
+		if (p->n_right->n_op != ICON)
+			cerror("mkstack");
+		if (!ISARY(pstk->in_t))
+			uerror("array indexing non-array");
+		pstk->in_n = (int)p->n_right->n_lval;
+		nfree(p->n_right);
+		break;
+
+	case NAME:
+		if (pstk->in_lnk) {
+			for (; pstk->in_lnk; pstk->in_lnk = pstk->in_lnk->snext)
+				if (pstk->in_lnk->sname == (char *)p->n_sp)
+					break;
+			if (pstk->in_lnk == NULL)
+				uerror("member missing");
+		} else {
+			uerror("not a struct/union");
+		}
+		break;
+	default:
+		cerror("mkstack2");
+	}
+	nfree(p);
+	stkpush();
+
+}
+
+/*
+ * Initialize a specific element, as per C99.
+ */
+void
+desinit(NODE *p)
+{
+	int op = p->n_op;
+
+	if (pstk == NULL)
+		stkpush(); /* passed end of array */
+	while (pstk->in_prev && pstk->in_fl == 0)
+		pstk = pstk->in_prev; /* Empty stack */
+
+	if (ISSOU(pstk->in_t))
+		pstk->in_lnk = strmemb(pstk->in_sym->sap);
+
+	mkstack(p);	/* Setup for assignment */
+
+	/* pop one step if SOU, ilbrace will push */
+	if (op == NAME || op == LB)
+		pstk = pstk->in_prev;
+
+#ifdef PCC_DEBUG
+	if (idebug > 1) {
+		printf("desinit e\n");
+		prtstk(pstk);
+	}
+#endif
+}
+
+/*
+ * Convert a string to an array of char/wchar for asginit.
+ */
+static void
+strcvt(NODE *p)
+{
+	NODE *q = p;
+	char *s;
+	int i;
+
+#ifdef mach_arm
+	/* XXX */
+	if (p->n_op == UMUL && p->n_left->n_op == ADDROF)
+		p = p->n_left->n_left;
+#endif
+
+	for (s = p->n_sp->sname; *s != 0; ) {
+		if (*s++ == '\\') {
+			i = esccon(&s);  
+		} else
+			i = (unsigned char)s[-1];
+		asginit(bcon(i));
+	} 
+	tfree(q);
+}
+
+/*
+ * Do an assignment to a struct element.
+ */
+void
+asginit(NODE *p)
+{
+	int g;
+
+#ifdef PCC_DEBUG
+	if (idebug)
+		printf("asginit %p\n", p);
+	if (idebug > 1 && p)
+		fwalk(p, eprint, 0);
+#endif
+
+	/* convert string to array of char/wchar */
+	if (p && (DEUNSIGN(p->n_type) == ARY+CHAR ||
+	    p->n_type == ARY+WCHAR_TYPE)) {
+		TWORD t;
+
+		t = p->n_type == ARY+WCHAR_TYPE ? ARY+WCHAR_TYPE : ARY+CHAR;
+		/*
+		 * ...but only if next element is ARY+CHAR, otherwise 
+		 * just fall through.
+		 */
+
+		/* HACKHACKHACK */
+		struct instk *is = pstk;
+
+		if (pstk == NULL)
+			stkpush();
+		while (ISSOU(pstk->in_t) || ISARY(pstk->in_t))
+			stkpush();
+		if (pstk->in_prev && 
+		    (DEUNSIGN(pstk->in_prev->in_t) == t ||
+		    pstk->in_prev->in_t == t)) {
+			pstk = pstk->in_prev;
+			if ((g = pstk->in_fl) == 0)
+				pstk->in_fl = 1; /* simulate ilbrace */
+
+			strcvt(p);
+			if (g == 0)
+				irbrace(); /* will fill with zeroes */
+			return;
+		} else
+			pstk = is; /* no array of char */
+		/* END HACKHACKHACK */
+	}
+
+	if (p == NULL) { /* only end of compound stmt */
+		irbrace();
+	} else /* assign next element */
+		scalinit(p);
+}
+
+#ifdef PCC_DEBUG
+void
+prtstk(struct instk *in)
+{
+	int i, o = 0;
+
+	printf("init stack:\n");
+	for (; in != NULL; in = in->in_prev) {
+		for (i = 0; i < o; i++)
+			printf("  ");
+		printf("%p) '%s' ", in, in->in_sym->sname);
+		tprint(stdout, in->in_t, 0);
+		printf(" %s ", scnames(in->in_sym->sclass));
+		if (in->in_df /* && in->in_df->ddim */)
+		    printf("arydim=%d ", in->in_df->ddim);
+		printf("ninit=%d ", in->in_n);
+		if (BTYPE(in->in_t) == STRTY || ISARY(in->in_t))
+			printf("stsize=%d ",
+			    (int)tsize(in->in_t, in->in_df, in->in_sym->sap));
+		if (in->in_fl) printf("{ ");
+		printf("soff=%d ", in->in_sym->soffset);
+		if (in->in_t == STRTY) {
+			if (in->in_lnk)
+				printf("curel %s ", in->in_lnk->sname);
+			else
+				printf("END struct");
+		}
+		printf("\n");
+		o++;
+	}
+}
+#endif
+
+/*
+ * Do a simple initialization.
+ * At block 0, just print out the value, at higher levels generate
+ * appropriate code.
+ */
+void
+simpleinit(struct symtab *sp, NODE *p)
+{
+	NODE *q, *r, *nt;
+	TWORD t;
+	int sz;
+
+	/* May be an initialization of an array of char by a string */
+	if ((DEUNSIGN(p->n_type) == ARY+CHAR &&
+	    DEUNSIGN(sp->stype) == ARY+CHAR) ||
+	    (DEUNSIGN(p->n_type) == DEUNSIGN(ARY+WCHAR_TYPE) &&
+	    DEUNSIGN(sp->stype) == DEUNSIGN(ARY+WCHAR_TYPE))) {
+		/* Handle "aaa" as { 'a', 'a', 'a' } */
+		beginit(sp);
+		strcvt(p);
+		if (csym->sdf->ddim == NOOFFSET)
+			scalinit(bcon(0)); /* Null-term arrays */
+		endinit();
+		return;
+	}
+
+	nt = nametree(sp);
+	switch (sp->sclass) {
+	case STATIC:
+	case EXTDEF:
+		q = nt;
+#ifndef NO_COMPLEX
+		if (ANYCX(q) || ANYCX(p)) {
+			r = cxop(ASSIGN, q, p);
+			/* XXX must unwind the code generated here */
+			/* We can rely on correct code generated */
+			p = r->n_left->n_right->n_left;
+			r->n_left->n_right->n_left = bcon(0);
+			tfree(r);
+			defloc(sp);
+			r = p->n_left->n_right;
+			sz = (int)tsize(r->n_type, r->n_df, r->n_ap);
+			ninval(0, sz, r);
+			ninval(0, sz, p->n_right->n_right);
+			tfree(p);
+			break;
+		}
+#endif
+		p = optim(buildtree(ASSIGN, nt, p));
+		defloc(sp);
+		q = p->n_right;
+		t = q->n_type;
+		sz = (int)tsize(t, q->n_df, q->n_ap);
+		ninval(0, sz, q);
+		tfree(p);
+		break;
+
+	case AUTO:
+	case REGISTER:
+		if (ISARY(sp->stype))
+			cerror("no array init");
+		q = nt;
+#ifndef NO_COMPLEX
+
+		if (ANYCX(q) || ANYCX(p))
+			r = cxop(ASSIGN, q, p);
+		else
+#endif
+			r = buildtree(ASSIGN, q, p);
+		ecomp(r);
+		break;
+
+	default:
+		uerror("illegal initialization");
+	}
+}
Index: uspace/app/pcc/cc/ccom/inline.c
===================================================================
--- uspace/app/pcc/cc/ccom/inline.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/inline.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,538 @@
+/*	$Id: inline.c,v 1.37.2.2 2011/02/26 11:31:45 ragge Exp $	*/
+/*
+ * Copyright (c) 2003, 2008 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "pass1.h"
+
+#include <stdarg.h>
+
+/*
+ * Simple description of how the inlining works:
+ * A function found with the keyword "inline" is always saved.
+ * If it also has the keyword "extern" it is written out thereafter.
+ * If it has the keyword "static" it will be written out if it is referenced.
+ * inlining will only be done if -xinline is given, and only if it is 
+ * possible to inline the function.
+ */
+static void printip(struct interpass *pole);
+
+struct ntds {
+	int temp;
+	TWORD type;
+	union dimfun *df;
+	struct attr *attr;
+};
+
+/*
+ * ilink from ipole points to the next struct in the list of functions.
+ */
+static struct istat {
+	SLIST_ENTRY(istat) link;
+	struct symtab *sp;
+	int flags;
+#define	CANINL	1	/* function is possible to inline */
+#define	WRITTEN	2	/* function is written out */
+#define	REFD	4	/* Referenced but not yet written out */
+	struct ntds *nt;/* Array of arg temp type data */
+	int nargs;	/* number of args in array */
+	int retval;	/* number of return temporary, if any */
+	struct interpass shead;
+} *cifun;
+
+static SLIST_HEAD(, istat) ipole = { NULL, &ipole.q_forw };
+static int nlabs;
+
+#define	IP_REF	(MAXIP+1)
+#ifdef PCC_DEBUG
+#define	SDEBUG(x)	if (sdebug) printf x
+#else
+#define	SDEBUG(x)
+#endif
+
+int isinlining;
+int inlnodecnt, inlstatcnt;
+
+#define	SZSI	sizeof(struct istat)
+#define	ialloc() memset(permalloc(SZSI), 0, SZSI); inlstatcnt++
+
+static void
+tcnt(NODE *p, void *arg)
+{
+	inlnodecnt++;
+	if (nlabs > 1 && (p->n_op == REG || p->n_op == OREG) &&
+	    regno(p) == FPREG)
+		SLIST_FIRST(&ipole)->flags &= ~CANINL; /* no stack refs */
+	if (p->n_op == NAME || p->n_op == ICON)
+		p->n_sp = NULL; /* let symtabs be freed for inline funcs */
+	if (nflag)
+		printf("locking node %p\n", p);
+}
+
+static struct istat *
+findfun(struct symtab *sp)
+{
+	struct istat *is;
+
+	SLIST_FOREACH(is, &ipole, link)
+		if (is->sp == sp)
+			return is;
+	return NULL;
+}
+
+static void
+refnode(struct symtab *sp)
+{
+	struct interpass *ip;
+
+	SDEBUG(("refnode(%s)\n", sp->sname));
+
+	ip = permalloc(sizeof(*ip));
+	ip->type = IP_REF;
+	ip->ip_name = (char *)sp;
+	inline_addarg(ip);
+}
+
+void
+inline_addarg(struct interpass *ip)
+{
+	extern NODE *cftnod;
+
+	SDEBUG(("inline_addarg(%p)\n", ip));
+	DLIST_INSERT_BEFORE(&cifun->shead, ip, qelem);
+	if (ip->type == IP_DEFLAB)
+		nlabs++;
+	if (ip->type == IP_NODE)
+		walkf(ip->ip_node, tcnt, 0); /* Count as saved */
+	if (cftnod)
+		cifun->retval = regno(cftnod);
+}
+
+/*
+ * Called to setup for inlining of a new function.
+ */
+void
+inline_start(struct symtab *sp)
+{
+	struct istat *is;
+
+	SDEBUG(("inline_start(\"%s\")\n", sp->sname));
+
+	if (isinlining)
+		cerror("already inlining function");
+
+	if ((is = findfun(sp)) != 0) {
+		if (!DLIST_ISEMPTY(&is->shead, qelem))
+			uerror("inline function already defined");
+	} else {
+		is = ialloc();
+		is->sp = sp;
+		SLIST_INSERT_FIRST(&ipole, is, link);
+		DLIST_INIT(&is->shead, qelem);
+	}
+	cifun = is;
+	nlabs = 0;
+	isinlining++;
+}
+
+/*
+ * End of an inline function. In C99 an inline function declared "extern"
+ * should also have external linkage and are therefore printed out.
+ * But; this is the opposite for gcc inline functions, hence special
+ * care must be taken to handle that specific case.
+ */
+void
+inline_end()
+{
+
+	SDEBUG(("inline_end()\n"));
+
+	if (sdebug)printip(&cifun->shead);
+	isinlining = 0;
+
+	if (attr_find(cifun->sp->sap, GCC_ATYP_GNU_INLINE)) {
+		if (cifun->sp->sclass == EXTDEF)
+			cifun->sp->sclass = 0;
+		else
+			cifun->sp->sclass = EXTDEF;
+	}
+
+	if (cifun->sp->sclass == EXTDEF) {
+		cifun->flags |= REFD;
+		inline_prtout();
+	}
+}
+
+/*
+ * Called when an inline function is found, to be sure that it will
+ * be written out.
+ * The function may not be defined when inline_ref() is called.
+ */
+void
+inline_ref(struct symtab *sp)
+{
+	struct istat *w;
+
+	SDEBUG(("inline_ref(\"%s\")\n", sp->sname));
+	if (sp->sclass == SNULL)
+		return; /* only inline, no references */
+	if (isinlining) {
+		refnode(sp);
+	} else {
+		SLIST_FOREACH(w,&ipole, link) {
+			if (w->sp != sp)
+				continue;
+			w->flags |= REFD;
+			return;
+		}
+		/* function not yet defined, print out when found */
+		w = ialloc();
+		w->sp = sp;
+		w->flags |= REFD;
+		SLIST_INSERT_FIRST(&ipole, w, link);
+		DLIST_INIT(&w->shead, qelem);
+	}
+}
+
+static void
+puto(struct istat *w)
+{
+	struct interpass_prolog *ipp, *epp, *pp;
+	struct interpass *ip, *nip;
+	extern int crslab;
+	int lbloff = 0;
+
+	/* Copy the saved function and print it out */
+	ipp = 0; /* XXX data flow analysis */
+	DLIST_FOREACH(ip, &w->shead, qelem) {
+		switch (ip->type) {
+		case IP_EPILOG:
+		case IP_PROLOG:
+			if (ip->type == IP_PROLOG) {
+				ipp = (struct interpass_prolog *)ip;
+				/* fix label offsets */
+				lbloff = crslab - ipp->ip_lblnum;
+			} else {
+				epp = (struct interpass_prolog *)ip;
+				crslab += (epp->ip_lblnum - ipp->ip_lblnum);
+			}
+			pp = tmpalloc(sizeof(struct interpass_prolog));
+			memcpy(pp, ip, sizeof(struct interpass_prolog));
+			pp->ip_lblnum += lbloff;
+#ifdef PCC_DEBUG
+			if (ip->type == IP_EPILOG && crslab != pp->ip_lblnum)
+				cerror("puto: %d != %d", crslab, pp->ip_lblnum);
+#endif
+			pass2_compile((struct interpass *)pp);
+			break;
+
+		case IP_REF:
+			inline_ref((struct symtab *)ip->ip_name);
+			break;
+
+		default:
+			nip = tmpalloc(sizeof(struct interpass));
+			*nip = *ip;
+			if (nip->type == IP_NODE) {
+				NODE *p;
+
+				p = nip->ip_node = ccopy(nip->ip_node);
+				if (p->n_op == GOTO)
+					p->n_left->n_lval += lbloff;
+				else if (p->n_op == CBRANCH)
+					p->n_right->n_lval += lbloff;
+			} else if (nip->type == IP_DEFLAB)
+				nip->ip_lbl += lbloff;
+			pass2_compile(nip);
+			break;
+		}
+	}
+	w->flags |= WRITTEN;
+}
+
+/*
+ * printout functions that are referenced.
+ */
+void
+inline_prtout()
+{
+	struct istat *w;
+	int gotone = 0;
+
+	SLIST_FOREACH(w, &ipole, link) {
+		if ((w->flags & (REFD|WRITTEN)) == REFD &&
+		    !DLIST_ISEMPTY(&w->shead, qelem)) {
+			defloc(w->sp);
+			puto(w);
+			w->flags |= WRITTEN;
+			gotone++;
+		}
+	}
+	if (gotone)
+		inline_prtout();
+}
+
+#if 1
+static void
+printip(struct interpass *pole)
+{
+	static char *foo[] = {
+	   0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" };
+	struct interpass *ip;
+	struct interpass_prolog *ipplg, *epplg;
+
+	DLIST_FOREACH(ip, pole, qelem) {
+		if (ip->type > MAXIP)
+			printf("IP(%d) (%p): ", ip->type, ip);
+		else
+			printf("%s (%p): ", foo[ip->type], ip);
+		switch (ip->type) {
+		case IP_NODE: printf("\n");
+#ifdef PCC_DEBUG
+			fwalk(ip->ip_node, eprint, 0); break;
+#endif
+		case IP_PROLOG:
+			ipplg = (struct interpass_prolog *)ip;
+			printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n",
+			    ipplg->ipp_name, ipplg->ipp_vis ? "(local)" : "",
+			    (long)ipplg->ipp_regs[0], ipplg->ipp_autos,
+			    ipplg->ip_tmpnum, ipplg->ip_lblnum);
+			break;
+		case IP_EPILOG:
+			epplg = (struct interpass_prolog *)ip;
+			printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n",
+			    epplg->ipp_name, epplg->ipp_vis ? "(local)" : "",
+			    (long)epplg->ipp_regs[0], epplg->ipp_autos,
+			    epplg->ip_tmpnum, epplg->ip_lblnum);
+			break;
+		case IP_DEFLAB: printf(LABFMT "\n", ip->ip_lbl); break;
+		case IP_DEFNAM: printf("\n"); break;
+		case IP_ASM: printf("%s\n", ip->ip_asm); break;
+		default:
+			break;
+		}
+	}
+}
+#endif
+
+static int toff;
+
+static NODE *
+mnode(struct ntds *nt, NODE *p)
+{
+	NODE *q;
+	int num = nt->temp + toff;
+
+	if (p->n_op == CM) {
+		q = p->n_right;
+		q = tempnode(num, nt->type, nt->df, nt->attr);
+		nt--;
+		p->n_right = buildtree(ASSIGN, q, p->n_right);
+		p->n_left = mnode(nt, p->n_left);
+		p->n_op = COMOP;
+	} else {
+		p = pconvert(p);
+		q = tempnode(num, nt->type, nt->df, nt->attr);
+		p = buildtree(ASSIGN, q, p);
+	}
+	return p;
+}
+
+static void
+rtmps(NODE *p, void *arg)
+{
+	if (p->n_op == TEMP)
+		regno(p) += toff;
+}
+
+/*
+ * Inline a function. Returns the return value.
+ * There are two major things that must be converted when 
+ * inlining a function:
+ * - Label numbers must be updated with an offset.
+ * - The stack block must be relocated (add to REG or OREG).
+ * - Temporaries should be updated (but no must)
+ */
+NODE *
+inlinetree(struct symtab *sp, NODE *f, NODE *ap)
+{
+	extern int crslab, tvaloff;
+	struct istat *is = findfun(sp);
+	struct interpass *ip, *ipf, *ipl;
+	int lmin, stksz, l0, l1, l2, gainl;
+	OFFSZ stkoff;
+	NODE *p, *rp;
+
+	if (is == NULL || nerrors) {
+		inline_ref(sp); /* prototype of not yet declared inline ftn */
+		return NIL;
+	}
+
+	SDEBUG(("inlinetree(%p,%p) OK %d\n", f, ap, is->flags & CANINL));
+
+	gainl = attr_find(sp->sap, GCC_ATYP_ALW_INL) != NULL;
+
+	if ((is->flags & CANINL) == 0 && gainl)
+		werror("cannot inline but always_inline");
+
+	if ((is->flags & CANINL) == 0 || (xinline == 0 && gainl == 0)) {
+		if (is->sp->sclass == STATIC || is->sp->sclass == USTATIC)
+			inline_ref(sp);
+		return NIL;
+	}
+
+	if (isinlining && cifun->sp == sp) {
+		/* Do not try to inline ourselves */
+		inline_ref(sp);
+		return NIL;
+	}
+
+#ifdef mach_i386
+	if (kflag) {
+		is->flags |= REFD; /* if static inline, emit */
+		return NIL; /* XXX cannot handle hidden ebx arg */
+	}
+#endif
+
+	stkoff = stksz = 0;
+	/* emit jumps to surround inline function */
+	branch(l0 = getlab());
+	plabel(l1 = getlab());
+	l2 = getlab();
+	SDEBUG(("branch labels %d,%d,%d\n", l0, l1, l2));
+
+	ipf = DLIST_NEXT(&is->shead, qelem); /* prolog */
+	ipl = DLIST_PREV(&is->shead, qelem); /* epilog */
+
+	/* Fix label & temp offsets */
+#define	IPP(x) ((struct interpass_prolog *)x)
+	SDEBUG(("pre-offsets crslab %d tvaloff %d\n", crslab, tvaloff));
+	lmin = crslab - IPP(ipf)->ip_lblnum;
+	crslab += (IPP(ipl)->ip_lblnum - IPP(ipf)->ip_lblnum) + 1;
+	toff = tvaloff - IPP(ipf)->ip_tmpnum;
+	tvaloff += (IPP(ipl)->ip_tmpnum - IPP(ipf)->ip_tmpnum) + 1;
+	SDEBUG(("offsets crslab %d lmin %d tvaloff %d toff %d\n",
+	    crslab, lmin, tvaloff, toff));
+
+	/* traverse until first real label */
+	ipf = DLIST_NEXT(ipf, qelem);
+	do
+		ipf = DLIST_NEXT(ipf, qelem);
+	while (ipf->type != IP_DEFLAB);
+
+	/* traverse backwards to last label */
+	do
+		ipl = DLIST_PREV(ipl, qelem);
+	while (ipl->type != IP_DEFLAB);
+
+	/* So, walk over all statements and emit them */
+	for (ip = ipf; ip != ipl; ip = DLIST_NEXT(ip, qelem)) {
+		switch (ip->type) {
+		case IP_NODE:
+			p = ccopy(ip->ip_node);
+			if (p->n_op == GOTO)
+				p->n_left->n_lval += lmin;
+			else if (p->n_op == CBRANCH)
+				p->n_right->n_lval += lmin;
+			walkf(p, rtmps, 0);
+#ifdef PCC_DEBUG
+			if (sdebug) {
+				printf("converted node\n");
+				fwalk(ip->ip_node, eprint, 0);
+				fwalk(p, eprint, 0);
+			}
+#endif
+			send_passt(IP_NODE, p);
+			break;
+
+		case IP_DEFLAB:
+			SDEBUG(("converted label %d to %d\n",
+			    ip->ip_lbl, ip->ip_lbl + lmin));
+			send_passt(IP_DEFLAB, ip->ip_lbl + lmin);
+			break;
+
+		case IP_ASM:
+			send_passt(IP_ASM, ip->ip_asm);
+			break;
+
+		case IP_REF:
+			inline_ref((struct symtab *)ip->ip_name);
+			break;
+
+		default:
+			cerror("bad inline stmt %d", ip->type);
+		}
+	}
+	SDEBUG(("last label %d to %d\n", ip->ip_lbl, ip->ip_lbl + lmin));
+	send_passt(IP_DEFLAB, ip->ip_lbl + lmin);
+
+	branch(l2);
+	plabel(l0);
+
+	rp = block(GOTO, bcon(l1), NIL, INT, 0, MKAP(INT));
+	if (is->retval)
+		p = tempnode(is->retval + toff, DECREF(sp->stype),
+		    sp->sdf, sp->sap);
+	else
+		p = bcon(0);
+	rp = buildtree(COMOP, rp, p);
+
+	if (is->nargs) {
+		p = mnode(&is->nt[is->nargs-1], ap);
+		rp = buildtree(COMOP, p, rp);
+	}
+
+	tfree(f);
+	return rp;
+}
+
+void
+inline_args(struct symtab **sp, int nargs)
+{
+	struct istat *cf;
+	int i;
+
+	SDEBUG(("inline_args\n"));
+	cf = cifun;
+	/*
+	 * First handle arguments.  We currently do not inline anything if:
+	 * - function has varargs
+	 * - function args are volatile, checked if no temp node is asg'd.
+	 */
+	if (nargs) {
+		for (i = 0; i < nargs; i++)
+			if ((sp[i]->sflags & STNODE) == 0)
+				return; /* not temporary */
+		cf->nt = permalloc(sizeof(struct ntds)*nargs);
+		for (i = 0; i < nargs; i++) {
+			cf->nt[i].temp = sp[i]->soffset;
+			cf->nt[i].type = sp[i]->stype;
+			cf->nt[i].df = sp[i]->sdf;
+			cf->nt[i].attr = sp[i]->sap;
+		}
+	}
+	cf->nargs = nargs;
+	cf->flags |= CANINL;
+}
Index: uspace/app/pcc/cc/ccom/main.c
===================================================================
--- uspace/app/pcc/cc/ccom/main.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/main.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,402 @@
+/*	$Id: main.c,v 1.106 2011/01/22 22:08:23 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2002 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "pass1.h"
+#include "pass2.h"
+
+int sflag, nflag, oflag, kflag, pflag;
+int lflag, odebug, rdebug, s2debug, udebug, x2debug;
+#if !defined(MULTIPASS) || defined(PASST)
+int iTflag, oTflag;
+#endif
+int xdebug, sdebug, gflag, c2debug, pdebug, g2debug;
+#ifdef CHAR_UNSIGNED
+int funsigned_char = 1;
+#else
+int funsigned_char = 0;
+#endif
+int sspflag;
+int xssaflag, xtailcallflag, xtemps, xdeljumps, xdce, xinline, xccp;
+
+int e2debug, t2debug, f2debug, b2debug;
+
+/*
+ * Ensure that this struct matches defines in manifest.h!
+ */
+const struct attr2 btattr[32] = {
+#define BTA(x)	{ 0, ATTR_BASETYP, { { SZ##x }, { AL##x }, }, },
+	{ 0 },	/* UNDEF */
+	{ 0 },	/* FARG */
+	BTA(CHAR)
+	BTA(CHAR)
+	BTA(SHORT)
+	BTA(SHORT)
+	BTA(INT)
+	BTA(INT)
+	BTA(LONG)
+	BTA(LONG)
+	BTA(LONGLONG)
+	BTA(LONGLONG)
+	BTA(FLOAT)
+	BTA(DOUBLE)
+	BTA(LDOUBLE)
+	{ 0 },	/* STRTY */
+	{ 0 },	/* UNIONTY */
+	{ 0 },	/* unused */
+	{ 0 },	/* unused */
+	{ 0, ATTR_BASETYP },	/* VOID */
+	{ 0 },	/* SIGNED */
+	BTA(BOOL)
+	BTA(FLOAT)	/* FIMAG */
+	BTA(DOUBLE)	/* IMAG */
+	BTA(LDOUBLE)	/* LIMAG */
+	BTA(FLOAT)	/* FCOMPLEX */
+	BTA(DOUBLE)	/* COMPLEX */
+	BTA(LDOUBLE)	/* LCOMPLEX */
+};
+
+char *prgname;
+
+static void prtstats(void);
+
+static void
+usage(void)
+{
+	(void)fprintf(stderr, "usage: %s [option] [infile] [outfile]...\n",
+	    prgname);
+	exit(1);
+}
+
+static void
+segvcatch(int a)
+{
+	char buf[1024];
+	int dummy;
+
+	snprintf(buf, sizeof buf, "%sinternal compiler error: %s, line %d\n",
+	    nerrors ? "" : "major ", ftitle, lineno);
+	dummy = write(STDERR_FILENO, buf, strlen(buf));
+	_exit(1);
+}
+
+static void
+fflags(char *str)
+{
+	int flagval = 1;
+
+	if (strncmp("no-", str, 3) == 0) {
+		str += 3;
+		flagval = 0;
+	}
+
+	if (strcmp(str, "signed-char") == 0)
+		funsigned_char = !flagval;
+	else if (strcmp(str, "unsigned-char") == 0)
+		funsigned_char = flagval;
+	else if (strcmp(str, "stack-protector") == 0)
+		sspflag = flagval;
+	else if (strcmp(str, "stack-protector-all") == 0)
+		sspflag = flagval;
+	else if (strncmp(str, "pack-struct", 11) == 0)
+		pragma_allpacked = (strlen(str) > 12 ? atoi(str+12) : 1);
+	else {
+		fprintf(stderr, "unrecognised option '%s'\n", str);
+		usage();
+	}
+}
+
+/* control multiple files */
+int
+main(int argc, char *argv[])
+{
+
+	int ch;
+
+#ifdef TIMING
+	struct timeval t1, t2;
+
+	(void)gettimeofday(&t1, NULL);
+#endif
+
+	prgname = argv[0];
+
+	while ((ch = getopt(argc, argv, "OT:VW:X:Z:f:gklm:psvwx:")) != -1)
+		switch (ch) {
+#if !defined(MULTIPASS) || defined(PASS1)
+		case 'X':
+			while (*optarg)
+				switch (*optarg++) {
+				case 'd': ++ddebug; break; /* declarations */
+				case 'i': ++idebug; break; /* initializations */
+				case 'b': ++bdebug; break; /* buildtree */
+				case 't': ++tdebug; break; /* type match */
+				case 'e': ++edebug; break; /* pass1 exit */
+				case 'x': ++xdebug; break; /* MD code */
+				case 's': ++sdebug; break; /* inline */
+				case 'n': ++nflag; break;  /* node alloc */
+				case 'o': ++oflag; break;  /* optim */
+				case 'p': ++pdebug; break; /* prototype */
+				default:
+					fprintf(stderr, "unknown X flag '%c'\n",
+					    optarg[-1]);
+					exit(1);
+				}
+#endif
+			break;
+#if !defined(MULTIPASS) || defined(PASST)
+		case 'T':
+			while (*optarg)
+				switch (*optarg++) {
+				case 'i': ++iTflag; break;
+				case 'o': ++oTflag; break;
+				case 'n': ++nflag; break;
+				default:
+					fprintf(stderr, "unknown T flag '%c'\n",
+					    optarg[-1]);
+					exit(1);
+				}
+#endif
+			break;
+#if !defined(MULTIPASS) || defined(PASS2)
+		case 'Z':
+			while (*optarg)
+				switch (*optarg++) {
+				case 'f': /* instruction matching */
+					++f2debug;
+					break;
+				case 'e': /* print tree upon pass2 enter */
+					++e2debug;
+					break;
+				case 'o': ++odebug; break;
+				case 'r': /* register alloc/graph coloring */
+					++rdebug;
+					break;
+				case 'b': /* basic block and SSA building */
+					++b2debug;
+					break;
+				case 'c': /* code printout */
+					++c2debug;
+					break;
+				case 't': ++t2debug; break;
+				case 's': /* shape matching */
+					++s2debug;
+					break;
+				case 'u': /* Sethi-Ullman debugging */
+					++udebug;
+					break;
+				case 'x': ++x2debug; break;
+				case 'g':  /* print flow graphs */
+					++g2debug;
+					break;
+				case 'n': ++nflag; break;
+				default:
+					fprintf(stderr, "unknown Z flag '%c'\n",
+					    optarg[-1]);
+					exit(1);
+				}
+#endif
+			break;
+
+		case 'f': /* Language */
+			fflags(optarg);
+			break;
+
+		case 'g': /* Debugging */
+			gflag = 1;
+			break;
+
+		case 'k': /* PIC code */
+			++kflag;
+			break;
+
+		case 'l': /* Linenos */
+			++lflag;
+			break;
+
+		case 'm': /* Target-specific */
+			mflags(optarg);
+			break;
+
+		case 'p': /* Profiling */
+			pflag = 1;
+			break;
+
+		case 's': /* Statistics */
+			++sflag;
+			break;
+
+		case 'W': /* Enable different warnings */
+			Wflags(optarg);
+			break;
+
+		case 'x': /* Different optimizations */
+			if (strcmp(optarg, "ssa") == 0)
+				xssaflag++;
+			else if (strcmp(optarg, "tailcall") == 0)
+				xtailcallflag++;
+			else if (strcmp(optarg, "temps") == 0)
+				xtemps++;
+			else if (strcmp(optarg, "deljumps") == 0)
+				xdeljumps++;
+			else if (strcmp(optarg, "dce") == 0)
+				xdce++;
+			else if (strcmp(optarg, "inline") == 0)
+				xinline++;
+			else if (strcmp(optarg, "ccp") == 0)
+				xccp++;
+			else
+				usage();
+			break;
+		case 'v':
+			printf("ccom: %s\n", VERSSTR);
+			break;
+
+		case '?':
+		default:
+			usage();
+		}
+		argc -= optind;
+		argv += optind;
+
+		if (argc > 0 && strcmp(argv[0], "-") != 0) {
+			if (freopen(argv[0], "r", stdin) == NULL) {
+				fprintf(stderr, "open input file '%s':",
+				    argv[0]);
+				perror(NULL);
+				exit(1);
+			}
+		} else {
+			fprintf(stderr, "Reading from standard input is disabled on HelenOS\n");
+			exit(1);
+		}
+		if (argc > 1 && strcmp(argv[1], "-") != 0) {
+			if (freopen(argv[1], "w", stdout) == NULL) {
+				fprintf(stderr, "open output file '%s':",
+				    argv[1]);
+				perror(NULL);
+				exit(1);
+			}
+		}
+
+	mkdope();
+#ifndef __helenos__
+	signal(SIGSEGV, segvcatch);
+#endif
+#ifdef SIGBUS
+	signal(SIGBUS, segvcatch);
+#endif
+	fregs = FREGS;	/* number of free registers */
+	lineno = 1;
+#ifdef GCC_COMPAT
+	gcc_init();
+#endif
+
+	/* starts past any of the above */
+	reached = 1;
+
+	bjobcode();
+#ifndef TARGET_VALIST
+	{
+		NODE *p = block(NAME, NIL, NIL, PTR|CHAR, NULL, MKAP(CHAR));
+		struct symtab *sp = lookup(addname("__builtin_va_list"), 0);
+		p->n_sp = sp;
+		defid(p, TYPEDEF);
+		nfree(p);
+	}
+#endif
+	complinit();
+
+#ifdef STABS
+	if (gflag) {
+		stabs_file(argc ? argv[0] : "");
+		stabs_init();
+	}
+#endif
+
+	if (sspflag)
+		sspinit();
+
+	(void) yyparse();
+	yyaccpt();
+
+	if (!nerrors)
+		lcommprint();
+
+#ifdef STABS
+	if (gflag)
+		stabs_efile(argc ? argv[0] : "");
+#endif
+
+	ejobcode( nerrors ? 1 : 0 );
+
+#ifdef TIMING
+	(void)gettimeofday(&t2, NULL);
+	t2.tv_sec -= t1.tv_sec;
+	t2.tv_usec -= t1.tv_usec;
+	if (t2.tv_usec < 0) {
+		t2.tv_usec += 1000000;
+		t2.tv_sec -= 1;
+	}
+	fprintf(stderr, "ccom total time: %ld s %ld us\n",
+	    t2.tv_sec, t2.tv_usec);
+#endif
+
+	if (sflag)
+		prtstats();
+	return(nerrors?1:0);
+
+}
+
+void
+prtstats(void)
+{
+	extern int nametabs, namestrlen, tmpallocsize, permallocsize;
+	extern int lostmem, arglistcnt, dimfuncnt, inlnodecnt, inlstatcnt;
+	extern int symtabcnt, suedefcnt;
+
+	fprintf(stderr, "Name table entries:		%d pcs\n", nametabs);
+	fprintf(stderr, "Name string size:		%d B\n", namestrlen);
+	fprintf(stderr, "Permanent allocated memory:	%d B\n", permallocsize);
+	fprintf(stderr, "Temporary allocated memory:	%d B\n", tmpallocsize);
+	fprintf(stderr, "Lost memory:			%d B\n", lostmem);
+	fprintf(stderr, "Argument list unions:		%d pcs\n", arglistcnt);
+	fprintf(stderr, "Dimension/function unions:	%d pcs\n", dimfuncnt);
+	fprintf(stderr, "Struct/union/enum blocks:	%d pcs\n", suedefcnt);
+	fprintf(stderr, "Inline node count:		%d pcs\n", inlnodecnt);
+	fprintf(stderr, "Inline control blocks:		%d pcs\n", inlstatcnt);
+	fprintf(stderr, "Permanent symtab entries:	%d pcs\n", symtabcnt);
+}
Index: uspace/app/pcc/cc/ccom/mkext/Makefile
===================================================================
--- uspace/app/pcc/cc/ccom/mkext/Makefile	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/mkext/Makefile	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,59 @@
+#
+# Copyright (c) 2011 Jiri Zarevucky
+# 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 must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - 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.
+#
+
+USPACE_PREFIX = ../../../../..
+MIPDIR = ../../../mip
+MDIR = ../../../arch/$(PLATFORM)
+OSDIR = ../../../os/helenos
+EXTRA_CFLAGS = -I$(MIPDIR) -I$(MDIR) -I$(OSDIR) -I. -w
+DEFS = -DMKEXT -Dmach_$(PLATFORM) -D__helenos__
+BINARY = cc_mkext
+
+POSIX_COMPAT = y
+
+PRE_DEPEND = mkext.c table.c common.c
+EXTRA_CLEAN = mkext.c table.c common.c
+
+# FIXME: external.{c,h} must be generated for each target system
+
+SOURCES = \
+	mkext.c \
+	table.c \
+	common.c
+
+include $(USPACE_PREFIX)/Makefile.common
+
+mkext.c: $(MIPDIR)/mkext.c
+	ln -s -f $^ $@
+
+table.c: $(MDIR)/table.c
+	ln -s -f $^ $@
+
+common.c: $(MIPDIR)/common.c
+	ln -s -f $^ $@
+
Index: uspace/app/pcc/cc/ccom/optim.c
===================================================================
--- uspace/app/pcc/cc/ccom/optim.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/optim.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,385 @@
+/*	$Id: optim.c,v 1.36.2.1 2011/03/01 17:40:21 ragge Exp $	*/
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+# include "pass1.h"
+
+# define SWAP(p,q) {sp=p; p=q; q=sp;}
+# define RCON(p) (p->n_right->n_op==ICON)
+# define RO(p) p->n_right->n_op
+# define RV(p) p->n_right->n_lval
+# define LCON(p) (p->n_left->n_op==ICON)
+# define LO(p) p->n_left->n_op
+# define LV(p) p->n_left->n_lval
+
+/* remove left node */
+static NODE *
+zapleft(NODE *p)
+{
+	NODE *q;
+
+	q = p->n_left;
+	nfree(p->n_right);
+	nfree(p);
+	return q;
+}
+
+/*
+ * fortran function arguments
+ */
+static NODE *
+fortarg(NODE *p)
+{
+	if( p->n_op == CM ){
+		p->n_left = fortarg( p->n_left );
+		p->n_right = fortarg( p->n_right );
+		return(p);
+	}
+
+	while( ISPTR(p->n_type) ){
+		p = buildtree( UMUL, p, NIL );
+	}
+	return( optim(p) );
+}
+
+	/* mapping relationals when the sides are reversed */
+short revrel[] ={ EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT };
+
+/*
+ * local optimizations, most of which are probably
+ * machine independent
+ */
+NODE *
+optim(NODE *p)
+{
+	struct attr *ap;
+	int o, ty;
+	NODE *sp, *q;
+	int i;
+	TWORD t;
+
+	t = BTYPE(p->n_type);
+	if( oflag ) return(p);
+
+	ty = coptype(p->n_op);
+	if( ty == LTYPE ) return(p);
+
+	if( ty == BITYPE ) p->n_right = optim(p->n_right);
+	p->n_left = optim(p->n_left);
+
+	/* collect constants */
+again:	o = p->n_op;
+	switch(o){
+
+	case SCONV:
+	case PCONV:
+		return( clocal(p) );
+
+	case FORTCALL:
+		p->n_right = fortarg( p->n_right );
+		break;
+
+	case ADDROF:
+		if (LO(p) == TEMP)
+			return p;
+		if( LO(p) != NAME ) cerror( "& error" );
+
+		if( !andable(p->n_left) ) return(p);
+
+		LO(p) = ICON;
+
+		setuleft:
+		/* paint over the type of the left hand side with the type of the top */
+		p->n_left->n_type = p->n_type;
+		p->n_left->n_df = p->n_df;
+		p->n_left->n_ap = p->n_ap;
+		q = p->n_left;
+		nfree(p);
+		return q;
+
+	case UMUL:
+		if (LO(p) == ADDROF) {
+			q = p->n_left->n_left;
+			nfree(p->n_left);
+			nfree(p);
+			return q;
+		}
+		if( LO(p) != ICON ) break;
+		LO(p) = NAME;
+		goto setuleft;
+
+	case RS:
+		if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right))
+			goto zapright;
+
+		ap = attr_find(p->n_ap, ATTR_BASETYP);
+
+		if (LO(p) == RS && RCON(p->n_left) && RCON(p) &&
+		    (RV(p) + RV(p->n_left)) < ap->atypsz) {
+			/* two right-shift  by constants */
+			RV(p) += RV(p->n_left);
+			p->n_left = zapleft(p->n_left);
+		}
+#if 0
+		  else if (LO(p) == LS && RCON(p->n_left) && RCON(p)) {
+			RV(p) -= RV(p->n_left);
+			if (RV(p) < 0)
+				o = p->n_op = LS, RV(p) = -RV(p);
+			p->n_left = zapleft(p->n_left);
+		}
+#endif
+		if (RO(p) == ICON) {
+			if (RV(p) < 0) {
+				RV(p) = -RV(p);
+				p->n_op = LS;
+				goto again;
+			}
+#ifdef notyet /* must check for side effects, --a >> 32; */
+			if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue) &&
+			    ISUNSIGNED(p->n_type)) { /* ignore signed shifts */
+				/* too many shifts */
+				tfree(p->n_left);
+				nfree(p->n_right);
+				p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL;
+			} else
+#endif
+			/* avoid larger shifts than type size */
+			if (RV(p) >= ap->atypsz) {
+				RV(p) = RV(p) % 
+				    attr_find(p->n_ap, ATTR_BASETYP)->atypsz;
+				werror("shift larger than type");
+			}
+			if (RV(p) == 0)
+				p = zapleft(p);
+		}
+		break;
+
+	case LS:
+		if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right))
+			goto zapright;
+
+		ap = attr_find(p->n_ap, ATTR_BASETYP);
+
+		if (LO(p) == LS && RCON(p->n_left) && RCON(p)) {
+			/* two left-shift  by constants */
+			RV(p) += RV(p->n_left);
+			p->n_left = zapleft(p->n_left);
+		}
+#if 0
+		  else if (LO(p) == RS && RCON(p->n_left) && RCON(p)) {
+			RV(p) -= RV(p->n_left);
+			p->n_left = zapleft(p->n_left);
+		}
+#endif
+		if (RO(p) == ICON) {
+			if (RV(p) < 0) {
+				RV(p) = -RV(p);
+				p->n_op = RS;
+				goto again;
+			}
+#ifdef notyet /* must check for side effects */
+			if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue)) {
+				/* too many shifts */
+				tfree(p->n_left);
+				nfree(p->n_right);
+				p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL;
+			} else
+#endif
+			/* avoid larger shifts than type size */
+			if (RV(p) >= ap->atypsz) {
+				RV(p) = RV(p) %
+				    attr_find(p->n_ap, ATTR_BASETYP)->atypsz;
+				werror("shift larger than type");
+			}
+			if (RV(p) == 0)  
+				p = zapleft(p);
+		}
+		break;
+
+	case MINUS:
+		if (LCON(p) && RCON(p) && p->n_left->n_sp == p->n_right->n_sp) {
+			/* link-time constants, but both are the same */
+			/* solve it now by forgetting the symbols */
+			p->n_left->n_sp = p->n_right->n_sp = NULL;
+		}
+		if( !nncon(p->n_right) ) break;
+		RV(p) = -RV(p);
+		o = p->n_op = PLUS;
+
+	case MUL:
+	case PLUS:
+	case AND:
+	case OR:
+	case ER:
+		/* commutative ops; for now, just collect constants */
+		/* someday, do it right */
+		if( nncon(p->n_left) || ( LCON(p) && !RCON(p) ) )
+			SWAP( p->n_left, p->n_right );
+		/* make ops tower to the left, not the right */
+		if( RO(p) == o ){
+			NODE *t1, *t2, *t3;
+			t1 = p->n_left;
+			sp = p->n_right;
+			t2 = sp->n_left;
+			t3 = sp->n_right;
+			/* now, put together again */
+			p->n_left = sp;
+			sp->n_left = t1;
+			sp->n_right = t2;
+			p->n_right = t3;
+			}
+		if(o == PLUS && LO(p) == MINUS && RCON(p) && RCON(p->n_left) &&
+		   conval(p->n_right, MINUS, p->n_left->n_right)){
+			zapleft:
+
+			q = p->n_left->n_left;
+			nfree(p->n_left->n_right);
+			nfree(p->n_left);
+			p->n_left = q;
+		}
+		if( RCON(p) && LO(p)==o && RCON(p->n_left) &&
+		    conval( p->n_right, o, p->n_left->n_right ) ){
+			goto zapleft;
+			}
+		else if( LCON(p) && RCON(p) && conval( p->n_left, o, p->n_right ) ){
+			zapright:
+			nfree(p->n_right);
+			q = makety(p->n_left, p->n_type, p->n_qual,
+			    p->n_df, p->n_ap);
+			nfree(p);
+			return clocal(q);
+			}
+
+		/* change muls to shifts */
+
+		if( o == MUL && nncon(p->n_right) && (i=ispow2(RV(p)))>=0){
+			if( i == 0 ) { /* multiplication by 1 */
+				goto zapright;
+				}
+			o = p->n_op = LS;
+			p->n_right->n_type = INT;
+			p->n_right->n_df = NULL;
+			RV(p) = i;
+			}
+
+		/* change +'s of negative consts back to - */
+		if( o==PLUS && nncon(p->n_right) && RV(p)<0 ){
+			RV(p) = -RV(p);
+			o = p->n_op = MINUS;
+			}
+
+		/* remove ops with RHS 0 */
+		if ((o == PLUS || o == MINUS || o == OR || o == ER) &&
+		    nncon(p->n_right) && RV(p) == 0) {
+			goto zapright;
+		}
+		break;
+
+	case DIV:
+		if( nncon( p->n_right ) && p->n_right->n_lval == 1 )
+			goto zapright;
+		if (LCON(p) && RCON(p) && conval(p->n_left, DIV, p->n_right))
+			goto zapright;
+		if (RCON(p) && ISUNSIGNED(p->n_type) && (i=ispow2(RV(p))) > 0) {
+			p->n_op = RS;
+			RV(p) = i;
+			q = p->n_right;
+			if(tsize(q->n_type, q->n_df, q->n_ap) > SZINT)
+				p->n_right = makety(q, INT, 0, 0, MKAP(INT));
+
+			break;
+		}
+		break;
+
+	case MOD:
+		if (RCON(p) && ISUNSIGNED(p->n_type) && ispow2(RV(p)) > 0) {
+			p->n_op = AND;
+			RV(p) = RV(p) -1;
+			break;
+		}
+		break;
+
+	case EQ:
+	case NE:
+	case LT:
+	case LE:
+	case GT:
+	case GE:
+	case ULT:
+	case ULE:
+	case UGT:
+	case UGE:
+		if( !LCON(p) ) break;
+
+		/* exchange operands */
+
+		sp = p->n_left;
+		p->n_left = p->n_right;
+		p->n_right = sp;
+		p->n_op = revrel[p->n_op - EQ ];
+		break;
+
+#ifdef notyet
+	case ASSIGN:
+		/* Simple test to avoid two branches */
+		if (RO(p) != NE)
+			break;
+		q = p->n_right;
+		if (RCON(q) && RV(q) == 0 && LO(q) == AND &&
+		    RCON(q->n_left) && (i = ispow2(RV(q->n_left))) &&
+		    q->n_left->n_type == INT) {
+			q->n_op = RS;
+			RV(q) = i;
+		}
+		break;
+#endif
+	}
+
+	return(p);
+	}
+
+int
+ispow2(CONSZ c)
+{
+	int i;
+	if( c <= 0 || (c&(c-1)) ) return(-1);
+	for( i=0; c>1; ++i) c >>= 1;
+	return(i);
+}
+
+int
+nncon( p ) NODE *p; {
+	/* is p a constant without a name */
+	return( p->n_op == ICON && p->n_sp == NULL );
+	}
Index: uspace/app/pcc/cc/ccom/pass1.h
===================================================================
--- uspace/app/pcc/cc/ccom/pass1.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/pass1.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,611 @@
+/*	$Id: pass1.h,v 1.215 2011/02/17 13:44:13 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 "config.h"
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#ifndef MKEXT
+#include "external.h"
+#else
+typedef unsigned int bittype; /* XXX - for basicblock */
+#endif
+#include "manifest.h"
+
+#include "ccconfig.h"
+
+/*
+ * Storage classes
+ */
+#define SNULL		0
+#define AUTO		1
+#define EXTERN		2
+#define STATIC		3
+#define REGISTER	4
+#define EXTDEF		5
+/* #define LABEL	6*/
+/* #define ULABEL	7*/
+#define MOS		8
+#define PARAM		9
+#define STNAME		10
+#define MOU		11
+#define UNAME		12
+#define TYPEDEF		13
+/* #define FORTRAN		14 */
+#define ENAME		15
+#define MOE		16
+/* #define UFORTRAN 	17 */
+#define USTATIC		18
+
+	/* field size is ORed in */
+#define FIELD		0200
+#define FLDSIZ		0177
+extern	char *scnames(int);
+
+/*
+ * Symbol table flags
+ */
+#define	SNORMAL		0
+#define	STAGNAME	01
+#define	SLBLNAME	02
+#define	SMOSNAME	03
+#define	SSTRING		04
+#define	NSTYPES		05
+#define	SMASK		07
+
+/* #define SSET		00010 */
+/* #define SREF		00020 */
+#define SNOCREAT	00040	/* don't create a symbol in lookup() */
+#define STEMP		00100	/* Allocate symtab from temp or perm mem */
+#define	SDYNARRAY	00200	/* symbol is dynamic array on stack */
+#define	SINLINE		00400	/* function is of type inline */
+#define	STNODE		01000	/* symbol shall be a temporary node */
+#define	SASG		04000	/* symbol is assigned to already */
+#define	SLOCAL1		010000
+#define	SLOCAL2		020000
+#define	SLOCAL3		040000
+
+	/* alignment of initialized quantities */
+#ifndef AL_INIT
+#define	AL_INIT ALINT
+#endif
+
+struct rstack;
+struct symtab;
+union arglist;
+#ifdef GCC_COMPAT
+struct gcc_attr_pack;
+#endif
+
+/*
+ * Dimension/prototype information.
+ * 	ddim > 0 holds the dimension of an array.
+ *	ddim < 0 is a dynamic array and refers to a tempnode.
+ *	...unless:
+ *		ddim == NOOFFSET, an array without dimenston, "[]"
+ *		ddim == -1, dynamic array while building before defid.
+ */
+union dimfun {
+	int	ddim;		/* Dimension of an array */
+	union arglist *dfun;	/* Prototype index */
+};
+
+/*
+ * Argument list member info when storing prototypes.
+ */
+union arglist {
+	TWORD type;
+	union dimfun *df;
+	struct attr *sap;
+};
+#define TNULL		INCREF(FARG) /* pointer to FARG -- impossible type */
+#define TELLIPSIS 	INCREF(INCREF(FARG))
+
+/*
+ * Symbol table definition.
+ */
+struct	symtab {
+	struct	symtab *snext;	/* link to other symbols in the same scope */
+	int	soffset;	/* offset or value */
+	char	sclass;		/* storage class */
+	char	slevel;		/* scope level */
+	short	sflags;		/* flags, see below */
+	char	*sname;		/* Symbol name */
+	char	*soname;	/* Written-out name */
+	TWORD	stype;		/* type word */
+	TWORD	squal;		/* qualifier word */
+	union	dimfun *sdf;	/* ptr to the dimension/prototype array */
+	struct	attr *sap;	/* the base type attribute list */
+};
+
+struct attr2 {
+	struct attr *next;
+	int atype;
+	union aarg aa[2];
+};
+
+#define	ISSOU(ty)   ((ty) == STRTY || (ty) == UNIONTY)
+#define	MKAP(type)  ((struct attr *)&btattr[type])
+extern const struct attr2 btattr[];
+
+/*
+ * External definitions
+ */
+struct swents {			/* switch table */
+	struct swents *next;	/* Next struct in linked list */
+	CONSZ	sval;		/* case value */
+	int	slab;		/* associated label */
+};
+int mygenswitch(int, TWORD, struct swents **, int);
+
+extern	int blevel;
+extern	int instruct, got_type;
+extern	int oldstyle;
+extern	int oflag;
+
+extern	int lineno, nerrors;
+
+extern	char *ftitle;
+extern	struct symtab *cftnsp;
+extern	int autooff, maxautooff, argoff, strucoff;
+extern	int brkflag;
+
+extern	OFFSZ inoff;
+
+extern	int reached;
+extern	int isinlining;
+extern	int xinline;
+
+extern	int sdebug, idebug, pdebug;
+
+/* various labels */
+extern	int brklab;
+extern	int contlab;
+extern	int flostat;
+extern	int retlab;
+
+/* pragma globals */
+extern int pragma_allpacked, pragma_packed, pragma_aligned;
+extern char *pragma_renamed;
+
+/*
+ * Flags used in the (elementary) flow analysis ...
+ */
+#define FBRK		02
+#define FCONT		04
+#define FDEF		010
+#define FLOOP		020
+
+/*	mark an offset which is undefined */
+
+#define NOOFFSET	(-10201)
+
+/* declarations of various functions */
+extern	NODE
+	*buildtree(int, NODE *, NODE *r),
+	*mkty(unsigned, union dimfun *, struct attr *),
+	*rstruct(char *, int),
+	*dclstruct(struct rstack *),
+	*strend(int gtype, char *),
+	*tymerge(NODE *, NODE *),
+	*stref(NODE *),
+	*offcon(OFFSZ, TWORD, union dimfun *, struct attr *),
+	*bcon(int),
+	*xbcon(CONSZ, struct symtab *, TWORD),
+	*bpsize(NODE *),
+	*convert(NODE *, int),
+	*pconvert(NODE *),
+	*oconvert(NODE *),
+	*ptmatch(NODE *),
+	*tymatch(NODE *),
+	*makety(NODE *, TWORD, TWORD, union dimfun *, struct attr *),
+	*block(int, NODE *, NODE *, TWORD, union dimfun *, struct attr *),
+	*doszof(NODE *),
+	*talloc(void),
+	*optim(NODE *),
+	*clocal(NODE *),
+	*ccopy(NODE *),
+	*tempnode(int, TWORD, union dimfun *, struct attr *),
+	*eve(NODE *),
+	*doacall(struct symtab *, NODE *, NODE *);
+NODE	*intprom(NODE *);
+OFFSZ	tsize(TWORD, union dimfun *, struct attr *),
+	psize(NODE *);
+NODE *	typenode(NODE *new);
+void	spalloc(NODE *, NODE *, OFFSZ);
+char	*exname(char *);
+NODE	*floatcon(char *);
+NODE	*fhexcon(char *);
+NODE	*bdty(int op, ...);
+extern struct rstack *rpole;
+
+int oalloc(struct symtab *, int *);
+void deflabel(char *, NODE *);
+void gotolabel(char *);
+unsigned int esccon(char **);
+void inline_start(struct symtab *);
+void inline_end(void);
+void inline_addarg(struct interpass *);
+void inline_ref(struct symtab *);
+void inline_prtout(void);
+void inline_args(struct symtab **, int);
+NODE *inlinetree(struct symtab *, NODE *, NODE *);
+void ftnarg(NODE *);
+struct rstack *bstruct(char *, int, NODE *);
+void moedef(char *);
+void beginit(struct symtab *);
+void simpleinit(struct symtab *, NODE *);
+struct symtab *lookup(char *, int);
+struct symtab *getsymtab(char *, int);
+char *addstring(char *);
+char *addname(char *);
+void symclear(int);
+struct symtab *hide(struct symtab *);
+void soumemb(NODE *, char *, int);
+int talign(unsigned int, struct attr *);
+void bfcode(struct symtab **, int);
+int chkftn(union arglist *, union arglist *);
+void branch(int);
+void cbranch(NODE *, NODE *);
+void extdec(struct symtab *);
+void defzero(struct symtab *);
+int falloc(struct symtab *, int, NODE *);
+TWORD ctype(TWORD);  
+void ninval(CONSZ, int, NODE *);
+void infld(CONSZ, int, CONSZ);
+void zbits(CONSZ, int);
+void instring(struct symtab *);
+void inwstring(struct symtab *);
+void plabel(int);
+void bjobcode(void);
+void ejobcode(int);
+void calldec(NODE *, NODE *);
+int cisreg(TWORD);
+char *tmpsprintf(char *, ...);
+char *tmpvsprintf(char *, va_list);
+void asginit(NODE *);
+void desinit(NODE *);
+void endinit(void);
+void endictx(void);
+void sspinit(void);
+void sspstart(void);
+void sspend(void);
+void ilbrace(void);
+void irbrace(void);
+CONSZ scalinit(NODE *);
+void p1print(char *, ...);
+char *copst(int);
+int cdope(int);
+void myp2tree(NODE *);
+void lcommprint(void);
+void lcommdel(struct symtab *);
+NODE *funcode(NODE *);
+struct symtab *enumhd(char *);
+NODE *enumdcl(struct symtab *);
+NODE *enumref(char *);
+CONSZ icons(NODE *);
+CONSZ valcast(CONSZ v, TWORD t);
+int mypragma(char *);
+char *pragtok(char *);
+int eat(int);
+void fixdef(struct symtab *);
+int cqual(TWORD, TWORD);
+void defloc(struct symtab *);
+int fldchk(int);
+int nncon(NODE *);
+void cunput(char);
+NODE *nametree(struct symtab *sp);
+void *inlalloc(int size);
+void *blkalloc(int size);
+void pass1_lastchance(struct interpass *);
+void fldty(struct symtab *p);
+int getlab(void);
+struct suedef *sueget(struct suedef *p);
+void complinit(void);
+NODE *structref(NODE *p, int f, char *name);
+NODE *cxop(int op, NODE *l, NODE *r);
+NODE *imop(int op, NODE *l, NODE *r);
+NODE *cxelem(int op, NODE *p);
+NODE *cxconj(NODE *p);
+NODE *cxret(NODE *p, NODE *q);
+NODE *cast(NODE *p, TWORD t, TWORD q);
+NODE *ccast(NODE *p, TWORD t, TWORD u, union dimfun *df, struct attr *sue);
+int andable(NODE *);
+int conval(NODE *, int, NODE *);
+int ispow2(CONSZ);
+void defid(NODE *q, int class);
+void efcode(void);
+void ecomp(NODE *p);
+void cendarg(void);
+int fldal(unsigned int);
+int upoff(int size, int alignment, int *poff);
+void nidcl(NODE *p, int class);
+void eprint(NODE *, int, int *, int *);
+int uclass(int class);
+int notlval(NODE *);
+void ecode(NODE *p);
+void bccode(void);
+void ftnend(void);
+void dclargs(void);
+int suemeq(struct attr *s1, struct attr *s2);
+struct symtab *strmemb(struct attr *ap);
+int yylex(void);
+void yyerror(char *);
+int pragmas_gcc(char *t);
+
+NODE *builtin_check(NODE *f, NODE *a);
+
+#ifdef SOFTFLOAT
+typedef struct softfloat SF;
+SF soft_neg(SF);
+SF soft_cast(CONSZ v, TWORD);
+SF soft_plus(SF, SF);
+SF soft_minus(SF, SF);
+SF soft_mul(SF, SF);
+SF soft_div(SF, SF);
+int soft_cmp_eq(SF, SF);
+int soft_cmp_ne(SF, SF);
+int soft_cmp_ge(SF, SF);
+int soft_cmp_gt(SF, SF);
+int soft_cmp_le(SF, SF);
+int soft_cmp_lt(SF, SF);
+int soft_isz(SF);
+CONSZ soft_val(SF);
+#define FLOAT_NEG(sf)		soft_neg(sf)
+#define	FLOAT_CAST(v,t)		soft_cast(v, t)
+#define	FLOAT_PLUS(x1,x2)	soft_plus(x1, x2)
+#define	FLOAT_MINUS(x1,x2)	soft_minus(x1, x2)
+#define	FLOAT_MUL(x1,x2)	soft_mul(x1, x2)
+#define	FLOAT_DIV(x1,x2)	soft_div(x1, x2)
+#define	FLOAT_ISZERO(sf)	soft_isz(sf)
+#define	FLOAT_VAL(sf)		soft_val(sf)
+#define FLOAT_EQ(x1,x2)		soft_cmp_eq(x1, x2)
+#define FLOAT_NE(x1,x2)		soft_cmp_ne(x1, x2)
+#define FLOAT_GE(x1,x2)		soft_cmp_ge(x1, x2)
+#define FLOAT_GT(x1,x2)		soft_cmp_gt(x1, x2)
+#define FLOAT_LE(x1,x2)		soft_cmp_le(x1, x2)
+#define FLOAT_LT(x1,x2)		soft_cmp_lt(x1, x2)
+#else
+#define	FLOAT_NEG(p)		-(p)
+#define	FLOAT_CAST(p,v)		(ISUNSIGNED(v) ? \
+		(long double)(U_CONSZ)(p) : (long double)(CONSZ)(p))
+#define	FLOAT_PLUS(x1,x2)	(x1) + (x2)
+#define	FLOAT_MINUS(x1,x2)	(x1) - (x2)
+#define	FLOAT_MUL(x1,x2)	(x1) * (x2)
+#define	FLOAT_DIV(x1,x2)	(x1) / (x2)
+#define	FLOAT_ISZERO(p)		(p) == 0.0
+#define FLOAT_VAL(p)		(CONSZ)(p)
+#define FLOAT_EQ(x1,x2)		(x1) == (x2)
+#define FLOAT_NE(x1,x2)		(x1) != (x2)
+#define FLOAT_GE(x1,x2)		(x1) >= (x2)
+#define FLOAT_GT(x1,x2)		(x1) > (x2)
+#define FLOAT_LE(x1,x2)		(x1) <= (x2)
+#define FLOAT_LT(x1,x2)		(x1) < (x2)
+#endif
+
+enum {	ATTR_NONE,
+
+	/* PCC used attributes */
+	ATTR_COMPLEX,	/* Internal definition of complex */
+	ATTR_BASETYP,	/* Internal; see below */
+	ATTR_QUALTYP,	/* Internal; const/volatile, see below */
+	ATTR_STRUCT,	/* Internal; element list */
+#define	ATTR_MAX ATTR_STRUCT
+
+#ifdef GCC_COMPAT
+	/* type attributes */
+	GCC_ATYP_ALIGNED,
+	GCC_ATYP_PACKED,
+	GCC_ATYP_SECTION,
+	GCC_ATYP_TRANSP_UNION,
+	GCC_ATYP_UNUSED,
+	GCC_ATYP_DEPRECATED,
+	GCC_ATYP_MAYALIAS,
+
+	/* variable attributes */
+	GCC_ATYP_MODE,
+
+	/* function attributes */
+	GCC_ATYP_NORETURN,
+	GCC_ATYP_FORMAT,
+	GCC_ATYP_NONNULL,
+	GCC_ATYP_SENTINEL,
+	GCC_ATYP_WEAK,
+	GCC_ATYP_FORMATARG,
+	GCC_ATYP_GNU_INLINE,
+	GCC_ATYP_MALLOC,
+	GCC_ATYP_NOTHROW,
+	GCC_ATYP_CONST,
+	GCC_ATYP_PURE,
+	GCC_ATYP_CONSTRUCTOR,
+	GCC_ATYP_DESTRUCTOR,
+	GCC_ATYP_VISIBILITY,
+	GCC_ATYP_STDCALL,
+	GCC_ATYP_CDECL,
+	GCC_ATYP_WARN_UNUSED_RESULT,
+	GCC_ATYP_USED,
+	GCC_ATYP_NO_INSTR_FUN,
+	GCC_ATYP_NOINLINE,
+	GCC_ATYP_ALIAS,
+	GCC_ATYP_WEAKREF,
+	GCC_ATYP_ALLOCSZ,
+	GCC_ATYP_ALW_INL,
+	GCC_ATYP_TLSMODEL,
+	GCC_ATYP_ALIASWEAK,
+
+	/* other stuff */
+	GCC_ATYP_BOUNDED,	/* OpenBSD extra boundary checks */
+
+	GCC_ATYP_MAX
+#endif
+};
+
+
+/*
+ * ATTR_BASETYP has the following layout:
+ * aa[0].iarg has size
+ * aa[1].iarg has alignment
+ * ATTR_QUALTYP has the following layout:
+ * aa[0].iarg has CON/VOL + FUN/ARY/PTR
+ * Not defined yet...
+ * aa[3].iarg is dimension for arrays (XXX future)
+ * aa[3].varg is function defs for functions.
+ */
+#define	atypsz	aa[0].iarg
+#define	aalign	aa[1].iarg
+
+/*
+ * ATTR_STRUCT member list.
+ */
+#define amlist  aa[0].varg
+#define	strattr(x)	(attr_find(x, ATTR_STRUCT))
+
+#define	iarg(x)	aa[x].iarg
+#define	sarg(x)	aa[x].sarg
+#define	varg(x)	aa[x].varg
+
+void gcc_init(void);
+int gcc_keyword(char *, NODE **);
+struct attr *gcc_attr_parse(NODE *);
+void gcc_tcattrfix(NODE *);
+struct gcc_attrib *gcc_get_attr(struct suedef *, int);
+void dump_attr(struct attr *gap);
+
+struct attr *attr_add(struct attr *orig, struct attr *new);
+struct attr *attr_new(int, int);
+struct attr *attr_find(struct attr *, int);
+struct attr *attr_copy(struct attr *src, struct attr *dst, int nelem);
+struct attr *attr_dup(struct attr *ap, int n);
+
+#ifdef STABS
+void stabs_init(void);
+void stabs_file(char *);
+void stabs_efile(char *);
+void stabs_line(int);
+void stabs_rbrac(int);
+void stabs_lbrac(int);
+void stabs_func(struct symtab *);
+void stabs_newsym(struct symtab *);
+void stabs_chgsym(struct symtab *);
+void stabs_struct(struct symtab *, struct attr *);
+#endif
+
+#ifndef CHARCAST
+/* to make character constants into character connstants */
+/* this is a macro to defend against cross-compilers, etc. */
+#define CHARCAST(x) (char)(x)
+#endif
+
+/* sometimes int is smaller than pointers */
+#if SZPOINT(CHAR) <= SZINT
+#define INTPTR  INT
+#elif SZPOINT(CHAR) <= SZLONG
+#define INTPTR  LONG
+#elif SZPOINT(CHAR) <= SZLONGLONG
+#define INTPTR  LONGLONG
+#else
+#error int size unknown
+#endif
+
+/*
+ * C compiler first pass extra defines.
+ */
+#define	QUALIFIER	(MAXOP+1)
+#define	CLASS		(MAXOP+2)
+#define	RB		(MAXOP+3)
+#define	DOT		(MAXOP+4)
+#define	ELLIPSIS	(MAXOP+5)
+#define	TYPE		(MAXOP+6)
+#define	LB		(MAXOP+7)
+#define	COMOP		(MAXOP+8)
+#define	QUEST		(MAXOP+9)
+#define	COLON		(MAXOP+10)
+#define	ANDAND		(MAXOP+11)
+#define	OROR		(MAXOP+12)
+#define	NOT		(MAXOP+13)
+#define	CAST		(MAXOP+14)
+#define	STRING		(MAXOP+15)
+
+/* The following must be in the same order as their NOASG counterparts */
+#define	PLUSEQ		(MAXOP+16)
+#define	MINUSEQ		(MAXOP+17)
+#define	DIVEQ		(MAXOP+18)
+#define	MODEQ		(MAXOP+19)
+#define	MULEQ		(MAXOP+20)
+#define	ANDEQ		(MAXOP+21)
+#define	OREQ		(MAXOP+22)
+#define	EREQ		(MAXOP+23)
+#define	LSEQ		(MAXOP+24)
+#define	RSEQ		(MAXOP+25)
+
+#define	UNASG		(-(PLUSEQ-PLUS))+
+
+#define INCR		(MAXOP+26)
+#define DECR		(MAXOP+27)
+#define SZOF		(MAXOP+28)
+#define CLOP		(MAXOP+29)
+#define ATTRIB		(MAXOP+30)
+#define XREAL		(MAXOP+31)
+#define XIMAG		(MAXOP+32)
+#define TYMERGE		(MAXOP+33)
+
+
+/*
+ * The following types are only used in pass1.
+ */
+#define SIGNED		(MAXTYPES+1)
+#define BOOL		(MAXTYPES+2)
+#define	FIMAG		(MAXTYPES+3)
+#define	IMAG		(MAXTYPES+4)
+#define	LIMAG		(MAXTYPES+5)
+#define	FCOMPLEX	(MAXTYPES+6)
+#define	COMPLEX		(MAXTYPES+7)
+#define	LCOMPLEX	(MAXTYPES+8)
+#define	ENUMTY		(MAXTYPES+9)
+
+#define	ISFTY(x)	((x) >= FLOAT && (x) <= LDOUBLE)
+#define	ISCTY(x)	((x) >= FCOMPLEX && (x) <= LCOMPLEX)
+#define	ISITY(x)	((x) >= FIMAG && (x) <= LIMAG)
+#define ANYCX(p) (p->n_type == STRTY && attr_find(p->n_ap, ATTR_COMPLEX))
+
+#define coptype(o)	(cdope(o)&TYFLG)
+#define clogop(o)	(cdope(o)&LOGFLG)
+#define casgop(o)	(cdope(o)&ASGFLG)
+
Index: uspace/app/pcc/cc/ccom/pftn.c
===================================================================
--- uspace/app/pcc/cc/ccom/pftn.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/pftn.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,3277 @@
+/*	$Id: pftn.c,v 1.311 2011/02/20 10:19:07 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Many changes from the 32V sources, among them:
+ * - New symbol table manager (moved to another file).
+ * - Prototype saving/checks.
+ */
+
+# include "pass1.h"
+
+#include "cgram.h"
+
+struct symtab *cftnsp;
+int arglistcnt, dimfuncnt;	/* statistics */
+int symtabcnt, suedefcnt;	/* statistics */
+int autooff,		/* the next unused automatic offset */
+    maxautooff,		/* highest used automatic offset in function */
+    argoff;		/* the next unused argument offset */
+int retlab = NOLAB;	/* return label for subroutine */
+int brklab;
+int contlab;
+int flostat;
+int blevel;
+int reached, prolab;
+
+struct params;
+
+#define MKTY(p, t, d, s) r = talloc(); *r = *p; \
+	r = argcast(r, t, d, s); *p = *r; nfree(r);
+
+/*
+ * Linked list stack while reading in structs.
+ */
+struct rstack {
+	struct	rstack *rnext;
+	int	rsou;
+	int	rstr;
+	struct	symtab *rsym;
+	struct	symtab *rb;
+	struct	attr *ap;
+	int	flags;
+#define	LASTELM	1
+} *rpole;
+
+/*
+ * Linked list for parameter (and struct elements) declaration.
+ */
+static struct params {
+	struct params *next, *prev;
+	struct symtab *sym;
+} *lpole, *lparam;
+static int nparams;
+
+/* defines used for getting things off of the initialization stack */
+
+NODE *arrstk[10];
+int arrstkp;
+static int intcompare;
+NODE *parlink;
+
+void fixtype(NODE *p, int class);
+int fixclass(int class, TWORD type);
+static void dynalloc(struct symtab *p, int *poff);
+static void evalidx(struct symtab *p);
+int isdyn(struct symtab *p);
+void inforce(OFFSZ n);
+void vfdalign(int n);
+static void ssave(struct symtab *);
+static void alprint(union arglist *al, int in);
+static void lcommadd(struct symtab *sp);
+static NODE *mkcmplx(NODE *p, TWORD dt);
+extern int fun_inline;
+
+int ddebug = 0;
+
+/*
+ * Declaration of an identifier.  Handles redeclarations, hiding,
+ * incomplete types and forward declarations.
+ *
+ * q is a TYPE node setup after parsing with n_type, n_df and n_ap.
+ * n_sp is a pointer to the not-yet initalized symbol table entry
+ * unless it's a redeclaration or supposed to hide a variable.
+ */
+
+void
+defid(NODE *q, int class)
+{
+	struct attr *ap;
+	struct symtab *p;
+	TWORD type, qual;
+	TWORD stp, stq;
+	int scl;
+	union dimfun *dsym, *ddef;
+	int slev, temp, changed;
+
+	if (q == NIL)
+		return;  /* an error was detected */
+
+	p = q->n_sp;
+
+	if (p->sname == NULL)
+		cerror("defining null identifier");
+
+#ifdef PCC_DEBUG
+	if (ddebug) {
+		printf("defid(%s (%p), ", p->sname, p);
+		tprint(stdout, q->n_type, q->n_qual);
+		printf(", %s, (%p)), level %d\n\t", scnames(class),
+		    q->n_df, blevel);
+		dump_attr(q->n_ap);
+	}
+#endif
+
+	fixtype(q, class);
+
+	type = q->n_type;
+	qual = q->n_qual;
+	class = fixclass(class, type);
+
+	stp = p->stype;
+	stq = p->squal;
+	slev = p->slevel;
+
+#ifdef PCC_DEBUG
+	if (ddebug) {
+		printf("	modified to ");
+		tprint(stdout, type, qual);
+		printf(", %s\n", scnames(class));
+		printf("	previous def'n: ");
+		tprint(stdout, stp, stq);
+		printf(", %s, (%p,%p)), level %d\n",
+		    scnames(p->sclass), p->sdf, p->sap, slev);
+	}
+#endif
+
+	if (blevel == 1) {
+		switch (class) {
+		default:
+			if (!(class&FIELD) && !ISFTN(type))
+				uerror("declared argument %s missing",
+				    p->sname );
+		case MOS:
+		case MOU:
+		case TYPEDEF:
+		case PARAM:
+			;
+		}
+	}
+
+	if (stp == UNDEF)
+		goto enter; /* New symbol */
+
+	if (type != stp)
+		goto mismatch;
+
+	if (blevel > slev && (class == AUTO || class == REGISTER))
+		/* new scope */
+		goto mismatch;
+
+	/*
+	 * test (and possibly adjust) dimensions.
+	 * also check that prototypes are correct.
+	 */
+	dsym = p->sdf;
+	ddef = q->n_df;
+	changed = 0;
+	for (temp = type; temp & TMASK; temp = DECREF(temp)) {
+		if (ISARY(temp)) {
+			if (dsym->ddim == NOOFFSET) {
+				dsym->ddim = ddef->ddim;
+				changed = 1;
+			} else if (ddef->ddim != NOOFFSET &&
+			    dsym->ddim!=ddef->ddim) {
+				goto mismatch;
+			}
+			++dsym;
+			++ddef;
+		} else if (ISFTN(temp)) {
+			/* add a late-defined prototype here */
+			if (cftnsp == NULL && dsym->dfun == NULL)
+				dsym->dfun = ddef->dfun;
+			if (!oldstyle && ddef->dfun != NULL &&
+			    chkftn(dsym->dfun, ddef->dfun))
+				uerror("declaration doesn't match prototype");
+			dsym++, ddef++;
+		}
+	}
+#ifdef STABS
+	if (changed && gflag)
+		stabs_chgsym(p); /* symbol changed */
+#endif
+
+	/* check that redeclarations are to the same structure */
+	if (temp == STRTY || temp == UNIONTY) {
+		if (strmemb(p->sap) != strmemb(q->n_ap))
+			goto mismatch;
+	}
+
+	scl = p->sclass;
+
+#ifdef PCC_DEBUG
+	if (ddebug)
+		printf("	previous class: %s\n", scnames(scl));
+#endif
+
+	/*
+	 * Its allowed to add attributes to existing declarations.
+	 * Be care ful though not to trash existing attributes.
+	 */
+	if (p->sap->atype <= ATTR_MAX) {
+		/* nothing special, just overwrite */
+		p->sap = q->n_ap;
+	} else {
+		for (ap = q->n_ap; ap; ap = ap->next) {
+			if (ap->atype > ATTR_MAX)
+				p->sap = attr_add(p->sap, attr_dup(ap, 3));
+		}
+	}
+
+	if (class & FIELD)
+		return;
+	switch(class) {
+
+	case EXTERN:
+		if (pragma_renamed)
+			p->soname = pragma_renamed;
+		pragma_renamed = NULL;
+		switch( scl ){
+		case STATIC:
+		case USTATIC:
+			if( slev==0 )
+				goto done;
+			break;
+		case EXTDEF:
+		case EXTERN:
+			goto done;
+		case SNULL:
+			if (p->sflags & SINLINE) {
+				p->sclass = EXTDEF;
+				inline_ref(p);
+				goto done;
+			}
+			break;
+		}
+		break;
+
+	case STATIC:
+		if (scl==USTATIC || (scl==EXTERN && blevel==0)) {
+			p->sclass = STATIC;
+			goto done;
+		}
+		if (changed || (scl == STATIC && blevel == slev))
+			goto done; /* identical redeclaration */
+		break;
+
+	case USTATIC:
+		if (scl==STATIC || scl==USTATIC)
+			goto done;
+		break;
+
+	case TYPEDEF:
+		if (scl == class)
+			goto done;
+		break;
+
+	case MOU:
+	case MOS:
+		goto done;
+
+	case EXTDEF:
+		switch (scl) {
+		case EXTERN:
+			p->sclass = EXTDEF;
+			goto done;
+		case USTATIC:
+			p->sclass = STATIC;
+			goto done;
+		case SNULL:
+			/*
+			 * Handle redeclarations of inlined functions.
+			 * This is allowed if the previous declaration is of
+			 * type gnu_inline.
+			 */
+			if (attr_find(p->sap, GCC_ATYP_GNU_INLINE))
+				goto done;
+			break;
+		}
+		break;
+
+	case AUTO:
+	case REGISTER:
+		break;  /* mismatch.. */
+	case SNULL:
+		if (fun_inline && ISFTN(type))
+			goto done;
+		break;
+	}
+
+	mismatch:
+
+	/*
+	 * Only allowed for automatic variables.
+	 */
+	if (blevel <= slev || class == EXTERN) {
+		uerror("redeclaration of %s", p->sname);
+		return;
+	}
+	q->n_sp = p = hide(p);
+
+	enter:  /* make a new entry */
+
+#ifdef PCC_DEBUG
+	if(ddebug)
+		printf("	new entry made\n");
+#endif
+	if (type < BTMASK && (ap = attr_find(q->n_ap, GCC_ATYP_MODE))) {
+		int u = ISUNSIGNED(type);
+		type = u ? ENUNSIGN(ap->iarg(0)) : ap->iarg(0);
+		if (type != XTYPE) {
+			for (ap = q->n_ap;
+			    ap->next->atype != ATTR_BASETYP; ap = ap->next)
+				;
+			ap->next = MKAP(type);
+		} else
+			uerror("fix XTYPE basetyp");
+	}
+	p->stype = type;
+	p->squal = qual;
+	p->sclass = (char)class;
+	p->slevel = (char)blevel;
+	p->soffset = NOOFFSET;
+	if (q->n_ap == NULL)
+		cerror("q->n_ap == NULL");
+	p->sap = attr_add(q->n_ap, p->sap);
+
+	/* copy dimensions */
+	p->sdf = q->n_df;
+	/* Do not save param info for old-style functions */
+	if (ISFTN(type) && oldstyle)
+		p->sdf->dfun = NULL;
+
+	if (arrstkp)
+		evalidx(p);
+
+	/* allocate offsets */
+	if (class&FIELD) {
+		(void) falloc(p, class&FLDSIZ, NIL);  /* new entry */
+	} else switch (class) {
+
+	case REGISTER:
+		cerror("register var");
+
+	case AUTO:
+		if (isdyn(p)) {
+			p->sflags |= SDYNARRAY;
+			dynalloc(p, &autooff);
+		} else
+			oalloc(p, &autooff);
+		break;
+
+	case PARAM:
+		oalloc(p, &argoff);
+		break;
+		
+	case STATIC:
+	case EXTDEF:
+	case EXTERN:
+		p->soffset = getlab();
+		if (pragma_renamed)
+			p->soname = pragma_renamed;
+		pragma_renamed = NULL;
+		break;
+
+	case MOU:
+		rpole->rstr = 0;
+		/* FALLTHROUGH */
+	case MOS:
+		oalloc(p, &rpole->rstr);
+		if (class == MOU)
+			rpole->rstr = 0;
+		break;
+	case SNULL:
+#ifdef notdef
+		if (fun_inline) {
+			p->slevel = 1;
+			p->soffset = getlab();
+		}
+#endif
+		break;
+	}
+
+#ifdef STABS
+	if (gflag)
+		stabs_newsym(p);
+#endif
+
+done:
+	fixdef(p);	/* Leave last word to target */
+#ifndef HAVE_WEAKREF
+	{
+		struct attr *at;
+
+		/* Refer renamed function */
+		if ((at = attr_find(p->sap, GCC_ATYP_WEAKREF)))
+			p->soname = at->sarg(0);
+	}
+#endif
+#ifdef PCC_DEBUG
+	if (ddebug) {
+		printf( "	sdf, offset: %p, %d\n\t",
+		    p->sdf, p->soffset);
+		dump_attr(p->sap);
+	}
+#endif
+}
+
+void
+ssave(struct symtab *sym)
+{
+	struct params *p;
+
+	p = tmpalloc(sizeof(struct params));
+	p->next = NULL;
+	p->sym = sym;
+
+	if ((p->prev = lparam) == NULL)
+		lpole = p;
+	else
+		lparam->next = p;
+	lparam = p;
+}
+
+/*
+ * end of function
+ */
+void
+ftnend()
+{
+	extern NODE *cftnod;
+	extern struct savbc *savbc;
+	extern struct swdef *swpole;
+	extern int tvaloff;
+	char *c;
+
+	if (retlab != NOLAB && nerrors == 0) { /* inside a real function */
+		plabel(retlab);
+		if (cftnod)
+			ecomp(buildtree(FORCE, cftnod, NIL));
+		efcode(); /* struct return handled here */
+		if ((c = cftnsp->soname) == NULL)
+			c = addname(exname(cftnsp->sname));
+		SETOFF(maxautooff, ALCHAR);
+		send_passt(IP_EPILOG, maxautooff/SZCHAR, c,
+		    cftnsp->stype, cftnsp->sclass == EXTDEF, retlab, tvaloff);
+	}
+
+	cftnod = NIL;
+	tcheck();
+	brklab = contlab = retlab = NOLAB;
+	flostat = 0;
+	if (nerrors == 0) {
+		if (savbc != NULL)
+			cerror("bcsave error");
+		if (lparam != NULL)
+			cerror("parameter reset error");
+		if (swpole != NULL)
+			cerror("switch error");
+	}
+	savbc = NULL;
+	lparam = NULL;
+	cftnsp = NULL;
+	maxautooff = autooff = AUTOINIT;
+	reached = 1;
+
+	if (isinlining)
+		inline_end();
+	inline_prtout();
+
+	tmpfree(); /* Release memory resources */
+}
+
+static struct symtab nulsym = {
+	NULL, 0, 0, 0, 0, "null", "null", INT, 0, NULL, NULL
+};
+
+void
+dclargs()
+{
+	union dimfun *df;
+	union arglist *al, *al2, *alb;
+	struct params *a;
+	struct symtab *p, **parr = NULL; /* XXX gcc */
+	int i;
+
+	/*
+	 * Deal with fun(void) properly.
+	 */
+	if (nparams == 1 && lparam->sym && lparam->sym->stype == VOID)
+		goto done;
+
+	/*
+	 * Generate a list for bfcode().
+	 * Parameters were pushed in reverse order.
+	 */
+	if (nparams != 0)
+		parr = tmpalloc(sizeof(struct symtab *) * nparams);
+
+	if (nparams)
+	    for (a = lparam, i = 0; a != NULL; a = a->prev) {
+		p = a->sym;
+		parr[i++] = p;
+		if (p == NULL) {
+			uerror("parameter %d name missing", i);
+			p = &nulsym; /* empty symtab */
+		}
+		if (p->stype == FARG) {
+			p->stype = INT;
+			p->sap = MKAP(INT);
+		}
+		if (ISARY(p->stype)) {
+			p->stype += (PTR-ARY);
+			p->sdf++;
+		} else if (ISFTN(p->stype)) {
+			werror("function declared as argument");
+			p->stype = INCREF(p->stype);
+		}
+#ifdef STABS
+		if (gflag)
+			stabs_newsym(p);
+#endif
+	}
+	if (oldstyle && (df = cftnsp->sdf) && (al = df->dfun)) {
+		/*
+		 * Check against prototype of oldstyle function.
+		 */
+		alb = al2 = tmpalloc(sizeof(union arglist) * nparams * 3 + 1);
+		for (i = 0; i < nparams; i++) {
+			TWORD type = parr[i]->stype;
+			(al2++)->type = type;
+			if (ISSOU(BTYPE(type)))
+				(al2++)->sap = parr[i]->sap;
+			while (!ISFTN(type) && !ISARY(type) && type > BTMASK)
+				type = DECREF(type);
+			if (type > BTMASK)
+				(al2++)->df = parr[i]->sdf;
+		}
+		al2->type = TNULL;
+		intcompare = 1;
+		if (chkftn(al, alb))
+			uerror("function doesn't match prototype");
+		intcompare = 0;
+
+	}
+
+	if (oldstyle && nparams) {
+		/* Must recalculate offset for oldstyle args here */
+		argoff = ARGINIT;
+		for (i = 0; i < nparams; i++) {
+			parr[i]->soffset = NOOFFSET;
+			oalloc(parr[i], &argoff);
+		}
+	}
+
+done:	cendarg();
+
+	plabel(prolab); /* after prolog, used in optimization */
+	retlab = getlab();
+	bfcode(parr, nparams);
+	if (fun_inline &&
+	    (xinline || attr_find(cftnsp->sap, GCC_ATYP_ALW_INL)))
+		inline_args(parr, nparams);
+	plabel(getlab()); /* used when spilling */
+	if (parlink)
+		ecomp(parlink);
+	parlink = NIL;
+	lparam = NULL;
+	nparams = 0;
+	symclear(1);	/* In case of function pointer args */
+}
+
+/*
+ * basic attributes for structs and enums
+ */
+static struct attr *
+seattr(void)
+{
+	return attr_add(attr_new(ATTR_BASETYP, 4), attr_new(ATTR_STRUCT, 1));
+}
+
+/*
+ * Struct/union/enum symtab construction.
+ */
+static void
+defstr(struct symtab *sp, int class)
+{
+	sp->sclass = (char)class;
+	if (class == STNAME)
+		sp->stype = STRTY;
+	else if (class == UNAME)
+		sp->stype = UNIONTY;
+	else if (class == ENAME)
+		sp->stype = ENUMTY;
+}
+
+/*
+ * Declare a struct/union/enum tag.
+ * If not found, create a new tag with UNDEF type.
+ */
+static struct symtab *
+deftag(char *name, int class)
+{
+	struct symtab *sp;
+
+	if ((sp = lookup(name, STAGNAME))->sap == NULL) {
+		/* New tag */
+		defstr(sp, class);
+	} else if (sp->sclass != class)
+		uerror("tag %s redeclared", name);
+	return sp;
+}
+
+/*
+ * reference to a structure or union, with no definition
+ */
+NODE *
+rstruct(char *tag, int soru)
+{
+	struct symtab *sp;
+
+	sp = deftag(tag, soru);
+	if (sp->sap == NULL)
+		sp->sap = seattr();
+	return mkty(sp->stype, 0, sp->sap);
+}
+
+static int enumlow, enumhigh;
+int enummer;
+
+/*
+ * Declare a member of enum.
+ */
+void
+moedef(char *name)
+{
+	struct symtab *sp;
+
+	sp = lookup(name, SNORMAL);
+	if (sp->stype == UNDEF || (sp->slevel < blevel)) {
+		if (sp->stype != UNDEF)
+			sp = hide(sp);
+		sp->stype = INT; /* always */
+		sp->sap = MKAP(INT);
+		sp->sclass = MOE;
+		sp->soffset = enummer;
+	} else
+		uerror("%s redeclared", name);
+	if (enummer < enumlow)
+		enumlow = enummer;
+	if (enummer > enumhigh)
+		enumhigh = enummer;
+	enummer++;
+}
+
+/*
+ * Declare an enum tag.  Complain if already defined.
+ */
+struct symtab *
+enumhd(char *name)
+{
+	struct attr *ap;
+	struct symtab *sp;
+
+	enummer = enumlow = enumhigh = 0;
+	if (name == NULL)
+		return NULL;
+
+	sp = deftag(name, ENAME);
+	if (sp->stype != ENUMTY) {
+		if (sp->slevel == blevel)
+			uerror("%s redeclared", name);
+		sp = hide(sp);
+		defstr(sp, ENAME);
+	}
+	if (sp->sap == NULL)
+		sp->sap = seattr();
+	ap = attr_find(sp->sap, ATTR_STRUCT);
+	ap->amlist = sp;
+	return sp;
+}
+
+/*
+ * finish declaration of an enum
+ */
+NODE *
+enumdcl(struct symtab *sp)
+{
+	struct attr *ap;
+	NODE *p;
+	TWORD t;
+
+#ifdef ENUMSIZE
+	t = ENUMSIZE(enumhigh, enumlow);
+#else
+	if (enumhigh <= MAX_CHAR && enumlow >= MIN_CHAR)
+		t = ctype(CHAR);
+	else if (enumhigh <= MAX_SHORT && enumlow >= MIN_SHORT)
+		t = ctype(SHORT);
+	else
+		t = ctype(INT);
+#endif
+	
+	if (sp) {
+		sp->stype = t;
+		ap = attr_find(sp->sap, ATTR_BASETYP);
+		ap->atypsz = (MKAP(t))->atypsz;
+		ap->aalign = (MKAP(t))->aalign;
+		ap = sp->sap;
+	} else
+		ap = MKAP(t);
+	p = mkty(t, 0, ap);
+	p->n_sp = sp;
+	return p;
+}
+
+/*
+ * Handle reference to an enum
+ */
+NODE *
+enumref(char *name)
+{
+	struct symtab *sp;
+	NODE *p;
+
+	sp = lookup(name, STAGNAME);
+
+#ifdef notdef
+	/*
+	 * 6.7.2.3 Clause 2:
+	 * "A type specifier of the form 'enum identifier' without an
+	 *  enumerator list shall only appear after the type it specifies
+	 *  is complete."
+	 */
+	if (sp->sclass != ENAME)
+		uerror("enum %s undeclared", name);
+#endif
+	if (sp->sclass == SNULL) {
+		/* declare existence of enum */
+		sp = enumhd(name);
+		sp->stype = ENUMTY;
+	}
+
+	p = mkty(sp->stype, 0, sp->sap);
+	p->n_sp = sp;
+	return p;
+}
+
+/*
+ * begining of structure or union declaration
+ * It's an error if this routine is called twice with the same struct.
+ */
+struct rstack *
+bstruct(char *name, int soru, NODE *gp)
+{
+	struct rstack *r;
+	struct symtab *sp;
+	struct attr *ap, *gap;
+
+	gap = gp ? gcc_attr_parse(gp) : NULL;
+
+	if (name != NULL) {
+		sp = deftag(name, soru);
+		if (sp->sap == NULL)
+			sp->sap = seattr();
+		ap = attr_find(sp->sap, ATTR_BASETYP);
+		if (ap->aalign != 0) {
+			if (sp->slevel < blevel) {
+				sp = hide(sp);
+				defstr(sp, soru);
+				sp->sap = seattr();
+			} else
+				uerror("%s redeclared", name);
+		}
+		gap = sp->sap = attr_add(sp->sap, gap);
+	} else {
+		gap = attr_add(seattr(), gap);
+		sp = NULL;
+	}
+
+	r = tmpcalloc(sizeof(struct rstack));
+	r->rsou = soru;
+	r->rsym = sp;
+	r->rb = NULL;
+	r->ap = gap;
+	r->rnext = rpole;
+	rpole = r;
+
+	return r;
+}
+
+/*
+ * Called after a struct is declared to restore the environment.
+ * - If ALSTRUCT is defined, this will be the struct alignment and the
+ *   struct size will be a multiple of ALSTRUCT, otherwise it will use
+ *   the alignment of the largest struct member.
+ */
+NODE *
+dclstruct(struct rstack *r)
+{
+	NODE *n;
+	struct attr *aps, *apb;
+	struct symtab *sp;
+	int al, sa, sz, coff;
+
+	apb = attr_find(r->ap, ATTR_BASETYP);
+	aps = attr_find(r->ap, ATTR_STRUCT);
+	aps->amlist = r->rb;
+
+#ifdef ALSTRUCT
+	al = ALSTRUCT;
+#else
+	al = ALCHAR;
+#endif
+
+	/*
+	 * extract size and alignment, calculate offsets
+	 */
+	coff = 0;
+	for (sp = r->rb; sp; sp = sp->snext) {
+		sa = talign(sp->stype, sp->sap);
+		if (sp->sclass & FIELD)
+			sz = sp->sclass&FLDSIZ;
+		else
+			sz = (int)tsize(sp->stype, sp->sdf, sp->sap);
+		if (sz > rpole->rstr)
+			rpole->rstr = sz;  /* for use with unions */
+		/*
+		 * set al, the alignment, to the lcm of the alignments
+		 * of the members.
+		 */
+		SETOFF(al, sa);
+	}
+
+	SETOFF(rpole->rstr, al);
+
+	apb->atypsz = rpole->rstr;
+	apb->aalign = al;
+
+#ifdef PCC_DEBUG
+	if (ddebug) {
+		printf("dclstruct(%s): size=%d, align=%d\n",
+		    r->rsym ? r->rsym->sname : "??",
+		    apb->atypsz, apb->aalign);
+	}
+	if (ddebug>1) {
+		printf("\tsize %d align %d link %p\n",
+		    apb->atypsz, apb->aalign, aps->amlist);
+		for (sp = aps->amlist; sp != NULL; sp = sp->snext) {
+			printf("\tmember %s(%p)\n", sp->sname, sp);
+		}
+	}
+#endif
+
+#ifdef STABS
+	if (gflag)
+		stabs_struct(r->rsym, r->ap);
+#endif
+
+	rpole = r->rnext;
+	n = mkty(r->rsou == STNAME ? STRTY : UNIONTY, 0, r->ap);
+
+	n->n_qual |= 1; /* definition place XXX used by attributes */
+	return n;
+}
+
+/*
+ * Add a new member to the current struct or union being declared.
+ */
+void
+soumemb(NODE *n, char *name, int class)
+{
+	struct symtab *sp, *lsp;
+	int incomp;
+	TWORD t;
+ 
+	if (rpole == NULL)
+		cerror("soumemb");
+ 
+	/* check if tag name exists */
+	lsp = NULL;
+	for (sp = rpole->rb; sp != NULL; lsp = sp, sp = sp->snext)
+		if (*name != '*' && sp->sname == name)
+			uerror("redeclaration of %s", name);
+
+	sp = getsymtab(name, SMOSNAME);
+	if (rpole->rb == NULL)
+		rpole->rb = sp;
+	else
+		lsp->snext = sp;
+#ifdef GCC_COMPAT
+	if (n->n_op == CM)
+		cerror("soumemb CM");
+#endif
+	n->n_sp = sp;
+	if ((class & FIELD) == 0)
+		class = rpole->rsou == STNAME ? MOS : MOU;
+	defid(n, class);
+
+	/*
+	 * 6.7.2.1 clause 16:
+	 * "...the last member of a structure with more than one
+	 *  named member may have incomplete array type;"
+	 */
+	if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET)
+		incomp = 1;
+	else
+		incomp = 0;
+	if ((rpole->flags & LASTELM) || (rpole->rb == sp && incomp == 1))
+		uerror("incomplete array in struct");
+	if (incomp == 1)
+		rpole->flags |= LASTELM;
+
+	/*
+	 * 6.7.2.1 clause 2:
+	 * "...such a structure shall not be a member of a structure
+	 *  or an element of an array."
+	 */
+	t = sp->stype;
+	if (rpole->rsou != STNAME || BTYPE(t) != STRTY)
+		return; /* not for unions */
+	while (ISARY(t))
+		t = DECREF(t);
+	if (ISPTR(t))
+		return;
+
+	if ((lsp = strmemb(sp->sap)) != NULL) {
+		for (; lsp->snext; lsp = lsp->snext)
+			;
+		if (ISARY(lsp->stype) && lsp->snext &&
+		    lsp->sdf->ddim == NOOFFSET)
+			uerror("incomplete struct in struct");
+	}
+}
+
+/*
+ * error printing routine in parser
+ */
+void
+yyerror(char *s)
+{
+	uerror(s);
+}
+
+void yyaccpt(void);
+void
+yyaccpt(void)
+{
+	ftnend();
+}
+
+/*
+ * p is top of type list given to tymerge later.
+ * Find correct CALL node and declare parameters from there.
+ */
+void
+ftnarg(NODE *p)
+{
+	NODE *q;
+
+#ifdef PCC_DEBUG
+	if (ddebug > 2)
+		printf("ftnarg(%p)\n", p);
+#endif
+	/*
+	 * Push argument symtab entries onto param stack in reverse order,
+	 * due to the nature of the stack it will be reclaimed correct.
+	 */
+	for (; p->n_op != NAME; p = p->n_left) {
+		if (p->n_op == UCALL && p->n_left->n_op == NAME)
+			return;	/* Nothing to enter */
+		if (p->n_op == CALL && p->n_left->n_op == NAME)
+			break;
+	}
+
+	p = p->n_right;
+	while (p->n_op == CM) {
+		q = p->n_right;
+		if (q->n_op != ELLIPSIS) {
+			ssave(q->n_sp);
+			nparams++;
+#ifdef PCC_DEBUG
+			if (ddebug > 2)
+				printf("	saving sym %s (%p) from (%p)\n",
+				    q->n_sp->sname, q->n_sp, q);
+#endif
+		}
+		p = p->n_left;
+	}
+	ssave(p->n_sp);
+	if (p->n_type != VOID)
+		nparams++;
+
+#ifdef PCC_DEBUG
+	if (ddebug > 2)
+		printf("	saving sym %s (%p) from (%p)\n",
+		    nparams ? p->n_sp->sname : "<noname>", p->n_sp, p);
+#endif
+}
+
+/*
+ * compute the alignment of an object with type ty, sizeoff index s
+ */
+int
+talign(unsigned int ty, struct attr *apl)
+{
+	struct attr *al;
+	int i;
+
+	if (ISPTR(ty))
+		return(ALPOINT); /* shortcut */
+
+	if(apl == NULL && ty!=INT && ty!=CHAR && ty!=SHORT &&
+	    ty!=UNSIGNED && ty!=UCHAR && ty!=USHORT) {
+		return(fldal(ty));
+	}
+
+	for( i=0; i<=(SZINT-BTSHIFT-1); i+=TSHIFT ){
+		switch( (ty>>i)&TMASK ){
+
+		case PTR:
+			return(ALPOINT);
+		case ARY:
+			continue;
+		case FTN:
+			cerror("compiler takes alignment of function");
+		case 0:
+			break;
+			}
+		}
+
+	
+	if ((al = attr_find(apl, GCC_ATYP_ALIGNED)))
+		return al->iarg(0);
+	al = attr_find(apl, ATTR_BASETYP);
+	if (al == NULL)
+		cerror("no basetyp");
+	if (al->aalign == 0)
+		uerror("no alignment");
+	return al->aalign;
+}
+
+/* compute the size associated with type ty,
+ *  dimoff d, and sizoff s */
+/* BETTER NOT BE CALLED WHEN t, d, and s REFER TO A BIT FIELD... */
+OFFSZ
+tsize(TWORD ty, union dimfun *d, struct attr *apl)
+{
+	struct attr *ap;
+	OFFSZ mult, sz;
+	int i;
+
+	mult = 1;
+
+	for( i=0; i<=(SZINT-BTSHIFT-1); i+=TSHIFT ){
+		switch( (ty>>i)&TMASK ){
+
+		case FTN:
+			uerror( "cannot take size of function");
+		case PTR:
+			return( SZPOINT(ty) * mult );
+		case ARY:
+			if (d->ddim == NOOFFSET)
+				return 0;
+			if (d->ddim < 0)
+				cerror("tsize: dynarray");
+			mult *= d->ddim;
+			d++;
+			continue;
+		case 0:
+			break;
+
+			}
+		}
+
+	ap = attr_find(apl, ATTR_BASETYP);
+	
+	if (ap == NULL) {
+		cerror("unknown type");
+		return SZINT;
+	}
+	
+	sz = ap->atypsz;
+	
+#ifdef GCC_COMPAT
+	if (ty == VOID)
+		sz = SZCHAR;
+#endif
+	if (!ISSOU(BTYPE(ty))) {
+		if (sz == 0) {
+			uerror("unknown size");
+			return(SZINT);
+		}
+	} else {
+		if (talign(ty, apl) == 0)
+			uerror("unknown structure/union/enum");
+	}
+
+	return((unsigned int)sz * mult);
+}
+
+/*
+ * Save string (and print it out).  If wide then wide string.
+ */
+NODE *
+strend(int wide, char *str)
+{
+	struct symtab *sp;
+	NODE *p;
+
+	/* If an identical string is already emitted, just forget this one */
+	if (wide) {
+		/* Do not save wide strings, at least not now */
+		sp = getsymtab(str, SSTRING|STEMP);
+	} else {
+		str = addstring(str);	/* enter string in string table */
+		sp = lookup(str, SSTRING);	/* check for existance */
+	}
+
+	if (sp->soffset == 0) { /* No string */
+		char *wr;
+		int i;
+
+		sp->sclass = STATIC;
+		sp->slevel = 1;
+		sp->soffset = getlab();
+		sp->squal = (CON >> TSHIFT);
+		sp->sdf = permalloc(sizeof(union dimfun));
+		if (wide) {
+			sp->stype = WCHAR_TYPE+ARY;
+			sp->sap = MKAP(WCHAR_TYPE);
+		} else {
+			if (funsigned_char) {
+				sp->stype = UCHAR+ARY;
+				sp->sap = MKAP(UCHAR);
+			} else {
+				sp->stype = CHAR+ARY;
+				sp->sap = MKAP(CHAR);
+			}
+		}
+		for (wr = sp->sname, i = 1; *wr; i++)
+			if (*wr++ == '\\')
+				(void)esccon(&wr);
+
+		sp->sdf->ddim = i;
+		if (wide)
+			inwstring(sp);
+		else
+			instring(sp);
+	}
+
+	p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->sap);
+	p->n_sp = sp;
+	return(clocal(p));
+}
+
+/*
+ * Print out a wide string by calling ninval().
+ */
+void
+inwstring(struct symtab *sp)
+{
+	char *s = sp->sname;
+	NODE *p;
+
+	defloc(sp);
+	p = xbcon(0, NULL, WCHAR_TYPE);
+	do {
+		if (*s++ == '\\')
+			p->n_lval = esccon(&s);
+		else
+			p->n_lval = (unsigned char)s[-1];
+		ninval(0, (MKAP(WCHAR_TYPE))->atypsz, p);
+	} while (s[-1] != 0);
+	nfree(p);
+}
+
+/*
+ * update the offset pointed to by poff; return the
+ * offset of a value of size `size', alignment `alignment',
+ * given that off is increasing
+ */
+int
+upoff(int size, int alignment, int *poff)
+{
+	int off;
+
+	off = *poff;
+	SETOFF(off, alignment);
+	if (off < 0)
+		cerror("structure or stack overgrown"); /* wrapped */
+	*poff = off+size;
+	return (off);
+}
+
+/*
+ * allocate p with offset *poff, and update *poff
+ */
+int
+oalloc(struct symtab *p, int *poff )
+{
+	int al, off, tsz;
+	int noff;
+
+	/*
+	 * Only generate tempnodes if we are optimizing,
+	 * and only for integers, floats or pointers,
+	 * and not if the type on this level is volatile.
+	 */
+	if (xtemps && ((p->sclass == AUTO) || (p->sclass == REGISTER)) &&
+	    (p->stype < STRTY || ISPTR(p->stype)) &&
+	    !(cqual(p->stype, p->squal) & VOL) && cisreg(p->stype)) {
+		NODE *tn = tempnode(0, p->stype, p->sdf, p->sap);
+		p->soffset = regno(tn);
+		p->sflags |= STNODE;
+		nfree(tn);
+		return 0;
+	}
+
+	al = talign(p->stype, p->sap);
+	noff = off = *poff;
+	tsz = (int)tsize(p->stype, p->sdf, p->sap);
+#ifdef BACKAUTO
+	if (p->sclass == AUTO) {
+		noff = off + tsz;
+		if (noff < 0)
+			cerror("stack overflow");
+		SETOFF(noff, al);
+		off = -noff;
+	} else
+#endif
+	if (p->sclass == PARAM && (p->stype == CHAR || p->stype == UCHAR ||
+	    p->stype == SHORT || p->stype == USHORT || p->stype == BOOL)) {
+		off = upoff(SZINT, ALINT, &noff);
+#ifndef RTOLBYTES
+		off = noff - tsz;
+#endif
+	} else {
+		off = upoff(tsz, al, &noff);
+	}
+
+	if (p->sclass != REGISTER) {
+	/* in case we are allocating stack space for register arguments */
+		if (p->soffset == NOOFFSET)
+			p->soffset = off;
+		else if(off != p->soffset)
+			return(1);
+	}
+
+	*poff = noff;
+	return(0);
+}
+
+/*
+ * Delay emission of code generated in argument headers.
+ */
+static void
+edelay(NODE *p)
+{
+	if (blevel == 1) {
+		/* Delay until after declarations */
+		if (parlink == NULL)
+			parlink = p;
+		else
+			parlink = block(COMOP, parlink, p, 0, 0, 0);
+	} else
+		ecomp(p);
+}
+
+/*
+ * Traverse through the array args, evaluate them and put the 
+ * resulting temp numbers in the dim fields.
+ */
+static void
+evalidx(struct symtab *sp)
+{
+	union dimfun *df;
+	NODE *p;
+	TWORD t;
+	int astkp = 0;
+
+	if (arrstk[0] == NIL)
+		astkp++; /* for parameter arrays */
+
+	if (isdyn(sp))
+		sp->sflags |= SDYNARRAY;
+
+	df = sp->sdf;
+	for (t = sp->stype; t > BTMASK; t = DECREF(t)) {
+		if (!ISARY(t))
+			continue;
+		if (df->ddim == -1) {
+			p = tempnode(0, INT, 0, MKAP(INT));
+			df->ddim = -regno(p);
+			edelay(buildtree(ASSIGN, p, arrstk[astkp++]));
+		}
+		df++;
+	}
+	arrstkp = 0;
+}
+
+/*
+ * Return 1 if dynamic array, 0 otherwise.
+ */
+int
+isdyn(struct symtab *sp)
+{
+	union dimfun *df = sp->sdf;
+	TWORD t;
+
+	for (t = sp->stype; t > BTMASK; t = DECREF(t)) {
+		if (!ISARY(t))
+			return 0;
+		if (df->ddim < 0 && df->ddim != NOOFFSET)
+			return 1;
+		df++;
+	}
+	return 0;
+}
+
+/*
+ * Allocate space on the stack for dynamic arrays (or at least keep track
+ * of the index).
+ * Strategy is as follows:
+ * - first entry is a pointer to the dynamic datatype.
+ * - if it's a one-dimensional array this will be the only entry used.
+ * - if it's a multi-dimensional array the following (numdim-1) integers
+ *   will contain the sizes to multiply the indexes with.
+ * - code to write the dimension sizes this will be generated here.
+ * - code to allocate space on the stack will be generated here.
+ */
+static void
+dynalloc(struct symtab *p, int *poff)
+{
+	union dimfun *df;
+	NODE *n, *tn, *pol;
+	TWORD t;
+
+	/*
+	 * The pointer to the array is not necessarily stored in a
+	 * TEMP node, but if it is, its number is in the soffset field;
+	 */
+	t = p->stype;
+	p->sflags |= STNODE;
+	p->stype = INCREF(p->stype); /* Make this an indirect pointer */
+	tn = tempnode(0, p->stype, p->sdf, p->sap);
+	p->soffset = regno(tn);
+
+	df = p->sdf;
+
+	pol = bcon(1);
+	for (; t > BTMASK; t = DECREF(t)) {
+		if (!ISARY(t))
+			break;
+		if (df->ddim < 0)
+			n = tempnode(-df->ddim, INT, 0, MKAP(INT));
+		else
+			n = bcon(df->ddim);
+
+		pol = buildtree(MUL, pol, n);
+		df++;
+	}
+	/* Create stack gap */
+	spalloc(tn, pol, tsize(t, 0, p->sap));
+}
+
+/*
+ * allocate a field of width w
+ * new is 0 if new entry, 1 if redefinition, -1 if alignment
+ */
+int
+falloc(struct symtab *p, int w, NODE *pty)
+{
+	int al,sz,type;
+
+	type = p ? p->stype : pty->n_type;
+
+	if (type == BOOL)
+		type = BOOL_TYPE;
+	if (type < CHAR || type > ULONGLONG) {
+		uerror("illegal field type");
+		type = INT;
+	}
+
+	al = btattr[type].aalign;
+	sz = btattr[type].atypsz;
+
+	if (w > sz) {
+		uerror("field too big");
+		w = sz;
+	}
+
+	if (w == 0) { /* align only */
+		SETOFF(rpole->rstr, al);
+		if (p != NULL)
+			uerror("zero size field");
+		return(0);
+	}
+
+	if (rpole->rstr%al + w > sz)
+		SETOFF(rpole->rstr, al);
+	if (p == NULL) {
+		rpole->rstr += w;  /* we know it will fit */
+		return(0);
+	}
+
+	/* establish the field */
+
+	p->soffset = rpole->rstr;
+	rpole->rstr += w;
+	p->stype = type;
+	fldty(p);
+	return(0);
+}
+
+/*
+ * handle unitialized declarations assumed to be not functions:
+ * int a;
+ * extern int a;
+ * static int a;
+ */
+void
+nidcl(NODE *p, int class)
+{
+	struct symtab *sp;
+	int commflag = 0;
+
+	/* compute class */
+	if (class == SNULL) {
+		if (blevel > 1)
+			class = AUTO;
+		else if (blevel != 0 || rpole)
+			cerror( "nidcl error" );
+		else /* blevel = 0 */
+			commflag = 1, class = EXTERN;
+	}
+
+	defid(p, class);
+
+#ifdef GCC_COMPAT
+	if (p->n_op == CM)
+		cerror("nidcl CM");
+#endif
+
+	sp = p->n_sp;
+	/* check if forward decl */
+	if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET)
+		return;
+
+	if (sp->sflags & SASG)
+		return; /* already initialized */
+
+	switch (class) {
+	case EXTDEF:
+		/* simulate initialization by 0 */
+		simpleinit(p->n_sp, bcon(0));
+		break;
+	case EXTERN:
+		if (commflag)
+			lcommadd(p->n_sp);
+		else
+			extdec(p->n_sp);
+		break;
+	case STATIC:
+		if (blevel == 0)
+			lcommadd(p->n_sp);
+		else
+			defzero(p->n_sp);
+		break;
+	}
+}
+
+struct lcd {
+	SLIST_ENTRY(lcd) next;
+	struct symtab *sp;
+};
+
+static SLIST_HEAD(, lcd) lhead = { NULL, &lhead.q_forw};
+
+/*
+ * Add a local common statement to the printout list.
+ */
+void
+lcommadd(struct symtab *sp)
+{
+	struct lcd *lc, *lcp;
+
+	lcp = NULL;
+	SLIST_FOREACH(lc, &lhead, next) {
+		if (lc->sp == sp)
+			return; /* already exists */
+		if (lc->sp == NULL && lcp == NULL)
+			lcp = lc;
+	}
+	if (lcp == NULL) {
+		lc = permalloc(sizeof(struct lcd));
+		lc->sp = sp;
+		SLIST_INSERT_LAST(&lhead, lc, next);
+	} else
+		lcp->sp = sp;
+}
+
+/*
+ * Delete a local common statement.
+ */
+void
+lcommdel(struct symtab *sp)
+{
+	struct lcd *lc;
+
+	SLIST_FOREACH(lc, &lhead, next) {
+		if (lc->sp == sp) {
+			lc->sp = NULL;
+			return;
+		}
+	}
+}
+
+/*
+ * Print out the remaining common statements.
+ */
+void
+lcommprint(void)
+{
+	struct lcd *lc;
+
+	SLIST_FOREACH(lc, &lhead, next) {
+		if (lc->sp != NULL)
+			defzero(lc->sp);
+	}
+}
+
+/*
+ * Merge given types to a single node.
+ * Any type can end up here.
+ * p is the old node, q is the old (if any).
+ * CLASS is AUTO, EXTERN, REGISTER, STATIC or TYPEDEF.
+ * QUALIFIER is VOL or CON
+ * TYPE is CHAR, SHORT, INT, LONG, SIGNED, UNSIGNED, VOID, BOOL, FLOAT,
+ * 	DOUBLE, STRTY, UNIONTY.
+ */
+struct typctx {
+	int class, qual, sig, uns, cmplx, imag, err;
+	TWORD type;
+	NODE *saved;
+	struct attr *pre, *post;
+};
+
+static void
+typwalk(NODE *p, void *arg)
+{
+	struct typctx *tc = arg;
+
+#define	cmop(x,y) block(CM, x, y, INT, 0, MKAP(INT))
+	switch (p->n_op) {
+	case ATTRIB:
+		if (tc->saved && (tc->saved->n_qual & 1)) {
+			tc->post = attr_add(tc->post,gcc_attr_parse(p->n_left));
+		} else {
+			tc->pre = attr_add(tc->pre, gcc_attr_parse(p->n_left));
+		}
+		p->n_left = bcon(0); /* For tfree() */
+		break;
+	case CLASS:
+		if (tc->class)
+			tc->err = 1; /* max 1 class */
+		tc->class = p->n_type;
+		break;
+
+	case QUALIFIER:
+#if 0
+		if (p->n_qual == 0)
+			uerror("invalid use of 'restrict'");
+#endif
+		tc->qual |= p->n_qual >> TSHIFT;
+		break;
+
+	case TYPE:
+		if (p->n_sp != NULL || ISSOU(p->n_type)) {
+			/* typedef, enum or struct/union */
+			if (tc->saved || tc->type)
+				tc->err = 1;
+#ifdef GCC_COMPAT
+			if (ISSOU(p->n_type) && p->n_left) {
+				if (tc->post)
+					cerror("typwalk");
+				tc->post = gcc_attr_parse(p->n_left);
+			}
+#endif
+			tc->saved = ccopy(p);
+			break;
+		}
+
+		switch (p->n_type) {
+		case BOOL:
+		case CHAR:
+		case FLOAT:
+		case VOID:
+			if (tc->type)
+				tc->err = 1;
+			tc->type = p->n_type;
+			break;
+		case DOUBLE:
+			if (tc->type == 0)
+				tc->type = DOUBLE;
+			else if (tc->type == LONG)
+				tc->type = LDOUBLE;
+			else
+				tc->err = 1;
+			break;
+		case SHORT:
+			if (tc->type == 0 || tc->type == INT)
+				tc->type = SHORT;
+			else
+				tc->err = 1;
+			break;
+		case INT:
+			if (tc->type == SHORT || tc->type == LONG ||
+			    tc->type == LONGLONG)
+				break;
+			else if (tc->type == 0)
+				tc->type = INT;
+			else
+				tc->err = 1;
+			break;
+		case LONG:
+			if (tc->type == 0)
+				tc->type = LONG;
+			else if (tc->type == INT)
+				break;
+			else if (tc->type == LONG)
+				tc->type = LONGLONG;
+			else if (tc->type == DOUBLE)
+				tc->type = LDOUBLE;
+			else
+				tc->err = 1;
+			break;
+		case SIGNED:
+			if (tc->sig || tc->uns)
+				tc->err = 1;
+			tc->sig = 1;
+			break;
+		case UNSIGNED:
+			if (tc->sig || tc->uns)
+				tc->err = 1;
+			tc->uns = 1;
+			break;
+		case COMPLEX:
+			tc->cmplx = 1;
+			break;
+		case IMAG:
+			tc->imag = 1;
+			break;
+		default:
+			cerror("typwalk");
+		}
+	}
+
+}
+
+NODE *
+typenode(NODE *p)
+{
+	struct symtab *sp;
+	struct typctx tc;
+	NODE *q;
+	char *c;
+
+	memset(&tc, 0, sizeof(struct typctx));
+
+	flist(p, typwalk, &tc);
+	tfree(p);
+
+	if (tc.err)
+		goto bad;
+
+	if (tc.cmplx || tc.imag) {
+		if (tc.type == 0)
+			tc.type = DOUBLE;
+		if ((tc.cmplx && tc.imag) || tc.sig || tc.uns ||
+		    !ISFTY(tc.type))
+			goto bad;
+		if (tc.cmplx) {
+			c = tc.type == DOUBLE ? "0d" :
+			    tc.type == FLOAT ? "0f" : "0l";
+			sp = lookup(addname(c), 0);
+			tc.type = STRTY;
+			tc.saved = mkty(tc.type, sp->sdf, sp->sap);
+			tc.saved->n_sp = sp;
+			tc.type = 0;
+		} else
+			tc.type += (FIMAG-FLOAT);
+	}
+
+	if (tc.saved && tc.type)
+		goto bad;
+	if (tc.sig || tc.uns) {
+		if (tc.type == 0)
+			tc.type = tc.sig ? INT : UNSIGNED;
+		if (tc.type > ULONGLONG)
+			goto bad;
+		if (tc.uns)
+			tc.type = ENUNSIGN(tc.type);
+	}
+
+	if (funsigned_char && tc.type == CHAR && tc.sig == 0)
+		tc.type = UCHAR;
+
+#ifdef GCC_COMPAT
+	if (pragma_packed) {
+		q = bdty(CALL, bdty(NAME, "packed"), bcon(pragma_packed));
+		tc.post = attr_add(tc.post, gcc_attr_parse(q));
+	}
+	if (pragma_aligned) {
+		/* Deal with relevant pragmas */
+		q = bdty(CALL, bdty(NAME, "aligned"), bcon(pragma_aligned));
+		tc.post = attr_add(tc.post, gcc_attr_parse(q));
+	}
+	pragma_aligned = pragma_packed = 0;
+#endif
+	if ((q = tc.saved) == NULL) {
+		TWORD t;
+		if ((t = BTYPE(tc.type)) > LDOUBLE && t != VOID &&
+		    t != BOOL && !(t >= FIMAG && t <= LIMAG))
+			cerror("typenode2 t %x", tc.type);
+		if (t == UNDEF) {
+			t = INT;
+			MODTYPE(tc.type, INT);
+		}
+		q =  mkty(tc.type, 0, MKAP(t));
+	}
+	q->n_ap = attr_add(q->n_ap, tc.post);
+	q->n_qual = tc.qual;
+	q->n_lval = tc.class;
+#ifdef GCC_COMPAT
+	if (tc.post) {
+		/* Can only occur for TYPEDEF, STRUCT or UNION */
+		if (tc.saved == NULL)
+			cerror("typenode");
+	}
+	if (tc.pre)
+		q->n_ap = attr_add(q->n_ap, tc.pre);
+	gcc_tcattrfix(q);
+#endif
+	return q;
+
+bad:	uerror("illegal type combination");
+	return mkty(INT, 0, 0);
+}
+
+struct tylnk {
+	struct tylnk *next;
+	union dimfun df;
+};
+
+static void tyreduce(NODE *p, struct tylnk **, int *);
+
+static void
+tylkadd(union dimfun dim, struct tylnk **tylkp, int *ntdim)
+{
+	(*tylkp)->next = tmpalloc(sizeof(struct tylnk));
+	*tylkp = (*tylkp)->next;
+	(*tylkp)->next = NULL;
+	(*tylkp)->df = dim;
+	(*ntdim)++;
+}
+
+/*
+ * merge type typ with identifier idp.
+ * idp is returned as a NAME node with correct types,
+ * typ is untouched since multiple declarations uses it.
+ * typ has type attributes, idp can never carry such attributes
+ * so on return just a pointer to the typ attributes is returned.
+ */
+NODE *
+tymerge(NODE *typ, NODE *idp)
+{
+	TWORD t;
+	NODE *p;
+	union dimfun *j;
+	struct tylnk *base, tylnk, *tylkp;
+	struct attr *ap, *bap;
+	int ntdim, i;
+
+#ifdef PCC_DEBUG
+	if (ddebug > 2) {
+		printf("tymerge(%p,%p)\n", typ, idp);
+		fwalk(typ, eprint, 0);
+		fwalk(idp, eprint, 0);
+	}
+#endif
+
+	if (typ->n_op == CM || idp->n_op == CM)
+		cerror("tymerge CM");
+
+	if (typ->n_op != TYPE)
+		cerror("tymerge: arg 1");
+
+	bap = typ->n_ap;
+
+	idp->n_type = typ->n_type;
+	idp->n_qual |= typ->n_qual;
+
+	tylkp = &tylnk;
+	tylkp->next = NULL;
+	ntdim = 0;
+
+	tyreduce(idp, &tylkp, &ntdim);
+
+	for (t = typ->n_type, j = typ->n_df; t&TMASK; t = DECREF(t))
+		if (ISARY(t) || ISFTN(t))
+			tylkadd(*j++, &tylkp, &ntdim);
+
+	if (ntdim) {
+		union dimfun *a = permalloc(sizeof(union dimfun) * ntdim);
+		dimfuncnt += ntdim;
+		for (i = 0, base = tylnk.next; base; base = base->next, i++)
+			a[i] = base->df;
+		idp->n_df = a;
+	} else
+		idp->n_df = NULL;
+
+	/* now idp is a single node: fix up type */
+	if ((t = ctype(idp->n_type)) != idp->n_type) {
+		idp->n_type = t;
+		t = BTYPE(t);
+		if (bap->atype == ATTR_BASETYP)
+			bap = MKAP(t);
+		else {
+			for (ap = bap; 
+			    ap->next->atype != ATTR_BASETYP; ap = ap->next)
+				;
+			ap->next = MKAP(t);
+		}
+	}
+	
+	if (idp->n_op != NAME) {
+		for (p = idp->n_left; p->n_op != NAME; p = p->n_left)
+			nfree(p);
+		nfree(p);
+		idp->n_op = NAME;
+	}
+	idp->n_ap = bap;
+
+	return(idp);
+}
+
+/*
+ * Retrieve all CM-separated argument types, sizes and dimensions and
+ * put them in an array.
+ * XXX - can only check first type level, side effects?
+ */
+static union arglist *
+arglist(NODE *n)
+{
+	union arglist *al;
+	NODE *w = n, **ap;
+	int num, cnt, i, j, k;
+	TWORD ty;
+
+#ifdef PCC_DEBUG
+	if (pdebug) {
+		printf("arglist %p\n", n);
+		fwalk(n, eprint, 0);
+	}
+#endif
+	/* First: how much to allocate */
+	for (num = cnt = 0, w = n; w->n_op == CM; w = w->n_left) {
+		cnt++;	/* Number of levels */
+		num++;	/* At least one per step */
+		if (w->n_right->n_op == ELLIPSIS)
+			continue;
+		ty = w->n_right->n_type;
+		if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY)
+			num++;
+		while (ISFTN(ty) == 0 && ISARY(ty) == 0 && ty > BTMASK)
+			ty = DECREF(ty);
+		if (ty > BTMASK)
+			num++;
+	}
+	cnt++;
+	ty = w->n_type;
+	if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY)
+		num++;
+	while (ISFTN(ty) == 0 && ISARY(ty) == 0 && ty > BTMASK)
+		ty = DECREF(ty);
+	if (ty > BTMASK)
+		num++;
+	num += 2; /* TEND + last arg type */
+
+	/* Second: Create list to work on */
+	ap = tmpalloc(sizeof(NODE *) * cnt);
+	al = permalloc(sizeof(union arglist) * num);
+	arglistcnt += num;
+
+	for (w = n, i = 0; w->n_op == CM; w = w->n_left)
+		ap[i++] = w->n_right;
+	ap[i] = w;
+
+	/* Third: Create actual arg list */
+	for (k = 0, j = i; j >= 0; j--) {
+		if (ap[j]->n_op == ELLIPSIS) {
+			al[k++].type = TELLIPSIS;
+			ap[j]->n_op = ICON; /* for tfree() */
+			continue;
+		}
+		/* Convert arrays to pointers */
+		if (ISARY(ap[j]->n_type)) {
+			ap[j]->n_type += (PTR-ARY);
+			ap[j]->n_df++;
+		}
+		/* Convert (silently) functions to pointers */
+		if (ISFTN(ap[j]->n_type))
+			ap[j]->n_type = INCREF(ap[j]->n_type);
+		ty = ap[j]->n_type;
+#ifdef GCC_COMPAT
+		if (ty == UNIONTY &&
+		    attr_find(ap[j]->n_ap, GCC_ATYP_TRANSP_UNION)){
+			/* transparent unions must have compatible types
+			 * shortcut here: if pointers, set void *, 
+			 * otherwise btype.
+			 */
+			struct symtab *sp = strmemb(ap[j]->n_ap);
+			ty = ISPTR(sp->stype) ? PTR|VOID : sp->stype;
+		}
+#endif
+		al[k++].type = ty;
+		if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY)
+			al[k++].sap = ap[j]->n_ap;
+		while (ISFTN(ty) == 0 && ISARY(ty) == 0 && ty > BTMASK)
+			ty = DECREF(ty);
+		if (ty > BTMASK)
+			al[k++].df = ap[j]->n_df;
+	}
+	al[k++].type = TNULL;
+	if (k > num)
+		cerror("arglist: k%d > num%d", k, num);
+	tfree(n);
+#ifdef PCC_DEBUG
+	if (pdebug)
+		alprint(al, 0);
+#endif
+	return al;
+}
+
+/*
+ * build a type, and stash away dimensions,
+ * from a parse tree of the declaration
+ * the type is build top down, the dimensions bottom up
+ */
+void
+tyreduce(NODE *p, struct tylnk **tylkp, int *ntdim)
+{
+	union dimfun dim;
+	NODE *r = NULL;
+	int o;
+	TWORD t, q;
+
+	o = p->n_op;
+	if (o == NAME) {
+		p->n_qual = DECQAL(p->n_qual);
+		return;
+	}
+
+	t = INCREF(p->n_type);
+	q = p->n_qual;
+	switch (o) {
+	case CALL:
+		t += (FTN-PTR);
+		dim.dfun = arglist(p->n_right);
+		break;
+	case UCALL:
+		t += (FTN-PTR);
+		dim.dfun = NULL;
+		break;
+	case LB:
+		t += (ARY-PTR);
+		if (p->n_right->n_op != ICON) {
+			r = p->n_right;
+			o = RB;
+		} else {
+			dim.ddim = (int)p->n_right->n_lval;
+			nfree(p->n_right);
+#ifdef notdef
+	/* XXX - check dimensions at usage time */
+			if (dim.ddim == NOOFFSET && p->n_left->n_op == LB)
+				uerror("null dimension");
+#endif
+		}
+		break;
+	}
+
+	p->n_left->n_type = t;
+	p->n_left->n_qual = INCQAL(q) | p->n_left->n_qual;
+	tyreduce(p->n_left, tylkp, ntdim);
+
+	if (o == LB || o == (UCALL) || o == CALL)
+		tylkadd(dim, tylkp, ntdim);
+	if (o == RB) {
+		dim.ddim = -1;
+		tylkadd(dim, tylkp, ntdim);
+		arrstk[arrstkp++] = r;
+	}
+
+	p->n_sp = p->n_left->n_sp;
+	p->n_type = p->n_left->n_type;
+	p->n_qual = p->n_left->n_qual;
+}
+
+static NODE *
+argcast(NODE *p, TWORD t, union dimfun *d, struct attr *ap)
+{
+	NODE *u, *r = talloc();
+
+	r->n_op = NAME;
+	r->n_type = t;
+	r->n_qual = 0; /* XXX */
+	r->n_df = d;
+	r->n_ap = ap;
+
+	u = buildtree(CAST, r, p);
+	nfree(u->n_left);
+	r = u->n_right;
+	nfree(u);
+	return r;
+}
+
+#ifdef PCC_DEBUG
+/*
+ * Print a prototype.
+ */
+static void
+alprint(union arglist *al, int in)
+{
+	TWORD t;
+	int i = 0, j;
+
+	for (; al->type != TNULL; al++) {
+		for (j = in; j > 0; j--)
+			printf("  ");
+		printf("arg %d: ", i++);
+		t = al->type;
+		tprint(stdout, t, 0);
+		while (t > BTMASK) {
+			if (ISARY(t)) {
+				al++;
+				printf(" dim %d ", al->df->ddim);
+			} else if (ISFTN(t)) {
+				al++;
+				alprint(al->df->dfun, in+1);
+			}
+			t = DECREF(t);
+		}
+		if (ISSOU(t)) {
+			al++;
+			struct attr *ap = attr_find(al->sap, ATTR_BASETYP);
+			printf(" (size %d align %d)", ap->atypsz,
+			    ap->aalign);
+		}
+		printf("\n");
+	}
+	if (in == 0)
+		printf("end arglist\n");
+}
+#endif
+int
+suemeq(struct attr *s1, struct attr *s2)
+{
+
+	return (strmemb(s1) == strmemb(s2));
+}
+
+/*
+ * Sanity-check old-style args.
+ */
+static NODE *
+oldarg(NODE *p)
+{
+	if (p->n_op == TYPE)
+		uerror("type is not an argument");
+	if (p->n_type == FLOAT)
+		return cast(p, DOUBLE, p->n_qual);
+	return p;
+}
+
+/*
+ * Do prototype checking and add conversions before calling a function.
+ * Argument f is function and a is a CM-separated list of arguments.
+ * Returns a merged node (via buildtree() of function and arguments.
+ */
+NODE *
+doacall(struct symtab *sp, NODE *f, NODE *a)
+{
+	NODE *w, *r;
+	union arglist *al;
+	struct ap {
+		struct ap *next;
+		NODE *node;
+	} *at, *apole = NULL;
+	int argidx/* , hasarray = 0*/;
+	TWORD type, arrt;
+
+#ifdef PCC_DEBUG
+	if (ddebug) {
+		printf("doacall.\n");
+		fwalk(f, eprint, 0);
+		if (a)
+			fwalk(a, eprint, 0);
+	}
+#endif
+
+	/* First let MD code do something */
+	calldec(f, a);
+/* XXX XXX hack */
+	if ((f->n_op == CALL) &&
+	    f->n_left->n_op == ADDROF &&
+	    f->n_left->n_left->n_op == NAME &&
+	    (f->n_left->n_left->n_type & 0x7e0) == 0x4c0)
+		goto build;
+/* XXX XXX hack */
+
+#ifndef NO_C_BUILTINS
+	/* check for builtins. function pointers are not allowed */
+	if (f->n_op == NAME &&
+	    f->n_sp->sname[0] == '_' && f->n_sp->sname[1] == '_')
+		if ((w = builtin_check(f, a)) != NIL)
+			return w;
+#endif
+
+	/* Check for undefined or late defined enums */
+	if (BTYPE(f->n_type) == ENUMTY) {
+		/* not-yet check if declared enum */
+		struct symtab *sq = strmemb(f->n_ap);
+		if (sq->stype != ENUMTY)
+			MODTYPE(f->n_type, sq->stype);
+		if (BTYPE(f->n_type) == ENUMTY)
+			uerror("enum %s not declared", sq->sname);
+	}
+
+	/*
+	 * Do some basic checks.
+	 */
+	if (f->n_df == NULL || (al = f->n_df[0].dfun) == NULL) {
+		/*
+		 * Handle non-prototype declarations.
+		 */
+		if (f->n_op == NAME && f->n_sp != NULL) {
+			if (strncmp(f->n_sp->sname, "__builtin", 9) != 0)
+				warner(Wmissing_prototypes, f->n_sp->sname);
+		} else
+			warner(Wmissing_prototypes, "<pointer>");
+
+		/* floats must be cast to double */
+		if (a == NULL)
+			goto build;
+		if (a->n_op != CM) {
+			a = oldarg(a);
+		} else {
+			for (w = a; w->n_left->n_op == CM; w = w->n_left)
+				w->n_right = oldarg(w->n_right);
+			w->n_left = oldarg(w->n_left);
+			w->n_right = oldarg(w->n_right);
+		}
+		goto build;
+	}
+	if (al->type == VOID) {
+		if (a != NULL)
+			uerror("function takes no arguments");
+		goto build; /* void function */
+	} else {
+		if (a == NULL) {
+			uerror("function needs arguments");
+			goto build;
+		}
+	}
+#ifdef PCC_DEBUG
+	if (pdebug) {
+		printf("arglist for %s\n",
+		    f->n_sp != NULL ? f->n_sp->sname : "function pointer");
+		alprint(al, 0);
+	}
+#endif
+
+	/*
+	 * Create a list of pointers to the nodes given as arg.
+	 */
+	for (w = a; w->n_op == CM; w = w->n_left) {
+		at = tmpalloc(sizeof(struct ap));
+		at->node = w->n_right;
+		at->next = apole;
+		apole = at;
+	}
+	at = tmpalloc(sizeof(struct ap));
+	at->node = w;
+	at->next = apole;
+	apole = at;
+
+	/*
+	 * Do the typechecking by walking up the list.
+	 */
+	argidx = 1;
+	while (al->type != TNULL) {
+		if (al->type == TELLIPSIS) {
+			/* convert the rest of float to double */
+			for (; apole; apole = apole->next) {
+				if (apole->node->n_type != FLOAT)
+					continue;
+				MKTY(apole->node, DOUBLE, 0, 0);
+			}
+			goto build;
+		}
+		if (apole == NULL) {
+			uerror("too few arguments to function");
+			goto build;
+		}
+/* al = prototyp, apole = argument till ftn */
+/* type = argumentets typ, arrt = prototypens typ */
+		type = apole->node->n_type;
+		arrt = al->type;
+#if 0
+		if ((hasarray = ISARY(arrt)))
+			arrt += (PTR-ARY);
+#endif
+		/* Taking addresses of arrays are meaningless in expressions */
+		/* but people tend to do that and also use in prototypes */
+		/* this is mostly a problem with typedefs */
+		if (ISARY(type)) {
+			if (ISPTR(arrt) && ISARY(DECREF(arrt)))
+				type = INCREF(type);
+			else
+				type += (PTR-ARY);
+		} else if (ISPTR(type) && !ISARY(DECREF(type)) &&
+		    ISPTR(arrt) && ISARY(DECREF(arrt))) {
+			type += (ARY-PTR);
+			type = INCREF(type);
+		}
+
+		/* Check structs */
+		if (type <= BTMASK && arrt <= BTMASK) {
+			if (type != arrt) {
+				if (ISSOU(BTYPE(type)) || ISSOU(BTYPE(arrt))) {
+incomp:					uerror("incompatible types for arg %d",
+					    argidx);
+				} else {
+					MKTY(apole->node, arrt, 0, 0)
+				}
+#ifndef NO_COMPLEX
+			} else if (type == STRTY &&
+			    attr_find(apole->node->n_ap, ATTR_COMPLEX) &&
+			    attr_find(al[1].sap, ATTR_COMPLEX)) {
+				/* Both are complex */
+				if (strmemb(apole->node->n_ap)->stype !=
+				    strmemb(al[1].sap)->stype) {
+					/* must convert to correct type */
+					w = talloc();
+					*w = *apole->node;
+					w = mkcmplx(w,
+					    strmemb(al[1].sap)->stype);
+					*apole->node = *w;
+					nfree(w);
+				}
+				goto out;
+#endif
+			} else if (ISSOU(BTYPE(type))) {
+				if (!suemeq(apole->node->n_ap, al[1].sap))
+					goto incomp;
+			}
+			goto out;
+		}
+
+		/* XXX should (recusively) check return type and arg list of
+		   func ptr arg XXX */
+		if (ISFTN(DECREF(arrt)) && ISFTN(type))
+			type = INCREF(type);
+
+		/* Hereafter its only pointers (or arrays) left */
+		/* Check for struct/union intermixing with other types */
+		if (((type <= BTMASK) && ISSOU(BTYPE(type))) ||
+		    ((arrt <= BTMASK) && ISSOU(BTYPE(arrt))))
+			goto incomp;
+
+		/* Check for struct/union compatibility */
+		if (type == arrt) {
+			if (ISSOU(BTYPE(type))) {
+				if (suemeq(apole->node->n_ap, al[1].sap))
+					goto out;
+			} else
+				goto out;
+		}
+		if (BTYPE(arrt) == VOID && type > BTMASK)
+			goto skip; /* void *f = some pointer */
+		if (arrt > BTMASK && BTYPE(type) == VOID)
+			goto skip; /* some *f = void pointer */
+		if (apole->node->n_op == ICON && apole->node->n_lval == 0)
+			goto skip; /* Anything assigned a zero */
+
+		if ((type & ~BTMASK) == (arrt & ~BTMASK)) {
+			/* do not complain for pointers with signedness */
+			if ((DEUNSIGN(BTYPE(type)) == DEUNSIGN(BTYPE(arrt))) &&
+			    (BTYPE(type) != BTYPE(arrt))) {
+				warner(Wpointer_sign, NULL);
+				goto skip;
+			}
+		}
+
+		werror("implicit conversion of argument %d due to prototype",
+		    argidx);
+
+skip:		if (ISSOU(BTYPE(arrt))) {
+			MKTY(apole->node, arrt, 0, al[1].sap)
+		} else {
+			MKTY(apole->node, arrt, 0, MKAP(BTYPE(arrt)))
+		}
+
+out:		al++;
+		if (ISSOU(BTYPE(arrt)))
+			al++;
+#if 0
+		while (arrt > BTMASK && !ISFTN(arrt))
+			arrt = DECREF(arrt);
+		if (ISFTN(arrt) || hasarray)
+			al++;
+#else
+		while (arrt > BTMASK) {
+			if (ISARY(arrt) || ISFTN(arrt)) {
+				al++;
+				break;
+			}
+			arrt = DECREF(arrt);
+		}
+#endif
+		apole = apole->next;
+		argidx++;
+	}
+	if (apole != NULL)
+		uerror("too many arguments to function");
+
+build:	if (sp != NULL && (sp->sflags & SINLINE) && (w = inlinetree(sp, f, a)))
+		return w;
+	return buildtree(a == NIL ? UCALL : CALL, f, a);
+}
+
+static int
+chk2(TWORD type, union dimfun *dsym, union dimfun *ddef)
+{
+	while (type > BTMASK) {
+		switch (type & TMASK) {
+		case ARY:
+			/* may be declared without dimension */
+			if (dsym->ddim == NOOFFSET)
+				dsym->ddim = ddef->ddim;
+			if (dsym->ddim < 0 && ddef->ddim < 0)
+				; /* dynamic arrays as arguments */
+			else if (ddef->ddim > 0 && dsym->ddim != ddef->ddim)
+				return 1;
+			dsym++, ddef++;
+			break;
+		case FTN:
+			/* old-style function headers with function pointers
+			 * will most likely not have a prototype.
+			 * This is not considered an error.  */
+			if (ddef->dfun == NULL) {
+#ifdef notyet
+				werror("declaration not a prototype");
+#endif
+			} else if (chkftn(dsym->dfun, ddef->dfun))
+				return 1;
+			dsym++, ddef++;
+			break;
+		}
+		type = DECREF(type);
+	}
+	return 0;
+}
+
+/*
+ * Compare two function argument lists to see if they match.
+ */
+int
+chkftn(union arglist *usym, union arglist *udef)
+{
+	TWORD t2;
+	int ty, tyn;
+
+	if (usym == NULL)
+		return 0;
+	if (cftnsp != NULL && udef == NULL && usym->type == VOID)
+		return 0; /* foo() { function with foo(void); prototype */
+	if (udef == NULL && usym->type != TNULL)
+		return 1;
+	while (usym->type != TNULL) {
+		if (usym->type == udef->type)
+			goto done;
+		/*
+		 * If an old-style declaration, then all types smaller than
+		 * int are given as int parameters.
+		 */
+		if (intcompare) {
+			ty = BTYPE(usym->type);
+			tyn = BTYPE(udef->type);
+			if (ty == tyn || ty != INT)
+				return 1;
+			if (tyn == CHAR || tyn == UCHAR ||
+			    tyn == SHORT || tyn == USHORT)
+				goto done;
+			return 1;
+		} else
+			return 1;
+
+done:		ty = BTYPE(usym->type);
+		t2 = usym->type;
+		if (ISSOU(ty)) {
+			usym++, udef++;
+			if (suemeq(usym->sap, udef->sap) == 0)
+				return 1;
+		}
+
+		while (ISFTN(t2) == 0 && ISARY(t2) == 0 && t2 > BTMASK)
+			t2 = DECREF(t2);
+		if (t2 > BTMASK) {
+			usym++, udef++;
+			if (chk2(t2, usym->df, udef->df))
+				return 1;
+		}
+		usym++, udef++;
+	}
+	if (usym->type != udef->type)
+		return 1;
+	return 0;
+}
+
+void
+fixtype(NODE *p, int class)
+{
+	unsigned int t, type;
+	int mod1, mod2;
+	/* fix up the types, and check for legality */
+
+	/* forward declared enums */
+	if (BTYPE(p->n_sp->stype) == ENUMTY) {
+		MODTYPE(p->n_sp->stype, strmemb(p->n_sp->sap)->stype);
+	}
+
+	if( (type = p->n_type) == UNDEF ) return;
+	if ((mod2 = (type&TMASK))) {
+		t = DECREF(type);
+		while( mod1=mod2, mod2 = (t&TMASK) ){
+			if( mod1 == ARY && mod2 == FTN ){
+				uerror( "array of functions is illegal" );
+				type = 0;
+				}
+			else if( mod1 == FTN && ( mod2 == ARY || mod2 == FTN ) ){
+				uerror( "function returns illegal type" );
+				type = 0;
+				}
+			t = DECREF(t);
+			}
+		}
+
+	/* detect function arguments, watching out for structure declarations */
+	if (rpole && ISFTN(type)) {
+		uerror("function illegal in structure or union");
+		type = INCREF(type);
+	}
+	p->n_type = type;
+}
+
+/*
+ * give undefined version of class
+ */
+int
+uclass(int class)
+{
+	if (class == SNULL)
+		return(EXTERN);
+	else if (class == STATIC)
+		return(USTATIC);
+	else
+		return(class);
+}
+
+int
+fixclass(int class, TWORD type)
+{
+	extern int fun_inline;
+
+	/* first, fix null class */
+	if (class == SNULL) {
+		if (fun_inline && ISFTN(type))
+			return SNULL;
+		if (rpole)
+			class = rpole->rsou == STNAME ? MOS : MOU;
+		else if (blevel == 0)
+			class = EXTDEF;
+		else
+			class = AUTO;
+	}
+
+	/* now, do general checking */
+
+	if( ISFTN( type ) ){
+		switch( class ) {
+		default:
+			uerror( "function has illegal storage class" );
+		case AUTO:
+			class = EXTERN;
+		case EXTERN:
+		case EXTDEF:
+		case TYPEDEF:
+		case STATIC:
+		case USTATIC:
+			;
+			}
+		}
+
+	if (class & FIELD) {
+		if (rpole && rpole->rsou != STNAME && rpole->rsou != UNAME)
+			uerror("illegal use of field");
+		return(class);
+	}
+
+	switch (class) {
+
+	case MOS:
+	case MOU:
+		if (rpole == NULL)
+			uerror("illegal member class");
+		return(class);
+
+	case REGISTER:
+		if (blevel == 0)
+			uerror("illegal register declaration");
+		if (blevel == 1)
+			return(PARAM);
+		else
+			return(AUTO);
+
+	case AUTO:
+		if( blevel < 2 ) uerror( "illegal ULABEL class" );
+		return( class );
+
+	case EXTERN:
+	case STATIC:
+	case EXTDEF:
+	case TYPEDEF:
+	case USTATIC:
+	case PARAM:
+		return( class );
+
+	default:
+		cerror( "illegal class: %d", class );
+		/* NOTREACHED */
+
+	}
+	return 0; /* XXX */
+}
+
+/*
+ * Generates a goto statement; sets up label number etc.
+ */
+void
+gotolabel(char *name)
+{
+	struct symtab *s = lookup(name, SLBLNAME);
+
+	if (s->soffset == 0)
+		s->soffset = -getlab();
+	branch(s->soffset < 0 ? -s->soffset : s->soffset);
+}
+
+/*
+ * Sets a label for gotos.
+ */
+void
+deflabel(char *name, NODE *p)
+{
+	struct symtab *s = lookup(name, SLBLNAME);
+
+	s->sap = gcc_attr_parse(p);
+	if (s->soffset > 0)
+		uerror("label '%s' redefined", name);
+	if (s->soffset == 0)
+		s->soffset = getlab();
+	if (s->soffset < 0)
+		s->soffset = -s->soffset;
+	plabel( s->soffset);
+}
+
+struct symtab *
+getsymtab(char *name, int flags)
+{
+	struct symtab *s;
+
+	if (flags & STEMP) {
+		s = tmpalloc(sizeof(struct symtab));
+	} else {
+		s = permalloc(sizeof(struct symtab));
+		symtabcnt++;
+	}
+	s->sname = name;
+	s->soname = NULL;
+	s->snext = NULL;
+	s->stype = UNDEF;
+	s->squal = 0;
+	s->sclass = SNULL;
+	s->sflags = (short)(flags & SMASK);
+	s->soffset = 0;
+	s->slevel = (char)blevel;
+	s->sdf = NULL;
+	s->sap = NULL;
+	return s;
+}
+
+int
+fldchk(int sz)
+{
+	if (rpole->rsou != STNAME && rpole->rsou != UNAME)
+		uerror("field outside of structure");
+	if (sz < 0 || sz >= FIELD) {
+		uerror("illegal field size");
+		return 1;
+	}
+	return 0;
+}
+
+#ifdef PCC_DEBUG
+static char *
+ccnames[] = { /* names of storage classes */
+	"SNULL",
+	"AUTO",
+	"EXTERN",
+	"STATIC",
+	"REGISTER",
+	"EXTDEF",
+	"LABEL",
+	"ULABEL",
+	"MOS",
+	"PARAM",
+	"STNAME",
+	"MOU",
+	"UNAME",
+	"TYPEDEF",
+	"FORTRAN",
+	"ENAME",
+	"MOE",
+	"UFORTRAN",
+	"USTATIC",
+	};
+
+char *
+scnames(int c)
+{
+	/* return the name for storage class c */
+	static char buf[12];
+	if( c&FIELD ){
+		snprintf( buf, sizeof(buf), "FIELD[%d]", c&FLDSIZ );
+		return( buf );
+		}
+	return( ccnames[c] );
+	}
+#endif
+
+static char *stack_chk_fail = "__stack_chk_fail";
+static char *stack_chk_guard = "__stack_chk_guard";
+static char *stack_chk_canary = "__stack_chk_canary";
+
+void
+sspinit()
+{
+	NODE *p;
+
+	p = block(NAME, NIL, NIL, FTN+VOID, 0, MKAP(VOID));
+	p->n_sp = lookup(stack_chk_fail, SNORMAL);
+	defid(p, EXTERN);
+	nfree(p);
+
+	p = block(NAME, NIL, NIL, INT, 0, MKAP(INT));
+	p->n_sp = lookup(stack_chk_guard, SNORMAL);
+	defid(p, EXTERN);
+	nfree(p);
+}
+
+void
+sspstart()
+{
+	NODE *p, *q;
+
+	q = block(NAME, NIL, NIL, INT, 0, MKAP(INT));
+ 	q->n_sp = lookup(stack_chk_guard, SNORMAL);
+	q = clocal(q);
+
+	p = block(REG, NIL, NIL, INT, 0, 0);
+	p->n_lval = 0;
+	p->n_rval = FPREG;
+	q = block(ER, p, q, INT, 0, MKAP(INT));
+	q = clocal(q);
+
+	p = block(NAME, NIL, NIL, INT, 0, MKAP(INT));
+	p->n_qual = VOL >> TSHIFT;
+	p->n_sp = lookup(stack_chk_canary, SNORMAL);
+	defid(p, AUTO);
+	p = clocal(p);
+	ecomp(buildtree(ASSIGN, p, q));
+}
+
+void
+sspend()
+{
+	NODE *p, *q;
+	TWORD t;
+	int lab;
+
+	if (retlab != NOLAB) {
+		plabel(retlab);
+		retlab = getlab();
+	}
+
+	t = DECREF(cftnsp->stype);
+	if (t == BOOL)
+		t = BOOL_TYPE;
+
+	p = block(NAME, NIL, NIL, INT, 0, MKAP(INT));
+	p->n_sp = lookup(stack_chk_canary, SNORMAL);
+	p = clocal(p);
+
+	q = block(REG, NIL, NIL, INT, 0, 0);
+	q->n_lval = 0;
+	q->n_rval = FPREG;
+	q = block(ER, p, q, INT, 0, MKAP(INT));
+
+	p = block(NAME, NIL, NIL, INT, 0, MKAP(INT));
+	p->n_sp = lookup(stack_chk_guard, SNORMAL);
+	p = clocal(p);
+
+	lab = getlab();
+	cbranch(buildtree(EQ, p, q), bcon(lab));
+
+	p = block(NAME, NIL, NIL, FTN+VOID, 0, MKAP(VOID));
+	p->n_sp = lookup(stack_chk_fail, SNORMAL);
+	p = clocal(p);
+
+	ecomp(buildtree(UCALL, p, NIL));
+
+	plabel(lab);
+}
+
+/*
+ * Allocate on the permanent heap for inlines, otherwise temporary heap.
+ */
+void *
+blkalloc(int size)
+{
+	return isinlining || blevel < 2 ?  permalloc(size) : tmpalloc(size);
+}
+
+/*
+ * Allocate on the permanent heap for inlines, otherwise temporary heap.
+ */
+void *
+inlalloc(int size)
+{
+	return isinlining ?  permalloc(size) : tmpalloc(size);
+}
+
+struct attr *
+attr_new(int type, int nelem)
+{
+	struct attr *ap;
+	int sz;
+
+	sz = sizeof(struct attr) + nelem * sizeof(union aarg);
+
+	ap = memset(blkalloc(sz), 0, sz);
+	ap->atype = type;
+	return ap;
+}
+
+/*
+ * Add attribute list new before old and return new.
+ */
+struct attr *
+attr_add(struct attr *old, struct attr *new)
+{
+	struct attr *ap;
+
+	if (new == NULL)
+		return old; /* nothing to add */
+
+	for (ap = new; ap->next; ap = ap->next)
+		;
+	ap->next = old;
+	return new;
+}
+
+/*
+ * Search for attribute type in list ap.  Return entry or NULL.
+ */
+struct attr *
+attr_find(struct attr *ap, int type)
+{
+
+	for (; ap && ap->atype != type; ap = ap->next)
+		;
+	return ap;
+}
+
+/*
+ * Copy an attribute struct.
+ * Return destination.
+ */
+struct attr *
+attr_copy(struct attr *aps, struct attr *apd, int n)
+{
+	int sz = sizeof(struct attr) + n * sizeof(union aarg);
+	return memcpy(apd, aps, sz);
+}
+
+/*
+ * Duplicate an attribute, like strdup.
+ */
+struct attr *
+attr_dup(struct attr *ap, int n)
+{
+	int sz = sizeof(struct attr) + n * sizeof(union aarg);
+	ap = memcpy(blkalloc(sz), ap, sz);
+	ap->next = NULL;
+	return ap;
+}
+
+/*
+ * Fetch pointer to first member in a struct list.
+ */
+struct symtab *
+strmemb(struct attr *ap)
+{
+
+	if ((ap = attr_find(ap, ATTR_STRUCT)) == NULL)
+		cerror("strmemb");
+	return ap->amlist;
+}
+
+#ifndef NO_COMPLEX
+
+static char *real, *imag;
+static struct symtab *cxsp[3];
+/*
+ * As complex numbers internally are handled as structs, create
+ * these by hand-crafting them.
+ */
+void
+complinit()
+{
+	struct attr *ap;
+	struct rstack *rp;
+	NODE *p, *q;
+	char *n[] = { "0f", "0d", "0l" };
+	int i, odebug;
+
+	odebug = ddebug;
+	ddebug = 0;
+	real = addname("__real");
+	imag = addname("__imag");
+	p = block(NAME, NIL, NIL, FLOAT, 0, MKAP(FLOAT));
+	for (i = 0; i < 3; i++) {
+		p->n_type = FLOAT+i;
+		p->n_ap = MKAP(FLOAT+i);
+		rpole = rp = bstruct(NULL, STNAME, NULL);
+		soumemb(p, real, 0);
+		soumemb(p, imag, 0);
+		q = dclstruct(rp);
+		cxsp[i] = q->n_sp = lookup(addname(n[i]), 0);
+		defid(q, TYPEDEF);
+		ap = attr_new(ATTR_COMPLEX, 0);
+		q->n_sp->sap = attr_add(q->n_sp->sap, ap);
+		nfree(q);
+	}
+	nfree(p);
+	ddebug = odebug;
+}
+
+/*
+ * Return the highest real floating point type.
+ * Known that at least one type is complex or imaginary.
+ */
+static TWORD
+maxtyp(NODE *l, NODE *r)
+{
+	TWORD tl, tr, t;
+
+	tl = ANYCX(l) ? strmemb(l->n_ap)->stype : l->n_type;
+	tr = ANYCX(r) ? strmemb(r->n_ap)->stype : r->n_type;
+	if (ISITY(tl))
+		tl -= (FIMAG - FLOAT);
+	if (ISITY(tr))
+		tr -= (FIMAG - FLOAT);
+	t = tl > tr ? tl : tr;
+	if (!ISFTY(t))
+		cerror("maxtyp");
+	return t;
+}
+
+/*
+ * Fetch space on stack for complex struct.
+ */
+static NODE *
+cxstore(TWORD t)
+{
+	struct symtab s;
+
+	s = *cxsp[t - FLOAT];
+	s.sclass = AUTO;
+	s.soffset = NOOFFSET;
+	oalloc(&s, &autooff);
+	return nametree(&s);
+}
+
+#define	comop(x,y) buildtree(COMOP, x, y)
+
+static NODE *
+mkcmplx(NODE *p, TWORD dt)
+{
+	NODE *q, *r, *i, *t;
+
+	if (!ANYCX(p)) {
+		/* Not complex, convert to complex on stack */
+		q = cxstore(dt);
+		if (ISITY(p->n_type)) {
+			p->n_type = p->n_type - FIMAG + FLOAT;
+			r = bcon(0);
+			i = p;
+		} else {
+			r = p;
+			i = bcon(0);
+		}
+		p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), r);
+		p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), i));
+		p = comop(p, q);
+	} else {
+		if (strmemb(p->n_ap)->stype != dt) {
+			q = cxstore(dt);
+			p = buildtree(ADDROF, p, NIL);
+			t = tempnode(0, p->n_type, p->n_df, p->n_ap);
+			p = buildtree(ASSIGN, ccopy(t), p);
+			p = comop(p, buildtree(ASSIGN,
+			    structref(ccopy(q), DOT, real),
+			    structref(ccopy(t), STREF, real)));
+			p = comop(p, buildtree(ASSIGN,
+			    structref(ccopy(q), DOT, imag),
+			    structref(t, STREF, imag)));
+			p = comop(p, q);
+		}
+	}
+	return p;
+}
+
+static NODE *
+cxasg(NODE *l, NODE *r)
+{
+	TWORD tl, tr;
+
+	tl = strattr(l->n_ap) ? strmemb(l->n_ap)->stype : 0;
+	tr = strattr(r->n_ap) ? strmemb(r->n_ap)->stype : 0;
+
+	if (ANYCX(l) && ANYCX(r) && tl != tr) {
+		/* different types in structs */
+		r = mkcmplx(r, tl);
+	} else if (!ANYCX(l))
+		r = structref(r, DOT, ISITY(l->n_type) ? imag : real);
+	else if (!ANYCX(r))
+		r = mkcmplx(r, tl);
+	return buildtree(ASSIGN, l, r);
+}
+
+/*
+ * Fixup complex operations.
+ * At least one operand is complex.
+ */
+NODE *
+cxop(int op, NODE *l, NODE *r)
+{
+	TWORD mxtyp;
+	NODE *p, *q;
+	NODE *ltemp, *rtemp;
+	NODE *real_l, *imag_l;
+	NODE *real_r, *imag_r;
+
+	if (op == ASSIGN)
+		return cxasg(l, r);
+
+	mxtyp = maxtyp(l, r);
+	l = mkcmplx(l, mxtyp);
+	r = mkcmplx(r, mxtyp);
+
+
+	/* put a pointer to left and right elements in a TEMP */
+	l = buildtree(ADDROF, l, NIL);
+	ltemp = tempnode(0, l->n_type, l->n_df, l->n_ap);
+	l = buildtree(ASSIGN, ccopy(ltemp), l);
+
+	r = buildtree(ADDROF, r, NIL);
+	rtemp = tempnode(0, r->n_type, r->n_df, r->n_ap);
+	r = buildtree(ASSIGN, ccopy(rtemp), r);
+
+	p = comop(l, r);
+
+	/* create the four trees needed for calculation */
+	real_l = structref(ccopy(ltemp), STREF, real);
+	real_r = structref(ccopy(rtemp), STREF, real);
+	imag_l = structref(ltemp, STREF, imag);
+	imag_r = structref(rtemp, STREF, imag);
+
+	/* get storage on stack for the result */
+	q = cxstore(mxtyp);
+
+	switch (op) {
+	case NE:
+	case EQ:
+		tfree(q);
+		p = buildtree(op, comop(p, real_l), real_r);
+		q = buildtree(op, imag_l, imag_r);
+		p = buildtree(op == EQ ? ANDAND : OROR, p, q);
+		return p;
+
+	case PLUS:
+	case MINUS:
+		p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), 
+		    buildtree(op, real_l, real_r)));
+		p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), 
+		    buildtree(op, imag_l, imag_r)));
+		break;
+
+	case MUL:
+		/* Complex mul is "complex" */
+		/* (u+iv)*(x+iy)=((u*x)-(v*y))+i(v*x+y*u) */
+		p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real),
+		    buildtree(MINUS,
+		    buildtree(MUL, ccopy(real_r), ccopy(real_l)),
+		    buildtree(MUL, ccopy(imag_r), ccopy(imag_l)))));
+		p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag),
+		    buildtree(PLUS,
+		    buildtree(MUL, real_r, imag_l),
+		    buildtree(MUL, imag_r, real_l))));
+		break;
+
+	case DIV:
+		/* Complex div is even more "complex" */
+		/* (u+iv)/(x+iy)=(u*x+v*y)/(x*x+y*y)+i((v*x-u*y)/(x*x+y*y)) */
+		p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real),
+		    buildtree(DIV,
+		      buildtree(PLUS,
+			buildtree(MUL, ccopy(real_r), ccopy(real_l)),
+			buildtree(MUL, ccopy(imag_r), ccopy(imag_l))),
+		      buildtree(PLUS,
+			buildtree(MUL, ccopy(real_r), ccopy(real_r)),
+			buildtree(MUL, ccopy(imag_r), ccopy(imag_r))))));
+		p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real),
+		    buildtree(DIV,
+		      buildtree(MINUS,
+			buildtree(MUL, ccopy(imag_l), ccopy(real_r)),
+			buildtree(MUL, ccopy(real_l), ccopy(imag_r))),
+		      buildtree(PLUS,
+			buildtree(MUL, ccopy(real_r), ccopy(real_r)),
+			buildtree(MUL, ccopy(imag_r), ccopy(imag_r))))));
+		tfree(real_r);
+		tfree(real_l);
+		tfree(imag_r);
+		tfree(imag_l);
+		break;
+	default:
+		cerror("bad complex op %d", op);
+	}
+	return comop(p, q);
+}
+
+/*
+ * Fixup imaginary operations.
+ * At least one operand is imaginary, none is complex.
+ */
+NODE *
+imop(int op, NODE *l, NODE *r)
+{
+	NODE *p, *q;
+	TWORD mxtyp;
+	int li, ri;
+
+	li = ri = 0;
+	if (ISITY(l->n_type))
+		li = 1, l->n_type = l->n_type - (FIMAG-FLOAT);
+	if (ISITY(r->n_type))
+		ri = 1, r->n_type = r->n_type - (FIMAG-FLOAT);
+
+	mxtyp = maxtyp(l, r);
+	switch (op) {
+	case ASSIGN:
+		/* if both are imag, store value, otherwise store 0.0 */
+		if (!(li && ri)) {
+			tfree(r);
+			r = bcon(0);
+		}
+		p = buildtree(ASSIGN, l, r);
+		p->n_type = p->n_type += (FIMAG-FLOAT);
+		break;
+
+	case PLUS:
+		if (li && ri) {
+			p = buildtree(PLUS, l, r);
+			p->n_type = p->n_type += (FIMAG-FLOAT);
+		} else {
+			/* If one is imaginary and one is real, make complex */
+			if (li)
+				q = l, l = r, r = q; /* switch */
+			q = cxstore(mxtyp);
+			p = buildtree(ASSIGN,
+			    structref(ccopy(q), DOT, real), l);
+			p = comop(p, buildtree(ASSIGN,
+			    structref(ccopy(q), DOT, imag), r));
+			p = comop(p, q);
+		}
+		break;
+
+	case MINUS:
+		if (li && ri) {
+			p = buildtree(MINUS, l, r);
+			p->n_type = p->n_type += (FIMAG-FLOAT);
+		} else if (li) {
+			q = cxstore(mxtyp);
+			p = buildtree(ASSIGN, structref(ccopy(q), DOT, real),
+			    buildtree(UMINUS, r, NIL));
+			p = comop(p, buildtree(ASSIGN,
+			    structref(ccopy(q), DOT, imag), l));
+			p = comop(p, q);
+		} else /* if (ri) */ {
+			q = cxstore(mxtyp);
+			p = buildtree(ASSIGN,
+			    structref(ccopy(q), DOT, real), l);
+			p = comop(p, buildtree(ASSIGN,
+			    structref(ccopy(q), DOT, imag),
+			    buildtree(UMINUS, r, NIL)));
+			p = comop(p, q);
+		}
+		break;
+
+	case MUL:
+		p = buildtree(MUL, l, r);
+		if (li && ri)
+			p = buildtree(UMINUS, p, NIL);
+		if (li ^ ri)
+			p->n_type = p->n_type += (FIMAG-FLOAT);
+		break;
+
+	case DIV:
+		p = buildtree(DIV, l, r);
+		if (ri && !li)
+			p = buildtree(UMINUS, p, NIL);
+		if (li ^ ri)
+			p->n_type = p->n_type += (FIMAG-FLOAT);
+		break;
+	default:
+		cerror("imop");
+		p = NULL;
+	}
+	return p;
+}
+
+NODE *
+cxelem(int op, NODE *p)
+{
+
+	if (ANYCX(p)) {
+		p = structref(p, DOT, op == XREAL ? real : imag);
+	} else if (op == XIMAG) {
+		/* XXX  sanitycheck? */
+		tfree(p);
+		p = bcon(0);
+	}
+	return p;
+}
+
+NODE *
+cxconj(NODE *p)
+{
+	NODE *q, *r;
+
+	/* XXX side effects? */
+	q = cxstore(strmemb(p->n_ap)->stype);
+	r = buildtree(ASSIGN, structref(ccopy(q), DOT, real),
+	    structref(ccopy(p), DOT, real));
+	r = comop(r, buildtree(ASSIGN, structref(ccopy(q), DOT, imag),
+	    buildtree(UMINUS, structref(p, DOT, imag), NIL)));
+	return comop(r, q);
+}
+
+/*
+ * Prepare for return.
+ * There may be implicit casts to other types.
+ */
+NODE *
+cxret(NODE *p, NODE *q)
+{
+//printf("cxret\n");
+//fwalk(p, eprint, 0);
+	if (ANYCX(q)) { /* Return complex type */
+		p = mkcmplx(p, strmemb(q->n_ap)->stype);
+	} else if (ISFTY(q->n_type) || ISITY(q->n_type)) { /* real or imag */
+		p = structref(p, DOT, ISFTY(q->n_type) ? real : imag);
+		if (p->n_type != q->n_type)
+			p = cast(p, q->n_type, 0);
+	} else 
+		cerror("cxred failing type");
+	return p;
+}
+#endif
Index: uspace/app/pcc/cc/ccom/scan.l
===================================================================
--- uspace/app/pcc/cc/ccom/scan.l	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/scan.l	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,773 @@
+%{
+/*	$Id: scan.l,v 1.102 2011/02/16 18:50:42 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2002 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+%}
+
+
+D			[0-9]
+L			[a-zA-Z_]
+H			[a-fA-F0-9]
+E			[Ee][+-]?{D}+
+P			[Pp][+-]?{D}+
+FS			(f|F|l|L)?i?
+IS			(u|U|l|L)*
+UL			({L}|\\u{H}{H}{H}{H}|\\U{H}{H}{H}{H}{H}{H}{H}{H})
+
+%{
+#include <stdlib.h>
+#include <errno.h>  
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "pass1.h"
+#include "cgram.h"
+
+static NODE *cvtdig(int radix);
+static NODE *charcon(void);
+static NODE *wcharcon(void);
+static void control(int);
+static void pragma(void);
+int notype, parbal, inattr, parlvl;
+static int resw(TWORD, int);
+
+#define	CPP_IDENT 	2
+#define	CPP_LINE 	3
+#define	CPP_HASH	4
+
+#ifdef STABS
+#define	STABS_LINE(x) if (gflag && cftnsp) stabs_line(x)
+#else
+#define STABS_LINE(x)
+#endif
+#if defined(FLEX_SCANNER) && YY_FLEX_SUBMINOR_VERSION == 31
+/* Hack to avoid unnecessary warnings */
+FILE *yyget_in  (void);
+FILE *yyget_out  (void);
+int yyget_leng  (void);
+char *yyget_text  (void);
+void yyset_in (FILE *);
+void yyset_out (FILE *);
+int yyget_debug  (void);
+void yyset_debug (int);
+int yylex_destroy  (void);
+extern int yyget_lineno (void);
+extern void yyset_lineno (int);
+#endif
+
+%}
+
+%%
+
+"__func__"		{
+				if (cftnsp == NULL)
+					uerror("__func__ outside function");
+				yylval.strp = cftnsp->sname; /* XXX - not C99 */
+				return(C_STRING);
+			}
+"asm"			{ return(C_ASM); }
+"auto"			{ 	return resw(AUTO, C_CLASS); }
+"_Bool"			{ 	return resw(BOOL, C_TYPE); }
+"break"			{ return(C_BREAK); }
+"case"			{ return(C_CASE); }
+"char"			{ 	return resw(CHAR, C_TYPE); }
+"_Complex"		{ 	return resw(COMPLEX, C_TYPE); }
+"const"			{ 	return resw(CON, C_QUALIFIER); }
+"continue"		{ return(C_CONTINUE); }
+"default"		{ return(C_DEFAULT); }
+"do"			{ return(C_DO); }
+"double"		{ 	return resw(DOUBLE, C_TYPE); }
+"else"			{ return(C_ELSE); }
+"enum"			{ notype=1; return(C_ENUM); }
+"extern"		{ 	return resw(EXTERN, C_CLASS); }
+"float"			{ 	return resw(FLOAT, C_TYPE); }
+"for"			{ return(C_FOR); }
+"goto"			{ notype=1; return(C_GOTO); }
+"if"			{ return(C_IF); }
+"_Imaginary"		{ 	return resw(IMAG, C_TYPE); }
+"inline"		{ return(C_FUNSPEC); }
+"int"			{ 	return resw(INT, C_TYPE); }
+"long"			{ 	return resw(LONG, C_TYPE); }
+"register"		{ 	return resw(REGISTER, C_CLASS); }
+"restrict"		{ ; /* just ignore */ }
+"return"		{ return(C_RETURN); }
+"short"			{ 	return resw(SHORT, C_TYPE); }
+"signed"		{ 	return resw(SIGNED, C_TYPE); }
+"sizeof"		{ return(C_SIZEOF); }
+"static"		{ 	return resw(STATIC, C_CLASS); }
+"struct"		{ yylval.intval = STNAME; notype=1; return(C_STRUCT); }
+"switch"		{ return(C_SWITCH); }
+"typedef"		{ 	return resw(TYPEDEF, C_CLASS); }
+"union"			{ yylval.intval = UNAME; notype=1; return(C_STRUCT); }
+"unsigned"		{ 	return resw(UNSIGNED, C_TYPE); }
+"void"			{ 	return resw(VOID, C_TYPE); }
+"volatile"		{	return resw(VOL, C_QUALIFIER); }
+"while"			{ return(C_WHILE); }
+
+{UL}({UL}|{D})*	{ 	struct symtab *s;
+			int i = 0;
+
+			yylval.strp = addname(yytext);
+#ifdef GCC_COMPAT
+			if ((i = gcc_keyword(yylval.strp, &yylval.nodep)) > 0)
+				return i;
+#endif
+			if (i == 0) {
+				if (notype)
+					return(C_NAME);
+				s = lookup(yylval.strp, SNOCREAT);
+				return s && s->sclass == TYPEDEF ?
+				    notype=1, C_TYPENAME : C_NAME;
+			}
+		}
+
+0[xX]{H}+{IS}?		{ yylval.nodep = cvtdig(16); return(C_ICON); }
+0{D}+{IS}?		{ yylval.nodep = cvtdig(8); return(C_ICON); }
+{D}+{IS}?		{ yylval.nodep = cvtdig(10); return(C_ICON); }
+L'(\\.|[^\\'])+'	{ yylval.nodep = wcharcon(); return(C_ICON); }
+'(\\.|[^\\'])+'		{ yylval.nodep = charcon(); return(C_ICON); }
+
+{D}+{E}{FS}?		{ yylval.nodep = floatcon(yytext); return(C_FCON); }
+{D}*"."{D}+({E})?{FS}?	{ yylval.nodep = floatcon(yytext); return(C_FCON); }
+{D}+"."{D}*({E})?{FS}?	{ yylval.nodep = floatcon(yytext); return(C_FCON); }
+0[xX]{H}*"."{H}+{P}{FS}? { yylval.nodep = fhexcon(yytext); return(C_FCON); }
+0[xX]{H}+"."{P}{FS}?	{ yylval.nodep = fhexcon(yytext); return(C_FCON); }
+0[xX]{H}+{P}{FS}?	{ yylval.nodep = fhexcon(yytext); return(C_FCON); }
+
+L?\"(\\.|[^\\"])*\"	{ yylval.strp = yytext; return C_STRING; }
+
+"..."			{ return(C_ELLIPSIS); }
+">>="			{ yylval.intval = RSEQ; return(C_ASOP); }
+"<<="			{ yylval.intval = LSEQ; return(C_ASOP); }
+"+="			{ yylval.intval = PLUSEQ; return(C_ASOP); }
+"-="			{ yylval.intval = MINUSEQ; return(C_ASOP); }
+"*="			{ yylval.intval = MULEQ; return(C_ASOP); }
+"/="			{ yylval.intval = DIVEQ; return(C_ASOP); }
+"%="			{ yylval.intval = MODEQ; return(C_ASOP); }
+"&="			{ yylval.intval = ANDEQ; return(C_ASOP); }
+"^="			{ yylval.intval = EREQ; return(C_ASOP); }
+"|="			{ yylval.intval = OREQ; return(C_ASOP); }
+">>"			{ yylval.intval = RS; return(C_SHIFTOP); }
+"<<"			{ yylval.intval = LS; return(C_SHIFTOP); }
+"++"			{ yylval.intval = INCR; return(C_INCOP); }
+"--"			{ yylval.intval = DECR; return(C_INCOP); }
+"->"			{ yylval.intval = STREF; return(C_STROP); }
+"&&"			{ yylval.intval = ANDAND; return(C_ANDAND); }
+"||"			{ yylval.intval = OROR; return(C_OROR); }
+"<="			{ yylval.intval = LE; return(C_RELOP); }
+">="			{ yylval.intval = GE; return(C_RELOP); }
+"=="			{ yylval.intval = EQ; return(C_EQUOP); }
+"!="			{ yylval.intval = NE; return(C_EQUOP); }
+";"			{ notype = 0; return(';'); }
+("{"|"<%")		{ notype = 0; return('{'); }
+("}"|"%>")		{ if (rpole) notype = 1; return('}'); }
+","			{ if (parbal) notype = 0; return(','); }
+":"			{ return(':'); }
+"="			{ return('='); }
+"("			{ parbal++; notype = 0; return('('); }
+")"			{	parbal--;
+				if (parbal==0) { notype = 0; }
+				if (inattr && parlvl == parbal)
+					inattr = 0;
+				return(')'); }
+("["|"<:")		{ return('['); }
+("]"|":>")		{ return(']'); }
+"."			{ yylval.intval = DOT; return(C_STROP); }
+"&"			{ return('&'); }
+"!"			{ yylval.intval = NOT; return(C_UNOP); }
+"~"			{ yylval.intval = COMPL; return(C_UNOP); }
+"-"			{ return('-'); }
+"+"			{ return('+'); }
+"*"			{ if (parbal && notype == 0) notype = 1; return('*'); }
+"/"			{ yylval.intval = DIV; return(C_DIVOP); }
+"%"			{ yylval.intval = MOD; return(C_DIVOP); }
+"<"			{ yylval.intval = LT; return(C_RELOP); }
+">"			{ yylval.intval = GT; return(C_RELOP); }
+"^"			{ return('^'); }
+"|"			{ return('|'); }
+"?"			{ return('?'); }
+^#pragma[ \t].*		{ pragma(); }
+^#ident[ \t].*		{ control(CPP_IDENT); }
+^#line[ \t].*		{ control(CPP_LINE); }
+^#.*			{ control(CPP_HASH); }
+
+[ \t\v\f]		{ }
+"\n"			{ ++lineno; STABS_LINE(lineno); }
+.			{ /* ignore bad characters */ }
+
+%%
+
+int lineno;
+char *ftitle = "<stdin>";
+
+int
+yywrap(void)
+{
+	if (0) unput(0); /* quiet gcc */
+	return(1);
+}
+
+int
+resw(TWORD t, int rv)
+{
+	if (inattr) {
+		yylval.strp = addname(yytext);
+		return C_NAME;
+	}
+
+	switch (rv) {
+	case C_CLASS:
+		yylval.nodep = block(CLASS, NIL, NIL, t, 0, 0);
+		return rv;
+
+	case C_QUALIFIER:
+		yylval.nodep = block(QUALIFIER, NIL, NIL, 0, 0, 0);
+		yylval.nodep->n_qual = t;
+		return rv;
+
+	case C_TYPE:
+		yylval.nodep = mkty(t, 0, MKAP(t));
+		notype=1;
+		return(rv);
+
+	default:
+		cerror("resw");
+	}
+	return 0;
+}
+
+#ifndef SOFTFLOAT
+
+static long double
+typround(long double dc, char *e, TWORD *tw)
+{
+	int im = 0;
+
+	*tw = DOUBLE;
+	for (; *e; e++) {
+		switch (*e) {
+		case 'f':
+		case 'F':
+			*tw = FLOAT;
+			dc = (float)dc;
+			break;
+		case 'l':
+		case 'L':
+			*tw = LDOUBLE;
+			break;
+		case 'i':
+		case 'I':
+			im = 1;
+			break;
+		}
+	}
+	if (*tw == DOUBLE)
+		dc = (double)dc;
+#ifndef NO_COMPLEX
+	if (im)
+		*tw += (FIMAG-FLOAT);
+#endif
+	return dc;
+}
+
+/*
+ * XXX floatcon() and fhexcon() should be in support libraries for
+ * the target floating point.
+ */
+static NODE *
+f2(char *str)
+{
+	TWORD tw;
+	NODE *p;
+	long double dc;
+	char *eptr;
+
+#ifdef HAVE_STRTOLD
+	dc = strtold(str, &eptr); /* XXX - avoid strtod() */
+#else
+	dc = strtod(str, &eptr); /* XXX - avoid strtod() */
+#endif
+	dc = typround(dc, eptr, &tw);
+	p = block(FCON, NIL, NIL, tw, 0, MKAP(tw));
+	p->n_dcon = dc;
+	return p;
+}
+
+NODE *
+floatcon(char *s)
+{
+	return f2(s);
+}
+
+static int
+h2n(int ch)
+{
+	if (ch >= '0' && ch <= '9')
+		return ch - '0';
+	if (ch >= 'a' && ch <= 'f')
+		return ch - 'a' + 10;
+	return ch - 'A' + 10;
+	
+}
+
+NODE *
+fhexcon(char *c)
+{
+	TWORD tw;
+	char *ep;
+	long double d;
+	int i, ed;
+	NODE *p;
+
+	d = 0.0;
+	ed = 0;
+	c+= 2; /* skip 0x */
+#define FSET(n) { d *= 2; if (i & n) d += 1.0; }
+	for (; *c != '.' && *c != 'p' && *c != 'P'; c++) {
+		i = h2n(*c);
+		FSET(8); FSET(4); FSET(2); FSET(1);
+	}
+	if (*c != '.' && *c != 'p' && *c != 'P')
+		cerror("fhexcon");
+	if (*c == '.') {
+		c++;
+		for (; *c != 'p' && *c != 'P'; c++) {
+			i = h2n(*c);
+			FSET(8); FSET(4); FSET(2); FSET(1);
+			ed -= 4;
+		}
+	}
+	if (*c != 'P' && *c != 'p')
+		cerror("fhexcon2");
+	c++;
+	ed += strtol(c, &ep, 10);
+
+	/* avoid looping in vain. Idea from Fred J. Tydeman */
+	if (ed > 32769) ed = 32769;
+	if (ed < -32769) ed = -32769;
+
+	while (ed > 0)
+		d *= 2, ed--;
+	while (ed < 0)
+		d /= 2, ed++;
+	d = typround(d, ep, &tw);
+	p = block(FCON, NIL, NIL, tw, 0, MKAP(tw));
+	p->n_dcon = d;
+	return p;
+}
+#endif
+
+unsigned int
+esccon(char **sptr)
+{
+	char *wr = *sptr;
+	char *owr;
+	char c;
+	unsigned int val;
+	int wsz = 4, esccon_warn = 1;
+
+	switch (*wr++) {
+	case 'a': val = '\a'; break;
+	case 'b': val = '\b'; break;
+	case 'f': val = '\f'; break;
+	case 'n': val = '\n'; break;
+	case 'r': val = '\r'; break;
+	case 't': val = '\t'; break;
+	case 'v': val = '\v'; break;
+	case '\"': val = '\"'; break;
+	case 'x': val = strtoul(wr, &wr, 16); break;
+	/* ISO/IEC 9099:1999 (E) 6.4.3 */
+	case 'U'|(char)0x80:
+		esccon_warn = 0;
+		/* FALLTHROUGH */
+	case 'U':
+		wsz = 8;
+		/* FALLTHROUGH */
+	case 'u':
+		owr = wr;
+		while (wr < (owr + wsz))
+			if (*wr == '\0')
+				break;
+			else
+				++wr;
+		if (wr != (owr + wsz)) {
+			/* incomplete */
+			val = strtoul(owr, &wr, 16);
+		} else {
+			c = owr[wsz];
+			owr[wsz] = '\0'; /* prevent it from reading too much */
+			val = strtoul(owr, &wr, 16);
+			owr[wsz] = c;
+		}
+		if (wr != (owr + wsz))
+			werror("incomplete universal character name");
+		if (wsz == 4)
+			val &= 0xFFFF;
+		if (esccon_warn && ((val >= 0xD800 && val <= 0xDFFF) ||
+		    (val < 0xA0 && val != 0x24 && val != 0x40 && val != 0x60)))
+			werror("invalid universal character name %04X", val);
+		break;
+	case '0': case '1': case '2': case '3': case '4': 
+	case '5': case '6': case '7':
+		val = wr[-1] - '0';
+		if (*wr >= '0' && *wr <= '7') {
+			val = (val << 3) + (*wr++ - '0');
+			if (*wr >= '0' && *wr <= '7')
+				val = (val << 3) + (*wr++ - '0');
+		}
+		break;
+	default: val = wr[-1];
+	}
+	*sptr = wr;
+	return val;
+}
+
+NODE *
+cvtdig(int radix)
+{
+	NODE *p;
+	TWORD ntype;
+	unsigned long long v;
+	char *ch = yytext;
+	int n, numl, numu;
+
+	if (radix == 16)
+		ch += 2; /* Skip 0x */
+	
+	v = 0;
+	while ((*ch >= '0' && *ch <= '9') || (*ch >= 'a' && *ch <= 'f') ||
+	    (*ch >= 'A' && *ch <= 'F')) {
+		v *= radix;
+		n = *ch;
+		n = (n <= '9' ? n - '0' : (n > 'F' ? n - 'a' : n - 'A') + 10);
+		ch++;
+		v += n;
+	}
+	/* Parse trailing chars */
+	ntype = INT;
+	numl = numu = 0;
+	for (n = 0; n < 3; n++) {
+		if (*ch == 0)
+			break;
+		if ((*ch == 'l' || *ch == 'L') && numl < 2)
+			ntype+=2, numl++;
+		else if ((*ch == 'u' || *ch == 'U') && numu < 1)
+			ntype = ENUNSIGN(ntype), numu++;
+		else
+			break;
+		ch++;
+	}
+	if (*ch)
+		uerror("constant has too many '%c'", *ch);
+
+	if (ntype == INT) {
+		/* v contains a number. Get type correct */
+		if (v > MAX_LONGLONG && radix != 10)
+			ntype = ULONGLONG;
+		else if (v > MAX_ULONG)
+			ntype = LONGLONG;
+		else if (v > MAX_LONG && radix != 10)
+			ntype = ULONG;
+		else if (v > MAX_UNSIGNED)
+			ntype = LONG;
+		else if (v > MAX_INT && radix != 10)
+			ntype = UNSIGNED;
+	}
+	ntype = ctype(ntype);
+	p = xbcon(v, NULL, ntype);
+	ASGLVAL(p->n_slval, v);
+
+	return p;
+}
+
+/*
+ * Convert a character constant to an integer.
+ */
+NODE *
+charcon(void)
+{
+	int lastcon = 0;
+	int val, i = 0;
+	char *pp = yytext;
+
+	if (*pp == 'L')
+		pp++;
+	pp++;
+	while (*pp != '\'') {
+		if (*pp++ == '\\') {
+			val = esccon(&pp);
+		} else
+			val = pp[-1];
+		makecc(val, i);
+		i++;
+	}
+
+	if (i == 0)
+		uerror("empty character constant");
+	if (i > (SZINT/SZCHAR) || (i>1))
+		werror("too many characters in character constant");
+	return bcon(lastcon);
+}
+
+NODE *
+wcharcon(void)
+{
+	unsigned int lastcon = 0;
+	unsigned int val, i = 0;
+	char *pp = yytext;
+
+	if (*pp == 'L')
+		pp++;
+	pp++;
+	while (*pp != '\'') {
+		if (*pp++ == '\\') {
+			val = esccon(&pp);
+		} else
+			val = pp[-1];
+#if WCHAR_SIZE == 2
+		lastcon = (lastcon << 16) | (val & 0xFFFF);
+#else
+		lastcon = val;
+#endif
+		i++;
+	}
+
+	if (i == 0)
+		uerror("empty wide character constant");
+	if (i > 1)
+		werror("too many characters in wide character constant");
+	return xbcon(lastcon, NULL, ctype(UNSIGNED));
+}
+
+void
+control(int t)
+{
+	char *wr = yytext;
+	char *eptr;
+	int val;
+
+	wr++;	/* Skip initial '#' */
+	switch (t) {
+	case CPP_IDENT:
+		return;	/* Just skip these for now. */
+
+	case CPP_LINE:
+		wr += 4;
+		/* FALLTHROUGH */
+	case CPP_HASH:
+		val = strtol(wr, &eptr, 10);
+		if (wr == eptr)	/* Illegal string */
+			goto bad;
+		wr = eptr;
+		lineno = val - 1;
+		while (*wr && *wr != '\"')
+			wr++;
+		if (*wr == 0)
+			return;
+		if (*wr++ != '\"')
+			goto bad;
+		eptr = wr;
+		while (*wr && *wr != '\"')
+			wr++;
+		if (*wr != '\"')
+			goto bad;
+		*wr = 0;
+		ftitle = addstring(eptr);
+#ifdef STABS
+		if (gflag)
+			stabs_file(ftitle);
+#endif
+	}
+	return;
+bad:
+	werror("%s: illegal control", yytext);
+}
+
+int pragma_allpacked;
+int pragma_packed, pragma_aligned;
+char *pragma_renamed;
+
+static int
+pragmas_weak(char *str)
+{
+	struct symtab *sp;
+	char *s1, *s2;
+
+	if ((s1 = pragtok(NULL)) == NULL)
+		return 1;
+	if ((s2 = pragtok(NULL)) == NULL) {
+		sp = lookup(addname(s1), SNORMAL);
+		sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(NAME, "weak")));
+	} else if (*s2 == '=') {
+		if ((s2 = pragtok(NULL)) == NULL)
+			return 1;
+		sp = lookup(addname(s2), SNORMAL);
+		sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(CALL,
+		    bdty(NAME, "aliasweak"), bdty(STRING, s1, 0))));
+	} else
+		return 1;
+	return 0;
+}
+
+char *pragstore;
+
+/* trivial tokenizer for pragmas */
+#define ps pragstore
+char *
+pragtok(char *sin)
+{
+	static char ss[2];
+	char *rv;
+
+	if (sin)
+		ps = sin;
+
+	for (; isspace((int)*ps); ps++)
+		;
+	if (*ps == 0)
+		return NULL;
+	for (rv = ps; isalpha((int)*ps) || isdigit((int)*ps) || *ps == '_'; ps++)
+		;
+	ss[0] = *ps;
+	if (rv == ps) {
+		rv = ss, ps++;
+	} else {
+		*ps = 0;
+		rv = tmpstrdup(rv);
+		*ps = ss[0];
+	}
+	return rv;
+}
+
+/* return 1 on error */
+int
+eat(int ch)
+{
+	char *s = pragtok(0);
+	return (s == 0 || *s != ch);
+}
+
+static int
+pragmas_alpack(char *t)
+{
+	char *s;
+	int ap;
+
+	ap = (s = pragtok(0)) ? atoi(s) : 1;
+	if (strcmp(t, "packed") == 0)
+		pragma_packed = ap;
+	else
+		pragma_aligned = ap;
+	return 0;
+}
+
+
+/*
+ * Packing control.
+ * still missing push/pop.
+ */
+static int
+pragmas_pack(char *t)
+{
+	char *s;
+
+	if (eat('('))
+		return 1;
+	s = pragtok(0);
+	if (*s == ')')
+		return pragma_allpacked = 0;
+
+	if (*s < '0' || *s > '9') /* no number */
+		return 1;
+	pragma_allpacked = atoi(s);
+	return eat(')');
+}
+
+static int
+pragmas_renamed(char *t)
+{
+	char *f = pragtok(0);
+
+	if (f == 0)
+		return 1;
+	pragma_renamed = newstring(f, strlen(f));
+	return 0;
+}
+
+static int
+pragmas_stdc(char *t)
+{
+	return 0; /* Just ignore */
+}
+
+struct pragmas {
+	char *name;
+	int (*fun)(char *);
+} pragmas[] = {
+	{ "pack", pragmas_pack },
+	{ "packed", pragmas_alpack },
+	{ "aligned", pragmas_alpack },
+	{ "rename", pragmas_renamed },
+#ifdef GCC_COMPAT
+	{ "GCC", pragmas_gcc },
+#endif
+	{ "STDC", pragmas_stdc },
+	{ "weak", pragmas_weak },
+	{ "ident", NULL },
+	{ 0 },
+};
+/*
+ * got a full pragma line.  Split it up here.
+ */
+static void
+pragma()
+{
+	struct pragmas *p;
+	char *t, *pt;
+
+	if ((t = pragtok(&yytext[7])) != NULL) {
+		pt = ps;
+		for (p = pragmas; p->name; p++) {
+			if (strcmp(t, p->name) == 0) {
+				if (p->fun && (*p->fun)(t))
+					uerror("bad argument to #pragma");
+				return;
+			}
+		}
+		ps = pt;
+		if (mypragma(t))
+			return;
+	}
+	warner(Wunknown_pragmas, t, ps);
+}
+
+void
+cunput(char c)
+{
+	unput(c);
+}
Index: uspace/app/pcc/cc/ccom/softfloat.c
===================================================================
--- uspace/app/pcc/cc/ccom/softfloat.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/softfloat.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,359 @@
+/*	$Id: softfloat.c,v 1.4 2009/07/29 12:32:34 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2008 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef SOFTFLOAT
+
+#include "pass1.h"
+
+
+/*
+ * Floating point emulation to be used when cross-compiling.
+ * Currently only supports F- and D-float, used in DEC machines.
+ * Should be trivial to add other emulations.
+ *
+ * XXX - assumes that:
+ *	- long long is (at least) 64 bits
+ *	- int is at least 32 bits.
+ *	- short is 16 bits.
+ */
+
+#ifdef FDFLOAT
+
+/*
+ * Useful macros to manipulate the float.
+ */
+#define DSIGN(w)	(((w).fd1 >> 15) & 1)
+#define DSIGNSET(w,s)	((w).fd1 = (s << 15) | ((w).fd1 & 077777))
+#define DEXP(w)		(((w).fd1 >> 7) & 0377)
+#define DEXPSET(w,e)	((w).fd1 = (((e) & 0377) << 7) | ((w).fd1 & 0100177))
+#define DMANTH(w)	((w).fd1 & 0177)
+#define DMANTHSET(w,m)	((w).fd1 = ((m) & 0177) | ((w).fd1 & 0177600))
+
+typedef unsigned int lword;
+typedef unsigned long long dword;
+
+#define MAXMANT 0x100000000000000LL
+
+/*
+ * Returns a zero dfloat.
+ */
+static SF
+nulldf(void)
+{
+	SF rv;
+
+	rv.fd1 = rv.fd2 = rv.fd3 = rv.fd4 = 0;
+	return rv;
+}
+
+/*
+ * Convert a (u)longlong to dfloat.
+ * XXX - fails on too large (> 55 bits) numbers.
+ */
+SF
+soft_cast(CONSZ ll, TWORD t)
+{
+	int i;
+	SF rv;
+
+	rv = nulldf();
+	if (ll == 0)
+		return rv;  /* fp is zero */
+	if (ll < 0)
+		DSIGNSET(rv,1), ll = -ll;
+	for (i = 0; ll > 0; i++, ll <<= 1)
+		;
+	DEXPSET(rv, 192-i);
+	DMANTHSET(rv, ll >> 56);
+	rv.fd2 = ll >> 40;
+	rv.fd3 = ll >> 24;
+	rv.fd4 = ll >> 8;
+	return rv;
+}
+
+/*
+ * multiply two dfloat. Use chop, not round.
+ */
+SF
+soft_mul(SF p1, SF p2)
+{
+	SF rv;
+	lword a1[2], a2[2], res[4];
+	dword sum;
+
+	res[0] = res[1] = res[2] = res[3] = 0;
+
+	/* move mantissa into lwords */
+	a1[0] = p1.fd4 | (p1.fd3 << 16);
+	a1[1] = p1.fd2 | DMANTH(p1) << 16 | 0x800000;
+
+	a2[0] = p2.fd4 | (p2.fd3 << 16);
+	a2[1] = p2.fd2 | DMANTH(p2) << 16 | 0x800000;
+
+#define MULONE(x,y,r) sum += (dword)a1[x] * (dword)a2[y]; sum += res[r]; \
+	res[r] = sum; sum >>= 32;
+
+	sum = 0;
+	MULONE(0, 0, 0);
+	MULONE(1, 0, 1);
+	res[2] = sum;
+	sum = 0;
+	MULONE(0, 1, 1);
+	MULONE(1, 1, 2);
+	res[3] = sum;
+
+	rv.fd1 = 0;
+	DSIGNSET(rv, DSIGN(p1) ^ DSIGN(p2));
+	DEXPSET(rv, DEXP(p1) + DEXP(p2) - 128);
+	if (res[3] & 0x8000) {
+		res[3] = (res[3] << 8) | (res[2] >> 24);
+		res[2] = (res[2] << 8) | (res[1] >> 24);
+	} else {
+		DEXPSET(rv, DEXP(rv) - 1);
+		res[3] = (res[3] << 9) | (res[2] >> 23);
+		res[2] = (res[2] << 9) | (res[1] >> 23);
+	}
+	DMANTHSET(rv, res[3] >> 16);
+	rv.fd2 = res[3];
+	rv.fd3 = res[2] >> 16;
+	rv.fd4 = res[2];
+	return rv;
+}
+
+SF
+soft_div(SF t, SF n)
+{
+	SF rv;
+	dword T, N, K;
+	int c;
+
+#define SHL(x,b) ((dword)(x) << b)
+	T = SHL(1,55) | SHL(DMANTH(t), 48) |
+	    SHL(t.fd2, 32) | SHL(t.fd3, 16) | t.fd4;
+	N = SHL(1,55) | SHL(DMANTH(n), 48) |
+	    SHL(n.fd2, 32) | SHL(n.fd3, 16) | n.fd4;
+
+	c = T > N;
+	for (K = 0; (K & 0x80000000000000ULL) == 0; ) {
+		if (T >= N) {
+			T -= N;
+			K |= 1;
+		}
+		T <<= 1;
+		K <<= 1;
+	}
+	rv.fd1 = 0;
+	DSIGNSET(rv, DSIGN(t) ^ DSIGN(n));
+	DEXPSET(rv, DEXP(t) - DEXP(n) + 128 + c);
+	DMANTHSET(rv, K >> 48);
+	rv.fd2 = K >> 32;
+	rv.fd3 = K >> 16;
+	rv.fd4 = K;
+	return rv;
+}
+
+/*
+ * Negate a float number. Easy.
+ */
+SF
+soft_neg(SF sf)
+{
+	int sign = DSIGN(sf) == 0;
+	DSIGNSET(sf, sign);
+	return sf;
+}
+
+/*
+ * Return true if fp number is zero.
+ */
+int
+soft_isz(SF sf)
+{
+	return (DEXP(sf) == 0);
+}
+
+int
+soft_cmp_eq(SF x1, SF x2)
+{
+	cerror("soft_cmp_eq");
+	return 0;
+}
+
+int
+soft_cmp_ne(SF x1, SF x2)
+{
+	cerror("soft_cmp_ne");
+	return 0;
+}
+
+int
+soft_cmp_le(SF x1, SF x2)
+{
+	cerror("soft_cmp_le");
+	return 0;
+}
+
+int
+soft_cmp_lt(SF x1, SF x2)
+{
+	cerror("soft_cmp_lt");
+	return 0;
+}
+
+int
+soft_cmp_ge(SF x1, SF x2)
+{
+	cerror("soft_cmp_ge");
+	return 0;
+}
+
+int
+soft_cmp_gt(SF x1, SF x2)
+{
+	cerror("soft_cmp_gt");
+	return 0;
+}
+
+/*
+ * Convert a fp number to a CONSZ.
+ */
+CONSZ
+soft_val(SF sf)
+{
+	CONSZ mant;
+	int exp = DEXP(sf) - 128;
+
+	mant = SHL(1,55) | SHL(DMANTH(sf), 48) |
+            SHL(sf.fd2, 32) | SHL(sf.fd3, 16) | sf.fd4;
+
+	while (exp < 0)
+		mant >>= 1, exp++;
+	while (exp > 0)
+		mant <<= 1, exp--;
+	return mant;
+}
+
+SF
+soft_plus(SF x1, SF x2)
+{
+	cerror("soft_plus");
+	return x1;
+}
+
+SF
+soft_minus(SF x1, SF x2)
+{
+	cerror("soft_minus");
+	return x1;
+}
+
+/*
+ * Convert a hex constant to floating point number.
+ */
+NODE *
+fhexcon(char *s)
+{
+	cerror("fhexcon");
+	return NULL;
+}
+
+/*
+ * Convert a floating-point constant to D-float and store it in a NODE.
+ */
+NODE *
+floatcon(char *s)
+{
+	NODE *p;
+	dword mant;
+	SF fl, flexp, exp5;
+	int exp, negexp, bexp;
+
+	exp = 0;
+	mant = 0;
+#define ADDTO(sum, val) sum = sum * 10 + val - '0'
+	for (; *s >= '0' && *s <= '9'; s++) {
+		if (mant<MAXMANT)
+			ADDTO(mant, *s);
+		else
+			exp++;
+	}
+	if (*s == '.') {
+		for (s++; *s >= '0' && *s <= '9'; s++) {
+			if (mant<MAXMANT) {
+				ADDTO(mant, *s);
+				exp--;
+			}
+		}
+	}
+
+	if ((*s == 'E') || (*s == 'e')) {
+		int eexp = 0, sign = 0;
+		s++;
+		if (*s == '+')
+			s++;
+		else if (*s=='-')
+			sign = 1, s++;
+
+		for (; *s >= '0' && *s <= '9'; s++)
+			ADDTO(eexp, *s);
+		if (sign)
+			eexp = -eexp;
+		exp = exp + eexp;
+	}
+
+	negexp = 1;
+	if (exp<0) {
+		negexp = -1;
+		exp = -exp;
+	}
+
+
+	flexp = soft_cast(1, INT);
+	exp5 = soft_cast(5, INT);
+	bexp = exp;
+	fl = soft_cast(mant, INT);
+
+	for (; exp; exp >>= 1) {
+		if (exp&01)
+			flexp = soft_mul(flexp, exp5);
+		exp5 = soft_mul(exp5, exp5);
+	}
+	if (negexp<0)
+		fl = soft_div(fl, flexp);
+	else
+		fl = soft_mul(fl, flexp);
+
+	DEXPSET(fl, DEXP(fl) + negexp*bexp);
+	p = block(FCON, NIL, NIL, DOUBLE, 0, MKSUE(DOUBLE)); /* XXX type */
+	p->n_dcon = fl;
+	return p;
+}
+#else
+#error missing softfloat definition
+#endif
+#endif
Index: uspace/app/pcc/cc/ccom/stabs.c
===================================================================
--- uspace/app/pcc/cc/ccom/stabs.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/stabs.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,459 @@
+/*	$Id: stabs.c,v 1.31 2010/08/11 14:08:44 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Simple implementation of the "stabs" debugging format.
+ * Not complete but at least makes it possible to set breakpoints,
+ * examine simple variables and do stack traces.
+ * Based on the stabs documentation that follows gdb.
+ */
+
+#include "pass1.h"
+
+#ifdef STABS
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+
+#define	STABHASH	256
+#define	INTNUM		1	/* internal number of type "int" */
+#undef BIT2BYTE /* from external.h */
+#define	BIT2BYTE(x)	((x)/SZCHAR)
+
+#ifndef STABLBL
+#error macdefs.h must define STABLBL
+#endif
+
+/* defines taken from BSD <stab.h> */
+#define N_GSYM          0x20    /* global symbol */
+#define N_FUN           0x24    /* procedure name */
+#define N_LCSYM         0x28    /* bss segment variable */
+#define N_RSYM          0x40    /* register variable */
+#define N_SLINE         0x44    /* text segment line number */
+#define N_SO            0x64    /* main source file name */
+#define N_LSYM          0x80    /* stack variable */
+#define N_SOL           0x84    /* included source file name */
+#define N_PSYM          0xa0    /* parameter variable */
+#define N_LBRAC         0xc0    /* left bracket */
+#define N_RBRAC         0xe0    /* right bracket */
+
+/*
+ * Local type mapping
+ * Types are defined as a typeword, a dimension pointer (in the case
+ * of arrays) and struct/union/enum declarations.
+ * Function prototypes are ignored.
+ */
+static struct stabtype {
+	struct stabtype *next;	/* linked list */
+	TWORD type;		/* pcc type number */
+	union dimfun *df;	/* dimension of arrays */
+	struct attr *ap;	/* struct/union/enum declarations */
+	int num;		/* local type number */
+} *stabhash[STABHASH];
+static int ntypes;
+static char *curfun;
+static int stablbl = 10;
+extern int inftn;
+
+void ptype(char *name, int num, int inhnum, long long min, long long max);
+struct stabtype *addtype(TWORD, union dimfun *, struct attr *);
+struct stabtype *findtype(TWORD t, union dimfun *df, struct attr *sue);
+void printtype(struct symtab *s, char *str, int len);
+void cprint(int p2, char *fmt, ...);
+
+#define	MAXPSTR	100
+
+extern int isinlining;
+
+/*
+ * Output type definitions for the stab debugging format.
+ * Note that "int" is always internal number 1.
+ */
+void
+stabs_init()
+{
+	struct stabtype *st;
+
+#define	ADDTYPE(y) addtype(y, NULL, MKAP(y))
+
+	ptype("int", ADDTYPE(INT)->num, INTNUM, MIN_INT, MAX_INT);
+
+	st = ADDTYPE(CHAR);
+	ptype("char", st->num, st->num, 0, MAX_CHAR);
+	ptype("short", ADDTYPE(SHORT)->num, INTNUM, MIN_SHORT, MAX_SHORT);
+	ptype("long", ADDTYPE(LONG)->num, INTNUM, MIN_LONG, MAX_LONG);
+	ptype("long long", ADDTYPE(LONGLONG)->num, INTNUM,
+	     MIN_LONGLONG, MAX_LONGLONG);
+	ptype("unsigned char", ADDTYPE(UCHAR)->num, INTNUM, 0, MAX_UCHAR);
+	ptype("unsigned short", ADDTYPE(USHORT)->num, INTNUM, 0, MAX_USHORT);
+	ptype("unsigned int", ADDTYPE(UNSIGNED)->num, INTNUM, 0, MAX_UNSIGNED);
+	ptype("unsigned long", ADDTYPE(ULONG)->num, INTNUM, 0, MAX_ULONG);
+	ptype("unsigned long long", ADDTYPE(ULONGLONG)->num, INTNUM,
+	    0, MAX_ULONGLONG);
+
+	ptype("float", ADDTYPE(FLOAT)->num, INTNUM, 4, 0);
+	ptype("double", ADDTYPE(DOUBLE)->num, INTNUM, 8, 0);
+	ptype("long double", ADDTYPE(LDOUBLE)->num, INTNUM, 12, 0);
+	st = ADDTYPE(VOID);
+	cprint(0, "\t.stabs \"void:t%d=r%d\",%d,0,0,0\n",
+	    st->num, st->num, N_LSYM);
+
+}
+
+/*
+ * Print a type in stabs format
+ */
+void
+ptype(char *name, int num, int inhnum, long long min, long long max)
+{
+	cprint(0, "\t.stabs \"%s:t%d=r%d;%lld;%lld;\",%d,0,0,0\n",
+	    name, num, inhnum, min, max, N_LSYM);
+}
+
+/*
+ * Add a new local type to the hash table.
+ * The search key is the (type, df, sue) triple.
+ */
+struct stabtype *
+addtype(TWORD t, union dimfun *df, struct attr *ap)
+{
+	struct stabtype *st;
+
+	st = permalloc(sizeof(struct stabtype));
+	st->type = t;
+	st->df = df;
+	st->ap = ap;
+	st->num = ++ntypes;
+	st->next = stabhash[t & (STABHASH-1)];
+	stabhash[t & (STABHASH-1)] = st;
+	return st;
+}
+
+/*
+ * Search for a given type and return a type pointer (or NULL).
+ */
+struct stabtype *
+findtype(TWORD t, union dimfun *df, struct attr *ap)
+{
+	struct stabtype *st;
+	union dimfun *dw, *dx;
+	TWORD tw;
+
+	st = stabhash[t & (STABHASH-1)];
+	for (; st; st = st->next) {
+		if (t != st->type || ap != st->ap)
+			continue;
+		/* Ok, type and sue matches, check dimensions */
+		if (st->df == NULL)
+			return st; /* no arrays, got match */
+		dw = st->df;
+		dx = df;
+		tw = t;
+		for (; tw > BTMASK; tw = DECREF(tw)) {
+			if (ISARY(tw)) {
+				if (dw->ddim == dx->ddim)
+					dw++, dx++;
+				else
+					break;
+			}
+		}
+		if (tw <= BTMASK)
+			return st;
+	}
+	return NULL;
+}
+
+/*
+ * Print current line number.
+ */
+void
+stabs_line(int line)
+{
+	if (inftn == 0)
+		return; /* ignore */
+#ifdef STAB_LINE_ABSOLUTE
+	cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
+	    N_SLINE, line, stablbl, stablbl);
+#else
+	cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
+	    N_SLINE, line, stablbl, curfun, stablbl);
+#endif
+	stablbl++;
+}
+
+/*
+ * Start of block.
+ */
+void
+stabs_lbrac(int blklvl)
+{
+#ifdef STAB_LINE_ABSOLUTE
+	cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
+	    N_LBRAC, blklvl, stablbl, stablbl);
+#else
+	cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
+	    N_LBRAC, blklvl, stablbl, curfun, stablbl);
+#endif
+	stablbl++;
+}
+
+/*
+ * End of block.
+ */
+void
+stabs_rbrac(int blklvl)
+{
+#ifdef STAB_LINE_ABSOLUTE
+	cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
+	    N_RBRAC, blklvl, stablbl, stablbl);
+#else
+	cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
+	    N_RBRAC, blklvl, stablbl, curfun, stablbl);
+#endif
+	stablbl++;
+}
+
+static char *mainfile;
+
+/*
+ * Print current file and set mark.
+ */
+void
+stabs_file(char *fname)
+{
+	if (mainfile == NULL)
+		mainfile = fname; /* first call */
+	cprint(inftn, "\t.stabs	\"%s\",%d,0,0," STABLBL "\n" STABLBL ":\n",
+	    fname, fname == mainfile ? N_SO : N_SOL, stablbl, stablbl);
+	stablbl++;
+}
+
+/*
+ * Print end mark
+ */
+void
+stabs_efile(char *fname)
+{
+	cprint(inftn, "\t.stabs	\"\",%d,0,0," STABLBL "\n" STABLBL ":\n",
+	    fname == mainfile ? N_SO : N_SOL, stablbl, stablbl);
+	stablbl++;
+}
+
+/*
+ * Print beginning of function.
+ */
+void
+stabs_func(struct symtab *s)
+{
+	char str[MAXPSTR];
+
+	if ((curfun = s->soname) == NULL)
+		curfun = addname(exname(s->sname));
+	printtype(s, str, sizeof(str));
+	cprint(1, "\t.stabs	\"%s:%c%s\",%d,0,%d,%s\n",
+	    curfun, s->sclass == STATIC ? 'f' : 'F', str,
+	    N_FUN, 0, curfun);
+}
+
+/*
+ * Print a (complex) type.
+ * Will also create subtypes.
+ * Printed string is like "20=*21=*1".
+ */
+void
+printtype(struct symtab *s, char *ostr, int len)
+{
+	struct stabtype *st;
+	union dimfun *df = s->sdf;
+	struct attr *ap = s->sap;
+	TWORD t = s->stype;
+	int op = 0;
+
+	/* Print out not-yet-found types */
+	if (ISFTN(t))
+		t = DECREF(t);
+	st = findtype(t, df, ap);
+	while (st == NULL && t > BTMASK) {
+		st = addtype(t, df, ap);
+		op+=snprintf(ostr+op, len - op, "%d=", st->num);
+		if (ISFTN(t))
+			ostr[op++] = 'f';
+		else if (ISPTR(t))
+			ostr[op++] = '*';
+		else if (ISARY(t)) {
+			op+=snprintf(ostr+op, len - op, "ar%d;0;%d;", INTNUM, df->ddim-1);
+		} else
+			cerror("printtype: notype");
+		if (ISARY(t))
+			df++;
+		t = DECREF(t);
+		st = findtype(t, df, ap);
+		if (op > MAXPSTR-10)
+			cerror("printtype: too difficult expression");
+	}
+	/* print out basic type. may have to be entered in case of sue */
+	snprintf(ostr+op, len - op, "%d", st == NULL ? 1 : st->num);
+	/* snprintf here null-terminated the string */
+}
+
+void
+stabs_newsym(struct symtab *s)
+{
+	extern int fun_inline;
+	char *sname;
+	char ostr[MAXPSTR];
+	int suesize, sz;
+
+	if (ISFTN(s->stype))
+		return; /* functions are handled separate */
+
+	if (s->sclass == STNAME || s->sclass == UNAME || s->sclass == MOS ||
+	    s->sclass == ENAME || s->sclass == MOU || s->sclass == MOE ||
+	    s->sclass == TYPEDEF || (s->sclass & FIELD) || ISSOU(s->stype))
+		return; /* XXX - fix structs */
+
+	if ((sname = s->soname) == NULL)
+		sname = exname(s->sname);
+	sz = tsize(s->stype, s->sdf, s->sap);
+	suesize = BIT2BYTE(sz);
+	if (suesize > 32767)
+		suesize = 32767;
+	else if (suesize < -32768)
+		suesize = -32768;
+
+	printtype(s, ostr, sizeof(ostr));
+	switch (s->sclass) {
+	case PARAM:
+		cprint(0, "\t.stabs \"%s:p%s\",%d,0,%d,%d\n", sname, ostr,
+		    N_PSYM, suesize, BIT2BYTE(s->soffset));
+		break;
+
+	case AUTO:
+		cprint(0, "\t.stabs \"%s:%s\",%d,0,%d,%d\n", sname, ostr,
+		    N_LSYM, suesize, BIT2BYTE(s->soffset));
+		break;
+
+	case STATIC:
+		if (blevel)
+			cprint(0, "\t.stabs \"%s:V%s\",%d,0,%d," LABFMT "\n", sname, ostr,
+			    N_LCSYM, suesize, s->soffset);
+		else
+			cprint(0, "\t.stabs \"%s:S%s\",%d,0,%d,%s\n", sname, ostr,
+			    N_LCSYM, suesize, sname);
+		break;
+
+	case EXTERN:
+	case EXTDEF:
+		cprint(0, "\t.stabs \"%s:G%s\",%d,0,%d,0\n", sname, ostr,
+		    N_GSYM, suesize);
+		break;
+
+	case REGISTER:
+		cprint(0, "\t.stabs \"%s:r%s\",%d,0,%d,%d\n", sname, ostr,
+		    N_RSYM, 1, s->soffset);
+		break;
+	case SNULL:
+		if (fun_inline)
+			break;
+		/* FALLTHROUGH */
+	default:
+		cerror("fix stab_newsym; class %d", s->sclass);
+	}
+}
+
+void
+stabs_chgsym(struct symtab *s)
+{
+}
+
+/*
+ * define a struct.
+ */
+void
+stabs_struct(struct symtab *p, struct attr *ap)
+{
+}
+
+struct stabsv {
+	SLIST_ENTRY(stabsv) next;
+	char *str;
+} ;
+static SLIST_HEAD(, stabsv) stpole = { NULL, &stpole.q_forw };
+
+/*
+ * Global variable debug info is printed out directly.
+ * For functions and their declarations, both the labels and 
+ * the debug info is put into ASM nodes and follows their statements
+ * into pass2.  
+ * Due to the possible unsync between pass1 and 2 and where the 
+ * stabs info for text is sent over the following syncing is used:
+ * curfun == 0
+ *	print out everything; only data will be.
+ * curfun != 0 && inftn == 0
+ *	save in linked list
+ * curfun != 0 && inftn != 0
+ *	print linked list first, empty it, then arg.
+ */
+void
+cprint(int p2, char *fmt, ...)
+{
+#define	CPBSZ	200
+	char buf[CPBSZ];
+	struct stabsv *w;
+	va_list ap;
+	char *str;
+
+	if (isinlining)
+		return; /* XXX do not save any inline functions currently */
+
+	va_start(ap, fmt);
+	if (p2) {
+		if (vsnprintf(buf, CPBSZ, fmt, ap) >= CPBSZ)
+			werror("stab symbol line too long, truncating");
+		str = tmpstrdup(buf);
+		if (inftn == 0) {
+			w = tmpalloc(sizeof(struct stabsv));
+			w->str = str;
+			SLIST_INSERT_LAST(&stpole, w, next);
+		} else {
+			if (stpole.q_last != &stpole.q_forw) {
+				SLIST_FOREACH(w, &stpole, next) {
+					send_passt(IP_ASM, w->str);
+				}
+				SLIST_INIT(&stpole);
+			}
+			send_passt(IP_ASM, str);
+		}
+	} else
+		vprintf(fmt, ap);
+	va_end(ap);
+}
+
+#endif
Index: uspace/app/pcc/cc/ccom/symtabs.c
===================================================================
--- uspace/app/pcc/cc/ccom/symtabs.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/symtabs.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,360 @@
+/*	$Id: symtabs.c,v 1.19 2011/01/22 22:08:23 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"
+
+/*
+ * These definitions are used in the patricia tree that stores
+ * the strings.
+ */
+#define	LEFT_IS_LEAF		0x80000000
+#define	RIGHT_IS_LEAF		0x40000000
+#define	IS_LEFT_LEAF(x)		(((x) & LEFT_IS_LEAF) != 0)
+#define	IS_RIGHT_LEAF(x)	(((x) & RIGHT_IS_LEAF) != 0)
+#define	BITNO(x)		((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
+#define	CHECKBITS		8
+
+struct tree {
+	int bitno;
+	struct tree *lr[2];
+};
+
+static struct tree *firstname;
+int nametabs, namestrlen;
+static struct tree *firststr;
+int strtabs, strstrlen;
+static char *symtab_add(char *key, struct tree **, int *, int *);
+
+#define	P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1
+#define	getree() permalloc(sizeof(struct tree))
+
+char *
+addname(char *key)      
+{
+	return symtab_add(key, &firstname, &nametabs, &namestrlen);
+}
+
+char *
+addstring(char *key)
+{
+	return symtab_add(key, &firststr, &strtabs, &strstrlen);
+}
+
+/*
+ * Add a name to the name stack (if its non-existing),
+ * return its address.
+ * This is a simple patricia implementation.
+ */
+char *
+symtab_add(char *key, struct tree **first, int *tabs, int *stlen)
+{
+	struct tree *w, *new, *last;
+	int cix, bit, fbit, svbit, ix, bitno, len;
+	char *m, *k, *sm;
+
+	/* Count full string length */
+	for (k = key, len = 0; *k; k++, len++)
+		;
+	
+	switch (*tabs) {
+	case 0:
+		*first = (struct tree *)newstring(key, len);
+		*stlen += (len + 1);
+		(*tabs)++;
+		return (char *)*first;
+
+	case 1:
+		m = (char *)*first;
+		svbit = 0; /* XXX why? */
+		break;
+
+	default:
+		w = *first;
+		bitno = len * CHECKBITS;
+		for (;;) {
+			bit = BITNO(w->bitno);
+			fbit = bit > bitno ? 0 : P_BIT(key, bit);
+			svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
+			    IS_LEFT_LEAF(w->bitno);
+			w = w->lr[fbit];
+			if (svbit) {
+				m = (char *)w;
+				break;
+			}
+		}
+	}
+
+	sm = m;
+	k = key;
+
+	/* Check for correct string and return */
+	for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS)
+		;
+	if (*m == 0 && *k == 0)
+		return sm;
+
+	ix = *m ^ *k;
+	while ((ix & 1) == 0)
+		ix >>= 1, cix++;
+
+	/* Create new node */
+	new = getree();
+	bit = P_BIT(key, cix);
+	new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+	new->lr[bit] = (struct tree *)newstring(key, len);
+	*stlen += (len + 1);
+
+	if ((*tabs)++ == 1) {
+		new->lr[!bit] = *first;
+		new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+		*first = new;
+		return (char *)new->lr[bit];
+	}
+
+
+	w = *first;
+	last = NULL;
+	for (;;) {
+		fbit = w->bitno;
+		bitno = BITNO(w->bitno);
+		if (bitno == cix)
+			cerror("bitno == cix");
+		if (bitno > cix)
+			break;
+		svbit = P_BIT(key, bitno);
+		last = w;
+		w = w->lr[svbit];
+		if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
+			break;
+	}
+
+	new->lr[!bit] = w;
+	if (last == NULL) {
+		*first = new;
+	} else {
+		last->lr[svbit] = new;
+		last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+	}
+	if (bitno < cix)
+		new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+	return (char *)new->lr[bit];
+}
+
+static struct tree *sympole[NSTYPES];
+static struct symtab *tmpsyms[NSTYPES];
+int numsyms[NSTYPES];
+
+/*
+ * Inserts a symbol into the symbol tree.
+ * Returns a struct symtab.
+ */
+struct symtab *
+lookup(char *key, int stype)
+{
+	struct symtab *sym;
+	struct tree *w, *new, *last;
+	int cix, bit, fbit, svbit, bitno;
+	int type, uselvl;
+	intptr_t ix, match, code = (intptr_t)key;
+
+	type = stype & SMASK;
+	uselvl = (blevel > 0 && type != SSTRING);
+
+	/*
+	 * The local symbols are kept in a simple linked list.
+	 * Check this list first.
+	 */
+	if (blevel > 0)
+		for (sym = tmpsyms[type]; sym; sym = sym->snext)
+			if (sym->sname == key)
+				return sym;
+
+	switch (numsyms[type]) {
+	case 0:
+		if (stype & SNOCREAT)
+			return NULL;
+		if (uselvl) {
+			sym = getsymtab(key, stype|STEMP);
+			sym->snext = tmpsyms[type];
+			tmpsyms[type] = sym;
+			return sym;
+		}
+		sympole[type] = (struct tree *)getsymtab(key, stype);
+		numsyms[type]++;
+		return (struct symtab *)sympole[type];
+
+	case 1:
+		w = (struct tree *)sympole[type];
+		svbit = 0; /* XXX why? */
+		break;
+
+	default:
+		w = sympole[type];
+		for (;;) {
+			bit = BITNO(w->bitno);
+			fbit = (code >> bit) & 1;
+			svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
+			    IS_LEFT_LEAF(w->bitno);
+			w = w->lr[fbit];
+			if (svbit)
+				break;
+		}
+	}
+
+	sym = (struct symtab *)w;
+	match = (intptr_t)sym->sname;
+
+	ix = code ^ match;
+	if (ix == 0)
+		return sym;
+	else if (stype & SNOCREAT)
+		return NULL;
+
+#ifdef PCC_DEBUG
+	if (ddebug)
+		printf("	adding %s as %s at level %d\n",
+		    key, uselvl ? "temp" : "perm", blevel);
+#endif
+
+	/*
+	 * Insert into the linked list, if feasible.
+	 */
+	if (uselvl) {
+		sym = getsymtab(key, stype|STEMP);
+		sym->snext = tmpsyms[type];
+		tmpsyms[type] = sym;
+		return sym;
+	}
+
+	/*
+	 * Need a new node. If type is SNORMAL and inside a function
+	 * the node must be allocated as permanent anyway.
+	 * This could be optimized by adding a remove routine, but it
+	 * may be more trouble than it is worth.
+	 */
+	if (stype == (STEMP|SNORMAL))
+		stype = SNORMAL;
+
+	for (cix = 0; (ix & 1) == 0; ix >>= 1, cix++)
+		;
+
+	new = stype & STEMP ? tmpalloc(sizeof(struct tree)) :
+	    permalloc(sizeof(struct tree));
+	bit = (code >> cix) & 1;
+	new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+	new->lr[bit] = (struct tree *)getsymtab(key, stype);
+	if (numsyms[type]++ == 1) {
+		new->lr[!bit] = sympole[type];
+		new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+		sympole[type] = new;
+		return (struct symtab *)new->lr[bit];
+	}
+
+
+	w = sympole[type];
+	last = NULL;
+	for (;;) {
+		fbit = w->bitno;
+		bitno = BITNO(w->bitno);
+		if (bitno == cix)
+			cerror("bitno == cix");
+		if (bitno > cix)
+			break;
+		svbit = (code >> bitno) & 1;
+		last = w;
+		w = w->lr[svbit];
+		if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
+			break;
+	}
+
+	new->lr[!bit] = w;
+	if (last == NULL) {
+		sympole[type] = new;
+	} else {
+		last->lr[svbit] = new;
+		last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+	}
+	if (bitno < cix)
+		new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+	return (struct symtab *)new->lr[bit];
+}
+
+void
+symclear(int level)
+{
+	struct symtab *s;
+	int i;
+
+#ifdef PCC_DEBUG
+	if (ddebug)
+		printf("symclear(%d)\n", level);
+#endif
+	if (level < 1) {
+		for (i = 0; i < NSTYPES; i++) {
+			s = tmpsyms[i];
+			tmpsyms[i] = 0;
+			if (i != SLBLNAME)
+				continue;
+			while (s != NULL) {
+				if (s->soffset < 0)
+					uerror("label '%s' undefined",s->sname);
+				s = s->snext;
+			}
+		}
+	} else {
+		for (i = 0; i < NSTYPES; i++) {
+			if (i == SLBLNAME)
+				continue; /* function scope */
+			while (tmpsyms[i] != NULL &&
+			    tmpsyms[i]->slevel > level) {
+				tmpsyms[i] = tmpsyms[i]->snext;
+			}
+		}
+	}
+}
+
+struct symtab *
+hide(struct symtab *sym)
+{
+	struct symtab *new;
+	int typ = sym->sflags & SMASK;
+
+	new = getsymtab(sym->sname, typ|STEMP);
+	new->snext = tmpsyms[typ];
+	tmpsyms[typ] = new;
+
+	warner(Wshadow, sym->sname, sym->slevel ? "local" : "global");
+
+#ifdef PCC_DEBUG
+	if (ddebug)
+		printf("\t%s hidden at level %d (%p -> %p)\n",
+		    sym->sname, blevel, sym, new);
+#endif
+	return new;
+}
Index: uspace/app/pcc/cc/ccom/trees.c
===================================================================
--- uspace/app/pcc/cc/ccom/trees.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/ccom/trees.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,2902 @@
+/*	$Id: trees.c,v 1.272.2.1 2011/03/01 17:39:28 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.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Some of the changes from 32V include:
+ * - Understand "void" as type.
+ * - Handle enums as ints everywhere.
+ * - Convert some C-specific ops into branches.
+ */
+
+# include "pass1.h"
+# include "pass2.h"
+
+# include <stdarg.h>
+# include <string.h>
+
+/* standard macros conflict with identifiers in this file */
+#ifdef true
+	#undef true
+	#undef false
+#endif
+
+static void chkpun(NODE *p);
+static int opact(NODE *p);
+static int moditype(TWORD);
+static NODE *strargs(NODE *);
+static void rmcops(NODE *p);
+void putjops(NODE *, void *);
+static struct symtab *findmember(struct symtab *, char *);
+int inftn; /* currently between epilog/prolog */
+
+static char *tnames[] = {
+	"undef",
+	"farg",
+	"char",
+	"unsigned char",
+	"short",
+	"unsigned short",
+	"int",
+	"unsigned int",
+	"long",
+	"unsigned long",
+	"long long",
+	"unsigned long long",
+	"float",
+	"double",
+	"long double",
+	"strty",
+	"unionty",
+	"enumty",
+	"moety",
+	"void",
+	"signed", /* pass1 */
+	"bool", /* pass1 */
+	"fimag", /* pass1 */
+	"dimag", /* pass1 */
+	"limag", /* pass1 */
+	"fcomplex", /* pass1 */
+	"dcomplex", /* pass1 */
+	"lcomplex", /* pass1 */
+	"enumty", /* pass1 */
+	"?", "?"
+};
+
+/*	some special actions, used in finding the type of nodes */
+# define NCVT 01
+# define PUN 02
+# define TYPL 04
+# define TYPR 010
+# define TYMATCH 040
+# define LVAL 0100
+# define CVTO 0200
+# define CVTL 0400
+# define CVTR 01000
+# define PTMATCH 02000
+# define OTHER 04000
+# define NCVTR 010000
+
+/* node conventions:
+
+	NAME:	rval>0 is stab index for external
+		rval<0 is -inlabel number
+		lval is offset in bits
+	ICON:	lval has the value
+		rval has the STAB index, or - label number,
+			if a name whose address is in the constant
+		rval = NONAME means no name
+	REG:	rval is reg. identification cookie
+
+	*/
+
+int bdebug = 0;
+extern int negrel[];
+
+NODE *
+buildtree(int o, NODE *l, NODE *r)
+{
+	NODE *p, *q;
+	int actions;
+	int opty;
+	struct symtab *sp = NULL; /* XXX gcc */
+	NODE *lr, *ll;
+
+#ifdef PCC_DEBUG
+	if (bdebug) {
+		printf("buildtree(%s, %p, %p)\n", copst(o), l, r);
+		if (l) fwalk(l, eprint, 0);
+		if (r) fwalk(r, eprint, 0);
+	}
+#endif
+	opty = coptype(o);
+
+	/* check for constants */
+
+	if (o == ANDAND || o == OROR || o == NOT) {
+		if (l->n_op == FCON) {
+			p = bcon(!FLOAT_ISZERO(l->n_dcon));
+			nfree(l);
+			l = p;
+		}
+		if (o != NOT && r->n_op == FCON) {
+			p = bcon(!FLOAT_ISZERO(r->n_dcon));
+			nfree(r);
+			r = p;
+		}
+	}
+
+	if( opty == UTYPE && l->n_op == ICON ){
+
+		switch( o ){
+
+		case NOT:
+		case UMINUS:
+		case COMPL:
+			if( conval( l, o, l ) ) return(l);
+			break;
+		}
+	} else if (o == NOT && l->n_op == FCON) {
+		l = clocal(block(SCONV, l, NIL, INT, 0, MKAP(INT)));
+	} else if( o == UMINUS && l->n_op == FCON ){
+			l->n_dcon = FLOAT_NEG(l->n_dcon);
+			return(l);
+
+	} else if( o==QUEST && l->n_op==ICON ) {
+		CONSZ c = l->n_lval;
+		nfree(l);
+		if (c) {
+			walkf(r->n_right, putjops, 0);
+			tfree(r->n_right);
+			l = r->n_left;
+		} else {
+			walkf(r->n_left, putjops, 0);
+			tfree(r->n_left);
+			l = r->n_right;
+		}
+		nfree(r);
+		return(l);
+	} else if( opty == BITYPE && l->n_op == ICON && r->n_op == ICON ){
+
+		switch( o ){
+
+		case PLUS:
+		case MINUS:
+		case MUL:
+		case DIV:
+		case MOD:
+			/*
+			 * Do type propagation for simple types here.
+			 * The constant value is correct anyway.
+			 * Maybe this op shortcut should be removed?
+			 */
+			if (l->n_sp == NULL && r->n_sp == NULL &&
+			    l->n_type < BTMASK && r->n_type < BTMASK) {
+				if (l->n_type > r->n_type)
+					r->n_type = l->n_type;
+				else
+					l->n_type = r->n_type;
+			}
+			/* FALLTHROUGH */
+		case ULT:
+		case UGT:
+		case ULE:
+		case UGE:
+		case LT:
+		case GT:
+		case LE:
+		case GE:
+		case EQ:
+		case NE:
+		case ANDAND:
+		case OROR:
+		case AND:
+		case OR:
+		case ER:
+		case LS:
+		case RS:
+			if (!ISPTR(l->n_type) && !ISPTR(r->n_type)) {
+				if( conval( l, o, r ) ) {
+					nfree(r);
+					return(l);
+				}
+			}
+			break;
+		}
+	} else if (opty == BITYPE && (l->n_op == FCON || l->n_op == ICON) &&
+	    (r->n_op == FCON || r->n_op == ICON) && (o == PLUS || o == MINUS ||
+	    o == MUL || o == DIV || (o >= EQ && o <= GT) )) {
+		TWORD t;
+#ifndef CC_DIV_0
+		if (o == DIV &&
+		    ((r->n_op == ICON && r->n_lval == 0) ||
+		     (r->n_op == FCON && r->n_dcon == 0.0)))
+				goto runtime; /* HW dependent */
+#endif
+		if (l->n_op == ICON)
+			l->n_dcon = FLOAT_CAST(l->n_lval, l->n_type);
+		if (r->n_op == ICON)
+			r->n_dcon = FLOAT_CAST(r->n_lval, r->n_type);
+		switch(o){
+		case PLUS:
+		case MINUS:
+		case MUL:
+		case DIV:
+			switch (o) {
+			case PLUS:
+				l->n_dcon = FLOAT_PLUS(l->n_dcon, r->n_dcon);
+				break;
+			case MINUS:
+				l->n_dcon = FLOAT_MINUS(l->n_dcon, r->n_dcon);
+				break;
+			case MUL:
+				l->n_dcon = FLOAT_MUL(l->n_dcon, r->n_dcon);
+				break;
+			case DIV:
+				l->n_dcon = FLOAT_DIV(l->n_dcon, r->n_dcon);
+				break;
+			}
+			t = (l->n_type > r->n_type ? l->n_type : r->n_type);
+			l->n_op = FCON;
+			l->n_type = t;
+			l->n_ap = MKAP(t);
+			nfree(r);
+			return(l);
+		case EQ:
+		case NE:
+		case LE:
+		case LT:
+		case GE:
+		case GT:
+			switch (o) {
+			case EQ:
+				l->n_lval = FLOAT_EQ(l->n_dcon, r->n_dcon);
+				break;
+			case NE:
+				l->n_lval = FLOAT_NE(l->n_dcon, r->n_dcon);
+				break;
+			case LE:
+				l->n_lval = FLOAT_LE(l->n_dcon, r->n_dcon);
+				break;
+			case LT:
+				l->n_lval = FLOAT_LT(l->n_dcon, r->n_dcon);
+				break;
+			case GE:
+				l->n_lval = FLOAT_GE(l->n_dcon, r->n_dcon);
+				break;
+			case GT:
+				l->n_lval = FLOAT_GT(l->n_dcon, r->n_dcon);
+				break;
+			}
+			nfree(r);
+			r = bcon(l->n_lval);
+			nfree(l);
+			return r;
+		}
+	}
+#ifndef CC_DIV_0
+runtime:
+#endif
+	/* its real; we must make a new node */
+
+	p = block(o, l, r, INT, 0, MKAP(INT));
+
+	actions = opact(p);
+
+	if (actions & LVAL) { /* check left descendent */
+		if (notlval(p->n_left)) {
+			uerror("lvalue required");
+			nfree(p);
+			return l;
+#ifdef notyet
+		} else {
+			if ((l->n_type > BTMASK && ISCON(l->n_qual)) ||
+			    (l->n_type <= BTMASK && ISCON(l->n_qual << TSHIFT)))
+				if (blevel > 0)
+					uerror("lvalue is declared const");
+#endif
+		}
+	}
+
+	if( actions & NCVTR ){
+		p->n_left = pconvert( p->n_left );
+		}
+	else if( !(actions & NCVT ) ){
+		switch( opty ){
+
+		case BITYPE:
+			p->n_right = pconvert( p->n_right );
+		case UTYPE:
+			p->n_left = pconvert( p->n_left );
+
+			}
+		}
+
+	if ((actions&PUN) && (o!=CAST))
+		chkpun(p);
+
+	if( actions & (TYPL|TYPR) ){
+
+		q = (actions&TYPL) ? p->n_left : p->n_right;
+
+		p->n_type = q->n_type;
+		p->n_qual = q->n_qual;
+		p->n_df = q->n_df;
+		p->n_ap = q->n_ap;
+		}
+
+	if( actions & CVTL ) p = convert( p, CVTL );
+	if( actions & CVTR ) p = convert( p, CVTR );
+	if( actions & TYMATCH ) p = tymatch(p);
+	if( actions & PTMATCH ) p = ptmatch(p);
+
+	if( actions & OTHER ){
+		struct symtab *sp1;
+
+		l = p->n_left;
+		r = p->n_right;
+
+		switch(o){
+
+		case NAME:
+			cerror("buildtree NAME");
+
+		case STREF:
+			/* p->x turned into *(p+offset) */
+			/* rhs must be a name; check correctness */
+
+			/* Find member symbol struct */
+			if (l->n_type != PTR+STRTY && l->n_type != PTR+UNIONTY){
+				uerror("struct or union required");
+				break;
+			}
+
+			if ((sp1 = strmemb(l->n_ap)) == NULL) {
+				uerror("undefined struct or union");
+				break;
+			}
+
+			if ((sp = findmember(sp1, r->n_name)) == NULL) {
+				uerror("member '%s' not declared", r->n_name);
+				break;
+			}
+
+			r->n_sp = sp;
+			p = stref(p);
+			break;
+
+		case UMUL:
+			if (l->n_op == ADDROF) {
+				nfree(p);
+				p = l->n_left;
+				nfree(l);
+			}
+			if( !ISPTR(l->n_type))uerror("illegal indirection");
+			p->n_type = DECREF(l->n_type);
+			p->n_qual = DECREF(l->n_qual);
+			p->n_df = l->n_df;
+			p->n_ap = l->n_ap;
+			break;
+
+		case ADDROF:
+			switch( l->n_op ){
+
+			case UMUL:
+				nfree(p);
+				p = l->n_left;
+				nfree(l);
+			case TEMP:
+			case NAME:
+				p->n_type = INCREF(l->n_type);
+				p->n_qual = INCQAL(l->n_qual);
+				p->n_df = l->n_df;
+				p->n_ap = l->n_ap;
+				break;
+
+			case COMOP:
+				nfree(p);
+				lr = buildtree(ADDROF, l->n_right, NIL);
+				p = buildtree( COMOP, l->n_left, lr );
+				nfree(l);
+				break;
+
+			case QUEST:
+				lr = buildtree( ADDROF, l->n_right->n_right, NIL );
+				ll = buildtree( ADDROF, l->n_right->n_left, NIL );
+				nfree(p); nfree(l->n_right);
+				p = buildtree( QUEST, l->n_left, buildtree( COLON, ll, lr ) );
+				nfree(l);
+				break;
+
+			default:
+				uerror("unacceptable operand of &: %d", l->n_op );
+				break;
+				}
+			break;
+
+		case LS:
+		case RS: /* must make type size at least int... */
+			if (p->n_type == CHAR || p->n_type == SHORT) {
+				p->n_left = makety(l, INT, 0, 0, MKAP(INT));
+			} else if (p->n_type == UCHAR || p->n_type == USHORT) {
+				p->n_left = makety(l, UNSIGNED, 0, 0,
+				    MKAP(UNSIGNED));
+			}
+			l = p->n_left;
+			p->n_type = l->n_type;
+			p->n_qual = l->n_qual;
+			p->n_df = l->n_df;
+			p->n_ap = l->n_ap;
+
+			/* FALLTHROUGH */
+		case LSEQ:
+		case RSEQ: /* ...but not for assigned types */
+			if(tsize(r->n_type, r->n_df, r->n_ap) > SZINT)
+				p->n_right = makety(r, INT, 0, 0, MKAP(INT));
+			break;
+
+		case RETURN:
+		case ASSIGN:
+		case CAST:
+			/* structure assignment */
+			/* take the addresses of the two sides; then make an
+			 * operator using STASG and
+			 * the addresses of left and right */
+
+			if (strmemb(l->n_ap) != strmemb(r->n_ap))
+				uerror("assignment of different structures");
+
+			r = buildtree(ADDROF, r, NIL);
+
+			l = block(STASG, l, r, r->n_type, r->n_df, r->n_ap);
+			l = clocal(l);
+
+			if( o == RETURN ){
+				nfree(p);
+				p = l;
+				break;
+			}
+
+			p->n_op = UMUL;
+			p->n_left = l;
+			p->n_right = NIL;
+			break;
+
+		case QUEST: /* fixup types of : */
+			if (r->n_left->n_type != p->n_type)
+				r->n_left = makety(r->n_left, p->n_type,
+				    p->n_qual, p->n_df, p->n_ap);
+			if (r->n_right->n_type != p->n_type)
+				r->n_right = makety(r->n_right, p->n_type,
+				    p->n_qual, p->n_df, p->n_ap);
+			break;
+
+		case COLON:
+			/* structure colon */
+
+			if (strmemb(l->n_ap) != strmemb(r->n_ap))
+				uerror( "type clash in conditional" );
+			break;
+
+		case CALL:
+			p->n_right = r = strargs(p->n_right);
+			p = funcode(p);
+			/* FALLTHROUGH */
+		case UCALL:
+			if (!ISPTR(l->n_type))
+				uerror("illegal function");
+			p->n_type = DECREF(l->n_type);
+			if (!ISFTN(p->n_type))
+				uerror("illegal function");
+			p->n_type = DECREF(p->n_type);
+			p->n_df = l->n_df+1; /* add one for prototypes */
+			p->n_ap = l->n_ap;
+			if (p->n_type == STRTY || p->n_type == UNIONTY) {
+				/* function returning structure */
+				/*  make function really return ptr to str., with * */
+
+				p->n_op += STCALL-CALL;
+				p->n_type = INCREF(p->n_type);
+				p = clocal(p); /* before recursing */
+				p = buildtree(UMUL, p, NIL);
+
+				}
+			break;
+
+		default:
+			cerror( "other code %d", o );
+			}
+
+		}
+
+	/*
+	 * Allow (void)0 casts.
+	 * XXX - anything on the right side must be possible to cast.
+	 * XXX - remove void types further on.
+	 */
+	if (p->n_op == CAST && p->n_type == VOID &&
+	    p->n_right->n_op == ICON)
+		p->n_right->n_type = VOID;
+
+	if (actions & CVTO)
+		p = oconvert(p);
+	p = clocal(p);
+
+#ifdef PCC_DEBUG
+	if (bdebug) {
+		printf("End of buildtree:\n");
+		fwalk(p, eprint, 0);
+	}
+#endif
+
+	return(p);
+
+	}
+
+/* Find a member in a struct or union.  May be an unnamed member */
+static struct symtab *
+findmember(struct symtab *sp, char *s)
+{
+	struct symtab *sp2, *sp3;
+
+	for (; sp != NULL; sp = sp->snext) {
+		if (sp->sname[0] == '*') {
+			/* unnamed member, recurse down */
+			if ((sp2 = findmember(strmemb(sp->sap), s))) {
+				sp3 = tmpalloc(sizeof (struct symtab));
+				*sp3 = *sp2;
+				sp3->soffset += sp->soffset;
+				return sp3;
+			}
+		} else if (sp->sname == s)
+			return sp;
+	}
+	return NULL;
+}
+
+
+/*
+ * Check if there will be a lost label destination inside of a ?:
+ * It cannot be reached so just print it out.
+ */
+void
+putjops(NODE *p, void *arg)
+{
+	if (p->n_op == COMOP && p->n_left->n_op == GOTO)
+		plabel(p->n_left->n_left->n_lval+1);
+}
+
+/*
+ * Build a name node based on a symtab entry.
+ * broken out from buildtree().
+ */
+NODE *
+nametree(struct symtab *sp)
+{
+	NODE *p;
+
+	p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->sap);
+	p->n_qual = sp->squal;
+	p->n_sp = sp;
+
+#ifndef NO_C_BUILTINS
+	if (sp->sname[0] == '_' && strncmp(sp->sname, "__builtin_", 10) == 0)
+		return p;  /* do not touch builtins here */
+	
+#endif
+
+	if (sp->sflags & STNODE) {
+		/* Generated for optimizer */
+		p->n_op = TEMP;
+		p->n_rval = sp->soffset;
+	}
+
+#ifdef GCC_COMPAT
+	/* Get a label name */
+	if (sp->sflags == SLBLNAME) {
+		p->n_type = VOID;
+		p->n_ap = MKAP(VOID);
+	}
+#endif
+	if (sp->stype == UNDEF) {
+		uerror("%s undefined", sp->sname);
+		/* make p look reasonable */
+		p->n_type = INT;
+		p->n_ap = MKAP(INT);
+		p->n_df = NULL;
+		defid(p, SNULL);
+	}
+	if (sp->sclass == MOE) {
+		p->n_op = ICON;
+		p->n_lval = sp->soffset;
+		p->n_df = NULL;
+		p->n_sp = NULL;
+	}
+	return clocal(p);
+}
+
+/*
+ * Cast a node to another type by inserting a cast.
+ * Just a nicer interface to buildtree.
+ * Returns the new tree.
+ */
+NODE *
+cast(NODE *p, TWORD t, TWORD u)
+{
+	NODE *q;
+
+	q = block(NAME, NIL, NIL, t, 0, MKAP(BTYPE(t)));
+	q->n_qual = u;
+	q = buildtree(CAST, q, p);
+	p = q->n_right;
+	nfree(q->n_left);
+	nfree(q);
+	return p;
+}
+
+/*
+ * Cast and complain if necessary by not inserining a cast.
+ */
+NODE *
+ccast(NODE *p, TWORD t, TWORD u, union dimfun *df, struct attr *ap)
+{
+	NODE *q;
+
+	/* let buildtree do typechecking (and casting) */ 
+	q = block(NAME, NIL, NIL, t, df, ap);
+	p = buildtree(ASSIGN, q, p);
+	nfree(p->n_left);
+	q = optim(p->n_right);
+	nfree(p);
+	return q;
+}
+
+/*
+ * Do a conditional branch.
+ */
+void
+cbranch(NODE *p, NODE *q)
+{
+	p = buildtree(CBRANCH, p, q);
+	if (p->n_left->n_op == ICON) {
+		if (p->n_left->n_lval != 0) {
+			branch(q->n_lval); /* branch always */
+			reached = 0;
+		}
+		tfree(p);
+		tfree(q);
+		return;
+	}
+	ecomp(p);
+}
+
+NODE *
+strargs( p ) register NODE *p;  { /* rewrite structure flavored arguments */
+
+	if( p->n_op == CM ){
+		p->n_left = strargs( p->n_left );
+		p->n_right = strargs( p->n_right );
+		return( p );
+		}
+
+	if( p->n_type == STRTY || p->n_type == UNIONTY ){
+		p = block(STARG, p, NIL, p->n_type, p->n_df, p->n_ap);
+		p->n_left = buildtree( ADDROF, p->n_left, NIL );
+		p = clocal(p);
+		}
+	return( p );
+}
+
+/*
+ * apply the op o to the lval part of p; if binary, rhs is val
+ */
+int
+conval(NODE *p, int o, NODE *q)
+{
+	TWORD tl = p->n_type, tr = q->n_type, td;
+	int i, u;
+	CONSZ val;
+	U_CONSZ v1, v2;
+
+	val = q->n_lval;
+
+	/* make both sides same type */
+	if (tl < BTMASK && tr < BTMASK) {
+		td = tl > tr ? tl : tr;
+		if (td < INT)
+			td = INT;
+		u = ISUNSIGNED(td);
+		if (tl != td)
+			p = makety(p, td, 0, 0, MKAP(td));
+		if (tr != td)
+			q = makety(q, td, 0, 0, MKAP(td));
+	} else
+		u = ISUNSIGNED(tl) || ISUNSIGNED(tr);
+	if( u && (o==LE||o==LT||o==GE||o==GT)) o += (UGE-GE);
+
+	if (p->n_sp != NULL && q->n_sp != NULL)
+		return(0);
+	if (q->n_sp != NULL && o != PLUS)
+		return(0);
+	if (p->n_sp != NULL && o != PLUS && o != MINUS)
+		return(0);
+
+	v1 = p->n_lval;
+	v2 = q->n_lval;
+	switch( o ){
+
+	case PLUS:
+		p->n_lval += val;
+		if (p->n_sp == NULL) {
+			p->n_right = q->n_right;
+			p->n_type = q->n_type;
+		}
+		break;
+	case MINUS:
+		p->n_lval -= val;
+		break;
+	case MUL:
+		p->n_lval *= val;
+		break;
+	case DIV:
+		if (val == 0)
+			uerror("division by 0");
+		else  {
+			if (u) {
+				v1 /= v2;
+				p->n_lval = v1;
+			} else
+				p->n_lval /= val;
+		}
+		break;
+	case MOD:
+		if (val == 0)
+			uerror("division by 0");
+		else  {
+			if (u) {
+				v1 %= v2;
+				p->n_lval = v1;
+			} else
+				p->n_lval %= val;
+		}
+		break;
+	case AND:
+		p->n_lval &= val;
+		break;
+	case OR:
+		p->n_lval |= val;
+		break;
+	case ER:
+		p->n_lval ^= val;
+		break;
+	case LS:
+		i = (int)val;
+		p->n_lval = p->n_lval << i;
+		break;
+	case RS:
+		i = (int)val;
+		if (u) {
+			v1 = v1 >> i;
+			p->n_lval = v1;
+		} else
+			p->n_lval = p->n_lval >> i;
+		break;
+
+	case UMINUS:
+		p->n_lval = - p->n_lval;
+		break;
+	case COMPL:
+		p->n_lval = ~p->n_lval;
+		break;
+	case NOT:
+		p->n_lval = !p->n_lval;
+		break;
+	case LT:
+		p->n_lval = p->n_lval < val;
+		break;
+	case LE:
+		p->n_lval = p->n_lval <= val;
+		break;
+	case GT:
+		p->n_lval = p->n_lval > val;
+		break;
+	case GE:
+		p->n_lval = p->n_lval >= val;
+		break;
+	case ULT:
+		p->n_lval = v1 < v2;
+		break;
+	case ULE:
+		p->n_lval = v1 <= v2;
+		break;
+	case UGT:
+		p->n_lval = v1 > v2;
+		break;
+	case UGE:
+		p->n_lval = v1 >= v2;
+		break;
+	case EQ:
+		p->n_lval = p->n_lval == val;
+		break;
+	case NE:
+		p->n_lval = p->n_lval != val;
+		break;
+	case ANDAND:
+		p->n_lval = p->n_lval && val;
+		break;
+	case OROR:
+		p->n_lval = p->n_lval || val;
+		break;
+	default:
+		return(0);
+		}
+	/* Do the best in making everything type correct after calc */
+	if (p->n_sp == NULL && q->n_sp == NULL)
+		p->n_lval = valcast(p->n_lval, p->n_type);
+	return(1);
+	}
+
+/*
+ * Ensure that v matches the type t; sign- or zero-extended
+ * as suitable to CONSZ.
+ * Only to be used for integer types.
+ */
+CONSZ
+valcast(CONSZ v, TWORD t)
+{
+	CONSZ r;
+
+	if (t < CHAR || t > ULONGLONG)
+		return v; /* cannot cast */
+
+	if (t >= LONGLONG)
+		return v; /* already largest */
+
+#define M(x)	((((1ULL << ((x)-1)) - 1) << 1) + 1)
+#define	NOTM(x)	(~M(x))
+#define	SBIT(x)	(1ULL << ((x)-1))
+
+	r = v & M(btattr[t].atypsz);
+	if (!ISUNSIGNED(t) && (SBIT(btattr[t].atypsz) & r))
+		r = r | NOTM(btattr[t].atypsz);
+	return r;
+}
+
+/*
+ * Checks p for the existance of a pun.  This is called when the op of p
+ * is ASSIGN, RETURN, CAST, COLON, or relational.
+ * One case is when enumerations are used: this applies only to lint.
+ * In the other case, one operand is a pointer, the other integer type
+ * we check that this integer is in fact a constant zero...
+ * in the case of ASSIGN, any assignment of pointer to integer is illegal
+ * this falls out, because the LHS is never 0.
+ * XXX - check for COMOPs in assignment RHS?
+ */
+void
+chkpun(NODE *p)
+{
+	union dimfun *d1, *d2;
+	NODE *q;
+	int t1, t2;
+
+	t1 = p->n_left->n_type;
+	t2 = p->n_right->n_type;
+
+	switch (p->n_op) {
+	case RETURN:
+		/* return of void allowed but nothing else */
+		if (t1 == VOID && t2 == VOID)
+			return;
+		if (t1 == VOID) {
+			werror("returning value from void function");
+			return;
+		}
+		if (t2 == VOID) {
+			uerror("using void value");
+			return;
+		}
+	case COLON:
+		if (t1 == VOID && t2 == VOID)
+			return;
+		break;
+	default:
+		if ((t1 == VOID && t2 != VOID) || (t1 != VOID && t2 == VOID)) {
+			uerror("value of void expression used");
+			return;
+		}
+		break;
+	}
+
+	/* allow void pointer assignments in any direction */
+	if (BTYPE(t1) == VOID && (t2 & TMASK))
+		return;
+	if (BTYPE(t2) == VOID && (t1 & TMASK))
+		return;
+
+	/* boolean have special syntax */
+	if (t1 == BOOL) {
+		if (!ISARY(t2)) /* Anything scalar */
+			return;
+	}
+
+	if (ISPTR(t1) || ISARY(t1))
+		q = p->n_right;
+	else
+		q = p->n_left;
+
+	if (!ISPTR(q->n_type) && !ISARY(q->n_type)) {
+		if (q->n_op != ICON || q->n_lval != 0)
+			werror("illegal combination of pointer and integer");
+	} else {
+		if (t1 == t2) {
+			if (ISSOU(BTYPE(t1)) &&
+			    !suemeq(p->n_left->n_ap, p->n_right->n_ap))
+				werror("illegal structure pointer combination");
+			return;
+		}
+		d1 = p->n_left->n_df;
+		d2 = p->n_right->n_df;
+		for (;;) {
+			if (ISARY(t1) || ISPTR(t1)) {
+				if (!ISARY(t2) && !ISPTR(t2))
+					break;
+				if (ISARY(t1) && ISARY(t2) && d1->ddim != d2->ddim) {
+					werror("illegal array size combination");
+					return;
+				}
+				if (ISARY(t1))
+					++d1;
+				if (ISARY(t2))
+					++d2;
+			} else if (ISFTN(t1)) {
+				if (chkftn(d1->dfun, d2->dfun)) {
+					werror("illegal function "
+					    "pointer combination");
+					return;
+				}
+				++d1;
+				++d2;
+			} else
+				break;
+			t1 = DECREF(t1);
+			t2 = DECREF(t2);
+		}
+		if (DEUNSIGN(t1) != DEUNSIGN(t2))
+			warner(Wpointer_sign, NULL);
+	}
+}
+
+NODE *
+stref(NODE *p)
+{
+	NODE *r;
+	struct attr *ap;
+	union dimfun *d;
+	TWORD t, q;
+	int dsc;
+	OFFSZ off;
+	struct symtab *s;
+
+	/* make p->x */
+	/* this is also used to reference automatic variables */
+
+	s = p->n_right->n_sp;
+	nfree(p->n_right);
+	r = p->n_left;
+	nfree(p);
+	p = pconvert(r);
+
+	/* make p look like ptr to x */
+
+	if (!ISPTR(p->n_type))
+		p->n_type = PTR+UNIONTY;
+
+	t = INCREF(s->stype);
+	q = INCQAL(s->squal);
+	d = s->sdf;
+	ap = s->sap;
+
+	p = makety(p, t, q, d, ap);
+
+	/* compute the offset to be added */
+
+	off = s->soffset;
+	dsc = s->sclass;
+
+#ifndef CAN_UNALIGN
+	/*
+	 * If its a packed struct, and the target cannot do unaligned
+	 * accesses, then split it up in two bitfield operations.
+	 * LHS and RHS accesses are different, so must delay
+	 * it until we know.  Do the bitfield construct here though.
+	 */
+	if ((dsc & FIELD) == 0 && (off % talign(s->stype, s->sap))) {
+#if 0
+		int sz = tsize(s->stype, s->sdf, s->sap);
+		int al = talign(s->stype, s->sap);
+		int sz1 = al - (off % al);
+#endif
+	}
+#endif
+
+#if 0
+	if (dsc & FIELD) {  /* make fields look like ints */
+		off = (off/ALINT)*ALINT;
+		ap = MKAP(INT);
+	}
+#endif
+	if (off != 0) {
+		p = block(PLUS, p, offcon(off, t, d, ap), t, d, ap);
+		p->n_qual = q;
+		p = optim(p);
+	}
+
+	p = buildtree(UMUL, p, NIL);
+
+	/* if field, build field info */
+
+	if (dsc & FIELD) {
+		p = block(FLD, p, NIL, s->stype, 0, s->sap);
+		p->n_qual = q;
+		p->n_rval = PKFIELD(dsc&FLDSIZ, s->soffset%talign(s->stype, ap));
+	}
+
+	p = clocal(p);
+	return p;
+}
+
+int
+notlval(p) register NODE *p; {
+
+	/* return 0 if p an lvalue, 1 otherwise */
+
+	again:
+
+	switch( p->n_op ){
+
+	case FLD:
+		p = p->n_left;
+		goto again;
+
+	case NAME:
+	case OREG:
+	case UMUL:
+		if( ISARY(p->n_type) || ISFTN(p->n_type) ) return(1);
+	case TEMP:
+	case REG:
+		return(0);
+
+	default:
+		return(1);
+
+		}
+
+	}
+/* make a constant node with value i */
+NODE *
+bcon(int i)
+{
+	return xbcon(i, NULL, INT);
+}
+
+NODE *
+xbcon(CONSZ val, struct symtab *sp, TWORD type)
+{
+	NODE *p;
+
+	p = block(ICON, NIL, NIL, type, 0, MKAP(type));
+	p->n_lval = val;
+	p->n_sp = sp;
+	return clocal(p);
+}
+
+NODE *
+bpsize(NODE *p)
+{
+	int isdyn(struct symtab *sp);
+	struct attr *ap;
+	struct symtab s;
+	NODE *q, *r;
+	TWORD t;
+
+	s.stype = DECREF(p->n_type);
+	s.sdf = p->n_df;
+	if (isdyn(&s)) {
+		q = bcon(1);
+		for (t = s.stype; t > BTMASK; t = DECREF(t)) {
+			if (ISPTR(t))
+				return buildtree(MUL, q, bcon(SZPOINT(t)));
+			if (ISARY(t)) {
+				if (s.sdf->ddim < 0)
+					r = tempnode(-s.sdf->ddim,
+					     INT, 0, MKAP(INT));
+				else
+					r = bcon(s.sdf->ddim/SZCHAR);
+				q = buildtree(MUL, q, r);
+				s.sdf++;
+			}
+		}
+		ap = attr_find(p->n_ap, ATTR_BASETYP);
+		p = buildtree(MUL, q, bcon(ap->atypsz/SZCHAR));
+	} else
+		p = (offcon(psize(p), p->n_type, p->n_df, p->n_ap));
+	return p;
+}
+
+/*
+ * p is a node of type pointer; psize returns the
+ * size of the thing pointed to
+ */
+OFFSZ
+psize(NODE *p)
+{
+
+	if (!ISPTR(p->n_type)) {
+		uerror("pointer required");
+		return(SZINT);
+	}
+	/* note: no pointers to fields */
+	return(tsize(DECREF(p->n_type), p->n_df, p->n_ap));
+}
+
+/*
+ * convert an operand of p
+ * f is either CVTL or CVTR
+ * operand has type int, and is converted by the size of the other side
+ * convert is called when an integer is to be added to a pointer, for
+ * example in arrays or structures.
+ */
+NODE *
+convert(NODE *p, int f)
+{
+	union dimfun *df;
+	TWORD ty, ty2;
+	NODE *q, *r, *s, *rv;
+
+	if (f == CVTL) {
+		q = p->n_left;
+		s = p->n_right;
+	} else {
+		q = p->n_right;
+		s = p->n_left;
+	}
+	ty2 = ty = DECREF(s->n_type);
+	while (ISARY(ty))
+		ty = DECREF(ty);
+
+	r = offcon(tsize(ty, s->n_df, s->n_ap), s->n_type, s->n_df, s->n_ap);
+	ty = ty2;
+	rv = bcon(1);
+	df = s->n_df;
+	while (ISARY(ty)) {
+		rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) :
+		    tempnode(-df->ddim, INT, 0, MKAP(INT)));
+		df++;
+		ty = DECREF(ty);
+	}
+	rv = clocal(block(PMCONV, rv, r, INT, 0, MKAP(INT)));
+	rv = optim(rv);
+
+	r = block(PMCONV, q, rv, INT, 0, MKAP(INT));
+	r = clocal(r);
+	/*
+	 * Indexing is only allowed with integer arguments, so insert
+	 * SCONV here if arg is not an integer.
+	 * XXX - complain?
+	 */
+	if (r->n_type != INTPTR)
+		r = clocal(block(SCONV, r, NIL, INTPTR, 0, MKAP(INTPTR)));
+	if (f == CVTL)
+		p->n_left = r;
+	else
+		p->n_right = r;
+	return(p);
+}
+
+NODE *
+pconvert( p ) register NODE *p; {
+
+	/* if p should be changed into a pointer, do so */
+
+	if( ISARY( p->n_type) ){
+		p->n_type = DECREF( p->n_type );
+		++p->n_df;
+		return( buildtree( ADDROF, p, NIL ) );
+	}
+	if( ISFTN( p->n_type) )
+		return( buildtree( ADDROF, p, NIL ) );
+
+	return( p );
+	}
+
+NODE *
+oconvert(p) register NODE *p; {
+	/* convert the result itself: used for pointer and unsigned */
+
+	switch(p->n_op) {
+
+	case LE:
+	case LT:
+	case GE:
+	case GT:
+		if(ISUNSIGNED(p->n_left->n_type) ||
+		    ISUNSIGNED(p->n_right->n_type) ||
+		    ISPTR(p->n_left->n_type) ||
+		    ISPTR(p->n_right->n_type))
+			 p->n_op += (ULE-LE);
+		/* FALLTHROUGH */
+	case EQ:
+	case NE:
+		return( p );
+
+	case MINUS:
+		p->n_type = INTPTR;
+		p->n_ap = MKAP(INTPTR);
+		return(  clocal( block( PVCONV,
+			p, bpsize(p->n_left), INT, 0, MKAP(INT))));
+		}
+
+	cerror( "illegal oconvert: %d", p->n_op );
+
+	return(p);
+	}
+
+/*
+ * makes the operands of p agree; they are
+ * either pointers or integers, by this time
+ * with MINUS, the sizes must be the same
+ * with COLON, the types must be the same
+ */
+NODE *
+ptmatch(NODE *p)
+{
+	struct attr *ap, *ap2;
+	union dimfun *d, *d2;
+	TWORD t1, t2, t, q1, q2, q;
+	int o;
+
+	o = p->n_op;
+	t = t1 = p->n_left->n_type;
+	q = q1 = p->n_left->n_qual;
+	t2 = p->n_right->n_type;
+	q2 = p->n_right->n_qual;
+	d = p->n_left->n_df;
+	d2 = p->n_right->n_df;
+	ap = p->n_left->n_ap;
+	ap2 = p->n_right->n_ap;
+
+	switch( o ){
+
+	case ASSIGN:
+	case RETURN:
+	case CAST:
+		{  break; }
+
+	case MINUS: {
+		int isdyn(struct symtab *sp);
+		struct symtab s1, s2;
+
+		s1.stype = DECREF(t);
+		s1.sdf = d;
+		s2.stype = DECREF(t2);
+		s2.sdf = d2;
+		if (isdyn(&s1) || isdyn(&s2))
+			; /* We don't know */
+		else if (psize(p->n_left) != psize(p->n_right))
+			uerror("illegal pointer subtraction");
+		break;
+		}
+
+	case COLON:
+		if (t1 != t2) {
+			/*
+			 * Check for void pointer types. They are allowed
+			 * to cast to/from any pointers.
+			 */
+			if (ISPTR(t1) && ISPTR(t2) &&
+			    (BTYPE(t1) == VOID || BTYPE(t2) == VOID))
+				break;
+			uerror("illegal types in :");
+		}
+		break;
+
+	default:  /* must work harder: relationals or comparisons */
+
+		if( !ISPTR(t1) ){
+			t = t2;
+			q = q2;
+			d = d2;
+			ap = ap2;
+			break;
+			}
+		if( !ISPTR(t2) ){
+			break;
+			}
+
+		/* both are pointers */
+		if( talign(t2,ap2) < talign(t,ap) ){
+			t = t2;
+			q = q2;
+			ap = ap2;
+			}
+		break;
+		}
+
+	p->n_left = makety( p->n_left, t, q, d, ap );
+	p->n_right = makety( p->n_right, t, q, d, ap );
+	if( o!=MINUS && !clogop(o) ){
+
+		p->n_type = t;
+		p->n_qual = q;
+		p->n_df = d;
+		p->n_ap = ap;
+		}
+
+	return(clocal(p));
+	}
+
+int tdebug = 0;
+
+
+/*
+ * Satisfy the types of various arithmetic binary ops.
+ *
+ * rules are:
+ *  if assignment, type of LHS
+ *  if any doubles, make double
+ *  else if any float make float
+ *  else if any longlongs, make long long
+ *  else if any longs, make long
+ *  else etcetc.
+ *
+ *  If the op with the highest rank is unsigned, this is the resulting type.
+ *  See:  6.3.1.1 rank order equal of signed and unsigned types
+ *  	  6.3.1.8 Usual arithmetic conversions
+ */
+NODE *
+tymatch(NODE *p)
+{
+	TWORD tl, tr, t, tu;
+	NODE *l, *r;
+	int o, lu, ru;
+
+	o = p->n_op;
+	r = p->n_right;
+	l = p->n_left;
+
+	tl = l->n_type;
+	tr = r->n_type;
+
+	lu = ru = 0;
+	if (ISUNSIGNED(tl)) {
+		lu = 1;
+		tl = DEUNSIGN(tl);
+	}
+	if (ISUNSIGNED(tr)) {
+		ru = 1;
+		tr = DEUNSIGN(tr);
+	}
+
+	if (clogop(o) && tl == tr && lu != ru &&
+	    l->n_op != ICON && r->n_op != ICON)
+		warner(Wsign_compare, NULL);
+
+	if (tl == LDOUBLE || tr == LDOUBLE)
+		t = LDOUBLE;
+	else if (tl == DOUBLE || tr == DOUBLE)
+		t = DOUBLE;
+	else if (tl == FLOAT || tr == FLOAT)
+		t = FLOAT;
+	else if (tl==LONGLONG || tr == LONGLONG)
+		t = LONGLONG;
+	else if (tl==LONG || tr==LONG)
+		t = LONG;
+	else /* everything else */
+		t = INT;
+
+	if (casgop(o)) {
+		tu = l->n_type;
+		t = tl;
+	} else {
+		/* Should result be unsigned? */
+		/* This depends on ctype() being called correctly */
+		tu = t;
+		if (UNSIGNABLE(t) && (lu || ru)) {
+			if (tl >= tr && lu)
+				tu = ENUNSIGN(t);
+			if (tr >= tl && ru)
+				tu = ENUNSIGN(t);
+		}
+	}
+
+	/* because expressions have values that are at least as wide
+	   as INT or UNSIGNED, the only conversions needed
+	   are those involving FLOAT/DOUBLE, and those
+	   from LONG to INT and ULONG to UNSIGNED */
+
+	if (t != tl || (ru && !lu)) {
+		if (o != CAST && r->n_op != ICON &&
+		    tsize(tl, 0, MKAP(tl)) > tsize(tu, 0, MKAP(tu)))
+			warner(Wtruncate, tnames[tu], tnames[tl]);
+		p->n_left = makety( p->n_left, tu, 0, 0, MKAP(tu));
+	}
+
+	if (t != tr || o==CAST || (lu && !ru)) {
+		if (o != CAST && r->n_op != ICON &&
+		    tsize(tr, 0, MKAP(tr)) > tsize(tu, 0, MKAP(tu)))
+			warner(Wtruncate, tnames[tu], tnames[tr]);
+		p->n_right = makety(p->n_right, tu, 0, 0, MKAP(tu));
+	}
+
+	if( casgop(o) ){
+		p->n_type = p->n_left->n_type;
+		p->n_df = p->n_left->n_df;
+		p->n_ap = p->n_left->n_ap;
+		}
+	else if( !clogop(o) ){
+		p->n_type = tu;
+		p->n_df = NULL;
+		p->n_ap = MKAP(t);
+		}
+
+#ifdef PCC_DEBUG
+	if (tdebug) {
+		printf("tymatch(%p): ", p);
+		tprint(stdout, tl, 0);
+		printf(" %s ", copst(o));
+		tprint(stdout, tr, 0);
+		printf(" => ");
+		tprint(stdout, tu, 0);
+		printf("\n");
+		fwalk(p, eprint, 0);
+	}
+#endif
+
+	return(p);
+	}
+
+/*
+ * Create a float const node of zero.
+ */
+static NODE *
+fzero(TWORD t)
+{
+	NODE *p = block(FCON, NIL, NIL, t, 0, MKAP(t));
+
+	p->n_dcon = FLOAT_CAST(0, INT);
+	return p;
+}
+
+/*
+ * make p into type t by inserting a conversion
+ */
+NODE *
+makety(NODE *p, TWORD t, TWORD q, union dimfun *d, struct attr *ap)
+{
+
+	if (t == p->n_type) {
+		p->n_df = d;
+		p->n_ap = ap;
+		p->n_qual = q;
+		return(p);
+	}
+
+	if (p->n_op == FCON && (t >= FLOAT && t <= LDOUBLE)) {
+		if (t == FLOAT)
+			p->n_dcon = (float)p->n_dcon;
+		else if (t == DOUBLE)
+			p->n_dcon = (double)p->n_dcon;
+		else
+			p->n_dcon = (long double)p->n_dcon;
+		p->n_type = t;
+		return p;
+	}
+
+	if (p->n_op == FCON) {
+		int isf = ISFTY(t);
+		NODE *r;
+
+		if (isf||ISITY(t)) {
+			if (isf == ISFTY(p->n_type)) {
+				p->n_type = t;
+				p->n_qual = q;
+				p->n_df = d;
+				p->n_ap = ap;
+				return(p);
+			} else if (isf == ISITY(p->n_type)) {
+				/* will be zero */
+				nfree(p);
+				return fzero(t);
+			} else if (ISCTY(p->n_type))
+				cerror("complex constant");
+		} else if (ISCTY(t)) {
+			if (ISITY(p->n_type)) {
+				/* convert to correct subtype */
+				r = fzero(t - (COMPLEX-DOUBLE));
+				p->n_type = t + (IMAG-COMPLEX);
+				p->n_qual = q;
+				p->n_df = d;
+				p->n_ap = MKAP(p->n_type);
+				return block(CM, r, p, t, 0, MKAP(t));
+			} else if (ISFTY(p->n_type)) {
+				/* convert to correct subtype */
+				r = fzero(t + (IMAG-COMPLEX));
+				p->n_type = t - (COMPLEX-DOUBLE);
+				p->n_qual = q;
+				p->n_df = d;
+				p->n_ap = MKAP(p->n_type);
+				return block(CM, p, r, t, 0, MKAP(t));
+			} else if (ISCTY(p->n_type))
+				cerror("complex constant2");
+		}
+	}
+
+	if (t & TMASK) {
+		/* non-simple type */
+		p = block(PCONV, p, NIL, t, d, ap);
+		p->n_qual = q;
+		return clocal(p);
+	}
+
+	if (p->n_op == ICON) {
+		if (ISFTY(t)) {
+			p->n_op = FCON;
+			p->n_dcon = FLOAT_CAST(p->n_lval, p->n_type);
+			p->n_type = t;
+			p->n_qual = q;
+			p->n_ap = MKAP(t);
+			return (clocal(p));
+		} else if (ISCTY(t) || ISITY(t))
+			cerror("complex constant3");
+	}
+
+	p = block(SCONV, p, NIL, t, d, ap);
+	p->n_qual = q;
+	return clocal(p);
+
+}
+
+NODE *
+block(int o, NODE *l, NODE *r, TWORD t, union dimfun *d, struct attr *ap)
+{
+	register NODE *p;
+
+	p = talloc();
+	p->n_rval = 0;
+	p->n_op = o;
+	p->n_lval = 0; /* Protect against large lval */
+	p->n_left = l;
+	p->n_right = r;
+	p->n_type = t;
+	p->n_qual = 0;
+	p->n_df = d;
+	p->n_ap = ap;
+#if !defined(MULTIPASS)
+	/* p->n_reg = */p->n_su = 0;
+	p->n_regw = 0;
+#endif
+	return(p);
+	}
+
+/*
+ * Return the constant value from an ICON.
+ */
+CONSZ
+icons(NODE *p)
+{
+	/* if p is an integer constant, return its value */
+	CONSZ val;
+
+	if (p->n_op != ICON || p->n_sp != NULL) {
+		uerror( "constant expected");
+		val = 1;
+	} else
+		val = p->n_lval;
+	tfree(p);
+	return(val);
+}
+
+/* 
+ * the intent of this table is to examine the
+ * operators, and to check them for
+ * correctness.
+ * 
+ * The table is searched for the op and the
+ * modified type (where this is one of the
+ * types INT (includes char and short), LONG,
+ * DOUBLE (includes FLOAT), and POINTER
+ * 
+ * The default action is to make the node type integer
+ * 
+ * The actions taken include:
+ * 	PUN	  check for puns
+ * 	CVTL	  convert the left operand
+ * 	CVTR	  convert the right operand
+ * 	TYPL	  the type is determined by the left operand
+ * 	TYPR	  the type is determined by the right operand
+ * 	TYMATCH	  force type of left and right to match,by inserting conversions
+ * 	PTMATCH	  like TYMATCH, but for pointers
+ * 	LVAL	  left operand must be lval
+ * 	CVTO	  convert the op
+ * 	NCVT	  do not convert the operands
+ * 	OTHER	  handled by code
+ * 	NCVTR	  convert the left operand, not the right...
+ * 
+ */
+
+# define MINT 01	/* integer */
+# define MDBI 02	/* integer or double */
+# define MSTR 04	/* structure */
+# define MPTR 010	/* pointer */
+# define MPTI 020	/* pointer or integer */
+
+int
+opact(NODE *p)
+{
+	int mt12, mt1, mt2, o;
+
+	mt1 = mt2 = mt12 = 0;
+
+	switch (coptype(o = p->n_op)) {
+	case BITYPE:
+		mt12=mt2 = moditype(p->n_right->n_type);
+	case UTYPE:
+		mt12 &= (mt1 = moditype(p->n_left->n_type));
+		break;
+	}
+
+	switch( o ){
+
+	case NAME :
+	case ICON :
+	case FCON :
+	case CALL :
+	case UCALL:
+	case UMUL:
+		{  return( OTHER ); }
+	case UMINUS:
+		if( mt1 & MDBI ) return( TYPL );
+		break;
+
+	case COMPL:
+		if( mt1 & MINT ) return( TYPL );
+		break;
+
+	case ADDROF:
+		return( NCVT+OTHER );
+	case NOT:
+/*	case INIT: */
+	case CM:
+	case CBRANCH:
+	case ANDAND:
+	case OROR:
+		return( 0 );
+
+	case MUL:
+	case DIV:
+		if( mt12 & MDBI ) return( TYMATCH );
+		break;
+
+	case MOD:
+	case AND:
+	case OR:
+	case ER:
+		if( mt12 & MINT ) return( TYMATCH );
+		break;
+
+	case LS:
+	case RS:
+		if( mt12 & MINT ) return( TYPL+OTHER );
+		break;
+
+	case EQ:
+	case NE:
+	case LT:
+	case LE:
+	case GT:
+	case GE:
+		if( mt12 & MDBI ) return( TYMATCH+CVTO );
+		else if( mt12 & MPTR ) return( PTMATCH+PUN+CVTO );
+		else if( mt12 & MPTI ) return( PTMATCH+PUN );
+		else break;
+
+	case QUEST:
+		return( TYPR+OTHER );
+	case COMOP:
+		return( TYPR );
+
+	case STREF:
+		return( NCVTR+OTHER );
+
+	case FORCE:
+		return( TYPL );
+
+	case COLON:
+		if( mt12 & MDBI ) return( TYMATCH );
+		else if( mt12 & MPTR ) return( TYPL+PTMATCH+PUN );
+		else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+PUN );
+		else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+PUN );
+		else if( mt12 & MSTR ) return( NCVT+TYPL+OTHER );
+		break;
+
+	case ASSIGN:
+	case RETURN:
+		if( mt12 & MSTR ) return( LVAL+NCVT+TYPL+OTHER );
+	case CAST:
+		if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH );
+		else if( mt1 & MPTR) return( LVAL+PTMATCH+PUN );
+		else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN );
+		break;
+
+	case LSEQ:
+	case RSEQ:
+		if( mt12 & MINT ) return( TYPL+LVAL+OTHER );
+		break;
+
+	case MULEQ:
+	case DIVEQ:
+		if( mt12 & MDBI ) return( LVAL+TYMATCH );
+		break;
+
+	case MODEQ:
+	case ANDEQ:
+	case OREQ:
+	case EREQ:
+		if (mt12 & MINT)
+			return(LVAL+TYMATCH);
+		break;
+
+	case PLUSEQ:
+	case MINUSEQ:
+	case INCR:
+	case DECR:
+		if (mt12 & MDBI)
+			return(TYMATCH+LVAL);
+		else if ((mt1&MPTR) && (mt2&MINT))
+			return(TYPL+LVAL+CVTR);
+		break;
+
+	case MINUS:
+		if (mt12 & MPTR)
+			return(CVTO+PTMATCH+PUN);
+		if (mt2 & MPTR)
+			break;
+		/* FALLTHROUGH */
+	case PLUS:
+		if (mt12 & MDBI)
+			return(TYMATCH);
+		else if ((mt1&MPTR) && (mt2&MINT))
+			return(TYPL+CVTR);
+		else if ((mt1&MINT) && (mt2&MPTR))
+			return(TYPR+CVTL);
+
+	}
+	uerror("operands of %s have incompatible types", copst(o));
+	return(NCVT);
+}
+
+int
+moditype(TWORD ty)
+{
+	switch (ty) {
+
+	case STRTY:
+	case UNIONTY:
+		return( MSTR );
+
+	case BOOL:
+	case CHAR:
+	case SHORT:
+	case UCHAR:
+	case USHORT:
+	case UNSIGNED:
+	case ULONG:
+	case ULONGLONG:
+	case INT:
+	case LONG:
+	case LONGLONG:
+		return( MINT|MDBI|MPTI );
+	case FLOAT:
+	case DOUBLE:
+	case LDOUBLE:
+#ifndef NO_COMPLEX
+	case FCOMPLEX:
+	case COMPLEX:
+	case LCOMPLEX:
+	case FIMAG:
+	case IMAG:
+	case LIMAG:
+#endif
+		return( MDBI );
+	default:
+		return( MPTR|MPTI );
+
+	}
+}
+
+int tvaloff = MAXREGS+NPERMREG > 100 ? MAXREGS+NPERMREG + 100 : 100;
+
+/*
+ * Returns a TEMP node with temp number nr.
+ * If nr == 0, return a node with a new number.
+ */
+NODE *
+tempnode(int nr, TWORD type, union dimfun *df, struct attr *ap)
+{
+	NODE *r;
+
+	if (tvaloff == -NOOFFSET)
+		tvaloff++; /* Skip this for array indexing */
+	r = block(TEMP, NIL, NIL, type, df, ap);
+	regno(r) = nr ? nr : tvaloff;
+	tvaloff += szty(type);
+	return r;
+}
+
+/*
+ * Do sizeof on p.
+ */
+NODE *
+doszof(NODE *p)
+{
+	extern NODE *arrstk[10];
+	extern int arrstkp;
+	union dimfun *df;
+	TWORD ty;
+	NODE *rv, *q;
+	int astkp;
+
+	if (p->n_op == FLD)
+		uerror("can't apply sizeof to bit-field");
+
+	/*
+	 * Arrays may be dynamic, may need to make computations.
+	 */
+
+	rv = bcon(1);
+	df = p->n_df;
+	ty = p->n_type;
+	astkp = 0;
+	while (ISARY(ty)) {
+		if (df->ddim == NOOFFSET)
+			uerror("sizeof of incomplete type");
+		if (df->ddim < 0) {
+			if (arrstkp)
+				q = arrstk[astkp++];
+			else
+				q = tempnode(-df->ddim, INT, 0, MKAP(INT));
+		} else
+			q = bcon(df->ddim);
+		rv = buildtree(MUL, rv, q);
+		df++;
+		ty = DECREF(ty);
+	}
+	rv = buildtree(MUL, rv, bcon(tsize(ty, p->n_df, p->n_ap)/SZCHAR));
+	tfree(p);
+	arrstkp = 0; /* XXX - may this fail? */
+	return rv;
+}
+
+#ifdef PCC_DEBUG
+void
+eprint(NODE *p, int down, int *a, int *b)
+{
+	int ty;
+
+	*a = *b = down+1;
+	while( down > 1 ){
+		printf( "\t" );
+		down -= 2;
+		}
+	if( down ) printf( "    " );
+
+	ty = coptype( p->n_op );
+
+	printf("%p) %s, ", p, copst(p->n_op));
+	if (p->n_op == XARG || p->n_op == XASM)
+		printf("id '%s', ", p->n_name);
+	if (ty == LTYPE) {
+		printf(CONFMT, p->n_lval);
+		if (p->n_op == NAME || p->n_op == ICON)
+			printf(", %p, ", p->n_sp);
+		else
+			printf(", %d, ", p->n_rval);
+	}
+	tprint(stdout, p->n_type, p->n_qual);
+	printf( ", %p, ", p->n_df);
+	dump_attr(p->n_ap);
+}
+# endif
+
+/*
+ * Emit everything that should be emitted on the left side 
+ * of a comma operator, and remove the operator.
+ * Do not traverse through QUEST, ANDAND and OROR.
+ * Enable this for all targets when stable enough.
+ */
+static void
+comops(NODE *p)
+{
+	int o;
+	NODE *q;
+
+	while (p->n_op == COMOP) {
+		/* XXX hack for GCC ({ }) ops */
+		if (p->n_left->n_op == GOTO) {
+			int v = (int)p->n_left->n_left->n_lval;
+			ecomp(p->n_left);
+			plabel(v+1);
+		} else
+			ecomp(p->n_left); /* will recurse if more COMOPs */
+		q = p->n_right;
+		*p = *q;
+		nfree(q);
+	}
+	o = coptype(p->n_op);
+	if (p->n_op == QUEST || p->n_op == ANDAND || p->n_op == OROR)
+		o = UTYPE;
+	if (o != LTYPE)
+		comops(p->n_left);
+	if (o == BITYPE)
+		comops(p->n_right);
+}
+
+/*
+ * Walk up through the tree from the leaves,
+ * removing constant operators.
+ */
+static void
+logwalk(NODE *p)
+{
+	int o = coptype(p->n_op);
+	NODE *l, *r;
+
+	l = p->n_left;
+	r = p->n_right;
+	switch (o) {
+	case LTYPE:
+		return;
+	case BITYPE:
+		logwalk(r);
+	case UTYPE:
+		logwalk(l);
+	}
+	if (!clogop(p->n_op))
+		return;
+	if (p->n_op == NOT && l->n_op == ICON) {
+		p->n_lval = l->n_lval == 0;
+		nfree(l);
+		p->n_op = ICON;
+	}
+	if (l->n_op == ICON && r->n_op == ICON) {
+		if (conval(l, p->n_op, r) == 0) {
+			/*
+			 * people sometimes tend to do really odd compares,
+			 * like "if ("abc" == "def")" etc.
+			 * do it runtime instead.
+			 */
+		} else {
+			p->n_lval = l->n_lval;
+			p->n_op = ICON;
+			nfree(l);
+			nfree(r);
+		}
+	}
+}
+
+/*
+ * Removes redundant logical operators for branch conditions.
+ */
+static void
+fixbranch(NODE *p, int label)
+{
+
+	logwalk(p);
+
+	if (p->n_op == ICON) {
+		if (p->n_lval != 0)
+			branch(label);
+		nfree(p);
+	} else {
+		if (!clogop(p->n_op)) /* Always conditional */
+			p = buildtree(NE, p, bcon(0));
+		ecode(buildtree(CBRANCH, p, bcon(label)));
+	}
+}
+
+/*
+ * Write out logical expressions as branches.
+ */
+static void
+andorbr(NODE *p, int true, int false)
+{
+	NODE *q;
+	int o, lab;
+
+	lab = -1;
+	switch (o = p->n_op) { 
+	case EQ:
+	case NE:
+		/*
+		 * Remove redundant EQ/NE nodes.
+		 */
+		while (((o = p->n_left->n_op) == EQ || o == NE) && 
+		    p->n_right->n_op == ICON) {
+			o = p->n_op;
+			q = p->n_left;
+			if (p->n_right->n_lval == 0) {
+				nfree(p->n_right);
+				*p = *q;
+				nfree(q);
+				if (o == EQ)
+					p->n_op = negrel[p->n_op - EQ];
+#if 0
+					p->n_op = NE; /* toggla */
+#endif
+			} else if (p->n_right->n_lval == 1) {
+				nfree(p->n_right);
+				*p = *q;
+				nfree(q);
+				if (o == NE)
+					p->n_op = negrel[p->n_op - EQ];
+#if 0
+					p->n_op = EQ; /* toggla */
+#endif
+			} else
+				break; /* XXX - should always be false */
+			
+		}
+		/* FALLTHROUGH */
+	case LE:
+	case LT:
+	case GE:
+	case GT:
+calc:		if (true < 0) {
+			p->n_op = negrel[p->n_op - EQ];
+			true = false;
+			false = -1;
+		}
+
+		rmcops(p->n_left);
+		rmcops(p->n_right);
+		fixbranch(p, true);
+		if (false >= 0)
+			branch(false);
+		break;
+
+	case ULE:
+	case UGT:
+		/* Convert to friendlier ops */
+		if (p->n_right->n_op == ICON && p->n_right->n_lval == 0)
+			p->n_op = o == ULE ? EQ : NE;
+		goto calc;
+
+	case UGE:
+	case ULT:
+		/* Already true/false by definition */
+		if (p->n_right->n_op == ICON && p->n_right->n_lval == 0) {
+			if (true < 0) {
+				o = o == ULT ? UGE : ULT;
+				true = false;
+			}
+			rmcops(p->n_left);
+			ecode(p->n_left);
+			rmcops(p->n_right);
+			ecode(p->n_right);
+			nfree(p);
+			if (o == UGE) /* true */
+				branch(true);
+			break;
+		}
+		goto calc;
+
+	case ANDAND:
+		lab = false<0 ? getlab() : false ;
+		andorbr(p->n_left, -1, lab);
+		comops(p->n_right);
+		andorbr(p->n_right, true, false);
+		if (false < 0)
+			plabel( lab);
+		nfree(p);
+		break;
+
+	case OROR:
+		lab = true<0 ? getlab() : true;
+		andorbr(p->n_left, lab, -1);
+		comops(p->n_right);
+		andorbr(p->n_right, true, false);
+		if (true < 0)
+			plabel( lab);
+		nfree(p);
+		break;
+
+	case NOT:
+		andorbr(p->n_left, false, true);
+		nfree(p);
+		break;
+
+	default:
+		rmcops(p);
+		if (true >= 0)
+			fixbranch(p, true);
+		if (false >= 0) {
+			if (true >= 0)
+				branch(false);
+			else
+				fixbranch(buildtree(EQ, p, bcon(0)), false);
+		}
+	}
+}
+
+/*
+ * Create a node for either TEMP or on-stack storage.
+ */
+static NODE *
+cstknode(TWORD t, union dimfun *df, struct attr *ap)
+{
+	struct symtab *sp;
+
+	/* create a symtab entry suitable for this type */
+	sp = getsymtab("0hej", STEMP);
+	sp->stype = t;
+	sp->sdf = df;
+	sp->sap = ap;
+	sp->sclass = AUTO;
+	sp->soffset = NOOFFSET;
+	oalloc(sp, &autooff);
+	return nametree(sp);
+
+}
+
+/*
+ * Massage the output trees to remove C-specific nodes:
+ *	COMOPs are split into separate statements.
+ *	QUEST/COLON are rewritten to branches.
+ *	ANDAND/OROR/NOT are rewritten to branches for lazy-evaluation.
+ *	CBRANCH conditions are rewritten for lazy-evaluation.
+ */
+static void
+rmcops(NODE *p)
+{
+	TWORD type;
+	NODE *q, *r, *tval;
+	int o, ty, lbl, lbl2;
+
+	tval = NIL;
+	o = p->n_op;
+	ty = coptype(o);
+	if (BTYPE(p->n_type) == ENUMTY) { /* fixup enum */
+		struct symtab *sp = strmemb(p->n_ap);
+		MODTYPE(p->n_type, sp->stype);
+		/*
+		 * XXX may fail if these are true:
+		 * - variable-sized enums
+		 * - non-byte-addressed targets.
+		 */
+		if (BTYPE(p->n_type) == ENUMTY && ISPTR(p->n_type))
+			MODTYPE(p->n_type, INT); /* INT ok? */
+	}
+	switch (o) {
+	case QUEST:
+
+		/*
+		 * Create a branch node from ?:
+		 * || and && must be taken special care of.
+		 */
+		type = p->n_type;
+		andorbr(p->n_left, -1, lbl = getlab());
+
+		/* Make ASSIGN node */
+		/* Only if type is not void */
+		q = p->n_right->n_left;
+		comops(q);
+		if (type != VOID) {
+			tval = cstknode(q->n_type, q->n_df, q->n_ap);
+			q = buildtree(ASSIGN, ccopy(tval), q);
+		}
+		rmcops(q);
+		ecode(q); /* Done with assign */
+		branch(lbl2 = getlab());
+		plabel( lbl);
+
+		q = p->n_right->n_right;
+		comops(q);
+		if (type != VOID) {
+			q = buildtree(ASSIGN, ccopy(tval), q);
+		}
+		rmcops(q);
+		ecode(q); /* Done with assign */
+
+		plabel( lbl2);
+
+		nfree(p->n_right);
+		if (p->n_type != VOID) {
+			*p = *tval;
+			nfree(tval);
+		} else {
+			p->n_op = ICON;
+			p->n_lval = 0;
+			p->n_sp = NULL;
+		}
+		break;
+
+	case ULE:
+	case ULT:
+	case UGE:
+	case UGT:
+	case EQ:
+	case NE:
+	case LE:
+	case LT:
+	case GE:
+	case GT:
+	case ANDAND:
+	case OROR:
+	case NOT:
+#ifdef SPECIAL_CCODES
+#error fix for private CCODES handling
+#else
+		r = talloc();
+		*r = *p;
+		andorbr(r, -1, lbl = getlab());
+
+		tval = cstknode(p->n_type, p->n_df, p->n_ap);
+
+		ecode(buildtree(ASSIGN, ccopy(tval), bcon(1)));
+		branch(lbl2 = getlab());
+		plabel( lbl);
+		ecode(buildtree(ASSIGN, ccopy(tval), bcon(0)));
+		plabel( lbl2);
+
+		*p = *tval;
+		nfree(tval);
+
+#endif
+		break;
+	case CBRANCH:
+		andorbr(p->n_left, p->n_right->n_lval, -1);
+		nfree(p->n_right);
+		p->n_op = ICON; p->n_type = VOID;
+		break;
+	case COMOP:
+		cerror("COMOP error");
+
+	default:
+		if (ty == LTYPE)
+			return;
+		rmcops(p->n_left);
+		if (ty == BITYPE)
+			rmcops(p->n_right);
+       }
+}
+
+/*
+ * Return 1 if an assignment is found.
+ */
+static int
+has_se(NODE *p)
+{
+	if (cdope(p->n_op) & ASGFLG)
+		return 1;
+	if (coptype(p->n_op) == LTYPE)
+		return 0;
+	if (has_se(p->n_left))
+		return 1;
+	if (coptype(p->n_op) == BITYPE)
+		return has_se(p->n_right);
+	return 0;
+}
+
+/*
+ * Find and convert asgop's to separate statements.
+ * Be careful about side effects.
+ * assign tells whether ASSIGN should be considered giving
+ * side effects or not.
+ */
+static NODE *
+delasgop(NODE *p)
+{
+	NODE *q, *r;
+	int tval;
+
+	if (p->n_op == INCR || p->n_op == DECR) {
+		/*
+		 * Rewrite x++ to (x += 1) -1; and deal with it further down.
+		 * Pass2 will remove -1 if unnecessary.
+		 */
+		q = ccopy(p);
+		tfree(p->n_left);
+		q->n_op = (p->n_op==INCR)?PLUSEQ:MINUSEQ;
+		p->n_op = (p->n_op==INCR)?MINUS:PLUS;
+		p->n_left = delasgop(q);
+
+	} else if ((cdope(p->n_op)&ASGOPFLG) &&
+	    p->n_op != RETURN && p->n_op != CAST) {
+		NODE *l = p->n_left;
+		NODE *ll = l->n_left;
+
+		if (has_se(l)) {
+			q = tempnode(0, ll->n_type, ll->n_df, ll->n_ap);
+			tval = regno(q);
+			r = tempnode(tval, ll->n_type, ll->n_df,ll->n_ap);
+			l->n_left = q;
+			/* Now the left side of node p has no side effects. */
+			/* side effects on the right side must be obeyed */
+			p = delasgop(p);
+			
+			r = buildtree(ASSIGN, r, ll);
+			r = delasgop(r);
+			ecode(r);
+		} else {
+#if 0 /* Cannot call buildtree() here, it would invoke double add shifts */
+			p->n_right = buildtree(UNASG p->n_op, ccopy(l),
+			    p->n_right);
+#else
+			p->n_right = block(UNASG p->n_op, ccopy(l),
+			    p->n_right, p->n_type, p->n_df, p->n_ap);
+#endif
+			p->n_op = ASSIGN;
+			p->n_right = delasgop(p->n_right);
+			p->n_right = clocal(p->n_right);
+		}
+		
+	} else {
+		if (coptype(p->n_op) == LTYPE)
+			return p;
+		p->n_left = delasgop(p->n_left);
+		if (coptype(p->n_op) == BITYPE)
+			p->n_right = delasgop(p->n_right);
+	}
+	return p;
+}
+
+int edebug = 0;
+void
+ecomp(NODE *p)
+{
+
+#ifdef PCC_DEBUG
+	if (edebug)
+		fwalk(p, eprint, 0);
+#endif
+	if (!reached) {
+		warner(Wunreachable_code, NULL);
+		reached = 1;
+	}
+	p = optim(p);
+	comops(p);
+	rmcops(p);
+	p = delasgop(p);
+	if (p->n_op == ICON && p->n_type == VOID)
+		tfree(p);
+	else
+		ecode(p);
+}
+
+
+#if defined(MULTIPASS)
+void	
+p2tree(NODE *p)
+{
+	struct symtab *q;
+	int ty;
+
+	myp2tree(p);  /* local action can be taken here */
+
+	ty = coptype(p->n_op);
+
+	printf("%d\t", p->n_op);
+
+	if (ty == LTYPE) {
+		printf(CONFMT, p->n_lval);
+		printf("\t");
+	}
+	if (ty != BITYPE) {
+		if (p->n_op == NAME || p->n_op == ICON)
+			printf("0\t");
+		else
+			printf("%d\t", p->n_rval);
+		}
+
+	printf("%o\t", p->n_type);
+
+	/* handle special cases */
+
+	switch (p->n_op) {
+
+	case NAME:
+	case ICON:
+		/* print external name */
+		if ((q = p->n_sp) != NULL) {
+			if ((q->sclass == STATIC && q->slevel > 0)) {
+				printf(LABFMT, q->soffset);
+			} else
+				printf("%s\n",
+				    q->soname ? q->soname : exname(q->sname));
+		} else
+			printf("\n");
+		break;
+
+	case STARG:
+	case STASG:
+	case STCALL:
+	case USTCALL:
+		/* print out size */
+		/* use lhs size, in order to avoid hassles
+		 * with the structure `.' operator
+		 */
+
+		/* note: p->left not a field... */
+		printf(CONFMT, (CONSZ)tsize(STRTY, p->n_left->n_df,
+		    p->n_left->n_ap));
+		printf("\t%d\t\n", talign(STRTY, p->n_left->n_ap));
+		break;
+
+	case XARG:
+	case XASM:
+		break;
+
+	default:
+		printf(	 "\n" );
+	}
+
+	if (ty != LTYPE)
+		p2tree(p->n_left);
+	if (ty == BITYPE)
+		p2tree(p->n_right);
+}
+#else
+static char *
+sptostr(struct symtab *sp)
+{
+	char *cp = inlalloc(32);
+	int n = sp->soffset;
+	if (n < 0)
+		n = -n;
+	snprintf(cp, 32, LABFMT, n);
+	return cp;
+}
+
+void
+p2tree(NODE *p)
+{
+	struct symtab *q;
+	int ty;
+
+	myp2tree(p);  /* local action can be taken here */
+
+	/* Fix left imaginary types */
+	if (ISITY(BTYPE(p->n_type)))
+		MODTYPE(p->n_type, p->n_type - (FIMAG-FLOAT));
+
+	ty = coptype(p->n_op);
+
+	switch( p->n_op ){
+
+	case NAME:
+	case ICON:
+		if ((q = p->n_sp) != NULL) {
+			if ((q->sclass == STATIC && q->slevel > 0)
+#ifdef GCC_COMPAT
+			    || q->sflags == SLBLNAME
+#endif
+			    ) {
+				p->n_name = sptostr(q);
+			} else {
+				if ((p->n_name = q->soname) == NULL)
+					p->n_name = addname(exname(q->sname));
+			}
+		} else
+			p->n_name = "";
+		break;
+
+	case STASG:
+		/* STASG used for stack array init */
+		if (ISARY(p->n_type)) {
+			int size1 = (int)tsize(p->n_type, p->n_left->n_df,
+			    p->n_left->n_ap)/SZCHAR;
+			p->n_stsize = (int)tsize(p->n_type, p->n_right->n_df,
+			    p->n_right->n_ap)/SZCHAR;
+			if (size1 < p->n_stsize)
+				p->n_stsize = size1;
+			p->n_stalign = talign(p->n_type,
+			    p->n_left->n_ap)/SZCHAR;
+			break;
+		}
+		/* FALLTHROUGH */
+	case STARG:
+	case STCALL:
+	case USTCALL:
+		/* set up size parameters */
+		p->n_stsize = (int)((tsize(STRTY, p->n_left->n_df,
+		    p->n_left->n_ap)+SZCHAR-1)/SZCHAR);
+		p->n_stalign = talign(STRTY,p->n_left->n_ap)/SZCHAR;
+		if (p->n_stalign == 0)
+			p->n_stalign = 1; /* At least char for packed structs */
+		break;
+
+	case XARG:
+	case XASM:
+		break;
+
+	default:
+		p->n_name = "";
+		}
+
+	if( ty != LTYPE ) p2tree( p->n_left );
+	if( ty == BITYPE ) p2tree( p->n_right );
+	}
+
+#endif
+
+/*
+ * Change void data types into char.
+ */
+static void
+delvoid(NODE *p, void *arg)
+{
+	/* Convert "PTR undef" (void *) to "PTR uchar" */
+	if (BTYPE(p->n_type) == VOID)
+		p->n_type = (p->n_type & ~BTMASK) | UCHAR;
+	if (BTYPE(p->n_type) == BOOL) {
+		if (p->n_op == SCONV && p->n_type == BOOL) {
+			/* create a jump and a set */
+			NODE *r;
+			int l, l2;
+
+			r = tempnode(0, BOOL_TYPE, NULL, MKAP(BOOL_TYPE));
+			cbranch(buildtree(EQ, p->n_left, bcon(0)),
+			    bcon(l = getlab()));
+			*p = *r;
+			ecode(buildtree(ASSIGN, tcopy(r), bcon(1)));
+			branch(l2 = getlab());
+			plabel(l);
+			ecode(buildtree(ASSIGN, r, bcon(0)));
+			plabel(l2);
+		} else
+			p->n_type = (p->n_type & ~BTMASK) | BOOL_TYPE;
+	}
+		
+}
+
+void
+ecode(NODE *p)	
+{
+	/* walk the tree and write out the nodes.. */
+
+	if (nerrors)	
+		return;
+
+#ifdef GCC_COMPAT
+	{
+		NODE *q = p;
+
+		if (q->n_op == UMUL)
+			q = p->n_left;
+		if (cdope(q->n_op)&CALLFLG &&
+		    attr_find(q->n_ap, GCC_ATYP_WARN_UNUSED_RESULT))
+			werror("return value ignored");
+	}
+#endif
+	p = optim(p);
+	p = delasgop(p);
+	walkf(p, delvoid, 0);
+#ifdef PCC_DEBUG
+	if (xdebug) {
+		printf("Fulltree:\n"); 
+		fwalk(p, eprint, 0); 
+	}
+#endif
+	p2tree(p);
+#if !defined(MULTIPASS)
+	send_passt(IP_NODE, p);
+#endif
+}
+
+/*
+ * Send something further on to the next pass.
+ */
+void
+send_passt(int type, ...)
+{
+	struct interpass *ip;
+	struct interpass_prolog *ipp;
+	extern int crslab;
+	va_list ap;
+	int sz;
+
+	va_start(ap, type);
+	if (cftnsp == NULL && type != IP_ASM) {
+#ifdef notyet
+		cerror("no function");
+#endif
+		if (type == IP_NODE)
+			tfree(va_arg(ap, NODE *));
+		return;
+	}
+	if (type == IP_PROLOG || type == IP_EPILOG)
+		sz = sizeof(struct interpass_prolog);
+	else
+		sz = sizeof(struct interpass);
+
+	ip = inlalloc(sz);
+	ip->type = type;
+	ip->lineno = lineno;
+	switch (type) {
+	case IP_NODE:
+		ip->ip_node = va_arg(ap, NODE *);
+		break;
+	case IP_EPILOG:
+		if (!isinlining)
+			defloc(cftnsp);
+		/* FALLTHROUGH */
+	case IP_PROLOG:
+		inftn = type == IP_PROLOG ? 1 : 0;
+		ipp = (struct interpass_prolog *)ip;
+		memset(ipp->ipp_regs, (type == IP_PROLOG)? -1 : 0,
+		    sizeof(ipp->ipp_regs));
+		ipp->ipp_autos = va_arg(ap, int);
+		ipp->ipp_name = va_arg(ap, char *);
+		ipp->ipp_type = va_arg(ap, TWORD);
+		ipp->ipp_vis = va_arg(ap, int);
+		ip->ip_lbl = va_arg(ap, int);
+		ipp->ip_tmpnum = va_arg(ap, int);
+		ipp->ip_lblnum = crslab;
+		if (type == IP_PROLOG)
+			ipp->ip_lblnum--;
+		break;
+	case IP_DEFLAB:
+		ip->ip_lbl = va_arg(ap, int);
+		break;
+	case IP_ASM:
+		if (blevel == 0) { /* outside function */
+			printf("\t");
+			printf("%s", va_arg(ap, char *));
+			printf("\n");
+			va_end(ap);
+			defloc(NULL);
+			return;
+		}
+		ip->ip_asm = va_arg(ap, char *);
+		break;
+	default:
+		cerror("bad send_passt type %d", type);
+	}
+	va_end(ap);
+	pass1_lastchance(ip); /* target-specific info */
+	if (isinlining)
+		inline_addarg(ip);
+	else
+		pass2_compile(ip);
+}
+
+char *
+copst(int op)
+{
+	if (op <= MAXOP)
+		return opst[op];
+#define	SNAM(x,y) case x: return #y;
+	switch (op) {
+	SNAM(QUALIFIER,QUALIFIER)
+	SNAM(CLASS,CLASS)
+	SNAM(RB,])
+	SNAM(DOT,.)
+	SNAM(ELLIPSIS,...)
+	SNAM(LB,[)
+	SNAM(TYPE,TYPE)
+	SNAM(COMOP,COMOP)
+	SNAM(QUEST,?)
+	SNAM(COLON,:)
+	SNAM(ANDAND,&&)
+	SNAM(OROR,||)
+	SNAM(NOT,!)
+	SNAM(CAST,CAST)
+	SNAM(PLUSEQ,+=)
+	SNAM(MINUSEQ,-=)
+	SNAM(MULEQ,*=)
+	SNAM(DIVEQ,/=)
+	SNAM(MODEQ,%=)
+	SNAM(ANDEQ,&=)
+	SNAM(OREQ,|=)
+	SNAM(EREQ,^=)
+	SNAM(LSEQ,<<=)
+	SNAM(RSEQ,>>=)
+	SNAM(INCR,++)
+	SNAM(DECR,--)
+	SNAM(STRING,STRING)
+	SNAM(SZOF,SIZEOF)
+	SNAM(ATTRIB,ATTRIBUTE)
+	SNAM(TYMERGE,TYMERGE)
+#ifdef GCC_COMPAT
+	SNAM(XREAL,__real__)
+	SNAM(XIMAG,__imag__)
+#endif
+	default:
+		cerror("bad copst %d", op);
+	}
+	return 0; /* XXX gcc */
+}
+
+int
+cdope(int op)
+{
+	if (op <= MAXOP)
+		return dope[op];
+	switch (op) {
+	case CLOP:
+	case STRING:
+	case QUALIFIER:
+	case CLASS:
+	case RB:
+	case ELLIPSIS:
+	case TYPE:
+		return LTYPE;
+	case DOT:
+	case SZOF:
+	case COMOP:
+	case QUEST:
+	case COLON:
+	case LB:
+	case TYMERGE:
+		return BITYPE;
+	case XIMAG:
+	case XREAL:
+	case ATTRIB:
+		return UTYPE;
+	case ANDAND:
+	case OROR:
+		return BITYPE|LOGFLG;
+	case NOT:
+		return UTYPE|LOGFLG;
+	case CAST:
+		return BITYPE|ASGFLG|ASGOPFLG;
+	case PLUSEQ:
+		return BITYPE|ASGFLG|ASGOPFLG|FLOFLG|SIMPFLG|COMMFLG;
+	case MINUSEQ:
+		return BITYPE|FLOFLG|SIMPFLG|ASGFLG|ASGOPFLG;
+	case MULEQ:
+		return BITYPE|FLOFLG|MULFLG|ASGFLG|ASGOPFLG;
+	case OREQ:
+	case EREQ:
+	case ANDEQ:
+		return BITYPE|SIMPFLG|COMMFLG|ASGFLG|ASGOPFLG;
+	case DIVEQ:
+		return BITYPE|FLOFLG|MULFLG|DIVFLG|ASGFLG|ASGOPFLG;
+	case MODEQ:
+		return BITYPE|DIVFLG|ASGFLG|ASGOPFLG;
+	case LSEQ:
+	case RSEQ:
+		return BITYPE|SHFFLG|ASGFLG|ASGOPFLG;
+	case INCR:
+	case DECR:
+		return BITYPE|ASGFLG;
+	}
+	cerror("cdope missing op %d", op);
+	return 0; /* XXX gcc */
+}
+
+/* 
+ * make a fresh copy of p
+ */
+NODE *
+ccopy(NODE *p) 
+{  
+	NODE *q;
+
+	q = talloc();
+	*q = *p;
+
+	switch (coptype(q->n_op)) {
+	case BITYPE:
+		q->n_right = ccopy(p->n_right);
+	case UTYPE: 
+		q->n_left = ccopy(p->n_left);
+	}
+
+	return(q);
+}
+
+/*
+ * set PROG-seg label.
+ */
+void
+plabel(int label)
+{
+	reached = 1; /* Will this always be correct? */
+	send_passt(IP_DEFLAB, label);
+}
+
+/*
+ * Perform integer promotion on node n.
+ */
+NODE *
+intprom(NODE *n)
+{
+	if ((n->n_type >= CHAR && n->n_type < INT) || n->n_type == BOOL) {
+		if ((n->n_type == UCHAR && MAX_UCHAR > MAX_INT) ||
+		    (n->n_type == USHORT && MAX_USHORT > MAX_INT))
+			return makety(n, UNSIGNED, 0, 0, MKAP(UNSIGNED));
+		return makety(n, INT, 0, 0, MKAP(INT));
+	}
+	return n;
+}
+
+/*
+ * Return CON/VOL/0, whichever are active for the current type.
+ */
+int
+cqual(TWORD t, TWORD q)
+{
+	while (ISARY(t))
+		t = DECREF(t), q = DECQAL(q);
+	if (t <= BTMASK)
+		q <<= TSHIFT;
+	return q & (CON|VOL);
+}
+
+int crslab = 10;
+/*
+ * Return a number for internal labels.
+ */
+int
+getlab(void)
+{
+	return crslab++;
+}
Index: uspace/app/pcc/cc/cpp/Makefile
===================================================================
--- uspace/app/pcc/cc/cpp/Makefile	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/Makefile	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,56 @@
+#
+# Copyright (c) 2011 Jiri Zarevucky
+# 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 must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - 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.
+#
+
+USPACE_PREFIX = ../../../..
+MIPDIR = ../../mip
+ARCHDIR = ../../arch/$(PLATFORM)
+EXTRA_CFLAGS = -I$(MIPDIR) -I$(ARCHDIR) -w
+DEFS = -DCPP_DEBUG -Dfree=free -DCPPBUF=16384
+BINARY = cpp
+
+PRE_DEPEND = compat.c
+EXTRA_CLEAN = compat.c y.tab.c y.tab.h
+
+POSIX_COMPAT = y
+
+YACC = yacc
+
+SOURCES = \
+	y.tab.c \
+	cpp.c \
+	token.c \
+	compat.c
+
+include $(USPACE_PREFIX)/Makefile.common
+
+y.tab.c:
+	$(YACC) -d cpy.y
+
+compat.c: $(MIPDIR)/compat.c
+	ln -s -f $^ $@
+
Index: uspace/app/pcc/cc/cpp/Makefile.in
===================================================================
--- uspace/app/pcc/cc/cpp/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,105 @@
+#	$Id: Makefile.in,v 1.30 2011/01/16 11:59:37 ragge Exp $
+#
+# Makefile.in for cpp
+#
+VPATH=@srcdir@
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+builddir=@builddir@
+top_builddir=@top_builddir@
+XFL=-DCPP_DEBUG
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
+mandir = @mandir@
+strip = @strip@
+CC = @CC@
+EXEEXT = @EXEEXT@
+CFLAGS = @CFLAGS@ @ADD_CFLAGS@
+CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ ${XFL} -I${srcdir} -I${top_builddir} -I${builddir} -I${MIPDIR} -I${MDIR}
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+YACC = @YACC@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+TARGMACH = @targmach@
+
+OBJS=cpp.o cpy.o token.o compat.o
+HEADERS=cpp.h
+DEST=@BINPREFIX@cpp$(EXEEXT)
+
+MIPDIR=$(top_srcdir)/mip
+MDIR=$(top_srcdir)/arch/$(TARGMACH)
+
+all: ${DEST}
+
+${DEST}: $(OBJS) $(HEADERS)
+	$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@
+
+.c.o:
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $<
+
+.l.o:
+	$(LEX) $(LFLAGS) $<
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ lex.yy.c
+
+.y.o:
+	$(YACC) -d $(YFLAGS) $<
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ y.tab.c
+
+compat.o: $(MIPDIR)/compat.c
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/compat.c
+
+$(OBJS): $(HEADERS)
+
+cpp.o: cpy.o
+token.o: cpy.o
+
+test:
+	./cpp < tests/test1 > tests/run1
+	cmp tests/run1 tests/res1
+	./cpp < tests/test2 > tests/run2
+	cmp tests/run2 tests/res2
+	./cpp < tests/test3 > tests/run3
+	cmp tests/run3 tests/res3
+	./cpp < tests/test4 > tests/run4
+	cmp tests/run4 tests/res4
+	./cpp < tests/test5 > tests/run5
+	cmp tests/run5 tests/res5
+	./cpp < tests/test6 > tests/run6
+	cmp tests/run6 tests/res6
+	./cpp < tests/test7 > tests/run7
+	cmp tests/run7 tests/res7
+	./cpp < tests/test8 > tests/run8
+	cmp tests/run8 tests/res8
+	./cpp < tests/test9 > tests/run9
+	cmp tests/run9 tests/res9
+	./cpp < tests/test10 > tests/run10
+	cmp tests/run10 tests/res10
+	./cpp < tests/test11 > tests/run11
+	cmp tests/run11 tests/res11
+	./cpp < tests/test12 > tests/run12
+	cmp tests/run12 tests/res12
+	./cpp < tests/test13 > tests/run13
+	cmp tests/run13 tests/res13
+
+
+install:
+	test -z "${DESTDIR}$(libexecdir)" || mkdir -p "${DESTDIR}$(libexecdir)"
+	${INSTALL_PROGRAM} ${DEST} ${DESTDIR}${libexecdir}
+	@if [ ${strip} = yes ]; then		\
+		strip ${DESTDIR}${libexecdir}/${DEST} ;	\
+		echo strip ${DESTDIR}${libexecdir}/${DEST} ;	\
+	fi
+	test -z "${DESTDIR}$(mandir)/man1" || mkdir -p "${DESTDIR}$(mandir)/man1"       
+	${INSTALL} $(srcdir)/cpp.1 ${DESTDIR}${mandir}/man1/$(DEST).1
+
+clean:
+	/bin/rm -f $(OBJS) $(DEST) lex.yy.c y.tab.[ch] tests/run*
+
+distclean: clean
+	/bin/rm -f Makefile
Index: uspace/app/pcc/cc/cpp/config.h
===================================================================
--- uspace/app/pcc/cc/cpp/config.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/config.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1 @@
+/home/jirkazr/HelenOS_pcc/uspace/app/pcc/config.h
Index: uspace/app/pcc/cc/cpp/cpp.1
===================================================================
--- uspace/app/pcc/cc/cpp/cpp.1	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/cpp.1	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,210 @@
+.\"	$Id: cpp.1,v 1.11 2010/04/05 13:13:57 reed Exp $
+.\"	$NetBSD$
+.\"	$OpenBSD$
+.\"
+.\" Copyright (c) 2007 Jeremy C. Reed <reed@reedmedia.net>
+.\"
+.\" Permission to use, copy, modify, and/or distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM
+.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND
+.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+.\" THIS SOFTWARE.
+.\"
+.Dd September 17, 2007
+.Dt CPP 1
+.Os
+.Sh NAME
+.Nm cpp
+.Nd C preprocessor
+.Sh SYNOPSIS
+.Nm
+.\" TODO also document -Dvar and below without spaces?
+.Op Fl CdMtVv
+.Op Fl D Ar macro[=value]
+.Op Fl I Ar path
+.Op Fl i Ar file
+.Op Fl S Ar path
+.Op Fl U Ar macro
+.Op Ar infile | -
+.Op Ar outfile
+.Sh DESCRIPTION
+The
+.Nm
+utility is a macro preprocessor used by the
+.Xr pcc 1
+compiler.
+It is used to include header files,
+expand macro definitions,
+and perform conditional compilation.
+.Pp
+The
+.Ar infile
+input file is optional.
+If not provided or the file name is
+.Qq -
+(dash),
+.Nm
+reads its initial file from standard input.
+The
+.Ar outfile
+output file is also optional.
+It writes by default to standard output.
+.Pp
+.\" TODO: document MAXARG  250 args to a macro, limited by char value
+.\" TODO: Include order:
+.\" For "..." files, first search "current" dir, then as <...> files.
+.\" For <...> files, first search -I directories, then system directories.
+.\"
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl ?
+Show command line usage for
+.Nm .
+.It Fl C
+Do not discard comments.
+.It Fl D Ar macro[=value]
+Fake a definition at the beginning by using
+.Do #define
+.Ar macro=value Dc .
+If
+.Ar value
+is not set on command-line, then define it as 1.
+.\" TODO: show example
+.It Fl dM
+Print list of
+.Dq #define
+statements to standard output for all defined macros other than
+builtin macros (see below).
+The normal results of preprocessing are not output.
+.\" TODO this doesn't show predefined macros
+.\" other -d options are ignored
+.It Fl I Ar path
+Add
+.Ar path
+to the list of directories containing needed header files.
+This may be used to override system include directories
+(see
+.Fl S
+option).
+.Fl I
+may be specified multiple times.
+.It Fl i Ar file
+Include a file at the beginning by using
+.Do #include
+.Ar file Dc .
+.\" Note: I did not use the .In macro above
+.It Fl M
+Generate dependencies for
+.Xr make 1 .
+.\" TODO: explain and show example?
+.It Fl P
+Inhibit generation of line markers.  This is sometimes useful when
+running the preprocessor on something other than C code.
+.It Fl S Ar path
+Add
+.Ar path
+to the list of system directories containing needed header files.
+The
+.Fl S
+option may be specified multiple times.
+Note:
+.Nm
+does not have a default include directory defined.
+.\" TODO: explain difference between -I and -S
+.\" The directories listed by -I are searched first?
+.It Fl t
+Traditional cpp syntax.
+Do not define the
+.Dv __TIME__ ,
+.Dv __DATE__ ,
+.Dv __STDC__ ,
+and
+.Dv __STDC_VERSION__
+macros.
+.\"
+.It Fl U Ar macro
+Undefine a macro at the beginning by using
+.Do #undef
+.Ar macro Dc .
+.It Fl V
+Verbose debugging output.
+.Fl V
+can be repeated for further details.
+.\" -V only available if cpp source built with CPP_DEBUG, which is the default.
+.It Fl v
+Display version.
+.El
+.Ss Builtin Macros
+A few macros are interpreted inside the
+.Nm cpp
+program:
+.Bl -diag
+.It __DATE__
+Expands to the date in abbreviated month, day, and year format from
+.Xr ctime 3
+in quotes.
+.\" TODO: is that ctime(3) format output change according to locale?
+.It __FILE__
+Expands to the name of the current input file in quotes.
+When read from standard input, it expands to
+.Qq Aq stdin .
+.It __LINE__
+Expands to the line number of the current line containing the macro.
+.It __STDC__
+Expands to the constant 1.
+This means the compiler conforms to
+.St -isoC
+.Po also known as
+.Do C90 Dc Pc .
+.It __STDC_VERSION__
+Expands to
+.Dq 199901L
+which indicates that
+.Nm
+supports
+.St -isoC-99
+.Po commonly referred to as
+.Do C99 Dc Pc .
+.It __TIME__
+Expands to the time in hour, minutes, and seconds from
+.Xr ctime 3
+in quotes.
+.El
+.Pp
+Also see the
+.Fl t
+option.
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width Ds
+.It 0
+Successfully finished.
+.It 1
+An error occurred.
+.El
+.Sh SEE ALSO
+.Xr as 1 ,
+.Xr ccom 1 ,
+.Xr pcc 1
+.\"
+.Sh HISTORY
+The
+.Nm
+command comes from the original Portable C Compiler by S. C. Johnson,
+written in the late 70's.
+The code originates from the V6 preprocessor with some additions
+from V7 cpp and ansi/c99 support.
+.Pp
+A lot of the PCC code was rewritten by Anders Magnusson.
+.Pp
+This product includes software developed or owned by Caldera
+International, Inc.
Index: uspace/app/pcc/cc/cpp/cpp.c
===================================================================
--- uspace/app/pcc/cc/cpp/cpp.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/cpp.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1984 @@
+/*	$Id: cpp.c,v 1.124.2.2 2011/03/27 13:17:19 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004,2010 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The C preprocessor.
+ * This code originates from the V6 preprocessor with some additions
+ * from V7 cpp, and at last ansi/c99 support.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "compat.h"
+#include "cpp.h"
+#include "y.tab.h"
+
+#define	SBSIZE	1000000
+
+static usch	sbf[SBSIZE];
+/* C command */
+
+int tflag;	/* traditional cpp syntax */
+#ifdef CPP_DEBUG
+int dflag;	/* debug printouts */
+#define	DPRINT(x) if (dflag) printf x
+#define	DDPRINT(x) if (dflag > 1) printf x
+#else
+#define DPRINT(x)
+#define DDPRINT(x)
+#endif
+
+int ofd;
+usch outbuf[CPPBUF];
+int obufp, istty;
+int Cflag, Mflag, dMflag, Pflag;
+usch *Mfile;
+struct initar *initar;
+int readmac, lastoch;
+
+/* include dirs */
+struct incs {
+	struct incs *next;
+	usch *dir;
+	dev_t dev;
+	ino_t ino;
+} *incdir[2];
+#define	INCINC 0
+#define	SYSINC 1
+
+static struct symtab *filloc;
+static struct symtab *linloc;
+static struct symtab *pragloc;
+int	trulvl;
+int	flslvl;
+int	elflvl;
+int	elslvl;
+usch *stringbuf = sbf;
+
+/*
+ * Macro replacement list syntax:
+ * - For object-type macros, replacement strings are stored as-is.
+ * - For function-type macros, macro args are substituted for the
+ *   character WARN followed by the argument number.
+ * - The value element points to the end of the string, to simplify
+ *   pushback onto the input queue.
+ * 
+ * The first character (from the end) in the replacement list is
+ * the number of arguments:
+ *   VARG  - ends with ellipsis, next char is argcount without ellips.
+ *   OBJCT - object-type macro
+ *   0 	   - empty parenthesis, foo()
+ *   1->   - number of args.
+ *
+ * WARN is used:
+ *	- in stored replacement lists to tell that an argument comes
+ *	- When expanding replacement lists to tell that the list ended.
+ *
+ * To ensure that an already expanded identifier won't get expanded
+ * again a EBLOCK char + its number is stored directly before any 
+ * expanded identifier.
+ */
+
+/* args for lookup() */
+#define	FIND	0
+#define	ENTER	1
+
+static int readargs(struct symtab *sp, const usch **args);
+void prline(const usch *s);
+static void prrep(const usch *s);
+static void exparg(int);
+static void subarg(struct symtab *sp, const usch **args, int);
+void define(void);
+void include(void);
+void include_next(void);
+void line(void);
+void flbuf(void);
+void usage(void);
+usch *xstrdup(const usch *str);
+static void addidir(char *idir, struct incs **ww);
+void imp(const char *);
+#define IMP(x) if (dflag>1) imp(x)
+
+int
+main(int argc, char **argv)
+{
+	struct initar *it;
+	struct symtab *nl;
+	register int ch;
+	const usch *fn1, *fn2;
+
+#ifdef TIMING
+	struct timeval t1, t2;
+
+	(void)gettimeofday(&t1, NULL);
+#endif
+
+	while ((ch = getopt(argc, argv, "CD:I:MPS:U:d:i:tvV?")) != -1)
+		switch (ch) {
+		case 'C': /* Do not discard comments */
+			Cflag++;
+			break;
+
+		case 'i': /* include */
+		case 'U': /* undef */
+		case 'D': /* define something */
+			/* XXX should not need malloc() here */
+			if ((it = malloc(sizeof(struct initar))) == NULL)
+				error("couldn't apply -%c %s", ch, optarg);
+			it->type = ch;
+			it->str = optarg;
+			it->next = initar;
+			initar = it;
+			break;
+
+		case 'M': /* Generate dependencies for make */
+			Mflag++;
+			break;
+
+		case 'P': /* Inhibit generation of line numbers */
+			Pflag++;
+			break;
+
+		case 'S':
+		case 'I':
+			addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
+			break;
+
+#ifdef CPP_DEBUG
+		case 'V':
+			dflag++;
+			break;
+#endif
+		case 'v':
+			printf("cpp: %s\n", VERSSTR);
+			break;
+		case 'd':
+			if (optarg[0] == 'M') {
+				dMflag = 1;
+				Mflag = 1;
+			}
+			/* ignore others */
+			break;
+
+		case 't':
+			tflag = 1;
+			break;
+
+		case '?':
+			usage();
+		default:
+			error("bad arg %c\n", ch);
+		}
+	argc -= optind;
+	argv += optind;
+
+	filloc = lookup((const usch *)"__FILE__", ENTER);
+	linloc = lookup((const usch *)"__LINE__", ENTER);
+	filloc->value = linloc->value = stringbuf;
+	savch(OBJCT);
+
+	/* create a complete macro for pragma */
+	pragloc = lookup((const usch *)"_Pragma", ENTER);
+	savch(0);
+	savstr((const usch *)"_Pragma(");
+	savch(0);
+	savch(WARN);
+	savch(')');
+	pragloc->value = stringbuf;
+	savch(1);
+
+	if (tflag == 0) {
+		time_t t = time(NULL);
+		usch *n = (usch *)ctime(&t);
+
+		/*
+		 * Manually move in the predefined macros.
+		 */
+		nl = lookup((const usch *)"__TIME__", ENTER);
+		savch(0); savch('"');  n[19] = 0; savstr(&n[11]); savch('"');
+		savch(OBJCT);
+		nl->value = stringbuf-1;
+
+		nl = lookup((const usch *)"__DATE__", ENTER);
+		savch(0); savch('"'); n[24] = n[11] = 0; savstr(&n[4]);
+		savstr(&n[20]); savch('"'); savch(OBJCT);
+		nl->value = stringbuf-1;
+
+		nl = lookup((const usch *)"__STDC__", ENTER);
+		savch(0); savch('1'); savch(OBJCT);
+		nl->value = stringbuf-1;
+
+		nl = lookup((const usch *)"__STDC_VERSION__", ENTER);
+		savch(0); savstr((const usch *)"199901L"); savch(OBJCT);
+		nl->value = stringbuf-1;
+	}
+
+	if (Mflag && !dMflag) {
+		usch *c;
+
+		if (argc < 1)
+			error("-M and no infile");
+		if ((c = (usch *)strrchr(argv[0], '/')) == NULL)
+			c = (usch *)argv[0];
+		else
+			c++;
+		Mfile = stringbuf;
+		savstr(c); savch(0);
+		if ((c = (usch *)strrchr((char *)Mfile, '.')) == NULL)
+			error("-M and no extension: ");
+		c[1] = 'o';
+		c[2] = 0;
+	}
+
+	if (argc == 2) {
+		if ((ofd = open(argv[1], O_WRONLY|O_CREAT, 0600)) < 0)
+			error("Can't creat %s", argv[1]);
+	} else
+		ofd = fileno(stdout);
+	istty = isatty(ofd);
+
+	if (argc && strcmp(argv[0], "-")) {
+		fn1 = fn2 = (usch *)argv[0];
+	} else {
+		fn1 = NULL;
+		fn2 = (const usch *)"";
+	}
+	if (pushfile(fn1, fn2, 0, NULL))
+		error("cannot open %s", argv[0]);
+
+	flbuf();
+	close(ofd);
+#ifdef TIMING
+	(void)gettimeofday(&t2, NULL);
+	t2.tv_sec -= t1.tv_sec;
+	t2.tv_usec -= t1.tv_usec;
+	if (t2.tv_usec < 0) {
+		t2.tv_usec += 1000000;
+		t2.tv_sec -= 1;
+	}
+	fprintf(stderr, "cpp total time: %ld s %ld us\n",
+	     t2.tv_sec, t2.tv_usec);
+#endif
+	return 0;
+}
+
+static void
+addidir(char *idir, struct incs **ww)
+{
+	struct incs *w;
+	struct stat st;
+
+	if (stat(idir, &st) == -1 || S_ISDIR(st.st_mode) == 0)
+		return; /* ignore */
+	if (*ww != NULL) {
+		for (w = *ww; w->next; w = w->next) {
+			if (w->dev == st.st_dev && w->ino == st.st_ino)
+				return;
+		}
+		if (w->dev == st.st_dev && w->ino == st.st_ino)
+			return;
+		ww = &w->next;
+	}
+	if ((w = calloc(sizeof(struct incs), 1)) == NULL)
+		error("couldn't add path %s", idir);
+	w->dir = (usch *)idir;
+	w->dev = st.st_dev;
+	w->ino = st.st_ino;
+	*ww = w;
+}
+
+void
+line()
+{
+	static usch *lbuf;
+	static int llen;
+	usch *p;
+	int c;
+
+	if ((c = yylex()) != NUMBER)
+		goto bad;
+	ifiles->lineno = (int)(yylval.node.nd_val - 1);
+
+	if ((c = yylex()) == '\n')
+		return;
+
+	if (c != STRING)
+		goto bad;
+
+	p = (usch *)yytext;
+	if (*p == 'L')
+		p++;
+	c = strlen((char *)p);
+	if (llen < c) {
+		/* XXX may loose heap space */
+		lbuf = stringbuf;
+		stringbuf += c;
+		llen = c;
+	}
+	p[strlen((char *)p)-1] = 0;
+	if (strlcpy((char *)lbuf, (char *)&p[1], SBSIZE) >= SBSIZE)
+		error("line exceeded buffer size");
+
+	ifiles->fname = lbuf;
+	if (yylex() == '\n')
+		return;
+
+bad:	error("bad line directive");
+}
+
+/*
+ * Search for and include next file.
+ * Return 1 on success.
+ */
+static int
+fsrch(const usch *fn, int idx, struct incs *w)
+{
+	int i;
+
+	for (i = idx; i < 2; i++) {
+		if (i > idx)
+			w = incdir[i];
+		for (; w; w = w->next) {
+			usch *nm = stringbuf;
+
+			savstr(w->dir); savch('/');
+			savstr(fn); savch(0);
+			if (pushfile(nm, fn, i, w->next) == 0)
+				return 1;
+			stringbuf = nm;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Include a file. Include order:
+ * - For <...> files, first search -I directories, then system directories.
+ * - For "..." files, first search "current" dir, then as <...> files.
+ */
+void
+include()
+{
+	struct symtab *nl;
+	usch *osp;
+	usch *fn, *safefn;
+	int c;
+
+	if (flslvl)
+		return;
+	osp = stringbuf;
+
+	while ((c = sloscan()) == WSPACE)
+		;
+	if (c == IDENT) {
+		/* sloscan() will not expand idents */
+		if ((nl = lookup((usch *)yytext, FIND)) == NULL)
+			goto bad;
+		if (kfind(nl))
+			unpstr(stringbuf);
+		else
+			unpstr(nl->namep);
+		stringbuf = osp;
+		c = yylex();
+	}
+	if (c != STRING && c != '<')
+		goto bad;
+
+	if (c == '<') {
+		fn = stringbuf;
+		while ((c = sloscan()) != '>' && c != '\n') {
+			if (c == '\n') /* XXX check - cannot reach */
+				goto bad;
+			savstr((usch *)yytext);
+		}
+		savch('\0');
+		while ((c = sloscan()) == WSPACE)
+			;
+		if (c != '\n')
+			goto bad;
+		(void) SYSINC;
+		safefn = fn;
+	} else {
+		usch *nm = stringbuf;
+
+		yytext[strlen((char *)yytext)-1] = 0;
+		fn = (usch *)&yytext[1];
+		/* first try to open file relative to previous file */
+		/* but only if it is not an absolute path */
+		if (*fn != '/') {
+			savstr(ifiles->orgfn);
+			if ((stringbuf =
+			    (usch *)strrchr((char *)nm, '/')) == NULL)
+				stringbuf = nm;
+			else
+				stringbuf++;
+		}
+		safefn = stringbuf;
+		savstr(fn); savch(0);
+		c = yylex();
+		if (c != '\n')
+			goto bad;
+		if (pushfile(nm, safefn, 0, NULL) == 0)
+			goto okret;
+		/* XXX may loose stringbuf space */
+	}
+
+	if (fsrch(safefn, 0, incdir[0]))
+		goto okret;
+
+	error("cannot find '%s'", safefn);
+	/* error() do not return */
+
+bad:	error("bad include");
+	/* error() do not return */
+okret:
+	prtline();
+}
+
+void
+include_next()
+{
+	struct symtab *nl;
+	usch *osp;
+	usch *fn;
+	int c;
+
+	if (flslvl)
+		return;
+	osp = stringbuf;
+	while ((c = sloscan()) == WSPACE)
+		;
+	if (c == IDENT) {
+		/* sloscan() will not expand idents */
+		if ((nl = lookup((usch *)yytext, FIND)) == NULL)
+			goto bad;
+		if (kfind(nl))
+			unpstr(stringbuf);
+		else
+			unpstr(nl->namep);
+		stringbuf = osp;
+		c = yylex();
+	}
+	if (c != STRING && c != '<')
+		goto bad;
+
+	fn = stringbuf;
+	if (c == STRING) {
+		savstr((usch *)&yytext[1]);
+		stringbuf[-1] = 0;
+	} else { /* < > */
+		while ((c = sloscan()) != '>') {
+			if (c == '\n')
+				goto bad;
+			savstr((usch *)yytext);
+		}
+		savch('\0');
+	}
+	while ((c = sloscan()) == WSPACE)
+		;
+	if (c != '\n')
+		goto bad;
+
+	if (fsrch(fn, ifiles->idx, ifiles->incs) == 0)
+		error("cannot find '%s'", fn);
+	prtline();
+	return;
+
+bad:	error("bad include");
+	/* error() do not return */
+}
+
+static int
+definp(void)
+{
+	int c;
+
+	do
+		c = sloscan();
+	while (c == WSPACE);
+	return c;
+}
+
+void
+getcmnt(void)
+{
+	int c;
+
+	savstr((usch *)yytext);
+	savch(cinput()); /* Lost * */
+	for (;;) {
+		c = cinput();
+		if (c == '*') {
+			c = cinput();
+			if (c == '/') {
+				savstr((const usch *)"*/");
+				return;
+			}
+			cunput(c);
+			c = '*';
+		}
+		savch(c);
+	}
+}
+
+/*
+ * Compare two replacement lists, taking in account comments etc.
+ */
+static int
+cmprepl(const usch *o, const usch *n)
+{
+	for (; *o; o--, n--) {
+		/* comment skip */
+		if (*o == '/' && o[-1] == '*') {
+			while (*o != '*' || o[-1] != '/')
+				o--;
+			o -= 2;
+		}
+		if (*n == '/' && n[-1] == '*') {
+			while (*n != '*' || n[-1] != '/')
+				n--;
+			n -= 2;
+		}
+		while (*o == ' ' || *o == '\t')
+			o--;
+		while (*n == ' ' || *n == '\t')
+			n--;
+		if (*o != *n)
+			return 1;
+	}
+	return 0;
+}
+
+static int
+isell(void)
+{
+	int ch;
+
+	if ((ch = cinput()) != '.') {
+		cunput(ch);
+		return 0;
+	}
+	if ((ch = cinput()) != '.') {
+		cunput(ch);
+		cunput('.');
+		return 0;
+	}
+	return 1;
+}
+
+void
+define()
+{
+	struct symtab *np;
+	usch *args[MAXARGS+1], *ubuf, *sbeg;
+	int c, i, redef;
+	int mkstr = 0, narg = -1;
+	int ellips = 0;
+#ifdef GCC_COMPAT
+	usch *gccvari = NULL;
+	int wascon;
+#endif
+
+	if (flslvl)
+		return;
+	if (sloscan() != WSPACE || sloscan() != IDENT)
+		goto bad;
+
+	if (isdigit((int)yytext[0]))
+		goto bad;
+
+	np = lookup((usch *)yytext, ENTER);
+	redef = np->value != NULL;
+
+	readmac = 1;
+	sbeg = stringbuf;
+	if ((c = sloscan()) == '(') {
+		narg = 0;
+		/* function-like macros, deal with identifiers */
+		c = definp();
+		for (;;) {
+			if (c == ')')
+				break;
+			if (c == '.' && isell()) {
+				ellips = 1;
+				if (definp() != ')')
+					goto bad;
+				break;
+			}
+			if (c == IDENT) {
+				/* make sure there is no arg of same name */
+				for (i = 0; i < narg; i++)
+					if (!strcmp((char *) args[i], (char *)yytext))
+						error("Duplicate macro "
+						  "parameter \"%s\"", yytext);
+				if (narg == MAXARGS)
+					error("Too many macro args");
+				args[narg++] = xstrdup(yytext);
+				if ((c = definp()) == ',') {
+					if ((c = definp()) == ')')
+						goto bad;
+					continue;
+				}
+#ifdef GCC_COMPAT
+				if (c == '.' && isell()) {
+					if (definp() != ')')
+						goto bad;
+					gccvari = args[--narg];
+					break;
+				}
+#endif
+				if (c == ')')
+					break;
+			}
+			goto bad;
+		}
+		c = sloscan();
+	} else if (c == '\n') {
+		/* #define foo */
+		;
+	} else if (c != WSPACE)
+		goto bad;
+
+	while (c == WSPACE)
+		c = sloscan();
+
+	/* replacement list cannot start with ## operator */
+	if (c == '#') {
+		if ((c = sloscan()) == '#')
+			goto bad;
+		savch('\0');
+#ifdef GCC_COMPAT
+		wascon = 0;
+#endif
+		goto in2;
+	}
+
+	/* parse replacement-list, substituting arguments */
+	savch('\0');
+	while (c != '\n') {
+#ifdef GCC_COMPAT
+		wascon = 0;
+loop:
+#endif
+		switch (c) {
+		case WSPACE:
+			/* remove spaces if it surrounds a ## directive */
+			ubuf = stringbuf;
+			savstr((usch *)yytext);
+			c = sloscan();
+			if (c == '#') {
+				if ((c = sloscan()) != '#')
+					goto in2;
+				stringbuf = ubuf;
+				savch(CONC);
+				if ((c = sloscan()) == WSPACE)
+					c = sloscan();
+#ifdef GCC_COMPAT
+				if (c == '\n')
+					break;
+				wascon = 1;
+				goto loop;
+#endif
+			}
+			continue;
+
+		case '#':
+			c = sloscan();
+			if (c == '#') {
+				/* concat op */
+				savch(CONC);
+				if ((c = sloscan()) == WSPACE)
+					c = sloscan();
+#ifdef GCC_COMPAT
+				if (c == '\n')
+					break;
+				wascon = 1;
+				goto loop;
+#else
+				continue;
+#endif
+			} 
+in2:			if (narg < 0) {
+				/* no meaning in object-type macro */
+				savch('#');
+				continue;
+			}
+			/* remove spaces between # and arg */
+			savch(SNUFF);
+			if (c == WSPACE)
+				c = sloscan(); /* whitespace, ignore */
+			mkstr = 1;
+			if (c == IDENT && strcmp((char *)yytext, "__VA_ARGS__") == 0)
+				continue;
+
+			/* FALLTHROUGH */
+		case IDENT:
+			if (strcmp((char *)yytext, "__VA_ARGS__") == 0) {
+				if (ellips == 0)
+					error("unwanted %s", yytext);
+#ifdef GCC_COMPAT
+				savch(wascon ? GCCARG : VARG);
+#else
+				savch(VARG);
+#endif
+
+				savch(WARN);
+				if (mkstr)
+					savch(SNUFF), mkstr = 0;
+				break;
+			}
+			if (narg < 0)
+				goto id; /* just add it if object */
+			/* check if its an argument */
+			for (i = 0; i < narg; i++)
+				if (strcmp((char *)yytext, (char *)args[i]) == 0)
+					break;
+			if (i == narg) {
+#ifdef GCC_COMPAT
+				if (gccvari &&
+				    strcmp((char *)yytext, (char *)gccvari) == 0) {
+					savch(wascon ? GCCARG : VARG);
+					savch(WARN);
+					if (mkstr)
+						savch(SNUFF), mkstr = 0;
+					break;
+				}
+#endif
+				if (mkstr)
+					error("not argument");
+				goto id;
+			}
+			savch(i);
+			savch(WARN);
+			if (mkstr)
+				savch(SNUFF), mkstr = 0;
+			break;
+
+		case CMNT: /* save comments */
+			getcmnt();
+			break;
+
+		default:
+id:			savstr((usch *)yytext);
+			break;
+		}
+		c = sloscan();
+	}
+	readmac = 0;
+	/* remove trailing whitespace */
+	while (stringbuf > sbeg) {
+		if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')
+			stringbuf--;
+		/* replacement list cannot end with ## operator */
+		else if (stringbuf[-1] == CONC)
+			goto bad;
+		else
+			break;
+	}
+#ifdef GCC_COMPAT
+	if (gccvari) {
+		savch(narg);
+		savch(VARG);
+	} else
+#endif
+	if (ellips) {
+		savch(narg);
+		savch(VARG);
+	} else
+		savch(narg < 0 ? OBJCT : narg);
+	if (redef && ifiles->idx != SYSINC) {
+		if (cmprepl(np->value, stringbuf-1)) {
+			sbeg = stringbuf;
+			np->value = stringbuf-1;
+			warning("%s redefined\nprevious define: %s:%d",
+			    np->namep, np->file, np->line);
+		}
+		stringbuf = sbeg;  /* forget this space */
+	} else
+		np->value = stringbuf-1;
+
+#ifdef CPP_DEBUG
+	if (dflag) {
+		const usch *w = np->value;
+
+		printf("!define: ");
+		if (*w == OBJCT)
+			printf("[object]");
+		else if (*w == VARG)
+			printf("[VARG%d]", *--w);
+		while (*--w) {
+			switch (*w) {
+			case WARN: printf("<%d>", *--w); break;
+			case CONC: printf("<##>"); break;
+			case SNUFF: printf("<\">"); break;
+			default: putchar(*w); break;
+			}
+		}
+		putchar('\n');
+	}
+#endif
+	for (i = 0; i < narg; i++)
+		free(args[i]);
+	return;
+
+bad:	error("bad define");
+}
+
+void
+xwarning(usch *s)
+{
+	usch *t;
+	usch *sb = stringbuf;
+
+	flbuf();
+	savch(0);
+	if (ifiles != NULL) {
+		t = sheap("%s:%d: warning: ", ifiles->fname, ifiles->lineno);
+		write (2, t, strlen((char *)t));
+	}
+	write (2, s, strlen((char *)s));
+	write (2, "\n", 1);
+	stringbuf = sb;
+}
+
+void
+xerror(usch *s)
+{
+	usch *t;
+
+	flbuf();
+	savch(0);
+	if (ifiles != NULL) {
+		t = sheap("%s:%d: error: ", ifiles->fname, ifiles->lineno);
+		write (2, t, strlen((char *)t));
+	}
+	write (2, s, strlen((char *)s));
+	write (2, "\n", 1);
+	exit(1);
+}
+
+static void
+sss(void)
+{
+	savch(EBLOCK);
+	savch(cinput());
+	savch(cinput());
+}
+
+static int
+addmac(struct symtab *sp)
+{
+	int c, i;
+
+	/* Check if it exists; then save some space */
+	/* May be more difficult to debug cpp */
+	for (i = 1; i < norepptr; i++)
+		if (norep[i] == sp)
+			return i;
+	if (norepptr >= RECMAX)
+		error("too many macros");
+	/* check norepptr */
+	if ((norepptr & 255) == 0)
+		norepptr++;
+	if (((norepptr >> 8) & 255) == 0)
+		norepptr += 256;
+	c = norepptr;
+	norep[norepptr++] = sp;
+	return c;
+}
+
+static void
+doblk(void)
+{
+	int c;
+
+	do {
+		donex();
+	} while ((c = sloscan()) == EBLOCK);
+	if (c != IDENT)
+		error("EBLOCK sync error");
+}
+
+/* Block next nr in lex buffer to expand */
+int
+donex(void)
+{
+	int n, i;
+
+	if (bidx == RECMAX)
+		error("too deep macro recursion");
+	n = cinput();
+	n = MKB(n, cinput());
+	for (i = 0; i < bidx; i++)
+		if (bptr[i] == n)
+			return n; /* already blocked */
+	bptr[bidx++] = n;
+	/* XXX - check for sp buffer overflow */
+	if (dflag>1) {
+		printf("donex %d (%d) blocking:\n", bidx, n);
+		printf("donex %s(%d) blocking:", norep[n]->namep, n);
+		for (i = bidx-1; i >= 0; i--)
+			printf(" '%s'", norep[bptr[i]]->namep);
+		printf("\n");
+	}
+	return n;
+}
+
+/*
+ * store a character into the "define" buffer.
+ */
+void
+savch(int c)
+{
+	if (stringbuf-sbf < SBSIZE) {
+		*stringbuf++ = (usch)c;
+	} else {
+		stringbuf = sbf; /* need space to write error message */
+		error("Too much defining");
+	} 
+}
+
+/*
+ * convert _Pragma to #pragma for output.
+ * Syntax is already correct.
+ */
+static void
+pragoper(void)
+{
+	usch *s;
+	int t;
+
+	while ((t = sloscan()) != '(')
+		;
+
+	while ((t = sloscan()) == WSPACE)
+		;
+	if (t != STRING)
+		error("pragma must have string argument");
+	savstr((const usch *)"\n#pragma ");
+	s = (usch *)yytext;
+	if (*s == 'L')
+		s++;
+	for (; *s; s++) {
+		if (*s == '\"')
+			continue;
+		if (*s == '\\' && (s[1] == '\"' || s[1] == '\\'))
+			s++;
+		savch(*s);
+	}
+	sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname);
+	while ((t = sloscan()) == WSPACE)
+		;
+	if (t != ')')
+		error("pragma syntax error");
+}
+
+/*
+ * Return true if it is OK to expand this symbol.
+ */
+static int
+okexp(struct symtab *sp)
+{
+	int i;
+
+	if (sp == NULL)
+		return 0;
+	for (i = 0; i < bidx; i++)
+		if (norep[bptr[i]] == sp)
+			return 0;
+	return 1;
+}
+
+/*
+ * Insert block(s) before each expanded name.
+ * Input is in lex buffer, output on lex buffer.
+ */
+static void
+insblock(int bnr)
+{ 
+	usch *bp = stringbuf;
+	int c, i;
+  
+	IMP("IB");
+	while ((c = sloscan()) != WARN) {
+		if (c == EBLOCK) {
+			sss();
+			continue;
+		}
+		if (c == IDENT) {
+			savch(EBLOCK), savch(bnr & 255), savch(bnr >> 8);
+			for (i = 0; i < bidx; i++)
+				savch(EBLOCK), savch(bptr[i] & 255),
+				    savch(bptr[i] >> 8);
+		}
+		savstr((const usch *)yytext);
+		if (c == '\n')
+			(void)cinput();
+	}
+	savch(0);
+	cunput(WARN);
+	unpstr(bp);
+	stringbuf = bp;
+	IMP("IBRET");
+} 
+
+/* Delete next WARN on the input stream */
+static void
+delwarn(void)
+{ 
+	usch *bp = stringbuf;
+	int c;
+  
+	IMP("DELWARN");
+	while ((c = sloscan()) != WARN) {
+		if (c == EBLOCK) {
+			sss();
+		} else
+			savstr(yytext);
+	}
+	savch(0);
+	unpstr(bp);
+	stringbuf = bp;
+	IMP("DELWRET");
+} 
+
+/*
+ * Handle defined macro keywords found on input stream.
+ * When finished print out the full expanded line.
+ * Everything on lex buffer except for the symtab.
+ */
+int
+kfind(struct symtab *sp)
+{
+	struct symtab *nl;
+	const usch *argary[MAXARGS+1], *cbp;
+	usch *sbp;
+	int c, o, chkf;
+
+	DPRINT(("%d:enter kfind(%s)\n",0,sp->namep));
+	IMP("KFIND");
+	if (*sp->value == OBJCT) {
+		if (sp == filloc) {
+			unpstr(sheap("\"%s\"", ifiles->fname));
+			return 1;
+		} else if (sp == linloc) {
+			unpstr(sheap("%d", ifiles->lineno));
+			return 1;
+		}
+		IMP("END1");
+		cunput(WARN);
+		for (cbp = sp->value-1; *cbp; cbp--)
+			cunput(*cbp);
+		insblock(addmac(sp));
+		IMP("ENDX");
+		exparg(1);
+
+upp:		sbp = stringbuf;
+		chkf = 1;
+		if (obufp != 0)
+			lastoch = outbuf[obufp-1];
+		if (iswsnl(lastoch))
+			chkf = 0;
+		while ((c = sloscan()) != WARN) {
+			switch (c) {
+			case STRING:
+				/* Remove embedded directives */
+				for (cbp = (usch *)yytext; *cbp; cbp++) {
+					if (*cbp == EBLOCK)
+						cbp+=2;
+					else if (*cbp != CONC)
+						savch(*cbp);
+				}
+				break;
+
+			case EBLOCK:
+				doblk();
+				/* FALLTHROUGH */
+			case IDENT:
+				/*
+				 * Tricky: if this is the last identifier
+				 * in the expanded list, and it is defined
+				 * as a function-like macro, then push it 
+				 * back on the input stream and let fastscan
+				 * handle it as a new macro.
+				 * BUT: if this macro is blocked then this
+				 * should not be done.
+				 */
+				nl = lookup((usch *)yytext, FIND);
+				o = okexp(nl);
+				bidx = 0;
+				/* Deal with pragmas here */
+				if (nl == pragloc) {
+					pragoper();
+					break;
+				}
+				if (nl == NULL || !o || *nl->value == OBJCT) {
+					/* Not fun-like macro */
+					savstr(yytext);
+					break;
+				}
+				c = cinput();
+				if (c == WARN) {
+					/* succeeded, push back */
+					unpstr(yytext);
+				} else {
+					savstr(yytext);
+				}
+				cunput(c);
+				break;
+
+			default:
+				if (chkf && c < 127)
+					putch(' ');
+				savstr(yytext);
+				break;
+			}
+			chkf = 0;
+		}
+		IMP("END2");
+		norepptr = 1;
+		savch(0);
+		stringbuf = sbp;
+		return 1;
+	}
+	/* Is a function-like macro */
+
+	/* Search for '(' */
+	sbp = stringbuf;
+	while (iswsnl(c = cinput()))
+		savch(c);
+	savch(0);
+	stringbuf = sbp;
+	if (c != '(') {
+		cunput(c);
+		unpstr(sbp);
+		return 0; /* Failed */
+	}
+
+	/* Found one, output \n to be in sync */
+	for (; *sbp; sbp++) {
+		if (*sbp == '\n')
+			putch('\n'), ifiles->lineno++;
+	}
+
+	/* fetch arguments */
+	if (readargs(sp, argary))
+		error("readargs");
+
+	c = addmac(sp);
+	sbp = stringbuf;
+	cunput(WARN);
+
+	IMP("KEXP");
+	subarg(sp, argary, 1);
+	IMP("KNEX");
+	insblock(c);
+	IMP("KBLK");
+
+	stringbuf = sbp;
+
+	exparg(1);
+
+	IMP("END");
+
+	goto upp;
+
+}
+
+/*
+ * Replace and push-back on input stream the eventual replaced macro.
+ * The check for whether it can expand or not should already have been done.
+ * Blocks for this identifier will be added via insblock() after expansion.
+ */
+int
+submac(struct symtab *sp, int lvl)
+{
+	const usch *argary[MAXARGS+1];
+	const usch *cp;
+	usch *bp;
+	int ch;
+
+	DPRINT(("%d:submac1: trying '%s'\n", lvl, sp->namep));
+	if (*sp->value == OBJCT) {
+		if (sp == filloc) {
+			unpstr(sheap("\"%s\"", ifiles->fname));
+			return 1;
+		} else if (sp == linloc) {
+			unpstr(sheap("%d", ifiles->lineno));
+			return 1;
+		}
+
+		DPRINT(("submac: exp object macro '%s'\n",sp->namep));
+		/* expand object-type macros */
+		ch = addmac(sp);
+		cunput(WARN);
+
+		for (cp = sp->value-1; *cp; cp--)
+			cunput(*cp);
+		insblock(ch);
+		delwarn();
+		return 1;
+	}
+
+	/*
+	 * Function-like macro; see if it is followed by a (
+	 * Be careful about the expand/noexpand balance.
+	 * Store read data on heap meanwhile.
+	 * For directive	#define foo() kaka
+	 * If input is 		<NEX><NEX>foo<EXP>()<EXP> then
+	 * output should be 	<NEX><NEX><EXP>kaka<EXP>.
+	 */
+	bp = stringbuf;
+	while (iswsnl(ch = cinput()))
+		savch(ch);
+	savch(0);
+	stringbuf = bp;
+	if (ch != '(') {
+		cunput(ch);
+		unpstr(bp);
+		return 0; /* Failed */
+	}
+
+	/* no \n should be here */
+
+	/*
+	 * A function-like macro has been found.  Read in the arguments,
+	 * expand them and push-back everything for another scan.
+	 */
+	DPRINT(("%d:submac: continue macro '%s'\n", lvl, sp->namep));
+	savch(0);
+	if (readargs(sp, argary)) {
+		/* Bailed out in the middle of arg list */
+		unpstr(bp);
+		if (dflag>1)printf("%d:noreadargs\n", lvl);
+		stringbuf = bp;
+		return 0;
+	}
+
+	/* when all args are read from input stream */
+	ch = addmac(sp);
+
+	DDPRINT(("%d:submac pre\n", lvl));
+	cunput(WARN);
+
+	subarg(sp, argary, lvl+1);
+
+	DDPRINT(("%d:submac post\n", lvl));
+	insblock(ch);
+	delwarn();
+
+	stringbuf = bp; /* Reset heap */
+	DPRINT(("%d:Return submac\n", lvl));
+	IMP("SM1");
+	return 1;
+}
+
+/*
+ * Read arguments and put in argument array.
+ * If WARN is encountered return 1, otherwise 0.
+ */
+int
+readargs(struct symtab *sp, const usch **args)
+{
+	const usch *vp = sp->value;
+	int c, i, plev, narg, ellips = 0;
+	int warn;
+
+	DPRINT(("readargs\n"));
+
+	narg = *vp--;
+	if (narg == VARG) {
+		narg = *vp--;
+		ellips = 1;
+	}
+
+	IMP("RDA1");
+	/*
+	 * read arguments and store them on heap.
+	 */
+	warn = 0;
+	c = '(';
+	for (i = 0; i < narg && c != ')'; i++) {
+		args[i] = stringbuf;
+		plev = 0;
+		while ((c = sloscan()) == WSPACE || c == '\n')
+			if (c == '\n')
+				putch(cinput());
+		for (;;) {
+			while (c == EBLOCK) {
+				sss();
+				c = sloscan();
+			}
+			if (c == WARN) {
+				warn++;
+				goto oho;
+			}
+			if (plev == 0 && (c == ')' || c == ','))
+				break;
+			if (c == '(')
+				plev++;
+			if (c == ')')
+				plev--;
+			savstr((usch *)yytext);
+oho:			while ((c = sloscan()) == '\n') {
+				putch(cinput());
+				savch(' ');
+			}
+			while (c == CMNT) {
+				getcmnt();
+				c = sloscan();
+			}
+			if (c == 0)
+				error("eof in macro");
+		}
+		while (args[i] < stringbuf &&
+		    iswsnl(stringbuf[-1]) && stringbuf[-3] != EBLOCK)
+			stringbuf--;
+		savch('\0');
+		if (dflag) {
+			printf("readargs: save arg %d '", i);
+			prline(args[i]);
+			printf("'\n");
+		}
+	}
+
+	IMP("RDA2");
+	/* Handle varargs readin */
+	if (ellips)
+		args[i] = (const usch *)"";
+	if (ellips && c != ')') {
+		args[i] = stringbuf;
+		plev = 0;
+		while ((c = sloscan()) == WSPACE)
+			;
+		for (;;) {
+			if (plev == 0 && c == ')')
+				break;
+			if (c == '(')
+				plev++;
+			if (c == ')')
+				plev--;
+			if (c == EBLOCK) {
+				sss();
+			} else
+				savstr((usch *)yytext);
+			while ((c = sloscan()) == '\n') {
+				cinput();
+				savch(' ');
+			}
+		}
+		while (args[i] < stringbuf && iswsnl(stringbuf[-1]))
+			stringbuf--;
+		savch('\0');
+		
+	}
+	if (narg == 0 && ellips == 0)
+		while ((c = sloscan()) == WSPACE || c == '\n')
+			if (c == '\n')
+				cinput();
+
+	if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
+		error("wrong arg count");
+	while (warn)
+		cunput(WARN), warn--;
+	return 0;
+}
+
+#if 0
+/*
+ * Maybe an indentifier (for macro expansion).
+ */
+static int
+mayid(usch *s)
+{
+	for (; *s; s++)
+		if (!isdigit(*s) && !isalpha(*s) && *s != '_')
+			return 0;
+	return 1;
+}
+#endif
+
+/*
+ * expand a function-like macro.
+ * vp points to end of replacement-list
+ * reads function arguments from sloscan()
+ * result is pushed-back for more scanning.
+ */
+void
+subarg(struct symtab *nl, const usch **args, int lvl)
+{
+	int narg, instr, snuff;
+	const usch *sp, *bp, *ap, *vp;
+
+	DPRINT(("%d:subarg '%s'\n", lvl, nl->namep));
+	vp = nl->value;
+	narg = *vp--;
+	if (narg == VARG)
+		narg = *vp--;
+
+	sp = vp;
+	instr = snuff = 0;
+	if (dflag>1) {
+		printf("%d:subarg ARGlist for %s: '", lvl, nl->namep);
+		prrep(vp);
+		printf("'\n");
+	}
+
+	/*
+	 * push-back replacement-list onto lex buffer while replacing
+	 * arguments.  Arguments are macro-expanded if required.
+	 */
+	while (*sp != 0) {
+		if (*sp == SNUFF)
+			cunput('\"'), snuff ^= 1;
+		else if (*sp == CONC)
+			;
+		else if (*sp == WARN) {
+
+			if (sp[-1] == VARG) {
+				bp = ap = args[narg];
+				sp--;
+#ifdef GCC_COMPAT
+			} else if (sp[-1] == GCCARG) {
+				ap = args[narg];
+				if (ap[0] == 0)
+					ap = (const usch *)"0";
+				bp = ap;
+				sp--;
+#endif
+			} else
+				bp = ap = args[(int)*--sp];
+			if (dflag>1){
+				printf("%d:subarg GOTwarn; arglist '", lvl);
+				prline(bp);
+				printf("'\n");
+			}
+			if (sp[2] != CONC && !snuff && sp[-1] != CONC) {
+				/*
+				 * Expand an argument; 6.10.3.1: 
+				 * "A parameter in the replacement list,
+				 *  is replaced by the corresponding argument
+				 *  after all macros contained therein have
+				 *  been expanded.".
+				 */
+				cunput(WARN);
+				unpstr(bp);
+				exparg(lvl+1);
+				delwarn();
+			} else {
+			while (*bp)
+				bp++;
+			while (bp > ap) {
+				bp--;
+				if (snuff && !instr && iswsnl(*bp)) {
+					while (iswsnl(*bp))
+						bp--;
+					cunput(' ');
+				}
+
+				cunput(*bp);
+				if ((*bp == '\'' || *bp == '"')
+				     && bp[-1] != '\\' && snuff) {
+					instr ^= 1;
+					if (instr == 0 && *bp == '"')
+						cunput('\\');
+				}
+				if (instr && (*bp == '\\' || *bp == '"'))
+					cunput('\\');
+			}
+			}
+		} else
+			cunput(*sp);
+		sp--;
+	}
+	DPRINT(("%d:Return subarg\n", lvl));
+	IMP("SUBARG");
+}
+
+/*
+ * Do a (correct) expansion of a WARN-terminated buffer of tokens.
+ * Data is read from the lex buffer, result on lex buffer, WARN-terminated.
+ * Expansion blocking is not altered here unless when tokens are 
+ * concatenated, in which case they are removed.
+ */
+void
+exparg(int lvl)
+{
+	struct symtab *nl;
+	int c, i;
+	usch *och;
+	usch *osb = stringbuf;
+	int anychange;
+
+	DPRINT(("%d:exparg\n", lvl));
+	IMP("EXPARG");
+
+	readmac++;
+rescan:
+	anychange = 0;
+	while ((c = sloscan()) != WARN) {
+		DDPRINT(("%d:exparg swdata %d\n", lvl, c));
+		IMP("EA0");
+		switch (c) {
+
+		case EBLOCK:
+			doblk();
+			/* FALLTHROUGH */
+		case IDENT:
+			/*
+			 * Handle argument concatenation here.
+			 * In case of concatenation, scratch all blockings.
+			 */
+			DDPRINT(("%d:exparg ident %d\n", lvl, c));
+			och = stringbuf;
+
+sav:			savstr(yytext);
+
+			if ((c = cinput()) == EBLOCK) {
+				/* yep, are concatenating; forget blocks */
+				do {
+					(void)cinput();
+					(void)cinput();
+				} while ((c = sloscan()) == EBLOCK);
+				bidx = 0;
+				goto sav;
+			}
+			cunput(c);
+
+			DPRINT(("%d:exparg: str '%s'\n", lvl, och));
+			IMP("EA1");
+			/* see if ident is expandable */
+			if ((nl = lookup(och, FIND)) && okexp(nl)) {
+				if (submac(nl, lvl+1)) {
+					/* Could expand, result on lexbuffer */
+					stringbuf = och; /* clear saved name */
+					anychange = 1;
+				}
+			} else if (bidx) {
+				/* must restore blocks */
+				stringbuf = och;
+				for (i = 0; i < bidx; i++)
+					savch(EBLOCK), savch(bptr[i] & 255),
+					    savch(bptr[i] >> 8);
+				savstr(yytext);
+			}
+			bidx = 0;
+			IMP("EA2");
+			break;
+
+		case CMNT:
+			getcmnt();
+			break;
+
+		case '\n':
+			cinput();
+			savch(' ');
+			break;
+
+		default:
+			savstr((usch *)yytext);
+			break;
+		}
+	}
+	*stringbuf = 0;
+	cunput(WARN);
+	unpstr(osb);
+	DPRINT(("%d:exparg return: change %d\n", lvl, anychange));
+	IMP("EXPRET");
+	stringbuf = osb;
+	if (anychange)
+		goto rescan;
+	readmac--;
+}
+
+void
+imp(const char *str)
+{
+	printf("%s (%d) '", str, bidx);
+	prline(ifiles->curptr);
+	printf("'\n");
+}
+
+void
+prrep(const usch *s)
+{
+	while (*s) {
+		switch (*s) {
+		case WARN: printf("<ARG(%d)>", *--s); break;
+		case CONC: printf("<CONC>"); break;
+		case SNUFF: printf("<SNUFF>"); break;
+		case EBLOCK: printf("<E(%d)>",s[-1] + s[-2] * 256); s-=2; break;
+		default: printf("%c", *s); break;
+		}
+		s--;
+	}
+}
+
+void
+prline(const usch *s)
+{
+	while (*s) {
+		switch (*s) {
+		case WARN: printf("<WARN>"); break;
+		case CONC: printf("<CONC>"); break;
+		case SNUFF: printf("<SNUFF>"); break;
+		case EBLOCK: printf("<E(%d)>",s[1] + s[2] * 256); s+=2; break;
+		case '\n': printf("<NL>"); break;
+		default: printf("%c", *s); break;
+		}
+		s++;
+	}
+}
+
+usch *
+savstr(const usch *str)
+{
+	usch *rv = stringbuf;
+
+	do {
+		if (stringbuf >= &sbf[SBSIZE])   {
+			stringbuf = sbf; /* need space to write error message */
+			error("out of macro space!");
+		}
+	} while ((*stringbuf++ = *str++));
+	stringbuf--;
+	return rv;
+}
+
+void
+unpstr(const usch *c)
+{
+	const usch *d = c;
+
+#if 0
+	if (dflag>1) {
+		printf("Xunpstr: '");
+		prline(c);
+		printf("'\n");
+	}
+#endif
+	while (*d) {
+		if (*d == EBLOCK)
+			d += 2;
+		d++;
+	}
+	while (d > c) {
+		cunput(*--d);
+	}
+}
+
+static ssize_t
+_write_all(int fd, const void* buffer, size_t count)
+{
+	size_t remaining = count;
+	while (remaining > 0) {
+		ssize_t retval = write(ofd, buffer, remaining);
+		if (retval < 0) {
+			return retval;
+		}
+		remaining -= retval;
+		buffer += retval;
+	}
+	return count;
+}
+
+void
+flbuf()
+{
+	if (obufp == 0)
+		return;
+	if (Mflag == 0 && _write_all(ofd, outbuf, obufp) < 0)
+		error("obuf write error");
+	lastoch = outbuf[obufp-1];
+	obufp = 0;
+}
+
+void
+putch(int ch)
+{
+	outbuf[obufp++] = (usch)ch;
+	if (obufp == CPPBUF || (istty && ch == '\n'))
+		flbuf();
+}
+
+void
+putstr(const usch *s)
+{
+	for (; *s; s++) {
+		outbuf[obufp++] = *s;
+		if (obufp == CPPBUF || (istty && *s == '\n'))
+			flbuf();
+	}
+}
+
+/*
+ * convert a number to an ascii string. Store it on the heap.
+ */
+static void
+num2str(int num)
+{
+	static usch buf[12];
+	usch *b = buf;
+	int m = 0;
+	
+	if (num < 0)
+		num = -num, m = 1;
+	do {
+		*b++ = (usch)(num % 10 + '0');
+		num /= 10;
+	} while (num);
+	if (m)
+		*b++ = '-';
+	while (b > buf)
+		savch(*--b);
+}
+
+/*
+ * similar to sprintf, but only handles %s and %d. 
+ * saves result on heap.
+ */
+usch *
+sheap(const char *fmt, ...)
+{
+	va_list ap;
+	usch *op = stringbuf;
+
+	va_start(ap, fmt);
+	for (; *fmt; fmt++) {
+		if (*fmt == '%') {
+			fmt++;
+			switch (*fmt) {
+			case 's':
+				savstr(va_arg(ap, usch *));
+				break;
+			case 'd':
+				num2str(va_arg(ap, int));
+				break;
+			case 'c':
+				savch(va_arg(ap, int));
+				break;
+			default:
+				break; /* cannot call error() here */
+			}
+		} else
+			savch(*fmt);
+	}
+	va_end(ap);
+	*stringbuf = 0;
+	return op;
+}
+
+void
+usage()
+{
+	error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]");
+}
+
+#ifdef notyet
+/*
+ * Symbol table stuff.
+ * The data structure used is a patricia tree implementation using only
+ * bytes to store offsets.  
+ * The information stored is (lower address to higher):
+ *
+ *	unsigned char bitno[2]; bit number in the string
+ *	unsigned char left[3];	offset from base to left element
+ *	unsigned char right[3];	offset from base to right element
+ */
+#endif
+
+/*
+ * This patricia implementation is more-or-less the same as
+ * used in ccom for string matching.
+ */
+struct tree {
+	int bitno;
+	struct tree *lr[2];
+};
+
+#define BITNO(x)		((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
+#define LEFT_IS_LEAF		0x80000000
+#define RIGHT_IS_LEAF		0x40000000
+#define IS_LEFT_LEAF(x)		(((x) & LEFT_IS_LEAF) != 0)
+#define IS_RIGHT_LEAF(x)	(((x) & RIGHT_IS_LEAF) != 0)
+#define P_BIT(key, bit)		(key[bit >> 3] >> (bit & 7)) & 1
+#define CHECKBITS		8
+
+static struct tree *sympole;
+static int numsyms;
+
+/*
+ * Allocate a symtab struct and store the string.
+ */
+static struct symtab *
+getsymtab(const usch *str)
+{
+	struct symtab *sp = malloc(sizeof(struct symtab));
+
+	if (sp == NULL)
+		error("getsymtab: couldn't allocate symtab");
+	sp->namep = savstr(str);
+	savch('\0');
+	sp->value = NULL;
+	sp->file = ifiles ? ifiles->orgfn : (const usch *)"<initial>";
+	sp->line = ifiles ? ifiles->lineno : 0;
+	return sp;
+}
+
+/*
+ * Do symbol lookup in a patricia tree.
+ * Only do full string matching, no pointer optimisations.
+ */
+struct symtab *
+lookup(const usch *key, int enterf)
+{
+	struct symtab *sp;
+	struct tree *w, *new, *last;
+	int len, cix, bit, fbit, svbit, ix, bitno;
+	const usch *k, *m;
+
+	/* Count full string length */
+	for (k = key, len = 0; *k; k++, len++)
+		;
+
+	switch (numsyms) {
+	case 0: /* no symbols yet */
+		if (enterf != ENTER)
+			return NULL;
+		sympole = (struct tree *)getsymtab(key);
+		numsyms++;
+		return (struct symtab *)sympole;
+
+	case 1:
+		w = sympole;
+		svbit = 0; /* XXX gcc */
+		break;
+
+	default:
+		w = sympole;
+		bitno = len * CHECKBITS;
+		for (;;) {
+			bit = BITNO(w->bitno);
+			fbit = bit > bitno ? 0 : P_BIT(key, bit);
+			svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
+			    IS_LEFT_LEAF(w->bitno);
+			w = w->lr[fbit];
+			if (svbit)
+				break;
+		}
+	}
+
+	sp = (struct symtab *)w;
+
+	m = sp->namep;
+	k = key;
+
+	/* Check for correct string and return */
+	for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS)
+		;
+	if (*m == 0 && *k == 0) {
+		if (enterf != ENTER && sp->value == NULL)
+			return NULL;
+		return sp;
+	}
+
+	if (enterf != ENTER)
+		return NULL; /* no string found and do not enter */
+
+	ix = *m ^ *k;
+	while ((ix & 1) == 0)
+		ix >>= 1, cix++;
+
+	/* Create new node */
+	if ((new = malloc(sizeof *new)) == NULL)
+		error("getree: couldn't allocate tree");
+	bit = P_BIT(key, cix);
+	new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+	new->lr[bit] = (struct tree *)getsymtab(key);
+
+	if (numsyms++ == 1) {
+		new->lr[!bit] = sympole;
+		new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+		sympole = new;
+		return (struct symtab *)new->lr[bit];
+	}
+
+	w = sympole;
+	last = NULL;
+	for (;;) {
+		fbit = w->bitno;
+		bitno = BITNO(w->bitno);
+		if (bitno == cix)
+			error("bitno == cix");
+		if (bitno > cix)
+			break;
+		svbit = P_BIT(key, bitno);
+		last = w;
+		w = w->lr[svbit];
+		if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
+			break;
+	}
+
+	new->lr[!bit] = w;
+	if (last == NULL) {
+		sympole = new;
+	} else {
+		last->lr[svbit] = new;
+		last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
+	}
+	if (bitno < cix)
+		new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
+	return (struct symtab *)new->lr[bit];
+}
+
+usch *
+xstrdup(const usch *str)
+{
+	size_t len = strlen((const char *)str)+1;
+	usch *rv;
+
+	if ((rv = malloc(len)) == NULL)
+		error("xstrdup: out of mem");
+	strlcpy((char *)rv, (const char *)str, len);
+	return rv;
+}
Index: uspace/app/pcc/cc/cpp/cpp.h
===================================================================
--- uspace/app/pcc/cc/cpp/cpp.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/cpp.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,184 @@
+/*	$Id: cpp.h,v 1.47.2.1 2011/02/26 06:36:40 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004,2010 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h> /* for obuf */
+#include <stdlib.h>
+
+#include "config.h"
+
+typedef unsigned char usch;
+extern usch yytext[];
+extern usch *stringbuf;
+
+extern	int	trulvl;
+extern	int	flslvl;
+extern	int	elflvl;
+extern	int	elslvl;
+extern	int	tflag, Cflag, Pflag;
+extern	int	Mflag, dMflag;
+extern	usch	*Mfile;
+extern	int	ofd;
+
+/* args for lookup() */
+#define FIND    0
+#define ENTER   1
+
+/* buffer used internally */
+#ifndef CPPBUF
+#if defined(__pdp11__)
+#define CPPBUF  BUFSIZ
+#define	BUF_STACK
+#elif defined(WIN32)
+/* winxp seems to fail > 26608 bytes */
+#define CPPBUF	16384
+#else
+#define CPPBUF	(65536*2)
+#endif
+#endif
+
+#define	MAXARGS	128	/* Max # of args to a macro. Should be enouth */
+
+#define	NAMEMAX	CPPBUF	/* currently pushbackbuffer */
+#define	BBUFSZ	(NAMEMAX+CPPBUF+1)
+
+#define GCCARG	0xfd	/* has gcc varargs that may be replaced with 0 */
+#define VARG	0xfe	/* has varargs */
+#define OBJCT	0xff
+#define WARN	1	/* SOH, not legal char */
+#define CONC	2	/* STX, not legal char */
+#define SNUFF	3	/* ETX, not legal char */
+#define	EBLOCK	4	/* EOT, not legal char */
+
+/* Used in macro expansion */
+#define RECMAX	10000			/* max # of recursive macros */
+extern struct symtab *norep[RECMAX];
+extern int norepptr;
+extern unsigned short bptr[RECMAX];
+extern int bidx;
+#define	MKB(l,h)	(l+((h)<<8))
+
+/* quick checks for some characters */
+#define C_SPEC	001
+#define C_EP	002
+#define C_ID	004
+#define C_I	(C_SPEC|C_ID)		
+#define C_2	010		/* for yylex() tokenizing */
+#define	C_WSNL	020		/* ' ','\t','\r','\n' */
+#define	iswsnl(x) (spechr[x] & C_WSNL)
+extern char spechr[];
+
+/* definition for include file info */
+struct includ {
+	struct includ *next;
+	const usch *fname;	/* current fn, changed if #line found */
+	const usch *orgfn;	/* current fn, not changed */
+	int lineno;
+	int infil;
+	usch *curptr;
+	usch *maxread;
+	usch *ostr;
+	usch *buffer;
+	int idx;
+	void *incs;
+	const usch *fn;
+#ifdef BUF_STACK
+	usch bbuf[BBUFSZ];
+#else
+	usch *bbuf;
+#endif
+} *ifiles;
+
+/* Symbol table entry  */
+struct symtab {
+	const usch *namep;    
+	const usch *value;    
+	const usch *file;
+	int line;
+};
+
+struct initar {
+	struct initar *next;
+	int type;
+	char *str;
+};
+
+/*
+ * Struct used in parse tree evaluation.
+ * op is one of:
+ *	- number type (NUMBER, UNUMBER)
+ *	- zero (0) if divided by zero.
+ */
+struct nd {
+	int op;
+	union {
+		long long val;
+		unsigned long long uval;
+	} n;
+};
+
+#define nd_val n.val
+#define nd_uval n.uval
+
+struct symtab *lookup(const usch *namep, int enterf);
+usch *gotident(struct symtab *nl);
+int slow;	/* scan slowly for new tokens */
+int submac(struct symtab *nl, int);
+int kfind(struct symtab *nl);
+int doexp(void);
+int donex(void);
+
+int pushfile(const usch *fname, const usch *fn, int idx, void *incs);
+void popfile(void);
+void prtline(void);
+int yylex(void);
+int sloscan(void);
+void cunput(int);
+int curline(void);
+char *curfile(void);
+void setline(int);
+void setfile(char *);
+int yyparse(void);
+void yyerror(const char *);
+void unpstr(const usch *);
+usch *savstr(const usch *str);
+void savch(int c);
+void mainscan(void);
+void putch(int);
+void putstr(const usch *s);
+void line(void);
+usch *sheap(const char *fmt, ...);
+void xwarning(usch *);
+void xerror(usch *);
+#ifdef HAVE_CPP_VARARG_MACRO_GCC
+#define warning(...) xwarning(sheap(__VA_ARGS__))
+#define error(...) xerror(sheap(__VA_ARGS__))
+#else
+#define warning printf
+#define error printf
+#endif
+int cinput(void);
+void getcmnt(void);
Index: uspace/app/pcc/cc/cpp/cpy.y
===================================================================
--- uspace/app/pcc/cc/cpp/cpy.y	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/cpy.y	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,221 @@
+/*	$Id: cpy.y,v 1.18 2010/02/25 15:49:00 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%{
+
+#include "cpp.h"
+
+void yyerror(const char *);
+int yylex(void);
+int setd(int l, int r);
+
+#define	EVALUNARY(tok, l, r) l.nd_val = tok r.nd_val; l.op = r.op
+#define	EVALBIN(tok, d, l, r)	\
+	d.op = setd(l.op, r.op); d.nd_val = l.nd_val tok r.nd_val
+#define	EVALUBIN(tok, d, l, r, t)				\
+	d.op = setd(l.op, r.op);				\
+	if (d.op == NUMBER) d.nd_val = l.nd_val tok r.nd_val;	\
+	else d.nd_uval = l.nd_uval tok r.nd_uval;		\
+	if (t && d.op) d.op = NUMBER
+#define	XEVALUBIN(tok, d, l, r)					\
+	if (r.nd_val) { EVALUBIN(tok, d, l, r, 0); } else d.op = 0
+%}
+
+%term stop
+%term EQ NE LE GE LS RS
+%term ANDAND OROR IDENT NUMBER UNUMBER DEFINED
+/*
+ * The following terminals are not used in the yacc code.
+ */
+%term STRING WSPACE CMNT
+
+%left ','
+%right '?' ':'
+%left OROR
+%left ANDAND
+%left '|' '^'
+%left '&'
+%binary EQ NE
+%binary '<' '>' LE GE
+%left LS RS
+%left '+' '-'
+%left '*' '/' '%'
+%right '!' '~' UMINUS
+%left '('
+
+%union {
+	struct nd node;
+}
+
+%type <node>	term e NUMBER UNUMBER
+
+%%
+S:	e '\n'	{ 
+		if ($1.op == 0)
+			error("division by zero");
+		return $1.nd_val;
+	}
+
+e:	  e '*' e
+		{ EVALUBIN(*, $$, $1, $3, 0); }
+	| e '/' e
+		{ XEVALUBIN(/, $$, $1, $3); }
+	| e '%' e
+		{ XEVALUBIN(%, $$, $1, $3); }
+	| e '+' e
+		{ EVALBIN(+, $$, $1, $3); }
+	| e '-' e
+		{ EVALBIN(-, $$, $1, $3); }
+	| e LS e
+		{ EVALBIN(<<, $$, $1, $3); }
+	| e RS e
+		{ EVALUBIN(>>, $$, $1, $3, 0); }
+	| e '<' e
+		{ EVALUBIN(<, $$, $1, $3, 1); }
+	| e '>' e
+		{ EVALUBIN(>, $$, $1, $3, 1); }
+	| e LE e
+		{ EVALUBIN(<=, $$, $1, $3, 1); }
+	| e GE e
+		{ EVALUBIN(>=, $$, $1, $3, 1); }
+	| e EQ e
+		{ EVALUBIN(==, $$, $1, $3, 1); }
+	| e NE e
+		{ EVALUBIN(!=, $$, $1, $3, 1); }
+	| e '&' e
+		{ EVALBIN(&, $$, $1, $3); }
+	| e '^' e
+		{ EVALBIN(^, $$, $1, $3); }
+	| e '|' e
+		{ EVALBIN(|, $$, $1, $3); }
+	| e ANDAND e {
+		$$ = $1;
+		if ($1.nd_val) {
+			$$.op = setd($1.op, $3.op);
+			$$.nd_val = ($3.nd_val != 0);
+		}
+		if ($$.op == UNUMBER) $$.op = NUMBER;
+	}
+	| e OROR e {
+		if ($1.nd_val != 0) {
+			$$.nd_val = ($1.nd_val != 0);
+			$$.op = $1.op;
+		} else {
+			$$.nd_val = ($3.nd_val != 0);
+			$$.op = setd($1.op, $3.op);
+		}
+		if ($$.op == UNUMBER) $$.op = NUMBER;
+	}
+	| e '?' e ':' e {
+		if ($1.op == 0)
+			$$ = $1;
+		else if ($1.nd_val)
+			$$ = $3;
+		else
+			$$ = $5;
+	}
+	| e ',' e {
+		$$.op = setd($1.op, $3.op);
+		$$.nd_val = $3.nd_val;
+		if ($$.op) $$.op =  $3.op;
+	}
+	| term
+		{$$ = $1;}
+term:
+	  '-' term %prec UMINUS
+		{ EVALUNARY(-, $$, $2); }
+	| '+' term %prec UMINUS
+		{$$ = $2;}
+	| '!' term
+		{ $$.nd_val = ! $2.nd_val; $$.op = $2.op ? NUMBER : 0; }
+	| '~' term
+		{ EVALUNARY(~, $$, $2); }
+	| '(' e ')'
+		{$$ = $2;}
+	| DEFINED '(' NUMBER ')'
+		{$$= $3;}
+	| DEFINED NUMBER
+		{$$ = $2;}
+	| NUMBER
+		{$$ = $1;}
+%%
+
+void
+yyerror(const char *err)
+{
+	error(err);
+}
+
+/*
+ * Set return type of an expression.
+ */
+int
+setd(int l, int r)
+{
+	if (!l || !r)
+		return 0; /* div by zero involved */
+	if (l == UNUMBER || r == UNUMBER)
+		return UNUMBER;
+	return NUMBER;
+}
+
Index: uspace/app/pcc/cc/cpp/scanner.l
===================================================================
--- uspace/app/pcc/cc/cpp/scanner.l	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/scanner.l	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,939 @@
+%{
+/*	$Id: scanner.l,v 1.49 2009/02/14 09:23:55 ragge Exp $   */
+
+/*
+ * Copyright (c) 2004 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
+
+#include "compat.h"
+#include "cpp.h"
+#include "y.tab.h"
+%}
+
+%{
+static void cvtdig(int rad);
+static int charcon(usch *);
+static void elsestmt(void);
+static void ifdefstmt(void);
+static void ifndefstmt(void);
+static void endifstmt(void);
+static void ifstmt(void);
+static void cpperror(void);
+static void pragmastmt(void);
+static void undefstmt(void);
+static void cpperror(void);
+static void elifstmt(void);
+static void storepb(void);
+static void badop(const char *);
+void  include(void);
+void  define(void);
+
+extern int yyget_lineno (void);
+extern void yyset_lineno (int);
+
+static int inch(void);
+
+static int scale, gotdef, contr;
+int inif;
+
+#ifdef FLEX_SCANNER /* should be set by autoconf instead */
+static int
+yyinput(char *b, int m)
+{
+	int c, i;
+
+	for (i = 0; i < m; i++) {
+		if ((c = inch()) < 0)
+			break;
+		*b++ = c;
+		if (c == '\n') {
+			i++;
+			break;
+		}
+	}
+	return i;
+}
+#undef YY_INPUT
+#undef YY_BUF_SIZE
+#define	YY_BUF_SIZE (8*65536)
+#define YY_INPUT(b,r,m) (r = yyinput(b, m))
+#ifdef HAVE_CPP_VARARG_MACRO_GCC
+#define fprintf(x, ...) error(__VA_ARGS__)
+#endif
+#define	ECHO putstr((usch *)yytext)
+#undef fileno
+#define fileno(x) 0
+
+#if YY_FLEX_SUBMINOR_VERSION >= 31
+/* Hack to avoid unnecessary warnings */
+FILE *yyget_in	(void);
+FILE *yyget_out  (void);
+int yyget_leng	(void);
+char *yyget_text  (void);
+void yyset_in (FILE *  in_str );
+void yyset_out (FILE *	out_str );
+int yyget_debug  (void);
+void yyset_debug (int  bdebug );
+int yylex_destroy  (void);
+#endif
+#else	/* Assume lex here */
+#undef input
+#undef unput
+#define input() inch()
+#define unput(ch) unch(ch)
+#endif
+#define PRTOUT(x) if (YYSTATE || slow) return x; if (!flslvl) putstr((usch *)yytext);
+/* protection against recursion in #include */
+#define MAX_INCLEVEL	100
+static int inclevel;
+%}
+
+D	[0-9]
+L	[a-zA-Z_]
+H	[a-fA-F0-9]
+E	[Ee][+-]?{D}+
+FS	(f|F|l|L)
+IS	(u|U|l|L)*
+WS	[\t ]
+
+%s IFR CONTR DEF COMMENT
+
+%%
+
+"\n"			{	int os = YYSTATE;
+				if (os != IFR)
+					BEGIN 0;
+				ifiles->lineno++;
+				if (flslvl == 0) {
+					if (ifiles->lineno == 1)
+						prtline();
+					else
+						putch('\n');
+				}
+				if ((os != 0 || slow) && !contr)
+					return '\n';
+				contr = 0;
+			}
+
+"\r"			{ ; /* Ignore CR's */ }
+
+<IFR>"++"		{ badop("++"); }
+<IFR>"--"		{ badop("--"); }
+<IFR>"=="		{ return EQ; }
+<IFR>"!="		{ return NE; }
+<IFR>"<="		{ return LE; }
+<IFR>"<<"		{ return LS; }
+<IFR>">>"		{ return RS; }
+<IFR>">="		{ return GE; }
+<IFR>"||"		{ return OROR; }
+<IFR>"&&"		{ return ANDAND; }
+<IFR>"defined"		{	int p, c;
+				gotdef = 1;
+				if ((p = c = yylex()) == '(')
+					c = yylex();
+				if (c != IDENT || (p != IDENT && p != '('))
+					error("syntax error");
+				if (p == '(' && yylex() != ')')
+					error("syntax error");
+				return NUMBER;
+			}
+
+<IFR>{WS}+		{ ; }
+<IFR>{L}({L}|{D})*	{
+				yylval.node.op = NUMBER;
+				if (gotdef) {
+					yylval.node.nd_val
+					    = lookup((usch *)yytext, FIND) != 0;
+					gotdef = 0;
+					return IDENT;
+				}
+				yylval.node.nd_val = 0;
+				return NUMBER;
+			}
+
+[0-9][0-9]*		{
+				if (slow && !YYSTATE)
+					return IDENT;
+				scale = yytext[0] == '0' ? 8 : 10;
+				goto num;
+			}
+
+0[xX]{H}+{IS}?		{	scale = 16;
+			num:	if (YYSTATE == IFR) 
+					cvtdig(scale);
+				PRTOUT(NUMBER);
+			}
+0{D}+{IS}?		{ scale = 8; goto num; }
+{D}+{IS}?		{ scale = 10; goto num; }
+'(\\.|[^\\'])+'		{
+				if (YYSTATE || slow) {
+					yylval.node.op = NUMBER;
+					yylval.node.nd_val = charcon((usch *)yytext);
+					return (NUMBER);
+				}
+				if (tflag)
+					yyless(1);
+				if (!flslvl)
+					putstr((usch *)yytext);
+			}
+
+<IFR>.			{ return yytext[0]; }
+
+{D}+{E}{FS}?		{ PRTOUT(FPOINT); }
+{D}*"."{D}+({E})?{FS}?	{ PRTOUT(FPOINT); }
+{D}+"."{D}*({E})?{FS}?	{ PRTOUT(FPOINT); }
+
+^{WS}*#{WS}*		{	extern int inmac;
+
+				if (inmac)
+					error("preprocessor directive found "
+					    "while expanding macro");
+				contr = 1;
+				BEGIN CONTR;
+			}
+{WS}+			{ PRTOUT(WSPACE); }
+
+<CONTR>"ifndef"		{ contr = 0; ifndefstmt(); }
+<CONTR>"ifdef"		{ contr = 0; ifdefstmt(); }
+<CONTR>"if"		{ contr = 0; storepb(); BEGIN IFR; ifstmt(); BEGIN 0; }
+<CONTR>"include"	{ contr = 0; BEGIN 0; include(); prtline(); }
+<CONTR>"else"		{ contr = 0; elsestmt(); }
+<CONTR>"endif"		{ contr = 0; endifstmt(); }
+<CONTR>"error"		{ contr = 0; if (slow) return IDENT; cpperror(); BEGIN 0; }
+<CONTR>"define"		{ contr = 0; BEGIN DEF; define(); BEGIN 0; }
+<CONTR>"undef"		{ contr = 0; if (slow) return IDENT; undefstmt(); }
+<CONTR>"line"		{ contr = 0; storepb(); BEGIN 0; line(); }
+<CONTR>"pragma"		{ contr = 0; pragmastmt(); BEGIN 0; }
+<CONTR>"elif"		{ contr = 0; storepb(); BEGIN IFR; elifstmt(); BEGIN 0; }
+
+
+
+"//".*$			{ /* if (tflag) yyless(..) */
+				if (Cflag && !flslvl && !slow)
+					putstr((usch *)yytext);
+				else if (!flslvl)
+					putch(' ');
+			}
+"/*"			{	int c, wrn;
+				int prtcm = Cflag && !flslvl && !slow;
+				extern int readmac;
+
+				if (Cflag && !flslvl && readmac)
+					return CMNT;
+
+				if (prtcm)
+					putstr((usch *)yytext);
+				wrn = 0;
+			more:	while ((c = input()) && c != '*') {
+					if (c == '\n')
+						putch(c), ifiles->lineno++;
+					else if (c == 1) /* WARN */
+						wrn = 1;
+					else if (prtcm)
+						putch(c);
+				}
+				if (c == 0)
+					return 0;
+				if (prtcm)
+					putch(c);
+				if ((c = input()) && c != '/') {
+					unput(c);
+					goto more;
+				}
+				if (prtcm)
+					putch(c);
+				if (c == 0)
+					return 0;
+				if (!tflag && !Cflag && !flslvl)
+					unput(' ');
+				if (wrn)
+					unput(1);
+			}
+
+<DEF>"##"		{ return CONCAT; }
+<DEF>"#"		{ return MKSTR; }
+<DEF>"..."		{ return ELLIPS; }
+<DEF>"__VA_ARGS__"	{ return VA_ARGS; }
+
+L?\"(\\.|[^\\"])*\"	{ PRTOUT(STRING); }
+[a-zA-Z_0-9]+		{ /* {L}({L}|{D})* */
+				struct symtab *nl;
+				if (slow)
+					return IDENT;
+				if (YYSTATE == CONTR) {
+					if (flslvl == 0) {
+						/*error("undefined control");*/
+						while (input() != '\n')
+							;
+						unput('\n');
+						BEGIN 0;
+						goto xx;
+					} else {
+						BEGIN 0; /* do nothing */
+					}
+				}
+				if (flslvl) {
+					; /* do nothing */
+				} else if (isdigit((int)yytext[0]) == 0 &&
+				    (nl = lookup((usch *)yytext, FIND)) != 0) {
+					usch *op = stringbuf;
+					putstr(gotident(nl));
+					stringbuf = op;
+				} else
+					putstr((usch *)yytext);
+				xx: ;
+			}
+
+.			{
+				if (contr) {
+					while (input() != '\n')
+						;
+					unput('\n');
+					BEGIN 0;
+					contr = 0;
+					goto yy;
+				}
+				if (YYSTATE || slow)
+					return yytext[0];
+				if (yytext[0] == 6) { /* PRAGS */
+					usch *obp = stringbuf;
+					extern usch *prtprag(usch *);
+					*stringbuf++ = yytext[0];
+					do {
+						*stringbuf = input();
+					} while (*stringbuf++ != 14);
+					prtprag(obp);
+					stringbuf = obp;
+				} else {
+					PRTOUT(yytext[0]);
+				}
+				yy:;
+			}
+
+%%
+
+usch *yyp, yybuf[CPPBUF];
+
+int yylex(void);
+int yywrap(void);
+
+static int
+inpch(void)
+{
+	int len;
+
+	if (ifiles->curptr < ifiles->maxread)
+		return *ifiles->curptr++;
+
+	if ((len = read(ifiles->infil, ifiles->buffer, CPPBUF)) < 0)
+		error("read error on file %s", ifiles->orgfn);
+	if (len == 0)
+		return -1;
+	ifiles->curptr = ifiles->buffer;
+	ifiles->maxread = ifiles->buffer + len;
+	return inpch();
+}
+
+#define unch(c) *--ifiles->curptr = c
+
+static int
+inch(void)
+{
+	int c;
+
+again:	switch (c = inpch()) {
+	case '\\': /* continued lines */
+msdos:		if ((c = inpch()) == '\n') {
+			ifiles->lineno++;
+			putch('\n');
+			goto again;
+		} else if (c == '\r')
+			goto msdos;
+		unch(c);
+		return '\\';
+	case '?': /* trigraphs */
+		if ((c = inpch()) != '?') {
+			unch(c);
+			return '?';
+		}
+		switch (c = inpch()) {
+		case '=': c = '#'; break;
+		case '(': c = '['; break;
+		case ')': c = ']'; break;
+		case '<': c = '{'; break;
+		case '>': c = '}'; break;
+		case '/': c = '\\'; break;
+		case '\'': c = '^'; break;
+		case '!': c = '|'; break;
+		case '-': c = '~'; break;
+		default:
+			unch(c);
+			unch('?');
+			return '?';
+		}
+		unch(c);
+		goto again;
+	default:
+		return c;
+	}
+}
+
+/*
+ * Let the command-line args be faked defines at beginning of file.
+ */
+static void
+prinit(struct initar *it, struct includ *ic)
+{
+	char *a, *pre, *post;
+
+	if (it->next)
+		prinit(it->next, ic);
+	pre = post = NULL; /* XXX gcc */
+	switch (it->type) {
+	case 'D':
+		pre = "#define ";
+		if ((a = strchr(it->str, '=')) != NULL) {
+			*a = ' ';
+			post = "\n";
+		} else
+			post = " 1\n";
+		break;
+	case 'U':
+		pre = "#undef ";
+		post = "\n";
+		break;
+	case 'i':
+		pre = "#include \"";
+		post = "\"\n";
+		break;
+	default:
+		error("prinit");
+	}
+	strlcat((char *)ic->buffer, pre, CPPBUF+1);
+	strlcat((char *)ic->buffer, it->str, CPPBUF+1);
+	if (strlcat((char *)ic->buffer, post, CPPBUF+1) >= CPPBUF+1)
+		error("line exceeds buffer size");
+
+	ic->lineno--;
+	while (*ic->maxread)
+		ic->maxread++;
+}
+
+/*
+ * A new file included.
+ * If ifiles == NULL, this is the first file and already opened (stdin).
+ * Return 0 on success, -1 if file to be included is not found.
+ */
+int
+pushfile(usch *file)
+{
+	extern struct initar *initar;
+	struct includ ibuf;
+	struct includ *ic;
+	int c, otrulvl;
+
+	ic = &ibuf;
+	ic->next = ifiles;
+
+	slow = 0;
+	if (file != NULL) {
+		if ((ic->infil = open((char *)file, O_RDONLY)) < 0)
+			return -1;
+		ic->orgfn = ic->fname = file;
+		if (++inclevel > MAX_INCLEVEL)
+			error("Limit for nested includes exceeded");
+	} else {
+		ic->infil = 0;
+		ic->orgfn = ic->fname = (usch *)"<stdin>";
+	}
+	ic->buffer = ic->bbuf+NAMEMAX;
+	ic->curptr = ic->buffer;
+	ifiles = ic;
+	ic->lineno = 1;
+	ic->maxread = ic->curptr;
+	prtline();
+	if (initar) {
+		*ic->maxread = 0;
+		prinit(initar, ic);
+		if (dMflag)
+			write(ofd, ic->buffer, strlen((char *)ic->buffer));
+		initar = NULL;
+	}
+
+	otrulvl = trulvl;
+
+	if ((c = yylex()) != 0)
+		error("yylex returned %d", c);
+
+	if (otrulvl != trulvl || flslvl)
+		error("unterminated conditional");
+
+	ifiles = ic->next;
+	close(ic->infil);
+	inclevel--;
+	return 0;
+}
+
+/*
+ * Print current position to output file.
+ */
+void
+prtline()
+{
+	usch *s, *os = stringbuf;
+
+	if (Mflag) {
+		if (dMflag)
+			return; /* no output */
+		if (ifiles->lineno == 1) {
+			s = sheap("%s: %s\n", Mfile, ifiles->fname);
+			write(ofd, s, strlen((char *)s));
+		}
+	} else if (!Pflag)
+		putstr(sheap("# %d \"%s\"\n", ifiles->lineno, ifiles->fname));
+	stringbuf = os;
+}
+
+void
+cunput(int c)
+{
+#ifdef CPP_DEBUG
+	extern int dflag;
+	if (dflag)printf(": '%c'(%d)", c > 31 ? c : ' ', c);
+#endif
+	unput(c);
+}
+
+int yywrap(void) { return 1; }
+
+static int
+dig2num(int c)
+{
+	if (c >= 'a')
+		c = c - 'a' + 10;
+	else if (c >= 'A')
+		c = c - 'A' + 10;
+	else
+		c = c - '0';
+	return c;
+}
+
+/*
+ * Convert string numbers to unsigned long long and check overflow.
+ */
+static void
+cvtdig(int rad)
+{
+	unsigned long long rv = 0;
+	unsigned long long rv2 = 0;
+	char *y = yytext;
+	int c;
+
+	c = *y++;
+	if (rad == 16)
+		y++;
+	while (isxdigit(c)) {
+		rv = rv * rad + dig2num(c);
+		/* check overflow */
+		if (rv / rad < rv2)
+			error("Constant \"%s\" is out of range", yytext);
+		rv2 = rv;
+		c = *y++;
+	}
+	y--;
+	while (*y == 'l' || *y == 'L')
+		y++;
+	yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER;
+	yylval.node.nd_uval = rv;
+	if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0)
+		yylval.node.op = UNUMBER;
+	if (yylval.node.op == NUMBER && yylval.node.nd_val < 0)
+		/* too large for signed */
+		error("Constant \"%s\" is out of range", yytext);
+}
+
+static int
+charcon(usch *p)
+{
+	int val, c;
+
+	p++; /* skip first ' */
+	val = 0;
+	if (*p++ == '\\') {
+		switch (*p++) {
+		case 'a': val = '\a'; break;
+		case 'b': val = '\b'; break;
+		case 'f': val = '\f'; break;
+		case 'n': val = '\n'; break;
+		case 'r': val = '\r'; break;
+		case 't': val = '\t'; break;
+		case 'v': val = '\v'; break;
+		case '\"': val = '\"'; break;
+		case '\'': val = '\''; break;
+		case '\\': val = '\\'; break;
+		case 'x':
+			while (isxdigit(c = *p)) {
+				val = val * 16 + dig2num(c);
+				p++;
+			}
+			break;
+		case '0': case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7':
+			p--;
+			while (isdigit(c = *p)) {
+				val = val * 8 + (c - '0');
+				p++;
+			}
+			break;
+		default: val = p[-1];
+		}
+
+	} else
+		val = p[-1];
+	return val;
+}
+
+static void
+chknl(int ignore)
+{
+	int t;
+
+	slow = 1;
+	while ((t = yylex()) == WSPACE)
+		;
+	if (t != '\n') {
+		if (ignore) {
+			warning("newline expected, got \"%s\"", yytext);
+			/* ignore rest of line */
+			while ((t = yylex()) && t != '\n')
+				;
+		}
+		else
+			error("newline expected, got \"%s\"", yytext);
+	}
+	slow = 0;
+}
+
+static void
+elsestmt(void)
+{
+	if (flslvl) {
+		if (elflvl > trulvl)
+			;
+		else if (--flslvl!=0) {
+			flslvl++;
+		} else {
+			trulvl++;
+			prtline();
+		}
+	} else if (trulvl) {
+		flslvl++;
+		trulvl--;
+	} else
+		error("If-less else");
+	if (elslvl==trulvl+flslvl)
+		error("Too many else");
+	elslvl=trulvl+flslvl;
+	chknl(1);
+}
+
+static void
+ifdefstmt(void)		 
+{ 
+	int t;
+
+	if (flslvl) {
+		/* just ignore the rest of the line */
+		while (input() != '\n')
+			;
+		unput('\n');
+		yylex();
+		flslvl++;
+		return;
+	}
+	slow = 1;
+	do
+		t = yylex();
+	while (t == WSPACE);
+	if (t != IDENT)
+		error("bad ifdef");
+	slow = 0;
+	if (flslvl == 0 && lookup((usch *)yytext, FIND) != 0)
+		trulvl++;
+	else
+		flslvl++;
+	chknl(0);
+}
+
+static void
+ifndefstmt(void)	  
+{ 
+	int t;
+
+	slow = 1;
+	do
+		t = yylex();
+	while (t == WSPACE);
+	if (t != IDENT)
+		error("bad ifndef");
+	slow = 0;
+	if (flslvl == 0 && lookup((usch *)yytext, FIND) == 0)
+		trulvl++;
+	else
+		flslvl++;
+	chknl(0);
+}
+
+static void
+endifstmt(void)		 
+{
+	if (flslvl) {
+		flslvl--;
+		if (flslvl == 0)
+			prtline();
+	} else if (trulvl)
+		trulvl--;
+	else
+		error("If-less endif");
+	if (flslvl == 0)
+		elflvl = 0;
+	elslvl = 0;
+	chknl(1);
+}
+
+/*
+ * Note! Ugly!
+ * Walk over the string s and search for defined, and replace it with 
+ * spaces and a 1 or 0. 
+ */
+static void
+fixdefined(usch *s)
+{
+	usch *bc, oc;
+
+	for (; *s; s++) {
+		if (*s != 'd')
+			continue;
+		if (memcmp(s, "defined", 7))
+			continue;
+		/* Ok, got defined, can scratch it now */
+		memset(s, ' ', 7);
+		s += 7;
+#define	WSARG(x) (x == ' ' || x == '\t')
+		if (*s != '(' && !WSARG(*s))
+			continue;
+		while (WSARG(*s))
+			s++;
+		if (*s == '(')
+			s++;
+		while (WSARG(*s))
+			s++;
+#define IDARG(x) ((x>= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z') || (x == '_'))
+#define	NUMARG(x) (x >= '0' && x <= '9')
+		if (!IDARG(*s))
+			error("bad defined arg");
+		bc = s;
+		while (IDARG(*s) || NUMARG(*s))
+			s++;
+		oc = *s;
+		*s = 0;
+		*bc = (lookup(bc, FIND) != 0) + '0';
+		memset(bc+1, ' ', s-bc-1);
+		*s = oc;
+	}
+}
+
+/*
+ * get the full line of identifiers after an #if, pushback a WARN and
+ * the line and prepare for expmac() to expand.
+ * This is done before switching state.  When expmac is finished,
+ * pushback the expanded line, change state and call yyparse.
+ */
+static void
+storepb(void)
+{
+	usch *opb = stringbuf;
+	int c;
+
+	while ((c = input()) != '\n') {
+		if (c == '/') {
+			 if ((c = input()) == '*') {
+				/* ignore comments here whatsoever */
+				usch *g = stringbuf;
+				getcmnt();
+				stringbuf = g;
+				continue;
+			} else if (c == '/') {
+				while ((c = input()) && c != '\n')
+					;
+				break;
+			}
+			unput(c);
+			c = '/';
+		}
+		savch(c);
+	}
+	cunput('\n');
+	savch(0);
+	fixdefined(opb); /* XXX can fail if #line? */
+	cunput(1); /* WARN XXX */
+	unpstr(opb);
+	stringbuf = opb;
+	slow = 1;
+	expmac(NULL);
+	slow = 0;
+	/* line now expanded */
+	while (stringbuf > opb)
+		cunput(*--stringbuf);
+}
+
+static void
+ifstmt(void)
+{
+	if (flslvl == 0) {
+		slow = 1;
+		if (yyparse())
+			++trulvl;
+		else
+			++flslvl;
+		slow = 0;
+	} else
+		++flslvl;
+}
+
+static void
+elifstmt(void)
+{
+	if (flslvl == 0)
+		elflvl = trulvl;
+	if (flslvl) {
+		if (elflvl > trulvl)
+			;
+		else if (--flslvl!=0)
+			++flslvl;
+		else {
+			slow = 1;
+			if (yyparse()) {
+				++trulvl;
+				prtline();
+			} else
+				++flslvl;
+			slow = 0;
+		}
+	} else if (trulvl) {
+		++flslvl;
+		--trulvl;
+	} else
+		error("If-less elif");
+}
+
+static usch *
+svinp(void)
+{
+	int c;
+	usch *cp = stringbuf;
+
+	while ((c = input()) && c != '\n')
+		savch(c);
+	savch('\n');
+	savch(0);
+	BEGIN 0;
+	return cp;
+}
+
+static void
+cpperror(void)
+{
+	usch *cp;
+	int c;
+
+	if (flslvl)
+		return;
+	c = yylex();
+	if (c != WSPACE && c != '\n')
+		error("bad error");
+	cp = svinp();
+	if (flslvl)
+		stringbuf = cp;
+	else
+		error("%s", cp);
+}
+
+static void
+undefstmt(void)
+{
+	struct symtab *np;
+
+	slow = 1;
+	if (yylex() != WSPACE || yylex() != IDENT)
+		error("bad undef");
+	if (flslvl == 0 && (np = lookup((usch *)yytext, FIND)))
+		np->value = 0;
+	slow = 0;
+	chknl(0);
+}
+
+static void
+pragmastmt(void)
+{
+	int c;
+
+	slow = 1;
+	if (yylex() != WSPACE)
+		error("bad pragma");
+	if (!flslvl)
+		putstr((usch *)"#pragma ");
+	do {
+		c = input();
+		if (!flslvl)
+			putch(c);	/* Do arg expansion instead? */
+	} while (c && c != '\n');
+	ifiles->lineno++;
+	prtline();
+	slow = 0;
+}
+
+static void
+badop(const char *op)
+{
+	error("invalid operator in preprocessor expression: %s", op);
+}
+
+int
+cinput()
+{
+	return input();
+}
Index: uspace/app/pcc/cc/cpp/tests/res1
===================================================================
--- uspace/app/pcc/cc/cpp/tests/res1	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/res1	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,8 @@
+
+# 1 "<stdin>"
+
+
+
+
+char p[] = "x ## y";	 
+			 
Index: uspace/app/pcc/cc/cpp/tests/res10
===================================================================
--- uspace/app/pcc/cc/cpp/tests/res10	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/res10	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,16 @@
+
+# 1 "<stdin>"
+
+
+
+
+
+int midiopen(int); 
+
+
+
+
+
+
+
+foo_optarg
Index: uspace/app/pcc/cc/cpp/tests/res11
===================================================================
--- uspace/app/pcc/cc/cpp/tests/res11	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/res11	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,22 @@
+
+# 1 "<stdin>"
+
+
+
+
+
+a
+a b
+a b c
+a b c d 
+
+
+
+
+
+
+__attribute__((__noreturn__))
+
+
+1  2
+
Index: uspace/app/pcc/cc/cpp/tests/res12
===================================================================
--- uspace/app/pcc/cc/cpp/tests/res12	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/res12	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,21 @@
+
+# 1 "<stdin>"
+
+
+
+
+
+2 2 2  2 2;
+
+
+
+
+
+
+
+
+
+
+
+
+(0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0,
Index: uspace/app/pcc/cc/cpp/tests/res13
===================================================================
--- uspace/app/pcc/cc/cpp/tests/res13	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/res13	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,13 @@
+
+# 1 "<stdin>"
+
+
+
+
+long
+
+
+
+
+
+
Index: uspace/app/pcc/cc/cpp/tests/res2
===================================================================
--- uspace/app/pcc/cc/cpp/tests/res2	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/res2	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,27 @@
+
+# 1 "<stdin>"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
+f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & 
+f(2 * (0,1))^m(0,1);
+int i[] = { 1, 23, 4, 5,  };
+char c[2][6] = { "hello", "" };
+
+
+
+
+
+ 
Index: uspace/app/pcc/cc/cpp/tests/res3
===================================================================
--- uspace/app/pcc/cc/cpp/tests/res3	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/res3	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,16 @@
+
+# 1 "<stdin>"
+
+
+
+
+
+
+
+
+printf("x" "1" "= %d, x" "2" "= %s", 	x1, x2);
+fputs(
+"strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s);
+\#include "vers2.h"
+"hello";
+"hello" ", world"
Index: uspace/app/pcc/cc/cpp/tests/res4
===================================================================
--- uspace/app/pcc/cc/cpp/tests/res4	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/res4	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,6 @@
+
+# 1 "<stdin>"
+
+
+
+(1)
Index: uspace/app/pcc/cc/cpp/tests/res5
===================================================================
--- uspace/app/pcc/cc/cpp/tests/res5	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/res5	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,5 @@
+
+# 1 "<stdin>"
+
+int j[] = { 123, 45, 67, 89,
+	10, 11, 12,  };
Index: uspace/app/pcc/cc/cpp/tests/res6
===================================================================
--- uspace/app/pcc/cc/cpp/tests/res6	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/res6	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,5 @@
+
+# 1 "<stdin>"
+
+
+foo
Index: uspace/app/pcc/cc/cpp/tests/res7
===================================================================
--- uspace/app/pcc/cc/cpp/tests/res7	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/res7	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,6 @@
+
+# 1 "<stdin>"
+
+
+a
+YES
Index: uspace/app/pcc/cc/cpp/tests/res8
===================================================================
--- uspace/app/pcc/cc/cpp/tests/res8	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/res8	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,9 @@
+
+# 1 "<stdin>"
+ 
+
+
+
+ 
+(hej.s_s.s_pos)
+
Index: uspace/app/pcc/cc/cpp/tests/res9
===================================================================
--- uspace/app/pcc/cc/cpp/tests/res9	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/res9	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,6 @@
+
+# 1 "<stdin>"
+
+
+
+ao
Index: uspace/app/pcc/cc/cpp/tests/test1
===================================================================
--- uspace/app/pcc/cc/cpp/tests/test1	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/test1	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,6 @@
+#define hash_hash # ## #
+#define mkstr(a) # a
+#define in_between(a) mkstr(a)
+#define join(c, d) in_between(c hash_hash d)
+char p[] = join(x, y);	// equivalent to
+			// char p[] = "x ## y";
Index: uspace/app/pcc/cc/cpp/tests/test10
===================================================================
--- uspace/app/pcc/cc/cpp/tests/test10	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/test10	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,14 @@
+#define __CONCAT(x,y) x ## y
+#define dev_type_open(n) int n(int)
+#define dev_decl(n,t) __CONCAT(dev_type_,t)(__CONCAT(n,t))
+#define cdev_decl(n) dev_decl(n,open)
+
+cdev_decl(midi); 
+
+# define __GETOPT_PREFIX foo_
+# define __GETOPT_CONCAT(x, y) x ## y
+# define __GETOPT_XCONCAT(x, y) __GETOPT_CONCAT (x, y)
+# define __GETOPT_ID(y) __GETOPT_XCONCAT (__GETOPT_PREFIX, y)
+# define optarg __GETOPT_ID (optarg)
+
+optarg
Index: uspace/app/pcc/cc/cpp/tests/test11
===================================================================
--- uspace/app/pcc/cc/cpp/tests/test11	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/test11	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,20 @@
+#define D1(s, ...) s
+#define D2(s, ...) s D1(__VA_ARGS__)
+#define D3(s, ...) s D2(__VA_ARGS__)
+#define D4(s, ...) s D3(__VA_ARGS__)
+
+D1(a)
+D2(a, b)
+D3(a, b, c)
+D4(a, b, c, d) 
+
+
+#define __sun_attr___noreturn__ __attribute__((__noreturn__))
+#define ___sun_attr_inner(__a) __sun_attr_##__a
+#define __sun_attr__(__a) ___sun_attr_inner __a
+#define __NORETURN __sun_attr__((__noreturn__))
+__NORETURN
+#define X(...)
+#define Y(...)  1 __VA_ARGS__ 2
+Y(X X() ())
+
Index: uspace/app/pcc/cc/cpp/tests/test12
===================================================================
--- uspace/app/pcc/cc/cpp/tests/test12	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/test12	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,19 @@
+#define y 2
+#define fe(p)       sfe(p) p
+#define sfe(p)    p
+#define Y fe(y) y  fe(y)
+
+Y;
+
+#    define S2B_QMIN 0
+#  define S2B_CMIN (S2B_QMIN + 8)
+#define S2B_1(i)        i,
+#define S2B_2(i)        S2B_1(i) S2B_1(i)
+#define S2B_4(i)        S2B_2(i) S2B_2(i)
+#define S2B_8(i)        S2B_4(i) S2B_4(i)
+#define S2B_16(i)       S2B_8(i) S2B_8(i)
+#define S2B_32(i)       S2B_16(i) S2B_16(i)
+#define S2B_64(i)       S2B_32(i) S2B_32(i)
+#define S2B_128(i)      S2B_64(i) S2B_64(i)
+#define S2B_256(i)      S2B_128(i) S2B_128(i)
+S2B_256(S2B_CMIN + 0)
Index: uspace/app/pcc/cc/cpp/tests/test13
===================================================================
--- uspace/app/pcc/cc/cpp/tests/test13	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/test13	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,11 @@
+
+#define UL long, foo
+#define D(I,F) I
+#define E(I) D(I)
+E(UL)
+
+#define FOO 1
+
+#if (FOO == 1)
+
+#endif /* FOO */ 
Index: uspace/app/pcc/cc/cpp/tests/test2
===================================================================
--- uspace/app/pcc/cc/cpp/tests/test2	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/test2	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,25 @@
+#define x 3
+#define f(a) f(x * (a))
+#undef x
+#define x 2
+#define g f
+#define z z[0]
+#define h g(~
+#define m(a) a(w)
+#define w 0,1
+#define t(a) a
+#define p() int
+#define q(x) x
+#define r(x,y) x ## y
+#define str(x) # x
+f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
+g(x+(3,4)-w) | h 5) & m
+(f)^m(m);
+p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };
+char c[2][6] = { str(hello), str() };
+/*
+ * f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
+ * f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
+ * int i[] = { 1, 23, 4, 5, };
+ * char c[2][6] = { "hello", "" };
+ */
Index: uspace/app/pcc/cc/cpp/tests/test3
===================================================================
--- uspace/app/pcc/cc/cpp/tests/test3	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/test3	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,15 @@
+#define str(s) # s
+#define xstr(s) str(s)
+#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \
+	x ## s, x ## t)
+#define INCFILE(n) vers ## n
+#define glue(a, b) a ## b
+#define xglue(a, b) glue(a, b)
+#define HIGHLOW "hello"
+#define LOW LOW ", world"
+debug(1, 2);
+fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away
+	== 0) str(: @\n), s);
+\#include xstr(INCFILE(2).h)
+glue(HIGH, LOW);
+xglue(HIGH, LOW)
Index: uspace/app/pcc/cc/cpp/tests/test4
===================================================================
--- uspace/app/pcc/cc/cpp/tests/test4	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/test4	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,4 @@
+#define foobar 1
+#define C(x,y) x##y
+#define D(x) (C(x,bar))
+D(foo)
Index: uspace/app/pcc/cc/cpp/tests/test5
===================================================================
--- uspace/app/pcc/cc/cpp/tests/test5	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/test5	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,3 @@
+#define t(x,y,z) x ## y ## z
+int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,),
+	t(10,,), t(,11,), t(,,12), t(,,) };
Index: uspace/app/pcc/cc/cpp/tests/test6
===================================================================
--- uspace/app/pcc/cc/cpp/tests/test6	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/test6	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,5 @@
+#define X(a,b, \
+	c,d) \
+	foo
+
+X(1,2,3,4)
Index: uspace/app/pcc/cc/cpp/tests/test7
===================================================================
--- uspace/app/pcc/cc/cpp/tests/test7	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/test7	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,4 @@
+#define a() YES
+#define b() a
+b()
+b()()
Index: uspace/app/pcc/cc/cpp/tests/test8
===================================================================
--- uspace/app/pcc/cc/cpp/tests/test8	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/test8	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,7 @@
+// test macro expansion in arguments
+#define s_pos              s_s.s_pos
+#define foo(x) (x)
+
+//hej.s_pos
+foo(hej.s_pos)
+
Index: uspace/app/pcc/cc/cpp/tests/test9
===================================================================
--- uspace/app/pcc/cc/cpp/tests/test9	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/tests/test9	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,4 @@
+#define C(a,b,c) a##b##c
+#define N(x,y) C(x,_,y)
+#define A_O ao
+N(A,O)
Index: uspace/app/pcc/cc/cpp/token.c
===================================================================
--- uspace/app/pcc/cc/cpp/token.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/cc/cpp/token.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1319 @@
+/*	$Id: token.c,v 1.48.2.2 2011/03/12 17:08:26 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004,2009 Anders Magnusson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 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.
+ */
+
+/*
+ * Tokenizer for the C preprocessor.
+ * There are three main routines:
+ *	- fastscan() loops over the input stream searching for magic
+ *		characters that may require actions.
+ *	- sloscan() tokenize the input stream and returns tokens.
+ *		It may recurse into itself during expansion.
+ *	- yylex() returns something from the input stream that 
+ *		is suitable for yacc.
+ *
+ *	Other functions of common use:
+ *	- inpch() returns a raw character from the current input stream.
+ *	- inch() is like inpch but \\n and trigraphs are expanded.
+ *	- unch() pushes back a character to the input stream.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
+
+#include "compat.h"
+#include "cpp.h"
+#include "y.tab.h"
+
+static void cvtdig(int rad);
+static int charcon(usch *);
+static void elsestmt(void);
+static void ifdefstmt(void);
+static void ifndefstmt(void);
+static void endifstmt(void);
+static void ifstmt(void);
+static void cpperror(void);
+static void pragmastmt(void);
+static void undefstmt(void);
+static void cppwarning(void);
+static void elifstmt(void);
+static void badop(const char *);
+static int chktg(void);
+static void ppdir(void);
+void  include(void);
+void  include_next(void);
+void  define(void);
+static int inpch(void);
+
+extern int yyget_lineno (void);
+extern void yyset_lineno (int);
+
+static int inch(void);
+
+int inif;
+extern int dflag;
+
+#define	PUTCH(ch) if (!flslvl) putch(ch)
+/* protection against recursion in #include */
+#define MAX_INCLEVEL	100
+static int inclevel;
+
+/* get next character unaltered */
+#define	NXTCH() (ifiles->curptr < ifiles->maxread ? *ifiles->curptr++ : inpch())
+
+usch yytext[CPPBUF];
+
+char spechr[256] = {
+	0,	0,	0,	0,	C_SPEC,	C_SPEC,	0,	0,
+	0,	C_WSNL,	C_SPEC|C_WSNL,	0,
+	0,	C_WSNL,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+	0,	0,	0,	0,	0,	0,	0,	0,
+
+	C_WSNL,	C_2,	C_SPEC,	0,	0,	0,	C_2,	C_SPEC,
+	0,	0,	0,	C_2,	0,	C_2,	0,	C_SPEC|C_2,
+	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,
+	C_I,	C_I,	0,	0,	C_2,	C_2,	C_2,	C_SPEC,
+
+	0,	C_I,	C_I,	C_I,	C_I,	C_I|C_EP, C_I,	C_I,
+	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,
+	C_I|C_EP, C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,
+	C_I,	C_I,	C_I,	0,	C_I,	0,	0,	C_I,
+
+	0,	C_I,	C_I,	C_I,	C_I,	C_I|C_EP, C_I,	C_I,
+	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,
+	C_I|C_EP, C_I,	C_I,	C_I,	C_I,	C_I,	C_I,	C_I,
+	C_I,	C_I,	C_I,	0,	C_2,	0,	0,	0,
+
+};
+
+/*
+ * No-replacement array.  If a macro is found and exists in this array
+ * then no replacement shall occur.  This is a stack.
+ */
+struct symtab *norep[RECMAX];	/* Symbol table index table */
+int norepptr = 1;			/* Top of index table */
+unsigned short bptr[RECMAX];	/* currently active noexpand macro stack */
+int bidx;			/* Top of bptr stack */
+
+static void
+unch(int c)
+{
+		
+	--ifiles->curptr;
+	if (ifiles->curptr < ifiles->bbuf)
+		error("pushback buffer full");
+	*ifiles->curptr = (usch)c;
+}
+
+static int
+eatcmnt(void)
+{
+	int ch;
+
+	if (Cflag) { PUTCH('/'); PUTCH('*'); }
+	for (;;) {
+		ch = inch();
+		if (ch == '\n') {
+			ifiles->lineno++;
+			PUTCH('\n');
+		}
+		if (ch == -1)
+			return -1;
+		if (ch == '*') {
+			ch = inch();
+			if (ch == '/') {
+				if (Cflag) {
+					PUTCH('*');
+					PUTCH('/');
+				} else
+					PUTCH(' ');
+				break;
+			}
+			unch(ch);
+			ch = '*';
+		}
+		if (Cflag) PUTCH(ch);
+	}
+	return 0;
+}
+
+/*
+ * Scan quickly the input file searching for:
+ *	- '#' directives
+ *	- keywords (if not flslvl)
+ *	- comments
+ *
+ *	Handle strings, numbers and trigraphs with care.
+ *	Only data from pp files are scanned here, never any rescans.
+ *	TODO: Only print out strings before calling other functions.
+ */
+static void
+fastscan(void)
+{
+	struct symtab *nl;
+	int ch, i, ccnt;
+	usch *cp;
+
+	goto run;
+	for (;;) {
+		ch = NXTCH();
+xloop:		if (ch == -1)
+			return;
+		if (dflag>1)
+			printf("fastscan ch %d (%c)\n", ch, ch > 31 ? ch : '@');
+		if ((spechr[ch] & C_SPEC) == 0) {
+			PUTCH(ch);
+			continue;
+		}
+		switch (ch) {
+		case EBLOCK:
+		case WARN:
+		case CONC:
+			error("bad char passed");
+			break;
+
+		case '/': /* Comments */
+			if ((ch = inch()) == '/') {
+cppcmt:				if (Cflag) { PUTCH(ch); } else { PUTCH(' '); }
+				do {
+					if (Cflag) PUTCH(ch);
+					ch = inch();
+				} while (ch != -1 && ch != '\n');
+				goto xloop;
+			} else if (ch == '*') {
+				if (eatcmnt())
+					return;
+			} else {
+				PUTCH('/');
+				goto xloop;
+			}
+			break;
+
+		case '?':  /* trigraphs */
+			if ((ch = chktg()))
+				goto xloop;
+			PUTCH('?');
+			break;
+
+		case '\\':
+			if ((ch = NXTCH()) == '\n') {
+				ifiles->lineno++;
+				continue;
+			} else {
+				PUTCH('\\');
+			}
+			goto xloop;
+
+		case '\n': /* newlines, for pp directives */
+run2:			ifiles->lineno++;
+			do {
+				PUTCH(ch);
+run:				ch = NXTCH();
+				if (ch == '/') {
+					ch = NXTCH();
+					if (ch == '/')
+						goto cppcmt;
+					if (ch == '*') {
+						if (eatcmnt())
+							return;
+						goto run;
+					} 
+					unch(ch);
+					ch = '/';
+				}
+			} while (ch == ' ' || ch == '\t');
+			if (ch == '\\') {
+				ch = NXTCH();
+				if (ch == '\n')
+					goto run2;
+				unch(ch);
+				ch = '\\';
+			}
+			if (ch == '#') {
+				ppdir();
+				continue;
+			} else if (ch == '%') {
+				ch = NXTCH();
+				if (ch == ':') {
+					ppdir();
+					continue;
+				} else {
+					unch(ch);
+					ch = '%';
+				}
+			}
+			goto xloop;
+
+		case '\"': /* strings */
+str:			PUTCH(ch);
+			while ((ch = inch()) != '\"') {
+					PUTCH(ch);
+				if (ch == '\\') {
+					ch = inch();
+					PUTCH(ch);
+				}
+				if (ch < 0)
+					return;
+			}
+			PUTCH(ch);
+			break;
+
+		case '.':  /* for pp-number */
+			PUTCH(ch);
+			ch = NXTCH();
+			if (ch < '0' || ch > '9')
+				goto xloop;
+			/* FALLTHROUGH */
+		case '0': case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+			do {
+				PUTCH(ch);
+nxt:				ch = NXTCH();
+				if (ch == '\\') {
+					ch = NXTCH();
+					if (ch == '\n') {
+						goto nxt;
+					} else {
+						unch(ch);
+						ch = '\\';
+					}
+				}
+				if (spechr[ch] & C_EP) {
+					PUTCH(ch);
+					ch = NXTCH();
+					if (ch == '-' || ch == '+')
+						continue;
+				}
+			} while ((spechr[ch] & C_ID) || (ch == '.'));
+			goto xloop;
+
+		case '\'': /* character literal */
+con:			PUTCH(ch);
+			if (tflag)
+				continue; /* character constants ignored */
+			while ((ch = NXTCH()) != '\'') {
+				PUTCH(ch);
+				if (ch == '\\') {
+					ch = NXTCH();
+					PUTCH(ch);
+				} else if (ch < 0)
+					return;
+				else if (ch == '\n')
+					goto xloop;
+			}
+			PUTCH(ch);
+			break;
+
+		case 'L':
+			ch = NXTCH();
+			if (ch == '\"') {
+				PUTCH('L');
+				goto str;
+			}
+			if (ch == '\'') {
+				PUTCH('L');
+				goto con;
+			}
+			unch(ch);
+			ch = 'L';
+			/* FALLTHROUGH */
+		default:
+			if ((spechr[ch] & C_ID) == 0)
+				error("fastscan");
+			if (flslvl) {
+				while (spechr[ch] & C_ID)
+					ch = NXTCH();
+				goto xloop;
+			}
+			i = ccnt = 0;
+			do {
+				yytext[i++] = (usch)ch;
+				ch = NXTCH();
+				if (ch == '\\') {
+					ch = NXTCH();
+					if (ch != '\n') {
+						unch('\n');
+						ch = '\\';
+					} else {
+						ifiles->lineno++;
+						ch = NXTCH();
+					}
+				}
+				if (ch < 0)
+					return;
+			} while (spechr[ch] & C_ID);
+
+			yytext[i] = 0;
+			unch(ch);
+
+			cp = stringbuf;
+			if ((nl = lookup((usch *)yytext, FIND)) && kfind(nl)) {
+				putstr(stringbuf);
+			} else
+				putstr((usch *)yytext);
+			stringbuf = cp;
+
+			break;
+		}
+	}
+}
+
+int
+sloscan()
+{
+	int ch;
+	int yyp;
+
+zagain:
+	yyp = 0;
+ 	ch = inch();
+	yytext[yyp++] = (usch)ch;
+	switch (ch) {
+	case -1:
+		return 0;
+	case '\n':
+		/* sloscan() never passes \n, that's up to fastscan() */
+		unch(ch);
+		goto yyret;
+
+	case '\r': /* Ignore CR's */
+		yyp = 0;
+		break;
+
+	case '0': case '1': case '2': case '3': case '4': case '5': 
+	case '6': case '7': case '8': case '9':
+		/* readin a "pp-number" */
+ppnum:		for (;;) {
+			ch = inch();
+			if (spechr[ch] & C_EP) {
+				yytext[yyp++] = (usch)ch;
+				ch = inch();
+				if (ch == '-' || ch == '+') {
+					yytext[yyp++] = (usch)ch;
+				} else
+					unch(ch);
+				continue;
+			}
+			if ((spechr[ch] & C_ID) || ch == '.') {
+				yytext[yyp++] = (usch)ch;
+				continue;
+			} 
+			break;
+		}
+		unch(ch);
+		yytext[yyp] = 0;
+
+		return NUMBER;
+
+	case '\'':
+chlit:		
+		for (;;) {
+			if ((ch = inch()) == '\\') {
+				yytext[yyp++] = (usch)ch;
+				yytext[yyp++] = (usch)inch();
+				continue;
+			} else if (ch == '\n') {
+				/* not a constant */
+				while (yyp > 1)
+					unch(yytext[--yyp]);
+				ch = '\'';
+				goto any;
+			} else
+				yytext[yyp++] = (usch)ch;
+			if (ch == '\'')
+				break;
+		}
+		yytext[yyp] = 0;
+
+		return (NUMBER);
+
+	case ' ':
+	case '\t':
+		while ((ch = inch()) == ' ' || ch == '\t')
+			yytext[yyp++] = (usch)ch;
+		unch(ch);
+		yytext[yyp] = 0;
+		return(WSPACE);
+
+	case '/':
+		if ((ch = inch()) == '/') {
+			do {
+				yytext[yyp++] = (usch)ch;
+				ch = inch();
+			} while (ch && ch != '\n');
+			yytext[yyp] = 0;
+			unch(ch);
+			goto zagain;
+		} else if (ch == '*') {
+			int c, wrn;
+			extern int readmac;
+
+			if (Cflag && !flslvl && readmac) {
+				unch(ch);
+				yytext[yyp] = 0;
+				return CMNT;
+			}
+
+			wrn = 0;
+		more:	while ((c = inch()) && c != '*') {
+				if (c == '\n')
+					putch(c), ifiles->lineno++;
+				else if (c == EBLOCK) {
+					(void)inch();
+					(void)inch();
+				} else if (c == 1) /* WARN */
+					wrn = 1;
+			}
+			if (c == 0)
+				return 0;
+			if ((c = inch()) && c != '/') {
+				unch(c);
+				goto more;
+			}
+			if (c == 0)
+				return 0;
+			if (!tflag && !Cflag && !flslvl)
+				unch(' ');
+			if (wrn)
+				unch(1);
+			goto zagain;
+		}
+		unch(ch);
+		ch = '/';
+		goto any;
+
+	case '.':
+		ch = inch();
+		if (isdigit(ch)) {
+			yytext[yyp++] = (usch)ch;
+			goto ppnum;
+		} else {
+			unch(ch);
+			ch = '.';
+		}
+		goto any;
+
+	case '\"':
+		if (tflag)
+			goto any;
+	strng:
+		for (;;) {
+			if ((ch = inch()) == '\\') {
+				yytext[yyp++] = (usch)ch;
+				yytext[yyp++] = (usch)inch();
+				continue;
+			} else 
+				yytext[yyp++] = (usch)ch;
+			if (ch == '\"')
+				break;
+		}
+		yytext[yyp] = 0;
+		return(STRING);
+
+	case 'L':
+		if ((ch = inch()) == '\"' && !tflag) {
+			yytext[yyp++] = (usch)ch;
+			goto strng;
+		} else if (ch == '\'' && !tflag) {
+			yytext[yyp++] = (usch)ch;
+			goto chlit;
+		}
+		unch(ch);
+		/* FALLTHROUGH */
+
+	/* Yetch, all identifiers */
+	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 
+	case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': 
+	case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': 
+	case 's': case 't': case 'u': case 'v': case 'w': case 'x': 
+	case 'y': case 'z':
+	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 
+	case 'G': case 'H': case 'I': case 'J': case 'K':
+	case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': 
+	case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': 
+	case 'Y': case 'Z':
+	case '_': /* {L}({L}|{D})* */
+
+		/* Special hacks */
+		for (;;) { /* get chars */
+			ch = inch();
+			if (isalpha(ch) || isdigit(ch) || ch == '_') {
+				yytext[yyp++] = (usch)ch;
+			} else {
+				unch(ch);
+				break;
+			}
+		}
+		yytext[yyp] = 0; /* need already string */
+		/* end special hacks */
+
+		return IDENT;
+	default:
+	any:
+		yytext[yyp] = 0;
+		return yytext[0];
+
+	} /* endcase */
+	goto zagain;
+
+yyret:
+	yytext[yyp] = 0;
+	return ch;
+}
+
+int
+yylex()
+{
+	static int ifdef, noex;
+	struct symtab *nl;
+	int ch, c2;
+
+	while ((ch = sloscan()) == WSPACE)
+		;
+	if (ch < 128 && spechr[ch] & C_2)
+		c2 = inpch();
+	else
+		c2 = 0;
+
+#define	C2(a,b,c) case a: if (c2 == b) return c; break
+	switch (ch) {
+	C2('=', '=', EQ);
+	C2('!', '=', NE);
+	C2('|', '|', OROR);
+	C2('&', '&', ANDAND);
+	case '<':
+		if (c2 == '<') return LS;
+		if (c2 == '=') return LE;
+		break;
+	case '>':
+		if (c2 == '>') return RS;
+		if (c2 == '=') return GE;
+		break;
+	case '+':
+	case '-':
+		if (ch == c2)
+			badop("");
+		break;
+
+	case '/':
+		if (Cflag == 0 || c2 != '*')
+			break;
+		/* Found comment that need to be skipped */
+		for (;;) {
+			ch = inpch();
+		c1:	if (ch != '*')
+				continue;
+			if ((ch = inpch()) == '/')
+				break;
+			goto c1;
+		}
+		return yylex();
+
+	case NUMBER:
+		if (yytext[0] == '\'') {
+			yylval.node.op = NUMBER;
+			yylval.node.nd_val = charcon((usch *)yytext);
+		} else
+			cvtdig(yytext[0] != '0' ? 10 :
+			    yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8);
+		return NUMBER;
+
+	case IDENT:
+		if (strcmp((char *)yytext, "defined") == 0) {
+			ifdef = 1;
+			return DEFINED;
+		}
+		nl = lookup((usch *)yytext, FIND);
+		if (ifdef) {
+			yylval.node.nd_val = nl != NULL;
+			ifdef = 0;
+		} else if (nl && noex == 0) {
+			usch *och = stringbuf;
+			int i;
+
+			i = kfind(nl);
+			unch(WARN);
+			if (i)
+				unpstr(stringbuf);
+			else
+				unpstr(nl->namep);
+			stringbuf = och;
+			noex = 1;
+			return yylex();
+		} else {
+			yylval.node.nd_val = 0;
+		}
+		yylval.node.op = NUMBER;
+		return NUMBER;
+	case WARN:
+		noex = 0;
+		return yylex();
+	default:
+		return ch;
+	}
+	unch(c2);
+	return ch;
+}
+
+usch *yyp, yybuf[CPPBUF];
+
+int yywrap(void);
+
+static int
+inpch(void)
+{
+	int len;
+
+	if (ifiles->curptr < ifiles->maxread)
+		return *ifiles->curptr++;
+
+	if (ifiles->infil == -1)
+		return -1;
+	if ((len = read(ifiles->infil, ifiles->buffer, CPPBUF)) < 0)
+		error("read error on file %s", ifiles->orgfn);
+	if (len == 0)
+		return -1;
+	ifiles->curptr = ifiles->buffer;
+	ifiles->maxread = ifiles->buffer + len;
+	return inpch();
+}
+
+static int
+inch(void)
+{
+	int c;
+
+again:	switch (c = inpch()) {
+	case '\\': /* continued lines */
+msdos:		if ((c = inpch()) == '\n') {
+			ifiles->lineno++;
+			goto again;
+		} else if (c == '\r')
+			goto msdos;
+		unch(c);
+		return '\\';
+	case '?': /* trigraphs */
+		if ((c = chktg())) {
+			unch(c);
+			goto again;
+		}
+		return '?';
+	default:
+		return c;
+	}
+}
+
+/*
+ * Let the command-line args be faked defines at beginning of file.
+ */
+static void
+prinit(struct initar *it, struct includ *ic)
+{
+	const char *pre, *post;
+	char *a;
+
+	if (it->next)
+		prinit(it->next, ic);
+	pre = post = NULL; /* XXX gcc */
+	switch (it->type) {
+	case 'D':
+		pre = "#define ";
+		if ((a = strchr(it->str, '=')) != NULL) {
+			*a = ' ';
+			post = "\n";
+		} else
+			post = " 1\n";
+		break;
+	case 'U':
+		pre = "#undef ";
+		post = "\n";
+		break;
+	case 'i':
+		pre = "#include \"";
+		post = "\"\n";
+		break;
+	default:
+		error("prinit");
+	}
+	strlcat((char *)ic->buffer, pre, CPPBUF+1);
+	strlcat((char *)ic->buffer, it->str, CPPBUF+1);
+	if (strlcat((char *)ic->buffer, post, CPPBUF+1) >= CPPBUF+1)
+		error("line exceeds buffer size");
+
+	ic->lineno--;
+	while (*ic->maxread)
+		ic->maxread++;
+}
+
+/*
+ * A new file included.
+ * If ifiles == NULL, this is the first file and already opened (stdin).
+ * Return 0 on success, -1 if file to be included is not found.
+ */
+int
+pushfile(const usch *file, const usch *fn, int idx, void *incs)
+{
+	extern struct initar *initar;
+	struct includ ibuf;
+	struct includ *ic;
+	int otrulvl;
+
+	ic = &ibuf;
+	ic->next = ifiles;
+
+	if (file != NULL) {
+		if ((ic->infil = open((const char *)file, O_RDONLY)) < 0)
+			return -1;
+		ic->orgfn = ic->fname = file;
+		if (++inclevel > MAX_INCLEVEL)
+			error("Limit for nested includes exceeded");
+	} else {
+		error("Reading from stdin is disabled on HelenOS.");
+		ic->infil = fileno(stdin);
+		ic->orgfn = ic->fname = (const usch *)"<stdin>";
+	}
+#ifndef BUF_STACK
+	ic->bbuf = malloc(BBUFSZ);
+#endif
+	ic->buffer = ic->bbuf+NAMEMAX;
+	ic->curptr = ic->buffer;
+	ifiles = ic;
+	ic->lineno = 1;
+	ic->maxread = ic->curptr;
+	ic->idx = idx;
+	ic->incs = incs;
+	ic->fn = fn;
+	prtline();
+	if (initar) {
+		int oin = ic->infil;
+		ic->infil = -1;
+		*ic->maxread = 0;
+		prinit(initar, ic);
+		initar = NULL;
+		if (dMflag)
+			write(ofd, ic->buffer, strlen((char *)ic->buffer));
+		fastscan();
+		prtline();
+		ic->infil = oin;
+	}
+
+	otrulvl = trulvl;
+
+	fastscan();
+
+	if (otrulvl != trulvl || flslvl)
+		error("unterminated conditional");
+
+#ifndef BUF_STACK
+	free(ic->bbuf);
+#endif
+	ifiles = ic->next;
+	close(ic->infil);
+	inclevel--;
+	return 0;
+}
+
+/*
+ * Print current position to output file.
+ */
+void
+prtline()
+{
+	usch *s, *os = stringbuf;
+
+	if (Mflag) {
+		if (dMflag)
+			return; /* no output */
+		if (ifiles->lineno == 1) {
+			s = sheap("%s: %s\n", Mfile, ifiles->fname);
+			write(ofd, s, strlen((char *)s));
+		}
+	} else if (!Pflag)
+		putstr(sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname));
+	stringbuf = os;
+}
+
+void
+cunput(int c)
+{
+#ifdef CPP_DEBUG
+//	extern int dflag;
+//	if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c);
+#endif
+#if 0
+if (c == 10) {
+	printf("c == 10!!!\n");
+}
+#endif
+	unch(c);
+}
+
+int yywrap(void) { return 1; }
+
+static int
+dig2num(int c)
+{
+	if (c >= 'a')
+		c = c - 'a' + 10;
+	else if (c >= 'A')
+		c = c - 'A' + 10;
+	else
+		c = c - '0';
+	return c;
+}
+
+/*
+ * Convert string numbers to unsigned long long and check overflow.
+ */
+static void
+cvtdig(int rad)
+{
+	unsigned long long rv = 0;
+	unsigned long long rv2 = 0;
+	usch *y = yytext;
+	int c;
+
+	c = *y++;
+	if (rad == 16)
+		y++;
+	while (isxdigit(c)) {
+		rv = rv * rad + dig2num(c);
+		/* check overflow */
+		if (rv / rad < rv2)
+			error("Constant \"%s\" is out of range", yytext);
+		rv2 = rv;
+		c = *y++;
+	}
+	y--;
+	while (*y == 'l' || *y == 'L')
+		y++;
+	yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER;
+	yylval.node.nd_uval = rv;
+	if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0)
+		yylval.node.op = UNUMBER;
+	if (yylval.node.op == NUMBER && yylval.node.nd_val < 0)
+		/* too large for signed, see 6.4.4.1 */
+		error("Constant \"%s\" is out of range", yytext);
+}
+
+static int
+charcon(usch *p)
+{
+	int val, c;
+
+	p++; /* skip first ' */
+	val = 0;
+	if (*p++ == '\\') {
+		switch (*p++) {
+		case 'a': val = '\a'; break;
+		case 'b': val = '\b'; break;
+		case 'f': val = '\f'; break;
+		case 'n': val = '\n'; break;
+		case 'r': val = '\r'; break;
+		case 't': val = '\t'; break;
+		case 'v': val = '\v'; break;
+		case '\"': val = '\"'; break;
+		case '\'': val = '\''; break;
+		case '\\': val = '\\'; break;
+		case 'x':
+			while (isxdigit(c = *p)) {
+				val = val * 16 + dig2num(c);
+				p++;
+			}
+			break;
+		case '0': case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7':
+			p--;
+			while (isdigit(c = *p)) {
+				val = val * 8 + (c - '0');
+				p++;
+			}
+			break;
+		default: val = p[-1];
+		}
+
+	} else
+		val = p[-1];
+	return val;
+}
+
+static void
+chknl(int ignore)
+{
+	int t;
+
+	while ((t = sloscan()) == WSPACE)
+		;
+	if (t != '\n') {
+		if (ignore) {
+			warning("newline expected, got \"%s\"", yytext);
+			/* ignore rest of line */
+			while ((t = sloscan()) && t != '\n')
+				;
+		}
+		else
+			error("newline expected, got \"%s\"", yytext);
+	}
+}
+
+static void
+elsestmt(void)
+{
+	if (flslvl) {
+		if (elflvl > trulvl)
+			;
+		else if (--flslvl!=0) {
+			flslvl++;
+		} else {
+			trulvl++;
+			prtline();
+		}
+	} else if (trulvl) {
+		flslvl++;
+		trulvl--;
+	} else
+		error("If-less else");
+	if (elslvl==trulvl+flslvl)
+		error("Too many else");
+	elslvl=trulvl+flslvl;
+	chknl(1);
+}
+
+static void
+skpln(void)
+{
+	/* just ignore the rest of the line */
+	while (inch() != '\n')
+		;
+	unch('\n');
+	flslvl++;
+}
+
+static void
+ifdefstmt(void)		 
+{ 
+	int t;
+
+	if (flslvl) {
+		skpln();
+		return;
+	}
+	do
+		t = sloscan();
+	while (t == WSPACE);
+	if (t != IDENT)
+		error("bad ifdef");
+	if (lookup((usch *)yytext, FIND) == 0) {
+		putch('\n');
+		flslvl++;
+	} else
+		trulvl++;
+	chknl(0);
+}
+
+static void
+ifndefstmt(void)	  
+{ 
+	int t;
+
+	if (flslvl) {
+		skpln();
+		return;
+	}
+	do
+		t = sloscan();
+	while (t == WSPACE);
+	if (t != IDENT)
+		error("bad ifndef");
+	if (lookup((usch *)yytext, FIND) != 0) {
+		putch('\n');
+		flslvl++;
+	} else
+		trulvl++;
+	chknl(0);
+}
+
+static void
+endifstmt(void)		 
+{
+	if (flslvl) {
+		flslvl--;
+		if (flslvl == 0) {
+			putch('\n');
+			prtline();
+		}
+	} else if (trulvl)
+		trulvl--;
+	else
+		error("If-less endif");
+	if (flslvl == 0)
+		elflvl = 0;
+	elslvl = 0;
+	chknl(1);
+}
+
+static void
+ifstmt(void)
+{
+	if (flslvl == 0) {
+		if (yyparse() == 0) {
+			putch('\n');
+			++flslvl;
+		} else
+			++trulvl;
+	} else
+		++flslvl;
+}
+
+static void
+elifstmt(void)
+{
+	if (flslvl == 0)
+		elflvl = trulvl;
+	if (flslvl) {
+		if (elflvl > trulvl)
+			;
+		else if (--flslvl!=0)
+			++flslvl;
+		else {
+			if (yyparse()) {
+				++trulvl;
+				prtline();
+			} else {
+				putch('\n');
+				++flslvl;
+			}
+		}
+	} else if (trulvl) {
+		++flslvl;
+		--trulvl;
+	} else
+		error("If-less elif");
+}
+
+static usch *
+svinp(void)
+{
+	int c;
+	usch *cp = stringbuf;
+
+	while ((c = inch()) && c != '\n')
+		savch(c);
+	savch('\n');
+	savch(0);
+	return cp;
+}
+
+static void
+cpperror(void)
+{
+	usch *cp;
+	int c;
+
+	if (flslvl)
+		return;
+	c = sloscan();
+	if (c != WSPACE && c != '\n')
+		error("bad error");
+	cp = svinp();
+	if (flslvl)
+		stringbuf = cp;
+	else
+		error("%s", cp);
+}
+
+static void
+cppwarning(void)
+{
+	usch *cp;
+	int c;
+
+	if (flslvl)
+		return;
+	c = sloscan();
+	if (c != WSPACE && c != '\n')
+		error("bad warning");
+
+	/* svinp() add an unwanted \n */
+	cp = stringbuf;
+	while ((c = inch()) && c != '\n')
+		savch(c);
+	savch(0);
+
+	if (flslvl)
+		stringbuf = cp;
+	else
+		warning("#warning %s", cp);
+
+	unch('\n');
+}
+
+static void
+undefstmt(void)
+{
+	struct symtab *np;
+
+	if (sloscan() != WSPACE || sloscan() != IDENT)
+		error("bad undef");
+	if (flslvl == 0 && (np = lookup((usch *)yytext, FIND)))
+		np->value = 0;
+	chknl(0);
+}
+
+static void
+pragmastmt(void)
+{
+	int c;
+
+	if (sloscan() != WSPACE)
+		error("bad pragma");
+	if (!flslvl)
+		putstr((const usch *)"\n#pragma ");
+	do {
+		c = inch();
+		if (!flslvl)
+			putch(c);	/* Do arg expansion instead? */
+	} while (c && c != '\n');
+	if (c == '\n')
+		unch(c);
+	prtline();
+}
+
+static void
+badop(const char *op)
+{
+	error("invalid operator in preprocessor expression: %s", op);
+}
+
+int
+cinput()
+{
+	return inch();
+}
+
+/*
+ * Check for (and convert) trigraphs.
+ */
+int
+chktg()
+{
+	int c;
+
+	if ((c = inpch()) != '?') {
+		unch(c);
+		return 0;
+	}
+	switch (c = inpch()) {
+	case '=': c = '#'; break;
+	case '(': c = '['; break;
+	case ')': c = ']'; break;
+	case '<': c = '{'; break;
+	case '>': c = '}'; break;
+	case '/': c = '\\'; break;
+	case '\'': c = '^'; break;
+	case '!': c = '|'; break;
+	case '-': c = '~'; break;
+	default:
+		unch(c);
+		unch('?');
+		c = 0;
+	}
+	return c;
+}
+
+static struct {
+	const char *name;
+	void (*fun)(void);
+} ppd[] = {
+	{ "ifndef", ifndefstmt },
+	{ "ifdef", ifdefstmt },
+	{ "if", ifstmt },
+	{ "include", include },
+	{ "else", elsestmt },
+	{ "endif", endifstmt },
+	{ "error", cpperror },
+	{ "warning", cppwarning },
+	{ "define", define },
+	{ "undef", undefstmt },
+	{ "line", line },
+	{ "pragma", pragmastmt },
+	{ "elif", elifstmt },
+#ifdef GCC_COMPAT
+	{ "include_next", include_next },
+#endif
+};
+
+/*
+ * Handle a preprocessor directive.
+ */
+void
+ppdir(void)
+{
+	char bp[20];
+	int ch, i;
+
+	while ((ch = inch()) == ' ' || ch == '\t')
+		;
+	if (ch == '\n') { /* empty directive */
+		unch(ch);
+		return;
+	}
+	if (ch < 'a' || ch > 'z')
+		goto out; /* something else, ignore */
+	i = 0;
+	do {
+		bp[i++] = (usch)ch;
+		if (i == sizeof(bp)-1)
+			goto out; /* too long */
+		ch = inch();
+	} while ((ch >= 'a' && ch <= 'z') || (ch == '_'));
+	unch(ch);
+	bp[i++] = 0;
+
+	/* got keyword */
+#define	SZ (int)(sizeof(ppd)/sizeof(ppd[0]))
+	for (i = 0; i < SZ; i++)
+		if (bp[0] == ppd[i].name[0] && strcmp(bp, ppd[i].name) == 0)
+			break;
+	if (i == SZ)
+		goto out;
+
+	/* Found matching keyword */
+	(*ppd[i].fun)();
+	return;
+
+out:	while ((ch = inch()) != '\n' && ch != -1)
+		;
+	unch('\n');
+}
Index: uspace/app/pcc/config.guess
===================================================================
--- uspace/app/pcc/config.guess	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/config.guess	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1516 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+#   Inc.
+
+timestamp='2007-07-22'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep __ELF__ >/dev/null
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[45])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep __LP64__ >/dev/null
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	case ${UNAME_MACHINE} in
+	    pc98)
+		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:windows32*:*)
+    	# uname -m includes "-pc" on this system.
+    	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:[3456]*)
+    	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    EM64T | authenticamd)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    arm*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo crisv32-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+    	echo frv-unknown-linux-gnu
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips
+	#undef mipsel
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mipsel
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips64
+	#undef mips64el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mips64el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips64
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo or32-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit ;;
+    xtensa:Linux:*:*)
+    	echo xtensa-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	# Set LC_ALL=C to ensure ld outputs messages in English.
+	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	  a.out-i386-linux)
+		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+		exit ;;
+	  coff-i386)
+		echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+		exit ;;
+	  "")
+		# Either a pre-BFD a.out linker (linux-gnuoldld) or
+		# one that does not give us useful --help.
+		echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+		exit ;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#ifdef __ELF__
+	# ifdef __GLIBC__
+	#  if __GLIBC__ >= 2
+	LIBC=gnu
+	#  else
+	LIBC=gnulibc1
+	#  endif
+	# else
+	LIBC=gnulibc1
+	# endif
+	#else
+	#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+	LIBC=gnu
+	#else
+	LIBC=gnuaout
+	#endif
+	#endif
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^LIBC/{
+		s: ::g
+		p
+	    }'`"
+	test x"${LIBC}" != x && {
+		echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+		exit
+	}
+	test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+	;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+	echo i386-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	case $UNAME_PROCESSOR in
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+  http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
Index: uspace/app/pcc/config.h
===================================================================
--- uspace/app/pcc/config.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/config.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,182 @@
+
+// FIXME: find out which of them are actually true
+
+/* Using a.out ABI */
+//#undef AOUTABI
+
+/* Define path to alternate assembler */
+#define ASSEMBLER "/app/as"
+
+/* Using Classic 68k ABI */
+//#undef CLASSIC68K
+
+/* Using COFF ABI */
+//#undef COFFABI
+
+/* Define path to alternate compiler */
+//#undef COMPILER
+
+/* Using ECOFF ABI */
+//#undef ECOFFABI
+
+/* Using ELF ABI */
+#define ELFABI 1
+
+/* Define to 1 if you have the `basename' function. */
+//#define HAVE_BASENAME 1
+
+/* Define to 1 if printf supports C99 size specifiers */
+//#define HAVE_C99_FORMAT 1
+
+/* Define to 1 if your compiler supports C99 variadic macros */
+#define HAVE_CPP_VARARG_MACRO_GCC 1
+
+/* Define to 1 if you have the `ffs' function. */
+#define HAVE_FFS 1
+
+/* Define to 1 if you have the `getopt' function. */
+#define HAVE_GETOPT 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <libgen.h> header file. */
+//#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkstemp' function. */
+//#define HAVE_MKSTEMP 1
+
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+//#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+//#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strtold' function. */
+#define HAVE_STRTOLD 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+//#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vfork' function. */
+//#define HAVE_VFORK 1
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#define HAVE_VSNPRINTF 1
+
+/* Define if host is BIG endian */
+//#undef HOST_BIG_ENDIAN
+
+/* Define if host is LITTLE endian */
+#define HOST_LITTLE_ENDIAN
+// FIXME: check architecture
+
+/* lex is flex */
+#define ISFLEX 1
+
+/* Define alternate standard lib directory */
+#define LIBDIR "/lib/"
+
+/* Define path to alternate linker */
+#define LINKER "/app/ld"
+
+/* Using Mach-O ABI */
+//#undef MACHOABI
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "<zarevucky.jiri@gmail.com>"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "pcc"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "pcc 1.0.0.RELEASE"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "pcc"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.0.0.RELEASE"
+
+/* Major version no */
+#define PCC_MAJOR 1
+
+/* Minor version no */
+#define PCC_MINOR 0
+
+/* Minor minor version no */
+#define PCC_MINORMINOR 0
+
+/* Using PE/COFF ABI */
+//#undef PECOFFABI
+
+/* Define path to alternate preprocessor */
+#undef PREPROCESSOR
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define alternate standard include directory */
+#define STDINC "/inc/c"
+
+/* Define if target defaults to BIG endian */
+//#undef TARGET_BIG_ENDIAN
+
+/* Define if target defaults to LITTLE endian */
+#define TARGET_LITTLE_ENDIAN
+// FIXME: check architecture
+
+/* Target OS */
+#define TARGOS helenos
+
+/* Target OS version */
+#define TARGOSVER 0
+
+/* Enable thread-local storage (TLS). */
+// #undef TLS
+
+/* Version string */
+#define VERSSTR "pcc 1.0.0.RELEASE 20110221 for HelenOS"
+
+/* Size of wide character type */
+#define WCHAR_SIZE 4
+
+/* Type to use for wide characters */
+#define WCHAR_TYPE INT
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+//#define YYTEXT_POINTER 1
+
+#undef COMPILER
+
Index: uspace/app/pcc/config.h.in
===================================================================
--- uspace/app/pcc/config.h.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/config.h.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,176 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Using a.out ABI */
+#undef AOUTABI
+
+/* Define path to alternate assembler */
+#undef ASSEMBLER
+
+/* Using Classic 68k ABI */
+#undef CLASSIC68K
+
+/* Using COFF ABI */
+#undef COFFABI
+
+/* Define path to alternate compiler */
+#undef COMPILER
+
+/* Using ECOFF ABI */
+#undef ECOFFABI
+
+/* Using ELF ABI */
+#undef ELFABI
+
+/* Define to 1 if you have the `basename' function. */
+#undef HAVE_BASENAME
+
+/* Define to 1 if printf supports C99 size specifiers */
+#undef HAVE_C99_FORMAT
+
+/* Define to 1 if your compiler supports C99 variadic macros */
+#undef HAVE_CPP_VARARG_MACRO_GCC
+
+/* Define to 1 if you have the `ffs' function. */
+#undef HAVE_FFS
+
+/* Define to 1 if you have the `getopt' function. */
+#undef HAVE_GETOPT
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#undef HAVE_LIBGEN_H
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mkstemp' function. */
+#undef HAVE_MKSTEMP
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strtold' function. */
+#undef HAVE_STRTOLD
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vfork' function. */
+#undef HAVE_VFORK
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Define if host is BIG endian */
+#undef HOST_BIG_ENDIAN
+
+/* Define if host is LITTLE endian */
+#undef HOST_LITTLE_ENDIAN
+
+/* lex is flex */
+#undef ISFLEX
+
+/* Define alternate standard lib directory */
+#undef LIBDIR
+
+/* Define path to alternate linker */
+#undef LINKER
+
+/* Using Mach-O ABI */
+#undef MACHOABI
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Major version no */
+#undef PCC_MAJOR
+
+/* Minor version no */
+#undef PCC_MINOR
+
+/* Minor minor version no */
+#undef PCC_MINORMINOR
+
+/* Using PE/COFF ABI */
+#undef PECOFFABI
+
+/* Define path to alternate preprocessor */
+#undef PREPROCESSOR
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define alternate standard include directory */
+#undef STDINC
+
+/* Define if target defaults to BIG endian */
+#undef TARGET_BIG_ENDIAN
+
+/* Define if target defaults to LITTLE endian */
+#undef TARGET_LITTLE_ENDIAN
+
+/* Target OS */
+#undef TARGOS
+
+/* Target OS version */
+#undef TARGOSVER
+
+/* Enable thread-local storage (TLS). */
+#undef TLS
+
+/* Version string */
+#undef VERSSTR
+
+/* Size of wide character type */
+#undef WCHAR_SIZE
+
+/* Type to use for wide characters */
+#undef WCHAR_TYPE
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#undef YYTEXT_POINTER
Index: uspace/app/pcc/config.sub
===================================================================
--- uspace/app/pcc/config.sub	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/config.sub	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1658 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2008-01-16'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray)
+		os=
+		basic_machine=$1
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64vr | mips64vrel \
+	| mips64orion | mips64orionel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| mt \
+	| msp430 \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu | strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+    	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tile*)
+		basic_machine=tile-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* | -midnightbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+        -os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+        -tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+        score-*)
+		os=-elf
+		;;
+        spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+        c4x-* | tic4x-*)
+        	os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+    	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
Index: uspace/app/pcc/configure
===================================================================
--- uspace/app/pcc/configure	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/configure	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,6240 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.61 for pcc 1.0.0.RELEASE.
+#
+# Report bugs to <<pcc-list@ludd.ltu.se>>.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+  if (eval ":") 2>/dev/null; then
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+
+  if test $as_have_required = yes && 	 (eval ":
+(as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=\$LINENO
+  as_lineno_2=\$LINENO
+  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+  :
+else
+  as_candidate_shells=
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  case $as_dir in
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+	   done;;
+       esac
+done
+IFS=$as_save_IFS
+
+
+      for as_shell in $as_candidate_shells $SHELL; do
+	 # Try only shells that exist, to save several forks.
+	 if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		{ ("$as_shell") 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+_ASEOF
+}; then
+  CONFIG_SHELL=$as_shell
+	       as_have_required=yes
+	       if { "$as_shell" 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+(as_func_return () {
+  (exit $1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+  break
+fi
+
+fi
+
+      done
+
+      if test "x$CONFIG_SHELL" != x; then
+  for as_var in BASH_ENV ENV
+        do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+        done
+        export CONFIG_SHELL
+        exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+    if test $as_have_required = no; then
+  echo This script requires a shell more modern than all the
+      echo shells that I found on your system.  Please install a
+      echo modern shell, or manually run the script under such a
+      echo shell if you do have one.
+      { (exit 1); exit 1; }
+fi
+
+
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+  echo No shell found that supports shell functions.
+  echo Please tell autoconf@gnu.org about your system,
+  echo including any error possibly output before this
+  echo message
+}
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s='ln -s'
+  # ... but there are two gotchas:
+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+  # In both cases, we have to default to `cp -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+	case $1 in
+        -*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+exec 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME='pcc'
+PACKAGE_TARNAME='pcc'
+PACKAGE_VERSION='1.0.0.RELEASE'
+PACKAGE_STRING='pcc 1.0.0.RELEASE'
+PACKAGE_BUGREPORT='<pcc-list@ludd.ltu.se>'
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL
+PATH_SEPARATOR
+PACKAGE_NAME
+PACKAGE_TARNAME
+PACKAGE_VERSION
+PACKAGE_STRING
+PACKAGE_BUGREPORT
+exec_prefix
+prefix
+program_transform_name
+bindir
+sbindir
+libexecdir
+datarootdir
+datadir
+sysconfdir
+sharedstatedir
+localstatedir
+includedir
+oldincludedir
+docdir
+infodir
+htmldir
+dvidir
+pdfdir
+psdir
+libdir
+localedir
+mandir
+DEFS
+ECHO_C
+ECHO_N
+ECHO_T
+LIBS
+build_alias
+host_alias
+target_alias
+build
+build_cpu
+build_vendor
+build_os
+host
+host_cpu
+host_vendor
+host_os
+target
+target_cpu
+target_vendor
+target_os
+BINPREFIX
+CC
+CFLAGS
+LDFLAGS
+CPPFLAGS
+ac_ct_CC
+EXEEXT
+OBJEXT
+CC_FOR_BUILD
+CPP
+GREP
+EGREP
+SET_MAKE
+INSTALL_PROGRAM
+INSTALL_SCRIPT
+INSTALL_DATA
+YACC
+YFLAGS
+strip
+LEX
+LEX_OUTPUT_ROOT
+LEXLIB
+targos
+targosver
+targmach
+ADD_CFLAGS
+ADD_CPPFLAGS
+LIBOBJS
+LTLIBOBJS'
+ac_subst_files=''
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+YACC
+YFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=*)	ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *)	ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+    eval enable_$ac_feature=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+    eval enable_$ac_feature=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+    eval with_$ac_package=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+    eval with_$ac_package=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute directory names.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; }
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  { echo "$as_me: error: Working directory cannot be determined" >&2
+   { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  { echo "$as_me: error: pwd does not report name of working directory" >&2
+   { (exit 1); exit 1; }; }
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$0" ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$0" : 'X\(//\)[^/]' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$0" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2
+   { (exit 1); exit 1; }; }
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures pcc 1.0.0.RELEASE to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+			  [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+			  [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR           user executables [EPREFIX/bin]
+  --sbindir=DIR          system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR       program executables [EPREFIX/libexec]
+  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR   modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR    modifiable single-machine data [PREFIX/var]
+  --libdir=DIR           object code libraries [EPREFIX/lib]
+  --includedir=DIR       C header files [PREFIX/include]
+  --oldincludedir=DIR    C header files for non-gcc [/usr/include]
+  --datarootdir=DIR      read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR          read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR          info documentation [DATAROOTDIR/info]
+  --localedir=DIR        locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR           man documentation [DATAROOTDIR/man]
+  --docdir=DIR           documentation root [DATAROOTDIR/doc/pcc]
+  --htmldir=DIR          html documentation [DOCDIR]
+  --dvidir=DIR           dvi documentation [DOCDIR]
+  --pdfdir=DIR           pdf documentation [DOCDIR]
+  --psdir=DIR            ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+  --target=TARGET   configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of pcc 1.0.0.RELEASE:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-tls            Enable Thread-local storage (TLS).
+  --disable-gcc-compat    Disable GCC compatibility
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-incdir=<path>    Specify the default include path.
+  --with-libdir=<path>    Specify the default library path.
+  --with-assembler=<path> Specify alternate assember.
+  --with-linker=<path>    Specify alternate linker.
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+  YACC        The `Yet Another C Compiler' implementation to use. Defaults to
+              the first program found out of: `bison -y', `byacc', `yacc'.
+  YFLAGS      The list of arguments that will be passed by default to $YACC.
+              This script will default YFLAGS to the empty string to avoid a
+              default value of `-d' given by some make applications.
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <<pcc-list@ludd.ltu.se>>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" || continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+pcc configure 1.0.0.RELEASE
+generated by GNU Autoconf 2.61
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by pcc $as_me 1.0.0.RELEASE, which was
+generated by GNU Autoconf 2.61.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  echo "PATH: $as_dir"
+done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      ac_configure_args="$ac_configure_args '$ac_arg'"
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      echo "$as_me: caught signal $ac_signal"
+    echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -n "$CONFIG_SITE"; then
+  set x "$CONFIG_SITE"
+elif test "x$prefix" != xNONE; then
+  set x "$prefix/share/config.site" "$prefix/etc/config.site"
+else
+  set x "$ac_default_prefix/share/config.site" \
+	"$ac_default_prefix/etc/config.site"
+fi
+shift
+for ac_site_file
+do
+  if test -r "$ac_site_file"; then
+    { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
+    { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	{ echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	{ echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5
+echo "$as_me:   former value:  $ac_old_val" >&2;}
+	{ echo "$as_me:$LINENO:   current value: $ac_new_val" >&5
+echo "$as_me:   current value: $ac_new_val" >&2;}
+	ac_cache_corrupted=:
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
+echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5
+echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;}
+   { (exit 1); exit 1; }; }
+
+{ echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6; }
+if test "${ac_cv_build+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+   { (exit 1); exit 1; }; }
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5
+echo "$as_me: error: invalid value of canonical build" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6; }
+if test "${ac_cv_host+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5
+echo "$as_me: error: invalid value of canonical host" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ echo "$as_me:$LINENO: checking target system type" >&5
+echo $ECHO_N "checking target system type... $ECHO_C" >&6; }
+if test "${ac_cv_target+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "x$target_alias" = x; then
+  ac_cv_target=$ac_cv_host
+else
+  ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
+    { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_target" >&5
+echo "${ECHO_T}$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical target" >&5
+echo "$as_me: error: invalid value of canonical target" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+  test "$program_prefix$program_suffix$program_transform_name" = \
+    NONENONEs,x,x, &&
+  program_prefix=${target_alias}-
+
+abi=unknown
+endian=little
+targosver=0
+tls=no
+gcccompat=yes
+# allowed: UNSIGNED (4-char u_int), INT (4-char int), SHORT (2-char u_short)
+wchar_type=INT
+
+case "$target_os" in
+
+    apple)
+	targos=apple
+	abi=classic68k
+	case "$target_cpu" in
+	    m68k) targmach=m68k endian=big ;;
+	esac
+	;;
+
+    bsd)
+	targos=bsd
+	abi=aout
+	targmach=pdp11
+	wchar_type=USHORT
+	;;
+
+    darwin*)
+	targos=darwin
+	abi=macho
+	case "$target_os" in
+	    *10.*) targosver=10 ;;
+	    *9.*) targosver=9 ;;
+	    *8.*) targosver=8 ;;
+	    *7.*) targosver=7 ;;
+	esac
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	    powerpc) targmach=powerpc endian=big ;;
+	    x86_64) targmach=amd64 ;;
+	esac
+        ;;
+
+    dragonfly*)
+	targos=dragonfly
+	abi=elf
+	tls=yes
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	    x86_64) targmach=amd64 ;;
+	esac
+	;;
+
+    freebsd*)
+	targos=freebsd
+	abi=elf
+	case "$target_os" in
+	    *9.*) targosver=9 ;;
+	    *8.*) targosver=8 ;;
+	    *7.*) targosver=7 ;;
+	    *6.*) targosver=6 ;;
+	    *5.*) targosver=5 ;;
+	    *4.*) targosver=4 ;;
+	esac
+	case "$target_cpu" in
+	    i386) targmach=i386 ;;
+	    x86_64) targmach=amd64 ;;
+	esac
+	;;
+
+    linux*)
+	targos=linux
+	abi=elf
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	    powerpc*) targmach=powerpc endian=big ;;
+	    x86_64) targmach=amd64 ;;
+	    mipseb) targmach=mips endian=big ;;
+	    mips*) targmach=mips ;;
+	esac
+	;;
+
+    midnightbsd*)
+	targos=midnightbsd
+	abi=elf
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	    sparc64) targmach=sparc64 endian=big ;;
+	esac
+	;;
+
+    mingw*)
+	targos=win32
+	abi=pecoff
+	wchar_type=USHORT
+	targmach=i386
+	altincdir="c:/mingw/include"
+	altlibdir="c:/mingw/lib"
+	;;
+
+    minix)
+	targos=minix
+	abi=coff
+	case "$target_cpu" in
+	    m68k) targmach=m68k endian=big ;;
+	esac
+	;;
+
+    mirbsd*)
+	targos=mirbsd
+	abi=elf
+	wchar_type=USHORT
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	esac
+	;;
+
+    netbsd*)
+	targos=netbsd
+	abi=elf
+	case "$target_os" in
+	    *5.*) targosver=5 ;;
+	    *4.*) targosver=4 ;;
+	    *3.*) targosver=3 ;;
+	    *2.*) targosver=2 ;;
+	    *1.*) targosver=1 ;;
+	esac
+	case "$target_cpu" in
+	    armeb) targmach=arm endian=big ;;
+	    arm*) targmach=arm ;;
+	    i?86) targmach=i386 ;;
+	    m68k*) targmach=m68k endian=big ;;
+	    mipseb) targmach=mips endian=big ;;
+	    mips*) targmach=mips ;;
+	    pdp10) targmach=pdp10 ;;
+	    powerpc) targmach=powerpc endian=big ;;
+	    sparc64) targmach=sparc64 endian=big ;;
+	    vax) targmach=vax ;;
+	    x86_64) targmach=amd64 ;;
+	esac
+	;;
+
+    nextstep*)
+	targos=nextstep
+	abi=macho
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	    sparc) targmach=sparc endian=big ;;
+	    hppa) targmach=hppa endian=big ;;
+	esac
+	;;
+
+    openbsd*)
+	targos=openbsd
+	abi=elf
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	    vax) targmach=vax ;;
+	    powerpc) targmach=powerpc endian=big ;;
+	    sparc64) targmach=sparc64 endian=big ;;
+	    x86_64) targmach=amd64 ;;
+	esac
+	;;
+
+    sunos*|solaris*)
+        targos=sunos
+        abi=elf
+        case "$target_cpu" in
+            i?86) targmach=i386 ;;
+            sparc*) targmach=sparc64 endian=big ;;
+        esac
+        ;;
+
+    windows*|pe*)
+	target_alias=i386-pe
+	targos=win32
+	abi=pecoff
+	wchar_type=USHORT
+	targmach=i386
+	;;
+
+    *)
+        targos="$target_os"
+	case "$target_cpu" in
+	    m16c) targmach=m16c ;;
+	    nova) targmach=nova ;;
+	esac
+	;;
+esac
+
+if test "X$targos" = X -o "X$targmach" = X ; then
+	{ { echo "$as_me:$LINENO: error: '$target' is not (yet) supported by pcc." >&5
+echo "$as_me: error: '$target' is not (yet) supported by pcc." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+case "$host_os" in
+
+    pe*)
+	# quick hack for cross-build to win32 host
+	if "$prefix" = NONE; then
+		prefix="c:/pcc"
+		assembler="yasm.exe -p gnu -f win32"
+		linker="link.exe /nologo"
+		ADD_CFLAGS=-DMSLINKER
+	fi
+	;;
+
+    sunos*|solaris*)
+	ADD_CPPFLAGS="$ADD_CPPFLAGS -D_XOPEN_SOURCE=600"
+	;;
+
+    darwin*)
+	if test "$targosver" -ge 10 ; then
+		targmach=amd64
+	fi
+	;;
+
+esac
+
+if test "X$endian" = "Xbig" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TARGET_BIG_ENDIAN 1
+_ACEOF
+
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define TARGET_LITTLE_ENDIAN 1
+_ACEOF
+
+fi
+
+case "$abi" in
+	elf*)
+cat >>confdefs.h <<\_ACEOF
+#define ELFABI
+_ACEOF
+ ;;
+	aout)
+cat >>confdefs.h <<\_ACEOF
+#define AOUTABI
+_ACEOF
+ ;;
+	macho)
+cat >>confdefs.h <<\_ACEOF
+#define MACHOABI
+_ACEOF
+ ;;
+	coff)
+cat >>confdefs.h <<\_ACEOF
+#define COFFABI
+_ACEOF
+ ;;
+	ecoff)
+cat >>confdefs.h <<\_ACEOF
+#define ECOFFABI
+_ACEOF
+ ;;
+	pecoff)
+cat >>confdefs.h <<\_ACEOF
+#define PECOFFABI
+_ACEOF
+ ;;
+	classic68k)
+cat >>confdefs.h <<\_ACEOF
+#define CLASSIC68K
+_ACEOF
+ ;;
+esac
+
+# Specify alternate assembler, linker, include and lib paths
+
+# Check whether --with-incdir was given.
+if test "${with_incdir+set}" = set; then
+  withval=$with_incdir; altincdir=$withval
+fi
+
+
+# Check whether --with-libdir was given.
+if test "${with_libdir+set}" = set; then
+  withval=$with_libdir; altlibdir=$withval
+fi
+
+
+# Check whether --with-assembler was given.
+if test "${with_assembler+set}" = set; then
+  withval=$with_assembler; assembler=$withval
+fi
+
+
+# Check whether --with-linker was given.
+if test "${with_linker+set}" = set; then
+  withval=$with_linker; linker=$withval
+fi
+
+# Check whether --enable-tls was given.
+if test "${enable_tls+set}" = set; then
+  enableval=$enable_tls; tls=$enableval
+fi
+
+if test "$tls" = "yes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TLS 1
+_ACEOF
+
+fi
+# Check whether --enable-gcc-compat was given.
+if test "${enable_gcc_compat+set}" = set; then
+  enableval=$enable_gcc_compat; gcccompat=$enableval
+fi
+
+if test "$gcccompat" = "yes"; then
+	ADD_CPPFLAGS="$ADD_CPPFLAGS -DGCC_COMPAT";
+fi
+
+# setup for building a cross-compiler
+if test "X$target_alias" = "X$host_alias" -o "X$target_alias" = "X"; then
+	BINPREFIX=""
+else
+	BINPREFIX="${target_alias}-"
+	test "X$prefix" = XNONE && prefix="$ac_default_prefix"
+	test "X$exec_prefix" = XNONE && exec_prefix="${prefix}"
+	if test -z "$altincdir"; then
+		altincdir=${exec_prefix}/${target_alias}/include
+	fi
+	if test -z "$altlibdir"; then
+		altlibdir=${exec_prefix}/${target_alias}/lib
+	fi
+	if test -z "$assembler"; then
+		assembler=${BINPREFIX}as
+	fi
+	if test -z  "$linker"; then
+		linker=${BINPREFIX}ld
+	fi
+	preprocessor="${BINPREFIX}cpp"
+	compiler="${BINPREFIX}ccom"
+fi
+
+
+if test -n "$altincdir"; then
+
+cat >>confdefs.h <<_ACEOF
+#define STDINC "$altincdir"
+_ACEOF
+
+fi
+if test -n "$altlibdir"; then
+
+cat >>confdefs.h <<_ACEOF
+#define LIBDIR "${altlibdir}/"
+_ACEOF
+
+fi
+if test -n "$assembler"; then
+
+cat >>confdefs.h <<_ACEOF
+#define ASSEMBLER "$assembler"
+_ACEOF
+
+fi
+if test -n "$linker"; then
+
+cat >>confdefs.h <<_ACEOF
+#define LINKER "$linker"
+_ACEOF
+
+fi
+if test -n "$preprocessor"; then
+
+cat >>confdefs.h <<_ACEOF
+#define PREPROCESSOR "${BINPREFIX}cpp"
+_ACEOF
+
+fi
+if test -n "$compiler"; then
+
+cat >>confdefs.h <<_ACEOF
+#define COMPILER "${BINPREFIX}ccom"
+_ACEOF
+
+fi
+
+case $wchar_type in
+USHORT) wchar_size=2 ;;
+UNSIGNED|INT) wchar_size=4 ;;
+*) { { echo "$as_me:$LINENO: error: Unknown wchar_t '$wchar_type'." >&5
+echo "$as_me: error: Unknown wchar_t '$wchar_type'." >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+
+
+cat >>confdefs.h <<_ACEOF
+#define WCHAR_TYPE $wchar_type
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define WCHAR_SIZE $wchar_size
+_ACEOF
+
+
+# check for additional compiler flags
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; }
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+#
+# List of possible output files, starting from the most likely.
+# The algorithm is not robust to junk in `.', hence go to wildcards (a.*)
+# only as a last resort.  b.out is created by i960 compilers.
+ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out'
+#
+# The IRIX 6 linker writes into existing files which may not be
+# executable, retaining their permissions.  Remove them first so a
+# subsequent execution test works.
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { (ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+        if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+
+{ echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6; }
+if test -z "$ac_file"; then
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; }
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  fi
+fi
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6; }
+
+{ echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; }
+if test "${ac_cv_objext+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	CFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6; } ;;
+  xno)
+    { echo "$as_me:$LINENO: result: unsupported" >&5
+echo "${ECHO_T}unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+DESIRED_FLAGS="-Wall -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wsign-compare -Wtruncate"
+for flag in $DESIRED_FLAGS
+do
+	{ echo "$as_me:$LINENO: checking whether $CC accepts $flag" >&5
+echo $ECHO_N "checking whether $CC accepts $flag... $ECHO_C" >&6; }
+	cat >conftest.$ac_ext <<_ACEOF
+int main() { return 0; }
+_ACEOF
+	$CC $CFLAGS $flag -c conftest.c > /dev/null 2> /dev/null
+	if test $? = 0 ; then
+		ADD_CFLAGS="$ADD_CFLAGS $flag"
+		{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; };
+	else
+		{ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; };
+	fi
+	rm -f conftest.o
+done
+
+# setup for cross-compiling mkext
+{ echo "$as_me:$LINENO: checking for a C compiler for mkext" >&5
+echo $ECHO_N "checking for a C compiler for mkext... $ECHO_C" >&6; }
+if test $cross_compiling = yes; then
+        { echo "$as_me:$LINENO: result: cross compiling" >&5
+echo "${ECHO_T}cross compiling" >&6; }
+        for ac_prog in pcc gcc cc
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC_FOR_BUILD+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC_FOR_BUILD"; then
+  ac_cv_prog_CC_FOR_BUILD="$CC_FOR_BUILD" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC_FOR_BUILD="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC_FOR_BUILD=$ac_cv_prog_CC_FOR_BUILD
+if test -n "$CC_FOR_BUILD"; then
+  { echo "$as_me:$LINENO: result: $CC_FOR_BUILD" >&5
+echo "${ECHO_T}$CC_FOR_BUILD" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$CC_FOR_BUILD" && break
+done
+
+else
+        { echo "$as_me:$LINENO: result: not cross compiling" >&5
+echo "${ECHO_T}not cross compiling" >&6; }
+        CC_FOR_BUILD=${CC-cc}
+
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # Extract the first word of "grep ggrep" to use in msg output
+if test -z "$GREP"; then
+set dummy grep ggrep; ac_prog_name=$2
+if test "${ac_cv_path_GREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_path_GREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in grep ggrep; do
+  for ac_exec_ext in '' $ac_executable_extensions; do
+    ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+    { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+    # Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+    $ac_path_GREP_found && break 3
+  done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+GREP="$ac_cv_path_GREP"
+if test -z "$GREP"; then
+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+echo "${ECHO_T}$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     # Extract the first word of "egrep" to use in msg output
+if test -z "$EGREP"; then
+set dummy egrep; ac_prog_name=$2
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_path_EGREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in egrep; do
+  for ac_exec_ext in '' $ac_executable_extensions; do
+    ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+    { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+    # Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+    $ac_path_EGREP_found && break 3
+  done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+EGREP="$ac_cv_path_EGREP"
+if test -z "$EGREP"; then
+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+
+   fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+echo "${ECHO_T}$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_stdc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_header_stdc=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then
+  :
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+{ echo "$as_me:$LINENO: checking for C99 printf size specifiers" >&5
+echo $ECHO_N "checking for C99 printf size specifiers... $ECHO_C" >&6; }
+if test "${ac_have_c99_format+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+  if test "$cross_compiling" = yes; then
+   ac_have_c99_format=yes
+else
+  cat >conftest.$ac_ext <<_ACEOF
+
+    /* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+      char buf[64];
+      if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5)
+        exit(1);
+      else if (strcmp(buf, "12345"))
+        exit(2);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+   ac_have_c99_format=yes
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ ac_have_c99_format=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_have_c99_format" >&5
+echo "${ECHO_T}$ac_have_c99_format" >&6; }
+if test $ac_have_c99_format = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_C99_FORMAT 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for C99 variadic macro support" >&5
+echo $ECHO_N "checking for C99 variadic macro support... $ECHO_C" >&6; }
+if test "${ac_have_variadic+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+  cat >conftest.$ac_ext <<_ACEOF
+
+	#define macro(...) func(__VA_ARGS__)
+	int func(int a, ...);
+	int test() { return macro(1, 2, 3); }
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_have_variadic=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	 ac_have_variadic=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_have_variadic" >&5
+echo "${ECHO_T}$ac_have_variadic" >&6; }
+if test $ac_have_variadic = yes ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CPP_VARARG_MACRO_GCC 1
+_ACEOF
+
+fi
+
+# Byteorder of host
+{ echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6; }
+if test "${ac_cv_c_bigendian+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if  ! (defined BYTE_ORDER && defined BIG_ENDIAN && defined LITTLE_ENDIAN \
+	&& BYTE_ORDER && BIG_ENDIAN && LITTLE_ENDIAN)
+ bogus endian macros
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_c_bigendian=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_c_bigendian=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	# It does not; compile a test program.
+if test "$cross_compiling" = yes; then
+  # try to guess the endianness by grepping values into an object file
+  ac_cv_c_bigendian=unknown
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }
+int
+main ()
+{
+ _ascii (); _ebcdic ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then
+  ac_cv_c_bigendian=yes
+fi
+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+  if test "$ac_cv_c_bigendian" = unknown; then
+    ac_cv_c_bigendian=no
+  else
+    # finding both strings is unlikely to happen, but who knows?
+    ac_cv_c_bigendian=unknown
+  fi
+fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+  /* Are we little or big endian?  From Harbison&Steele.  */
+  union
+  {
+    long int l;
+    char c[sizeof (long int)];
+  } u;
+  u.l = 1;
+  return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_bigendian=no
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6; }
+case $ac_cv_c_bigendian in
+  yes)
+
+cat >>confdefs.h <<\_ACEOF
+#define HOST_BIG_ENDIAN
+_ACEOF
+ ;;
+  no)
+
+cat >>confdefs.h <<\_ACEOF
+#define HOST_LITTLE_ENDIAN
+_ACEOF
+ ;;
+  *)
+    { { echo "$as_me:$LINENO: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&5
+echo "$as_me: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+
+
+
+# Checks for programs.
+{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; }
+set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+	@echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+  SET_MAKE=
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+  ./ | .// | /cC/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	    break 3
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+done
+IFS=$as_save_IFS
+
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+for ac_prog in 'bison -y' byacc
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_YACC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_YACC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+  { echo "$as_me:$LINENO: result: $YACC" >&5
+echo "${ECHO_T}$YACC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+# Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_strip+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$strip"; then
+  ac_cv_prog_strip="$strip" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_strip="yes"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_prog_strip" && ac_cv_prog_strip="no"
+fi
+fi
+strip=$ac_cv_prog_strip
+if test -n "$strip"; then
+  { echo "$as_me:$LINENO: result: $strip" >&5
+echo "${ECHO_T}$strip" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+
+for ac_prog in flex lex
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_LEX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$LEX"; then
+  ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_LEX="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+LEX=$ac_cv_prog_LEX
+if test -n "$LEX"; then
+  { echo "$as_me:$LINENO: result: $LEX" >&5
+echo "${ECHO_T}$LEX" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=":"
+
+if test "x$LEX" != "x:"; then
+  cat >conftest.l <<_ACEOF
+%%
+a { ECHO; }
+b { REJECT; }
+c { yymore (); }
+d { yyless (1); }
+e { yyless (input () != 0); }
+f { unput (yytext[0]); }
+. { BEGIN INITIAL; }
+%%
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#endif
+int
+main (void)
+{
+  return ! yylex () + ! yywrap ();
+}
+_ACEOF
+{ (ac_try="$LEX conftest.l"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$LEX conftest.l") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ echo "$as_me:$LINENO: checking lex output file root" >&5
+echo $ECHO_N "checking lex output file root... $ECHO_C" >&6; }
+if test "${ac_cv_prog_lex_root+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+if test -f lex.yy.c; then
+  ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+  ac_cv_prog_lex_root=lexyy
+else
+  { { echo "$as_me:$LINENO: error: cannot find output from $LEX; giving up" >&5
+echo "$as_me: error: cannot find output from $LEX; giving up" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_root" >&5
+echo "${ECHO_T}$ac_cv_prog_lex_root" >&6; }
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+if test -z "${LEXLIB+set}"; then
+  { echo "$as_me:$LINENO: checking lex library" >&5
+echo $ECHO_N "checking lex library... $ECHO_C" >&6; }
+if test "${ac_cv_lib_lex+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+    ac_save_LIBS=$LIBS
+    ac_cv_lib_lex='none needed'
+    for ac_lib in '' -lfl -ll; do
+      LIBS="$ac_lib $ac_save_LIBS"
+      cat >conftest.$ac_ext <<_ACEOF
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_lex=$ac_lib
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+      test "$ac_cv_lib_lex" != 'none needed' && break
+    done
+    LIBS=$ac_save_LIBS
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_lex" >&5
+echo "${ECHO_T}$ac_cv_lib_lex" >&6; }
+  test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex
+fi
+
+
+{ echo "$as_me:$LINENO: checking whether yytext is a pointer" >&5
+echo $ECHO_N "checking whether yytext is a pointer... $ECHO_C" >&6; }
+if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent.  Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+ac_save_LIBS=$LIBS
+LIBS="$LEXLIB $ac_save_LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#define YYTEXT_POINTER 1
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_prog_lex_yytext_pointer=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_save_LIBS
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_yytext_pointer" >&5
+echo "${ECHO_T}$ac_cv_prog_lex_yytext_pointer" >&6; }
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define YYTEXT_POINTER 1
+_ACEOF
+
+fi
+rm -f conftest.l $LEX_OUTPUT_ROOT.c
+
+fi
+if test "$LEX" = flex ; then
+
+cat >>confdefs.h <<_ACEOF
+#define ISFLEX 1
+_ACEOF
+
+fi
+
+# Checks for libraries.
+
+# Checks for header files.
+# AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h])
+
+
+
+for ac_header in string.h malloc.h libgen.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------- ##
+## Report this to <pcc-list@ludd.ltu.se> ##
+## ------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+{ echo "$as_me:$LINENO: checking for sys/wait.h that is POSIX.1 compatible" >&5
+echo $ECHO_N "checking for sys/wait.h that is POSIX.1 compatible... $ECHO_C" >&6; }
+if test "${ac_cv_header_sys_wait_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+int
+main ()
+{
+  int s;
+  wait (&s);
+  s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_sys_wait_h=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_header_sys_wait_h=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_wait_h" >&6; }
+if test $ac_cv_header_sys_wait_h = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SYS_WAIT_H 1
+_ACEOF
+
+fi
+
+
+# Checks for library functions.
+##  AC_FUNC_STRTOD
+# AC_FUNC_VPRINTF
+# AC_CHECK_FUNCS([memset strchr strdup strrchr strtol])
+
+
+
+
+
+
+
+
+
+
+for ac_func in strtold vsnprintf snprintf mkstemp strlcat strlcpy basename getopt ffs vfork
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+pcc_major=`echo $PACKAGE_VERSION | awk -F. '{print $1}'`
+pcc_minor=`echo $PACKAGE_VERSION | awk -F. '{print $2}'`
+pcc_minorminor=`echo $PACKAGE_VERSION | awk -F. '{print $3}'`
+versstr="\"$PACKAGE_STRING `cat $srcdir/DATESTAMP` for $target, $USER@`hostname`\""
+
+
+cat >>confdefs.h <<_ACEOF
+#define TARGOS $targos
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define TARGOSVER $targosver
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PCC_MAJOR $pcc_major
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PCC_MINOR $pcc_minor
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PCC_MINORMINOR $pcc_minorminor
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSSTR $versstr
+_ACEOF
+
+
+ac_config_files="$ac_config_files Makefile cc/Makefile cc/cc/Makefile cc/cpp/Makefile cc/ccom/Makefile f77/Makefile f77/f77/Makefile f77/fcom/Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes (double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    test "x$cache_file" != "x/dev/null" &&
+      { echo "$as_me:$LINENO: updating cache $cache_file" >&5
+echo "$as_me: updating cache $cache_file" >&6;}
+    cat confcache >$cache_file
+  else
+    { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s='ln -s'
+  # ... but there are two gotchas:
+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+  # In both cases, we have to default to `cp -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+	case $1 in
+        -*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+
+# Save the log message, to keep $[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by pcc $as_me 1.0.0.RELEASE, which was
+generated by GNU Autoconf 2.61.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+  -q, --quiet      do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+  --file=FILE[:TEMPLATE]
+		   instantiate the configuration file FILE
+  --header=FILE[:TEMPLATE]
+		   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to <bug-autoconf@gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+pcc config.status 1.0.0.RELEASE
+configured by $0, generated by GNU Autoconf 2.61,
+  with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2006 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value.  By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    echo "$ac_cs_version"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    { echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$ac_config_targets $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+  echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+  CONFIG_SHELL=$SHELL
+  export CONFIG_SHELL
+  exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "cc/Makefile") CONFIG_FILES="$CONFIG_FILES cc/Makefile" ;;
+    "cc/cc/Makefile") CONFIG_FILES="$CONFIG_FILES cc/cc/Makefile" ;;
+    "cc/cpp/Makefile") CONFIG_FILES="$CONFIG_FILES cc/cpp/Makefile" ;;
+    "cc/ccom/Makefile") CONFIG_FILES="$CONFIG_FILES cc/ccom/Makefile" ;;
+    "f77/Makefile") CONFIG_FILES="$CONFIG_FILES f77/Makefile" ;;
+    "f77/f77/Makefile") CONFIG_FILES="$CONFIG_FILES f77/f77/Makefile" ;;
+    "f77/fcom/Makefile") CONFIG_FILES="$CONFIG_FILES f77/fcom/Makefile" ;;
+
+  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp=
+  trap 'exit_status=$?
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} ||
+{
+   echo "$me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+#
+# Set up the sed scripts for CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "$CONFIG_FILES"; then
+
+_ACEOF
+
+
+
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  cat >conf$$subs.sed <<_ACEOF
+SHELL!$SHELL$ac_delim
+PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim
+PACKAGE_NAME!$PACKAGE_NAME$ac_delim
+PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim
+PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim
+PACKAGE_STRING!$PACKAGE_STRING$ac_delim
+PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim
+exec_prefix!$exec_prefix$ac_delim
+prefix!$prefix$ac_delim
+program_transform_name!$program_transform_name$ac_delim
+bindir!$bindir$ac_delim
+sbindir!$sbindir$ac_delim
+libexecdir!$libexecdir$ac_delim
+datarootdir!$datarootdir$ac_delim
+datadir!$datadir$ac_delim
+sysconfdir!$sysconfdir$ac_delim
+sharedstatedir!$sharedstatedir$ac_delim
+localstatedir!$localstatedir$ac_delim
+includedir!$includedir$ac_delim
+oldincludedir!$oldincludedir$ac_delim
+docdir!$docdir$ac_delim
+infodir!$infodir$ac_delim
+htmldir!$htmldir$ac_delim
+dvidir!$dvidir$ac_delim
+pdfdir!$pdfdir$ac_delim
+psdir!$psdir$ac_delim
+libdir!$libdir$ac_delim
+localedir!$localedir$ac_delim
+mandir!$mandir$ac_delim
+DEFS!$DEFS$ac_delim
+ECHO_C!$ECHO_C$ac_delim
+ECHO_N!$ECHO_N$ac_delim
+ECHO_T!$ECHO_T$ac_delim
+LIBS!$LIBS$ac_delim
+build_alias!$build_alias$ac_delim
+host_alias!$host_alias$ac_delim
+target_alias!$target_alias$ac_delim
+build!$build$ac_delim
+build_cpu!$build_cpu$ac_delim
+build_vendor!$build_vendor$ac_delim
+build_os!$build_os$ac_delim
+host!$host$ac_delim
+host_cpu!$host_cpu$ac_delim
+host_vendor!$host_vendor$ac_delim
+host_os!$host_os$ac_delim
+target!$target$ac_delim
+target_cpu!$target_cpu$ac_delim
+target_vendor!$target_vendor$ac_delim
+target_os!$target_os$ac_delim
+BINPREFIX!$BINPREFIX$ac_delim
+CC!$CC$ac_delim
+CFLAGS!$CFLAGS$ac_delim
+LDFLAGS!$LDFLAGS$ac_delim
+CPPFLAGS!$CPPFLAGS$ac_delim
+ac_ct_CC!$ac_ct_CC$ac_delim
+EXEEXT!$EXEEXT$ac_delim
+OBJEXT!$OBJEXT$ac_delim
+CC_FOR_BUILD!$CC_FOR_BUILD$ac_delim
+CPP!$CPP$ac_delim
+GREP!$GREP$ac_delim
+EGREP!$EGREP$ac_delim
+SET_MAKE!$SET_MAKE$ac_delim
+INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim
+INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim
+INSTALL_DATA!$INSTALL_DATA$ac_delim
+YACC!$YACC$ac_delim
+YFLAGS!$YFLAGS$ac_delim
+strip!$strip$ac_delim
+LEX!$LEX$ac_delim
+LEX_OUTPUT_ROOT!$LEX_OUTPUT_ROOT$ac_delim
+LEXLIB!$LEXLIB$ac_delim
+targos!$targos$ac_delim
+targosver!$targosver$ac_delim
+targmach!$targmach$ac_delim
+ADD_CFLAGS!$ADD_CFLAGS$ac_delim
+ADD_CPPFLAGS!$ADD_CPPFLAGS$ac_delim
+LIBOBJS!$LIBOBJS$ac_delim
+LTLIBOBJS!$LTLIBOBJS$ac_delim
+_ACEOF
+
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 78; then
+    break
+  elif $ac_last_try; then
+    { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+if test -n "$ac_eof"; then
+  ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+  ac_eof=`expr $ac_eof + 1`
+fi
+
+cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
+_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+rm -f conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+:end
+s/|#_!!_#|//g
+CEOF$ac_eof
+_ACEOF
+
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[	 ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+fi # test -n "$CONFIG_FILES"
+
+
+for ac_tag in  :F $CONFIG_FILES  :H $CONFIG_HEADERS
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
+echo "$as_me: error: Invalid tag $ac_tag." >&2;}
+   { (exit 1); exit 1; }; };;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+   { (exit 1); exit 1; }; };;
+      esac
+      ac_file_inputs="$ac_file_inputs $ac_f"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input="Generated from "`IFS=:
+	  echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure."
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+    fi
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$tmp/stdin";;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  { as_dir="$ac_dir"
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+echo "$as_me: error: cannot create directory $as_dir" >&2;}
+   { (exit 1); exit 1; }; }; }
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+
+case `sed -n '/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+' $ac_file_inputs` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+    s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF
+  sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s&@configure_input@&$configure_input&;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+  { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&5
+echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&2;}
+
+  rm -f "$tmp/stdin"
+  case $ac_file in
+  -) cat "$tmp/out"; rm -f "$tmp/out";;
+  *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;;
+  esac
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+_ACEOF
+
+# Transform confdefs.h into a sed script `conftest.defines', that
+# substitutes the proper values into config.h.in to produce config.h.
+rm -f conftest.defines conftest.tail
+# First, append a space to every undef/define line, to ease matching.
+echo 's/$/ /' >conftest.defines
+# Then, protect against being on the right side of a sed subst, or in
+# an unquoted here document, in config.status.  If some macros were
+# called several times there might be several #defines for the same
+# symbol, which is useless.  But do not sort them, since the last
+# AC_DEFINE must be honored.
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where
+# NAME is the cpp macro being defined, VALUE is the value it is being given.
+# PARAMS is the parameter list in the macro definition--in most cases, it's
+# just an empty string.
+ac_dA='s,^\\([	 #]*\\)[^	 ]*\\([	 ]*'
+ac_dB='\\)[	 (].*,\\1define\\2'
+ac_dC=' '
+ac_dD=' ,'
+
+uniq confdefs.h |
+  sed -n '
+	t rset
+	:rset
+	s/^[	 ]*#[	 ]*define[	 ][	 ]*//
+	t ok
+	d
+	:ok
+	s/[\\&,]/\\&/g
+	s/^\('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p
+	s/^\('"$ac_word_re"'\)[	 ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p
+  ' >>conftest.defines
+
+# Remove the space that was appended to ease matching.
+# Then replace #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+# (The regexp can be short, since the line contains either #define or #undef.)
+echo 's/ $//
+s,^[	 #]*u.*,/* & */,' >>conftest.defines
+
+# Break up conftest.defines:
+ac_max_sed_lines=50
+
+# First sed command is:	 sed -f defines.sed $ac_file_inputs >"$tmp/out1"
+# Second one is:	 sed -f defines.sed "$tmp/out1" >"$tmp/out2"
+# Third one will be:	 sed -f defines.sed "$tmp/out2" >"$tmp/out1"
+# et cetera.
+ac_in='$ac_file_inputs'
+ac_out='"$tmp/out1"'
+ac_nxt='"$tmp/out2"'
+
+while :
+do
+  # Write a here document:
+    cat >>$CONFIG_STATUS <<_ACEOF
+    # First, check the format of the line:
+    cat >"\$tmp/defines.sed" <<\\CEOF
+/^[	 ]*#[	 ]*undef[	 ][	 ]*$ac_word_re[	 ]*\$/b def
+/^[	 ]*#[	 ]*define[	 ][	 ]*$ac_word_re[(	 ]/b def
+b
+:def
+_ACEOF
+  sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS
+  echo 'CEOF
+    sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS
+  ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in
+  sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail
+  grep . conftest.tail >/dev/null || break
+  rm -f conftest.defines
+  mv conftest.tail conftest.defines
+done
+rm -f conftest.defines conftest.tail
+
+echo "ac_result=$ac_in" >>$CONFIG_STATUS
+cat >>$CONFIG_STATUS <<\_ACEOF
+  if test x"$ac_file" != x-; then
+    echo "/* $configure_input  */" >"$tmp/config.h"
+    cat "$ac_result" >>"$tmp/config.h"
+    if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then
+      { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f $ac_file
+      mv "$tmp/config.h" $ac_file
+    fi
+  else
+    echo "/* $configure_input  */"
+    cat "$ac_result"
+  fi
+  rm -f "$tmp/out12"
+ ;;
+
+
+  esac
+
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || { (exit 1); exit 1; }
+fi
+
+
+eval "exec_prefix=$exec_prefix"
+eval "bindir=$bindir"
+eval "libexecdir=$libexecdir"
+
+echo
+echo "Target CPU is .................... ${targmach}"
+echo "Target ABI is .................... ${abi}"
+echo "Target OS is ..................... ${targos}"
+echo "Compiler is called ............... ${BINPREFIX}pcc${EXEEXT}"
+echo "Installing compiler into ......... ${bindir}"
+echo "Installing pre-processor into .... ${libexecdir}"
+echo "Using assembler .................. ${assembler-<default>}"
+echo "Using linker ..................... ${linker-<default>}"
+echo "Using include path ............... ${altincdir-<default>}"
+echo "Using library path ............... ${altlibdir-<default>}"
+echo "Has TLS support .................. $tls"
+echo "Has GCC compatibility ............ $gcccompat"
+echo "Type of wchar_t is ............... ${wchar_type} (${wchar_size} chars)"
+echo
+echo "Configure finished.  Do 'make && make install' to compile and install.
+"
Index: uspace/app/pcc/configure.ac
===================================================================
--- uspace/app/pcc/configure.ac	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/configure.ac	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,482 @@
+                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT([pcc], [1.0.0.RELEASE], <pcc-list@ludd.ltu.se>)
+AC_CONFIG_HEADER([config.h])
+
+AC_CANONICAL_TARGET
+
+abi=unknown
+endian=little
+targosver=0
+tls=no
+gcccompat=yes
+# allowed: UNSIGNED (4-char u_int), INT (4-char int), SHORT (2-char u_short)
+wchar_type=INT
+
+case "$target_os" in
+
+    apple)
+	targos=apple
+	abi=classic68k
+	case "$target_cpu" in
+	    m68k) targmach=m68k endian=big ;;
+	esac
+	;;
+
+    bsd)
+	targos=bsd
+	abi=aout
+	targmach=pdp11
+	wchar_type=USHORT
+	;;
+
+    darwin*)
+	targos=darwin
+	abi=macho
+	case "$target_os" in
+	    *10.*) targosver=10 ;;
+	    *9.*) targosver=9 ;;
+	    *8.*) targosver=8 ;;
+	    *7.*) targosver=7 ;;
+	esac
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	    powerpc) targmach=powerpc endian=big ;;
+	    x86_64) targmach=amd64 ;;
+	esac
+        ;;
+
+    dragonfly*)
+	targos=dragonfly
+	abi=elf
+	tls=yes
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	    x86_64) targmach=amd64 ;;
+	esac
+	;;
+
+    freebsd*)
+	targos=freebsd
+	abi=elf
+	case "$target_os" in
+	    *9.*) targosver=9 ;;
+	    *8.*) targosver=8 ;;
+	    *7.*) targosver=7 ;;
+	    *6.*) targosver=6 ;;
+	    *5.*) targosver=5 ;;
+	    *4.*) targosver=4 ;;
+	esac
+	case "$target_cpu" in
+	    i386) targmach=i386 ;;
+	    x86_64) targmach=amd64 ;;
+	esac
+	;;
+
+    linux*)
+	targos=linux
+	abi=elf
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	    powerpc*) targmach=powerpc endian=big ;;
+	    x86_64) targmach=amd64 ;;
+	    mipseb) targmach=mips endian=big ;;
+	    mips*) targmach=mips ;;
+	esac
+	;;
+
+    midnightbsd*)
+	targos=midnightbsd
+	abi=elf
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	    sparc64) targmach=sparc64 endian=big ;;
+	esac
+	;;
+
+    mingw*)
+	targos=win32
+	abi=pecoff
+	wchar_type=USHORT
+	targmach=i386
+	altincdir="c:/mingw/include"
+	altlibdir="c:/mingw/lib"
+	;;
+
+    minix)
+	targos=minix
+	abi=coff
+	case "$target_cpu" in
+	    m68k) targmach=m68k endian=big ;;
+	esac
+	;;
+
+    mirbsd*)
+	targos=mirbsd
+	abi=elf
+	wchar_type=USHORT
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	esac
+	;;
+
+    netbsd*)
+	targos=netbsd
+	abi=elf
+	case "$target_os" in
+	    *5.*) targosver=5 ;;
+	    *4.*) targosver=4 ;;
+	    *3.*) targosver=3 ;;
+	    *2.*) targosver=2 ;;
+	    *1.*) targosver=1 ;;
+	esac
+	case "$target_cpu" in
+	    armeb) targmach=arm endian=big ;;
+	    arm*) targmach=arm ;;
+	    i?86) targmach=i386 ;;
+	    m68k*) targmach=m68k endian=big ;;
+	    mipseb) targmach=mips endian=big ;;
+	    mips*) targmach=mips ;;
+	    pdp10) targmach=pdp10 ;;
+	    powerpc) targmach=powerpc endian=big ;;
+	    sparc64) targmach=sparc64 endian=big ;;
+	    vax) targmach=vax ;;
+	    x86_64) targmach=amd64 ;;
+	esac
+	;;
+
+    nextstep*)
+	targos=nextstep
+	abi=macho
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	    sparc) targmach=sparc endian=big ;;
+	    hppa) targmach=hppa endian=big ;;
+	esac
+	;;
+
+    openbsd*)
+	targos=openbsd
+	abi=elf
+	case "$target_cpu" in
+	    i?86) targmach=i386 ;;
+	    vax) targmach=vax ;;
+	    powerpc) targmach=powerpc endian=big ;;
+	    sparc64) targmach=sparc64 endian=big ;;
+	    x86_64) targmach=amd64 ;;
+	esac
+	;;
+
+    sunos*|solaris*)
+        targos=sunos
+        abi=elf
+        case "$target_cpu" in
+            i?86) targmach=i386 ;;
+            sparc*) targmach=sparc64 endian=big ;;
+        esac
+        ;;
+
+    windows*|pe*)
+	target_alias=i386-pe
+	targos=win32
+	abi=pecoff
+	wchar_type=USHORT
+	targmach=i386
+	;;
+
+    *)
+        targos="$target_os"
+	case "$target_cpu" in
+	    m16c) targmach=m16c ;;
+	    nova) targmach=nova ;;
+	esac
+	;;
+esac
+
+if test "X$targos" = X -o "X$targmach" = X ; then
+	AC_MSG_ERROR(['$target' is not (yet) supported by pcc.])
+fi
+
+case "$host_os" in
+
+    pe*)
+	# quick hack for cross-build to win32 host
+	if "$prefix" = NONE; then
+		prefix="c:/pcc"
+		assembler="yasm.exe -p gnu -f win32"
+		linker="link.exe /nologo"
+		ADD_CFLAGS=-DMSLINKER
+	fi
+	;;
+
+    sunos*|solaris*)
+	ADD_CPPFLAGS="$ADD_CPPFLAGS -D_XOPEN_SOURCE=600"
+	;;
+
+    darwin*)
+	if test "$targosver" -ge 10 ; then
+		targmach=amd64
+	fi
+	;;
+
+esac
+
+if test "X$endian" = "Xbig" ; then
+	AC_DEFINE(TARGET_BIG_ENDIAN, 1,
+		[Define if target defaults to BIG endian])
+else
+	AC_DEFINE(TARGET_LITTLE_ENDIAN, 1,
+		[Define if target defaults to LITTLE endian])
+fi
+
+case "$abi" in
+	elf*)		AC_DEFINE(ELFABI, [], [Using ELF ABI]) ;;
+	aout)		AC_DEFINE(AOUTABI, [], [Using a.out ABI]) ;;
+	macho)		AC_DEFINE(MACHOABI, [], [Using Mach-O ABI]) ;;
+	coff)		AC_DEFINE(COFFABI, [], [Using COFF ABI]) ;;
+	ecoff)		AC_DEFINE(ECOFFABI, [], [Using ECOFF ABI]) ;;
+	pecoff)		AC_DEFINE(PECOFFABI, [], [Using PE/COFF ABI]) ;;
+	classic68k)	AC_DEFINE(CLASSIC68K, [], [Using Classic 68k ABI]) ;;
+esac
+
+# Specify alternate assembler, linker, include and lib paths
+AC_ARG_WITH(incdir,
+	AC_HELP_STRING([--with-incdir=<path>],
+		[Specify the default include path.]),
+	altincdir=$withval,
+	[])
+AC_ARG_WITH(libdir,
+	AC_HELP_STRING([--with-libdir=<path>],
+		[Specify the default library path.]),
+	altlibdir=$withval,
+	[])
+AC_ARG_WITH(assembler,
+	AC_HELP_STRING([--with-assembler=<path>],
+		[Specify alternate assember.]),
+	assembler=$withval,
+	[])
+AC_ARG_WITH(linker,
+	AC_HELP_STRING([--with-linker=<path>],
+		[Specify alternate linker.]),
+	linker=$withval,
+	[])
+AC_ARG_ENABLE(tls,
+	AC_HELP_STRING([--enable-tls],
+		[Enable Thread-local storage (TLS).]),
+	[tls=$enableval], [])
+if test "$tls" = "yes"; then
+	AC_DEFINE(TLS, 1, [Enable thread-local storage (TLS).])
+fi
+AC_ARG_ENABLE(gcc-compat,
+	AC_HELP_STRING([--disable-gcc-compat],
+		[Disable GCC compatibility]),
+	[gcccompat=$enableval], [])
+if test "$gcccompat" = "yes"; then
+	ADD_CPPFLAGS="$ADD_CPPFLAGS -DGCC_COMPAT";
+fi
+
+# setup for building a cross-compiler
+if test "X$target_alias" = "X$host_alias" -o "X$target_alias" = "X"; then
+	BINPREFIX=""
+else
+	BINPREFIX="${target_alias}-"
+	test "X$prefix" = XNONE && prefix="$ac_default_prefix"
+	test "X$exec_prefix" = XNONE && exec_prefix="${prefix}"
+	if test -z "$altincdir"; then
+		altincdir=${exec_prefix}/${target_alias}/include
+	fi
+	if test -z "$altlibdir"; then
+		altlibdir=${exec_prefix}/${target_alias}/lib
+	fi
+	if test -z "$assembler"; then
+		assembler=${BINPREFIX}as
+	fi
+	if test -z  "$linker"; then
+		linker=${BINPREFIX}ld
+	fi
+	preprocessor="${BINPREFIX}cpp"
+	compiler="${BINPREFIX}ccom"
+fi
+AC_SUBST(BINPREFIX)
+
+if test -n "$altincdir"; then
+	AC_DEFINE_UNQUOTED(STDINC, "$altincdir",
+		[Define alternate standard include directory])
+fi
+if test -n "$altlibdir"; then
+	AC_DEFINE_UNQUOTED(LIBDIR, "${altlibdir}/",
+		[Define alternate standard lib directory])
+fi
+if test -n "$assembler"; then
+	AC_DEFINE_UNQUOTED(ASSEMBLER, "$assembler",
+		[Define path to alternate assembler])
+fi
+if test -n "$linker"; then
+	AC_DEFINE_UNQUOTED(LINKER, "$linker",
+		[Define path to alternate linker])
+fi
+if test -n "$preprocessor"; then
+	AC_DEFINE_UNQUOTED(PREPROCESSOR, "${BINPREFIX}cpp",
+		[Define path to alternate preprocessor])
+fi
+if test -n "$compiler"; then
+	AC_DEFINE_UNQUOTED(COMPILER, "${BINPREFIX}ccom",
+		[Define path to alternate compiler])
+fi
+
+case $wchar_type in
+USHORT) wchar_size=2 ;;
+UNSIGNED|INT) wchar_size=4 ;;
+*) AC_MSG_ERROR([Unknown wchar_t '$wchar_type'.]) ;;
+esac
+
+AC_DEFINE_UNQUOTED(WCHAR_TYPE, $wchar_type, [Type to use for wide characters])
+AC_DEFINE_UNQUOTED(WCHAR_SIZE, $wchar_size, [Size of wide character type in chars])
+
+# check for additional compiler flags
+AC_PROG_CC
+DESIRED_FLAGS="-Wall -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wsign-compare -Wtruncate"
+for flag in $DESIRED_FLAGS
+do
+	AC_MSG_CHECKING([whether $CC accepts $flag])
+	AC_LANG_CONFTEST([int main() { return 0; }])
+	$CC $CFLAGS $flag -c conftest.c > /dev/null 2> /dev/null
+	if test $? = 0 ; then
+		ADD_CFLAGS="$ADD_CFLAGS $flag"
+		AC_MSG_RESULT([yes]);
+	else
+		AC_MSG_RESULT([no]);
+	fi
+	rm -f conftest.o
+done
+
+# setup for cross-compiling mkext
+AC_MSG_CHECKING([for a C compiler for mkext])
+if test $cross_compiling = yes; then
+        AC_MSG_RESULT([cross compiling])
+        AC_CHECK_PROGS(CC_FOR_BUILD, [pcc gcc cc])
+else
+        AC_MSG_RESULT([not cross compiling])
+        CC_FOR_BUILD=${CC-cc}
+        AC_SUBST(CC_FOR_BUILD)
+fi
+
+AC_CACHE_CHECK([for C99 printf size specifiers], ac_have_c99_format, [
+  AC_RUN_IFELSE([
+    AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT], [[
+      char buf[64];
+      if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5)
+        exit(1);
+      else if (strcmp(buf, "12345"))
+        exit(2);
+      ]])],
+    [ ac_have_c99_format=yes ],
+    [ ac_have_c99_format=no ],
+    [ ac_have_c99_format=yes ])
+])
+if test $ac_have_c99_format = yes; then
+  AC_DEFINE([HAVE_C99_FORMAT], 1,
+    [Define to 1 if printf supports C99 size specifiers])
+fi
+
+AC_CACHE_CHECK([for C99 variadic macro support], ac_have_variadic, [
+  AC_COMPILE_IFELSE([
+	#define macro(...) func(__VA_ARGS__)
+	int func(int a, ...);
+	int test() { return macro(1, 2, 3); }
+	], [ ac_have_variadic=yes ], [ ac_have_variadic=no ])])
+if test $ac_have_variadic = yes ; then
+  AC_DEFINE([HAVE_CPP_VARARG_MACRO_GCC], 1, 
+    [Define to 1 if your compiler supports C99 variadic macros])
+fi
+
+# Byteorder of host
+AC_C_BIGENDIAN([AC_DEFINE(HOST_BIG_ENDIAN,[],[Define if host is BIG endian])],
+	[AC_DEFINE(HOST_LITTLE_ENDIAN,[],[Define if host is LITTLE endian])],
+	[],[])
+
+
+# Checks for programs.
+AC_PROG_MAKE_SET
+AC_PROG_INSTALL
+AC_PROG_YACC
+AC_CHECK_PROG(strip,strip,yes,no)
+
+AC_PROG_LEX
+if test "$LEX" = flex ; then
+	AC_DEFINE_UNQUOTED(ISFLEX, 1, [lex is flex])
+fi
+
+# Checks for libraries.
+
+# Checks for header files.
+# AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h])
+AC_CHECK_HEADERS([string.h malloc.h libgen.h])
+AC_HEADER_SYS_WAIT
+
+# Checks for library functions.
+##  AC_FUNC_STRTOD
+# AC_FUNC_VPRINTF
+# AC_CHECK_FUNCS([memset strchr strdup strrchr strtol])
+AC_CHECK_FUNCS([strtold vsnprintf snprintf mkstemp strlcat strlcpy basename getopt ffs vfork])
+
+AC_EXEEXT
+
+AC_SUBST(targos)
+AC_SUBST(targosver)
+AC_SUBST(targmach)
+AC_SUBST(prefix)
+AC_SUBST(exec_prefix)
+AC_SUBST(libexecdir)
+AC_SUBST(includedir)
+AC_SUBST(strip)
+AC_SUBST(PACKAGE_VERSION)
+AC_SUBST(ADD_CFLAGS)
+AC_SUBST(ADD_CPPFLAGS)
+
+pcc_major=`echo $PACKAGE_VERSION | awk -F. '{print $1}'`
+pcc_minor=`echo $PACKAGE_VERSION | awk -F. '{print $2}'`
+pcc_minorminor=`echo $PACKAGE_VERSION | awk -F. '{print $3}'`
+versstr="\"$PACKAGE_STRING `cat $srcdir/DATESTAMP` for $target, $USER@`hostname`\""
+
+AC_DEFINE_UNQUOTED(TARGOS, $targos, [Target OS])
+AC_DEFINE_UNQUOTED(TARGOSVER, $targosver, [Target OS version])
+AC_DEFINE_UNQUOTED(PCC_MAJOR, $pcc_major, [Major version no])
+AC_DEFINE_UNQUOTED(PCC_MINOR, $pcc_minor, [Minor version no])
+AC_DEFINE_UNQUOTED(PCC_MINORMINOR, $pcc_minorminor, [Minor minor version no])
+AC_DEFINE_UNQUOTED(VERSSTR, $versstr, [Version string])
+
+AC_CONFIG_FILES([Makefile
+		cc/Makefile
+		cc/cc/Makefile
+		cc/cpp/Makefile
+		cc/ccom/Makefile
+		f77/Makefile
+		f77/f77/Makefile
+		f77/fcom/Makefile
+])
+AC_OUTPUT
+
+eval "exec_prefix=$exec_prefix"
+eval "bindir=$bindir"
+eval "libexecdir=$libexecdir"
+
+echo
+echo "Target CPU is .................... ${targmach}"
+echo "Target ABI is .................... ${abi}"
+echo "Target OS is ..................... ${targos}"
+echo "Compiler is called ............... ${BINPREFIX}pcc${EXEEXT}"
+echo "Installing compiler into ......... ${bindir}"
+echo "Installing pre-processor into .... ${libexecdir}"
+echo "Using assembler .................. ${assembler-<default>}"
+echo "Using linker ..................... ${linker-<default>}"
+echo "Using include path ............... ${altincdir-<default>}"
+echo "Using library path ............... ${altlibdir-<default>}"
+echo "Has TLS support .................. $tls"
+echo "Has GCC compatibility ............ $gcccompat"
+echo "Type of wchar_t is ............... ${wchar_type} (${wchar_size} chars)"
+echo
+echo "Configure finished.  Do 'make && make install' to compile and install.
+"
Index: uspace/app/pcc/f77/Makefile.in
===================================================================
--- uspace/app/pcc/f77/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,36 @@
+#	$Id: Makefile.in,v 1.3 2008/07/18 14:00:38 gmcgarry Exp $
+#
+# Makefile.in for top-level of pcc.
+#
+
+@SET_MAKE@
+CC=@CC@
+CFLAGS=@CFLAGS@ @ADD_CFLAGS@
+LDFLAGS=@LDFLAGS@
+CPPFLAGS=@CPPFLAGS@
+YACC=@YACC@
+LEX=@LEX@
+
+SUBDIR=f77 fcom
+
+all: ${SUBDIR}
+
+install:
+	cd f77 && ${MAKE} install
+	cd fcom && ${MAKE} install
+
+clean:
+	cd f77 && ${MAKE} clean
+	cd fcom && ${MAKE} clean
+
+distclean:
+	cd f77 && ${MAKE} distclean
+	cd fcom && ${MAKE} distclean
+	/bin/rm -rf Makefile config.log stamp-h1 config.status \
+	configure.lineno config.h autom4te.cache
+
+${SUBDIR}: nonexistant
+	cd $@; $(MAKE) all $(MFLAGS)
+
+nonexistant:
+
Index: uspace/app/pcc/f77/f77/Makefile.in
===================================================================
--- uspace/app/pcc/f77/f77/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/f77/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,52 @@
+#	$Id: Makefile.in,v 1.8 2008/12/19 08:08:48 ragge Exp $
+#
+# Makefile.in for the f77 frontend of pcc.
+#
+VPATH=@srcdir@
+top_srcdir=@top_srcdir@
+top_builddir=@top_builddir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libexecdir = @libexecdir@
+includedir = @includedir@
+strip = @strip@
+CC = @CC@
+TARGOS = @targos@
+TARGMACH = @targmach@
+F77LIBDIR=-L${prefix}/lib
+CFLAGS = @CFLAGS@ @ADD_CFLAGS@  -DLIBEXECDIR=\"${libexecdir}\" -DINCLUDEDIR=\"${includedir}\"
+CPPFLAGS = @CPPFLAGS@ -I${top_builddir} -I${top_srcdir}/os/${TARGOS} -I${MDIR} \
+	-Dmach_${TARGMACH} -Dos_${TARGOS} -I${FCOMDIR} -DLANG_F77 \
+	-DLIBDIR=\"${F77LIBDIR}\"
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+OBJS=f77.o
+DEST=@BINPREFIX@f77
+
+MIPDIR=${top_srcdir}/mip
+MDIR=${top_srcdir}/arch/$(TARGMACH)
+FCOMDIR=${top_srcdir}/f77/fcom
+
+all: ${DEST}
+
+${DEST}: $(OBJS)
+	$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@
+
+.c.o:
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c $<
+
+install:
+	${INSTALL_PROGRAM} ${DEST} ${bindir}
+	@if [ ${strip} = yes ]; then		\
+		strip ${bindir}/${DEST} ;	\
+		echo strip ${bindir}/${DEST} ;	\
+	fi
+
+clean:
+	/bin/rm -f  $(OBJS) ${DEST}
+
+distclean: clean
+	/bin/rm -f  Makefile
Index: uspace/app/pcc/f77/f77/f77.1
===================================================================
--- uspace/app/pcc/f77/f77/f77.1	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/f77/f77.1	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,175 @@
+.\"	$Id: f77.1,v 1.2 2008/12/24 17:40:41 sgk 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.
+.\"
+.TH F77 1
+.SH NAME
+f77 \- Fortran 77 compiler
+.SH SYNOPSIS
+.B f77
+[ option ] ... file ...
+.SH DESCRIPTION
+.I F77
+is the UNIX Fortran 77 compiler.
+It accepts several types of arguments:
+.PP
+Arguments whose names end with `.f' are taken to be
+Fortran 77 source programs;
+they are compiled, and
+each object program is left on the file in the current directory
+whose name is that of the source with `.o' substituted
+for '.f'.
+.PP
+Arguments whose names end with `.r' or `.e' are taken to be Ratfor or EFL
+source programs, respectively; these are first transformed by the
+appropriate preprocessor, then compiled by f77.
+.PP
+In the same way,
+arguments whose names end with `.c' or `.s' are taken to be C or assembly source programs
+and are compiled or assembled, producing a `.o' file.
+.PP
+The following options have the same meaning as in
+.IR cc (1).
+See
+.IR ld (1)
+for load-time options.
+.TP
+.B \-c
+Suppress loading and produce `.o' files for each source 
+file.
+.TP
+.B \-p
+Prepare object files for profiling, see
+.IR  prof (1).
+.TP
+.SM
+.B \-O
+Invoke an
+object-code optimizer.
+.TP
+.SM
+.B \-S
+Compile the named programs, and leave the
+assembler-language output on corresponding files suffixed `.s'.
+(No `.o' is created.).
+.TP
+.B \-f
+Use a floating point interpreter (for PDP11's that lack
+11/70-style floating point).
+.TP
+.BR \-o " output"
+Name the final output file
+.I output
+instead of `a.out'.
+.PP
+The following options are peculiar to
+.IR f77 .
+.TP
+.SM
+.BR \-onetrip
+Compile DO loops that are performed at least once if reached.
+(Fortran 77 DO loops are not performed at all if the upper limit is smaller than the lower limit.)
+.TP
+.BR \-u
+Make the default type of a variable `undefined' rather than using the default Fortran rules.
+.TP
+.BR \-q
+Suppress printing of procedure names during compilation.
+.TP
+.BR \-C
+Compile code to check that subscripts are within declared array bounds.
+.TP
+.BR \-w
+Suppress all warning messages.
+If the option is `\-w66', only Fortran 66 compatibility warnings are suppressed.
+.TP
+.BR \-F
+Apply EFL and Ratfor preprocessor to relevant files, put the result in the file
+with the suffix changed to `.f', but do not compile.
+.TP
+.BR \-m
+Apply the M4 preprocessor to each `.r' or `.e' file before transforming
+it with the Ratfor or EFL preprocessor.
+.TP
+.TP
+.BI \-E x
+Use the string
+.I x
+as an EFL option in processing `.e' files.
+.TP
+.BI \-R x
+Use the string 
+.I x
+as a Ratfor option in processing `.r' files.
+.PP
+Other arguments
+are taken
+to be either loader option arguments, or F77-compatible
+object programs, typically produced by an earlier
+run,
+or perhaps libraries of F77-compatible routines.
+These programs, together with the results of any
+compilations specified, are loaded (in the order
+given) to produce an executable program with name
+`a.out'.
+.SH FILES
+.nf
+.ta \w'/usr/lib/libF77.a   'u
+file.[fresc]	input file
+file.o	object file
+a.out	loaded output
+./fort[pid].?	temporary
+/usr/lib/f77pass1	compiler
+/lib/f1	pass 2
+/lib/c2	optional optimizer
+/usr/lib/libF77.a	intrinsic function library
+/usr/lib/libI77.a	Fortran I/O library
+/lib/libc.a	C library, see section 3
+.fi
+.SH "SEE ALSO"
+S. I. Feldman,
+P. J. Weinberger,
+.I
+A Portable Fortran 77 Compiler
+.br
+prof(1), cc(1), ld(1)
+.SH DIAGNOSTICS
+The diagnostics produced by
+.I f77
+itself are intended to be
+self-explanatory.
+Occasional messages may be produced by the loader.
+.SH BUGS
+The Fortran 66 subset of the language has been
+exercised extensively;
+the newer features have not.
Index: uspace/app/pcc/f77/f77/f77.c
===================================================================
--- uspace/app/pcc/f77/f77/f77.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/f77/f77.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,797 @@
+/*	$Id: f77.c,v 1.21 2008/12/27 00:36:39 sgk 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.
+ */
+
+char xxxvers[] = "FORTRAN 77 DRIVER, VERSION 1.11,   28 JULY 1978\n";
+
+#include <sys/wait.h>
+
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include "ccconfig.h"
+
+typedef FILE *FILEP;
+typedef int flag;
+#define	YES 1
+#define NO 0
+
+FILEP diagfile;
+
+static int pid;
+static int sigivalue	= 0;
+static int sigqvalue	= 0;
+
+#ifndef FCOM
+#define	FCOM		"fcom"
+#endif
+
+#ifndef ASSEMBLER
+#define ASSEMBLER       "as"
+#endif
+
+#ifndef LINKER
+#define LINKER          "ld"
+#endif
+
+static char *fcom	= LIBEXECDIR "/" FCOM ;
+static char *asmname	= ASSEMBLER ;
+static char *ldname	= LINKER ;
+static char *startfiles[] = STARTFILES;
+static char *endfiles[] = ENDFILES;
+static char *dynlinker[] = DYNLINKER;
+static char *crt0file = CRT0FILE;
+static char *macroname	= "m4";
+static char *shellname	= "/bin/sh";
+static char *aoutname	= "a.out" ;
+static char *libdir	= LIBDIR ;
+static char *liblist[] = F77LIBLIST;
+
+static char *infname;
+static char asmfname[15];
+static char prepfname[15];
+
+#define MAXARGS 100
+int ffmax;
+static char *ffary[MAXARGS];
+static char eflags[30]	= "";
+static char rflags[30]	= "";
+static char lflag[3]	= "-x";
+static char *eflagp	= eflags;
+static char *rflagp	= rflags;
+static char **loadargs;
+static char **loadp;
+static int oflag;
+
+static flag loadflag	= YES;
+static flag saveasmflag	= NO;
+static flag profileflag	= NO;
+static flag optimflag	= NO;
+static flag debugflag	= NO;
+static flag verbose	= NO;
+static flag fortonly	= NO;
+static flag macroflag	= NO;
+
+static char *setdoto(char *), *lastchar(char *), *lastfield(char *);
+static void intrupt(int);
+static void enbint(void (*)(int));
+static void crfnames(void);
+static void fatal1(char *, ...);
+static void done(int), texec(char *, char **);
+static char *copyn(int, char *);
+static int dotchar(char *), unreadable(char *), sys(char *), dofort(char *);
+static int nodup(char *);
+static int await(int);
+static void rmf(char *), doload(char *[], char *[]), doasm(char *);
+static int callsys(char *, char **);
+static void errorx(char *, ...);
+
+static void
+addarg(char **ary, int *num, char *arg)
+{
+	ary[(*num)++] = arg;
+	if ((*num) == MAXARGS) {
+		fprintf(stderr, "argument array too small\n");
+		exit(1);
+	}
+}
+
+int
+main(int argc, char **argv)
+{
+	int i, c, status;
+	char *s;
+	char fortfile[20], *t;
+	char buff[100];
+
+	diagfile = stderr;
+
+	sigivalue = (int) signal(SIGINT, SIG_IGN) & 01;
+	sigqvalue = (int) signal(SIGQUIT, SIG_IGN) & 01;
+	enbint(intrupt);
+
+	pid = getpid();
+	crfnames();
+
+	loadargs = (char **)calloc(1, (argc + 20) * sizeof(*loadargs));
+	if (!loadargs)
+		fatal1("out of memory");
+	loadp = loadargs;
+
+	--argc;
+	++argv;
+
+	while(argc>0 && argv[0][0]=='-' && argv[0][1]!='\0') {
+		for(s = argv[0]+1 ; *s ; ++s)
+			switch(*s) {
+			case 'T':  /* use special passes */
+				switch(*++s) {
+				case '1':
+					fcom = s+1; goto endfor;
+				case 'a':
+					asmname = s+1; goto endfor;
+				case 'l':
+					ldname = s+1; goto endfor;
+				case 'm':
+					macroname = s+1; goto endfor;
+				default:
+					fatal1("bad option -T%c", *s);
+				}
+				break;
+
+			case 'w': /* F66 warn or no warn */
+				addarg(ffary, &ffmax, s-1);
+				break;
+
+			case 'q':
+				/*
+				 * Suppress printing of procedure names during
+				 * compilation.
+				 */
+				addarg(ffary, &ffmax, s-1);
+				break;
+
+			copyfflag:
+			case 'u':
+			case 'U':
+			case 'M':
+			case '1':
+			case 'C':
+				addarg(ffary, &ffmax, s-1);
+				break;
+
+			case 'O':
+				optimflag = YES;
+				addarg(ffary, &ffmax, s-1);
+				break;
+
+			case 'm':
+				if(s[1] == '4')
+					++s;
+				macroflag = YES;
+				break;
+
+			case 'S':
+				saveasmflag = YES;
+
+			case 'c':
+				loadflag = NO;
+				break;
+
+			case 'v':
+				verbose = YES;
+				break;
+
+			case 'd':
+				debugflag = YES;
+				goto copyfflag;
+
+			case 'p':
+				profileflag = YES;
+				goto copyfflag;
+
+			case 'o':
+				if(!strcmp(s, "onetrip")) {
+					addarg(ffary, &ffmax, s-1);
+					goto endfor;
+				}
+				oflag = 1;
+				aoutname = *++argv;
+				--argc;
+				break;
+
+			case 'F':
+				fortonly = YES;
+				loadflag = NO;
+				break;
+
+			case 'I':
+				if(s[1]=='2' || s[1]=='4' || s[1]=='s')
+					goto copyfflag;
+				fprintf(diagfile, "invalid flag -I%c\n", s[1]);
+				done(1);
+
+			case 'l':	/* letter ell--library */
+				s[-1] = '-';
+				*loadp++ = s-1;
+				goto endfor;
+
+			case 'E':	/* EFL flag argument */
+				while(( *eflagp++ = *++s))
+					;
+				*eflagp++ = ' ';
+				goto endfor;
+			case 'R':
+				while(( *rflagp++ = *++s ))
+					;
+				*rflagp++ = ' ';
+				goto endfor;
+			default:
+				lflag[1] = *s;
+				*loadp++ = copyn(strlen(lflag), lflag);
+				break;
+			}
+endfor:
+	--argc;
+	++argv;
+	}
+
+	if (verbose)
+		fprintf(stderr, xxxvers);
+
+	if (argc == 0)
+		errorx("No input files");
+
+#ifdef mach_pdp11
+	if(nofloating)
+		*loadp++ = (profileflag ? NOFLPROF : NOFLFOOT);
+	else
+#endif
+
+	for(i = 0 ; i<argc ; ++i)
+		switch(c =  dotchar(infname = argv[i]) ) {
+		case 'r':	/* Ratfor file */
+		case 'e':	/* EFL file */
+			if( unreadable(argv[i]) )
+				break;
+			s = fortfile;
+			t = lastfield(argv[i]);
+			while(( *s++ = *t++))
+				;
+			s[-2] = 'f';
+
+			if(macroflag) {
+				sprintf(buff, "%s %s >%s", macroname, infname, prepfname);
+				if(sys(buff)) {
+					rmf(prepfname);
+					break;
+				}
+				infname = prepfname;
+			}
+
+			if(c == 'e')
+				sprintf(buff, "efl %s %s >%s", eflags, infname, fortfile);
+			else
+				sprintf(buff, "ratfor %s %s >%s", rflags, infname, fortfile);
+			status = sys(buff);
+			if(macroflag)
+				rmf(infname);
+			if(status) {
+				loadflag = NO;
+				rmf(fortfile);
+				break;
+			}
+
+			if( ! fortonly ) {
+				infname = argv[i] = lastfield(argv[i]);
+				*lastchar(infname) = 'f';
+	
+				if( dofort(argv[i]) )
+					loadflag = NO;
+				else	{
+					if( nodup(t = setdoto(argv[i])) )
+						*loadp++ = t;
+					rmf(fortfile);
+				}
+			}
+			break;
+
+		case 'f':	/* Fortran file */
+		case 'F':
+			if( unreadable(argv[i]) )
+				break;
+			if( dofort(argv[i]) )
+				loadflag = NO;
+			else if( nodup(t=setdoto(argv[i])) )
+				*loadp++ = t;
+			break;
+
+		case 'c':	/* C file */
+		case 's':	/* Assembler file */
+			if( unreadable(argv[i]) )
+				break;
+			fprintf(diagfile, "%s:\n", argv[i]);
+			sprintf(buff, "cc -c %s", argv[i] );
+			if( sys(buff) )
+				loadflag = NO;
+			else
+				if( nodup(t = setdoto(argv[i])) )
+					*loadp++ = t;
+			break;
+
+		case 'o':
+			if( nodup(argv[i]) )
+				*loadp++ = argv[i];
+			break;
+
+		default:
+			if( ! strcmp(argv[i], "-o") )
+				aoutname = argv[++i];
+			else
+				*loadp++ = argv[i];
+			break;
+		}
+
+	if(loadflag)
+		doload(loadargs, loadp);
+	done(0);
+	return 0;
+}
+
+#define	ADD(x)	addarg(params, &nparms, (x))
+
+static int
+dofort(char *s)
+{
+	int nparms, i;
+	char *params[MAXARGS];
+
+	nparms = 0;
+	ADD(FCOM);
+	for (i = 0; i < ffmax; i++)
+		ADD(ffary[i]);
+	ADD(s);
+	ADD(asmfname);
+	ADD(NULL);
+
+	infname = s;
+	if (callsys(fcom, params))
+		errorx("Error.  No assembly.");
+	doasm(s);
+
+	if (saveasmflag == NO)
+		rmf(asmfname);
+	return(0);
+}
+
+
+static void
+doasm(char *s)
+{
+	char *obj;
+	char *params[MAXARGS];
+	int nparms;
+
+	if (oflag && loadflag == NO)
+		obj = aoutname;
+	else
+		obj = setdoto(s);
+
+	nparms = 0;
+	ADD(asmname);
+	ADD("-o");
+	ADD(obj);
+	ADD(asmfname);
+	ADD(NULL);
+
+	if (callsys(asmname, params))
+		fatal1("assembler error");
+	if(verbose)
+		fprintf(diagfile, "\n");
+}
+
+
+static void
+doload(char *v0[], char *v[])
+{
+	int nparms, i;
+	char *params[MAXARGS];
+	char **p;
+
+	nparms = 0;
+	ADD(ldname);
+	ADD("-X");
+	ADD("-d");
+	for (i = 0; dynlinker[i]; i++)
+		ADD(dynlinker[i]);
+	ADD("-o");
+	ADD(aoutname);
+	ADD(crt0file);
+	for (i = 0; startfiles[i]; i++)
+		ADD(startfiles[i]);
+	*v = NULL;
+	for(p = v0; *p ; p++)
+		ADD(*p);
+	if (libdir)
+		ADD(libdir);
+	for(p = liblist ; *p ; p++)
+		ADD(*p);
+	for (i = 0; endfiles[i]; i++)
+		ADD(endfiles[i]);
+	ADD(NULL);
+
+	if (callsys(ldname, params))
+		fatal1("couldn't load %s", ldname);
+
+	if(verbose)
+		fprintf(diagfile, "\n");
+}
+
+/* Process control and Shell-simulating routines */
+
+/*
+ * Execute f[] with parameter array v[].
+ * Copied from cc.
+ */
+static int
+callsys(char f[], char *v[])
+{
+	int t, status = 0;
+	pid_t p;
+	char *s;
+
+	if (debugflag || verbose) {
+		fprintf(stderr, "%s ", f);
+		for (t = 1; v[t]; t++)
+			fprintf(stderr, "%s ", v[t]);
+		fprintf(stderr, "\n");
+	}
+
+	if ((p = fork()) == 0) {
+#ifdef notyet
+		if (Bflag) {
+			size_t len = strlen(Bflag) + 8;
+			char *a = malloc(len);
+			if (a == NULL) {
+				error("callsys: malloc failed");
+				exit(1);
+			}
+			if ((s = strrchr(f, '/'))) {
+				strlcpy(a, Bflag, len);
+				strlcat(a, s, len);
+				execv(a, v);
+			}
+		}
+#endif
+		execvp(f, v);
+		if ((s = strrchr(f, '/')))
+			execvp(s+1, v);
+		fprintf(stderr, "Can't find %s\n", f);
+		_exit(100);
+	} else {
+		if (p == -1) {
+			printf("Try again\n");
+			return(100);
+		}
+	}
+	while (waitpid(p, &status, 0) == -1 && errno == EINTR)
+		;
+	if (WIFEXITED(status))
+		return (WEXITSTATUS(status));
+	if (WIFSIGNALED(status))
+		done(1);
+	fatal1("Fatal error in %s", f);
+	return 0; /* XXX */
+}
+
+
+static int
+sys(char *str)
+{
+	char *s, *t;
+	char *argv[100], path[100];
+	char *inname, *outname;
+	int append = 0;
+	int wait_pid;
+	int argc;
+
+
+	if(debugflag)
+		fprintf(diagfile, "%s\n", str);
+	inname  = NULL;
+	outname = NULL;
+	argv[0] = shellname;
+	argc = 1;
+
+	t = str;
+	while( isspace((int)*t) )
+		++t;
+	while(*t) {
+		if(*t == '<')
+			inname = t+1;
+		else if(*t == '>') {
+			if(t[1] == '>') {
+				append = YES;
+				outname = t+2;
+			} else	{
+				append = NO;
+				outname = t+1;
+			}
+		} else
+			argv[argc++] = t;
+		while( !isspace((int)*t) && *t!='\0' )
+			++t;
+		if(*t) {
+			*t++ = '\0';
+			while( isspace((int)*t) )
+				++t;
+		}
+	}
+
+	if(argc == 1)   /* no command */
+		return(-1);
+	argv[argc] = 0;
+
+	s = path;
+	t = "/usr/bin/";
+	while(*t)
+		*s++ = *t++;
+	for(t = argv[1] ; (*s++ = *t++) ; )
+		;
+	if((wait_pid = fork()) == 0) {
+		if(inname)
+			freopen(inname, "r", stdin);
+		if(outname)
+			freopen(outname, (append ? "a" : "w"), stdout);
+		enbint(SIG_DFL);
+
+		texec(path+9, argv);  /* command */
+		texec(path+4, argv);  /*  /bin/command */
+		texec(path  , argv);  /* /usr/bin/command */
+
+		fatal1("Cannot load %s",path+9);
+	}
+
+	return( await(wait_pid) );
+}
+
+/* modified version from the Shell */
+static void
+texec(char *f, char **av)
+{
+
+	execv(f, av+1);
+
+	if (errno==ENOEXEC) {
+		av[1] = f;
+		execv(shellname, av);
+		fatal1("No shell!");
+	}
+	if (errno==ENOMEM)
+		fatal1("%s: too large", f);
+}
+
+/*
+ * Cleanup and exit with value k.
+ */
+static void
+done(int k)
+{
+	static int recurs	= NO;
+
+	if(recurs == NO) {
+		recurs = YES;
+		if (saveasmflag == NO)
+			rmf(asmfname);
+	}
+	exit(k);
+}
+
+
+static void
+enbint(void (*k)(int))
+{
+if(sigivalue == 0)
+	signal(SIGINT,k);
+if(sigqvalue == 0)
+	signal(SIGQUIT,k);
+}
+
+
+
+static void
+intrupt(int a)
+{
+done(2);
+}
+
+
+static int
+await(int wait_pid)
+{
+int w, status;
+
+enbint(SIG_IGN);
+while ( (w = wait(&status)) != wait_pid)
+	if(w == -1)
+		fatal1("bad wait code");
+enbint(intrupt);
+if(status & 0377)
+	{
+	if(status != SIGINT)
+		fprintf(diagfile, "Termination code %d", status);
+	done(3);
+	}
+return(status>>8);
+}
+
+
+/* File Name and File Manipulation Routines */
+
+static int
+unreadable(char *s)
+{
+	FILE *fp;
+
+	if((fp = fopen(s, "r"))) {
+		fclose(fp);
+		return(NO);
+	} else {
+		fprintf(diagfile, "Error: Cannot read file %s\n", s);
+		loadflag = NO;
+		return(YES);
+	}
+}
+
+
+static void
+crfnames(void)
+{
+	sprintf(asmfname,  "fort%d.%s", pid, "s");
+	sprintf(prepfname, "fort%d.%s", pid, "p");
+}
+
+
+
+static void
+rmf(char *fn)
+{
+if(!debugflag && fn!=NULL && *fn!='\0')
+	unlink(fn);
+}
+
+
+static int
+dotchar(char *s)
+{
+for( ; *s ; ++s)
+	if(s[0]=='.' && s[1]!='\0' && s[2]=='\0')
+		return( s[1] );
+return(NO);
+}
+
+
+static char *
+lastfield(char *s)
+{
+char *t;
+for(t = s; *s ; ++s)
+	if(*s == '/')
+		t = s+1;
+return(t);
+}
+
+
+static char *
+lastchar(char *s)
+{
+while(*s)
+	++s;
+return(s-1);
+}
+
+
+static char *
+setdoto(char *s)
+{
+*lastchar(s) = 'o';
+return( lastfield(s) );
+}
+
+
+static char *
+copyn(int n, char *s)
+{
+	char *p, *q;
+
+	p = q = (char *)calloc(1, (unsigned) n + 1);
+	if (!p)
+		fatal1("out of memory");
+
+	while(n-- > 0)
+		*q++ = *s++;
+	return (p);
+}
+
+
+static int
+nodup(char *s)
+{
+char **p;
+
+for(p = loadargs ; p < loadp ; ++p)
+	if( !strcmp(*p, s) )
+		return(NO);
+
+return(YES);
+}
+
+
+static void
+errorx(char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	vfprintf(diagfile, fmt, ap);
+	fprintf(diagfile, "\n");
+	va_end(ap);
+
+	if (debugflag)
+		abort();
+	done(1);
+}
+
+
+static void
+fatal1(char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	fprintf(diagfile, "Compiler error in file %s: ", infname);
+	vfprintf(diagfile, fmt, ap);
+	fprintf(diagfile, "\n");
+	va_end(ap);
+
+	if (debugflag)
+		abort();
+	done(1);
+}
Index: uspace/app/pcc/f77/fcom/Makefile.in
===================================================================
--- uspace/app/pcc/f77/fcom/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/Makefile.in	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,121 @@
+#	$Id: Makefile.in,v 1.13 2008/12/19 08:08:48 ragge Exp $
+#
+# Makefile for the Fortran 77 command
+#  Running on the @targmach@
+#  Generating code for the @targmach@
+#  Using the Johnson C compiler's second pass (binary version)
+VPATH=@srcdir@
+srcdir=@srcdir@
+top_srcdir=@top_srcdir@
+builddir=@builddir@
+top_builddir=@top_builddir@
+XFL=-DPCC_DEBUG  -Wall -Wmissing-prototypes -Wstrict-prototypes -Werror \
+	-Werror -Wshadow -Wsign-compare
+
+CC = @CC@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@ @ADD_CFLAGS@
+CPPFLAGS = @CPPFLAGS@ ${XFL} -DFCOM -DLANG_F77 -Dos_${TARGOS} \
+	-I${srcdir} -I${builddir} -I${top_builddir} \
+	-I${MIPDIR} -I${MDIR} -Dmach_${TARGMACH} -I${top_srcdir}/os/${TARGOS}
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+TARGOS = @targos@
+TARGMACH = @targmach@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+libexecdir = @libexecdir@
+datarootdir = @datarootdir@
+mandir = @mandir@
+strip = @strip@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+YFLAGS = -d
+
+MDIR=$(top_srcdir)/arch/$(TARGMACH)
+MIPDIR=$(top_srcdir)/mip
+
+DEST=@BINPREFIX@fcom
+
+OBJS1 = main.o init.o proc.o gram.o lex.o \
+	  equiv.o data.o expr.o exec.o intr.o io.o misc.o error.o\
+	  put.o putscj.o flocal.o
+
+OBJS2=match.o reader.o optim2.o regs.o local2.o order.o table.o
+
+OBJS=$(OBJS1) $(OBJS2) common.o external.o
+
+all: ${DEST}
+
+${DEST}: $(OBJS)
+	$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $@
+
+gram.c:	gram.head gram.dcl gram.expr gram.exec gram.io tokdefs
+	( sed <tokdefs "s/#define/%token/" ;\
+		cat gram.head gram.dcl gram.expr gram.exec gram.io ) >gram.in
+	$(YACC) $(YFLAGS) gram.in
+	mv y.tab.c gram.c
+	mv y.tab.h gram.h
+	rm gram.in
+
+tokdefs: tokens
+	grep -n . <tokens | sed "s/\([^:]*\):\(.*\)/#define \2 \1/" >tokdefs
+
+lex.o : tokdefs
+driver.o $(OBJS)  : defs.h defines.h ftypes.h
+
+clean:
+	/bin/rm -f $(OBJS) ${DEST} gram.in gram.[ch] tokdefs \
+		mkext external.[ch]
+
+distclean: clean
+	/bin/rm -f Makefile
+
+install: 
+	${INSTALL_PROGRAM} ${DEST} ${libexecdir}
+	@if [ ${strip} = yes ]; then            \
+		strip ${libexecdir}/${DEST} ;       \
+		echo strip ${libexecdir}/${DEST} ;  \
+	fi
+
+.c.o :
+	$(CC) -c $(CFLAGS) $(CPPFLAGS) $*.c
+
+flocal.o: $(MDIR)/flocal.c
+	$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $(MDIR)/flocal.c
+
+local2.o: $(MDIR)/local2.c
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MDIR)/local2.c
+
+order.o: $(MDIR)/order.c
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MDIR)/order.c
+
+table.o: $(MDIR)/table.c
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MDIR)/table.c
+
+match.o: $(MIPDIR)/match.c
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/match.c
+
+reader.o: $(MIPDIR)/reader.c
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/reader.c
+
+optim2.o: $(MIPDIR)/optim2.c
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/optim2.c
+
+regs.o: $(MIPDIR)/regs.c
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/regs.c
+
+compat.o: $(MIPDIR)/compat.c
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/compat.c
+
+common.o: $(MIPDIR)/common.c
+	$(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(MIPDIR)/common.c
+
+external.h external.c: ${MIPDIR}/mkext.c $(MDIR)/table.c
+	$(CC_FOR_BUILD) $(DEFS) $(CPPFLAGS) $(CFLAGS) -DMKEXT -o mkext \
+	${MIPDIR}/mkext.c $(MDIR)/table.c ${MIPDIR}/common.c
+	./mkext
+	-rm -f mkext.o table.o common.o
+
+$(OBJS): external.h
+
Index: uspace/app/pcc/f77/fcom/data.c
===================================================================
--- uspace/app/pcc/f77/fcom/data.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/data.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,358 @@
+/*	$Id: data.c,v 1.15 2008/05/11 15:28:03 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 "defines.h"
+#include "defs.h"
+
+#if 1 /* RAGGE */
+extern FILE *initfile;
+#endif
+
+/* ROUTINES CALLED DURING DATA STATEMENT PROCESSING */
+LOCAL void setdata(struct bigblock *, struct bigblock *, ftnint, ftnint);
+
+static char datafmt[] = "%s\t%05ld\t%05ld\t%d" ;
+
+/* another initializer, called from parser */
+void
+dataval(repp, valp)
+register struct bigblock *repp, *valp;
+{
+int i, nrep;
+ftnint elen, vlen;
+register struct bigblock *p;
+
+if(repp == NULL)
+	nrep = 1;
+else if (ISICON(repp) && repp->b_const.fconst.ci >= 0)
+	nrep = repp->b_const.fconst.ci;
+else
+	{
+	err("invalid repetition count in DATA statement");
+	frexpr(repp);
+	goto ret;
+	}
+frexpr(repp);
+
+if( ! ISCONST(valp) )
+	{
+	err("non-constant initializer");
+	goto ret;
+	}
+
+if(toomanyinit) goto ret;
+for(i = 0 ; i < nrep ; ++i)
+	{
+	p = nextdata(&elen, &vlen);
+	if(p == NULL)
+		{
+		err("too many initializers");
+		toomanyinit = YES;
+		goto ret;
+		}
+	setdata(p, valp, elen, vlen);
+	frexpr(p);
+	}
+
+ret:
+	frexpr(valp);
+}
+
+
+struct bigblock *nextdata(elenp, vlenp)
+ftnint *elenp, *vlenp;
+{
+register struct bigblock *ip;
+struct bigblock *pp;
+register struct bigblock *np;
+register chainp rp;
+bigptr p;
+bigptr neltp;
+register bigptr q;
+int skip;
+ftnint off;
+
+while(curdtp)
+	{
+	p = curdtp->chain.datap;
+	if(p->tag == TIMPLDO)
+		{
+		ip = p;
+		if(ip->b_impldo.implb==NULL || ip->b_impldo.impub==NULL || ip->b_impldo.varnp==NULL)
+			fatal1("bad impldoblock 0%o", ip);
+		if(ip->isactive)
+			ip->b_impldo.varvp->b_const.fconst.ci += ip->b_impldo.impdiff;
+		else
+			{
+			q = fixtype(cpexpr(ip->b_impldo.implb));
+			if( ! ISICON(q) )
+				goto doerr;
+			ip->b_impldo.varvp = q;
+
+			if(ip->b_impldo.impstep)
+				{
+				q = fixtype(cpexpr(ip->b_impldo.impstep));
+				if( ! ISICON(q) )
+					goto doerr;
+				ip->b_impldo.impdiff = q->b_const.fconst.ci;
+				frexpr(q);
+				}
+			else
+				ip->b_impldo.impdiff = 1;
+
+			q = fixtype(cpexpr(ip->b_impldo.impub));
+			if(! ISICON(q))
+				goto doerr;
+			ip->b_impldo.implim = q->b_const.fconst.ci;
+			frexpr(q);
+
+			ip->isactive = YES;
+			rp = ALLOC(rplblock);
+			rp->rplblock.nextp = rpllist;
+			rpllist = rp;
+			rp->rplblock.rplnp = ip->b_impldo.varnp;
+			rp->rplblock.rplvp = ip->b_impldo.varvp;
+			rp->rplblock.rpltag = TCONST;
+			}
+
+		if( (ip->b_impldo.impdiff>0 &&
+		 (ip->b_impldo.varvp->b_const.fconst.ci <= ip->b_impldo.implim))
+		 || (ip->b_impldo.impdiff<0 &&
+		(ip->b_impldo.varvp->b_const.fconst.ci >= ip->b_impldo.implim)))
+			{ /* start new loop */
+			curdtp = ip->b_impldo.datalist;
+			goto next;
+			}
+
+		/* clean up loop */
+
+		popstack(&rpllist);
+
+		frexpr(ip->b_impldo.varvp);
+		ip->isactive = NO;
+		curdtp = curdtp->chain.nextp;
+		goto next;
+		}
+
+	pp = p;
+	np = pp->b_prim.namep;
+	skip = YES;
+
+	if(p->b_prim.argsp==NULL && np->b_name.vdim!=NULL)
+		{   /* array initialization */
+		q = mkaddr(np);
+		off = typesize[np->vtype] * curdtelt;
+		if(np->vtype == TYCHAR)
+			off *= np->vleng->b_const.fconst.ci;
+		q->b_addr.memoffset = mkexpr(OPPLUS, q->b_addr.memoffset, mkintcon(off) );
+		if( (neltp = np->b_name.vdim->nelt) && ISCONST(neltp))
+			{
+			if(++curdtelt < neltp->b_const.fconst.ci)
+				skip = NO;
+			}
+		else
+			err("attempt to initialize adjustable array");
+		}
+	else
+		q = mklhs( cpexpr(pp) );
+	if(skip)
+		{
+		curdtp = curdtp->chain.nextp;
+		curdtelt = 0;
+		}
+	if(q->vtype == TYCHAR)
+		if(ISICON(q->vleng))
+			*elenp = q->vleng->b_const.fconst.ci;
+		else	{
+			err("initialization of string of nonconstant length");
+			continue;
+			}
+	else	*elenp = typesize[q->vtype];
+
+	if(np->vstg == STGCOMMON)
+		*vlenp = extsymtab[np->b_name.vardesc.varno].maxleng;
+	else if(np->vstg == STGEQUIV)
+		*vlenp = eqvclass[np->b_name.vardesc.varno].eqvleng;
+	else	{
+		*vlenp =  (np->vtype==TYCHAR ?
+				np->vleng->b_const.fconst.ci : typesize[np->vtype]);
+		if(np->b_name.vdim)
+			*vlenp *= np->b_name.vdim->nelt->b_const.fconst.ci;
+		}
+	return(q);
+
+doerr:
+		err("nonconstant implied DO parameter");
+		frexpr(q);
+		curdtp = curdtp->chain.nextp;
+
+next:	curdtelt = 0;
+	}
+
+return(NULL);
+}
+
+
+
+
+
+
+LOCAL void setdata(varp, valp, elen, vlen)
+struct bigblock *varp;
+ftnint elen, vlen;
+struct bigblock *valp;
+{
+union constant con;
+int i, k;
+int stg, type, valtype;
+ftnint offset;
+register char *s, *t;
+static char varname[XL+2];
+
+/* output form of name is padded with blanks and preceded
+   with a storage class digit
+*/
+
+stg = varp->vstg;
+varname[0] = (stg==STGCOMMON ? '2' : (stg==STGEQUIV ? '1' : '0') );
+s = memname(stg, varp->b_addr.memno);
+for(t = varname+1 ; *s ; )
+	*t++ = *s++;
+while(t < varname+XL+1)
+	*t++ = ' ';
+varname[XL+1] = '\0';
+
+offset = varp->b_addr.memoffset->b_const.fconst.ci;
+type = varp->vtype;
+valtype = valp->vtype;
+if(type!=TYCHAR && valtype==TYCHAR)
+	{
+	if(! ftn66flag)
+		warn("non-character datum initialized with character string");
+	varp->vleng = MKICON(typesize[type]);
+	varp->vtype = type = TYCHAR;
+	}
+else if( (type==TYCHAR && valtype!=TYCHAR) ||
+	 (cktype(OPASSIGN,type,valtype) == TYERROR) )
+	{
+	err("incompatible types in initialization");
+	return;
+	}
+if(type != TYCHAR) {
+	if(valtype == TYUNKNOWN)
+		con.ci = valp->b_const.fconst.ci;
+	else	consconv(type, &con, valtype, &valp->b_const.fconst);
+}
+
+k = 1;
+switch(type)
+	{
+	case TYLOGICAL:
+		type = tylogical;
+	case TYSHORT:
+	case TYLONG:
+		fprintf(initfile, datafmt, varname, offset, vlen, type);
+		prconi(initfile, type, con.ci);
+		break;
+
+	case TYCOMPLEX:
+		k = 2;
+		type = TYREAL;
+	case TYREAL:
+		goto flpt;
+
+	case TYDCOMPLEX:
+		k = 2;
+		type = TYDREAL;
+	case TYDREAL:
+	flpt:
+
+		for(i = 0 ; i < k ; ++i)
+			{
+			fprintf(initfile, datafmt, varname, offset, vlen, type);
+			prconr(initfile, type, con.cd[i]);
+			offset += typesize[type];
+			}
+		break;
+
+	case TYCHAR:
+		k = valp->vleng->b_const.fconst.ci;
+		if(elen < k)
+			k = elen;
+
+		for(i = 0 ; i < k ; ++i)
+			{
+			fprintf(initfile, datafmt, varname, offset++, vlen, TYCHAR);
+			fprintf(initfile, "\t%d\n", valp->b_const.fconst.ccp[i]);
+			}
+		k = elen - valp->vleng->b_const.fconst.ci;
+		while( k-- > 0)
+			{
+			fprintf(initfile, datafmt, varname, offset++, vlen, TYCHAR);
+			fprintf(initfile, "\t%d\n", ' ');
+			}
+		break;
+
+	default:
+		fatal1("setdata: impossible type %d", type);
+	}
+
+}
+
+
+void
+frdata(p0)
+chainp p0;
+{
+register chainp p;
+register bigptr q;
+
+for(p = p0 ; p ; p = p->chain.nextp)
+	{
+	q = p->chain.datap;
+	if(q->tag == TIMPLDO)
+		{
+		if(q->isbusy)
+			return;	/* circular chain completed */
+		q->isbusy = YES;
+		frdata(q->b_impldo.datalist);
+		ckfree(q);
+		}
+	else
+		frexpr(q);
+	}
+
+frchain( &p0);
+}
Index: uspace/app/pcc/f77/fcom/defines.h
===================================================================
--- uspace/app/pcc/f77/fcom/defines.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/defines.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,267 @@
+/*	$Id: defines.h,v 1.15 2008/05/10 07:53:41 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>
+
+#ifdef FCOM
+#include "pass2.h"
+#endif
+#include "ftypes.h"
+
+#define INTERDATA 2
+#define GCOS 3
+#define PDP11 4
+#define IBM 5
+#define CMACH 6
+#define VAX 7
+
+#define DMR 2
+#define SCJ 3
+
+#define BINARY 2
+#define ASCII 3
+
+#define PREFIX 2
+#define POSTFIX 3
+
+#define M(x) (1<<x)
+#define ALLOC(x) ckalloc(sizeof(struct x))
+#define	BALLO()	(bigptr)ckalloc(sizeof(struct bigblock))
+typedef void *ptr;
+typedef FILE *FILEP;
+typedef short flag;
+typedef long int ftnint;
+#define LOCAL static
+
+#define NO 0
+#define YES 1
+
+
+
+/* block tag values */
+
+#define TNAME 1
+#define TCONST 2
+#define TEXPR 3
+#define TADDR 4
+#define TPRIM 5
+#define TLIST 6
+#define TIMPLDO 7
+#define TERROR 8
+
+
+/* parser states */
+
+#define OUTSIDE 0
+#define INSIDE 1
+#define INDCL 2
+#define INDATA 3
+#define INEXEC 4
+
+/* procedure classes */
+
+#define PROCMAIN 1
+#define PROCBLOCK 2
+#define PROCSUBR 3
+#define PROCFUNCT 4
+
+
+/* storage classes */
+
+#define STGUNKNOWN 0
+#define STGARG 1
+#define STGAUTO 2
+#define STGBSS 3
+#define STGINIT 4
+#define STGCONST 5
+#define STGEXT 6
+#define STGINTR 7
+#define STGSTFUNCT 8
+#define STGCOMMON 9
+#define STGEQUIV 10
+#define STGREG 11
+#define STGLENG 12
+
+/* name classes */
+
+#define CLUNKNOWN 0
+#define CLPARAM 1
+#define CLVAR 2
+#define CLENTRY 3
+#define CLMAIN 4
+#define CLBLOCK 5
+#define CLPROC 6
+
+
+/* vproclass values */
+
+#define PUNKNOWN 0
+#define PEXTERNAL 1
+#define PINTRINSIC 2
+#define PSTFUNCT 3
+#define PTHISPROC 4
+
+/* control stack codes */
+
+#define CTLDO 1
+#define CTLIF 2
+#define CTLELSE 3
+
+
+/* operators */
+
+#define OPPLUS 1
+#define OPMINUS 2
+#define OPSTAR 3
+#define OPSLASH 4
+#define OPPOWER 5
+#define OPNEG 6
+#define OPOR 7
+#define OPAND 8
+#define OPEQV 9
+#define OPNEQV 10
+#define OPNOT 11
+#define OPCONCAT 12
+#define OPLT 13
+#define OPEQ 14
+#define OPGT 15
+#define OPLE 16
+#define OPNE 17
+#define OPGE 18
+#define OPCALL 19
+#define OPCCALL 20
+#define OPASSIGN 21
+/* #define OPPLUSEQ 22 */
+/* #define OPSTAREQ 23 */
+#define OPCONV 24
+#define OPLSHIFT 25
+#define OPMOD 26
+#define OPCOMMA 27
+/* #define OPQUEST 28 */
+/* #define OPCOLON 29 */
+#define OPABS 30
+#define OPMIN 31
+#define OPMAX 32
+#define OPADDR 33
+#define OPINDIRECT 34
+#define OPBITOR 35
+#define OPBITAND 36
+#define OPBITXOR 37
+#define OPBITNOT 38
+#define OPRSHIFT 39
+
+
+/* memory regions */
+
+#define REGARG 1
+#define REGAUTO 2
+#define REGBSS 3
+#define REGINIT 4
+#define REGCONST 5
+#define REGEXT 6
+#define REGPROG 7
+
+/* label type codes */
+
+#define LABUNKNOWN 0
+#define LABEXEC 1
+#define LABFORMAT 2
+#define LABOTHER 3
+
+
+/* INTRINSIC function codes*/
+
+#define INTREND 0
+#define INTRCONV 1
+#define INTRMIN 2
+#define INTRMAX 3
+#define INTRGEN 4
+#define INTRSPEC 5
+#define INTRBOOL 6
+#define INTRCNST 7
+
+
+/* I/O statement codes */
+
+#define IOSTDIN MKICON(5)
+#define IOSTDOUT MKICON(6)
+
+#define IOSBAD (-1)
+#define IOSPOSITIONAL 0
+#define IOSUNIT 1
+#define IOSFMT 2
+
+#define IOINQUIRE 1
+#define IOOPEN 2
+#define IOCLOSE 3
+#define IOREWIND 4
+#define IOBACKSPACE 5
+#define IOENDFILE 6
+#define IOREAD 7
+#define IOWRITE 8
+
+
+/* type masks */
+
+#define MSKLOGICAL	M(TYLOGICAL)
+#define MSKADDR	M(TYADDR)
+#define MSKCHAR	M(TYCHAR)
+#define MSKINT	M(TYSHORT)|M(TYLONG)
+#define MSKREAL	M(TYREAL)|M(TYDREAL)
+#define MSKCOMPLEX	M(TYCOMPLEX)|M(TYDCOMPLEX)
+
+/* miscellaneous macros */
+
+#define ONEOF(x,y) (M(x) & (y))
+#define ISCOMPLEX(z) ONEOF(z, MSKCOMPLEX)
+#define ISREAL(z) ONEOF(z, MSKREAL)
+#define ISNUMERIC(z) ONEOF(z, MSKINT|MSKREAL|MSKCOMPLEX)
+#define ISICON(z) (z->tag==TCONST && ISINT(z->vtype))
+#define ISCHAR(z) (z->vtype==TYCHAR)
+#define ISINT(z)   ONEOF(z, MSKINT)
+#define ISCONST(z) (z->tag==TCONST)
+#define ISERROR(z) (z->tag==TERROR)
+#define ISPLUSOP(z) (z->tag==TEXPR && z->b_expr.opcode==OPPLUS)
+#define ISSTAROP(z) (z->tag==TEXPR && z->b_expr.opcode==OPSTAR)
+#define ISONE(z) (ISICON(z) && z->b_const.fconst.ci==1)
+/* #define INT(z) ONEOF(z, MSKINT|MSKCHAR) */
+#define MKICON(z) mkintcon( (ftnint)(z) )
+#define CHCON(z) mkstrcon(strlen(z), z)
+
+/* round a up to a multiple of b */
+#define roundup(a,b)    ( b * ( (a+b-1)/b) )
+
+/* prototypes for cpu-specific functions */
+void prchars(int *);
+
Index: uspace/app/pcc/f77/fcom/defs.h
===================================================================
--- uspace/app/pcc/f77/fcom/defs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/defs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,563 @@
+/*	$Id: defs.h,v 1.22 2008/12/24 17:40:41 sgk 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 <ctype.h>
+#include <stdlib.h>
+
+#define VL 6
+#define XL 8
+
+#define MAXINCLUDES 10
+#define MAXLITERALS 20
+#define MAXCTL 20
+#define MAXHASH 401
+#define MAXSTNO 1000
+#define MAXEXT 200
+#define MAXEQUIV 150
+#define MAXLABLIST 100
+
+typedef struct bigblock *bigptr;
+typedef union chainedblock *chainp;
+
+extern FILE *infile;
+extern FILE *diagfile;
+extern long int headoffset;
+
+extern char token [ ];
+extern int toklen;
+extern int lineno;
+extern char *infname;
+extern int needkwd;
+extern struct labelblock *thislabel;
+
+extern int mflag, tflag;
+
+extern flag profileflag;
+extern flag optimflag;
+extern flag quietflag;
+extern flag nowarnflag;
+extern flag ftn66flag;
+extern flag shiftcase;
+extern flag undeftype;
+extern flag shortsubs;
+extern flag onetripflag;
+extern flag checksubs;
+extern flag debugflag;
+extern int nerr;
+extern int nwarn;
+extern int ndata;
+
+extern int parstate;
+extern flag headerdone;
+extern int blklevel;
+extern flag saveall;
+extern flag substars;
+extern int impltype[ ];
+extern int implleng[ ];
+extern int implstg[ ];
+
+extern int tyint;
+extern int tylogical;
+extern ftnint typesize[];
+extern int typealign[];
+extern int procno;
+extern int proctype;
+extern char * procname;
+extern int rtvlabel[ ];
+extern int fudgelabel;	/* to confuse the pdp11 optimizer */
+extern struct bigblock *typeaddr;
+extern struct bigblock *retslot;
+extern int cxslot;
+extern int chslot;
+extern int chlgslot;
+extern int procclass;
+extern ftnint procleng;
+extern int nentry;
+extern flag multitype;
+extern int blklevel;
+extern int lastlabno;
+extern int lastvarno;
+extern int lastargslot;
+extern int argloc;
+extern ftnint autoleng;
+extern ftnint bssleng;
+extern int retlabel;
+extern int ret0label;
+extern int dorange;
+extern int regnum[ ];
+extern bigptr regnamep[ ];
+extern int maxregvar;
+extern int highregvar;
+
+extern chainp templist;
+extern chainp holdtemps;
+extern chainp entries;
+extern chainp rpllist;
+extern chainp curdtp;
+extern ftnint curdtelt;
+extern flag toomanyinit;
+
+extern flag inioctl;
+extern int iostmt;
+extern struct bigblock *ioblkp;
+extern int nioctl;
+extern int nequiv;
+extern int nintnames;
+extern int nextnames;
+
+
+struct chain
+	{
+	chainp nextp;
+	bigptr datap;
+	};
+
+extern chainp chains;
+
+struct ctlframe
+	{
+	unsigned ctltype:8;
+	unsigned dostepsign:8;
+	int ctlabels[4];
+	int dolabel;
+	struct bigblock *donamep;
+	bigptr domax;
+	bigptr dostep;
+	};
+#define endlabel ctlabels[0]
+#define elselabel ctlabels[1]
+#define dobodylabel ctlabels[1]
+#define doposlabel ctlabels[2]
+#define doneglabel ctlabels[3]
+extern struct ctlframe ctls[ ];
+extern struct ctlframe *ctlstack;
+extern struct ctlframe *lastctl;
+
+struct extsym
+	{
+	char extname[XL];
+	unsigned extstg:4;
+	unsigned extsave:1;
+	unsigned extinit:1;
+	chainp extp;
+	ftnint extleng;
+	ftnint maxleng;
+	};
+
+extern struct extsym extsymtab[ ];
+extern struct extsym *nextext;
+extern struct extsym *lastext;
+
+struct labelblock
+	{
+	int labelno;
+	unsigned blklevel:8;
+	unsigned labused:1;
+	unsigned labinacc:1;
+	unsigned labdefined:1;
+	unsigned labtype:2;
+	ftnint stateno;
+	};
+
+extern struct labelblock labeltab[ ];
+extern struct labelblock *labtabend;
+extern struct labelblock *highlabtab;
+
+struct entrypoint
+	{
+	chainp nextp;
+	struct extsym *entryname;
+	chainp arglist;
+	int entrylabel;
+	int typelabel;
+	ptr enamep;
+	};
+
+struct primblock
+	{
+	struct bigblock *namep;
+	struct bigblock *argsp;
+	bigptr fcharp;
+	bigptr lcharp;
+	};
+
+
+struct hashentry
+	{
+	int hashval;
+	struct bigblock *varp;
+	};
+extern struct hashentry hashtab[ ];
+extern struct hashentry *lasthash;
+
+struct intrpacked	/* bits for intrinsic function description */
+	{
+	unsigned f1:3;
+	unsigned f2:4;
+	unsigned f3:7;
+	};
+
+struct nameblock
+	{
+	char varname[VL];
+	unsigned vdovar:1;
+	unsigned vdcldone:1;
+	unsigned vadjdim:1;
+	unsigned vsave:1;
+	unsigned vprocclass:3;
+	unsigned vregno:4;
+	union	{
+		int varno;
+		chainp vstfdesc;	/* points to (formals, expr) pair */
+		struct intrpacked intrdesc;	/* bits for intrinsic function */
+		} vardesc;
+	struct dimblock *vdim;
+	int voffset;
+	};
+
+
+struct paramblock
+	{
+	char varname[VL];
+	bigptr paramval;
+	} ;
+
+
+struct exprblock
+	{
+	unsigned opcode:6;
+	bigptr leftp;
+	bigptr rightp;
+	};
+
+struct dcomplex {
+	double dreal, dimag;
+};
+
+union constant
+	{
+	char *ccp;
+	ftnint ci;
+	double cd[2];
+	struct dcomplex dc;
+	};
+
+struct constblock
+	{
+	union constant fconst;
+	};
+
+
+struct listblock
+	{
+	chainp listp;
+	};
+
+
+
+struct addrblock
+	{
+	int memno;
+	bigptr memoffset;
+	unsigned istemp:1;
+	unsigned ntempelt:10;
+	};
+
+
+
+struct errorblock
+	{
+	int pad;
+	};
+
+
+struct dimblock
+	{
+	int ndim;
+	bigptr nelt;
+	bigptr baseoffset;
+	bigptr basexpr;
+	struct
+		{
+		bigptr dimsize;
+		bigptr dimexpr;
+		} dims[1];
+	};
+
+
+struct impldoblock  /* XXXX */
+	{
+#define	isactive vtype
+#define isbusy vclass
+	struct bigblock *varnp;
+	struct bigblock *varvp;
+	bigptr implb;
+	bigptr impub;
+	bigptr impstep;
+	ftnint impdiff;
+	ftnint implim;
+	chainp datalist;
+	};
+
+
+struct rplblock	/* name replacement block */
+	{
+	chainp nextp;
+	struct bigblock *rplnp;
+	ptr rplvp;
+	struct bigblock *rplxp;
+	int rpltag;
+	};
+
+
+
+struct equivblock
+	{
+	ptr equivs;
+	unsigned eqvinit:1;
+	long int eqvtop;
+	long int eqvbottom;
+	} ;
+#define eqvleng eqvtop
+
+extern struct equivblock eqvclass[ ];
+
+
+struct eqvchain
+	{
+	chainp nextp;
+	ptr eqvitem;
+	long int eqvoffset;
+	} ;
+
+union chainedblock
+	{
+	struct chain chain;
+	struct entrypoint entrypoint;
+	struct rplblock rplblock;
+	struct eqvchain eqvchain;
+	};
+
+
+struct bigblock {
+	unsigned tag:4;
+	unsigned vtype:4;
+	unsigned vclass:4;
+	unsigned vstg:4;
+	bigptr vleng;
+	union {
+		struct exprblock _expr;
+		struct addrblock _addr;
+		struct constblock _const;
+		struct errorblock _error;
+		struct listblock _list;
+		struct primblock _prim;
+		struct nameblock _name;
+		struct paramblock _param;
+		struct impldoblock _impldo;
+	} _u;
+#define	b_expr		_u._expr
+#define	b_addr		_u._addr
+#define	b_const		_u._const
+#define	b_error		_u._error
+#define	b_list		_u._list
+#define	b_prim		_u._prim
+#define	b_name		_u._name
+#define	b_param		_u._param
+#define	b_impldo	_u._impldo
+};
+
+struct literal
+	{
+	short littype;
+	short litnum;
+	union	{
+		ftnint litival;
+		double litdval;
+		struct	{
+			char litclen;	/* small integer */
+			char litcstr[XL];
+			} litcval;
+		} litval;
+	};
+
+extern struct literal litpool[ ];
+extern int nliterals;
+
+
+
+
+
+/* popular functions with non integer return values */
+#define	expptr bigptr
+#define	tagptr bigptr
+
+ptr cpblock(int ,void *);
+
+ptr ckalloc(int);
+char *varstr(int, char *), *nounder(int, char *), *varunder(int, char *);
+char *copyn(int, char *), *copys(char *);
+chainp hookup(chainp, chainp), mkchain(bigptr, chainp);
+ftnint convci(int, char *), iarrlen(struct bigblock *q);
+ftnint lmin(ftnint, ftnint), lmax(ftnint, ftnint);
+ftnint simoffset(expptr *);
+char *memname(int, int), *convic(ftnint), *setdoto(char *);
+double convcd(int, char *);
+struct extsym *mkext(char *), 
+	*newentry(struct bigblock *),
+	*comblock(int, char *s);
+struct bigblock *mkname(int, char *);
+struct labelblock *mklabel(ftnint);
+struct bigblock *addrof(expptr), *call1(int, char *, expptr),
+	*call2(int, char *, expptr, expptr),
+	*call3(int, char *, expptr, expptr, expptr),
+	*call4(int, char *, expptr, expptr, expptr, expptr);
+struct bigblock *call0(int, char *), *mkexpr(int, bigptr, bigptr);
+struct bigblock *callk(int, char *, bigptr);
+
+struct bigblock *builtin(int, char *), *fmktemp(int, bigptr),
+	*mktmpn(int, int, bigptr), *nextdata(ftnint *, ftnint *),
+	*autovar(int, int, bigptr), *mklhs(struct bigblock *),
+	*mkaddr(struct bigblock *), *putconst(struct bigblock *),
+	*memversion(struct bigblock *);
+struct bigblock *mkscalar(struct bigblock *np);
+struct bigblock *realpart(struct bigblock *p);
+struct bigblock *imagpart(struct bigblock *p);
+
+struct bigblock *mkintcon(ftnint), *mkbitcon(int, int, char *),
+	*mklogcon(int), *mkaddcon(int), *mkrealcon(int, double),
+	*mkstrcon(int, char *), *mkcxcon(bigptr,bigptr);
+bigptr mkconst(int t);
+
+bigptr mklist(chainp p);
+bigptr mkiodo(chainp, chainp);
+
+
+bigptr mkconv(int, bigptr),
+	mkfunct(struct bigblock *), fixexpr(struct bigblock *),
+	fixtype(bigptr);
+
+
+bigptr cpexpr(bigptr), mkprim(bigptr, struct bigblock *, bigptr, bigptr);
+struct bigblock *mkarg(int, int);
+struct bigblock *errnode(void);
+void initkey(void), prtail(void), puteof(void), done(int);
+void fileinit(void), procinit(void), endproc(void), doext(void), preven(int);
+int inilex(char *), yyparse(void), newlabel(void), lengtype(int, int);
+void err(char *, ...), warn(char *, ...), fatal(char *, ...), enddcl(void);
+void p2pass(char *s), frexpr(bigptr), execerr(char *, ...);
+void setimpl(int, ftnint, int, int), setlog(void), newproc(void);
+void prdbginfo(void), impldcl(struct bigblock *p);
+void putbracket(void), enddcl(void), doequiv(void);
+void puthead(char *), startproc(struct extsym *, int);
+void dclerr(char *s, struct bigblock *v), putforce(int, bigptr);
+void entrypt(int, int, ftnint, struct extsym *, chainp);
+void settype(struct bigblock *, int, int), putlabel(int);
+void putbranch(struct bigblock *p), goret(int), putrbrack(int);
+void prolog(struct entrypoint *, struct bigblock *), prendproc(void);
+void prlocvar(char *, ftnint), prext(char *, ftnint, int);
+void vardcl(struct bigblock *v), frchain(chainp *p); 
+void frtemp(struct bigblock *p), incomm(struct extsym *, struct bigblock *);
+void setintr(struct bigblock * v), setext(struct bigblock * v);
+struct uux { expptr lb, ub; };
+void setbound(struct bigblock *, int, struct uux []);
+void setfmt(struct labelblock *lp), frdata(chainp), frrpl(void),
+	dataval(struct bigblock *, struct bigblock *),
+	consnegop(struct bigblock *p), exdo(int, chainp), exelse(void),
+	exendif(void), exif(bigptr), exelif(bigptr),
+	exequals(struct bigblock *, bigptr),
+	exassign(struct bigblock *, struct labelblock *),
+	exarif(bigptr, struct labelblock *, struct labelblock *,
+	    struct labelblock *);
+
+
+
+int intrfunct(char s[VL]), eqn(int, char *, char *);
+int fmtstmt(struct labelblock *lp);
+int cktype(int, int, int);
+int yylex(void), inregister(struct bigblock *);
+int inilex(char *), iocname(void);
+int maxtype(int, int), flog2(ftnint), hextoi(int);
+int cmpstr(char *, char *, ftnint, ftnint);
+int enregister(struct bigblock *np);
+int conssgn(bigptr p);
+int fixargs(int, struct bigblock *);
+int addressable(bigptr p);
+
+void prlabel(int);
+void prconi(FILE *, int, ftnint);
+void prcona(ftnint);
+void prconr(FILE *, int, double);
+void prarif(bigptr, int, int, int);
+void putstr(char *, ftnint);
+NODE *putex1(bigptr p);
+void puteq(bigptr, bigptr);
+void popstack(chainp *p); 
+void consconv(int, union constant *, int, union constant *);
+void yyerror(char *s);
+void enddo(int);
+void doinclude(char *);
+void flline(void);
+void startioctl(void);
+void endioctl(void), endio(void), ioclause(int, bigptr), doio(chainp);
+void excall(struct bigblock *, struct bigblock *, int, struct labelblock *[]);
+void exreturn(expptr p);
+void exstop(int, expptr);
+void exgoto(struct labelblock *);
+void exasgoto(bigptr);
+void putcmgo(expptr, int, struct labelblock *[]);
+void putexpr(expptr p);
+void putif(expptr, int);
+void putgoto(int);
+void deregister(struct bigblock *np);
+NODE *putx(expptr p);
+void cpn(int, char *, char *);
+void prcmgoto(expptr, int, int, int);
+char *lexline(ftnint *n);
+bigptr suboffset(struct bigblock *p);
+struct bigblock *intraddr(struct bigblock *np);
+struct bigblock *intrcall(bigptr, bigptr, int);
+void setloc(int);
+void prnloc(char *name);
+void fprint(bigptr p, int indx);
+void ckfree(void *p);
+
+#undef expptr
+#undef tagptr
+
+#define	err1 err
+#define err2 err
+#define	warn1 warn
+#define	fatal1 fatal
Index: uspace/app/pcc/f77/fcom/equiv.c
===================================================================
--- uspace/app/pcc/f77/fcom/equiv.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/equiv.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,309 @@
+/*	$Id: equiv.c,v 1.11 2008/05/11 15:28:03 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 "defines.h"
+#include "defs.h"
+
+
+/* ROUTINES RELATED TO EQUIVALENCE CLASS PROCESSING */
+LOCAL void eqvcommon(struct equivblock *, int, ftnint);
+LOCAL void eqveqv(int, int, ftnint);
+LOCAL void freqchain(struct equivblock *p);
+LOCAL int nsubs(struct bigblock *p);
+
+/* called at end of declarations section to process chains
+   created by EQUIVALENCE statements
+ */
+void
+doequiv()
+{
+register int i;
+int inequiv, comno, ovarno;
+ftnint comoffset, offset, leng;
+register struct equivblock *p;
+register chainp q;
+struct bigblock *itemp;
+register struct bigblock *np;
+bigptr offp;
+int ns;
+chainp cp;
+
+ovarno = comoffset = offset = 0; /* XXX gcc */
+for(i = 0 ; i < nequiv ; ++i)
+	{
+	p = &eqvclass[i];
+	p->eqvbottom = p->eqvtop = 0;
+	comno = -1;
+
+	for(q = p->equivs ; q ; q = q->eqvchain.nextp)
+		{
+		itemp = q->eqvchain.eqvitem;
+		vardcl(np = itemp->b_prim.namep);
+		if(itemp->b_prim.argsp || itemp->b_prim.fcharp)
+			{
+			if(np->b_name.vdim!=NULL && np->b_name.vdim->ndim>1 &&
+			   nsubs(itemp->b_prim.argsp)==1 )
+				{
+				if(! ftn66flag)
+					warn("1-dim subscript in EQUIVALENCE");
+				cp = NULL;
+				ns = np->b_name.vdim->ndim;
+				while(--ns > 0)
+					cp = mkchain( MKICON(1), cp);
+				itemp->b_prim.argsp->b_list.listp->chain.nextp = cp;
+				}
+			offp = suboffset(itemp);
+			}
+		else	offp = MKICON(0);
+		if(ISICON(offp))
+			offset = q->eqvchain.eqvoffset = offp->b_const.fconst.ci;
+		else	{
+			dclerr("nonconstant subscript in equivalence ", np);
+			np = NULL;
+			goto endit;
+			}
+		if( (leng = iarrlen(np)) < 0)
+			{
+			dclerr("adjustable in equivalence", np);
+			np = NULL;
+			goto endit;
+			}
+		p->eqvbottom = lmin(p->eqvbottom, -offset);
+		p->eqvtop = lmax(p->eqvtop, leng-offset);
+
+		switch(np->vstg)
+			{
+			case STGUNKNOWN:
+			case STGBSS:
+			case STGEQUIV:
+				break;
+
+			case STGCOMMON:
+				comno = np->b_name.vardesc.varno;
+				comoffset = np->b_name.voffset + offset;
+				break;
+
+			default:
+				dclerr("bad storage class in equivalence", np);
+				np = NULL;
+				goto endit;
+			}
+	endit:
+		frexpr(offp);
+		q->eqvchain.eqvitem = np;
+		}
+
+	if(comno >= 0)
+		eqvcommon(p, comno, comoffset);
+	else  for(q = p->equivs ; q ; q = q->eqvchain.nextp)
+		{
+		if((np = q->eqvchain.eqvitem))
+			{
+			inequiv = NO;
+			if(np->vstg==STGEQUIV) {
+				if( (ovarno = np->b_name.vardesc.varno) == i)
+					{
+					if(np->b_name.voffset + q->eqvchain.eqvoffset != 0)
+						dclerr("inconsistent equivalence", np);
+					}
+				else	{
+					offset = np->b_name.voffset;
+					inequiv = YES;
+					}
+			}
+			np->vstg = STGEQUIV;
+			np->b_name.vardesc.varno = i;
+			np->b_name.voffset = - q->eqvchain.eqvoffset;
+
+			if(inequiv)
+				eqveqv(i, ovarno, q->eqvchain.eqvoffset + offset);
+			}
+		}
+	}
+
+for(i = 0 ; i < nequiv ; ++i)
+	{
+	p = & eqvclass[i];
+	if(p->eqvbottom!=0 || p->eqvtop!=0)
+		{
+		for(q = p->equivs ; q; q = q->eqvchain.nextp)
+			{
+			np = q->eqvchain.eqvitem;
+			np->b_name.voffset -= p->eqvbottom;
+			if(np->b_name.voffset % typealign[np->vtype] != 0)
+				dclerr("bad alignment forced by equivalence", np);
+			}
+		p->eqvtop -= p->eqvbottom;
+		p->eqvbottom = 0;
+		}
+	freqchain(p);
+	}
+}
+
+
+
+
+
+/* put equivalence chain p at common block comno + comoffset */
+
+LOCAL void eqvcommon(p, comno, comoffset)
+struct equivblock *p;
+int comno;
+ftnint comoffset;
+{
+int ovarno;
+ftnint k, offq;
+register struct bigblock *np;
+register chainp q;
+
+if(comoffset + p->eqvbottom < 0)
+	{
+	err1("attempt to extend common %s backward",
+		nounder(XL, extsymtab[comno].extname) );
+	freqchain(p);
+	return;
+	}
+
+if( (k = comoffset + p->eqvtop) > extsymtab[comno].extleng)
+	extsymtab[comno].extleng = k;
+
+for(q = p->equivs ; q ; q = q->eqvchain.nextp)
+	if((np = q->eqvchain.eqvitem))
+		{
+		switch(np->vstg)
+			{
+			case STGUNKNOWN:
+			case STGBSS:
+				np->vstg = STGCOMMON;
+				np->b_name.vardesc.varno = comno;
+				np->b_name.voffset = comoffset - q->eqvchain.eqvoffset;
+				break;
+
+			case STGEQUIV:
+				ovarno = np->b_name.vardesc.varno;
+				offq = comoffset - q->eqvchain.eqvoffset - np->b_name.voffset;
+				np->vstg = STGCOMMON;
+				np->b_name.vardesc.varno = comno;
+				np->b_name.voffset = comoffset - q->eqvchain.eqvoffset;
+				if(ovarno != (p - eqvclass))
+					eqvcommon(&eqvclass[ovarno], comno, offq);
+				break;
+
+			case STGCOMMON:
+				if(comno != np->b_name.vardesc.varno ||
+				   comoffset != np->b_name.voffset+q->eqvchain.eqvoffset)
+					dclerr("inconsistent common usage", np);
+				break;
+
+
+			default:
+				fatal1("eqvcommon: impossible vstg %d", np->vstg);
+			}
+		}
+
+freqchain(p);
+p->eqvbottom = p->eqvtop = 0;
+}
+
+
+/* put all items on ovarno chain on front of nvarno chain
+ * adjust offsets of ovarno elements and top and bottom of nvarno chain
+ */
+
+LOCAL void eqveqv(nvarno, ovarno, delta)
+int ovarno, nvarno;
+ftnint delta;
+{
+register struct equivblock *p0, *p;
+register struct nameblock *np;
+chainp q, q1;
+
+p0 = eqvclass + nvarno;
+p = eqvclass + ovarno;
+p0->eqvbottom = lmin(p0->eqvbottom, p->eqvbottom - delta);
+p0->eqvtop = lmax(p0->eqvtop, p->eqvtop - delta);
+p->eqvbottom = p->eqvtop = 0;
+
+for(q = p->equivs ; q ; q = q1)
+	{
+	q1 = q->eqvchain.nextp;
+	if( (np = q->eqvchain.eqvitem) && np->vardesc.varno==ovarno)
+		{
+		q->eqvchain.nextp = p0->equivs;
+		p0->equivs = q;
+		q->eqvchain.eqvoffset -= delta;
+		np->vardesc.varno = nvarno;
+		np->voffset -= delta;
+		}
+	else	ckfree(q);
+	}
+p->equivs = NULL;
+}
+
+
+
+
+LOCAL void
+freqchain(p)
+register struct equivblock *p;
+{
+register chainp q, oq;
+
+for(q = p->equivs ; q ; q = oq)
+	{
+	oq = q->eqvchain.nextp;
+	ckfree(q);
+	}
+p->equivs = NULL;
+}
+
+
+
+
+
+LOCAL int
+nsubs(p)
+register struct bigblock *p;
+{
+register int n;
+register chainp q;
+
+n = 0;
+if(p)
+	for(q = p->b_list.listp ; q ; q = q->chain.nextp)
+		++n;
+
+return(n);
+}
Index: uspace/app/pcc/f77/fcom/error.c
===================================================================
--- uspace/app/pcc/f77/fcom/error.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/error.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,121 @@
+/*	$Id: error.c,v 1.8 2008/05/10 07:53:41 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 conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+
+#include "defines.h"
+#include "defs.h"
+
+void
+warn(char *s, ...)
+{
+	va_list ap;
+
+	if(nowarnflag)
+		return;
+
+	va_start(ap, s);
+	fprintf(diagfile, "Warning on line %d of %s: ", lineno, infname);
+	vfprintf(diagfile, s, ap);
+	fprintf(diagfile, "\n");
+	va_end(ap);
+	++nwarn;
+}
+
+void
+err(char *s, ...)
+{
+	va_list ap;
+
+	va_start(ap, s);
+	fprintf(diagfile, "Error on line %d of %s: ", lineno, infname);
+	vfprintf(diagfile, s, ap);
+	fprintf(diagfile, "\n");
+	va_end(ap);
+	++nerr;
+}
+
+void
+yyerror(s)
+char *s;
+{ err(s); }
+
+
+void
+dclerr(s, v)
+	char *s;
+	struct bigblock *v;
+{
+	char buff[100];
+
+	if(v) {
+		sprintf(buff, "Declaration error for %s: %s",
+		    varstr(VL, v->b_name.varname), s);
+		err( buff);
+	} else
+		err1("Declaration error %s", s);
+}
+
+
+void
+execerr(char *s, ...)
+{
+	va_list ap;
+
+	va_start(ap, s);
+	fprintf(diagfile, "Error on line %d of %s: Execution error ",
+	    lineno, infname);
+	vfprintf(diagfile, s, ap);
+	fprintf(diagfile, "\n");
+	va_end(ap);
+	++nerr;
+}
+
+void
+fatal(char *s, ...)
+{
+	va_list ap;
+
+	va_start(ap, s);
+	fprintf(diagfile, "Compiler error line %d of %s: ", lineno, infname);
+	vfprintf(diagfile, s, ap);
+	fprintf(diagfile, "\n");
+	va_end(ap);
+
+	if(debugflag)
+		abort();
+	done(3);
+	exit(3);
+}
Index: uspace/app/pcc/f77/fcom/exec.c
===================================================================
--- uspace/app/pcc/f77/fcom/exec.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/exec.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,593 @@
+/*	$Id: exec.c,v 1.14 2008/05/11 15:28:03 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 conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <string.h>
+
+#include "defines.h"
+#include "defs.h"
+
+/*   Logical IF codes
+*/
+LOCAL void exar2(int, bigptr, int, int);
+LOCAL void pushctl(int code);
+LOCAL void popctl(void);
+LOCAL void poplab(void);
+LOCAL void mkstfunct(struct bigblock *, bigptr);
+
+void
+exif(p)
+bigptr p;
+{
+pushctl(CTLIF);
+ctlstack->elselabel = newlabel();
+putif(p, ctlstack->elselabel);
+}
+
+
+void
+exelif(p)
+bigptr p;
+{
+if(ctlstack->ctltype == CTLIF)
+	{
+	if(ctlstack->endlabel == 0)
+		ctlstack->endlabel = newlabel();
+	putgoto(ctlstack->endlabel);
+	putlabel(ctlstack->elselabel);
+	ctlstack->elselabel = newlabel();
+	putif(p, ctlstack->elselabel);
+	}
+
+else	execerr("elseif out of place", 0);
+}
+
+
+
+
+void
+exelse()
+{
+if(ctlstack->ctltype==CTLIF)
+	{
+	if(ctlstack->endlabel == 0)
+		ctlstack->endlabel = newlabel();
+	putgoto( ctlstack->endlabel );
+	putlabel(ctlstack->elselabel);
+	ctlstack->ctltype = CTLELSE;
+	}
+
+else	execerr("else out of place", 0);
+}
+
+void
+exendif()
+{
+if(ctlstack->ctltype == CTLIF)
+	{
+	putlabel(ctlstack->elselabel);
+	if(ctlstack->endlabel)
+		putlabel(ctlstack->endlabel);
+	popctl();
+	}
+else if(ctlstack->ctltype == CTLELSE)
+	{
+	putlabel(ctlstack->endlabel);
+	popctl();
+	}
+
+else	execerr("endif out of place", 0);
+}
+
+
+
+LOCAL void
+pushctl(code)
+int code;
+{
+register int i;
+
+if(++ctlstack >= lastctl)
+	fatal("nesting too deep");
+ctlstack->ctltype = code;
+for(i = 0 ; i < 4 ; ++i)
+	ctlstack->ctlabels[i] = 0;
+++blklevel;
+}
+
+
+LOCAL void
+popctl()
+{
+if( ctlstack-- < ctls )
+	fatal("control stack empty");
+--blklevel;
+poplab();
+}
+
+
+
+LOCAL void
+poplab()
+{
+register struct labelblock  *lp;
+
+for(lp = labeltab ; lp < highlabtab ; ++lp)
+	if(lp->labdefined)
+		{
+		/* mark all labels in inner blocks unreachable */
+		if(lp->blklevel > blklevel)
+			lp->labinacc = YES;
+		}
+	else if(lp->blklevel > blklevel)
+		{
+		/* move all labels referred to in inner blocks out a level */
+		lp->blklevel = blklevel;
+		}
+}
+
+
+
+
+/*  BRANCHING CODE
+*/
+void
+exgoto(lab)
+struct labelblock *lab;
+{
+putgoto(lab->labelno);
+}
+
+
+
+
+/*
+ * Found an assignment expression.
+ */
+void
+exequals(struct bigblock *lp, bigptr rp)
+{
+	if(lp->tag != TPRIM) {
+		err("assignment to a non-variable");
+		frexpr(lp);
+		frexpr(rp);
+	} else if(lp->b_prim.namep->vclass!=CLVAR && lp->b_prim.argsp) {
+		if(parstate >= INEXEC)
+			err("statement function amid executables");
+		else
+			mkstfunct(lp, rp);
+	} else {
+		if(parstate < INDATA)
+			enddcl();
+		puteq(mklhs(lp), rp);
+	}
+}
+
+/*
+ * Create a statement function; e.g. like "f(i)=i*i"
+ */
+void
+mkstfunct(struct bigblock *lp, bigptr rp)
+{
+	struct bigblock *p;
+	struct bigblock *np;
+	chainp args;
+
+	np = lp->b_prim.namep;
+	if(np->vclass == CLUNKNOWN)
+		np->vclass = CLPROC;
+	else {
+		dclerr("redeclaration of statement function", np);
+		return;
+	}
+
+	np->b_name.vprocclass = PSTFUNCT;
+	np->vstg = STGSTFUNCT;
+	impldcl(np);
+	args = (lp->b_prim.argsp ? lp->b_prim.argsp->b_list.listp : NULL);
+	np->b_name.vardesc.vstfdesc = mkchain((void *)args, (void *)rp);
+
+	for( ; args ; args = args->chain.nextp)
+		if( (p = args->chain.datap)->tag!=TPRIM ||
+		    p->b_prim.argsp || p->b_prim.fcharp || p->b_prim.lcharp)
+			err("non-variable argument in statement function definition");
+		else {
+			vardcl(args->chain.datap = p->b_prim.namep);
+			ckfree(p);
+		}
+}
+
+
+void
+excall(name, args, nstars, labels)
+struct bigblock *name;
+struct bigblock *args;
+int nstars;
+struct labelblock *labels[ ];
+{
+register bigptr p;
+
+settype(name, TYSUBR, 0);
+p = mkfunct( mkprim(name, args, NULL, NULL) );
+p->vtype = p->b_expr.leftp->vtype = TYINT;
+if(nstars > 0)
+	putcmgo(p, nstars, labels);
+else putexpr(p);
+}
+
+
+void
+exstop(stop, p)
+int stop;
+register bigptr p;
+{
+char *q;
+int n;
+
+if(p)
+	{
+	if( ! ISCONST(p) )
+		{
+		execerr("pause/stop argument must be constant", 0);
+		frexpr(p);
+		p = mkstrcon(0, 0);
+		}
+	else if( ISINT(p->vtype) )
+		{
+		q = convic(p->b_const.fconst.ci);
+		n = strlen(q);
+		if(n > 0)
+			{
+			p->b_const.fconst.ccp = copyn(n, q);
+			p->vtype = TYCHAR;
+			p->vleng = MKICON(n);
+			}
+		else
+			p = mkstrcon(0, 0);
+		}
+	else if(p->vtype != TYCHAR)
+		{
+		execerr("pause/stop argument must be integer or string", 0);
+		p = mkstrcon(0, 0);
+		}
+	}
+else	p = mkstrcon(0, 0);
+
+putexpr( call1(TYSUBR, (stop ? "s_stop" : "s_paus"), p) );
+}
+
+
+/* DO LOOP CODE */
+
+#define DOINIT	par[0]
+#define DOLIMIT	par[1]
+#define DOINCR	par[2]
+
+#define VARSTEP	0
+#define POSSTEP	1
+#define NEGSTEP	2
+
+void
+exdo(range, spec)
+int range;
+chainp spec;
+{
+register bigptr p, q;
+bigptr q1;
+register struct bigblock *np;
+chainp cp;
+register int i;
+int dotype, incsign = 0; /* XXX gcc */
+struct bigblock *dovarp, *dostgp;
+bigptr par[3];
+
+pushctl(CTLDO);
+dorange = ctlstack->dolabel = range;
+np = spec->chain.datap;
+ctlstack->donamep = NULL;
+if(np->b_name.vdovar)
+	{
+	err1("nested loops with variable %s", varstr(VL,np->b_name.varname));
+	ctlstack->donamep = NULL;
+	return;
+	}
+
+dovarp = mklhs( mkprim(np, 0,0,0) );
+if( ! ONEOF(dovarp->vtype, MSKINT|MSKREAL) )
+	{
+	err("bad type on do variable");
+	return;
+	}
+ctlstack->donamep = np;
+
+np->b_name.vdovar = YES;
+if( enregister(np) )
+	{
+	/* stgp points to a storage version, varp to a register version */
+	dostgp = dovarp;
+	dovarp = mklhs( mkprim(np, 0,0,0) );
+	}
+else
+	dostgp = NULL;
+dotype = dovarp->vtype;
+
+for(i=0 , cp = spec->chain.nextp ; cp!=NULL && i<3 ; cp = cp->chain.nextp)
+	{
+	p = par[i++] = fixtype(cp->chain.datap);
+	if( ! ONEOF(p->vtype, MSKINT|MSKREAL) )
+		{
+		err("bad type on DO parameter");
+		return;
+		}
+	}
+
+frchain(&spec);
+switch(i)
+	{
+	case 0:
+	case 1:
+		err("too few DO parameters");
+		return;
+
+	default:
+		err("too many DO parameters");
+		return;
+
+	case 2:
+		DOINCR = MKICON(1);
+
+	case 3:
+		break;
+	}
+
+ctlstack->endlabel = newlabel();
+ctlstack->dobodylabel = newlabel();
+
+if( ISCONST(DOLIMIT) )
+	ctlstack->domax = mkconv(dotype, DOLIMIT);
+else
+	ctlstack->domax = fmktemp(dotype, NULL);
+
+if( ISCONST(DOINCR) )
+	{
+	ctlstack->dostep = mkconv(dotype, DOINCR);
+	if( (incsign = conssgn(ctlstack->dostep)) == 0)
+		err("zero DO increment");
+	ctlstack->dostepsign = (incsign > 0 ? POSSTEP : NEGSTEP);
+	}
+else
+	{
+	ctlstack->dostep = fmktemp(dotype, NULL);
+	ctlstack->dostepsign = VARSTEP;
+	ctlstack->doposlabel = newlabel();
+	ctlstack->doneglabel = newlabel();
+	}
+
+if( ISCONST(ctlstack->domax) && ISCONST(DOINIT) && ctlstack->dostepsign!=VARSTEP)
+	{
+	puteq(cpexpr(dovarp), cpexpr(DOINIT));
+	if( onetripflag )
+		frexpr(DOINIT);
+	else
+		{
+		q = mkexpr(OPPLUS, MKICON(1),
+			mkexpr(OPMINUS, cpexpr(ctlstack->domax), cpexpr(DOINIT)) );
+		if(incsign != conssgn(q))
+			{
+			warn("DO range never executed");
+			putgoto(ctlstack->endlabel);
+			}
+		frexpr(q);
+		}
+	}
+else if(ctlstack->dostepsign!=VARSTEP && !onetripflag)
+	{
+	if( ISCONST(ctlstack->domax) )
+		q = cpexpr(ctlstack->domax);
+	else
+		q = mkexpr(OPASSIGN, cpexpr(ctlstack->domax), DOLIMIT);
+
+	q1 = mkexpr(OPASSIGN, cpexpr(dovarp), DOINIT);
+	q = mkexpr( (ctlstack->dostepsign==POSSTEP ? OPLE : OPGE), q1, q);
+	putif(q, ctlstack->endlabel);
+	}
+else
+	{
+	if(! ISCONST(ctlstack->domax) )
+		puteq( cpexpr(ctlstack->domax), DOLIMIT);
+	q = DOINIT;
+	if( ! onetripflag )
+		q = mkexpr(OPMINUS, q,
+			mkexpr(OPASSIGN, cpexpr(ctlstack->dostep), DOINCR) );
+	puteq( cpexpr(dovarp), q);
+	if(onetripflag && ctlstack->dostepsign==VARSTEP)
+		puteq( cpexpr(ctlstack->dostep), DOINCR);
+	}
+
+if(ctlstack->dostepsign == VARSTEP)
+	{
+	if(onetripflag)
+		putgoto(ctlstack->dobodylabel);
+	else
+		putif( mkexpr(OPGE, cpexpr(ctlstack->dostep), MKICON(0)),
+			ctlstack->doneglabel );
+	putlabel(ctlstack->doposlabel);
+
+	p = cpexpr(dovarp);
+	putif( mkexpr(OPLE, mkexpr(OPASSIGN, p,
+	    mkexpr(OPPLUS, cpexpr(dovarp), cpexpr(ctlstack->dostep))),
+	    cpexpr(ctlstack->domax)), ctlstack->endlabel);
+	}
+putlabel(ctlstack->dobodylabel);
+if(dostgp)
+	puteq(dostgp, cpexpr(dovarp));
+frexpr(dovarp);
+}
+
+/*
+ * Reached the end of a DO statement.
+ */
+void
+enddo(int here)
+{
+	register struct ctlframe *q;
+	register bigptr t;
+	struct bigblock *np;
+	struct bigblock *ap;
+	register int i;
+
+	while(here == dorange) {
+		if((np = ctlstack->donamep)) {
+
+			t = mklhs(mkprim(ctlstack->donamep, 0,0 ,0));
+			t = mkexpr(OPASSIGN, cpexpr(t), 
+			    mkexpr(OPPLUS, t, cpexpr(ctlstack->dostep)));
+
+			if(ctlstack->dostepsign == VARSTEP) {
+				putif( mkexpr(OPLE, cpexpr(ctlstack->dostep),
+				    MKICON(0)), ctlstack->doposlabel);
+				putlabel(ctlstack->doneglabel);
+				putif( mkexpr(OPLT, t, ctlstack->domax),
+				    ctlstack->dobodylabel);
+			} else
+				putif( mkexpr( (ctlstack->dostepsign==POSSTEP ?
+					OPGT : OPLT), t, ctlstack->domax),
+					ctlstack->dobodylabel);
+			putlabel(ctlstack->endlabel);
+			if((ap = memversion(np)))
+				puteq(ap, mklhs( mkprim(np,0,0,0)) );
+			for(i = 0 ; i < 4 ; ++i)
+				ctlstack->ctlabels[i] = 0;
+			deregister(ctlstack->donamep);
+			ctlstack->donamep->b_name.vdovar = NO;
+			frexpr(ctlstack->dostep);
+		}
+
+		popctl();
+		dorange = 0;
+		for(q = ctlstack ; q>=ctls ; --q)
+			if(q->ctltype == CTLDO) {
+				dorange = q->dolabel;
+				break;
+			}
+	}
+}
+
+void
+exassign(vname, labelval)
+struct bigblock *vname;
+struct labelblock *labelval;
+{
+struct bigblock *p;
+
+p = mklhs(mkprim(vname,0,0,0));
+if( ! ONEOF(p->vtype, MSKINT|MSKADDR) )
+	err("noninteger assign variable");
+else
+	puteq(p, mkaddcon(labelval->labelno) );
+}
+
+
+void
+exarif(expr, neglab, zerlab, poslab)
+bigptr expr;
+struct labelblock *neglab, *zerlab, *poslab;
+{
+register int lm, lz, lp;
+
+lm = neglab->labelno;
+lz = zerlab->labelno;
+lp = poslab->labelno;
+expr = fixtype(expr);
+
+if( ! ONEOF(expr->vtype, MSKINT|MSKREAL) )
+	{
+	err("invalid type of arithmetic if expression");
+	frexpr(expr);
+	}
+else
+	{
+	if(lm == lz)
+		exar2(OPLE, expr, lm, lp);
+	else if(lm == lp)
+		exar2(OPNE, expr, lm, lz);
+	else if(lz == lp)
+		exar2(OPGE, expr, lz, lm);
+	else
+		prarif(expr, lm, lz, lp);
+	}
+}
+
+
+
+LOCAL void exar2(op, e, l1, l2)
+int op;
+bigptr e;
+int l1, l2;
+{
+putif( mkexpr(op, e, MKICON(0)), l2);
+putgoto(l1);
+}
+
+void
+exreturn(p)
+register bigptr p;
+{
+if(p && (proctype!=TYSUBR || procclass!=CLPROC) )
+	{
+	err("alternate return in nonsubroutine");
+	p = 0;
+	}
+
+if(p)
+	{
+	putforce(TYINT, p);
+	putgoto(retlabel);
+	}
+else
+	putgoto(procclass==TYSUBR ? ret0label : retlabel);
+}
+
+
+void
+exasgoto(labvar)
+bigptr labvar;
+{
+register struct bigblock *p;
+
+p = mklhs( mkprim(labvar,0,0,0) );
+if( ! ISINT(p->vtype) )
+	err("assigned goto variable must be integer");
+else
+	putbranch(p);
+}
Index: uspace/app/pcc/f77/fcom/expr.c
===================================================================
--- uspace/app/pcc/f77/fcom/expr.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/expr.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,2186 @@
+/*	$Id: expr.c,v 1.20 2008/05/11 15:28:03 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 <string.h>
+
+#include "defines.h"
+#include "defs.h"
+
+/* little routines to create constant blocks */
+LOCAL int letter(int c);
+LOCAL void conspower(union constant *, struct bigblock *, ftnint);
+LOCAL void consbinop(int, int, union constant *, union constant *,
+	union constant *);
+LOCAL void zdiv(struct dcomplex *, struct dcomplex *, struct dcomplex *);
+LOCAL struct bigblock *stfcall(struct bigblock *, struct bigblock *);
+LOCAL bigptr mkpower(struct bigblock *p);
+LOCAL bigptr fold(struct bigblock *e);
+LOCAL bigptr subcheck(struct bigblock *, bigptr);
+
+struct bigblock *mkconst(t)
+register int t;
+{
+register struct bigblock *p;
+
+p = BALLO();
+p->tag = TCONST;
+p->vtype = t;
+return(p);
+}
+
+
+struct bigblock *mklogcon(l)
+register int l;
+{
+register struct bigblock * p;
+
+p = mkconst(TYLOGICAL);
+p->b_const.fconst.ci = l;
+return(p);
+}
+
+
+
+struct bigblock *mkintcon(l)
+ftnint l;
+{
+register struct bigblock *p;
+
+p = mkconst(TYLONG);
+p->b_const.fconst.ci = l;
+#ifdef MAXSHORT
+	if(l >= -MAXSHORT   &&   l <= MAXSHORT)
+		p->vtype = TYSHORT;
+#endif
+return(p);
+}
+
+
+
+struct bigblock *mkaddcon(l)
+register int l;
+{
+register struct bigblock *p;
+
+p = mkconst(TYADDR);
+p->b_const.fconst.ci = l;
+return(p);
+}
+
+
+
+struct bigblock *mkrealcon(t, d)
+register int t;
+double d;
+{
+register struct bigblock *p;
+
+p = mkconst(t);
+p->b_const.fconst.cd[0] = d;
+return(p);
+}
+
+
+struct bigblock *mkbitcon(shift, leng, s)
+int shift;
+int leng;
+char *s;
+{
+register struct bigblock *p;
+
+p = mkconst(TYUNKNOWN);
+p->b_const.fconst.ci = 0;
+while(--leng >= 0)
+	if(*s != ' ')
+		p->b_const.fconst.ci = (p->b_const.fconst.ci << shift) | hextoi(*s++);
+return(p);
+}
+
+
+
+
+
+struct bigblock *mkstrcon(l,v)
+int l;
+register char *v;
+{
+register struct bigblock *p;
+register char *s;
+
+p = mkconst(TYCHAR);
+p->vleng = MKICON(l);
+p->b_const.fconst.ccp = s = (char *) ckalloc(l);
+while(--l >= 0)
+	*s++ = *v++;
+return(p);
+}
+
+
+struct bigblock *mkcxcon(realp,imagp)
+register bigptr realp, imagp;
+{
+int rtype, itype;
+register struct bigblock *p;
+
+rtype = realp->vtype;
+itype = imagp->vtype;
+
+if( ISCONST(realp) && ISNUMERIC(rtype) && ISCONST(imagp) && ISNUMERIC(itype) )
+	{
+	p = mkconst( (rtype==TYDREAL||itype==TYDREAL) ? TYDCOMPLEX : TYCOMPLEX );
+	if( ISINT(rtype) )
+		p->b_const.fconst.cd[0] = realp->b_const.fconst.ci;
+	else	p->b_const.fconst.cd[0] = realp->b_const.fconst.cd[0];
+	if( ISINT(itype) )
+		p->b_const.fconst.cd[1] = imagp->b_const.fconst.ci;
+	else	p->b_const.fconst.cd[1] = imagp->b_const.fconst.cd[0];
+	}
+else
+	{
+	err("invalid complex constant");
+	p = errnode();
+	}
+
+frexpr(realp);
+frexpr(imagp);
+return(p);
+}
+
+
+struct bigblock *errnode()
+{
+struct bigblock *p;
+p = BALLO();
+p->tag = TERROR;
+p->vtype = TYERROR;
+return(p);
+}
+
+
+
+
+
+bigptr mkconv(t, p)
+register int t;
+register bigptr p;
+{
+register bigptr q;
+
+if(t==TYUNKNOWN || t==TYERROR)
+	fatal1("mkconv of impossible type %d", t);
+if(t == p->vtype)
+	return(p);
+
+else if( ISCONST(p) && p->vtype!=TYADDR)
+	{
+	q = mkconst(t);
+	consconv(t, &(q->b_const.fconst), p->vtype, &(p->b_const.fconst));
+	frexpr(p);
+	}
+else
+	{
+	q = mkexpr(OPCONV, p, 0);
+	q->vtype = t;
+	}
+return(q);
+}
+
+
+
+struct bigblock *addrof(p)
+bigptr p;
+{
+return( mkexpr(OPADDR, p, NULL) );
+}
+
+
+
+bigptr
+cpexpr(p)
+register bigptr p;
+{
+register bigptr e;
+int tag;
+register chainp ep, pp;
+
+#if 0
+static int blksize[ ] = { 0, sizeof(struct nameblock), sizeof(struct constblock),
+		 sizeof(struct exprblock), sizeof(struct addrblock),
+		 sizeof(struct primblock), sizeof(struct listblock),
+		 sizeof(struct errorblock)
+	};
+#endif
+
+if(p == NULL)
+	return(NULL);
+
+if( (tag = p->tag) == TNAME)
+	return(p);
+
+#if 0
+e = cpblock( blksize[p->tag] , p);
+#else
+e = cpblock( sizeof(struct bigblock) , p);
+#endif
+
+switch(tag)
+	{
+	case TCONST:
+		if(e->vtype == TYCHAR)
+			{
+			e->b_const.fconst.ccp = copyn(1+strlen(e->b_const.fconst.ccp), e->b_const.fconst.ccp);
+			e->vleng = cpexpr(e->vleng);
+			}
+	case TERROR:
+		break;
+
+	case TEXPR:
+		e->b_expr.leftp = cpexpr(p->b_expr.leftp);
+		e->b_expr.rightp = cpexpr(p->b_expr.rightp);
+		break;
+
+	case TLIST:
+		if((pp = p->b_list.listp))
+			{
+			ep = e->b_list.listp = mkchain( cpexpr(pp->chain.datap), NULL);
+			for(pp = pp->chain.nextp ; pp ; pp = pp->chain.nextp)
+				ep = ep->chain.nextp = mkchain( cpexpr(pp->chain.datap), NULL);
+			}
+		break;
+
+	case TADDR:
+		e->vleng = cpexpr(e->vleng);
+		e->b_addr.memoffset = cpexpr(e->b_addr.memoffset);
+		e->b_addr.istemp = NO;
+		break;
+
+	case TPRIM:
+		e->b_prim.argsp = cpexpr(e->b_prim.argsp);
+		e->b_prim.fcharp = cpexpr(e->b_prim.fcharp);
+		e->b_prim.lcharp = cpexpr(e->b_prim.lcharp);
+		break;
+
+	default:
+		fatal1("cpexpr: impossible tag %d", tag);
+	}
+
+return(e);
+}
+
+void
+frexpr(p)
+register bigptr p;
+{
+register chainp q;
+
+if(p == NULL)
+	return;
+
+switch(p->tag)
+	{
+	case TCONST:
+		if( ISCHAR(p) )
+			{
+			ckfree(p->b_const.fconst.ccp);
+			frexpr(p->vleng);
+			}
+		break;
+
+	case TADDR:
+		if(p->b_addr.istemp)
+			{
+			frtemp(p);
+			return;
+			}
+		frexpr(p->vleng);
+		frexpr(p->b_addr.memoffset);
+		break;
+
+	case TERROR:
+		break;
+
+	case TNAME:
+		return;
+
+	case TPRIM:
+		frexpr(p->b_prim.argsp);
+		frexpr(p->b_prim.fcharp);
+		frexpr(p->b_prim.lcharp);
+		break;
+
+	case TEXPR:
+		frexpr(p->b_expr.leftp);
+		if(p->b_expr.rightp)
+			frexpr(p->b_expr.rightp);
+		break;
+
+	case TLIST:
+		for(q = p->b_list.listp ; q ; q = q->chain.nextp)
+			frexpr(q->chain.datap);
+		frchain( &(p->b_list.listp) );
+		break;
+
+	default:
+		fatal1("frexpr: impossible tag %d", p->tag);
+	}
+
+ckfree(p);
+}
+
+
+/* fix up types in expression; replace subtrees and convert
+   names to address blocks */
+
+bigptr fixtype(p)
+register bigptr p;
+{
+
+if(p == 0)
+	return(0);
+
+switch(p->tag)
+	{
+	case TCONST:
+		if( ! ONEOF(p->vtype, MSKINT|MSKLOGICAL|MSKADDR) )
+			p = putconst(p);
+		return(p);
+
+	case TADDR:
+		p->b_addr.memoffset = fixtype(p->b_addr.memoffset);
+		return(p);
+
+	case TERROR:
+		return(p);
+
+	default:
+		fatal1("fixtype: impossible tag %d", p->tag);
+
+	case TEXPR:
+		return( fixexpr(p) );
+
+	case TLIST:
+		return( p );
+
+	case TPRIM:
+		if(p->b_prim.argsp && p->b_prim.namep->vclass!=CLVAR)
+			return( mkfunct(p) );
+		else	return( mklhs(p) );
+	}
+}
+
+
+
+
+
+/* special case tree transformations and cleanups of expression trees */
+
+bigptr fixexpr(p)
+register struct bigblock *p;
+{
+bigptr lp;
+register bigptr rp;
+register bigptr q;
+int opcode, ltype, rtype, ptype, mtype;
+
+if(p->tag == TERROR)
+	return(p);
+else if(p->tag != TEXPR)
+	fatal1("fixexpr: invalid tag %d", p->tag);
+opcode = p->b_expr.opcode;
+lp = p->b_expr.leftp = fixtype(p->b_expr.leftp);
+ltype = lp->vtype;
+if(opcode==OPASSIGN && lp->tag!=TADDR)
+	{
+	err("left side of assignment must be variable");
+	frexpr(p);
+	return( errnode() );
+	}
+
+if(p->b_expr.rightp)
+	{
+	rp = p->b_expr.rightp = fixtype(p->b_expr.rightp);
+	rtype = rp->vtype;
+	}
+else
+	{
+	rp = NULL;
+	rtype = 0;
+	}
+
+/* force folding if possible */
+if( ISCONST(lp) && (rp==NULL || ISCONST(rp)) )
+	{
+	q = mkexpr(opcode, lp, rp);
+	if( ISCONST(q) )
+		return(q);
+	ckfree(q);	/* constants did not fold */
+	}
+
+if( (ptype = cktype(opcode, ltype, rtype)) == TYERROR)
+	{
+	frexpr(p);
+	return( errnode() );
+	}
+
+switch(opcode)
+	{
+	case OPCONCAT:
+		if(p->vleng == NULL)
+			p->vleng = mkexpr(OPPLUS, cpexpr(lp->vleng),
+				cpexpr(rp->vleng) );
+		break;
+
+	case OPASSIGN:
+		if(ltype == rtype)
+			break;
+		if( ! ISCONST(rp) && ISREAL(ltype) && ISREAL(rtype) )
+			break;
+		if( ISCOMPLEX(ltype) || ISCOMPLEX(rtype) )
+			break;
+		if( ONEOF(ltype, MSKADDR|MSKINT) && ONEOF(rtype, MSKADDR|MSKINT)
+		    && typesize[ltype]>=typesize[rtype] )
+			break;
+		p->b_expr.rightp = fixtype( mkconv(ptype, rp) );
+		break;
+
+	case OPSLASH:
+		if( ISCOMPLEX(rtype) )
+			{
+			p = call2(ptype, ptype==TYCOMPLEX? "c_div" : "z_div",
+				mkconv(ptype, lp), mkconv(ptype, rp) );
+			break;
+			}
+	case OPPLUS:
+	case OPMINUS:
+	case OPSTAR:
+	case OPMOD:
+		if(ptype==TYDREAL && ( (ltype==TYREAL && ! ISCONST(lp) ) ||
+		    (rtype==TYREAL && ! ISCONST(rp) ) ))
+			break;
+		if( ISCOMPLEX(ptype) )
+			break;
+		if(ltype != ptype)
+			p->b_expr.leftp = fixtype(mkconv(ptype,lp));
+		if(rtype != ptype)
+			p->b_expr.rightp = fixtype(mkconv(ptype,rp));
+		break;
+
+	case OPPOWER:
+		return( mkpower(p) );
+
+	case OPLT:
+	case OPLE:
+	case OPGT:
+	case OPGE:
+	case OPEQ:
+	case OPNE:
+		if(ltype == rtype)
+			break;
+		mtype = cktype(OPMINUS, ltype, rtype);
+		if(mtype==TYDREAL && ( (ltype==TYREAL && ! ISCONST(lp)) ||
+		    (rtype==TYREAL && ! ISCONST(rp)) ))
+			break;
+		if( ISCOMPLEX(mtype) )
+			break;
+		if(ltype != mtype)
+			p->b_expr.leftp = fixtype(mkconv(mtype,lp));
+		if(rtype != mtype)
+			p->b_expr.rightp = fixtype(mkconv(mtype,rp));
+		break;
+
+
+	case OPCONV:
+		ptype = cktype(OPCONV, p->vtype, ltype);
+		if(lp->tag==TEXPR && lp->b_expr.opcode==OPCOMMA)
+			{
+			lp->b_expr.rightp = fixtype( mkconv(ptype, lp->b_expr.rightp) );
+			ckfree(p);
+			p = lp;
+			}
+		break;
+
+	case OPADDR:
+		if(lp->tag==TEXPR && lp->b_expr.opcode==OPADDR)
+			fatal("addr of addr");
+		break;
+
+	case OPCOMMA:
+		break;
+
+	case OPMIN:
+	case OPMAX:
+		ptype = p->vtype;
+		break;
+
+	default:
+		break;
+	}
+
+p->vtype = ptype;
+return(p);
+}
+
+
+#if SZINT < SZLONG
+/*
+   for efficient subscripting, replace long ints by shorts
+   in easy places
+*/
+
+bigptr shorten(p)
+register bigptr p;
+{
+register bigptr q;
+
+if(p->vtype != TYLONG)
+	return(p);
+
+switch(p->tag)
+	{
+	case TERROR:
+	case TLIST:
+		return(p);
+
+	case TCONST:
+	case TADDR:
+		return( mkconv(TYINT,p) );
+
+	case TEXPR:
+		break;
+
+	default:
+		fatal1("shorten: invalid tag %d", p->tag);
+	}
+
+switch(p->opcode)
+	{
+	case OPPLUS:
+	case OPMINUS:
+	case OPSTAR:
+		q = shorten( cpexpr(p->rightp) );
+		if(q->vtype == TYINT)
+			{
+			p->leftp = shorten(p->leftp);
+			if(p->leftp->vtype == TYLONG)
+				frexpr(q);
+			else
+				{
+				frexpr(p->rightp);
+				p->rightp = q;
+				p->vtype = TYINT;
+				}
+			}
+		break;
+
+	case OPNEG:
+		p->leftp = shorten(p->leftp);
+		if(p->leftp->vtype == TYINT)
+			p->vtype = TYINT;
+		break;
+
+	case OPCALL:
+	case OPCCALL:
+		p = mkconv(TYINT,p);
+		break;
+	default:
+		break;
+	}
+
+return(p);
+}
+#endif
+
+int
+fixargs(doput, p0)
+int doput;
+struct bigblock *p0;
+{
+register chainp p;
+register bigptr q, t;
+register int qtag;
+int nargs;
+
+nargs = 0;
+if(p0)
+    for(p = p0->b_list.listp ; p ; p = p->chain.nextp)
+	{
+	++nargs;
+	q = p->chain.datap;
+	qtag = q->tag;
+	if(qtag == TCONST)
+		{
+		if(q->vtype == TYSHORT)
+			q = mkconv(tyint, q);
+		if(doput)
+			p->chain.datap = putconst(q);
+		else
+			p->chain.datap = q;
+		}
+	else if(qtag==TPRIM && q->b_prim.argsp==0 && q->b_prim.namep->vclass==CLPROC)
+		p->chain.datap = mkaddr(q->b_prim.namep);
+	else if(qtag==TPRIM && q->b_prim.argsp==0 && q->b_prim.namep->b_name.vdim!=NULL)
+		p->chain.datap = mkscalar(q->b_prim.namep);
+	else if(qtag==TPRIM && q->b_prim.argsp==0 && q->b_prim.namep->b_name.vdovar && 
+		(t = memversion(q->b_prim.namep)) )
+			p->chain.datap = fixtype(t);
+	else	p->chain.datap = fixtype(q);
+	}
+return(nargs);
+}
+
+struct bigblock *
+mkscalar(np)
+register struct bigblock *np;
+{
+register struct bigblock *ap;
+
+vardcl(np);
+ap = mkaddr(np);
+
+#ifdef __vax__
+	/* on the VAX, prolog causes array arguments
+	   to point at the (0,...,0) element, except when
+	   subscript checking is on
+	*/
+	if( !checksubs && np->vstg==STGARG)
+		{
+		register struct dimblock *dp;
+		dp = np->vdim;
+		frexpr(ap->memoffset);
+		ap->memoffset = mkexpr(OPSTAR, MKICON(typesize[np->vtype]),
+					cpexpr(dp->baseoffset) );
+		}
+#endif
+return(ap);
+}
+
+
+
+
+
+bigptr mkfunct(p)
+register struct bigblock * p;
+{
+chainp ep;
+struct bigblock *ap;
+struct extsym *extp;
+register struct bigblock *np;
+register struct bigblock *q;
+int k, nargs;
+int class;
+
+np = p->b_prim.namep;
+class = np->vclass;
+
+if(class == CLUNKNOWN)
+	{
+	np->vclass = class = CLPROC;
+	if(np->vstg == STGUNKNOWN)
+		{
+		if((k = intrfunct(np->b_name.varname)))
+			{
+			np->vstg = STGINTR;
+			np->b_name.vardesc.varno = k;
+			np->b_name.vprocclass = PINTRINSIC;
+			}
+		else
+			{
+			extp = mkext( varunder(VL,np->b_name.varname) );
+			extp->extstg = STGEXT;
+			np->vstg = STGEXT;
+			np->b_name.vardesc.varno = extp - extsymtab;
+			np->b_name.vprocclass = PEXTERNAL;
+			}
+		}
+	else if(np->vstg==STGARG)
+		{
+		if(np->vtype!=TYCHAR && !ftn66flag)
+		    warn("Dummy procedure not declared EXTERNAL. Code may be wrong.");
+		np->b_name.vprocclass = PEXTERNAL;
+		}
+	}
+
+if(class != CLPROC)
+	fatal1("invalid class code for function", class);
+if(p->b_prim.fcharp || p->b_prim.lcharp)
+	{
+	err("no substring of function call");
+	goto error;
+	}
+impldcl(np);
+nargs = fixargs( np->b_name.vprocclass!=PINTRINSIC,  p->b_prim.argsp);
+
+switch(np->b_name.vprocclass)
+	{
+	case PEXTERNAL:
+		ap = mkaddr(np);
+	call:
+		q = mkexpr(OPCALL, ap, p->b_prim.argsp);
+		q->vtype = np->vtype;
+		if(np->vleng)
+			q->vleng = cpexpr(np->vleng);
+		break;
+
+	case PINTRINSIC:
+		q = intrcall(np, p->b_prim.argsp, nargs);
+		break;
+
+	case PSTFUNCT:
+		q = stfcall(np, p->b_prim.argsp);
+		break;
+
+	case PTHISPROC:
+		warn("recursive call");
+		for(ep = entries ; ep ; ep = ep->entrypoint.nextp)
+			if(ep->entrypoint.enamep == np)
+				break;
+		if(ep == NULL)
+			fatal("mkfunct: impossible recursion");
+		ap = builtin(np->vtype, varstr(XL, ep->entrypoint.entryname->extname) );
+		goto call;
+
+	default:
+		fatal1("mkfunct: impossible vprocclass %d", np->b_name.vprocclass);
+		q = 0; /* XXX gcc */
+	}
+ckfree(p);
+return(q);
+
+error:
+	frexpr(p);
+	return( errnode() );
+}
+
+
+
+LOCAL struct bigblock *
+stfcall(struct bigblock *np, struct bigblock *actlist)
+{
+	register chainp actuals;
+	int nargs;
+	chainp oactp, formals;
+	int type;
+	struct bigblock *q, *rhs;
+	bigptr ap;
+	register chainp rp;
+	chainp tlist;
+
+	if(actlist) {
+		actuals = actlist->b_list.listp;
+		ckfree(actlist);
+	} else
+		actuals = NULL;
+	oactp = actuals;
+
+	nargs = 0;
+	tlist = NULL;
+	type = np->vtype;
+
+	formals = (chainp)np->b_name.vardesc.vstfdesc->chain.datap;
+	rhs = (bigptr)np->b_name.vardesc.vstfdesc->chain.nextp;
+
+	/* copy actual arguments into temporaries */
+	while(actuals!=NULL && formals!=NULL) {
+		rp = ALLOC(rplblock);
+		rp->rplblock.rplnp = q = formals->chain.datap;
+		ap = fixtype(actuals->chain.datap);
+		if(q->vtype==ap->vtype && q->vtype!=TYCHAR
+		   && (ap->tag==TCONST || ap->tag==TADDR) ) {
+			rp->rplblock.rplvp = ap;
+			rp->rplblock.rplxp = NULL;
+			rp->rplblock.rpltag = ap->tag;
+		} else	{
+			rp->rplblock.rplvp = fmktemp(q->vtype, q->vleng);
+			rp->rplblock.rplxp = fixtype( mkexpr(OPASSIGN,
+			    cpexpr(rp->rplblock.rplvp), ap) );
+			if( (rp->rplblock.rpltag =
+			    rp->rplblock.rplxp->tag) == TERROR)
+				err("disagreement of argument types in statement function call");
+		}
+		rp->rplblock.nextp = tlist;
+		tlist = rp;
+		actuals = actuals->chain.nextp;
+		formals = formals->chain.nextp;
+		++nargs;
+	}
+
+	if(actuals!=NULL || formals!=NULL)
+		err("statement function definition and argument list differ");
+
+	/*
+	   now push down names involved in formal argument list, then
+	   evaluate rhs of statement function definition in this environment
+	*/
+	rpllist = hookup(tlist, rpllist);
+	q = mkconv(type, fixtype(cpexpr(rhs)) );
+
+	/* now generate the tree ( t1=a1, (t2=a2,... , f))))) */
+	while(--nargs >= 0) {
+		if(rpllist->rplblock.rplxp)
+			q = mkexpr(OPCOMMA, rpllist->rplblock.rplxp, q);
+		rp = rpllist->rplblock.nextp;
+		frexpr(rpllist->rplblock.rplvp);
+		ckfree(rpllist);
+		rpllist = rp;
+	}
+
+	frchain( &oactp );
+	return(q);
+}
+
+
+
+
+struct bigblock *
+mklhs(struct bigblock *p)
+{
+	struct bigblock *s;
+	struct bigblock *np;
+	chainp rp;
+	int regn;
+
+	/* first fixup name */
+
+	if(p->tag != TPRIM)
+		return(p);
+
+	np = p->b_prim.namep;
+
+	/* is name on the replace list? */
+
+	for(rp = rpllist ; rp ; rp = rp->rplblock.nextp) {
+		if(np == rp->rplblock.rplnp) {
+			if(rp->rplblock.rpltag == TNAME) {
+				np = p->b_prim.namep = rp->rplblock.rplvp;
+				break;
+			} else
+				return( cpexpr(rp->rplblock.rplvp) );
+		}
+	}
+
+	/* is variable a DO index in a register ? */
+
+	if(np->b_name.vdovar && ( (regn = inregister(np)) >= 0) ) {
+		if(np->vtype == TYERROR)
+			return( errnode() );
+		else {
+			s = BALLO();
+			s->tag = TADDR;
+			s->vstg = STGREG;
+			s->vtype = TYIREG;
+			s->b_addr.memno = regn;
+			s->b_addr.memoffset = MKICON(0);
+			return(s);
+		}
+	}
+
+	vardcl(np);
+	s = mkaddr(np);
+	s->b_addr.memoffset = mkexpr(OPPLUS, s->b_addr.memoffset, suboffset(p) );
+	frexpr(p->b_prim.argsp);
+	p->b_prim.argsp = NULL;
+
+	/* now do substring part */
+
+	if(p->b_prim.fcharp || p->b_prim.lcharp) {
+		if(np->vtype != TYCHAR)
+			err1("substring of noncharacter %s",
+			    varstr(VL,np->b_name.varname));
+		else	{
+			if(p->b_prim.lcharp == NULL)
+				p->b_prim.lcharp = cpexpr(s->vleng);
+			if(p->b_prim.fcharp)
+				s->vleng = mkexpr(OPMINUS, p->b_prim.lcharp,
+					mkexpr(OPMINUS, p->b_prim.fcharp, MKICON(1) ));
+			else	{
+				frexpr(s->vleng);
+				s->vleng = p->b_prim.lcharp;
+			}
+		}
+	}
+
+	s->vleng = fixtype( s->vleng );
+	s->b_addr.memoffset = fixtype( s->b_addr.memoffset );
+	ckfree(p);
+	return(s);
+}
+
+
+
+
+void
+deregister(np)
+struct bigblock *np;
+{
+}
+
+
+
+
+struct bigblock *memversion(np)
+register struct bigblock *np;
+{
+register struct bigblock *s;
+
+if(np->b_name.vdovar==NO || (inregister(np)<0) )
+	return(NULL);
+np->b_name.vdovar = NO;
+s = mklhs( mkprim(np, 0,0,0) );
+np->b_name.vdovar = YES;
+return(s);
+}
+
+
+int
+inregister(np)
+register struct bigblock *np;
+{
+return(-1);
+}
+
+
+
+int
+enregister(np)
+struct bigblock *np;
+{
+	return(NO);
+}
+
+
+
+
+bigptr suboffset(p)
+register struct bigblock *p;
+{
+int n;
+bigptr size;
+chainp cp;
+bigptr offp, prod;
+struct dimblock *dimp;
+bigptr sub[8];
+register struct bigblock *np;
+
+np = p->b_prim.namep;
+offp = MKICON(0);
+n = 0;
+if(p->b_prim.argsp)
+	for(cp = p->b_prim.argsp->b_list.listp ; cp ; cp = cp->chain.nextp)
+		{
+		sub[n++] = fixtype(cpexpr(cp->chain.datap));
+		if(n > 7)
+			{
+			err("more than 7 subscripts");
+			break;
+			}
+		}
+
+dimp = np->b_name.vdim;
+if(n>0 && dimp==NULL)
+	err("subscripts on scalar variable");
+else if(dimp && dimp->ndim!=n)
+	err1("wrong number of subscripts on %s",
+		varstr(VL, np->b_name.varname) );
+else if(n > 0)
+	{
+	prod = sub[--n];
+	while( --n >= 0)
+		prod = mkexpr(OPPLUS, sub[n],
+			mkexpr(OPSTAR, prod, cpexpr(dimp->dims[n].dimsize)) );
+#ifdef __vax__
+	if(checksubs || np->vstg!=STGARG)
+		prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset));
+#else
+	prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset));
+#endif
+	if(checksubs)
+		prod = subcheck(np, prod);
+	if(np->vtype == TYCHAR)
+		size = cpexpr(np->vleng);
+	else	size = MKICON( typesize[np->vtype] );
+	prod = mkexpr(OPSTAR, prod, size);
+	offp = mkexpr(OPPLUS, offp, prod);
+	}
+
+if(p->b_prim.fcharp && np->vtype==TYCHAR)
+	offp = mkexpr(OPPLUS, offp, mkexpr(OPMINUS, cpexpr(p->b_prim.fcharp), MKICON(1) ));
+
+return(offp);
+}
+
+
+/*
+ * Check if an array is addressed out of bounds.
+ */
+bigptr
+subcheck(struct bigblock *np, bigptr p)
+{
+	struct dimblock *dimp;
+	bigptr t, badcall;
+	int l1, l2;
+
+	dimp = np->b_name.vdim;
+	if(dimp->nelt == NULL)
+		return(p);	/* don't check arrays with * bounds */
+	if( ISICON(p) ) {
+		if(p->b_const.fconst.ci < 0)
+			goto badsub;
+		if( ISICON(dimp->nelt) ) {
+			if(p->b_const.fconst.ci < dimp->nelt->b_const.fconst.ci)
+				return(p);
+			else
+				goto badsub;
+		}
+	}
+
+	if (p->tag==TADDR && p->vstg==STGREG) {
+		t = p;
+	} else {
+		t = fmktemp(p->vtype, NULL);
+		putexpr(mkexpr(OPASSIGN, cpexpr(t), p));
+	}
+	/* t now cotains evaluated expression */
+
+	l1 = newlabel();
+	l2 = newlabel();
+	putif(mkexpr(OPLT, cpexpr(t), cpexpr(dimp->nelt)), l1);
+	putif(mkexpr(OPGE, cpexpr(t), MKICON(0)), l1);
+	putgoto(l2);
+	putlabel(l1);
+	
+	badcall = call4(t->vtype, "s_rnge", mkstrcon(VL, np->b_name.varname),
+		mkconv(TYLONG,  cpexpr(t)),
+		mkstrcon(XL, procname), MKICON(lineno));
+	badcall->b_expr.opcode = OPCCALL;
+
+	putexpr(badcall);
+	putlabel(l2);
+	return t;
+
+badsub:
+	frexpr(p);
+	err1("subscript on variable %s out of range",
+	    varstr(VL,np->b_name.varname));
+	return ( MKICON(0) );
+}
+
+
+
+
+struct bigblock *mkaddr(p)
+register struct bigblock *p;
+{
+struct extsym *extp;
+register struct bigblock *t;
+
+switch( p->vstg)
+	{
+	case STGUNKNOWN:
+		if(p->vclass != CLPROC)
+			break;
+		extp = mkext( varunder(VL, p->b_name.varname) );
+		extp->extstg = STGEXT;
+		p->vstg = STGEXT;
+		p->b_name.vardesc.varno = extp - extsymtab;
+		p->b_name.vprocclass = PEXTERNAL;
+
+	case STGCOMMON:
+	case STGEXT:
+	case STGBSS:
+	case STGINIT:
+	case STGEQUIV:
+	case STGARG:
+	case STGLENG:
+	case STGAUTO:
+		t = BALLO();
+		t->tag = TADDR;
+		t->vclass = p->vclass;
+		t->vtype = p->vtype;
+		t->vstg = p->vstg;
+		t->b_addr.memno = p->b_name.vardesc.varno;
+		t->b_addr.memoffset = MKICON(p->b_name.voffset);
+		if(p->vleng)
+			t->vleng = cpexpr(p->vleng);
+		return(t);
+
+	case STGINTR:
+		return( intraddr(p) );
+
+	}
+/*debug*/ fprintf(diagfile, "mkaddr. vtype=%d, vclass=%d\n", p->vtype, p->vclass);
+fatal1("mkaddr: impossible storage tag %d", p->vstg);
+/* NOTREACHED */
+return 0; /* XXX gcc */
+}
+
+
+
+struct bigblock *
+mkarg(type, argno)
+int type, argno;
+{
+register struct bigblock *p;
+
+p = BALLO();
+p->tag = TADDR;
+p->vtype = type;
+p->vclass = CLVAR;
+p->vstg = (type==TYLENG ? STGLENG : STGARG);
+p->b_addr.memno = argno;
+return(p);
+}
+
+
+
+
+bigptr mkprim(v, args, lstr, rstr)
+register bigptr v;
+struct bigblock *args;
+bigptr lstr, rstr;
+{
+register struct bigblock *p;
+
+if(v->vclass == CLPARAM)
+	{
+	if(args || lstr || rstr)
+		{
+		err1("no qualifiers on parameter name", varstr(VL,v->b_name.varname));
+		frexpr(args);
+		frexpr(lstr);
+		frexpr(rstr);
+		frexpr(v);
+		return( errnode() );
+		}
+	return( cpexpr(v->b_param.paramval) );
+	}
+
+p = BALLO();
+p->tag = TPRIM;
+p->vtype = v->vtype;
+p->b_prim.namep = v;
+p->b_prim.argsp = args;
+p->b_prim.fcharp = lstr;
+p->b_prim.lcharp = rstr;
+return(p);
+}
+
+
+void
+vardcl(v)
+register struct bigblock *v;
+{
+int nelt;
+struct dimblock *t;
+struct bigblock *p;
+bigptr neltp;
+
+if(v->b_name.vdcldone) return;
+
+if(v->vtype == TYUNKNOWN)
+	impldcl(v);
+if(v->vclass == CLUNKNOWN)
+	v->vclass = CLVAR;
+else if(v->vclass!=CLVAR && v->b_name.vprocclass!=PTHISPROC)
+	{
+	dclerr("used as variable", v);
+	return;
+	}
+if(v->vstg==STGUNKNOWN)
+	v->vstg = implstg[ letter(v->b_name.varname[0]) ];
+
+switch(v->vstg)
+	{
+	case STGBSS:
+		v->b_name.vardesc.varno = ++lastvarno;
+		break;
+	case STGAUTO:
+		if(v->vclass==CLPROC && v->b_name.vprocclass==PTHISPROC)
+			break;
+		nelt = 1;
+		if((t = v->b_name.vdim)) {
+			if( (neltp = t->nelt) && ISCONST(neltp) )
+				nelt = neltp->b_const.fconst.ci;
+			else
+				dclerr("adjustable automatic array", v);
+		}
+		p = autovar(nelt, v->vtype, v->vleng);
+		v->b_name.voffset = p->b_addr.memoffset->b_const.fconst.ci;
+		frexpr(p);
+		break;
+
+	default:
+		break;
+	}
+v->b_name.vdcldone = YES;
+}
+
+
+
+void
+impldcl(p)
+register struct bigblock *p;
+{
+register int k;
+int type, leng;
+
+if(p->b_name.vdcldone || (p->vclass==CLPROC && p->b_name.vprocclass==PINTRINSIC) )
+	return;
+if(p->vtype == TYUNKNOWN)
+	{
+	k = letter(p->b_name.varname[0]);
+	type = impltype[ k ];
+	leng = implleng[ k ];
+	if(type == TYUNKNOWN)
+		{
+		if(p->vclass == CLPROC)
+			return;
+		dclerr("attempt to use undefined variable", p);
+		type = TYERROR;
+		leng = 1;
+		}
+	settype(p, type, leng);
+	}
+}
+
+
+
+
+LOCAL int
+letter(c)
+register int c;
+{
+if( isupper(c) )
+	c = tolower(c);
+return(c - 'a');
+}
+
+
+#define ICONEQ(z, c)  (ISICON(z) && z->b_const.fconst.ci==c)
+#define COMMUTE	{ e = lp;  lp = rp;  rp = e; }
+
+
+struct bigblock * 
+mkexpr(opcode, lp, rp)
+int opcode;
+register bigptr lp, rp;
+{
+register struct bigblock *e, *e1;
+int etype;
+int ltype, rtype;
+int ltag, rtag;
+
+ltype = lp->vtype;
+ltag = lp->tag;
+if(rp && opcode!=OPCALL && opcode!=OPCCALL)
+	{
+	rtype = rp->vtype;
+	rtag = rp->tag;
+	}
+else  rtype = rtag = 0;
+
+etype = cktype(opcode, ltype, rtype);
+if(etype == TYERROR)
+	goto error;
+
+switch(opcode)
+	{
+	/* check for multiplication by 0 and 1 and addition to 0 */
+
+	case OPSTAR:
+		if( ISCONST(lp) )
+			COMMUTE
+
+		if( ISICON(rp) )
+			{
+			if(rp->b_const.fconst.ci == 0)
+				goto retright;
+			goto mulop;
+			}
+		break;
+
+	case OPSLASH:
+	case OPMOD:
+		if( ICONEQ(rp, 0) )
+			{
+			err("attempted division by zero");
+			rp = MKICON(1);
+			break;
+			}
+		if(opcode == OPMOD)
+			break;
+
+
+	mulop:
+		if( ISICON(rp) )
+			{
+			if(rp->b_const.fconst.ci == 1)
+				goto retleft;
+
+			if(rp->b_const.fconst.ci == -1)
+				{
+				frexpr(rp);
+				return( mkexpr(OPNEG, lp, 0) );
+				}
+			}
+
+		if( ISSTAROP(lp) && ISICON(lp->b_expr.rightp) )
+			{
+			if(opcode == OPSTAR)
+				e = mkexpr(OPSTAR, lp->b_expr.rightp, rp);
+			else  if(ISICON(rp) && lp->b_expr.rightp->b_const.fconst.ci % rp->b_const.fconst.ci == 0)
+				e = mkexpr(OPSLASH, lp->b_expr.rightp, rp);
+			else	break;
+
+			e1 = lp->b_expr.leftp;
+			ckfree(lp);
+			return( mkexpr(OPSTAR, e1, e) );
+			}
+		break;
+
+
+	case OPPLUS:
+		if( ISCONST(lp) )
+			COMMUTE
+		goto addop;
+
+	case OPMINUS:
+		if( ICONEQ(lp, 0) )
+			{
+			frexpr(lp);
+			return( mkexpr(OPNEG, rp, 0) );
+			}
+
+		if( ISCONST(rp) )
+			{
+			opcode = OPPLUS;
+			consnegop(rp);
+			}
+
+	addop:
+		if( ISICON(rp) )
+			{
+			if(rp->b_const.fconst.ci == 0)
+				goto retleft;
+			if( ISPLUSOP(lp) && ISICON(lp->b_expr.rightp) )
+				{
+				e = mkexpr(OPPLUS, lp->b_expr.rightp, rp);
+				e1 = lp->b_expr.leftp;
+				ckfree(lp);
+				return( mkexpr(OPPLUS, e1, e) );
+				}
+			}
+		break;
+
+
+	case OPPOWER:
+		break;
+
+	case OPNEG:
+		if(ltag==TEXPR && lp->b_expr.opcode==OPNEG)
+			{
+			e = lp->b_expr.leftp;
+			ckfree(lp);
+			return(e);
+			}
+		break;
+
+	case OPNOT:
+		if(ltag==TEXPR && lp->b_expr.opcode==OPNOT)
+			{
+			e = lp->b_expr.leftp;
+			ckfree(lp);
+			return(e);
+			}
+		break;
+
+	case OPCALL:
+	case OPCCALL:
+		etype = ltype;
+		if(rp!=NULL && rp->b_list.listp==NULL)
+			{
+			ckfree(rp);
+			rp = NULL;
+			}
+		break;
+
+	case OPAND:
+	case OPOR:
+		if( ISCONST(lp) )
+			COMMUTE
+
+		if( ISCONST(rp) )
+			{
+			if(rp->b_const.fconst.ci == 0)
+				if(opcode == OPOR)
+					goto retleft;
+				else
+					goto retright;
+			else if(opcode == OPOR)
+				goto retright;
+			else
+				goto retleft;
+			}
+	case OPEQV:
+	case OPNEQV:
+
+	case OPBITAND:
+	case OPBITOR:
+	case OPBITXOR:
+	case OPBITNOT:
+	case OPLSHIFT:
+	case OPRSHIFT:
+
+	case OPLT:
+	case OPGT:
+	case OPLE:
+	case OPGE:
+	case OPEQ:
+	case OPNE:
+
+	case OPCONCAT:
+		break;
+	case OPMIN:
+	case OPMAX:
+
+	case OPASSIGN:
+
+	case OPCONV:
+	case OPADDR:
+
+	case OPCOMMA:
+		break;
+
+	default:
+		fatal1("mkexpr: impossible opcode %d", opcode);
+	}
+
+e = BALLO();
+e->tag = TEXPR;
+e->b_expr.opcode = opcode;
+e->vtype = etype;
+e->b_expr.leftp = lp;
+e->b_expr.rightp = rp;
+if(ltag==TCONST && (rp==0 || rtag==TCONST) )
+	e = fold(e);
+return(e);
+
+retleft:
+	frexpr(rp);
+	return(lp);
+
+retright:
+	frexpr(lp);
+	return(rp);
+
+error:
+	frexpr(lp);
+	if(rp && opcode!=OPCALL && opcode!=OPCCALL)
+		frexpr(rp);
+	return( errnode() );
+}
+
+
+#define ERR(s)   { errs = s; goto error; }
+
+int
+cktype(op, lt, rt)
+register int op, lt, rt;
+{
+char *errs = NULL; /* XXX gcc */
+
+if(lt==TYERROR || rt==TYERROR)
+	goto error1;
+
+if(lt==TYUNKNOWN)
+	return(TYUNKNOWN);
+if(rt==TYUNKNOWN)
+	if(op!=OPNOT && op!=OPBITNOT && op!=OPNEG && op!=OPCALL && op!=OPCCALL && op!=OPADDR)
+		return(TYUNKNOWN);
+
+switch(op)
+	{
+	case OPPLUS:
+	case OPMINUS:
+	case OPSTAR:
+	case OPSLASH:
+	case OPPOWER:
+	case OPMOD:
+		if( ISNUMERIC(lt) && ISNUMERIC(rt) )
+			return( maxtype(lt, rt) );
+		ERR("nonarithmetic operand of arithmetic operator")
+
+	case OPNEG:
+		if( ISNUMERIC(lt) )
+			return(lt);
+		ERR("nonarithmetic operand of negation")
+
+	case OPNOT:
+		if(lt == TYLOGICAL)
+			return(TYLOGICAL);
+		ERR("NOT of nonlogical")
+
+	case OPAND:
+	case OPOR:
+	case OPEQV:
+	case OPNEQV:
+		if(lt==TYLOGICAL && rt==TYLOGICAL)
+			return(TYLOGICAL);
+		ERR("nonlogical operand of logical operator")
+
+	case OPLT:
+	case OPGT:
+	case OPLE:
+	case OPGE:
+	case OPEQ:
+	case OPNE:
+		if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL)
+			{
+			if(lt != rt)
+				ERR("illegal comparison")
+			}
+
+		else if( ISCOMPLEX(lt) || ISCOMPLEX(rt) )
+			{
+			if(op!=OPEQ && op!=OPNE)
+				ERR("order comparison of complex data")
+			}
+
+		else if( ! ISNUMERIC(lt) || ! ISNUMERIC(rt) )
+			ERR("comparison of nonarithmetic data")
+		return(TYLOGICAL);
+
+	case OPCONCAT:
+		if(lt==TYCHAR && rt==TYCHAR)
+			return(TYCHAR);
+		ERR("concatenation of nonchar data")
+
+	case OPCALL:
+	case OPCCALL:
+		return(lt);
+
+	case OPADDR:
+		return(TYADDR);
+
+	case OPCONV:
+		if(rt == 0)
+			return(0);
+	case OPASSIGN:
+		if( ISINT(lt) && rt==TYCHAR)
+			return(lt);
+		if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL)
+			if(op!=OPASSIGN || lt!=rt)
+				{
+/* debug fprintf(diagfile, " lt=%d, rt=%d, op=%d\n", lt, rt, op); */
+/* debug fatal("impossible conversion.  possible compiler bug"); */
+				ERR("impossible conversion")
+				}
+		return(lt);
+
+	case OPMIN:
+	case OPMAX:
+	case OPBITOR:
+	case OPBITAND:
+	case OPBITXOR:
+	case OPBITNOT:
+	case OPLSHIFT:
+	case OPRSHIFT:
+		return(lt);
+
+	case OPCOMMA:
+		return(rt);
+
+	default:
+		fatal1("cktype: impossible opcode %d", op);
+	}
+error:	err(errs);
+error1:	return(TYERROR);
+}
+
+
+LOCAL bigptr fold(e)
+register struct bigblock *e;
+{
+struct bigblock *p;
+register bigptr lp, rp;
+int etype, mtype, ltype, rtype, opcode;
+int i, ll, lr;
+char *q, *s;
+union constant lcon, rcon;
+
+opcode = e->b_expr.opcode;
+etype = e->vtype;
+
+lp = e->b_expr.leftp;
+ltype = lp->vtype;
+rp = e->b_expr.rightp;
+
+if(rp == 0)
+	switch(opcode)
+		{
+		case OPNOT:
+			lp->b_const.fconst.ci = ! lp->b_const.fconst.ci;
+			return(lp);
+
+		case OPBITNOT:
+			lp->b_const.fconst.ci = ~ lp->b_const.fconst.ci;
+			return(lp);
+
+		case OPNEG:
+			consnegop(lp);
+			return(lp);
+
+		case OPCONV:
+		case OPADDR:
+			return(e);
+
+		default:
+			fatal1("fold: invalid unary operator %d", opcode);
+		}
+
+rtype = rp->vtype;
+
+p = BALLO();
+p->tag = TCONST;
+p->vtype = etype;
+p->vleng = e->vleng;
+
+switch(opcode)
+	{
+	case OPCOMMA:
+		return(e);
+
+	case OPAND:
+		p->b_const.fconst.ci = lp->b_const.fconst.ci && rp->b_const.fconst.ci;
+		break;
+
+	case OPOR:
+		p->b_const.fconst.ci = lp->b_const.fconst.ci || rp->b_const.fconst.ci;
+		break;
+
+	case OPEQV:
+		p->b_const.fconst.ci = lp->b_const.fconst.ci == rp->b_const.fconst.ci;
+		break;
+
+	case OPNEQV:
+		p->b_const.fconst.ci = lp->b_const.fconst.ci != rp->b_const.fconst.ci;
+		break;
+
+	case OPBITAND:
+		p->b_const.fconst.ci = lp->b_const.fconst.ci & rp->b_const.fconst.ci;
+		break;
+
+	case OPBITOR:
+		p->b_const.fconst.ci = lp->b_const.fconst.ci | rp->b_const.fconst.ci;
+		break;
+
+	case OPBITXOR:
+		p->b_const.fconst.ci = lp->b_const.fconst.ci ^ rp->b_const.fconst.ci;
+		break;
+
+	case OPLSHIFT:
+		p->b_const.fconst.ci = lp->b_const.fconst.ci << rp->b_const.fconst.ci;
+		break;
+
+	case OPRSHIFT:
+		p->b_const.fconst.ci = lp->b_const.fconst.ci >> rp->b_const.fconst.ci;
+		break;
+
+	case OPCONCAT:
+		ll = lp->vleng->b_const.fconst.ci;
+		lr = rp->vleng->b_const.fconst.ci;
+		p->b_const.fconst.ccp = q = (char *) ckalloc(ll+lr);
+		p->vleng = MKICON(ll+lr);
+		s = lp->b_const.fconst.ccp;
+		for(i = 0 ; i < ll ; ++i)
+			*q++ = *s++;
+		s = rp->b_const.fconst.ccp;
+		for(i = 0; i < lr; ++i)
+			*q++ = *s++;
+		break;
+
+
+	case OPPOWER:
+		if( ! ISINT(rtype) )
+			return(e);
+		conspower(&(p->b_const.fconst), lp, rp->b_const.fconst.ci);
+		break;
+
+
+	default:
+		if(ltype == TYCHAR)
+			{
+			lcon.ci = cmpstr(lp->b_const.fconst.ccp, rp->b_const.fconst.ccp,
+					lp->vleng->b_const.fconst.ci, rp->vleng->b_const.fconst.ci);
+			rcon.ci = 0;
+			mtype = tyint;
+			}
+		else	{
+			mtype = maxtype(ltype, rtype);
+			consconv(mtype, &lcon, ltype, &(lp->b_const.fconst) );
+			consconv(mtype, &rcon, rtype, &(rp->b_const.fconst) );
+			}
+		consbinop(opcode, mtype, &(p->b_const.fconst), &lcon, &rcon);
+		break;
+	}
+
+frexpr(e);
+return(p);
+}
+
+
+
+/* assign constant l = r , doing coercion */
+void
+consconv(lt, lv, rt, rv)
+int lt, rt;
+register union constant *lv, *rv;
+{
+switch(lt)
+	{
+	case TYSHORT:
+	case TYLONG:
+		if( ISINT(rt) )
+			lv->ci = rv->ci;
+		else	lv->ci = rv->cd[0];
+		break;
+
+	case TYCOMPLEX:
+	case TYDCOMPLEX:
+		switch(rt)
+			{
+			case TYSHORT:
+			case TYLONG:
+				/* fall through and do real assignment of
+				   first element
+				*/
+			case TYREAL:
+			case TYDREAL:
+				lv->cd[1] = 0; break;
+			case TYCOMPLEX:
+			case TYDCOMPLEX:
+				lv->cd[1] = rv->cd[1]; break;
+			}
+
+	case TYREAL:
+	case TYDREAL:
+		if( ISINT(rt) )
+			lv->cd[0] = rv->ci;
+		else	lv->cd[0] = rv->cd[0];
+		break;
+
+	case TYLOGICAL:
+		lv->ci = rv->ci;
+		break;
+	}
+}
+
+
+void
+consnegop(p)
+register struct bigblock *p;
+{
+switch(p->vtype)
+	{
+	case TYSHORT:
+	case TYLONG:
+		p->b_const.fconst.ci = - p->b_const.fconst.ci;
+		break;
+
+	case TYCOMPLEX:
+	case TYDCOMPLEX:
+		p->b_const.fconst.cd[1] = - p->b_const.fconst.cd[1];
+		/* fall through and do the real parts */
+	case TYREAL:
+	case TYDREAL:
+		p->b_const.fconst.cd[0] = - p->b_const.fconst.cd[0];
+		break;
+	default:
+		fatal1("consnegop: impossible type %d", p->vtype);
+	}
+}
+
+
+
+LOCAL void
+conspower(powp, ap, n)
+register union constant *powp;
+struct bigblock *ap;
+ftnint n;
+{
+register int type;
+union constant x;
+
+switch(type = ap->vtype)	/* pow = 1 */ 
+	{
+	case TYSHORT:
+	case TYLONG:
+		powp->ci = 1;
+		break;
+	case TYCOMPLEX:
+	case TYDCOMPLEX:
+		powp->cd[1] = 0;
+	case TYREAL:
+	case TYDREAL:
+		powp->cd[0] = 1;
+		break;
+	default:
+		fatal1("conspower: invalid type %d", type);
+	}
+
+if(n == 0)
+	return;
+if(n < 0)
+	{
+	if( ISINT(type) )
+		{
+		err("integer ** negative power ");
+		return;
+		}
+	n = - n;
+	consbinop(OPSLASH, type, &x, powp, &(ap->b_const.fconst));
+	}
+else
+	consbinop(OPSTAR, type, &x, powp, &(ap->b_const.fconst));
+
+for( ; ; )
+	{
+	if(n & 01)
+		consbinop(OPSTAR, type, powp, powp, &x);
+	if(n >>= 1)
+		consbinop(OPSTAR, type, &x, &x, &x);
+	else
+		break;
+	}
+}
+
+
+
+/* do constant operation cp = a op b */
+
+
+LOCAL void
+consbinop(opcode, type, cp, ap, bp)
+int opcode, type;
+register union constant *ap, *bp, *cp;
+{
+int k;
+double temp;
+
+switch(opcode)
+	{
+	case OPPLUS:
+		switch(type)
+			{
+			case TYSHORT:
+			case TYLONG:
+				cp->ci = ap->ci + bp->ci;
+				break;
+			case TYCOMPLEX:
+			case TYDCOMPLEX:
+				cp->cd[1] = ap->cd[1] + bp->cd[1];
+			case TYREAL:
+			case TYDREAL:
+				cp->cd[0] = ap->cd[0] + bp->cd[0];
+				break;
+			}
+		break;
+
+	case OPMINUS:
+		switch(type)
+			{
+			case TYSHORT:
+			case TYLONG:
+				cp->ci = ap->ci - bp->ci;
+				break;
+			case TYCOMPLEX:
+			case TYDCOMPLEX:
+				cp->cd[1] = ap->cd[1] - bp->cd[1];
+			case TYREAL:
+			case TYDREAL:
+				cp->cd[0] = ap->cd[0] - bp->cd[0];
+				break;
+			}
+		break;
+
+	case OPSTAR:
+		switch(type)
+			{
+			case TYSHORT:
+			case TYLONG:
+				cp->ci = ap->ci * bp->ci;
+				break;
+			case TYREAL:
+			case TYDREAL:
+				cp->cd[0] = ap->cd[0] * bp->cd[0];
+				break;
+			case TYCOMPLEX:
+			case TYDCOMPLEX:
+				temp = ap->cd[0] * bp->cd[0] -
+					    ap->cd[1] * bp->cd[1] ;
+				cp->cd[1] = ap->cd[0] * bp->cd[1] +
+					    ap->cd[1] * bp->cd[0] ;
+				cp->cd[0] = temp;
+				break;
+			}
+		break;
+	case OPSLASH:
+		switch(type)
+			{
+			case TYSHORT:
+			case TYLONG:
+				cp->ci = ap->ci / bp->ci;
+				break;
+			case TYREAL:
+			case TYDREAL:
+				cp->cd[0] = ap->cd[0] / bp->cd[0];
+				break;
+			case TYCOMPLEX:
+			case TYDCOMPLEX:
+				zdiv(&cp->dc, &ap->dc, &bp->dc);
+				break;
+			}
+		break;
+
+	case OPMOD:
+		if( ISINT(type) )
+			{
+			cp->ci = ap->ci % bp->ci;
+			break;
+			}
+		else
+			fatal("inline mod of noninteger");
+
+	default:	  /* relational ops */
+		switch(type)
+			{
+			case TYSHORT:
+			case TYLONG:
+				if(ap->ci < bp->ci)
+					k = -1;
+				else if(ap->ci == bp->ci)
+					k = 0;
+				else	k = 1;
+				break;
+			case TYREAL:
+			case TYDREAL:
+				if(ap->cd[0] < bp->cd[0])
+					k = -1;
+				else if(ap->cd[0] == bp->cd[0])
+					k = 0;
+				else	k = 1;
+				break;
+			case TYCOMPLEX:
+			case TYDCOMPLEX:
+				if(ap->cd[0] == bp->cd[0] &&
+				   ap->cd[1] == bp->cd[1] )
+					k = 0;
+				else	k = 1;
+				break;
+			default: /* XXX gcc */
+				k = 0;
+				break;
+			}
+
+		switch(opcode)
+			{
+			case OPEQ:
+				cp->ci = (k == 0);
+				break;
+			case OPNE:
+				cp->ci = (k != 0);
+				break;
+			case OPGT:
+				cp->ci = (k == 1);
+				break;
+			case OPLT:
+				cp->ci = (k == -1);
+				break;
+			case OPGE:
+				cp->ci = (k >= 0);
+				break;
+			case OPLE:
+				cp->ci = (k <= 0);
+				break;
+			}
+		break;
+	}
+}
+
+
+
+int
+conssgn(p)
+register bigptr p;
+{
+if( ! ISCONST(p) )
+	fatal( "sgn(nonconstant)" );
+
+switch(p->vtype)
+	{
+	case TYSHORT:
+	case TYLONG:
+		if(p->b_const.fconst.ci > 0) return(1);
+		if(p->b_const.fconst.ci < 0) return(-1);
+		return(0);
+
+	case TYREAL:
+	case TYDREAL:
+		if(p->b_const.fconst.cd[0] > 0) return(1);
+		if(p->b_const.fconst.cd[0] < 0) return(-1);
+		return(0);
+
+	case TYCOMPLEX:
+	case TYDCOMPLEX:
+		return(p->b_const.fconst.cd[0]!=0 || p->b_const.fconst.cd[1]!=0);
+
+	default:
+		fatal1( "conssgn(type %d)", p->vtype);
+	}
+/* NOTREACHED */
+return 0; /* XXX gcc */
+}
+
+
+char *powint[ ] = { "pow_ii", "pow_ri", "pow_di", "pow_ci", "pow_zi" };
+
+
+LOCAL bigptr mkpower(p)
+register struct bigblock *p;
+{
+register bigptr q, lp, rp;
+int ltype, rtype, mtype;
+
+lp = p->b_expr.leftp;
+rp = p->b_expr.rightp;
+ltype = lp->vtype;
+rtype = rp->vtype;
+
+if(ISICON(rp))
+	{
+	if(rp->b_const.fconst.ci == 0)
+		{
+		frexpr(p);
+		if( ISINT(ltype) )
+			return( MKICON(1) );
+		else
+			return( putconst( mkconv(ltype, MKICON(1))) );
+		}
+	if(rp->b_const.fconst.ci < 0)
+		{
+		if( ISINT(ltype) )
+			{
+			frexpr(p);
+			err("integer**negative");
+			return( errnode() );
+			}
+		rp->b_const.fconst.ci = - rp->b_const.fconst.ci;
+		p->b_expr.leftp = lp = fixexpr(mkexpr(OPSLASH, MKICON(1), lp));
+		}
+	if(rp->b_const.fconst.ci == 1)
+		{
+		frexpr(rp);
+		ckfree(p);
+		return(lp);
+		}
+
+	if( ONEOF(ltype, MSKINT|MSKREAL) )
+		{
+		p->vtype = ltype;
+		return(p);
+		}
+	}
+if( ISINT(rtype) )
+	{
+	if(ltype==TYSHORT && rtype==TYSHORT)
+		q = call2(TYSHORT, "pow_hh", lp, rp);
+	else	{
+		if(ltype == TYSHORT)
+			{
+			ltype = TYLONG;
+			lp = mkconv(TYLONG,lp);
+			}
+		q = call2(ltype, powint[ltype-TYLONG], lp, mkconv(TYLONG, rp));
+		}
+	}
+else if( ISREAL( (mtype = maxtype(ltype,rtype)) ))
+	q = call2(mtype, "pow_dd",
+		mkconv(TYDREAL,lp), mkconv(TYDREAL,rp));
+else	{
+	q = call2(TYDCOMPLEX, "pow_zz",
+		mkconv(TYDCOMPLEX,lp), mkconv(TYDCOMPLEX,rp));
+	if(mtype == TYCOMPLEX)
+		q = mkconv(TYCOMPLEX, q);
+	}
+ckfree(p);
+return(q);
+}
+
+
+
+
+/* Complex Division.  Same code as in Runtime Library
+*/
+
+
+
+LOCAL void
+zdiv(c, a, b)
+register struct dcomplex *a, *b, *c;
+{
+double ratio, den;
+double abr, abi;
+
+if( (abr = b->dreal) < 0.)
+	abr = - abr;
+if( (abi = b->dimag) < 0.)
+	abi = - abi;
+if( abr <= abi )
+	{
+	if(abi == 0)
+		fatal("complex division by zero");
+	ratio = b->dreal / b->dimag ;
+	den = b->dimag * (1 + ratio*ratio);
+	c->dreal = (a->dreal*ratio + a->dimag) / den;
+	c->dimag = (a->dimag*ratio - a->dreal) / den;
+	}
+
+else
+	{
+	ratio = b->dimag / b->dreal ;
+	den = b->dreal * (1 + ratio*ratio);
+	c->dreal = (a->dreal + a->dimag*ratio) / den;
+	c->dimag = (a->dimag - a->dreal*ratio) / den;
+	}
+
+}
Index: uspace/app/pcc/f77/fcom/ftypes.h
===================================================================
--- uspace/app/pcc/f77/fcom/ftypes.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/ftypes.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,82 @@
+/*	$Id: ftypes.h,v 1.5 2008/12/19 08:08:48 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.
+ */
+/* variable types
+ * numeric assumptions:
+ *	int < reals < complexes
+ *	TYDREAL-TYREAL = TYDCOMPLEX-TYCOMPLEX
+ */
+
+#ifndef _FTYPES_H_
+#define _FTYPES_H_
+
+
+#define TYUNKNOWN 0
+#define TYADDR 1
+#define TYSHORT 2
+#define TYLONG 3
+#define TYREAL 4
+#define TYDREAL 5
+#define TYCOMPLEX 6
+#define TYDCOMPLEX 7
+#define TYLOGICAL 8
+#define TYCHAR 9
+#define TYSUBR 10
+#define TYERROR 11
+
+#define NTYPES (TYERROR+1)
+
+/*
+ * Type conversion from pcc to f77 internal format.
+ */
+#define	FSZADDR		(SZPOINT(0)/SZCHAR) /* XXX - typecheck? */
+#define	FSZSHORT	(SZSHORT/SZCHAR)
+#define	FSZINT		(SZINT/SZCHAR)
+#define	FSZLONG		(SZLONG/SZCHAR)
+#define	ALIADDR		(ALPOINT/ALCHAR)
+#define	ALISHORT	(ALSHORT/ALCHAR)
+#define	ALILONG		(ALLONG/ALCHAR)
+#define	ALIDOUBLE	(ALDOUBLE/ALCHAR)
+
+#ifndef SZINT
+#include "macdefs.h"
+#endif
+#if SZINT == SZSHORT
+#define TYINT	TYSHORT
+#else /* SZLONG >= SZINT */
+#define	TYINT	TYLONG
+#endif
+
+#define TYLENG  TYLONG
+#endif /* !_FTYPES_H_ */
Index: uspace/app/pcc/f77/fcom/gram.dcl
===================================================================
--- uspace/app/pcc/f77/fcom/gram.dcl	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/gram.dcl	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,318 @@
+spec:	  dcl
+	| common
+	| external
+	| intrinsic
+	| equivalence
+	| data
+	| implicit
+	| SSAVE
+		{ saveall = YES; }
+	| SSAVE savelist
+	| SFORMAT
+		{ fmtstmt(thislabel); setfmt(thislabel); }
+	| SPARAM in_dcl SLPAR paramlist SRPAR
+	;
+
+dcl:	  type name in_dcl dims lengspec
+		{ settype($2, $1, $5);
+		  if(ndim>0) setbound($2,ndim,dims);
+		}
+	| dcl SCOMMA name dims lengspec
+		{ settype($3, $1, $5);
+		  if(ndim>0) setbound($3,ndim,dims);
+		}
+	;
+
+type:	  typespec lengspec
+		{ varleng = $2; }
+	;
+
+typespec:  typename
+		{ varleng = ($1<0 || $1==TYLONG ? 0 : typesize[$1]); }
+	;
+
+typename:    SINTEGER	{ $$ = TYLONG; }
+	| SREAL		{ $$ = TYREAL; }
+	| SCOMPLEX	{ $$ = TYCOMPLEX; }
+	| SDOUBLE	{ $$ = TYDREAL; }
+	| SDCOMPLEX	{ $$ = TYDCOMPLEX; }
+	| SLOGICAL	{ $$ = TYLOGICAL; }
+	| SCHARACTER	{ $$ = TYCHAR; }
+	| SUNDEFINED	{ $$ = TYUNKNOWN; }
+	| SDIMENSION	{ $$ = TYUNKNOWN; }
+	| SAUTOMATIC	{ $$ = - STGAUTO; }
+	| SSTATIC	{ $$ = - STGBSS; }
+	;
+
+lengspec:
+		{ $$ = varleng; }
+	| SSTAR expr
+		{
+		  if( ! ISICON($2) )
+			{
+			$$ = 0;
+			dclerr("length must be an integer constant", 0);
+			}
+		  else $$ = $2->b_const.fconst.ci;
+		}
+	| SSTAR SLPAR SSTAR SRPAR
+		{ $$ = 0; }
+	;
+
+common:	  SCOMMON in_dcl var
+		{ incomm( $$ = comblock(0, 0) , $3 ); }
+	| SCOMMON in_dcl comblock var
+		{ $$ = $3;  incomm($3, $4); }
+	| common opt_comma comblock opt_comma var
+		{ $$ = $3;  incomm($3, $5); }
+	| common SCOMMA var
+		{ incomm($1, $3); }
+	;
+
+comblock:  SCONCAT
+		{ $$ = comblock(0, 0); }
+	| SSLASH SFNAME SSLASH
+		{ $$ = comblock(toklen, token); }
+	;
+
+external: SEXTERNAL in_dcl name
+		{ setext($3); }
+	| external SCOMMA name
+		{ setext($3); }
+	;
+
+intrinsic:  SINTRINSIC in_dcl name
+		{ setintr($3); }
+	| intrinsic SCOMMA name
+		{ setintr($3); }
+	;
+
+equivalence:  SEQUIV in_dcl equivset
+	| equivalence SCOMMA equivset
+	;
+
+equivset:  SLPAR equivlist SRPAR
+		{
+		struct equivblock *p;
+		if(nequiv >= MAXEQUIV)
+			fatal("too many equivalences");
+		p  =  & eqvclass[nequiv++];
+		p->eqvinit = 0;
+		p->eqvbottom = 0;
+		p->eqvtop = 0;
+		p->equivs = $2;
+		}
+	;
+
+equivlist:  lhs
+		{ $$ = ALLOC(eqvchain); $$->eqvchain.eqvitem = $1; }
+	| equivlist SCOMMA lhs
+		{ $$ = ALLOC(eqvchain); $$->eqvchain.eqvitem = $3; $$->eqvchain.nextp = $1; }
+	;
+
+data:	  SDATA in_data datalist
+	| data opt_comma datalist
+	;
+
+in_data:
+		{ if(parstate == OUTSIDE)
+			{
+			newproc();
+			startproc(0, CLMAIN);
+			}
+		  if(parstate < INDATA)
+			{
+			enddcl();
+			parstate = INDATA;
+			}
+		}
+	;
+
+datalist:  datavarlist SSLASH vallist SSLASH
+		{ ftnint junk;
+		  if(nextdata(&junk,&junk) != NULL)
+			{
+			err("too few initializers");
+			curdtp = NULL;
+			}
+		  frdata($1);
+		  frrpl();
+		}
+	;
+
+vallist:  { toomanyinit = NO; }  val
+	| vallist SCOMMA val
+	;
+
+val:	  value
+		{ dataval(NULL, $1); }
+	| simple SSTAR value
+		{ dataval($1, $3); }
+	;
+
+value:	  simple
+	| addop simple
+		{ if( $1==OPMINUS && ISCONST($2) )
+			consnegop($2);
+		  $$ = $2;
+		}
+	| complex_const
+	| bit_const
+	;
+
+savelist: saveitem
+	| savelist SCOMMA saveitem
+	;
+
+saveitem: name
+		{ int k;
+		  $1->b_name.vsave = 1;
+		  k = $1->vstg;
+		if( ! ONEOF(k, M(STGUNKNOWN)|M(STGBSS)|M(STGINIT)) )
+			dclerr("can only save static variables", $1);
+		}
+	| comblock
+		{ $1->extsave = 1; }
+	;
+
+paramlist:  paramitem
+	| paramlist SCOMMA paramitem
+	;
+
+paramitem:  name SEQUALS expr
+		{ if($1->vclass == CLUNKNOWN)
+			{ $1->vclass = CLPARAM;
+			  $1->b_param.paramval = $3;
+			}
+		  else dclerr("cannot make %s parameter", $1);
+		}
+	;
+
+var:	  name dims
+		{ if(ndim>0) setbound($1, ndim, dims); }
+	;
+
+datavar:	  lhs
+		{ struct bigblock *np;
+		  vardcl(np = $1->b_prim.namep);
+		  if(np->vstg == STGBSS)
+			np->vstg = STGINIT;
+		  else if(np->vstg == STGCOMMON)
+			extsymtab[np->b_name.vardesc.varno].extinit = YES;
+		  else if(np->vstg==STGEQUIV)
+			eqvclass[np->b_name.vardesc.varno].eqvinit = YES;
+		  else if(np->vstg != STGINIT)
+			dclerr("inconsistent storage classes", np);
+		  $$ = mkchain($1, 0);
+		}
+	| SLPAR datavarlist SCOMMA dospec SRPAR
+		{ chainp p; struct bigblock *q;
+		q = BALLO();
+		q->tag = TIMPLDO;
+		q->b_impldo.varnp = $4->chain.datap;
+		p = $4->chain.nextp;
+		if(p)  { q->b_impldo.implb = p->chain.datap; p = p->chain.nextp; }
+		if(p)  { q->b_impldo.impub = p->chain.datap; p = p->chain.nextp; }
+		if(p)  { q->b_impldo.impstep = p->chain.datap; p = p->chain.nextp; }
+		frchain( & ($4) );
+		$$ = mkchain(q, 0);
+		q->b_impldo.datalist = hookup($2, $$);
+		}
+	;
+
+datavarlist: datavar
+		{ curdtp = $1; curdtelt = 0; }
+	| datavarlist SCOMMA datavar
+		{ $$ = hookup($1, $3); }
+	;
+
+dims:
+		{ ndim = 0; }
+	| SLPAR dimlist SRPAR
+	;
+
+dimlist:   { ndim = 0; }   dim
+	| dimlist SCOMMA dim
+	;
+
+dim:	  ubound
+		{ dims[ndim].lb = 0;
+		  dims[ndim].ub = $1;
+		  ++ndim;
+		}
+	| expr SCOLON ubound
+		{ dims[ndim].lb = $1;
+		  dims[ndim].ub = $3;
+		  ++ndim;
+		}
+	;
+
+ubound:	  SSTAR
+		{ $$ = 0; }
+	| expr
+	;
+
+labellist: label
+		{ nstars = 1; labarray[0] = $1; }
+	| labellist SCOMMA label
+		{ labarray[nstars++] = $3; }
+	;
+
+label:	  labelval
+		{ if($1->labinacc)
+			warn1("illegal branch to inner block, statement %s",
+				convic( (ftnint) ($1->stateno) ));
+		  else if($1->labdefined == NO)
+			$1->blklevel = blklevel;
+		  $1->labused = YES;
+		}
+	;
+
+labelval:   SICON
+		{ $$ = mklabel( convci(toklen, token) ); }
+	;
+
+implicit:  SIMPLICIT in_dcl implist
+	| implicit SCOMMA implist
+	;
+
+implist:  imptype SLPAR letgroups SRPAR
+	;
+
+imptype:   { needkwd = 1; } type
+		{ vartype = $2; }
+	;
+
+letgroups: letgroup
+	| letgroups SCOMMA letgroup
+	;
+
+letgroup:  letter
+		{ setimpl(vartype, varleng, $1, $1); }
+	| letter SMINUS letter
+		{ setimpl(vartype, varleng, $1, $3); }
+	;
+
+letter:  SFNAME
+		{ if(toklen!=1 || token[0]<'a' || token[0]>'z')
+			{
+			dclerr("implicit item must be single letter", 0);
+			$$ = 0;
+			}
+		  else $$ = token[0];
+		}
+	;
+
+in_dcl:
+		{ switch(parstate)	
+			{
+			case OUTSIDE:	newproc();
+					startproc(0, CLMAIN);
+			case INSIDE:	parstate = INDCL;
+			case INDCL:	break;
+
+			default:
+				dclerr("declaration among executables", 0);
+			}
+		}
+	;
Index: uspace/app/pcc/f77/fcom/gram.exec
===================================================================
--- uspace/app/pcc/f77/fcom/gram.exec	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/gram.exec	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,112 @@
+exec:	  iffable
+	| SDO end_spec label opt_comma dospec
+		{
+		if($3->labdefined)
+			execerr("no backward DO loops");
+		$3->blklevel = blklevel+1;
+		exdo($3->labelno, $5);
+		}
+	| logif iffable
+		{ exendif();  thiswasbranch = NO; }
+	| logif STHEN
+	| SELSEIF end_spec SLPAR expr SRPAR STHEN
+		{ exelif($4); lastwasbranch = NO; }
+	| SELSE end_spec
+		{ exelse(); lastwasbranch = NO; }
+	| SENDIF end_spec
+		{ exendif(); lastwasbranch = NO; }
+	;
+
+logif:	  SLOGIF end_spec SLPAR expr SRPAR
+		{ exif($4); }
+	;
+
+dospec:	  name SEQUALS exprlist
+		{ $$ = mkchain($1, $3); }
+	;
+
+iffable:  let lhs SEQUALS expr
+		{ exequals($2, $4); }
+	| SASSIGN end_spec labelval STO name
+		{ exassign($5, $3); }
+	| SCONTINUE end_spec
+	| goto
+	| io
+		{ inioctl = NO; }
+	| SARITHIF end_spec SLPAR expr SRPAR label SCOMMA label SCOMMA label
+		{ exarif($4, $6, $8, $10);  thiswasbranch = YES; }
+	| call
+		{ excall($1, 0, 0, labarray); }
+	| call SLPAR SRPAR
+		{ excall($1, 0, 0, labarray); }
+	| call SLPAR callarglist SRPAR
+		{ excall($1, mklist($3), nstars, labarray); }
+	| SRETURN end_spec opt_expr
+		{ exreturn($3);  thiswasbranch = YES; }
+	| stop end_spec opt_expr
+		{ exstop($1, $3);  thiswasbranch = $1; }
+	;
+
+let:	  SLET
+		{ if(parstate == OUTSIDE)
+			{
+			newproc();
+			startproc(0, CLMAIN);
+			}
+		}
+	;
+
+goto:	  SGOTO end_spec label
+		{ exgoto($3);  thiswasbranch = YES; }
+	| SASGOTO end_spec name
+		{ exasgoto($3);  thiswasbranch = YES; }
+	| SASGOTO end_spec name opt_comma SLPAR labellist SRPAR
+		{ exasgoto($3);  thiswasbranch = YES; }
+	| SCOMPGOTO end_spec SLPAR labellist SRPAR opt_comma expr
+		{ putcmgo(fixtype($7), nstars, labarray); }
+	;
+
+opt_comma:
+	| SCOMMA
+	;
+
+call:	  SCALL end_spec name
+		{ nstars = 0; $$ = $3; }
+	;
+
+callarglist:  callarg
+		{ $$ = ($1 ? mkchain($1,0) : 0); }
+	| callarglist SCOMMA callarg
+		{ if($3) {
+			if($1) $$ = hookup($1, mkchain($3,0));
+			else $$ = mkchain($3,0);
+		}
+		}
+	;
+
+callarg:  expr
+	| SSTAR label
+		{ labarray[nstars++] = $2; $$ = 0; }
+	;
+
+stop:	  SPAUSE
+		{ $$ = 0; }
+	| SSTOP
+		{ $$ = 1; }
+	;
+
+exprlist:  expr
+		{ $$ = mkchain($1, 0); }
+	| exprlist SCOMMA expr
+		{ $$ = hookup($1, mkchain($3,0) ); }
+	;
+
+end_spec:
+		{ if(parstate == OUTSIDE)
+			{
+			newproc();
+			startproc(0, CLMAIN);
+			}
+		  if(parstate < INDATA) enddcl();
+		}
+	;
Index: uspace/app/pcc/f77/fcom/gram.expr
===================================================================
--- uspace/app/pcc/f77/fcom/gram.expr	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/gram.expr	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,125 @@
+funarglist:
+		{ $$ = 0; }
+	| funargs
+	;
+
+funargs:  expr
+		{ $$ = mkchain($1, 0); }
+	| funargs SCOMMA expr
+		{ $$ = hookup($1, mkchain($3,0) ); }
+	;
+
+
+expr:	  uexpr
+	| SLPAR expr SRPAR	{ $$ = $2; }
+	| complex_const
+	;
+
+uexpr:	  lhs
+	| simple_const
+	| expr addop expr   %prec SPLUS
+		{ $$ = mkexpr($2, $1, $3); }
+	| expr SSTAR expr
+		{ $$ = mkexpr(OPSTAR, $1, $3); }
+	| expr SSLASH expr
+		{ $$ = mkexpr(OPSLASH, $1, $3); }
+	| expr SPOWER expr
+		{ $$ = mkexpr(OPPOWER, $1, $3); }
+	| addop expr  %prec SSTAR
+		{ if($1 == OPMINUS)
+			$$ = mkexpr(OPNEG, $2, 0);
+		  else 	$$ = $2;
+		}
+	| expr relop expr  %prec SEQ
+		{ $$ = mkexpr($2, $1, $3); }
+	| expr SEQV expr
+		{ $$ = mkexpr(OPEQV, $1,$3); }
+	| expr SNEQV expr
+		{ $$ = mkexpr(OPNEQV, $1, $3); }
+	| expr SOR expr
+		{ $$ = mkexpr(OPOR, $1, $3); }
+	| expr SAND expr
+		{ $$ = mkexpr(OPAND, $1, $3); }
+	| SNOT expr
+		{ $$ = mkexpr(OPNOT, $2, 0); }
+	| expr SCONCAT expr
+		{ $$ = mkexpr(OPCONCAT, $1, $3); }
+	;
+
+addop:	  SPLUS		{ $$ = OPPLUS; }
+	| SMINUS	{ $$ = OPMINUS; }
+	;
+
+relop:	  SEQ	{ $$ = OPEQ; }
+	| SGT	{ $$ = OPGT; }
+	| SLT	{ $$ = OPLT; }
+	| SGE	{ $$ = OPGE; }
+	| SLE	{ $$ = OPLE; }
+	| SNE	{ $$ = OPNE; }
+	;
+
+lhs:	 name
+		{ $$ = mkprim($1, 0, 0, 0); }
+	| name SLPAR opt_expr SCOLON opt_expr SRPAR
+		{ $$ = mkprim($1, 0, $3, $5); }
+	| name SLPAR funarglist SRPAR
+		{ $$ = mkprim($1, mklist($3), 0, 0); }
+	| name SLPAR funarglist SRPAR SLPAR opt_expr SCOLON opt_expr SRPAR
+		{ $$ = mkprim($1, mklist($3), $6, $8); }
+	;
+
+opt_expr:
+		{ $$ = 0; }
+	| expr
+	;
+
+simple:	  name
+		{ if($1->vclass == CLPARAM)
+			$$ = cpexpr($1->b_param.paramval);
+		}
+	| simple_const
+	;
+
+simple_const:   STRUE	{ $$ = mklogcon(1); }
+	| SFALSE	{ $$ = mklogcon(0); }
+	| SHOLLERITH  { $$ = mkstrcon(toklen, token); }
+	| SICON	{ $$ = mkintcon( convci(toklen, token) ); }
+	| SRCON	{ $$ = mkrealcon(TYREAL, convcd(toklen, token)); }
+	| SDCON	{ $$ = mkrealcon(TYDREAL, convcd(toklen, token)); }
+	;
+
+complex_const:  SLPAR uexpr SCOMMA uexpr SRPAR
+		{ $$ = mkcxcon($2,$4); }
+	;
+
+bit_const:  SHEXCON
+		{ $$ = mkbitcon(4, toklen, token); }
+	| SOCTCON
+		{ $$ = mkbitcon(3, toklen, token); }
+	| SBITCON
+		{ $$ = mkbitcon(1, toklen, token); }
+	;
+
+fexpr:	  unpar_fexpr
+	| SLPAR fexpr SRPAR
+		{ $$ = $2; }
+	;
+
+unpar_fexpr:	  lhs
+	| simple_const
+	| fexpr addop fexpr   %prec SPLUS
+		{ $$ = mkexpr($2, $1, $3); }
+	| fexpr SSTAR fexpr
+		{ $$ = mkexpr(OPSTAR, $1, $3); }
+	| fexpr SSLASH fexpr
+		{ $$ = mkexpr(OPSLASH, $1, $3); }
+	| fexpr SPOWER fexpr
+		{ $$ = mkexpr(OPPOWER, $1, $3); }
+	| addop fexpr  %prec SSTAR
+		{ if($1 == OPMINUS)
+			$$ = mkexpr(OPNEG, $2, 0);
+		  else	$$ = $2;
+		}
+	| fexpr SCONCAT fexpr
+		{ $$ = mkexpr(OPCONCAT, $1, $3); }
+	;
Index: uspace/app/pcc/f77/fcom/gram.head
===================================================================
--- uspace/app/pcc/f77/fcom/gram.head	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/gram.head	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,174 @@
+%{
+
+#include "defines.h"
+#include "defs.h"
+
+static int nstars;
+static int ndim;
+static int vartype;
+static ftnint varleng;
+struct uux dims[8];
+static struct labelblock *labarray[100];
+static int lastwasbranch = NO;
+static int thiswasbranch = NO;
+
+%}
+
+/* Specify precedences and associativies. */
+
+%left SCOMMA
+%nonassoc SCOLON
+%right SEQUALS
+%left SEQV SNEQV
+%left SOR
+%left SAND
+%left SNOT
+%nonassoc SLT SGT SLE SGE SEQ SNE
+%left SCONCAT
+%left SPLUS SMINUS
+%left SSTAR SSLASH
+%right SPOWER
+
+%union {
+	struct labelblock *label;
+	struct extsym *extsym;
+
+	bigptr bigptr;
+	chainp chainp;
+
+	ftnint fint;
+	char *str;
+	char token;
+	int num;
+}
+
+%type <label>	thislabel label labelval
+%type <str>	filename
+%type <num>	SLABEL type dcl typename addop relop
+		stop nameeq
+%type <extsym>	progname entryname common comblock
+%type <bigptr>	name var call lhs simple inelt other bit_const
+		value simple_const complex_const arg
+%type <chainp>	args datavarlist datavar dospec funarglist funargs exprlist
+		callarglist inlist outlist out2 equivlist arglist
+%type <fint>	lengspec
+%type <token>	letter
+%type <bigptr>	uexpr callarg opt_expr unpar_fexpr ubound expr fexpr
+
+%%
+
+program:
+	| program stat SEOS
+	;
+
+stat:	  thislabel entry
+		{ lastwasbranch = NO; }
+	| thislabel  spec
+	| thislabel  exec
+		{ if($1 && ($1->labelno==dorange))
+			enddo($1->labelno);
+		  if(lastwasbranch && thislabel==NULL)
+			warn1("statement cannot be reached");
+		  lastwasbranch = thiswasbranch;
+		  thiswasbranch = NO;
+		}
+	| thislabel SINCLUDE filename
+		{ doinclude( $3 ); }
+	| thislabel  SEND  end_spec
+		{ lastwasbranch = NO;  endproc(); }
+	| thislabel SUNKNOWN
+		{ execerr("unclassifiable statement", 0);  flline(); }
+	| error
+		{ flline();  needkwd = NO;  inioctl = NO; 
+		  yyerrok; yyclearin; }
+	;
+
+thislabel:  SLABEL
+		{
+		if($1)
+			{
+			$$ = thislabel =  mklabel( (ftnint) $1);
+			if( ! headerdone )
+				puthead(NULL);
+			if(thislabel->labdefined)
+				execerr("label %s already defined",
+					convic(thislabel->stateno) );
+			else	{
+				if(thislabel->blklevel!=0 && thislabel->blklevel<blklevel
+				    && thislabel->labtype!=LABFORMAT)
+					warn1("there is a branch to label %s from outside block",
+					      convic( (ftnint) (thislabel->stateno) ) );
+				thislabel->blklevel = blklevel;
+				thislabel->labdefined = YES;
+				if(thislabel->labtype != LABFORMAT)
+					putlabel(thislabel->labelno);
+				}
+			}
+		else    $$ = thislabel = NULL;
+		}
+	;
+
+entry:	  SPROGRAM new_proc progname
+		{ startproc($3, CLMAIN); }
+	| SBLOCK new_proc progname
+		{ startproc($3, CLBLOCK); }
+	| SSUBROUTINE new_proc entryname arglist
+		{ entrypt(CLPROC, TYSUBR, (ftnint) 0,  $3, $4); }
+	| SFUNCTION new_proc entryname arglist
+		{ entrypt(CLPROC, TYUNKNOWN, (ftnint) 0, $3, $4); }
+	| type SFUNCTION new_proc entryname arglist
+		{ entrypt(CLPROC, $1, varleng, $4, $5); }
+	| SENTRY entryname arglist
+		{ if(parstate==OUTSIDE || procclass==CLMAIN
+			|| procclass==CLBLOCK)
+				execerr("misplaced entry statement", 0);
+		  entrypt(CLENTRY, 0, (ftnint) 0, $2, $3);
+		}
+	;
+
+new_proc:
+		{ newproc(); }
+	;
+
+entryname:  name
+		{ $$ = newentry($1); }
+	;
+
+name:	  SFNAME
+		{ $$ = mkname(toklen, token); }
+	;
+
+progname:		{ $$ = NULL; }
+	| entryname
+	;
+
+arglist:
+		{ $$ = 0; }
+	| SLPAR SRPAR
+		{ $$ = 0; }
+	| SLPAR args SRPAR
+		{$$ = $2; }
+	;
+
+args:	  arg
+		{ $$ = ($1 ? mkchain($1,0) : 0 ); }
+	| args SCOMMA arg
+		{ if($3) $1 = $$ = hookup($1, mkchain($3,0)); }
+	;
+
+arg:	  name
+		{ $1->vstg = STGARG; }
+	| SSTAR
+		{ $$ = 0;  substars = YES; }
+	;
+
+
+
+filename:   SHOLLERITH
+		{
+		char *s;
+		s = copyn(toklen+1, token);
+		s[toklen] = '\0';
+		$$ = s;
+		}
+	;
Index: uspace/app/pcc/f77/fcom/gram.io
===================================================================
--- uspace/app/pcc/f77/fcom/gram.io	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/gram.io	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,156 @@
+  /*  Input/Output Statements */
+
+io:	  io1
+		{ endio(); }
+	;
+
+io1:	  iofmove ioctl
+	| iofmove unpar_fexpr
+		{ ioclause(IOSUNIT, $2); endioctl(); }
+	| iofctl ioctl
+	| read ioctl
+		{ doio(NULL); }
+	| read ioctl inlist
+		{ doio($3); }
+	| read infmt SCOMMA inlist
+		{ doio($4); }
+	| read ioctl SCOMMA inlist
+		{ doio($4); }
+	| write ioctl
+		{ doio(NULL); }
+	| write ioctl outlist
+		{ doio($3); }
+	| print
+		{ doio(NULL); }
+	| print SCOMMA outlist
+		{ doio($3); }
+	;
+
+iofmove:   fmkwd end_spec in_ioctl
+	;
+
+fmkwd:	  SBACKSPACE
+		{ iostmt = IOREWIND; }
+	| SREWIND
+		{ iostmt = IOREWIND; }
+	| SENDFILE
+		{ iostmt = IOENDFILE; }
+	;
+
+iofctl:  ctlkwd end_spec in_ioctl
+	;
+
+ctlkwd:	  SINQUIRE
+		{ iostmt = IOINQUIRE; }
+	| SOPEN
+		{ iostmt = IOOPEN; }
+	| SCLOSE
+		{ iostmt = IOCLOSE; }
+	;
+
+infmt:	  unpar_fexpr
+		{
+		ioclause(IOSUNIT, NULL);
+		ioclause(IOSFMT, $1);
+		endioctl();
+		}
+	| SSTAR
+		{
+		ioclause(IOSUNIT, NULL);
+		ioclause(IOSFMT, NULL);
+		endioctl();
+		}
+	;
+
+ioctl:	  SLPAR fexpr SRPAR
+		{ ioclause(IOSUNIT, $2); endioctl(); }
+	| SLPAR ctllist SRPAR
+		{ endioctl(); }
+	;
+
+ctllist:  ioclause SCOMMA ioclause
+	| ctllist SCOMMA ioclause
+	;
+
+ioclause:  fexpr
+		{ ioclause(IOSPOSITIONAL, $1); }
+	| SSTAR
+		{ ioclause(IOSPOSITIONAL, NULL); }
+	| nameeq expr
+		{ ioclause($1, $2); }
+	| nameeq SSTAR
+		{ ioclause($1, NULL); }
+	;
+
+nameeq:  SNAMEEQ
+		{ $$ = iocname(); }
+	;
+
+read:	  SREAD end_spec in_ioctl
+		{ iostmt = IOREAD; }
+	;
+
+write:	  SWRITE end_spec in_ioctl
+		{ iostmt = IOWRITE; }
+	;
+
+print:	  SPRINT end_spec fexpr in_ioctl
+		{
+		iostmt = IOWRITE;
+		ioclause(IOSUNIT, NULL);
+		ioclause(IOSFMT, $3);
+		endioctl();
+		}
+	| SPRINT end_spec SSTAR in_ioctl
+		{
+		iostmt = IOWRITE;
+		ioclause(IOSUNIT, NULL);
+		ioclause(IOSFMT, NULL);
+		endioctl();
+		}
+	;
+
+inlist:	  inelt
+		{ $$ = mkchain($1,0); }
+	| inlist SCOMMA inelt
+		{ $$ = hookup($1, mkchain($3,0)); }
+	;
+
+inelt:	  lhs
+	| SLPAR inlist SCOMMA dospec SRPAR
+		{ $$ = mkiodo($4,$2); }
+	;
+
+outlist:  uexpr
+		{ $$ = mkchain($1, 0); }
+	| other
+		{ $$ = mkchain($1, 0); }
+	| out2
+	;
+
+out2:	  uexpr SCOMMA uexpr
+		{ $$ = mkchain($1, mkchain($3, 0) ); }
+	| uexpr SCOMMA other
+		{ $$ = mkchain($1, mkchain($3, 0) ); }
+	| other SCOMMA uexpr
+		{ $$ = mkchain($1, mkchain($3, 0) ); }
+	| other SCOMMA other
+		{ $$ = mkchain($1, mkchain($3, 0) ); }
+	| out2  SCOMMA uexpr
+		{ $$ = hookup($1, mkchain($3, 0) ); }
+	| out2  SCOMMA other
+		{ $$ = hookup($1, mkchain($3, 0) ); }
+	;
+
+other:	  complex_const
+	| SLPAR uexpr SCOMMA dospec SRPAR
+		{ $$ = mkiodo($4, mkchain($2, 0) ); }
+	| SLPAR other SCOMMA dospec SRPAR
+		{ $$ = mkiodo($4, mkchain($2, 0) ); }
+	| SLPAR out2  SCOMMA dospec SRPAR
+		{ $$ = mkiodo($4, $2); }
+	;
+
+in_ioctl:
+		{ startioctl(); }
+	;
Index: uspace/app/pcc/f77/fcom/init.c
===================================================================
--- uspace/app/pcc/f77/fcom/init.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/init.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,292 @@
+/*	$Id: init.c,v 1.16 2008/12/24 17:40:41 sgk 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 "defines.h"
+#include "defs.h"
+
+
+FILEP infile;
+FILEP diagfile;
+
+long int headoffset;
+
+char token[100];
+int toklen;
+int lineno;
+char *infname;
+int needkwd;
+struct labelblock *thislabel	= NULL;
+flag nowarnflag	= NO;
+flag ftn66flag	= NO;
+flag profileflag	= NO;
+flag optimflag	= NO;
+flag quietflag	= NO;
+flag shiftcase	= YES;
+flag undeftype	= NO;
+flag shortsubs	= YES;
+flag onetripflag	= NO;
+flag checksubs	= NO;
+flag debugflag	= NO;
+int nerr;
+int nwarn;
+int ndata;
+
+flag saveall;
+flag substars;
+int parstate	= OUTSIDE;
+flag headerdone	= NO;
+int blklevel;
+int impltype[26];
+int implleng[26];
+int implstg[26];
+
+int tyint	= TYLONG ;
+int tylogical	= TYLONG;
+ftnint typesize[NTYPES]
+	= { 1, FSZADDR, FSZSHORT, FSZLONG, FSZLONG, 2*FSZLONG,
+	    2*FSZLONG, 4*FSZLONG, FSZLONG, 1, 1, 1};
+int typealign[NTYPES]
+	= { 1, ALIADDR, ALISHORT, ALILONG, ALILONG, ALIDOUBLE,
+	    ALILONG, ALIDOUBLE, ALILONG, 1, 1, 1};
+int procno;
+int proctype	= TYUNKNOWN;
+char *procname;
+int rtvlabel[NTYPES];
+int fudgelabel;
+struct bigblock *typeaddr;
+struct bigblock *retslot;
+int cxslot	= -1;
+int chslot	= -1;
+int chlgslot	= -1;
+int procclass	= CLUNKNOWN;
+int nentry;
+flag multitype;
+ftnint procleng;
+int lastlabno	= 10;
+int lastvarno;
+int lastargslot;
+int argloc;
+ftnint autoleng;
+ftnint bssleng	= 0;
+int retlabel;
+int ret0label;
+struct ctlframe ctls[MAXCTL];
+struct ctlframe *ctlstack	= ctls-1;
+struct ctlframe *lastctl	= ctls+MAXCTL ;
+
+bigptr regnamep[10]; /* XXX MAXREGVAR */
+int highregvar;
+
+struct extsym extsymtab[MAXEXT];
+struct extsym *nextext	= extsymtab;
+struct extsym *lastext	= extsymtab+MAXEXT;
+
+struct equivblock eqvclass[MAXEQUIV];
+struct hashentry hashtab[MAXHASH];
+struct hashentry *lasthash	= hashtab+MAXHASH;
+
+struct labelblock labeltab[MAXSTNO];
+struct labelblock *labtabend	= labeltab+MAXSTNO;
+struct labelblock *highlabtab =	labeltab;
+chainp rpllist	= NULL;
+chainp curdtp	= NULL;
+flag toomanyinit;
+ftnint curdtelt;
+chainp templist	= NULL;
+chainp holdtemps	= NULL;
+int dorange	= 0;
+chainp entries	= NULL;
+chainp chains	= NULL;
+
+flag inioctl;
+struct bigblock *ioblkp;
+int iostmt;
+int nioctl;
+int nequiv	= 0;
+int nintnames	= 0;
+int nextnames	= 0;
+
+struct literal litpool[MAXLITERALS];
+int nliterals;
+
+/*
+ * Return a number for internal labels.
+ */
+int getlab(void);
+
+int crslab = 10;
+int
+getlab(void)
+{
+	return crslab++;
+}
+
+
+void
+fileinit()
+{
+procno = 0;
+lastlabno = 10;
+lastvarno = 0;
+nextext = extsymtab;
+nliterals = 0;
+nerr = 0;
+ndata = 0;
+}
+
+
+
+
+void
+procinit()
+{
+register struct bigblock *p;
+register struct dimblock *q;
+register struct hashentry *hp;
+register struct labelblock *lp;
+chainp cp;
+int i;
+
+	setloc(RDATA);
+parstate = OUTSIDE;
+headerdone = NO;
+blklevel = 1;
+saveall = NO;
+substars = NO;
+nwarn = 0;
+thislabel = NULL;
+needkwd = 0;
+
+++procno;
+proctype = TYUNKNOWN;
+procname = "MAIN_    ";
+procclass = CLUNKNOWN;
+nentry = 0;
+multitype = NO;
+typeaddr = NULL;
+retslot = NULL;
+cxslot = -1;
+chslot = -1;
+chlgslot = -1;
+procleng = 0;
+blklevel = 1;
+lastargslot = 0;
+	autoleng = AUTOINIT;
+
+for(lp = labeltab ; lp < labtabend ; ++lp)
+	lp->stateno = 0;
+
+for(hp = hashtab ; hp < lasthash ; ++hp)
+	if((p = hp->varp))
+		{
+		frexpr(p->vleng);
+		if((q = p->b_name.vdim))
+			{
+			for(i = 0 ; i < q->ndim ; ++i)
+				{
+				frexpr(q->dims[i].dimsize);
+				frexpr(q->dims[i].dimexpr);
+				}
+			frexpr(q->nelt);
+			frexpr(q->baseoffset);
+			frexpr(q->basexpr);
+			ckfree(q);
+			}
+		ckfree(p);
+		hp->varp = NULL;
+		}
+nintnames = 0;
+highlabtab = labeltab;
+
+ctlstack = ctls - 1;
+for(cp = templist ; cp ; cp = cp->chain.nextp)
+	ckfree(cp->chain.datap);
+frchain(&templist);
+holdtemps = NULL;
+dorange = 0;
+highregvar = 0;
+entries = NULL;
+rpllist = NULL;
+inioctl = NO;
+ioblkp = NULL;
+nequiv = 0;
+
+for(i = 0 ; i<NTYPES ; ++i)
+	rtvlabel[i] = 0;
+fudgelabel = 0;
+
+if(undeftype)
+	setimpl(TYUNKNOWN, (ftnint) 0, 'a', 'z');
+else
+	{
+	setimpl(TYREAL, (ftnint) 0, 'a', 'z');
+	setimpl(tyint,  (ftnint) 0, 'i', 'n');
+	}
+setimpl(-STGBSS, (ftnint) 0, 'a', 'z');	/* set class */
+setlog();
+}
+
+
+
+void
+setimpl(type, length, c1, c2)
+int type;
+ftnint length;
+int c1, c2;
+{
+int i;
+char buff[100];
+
+if(c1==0 || c2==0)
+	return;
+
+if(c1 > c2) {
+	sprintf(buff, "characters out of order in implicit:%c-%c", c1, c2);
+	err(buff);
+} else
+	if(type < 0)
+		for(i = c1 ; i<=c2 ; ++i)
+			implstg[i-'a'] = - type;
+	else
+		{
+		type = lengtype(type, (int) length);
+		if(type != TYCHAR)
+			length = 0;
+		for(i = c1 ; i<=c2 ; ++i)
+			{
+			impltype[i-'a'] = type;
+			implleng[i-'a'] = length;
+			}
+		}
+}
Index: uspace/app/pcc/f77/fcom/intr.c
===================================================================
--- uspace/app/pcc/f77/fcom/intr.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/intr.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,608 @@
+/*	$Id: intr.c,v 1.13 2008/05/11 15:28:03 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 conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "defines.h"
+#include "defs.h"
+
+
+static struct bigblock *finline(int, int, chainp);
+
+union
+	{
+	int ijunk;
+	struct intrpacked bits;
+	} packed;
+
+struct intrbits
+	{
+	int intrgroup /* :3 */;
+	int intrstuff /* result type or number of generics */;
+	int intrno /* :7 */;
+	};
+
+LOCAL struct intrblock
+	{
+	char intrfname[VL];
+	struct intrbits intrval;
+	} intrtab[ ] =
+{
+{ "int", 		{ INTRCONV, TYLONG }, },
+{ "real", 	{ INTRCONV, TYREAL }, },
+{ "dble", 	{ INTRCONV, TYDREAL }, },
+{ "cmplx", 	{ INTRCONV, TYCOMPLEX }, },
+{ "dcmplx", 	{ INTRCONV, TYDCOMPLEX }, },
+{ "ifix", 	{ INTRCONV, TYLONG }, },
+{ "idint", 	{ INTRCONV, TYLONG }, },
+{ "float", 	{ INTRCONV, TYREAL }, },
+{ "dfloat",	{ INTRCONV, TYDREAL }, },
+{ "sngl", 	{ INTRCONV, TYREAL }, },
+{ "ichar", 	{ INTRCONV, TYLONG }, },
+{ "char", 	{ INTRCONV, TYCHAR }, },
+
+{ "max", 		{ INTRMAX, TYUNKNOWN }, },
+{ "max0", 	{ INTRMAX, TYLONG }, },
+{ "amax0", 	{ INTRMAX, TYREAL }, },
+{ "max1", 	{ INTRMAX, TYLONG }, },
+{ "amax1", 	{ INTRMAX, TYREAL }, },
+{ "dmax1", 	{ INTRMAX, TYDREAL }, },
+
+{ "and",		{ INTRBOOL, TYUNKNOWN, OPBITAND }, },
+{ "or",		{ INTRBOOL, TYUNKNOWN, OPBITOR }, },
+{ "xor",		{ INTRBOOL, TYUNKNOWN, OPBITXOR }, },
+{ "not",		{ INTRBOOL, TYUNKNOWN, OPBITNOT }, },
+{ "lshift",	{ INTRBOOL, TYUNKNOWN, OPLSHIFT }, },
+{ "rshift",	{ INTRBOOL, TYUNKNOWN, OPRSHIFT }, },
+
+{ "min", 		{ INTRMIN, TYUNKNOWN }, },
+{ "min0", 	{ INTRMIN, TYLONG }, },
+{ "amin0", 	{ INTRMIN, TYREAL }, },
+{ "min1", 	{ INTRMIN, TYLONG }, },
+{ "amin1", 	{ INTRMIN, TYREAL }, },
+{ "dmin1", 	{ INTRMIN, TYDREAL }, },
+
+{ "aint", 	{ INTRGEN, 2, 0 }, },
+{ "dint", 	{ INTRSPEC, TYDREAL, 1 }, },
+
+{ "anint", 	{ INTRGEN, 2, 2 }, },
+{ "dnint", 	{ INTRSPEC, TYDREAL, 3 }, },
+
+{ "nint", 	{ INTRGEN, 4, 4 }, },
+{ "idnint", 	{ INTRGEN, 2, 6 }, },
+
+{ "abs", 		{ INTRGEN, 6, 8 }, },
+{ "iabs", 	{ INTRGEN, 2, 9 }, },
+{ "dabs", 	{ INTRSPEC, TYDREAL, 11 }, },
+{ "cabs", 	{ INTRSPEC, TYREAL, 12 }, },
+{ "zabs", 	{ INTRSPEC, TYDREAL, 13 }, },
+
+{ "mod", 		{ INTRGEN, 4, 14 }, },
+{ "amod", 	{ INTRSPEC, TYREAL, 16 }, },
+{ "dmod", 	{ INTRSPEC, TYDREAL, 17 }, },
+
+{ "sign", 	{ INTRGEN, 4, 18 }, },
+{ "isign", 	{ INTRGEN, 2, 19 }, },
+{ "dsign", 	{ INTRSPEC, TYDREAL, 21 }, },
+
+{ "dim", 		{ INTRGEN, 4, 22 }, },
+{ "idim", 	{ INTRGEN, 2, 23 }, },
+{ "ddim", 	{ INTRSPEC, TYDREAL, 25 }, },
+
+{ "dprod", 	{ INTRSPEC, TYDREAL, 26 }, },
+
+{ "len", 		{ INTRSPEC, TYLONG, 27 }, },
+{ "index", 	{ INTRSPEC, TYLONG, 29 }, },
+
+{ "imag", 	{ INTRGEN, 2, 31 }, },
+{ "aimag", 	{ INTRSPEC, TYREAL, 31 }, },
+{ "dimag", 	{ INTRSPEC, TYDREAL, 32 }, },
+
+{ "conjg", 	{ INTRGEN, 2, 33 }, },
+{ "dconjg", 	{ INTRSPEC, TYDCOMPLEX, 34 }, },
+
+{ "sqrt", 	{ INTRGEN, 4, 35 }, },
+{ "dsqrt", 	{ INTRSPEC, TYDREAL, 36 }, },
+{ "csqrt", 	{ INTRSPEC, TYCOMPLEX, 37 }, },
+{ "zsqrt", 	{ INTRSPEC, TYDCOMPLEX, 38 }, },
+
+{ "exp", 		{ INTRGEN, 4, 39 }, },
+{ "dexp", 	{ INTRSPEC, TYDREAL, 40 }, },
+{ "cexp", 	{ INTRSPEC, TYCOMPLEX, 41 }, },
+{ "zexp", 	{ INTRSPEC, TYDCOMPLEX, 42 }, },
+
+{ "log", 		{ INTRGEN, 4, 43 }, },
+{ "alog", 	{ INTRSPEC, TYREAL, 43 }, },
+{ "dlog", 	{ INTRSPEC, TYDREAL, 44 }, },
+{ "clog", 	{ INTRSPEC, TYCOMPLEX, 45 }, },
+{ "zlog", 	{ INTRSPEC, TYDCOMPLEX, 46 }, },
+
+{ "log10", 	{ INTRGEN, 2, 47 }, },
+{ "alog10", 	{ INTRSPEC, TYREAL, 47 }, },
+{ "dlog10", 	{ INTRSPEC, TYDREAL, 48 }, },
+
+{ "sin", 		{ INTRGEN, 4, 49 }, },
+{ "dsin", 	{ INTRSPEC, TYDREAL, 50 }, },
+{ "csin", 	{ INTRSPEC, TYCOMPLEX, 51 }, },
+{ "zsin", 	{ INTRSPEC, TYDCOMPLEX, 52 }, },
+
+{ "cos", 		{ INTRGEN, 4, 53 }, },
+{ "dcos", 	{ INTRSPEC, TYDREAL, 54 }, },
+{ "ccos", 	{ INTRSPEC, TYCOMPLEX, 55 }, },
+{ "zcos", 	{ INTRSPEC, TYDCOMPLEX, 56 }, },
+
+{ "tan", 		{ INTRGEN, 2, 57 }, },
+{ "dtan", 	{ INTRSPEC, TYDREAL, 58 }, },
+
+{ "asin", 	{ INTRGEN, 2, 59 }, },
+{ "dasin", 	{ INTRSPEC, TYDREAL, 60 }, },
+
+{ "acos", 	{ INTRGEN, 2, 61 }, },
+{ "dacos", 	{ INTRSPEC, TYDREAL, 62 }, },
+
+{ "atan", 	{ INTRGEN, 2, 63 }, },
+{ "datan", 	{ INTRSPEC, TYDREAL, 64 }, },
+
+{ "atan2", 	{ INTRGEN, 2, 65 }, },
+{ "datan2", 	{ INTRSPEC, TYDREAL, 66 }, },
+
+{ "sinh", 	{ INTRGEN, 2, 67 }, },
+{ "dsinh", 	{ INTRSPEC, TYDREAL, 68 }, },
+
+{ "cosh", 	{ INTRGEN, 2, 69 }, },
+{ "dcosh", 	{ INTRSPEC, TYDREAL, 70 }, },
+
+{ "tanh", 	{ INTRGEN, 2, 71 }, },
+{ "dtanh", 	{ INTRSPEC, TYDREAL, 72 }, },
+
+{ "lge",		{ INTRSPEC, TYLOGICAL, 73}, },
+{ "lgt",		{ INTRSPEC, TYLOGICAL, 75}, },
+{ "lle",		{ INTRSPEC, TYLOGICAL, 77}, },
+{ "llt",		{ INTRSPEC, TYLOGICAL, 79}, },
+
+{ "" }, };
+
+
+
+LOCAL struct specblock
+	{
+	char atype;
+	char rtype;
+	char nargs;
+	char spxname[XL];
+	char othername;	/* index into callbyvalue table */
+	} spectab[ ] =
+{
+	{ TYREAL,TYREAL,1,"r_int" },
+	{ TYDREAL,TYDREAL,1,"d_int" },
+
+	{ TYREAL,TYREAL,1,"r_nint" },
+	{ TYDREAL,TYDREAL,1,"d_nint" },
+
+	{ TYREAL,TYSHORT,1,"h_nint" },
+	{ TYREAL,TYLONG,1,"i_nint" },
+
+	{ TYDREAL,TYSHORT,1,"h_dnnt" },
+	{ TYDREAL,TYLONG,1,"i_dnnt" },
+
+	{ TYREAL,TYREAL,1,"r_abs" },
+	{ TYSHORT,TYSHORT,1,"h_abs" },
+	{ TYLONG,TYLONG,1,"i_abs" },
+	{ TYDREAL,TYDREAL,1,"d_abs" },
+	{ TYCOMPLEX,TYREAL,1,"c_abs" },
+	{ TYDCOMPLEX,TYDREAL,1,"z_abs" },
+
+	{ TYSHORT,TYSHORT,2,"h_mod" },
+	{ TYLONG,TYLONG,2,"i_mod" },
+	{ TYREAL,TYREAL,2,"r_mod" },
+	{ TYDREAL,TYDREAL,2,"d_mod" },
+
+	{ TYREAL,TYREAL,2,"r_sign" },
+	{ TYSHORT,TYSHORT,2,"h_sign" },
+	{ TYLONG,TYLONG,2,"i_sign" },
+	{ TYDREAL,TYDREAL,2,"d_sign" },
+
+	{ TYREAL,TYREAL,2,"r_dim" },
+	{ TYSHORT,TYSHORT,2,"h_dim" },
+	{ TYLONG,TYLONG,2,"i_dim" },
+	{ TYDREAL,TYDREAL,2,"d_dim" },
+
+	{ TYREAL,TYDREAL,2,"d_prod" },
+
+	{ TYCHAR,TYSHORT,1,"h_len" },
+	{ TYCHAR,TYLONG,1,"i_len" },
+
+	{ TYCHAR,TYSHORT,2,"h_indx" },
+	{ TYCHAR,TYLONG,2,"i_indx" },
+
+	{ TYCOMPLEX,TYREAL,1,"r_imag" },
+	{ TYDCOMPLEX,TYDREAL,1,"d_imag" },
+	{ TYCOMPLEX,TYCOMPLEX,1,"r_cnjg" },
+	{ TYDCOMPLEX,TYDCOMPLEX,1,"d_cnjg" },
+
+	{ TYREAL,TYREAL,1,"r_sqrt", 1 },
+	{ TYDREAL,TYDREAL,1,"d_sqrt", 1 },
+	{ TYCOMPLEX,TYCOMPLEX,1,"c_sqrt" },
+	{ TYDCOMPLEX,TYDCOMPLEX,1,"z_sqrt" },
+
+	{ TYREAL,TYREAL,1,"r_exp", 2 },
+	{ TYDREAL,TYDREAL,1,"d_exp", 2 },
+	{ TYCOMPLEX,TYCOMPLEX,1,"c_exp" },
+	{ TYDCOMPLEX,TYDCOMPLEX,1,"z_exp" },
+
+	{ TYREAL,TYREAL,1,"r_log", 3 },
+	{ TYDREAL,TYDREAL,1,"d_log", 3 },
+	{ TYCOMPLEX,TYCOMPLEX,1,"c_log" },
+	{ TYDCOMPLEX,TYDCOMPLEX,1,"z_log" },
+
+	{ TYREAL,TYREAL,1,"r_lg10" },
+	{ TYDREAL,TYDREAL,1,"d_lg10" },
+
+	{ TYREAL,TYREAL,1,"r_sin", 4 },
+	{ TYDREAL,TYDREAL,1,"d_sin", 4 },
+	{ TYCOMPLEX,TYCOMPLEX,1,"c_sin" },
+	{ TYDCOMPLEX,TYDCOMPLEX,1,"z_sin" },
+
+	{ TYREAL,TYREAL,1,"r_cos", 5 },
+	{ TYDREAL,TYDREAL,1,"d_cos", 5 },
+	{ TYCOMPLEX,TYCOMPLEX,1,"c_cos" },
+	{ TYDCOMPLEX,TYDCOMPLEX,1,"z_cos" },
+
+	{ TYREAL,TYREAL,1,"r_tan", 6 },
+	{ TYDREAL,TYDREAL,1,"d_tan", 6 },
+
+	{ TYREAL,TYREAL,1,"r_asin", 7 },
+	{ TYDREAL,TYDREAL,1,"d_asin", 7 },
+
+	{ TYREAL,TYREAL,1,"r_acos", 8 },
+	{ TYDREAL,TYDREAL,1,"d_acos", 8 },
+
+	{ TYREAL,TYREAL,1,"r_atan", 9 },
+	{ TYDREAL,TYDREAL,1,"d_atan", 9 },
+
+	{ TYREAL,TYREAL,2,"r_atn2", 10 },
+	{ TYDREAL,TYDREAL,2,"d_atn2", 10 },
+
+	{ TYREAL,TYREAL,1,"r_sinh", 11 },
+	{ TYDREAL,TYDREAL,1,"d_sinh", 11 },
+
+	{ TYREAL,TYREAL,1,"r_cosh", 12 },
+	{ TYDREAL,TYDREAL,1,"d_cosh", 12 },
+
+	{ TYREAL,TYREAL,1,"r_tanh", 13 },
+	{ TYDREAL,TYDREAL,1,"d_tanh", 13 },
+
+	{ TYCHAR,TYLOGICAL,2,"hl_ge" },
+	{ TYCHAR,TYLOGICAL,2,"l_ge" },
+
+	{ TYCHAR,TYLOGICAL,2,"hl_gt" },
+	{ TYCHAR,TYLOGICAL,2,"l_gt" },
+
+	{ TYCHAR,TYLOGICAL,2,"hl_le" },
+	{ TYCHAR,TYLOGICAL,2,"l_le" },
+
+	{ TYCHAR,TYLOGICAL,2,"hl_lt" },
+	{ TYCHAR,TYLOGICAL,2,"l_lt" }
+} ;
+
+
+
+
+
+
+char callbyvalue[ ][XL] =
+	{
+	"sqrt",
+	"exp",
+	"log",
+	"sin",
+	"cos",
+	"tan",
+	"asin",
+	"acos",
+	"atan",
+	"atan2",
+	"sinh",
+	"cosh",
+	"tanh"
+	};
+
+
+struct bigblock *
+intrcall(np, argsp, nargs)
+struct bigblock *np;
+struct bigblock *argsp;
+int nargs;
+{
+int i, rettype;
+struct bigblock *ap;
+register struct specblock *sp;
+struct bigblock *q;
+register chainp cp;
+bigptr ep;
+int mtype;
+int op;
+
+packed.ijunk = np->b_name.vardesc.varno;
+if(nargs == 0)
+	goto badnargs;
+
+mtype = 0;
+for(cp = argsp->b_list.listp ; cp ; cp = cp->chain.nextp)
+	{
+/* TEMPORARY */ ep = cp->chain.datap;
+/* TEMPORARY */	if( ISCONST(ep) && ep->vtype==TYSHORT )
+/* TEMPORARY */		cp->chain.datap = mkconv(tyint, ep);
+	mtype = maxtype(mtype, ep->vtype);
+	}
+
+switch(packed.bits.f1)
+	{
+	case INTRBOOL:
+		op = packed.bits.f3;
+		if( ! ONEOF(mtype, MSKINT|MSKLOGICAL) )
+			goto badtype;
+		if(op == OPBITNOT)
+			{
+			if(nargs != 1)
+				goto badnargs;
+			q = mkexpr(OPBITNOT, argsp->b_list.listp->chain.datap, NULL);
+			}
+		else
+			{
+			if(nargs != 2)
+				goto badnargs;
+			q = mkexpr(op, argsp->b_list.listp->chain.datap,
+				argsp->b_list.listp->chain.nextp->chain.datap);
+			}
+		frchain( &(argsp->b_list.listp) );
+		ckfree(argsp);
+		return(q);
+
+	case INTRCONV:
+		rettype = packed.bits.f2;
+		if(rettype == TYLONG)
+			rettype = tyint;
+		if( ISCOMPLEX(rettype) && nargs==2)
+			{
+			bigptr qr, qi;
+			qr = argsp->b_list.listp->chain.datap;
+			qi = argsp->b_list.listp->chain.nextp->chain.datap;
+			if(ISCONST(qr) && ISCONST(qi))
+				q = mkcxcon(qr,qi);
+			else	q = mkexpr(OPCONV,mkconv(rettype-2,qr),
+					mkconv(rettype-2,qi));
+			}
+		else if(nargs == 1)
+			q = mkconv(rettype, argsp->b_list.listp->chain.datap);
+		else goto badnargs;
+
+		q->vtype = rettype;
+		frchain(&(argsp->b_list.listp));
+		ckfree(argsp);
+		return(q);
+
+
+	case INTRGEN:
+		sp = spectab + packed.bits.f3;
+		for(i=0; i<packed.bits.f2 ; ++i)
+			if(sp->atype == mtype) {
+				if (tyint == TYLONG &&
+				    sp->rtype == TYSHORT && 
+				    sp[1].atype == mtype)
+					sp++; /* use long int */
+				goto specfunct;
+			} else
+				++sp;
+		goto badtype;
+
+	case INTRSPEC:
+		sp = spectab + packed.bits.f3;
+		if(tyint==TYLONG && sp->rtype==TYSHORT)
+			++sp;
+
+	specfunct:
+		if(nargs != sp->nargs)
+			goto badnargs;
+		if(mtype != sp->atype)
+			goto badtype;
+		fixargs(YES, argsp);
+		if((q = finline(sp-spectab, mtype, argsp->b_list.listp)))
+			{
+			frchain( &(argsp->b_list.listp) );
+			ckfree(argsp);
+			}
+		else if(sp->othername)
+			{
+			ap = builtin(sp->rtype,
+				varstr(XL, callbyvalue[sp->othername-1]) );
+			q = fixexpr( mkexpr(OPCCALL, ap, argsp) );
+			}
+		else
+			{
+			ap = builtin(sp->rtype, varstr(XL, sp->spxname) );
+			q = fixexpr( mkexpr(OPCALL, ap, argsp) );
+			}
+		return(q);
+
+	case INTRMIN:
+	case INTRMAX:
+		if(nargs < 2)
+			goto badnargs;
+		if( ! ONEOF(mtype, MSKINT|MSKREAL) )
+			goto badtype;
+		argsp->vtype = mtype;
+		q = mkexpr( (packed.bits.f1==INTRMIN ? OPMIN : OPMAX), argsp, NULL);
+
+		q->vtype = mtype;
+		rettype = packed.bits.f2;
+		if(rettype == TYLONG)
+			rettype = tyint;
+		else if(rettype == TYUNKNOWN)
+			rettype = mtype;
+		return( mkconv(rettype, q) );
+
+	default:
+		fatal1("intrcall: bad intrgroup %d", packed.bits.f1);
+	}
+badnargs:
+	err1("bad number of arguments to intrinsic %s",
+		varstr(VL,np->b_name.varname) );
+	goto bad;
+
+badtype:
+	err1("bad argument type to intrinsic %s", varstr(VL, np->b_name.varname) );
+
+bad:
+	return( errnode() );
+}
+
+
+
+int
+intrfunct(s)
+char s[VL];
+{
+register struct intrblock *p;
+char nm[VL];
+register int i;
+
+for(i = 0 ; i<VL ; ++s)
+	nm[i++] = (*s==' ' ? '\0' : *s);
+
+for(p = intrtab; p->intrval.intrgroup!=INTREND ; ++p)
+	{
+	if( eqn(VL, nm, p->intrfname) )
+		{
+		packed.bits.f1 = p->intrval.intrgroup;
+		packed.bits.f2 = p->intrval.intrstuff;
+		packed.bits.f3 = p->intrval.intrno;
+		return(packed.ijunk);
+		}
+	}
+
+return(0);
+}
+
+
+
+
+
+struct bigblock *
+intraddr(np)
+struct bigblock *np;
+{
+struct bigblock *q;
+struct specblock *sp;
+
+if(np->vclass!=CLPROC || np->b_name.vprocclass!=PINTRINSIC)
+	fatal1("intraddr: %s is not intrinsic", varstr(VL,np->b_name.varname));
+packed.ijunk = np->b_name.vardesc.varno;
+
+switch(packed.bits.f1)
+	{
+	case INTRGEN:
+		/* imag, log, and log10 arent specific functions */
+		if(packed.bits.f3==31 || packed.bits.f3==43 || packed.bits.f3==47)
+			goto bad;
+
+	case INTRSPEC:
+		sp = spectab + packed.bits.f3;
+		if(tyint==TYLONG && sp->rtype==TYSHORT)
+			++sp;
+		q = builtin(sp->rtype, varstr(XL,sp->spxname) );
+		return(q);
+
+	case INTRCONV:
+	case INTRMIN:
+	case INTRMAX:
+	case INTRBOOL:
+	bad:
+		err1("cannot pass %s as actual",
+			varstr(VL,np->b_name.varname));
+		return( errnode() );
+	}
+fatal1("intraddr: impossible f1=%d\n", packed.bits.f1);
+/* NOTREACHED */
+return 0; /* XXX gcc */
+}
+
+
+
+
+/*
+ * Try to inline simple function calls.
+ */
+struct bigblock *
+finline(int fno, int type, chainp args)
+{
+	register struct bigblock *q, *t;
+	struct bigblock *x1;
+	int l1;
+
+	switch(fno) {
+	case 8:	/* real abs */
+	case 9:	/* short int abs */
+	case 10:	/* long int abs */
+	case 11:	/* double precision abs */
+		t = fmktemp(type, NULL);
+		putexpr(mkexpr(OPASSIGN, cpexpr(t), args->chain.datap));
+		/* value now in t */
+
+		/* if greater, jump to return */
+		x1 = mkexpr(OPLE, cpexpr(t), mkconv(type,MKICON(0)));
+		l1 = newlabel();
+		putif(x1, l1);
+
+		/* negate */
+		putexpr(mkexpr(OPASSIGN, cpexpr(t),
+		    mkexpr(OPNEG, cpexpr(t), NULL)));
+		putlabel(l1);
+		return(t);
+		
+	case 26:	/* dprod */
+		q = mkexpr(OPSTAR, args->chain.datap, args->chain.nextp->chain.datap);
+		q->vtype = TYDREAL;
+		return(q);
+
+	case 27:	/* len of character string */
+		q = cpexpr(args->chain.datap->vleng);
+		frexpr(args->chain.datap);
+		return(q);
+
+	case 14:	/* half-integer mod */
+	case 15:	/* mod */
+		return( mkexpr(OPMOD, args->chain.datap, args->chain.nextp->chain.datap) );
+	}
+return(NULL);
+}
Index: uspace/app/pcc/f77/fcom/io.c
===================================================================
--- uspace/app/pcc/f77/fcom/io.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/io.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,799 @@
+/*	$Id: io.c,v 1.15 2008/12/19 08:08:48 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 conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/* TEMPORARY */
+#define TYIOINT TYLONG
+#define FSZIOINT FSZLONG
+
+#include <string.h>
+
+#include "defines.h"
+#include "defs.h"
+
+LOCAL void doiolist(chainp);
+LOCAL void dofopen(void);
+LOCAL void dofclose(void);
+LOCAL void dofinquire(void);
+LOCAL void dofmove(char *);
+LOCAL void ioset(int, int, bigptr);
+LOCAL void iosetc(int, bigptr);
+LOCAL void iosetip(int, int);
+LOCAL void iosetlc(int, int, int);
+LOCAL void putiocall(struct bigblock *q);
+LOCAL void putio(bigptr, bigptr);
+LOCAL void startrw(void);
+
+
+LOCAL char ioroutine[XL+1];
+
+LOCAL int ioendlab;
+LOCAL int ioerrlab;
+LOCAL int endbit;
+LOCAL int jumplab;
+LOCAL int skiplab;
+LOCAL int ioformatted;
+
+#define UNFORMATTED 0
+#define FORMATTED 1
+#define LISTDIRECTED 2
+
+#define V(z)	ioc[z].iocval
+
+#define IOALL 07777
+
+LOCAL struct ioclist
+	{
+	char *iocname;
+	int iotype;
+	bigptr iocval;
+	} ioc[ ] =
+	{
+		{ "", 0 },
+		{ "unit", IOALL },
+		{ "fmt", M(IOREAD) | M(IOWRITE) },
+		{ "err", IOALL },
+		{ "end", M(IOREAD) },
+		{ "iostat", IOALL },
+		{ "rec", M(IOREAD) | M(IOWRITE) },
+		{ "recl", M(IOOPEN) | M(IOINQUIRE) },
+		{ "file", M(IOOPEN) | M(IOINQUIRE) },
+		{ "status", M(IOOPEN) | M(IOCLOSE) },
+		{ "access", M(IOOPEN) | M(IOINQUIRE) },
+		{ "form", M(IOOPEN) | M(IOINQUIRE) },
+		{ "blank", M(IOOPEN) | M(IOINQUIRE) },
+		{ "exist", M(IOINQUIRE) },
+		{ "opened", M(IOINQUIRE) },
+		{ "number", M(IOINQUIRE) },
+		{ "named", M(IOINQUIRE) },
+		{ "name", M(IOINQUIRE) },
+		{ "sequential", M(IOINQUIRE) },
+		{ "direct", M(IOINQUIRE) },
+		{ "formatted", M(IOINQUIRE) },
+		{ "unformatted", M(IOINQUIRE) },
+		{ "nextrec", M(IOINQUIRE) }
+	} ;
+
+#define NIOS (sizeof(ioc)/sizeof(struct ioclist) - 1)
+#define MAXIO	FSZFLAG + 10*FSZIOINT + 15*FSZADDR
+
+#define IOSUNIT 1
+#define IOSFMT 2
+#define IOSERR 3
+#define IOSEND 4
+#define IOSIOSTAT 5
+#define IOSREC 6
+#define IOSRECL 7
+#define IOSFILE 8
+#define IOSSTATUS 9
+#define IOSACCESS 10
+#define IOSFORM 11
+#define IOSBLANK 12
+#define IOSEXISTS 13
+#define IOSOPENED 14
+#define IOSNUMBER 15
+#define IOSNAMED 16
+#define IOSNAME 17
+#define IOSSEQUENTIAL 18
+#define IOSDIRECT 19
+#define IOSFORMATTED 20
+#define IOSUNFORMATTED 21
+#define IOSNEXTREC 22
+
+#define IOSTP V(IOSIOSTAT)
+
+
+/* offsets in generated structures */
+
+#define FSZFLAG FSZIOINT
+
+#define XERR 0
+#define XUNIT	FSZFLAG
+#define XEND	FSZFLAG + FSZIOINT
+#define XFMT	2*FSZFLAG + FSZIOINT
+#define XREC	2*FSZFLAG + FSZIOINT + FSZADDR
+#define XRLEN	2*FSZFLAG + 2*FSZADDR
+#define XRNUM	2*FSZFLAG + 2*FSZADDR + FSZIOINT
+
+#define XIFMT	2*FSZFLAG + FSZADDR
+#define XIEND	FSZFLAG + FSZADDR
+#define XIUNIT	FSZFLAG
+
+#define XFNAME	FSZFLAG + FSZIOINT
+#define XFNAMELEN	FSZFLAG + FSZIOINT + FSZADDR
+#define XSTATUS	FSZFLAG + 2*FSZIOINT + FSZADDR
+#define XACCESS	FSZFLAG + 2*FSZIOINT + 2*FSZADDR
+#define XFORMATTED	FSZFLAG + 2*FSZIOINT + 3*FSZADDR
+#define XRECLEN	FSZFLAG + 2*FSZIOINT + 4*FSZADDR
+#define XBLANK	FSZFLAG + 3*FSZIOINT + 4*FSZADDR
+
+#define XCLSTATUS	FSZFLAG + FSZIOINT
+
+#define XFILE	FSZFLAG + FSZIOINT
+#define XFILELEN	FSZFLAG + FSZIOINT + FSZADDR
+#define XEXISTS	FSZFLAG + 2*FSZIOINT + FSZADDR
+#define XOPEN	FSZFLAG + 2*FSZIOINT + 2*FSZADDR
+#define XNUMBER	FSZFLAG + 2*FSZIOINT + 3*FSZADDR
+#define XNAMED	FSZFLAG + 2*FSZIOINT + 4*FSZADDR
+#define XNAME	FSZFLAG + 2*FSZIOINT + 5*FSZADDR
+#define XNAMELEN	FSZFLAG + 2*FSZIOINT + 6*FSZADDR
+#define XQACCESS	FSZFLAG + 3*FSZIOINT + 6*FSZADDR
+#define XQACCLEN	FSZFLAG + 3*FSZIOINT + 7*FSZADDR
+#define XSEQ	FSZFLAG + 4*FSZIOINT + 7*FSZADDR
+#define XSEQLEN	FSZFLAG + 4*FSZIOINT + 8*FSZADDR
+#define XDIRECT	FSZFLAG + 5*FSZIOINT + 8*FSZADDR
+#define XDIRLEN	FSZFLAG + 5*FSZIOINT + 9*FSZADDR
+#define XFORM	FSZFLAG + 6*FSZIOINT + 9*FSZADDR
+#define XFORMLEN	FSZFLAG + 6*FSZIOINT + 10*FSZADDR
+#define XFMTED	FSZFLAG + 7*FSZIOINT + 10*FSZADDR
+#define XFMTEDLEN	FSZFLAG + 7*FSZIOINT + 11*FSZADDR
+#define XUNFMT	FSZFLAG + 8*FSZIOINT + 11*FSZADDR
+#define XUNFMTLEN	FSZFLAG + 8*FSZIOINT + 12*FSZADDR
+#define XQRECL	FSZFLAG + 9*FSZIOINT + 12*FSZADDR
+#define XNEXTREC	FSZFLAG + 9*FSZIOINT + 13*FSZADDR
+#define XQBLANK	FSZFLAG + 9*FSZIOINT + 14*FSZADDR
+#define XQBLANKLEN	FSZFLAG + 9*FSZIOINT + 15*FSZADDR
+
+
+int
+fmtstmt(lp)
+register struct labelblock *lp;
+{
+if(lp == NULL)
+	{
+	execerr("unlabeled format statement" , 0);
+	return(-1);
+	}
+if(lp->labtype == LABUNKNOWN)
+	{
+	lp->labtype = LABFORMAT;
+	lp->labelno = newlabel();
+	}
+else if(lp->labtype != LABFORMAT)
+	{
+	execerr("bad format number", 0);
+	return(-1);
+	}
+return(lp->labelno);
+}
+
+
+void
+setfmt(struct labelblock *lp)
+{
+	ftnint n;
+	char *s;
+
+	s = lexline(&n);
+	preven(ALILONG);
+	prlabel(lp->labelno);
+	putstr(s, n);
+	flline();
+}
+
+
+void
+startioctl()
+{
+unsigned int i;
+
+inioctl = YES;
+nioctl = 0;
+ioerrlab = 0;
+ioformatted = UNFORMATTED;
+for(i = 1 ; i<=NIOS ; ++i)
+	V(i) = NULL;
+}
+
+
+void
+endioctl()
+{
+unsigned int i;
+bigptr p;
+
+inioctl = NO;
+if(ioblkp == NULL)
+	ioblkp = autovar( (MAXIO+FSZIOINT-1)/FSZIOINT , TYIOINT, NULL);
+
+/* set up for error recovery */
+
+ioerrlab = ioendlab = skiplab = jumplab = 0;
+
+if((p = V(IOSEND))) {
+	if(ISICON(p))
+		ioendlab = mklabel(p->b_const.fconst.ci)->labelno;
+	else
+		err("bad end= clause");
+}
+
+if((p = V(IOSERR))) {
+	if(ISICON(p))
+		ioerrlab = mklabel(p->b_const.fconst.ci)->labelno;
+	else
+		err("bad err= clause");
+}
+
+if(IOSTP==NULL && ioerrlab!=0 && ioendlab!=0 && ioerrlab!=ioendlab)
+	IOSTP = fmktemp(TYINT, NULL);
+
+if(IOSTP != NULL) {
+	if(IOSTP->tag!=TADDR || ! ISINT(IOSTP->vtype) )
+		{
+		err("iostat must be an integer variable");
+		frexpr(IOSTP);
+		IOSTP = NULL;
+		}
+}
+
+if(IOSTP)
+	{
+	if( (iostmt==IOREAD || iostmt==IOWRITE) &&
+	    (ioerrlab!=ioendlab || ioerrlab==0) )
+		jumplab = skiplab = newlabel();
+	else
+		jumplab = ioerrlab;
+	}
+else
+	{
+	jumplab = ioerrlab;
+	if(ioendlab)
+		jumplab = ioendlab;
+	}
+
+ioset(TYIOINT, XERR, MKICON(IOSTP!=NULL || ioerrlab!=0) );
+endbit = IOSTP!=NULL || ioendlab!=0;	/* for use in startrw() */
+
+switch(iostmt)
+	{
+	case IOOPEN:
+		dofopen();  break;
+
+	case IOCLOSE:
+		dofclose();  break;
+
+	case IOINQUIRE:
+		dofinquire();  break;
+
+	case IOBACKSPACE:
+		dofmove("f_back"); break;
+
+	case IOREWIND:
+		dofmove("f_rew");  break;
+
+	case IOENDFILE:
+		dofmove("f_end");  break;
+
+	case IOREAD:
+	case IOWRITE:
+		startrw();  break;
+
+	default:
+		fatal1("impossible iostmt %d", iostmt);
+	}
+for(i = 1 ; i<=NIOS ; ++i)
+	if(i!=IOSIOSTAT || (iostmt!=IOREAD && iostmt!=IOWRITE) )
+		frexpr(V(i));
+}
+
+
+int
+iocname()
+{
+unsigned int i;
+int found, mask;
+
+found = 0;
+mask = M(iostmt);
+for(i = 1 ; i <= NIOS ; ++i) {
+	if(toklen==(int)strlen(ioc[i].iocname) && eqn(toklen, token, ioc[i].iocname)) {
+		if(ioc[i].iotype & mask)
+			return(i);
+		else	found = i;
+	}
+}
+
+if(found)
+	err1("invalid control %s for statement", ioc[found].iocname);
+else
+	err1("unknown iocontrol %s", varstr(toklen, token) );
+return(IOSBAD);
+}
+
+void
+ioclause(n, p)
+register int n;
+register bigptr p;
+{
+struct ioclist *iocp;
+
+++nioctl;
+if(n == IOSBAD)
+	return;
+if(n == IOSPOSITIONAL)
+	{
+	if(nioctl > IOSFMT)
+		{
+		err("illegal positional iocontrol");
+		return;
+		}
+	n = nioctl;
+	}
+
+if(p == NULL)
+	{
+	if(n == IOSUNIT)
+		p = (iostmt==IOREAD ? IOSTDIN : IOSTDOUT);
+	else if(n != IOSFMT)
+		{
+		err("illegal * iocontrol");
+		return;
+		}
+	}
+if(n == IOSFMT)
+	ioformatted = (p==NULL ? LISTDIRECTED : FORMATTED);
+
+iocp = & ioc[n];
+if(iocp->iocval == NULL)
+	{
+	p = cpexpr(p);
+	if(n!=IOSFMT && ( n!=IOSUNIT || (p!=NULL && p->vtype!=TYCHAR) ) )
+		p = fixtype(p);
+	iocp->iocval = p;
+}
+else
+	err1("iocontrol %s repeated", iocp->iocname);
+}
+
+/* io list item */
+void
+doio(list)
+chainp list;
+{
+doiolist(list);
+ioroutine[0] = 'e';
+putiocall( call0(TYINT, ioroutine) );
+frexpr(IOSTP);
+}
+
+
+
+
+
+LOCAL void doiolist(p0)
+chainp p0;
+{
+chainp p;
+register bigptr q;
+register bigptr qe;
+register struct bigblock *qn;
+struct bigblock *tp;
+int range;
+
+for (p = p0 ; p ; p = p->chain.nextp)
+	{
+	q = p->chain.datap;
+	if(q->tag == TIMPLDO)
+		{
+		exdo(range=newlabel(), (chainp)q->b_impldo.varnp);
+		doiolist(q->b_impldo.datalist);
+		enddo(range);
+		ckfree(q);
+		}
+	else	{
+		if(q->tag==TPRIM && q->b_prim.argsp==NULL && q->b_prim.namep->b_name.vdim!=NULL)
+			{
+			vardcl(qn = q->b_prim.namep);
+			if(qn->b_name.vdim->nelt)
+				putio( fixtype(cpexpr(qn->b_name.vdim->nelt)),
+					mkscalar(qn) );
+			else
+				err("attempt to i/o array of unknown size");
+			}
+		else if(q->tag==TPRIM && q->b_prim.argsp==NULL && (qe = memversion(q->b_prim.namep)) )
+			putio(MKICON(1),qe);
+		else if( (qe = fixtype(cpexpr(q)))->tag==TADDR)
+			putio(MKICON(1), qe);
+		else if(qe->vtype != TYERROR)
+			{
+			if(iostmt == IOWRITE)
+				{
+				tp = fmktemp(qe->vtype, qe->vleng);
+				puteq( cpexpr(tp), qe);
+				putio(MKICON(1), tp);
+				}
+			else
+				err("non-left side in READ list");
+			}
+		frexpr(q);
+		}
+	}
+frchain( &p0 );
+}
+
+
+
+
+
+LOCAL void
+putio(nelt, addr)
+bigptr nelt;
+register bigptr addr;
+{
+int type;
+register struct bigblock *q;
+
+type = addr->vtype;
+if(ioformatted!=LISTDIRECTED && ISCOMPLEX(type) )
+	{
+	nelt = mkexpr(OPSTAR, MKICON(2), nelt);
+	type -= (TYCOMPLEX-TYREAL);
+	}
+
+/* pass a length with every item.  for noncharacter data, fake one */
+if(type != TYCHAR)
+	{
+	if( ISCONST(addr) )
+		addr = putconst(addr);
+	addr->vtype = TYCHAR;
+	addr->vleng = MKICON( typesize[type] );
+	}
+
+nelt = fixtype( mkconv(TYLENG,nelt) );
+if(ioformatted == LISTDIRECTED)
+	q = call3(TYINT, "do_lio", mkconv(TYLONG, MKICON(type)), nelt, addr);
+else
+	q = call2(TYINT, (ioformatted==FORMATTED ? "do_fio" : "do_uio"),
+		nelt, addr);
+putiocall(q);
+}
+
+
+
+void
+endio()
+{
+if(skiplab)
+	{
+	putlabel(skiplab);
+	if(ioendlab)
+		putif( mkexpr(OPGE, cpexpr(IOSTP), MKICON(0)), ioendlab);
+	if(ioerrlab)
+		putif( mkexpr( ( (iostmt==IOREAD||iostmt==IOWRITE) ? OPLE : OPEQ),
+			cpexpr(IOSTP), MKICON(0)) , ioerrlab);
+	}
+if(IOSTP)
+	frexpr(IOSTP);
+}
+
+
+
+LOCAL void
+putiocall(q)
+register struct bigblock *q;
+{
+if(IOSTP)
+	{
+	q->vtype = TYINT;
+	q = fixexpr( mkexpr(OPASSIGN, cpexpr(IOSTP), q));
+	}
+
+if(jumplab)
+	putif( mkexpr(OPEQ, q, MKICON(0) ), jumplab);
+else
+	putexpr(q);
+}
+
+
+
+void
+startrw()
+{
+register bigptr p;
+register struct bigblock *np;
+register struct bigblock *unitp, *nump;
+int k, fmtoff;
+int intfile, sequential;
+
+
+sequential = YES;
+if((p = V(IOSREC))) {
+	if( ISINT(p->vtype) )
+		{
+		ioset(TYIOINT, XREC, cpexpr(p) );
+		sequential = NO;
+		}
+	else
+		err("bad REC= clause");
+}
+
+intfile = NO;
+if((p = V(IOSUNIT)))
+	{
+	if( ISINT(p->vtype) )
+		ioset(TYIOINT, XUNIT, cpexpr(p) );
+	else if(p->vtype == TYCHAR)
+		{
+		intfile = YES;
+		if(p->tag==TPRIM && p->b_prim.argsp==NULL && (np = p->b_prim.namep)->b_name.vdim!=NULL)
+			{
+			vardcl(np);
+			if(np->b_name.vdim->nelt)
+				nump = cpexpr(np->b_name.vdim->nelt);
+			else
+				{
+				err("attempt to use internal unit array of unknown size");
+				nump = MKICON(1);
+				}
+			unitp = mkscalar(np);
+			}
+		else	{
+			nump = MKICON(1);
+			unitp = fixtype(cpexpr(p));
+			}
+		ioset(TYIOINT, XRNUM, nump);
+		ioset(TYIOINT, XRLEN, cpexpr(unitp->vleng) );
+		ioset(TYADDR, XUNIT, addrof(unitp) );
+		}
+	}
+else
+	err("bad unit specifier");
+
+if(iostmt == IOREAD)
+	ioset(TYIOINT, (intfile ? XIEND : XEND), MKICON(endbit) );
+
+fmtoff = (intfile ? XIFMT : XFMT);
+
+if((p = V(IOSFMT)))
+	{
+	if(p->tag==TPRIM && p->b_prim.argsp==NULL)
+		{
+		vardcl(np = p->b_prim.namep);
+		if(np->b_name.vdim)
+			{
+			ioset(TYADDR, fmtoff, addrof(mkscalar(np)) );
+			goto endfmt;
+			}
+		if( ISINT(np->vtype) )
+			{
+			ioset(TYADDR, fmtoff, cpexpr(p));
+			goto endfmt;
+			}
+		}
+	p = V(IOSFMT) = fixtype(p);
+	if(p->vtype == TYCHAR)
+		ioset(TYADDR, fmtoff, addrof(cpexpr(p)) );
+	else if( ISICON(p) )
+		{
+		if( (k = fmtstmt( mklabel(p->b_const.fconst.ci) )) > 0 )
+			ioset(TYADDR, fmtoff, mkaddcon(k) );
+		else
+			ioformatted = UNFORMATTED;
+		}
+	else	{
+		err("bad format descriptor");
+		ioformatted = UNFORMATTED;
+		}
+	}
+else
+	ioset(TYADDR, fmtoff, MKICON(0) );
+
+endfmt:
+
+
+ioroutine[0] = 's';
+ioroutine[1] = '_';
+ioroutine[2] = (iostmt==IOREAD ? 'r' : 'w');
+ioroutine[3] = (sequential ? 's' : 'd');
+ioroutine[4] = "ufl" [ioformatted];
+ioroutine[5] = (intfile ? 'i' : 'e');
+ioroutine[6] = '\0';
+putiocall( call1(TYINT, ioroutine, cpexpr(ioblkp) ));
+}
+
+
+
+LOCAL void dofopen()
+{
+register bigptr p;
+
+if( (p = V(IOSUNIT)) && ISINT(p->vtype) )
+	ioset(TYIOINT, XUNIT, cpexpr(p) );
+else
+	err("bad unit in open");
+if( (p = V(IOSFILE)) && p->vtype==TYCHAR)
+	{
+	ioset(TYIOINT, XFNAMELEN, cpexpr(p->vleng) );
+	iosetc(XFNAME, p);
+	}
+else
+	err("bad file in open");
+
+if((p = V(IOSRECL)))
+	if( ISINT(p->vtype) )
+		ioset(TYIOINT, XRECLEN, cpexpr(p) );
+	else
+		err("bad recl");
+else
+	ioset(TYIOINT, XRECLEN, MKICON(0) );
+
+iosetc(XSTATUS, V(IOSSTATUS));
+iosetc(XACCESS, V(IOSACCESS));
+iosetc(XFORMATTED, V(IOSFORM));
+iosetc(XBLANK, V(IOSBLANK));
+
+putiocall( call1(TYINT, "f_open", cpexpr(ioblkp) ));
+}
+
+
+LOCAL void
+dofclose()
+{
+register bigptr p;
+
+if( (p = V(IOSUNIT)) && ISINT(p->vtype) )
+	{
+	ioset(TYIOINT, XUNIT, cpexpr(p) );
+	iosetc(XCLSTATUS, V(IOSSTATUS));
+	putiocall( call1(TYINT, "f_clos", cpexpr(ioblkp)) );
+	}
+else
+	err("bad unit in close statement");
+}
+
+
+LOCAL void dofinquire()
+{
+register bigptr p;
+if((p = V(IOSUNIT)))
+	{
+	if( V(IOSFILE) )
+		err("inquire by unit or by file, not both");
+	ioset(TYIOINT, XUNIT, cpexpr(p) );
+	}
+else if( ! V(IOSFILE) )
+	err("must inquire by unit or by file");
+iosetlc(IOSFILE, XFILE, XFILELEN);
+iosetip(IOSEXISTS, XEXISTS);
+iosetip(IOSOPENED, XOPEN);
+iosetip(IOSNUMBER, XNUMBER);
+iosetip(IOSNAMED, XNAMED);
+iosetlc(IOSNAME, XNAME, XNAMELEN);
+iosetlc(IOSACCESS, XQACCESS, XQACCLEN);
+iosetlc(IOSSEQUENTIAL, XSEQ, XSEQLEN);
+iosetlc(IOSDIRECT, XDIRECT, XDIRLEN);
+iosetlc(IOSFORM, XFORM, XFORMLEN);
+iosetlc(IOSFORMATTED, XFMTED, XFMTEDLEN);
+iosetlc(IOSUNFORMATTED, XUNFMT, XUNFMTLEN);
+iosetip(IOSRECL, XQRECL);
+iosetip(IOSNEXTREC, XNEXTREC);
+
+putiocall( call1(TYINT,  "f_inqu", cpexpr(ioblkp) ));
+}
+
+
+
+LOCAL void
+dofmove(subname)
+char *subname;
+{
+register bigptr p;
+
+if( (p = V(IOSUNIT)) && ISINT(p->vtype) )
+	{
+	ioset(TYIOINT, XUNIT, cpexpr(p) );
+	putiocall( call1(TYINT, subname, cpexpr(ioblkp) ));
+	}
+else
+	err("bad unit in move statement");
+}
+
+
+
+LOCAL void
+ioset(type, offset, p)
+int type, offset;
+bigptr p;
+{
+register struct bigblock *q;
+
+q = cpexpr(ioblkp);
+q->vtype = type;
+q->b_addr.memoffset = fixtype( mkexpr(OPPLUS, q->b_addr.memoffset, MKICON(offset)) );
+puteq(q, p);
+}
+
+
+
+
+LOCAL void
+iosetc(offset, p)
+int offset;
+register bigptr p;
+{
+if(p == NULL)
+	ioset(TYADDR, offset, MKICON(0) );
+else if(p->vtype == TYCHAR)
+	ioset(TYADDR, offset, addrof(cpexpr(p) ));
+else
+	err("non-character control clause");
+}
+
+
+
+LOCAL void
+iosetip(i, offset)
+int i, offset;
+{
+register bigptr p;
+
+if((p = V(i))) {
+	if(p->tag==TADDR && ONEOF(p->vtype, M(TYLONG)|M(TYLOGICAL)) )
+		ioset(TYADDR, offset, addrof(cpexpr(p)) );
+	else
+		err1("impossible inquire parameter %s", ioc[i].iocname);
+} else
+	ioset(TYADDR, offset, MKICON(0) );
+}
+
+
+
+LOCAL void
+iosetlc(i, offp, offl)
+int i, offp, offl;
+{
+register bigptr p;
+if( (p = V(i)) && p->vtype==TYCHAR)
+	ioset(TYIOINT, offl, cpexpr(p->vleng) );
+iosetc(offp, p);
+}
Index: uspace/app/pcc/f77/fcom/lex.c
===================================================================
--- uspace/app/pcc/f77/fcom/lex.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/lex.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,957 @@
+/*	$Id: lex.c,v 1.12 2008/05/11 15:28:03 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 "defines.h"
+#include "defs.h"
+
+#include "gram.h"
+
+# define BLANK	' '
+# define MYQUOTE (2)
+# define SEOF 0
+
+/* card types */
+
+# define STEOF 1
+# define STINITIAL 2
+# define STCONTINUE 3
+
+/* lex states */
+
+#define NEWSTMT	1
+#define FIRSTTOKEN	2
+#define OTHERTOKEN	3
+#define RETEOS	4
+
+
+LOCAL int stkey;
+LOCAL int stno;
+LOCAL long int nxtstno;
+LOCAL int parlev;
+LOCAL int expcom;
+LOCAL int expeql;
+LOCAL char *nextch;
+LOCAL char *lastch;
+LOCAL char *nextcd 	= NULL;
+LOCAL char *endcd;
+LOCAL int prevlin;
+LOCAL int thislin;
+LOCAL int code;
+LOCAL int lexstate	= NEWSTMT;
+LOCAL char s[1390];
+LOCAL char *send	= s+20*66;
+LOCAL int nincl	= 0;
+
+struct inclfile
+	{
+	struct inclfile *inclnext;
+	FILEP inclfp;
+	char *inclname;
+	int incllno;
+	char *incllinp;
+	int incllen;
+	int inclcode;
+	ftnint inclstno;
+	} ;
+
+LOCAL struct inclfile *inclp	=  NULL;
+struct keylist { char *keyname; int keyval; } ;
+struct punctlist { char punchar; int punval; };
+struct fmtlist { char fmtchar; int fmtval; };
+struct dotlist { char *dotname; int dotval; };
+LOCAL struct dotlist  dots[];
+LOCAL struct keylist *keystart[26], *keyend[26];
+LOCAL struct keylist  keys[];
+
+LOCAL int getcds(void);
+LOCAL void crunch(void);
+LOCAL void analyz(void);
+LOCAL int gettok(void);
+LOCAL int getcd(char *b);
+LOCAL int getkwd(void);
+LOCAL int popinclude(void);
+
+/*
+ * called from main() to start parsing.
+ * name[0] may be \0 if stdin.
+ */
+int
+inilex(char *name)
+{
+	nincl = 0;
+	inclp = NULL;
+	doinclude(name);
+	lexstate = NEWSTMT;
+	return(NO);
+}
+
+
+
+/* throw away the rest of the current line */
+void
+flline()
+{
+lexstate = RETEOS;
+}
+
+
+
+char *lexline(n)
+ftnint *n;
+{
+*n = (lastch - nextch) + 1;
+return(nextch);
+}
+
+
+
+
+void
+doinclude(char *name)
+{
+	FILEP fp;
+	struct inclfile *t;
+
+	if(inclp) {
+		inclp->incllno = thislin;
+		inclp->inclcode = code;
+		inclp->inclstno = nxtstno;
+		if(nextcd)
+			inclp->incllinp =
+			    copyn(inclp->incllen = endcd-nextcd , nextcd);
+		else
+			inclp->incllinp = 0;
+	}
+	nextcd = NULL;
+
+	if(++nincl >= MAXINCLUDES)
+		fatal("includes nested too deep");
+	if(name[0] == '\0')
+		fp = stdin;
+	else
+		fp = fopen(name, "r");
+	if( fp ) {
+		t = inclp;
+		inclp = ALLOC(inclfile);
+		inclp->inclnext = t;
+		prevlin = thislin = 0;
+		infname = inclp->inclname = name;
+		infile = inclp->inclfp = fp;
+	} else {
+		fprintf(diagfile, "Cannot open file %s", name);
+		done(1);
+	}
+}
+
+
+
+
+LOCAL int
+popinclude()
+{
+	struct inclfile *t;
+	register char *p;
+	register int k;
+
+	if(infile != stdin)
+		fclose(infile);
+	ckfree(infname);
+
+	--nincl;
+	t = inclp->inclnext;
+	ckfree(inclp);
+	inclp = t;
+	if(inclp == NULL)
+		return(NO);
+
+	infile = inclp->inclfp;
+	infname = inclp->inclname;
+	prevlin = thislin = inclp->incllno;
+	code = inclp->inclcode;
+	stno = nxtstno = inclp->inclstno;
+	if(inclp->incllinp) {
+		endcd = nextcd = s;
+		k = inclp->incllen;
+		p = inclp->incllinp;
+		while(--k >= 0)
+			*endcd++ = *p++;
+		ckfree(inclp->incllinp);
+	} else
+		nextcd = NULL;
+	return(YES);
+}
+
+
+
+int
+yylex()
+{
+static int  tokno;
+
+	switch(lexstate)
+	{
+case NEWSTMT :	/* need a new statement */
+	if(getcds() == STEOF)
+		return(SEOF);
+	crunch();
+	tokno = 0;
+	lexstate = FIRSTTOKEN;
+	yylval.num = stno;
+	stno = nxtstno;
+	toklen = 0;
+	return(SLABEL);
+
+first:
+case FIRSTTOKEN :	/* first step on a statement */
+	analyz();
+	lexstate = OTHERTOKEN;
+	tokno = 1;
+	return(stkey);
+
+case OTHERTOKEN :	/* return next token */
+	if(nextch > lastch)
+		goto reteos;
+	++tokno;
+	if((stkey==SLOGIF || stkey==SELSEIF) && parlev==0 && tokno>3) goto first;
+	if(stkey==SASSIGN && tokno==3 && nextch<lastch &&
+		nextch[0]=='t' && nextch[1]=='o')
+			{
+			nextch+=2;
+			return(STO);
+			}
+	return(gettok());
+
+reteos:
+case RETEOS:
+	lexstate = NEWSTMT;
+	return(SEOS);
+	}
+fatal1("impossible lexstate %d", lexstate);
+/* NOTREACHED */
+return 0; /* XXX gcc */
+}
+
+LOCAL int
+getcds()
+{
+register char *p, *q;
+
+top:
+	if(nextcd == NULL)
+		{
+		code = getcd( nextcd = s );
+		stno = nxtstno;
+		prevlin = thislin;
+		}
+	if(code == STEOF) {
+		if( popinclude() )
+			goto top;
+		else
+			return(STEOF);
+	}
+	if(code == STCONTINUE)
+		{
+		lineno = thislin;
+		err("illegal continuation card ignored");
+		nextcd = NULL;
+		goto top;
+		}
+
+	if(nextcd > s)
+		{
+		q = nextcd;
+		p = s;
+		while(q < endcd)
+			*p++ = *q++;
+		endcd = p;
+		}
+	for(nextcd = endcd ;
+		nextcd+66<=send && (code = getcd(nextcd))==STCONTINUE ;
+		nextcd = endcd )
+			;
+	nextch = s;
+	lastch = nextcd - 1;
+	if(nextcd >= send)
+		nextcd = NULL;
+	lineno = prevlin;
+	prevlin = thislin;
+	return(STINITIAL);
+}
+
+LOCAL int
+getcd(b)
+register char *b;
+{
+register int c;
+register char *p, *bend;
+int speclin;
+static char a[6];
+static char *aend	= a+6;
+
+top:
+	endcd = b;
+	bend = b+66;
+	speclin = NO;
+
+	if( (c = getc(infile)) == '&')
+		{
+		a[0] = BLANK;
+		a[5] = 'x';
+		speclin = YES;
+		bend = send;
+		}
+	else if(c=='c' || c=='C' || c=='*')
+		{
+		while( (c = getc(infile)) != '\n')
+			if(c == EOF)
+				return(STEOF);
+		++thislin;
+		goto top;
+		}
+
+	else if(c != EOF)
+		{
+		/* a tab in columns 1-6 skips to column 7 */
+		ungetc(c, infile);
+		for(p=a; p<aend && (c=getc(infile)) != '\n' && c!=EOF; )
+			if(c == '\t')
+				{
+				while(p < aend)
+					*p++ = BLANK;
+				speclin = YES;
+				bend = send;
+				}
+			else
+				*p++ = c;
+		}
+	if(c == EOF)
+		return(STEOF);
+	if(c == '\n')
+		{
+		p = a; /* XXX ??? */
+		while(p < aend)
+			*p++ = BLANK;
+		if( ! speclin )
+			while(endcd < bend)
+				*endcd++ = BLANK;
+		}
+	else	{	/* read body of line */
+		while( endcd<bend && (c=getc(infile)) != '\n' && c!=EOF )
+			*endcd++ = (c == '\t' ? BLANK : c);
+		if(c == EOF)
+			return(STEOF);
+		if(c != '\n')
+			{
+			while( (c=getc(infile)) != '\n')
+				if(c == EOF)
+					return(STEOF);
+			}
+
+		if( ! speclin )
+			while(endcd < bend)
+				*endcd++ = BLANK;
+		}
+	++thislin;
+	if(a[5]!=BLANK && a[5]!='0')
+		return(STCONTINUE);
+	for(p=a; p<aend; ++p)
+		if(*p != BLANK) goto initline;
+	for(p = b ; p<endcd ; ++p)
+		if(*p != BLANK) goto initline;
+	goto top;
+
+initline:
+	nxtstno = 0;
+	for(p = a ; p<a+5 ; ++p)
+		if(*p != BLANK) {
+			if(isdigit((int)*p))
+				nxtstno = 10*nxtstno + (*p - '0');
+			else	{
+				lineno = thislin;
+				err("nondigit in statement number field");
+				nxtstno = 0;
+				break;
+				}
+		}
+	return(STINITIAL);
+}
+
+LOCAL void
+crunch()
+{
+register char *i, *j, *j0, *j1, *prvstr;
+int ten, nh, quote;
+
+/* i is the next input character to be looked at
+j is the next output character */
+parlev = 0;
+expcom = 0;	/* exposed ','s */
+expeql = 0;	/* exposed equal signs */
+j = s;
+prvstr = s;
+for(i=s ; i<=lastch ; ++i)
+	{
+	if(*i == BLANK) continue;
+	if(*i=='\'' ||  *i=='"')
+		{
+		quote = *i;
+		*j = MYQUOTE; /* special marker */
+		for(;;)
+			{
+			if(++i > lastch)
+				{
+				err("unbalanced quotes; closing quote supplied");
+				break;
+				}
+			if(*i == quote)
+				if(i<lastch && i[1]==quote) ++i;
+				else break;
+			else if(*i=='\\' && i<lastch)
+				switch(*++i)
+					{
+					case 't':
+						*i = '\t'; break;
+					case 'b':
+						*i = '\b'; break;
+					case 'n':
+						*i = '\n'; break;
+					case 'f':
+						*i = '\f'; break;
+					case '0':
+						*i = '\0'; break;
+					default:
+						break;
+					}
+			*++j = *i;
+			}
+		j[1] = MYQUOTE;
+		j += 2;
+		prvstr = j;
+		}
+	else if( (*i=='h' || *i=='H')  && j>prvstr)	/* test for Hollerith strings */
+		{
+		if( ! isdigit((int)j[-1])) goto copychar;
+		nh = j[-1] - '0';
+		ten = 10;
+		j1 = prvstr - 1;
+		if (j1<j-5) j1=j-5;
+		for(j0=j-2 ; j0>j1; -- j0)
+			{
+			if( ! isdigit((int)*j0 ) ) break;
+			nh += ten * (*j0-'0');
+			ten*=10;
+			}
+		if(j0 <= j1) goto copychar;
+/* a hollerith must be preceded by a punctuation mark.
+   '*' is possible only as repetition factor in a data statement
+   not, in particular, in character*2h
+*/
+
+		if( !(*j0=='*'&&s[0]=='d') && *j0!='/' && *j0!='(' &&
+			*j0!=',' && *j0!='=' && *j0!='.')
+				goto copychar;
+		if(i+nh > lastch)
+			{
+			err1("%dH too big", nh);
+			nh = lastch - i;
+			}
+		j0[1] = MYQUOTE; /* special marker */
+		j = j0 + 1;
+		while(nh-- > 0)
+			{
+			if(*++i == '\\')
+				switch(*++i)
+					{
+					case 't':
+						*i = '\t'; break;
+					case 'b':
+						*i = '\b'; break;
+					case 'n':
+						*i = '\n'; break;
+					case 'f':
+						*i = '\f'; break;
+					case '0':
+						*i = '\0'; break;
+					default:
+						break;
+					}
+			*++j = *i;
+			}
+		j[1] = MYQUOTE;
+		j+=2;
+		prvstr = j;
+		}
+	else	{
+		if(*i == '(') ++parlev;
+		else if(*i == ')') --parlev;
+		else if(parlev == 0) {
+			if(*i == '=') expeql = 1;
+			else if(*i == ',') expcom = 1;
+copychar:	;	/*not a string of BLANK -- copy, shifting case if necessary */
+		}
+		if(shiftcase && isupper((int)*i))
+			*j++ = tolower((int)*i);
+		else	*j++ = *i;
+		}
+	}
+lastch = j - 1;
+nextch = s;
+}
+
+LOCAL void
+analyz()
+{
+register char *i;
+
+	if(parlev != 0)
+		{
+		err("unbalanced parentheses, statement skipped");
+		stkey = SUNKNOWN;
+		return;
+		}
+	if(nextch+2<=lastch && nextch[0]=='i' && nextch[1]=='f' && nextch[2]=='(')
+		{
+/* assignment or if statement -- look at character after balancing paren */
+		parlev = 1;
+		for(i=nextch+3 ; i<=lastch; ++i)
+			if(*i == (MYQUOTE))
+				{
+				while(*++i != MYQUOTE)
+					;
+				}
+			else if(*i == '(')
+				++parlev;
+			else if(*i == ')')
+				{
+				if(--parlev == 0)
+					break;
+				}
+		if(i >= lastch)
+			stkey = SLOGIF;
+		else if(i[1] == '=')
+			stkey = SLET;
+		else if( isdigit((int)i[1]) )
+			stkey = SARITHIF;
+		else	stkey = SLOGIF;
+		if(stkey != SLET)
+			nextch += 2;
+		}
+	else if(expeql) /* may be an assignment */
+		{
+		if(expcom && nextch<lastch &&
+			nextch[0]=='d' && nextch[1]=='o')
+				{
+				stkey = SDO;
+				nextch += 2;
+				}
+		else	stkey = SLET;
+		}
+/* otherwise search for keyword */
+	else	{
+		stkey = getkwd();
+		if(stkey==SGOTO && lastch>=nextch) {
+			if(nextch[0]=='(')
+				stkey = SCOMPGOTO;
+			else if(isalpha((int)nextch[0]))
+				stkey = SASGOTO;
+		}
+	}
+	parlev = 0;
+}
+
+
+
+LOCAL int
+getkwd()
+{
+register char *i, *j;
+register struct keylist *pk, *pend;
+int k;
+
+if(! isalpha((int)nextch[0]) )
+	return(SUNKNOWN);
+k = nextch[0] - 'a';
+if((pk = keystart[k]))
+	for(pend = keyend[k] ; pk<=pend ; ++pk )
+		{
+		i = pk->keyname;
+		j = nextch;
+		while(*++i==*++j && *i!='\0')
+			;
+		if(*i == '\0')
+			{
+			nextch = j;
+			return(pk->keyval);
+			}
+		}
+return(SUNKNOWN);
+}
+
+
+void
+initkey()
+{
+register struct keylist *p;
+register int i,j;
+
+for(i = 0 ; i<26 ; ++i)
+	keystart[i] = NULL;
+
+for(p = keys ; p->keyname ; ++p)
+	{
+	j = p->keyname[0] - 'a';
+	if(keystart[j] == NULL)
+		keystart[j] = p;
+	keyend[j] = p;
+	}
+}
+
+
+LOCAL int
+gettok()
+{
+int havdot, havexp, havdbl;
+int radix;
+extern struct punctlist puncts[];
+struct punctlist *pp;
+#if 0
+extern struct fmtlist fmts[];
+#endif
+struct dotlist *pd;
+
+char *i, *j, *n1, *p;
+
+	if(*nextch == (MYQUOTE))
+		{
+		++nextch;
+		p = token;
+		while(*nextch != MYQUOTE)
+			*p++ = *nextch++;
+		++nextch;
+		toklen = p - token;
+		*p = '\0';
+		return (SHOLLERITH);
+		}
+/*
+	if(stkey == SFORMAT)
+		{
+		for(pf = fmts; pf->fmtchar; ++pf)
+			{
+			if(*nextch == pf->fmtchar)
+				{
+				++nextch;
+				if(pf->fmtval == SLPAR)
+					++parlev;
+				else if(pf->fmtval == SRPAR)
+					--parlev;
+				return(pf->fmtval);
+				}
+			}
+		if( isdigit(*nextch) )
+			{
+			p = token;
+			*p++ = *nextch++;
+			while(nextch<=lastch && isdigit(*nextch) )
+				*p++ = *nextch++;
+			toklen = p - token;
+			*p = '\0';
+			if(nextch<=lastch && *nextch=='p')
+				{
+				++nextch;
+				return(SSCALE);
+				}
+			else	return(SICON);
+			}
+		if( isalpha(*nextch) )
+			{
+			p = token;
+			*p++ = *nextch++;
+			while(nextch<=lastch &&
+				(*nextch=='.' || isdigit(*nextch) || isalpha(*nextch) ))
+					*p++ = *nextch++;
+			toklen = p - token;
+			*p = '\0';
+			return(SFIELD);
+			}
+		goto badchar;
+		}
+ XXX ??? */
+/* Not a format statement */
+
+if(needkwd)
+	{
+	needkwd = 0;
+	return( getkwd() );
+	}
+
+	for(pp=puncts; pp->punchar; ++pp)
+		if(*nextch == pp->punchar)
+			{
+			if( (*nextch=='*' || *nextch=='/') &&
+				nextch<lastch && nextch[1]==nextch[0])
+					{
+					if(*nextch == '*')
+						yylval.num = SPOWER;
+					else	yylval.num = SCONCAT;
+					nextch+=2;
+					}
+			else	{yylval.num=pp->punval;
+					if(yylval.num==SLPAR)
+						++parlev;
+					else if(yylval.num==SRPAR)
+						--parlev;
+					++nextch;
+				}
+			return(yylval.num);
+			}
+	if(*nextch == '.') {
+		if(nextch >= lastch) goto badchar;
+		else if(isdigit((int)nextch[1])) goto numconst;
+		else	{
+			for(pd=dots ; (j=pd->dotname) ; ++pd)
+				{
+				for(i=nextch+1 ; i<=lastch ; ++i)
+					if(*i != *j) break;
+					else if(*i != '.') ++j;
+					else	{
+						nextch = i+1;
+						return(pd->dotval);
+						}
+				}
+			goto badchar;
+			}
+	}
+	if( isalpha((int)*nextch) )
+		{
+		p = token;
+		*p++ = *nextch++;
+		while(nextch<=lastch)
+			if( isalpha((int)*nextch) || isdigit((int)*nextch) )
+				*p++ = *nextch++;
+			else break;
+		toklen = p - token;
+		*p = '\0';
+		if(inioctl && nextch<=lastch && *nextch=='=')
+			{
+			++nextch;
+			return(SNAMEEQ);
+			}
+		if(toklen>=8 && eqn(8, token, "function") &&
+			nextch<lastch && *nextch=='(')
+				{
+				nextch -= (toklen - 8);
+				return(SFUNCTION);
+				}
+		if(toklen > VL)
+			{
+			err2("name %s too long, truncated to %d", token, VL);
+			toklen = VL;
+			token[6] = '\0';
+			}
+		if(toklen==1 && *nextch==MYQUOTE)
+			{
+			switch(token[0])
+				{
+				case 'z':  case 'Z':
+				case 'x':  case 'X':
+					radix = 16; break;
+				case 'o':  case 'O':
+					radix = 8; break;
+				case 'b':  case 'B':
+					radix = 2; break;
+				default:
+					err("bad bit identifier");
+					return(SFNAME);
+				}
+			++nextch;
+			for(p = token ; *nextch!=MYQUOTE ; )
+				if( hextoi(*p++ = *nextch++) >= radix)
+					{
+					err("invalid binary character");
+					break;
+					}
+			++nextch;
+			toklen = p - token;
+			return( radix==16 ? SHEXCON : (radix==8 ? SOCTCON : SBITCON) );
+			}
+		return(SFNAME);
+		}
+	if( ! isdigit((int)*nextch) ) goto badchar;
+numconst:
+	havdot = NO;
+	havexp = NO;
+	havdbl = NO;
+	for(n1 = nextch ; nextch<=lastch ; ++nextch)
+		{
+		if(*nextch == '.')
+			if(havdot) break;
+			else if(nextch+2<=lastch && isalpha((int)nextch[1])
+				&& isalpha((int)nextch[2]))
+					break;
+			else	havdot = YES;
+		else if(*nextch=='d' || *nextch=='e')
+			{
+			p = nextch;
+			havexp = YES;
+			if(*nextch == 'd')
+				havdbl = YES;
+			if(nextch<lastch)
+				if(nextch[1]=='+' || nextch[1]=='-')
+					++nextch;
+			if( ! isdigit((int)*++nextch) )
+				{
+				nextch = p;
+				havdbl = havexp = NO;
+				break;
+				}
+			for(++nextch ;
+				nextch<=lastch && isdigit((int)*nextch);
+				++nextch);
+			break;
+			}
+		else if( ! isdigit((int)*nextch) )
+			break;
+		}
+	p = token;
+	i = n1;
+	while(i < nextch)
+		*p++ = *i++;
+	toklen = p - token;
+	*p = '\0';
+	if(havdbl) return(SDCON);
+	if(havdot || havexp) return(SRCON);
+	return(SICON);
+badchar:
+	s[0] = *nextch++;
+	return(SUNKNOWN);
+}
+
+
+/* KEYWORD AND SPECIAL CHARACTER TABLES
+*/
+
+struct punctlist puncts[ ] =
+	{
+{	'(', SLPAR, },
+{	')', SRPAR, },
+{	'=', SEQUALS, },
+{	',', SCOMMA, },
+{	'+', SPLUS, },
+{	'-', SMINUS, },
+{	'*', SSTAR, },
+{	'/', SSLASH, },
+{	'$', SCURRENCY, },
+{	':', SCOLON, },
+{	0, 0 }, } ;
+
+/*
+LOCAL struct fmtlist  fmts[ ] =
+	{
+	'(', SLPAR,
+	')', SRPAR,
+	'/', SSLASH,
+	',', SCOMMA,
+	'-', SMINUS,
+	':', SCOLON,
+	0, 0 } ;
+*/
+
+LOCAL struct dotlist  dots[ ] =
+	{
+{	"and.", SAND, },
+{	"or.", SOR, },
+{	"not.", SNOT, },
+{	"true.", STRUE, },
+{	"false.", SFALSE, },
+{	"eq.", SEQ, },
+{	"ne.", SNE, },
+{	"lt.", SLT, },
+{	"le.", SLE, },
+{	"gt.", SGT, },
+{	"ge.", SGE, },
+{	"neqv.", SNEQV, },
+{	"eqv.", SEQV, },
+{	0, 0 }, } ;
+
+LOCAL struct keylist  keys[ ] =
+	{
+{	"assign",  SASSIGN, },
+{	"automatic",  SAUTOMATIC, },
+{	"backspace",  SBACKSPACE, },
+{	"blockdata",  SBLOCK, },
+{	"call",  SCALL, },
+{	"character",  SCHARACTER, },
+{	"close",  SCLOSE, },
+{	"common",  SCOMMON, },
+{	"complex",  SCOMPLEX, },
+{	"continue",  SCONTINUE, },
+{	"data",  SDATA, },
+{	"dimension",  SDIMENSION, },
+{	"doubleprecision",  SDOUBLE, },
+{	"doublecomplex", SDCOMPLEX, },
+{	"elseif",  SELSEIF, },
+{	"else",  SELSE, },
+{	"endfile",  SENDFILE, },
+{	"endif",  SENDIF, },
+{	"end",  SEND, },
+{	"entry",  SENTRY, },
+{	"equivalence",  SEQUIV, },
+{	"external",  SEXTERNAL, },
+{	"format",  SFORMAT, },
+{	"function",  SFUNCTION, },
+{	"goto",  SGOTO, },
+{	"implicit",  SIMPLICIT, },
+{	"include",  SINCLUDE, },
+{	"inquire",  SINQUIRE, },
+{	"intrinsic",  SINTRINSIC, },
+{	"integer",  SINTEGER, },
+{	"logical",  SLOGICAL, },
+{	"open",  SOPEN, },
+{	"parameter",  SPARAM, },
+{	"pause",  SPAUSE, },
+{	"print",  SPRINT, },
+{	"program",  SPROGRAM, },
+{	"punch",  SPUNCH, },
+{	"read",  SREAD, },
+{	"real",  SREAL, },
+{	"return",  SRETURN, },
+{	"rewind",  SREWIND, },
+{	"save",  SSAVE, },
+{	"static",  SSTATIC, },
+{	"stop",  SSTOP, },
+{	"subroutine",  SSUBROUTINE, },
+{	"then",  STHEN, },
+{	"undefined", SUNDEFINED, },
+{	"write",  SWRITE, },
+{	0, 0 }, };
Index: uspace/app/pcc/f77/fcom/main.c
===================================================================
--- uspace/app/pcc/f77/fcom/main.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/main.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,427 @@
+/*	$Id: main.c,v 1.14 2009/02/09 15:59:48 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.
+ */
+char xxxvers[] = "\nFORTRAN 77 PASS 1, VERSION 1.16,  3 NOVEMBER 1978\n";
+
+#include <unistd.h>
+
+#include "defines.h"
+#include "defs.h"
+
+void mkdope(void);
+
+int f2debug, e2debug, odebug, rdebug, b2debug, c2debug, t2debug;
+int s2debug, udebug, x2debug, nflag, kflag, g2debug;
+int xdeljumps, xtemps, xssaflag, xdce;
+
+int mflag, tflag;
+
+#if 1 /* RAGGE */
+FILE *initfile, *sortfile;
+int dodata(char *file);
+LOCAL int nch   = 0;
+#endif
+
+static void
+usage(void)
+{
+	fprintf(stderr, "usage: fcom [qw:UuOdpC1I:Z:]\n");
+	exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+	int ch;
+	int k, retcode;
+
+	infile = stdin;
+	diagfile = stderr;
+#if 1 /* RAGGE */
+	char file[] = "/tmp/initfile.XXXXXX";
+	char buf[100];
+	close(mkstemp(file));
+	sprintf(buf, "sort > %s", file);
+	initfile = popen(buf, "w");
+#endif
+
+
+#define DONE(c)	{ retcode = c; goto finis; }
+
+	while ((ch = getopt(argc, argv, "qw:UuOdpC1I:Z:X:")) != -1)
+		switch (ch) {
+		case 'q':
+			quietflag = YES;
+			break;
+
+		case 'w':
+			if(optarg[0]=='6' && optarg[1]=='6') {
+				ftn66flag = YES;
+			} else
+				nowarnflag = YES;
+			break;
+
+		case 'U':
+			shiftcase = NO;
+			break;
+
+		case 'u':
+			undeftype = YES;
+			break;
+
+		case 'O':
+			optimflag = YES;
+#ifdef notyet
+			xdeljumps = 1;
+			xtemps = 1;
+#endif
+			break;
+
+		case 'd':
+			debugflag = YES;
+			break;
+
+		case 'p':
+			profileflag = YES;
+			break;
+
+		case 'C':
+			checksubs = YES;
+			break;
+
+		case '1':
+			onetripflag = YES;
+			break;
+
+		case 'I':
+			if(*optarg == '2')
+				tyint = TYSHORT;
+			else if(*optarg == '4') {
+				shortsubs = NO;
+				tyint = TYLONG;
+			} else if(*optarg == 's')
+				shortsubs = YES;
+			else
+				fatal1("invalid flag -I%c\n", *optarg);
+			tylogical = tyint;
+			break;
+
+		case 'Z':
+			while (*optarg)
+				switch (*optarg++) {
+				case 'f': /* instruction matching */
+					++f2debug;
+					break;
+				case 'e': /* print tree upon pass2 enter */
+					++e2debug;
+					break;
+				case 'o': ++odebug; break;
+				case 'r': /* register alloc/graph coloring */
+					++rdebug;
+					break;
+				case 'b': /* basic block and SSA building */
+					++b2debug;
+					break;
+				case 'c': /* code printout */
+					++c2debug;
+					break;
+				case 't': ++t2debug; break;
+				case 's': /* shape matching */
+					++s2debug;
+					break;
+				case 'u': /* Sethi-Ullman debugging */
+					++udebug;
+					break;
+				case 'x': ++x2debug; break;
+				case 'g': ++g2debug; break;
+				case 'n': ++nflag; break;
+				default:
+					fprintf(stderr, "unknown Z flag '%c'\n",
+					    optarg[-1]);
+					exit(1);
+				}
+			break;
+
+		case 'X':
+			while (*optarg)
+				switch (*optarg++) {
+				case 't': /* tree debugging */
+					tflag++;
+					break;
+				case 'm': /* memory allocation */
+					++mflag;
+					break;
+				default:
+					usage();
+				}
+			break;
+
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	mkdope();
+	initkey();
+	if (argc > 0) {
+		if (inilex(copys(argv[0])))
+			DONE(1);
+		if (!quietflag)
+			fprintf(diagfile, "%s:\n", argv[0]);
+		if (argc != 1)
+			if (freopen(argv[1], "w", stdout) == NULL) {
+				fprintf(stderr, "open output file '%s':",
+				    argv[1]);
+				perror(NULL);
+				exit(1);
+			}
+	} else {
+		inilex(copys(""));
+	}
+	fileinit();
+	procinit();
+	if((k = yyparse())) {
+		fprintf(diagfile, "Bad parse, return code %d\n", k);
+		DONE(1);
+	}
+	if(nerr > 0)
+		DONE(1);
+	if(parstate != OUTSIDE) {
+		warn("missing END statement");
+		endproc();
+	}
+	doext();
+	preven(ALIDOUBLE);
+	prtail();
+	puteof();
+	DONE(0);
+
+
+finis:
+	pclose(initfile);
+	retcode |= dodata(file);
+	unlink(file);
+	done(retcode);
+	return(retcode);
+}
+
+#define USEINIT ".data\t2"
+#define LABELFMT "%s:\n"
+
+static void
+prcha(FILEP fp, int *s)
+{
+
+fprintf(fp, ".byte 0%o,0%o\n", s[0], s[1]);
+}
+
+static void
+prskip(FILEP fp, ftnint k)
+{
+fprintf(fp, "\t.space\t%ld\n", k);
+}
+
+
+static void
+prch(int c)
+{
+static int buff[SZSHORT];
+
+buff[nch++] = c;
+if(nch == SZSHORT)
+        {
+        prcha(stdout, buff);
+        nch = 0;
+        }
+}
+
+
+static int
+rdname(int *vargroupp, char *name)
+{
+register int i, c;
+
+if( (c = getc(sortfile)) == EOF)
+        return(NO);
+*vargroupp = c - '0';
+
+for(i = 0 ; i<XL ; ++i)
+        {
+        if( (c = getc(sortfile)) == EOF)
+                return(NO);
+        if(c != ' ')
+                *name++ = c;
+        }
+*name = '\0';
+return(YES);
+}
+
+static int
+rdlong(ftnint *n)
+{
+register int c;
+
+for(c = getc(sortfile) ; c!=EOF && isspace(c) ; c = getc(sortfile) );
+        ;
+if(c == EOF)
+        return(NO);
+
+for(*n = 0 ; isdigit(c) ; c = getc(sortfile) )
+        *n = 10* (*n) + c - '0';
+return(YES);
+}
+
+static void
+prspace(ftnint n)
+{
+register ftnint m;
+
+while(nch>0 && n>0)
+        {
+        --n;
+        prch(0);
+        }
+m = SZSHORT * (n/SZSHORT);
+if(m > 0)
+        prskip(stdout, m);
+for(n -= m ; n>0 ; --n)
+        prch(0);
+}
+
+static ftnint
+doeven(ftnint tot, int align)
+{
+ftnint new;
+new = roundup(tot, align);
+prspace(new - tot);
+return(new);
+}
+
+
+int
+dodata(char *file)
+{
+	char varname[XL+1], ovarname[XL+1];
+	flag erred;
+	ftnint offset, vlen, type;
+	register ftnint ooffset, ovlen;
+	ftnint vchar;
+	int size, align;
+	int vargroup;
+	ftnint totlen;
+
+	erred = NO;
+	ovarname[0] = '\0';
+	ooffset = 0;
+	ovlen = 0;
+	totlen = 0;
+	nch = 0;
+
+	if( (sortfile = fopen(file, "r")) == NULL)
+		fatal1(file);
+#if 0
+	pruse(asmfile, USEINIT);
+#else
+	printf("\t%s\n", USEINIT);
+#endif
+	while (rdname(&vargroup, varname) && rdlong(&offset) &&
+	    rdlong(&vlen) && rdlong(&type) ) {
+		size = typesize[type];
+		if( strcmp(varname, ovarname) ) {
+			prspace(ovlen-ooffset);
+			strcpy(ovarname, varname);
+			ooffset = 0;
+			totlen += ovlen;
+			ovlen = vlen;
+			if(vargroup == 0)
+				align = (type==TYCHAR ? SZLONG :
+				    typealign[type]);
+			else
+				align = ALIDOUBLE;
+			totlen = doeven(totlen, align);
+			if(vargroup == 2) {
+#if 0
+				prcomblock(asmfile, varname);
+#else
+				printf(LABELFMT, varname);
+#endif
+			} else {
+#if 0
+				fprintf(asmfile, LABELFMT, varname);
+#else
+				printf(LABELFMT, varname);
+#endif
+			}
+		}
+		if(offset < ooffset) {
+			erred = YES;
+			err("overlapping initializations");
+		}
+		if(offset > ooffset) {
+			prspace(offset-ooffset);
+			ooffset = offset;
+		}
+		if(type == TYCHAR) {
+			if( ! rdlong(&vchar) )
+				fatal("bad intermediate file format");
+			prch( (int) vchar );
+		} else {
+			putc('\t', stdout);
+			while	( putc( getc(sortfile), stdout)  != '\n')
+				;
+		}
+		if( (ooffset += size) > ovlen) {
+			erred = YES;
+			err("initialization out of bounds");
+		}
+	}
+
+	prspace(ovlen-ooffset);
+	totlen = doeven(totlen+ovlen, (ALIDOUBLE>SZLONG ? ALIDOUBLE : SZLONG) );
+	return(erred);
+}
+
+void
+done(k)
+int k;
+{
+static int recurs	= NO;
+
+if(recurs == NO)
+	{
+	recurs = YES;
+	}
+exit(k);
+}
Index: uspace/app/pcc/f77/fcom/misc.c
===================================================================
--- uspace/app/pcc/f77/fcom/misc.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/misc.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,704 @@
+/*	$Id: misc.c,v 1.17 2009/02/11 15:58:55 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 conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "defines.h"
+#include "defs.h"
+
+int max(int, int);
+
+void
+cpn(n, a, b)
+register int n;
+register char *a, *b;
+{
+while(--n >= 0)
+	*b++ = *a++;
+}
+
+
+int
+eqn(n, a, b)
+register int n;
+register char *a, *b;
+{
+while(--n >= 0)
+	if(*a++ != *b++)
+		return(NO);
+return(YES);
+}
+
+
+
+
+
+
+int
+cmpstr(a, b, la, lb)	/* compare two strings */
+register char *a, *b;
+ftnint la, lb;
+{
+register char *aend, *bend;
+aend = a + la;
+bend = b + lb;
+
+
+if(la <= lb)
+	{
+	while(a < aend)
+		if(*a != *b)
+			return( *a - *b );
+		else
+			{ ++a; ++b; }
+
+	while(b < bend)
+		if(*b != ' ')
+			return(' ' - *b);
+		else
+			++b;
+	}
+
+else
+	{
+	while(b < bend)
+		if(*a != *b)
+			return( *a - *b );
+		else
+			{ ++a; ++b; }
+	while(a < aend)
+		if(*a != ' ')
+			return(*a - ' ');
+		else
+			++a;
+	}
+return(0);
+}
+
+
+
+
+
+chainp hookup(x,y)
+register chainp x, y;
+{
+register chainp p;
+
+if(x == NULL)
+	return(y);
+
+for(p = x ; p->chain.nextp ; p = p->chain.nextp)
+	;
+p->chain.nextp = y;
+return(x);
+}
+
+
+
+struct bigblock *mklist(p)
+chainp p;
+{
+register struct bigblock *q;
+
+q = BALLO();
+q->tag = TLIST;
+q->b_list.listp = p;
+return(q);
+}
+
+
+chainp
+mkchain(bigptr p, chainp q)
+{
+	chainp r;
+
+	if(chains) {
+		r = chains;
+		chains = chains->chain.nextp;
+	} else
+		r = ALLOC(chain);
+
+	r->chain.datap = p;
+	r->chain.nextp = q;
+	return(r);
+}
+
+
+
+char * varstr(n, s)
+register int n;
+register char *s;
+{
+register int i;
+static char name[XL+1];
+
+for(i=0;  i<n && *s!=' ' && *s!='\0' ; ++i)
+	name[i] = *s++;
+
+name[i] = '\0';
+
+return( name );
+}
+
+
+
+
+char * varunder(n, s)
+register int n;
+register char *s;
+{
+register int i;
+static char name[XL+1];
+
+for(i=0;  i<n && *s!=' ' && *s!='\0' ; ++i)
+	name[i] = *s++;
+
+name[i] = '\0';
+
+return( name );
+}
+
+
+
+
+
+char * nounder(n, s)
+register int n;
+register char *s;
+{
+register int i;
+static char name[XL+1];
+
+for(i=0;  i<n && *s!=' ' && *s!='\0' ; ++s)
+	if(*s != '_')
+		name[i++] = *s;
+
+name[i] = '\0';
+
+return( name );
+}
+
+/*
+ * Save a block on heap.
+ */
+char *
+copyn(int n, char *s)
+{
+	char *p, *q;
+
+	p = q = ckalloc(n);
+	while(--n >= 0)
+		*q++ = *s++;
+	return(p);
+}
+
+/*
+ * Save a string on heap.
+ */
+char *
+copys(char *s)
+{
+	return(copyn(strlen(s)+1 , s));
+}
+
+/*
+ * convert a string to an int.
+ */
+ftnint
+convci(int n, char *s)
+{
+	ftnint sum;
+	sum = 0;
+	while(n-- > 0)
+		sum = 10*sum + (*s++ - '0');
+	return(sum);
+}
+
+char *convic(n)
+ftnint n;
+{
+static char s[20];
+register char *t;
+
+s[19] = '\0';
+t = s+19;
+
+do	{
+	*--t = '0' + n%10;
+	n /= 10;
+	} while(n > 0);
+
+return(t);
+}
+
+
+
+double convcd(n, s)
+int n;
+register char *s;
+{
+char v[100];
+register char *t;
+if(n > 90)
+	{
+	err("too many digits in floating constant");
+	n = 90;
+	}
+for(t = v ; n-- > 0 ; s++)
+	*t++ = (*s=='d' ? 'e' : *s);
+*t = '\0';
+return( atof(v) );
+}
+
+
+
+struct bigblock *mkname(l, s)
+int l;
+register char *s;
+{
+struct hashentry *hp;
+int hash;
+register struct bigblock *q;
+register int i;
+char n[VL];
+
+hash = 0;
+for(i = 0 ; i<l && *s!='\0' ; ++i)
+	{
+	hash += *s;
+	n[i] = *s++;
+	}
+hash %= MAXHASH;
+while( i < VL )
+	n[i++] = ' ';
+
+hp = hashtab + hash;
+while((q = hp->varp))
+	if( hash==hp->hashval && eqn(VL,n,q->b_name.varname) )
+		return(q);
+	else if(++hp >= lasthash)
+		hp = hashtab;
+
+if(++nintnames >= MAXHASH-1)
+	fatal("hash table full");
+hp->varp = q = BALLO();
+hp->hashval = hash;
+q->tag = TNAME;
+cpn(VL, n, q->b_name.varname);
+return(q);
+}
+
+
+
+struct labelblock *mklabel(l)
+ftnint l;
+{
+register struct labelblock *lp;
+
+if(l == 0)
+	return(0);
+
+for(lp = labeltab ; lp < highlabtab ; ++lp)
+	if(lp->stateno == l)
+		return(lp);
+
+if(++highlabtab >= labtabend)
+	fatal("too many statement numbers");
+
+lp->stateno = l;
+lp->labelno = newlabel();
+lp->blklevel = 0;
+lp->labused = NO;
+lp->labdefined = NO;
+lp->labinacc = NO;
+lp->labtype = LABUNKNOWN;
+return(lp);
+}
+
+int
+newlabel()
+{
+return( lastlabno++ );
+}
+
+
+/* find or put a name in the external symbol table */
+
+struct extsym *mkext(s)
+char *s;
+{
+int i;
+register char *t;
+char n[XL];
+struct extsym *p;
+
+i = 0;
+t = n;
+while(i<XL && *s)
+	*t++ = *s++;
+while(t < n+XL)
+	*t++ = ' ';
+
+for(p = extsymtab ; p<nextext ; ++p)
+	if(eqn(XL, n, p->extname))
+		return( p );
+
+if(nextext >= lastext)
+	fatal("too many external symbols");
+
+cpn(XL, n, nextext->extname);
+nextext->extstg = STGUNKNOWN;
+nextext->extsave = NO;
+nextext->extp = 0;
+nextext->extleng = 0;
+nextext->maxleng = 0;
+nextext->extinit = NO;
+return( nextext++ );
+}
+
+
+
+
+
+
+
+
+struct bigblock *builtin(t, s)
+int t;
+char *s;
+{
+register struct extsym *p;
+register struct bigblock *q;
+
+p = mkext(s);
+if(p->extstg == STGUNKNOWN)
+	p->extstg = STGEXT;
+else if(p->extstg != STGEXT)
+	{
+	err1("improper use of builtin %s", s);
+	return(0);
+	}
+
+q = BALLO();
+q->tag = TADDR;
+q->vtype = t;
+q->vclass = CLPROC;
+q->vstg = STGEXT;
+q->b_addr.memno = p - extsymtab;
+return(q);
+}
+
+
+void
+frchain(p)
+register chainp *p;
+{
+register chainp q;
+
+if(p==0 || *p==0)
+	return;
+
+for(q = *p; q->chain.nextp ; q = q->chain.nextp)
+	;
+q->chain.nextp = chains;
+chains = *p;
+*p = 0;
+}
+
+
+ptr cpblock(n,p)
+register int n;
+register void * p;
+{
+register char *q, *r = p;
+ptr q0;
+
+q = q0 = ckalloc(n);
+while(n-- > 0)
+	*q++ = *r++;
+return(q0);
+}
+
+
+int
+max(a,b)
+int a,b;
+{
+return( a>b ? a : b);
+}
+
+
+ftnint lmax(a, b)
+ftnint a, b;
+{
+return( a>b ? a : b);
+}
+
+ftnint lmin(a, b)
+ftnint a, b;
+{
+return(a < b ? a : b);
+}
+
+
+
+int
+maxtype(t1, t2)
+int t1, t2;
+{
+int t;
+
+t = max(t1, t2);
+if(t==TYCOMPLEX && (t1==TYDREAL || t2==TYDREAL) )
+	t = TYDCOMPLEX;
+return(t);
+}
+
+
+
+/* return log base 2 of n if n a power of 2; otherwise -1 */
+int
+flog2(n)
+ftnint n;
+{
+int k;
+
+/* trick based on binary representation */
+
+if(n<=0 || (n & (n-1))!=0)
+	return(-1);
+
+for(k = 0 ;  n >>= 1  ; ++k)
+	;
+return(k);
+}
+
+
+void
+frrpl()
+{
+chainp rp;
+
+while(rpllist)
+	{
+	rp = rpllist->rplblock.nextp;
+	ckfree(rpllist);
+	rpllist = rp;
+	}
+}
+
+void
+popstack(p)
+register chainp *p;
+{
+register chainp q;
+
+if(p==NULL || *p==NULL)
+	fatal("popstack: stack empty");
+q = (*p)->chain.nextp;
+ckfree(*p);
+*p = q;
+}
+
+
+
+struct bigblock *
+callk(type, name, args)
+int type;
+char *name;
+bigptr args;
+{
+register struct bigblock *p;
+
+p = mkexpr(OPCALL, builtin(type,name), args);
+p->vtype = type;
+return(p);
+}
+
+
+
+struct bigblock *
+call4(type, name, arg1, arg2, arg3, arg4)
+int type;
+char *name;
+bigptr arg1, arg2, arg3, arg4;
+{
+struct bigblock *args;
+args = mklist( mkchain(arg1, mkchain(arg2, mkchain(arg3, mkchain(arg4, NULL)) ) ) );
+return( callk(type, name, args) );
+}
+
+
+
+
+struct bigblock *call3(type, name, arg1, arg2, arg3)
+int type;
+char *name;
+bigptr arg1, arg2, arg3;
+{
+struct bigblock *args;
+args = mklist( mkchain(arg1, mkchain(arg2, mkchain(arg3, NULL) ) ) );
+return( callk(type, name, args) );
+}
+
+
+
+
+
+struct bigblock *
+call2(type, name, arg1, arg2)
+int type;
+char *name;
+bigptr arg1, arg2;
+{
+bigptr args;
+
+args = mklist( mkchain(arg1, mkchain(arg2, NULL) ) );
+return( callk(type,name, args) );
+}
+
+
+
+
+struct bigblock *call1(type, name, arg)
+int type;
+char *name;
+bigptr arg;
+{
+return( callk(type,name, mklist(mkchain(arg,0)) ));
+}
+
+
+struct bigblock *call0(type, name)
+int type;
+char *name;
+{
+return( callk(type, name, NULL) );
+}
+
+
+
+struct bigblock *
+mkiodo(dospec, list)
+chainp dospec, list;
+{
+register struct bigblock *q;
+
+q = BALLO();
+q->tag = TIMPLDO;
+q->b_impldo.varnp = (struct bigblock *)dospec;
+q->b_impldo.datalist = list;
+return(q);
+}
+
+
+
+
+ptr 
+ckalloc(int n)
+{
+	ptr p;
+
+	if ((p = calloc(1, (unsigned) n)) == NULL)
+		fatal("out of memory");
+#ifdef PCC_DEBUG
+	if (mflag)
+		printf("ckalloc: sz %d ptr %p\n", n, p);
+#endif
+	return(p);
+}
+
+void
+ckfree(void *p)
+{
+#ifdef PCC_DEBUG
+	if (mflag)
+		printf("ckfree: ptr %p\n", p);
+#endif
+	free(p);
+}
+
+#if 0
+int
+isaddr(p)
+register bigptr p;
+{
+if(p->tag == TADDR)
+	return(YES);
+if(p->tag == TEXPR)
+	switch(p->b_expr.opcode)
+		{
+		case OPCOMMA:
+			return( isaddr(p->b_expr.rightp) );
+
+		case OPASSIGN:
+		case OPPLUSEQ:
+			return( isaddr(p->b_expr.leftp) );
+		}
+return(NO);
+}
+#endif
+
+/*
+ * Return YES if not an expression.
+ */
+int
+addressable(bigptr p)
+{
+	switch(p->tag) {
+	case TCONST:
+		return(YES);
+
+	case TADDR:
+		return( addressable(p->b_addr.memoffset) );
+
+	default:
+		return(NO);
+	}
+}
+
+
+int
+hextoi(c)
+register int c;
+{
+register char *p;
+static char p0[17] = "0123456789abcdef";
+
+for(p = p0 ; *p ; ++p)
+	if(*p == c)
+		return( p-p0 );
+return(16);
+}
Index: uspace/app/pcc/f77/fcom/proc.c
===================================================================
--- uspace/app/pcc/f77/fcom/proc.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/proc.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,913 @@
+/*	$Id: proc.c,v 1.14 2008/12/24 17:40:41 sgk 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 <string.h>
+
+#include "defines.h"
+#include "defs.h"
+
+LOCAL void doentry(struct entrypoint *ep);
+LOCAL void retval(int t);
+LOCAL void epicode(void);
+LOCAL void procode(void);
+LOCAL int nextarg(int);
+LOCAL int nextarg(int);
+LOCAL void dobss(void);
+LOCAL void docommon(void);
+LOCAL void docomleng(void);
+
+
+/* start a new procedure */
+
+void
+newproc()
+{
+	if(parstate != OUTSIDE) {
+		execerr("missing end statement");
+		endproc();
+	}
+
+	parstate = INSIDE;
+	procclass = CLMAIN;	/* default */
+}
+
+
+
+/* end of procedure. generate variables, epilogs, and prologs */
+
+void
+endproc()
+{
+	struct labelblock *lp;
+
+	if(parstate < INDATA)
+		enddcl();
+	if(ctlstack >= ctls)
+		err("DO loop or BLOCK IF not closed");
+	for(lp = labeltab ; lp < labtabend ; ++lp)
+		if(lp->stateno!=0 && lp->labdefined==NO)
+			err1("missing statement number %s",
+			    convic(lp->stateno) );
+
+	epicode();
+	procode();
+	dobss();
+	prdbginfo();
+
+	putbracket();
+
+	procinit();	/* clean up for next procedure */
+}
+
+
+
+/*
+ * End of declaration section of procedure.  Allocate storage.
+ */
+void
+enddcl()
+{
+	chainp p;
+
+	parstate = INEXEC;
+	docommon();
+	doequiv();
+	docomleng();
+	for(p = entries ; p ; p = p->entrypoint.nextp)
+		doentry(&p->entrypoint);
+}
+
+/* ROUTINES CALLED WHEN ENCOUNTERING ENTRY POINTS */
+
+/*
+ * Called when a PROGRAM or BLOCK DATA statement is found, or if a statement
+ * is encountered outside of any block.
+ */
+void
+startproc(struct extsym *progname, int class)
+{
+	chainp p;
+
+	p = ALLOC(entrypoint);
+	if(class == CLMAIN) {
+		puthead("MAIN__");
+		newentry( mkname(5, "MAIN_") );
+	}
+	p->entrypoint.entryname = progname;
+	p->entrypoint.entrylabel = newlabel();
+	entries = p;
+
+	procclass = class;
+	retlabel = newlabel();
+	if (!quietflag) {
+		fprintf(diagfile, "   %s",
+		    (class==CLMAIN ? "MAIN" : "BLOCK DATA") );
+		if (progname)
+			fprintf(diagfile, " %s",
+			    nounder(XL, procname = progname->extname));
+		fprintf(diagfile, ":\n");
+	}
+}
+
+/* subroutine or function statement */
+
+struct extsym *
+newentry(struct bigblock *v)
+{
+	struct extsym *p;
+
+	p = mkext( varunder(VL, v->b_name.varname) );
+
+	if (p==NULL || p->extinit ||
+	    !ONEOF(p->extstg, M(STGUNKNOWN)|M(STGEXT))) {
+		if(p == 0)
+			dclerr("invalid entry name", v);
+		else
+			dclerr("external name already used", v);
+		return(0);
+	}
+	v->vstg = STGAUTO;
+	v->b_name.vprocclass = PTHISPROC;
+	v->vclass = CLPROC;
+	p->extstg = STGEXT;
+	p->extinit = YES;
+	return(p);
+}
+
+/*
+ * Called if a SUBROUTINE, FUNCTION or ENTRY statement is found.
+ */
+void
+entrypt(int class, int type, ftnint length, struct extsym *entry, chainp args)
+{
+	struct bigblock *q;
+	chainp p;
+
+	if(class != CLENTRY)
+		puthead( varstr(XL, procname = entry->extname) );
+	if (!quietflag) {
+		if (class == CLENTRY)
+			fprintf(diagfile, "       entry ");
+		fprintf(diagfile, "   %s:\n", nounder(XL, entry->extname));
+	}
+	q = mkname(VL, nounder(XL,entry->extname) );
+
+	if( (type = lengtype(type, (int) length)) != TYCHAR)
+		length = 0;
+
+	if(class == CLPROC) {
+		procclass = CLPROC;
+		proctype = type;
+		procleng = length;
+
+		retlabel = newlabel();
+		if(type == TYSUBR)
+			ret0label = newlabel();
+	}
+
+	p = ALLOC(entrypoint);
+	entries = hookup(entries, p);
+	p->entrypoint.entryname = entry;
+	p->entrypoint.arglist = args;
+	p->entrypoint.entrylabel = newlabel();
+	p->entrypoint.enamep = q;
+
+	if(class == CLENTRY) {
+		class = CLPROC;
+		if(proctype == TYSUBR)
+			type = TYSUBR;
+	}
+
+	q->vclass = class;
+	q->b_name.vprocclass = PTHISPROC;
+	settype(q, type, (int) length);
+	/* hold all initial entry points till end of declarations */
+	if(parstate >= INDATA)
+		doentry(&p->entrypoint);
+}
+
+
+/* generate epilogs */
+
+int multitypes = 0; /* XXX */
+
+LOCAL void
+epicode()
+{
+	int i;
+
+	if(procclass==CLPROC) {
+		if(proctype==TYSUBR) {
+			putlabel(ret0label);
+			if(substars)
+				putforce(TYINT, MKICON(0) );
+			putlabel(retlabel);
+			goret(TYSUBR);
+		} else	{
+			putlabel(retlabel);
+			if(multitypes) {
+				typeaddr = autovar(1, TYADDR, NULL);
+				putbranch( cpexpr(typeaddr) );
+				for(i = 0; i < NTYPES ; ++i) {
+					if(rtvlabel[i] != 0) {
+						putlabel(rtvlabel[i]);
+						retval(i);
+					}
+				}
+			} else
+				retval(proctype);
+		}
+	} else if(procclass != CLBLOCK) {
+		putlabel(retlabel);
+		goret(TYSUBR);
+	}
+}
+
+
+/* generate code to return value of type  t */
+
+LOCAL void
+retval(t)
+register int t;
+{
+register struct bigblock *p;
+
+switch(t)
+	{
+	case TYCHAR:
+	case TYCOMPLEX:
+	case TYDCOMPLEX:
+		break;
+
+	case TYLOGICAL:
+		t = tylogical;
+	case TYADDR:
+	case TYSHORT:
+	case TYLONG:
+		p = cpexpr(retslot);
+		p->vtype = t;
+		putforce(t, p);
+		break;
+
+	case TYREAL:
+	case TYDREAL:
+		p = cpexpr(retslot);
+		p->vtype = t;
+		putforce(t, p);
+		break;
+
+	default:
+		fatal1("retval: impossible type %d", t);
+	}
+goret(t);
+}
+
+
+/* Allocate extra argument array if needed. Generate prologs. */
+
+LOCAL void
+procode()
+{
+register chainp p;
+struct bigblock *argvec;
+
+	if(lastargslot>0 && nentry>1)
+		argvec = autovar(lastargslot/FSZADDR, TYADDR, NULL);
+	else
+		argvec = NULL;
+
+	for(p = entries ; p ; p = p->entrypoint.nextp)
+		prolog(&p->entrypoint, argvec);
+
+	putrbrack(procno);
+
+	prendproc();
+}
+
+/*
+   manipulate argument lists (allocate argument slot positions)
+ * keep track of return types and labels
+ */
+LOCAL void
+doentry(struct entrypoint *ep)
+{
+	int type;
+	struct bigblock *np, *q;
+	chainp p;
+
+	++nentry;
+	if(procclass == CLMAIN) {
+		putlabel(ep->entrylabel);
+		return;
+	} else if(procclass == CLBLOCK)
+		return;
+
+	impldcl(np = mkname(VL, nounder(XL, ep->entryname->extname)));
+	type = np->vtype;
+	if(proctype == TYUNKNOWN)
+		if( (proctype = type) == TYCHAR)
+			procleng = (np->vleng ? np->vleng->b_const.fconst.ci : (ftnint) 0);
+
+	if(proctype == TYCHAR) {
+		if(type != TYCHAR)
+			err("noncharacter entry of character function");
+		else if( (np->vleng ? np->vleng->b_const.fconst.ci : (ftnint) 0) != procleng)
+			err("mismatched character entry lengths");
+	} else if(type == TYCHAR)
+		err("character entry of noncharacter function");
+	else if(type != proctype)
+		multitype = YES;
+	if(rtvlabel[type] == 0)
+		rtvlabel[type] = newlabel();
+	ep->typelabel = rtvlabel[type];
+
+	if(type == TYCHAR) {
+		if(chslot < 0) {
+			chslot = nextarg(TYADDR);
+			chlgslot = nextarg(TYLENG);
+		}
+		np->vstg = STGARG;
+		np->b_name.vardesc.varno = chslot;
+		if(procleng == 0)
+			np->vleng = mkarg(TYLENG, chlgslot);
+	} else if( ISCOMPLEX(type) ) {
+		np->vstg = STGARG;
+		if(cxslot < 0)
+			cxslot = nextarg(TYADDR);
+		np->b_name.vardesc.varno = cxslot;
+	} else if(type != TYSUBR) {
+		if(nentry == 1)
+			retslot = autovar(1, TYDREAL, NULL);
+		np->vstg = STGAUTO;
+		np->b_name.voffset = retslot->b_addr.memoffset->b_const.fconst.ci;
+	}
+
+	for(p = ep->arglist ; p ; p = p->chain.nextp)
+		if(! ((q = p->chain.datap)->b_name.vdcldone) )
+			q->b_name.vardesc.varno = nextarg(TYADDR);
+
+	for(p = ep->arglist ; p ; p = p->chain.nextp)
+		if(! ((q = p->chain.datap)->b_name.vdcldone) ) {
+			impldcl(q);
+			q->b_name.vdcldone = YES;
+			if(q->vtype == TYCHAR) {
+				if(q->vleng == NULL)	/* character*(*) */
+					q->vleng = mkarg(TYLENG, nextarg(TYLENG) );
+				else if(nentry == 1)
+					nextarg(TYLENG);
+			} else if(q->vclass==CLPROC && nentry==1)
+				nextarg(TYLENG) ;
+		}
+	putlabel(ep->entrylabel);
+}
+
+
+
+LOCAL int
+nextarg(type)
+int type;
+{
+int k;
+k = lastargslot;
+lastargslot += typesize[type];
+return(k);
+}
+
+
+/* generate variable references */
+
+LOCAL void
+dobss()
+{
+register struct hashentry *p;
+register struct bigblock *q;
+register int i;
+int align;
+ftnint leng, iarrl;
+
+	setloc(UDATA);
+
+for(p = hashtab ; p<lasthash ; ++p)
+    if((q = p->varp))
+	{
+	if( (q->vclass==CLUNKNOWN && q->vstg!=STGARG) ||
+	    (q->vclass==CLVAR && q->vstg==STGUNKNOWN) )
+		warn1("local variable %s never used", varstr(VL,q->b_name.varname) );
+	else if(q->vclass==CLVAR && q->vstg==STGBSS)
+		{
+		align = (q->vtype==TYCHAR ? ALILONG : typealign[q->vtype]);
+		if(bssleng % align != 0)
+			{
+			bssleng = roundup(bssleng, align);
+			preven(align);
+			}
+		prlocvar( memname(STGBSS, q->b_name.vardesc.varno), iarrl = iarrlen(q) );
+		bssleng += iarrl;
+		}
+	else if(q->vclass==CLPROC && q->b_name.vprocclass==PEXTERNAL && q->vstg!=STGARG)
+		mkext(varunder(VL, q->b_name.varname)) ->extstg = STGEXT;
+
+	if(q->vclass==CLVAR && q->vstg!=STGARG)
+		{
+		if(q->b_name.vdim && !ISICON(q->b_name.vdim->nelt) )
+			dclerr("adjustable dimension on non-argument", q);
+		if(q->vtype==TYCHAR && (q->vleng==NULL || !ISICON(q->vleng)))
+			dclerr("adjustable leng on nonargument", q);
+		}
+	}
+
+for(i = 0 ; i < nequiv ; ++i)
+	if(eqvclass[i].eqvinit==NO && (leng = eqvclass[i].eqvleng)!=0 )
+		{
+		bssleng = roundup(bssleng, ALIDOUBLE);
+		preven(ALIDOUBLE);
+		prlocvar( memname(STGEQUIV, i), leng);
+		bssleng += leng;
+		}
+}
+
+
+
+void
+doext()
+{
+struct extsym *p;
+
+for(p = extsymtab ; p<nextext ; ++p)
+	prext( varstr(XL, p->extname), p->maxleng, p->extinit);
+}
+
+
+
+
+ftnint iarrlen(q)
+register struct bigblock *q;
+{
+ftnint leng;
+
+leng = typesize[q->vtype];
+if(leng <= 0)
+	return(-1);
+if(q->b_name.vdim) {
+	if( ISICON(q->b_name.vdim->nelt) )
+		leng *= q->b_name.vdim->nelt->b_const.fconst.ci;
+	else	return(-1);
+}
+if(q->vleng) {
+	if( ISICON(q->vleng) )
+		leng *= q->vleng->b_const.fconst.ci;
+	else 	return(-1);
+}
+return(leng);
+}
+
+
+LOCAL void 
+docommon()
+{
+register struct extsym *p;
+register chainp q;
+struct dimblock *t;
+bigptr neltp;
+register struct bigblock *v;
+ftnint size;
+int type;
+
+for(p = extsymtab ; p<nextext ; ++p)
+	if(p->extstg==STGCOMMON)
+		{
+		for(q = p->extp ; q ; q = q->chain.nextp)
+			{
+			v = q->chain.datap;
+			if(v->b_name.vdcldone == NO)
+				vardcl(v);
+			type = v->vtype;
+			if(p->extleng % typealign[type] != 0)
+				{
+				dclerr("common alignment", v);
+				p->extleng = roundup(p->extleng, typealign[type]);
+				}
+			v->b_name.voffset = p->extleng;
+			v->b_name.vardesc.varno = p - extsymtab;
+			if(type == TYCHAR)
+				size = v->vleng->b_const.fconst.ci;
+			else	size = typesize[type];
+			if((t = v->b_name.vdim)) {
+				if( (neltp = t->nelt) && ISCONST(neltp) )
+					size *= neltp->b_const.fconst.ci;
+				else
+					dclerr("adjustable array in common", v);
+			}
+			p->extleng += size;
+			}
+
+		frchain( &(p->extp) );
+		}
+}
+
+
+
+
+
+LOCAL void
+docomleng()
+{
+register struct extsym *p;
+
+for(p = extsymtab ; p < nextext ; ++p)
+	if(p->extstg == STGCOMMON)
+		{
+		if(p->maxleng!=0 && p->extleng!=0 && p->maxleng!=p->extleng &&
+		    !eqn(XL,"_BLNK__ ",p->extname) )
+			warn1("incompatible lengths for common block %s",
+				nounder(XL, p->extname) );
+		if(p->maxleng < p->extleng)
+			p->maxleng = p->extleng;
+		p->extleng = 0;
+	}
+}
+
+
+
+
+
+/* ROUTINES DEALING WITH AUTOMATIC AND TEMPORARY STORAGE */
+void
+frtemp(p)
+struct bigblock *p;
+{
+holdtemps = mkchain(p, holdtemps);
+}
+
+
+
+
+/* allocate an automatic variable slot */
+
+struct bigblock *
+autovar(int nelt, int t, bigptr lengp)
+{
+	ftnint leng = 0;
+	register struct bigblock *q;
+
+	if(t == TYCHAR) {
+		if( ISICON(lengp) )
+			leng = lengp->b_const.fconst.ci;
+		else
+			fatal("automatic variable of nonconstant length");
+	} else
+		leng = typesize[t];
+	autoleng = roundup( autoleng, typealign[t]);
+
+	q = BALLO();
+	q->tag = TADDR;
+	q->vtype = t;
+	if(t == TYCHAR)
+		q->vleng = MKICON(leng);
+	q->vstg = STGAUTO;
+	q->b_addr.ntempelt = nelt;
+#ifdef BACKAUTO
+	/* stack grows downward */
+	autoleng += nelt*leng;
+	q->b_addr.memoffset = MKICON( - autoleng );
+#else
+	q->b_addr.memoffset = MKICON( autoleng );
+	autoleng += nelt*leng;
+#endif
+
+	return(q);
+}
+
+
+struct bigblock *mktmpn(nelt, type, lengp)
+int nelt;
+register int type;
+bigptr lengp;
+{
+ftnint leng = 0; /* XXX gcc */
+chainp p, oldp;
+register struct bigblock *q;
+
+if(type==TYUNKNOWN || type==TYERROR)
+	fatal1("mktmpn: invalid type %d", type);
+
+if(type==TYCHAR) {
+	if( ISICON(lengp) )
+		leng = lengp->b_const.fconst.ci;
+	else	{
+		err("adjustable length");
+		return( errnode() );
+		}
+}
+for(oldp = (chainp)&templist ; (p = oldp->chain.nextp) ; oldp = p)
+	{
+	q = p->chain.datap;
+	if(q->vtype==type && q->b_addr.ntempelt==nelt &&
+	    (type!=TYCHAR || q->vleng->b_const.fconst.ci==leng) )
+		{
+		oldp->chain.nextp = p->chain.nextp;
+		ckfree(p);
+		return(q);
+		}
+	}
+q = autovar(nelt, type, lengp);
+q->b_addr.istemp = YES;
+return(q);
+}
+
+
+
+
+struct bigblock *fmktemp(type, lengp)
+int type;
+bigptr lengp;
+{
+return( mktmpn(1,type,lengp) );
+}
+
+
+/* VARIOUS ROUTINES FOR PROCESSING DECLARATIONS */
+
+struct extsym *comblock(len, s)
+register int len;
+register char *s;
+{
+struct extsym *p;
+
+if(len == 0)
+	{
+	s = BLANKCOMMON;
+	len = strlen(s);
+	}
+p = mkext( varunder(len, s) );
+if(p->extstg == STGUNKNOWN)
+	p->extstg = STGCOMMON;
+else if(p->extstg != STGCOMMON)
+	{
+	err1("%s cannot be a common block name", s);
+	return(0);
+	}
+
+return( p );
+}
+
+void
+incomm(c, v)
+struct extsym *c;
+struct bigblock *v;
+{
+if(v->vstg != STGUNKNOWN)
+	dclerr("incompatible common declaration", v);
+else
+	{
+	v->vstg = STGCOMMON;
+	c->extp = hookup(c->extp, mkchain(v,NULL) );
+	}
+}
+
+
+
+void
+settype(v, type, length)
+register struct bigblock * v;
+register int type;
+register int length;
+{
+if(type == TYUNKNOWN)
+	return;
+
+if(type==TYSUBR && v->vtype!=TYUNKNOWN && v->vstg==STGARG)
+	{
+	v->vtype = TYSUBR;
+	frexpr(v->vleng);
+	}
+else if(type < 0)	/* storage class set */
+	{
+	if(v->vstg == STGUNKNOWN)
+		v->vstg = - type;
+	else if(v->vstg != -type)
+		dclerr("incompatible storage declarations", v);
+	}
+else if(v->vtype == TYUNKNOWN)
+	{
+	if( (v->vtype = lengtype(type, length))==TYCHAR && length!=0)
+		v->vleng = MKICON(length);
+	}
+else if(v->vtype!=type || (type==TYCHAR && v->vleng->b_const.fconst.ci!=length) )
+	dclerr("incompatible type declarations", v);
+}
+
+
+
+
+int
+lengtype(type, length)
+register int type;
+register int length;
+{
+switch(type)
+	{
+	case TYREAL:
+		if(length == 8)
+			return(TYDREAL);
+		if(length == 4)
+			goto ret;
+		break;
+
+	case TYCOMPLEX:
+		if(length == 16)
+			return(TYDCOMPLEX);
+		if(length == 8)
+			goto ret;
+		break;
+
+	case TYSHORT:
+	case TYDREAL:
+	case TYDCOMPLEX:
+	case TYCHAR:
+	case TYUNKNOWN:
+	case TYSUBR:
+	case TYERROR:
+		goto ret;
+
+	case TYLOGICAL:
+		if(length == 4)
+			goto ret;
+		break;
+
+	case TYLONG:
+		if(length == 0)
+			return(tyint);
+		if(length == 2)
+			return(TYSHORT);
+		if(length == 4)
+			goto ret;
+		break;
+	default:
+		fatal1("lengtype: invalid type %d", type);
+	}
+
+if(length != 0)
+	err("incompatible type-length combination");
+
+ret:
+	return(type);
+}
+
+
+
+
+void
+setintr(v)
+register struct bigblock * v;
+{
+register int k;
+
+if(v->vstg == STGUNKNOWN)
+	v->vstg = STGINTR;
+else if(v->vstg!=STGINTR)
+	dclerr("incompatible use of intrinsic function", v);
+if(v->vclass==CLUNKNOWN)
+	v->vclass = CLPROC;
+if(v->b_name.vprocclass == PUNKNOWN)
+	v->b_name.vprocclass = PINTRINSIC;
+else if(v->b_name.vprocclass != PINTRINSIC)
+	dclerr("invalid intrinsic declaration", v);
+if((k = intrfunct(v->b_name.varname)))
+	v->b_name.vardesc.varno = k;
+else
+	dclerr("unknown intrinsic function", v);
+}
+
+
+void
+setext(v)
+register struct bigblock * v;
+{
+if(v->vclass == CLUNKNOWN)
+	v->vclass = CLPROC;
+else if(v->vclass != CLPROC)
+	dclerr("invalid external declaration", v);
+
+if(v->b_name.vprocclass == PUNKNOWN)
+	v->b_name.vprocclass = PEXTERNAL;
+else if(v->b_name.vprocclass != PEXTERNAL)
+	dclerr("invalid external declaration", v);
+}
+
+
+
+
+/* create dimensions block for array variable */
+void
+setbound(v, nd, dims)
+register struct bigblock * v;
+int nd;
+struct uux dims[ ];
+{
+register bigptr q, t;
+register struct dimblock *p;
+int i;
+
+if(v->vclass == CLUNKNOWN)
+	v->vclass = CLVAR;
+else if(v->vclass != CLVAR)
+	{
+	dclerr("only variables may be arrays", v);
+	return;
+	}
+
+v->b_name.vdim = p = (struct dimblock *) ckalloc( sizeof(int) + (3+2*nd)*sizeof(bigptr) );
+p->ndim = nd;
+p->nelt = MKICON(1);
+
+for(i=0 ; i<nd ; ++i)
+	{
+	if( (q = dims[i].ub) == NULL)
+		{
+		if(i == nd-1)
+			{
+			frexpr(p->nelt);
+			p->nelt = NULL;
+			}
+		else
+			err("only last bound may be asterisk");
+		p->dims[i].dimsize = MKICON(1);;
+		p->dims[i].dimexpr = NULL;
+		}
+	else
+		{
+		if(dims[i].lb)
+			{
+			q = mkexpr(OPMINUS, q, cpexpr(dims[i].lb));
+			q = mkexpr(OPPLUS, q, MKICON(1) );
+			}
+		if( ISCONST(q) )
+			{
+			p->dims[i].dimsize = q;
+			p->dims[i].dimexpr = NULL;
+			}
+		else	{
+			p->dims[i].dimsize = autovar(1, tyint, NULL);
+			p->dims[i].dimexpr = q;
+			}
+		if(p->nelt)
+			p->nelt = mkexpr(OPSTAR, p->nelt, cpexpr(p->dims[i].dimsize));
+		}
+	}
+
+q = dims[nd-1].lb;
+if(q == NULL)
+	q = MKICON(1);
+
+for(i = nd-2 ; i>=0 ; --i)
+	{
+	t = dims[i].lb;
+	if(t == NULL)
+		t = MKICON(1);
+	if(p->dims[i].dimsize)
+		q = mkexpr(OPPLUS, t, mkexpr(OPSTAR, cpexpr(p->dims[i].dimsize), q) );
+	}
+
+if( ISCONST(q) )
+	{
+	p->baseoffset = q;
+	p->basexpr = NULL;
+	}
+else
+	{
+	p->baseoffset = autovar(1, tyint, NULL);
+	p->basexpr = q;
+	}
+}
Index: uspace/app/pcc/f77/fcom/put.c
===================================================================
--- uspace/app/pcc/f77/fcom/put.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/put.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,299 @@
+/*	$Id: put.c,v 1.17 2008/05/11 15:28:03 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 conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * INTERMEDIATE CODE GENERATION PROCEDURES COMMON TO BOTH
+ * JOHNSON AND RITCHIE FAMILIES OF SECOND PASSES
+*/
+
+#include "defines.h"
+#include "defs.h"
+
+#include "scjdefs.h"
+
+char *ops [ ] =
+	{
+	"??", "+", "-", "*", "/", "**", "-",
+	"OR", "AND", "EQV", "NEQV", "NOT",
+	"CONCAT",
+	"<", "==", ">", "<=", "!=", ">=",
+	" of ", " ofC ", " = ", " += ", " *= ", " CONV ", " << ", " % ",
+	" , ", " ? ", " : "
+	" abs ", " min ", " max ", " addr ", " indirect ",
+	" bitor ", " bitand ", " bitxor ", " bitnot ", " >> ",
+	};
+
+/*
+ * The index position here matches tho OPx numbers in defines.h.
+ * Do not change!
+ */
+int ops2 [ ] =
+	{
+	P2BAD, P2PLUS, P2MINUS, P2STAR, P2SLASH, P2BAD, P2NEG,
+	P2BAD, P2BAD, P2EQ, P2NE, P2BAD,
+	P2BAD,
+	P2LT, P2EQ, P2GT, P2LE, P2NE, P2GE,
+	P2CALL, P2CALL, P2ASSIGN, P2BAD, P2BAD, P2CONV, P2LSHIFT, P2MOD,
+	P2BAD, P2BAD, P2BAD,
+	P2BAD, P2BAD, P2BAD, P2BAD, P2BAD,
+	P2BITOR, P2BITAND, P2BITXOR, P2BITNOT, P2RSHIFT
+	};
+
+
+int types2 [ ] =
+	{
+	P2BAD, INT|PTR, SHORT, LONG, FLOAT, DOUBLE,
+	FLOAT, DOUBLE, LONG, CHAR, INT, P2BAD
+	};
+
+void
+setlog()
+{
+types2[TYLOGICAL] = types2[tylogical];
+}
+
+NODE *
+putex1(bigptr q)
+{
+	NODE *p;
+	q = fixtype(q);
+	p = putx(q);
+	templist = hookup(templist, holdtemps);
+	holdtemps = NULL;
+	return p;
+}
+
+/*
+ * Print out an assignment.
+ */
+void
+puteq(bigptr lp, bigptr rp)
+{
+	putexpr(mkexpr(OPASSIGN, lp, rp));
+}
+
+/*
+ * Return a copied node of the real part of an expression.
+ */
+struct bigblock *
+realpart(struct bigblock *p)
+{
+	struct bigblock *q;
+
+	q = cpexpr(p);
+	if( ISCOMPLEX(p->vtype) )
+		q->vtype += (TYREAL-TYCOMPLEX);
+	return(q);
+}
+
+/*
+ * Return a copied node of the imaginary part of an expression.
+ */
+struct bigblock *
+imagpart(struct bigblock *p)
+{
+	struct bigblock *q;
+
+	if( ISCOMPLEX(p->vtype) ) {
+		q = cpexpr(p);
+		q->vtype += (TYREAL-TYCOMPLEX);
+		q->b_addr.memoffset = mkexpr(OPPLUS, q->b_addr.memoffset,
+		    MKICON(typesize[q->vtype]));
+	} else
+		q = mkrealcon( ISINT(p->vtype) ? TYDREAL : p->vtype , 0.0);
+	return(q);
+}
+
+struct bigblock *
+putconst(struct bigblock *p)
+{
+	struct bigblock *q;
+	struct literal *litp, *lastlit;
+	int i, k, type;
+	int litflavor;
+
+	if( ! ISCONST(p) )
+		fatal1("putconst: bad tag %d", p->tag);
+
+	q = BALLO();
+	q->tag = TADDR;
+	type = p->vtype;
+	q->vtype = ( type==TYADDR ? TYINT : type );
+	q->vleng = cpexpr(p->vleng);
+	q->vstg = STGCONST;
+	q->b_addr.memno = newlabel();
+	q->b_addr.memoffset = MKICON(0);
+
+	/* check for value in literal pool, and update pool if necessary */
+
+	switch(type = p->vtype) {
+	case TYCHAR:
+		if(p->vleng->b_const.fconst.ci > XL)
+			break;	/* too long for literal table */
+		litflavor = 1;
+		goto loop;
+
+	case TYREAL:
+	case TYDREAL:
+		litflavor = 2;
+		goto loop;
+
+	case TYLOGICAL:
+		type = tylogical;
+	case TYSHORT:
+	case TYLONG:
+		litflavor = 3;
+
+	loop:
+		lastlit = litpool + nliterals;
+		for(litp = litpool ; litp<lastlit ; ++litp)
+			if(type == litp->littype)
+			    switch(litflavor) {
+			case 1:
+				if(p->vleng->b_const.fconst.ci !=
+				    litp->litval.litcval.litclen)
+					break;
+				if(!eqn((int)p->vleng->b_const.fconst.ci,
+				    p->b_const.fconst.ccp,
+					litp->litval.litcval.litcstr) )
+						break;
+			ret:
+				q->b_addr.memno = litp->litnum;
+				frexpr(p);
+				return(q);
+
+			case 2:
+				if(p->b_const.fconst.cd[0] ==
+				    litp->litval.litdval)
+					goto ret;
+				break;
+
+			case 3:
+				if(p->b_const.fconst.ci == litp->litval.litival)
+					goto ret;
+				break;
+			}
+		if(nliterals < MAXLITERALS) {
+			++nliterals;
+			litp->littype = type;
+			litp->litnum = q->b_addr.memno;
+			switch(litflavor) {
+			case 1:
+				litp->litval.litcval.litclen =
+				    p->vleng->b_const.fconst.ci;
+				cpn( (int) litp->litval.litcval.litclen,
+					p->b_const.fconst.ccp,
+					litp->litval.litcval.litcstr);
+				break;
+
+			case 2:
+				litp->litval.litdval = p->b_const.fconst.cd[0];
+				break;
+
+			case 3:
+				litp->litval.litival = p->b_const.fconst.ci;
+				break;
+			}
+		}
+	default:
+		break;
+	}
+
+	preven(typealign[ type==TYCHAR ? TYLONG : type ]);
+	prlabel(q->b_addr.memno);
+
+	k = 1;
+	switch(type) {
+	case TYLOGICAL:
+	case TYSHORT:
+	case TYLONG:
+		prconi(stdout, type, p->b_const.fconst.ci);
+		break;
+
+	case TYCOMPLEX:
+		k = 2;
+	case TYREAL:
+		type = TYREAL;
+		goto flpt;
+
+	case TYDCOMPLEX:
+		k = 2;
+	case TYDREAL:
+		type = TYDREAL;
+
+	flpt:
+		for(i = 0 ; i < k ; ++i)
+			prconr(stdout, type, p->b_const.fconst.cd[i]);
+		break;
+
+	case TYCHAR:
+		putstr(p->b_const.fconst.ccp,
+		    p->vleng->b_const.fconst.ci);
+		break;
+
+	case TYADDR:
+		prcona(p->b_const.fconst.ci);
+		break;
+
+	default:
+		fatal1("putconst: bad type %d", p->vtype);
+	}
+
+	frexpr(p);
+	return( q );
+}
+
+/*
+ * put out a character string constant.  begin every one on
+ * a long integer boundary, and pad with nulls
+ */
+void
+putstr(char *s, ftnint n)
+{
+	int b[FSZSHORT];
+	int i;
+
+	i = 0;
+	while(--n >= 0) {
+		b[i++] = *s++;
+		if(i == FSZSHORT) {
+			prchars(b);
+			i = 0;
+		}
+	}
+
+	while(i < FSZSHORT)
+		b[i++] = '\0';
+	prchars(b);
+}
Index: uspace/app/pcc/f77/fcom/putscj.c
===================================================================
--- uspace/app/pcc/f77/fcom/putscj.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/putscj.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1453 @@
+/*	$Id: putscj.c,v 1.18 2008/12/19 08:08:48 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 conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/* INTERMEDIATE CODE GENERATION FOR S C JOHNSON C COMPILERS */
+/* NEW VERSION USING BINARY POLISH POSTFIX INTERMEDIATE */
+
+#include <unistd.h>
+#include <string.h>
+
+#include "defines.h"
+#include "defs.h"
+
+#include "scjdefs.h"
+
+LOCAL struct bigblock *putcall(struct bigblock *p);
+LOCAL NODE *putmnmx(struct bigblock *p);
+LOCAL NODE *putmem(bigptr, int, ftnint);
+LOCAL NODE *putaddr(struct bigblock *, int);
+LOCAL void putct1(bigptr, struct bigblock *, struct bigblock *, int *);
+LOCAL int ncat(bigptr p);
+LOCAL NODE *putcat(struct bigblock *, bigptr);
+LOCAL NODE *putchcmp(struct bigblock *p);
+LOCAL NODE *putcheq(struct bigblock *p);
+LOCAL NODE *putcxcmp(struct bigblock *p);
+LOCAL struct bigblock *putcx1(bigptr);
+LOCAL NODE *putcxop(bigptr p);
+LOCAL struct bigblock *putcxeq(struct bigblock *p);
+LOCAL NODE *putpower(bigptr p);
+LOCAL NODE *putop(bigptr p);
+LOCAL NODE *putchop(bigptr p);
+LOCAL struct bigblock *putch1(bigptr);
+LOCAL struct bigblock *intdouble(struct bigblock *);
+
+extern int ops2[];
+extern int types2[];
+static char *inproc;
+static NODE *callval; /* to get return value right */
+extern int negrel[];
+
+#define XINT(z) 	ONEOF(z, MSKINT|MSKCHAR)
+#define	P2TYPE(x)	(types2[(x)->vtype])
+#define	P2OP(x)		(ops2[(x)->b_expr.opcode])
+
+static void
+sendp2(NODE *p)
+{
+	extern int thisline;
+
+	p2tree(p);
+	thisline = lineno;
+	if (debugflag)
+		fwalk(p, e2print, 0);
+	pass2_compile(ipnode(p));
+}
+
+static NODE *
+putassign(bigptr lp, bigptr rp)
+{
+	return putx(fixexpr(mkexpr(OPASSIGN, lp, rp)));
+}
+
+
+void
+puthead(char *s)
+{
+	struct interpass_prolog *ipp = ckalloc(sizeof(struct interpass_prolog));
+	int olbl, lbl1, lbl2;
+	unsigned int i;
+
+	if (s == NULL)
+		return;
+	if (inproc)
+		fatal1("puthead %s in procedure", s);
+	inproc = s;
+	olbl = lastlabno;
+	lbl1 = newlabel();
+	lbl2 = newlabel();
+
+	for (i = 0; i < NIPPREGS; i++)
+		ipp->ipp_regs[i] = 0;	/* no regs used yet */
+	ipp->ipp_autos = 0;		/* no autos used yet */
+	ipp->ipp_name = copys(s);		/* function name */
+	ipp->ipp_type = INT;		/* type not known yet? */
+	ipp->ipp_vis = 1;		/* always visible */
+	ipp->ip_tmpnum = 0; 		/* no temp nodes used in F77 yet */
+	ipp->ip_lblnum = olbl;		/* # used labels so far */
+	ipp->ipp_ip.ip_lbl = lbl1; 	/* first label, for optim */
+	ipp->ipp_ip.type = IP_PROLOG;
+	pass2_compile((struct interpass *)ipp);
+
+}
+
+/* It is necessary to precede each procedure with a "left bracket"
+ * line that tells pass 2 how many register variables and how
+ * much automatic space is required for the function.  This compiler
+ * does not know how much automatic space is needed until the
+ * entire procedure has been processed.  Therefore, "puthead"
+ * is called at the begining to record the current location in textfile,
+ * then to put out a placeholder left bracket line.  This procedure
+ * repositions the file and rewrites that line, then puts the
+ * file pointer back to the end of the file.
+ */
+
+void
+putbracket()
+{
+	struct interpass_prolog *ipp = ckalloc(sizeof(struct interpass_prolog));
+	unsigned int i;
+
+	if (inproc == 0)
+		fatal1("puteof outside procedure");
+	for (i = 0; i < NIPPREGS; i++)
+		ipp->ipp_regs[i] = 0;
+	ipp->ipp_autos = autoleng;
+	ipp->ipp_name = copys(inproc);
+	ipp->ipp_type = INT; /* XXX should set the correct type */
+	ipp->ipp_vis = 1;
+	ipp->ip_tmpnum = 0;
+	ipp->ip_lblnum = lastlabno;
+	ipp->ipp_ip.ip_lbl = retlabel;
+	ipp->ipp_ip.type = IP_EPILOG;
+	printf("\t.text\n"); /* XXX */
+	pass2_compile((struct interpass *)ipp);
+	inproc = 0;
+}
+
+
+
+void
+putrbrack(int k)
+{
+}
+
+
+void
+puteof()
+{
+}
+
+
+/* put out code for if( ! p) goto l  */
+void
+putif(bigptr p, int l)
+{
+	NODE *p1;
+	int k;
+
+	if( ( k = (p = fixtype(p))->vtype) != TYLOGICAL) {
+		if(k != TYERROR)
+			err("non-logical expression in IF statement");
+		frexpr(p);
+	} else {
+		p1 = putex1(p);
+		if (p1->n_op == EQ && p1->n_right->n_op == ICON &&
+		    p1->n_right->n_lval == 0 && logop(p1->n_left->n_op)) {
+			/* created by OPOR */
+			NODE *q = p1->n_left;
+			q->n_op = negrel[q->n_op - EQ];
+			nfree(p1->n_right);
+			nfree(p1);
+			p1 = q;
+		}
+		if (logop(p1->n_op) == 0)
+			p1 = mkbinode(NE, p1, mklnode(ICON, 0, 0, INT), INT);
+		if (p1->n_left->n_op == ICON) {
+			/* change constants to right */
+			NODE *p2 = p1->n_left;
+			p1->n_left = p1->n_right;
+			p1->n_right = p2;
+			if (p1->n_op != EQ && p1->n_op != NE)
+				p1->n_op = negrel[p1->n_op - EQ];
+		}
+		p1->n_op = negrel[p1->n_op - EQ];
+		p1 = mkbinode(CBRANCH, p1, mklnode(ICON, l, 0, INT), INT);
+		sendp2(p1);
+	}
+}
+
+/* Arithmetic IF  */
+void
+prarif(bigptr p, int neg, int zer, int pos)
+{
+	bigptr x1 = fmktemp(p->vtype, NULL);
+
+	putexpr(mkexpr(OPASSIGN, cpexpr(x1), p));
+	putif(mkexpr(OPGE, cpexpr(x1), MKICON(0)), neg);
+	putif(mkexpr(OPLE, x1, MKICON(0)), pos);
+	putgoto(zer);
+}
+
+/* put out code for  goto l   */
+void
+putgoto(int label)
+{
+	NODE *p;
+
+	p = mkunode(GOTO, mklnode(ICON, label, 0, INT), 0, INT);
+	sendp2(p);
+}
+
+
+/* branch to address constant or integer variable */
+void
+putbranch(struct bigblock *q)
+{
+	NODE *p;
+
+	p = mkunode(GOTO, putex1(q), 0, INT);
+	sendp2(p);
+}
+
+/*
+ * put out label l: in text segment
+ */
+void
+putlabel(int label)
+{
+	struct interpass *ip = ckalloc(sizeof(struct interpass));
+
+	ip->type = IP_DEFLAB;
+	ip->lineno = lineno;
+	ip->ip_lbl = label;
+	pass2_compile(ip);
+}
+
+
+/*
+ * Called from inner routines.  Generates a NODE tree and writes it out.
+ */
+void
+putexpr(bigptr q)
+{
+	NODE *p;
+	p = putex1(q);
+	sendp2(p);
+}
+
+
+
+void
+putcmgo(bigptr x, int nlab, struct labelblock *labels[])
+{
+	bigptr y;
+	int i;
+
+	if (!ISINT(x->vtype)) {
+		execerr("computed goto index must be integer", NULL);
+		return;
+	}
+
+	y = fmktemp(x->vtype, NULL);
+	putexpr(mkexpr(OPASSIGN, cpexpr(y), x));
+#ifdef notyet /* target-specific computed goto */
+	vaxgoto(y, nlab, labels);
+#else
+	/*
+	 * Primitive implementation, should use table here.
+	 */
+	for(i = 0 ; i < nlab ; ++i)
+		putif(mkexpr(OPNE, cpexpr(y), MKICON(i+1)), labels[i]->labelno);
+	frexpr(y);
+#endif
+}
+
+/*
+ * Convert a f77 tree statement to something that looks like a
+ * pcc expression tree.
+ */
+NODE *
+putx(bigptr q)
+{
+	struct bigblock *x1;
+	NODE *p = NULL; /* XXX */
+	int opc;
+	int type, k;
+
+#ifdef PCC_DEBUG
+	if (tflag) {
+		printf("putx %p\n", q);
+		fprint(q, 0);
+	}
+#endif
+
+	switch(q->tag) {
+	case TERROR:
+		ckfree(q);
+		break;
+
+	case TCONST:
+		switch(type = q->vtype) {
+			case TYLOGICAL:
+				type = tyint;
+			case TYLONG:
+			case TYSHORT:
+				p = mklnode(ICON, q->b_const.fconst.ci,
+				    0, types2[type]);
+				ckfree(q);
+				break;
+
+			case TYADDR:
+				p = mklnode(ICON, 0, 0, types2[type]);
+				p->n_name = copys(memname(STGCONST,
+				    (int)q->b_const.fconst.ci));
+				ckfree(q);
+				break;
+
+			default:
+				p = putx(putconst(q));
+				break;
+			}
+		break;
+
+	case TEXPR:
+		switch(opc = q->b_expr.opcode) {
+			case OPCALL:
+			case OPCCALL:
+				if( ISCOMPLEX(q->vtype) )
+					p = putcxop(q);
+				else {
+					putcall(q);
+					p = callval;
+				}
+				break;
+
+			case OPMIN:
+			case OPMAX:
+				p = putmnmx(q);
+				break;
+
+			case OPASSIGN:
+				if (ISCOMPLEX(q->b_expr.leftp->vtype) ||
+				    ISCOMPLEX(q->b_expr.rightp->vtype)) {
+					frexpr(putcxeq(q));
+				} else if (ISCHAR(q))
+					p = putcheq(q);
+				else
+					goto putopp;
+				break;
+
+			case OPEQ:
+			case OPNE:
+				if (ISCOMPLEX(q->b_expr.leftp->vtype) ||
+				    ISCOMPLEX(q->b_expr.rightp->vtype) ) {
+					p = putcxcmp(q);
+					break;
+				}
+			case OPLT:
+			case OPLE:
+			case OPGT:
+			case OPGE:
+				if(ISCHAR(q->b_expr.leftp))
+					p = putchcmp(q);
+				else
+					goto putopp;
+				break;
+
+			case OPPOWER:
+				p = putpower(q);
+				break;
+
+			case OPSTAR:
+				/*   m * (2**k) -> m<<k   */
+				if (XINT(q->b_expr.leftp->vtype) &&
+				    ISICON(q->b_expr.rightp) &&
+				    ((k = flog2(q->b_expr.rightp->b_const.fconst.ci))>0) ) {
+					q->b_expr.opcode = OPLSHIFT;
+					frexpr(q->b_expr.rightp);
+					q->b_expr.rightp = MKICON(k);
+					goto putopp;
+				}
+
+			case OPMOD:
+				goto putopp;
+			case OPPLUS:
+			case OPMINUS:
+			case OPSLASH:
+			case OPNEG:
+				if( ISCOMPLEX(q->vtype) )
+					p = putcxop(q);
+				else	
+					goto putopp;
+				break;
+
+			case OPCONV:
+				if( ISCOMPLEX(q->vtype) )
+					p = putcxop(q);
+				else if (ISCOMPLEX(q->b_expr.leftp->vtype)) {
+					p = putx(mkconv(q->vtype,
+					    realpart(putcx1(q->b_expr.leftp))));
+					ckfree(q);
+				} else
+					goto putopp;
+				break;
+
+			case OPAND:
+				/* Create logical AND */
+				x1 = fmktemp(TYLOGICAL, NULL);
+				putexpr(mkexpr(OPASSIGN, cpexpr(x1),
+				    mklogcon(0)));
+				k = newlabel();
+				putif(q->b_expr.leftp, k);
+				putif(q->b_expr.rightp, k);
+				putexpr(mkexpr(OPASSIGN, cpexpr(x1),
+				    mklogcon(1)));
+				putlabel(k);
+				p = putx(x1);
+				break;
+
+			case OPNOT: /* Logical NOT */
+				x1 = fmktemp(TYLOGICAL, NULL);
+				putexpr(mkexpr(OPASSIGN, cpexpr(x1),
+				    mklogcon(1)));
+				k = newlabel();
+				putif(q->b_expr.leftp, k);
+				putexpr(mkexpr(OPASSIGN, cpexpr(x1),
+				    mklogcon(0)));
+				putlabel(k);
+				p = putx(x1);
+				break;
+
+			case OPOR: /* Create logical OR */
+				x1 = fmktemp(TYLOGICAL, NULL);
+				putexpr(mkexpr(OPASSIGN, cpexpr(x1),
+				    mklogcon(1)));
+				k = newlabel();
+				putif(mkexpr(OPEQ, q->b_expr.leftp,
+				    mklogcon(0)), k);
+				putif(mkexpr(OPEQ, q->b_expr.rightp,
+				    mklogcon(0)), k);
+				putexpr(mkexpr(OPASSIGN, cpexpr(x1),
+				    mklogcon(0)));
+				putlabel(k);
+				p = putx(x1);
+				break;
+
+			case OPCOMMA:
+				for (x1 = q; x1->b_expr.opcode == OPCOMMA; 
+				    x1 = x1->b_expr.leftp)
+					putexpr(x1->b_expr.rightp);
+				p = putx(x1);
+				break;
+
+			case OPEQV:
+			case OPNEQV:
+			case OPADDR:
+			case OPBITOR:
+			case OPBITAND:
+			case OPBITXOR:
+			case OPBITNOT:
+			case OPLSHIFT:
+			case OPRSHIFT:
+		putopp:
+				p = putop(q);
+				break;
+
+			default:
+				fatal1("putx: invalid opcode %d", opc);
+			}
+		break;
+
+	case TADDR:
+		p = putaddr(q, YES);
+		break;
+
+	default:
+		fatal1("putx: impossible tag %d", q->tag);
+	}
+	return p;
+}
+
+LOCAL NODE *
+putop(bigptr q)
+{
+	NODE *p;
+	int k;
+	bigptr lp, tp;
+	int pt, lt;
+
+#ifdef PCC_DEBUG
+	if (tflag) {
+		printf("putop %p\n", q);
+		fprint(q, 0);
+	}
+#endif
+	switch(q->b_expr.opcode) { /* check for special cases and rewrite */
+	case OPCONV:
+		pt = q->vtype;
+		lp = q->b_expr.leftp;
+		lt = lp->vtype;
+		while(q->tag==TEXPR && q->b_expr.opcode==OPCONV &&
+		     ((ISREAL(pt)&&ISREAL(lt)) ||
+			(XINT(pt)&&(ONEOF(lt,MSKINT|MSKADDR))) )) {
+			if(lp->tag != TEXPR) {
+				if(pt==TYINT && lt==TYLONG)
+					break;
+				if(lt==TYINT && pt==TYLONG)
+					break;
+			}
+			ckfree(q);
+			q = lp;
+			pt = lt;
+			lp = q->b_expr.leftp;
+			lt = lp->vtype;
+		}
+		if(q->tag==TEXPR && q->b_expr.opcode==OPCONV)
+			break;
+		p = putx(q);
+		return p;
+
+	case OPADDR:
+		lp = q->b_expr.leftp;
+		if(lp->tag != TADDR) {
+			tp = fmktemp(lp->vtype, lp->vleng);
+			p = putx(mkexpr(OPASSIGN, cpexpr(tp), lp));
+			sendp2(p);
+			lp = tp;
+		}
+		p = putaddr(lp, NO);
+		ckfree(q);
+		return p;
+	}
+
+	if ((k = ops2[q->b_expr.opcode]) <= 0)
+		fatal1("putop: invalid opcode %d (%d)", q->b_expr.opcode, k);
+	p = putx(q->b_expr.leftp);
+	if(q->b_expr.rightp)
+		p = mkbinode(k, p, putx(q->b_expr.rightp), types2[q->vtype]);
+	else
+		p = mkunode(k, p, 0, types2[q->vtype]);
+
+	if(q->vleng)
+		frexpr(q->vleng);
+	ckfree(q);
+	return p;
+}
+
+/*
+ * Put return values into correct register.
+ */
+void
+putforce(int t, bigptr p)
+{
+	NODE *p1;
+
+	p = mkconv(t, fixtype(p));
+	p1 = putx(p);
+	p1 = mkunode(FORCE, p1, 0, 
+		(t==TYSHORT ? SHORT : (t==TYLONG ? LONG : LDOUBLE)));
+	sendp2(p1);
+}
+
+LOCAL NODE *
+putpower(bigptr p)
+{
+	NODE *p3;
+	bigptr base;
+	struct bigblock *t1, *t2;
+	ftnint k = 0; /* XXX gcc */
+	int type;
+
+	if(!ISICON(p->b_expr.rightp) ||
+	    (k = p->b_expr.rightp->b_const.fconst.ci)<2)
+		fatal("putpower: bad call");
+	base = p->b_expr.leftp;
+	type = base->vtype;
+	t1 = fmktemp(type, NULL);
+	t2 = NULL;
+	p3 = putassign(cpexpr(t1), cpexpr(base) );
+	sendp2(p3);
+
+	for( ; (k&1)==0 && k>2 ; k>>=1 ) {
+		p3 = putassign(cpexpr(t1),
+		    mkexpr(OPSTAR, cpexpr(t1), cpexpr(t1)));
+		sendp2(p3);
+	}
+
+	if(k == 2)
+		p3 = putx(mkexpr(OPSTAR, cpexpr(t1), cpexpr(t1)));
+	else {
+		t2 = fmktemp(type, NULL);
+		p3 = putassign(cpexpr(t2), cpexpr(t1));
+		sendp2(p3);
+	
+		for(k>>=1 ; k>1 ; k>>=1) {
+			p3 = putassign(cpexpr(t1),
+			    mkexpr(OPSTAR, cpexpr(t1), cpexpr(t1)));
+			sendp2(p3);
+			if(k & 1) {
+				p3 = putassign(cpexpr(t2),
+				    mkexpr(OPSTAR, cpexpr(t2), cpexpr(t1)));
+				sendp2(p3);
+			}
+		}
+		p3 = putx( mkexpr(OPSTAR, cpexpr(t2),
+		mkexpr(OPSTAR, cpexpr(t1), cpexpr(t1)) ));
+	}
+	frexpr(t1);
+	if(t2)
+		frexpr(t2);
+	frexpr(p);
+	return p3;
+}
+
+LOCAL struct bigblock *
+intdouble(struct bigblock *p)
+{
+	struct bigblock *t;
+
+	t = fmktemp(TYDREAL, NULL);
+
+	sendp2(putassign(cpexpr(t), p));
+	return(t);
+}
+
+LOCAL struct bigblock *
+putcxeq(struct bigblock *q)
+{
+	struct bigblock *lp, *rp;
+
+	lp = putcx1(q->b_expr.leftp);
+	rp = putcx1(q->b_expr.rightp);
+	sendp2(putassign(realpart(lp), realpart(rp)));
+	if( ISCOMPLEX(q->vtype) ) {
+		sendp2(putassign(imagpart(lp), imagpart(rp)));
+	}
+	frexpr(rp);
+	ckfree(q);
+	return(lp);
+}
+
+
+
+LOCAL NODE *
+putcxop(bigptr q)
+{
+	NODE *p;
+
+	p = putaddr(putcx1(q), NO);
+	return p;
+}
+
+LOCAL struct bigblock *
+putcx1(bigptr qq)
+{
+	struct bigblock *q, *lp, *rp;
+	register struct bigblock *resp;
+	NODE *p;
+	int opcode;
+	int ltype, rtype;
+
+	ltype = rtype = 0; /* XXX gcc */
+	if(qq == NULL)
+		return(NULL);
+
+	switch(qq->tag) {
+	case TCONST:
+		if( ISCOMPLEX(qq->vtype) )
+			qq = putconst(qq);
+		return( qq );
+
+	case TADDR:
+		if( ! addressable(qq) ) {
+			resp = fmktemp(tyint, NULL);
+			p = putassign( cpexpr(resp), qq->b_addr.memoffset );
+			sendp2(p);
+			qq->b_addr.memoffset = resp;
+		}
+		return( qq );
+
+	case TEXPR:
+		if( ISCOMPLEX(qq->vtype) )
+			break;
+		resp = fmktemp(TYDREAL, NO);
+		p = putassign( cpexpr(resp), qq);
+		sendp2(p);
+		return(resp);
+
+	default:
+		fatal1("putcx1: bad tag %d", qq->tag);
+	}
+
+	opcode = qq->b_expr.opcode;
+	if(opcode==OPCALL || opcode==OPCCALL) {
+		q = putcall(qq);
+		sendp2(callval);
+		return(q);
+	} else if(opcode == OPASSIGN) {
+		return( putcxeq(qq) );
+	}
+
+	resp = fmktemp(qq->vtype, NULL);
+	if((lp = putcx1(qq->b_expr.leftp) ))
+		ltype = lp->vtype;
+	if((rp = putcx1(qq->b_expr.rightp) ))
+		rtype = rp->vtype;
+
+	switch(opcode) {
+	case OPCOMMA:
+		frexpr(resp);
+		resp = rp;
+		rp = NULL;
+		break;
+
+	case OPNEG:
+		p = putassign(realpart(resp),
+		    mkexpr(OPNEG, realpart(lp), NULL));
+		sendp2(p);
+		p = putassign(imagpart(resp),
+		    mkexpr(OPNEG, imagpart(lp), NULL));
+		sendp2(p);
+		break;
+
+	case OPPLUS:
+	case OPMINUS:
+		p = putassign( realpart(resp),
+		    mkexpr(opcode, realpart(lp), realpart(rp) ));
+		sendp2(p);
+		if(rtype < TYCOMPLEX) {
+			p = putassign(imagpart(resp), imagpart(lp) );
+		} else if(ltype < TYCOMPLEX) {
+			if(opcode == OPPLUS)
+				p = putassign( imagpart(resp), imagpart(rp) );
+			else
+				p = putassign( imagpart(resp),
+				    mkexpr(OPNEG, imagpart(rp), NULL) );
+		} else
+			p = putassign( imagpart(resp),
+			    mkexpr(opcode, imagpart(lp), imagpart(rp) ));
+		sendp2(p);
+		break;
+
+	case OPSTAR:
+		if(ltype < TYCOMPLEX) {
+			if( ISINT(ltype) )
+				lp = intdouble(lp);
+			p = putassign( realpart(resp),
+			    mkexpr(OPSTAR, cpexpr(lp), realpart(rp) ));
+			sendp2(p);
+			p = putassign( imagpart(resp),
+			    mkexpr(OPSTAR, cpexpr(lp), imagpart(rp) ));
+		} else if(rtype < TYCOMPLEX) {
+			if( ISINT(rtype) )
+				rp = intdouble(rp);
+			p = putassign( realpart(resp),
+			    mkexpr(OPSTAR, cpexpr(rp), realpart(lp) ));
+			sendp2(p);
+			p = putassign( imagpart(resp),
+			    mkexpr(OPSTAR, cpexpr(rp), imagpart(lp) ));
+		} else {
+			p = putassign( realpart(resp), mkexpr(OPMINUS,
+				mkexpr(OPSTAR, realpart(lp), realpart(rp)),
+				mkexpr(OPSTAR, imagpart(lp), imagpart(rp)) ));
+			sendp2(p);
+			p = putassign( imagpart(resp), mkexpr(OPPLUS,
+				mkexpr(OPSTAR, realpart(lp), imagpart(rp)),
+				mkexpr(OPSTAR, imagpart(lp), realpart(rp)) ));
+		}
+		sendp2(p);
+		break;
+
+	case OPSLASH:
+		/* fixexpr has already replaced all divisions
+		 * by a complex by a function call
+		 */
+		if( ISINT(rtype) )
+			rp = intdouble(rp);
+		p = putassign( realpart(resp),
+		    mkexpr(OPSLASH, realpart(lp), cpexpr(rp)) );
+		sendp2(p);
+		p = putassign( imagpart(resp),
+		    mkexpr(OPSLASH, imagpart(lp), cpexpr(rp)) );
+		sendp2(p);
+		break;
+
+	case OPCONV:
+		p = putassign( realpart(resp), realpart(lp) );
+		if( ISCOMPLEX(lp->vtype) )
+			q = imagpart(lp);
+		else if(rp != NULL)
+			q = realpart(rp);
+		else
+			q = mkrealcon(TYDREAL, 0.0);
+		sendp2(p);
+		p = putassign( imagpart(resp), q);
+		sendp2(p);
+		break;
+
+	default:
+		fatal1("putcx1 of invalid opcode %d", opcode);
+	}
+
+	frexpr(lp);
+	frexpr(rp);
+	ckfree(qq);
+	return(resp);
+}
+
+
+LOCAL NODE *
+putcxcmp(struct bigblock *p)
+{
+	NODE *p1;
+	int opcode;
+	struct bigblock *lp, *rp;
+	struct bigblock *q;
+
+	opcode = p->b_expr.opcode;
+	lp = putcx1(p->b_expr.leftp);
+	rp = putcx1(p->b_expr.rightp);
+
+	q = mkexpr( opcode==OPEQ ? OPAND : OPOR ,
+	    mkexpr(opcode, realpart(lp), realpart(rp)),
+	    mkexpr(opcode, imagpart(lp), imagpart(rp)) );
+	p1 = putx( fixexpr(q) );
+
+	ckfree(lp);
+	ckfree(rp);
+	ckfree(p);
+	return p1;
+}
+
+LOCAL struct bigblock *
+putch1(bigptr p)
+{
+	struct bigblock *t;
+
+	switch(p->tag) {
+	case TCONST:
+		return( putconst(p) );
+
+	case TADDR:
+		return(p);
+
+	case TEXPR:
+		switch(p->b_expr.opcode) {
+			case OPCALL:
+			case OPCCALL:
+				t = putcall(p);
+				sendp2(callval);
+				break;
+
+			case OPCONCAT:
+				t = fmktemp(TYCHAR, cpexpr(p->vleng) );
+				sendp2(putcat( cpexpr(t), p ));
+				break;
+
+			case OPCONV:
+				if(!ISICON(p->vleng) ||
+				    p->vleng->b_const.fconst.ci!=1
+				   || ! XINT(p->b_expr.leftp->vtype) )
+					fatal("putch1: bad character conversion");
+				t = fmktemp(TYCHAR, MKICON(1) );
+				sendp2(putassign( cpexpr(t), p));
+				break;
+			default:
+				fatal1("putch1: invalid opcode %d", p->b_expr.opcode);
+				t = NULL; /* XXX gcc */
+			}
+		return(t);
+
+	default:
+		fatal1("putch1: bad tag %d", p->tag);
+	}
+/* NOTREACHED */
+return NULL; /* XXX gcc */
+}
+
+
+
+
+
+LOCAL NODE *
+putchop(bigptr p)
+{
+	NODE *p1;
+
+	p1 = putaddr( putch1(p) , NO );
+	return p1;
+}
+
+
+/*
+ * Assign a character to another.
+ */
+LOCAL NODE *
+putcheq(struct bigblock *p)
+{
+	NODE *p1, *p2, *p3;
+
+	if( p->b_expr.rightp->tag==TEXPR &&
+	    p->b_expr.rightp->b_expr.opcode==OPCONCAT )
+		p3 = putcat(p->b_expr.leftp, p->b_expr.rightp);
+	else if( ISONE(p->b_expr.leftp->vleng) &&
+	    ISONE(p->b_expr.rightp->vleng) ) {
+		p1 = putaddr( putch1(p->b_expr.leftp) , YES );
+		p2 = putaddr( putch1(p->b_expr.rightp) , YES );
+		p3 = mkbinode(ASSIGN, p1, p2, CHAR);
+	} else
+		p3 = putx(call2(TYINT, "s_copy",
+		    p->b_expr.leftp, p->b_expr.rightp));
+
+	frexpr(p->vleng);
+	ckfree(p);
+	return p3;
+}
+
+
+
+/*
+ * Compare character(s) code.
+ */
+LOCAL NODE *
+putchcmp(struct bigblock *p)
+{
+	NODE *p1, *p2, *p3;
+
+	if(ISONE(p->b_expr.leftp->vleng) && ISONE(p->b_expr.rightp->vleng) ) {
+		p1 = putaddr( putch1(p->b_expr.leftp) , YES );
+		p2 = putaddr( putch1(p->b_expr.rightp) , YES );
+		p3 = mkbinode(ops2[p->b_expr.opcode], p1, p2, CHAR);
+		ckfree(p);
+	} else {
+		p->b_expr.leftp = call2(TYINT,"s_cmp",
+		    p->b_expr.leftp, p->b_expr.rightp);
+		p->b_expr.rightp = MKICON(0);
+		p3 = putop(p);
+	}
+	return p3;
+}
+
+LOCAL NODE *
+putcat(bigptr lhs, bigptr rhs)
+{
+	NODE *p3;
+	int n;
+	struct bigblock *lp, *cp;
+
+	n = ncat(rhs);
+	lp = mktmpn(n, TYLENG, NULL);
+	cp = mktmpn(n, TYADDR, NULL);
+
+	n = 0;
+	putct1(rhs, lp, cp, &n);
+
+	p3 = putx( call4(TYSUBR, "s_cat", lhs, cp, lp, MKICON(n) ) );
+	return p3;
+}
+
+LOCAL int
+ncat(bigptr p)
+{
+	if(p->tag==TEXPR && p->b_expr.opcode==OPCONCAT)
+		return( ncat(p->b_expr.leftp) + ncat(p->b_expr.rightp) );
+	else
+		return(1);
+}
+
+LOCAL void
+putct1(bigptr q, bigptr lp, bigptr cp, int *ip)
+{
+	NODE *p;
+	int i;
+	struct bigblock *lp1, *cp1;
+
+	if(q->tag==TEXPR && q->b_expr.opcode==OPCONCAT) {
+		putct1(q->b_expr.leftp, lp, cp, ip);
+		putct1(q->b_expr.rightp, lp, cp , ip);
+		frexpr(q->vleng);
+		ckfree(q);
+	} else {
+		i = (*ip)++;
+		lp1 = cpexpr(lp);
+		lp1->b_addr.memoffset =
+		    mkexpr(OPPLUS, lp1->b_addr.memoffset, MKICON(i*FSZLENG));
+		cp1 = cpexpr(cp);
+		cp1->b_addr.memoffset =
+		    mkexpr(OPPLUS, cp1->b_addr.memoffset, MKICON(i*FSZADDR));
+		p = putassign( lp1, cpexpr(q->vleng) );
+		sendp2(p);
+		p = putassign( cp1, addrof(putch1(q)) );
+		sendp2(p);
+	}
+}
+
+/*
+ * Create a tree that can later be converted to an OREG.
+ */
+static NODE *
+oregtree(int off, int reg, int type)
+{
+	NODE *p, *q;
+
+	p = mklnode(REG, 0, reg, INCREF(type));
+	q = mklnode(ICON, off, 0, INT);
+	return mkunode(UMUL, mkbinode(PLUS, p, q, INCREF(type)), 0, type);
+}
+
+static NODE *
+putaddr(bigptr q, int indir)
+{
+	int type, type2, funct;
+	NODE *p, *p1, *p2;
+	ftnint offset;
+	bigptr offp;
+
+	p = p1 = p2 = NULL; /* XXX */
+
+	type = q->vtype;
+	type2 = types2[type];
+	funct = (q->vclass==CLPROC ? FTN<<TSHIFT : 0);
+
+	offp = (q->b_addr.memoffset ? cpexpr(q->b_addr.memoffset) : NULL);
+
+	offset = simoffset(&offp);
+	if(offp)
+		offp = mkconv(TYINT, offp);
+
+	switch(q->vstg) {
+	case STGAUTO:
+		if(indir && !offp) {
+			p = oregtree(offset, AUTOREG, type2);
+			break;
+		}
+
+		if(!indir && !offp && !offset) {
+			p = mklnode(REG, 0, AUTOREG, INCREF(type2));
+			break;
+		}
+
+		p = mklnode(REG, 0, AUTOREG, INCREF(type2));
+		if(offp) {
+			p1 = putx(offp);
+			if(offset)
+				p2 = mklnode(ICON, offset, 0, INT);
+		} else
+			p1 = mklnode(ICON, offset, 0, INT);
+		if (offp && offset)
+			p1 = mkbinode(PLUS, p1, p2, INCREF(type2));
+		p = mkbinode(PLUS, p, p1, INCREF(type2));
+		if (indir)
+			p = mkunode(UMUL, p, 0, type2);
+		break;
+
+	case STGARG:
+		p = oregtree(ARGOFFSET + (ftnint)(q->b_addr.memno),
+		    ARGREG, INCREF(type2)|funct);
+
+		if (offp)
+			p1 = putx(offp);
+		if (offset)
+			p2 = mklnode(ICON, offset, 0, INT);
+		if (offp && offset)
+			p1 = mkbinode(PLUS, p1, p2, INCREF(type2));
+		else if (offset)
+			p1 = p2;
+		if (offp || offset)
+			p = mkbinode(PLUS, p, p1, INCREF(type2));
+		if (indir)
+			p = mkunode(UMUL, p, 0, type2);
+		break;
+
+	case STGLENG:
+		if(indir) {
+			p = oregtree(ARGOFFSET + (ftnint)(q->b_addr.memno),
+			    ARGREG, INCREF(type2)|funct);
+		} else	{
+			fatal1("faddrnode: STGLENG: fixme!");
+#if 0
+			p2op(P2PLUS, types2[TYLENG] | P2PTR );
+			p2reg(ARGREG, types2[TYLENG] | P2PTR );
+			p2icon( ARGOFFSET +
+				(ftnint) (FUDGEOFFSET*p->b_addr.memno), P2INT);
+#endif
+		}
+		break;
+
+
+	case STGBSS:
+	case STGINIT:
+	case STGEXT:
+	case STGCOMMON:
+	case STGEQUIV:
+	case STGCONST:
+		if(offp) {
+			p1 = putx(offp);
+			p2 = putmem(q, ICON, offset);
+			p = mkbinode(PLUS, p1, p2, INCREF(type2));
+			if(indir)
+				p = mkunode(UMUL, p, 0, type2);
+		} else
+			p = putmem(q, (indir ? NAME : ICON), offset);
+		break;
+
+	case STGREG:
+		if(indir)
+			p = mklnode(REG, 0, q->b_addr.memno, type2);
+		else
+			fatal("attempt to take address of a register");
+		break;
+
+	default:
+		fatal1("putaddr: invalid vstg %d", q->vstg);
+	}
+	frexpr(q);
+	return p;
+}
+
+NODE *
+putmem(bigptr q, int class, ftnint offset)
+{
+	NODE *p;
+	int type2;
+
+	type2 = types2[q->vtype];
+	if(q->vclass == CLPROC)
+		type2 |= (FTN<<TSHIFT);
+	if (class == ICON)
+		type2 |= PTR;
+	p = mklnode(class, offset, 0, type2);
+	p->n_name = copys(memname(q->vstg, q->b_addr.memno));
+	return p;
+}
+
+
+
+
+LOCAL struct bigblock *
+putcall(struct bigblock *qq)
+{
+	chainp arglist, charsp, cp;
+	int n, first;
+	struct bigblock *t;
+	struct bigblock *q;
+	struct bigblock *fval;
+	int type, type2, ctype, indir;
+	NODE *lp, *p1, *p2;
+
+	lp = p2 = NULL; /* XXX */
+
+	type2 = types2[type = qq->vtype];
+	charsp = NULL;
+	indir =  (qq->b_expr.opcode == OPCCALL);
+	n = 0;
+	first = YES;
+
+	if(qq->b_expr.rightp) {
+		arglist = qq->b_expr.rightp->b_list.listp;
+		ckfree(qq->b_expr.rightp);
+	} else
+		arglist = NULL;
+
+	for(cp = arglist ; cp ; cp = cp->chain.nextp)
+		if(indir) {
+			++n;
+		} else {
+			q = cp->chain.datap;
+			if(q->tag == TCONST)
+				cp->chain.datap = q = putconst(q);
+			if( ISCHAR(q) ) {
+				charsp = hookup(charsp,
+				    mkchain(cpexpr(q->vleng), 0) );
+				n += 2;
+			} else if(q->vclass == CLPROC) {
+				charsp = hookup(charsp,
+				    mkchain( MKICON(0) , 0));
+				n += 2;
+			} else
+				n += 1;
+		}
+
+	if(type == TYCHAR) {
+		if( ISICON(qq->vleng) ) {
+			fval = fmktemp(TYCHAR, qq->vleng);
+			n += 2;
+		} else {
+			err("adjustable character function");
+			return NULL;
+		}
+	} else if(ISCOMPLEX(type)) {
+		fval = fmktemp(type, NULL);
+		n += 1;
+	} else
+		fval = NULL;
+
+	ctype = (fval ? P2INT : type2);
+	p1 = putaddr(qq->b_expr.leftp, NO);
+
+	if(fval) {
+		first = NO;
+		lp = putaddr( cpexpr(fval), NO);
+		if(type==TYCHAR)
+			lp = mkbinode(CM, lp, putx(cpexpr(qq->vleng)), INT);
+	}
+
+	for(cp = arglist ; cp ; cp = cp->chain.nextp) {
+		q = cp->chain.datap;
+		if(q->tag==TADDR && (indir || q->vstg!=STGREG) )
+			p2 = putaddr(q, indir && q->vtype!=TYCHAR);
+		else if( ISCOMPLEX(q->vtype) )
+			p2 = putcxop(q);
+		else if (ISCHAR(q) ) {
+			p2 = putchop(q);
+		} else if( ! ISERROR(q) ) {
+			if(indir)
+				p2 = putx(q);
+			else	{
+				t = fmktemp(q->vtype, q->vleng);
+				p2 = putassign( cpexpr(t), q );
+				sendp2(p2);
+				p2 = putaddr(t, NO);
+			}
+		}
+		if(first) {
+			first = NO;
+			lp = p2;
+		} else
+			lp = mkbinode(CM, lp, p2, INT);
+	}
+
+	if(arglist)
+		frchain(&arglist);
+	for(cp = charsp ; cp ; cp = cp->chain.nextp) {
+		p2 = putx( mkconv(TYLENG,cp->chain.datap) );
+		lp = mkbinode(CM, lp, p2, INT);
+	}
+	frchain(&charsp);
+	if (n > 0)
+		callval = mkbinode(CALL, p1, lp, ctype);
+	else
+		callval = mkunode(UCALL, p1, 0, ctype);
+	ckfree(qq);
+	return(fval);
+}
+
+/*
+ * Write out code to do min/max calculations.
+ * Note that these operators may have multiple arguments in fortran.
+ */
+LOCAL NODE *
+putmnmx(struct bigblock *p)
+{
+	NODE *n1, *n2;
+	int op, type, lab;
+	chainp p0, p1;
+	struct bigblock *tp;
+
+	type = p->vtype;
+	op = (p->b_expr.opcode==OPMIN ? LT : GT );
+	p0 = p->b_expr.leftp->b_list.listp;
+	ckfree(p->b_expr.leftp);
+	ckfree(p);
+
+	/*
+	 * Store first value in a temporary, then compare it with 
+	 * each following value and save that if needed.
+	 */
+	tp = fmktemp(type, NULL);
+	sendp2(putassign(cpexpr(tp), p0->chain.datap));
+
+	for(p1 = p0->chain.nextp ; p1 ; p1 = p1->chain.nextp) {
+		n1 = putx(cpexpr(tp));
+		n2 = putx(cpexpr(p1->chain.datap));
+		lab = newlabel();
+		sendp2(mkbinode(CBRANCH, mkbinode(op, n1, n2, INT), 
+		    mklnode(ICON, lab, 0, INT), INT));
+		sendp2(putassign(cpexpr(tp), p1->chain.datap));
+		putlabel(lab);
+	}
+	return putx(tp);
+}
+
+ftnint
+simoffset(bigptr *p0)
+{
+	ftnint offset, prod;
+	bigptr p, lp, rp;
+
+	offset = 0;
+	p = *p0;
+	if(p == NULL)
+		return(0);
+
+	if( ! ISINT(p->vtype) )
+		return(0);
+
+	if(p->tag==TEXPR && p->b_expr.opcode==OPSTAR) {
+		lp = p->b_expr.leftp;
+		rp = p->b_expr.rightp;
+		if(ISICON(rp) && lp->tag==TEXPR &&
+		    lp->b_expr.opcode==OPPLUS && ISICON(lp->b_expr.rightp)) {
+			p->b_expr.opcode = OPPLUS;
+			lp->b_expr.opcode = OPSTAR;
+			prod = rp->b_const.fconst.ci *
+			    lp->b_expr.rightp->b_const.fconst.ci;
+			lp->b_expr.rightp->b_const.fconst.ci =
+			    rp->b_const.fconst.ci;
+			rp->b_const.fconst.ci = prod;
+		}
+	}
+
+	if(p->tag==TEXPR && p->b_expr.opcode==OPPLUS &&
+	    ISICON(p->b_expr.rightp)) {
+		rp = p->b_expr.rightp;
+		lp = p->b_expr.leftp;
+		offset += rp->b_const.fconst.ci;
+		frexpr(rp);
+		ckfree(p);
+		*p0 = lp;
+	}
+
+	if(p->tag == TCONST) {
+		offset += p->b_const.fconst.ci;
+		frexpr(p);
+		*p0 = NULL;
+	}
+
+	return(offset);
+}
+
+/*
+ * F77 uses ckalloc() (malloc) for NODEs.
+ */
+NODE *
+talloc()
+{
+	NODE *p = ckalloc(sizeof(NODE));
+	p->n_name = "";
+	return p;
+}
+
+#ifdef PCC_DEBUG
+static char *tagnam[] = {
+ "NONE", "NAME", "CONST", "EXPR", "ADDR", "PRIM", "LIST", "IMPLDO", "ERROR",
+};
+static char *typnam[] = {
+ "unknown", "addr", "short", "long", "real", "dreal", "complex", "dcomplex",
+ "logical", "char", "subr", "error",
+};
+static char *classnam[] = {
+ "unknown", "param", "var", "entry", "main", "block", "proc",
+};
+static char *stgnam[] = {
+ "unknown", "arg", "auto", "bss", "init", "const", "intr", "stfunct",
+ "common", "equiv", "reg", "leng",
+};
+
+
+/*
+ * Print out a f77 tree, for diagnostic purposes.
+ */
+void
+fprint(bigptr p, int indx)
+{
+	extern char *ops[];
+	int x = indx;
+	bigptr lp, rp;
+	struct chain *bp;
+
+	if (p == NULL)
+		return;
+
+	while (x >= 2) {
+		putchar('\t');
+		x -= 2;
+	}
+	if (x--)
+		printf("    " );
+	printf("%p) %s, ", p, tagnam[p->tag]);
+	if (p->vtype)
+		printf("type=%s, ", typnam[p->vtype]);
+	if (p->vclass)
+		printf("class=%s, ", classnam[p->vclass]);
+	if (p->vstg)
+		printf("stg=%s, ", stgnam[p->vstg]);
+
+	lp = rp = NULL;
+	switch (p->tag) {
+	case TEXPR:
+		printf("OP %s\n", ops[p->b_expr.opcode]);
+		lp = p->b_expr.leftp;
+		rp = p->b_expr.rightp;
+		break;
+	case TADDR:
+		printf("memno=%d\n", p->b_addr.memno);
+		lp = p->vleng;
+		rp = p->b_addr.memoffset;
+		break;
+	case TCONST:
+		switch (p->vtype) {
+		case TYSHORT:
+		case TYLONG:
+		case TYLOGICAL:
+		case TYADDR:
+			printf("val=%ld\n", p->b_const.fconst.ci);
+			break;
+		case TYCHAR:
+			lp = p->vleng;
+			printf("\n");
+			break;
+		}
+		break;
+	case TPRIM:
+		lp = p->b_prim.namep;
+		rp = p->b_prim.argsp;
+		printf("fcharp=%p, lcharp=%p\n", p->b_prim.fcharp, p->b_prim.lcharp);
+		break;
+	case TNAME:
+		printf("name=%s\n", p->b_name.varname);
+		break;
+	case TLIST:
+		printf("\n");
+		for (bp = &p->b_list.listp->chain; bp; bp = &bp->nextp->chain)
+			fprint(bp->datap, indx+1);
+		break;
+	default:
+		printf("\n");
+	}
+
+	fprint(lp, indx+1);
+	fprint(rp, indx+1);
+}
+#endif
Index: uspace/app/pcc/f77/fcom/scjdefs.h
===================================================================
--- uspace/app/pcc/f77/fcom/scjdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/scjdefs.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,37 @@
+/*
+ * Map pass2 nodes to pass1 dito.
+ */
+#include "node.h"
+
+
+#define P2BAD -1
+#define P2PLUS PLUS
+#define P2MINUS MINUS
+#define P2NEG UMINUS
+#define P2STAR MUL
+#define P2BITAND AND
+#define P2BITOR OR
+#define P2BITXOR ER
+#define P2GOTO GOTO
+#define P2ASSIGN ASSIGN
+#define P2SLASH DIV
+#define P2MOD MOD
+#define P2LSHIFT LS
+#define P2RSHIFT RS
+#define P2CALL CALL
+#define P2CALL0 UCALL
+
+#define P2BITNOT -1
+#define P2EQ EQ
+#define P2NE NE
+#define P2LE LE
+#define P2LT LT
+#define P2GE GE
+#define P2GT GT
+#define	P2CONV	SCONV
+
+/* special operators included only for fortran's use */
+
+#define P2INT INT
+
+#define P2PTR PTR
Index: uspace/app/pcc/f77/fcom/tokens
===================================================================
--- uspace/app/pcc/f77/fcom/tokens	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/f77/fcom/tokens	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,95 @@
+SEOS
+SCOMMENT
+SLABEL
+SUNKNOWN
+SHOLLERITH
+SICON
+SRCON
+SDCON
+SBITCON
+SOCTCON
+SHEXCON
+STRUE
+SFALSE
+SFNAME
+SNAMEEQ
+SFIELD
+SSCALE
+SINCLUDE
+SLET
+SASSIGN
+SAUTOMATIC
+SBACKSPACE
+SBLOCK
+SCALL
+SCHARACTER
+SCLOSE
+SCOMMON
+SCOMPLEX
+SCONTINUE
+SDATA
+SDCOMPLEX
+SDIMENSION
+SDO
+SDOUBLE
+SELSE
+SELSEIF
+SEND
+SENDFILE
+SENDIF
+SENTRY
+SEQUIV
+SEXTERNAL
+SFORMAT
+SFUNCTION
+SGOTO
+SASGOTO
+SCOMPGOTO
+SARITHIF
+SLOGIF
+SIMPLICIT
+SINQUIRE
+SINTEGER
+SINTRINSIC
+SLOGICAL
+SOPEN
+SPARAM
+SPAUSE
+SPRINT
+SPROGRAM
+SPUNCH
+SREAD
+SREAL
+SRETURN
+SREWIND
+SSAVE
+SSTATIC
+SSTOP
+SSUBROUTINE
+STHEN
+STO
+SUNDEFINED
+SWRITE
+SLPAR
+SRPAR
+SEQUALS
+SCOLON
+SCOMMA
+SCURRENCY
+SPLUS
+SMINUS
+SSTAR
+SSLASH
+SPOWER
+SCONCAT
+SAND
+SOR
+SNEQV
+SEQV
+SNOT
+SEQ
+SLT
+SGT
+SLE
+SGE
+SNE
Index: uspace/app/pcc/install-sh
===================================================================
--- uspace/app/pcc/install-sh	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/install-sh	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,294 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+#
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd=$cpprog
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd=$stripprog
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "$0: no input file specified" >&2
+	exit 1
+else
+	:
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+
+	if [ -d "$dst" ]; then
+		instcmd=:
+		chmodcmd=""
+	else
+		instcmd=$mkdirprog
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f "$src" ] || [ -d "$src" ]
+	then
+		:
+	else
+		echo "$0: $src does not exist" >&2
+		exit 1
+	fi
+
+	if [ x"$dst" = x ]
+	then
+		echo "$0: no destination specified" >&2
+		exit 1
+	else
+		:
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d "$dst" ]
+	then
+		dst=$dst/`basename "$src"`
+	else
+		:
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+	'
+IFS="${IFS-$defaultIFS}"
+
+oIFS=$IFS
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS=$oIFS
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp=$pathcomp$1
+	shift
+
+	if [ ! -d "$pathcomp" ] ;
+        then
+		$mkdirprog "$pathcomp"
+	else
+		:
+	fi
+
+	pathcomp=$pathcomp/
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd "$dst" &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ]
+	then
+		dstfile=`basename "$dst"`
+	else
+		dstfile=`basename "$dst" $transformbasename |
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ]
+	then
+		dstfile=`basename "$dst"`
+	else
+		:
+	fi
+
+# Make a couple of temp file names in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+	rmtmp=$dstdir/#rm.$$#
+
+# Trap to clean up temp files at exit.
+
+	trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
+	trap '(exit $?); exit' 1 2 13 15
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd "$src" "$dsttmp" &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi &&
+
+# Now remove or move aside any old file at destination location.  We try this
+# two ways since rm can't unlink itself on some systems and the destination
+# file might be busy for other reasons.  In this case, the final cleanup
+# might fail but the new file should still install successfully.
+
+{
+	if [ -f "$dstdir/$dstfile" ]
+	then
+		$doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null ||
+		$doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null ||
+		{
+		  echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+		  (exit 1); exit
+		}
+	else
+		:
+	fi
+} &&
+
+# Now rename the file to the real destination.
+
+	$doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+
+fi &&
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+
+{
+	(exit 0); exit
+}
Index: uspace/app/pcc/mip/common.c
===================================================================
--- uspace/app/pcc/mip/common.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/mip/common.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,784 @@
+/*	$Id: common.c,v 1.93 2011/01/22 22:08:23 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pass2.h"
+
+# ifndef EXIT
+# define EXIT exit
+# endif
+
+int nerrors = 0;  /* number of errors */
+extern char *ftitle;
+int lineno;
+
+int warniserr = 0;
+
+#ifndef WHERE
+#define	WHERE(ch) fprintf(stderr, "%s, line %d: ", ftitle, lineno);
+#endif
+
+static void
+incerr(void)
+{
+	if (++nerrors > 30)
+		cerror("too many errors");
+}
+
+/*
+ * nonfatal error message
+ * the routine where is different for pass 1 and pass 2;
+ * it tells where the error took place
+ */
+void
+uerror(char *s, ...)
+{
+	va_list ap;
+
+	va_start(ap, s);
+	WHERE('u');
+	vfprintf(stderr, s, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+	incerr();
+}
+
+/*
+ * compiler error: die
+ */
+void
+cerror(char *s, ...)
+{
+	va_list ap;
+
+	va_start(ap, s);
+	WHERE('c');
+
+	/* give the compiler the benefit of the doubt */
+	if (nerrors && nerrors <= 30) {
+		fprintf(stderr,
+		    "cannot recover from earlier errors: goodbye!\n");
+	} else {
+		fprintf(stderr, "compiler error: ");
+		vfprintf(stderr, s, ap);
+		fprintf(stderr, "\n");
+	}
+	va_end(ap);
+	EXIT(1);
+}
+
+/*
+ * warning
+ */
+void
+werror(char *s, ...)
+{
+	va_list ap;
+
+	va_start(ap, s);
+	WHERE('w');
+	fprintf(stderr, "warning: ");
+	vfprintf(stderr, s, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+	if (warniserr)
+		incerr();
+}
+
+#ifndef MKEXT
+
+bittype warnary[(NUMW/NUMBITS)+1], werrary[(NUMW/NUMBITS)+1];
+
+static char *warntxt[] = {
+	"conversion to '%s' from '%s' may alter its value",
+	"function declaration isn't a prototype", /* Wstrict_prototypes */
+	"no previous prototype for `%s'", /* Wmissing_prototypes */
+	"return type defaults to `int'", /* Wimplicit_int */
+		 /* Wimplicit_function_declaration */
+	"implicit declaration of function '%s'",
+	"declaration of '%s' shadows a %s declaration", /* Wshadow */
+	"illegal pointer combination", /* Wpointer_sign */
+	"comparison between signed and unsigned", /* Wsign_compare */
+	"ignoring #pragma %s %s", /* Wunknown_pragmas */
+	"statement not reached", /* Wunreachable_code */
+};
+
+char *flagstr[] = {
+	"truncate", "strict-prototypes", "missing-prototypes", 
+	"implicit-int", "implicit-function-declaration", "shadow", 
+	"pointer-sign", "sign-compare", "unknown-pragmas", 
+	"unreachable-code", 
+};
+
+/*
+ * "emulate" the gcc warning flags.
+ */
+void
+Wflags(char *str)
+{
+	int i, flagval;
+
+	if (strncmp("no-", str, 3) == 0) {
+		str += 3;
+		flagval = 0;
+	} else
+		flagval = 1;
+	if (strcmp(str, "error") == 0) {
+		/* special */
+		for (i = 0; i < NUMW; i++)
+			BITSET(werrary, i);
+		return;
+	}
+	for (i = 0; i < NUMW; i++) {
+		if (strcmp(flagstr[i], str) != 0)
+			continue;
+		if (flagval)
+			BITSET(warnary, i);
+		else
+			BITCLEAR(warnary, i);
+		return;
+	}
+	fprintf(stderr, "unrecognised warning option '%s'\n", str);
+}
+
+/*
+ * Deal with gcc warnings.
+ */
+void
+warner(int type, ...)
+{
+	va_list ap;
+	char *w;
+
+	if (TESTBIT(warnary, type) == 0)
+		return; /* no warning */
+	if (TESTBIT(werrary, type)) {
+		w = "error";
+		incerr();
+	} else
+		w = "warning";
+
+	va_start(ap, type);
+	fprintf(stderr, "%s:%d: %s: ", ftitle, lineno, w);
+	vfprintf(stderr, warntxt[type], ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+}
+#endif /* MKEXT */
+
+#ifndef MKEXT
+static NODE *freelink;
+static int usednodes;
+
+#ifndef LANG_F77
+NODE *
+talloc()
+{
+	register NODE *p;
+
+	usednodes++;
+
+	if (freelink != NULL) {
+		p = freelink;
+		freelink = p->next;
+		if (p->n_op != FREE)
+			cerror("node not FREE: %p", p);
+		if (nflag)
+			printf("alloc node %p from freelist\n", p);
+		return p;
+	}
+
+	p = permalloc(sizeof(NODE));
+	p->n_op = FREE;
+	if (nflag)
+		printf("alloc node %p from memory\n", p);
+	return p;
+}
+#endif
+
+/*
+ * make a fresh copy of p
+ */
+NODE *
+tcopy(NODE *p)
+{
+	NODE *q;
+
+	q = talloc();
+	*q = *p;
+
+	switch (optype(q->n_op)) {
+	case BITYPE:
+		q->n_right = tcopy(p->n_right);
+	case UTYPE:
+		q->n_left = tcopy(p->n_left);
+	}
+
+	return(q);
+}
+
+#ifndef LANG_F77
+/*
+ * ensure that all nodes have been freed
+ */
+void
+tcheck()
+{
+	extern int inlnodecnt;
+
+	if (nerrors)
+		return;
+
+	if ((usednodes - inlnodecnt) != 0)
+		cerror("usednodes == %d, inlnodecnt %d", usednodes, inlnodecnt);
+}
+#endif
+
+/*
+ * free the tree p
+ */
+void
+tfree(NODE *p)
+{
+	if (p->n_op != FREE)
+		walkf(p, (void (*)(NODE *, void *))nfree, 0);
+}
+
+/*
+ * Free a node, and return its left descendant.
+ * It is up to the caller to know whether the return value is usable.
+ */
+NODE *
+nfree(NODE *p)
+{
+	NODE *l;
+#ifdef PCC_DEBUG_NODES
+	NODE *q;
+#endif
+
+	if (p == NULL)
+		cerror("freeing blank node!");
+		
+	l = p->n_left;
+	if (p->n_op == FREE)
+		cerror("freeing FREE node", p);
+#ifdef PCC_DEBUG_NODES
+	q = freelink;
+	while (q != NULL) {
+		if (q == p)
+			cerror("freeing free node %p", p);
+		q = q->next;
+	}
+#endif
+
+	if (nflag)
+		printf("freeing node %p\n", p);
+	p->n_op = FREE;
+	p->next = freelink;
+	freelink = p;
+	usednodes--;
+	return l;
+}
+#endif
+
+#ifdef LANG_F77
+#define OPTYPE(x) optype(x)
+#else
+#define OPTYPE(x) coptype(x)
+#endif
+
+#ifdef MKEXT
+#define coptype(o)	(dope[o]&TYFLG)
+#else
+int cdope(int);
+#define coptype(o)	(cdope(o)&TYFLG)
+#endif
+
+void
+fwalk(NODE *t, void (*f)(NODE *, int, int *, int *), int down)
+{
+
+	int down1, down2;
+
+	more:
+	down1 = down2 = 0;
+
+	(*f)(t, down, &down1, &down2);
+
+	switch (OPTYPE( t->n_op )) {
+
+	case BITYPE:
+		fwalk( t->n_left, f, down1 );
+		t = t->n_right;
+		down = down2;
+		goto more;
+
+	case UTYPE:
+		t = t->n_left;
+		down = down1;
+		goto more;
+
+	}
+}
+
+void
+walkf(NODE *t, void (*f)(NODE *, void *), void *arg)
+{
+	int opty;
+
+
+	opty = OPTYPE(t->n_op);
+
+	if (opty != LTYPE)
+		walkf( t->n_left, f, arg );
+	if (opty == BITYPE)
+		walkf( t->n_right, f, arg );
+	(*f)(t, arg);
+}
+
+int dope[DSIZE];
+char *opst[DSIZE];
+
+struct dopest {
+	int dopeop;
+	char opst[8];
+	int dopeval;
+} indope[] = {
+	{ NAME, "NAME", LTYPE, },
+	{ REG, "REG", LTYPE, },
+	{ OREG, "OREG", LTYPE, },
+	{ TEMP, "TEMP", LTYPE, },
+	{ ICON, "ICON", LTYPE, },
+	{ FCON, "FCON", LTYPE, },
+	{ CCODES, "CCODES", LTYPE, },
+	{ UMINUS, "U-", UTYPE, },
+	{ UMUL, "U*", UTYPE, },
+	{ FUNARG, "FUNARG", UTYPE, },
+	{ UCALL, "UCALL", UTYPE|CALLFLG, },
+	{ UFORTCALL, "UFCALL", UTYPE|CALLFLG, },
+	{ COMPL, "~", UTYPE, },
+	{ FORCE, "FORCE", UTYPE, },
+	{ XARG, "XARG", UTYPE, },
+	{ XASM, "XASM", BITYPE, },
+	{ SCONV, "SCONV", UTYPE, },
+	{ PCONV, "PCONV", UTYPE, },
+	{ PLUS, "+", BITYPE|FLOFLG|SIMPFLG|COMMFLG, },
+	{ MINUS, "-", BITYPE|FLOFLG|SIMPFLG, },
+	{ MUL, "*", BITYPE|FLOFLG|MULFLG, },
+	{ AND, "&", BITYPE|SIMPFLG|COMMFLG, },
+	{ CM, ",", BITYPE, },
+	{ ASSIGN, "=", BITYPE|ASGFLG, },
+	{ DIV, "/", BITYPE|FLOFLG|MULFLG|DIVFLG, },
+	{ MOD, "%", BITYPE|DIVFLG, },
+	{ LS, "<<", BITYPE|SHFFLG, },
+	{ RS, ">>", BITYPE|SHFFLG, },
+	{ OR, "|", BITYPE|COMMFLG|SIMPFLG, },
+	{ ER, "^", BITYPE|COMMFLG|SIMPFLG, },
+	{ STREF, "->", BITYPE, },
+	{ CALL, "CALL", BITYPE|CALLFLG, },
+	{ FORTCALL, "FCALL", BITYPE|CALLFLG, },
+	{ EQ, "==", BITYPE|LOGFLG, },
+	{ NE, "!=", BITYPE|LOGFLG, },
+	{ LE, "<=", BITYPE|LOGFLG, },
+	{ LT, "<", BITYPE|LOGFLG, },
+	{ GE, ">=", BITYPE|LOGFLG, },
+	{ GT, ">", BITYPE|LOGFLG, },
+	{ UGT, "UGT", BITYPE|LOGFLG, },
+	{ UGE, "UGE", BITYPE|LOGFLG, },
+	{ ULT, "ULT", BITYPE|LOGFLG, },
+	{ ULE, "ULE", BITYPE|LOGFLG, },
+	{ CBRANCH, "CBRANCH", BITYPE, },
+	{ FLD, "FLD", UTYPE, },
+	{ PMCONV, "PMCONV", BITYPE, },
+	{ PVCONV, "PVCONV", BITYPE, },
+	{ RETURN, "RETURN", BITYPE|ASGFLG|ASGOPFLG, },
+	{ GOTO, "GOTO", UTYPE, },
+	{ STASG, "STASG", BITYPE|ASGFLG, },
+	{ STARG, "STARG", UTYPE, },
+	{ STCALL, "STCALL", BITYPE|CALLFLG, },
+	{ USTCALL, "USTCALL", UTYPE|CALLFLG, },
+	{ ADDROF, "U&", UTYPE, },
+
+	{ -1,	"",	0 },
+};
+
+void
+mkdope()
+{
+	struct dopest *q;
+
+	for( q = indope; q->dopeop >= 0; ++q ){
+		dope[q->dopeop] = q->dopeval;
+		opst[q->dopeop] = q->opst;
+	}
+}
+
+/*
+ * output a nice description of the type of t
+ */
+void
+tprint(FILE *fp, TWORD t, TWORD q)
+{
+	static char * tnames[] = {
+		"undef",
+		"farg",
+		"char",
+		"uchar",
+		"short",
+		"ushort",
+		"int",
+		"unsigned",
+		"long",
+		"ulong",
+		"longlong",
+		"ulonglong",
+		"float",
+		"double",
+		"ldouble",
+		"strty",
+		"unionty",
+		"enumty",
+		"moety",
+		"void",
+		"signed", /* pass1 */
+		"bool", /* pass1 */
+		"fimag", /* pass1 */
+		"dimag", /* pass1 */
+		"limag", /* pass1 */
+		"fcomplex", /* pass1 */
+		"dcomplex", /* pass1 */
+		"lcomplex", /* pass1 */
+		"enumty", /* pass1 */
+		"?", "?"
+		};
+
+	for(;; t = DECREF(t), q = DECREF(q)) {
+		if (ISCON(q))
+			fputc('C', fp);
+		if (ISVOL(q))
+			fputc('V', fp);
+
+		if (ISPTR(t))
+			fprintf(fp, "PTR ");
+		else if (ISFTN(t))
+			fprintf(fp, "FTN ");
+		else if (ISARY(t))
+			fprintf(fp, "ARY ");
+		else {
+			fprintf(fp, "%s%s%s", ISCON(q << TSHIFT) ? "const " : "",
+			    ISVOL(q << TSHIFT) ? "volatile " : "", tnames[t]);
+			return;
+		}
+	}
+}
+
+/*
+ * Memory allocation routines.
+ * Memory are allocated from the system in MEMCHUNKSZ blocks.
+ * permalloc() returns a bunch of memory that is never freed.
+ * Memory allocated through tmpalloc() will be released the
+ * next time a function is ended (via tmpfree()).
+ */
+
+#define	MEMCHUNKSZ 8192	/* 8k per allocation */
+struct balloc {
+	char a1;
+	union {
+		long long l;
+		long double d;
+	} a2;
+};
+
+#define ALIGNMENT ((long)&((struct balloc *)0)->a2)
+#define	ROUNDUP(x) (((x) + ((ALIGNMENT)-1)) & ~((ALIGNMENT)-1))
+
+static char *allocpole;
+static int allocleft;
+int permallocsize, tmpallocsize, lostmem;
+
+void *
+permalloc(int size)
+{
+	void *rv;
+
+	if (size > MEMCHUNKSZ) {
+		if ((rv = malloc(size)) == NULL)
+			cerror("permalloc: missing %d bytes", size);
+		return rv;
+	}
+	if (size <= 0)
+		cerror("permalloc2");
+	if (allocleft < size) {
+		/* looses unused bytes */
+		lostmem += allocleft;
+		if ((allocpole = malloc(MEMCHUNKSZ)) == NULL)
+			cerror("permalloc: out of memory");
+		allocleft = MEMCHUNKSZ;
+	}
+	size = ROUNDUP(size);
+	rv = &allocpole[MEMCHUNKSZ-allocleft];
+	allocleft -= size;
+	permallocsize += size;
+	return rv;
+}
+
+void *
+tmpcalloc(int size)
+{
+	void *rv;
+
+	rv = tmpalloc(size);
+	memset(rv, 0, size);
+	return rv;
+}
+
+/*
+ * Duplicate a string onto the temporary heap.
+ */
+char *
+tmpstrdup(char *str)
+{
+	int len;
+
+	len = strlen(str) + 1;
+	return memcpy(tmpalloc(len), str, len);
+}
+
+/*
+ * Allocation routines for temporary memory.
+ */
+#if 0
+#define	ALLDEBUG(x)	printf x
+#else
+#define	ALLDEBUG(x)
+#endif
+
+#define	NELEM	((MEMCHUNKSZ-ROUNDUP(sizeof(struct xalloc *)))/ALIGNMENT)
+#define	ELEMSZ	(ALIGNMENT)
+#define	MAXSZ	(NELEM*ELEMSZ)
+struct xalloc {
+	struct xalloc *next;
+	union {
+		struct balloc b; /* for initial alignment */
+		char elm[MAXSZ];
+	} u;
+} *tapole, *tmpole;
+int uselem = NELEM; /* next unused element */
+
+void *
+tmpalloc(int size)
+{
+	struct xalloc *xp;
+	void *rv;
+	size_t nelem;
+
+	nelem = ROUNDUP(size)/ELEMSZ;
+	ALLDEBUG(("tmpalloc(%ld,%ld) %d (%zd) ", ELEMSZ, NELEM, size, nelem));
+	if (nelem > NELEM/2) {
+		xp = malloc(size + ROUNDUP(sizeof(struct xalloc *)));
+		if (xp == NULL)
+			cerror("out of memory");
+		ALLDEBUG(("XMEM! (%ld,%p) ",
+		    size + ROUNDUP(sizeof(struct xalloc *)), xp));
+		xp->next = tmpole;
+		tmpole = xp;
+		ALLDEBUG(("rv %p\n", &xp->u.elm[0]));
+		return &xp->u.elm[0];
+	}
+	if (nelem + uselem >= NELEM) {
+		ALLDEBUG(("MOREMEM! "));
+		/* alloc more */
+		if ((xp = malloc(sizeof(struct xalloc))) == NULL)
+			cerror("out of memory");
+		xp->next = tapole;
+		tapole = xp;
+		uselem = 0;
+	} else
+		xp = tapole;
+	rv = &xp->u.elm[uselem * ELEMSZ];
+	ALLDEBUG(("elemno %d ", uselem));
+	uselem += nelem;
+	ALLDEBUG(("new %d rv %p\n", uselem, rv));
+	return rv;
+}
+
+void
+tmpfree()
+{
+	struct xalloc *x1;
+
+	while (tmpole) {
+		x1 = tmpole;
+		tmpole = tmpole->next;
+		ALLDEBUG(("XMEM! free %p\n", x1));
+		free(x1);
+	}
+	while (tapole && tapole->next) {
+		x1 = tapole;
+		tapole = tapole->next;
+		ALLDEBUG(("MOREMEM! free %p\n", x1));
+		free(x1);
+	}
+	if (tapole)
+		uselem = 0;
+}
+
+/*
+ * Set a mark for later removal from the temp heap.
+ */
+void
+markset(struct mark *m)
+{
+	m->tmsav = tmpole;
+	m->tasav = tapole;
+	m->elem = uselem;
+}
+
+/*
+ * Remove everything on tmp heap from a mark.
+ */
+void
+markfree(struct mark *m)
+{
+	struct xalloc *x1;
+
+	while (tmpole != m->tmsav) {
+		x1 = tmpole;
+		tmpole = tmpole->next;
+		free(x1);
+	}
+	while (tapole != m->tasav) {
+		x1 = tapole;
+		tapole = tapole->next;
+		free(x1);
+	}
+	uselem = m->elem;
+}
+
+/*
+ * Allocate space on the permanent stack for a string of length len+1
+ * and copy it there.
+ * Return the new address.
+ */
+char *
+newstring(char *s, int len)
+{
+	char *u, *c;
+
+	len++;
+	if (allocleft < len) {
+		u = c = permalloc(len);
+	} else {
+		u = c = &allocpole[MEMCHUNKSZ-allocleft];
+		allocleft -= ROUNDUP(len+1);
+	}
+	while (len--)
+		*c++ = *s++;
+	return u;
+}
+
+/*
+ * Do a preorder walk of the CM list p and apply function f on each element.
+ */
+void
+flist(NODE *p, void (*f)(NODE *, void *), void *arg)
+{
+	if (p->n_op == CM) {
+		(*f)(p->n_right, arg);
+		flist(p->n_left, f, arg);
+	} else
+		(*f)(p, arg);
+}
+
+/*
+ * The same as flist but postorder.
+ */
+void
+listf(NODE *p, void (*f)(NODE *))
+{
+	if (p->n_op == CM) {
+		listf(p->n_left, f);
+		(*f)(p->n_right);
+	} else
+		(*f)(p);
+}
+
+/*
+ * Get list argument number n from list, or NIL if out of list.
+ */
+NODE *
+listarg(NODE *p, int n, int *cnt)
+{
+	NODE *r;
+
+	if (p->n_op == CM) {
+		r = listarg(p->n_left, n, cnt);
+		if (n == ++(*cnt))
+			r = p->n_right;
+	} else {
+		*cnt = 0;
+		r = n == 0 ? p : NIL;
+	}
+	return r;
+}
Index: uspace/app/pcc/mip/compat.c
===================================================================
--- uspace/app/pcc/mip/compat.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/mip/compat.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,922 @@
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: compat.c,v 1.9 2010/02/25 15:31:40 ragge Exp $
+ */
+
+/*-
+ * Copyright (c) 1997, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Klaus Klein and Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	$NetBSD: basename.c,v 1.9 2009/11/24 13:34:20 tnozaki Exp $
+ */
+
+/*
+ * Copyright (c) 1987, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	$NetBSD: gettemp.c,v 1.13 2003/12/05 00:57:36 uebayasi Exp $
+ */
+
+#include <string.h>
+#include <fcntl.h>
+
+#include "config.h"
+#define MKEXT	/* XXX */
+#include "manifest.h"
+
+#ifndef HAVE_STRLCAT
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(initial dst) + strlen(src); if retval >= siz,
+ * truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+	char *d = dst;
+	const char *s = src;
+	size_t n = siz;
+	size_t dlen;
+
+	/* Find the end of dst and adjust bytes left but don't go past end */
+	while (n-- != 0 && *d != '\0')
+		d++;
+	dlen = d - dst;
+	n = siz - dlen;
+
+	if (n == 0)
+		return(dlen + strlen(s));
+	while (*s != '\0') {
+		if (n != 1) {
+			*d++ = *s;
+			n--;
+		}
+		s++;
+	}
+	*d = '\0';
+
+	return(dlen + (s - src));	/* count does not include NUL */
+}
+#endif
+
+
+#ifndef HAVE_STRLCPY
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+	char *d = dst;
+	const char *s = src;
+	size_t n = siz;
+
+	/* Copy as many bytes as will fit */
+	if (n != 0 && --n != 0) {
+		do {
+			if ((*d++ = *s++) == 0)
+				break;
+		} while (--n != 0);
+	}
+
+	/* Not enough room in dst, add NUL and traverse rest of src */
+	if (n == 0) {
+		if (siz != 0)
+			*d = '\0';	/* NUL-terminate dst */
+		while (*s++)
+			;
+	}
+
+	return(s - src - 1);	/* count does not include NUL */
+}
+#endif
+
+#ifndef HAVE_GETOPT
+char *optarg;
+int optind = 1;
+int
+getopt(int argc, char **argv, char *args)
+{
+        int n;
+	int nlen = strlen(args);
+        char cmd;
+        char rv;
+
+        if (argv[optind] && *argv[optind] == '-') {
+                cmd = *(argv[optind] + 1);
+
+                for (n = 0; n < nlen; n++) {
+                        if (args[n] == ':')
+				continue;
+                        if (args[n] == cmd) {
+                                rv = *(argv[optind] + 1);
+                                if (args[n+1] == ':') {
+					if (*(argv[optind] + 2) != '\0') {
+	                                        optarg = argv[optind] + 2;
+						optind += 1;
+					} else {
+	                                        optarg = argv[optind + 1];
+                                        	optind += 2;
+					}
+                                        if (!optarg)
+						 optarg="";
+                                        return rv;
+                                } else {
+                                        optarg = NULL;
+                                        optind += 1;
+                                        return rv;
+                                }
+                        }
+                }       
+        }
+
+        return -1;
+}
+#endif
+
+#ifdef WIN32
+#define ISPATHSEPARATOR(x) ((x == '/') || (x == '\\'))
+#else
+#define ISPATHSEPARATOR(x) (x == '/')
+#endif
+
+#ifndef HAVE_BASENAME
+#ifndef PATH_MAX
+#define PATH_MAX 5000
+#endif
+
+char *
+basename(char *path)
+{
+	static char result[PATH_MAX];
+	char *p, *lastp;
+	size_t len;
+
+	/*
+	 * If `path' is a null pointer or points to an empty string,
+	 * return a pointer to the string ".".
+	 */
+	if ((path == NULL) || (*path == '\0')) {
+		result[0] = '.';
+		result[1] = '\0';
+
+		return (result);
+	}
+
+	/* Strip trailing slashes, if any. */
+	lastp = path + strlen(path) - 1;
+	while (lastp != path && ISPATHSEPARATOR(*lastp))
+		lastp--;
+
+	/* Now find the beginning of this (final) component. */
+	p = lastp;
+	while (p != path && !ISPATHSEPARATOR(*(p - 1)))
+		p--;
+
+	/* ...and copy the result into the result buffer. */
+	len = (lastp - p) + 1 /* last char */;
+	if (len > (PATH_MAX - 1))
+		len = PATH_MAX - 1;
+
+	memcpy(result, p, len);
+	result[len] = '\0';
+
+	return (result);
+}
+#endif
+
+#if !defined(HAVE_MKSTEMP) && !defined(WIN32)
+int
+mkstemp(char *path)
+{
+	char *start, *trv;
+	unsigned int pid;
+
+	/* To guarantee multiple calls generate unique names even if
+	   the file is not created. 676 different possibilities with 7
+	   or more X's, 26 with 6 or less. */
+	static char xtra[2] = "aa";
+	int xcnt = 0;
+
+	pid = getpid();
+
+	/* Move to end of path and count trailing X's. */
+	for (trv = path; *trv; ++trv)
+		if (*trv == 'X')
+			xcnt++;
+		else
+			xcnt = 0;
+
+	/* Use at least one from xtra.  Use 2 if more than 6 X's. */
+	if (*(trv - 1) == 'X')
+		*--trv = xtra[0];
+	if (xcnt > 6 && *(trv - 1) == 'X')
+		*--trv = xtra[1];
+
+	/* Set remaining X's to pid digits with 0's to the left. */
+	while (*--trv == 'X') {
+		*trv = (pid % 10) + '0';
+		pid /= 10;
+	}
+
+	/* update xtra for next call. */
+	if (xtra[0] != 'z')
+		xtra[0]++;
+	else {
+		xtra[0] = 'a';
+		if (xtra[1] != 'z')
+			xtra[1]++;
+		else
+			xtra[1] = 'a';
+	}
+
+	return open(path, O_CREAT | O_EXCL | O_RDWR, 0600);
+}
+#endif
+
+#ifndef HAVE_FFS
+int
+ffs(int x) 
+{ 
+	int r = 1;
+	if (!x) return 0; 
+	if (!(x & 0xffff)) { x >>= 16; r += 16; }
+	if (!(x &   0xff)) { x >>= 8;  r += 8;  }
+	if (!(x &    0xf)) { x >>= 4;  r += 4;  }
+	if (!(x &      3)) { x >>= 2;  r += 2;  }
+	if (!(x &      1)) { x >>= 1;  r += 1;  }
+
+	return r; 
+}
+#endif
+
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell@astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
+
+static void 
+dopr(char *buffer, size_t maxlen, const char *format, va_list args);
+
+static void 
+fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, 
+    int min, int max);
+
+static void 
+fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, 
+    int min, int max, int flags);
+
+static void 
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
+    int min, int max, int flags);
+
+static void
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS   1
+#define DP_S_MIN     2
+#define DP_S_DOT     3
+#define DP_S_MAX     4
+#define DP_S_MOD     5
+#define DP_S_CONV    6
+#define DP_S_DONE    7
+
+/* format flags - Bits */
+#define DP_F_MINUS 	(1 << 0)
+#define DP_F_PLUS  	(1 << 1)
+#define DP_F_SPACE 	(1 << 2)
+#define DP_F_NUM   	(1 << 3)
+#define DP_F_ZERO  	(1 << 4)
+#define DP_F_UP    	(1 << 5)
+#define DP_F_UNSIGNED 	(1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT     1
+#define DP_C_LONG      2
+#define DP_C_LDOUBLE   3
+#define DP_C_LONG_LONG 4
+
+#define char_to_int(p) (p - '0')
+#define abs_val(p) (p < 0 ? -p : p)
+
+
+static void 
+dopr(char *buffer, size_t maxlen, const char *format, va_list args)
+{
+	char *strvalue, ch;
+	long value;
+	long double fvalue;
+	int min = 0, max = -1, state = DP_S_DEFAULT, flags = 0, cflags = 0;
+	size_t currlen = 0;
+  
+	ch = *format++;
+
+	while (state != DP_S_DONE) {
+		if ((ch == '\0') || (currlen >= maxlen)) 
+			state = DP_S_DONE;
+
+		switch(state) {
+		case DP_S_DEFAULT:
+			if (ch == '%') 
+				state = DP_S_FLAGS;
+			else 
+				dopr_outch(buffer, &currlen, maxlen, ch);
+			ch = *format++;
+			break;
+		case DP_S_FLAGS:
+			switch (ch) {
+			case '-':
+				flags |= DP_F_MINUS;
+				ch = *format++;
+				break;
+			case '+':
+				flags |= DP_F_PLUS;
+				ch = *format++;
+				break;
+			case ' ':
+				flags |= DP_F_SPACE;
+				ch = *format++;
+				break;
+			case '#':
+				flags |= DP_F_NUM;
+				ch = *format++;
+				break;
+			case '0':
+				flags |= DP_F_ZERO;
+				ch = *format++;
+				break;
+			default:
+				state = DP_S_MIN;
+				break;
+			}
+			break;
+		case DP_S_MIN:
+			if (isdigit((unsigned char)ch)) {
+				min = 10 * min + char_to_int (ch);
+				ch = *format++;
+			} else if (ch == '*') {
+				min = va_arg (args, int);
+				ch = *format++;
+				state = DP_S_DOT;
+			} else 
+				state = DP_S_DOT;
+			break;
+		case DP_S_DOT:
+			if (ch == '.') {
+				state = DP_S_MAX;
+				ch = *format++;
+			} else 
+				state = DP_S_MOD;
+			break;
+		case DP_S_MAX:
+			if (isdigit((unsigned char)ch)) {
+				if (max < 0)
+					max = 0;
+				max = 10 * max + char_to_int(ch);
+				ch = *format++;
+			} else if (ch == '*') {
+				max = va_arg (args, int);
+				ch = *format++;
+				state = DP_S_MOD;
+			} else 
+				state = DP_S_MOD;
+			break;
+		case DP_S_MOD:
+			switch (ch) {
+			case 'h':
+				cflags = DP_C_SHORT;
+				ch = *format++;
+				break;
+			case 'l':
+				cflags = DP_C_LONG;
+				ch = *format++;
+				if (ch == 'l') {
+					cflags = DP_C_LONG_LONG;
+					ch = *format++;
+				}
+				break;
+			case 'q':
+				cflags = DP_C_LONG_LONG;
+				ch = *format++;
+				break;
+			case 'L':
+				cflags = DP_C_LDOUBLE;
+				ch = *format++;
+				break;
+			default:
+				break;
+			}
+			state = DP_S_CONV;
+			break;
+		case DP_S_CONV:
+			switch (ch) {
+			case 'd':
+			case 'i':
+				if (cflags == DP_C_SHORT) 
+					value = va_arg(args, int);
+				else if (cflags == DP_C_LONG)
+					value = va_arg(args, long int);
+				else if (cflags == DP_C_LONG_LONG)
+					value = va_arg (args, long long);
+				else
+					value = va_arg (args, int);
+				fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
+				break;
+			case 'o':
+				flags |= DP_F_UNSIGNED;
+				if (cflags == DP_C_SHORT)
+					value = va_arg(args, unsigned int);
+				else if (cflags == DP_C_LONG)
+					value = va_arg(args, unsigned long int);
+				else if (cflags == DP_C_LONG_LONG)
+					value = va_arg(args, unsigned long long);
+				else
+					value = va_arg(args, unsigned int);
+				fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
+				break;
+			case 'u':
+				flags |= DP_F_UNSIGNED;
+				if (cflags == DP_C_SHORT)
+					value = va_arg(args, unsigned int);
+				else if (cflags == DP_C_LONG)
+					value = va_arg(args, unsigned long int);
+				else if (cflags == DP_C_LONG_LONG)
+					value = va_arg(args, unsigned long long);
+				else
+					value = va_arg(args, unsigned int);
+				fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+				break;
+			case 'X':
+				flags |= DP_F_UP;
+			case 'x':
+				flags |= DP_F_UNSIGNED;
+				if (cflags == DP_C_SHORT)
+					value = va_arg(args, unsigned int);
+				else if (cflags == DP_C_LONG)
+					value = va_arg(args, unsigned long int);
+				else if (cflags == DP_C_LONG_LONG)
+					value = va_arg(args, unsigned long long);
+				else
+					value = va_arg(args, unsigned int);
+				fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
+				break;
+			case 'f':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, long double);
+				else
+					fvalue = va_arg(args, double);
+				/* um, floating point? */
+				fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
+				break;
+			case 'E':
+				flags |= DP_F_UP;
+			case 'e':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, long double);
+				else
+					fvalue = va_arg(args, double);
+				break;
+			case 'G':
+				flags |= DP_F_UP;
+			case 'g':
+				if (cflags == DP_C_LDOUBLE)
+					fvalue = va_arg(args, long double);
+				else
+					fvalue = va_arg(args, double);
+				break;
+			case 'c':
+				dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
+				break;
+			case 's':
+				strvalue = va_arg(args, char *);
+				if (max < 0) 
+					max = maxlen; /* ie, no max */
+				fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
+				break;
+			case 'p':
+				strvalue = va_arg(args, void *);
+				fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
+				break;
+			case 'n':
+				if (cflags == DP_C_SHORT) {
+					short int *num;
+					num = va_arg(args, short int *);
+					*num = currlen;
+				} else if (cflags == DP_C_LONG) {
+					long int *num;
+					num = va_arg(args, long int *);
+					*num = currlen;
+				} else if (cflags == DP_C_LONG_LONG) {
+					long long *num;
+					num = va_arg(args, long long *);
+					*num = currlen;
+				} else {
+					int *num;
+					num = va_arg(args, int *);
+					*num = currlen;
+				}
+				break;
+			case '%':
+				dopr_outch(buffer, &currlen, maxlen, ch);
+				break;
+			case 'w': /* not supported yet, treat as next char */
+				ch = *format++;
+				break;
+			default: /* Unknown, skip */
+			break;
+			}
+			ch = *format++;
+			state = DP_S_DEFAULT;
+			flags = cflags = min = 0;
+			max = -1;
+			break;
+		case DP_S_DONE:
+			break;
+		default: /* hmm? */
+			break; /* some picky compilers need this */
+		}
+	}
+	if (currlen < maxlen - 1) 
+		buffer[currlen] = '\0';
+	else 
+		buffer[maxlen - 1] = '\0';
+}
+
+static void
+fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+    char *value, int flags, int min, int max)
+{
+	int cnt = 0, padlen, strln;     /* amount to pad */
+  
+	if (value == 0) 
+		value = "<NULL>";
+
+	for (strln = 0; value[strln]; ++strln); /* strlen */
+	padlen = min - strln;
+	if (padlen < 0) 
+		padlen = 0;
+	if (flags & DP_F_MINUS) 
+		padlen = -padlen; /* Left Justify */
+
+	while ((padlen > 0) && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--padlen;
+		++cnt;
+	}
+	while (*value && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, *value++);
+		++cnt;
+	}
+	while ((padlen < 0) && (cnt < max)) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		++padlen;
+		++cnt;
+	}
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void 
+fmtint(char *buffer, size_t *currlen, size_t maxlen,
+    long value, int base, int min, int max, int flags)
+{
+	unsigned long uvalue;
+	char convert[20];
+	int signvalue = 0, place = 0, caps = 0;
+	int spadlen = 0; /* amount to space pad */
+	int zpadlen = 0; /* amount to zero pad */
+
+#define PADMAX(x,y)	((x) > (y) ? (x) : (y))
+
+	if (max < 0)
+		max = 0;
+
+	uvalue = value;
+
+	if (!(flags & DP_F_UNSIGNED)) {
+		if (value < 0) {
+			signvalue = '-';
+			uvalue = -value;
+		} else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+			signvalue = '+';
+		else if (flags & DP_F_SPACE)
+			signvalue = ' ';
+	}
+  
+	if (flags & DP_F_UP) 
+		caps = 1; /* Should characters be upper case? */
+	do {
+		convert[place++] =
+		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+		    [uvalue % (unsigned)base];
+		uvalue = (uvalue / (unsigned)base );
+	} while (uvalue && (place < 20));
+	if (place == 20) 
+		place--;
+	convert[place] = 0;
+
+	zpadlen = max - place;
+	spadlen = min - PADMAX(max, place) - (signvalue ? 1 : 0);
+	if (zpadlen < 0)
+		zpadlen = 0;
+	if (spadlen < 0)
+		spadlen = 0;
+	if (flags & DP_F_ZERO) {
+		zpadlen = PADMAX(zpadlen, spadlen);
+		spadlen = 0;
+	}
+	if (flags & DP_F_MINUS) 
+		spadlen = -spadlen; /* Left Justifty */
+
+	/* Spaces */
+	while (spadlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--spadlen;
+	}
+
+	/* Sign */
+	if (signvalue) 
+		dopr_outch(buffer, currlen, maxlen, signvalue);
+
+	/* Zeros */
+	if (zpadlen > 0) {
+		while (zpadlen > 0) {
+			dopr_outch(buffer, currlen, maxlen, '0');
+			--zpadlen;
+		}
+	}
+
+	/* Digits */
+	while (place > 0) 
+		dopr_outch(buffer, currlen, maxlen, convert[--place]);
+  
+	/* Left Justified spaces */
+	while (spadlen < 0) {
+		dopr_outch (buffer, currlen, maxlen, ' ');
+		++spadlen;
+	}
+}
+
+static long double 
+pow10(int exp)
+{
+	long double result = 1;
+
+	while (exp) {
+		result *= 10;
+		exp--;
+	}
+  
+	return result;
+}
+
+static long 
+round(long double value)
+{
+	long intpart = value;
+
+	value -= intpart;
+	if (value >= 0.5)
+		intpart++;
+
+	return intpart;
+}
+
+static void 
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
+      int min, int max, int flags)
+{
+	char iconvert[20], fconvert[20];
+	int signvalue = 0, iplace = 0, fplace = 0;
+	int padlen = 0; /* amount to pad */
+	int zpadlen = 0, caps = 0;
+	long intpart, fracpart;
+	long double ufvalue;
+  
+	/* 
+	 * AIX manpage says the default is 0, but Solaris says the default
+	 * is 6, and sprintf on AIX defaults to 6
+	 */
+	if (max < 0)
+		max = 6;
+
+	ufvalue = abs_val(fvalue);
+
+	if (fvalue < 0)
+		signvalue = '-';
+	else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
+		signvalue = '+';
+	else if (flags & DP_F_SPACE)
+		signvalue = ' ';
+
+	intpart = ufvalue;
+
+	/* 
+	 * Sorry, we only support 9 digits past the decimal because of our 
+	 * conversion method
+	 */
+	if (max > 9)
+		max = 9;
+
+	/* We "cheat" by converting the fractional part to integer by
+	 * multiplying by a factor of 10
+	 */
+	fracpart = round((pow10 (max)) * (ufvalue - intpart));
+
+	if (fracpart >= pow10 (max)) {
+		intpart++;
+		fracpart -= pow10 (max);
+	}
+
+	/* Convert integer part */
+	do {
+		iconvert[iplace++] =
+		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+		    [intpart % 10];
+		intpart = (intpart / 10);
+	} while(intpart && (iplace < 20));
+	if (iplace == 20) 
+		iplace--;
+	iconvert[iplace] = 0;
+
+	/* Convert fractional part */
+	do {
+		fconvert[fplace++] =
+		    (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+		    [fracpart % 10];
+		fracpart = (fracpart / 10);
+	} while(fracpart && (fplace < 20));
+	if (fplace == 20) 
+		fplace--;
+	fconvert[fplace] = 0;
+
+	/* -1 for decimal point, another -1 if we are printing a sign */
+	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
+	zpadlen = max - fplace;
+	if (zpadlen < 0)
+		zpadlen = 0;
+	if (padlen < 0) 
+		padlen = 0;
+	if (flags & DP_F_MINUS) 
+		padlen = -padlen; /* Left Justifty */
+
+	if ((flags & DP_F_ZERO) && (padlen > 0)) {
+		if (signvalue) {
+			dopr_outch(buffer, currlen, maxlen, signvalue);
+			--padlen;
+			signvalue = 0;
+		}
+		while (padlen > 0) {
+			dopr_outch(buffer, currlen, maxlen, '0');
+			--padlen;
+		}
+	}
+	while (padlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		--padlen;
+	}
+	if (signvalue) 
+		dopr_outch(buffer, currlen, maxlen, signvalue);
+
+	while (iplace > 0) 
+		dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
+
+	/*
+	 * Decimal point.  This should probably use locale to find the 
+	 * correct char to print out.
+	 */
+	dopr_outch(buffer, currlen, maxlen, '.');
+
+	while (fplace > 0) 
+		dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
+
+	while (zpadlen > 0) {
+		dopr_outch(buffer, currlen, maxlen, '0');
+		--zpadlen;
+	}
+
+	while (padlen < 0) {
+		dopr_outch(buffer, currlen, maxlen, ' ');
+		++padlen;
+	}
+}
+
+static void 
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+	if (*currlen < maxlen)
+		buffer[(*currlen)++] = c;
+}
+#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
+
+#ifndef HAVE_VSNPRINTF
+int 
+vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+{
+	str[0] = 0;
+	dopr(str, count, fmt, args);
+
+	return(strlen(str));
+}
+#endif /* !HAVE_VSNPRINTF */
+
+#ifndef HAVE_SNPRINTF
+int 
+snprintf(char *str,size_t count,const char *fmt,...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	(void) vsnprintf(str, count, fmt, ap);
+	va_end(ap);
+
+	return(strlen(str));
+}
+
+#endif /* !HAVE_SNPRINTF */
Index: uspace/app/pcc/mip/compat.h
===================================================================
--- uspace/app/pcc/mip/compat.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/mip/compat.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,45 @@
+/*
+ * Just compatibility function prototypes.
+ * Public domain.
+ */
+
+#ifndef COMPAT_H
+#define COMPAT_H
+
+#include <string.h>
+
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *dst, const char *src, size_t siz);
+#endif
+
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *dst, const char *src, size_t siz);
+#endif
+
+#ifndef HAVE_GETOPT
+extern char *optarg;
+extern int optind;
+int getopt(int, char **, char *);
+#endif
+
+#ifndef HAVE_BASENAME
+char *basename(char *);
+#endif
+
+#ifndef HAVE_MKSTEMP
+int mkstemp(char *);
+#endif
+
+#ifndef HAVE_FFS
+int ffs(int);
+#endif
+
+#ifndef HAVE_SNPRINTF
+int snprintf(char *str, size_t count, const char *fmt, ...);
+#endif
+
+#ifndef HAVE_VSNPRINTF
+int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
+#endif
+
+#endif
Index: uspace/app/pcc/mip/config.h
===================================================================
--- uspace/app/pcc/mip/config.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/mip/config.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1 @@
+../config.h
Index: uspace/app/pcc/mip/manifest.h
===================================================================
--- uspace/app/pcc/mip/manifest.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/mip/manifest.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,380 @@
+/*	$Id: manifest.h,v 1.92 2011/01/22 22:08:54 ragge Exp $	*/
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MANIFEST
+#define	MANIFEST
+
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+#include "macdefs.h"
+#include "node.h"
+#include "compat.h"
+
+/*
+ * Node types
+ */
+#define LTYPE	02		/* leaf */
+#define UTYPE	04		/* unary */
+#define BITYPE	010		/* binary */
+
+/*
+ * DSIZE is the size of the dope array
+ */
+#define DSIZE	(MAXOP+1)
+
+/*
+ * Type names, used in symbol table building.
+ * The order of the integer types are important.
+ * Signed types must have bit 0 unset, unsigned types set (used below).
+ */
+#define	UNDEF		0	/* free symbol table entry */
+#define	FARG		1 	/* function argument */
+#define	CHAR		2
+#define	UCHAR		3
+#define	SHORT		4
+#define	USHORT		5
+#define	INT		6
+#define	UNSIGNED	7
+#define	LONG		8
+#define	ULONG		9      
+#define	LONGLONG	10
+#define	ULONGLONG	11
+#define	FLOAT		12
+#define	DOUBLE		13
+#define	LDOUBLE		14
+#define	STRTY		15
+#define	UNIONTY		16
+#define	XTYPE		17	/* Extended target-specific type */
+/* #define	MOETY		18 */	/* member of enum */
+#define	VOID		19
+
+#define	MAXTYPES	19	/* highest type+1 to be used by lang code */
+/*
+ * Various flags
+ */
+#define NOLAB	(-1)
+
+/* 
+ * Type modifiers.
+ */
+#define	PTR		0x20
+#define	FTN		0x40
+#define	ARY		0x60
+#define	CON		0x20
+#define	VOL		0x40
+
+/*
+ * Type packing constants
+ */
+#define TMASK	0x060
+#define TMASK1	0x180
+#define TMASK2	0x1e0
+#define BTMASK	0x1f
+#define BTSHIFT	5
+#define TSHIFT	2
+
+/*
+ * Macros
+ */
+#define MODTYPE(x,y)	x = ((x)&(~BTMASK))|(y)	/* set basic type of x to y */
+#define BTYPE(x)	((x)&BTMASK)		/* basic type of x */
+#define	ISLONGLONG(x)	((x) == LONGLONG || (x) == ULONGLONG)
+#define ISUNSIGNED(x)	(((x) <= ULONGLONG) && (((x) & 1) == (UNSIGNED & 1)))
+#define UNSIGNABLE(x)	(((x)<=ULONGLONG&&(x)>=CHAR) && !ISUNSIGNED(x))
+#define ENUNSIGN(x)	((x)|1)
+#define DEUNSIGN(x)	((x)&~1)
+#define ISINTEGER(x)	(((x) >= CHAR && (x) <= ULONGLONG) || (x) == BOOL)
+#define ISPTR(x)	(((x)&TMASK)==PTR)
+#define ISFTN(x)	(((x)&TMASK)==FTN)	/* is x a function type? */
+#define ISARY(x)	(((x)&TMASK)==ARY)	/* is x an array type? */
+#define	ISCON(x)	(((x)&CON)==CON)	/* is x const? */
+#define	ISVOL(x)	(((x)&VOL)==VOL)	/* is x volatile? */
+#define INCREF(x)	((((x)&~BTMASK)<<TSHIFT)|PTR|((x)&BTMASK))
+#define INCQAL(x)	((((x)&~BTMASK)<<TSHIFT)|((x)&BTMASK))
+#define DECREF(x)	((((x)>>TSHIFT)&~BTMASK)|((x)&BTMASK))
+#define DECQAL(x)	((((x)>>TSHIFT)&~BTMASK)|((x)&BTMASK))
+#define SETOFF(x,y)	{ if ((x)%(y) != 0) (x) = (((x)/(y) + 1) * (y)); }
+		/* advance x to a multiple of y */
+#define NOFIT(x,y,z)	(((x)%(z) + (y)) > (z))
+		/* can y bits be added to x without overflowing z */
+
+#ifndef SPECIAL_INTEGERS
+#define	ASGLVAL(lval, val)
+#endif
+
+/*
+ * Pack and unpack field descriptors (size and offset)
+ */
+#define PKFIELD(s,o)	(((o)<<7)| (s))
+#define UPKFSZ(v)	((v)&0177)
+#define UPKFOFF(v)	((v)>>7)
+
+/*
+ * Operator information
+ */
+#define TYFLG	016
+#define ASGFLG	01
+#define LOGFLG	020
+
+#define SIMPFLG	040
+#define COMMFLG	0100
+#define DIVFLG	0200
+#define FLOFLG	0400
+#define LTYFLG	01000
+#define CALLFLG	02000
+#define MULFLG	04000
+#define SHFFLG	010000
+#define ASGOPFLG 020000
+
+#define SPFLG	040000
+
+/*
+ * Location counters
+ */
+#define PROG		0		/* (ro) program segment */
+#define DATA		1		/* (rw) data segment */
+#define RDATA		2		/* (ro) data segment */
+#define STRNG		3		/* (ro) string segment */
+#define	UDATA		4		/* (rw) uninitialized data */
+
+
+#define	regno(p)	((p)->n_rval)	/* register number */
+
+/*
+ * 
+ */
+extern int bdebug, tdebug, edebug;
+extern int ddebug, xdebug, f2debug;
+extern int iTflag, oTflag, kflag;
+extern int sflag, nflag, gflag, pflag;
+extern int funsigned_char;
+extern int sspflag;
+extern int xssaflag, xtailcallflag, xtemps, xdeljumps, xdce;
+
+int yyparse(void);
+void yyaccpt(void);
+
+/*
+ * List handling macros, similar to those in 4.4BSD.
+ * The double-linked list is insque-style.
+ */
+/* Double-linked list macros */
+#define	DLIST_INIT(h,f)		{ (h)->f.q_forw = (h); (h)->f.q_back = (h); }
+#define	DLIST_ENTRY(t)		struct { struct t *q_forw, *q_back; }
+#define	DLIST_NEXT(h,f)		(h)->f.q_forw
+#define	DLIST_PREV(h,f)		(h)->f.q_back
+#define DLIST_ISEMPTY(h,f)	((h)->f.q_forw == (h))
+#define DLIST_ENDMARK(h)	(h)
+#define	DLIST_FOREACH(v,h,f) \
+	for ((v) = (h)->f.q_forw; (v) != (h); (v) = (v)->f.q_forw)
+#define	DLIST_FOREACH_REVERSE(v,h,f) \
+	for ((v) = (h)->f.q_back; (v) != (h); (v) = (v)->f.q_back)
+#define	DLIST_INSERT_BEFORE(h,e,f) {	\
+	(e)->f.q_forw = (h);		\
+	(e)->f.q_back = (h)->f.q_back;	\
+	(e)->f.q_back->f.q_forw = (e);	\
+	(h)->f.q_back = (e);		\
+}
+#define	DLIST_INSERT_AFTER(h,e,f) {	\
+	(e)->f.q_forw = (h)->f.q_forw;	\
+	(e)->f.q_back = (h);		\
+	(e)->f.q_forw->f.q_back = (e);	\
+	(h)->f.q_forw = (e);		\
+}
+#define DLIST_REMOVE(e,f) {			 \
+	(e)->f.q_forw->f.q_back = (e)->f.q_back; \
+	(e)->f.q_back->f.q_forw = (e)->f.q_forw; \
+}
+
+/* Single-linked list */
+#define	SLIST_INIT(h)	\
+	{ (h)->q_forw = NULL; (h)->q_last = &(h)->q_forw; }
+#define	SLIST_SETUP(h) { NULL, &(h)->q_forw }
+#define	SLIST_ENTRY(t)	struct { struct t *q_forw; }
+#define	SLIST_HEAD(n,t) struct n { struct t *q_forw, **q_last; }
+#define	SLIST_ISEMPTY(h) ((h)->q_last == &(h)->q_forw)
+#define	SLIST_FIRST(h)	((h)->q_forw)
+#define	SLIST_FOREACH(v,h,f) \
+	for ((v) = (h)->q_forw; (v) != NULL; (v) = (v)->f.q_forw)
+#define	SLIST_INSERT_FIRST(h,e,f) {		\
+	if ((h)->q_last == &(h)->q_forw)	\
+		(h)->q_last = &(e)->f.q_forw;	\
+	(e)->f.q_forw = (h)->q_forw;		\
+	(h)->q_forw = (e);			\
+}
+#define	SLIST_INSERT_LAST(h,e,f) {	\
+	(e)->f.q_forw = NULL;		\
+	*(h)->q_last = (e);		\
+	(h)->q_last = &(e)->f.q_forw;	\
+}
+
+#ifndef	MKEXT
+/*
+ * Functions for inter-pass communication.
+ *
+ */
+struct interpass {
+	DLIST_ENTRY(interpass) qelem;
+	int type;
+	int lineno;
+	union {
+		NODE *_p;
+		int _locctr;
+		int _label;
+		int _curoff;
+		char *_name;
+	} _un;
+};
+
+/*
+ * Special struct for prologue/epilogue.
+ * - ip_lblnum contains the lowest/highest+1 label used
+ * - ip_lbl is set before/after all code and after/before the prolog/epilog.
+ */
+struct interpass_prolog {
+	struct interpass ipp_ip;
+	char *ipp_name;		/* Function name */
+	int ipp_vis;		/* Function visibility */
+	TWORD ipp_type;		/* Function type */
+#define	NIPPREGS	BIT2BYTE(MAXREGS)/sizeof(bittype)
+	bittype ipp_regs[NIPPREGS];
+				/* Bitmask of registers to save */
+	int ipp_autos;		/* Size on stack needed */
+	int ip_tmpnum;		/* # allocated temp nodes so far */
+	int ip_lblnum;		/* # used labels so far */
+#ifdef TARGET_IPP_MEMBERS
+	TARGET_IPP_MEMBERS
+#endif
+};
+#else
+struct interpass { int dummy; };
+struct interpass_prolog;
+#endif /* !MKEXT */
+
+/*
+ * Epilog/prolog takes following arguments (in order):
+ * - type
+ * - regs
+ * - autos
+ * - name
+ * - type
+ * - retlab
+ */
+
+#define	ip_node	_un._p
+#define	ip_locc	_un._locctr
+#define	ip_lbl	_un._label
+#define	ip_name	_un._name
+#define	ip_asm	_un._name
+#define	ip_off	_un._curoff
+
+/* Types of inter-pass structs */
+#define	IP_NODE		1
+#define	IP_PROLOG	2
+#define	IP_EPILOG	4
+#define	IP_DEFLAB	5
+#define	IP_DEFNAM	6
+#define	IP_ASM		7
+#define	MAXIP		7
+
+void send_passt(int type, ...);
+/*
+ * External declarations, typedefs and the like
+ */
+
+/* used for memory allocation */
+typedef struct mark {
+	void *tmsav;
+	void *tasav;
+	int elem;
+} MARK;
+
+/* memory management stuff */
+void *permalloc(int size);
+void *tmpcalloc(int size);
+void *tmpalloc(int size);
+void tmpfree(void);
+char *newstring(char *, int len);
+char *tmpstrdup(char *str);
+void markset(struct mark *m);
+void markfree(struct mark *m);
+
+/* command-line processing */
+void mflags(char *);
+
+void tprint(FILE *, TWORD, TWORD);
+
+/* pass t communication subroutines */
+void topt_compile(struct interpass *);
+
+/* pass 2 communication subroutines */
+void pass2_compile(struct interpass *);
+
+/* node routines */
+NODE *nfree(NODE *);
+void tfree(NODE *);
+NODE *tcopy(NODE *);
+void walkf(NODE *, void (*f)(NODE *, void *), void *);
+void fwalk(NODE *t, void (*f)(NODE *, int, int *, int *), int down);
+void flist(NODE *p, void (*f)(NODE *, void *), void *);
+void listf(NODE *p, void (*f)(NODE *));
+NODE *listarg(NODE *p, int n, int *cnt);
+void cerror(char *s, ...);
+void werror(char *s, ...);
+void uerror(char *s, ...);
+void mkdope(void);
+void tcheck(void);
+
+extern	int nerrors;		/* number of errors seen so far */
+extern	int warniserr;		/* treat warnings as errors */
+
+/* gcc warning stuff */
+#define	Wtruncate			0
+#define	Wstrict_prototypes		1
+#define	Wmissing_prototypes		2
+#define	Wimplicit_int			3
+#define	Wimplicit_function_declaration	4
+#define	Wshadow				5
+#define	Wpointer_sign			6
+#define	Wsign_compare			7
+#define	Wunknown_pragmas		8
+#define	Wunreachable_code		9
+#define	NUMW				10
+
+void warner(int type, ...);
+void Wflags(char *str);
+
+#endif
Index: uspace/app/pcc/mip/match.c
===================================================================
--- uspace/app/pcc/mip/match.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/mip/match.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1260 @@
+/*      $Id: match.c,v 1.93 2010/06/04 05:58:31 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.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pass2.h"
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+void setclass(int tmp, int class);
+int getclass(int tmp);
+
+int s2debug;
+
+extern char *ltyp[], *rtyp[];
+
+static char *srtyp[] = { "SRNOPE", "SRDIR", "SROREG", "SRREG" };
+
+/*
+ * return true if shape is appropriate for the node p
+ * side effect for SFLD is to set up fldsz, etc
+ *
+ * Return values:
+ * SRNOPE  Cannot match this shape.
+ * SRDIR   Direct match, may or may not traverse down.
+ * SRREG   Will match if put in a regster XXX - kill this?
+ */
+int
+tshape(NODE *p, int shape)
+{
+	int o, mask;
+
+	o = p->n_op;
+
+#ifdef PCC_DEBUG
+	if (s2debug)
+		printf("tshape(%p, %s) op = %s\n", p, prcook(shape), opst[o]);
+#endif
+
+	if (shape & SPECIAL) {
+
+		switch (shape) {
+		case SZERO:
+		case SONE:
+		case SMONE:
+		case SSCON:
+		case SCCON:
+			if (o != ICON || p->n_name[0])
+				return SRNOPE;
+			if (p->n_lval == 0 && shape == SZERO)
+				return SRDIR;
+			if (p->n_lval == 1 && shape == SONE)
+				return SRDIR;
+			if (p->n_lval == -1 && shape == SMONE)
+				return SRDIR;
+			if (p->n_lval > -257 && p->n_lval < 256 &&
+			    shape == SCCON)
+				return SRDIR;
+			if (p->n_lval > -32769 && p->n_lval < 32768 &&
+			    shape == SSCON)
+				return SRDIR;
+			return SRNOPE;
+
+		case SSOREG:	/* non-indexed OREG */
+			if (o == OREG && !R2TEST(p->n_rval))
+				return SRDIR;
+			return SRNOPE;
+
+		default:
+			return (special(p, shape));
+		}
+	}
+
+	if (shape & SANY)
+		return SRDIR;
+
+	if ((shape&INTEMP) && shtemp(p)) /* XXX remove? */
+		return SRDIR;
+
+	if ((shape&SWADD) && (o==NAME||o==OREG))
+		if (BYTEOFF(p->n_lval))
+			return SRNOPE;
+
+	switch (o) {
+
+	case NAME:
+		if (shape & SNAME)
+			return SRDIR;
+		break;
+
+	case ICON:
+	case FCON:
+		if (shape & SCON)
+			return SRDIR;
+		break;
+
+	case FLD:
+		if (shape & SFLD)
+			return flshape(p->n_left);
+		break;
+
+	case CCODES:
+		if (shape & SCC)
+			return SRDIR;
+		break;
+
+	case REG:
+	case TEMP:
+		mask = PCLASS(p);
+		if (shape & mask)
+			return SRDIR;
+		break;
+
+	case OREG:
+		if (shape & SOREG)
+			return SRDIR;
+		break;
+
+	case UMUL:
+#if 0
+		if (shumul(p->n_left) & shape)
+			return SROREG;	/* Calls offstar to traverse down */
+		break;
+#else
+		return shumul(p->n_left, shape);
+#endif
+
+	}
+	return SRNOPE;
+}
+
+/*
+ * does the type t match tword
+ */
+int
+ttype(TWORD t, int tword)
+{
+	if (tword & TANY)
+		return(1);
+
+#ifdef PCC_DEBUG
+	if (t2debug)
+		printf("ttype(%o, %o)\n", t, tword);
+#endif
+	if (ISPTR(t) && ISFTN(DECREF(t)) && (tword & TFTN)) {
+		/* For funny function pointers */
+		return 1;
+	}
+	if (ISPTR(t) && (tword&TPTRTO)) {
+		do {
+			t = DECREF(t);
+		} while (ISARY(t));
+			/* arrays that are left are usually only
+			 * in structure references...
+			 */
+		return (ttype(t, tword&(~TPTRTO)));
+	}
+	if (t != BTYPE(t))
+		return (tword & TPOINT); /* TPOINT means not simple! */
+	if (tword & TPTRTO)
+		return(0);
+
+	switch (t) {
+	case CHAR:
+		return( tword & TCHAR );
+	case SHORT:
+		return( tword & TSHORT );
+	case STRTY:
+	case UNIONTY:
+		return( tword & TSTRUCT );
+	case INT:
+		return( tword & TINT );
+	case UNSIGNED:
+		return( tword & TUNSIGNED );
+	case USHORT:
+		return( tword & TUSHORT );
+	case UCHAR:
+		return( tword & TUCHAR );
+	case ULONG:
+		return( tword & TULONG );
+	case LONG:
+		return( tword & TLONG );
+	case LONGLONG:
+		return( tword & TLONGLONG );
+	case ULONGLONG:
+		return( tword & TULONGLONG );
+	case FLOAT:
+		return( tword & TFLOAT );
+	case DOUBLE:
+		return( tword & TDOUBLE );
+	case LDOUBLE:
+		return( tword & TLDOUBLE );
+	}
+
+	return(0);
+}
+
+#define FLDSZ(x)	UPKFSZ(x)
+#ifdef RTOLBYTES
+#define	FLDSHF(x)	UPKFOFF(x)
+#else
+#define	FLDSHF(x)	(SZINT - FLDSZ(x) - UPKFOFF(x))
+#endif
+
+/*
+ * generate code by interpreting table entry
+ */
+void
+expand(NODE *p, int cookie, char *cp)
+{
+	CONSZ val;
+
+#if 0
+	printf("expand\n");
+	fwalk(p, e2print, 0);
+#endif
+
+	for( ; *cp; ++cp ){
+		switch( *cp ){
+
+		default:
+			PUTCHAR( *cp );
+			continue;  /* this is the usual case... */
+
+		case 'Z':  /* special machine dependent operations */
+			zzzcode( p, *++cp );
+			continue;
+
+		case 'F':  /* this line deleted if FOREFF is active */
+			if (cookie & FOREFF) {
+				while (*cp && *cp != '\n')
+					cp++;
+				if (*cp == 0)
+					return;
+			}
+			continue;
+
+		case 'S':  /* field size */
+			if (fldexpand(p, cookie, &cp))
+				continue;
+			printf("%d", FLDSZ(p->n_rval));
+			continue;
+
+		case 'H':  /* field shift */
+			if (fldexpand(p, cookie, &cp))
+				continue;
+			printf("%d", FLDSHF(p->n_rval));
+			continue;
+
+		case 'M':  /* field mask */
+		case 'N':  /* complement of field mask */
+			if (fldexpand(p, cookie, &cp))
+				continue;
+			val = 1;
+			val <<= FLDSZ(p->n_rval);
+			--val;
+			val <<= FLDSHF(p->n_rval);
+			adrcon( *cp=='M' ? val : ~val );
+			continue;
+
+		case 'L':  /* output special label field */
+			if (*++cp == 'C')
+				printf(LABFMT, p->n_label);
+			else
+				printf(LABFMT, (int)getlr(p,*cp)->n_lval);
+			continue;
+
+		case 'O':  /* opcode string */
+#ifdef FINDMOPS
+			if (p->n_op == ASSIGN)
+				hopcode(*++cp, p->n_right->n_op);
+			else
+#endif
+			hopcode( *++cp, p->n_op );
+			continue;
+
+		case 'B':  /* byte offset in word */
+			val = getlr(p,*++cp)->n_lval;
+			val = BYTEOFF(val);
+			printf( CONFMT, val );
+			continue;
+
+		case 'C': /* for constant value only */
+			conput(stdout, getlr( p, *++cp ) );
+			continue;
+
+		case 'I': /* in instruction */
+			insput( getlr( p, *++cp ) );
+			continue;
+
+		case 'A': /* address of */
+			adrput(stdout, getlr( p, *++cp ) );
+			continue;
+
+		case 'U': /* for upper half of address, only */
+			upput(getlr(p, *++cp), SZLONG);
+			continue;
+
+			}
+
+		}
+
+	}
+
+NODE resc[4];
+
+NODE *
+getlr(NODE *p, int c)
+{
+	NODE *q;
+
+	/* return the pointer to the left or right side of p, or p itself,
+	   depending on the optype of p */
+
+	switch (c) {
+
+	case '1':
+	case '2':
+	case '3':
+	case 'D':
+		if (c == 'D')
+			c = 0;
+		else
+			c -= '0';
+		q = &resc[c];
+		q->n_op = REG;
+		q->n_type = p->n_type; /* XXX should be correct type */
+		q->n_rval = DECRA(p->n_reg, c);
+		q->n_su = p->n_su;
+		return q;
+
+	case 'L':
+		return( optype( p->n_op ) == LTYPE ? p : p->n_left );
+
+	case 'R':
+		return( optype( p->n_op ) != BITYPE ? p : p->n_right );
+
+	}
+	cerror( "bad getlr: %c", c );
+	/* NOTREACHED */
+	return NULL;
+}
+
+#ifdef PCC_DEBUG
+#define	F2DEBUG(x)	if (f2debug) printf x
+#define	F2WALK(x)	if (f2debug) fwalk(x, e2print, 0)
+#else
+#define	F2DEBUG(x)
+#define	F2WALK(x)
+#endif
+
+/*
+ * Convert a node to REG or OREG.
+ * Shape is register class where we want the result.
+ * Returns register class if register nodes.
+ * If w is: (should be shapes)
+ *	- SRREG - result in register, call geninsn().
+ *	- SROREG - create OREG; call offstar().
+ *	- 0 - clear su, walk down.
+ */
+static int
+swmatch(NODE *p, int shape, int w)
+{
+	int rv = 0;
+
+	F2DEBUG(("swmatch: p=%p, shape=%s, w=%s\n", p, prcook(shape), srtyp[w]));
+
+	switch (w) {
+	case SRREG:
+		rv = geninsn(p, shape);
+		break;
+
+	case SROREG:
+		/* should be here only if op == UMUL */
+		if (p->n_op != UMUL && p->n_op != FLD)
+			comperr("swmatch %p", p);
+		if (p->n_op == FLD) {
+			offstar(p->n_left->n_left, shape);
+			p->n_left->n_su = 0;
+		} else
+			offstar(p->n_left, shape);
+		p->n_su = 0;
+		rv = ffs(shape)-1;
+		break;
+
+	case 0:
+		if (optype(p->n_op) == BITYPE)
+			swmatch(p->n_right, 0, 0);
+		if (optype(p->n_op) != LTYPE)
+			swmatch(p->n_left, 0, 0);
+		p->n_su = 0;
+	}
+	return rv;
+
+}
+
+/*
+ * Help routines for find*() functions.
+ * If the node will be a REG node and it will be rewritten in the
+ * instruction, ask for it to be put in a register.
+ */
+static int
+chcheck(NODE *p, int shape, int rew)
+{
+	int sh, sha;
+
+	sha = shape;
+	if (shape & SPECIAL)
+		shape = 0;
+
+	switch ((sh = tshape(p, sha))) {
+	case SRNOPE:
+		if (shape & INREGS)
+			sh = SRREG;
+		break;
+
+	case SROREG:
+	case SRDIR:
+		if (rew == 0)
+			break;
+		if (shape & INREGS)
+			sh = SRREG;
+		else
+			sh = SRNOPE;
+		break;
+	}
+	return sh;
+}
+
+/*
+ * Check how to walk further down.
+ * Merge with swmatch()?
+ * 	sh - shape for return value (register class).
+ *	p - node (for this leg)
+ *	shape - given shape for this leg
+ *	cookie - cookie given for parent node
+ *	rew - 
+ *	go - switch key for traversing down
+ *	returns register class.
+ */
+static int
+shswitch(int sh, NODE *p, int shape, int cookie, int rew, int go)
+{
+	int lsh;
+
+	F2DEBUG(("shswitch: p=%p, shape=%s, ", p, prcook(shape)));
+	F2DEBUG(("cookie=%s, rew=0x%x, go=%s\n", prcook(cookie), rew, srtyp[go]));
+
+	switch (go) {
+	case SRDIR: /* direct match, just clear su */
+		(void)swmatch(p, 0, 0);
+		break;
+
+	case SROREG: /* call offstar to prepare for OREG conversion */
+		(void)swmatch(p, shape, SROREG);
+		break;
+
+	case SRREG: /* call geninsn() to get value into register */
+		lsh = shape & (FORCC | INREGS);
+		if (rew && cookie != FOREFF)
+			lsh &= (cookie & (FORCC | INREGS));
+		lsh = swmatch(p, lsh, SRREG);
+		if (rew)
+			sh = lsh;
+		break;
+	}
+	return sh;
+}
+
+/*
+ * Find the best instruction to evaluate the given tree.
+ * Best is to match both subnodes directly, second-best is if
+ * subnodes must be evaluated into OREGs, thereafter if nodes 
+ * must be put into registers.
+ * Whether 2-op instructions or 3-op is preferred is depending on in
+ * which order they are found in the table.
+ * mtchno is set to the count of regs needed for its legs.
+ */
+int
+findops(NODE *p, int cookie)
+{
+	extern int *qtable[];
+	struct optab *q, *qq = NULL;
+	int i, shl, shr, *ixp, sh;
+	int lvl = 10, idx = 0, gol = 0, gor = 0;
+	NODE *l, *r;
+
+	F2DEBUG(("findops node %p (%s)\n", p, prcook(cookie)));
+	F2WALK(p);
+
+	ixp = qtable[p->n_op];
+	l = getlr(p, 'L');
+	r = getlr(p, 'R');
+	for (i = 0; ixp[i] >= 0; i++) {
+		q = &table[ixp[i]];
+
+		F2DEBUG(("findop: ixp %d str %s\n", ixp[i], q->cstring));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
+
+		if (ttype(l->n_type, q->ltype) == 0 ||
+		    ttype(r->n_type, q->rtype) == 0)
+			continue; /* Types must be correct */
+
+		if ((cookie & q->visit) == 0)
+			continue; /* must get a result */
+
+		F2DEBUG(("findop got types\n"));
+
+		if ((shl = chcheck(l, q->lshape, q->rewrite & RLEFT)) == SRNOPE)
+			continue;
+
+		F2DEBUG(("findop lshape %s\n", srtyp[shl]));
+		F2WALK(l);
+
+		if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT)) == SRNOPE)
+			continue;
+
+		F2DEBUG(("findop rshape %s\n", srtyp[shr]));
+		F2WALK(r);
+
+		/* Help register assignment after SSA by preferring */
+		/* 2-op insns instead of 3-ops */
+		if (xssaflag && (q->rewrite & RLEFT) == 0 && shl == SRDIR)
+			shl = SRREG;
+
+		if (q->needs & REWRITE)
+			break;  /* Done here */
+
+		if (lvl <= (shl + shr))
+			continue;
+		lvl = shl + shr;
+		qq = q;
+		idx = ixp[i];
+		gol = shl;
+		gor = shr;
+	}
+	if (lvl == 10) {
+		F2DEBUG(("findops failed\n"));
+		if (setbin(p))
+			return FRETRY;
+		return FFAIL;
+	}
+
+	F2DEBUG(("findops entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor]));
+
+	sh = -1;
+
+#ifdef mach_pdp11
+	if (cookie == FORCC && p->n_op != AND)	/* XXX - fix */
+		cookie = INREGS;
+#else
+	if (cookie == FORCC)
+		cookie = INREGS;
+#endif
+
+	sh = shswitch(sh, p->n_left, qq->lshape, cookie,
+	    qq->rewrite & RLEFT, gol);
+	sh = shswitch(sh, p->n_right, qq->rshape, cookie,
+	    qq->rewrite & RRIGHT, gor);
+
+	if (sh == -1) {
+		if (cookie == FOREFF || cookie == FORCC)
+			sh = 0;
+		else
+			sh = ffs(cookie & qq->visit & INREGS)-1;
+	}
+	F2DEBUG(("findops: node %p sh %d (%s)\n", p, sh, prcook(1 << sh)));
+	p->n_su = MKIDX(idx, 0);
+	SCLASS(p->n_su, sh);
+	return sh;
+}
+
+/*
+ * Find the best relation op for matching the two trees it has.
+ * This is a sub-version of the function findops() above.
+ * The instruction with the lowest grading is emitted.
+ *
+ * Level assignment for priority:
+ *	left	right	prio
+ *	-	-	-
+ *	direct	direct	1
+ *	direct	OREG	2	# make oreg
+ *	OREG	direct	2	# make oreg
+ *	OREG	OREG	2	# make both oreg
+ *	direct	REG	3	# put in reg
+ *	OREG	REG	3	# put in reg, make oreg
+ *	REG	direct	3	# put in reg
+ *	REG	OREG	3	# put in reg, make oreg
+ *	REG	REG	4	# put both in reg
+ */
+int
+relops(NODE *p)
+{
+	extern int *qtable[];
+	struct optab *q;
+	int i, shl = 0, shr = 0;
+	NODE *l, *r;
+	int *ixp, idx = 0;
+	int lvl = 10, gol = 0, gor = 0;
+
+	F2DEBUG(("relops tree:\n"));
+	F2WALK(p);
+
+	l = getlr(p, 'L');
+	r = getlr(p, 'R');
+	ixp = qtable[p->n_op];
+	for (i = 0; ixp[i] >= 0; i++) {
+		q = &table[ixp[i]];
+
+		F2DEBUG(("relops: ixp %d\n", ixp[i]));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
+
+		if (ttype(l->n_type, q->ltype) == 0 ||
+		    ttype(r->n_type, q->rtype) == 0)
+			continue; /* Types must be correct */
+
+		F2DEBUG(("relops got types\n"));
+		if ((shl = chcheck(l, q->lshape, 0)) == SRNOPE)
+			continue;
+		F2DEBUG(("relops lshape %d\n", shl));
+		F2WALK(p);
+		if ((shr = chcheck(r, q->rshape, 0)) == SRNOPE)
+			continue;
+		F2DEBUG(("relops rshape %d\n", shr));
+		F2WALK(p);
+		if (q->needs & REWRITE)
+			break;	/* Done here */
+
+		if (lvl <= (shl + shr))
+			continue;
+		lvl = shl + shr;
+		idx = ixp[i];
+		gol = shl;
+		gor = shr;
+	}
+	if (lvl == 10) {
+		F2DEBUG(("relops failed\n"));
+		if (setbin(p))
+			return FRETRY;
+		return FFAIL;
+	}
+	F2DEBUG(("relops entry %d(%s %s)\n", idx, srtyp[gol], srtyp[gor]));
+
+	q = &table[idx];
+
+	(void)shswitch(-1, p->n_left, q->lshape, FORCC,
+	    q->rewrite & RLEFT, gol);
+
+	(void)shswitch(-1, p->n_right, q->rshape, FORCC,
+	    q->rewrite & RRIGHT, gor);
+	
+	F2DEBUG(("relops: node %p\n", p));
+	p->n_su = MKIDX(idx, 0);
+	SCLASS(p->n_su, CLASSA); /* XXX */
+	return 0;
+}
+
+/*
+ * Find a matching assign op.
+ *
+ * Level assignment for priority:
+ *	left	right	prio
+ *	-	-	-
+ *	direct	direct	1
+ *	direct	REG	2
+ *	direct	OREG	3
+ *	OREG	direct	4
+ *	OREG	REG	5
+ *	OREG	OREG	6
+ */
+int
+findasg(NODE *p, int cookie)
+{
+	extern int *qtable[];
+	struct optab *q;
+	int i, sh, shl, shr, lvl = 10;
+	NODE *l, *r;
+	int *ixp;
+	struct optab *qq = NULL; /* XXX gcc */
+	int idx = 0, gol = 0, gor = 0;
+
+	shl = shr = 0;
+
+	F2DEBUG(("findasg tree: %s\n", prcook(cookie)));
+	F2WALK(p);
+
+	ixp = qtable[p->n_op];
+	l = getlr(p, 'L');
+	r = getlr(p, 'R');
+	for (i = 0; ixp[i] >= 0; i++) {
+		q = &table[ixp[i]];
+
+		F2DEBUG(("findasg: ixp %d\n", ixp[i]));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
+
+		if (ttype(l->n_type, q->ltype) == 0 ||
+		    ttype(r->n_type, q->rtype) == 0)
+			continue; /* Types must be correct */
+
+		if ((cookie & q->visit) == 0)
+			continue; /* must get a result */
+
+		F2DEBUG(("findasg got types\n"));
+#ifdef mach_pdp11 /* XXX - check for other targets too */
+		if (p->n_op == STASG && ISPTR(l->n_type)) {
+			/* Accept lvalue to be in register */
+			/* if struct assignment is given a pointer */
+			if ((shl = chcheck(l, q->lshape,
+			    q->rewrite & RLEFT)) == SRNOPE)
+				continue;
+		} else
+#endif
+		{
+			if ((shl = tshape(l, q->lshape)) == SRNOPE)
+				continue;
+			if (shl == SRREG)
+				continue;
+		}
+
+		F2DEBUG(("findasg lshape %d\n", shl));
+		F2WALK(l);
+
+		if ((shr = chcheck(r, q->rshape, q->rewrite & RRIGHT)) == SRNOPE)
+			continue;
+
+		F2DEBUG(("findasg rshape %d\n", shr));
+		F2WALK(r);
+		if (q->needs & REWRITE)
+			break;	/* Done here */
+
+		if (lvl <= (shl + shr))
+			continue;
+
+		lvl = shl + shr;
+		qq = q;
+		idx = ixp[i];
+		gol = shl;
+		gor = shr;
+	}
+
+	if (lvl == 10) {
+		F2DEBUG(("findasg failed\n"));
+		if (setasg(p, cookie))
+			return FRETRY;
+		return FFAIL;
+	}
+	F2DEBUG(("findasg entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor]));
+
+	sh = -1;
+	sh = shswitch(sh, p->n_left, qq->lshape, cookie,
+	    qq->rewrite & RLEFT, gol);
+
+	sh = shswitch(sh, p->n_right, qq->rshape, cookie,
+	    qq->rewrite & RRIGHT, gor);
+
+#ifdef mach_pdp11 /* XXX all targets? */
+	lvl = 0;
+	if (cookie == FOREFF)
+		lvl = RVEFF, sh = 0;
+	else if (cookie == FORCC)
+		lvl = RVCC, sh = 0;
+	else if (sh == -1) {
+		sh = ffs(cookie & qq->visit & INREGS)-1;
+#ifdef PCC_DEBUG
+		if (sh == -1)
+			comperr("findasg bad shape");
+#endif
+		SCLASS(lvl,sh);
+	} else
+		SCLASS(lvl,sh);
+	p->n_su = MKIDX(idx, lvl);
+#else
+	if (sh == -1) {
+		if (cookie == FOREFF)
+			sh = 0;
+		else
+			sh = ffs(cookie & qq->visit & INREGS)-1;
+	}
+	F2DEBUG(("findasg: node %p class %d\n", p, sh));
+
+	p->n_su = MKIDX(idx, 0);
+	SCLASS(p->n_su, sh);
+#endif /* mach_pdp11 */
+#ifdef FINDMOPS
+	p->n_flags &= ~1;
+#endif
+	return sh;
+}
+
+/*
+ * Search for an UMUL table entry that can turn an indirect node into
+ * a move from an OREG.
+ */
+int
+findumul(NODE *p, int cookie)
+{
+	extern int *qtable[];
+	struct optab *q = NULL; /* XXX gcc */
+	int i, shl = 0, shr = 0, sh;
+	int *ixp;
+
+	F2DEBUG(("findumul p %p (%s)\n", p, prcook(cookie)));
+	F2WALK(p);
+
+	ixp = qtable[p->n_op];
+	for (i = 0; ixp[i] >= 0; i++) {
+		q = &table[ixp[i]];
+
+		F2DEBUG(("findumul: ixp %d\n", ixp[i]));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
+
+		if ((q->visit & cookie) == 0)
+			continue; /* wrong registers */
+
+		if (ttype(p->n_type, q->rtype) == 0)
+			continue; /* Types must be correct */
+		
+
+		F2DEBUG(("findumul got types, rshape %s\n", prcook(q->rshape)));
+		/*
+		 * Try to create an OREG of the node.
+		 * Fake left even though it's right node,
+		 * to be sure of conversion if going down left.
+		 */
+		if ((shl = chcheck(p, q->rshape, 0)) == SRNOPE)
+			continue;
+		
+		shr = 0;
+
+		if (q->needs & REWRITE)
+			break;	/* Done here */
+
+		F2DEBUG(("findumul got shape %s\n", srtyp[shl]));
+
+		break; /* XXX search better matches */
+	}
+	if (ixp[i] < 0) {
+		F2DEBUG(("findumul failed\n"));
+		if (setuni(p, cookie))
+			return FRETRY;
+		return FFAIL;
+	}
+	F2DEBUG(("findumul entry %d(%s %s)\n", ixp[i], srtyp[shl], srtyp[shr]));
+
+	sh = shswitch(-1, p, q->rshape, cookie, q->rewrite & RLEFT, shl);
+	if (sh == -1)
+		sh = ffs(cookie & q->visit & INREGS)-1;
+
+	F2DEBUG(("findumul: node %p (%s)\n", p, prcook(1 << sh)));
+	p->n_su = MKIDX(ixp[i], 0);
+	SCLASS(p->n_su, sh);
+	return sh;
+}
+
+/*
+ * Find a leaf type node that puts the value into a register.
+ */
+int
+findleaf(NODE *p, int cookie)
+{
+	extern int *qtable[];
+	struct optab *q = NULL; /* XXX gcc */
+	int i, sh;
+	int *ixp;
+
+	F2DEBUG(("findleaf p %p (%s)\n", p, prcook(cookie)));
+	F2WALK(p);
+
+	ixp = qtable[p->n_op];
+	for (i = 0; ixp[i] >= 0; i++) {
+		q = &table[ixp[i]];
+
+		F2DEBUG(("findleaf: ixp %d\n", ixp[i]));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
+		if ((q->visit & cookie) == 0)
+			continue; /* wrong registers */
+
+		if (ttype(p->n_type, q->rtype) == 0 ||
+		    ttype(p->n_type, q->ltype) == 0)
+			continue; /* Types must be correct */
+
+		F2DEBUG(("findleaf got types, rshape %s\n", prcook(q->rshape)));
+
+		if (chcheck(p, q->rshape, 0) != SRDIR)
+			continue;
+
+		if (q->needs & REWRITE)
+			break;	/* Done here */
+
+		break;
+	}
+	if (ixp[i] < 0) {
+		F2DEBUG(("findleaf failed\n"));
+		if (setuni(p, cookie))
+			return FRETRY;
+		return FFAIL;
+	}
+	F2DEBUG(("findleaf entry %d\n", ixp[i]));
+
+	sh = ffs(cookie & q->visit & INREGS)-1;
+	F2DEBUG(("findleaf: node %p (%s)\n", p, prcook(1 << sh)));
+	p->n_su = MKIDX(ixp[i], 0);
+	SCLASS(p->n_su, sh);
+	return sh;
+}
+
+/*
+ * Find a UNARY op that satisfy the needs.
+ * For now, the destination is always a register.
+ * Both source and dest types must match, but only source (left)
+ * shape is of interest.
+ */
+int
+finduni(NODE *p, int cookie)
+{
+	extern int *qtable[];
+	struct optab *q;
+	NODE *l, *r;
+	int i, shl = 0, num = 4;
+	int *ixp, idx = 0;
+	int sh;
+
+	F2DEBUG(("finduni tree: %s\n", prcook(cookie)));
+	F2WALK(p);
+
+	l = getlr(p, 'L');
+	if (p->n_op == CALL || p->n_op == FORTCALL || p->n_op == STCALL)
+		r = p;
+	else
+		r = getlr(p, 'R');
+	ixp = qtable[p->n_op];
+	for (i = 0; ixp[i] >= 0; i++) {
+		q = &table[ixp[i]];
+
+		F2DEBUG(("finduni: ixp %d\n", ixp[i]));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
+
+		if (ttype(l->n_type, q->ltype) == 0)
+			continue; /* Type must be correct */
+
+		F2DEBUG(("finduni got left type\n"));
+		if (ttype(r->n_type, q->rtype) == 0)
+			continue; /* Type must be correct */
+
+		F2DEBUG(("finduni got types\n"));
+		if ((shl = chcheck(l, q->lshape, q->rewrite & RLEFT)) == SRNOPE)
+			continue;
+
+		F2DEBUG(("finduni got shapes %d\n", shl));
+
+		if ((cookie & q->visit) == 0)	/* check correct return value */
+			continue;		/* XXX - should check needs */
+
+		/* avoid clobbering of longlived regs */
+		/* let register allocator coalesce */
+		if ((q->rewrite & RLEFT) && (shl == SRDIR) /* && isreg(l) */)
+			shl = SRREG;
+
+		F2DEBUG(("finduni got cookie\n"));
+		if (q->needs & REWRITE)
+			break;	/* Done here */
+
+		if (shl >= num)
+			continue;
+		num = shl;
+		idx = ixp[i];
+
+		if (shl == SRDIR)
+			break;
+	}
+
+	if (num == 4) {
+		F2DEBUG(("finduni failed\n"));
+	} else
+		F2DEBUG(("finduni entry %d(%s)\n", idx, srtyp[num]));
+
+	if (num == 4) {
+		if (setuni(p, cookie))
+			return FRETRY;
+		return FFAIL;
+	}
+	q = &table[idx];
+
+	sh = shswitch(-1, p->n_left, q->lshape, cookie,
+	    q->rewrite & RLEFT, num);
+	if (sh == -1)
+		sh = ffs(cookie & q->visit & INREGS)-1;
+	if (sh == -1)
+		sh = 0;
+
+	F2DEBUG(("finduni: node %p (%s)\n", p, prcook(1 << sh)));
+	p->n_su = MKIDX(idx, 0);
+	SCLASS(p->n_su, sh);
+	return sh;
+}
+
+#ifdef FINDMOPS
+/*
+ * Try to find constructs like "a = a + 1;" and match them together
+ * with instructions like "incl a" or "addl $1,a".
+ *
+ * Level assignment for priority:
+ *	left	right	prio
+ *	-	-	-
+ *	direct	direct	1
+ *	direct	REG	2
+ *	direct	OREG	3
+ *	OREG	direct	4
+ *	OREG	REG	5
+ *	OREG	OREG	6
+ */
+int
+findmops(NODE *p, int cookie)
+{
+	extern int *qtable[];
+	struct optab *q;
+	int i, sh, shl, shr, lvl = 10;
+	NODE *l, *r;
+	int *ixp;
+	struct optab *qq = NULL; /* XXX gcc */
+	int idx = 0, gol = 0, gor = 0;
+
+	shl = shr = 0;
+
+	F2DEBUG(("findmops tree: %s\n", prcook(cookie)));
+	F2WALK(p);
+
+	l = getlr(p, 'L');
+	r = getlr(p, 'R');
+	/* See if this is a usable tree to work with */
+	/* Currently only check for leaves */
+	if (optype(r->n_op) != BITYPE || treecmp(l, r->n_left) == 0)
+		return FFAIL;
+
+	F2DEBUG(("findmops is useable\n"));
+
+	/* We can try to find a match.  Use right op */
+	ixp = qtable[r->n_op];
+	l = getlr(r, 'L');
+	r = getlr(r, 'R');
+
+	for (i = 0; ixp[i] >= 0; i++) {
+		q = &table[ixp[i]];
+
+		F2DEBUG(("findmops: ixp %d\n", ixp[i]));
+		if (!acceptable(q))		/* target-dependent filter */
+			continue;
+
+		if (ttype(l->n_type, q->ltype) == 0 ||
+		    ttype(r->n_type, q->rtype) == 0)
+			continue; /* Types must be correct */
+
+		F2DEBUG(("findmops got types\n"));
+
+		switch (cookie) {
+		case FOREFF:
+			if ((q->visit & FOREFF) == 0)
+				continue; /* Not only for side effects */
+			break;
+		case FORCC:
+			if ((q->visit & FORCC) == 0)
+				continue; /* Not only for side effects */
+			break;
+		default:
+			if ((cookie & q->visit) == 0)
+				continue; /* Won't match requested shape */
+			if (((cookie & INREGS & q->lshape) == 0) || !isreg(l))
+				continue; /* Bad return register */
+			break;
+		}
+		F2DEBUG(("findmops cookie\n"));
+
+		/*
+		 * left shape must match left node.
+		 */
+		if ((shl = tshape(l, q->lshape)) != SRDIR && (shl != SROREG))
+			continue;
+
+		F2DEBUG(("findmops lshape %s\n", srtyp[shl]));
+		F2WALK(l);
+
+		if ((shr = chcheck(r, q->rshape, 0)) == SRNOPE)
+			continue;
+
+		F2DEBUG(("findmops rshape %s\n", srtyp[shr]));
+
+		/*
+		 * Only allow RLEFT. XXX
+		 */
+		if ((q->rewrite & (RLEFT|RRIGHT)) != RLEFT)
+			continue;
+
+		F2DEBUG(("rewrite OK\n"));
+
+		F2WALK(r);
+		if (q->needs & REWRITE)
+			break;	/* Done here */
+
+		if (lvl <= (shl + shr))
+			continue;
+
+		lvl = shl + shr;
+		qq = q;
+		idx = ixp[i];
+		gol = shl;
+		gor = shr;
+	}
+
+	if (lvl == 10)
+		return FFAIL;
+	F2DEBUG(("findmops entry %d(%s,%s)\n", idx, srtyp[gol], srtyp[gor]));
+
+	/*
+	 * Now we're here and have a match. left is semi-direct and 
+	 * right may be anything.
+	 */
+
+	sh = -1;
+	sh = shswitch(sh, p->n_left, qq->lshape, cookie,
+	    qq->rewrite & RLEFT, gol);
+	sh = shswitch(sh, r, qq->rshape, cookie, 0, gor);
+
+	if (sh == -1) {
+		if (cookie & (FOREFF|FORCC))
+			sh = 0;
+		else
+			sh = ffs(cookie & qq->visit & INREGS)-1;
+	}
+	F2DEBUG(("findmops done: node %p class %d\n", p, sh));
+
+	/* Trickery:  Set table index on assign to op instead */
+	/* gencode() will remove useless nodes */
+	p->n_su = MKIDX(idx, 0);
+	p->n_flags |= 1; /* XXX tell gencode to reduce the right tree */
+	SCLASS(p->n_su, sh);
+
+	return sh;
+}
+
+/*
+ * Compare two trees; return 1 if equal and 0 if not.
+ */
+int
+treecmp(NODE *p1, NODE *p2)
+{
+	if (p1->n_op != p2->n_op)
+		return 0;
+
+	switch (p1->n_op) {
+	case SCONV:
+	case UMUL:
+		return treecmp(p1->n_left, p2->n_left);
+
+	case OREG:
+		if (p1->n_lval != p2->n_lval || p1->n_rval != p2->n_rval)
+			return 0;
+		break;
+
+	case NAME:
+	case ICON:
+		if (strcmp(p1->n_name, p2->n_name))
+			return 0;
+		/* FALLTHROUGH */
+		if (p1->n_lval != p2->n_lval)
+			return 0;
+		break;
+
+	case TEMP:
+#ifdef notyet
+		/* SSA will put assignment in separate register */
+		/* Help out by accepting different regs here */
+		if (xssaflag)
+			break;
+#endif
+	case REG:
+		if (p1->n_rval != p2->n_rval)
+			return 0;
+		break;
+	case LS:
+	case RS:
+	case PLUS:
+	case MINUS:
+	case MUL:
+	case DIV:
+		if (treecmp(p1->n_left, p2->n_left) == 0 ||
+		    treecmp(p1->n_right, p2->n_right) == 0)
+			return 0;
+		break;
+
+	default:
+		return 0;
+	}
+	return 1;
+}
+#endif
Index: uspace/app/pcc/mip/mkext.c
===================================================================
--- uspace/app/pcc/mip/mkext.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/mip/mkext.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,474 @@
+
+/*
+ * Generate defines for the needed hardops.
+ */
+#include "pass2.h"
+#include <stdlib.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_C99_FORMAT
+#define FMTdPTR "%td"
+#else
+#if defined(_WIN64) || defined(LP64)
+#define FMTdPTR "%ld"
+#else
+#define FMTdPTR "%d"
+#endif
+#endif
+
+int chkop[DSIZE];
+
+void mktables(void);
+
+char *ftitle;
+char *cname = "external.c";
+char *hname = "external.h";
+FILE *fc, *fh;
+
+/*
+ * masks for matching dope with shapes
+ */
+int mamask[] = {
+        SIMPFLG,                /* OPSIMP */
+        SIMPFLG|ASGFLG,         /* ASG OPSIMP */
+        COMMFLG,        /* OPCOMM */
+        COMMFLG|ASGFLG, /* ASG OPCOMM */
+        MULFLG,         /* OPMUL */
+        MULFLG|ASGFLG,  /* ASG OPMUL */
+        DIVFLG,         /* OPDIV */
+        DIVFLG|ASGFLG,  /* ASG OPDIV */
+        UTYPE,          /* OPUNARY */
+        TYFLG,          /* ASG OPUNARY is senseless */
+        LTYPE,          /* OPLEAF */
+        TYFLG,          /* ASG OPLEAF is senseless */
+        0,              /* OPANY */
+        ASGOPFLG|ASGFLG,        /* ASG OPANY */
+        LOGFLG,         /* OPLOG */
+        TYFLG,          /* ASG OPLOG is senseless */
+        FLOFLG,         /* OPFLOAT */
+        FLOFLG|ASGFLG,  /* ASG OPFLOAT */
+        SHFFLG,         /* OPSHFT */
+        SHFFLG|ASGFLG,  /* ASG OPSHIFT */
+        SPFLG,          /* OPLTYPE */
+        TYFLG,          /* ASG OPLTYPE is senseless */
+        };
+
+
+struct checks {
+	int op, type;
+	char *name;
+} checks[] = {
+	{ MUL, TLONGLONG, "SMULLL", },
+	{ DIV, TLONGLONG, "SDIVLL", },
+	{ MOD, TLONGLONG, "SMODLL", },
+	{ PLUS, TLONGLONG, "SPLUSLL", },
+	{ MINUS, TLONGLONG, "SMINUSLL", },
+	{ MUL, TULONGLONG, "UMULLL", },
+	{ DIV, TULONGLONG, "UDIVLL", },
+	{ MOD, TULONGLONG, "UMODLL", },
+	{ PLUS, TULONGLONG, "UPLUSLL", },
+	{ MINUS, TULONGLONG, "UMINUSLL", },
+	{ 0, 0, 0, },
+};
+
+int rstatus[] = { RSTATUS };
+int roverlay[MAXREGS][MAXREGS] = { ROVERLAP };
+int regclassmap[CLASSG][MAXREGS]; /* CLASSG is highest class */
+
+static void
+compl(struct optab *q, char *str)
+{
+	int op = q->op;
+	char *s;
+
+	if (op < OPSIMP) {
+		s = opst[op];
+	} else
+		switch (op) {
+		default:	s = "Special op";	break;
+		case OPSIMP:	s = "OPLSIMP";	break;
+		case OPCOMM:	s = "OPCOMM";	break;
+		case OPMUL:	s = "OPMUL";	break;
+		case OPDIV:	s = "OPDIV";	break;
+		case OPUNARY:	s = "OPUNARY";	break;
+		case OPLEAF:	s = "OPLEAF";	break;
+		case OPANY:	s = "OPANY";	break;
+		case OPLOG:	s = "OPLOG";	break;
+		case OPFLOAT:	s = "OPFLOAT";	break;
+		case OPSHFT:	s = "OPSHFT";	break;
+		case OPLTYPE:	s = "OPLTYPE";	break;
+		}
+
+	printf("table entry " FMTdPTR ", op %s: %s\n", q - table, s, str);
+}
+
+static int
+getrcl(struct optab *q)
+{
+	int v = q->needs &
+	    (NACOUNT|NBCOUNT|NCCOUNT|NDCOUNT|NECOUNT|NFCOUNT|NGCOUNT);
+	int r = q->rewrite & RESC1 ? 1 : q->rewrite & RESC2 ? 2 : 3;
+	int i = 0;
+
+#define INCK(c) while (v & c##COUNT) { \
+	v -= c##REG, i++; if (i == r) return I##c##REG; }
+	INCK(NA)
+	INCK(NB)
+	INCK(NC)
+	INCK(ND)
+	INCK(NE)
+	INCK(NF)
+	INCK(NG)
+	return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+	struct optab *q;
+	struct checks *ch;
+	int i, j, areg, breg, creg, dreg, mx, ereg, freg, greg;
+	char *bitary;
+	int bitsz, rval, nelem;
+
+	if (argc == 2) {
+		i = atoi(argv[1]);
+		printf("Entry %d:\n%s\n", i, table[i].cstring);
+		return 0;
+	}
+
+	mkdope();
+
+	for (q = table; q->op != FREE; q++) {
+		if (q->op >= OPSIMP)
+			continue;
+		if ((q->ltype & TLONGLONG) &&
+		    (q->rtype & TLONGLONG))
+			chkop[q->op] |= TLONGLONG;
+		if ((q->ltype & TULONGLONG) &&
+		    (q->rtype & TULONGLONG))
+			chkop[q->op] |= TULONGLONG;
+	}
+	if ((fc = fopen(cname, "w")) == NULL) {
+		perror("open cfile");
+		return(1);
+	}
+	if ((fh = fopen(hname, "w")) == NULL) {
+		perror("open hfile");
+		return(1);
+	}
+	fprintf(fh, "#ifndef _EXTERNAL_H_\n#define _EXTERNAL_H_\n");
+
+	for (ch = checks; ch->op != 0; ch++) {
+		if ((chkop[ch->op] & ch->type) == 0)
+			fprintf(fh, "#define NEED_%s\n", ch->name);
+	}
+
+	fprintf(fc, "#include \"pass2.h\"\n");
+	/* create fast-lookup tables */
+	mktables();
+
+	/* create efficient bitset sizes */
+	if (sizeof(long) == 8) { /* 64-bit arch */
+		bitary = "long";
+		bitsz = 64;
+	} else {
+		bitary = "int";
+		bitsz = sizeof(int) == 4 ? 32 : 16;
+	}
+	fprintf(fh, "#define NUMBITS %d\n", bitsz);
+	fprintf(fh, "#define BIT2BYTE(bits) "
+	     "((((bits)+NUMBITS-1)/NUMBITS)*(NUMBITS/8))\n");
+	fprintf(fh, "#define BITSET(arr, bit) "
+	     "(arr[bit/NUMBITS] |= ((%s)1 << (bit & (NUMBITS-1))))\n",
+	     bitary);
+	fprintf(fh, "#define BITCLEAR(arr, bit) "
+	     "(arr[bit/NUMBITS] &= ~((%s)1 << (bit & (NUMBITS-1))))\n",
+	     bitary);
+	fprintf(fh, "#define TESTBIT(arr, bit) "
+	     "(arr[bit/NUMBITS] & ((%s)1 << (bit & (NUMBITS-1))))\n",
+	     bitary);
+	fprintf(fh, "typedef %s bittype;\n", bitary);
+
+	/* register class definitions, used by graph-coloring */
+	/* TODO */
+
+	/* Sanity-check the table */
+	rval = 0;
+	for (q = table; q->op != FREE; q++) {
+		switch (q->op) {
+		case ASSIGN:
+#define	F(x) (q->visit & x && q->rewrite & (RLEFT|RRIGHT) && \
+		    q->lshape & ~x && q->rshape & ~x)
+			if (F(INAREG) || F(INBREG) || F(INCREG) || F(INDREG) ||
+			    F(INEREG) || F(INFREG) || F(INGREG)) {
+				compl(q, "may match without result register");
+				rval++;
+			}
+#undef F
+			/* FALLTHROUGH */
+		case STASG:
+			if ((q->visit & INREGS) && !(q->rewrite & RDEST)) {
+				compl(q, "ASSIGN/STASG reclaim must be RDEST");
+				rval++;
+			}
+			break;
+		}
+		/* check that reclaim is not the wrong class */
+		if ((q->rewrite & (RESC1|RESC2|RESC3)) && 
+		    !(q->needs & REWRITE)) {
+			if ((q->visit & getrcl(q)) == 0) {
+				compl(q, "wrong RESCx class");
+				rval++;
+			}
+		}
+		if (q->rewrite & (RESC1|RESC2|RESC3) && q->visit & FOREFF)
+			compl(q, "FOREFF may cause reclaim of wrong class");
+	}
+
+	/* print out list of scratched and permanent registers */
+	fprintf(fh, "extern int tempregs[], permregs[];\n");
+	fprintf(fc, "int tempregs[] = { ");
+	for (i = j = 0; i < MAXREGS; i++)
+		if (rstatus[i] & TEMPREG)
+			fprintf(fc, "%d, ", i), j++;
+	fprintf(fc, "-1 };\n");
+	fprintf(fh, "#define NTEMPREG %d\n", j+1);
+	fprintf(fh, "#define FREGS %d\n", j);	/* XXX - to die */
+	fprintf(fc, "int permregs[] = { ");
+	for (i = j = 0; i < MAXREGS; i++)
+		if (rstatus[i] & PERMREG)
+			fprintf(fc, "%d, ", i), j++;
+	fprintf(fc, "-1 };\n");
+	fprintf(fh, "#define NPERMREG %d\n", j+1);
+	fprintf(fc, "bittype validregs[] = {\n");
+
+if (bitsz == 64) {
+	for (j = 0; j < MAXREGS; j += bitsz) {
+		long cbit = 0;
+		for (i = 0; i < bitsz; i++) {
+			if (i+j == MAXREGS)
+				break;
+			if (rstatus[i+j] & INREGS)
+				cbit |= ((long)1 << i);
+		}
+		fprintf(fc, "\t0x%lx,\n", cbit);
+	}
+} else {
+	for (j = 0; j < MAXREGS; j += bitsz) {
+		int cbit = 0;
+		for (i = 0; i < bitsz; i++) {
+			if (i+j == MAXREGS)
+				break;
+			if (rstatus[i+j] & INREGS)
+				cbit |= (1 << i);
+		}
+		fprintf(fc, "\t0x%08x,\n", cbit);
+	}
+}
+
+	fprintf(fc, "};\n");
+	fprintf(fh, "extern bittype validregs[];\n");
+
+	/*
+	 * The register allocator uses bitmasks of registers for each class.
+	 */
+	areg = breg = creg = dreg = ereg = freg = greg = 0;
+	for (i = 0; i < MAXREGS; i++) {
+		for (j = 0; j < NUMCLASS; j++)
+			regclassmap[j][i] = -1;
+		if (rstatus[i] & SAREG) regclassmap[0][i] = areg++;
+		if (rstatus[i] & SBREG) regclassmap[1][i] = breg++;
+		if (rstatus[i] & SCREG) regclassmap[2][i] = creg++;
+		if (rstatus[i] & SDREG) regclassmap[3][i] = dreg++;
+		if (rstatus[i] & SEREG) regclassmap[4][i] = ereg++;
+		if (rstatus[i] & SFREG) regclassmap[5][i] = freg++;
+		if (rstatus[i] & SGREG) regclassmap[6][i] = greg++;
+	}
+	fprintf(fh, "#define AREGCNT %d\n", areg);
+	fprintf(fh, "#define BREGCNT %d\n", breg);
+	fprintf(fh, "#define CREGCNT %d\n", creg);
+	fprintf(fh, "#define DREGCNT %d\n", dreg);
+	fprintf(fh, "#define EREGCNT %d\n", ereg);
+	fprintf(fh, "#define FREGCNT %d\n", freg);
+	fprintf(fh, "#define GREGCNT %d\n", greg);
+	if (areg > bitsz)
+		printf("%d regs in class A (max %d)\n", areg, bitsz), rval++;
+	if (breg > bitsz)
+		printf("%d regs in class B (max %d)\n", breg, bitsz), rval++;
+	if (creg > bitsz)
+		printf("%d regs in class C (max %d)\n", creg, bitsz), rval++;
+	if (dreg > bitsz)
+		printf("%d regs in class D (max %d)\n", dreg, bitsz), rval++;
+	if (ereg > bitsz)
+		printf("%d regs in class E (max %d)\n", ereg, bitsz), rval++;
+	if (freg > bitsz)
+		printf("%d regs in class F (max %d)\n", freg, bitsz), rval++;
+	if (greg > bitsz)
+		printf("%d regs in class G (max %d)\n", greg, bitsz), rval++;
+
+	fprintf(fc, "static int amap[MAXREGS][NUMCLASS] = {\n");
+	for (i = 0; i < MAXREGS; i++) {
+		int ba, bb, bc, bd, r, be, bf, bg;
+		ba = bb = bc = bd = be = bf = bg = 0;
+		if (rstatus[i] & SAREG) ba = (1 << regclassmap[0][i]);
+		if (rstatus[i] & SBREG) bb = (1 << regclassmap[1][i]);
+		if (rstatus[i] & SCREG) bc = (1 << regclassmap[2][i]);
+		if (rstatus[i] & SDREG) bd = (1 << regclassmap[3][i]);
+		if (rstatus[i] & SEREG) be = (1 << regclassmap[4][i]);
+		if (rstatus[i] & SFREG) bf = (1 << regclassmap[5][i]);
+		if (rstatus[i] & SGREG) bg = (1 << regclassmap[6][i]);
+		for (j = 0; roverlay[i][j] >= 0; j++) {
+			r = roverlay[i][j];
+			if (rstatus[r] & SAREG)
+				ba |= (1 << regclassmap[0][r]);
+			if (rstatus[r] & SBREG)
+				bb |= (1 << regclassmap[1][r]);
+			if (rstatus[r] & SCREG)
+				bc |= (1 << regclassmap[2][r]);
+			if (rstatus[r] & SDREG)
+				bd |= (1 << regclassmap[3][r]);
+			if (rstatus[r] & SEREG)
+				be |= (1 << regclassmap[4][r]);
+			if (rstatus[r] & SFREG)
+				bf |= (1 << regclassmap[5][r]);
+			if (rstatus[r] & SGREG)
+				bg |= (1 << regclassmap[6][r]);
+		}
+		fprintf(fc, "\t/* %d */{ 0x%x", i, ba);
+		if (NUMCLASS > 1) fprintf(fc, ",0x%x", bb);
+		if (NUMCLASS > 2) fprintf(fc, ",0x%x", bc);
+		if (NUMCLASS > 3) fprintf(fc, ",0x%x", bd);
+		if (NUMCLASS > 4) fprintf(fc, ",0x%x", be);
+		if (NUMCLASS > 5) fprintf(fc, ",0x%x", bf);
+		if (NUMCLASS > 6) fprintf(fc, ",0x%x", bg);
+		fprintf(fc, " },\n");
+	}
+	fprintf(fc, "};\n");
+
+	fprintf(fh, "int aliasmap(int class, int regnum);\n");
+	fprintf(fc, "int\naliasmap(int class, int regnum)\n{\n");
+	fprintf(fc, "	return amap[regnum][class-1];\n}\n");
+
+	/* routines to convert back from color to regnum */
+	mx = areg;
+	if (breg > mx) mx = breg;
+	if (creg > mx) mx = creg;
+	if (dreg > mx) mx = dreg;
+	if (ereg > mx) mx = ereg;
+	if (freg > mx) mx = freg;
+	if (greg > mx) mx = greg;
+	if (mx > (int)(sizeof(int)*8)-1) {
+		printf("too many regs in a class, use two classes instead\n");
+#ifdef HAVE_C99_FORMAT
+		printf("%d > %zu\n", mx, (sizeof(int)*8)-1);
+#else
+		printf("%d > %d\n", mx, (int)(sizeof(int)*8)-1);
+#endif
+		rval++;
+	}
+	fprintf(fc, "static int rmap[NUMCLASS][%d] = {\n", mx);
+	for (j = 0; j < NUMCLASS; j++) {
+		int cl = (1 << (j+1));
+		fprintf(fc, "\t{ ");
+		for (i = 0; i < MAXREGS; i++)
+			if (rstatus[i] & cl) fprintf(fc, "%d, ", i);
+		fprintf(fc, "},\n");
+	}
+	fprintf(fc, "};\n\n");
+
+	fprintf(fh, "int color2reg(int color, int class);\n");
+	fprintf(fc, "int\ncolor2reg(int color, int class)\n{\n");
+	fprintf(fc, "	return rmap[class-1][color];\n}\n");
+
+	/* used by register allocator */
+	fprintf(fc, "int regK[] = { 0, %d, %d, %d, %d, %d, %d, %d };\n",
+	    areg, breg, creg, dreg, ereg, freg, greg);
+	fprintf(fc, "int\nclassmask(int class)\n{\n");
+	fprintf(fc, "\tif(class == CLASSA) return 0x%x;\n", (1 << areg)-1);
+	fprintf(fc, "\tif(class == CLASSB) return 0x%x;\n", (1 << breg)-1);
+	fprintf(fc, "\tif(class == CLASSC) return 0x%x;\n", (1 << creg)-1);
+	fprintf(fc, "\tif(class == CLASSD) return 0x%x;\n", (1 << dreg)-1);
+	fprintf(fc, "\tif(class == CLASSE) return 0x%x;\n", (1 << ereg)-1);
+	fprintf(fc, "\tif(class == CLASSF) return 0x%x;\n", (1 << freg)-1);
+	fprintf(fc, "\treturn 0x%x;\n}\n", (1 << greg)-1);
+
+	fprintf(fh, "int interferes(int reg1, int reg2);\n");
+	nelem = (MAXREGS+bitsz-1)/bitsz;
+	fprintf(fc, "static bittype ovlarr[MAXREGS][%d] = {\n", nelem);
+	for (i = 0; i < MAXREGS; i++) {
+		int el[10];
+		memset(el, 0, sizeof(el));
+		el[i/bitsz] = 1 << (i % bitsz);
+		for (j = 0; roverlay[i][j] >= 0; j++) {
+			int k = roverlay[i][j];
+			el[k/bitsz] |= (1 << (k % bitsz));
+		}
+		fprintf(fc, "{ ");
+		for (j = 0; j < MAXREGS; j += bitsz)
+			fprintf(fc, "0x%x, ", el[j/bitsz]);
+		fprintf(fc, " },\n");
+	}
+	fprintf(fc, "};\n");
+
+	fprintf(fc, "int\ninterferes(int reg1, int reg2)\n{\n");
+	fprintf(fc, "return (TESTBIT(ovlarr[reg1], reg2)) != 0;\n}\n");
+	fclose(fc);
+	fprintf(fh, "#endif /* _EXTERNAL_H_ */\n");
+	fclose(fh);
+	return rval;
+}
+
+#define	P(x)	fprintf x
+
+void
+mktables()
+{
+	struct optab *op;
+	int mxalen = 0, curalen;
+	int i;
+
+#if 0
+	P((fc, "#include \"pass2.h\"\n\n"));
+#endif
+	for (i = 0; i <= MAXOP; i++) {
+		curalen = 0;
+		P((fc, "static int op%d[] = { ", i));
+		if (dope[i] != 0)
+		for (op = table; op->op != FREE; op++) {
+			if (op->op < OPSIMP) {
+				if (op->op == i) {
+					P((fc, FMTdPTR ", ", op - table));
+					curalen++;
+				}
+			} else {
+				int opmtemp;
+				if ((opmtemp=mamask[op->op - OPSIMP])&SPFLG) {
+					if (i==NAME || i==ICON || i==TEMP ||
+					    i==OREG || i == REG || i == FCON) {
+						P((fc, FMTdPTR ", ",
+						    op - table));
+						curalen++;
+					}
+				} else if ((dope[i]&(opmtemp|ASGFLG))==opmtemp){
+					P((fc, FMTdPTR ", ", op - table));
+					curalen++;
+				}
+			}
+		}
+		if (curalen > mxalen)
+			mxalen = curalen;
+		P((fc, "-1 };\n"));
+	}
+	P((fc, "\n"));
+
+	P((fc, "int *qtable[] = { \n"));
+	for (i = 0; i <= MAXOP; i++) {
+		P((fc, "	op%d,\n", i));
+	}
+	P((fc, "};\n"));
+	P((fh, "#define MAXOPLEN %d\n", mxalen+1));
+}
Index: uspace/app/pcc/mip/node.h
===================================================================
--- uspace/app/pcc/mip/node.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/mip/node.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,236 @@
+/*	$Id: node.h,v 1.36 2010/08/11 14:08:44 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.
+ */
+
+#ifndef NODE_H
+#define NODE_H
+
+/*
+ * The attribute struct contains stuff that might be useful in
+ * both passes; but currently it's only legal to use it in pass1.
+ */
+union aarg {
+	int iarg;
+	char *sarg;
+	void *varg;
+};
+
+struct attr {
+	struct attr *next;
+	int atype;
+	union aarg aa[];
+};
+
+/*
+ * The node structure is the basic element in the compiler.
+ * Depending on the operator, it may be one of several types.
+ *
+ * This is rewritten to be a struct instead of a union as it
+ * was in the old compiler.
+ */
+typedef unsigned int TWORD;
+#define NIL (NODE *)0
+
+struct symtab;
+struct suedef;
+struct regw;
+
+typedef struct node {
+	struct	node *next;
+	int	n_op;
+	union {
+		int _reg;
+		struct regw *_regw;
+	} n_3;
+#define	n_reg	n_3._reg
+#define	n_regw	n_3._regw
+	TWORD	n_type;
+	TWORD	n_qual;
+	int	n_su;
+	union {
+		char *	_name;
+		int	_stsize;
+		union	dimfun *_df;
+	} n_5;
+	union {
+		int	_label;
+		int	_stalign;
+		int	_flags;
+#if 0
+		/* not anymore */
+		struct	suedef *_sue;
+#else
+		struct attr *_ap;
+#endif
+	} n_6;
+	union {
+		struct {
+			union {
+				struct node *_left;
+				CONSZ _lval;
+#ifdef SPECIAL_INTEGERS
+				SPECLVAL _slval;
+#endif
+			} n_l;
+			union {
+				struct node *_right;
+				int _rval;
+				struct symtab *_sp;
+			} n_r;
+		} n_u;
+#ifdef SOFTFLOAT
+#ifdef FDFLOAT
+		/* To store F- or D-floats */
+		struct softfloat {
+			unsigned short fd1, fd2, fd3, fd4;
+		} _dcon;
+#else
+#error missing softfloat structure definition
+#endif
+#else
+		long double	_dcon;
+#endif
+	} n_f;
+} NODE;
+
+#define	n_name	n_5._name
+#define	n_stsize n_5._stsize
+#define	n_df	n_5._df
+
+#define	n_label	n_6._label
+#define	n_stalign n_6._stalign
+#define	n_flags n_6._flags
+#define	n_ap	n_6._ap
+
+#define	n_left	n_f.n_u.n_l._left
+#define	n_lval	n_f.n_u.n_l._lval
+#define	n_slval	n_f.n_u.n_l._slval
+#define	n_right	n_f.n_u.n_r._right
+#define	n_rval	n_f.n_u.n_r._rval
+#define	n_sp	n_f.n_u.n_r._sp
+#define	n_dcon	n_f._dcon
+
+#define	NLOCAL1	010000
+#define	NLOCAL2	020000
+#define	NLOCAL3	040000
+/*
+ * Node types.
+ *
+ * MAXOP is the highest number used by the backend.
+ */
+
+#define FREE	1
+/*
+ * Value nodes.
+ */
+#define NAME	2
+#define ICON	4
+#define FCON	5
+#define REG	6
+#define OREG	7
+#define TEMP	8
+#define XARG	9
+
+/*
+ * Arithmetic nodes.
+ */
+#define PLUS	10
+#define MINUS	11
+#define DIV	12
+#define MOD	13
+#define MUL	14
+
+/*
+ * Bitwise operations.
+ */
+#define AND	15
+#define OR	16
+#define ER	17
+#define LS	18
+#define RS	19
+#define COMPL	20
+
+#define UMUL	23
+#define UMINUS	24
+
+/*
+ * Logical compare nodes.
+ */
+#define EQ	25
+#define NE	26
+#define LE	27
+#define LT	28
+#define GE	29
+#define GT	30
+#define ULE	31
+#define ULT	32
+#define UGE	33
+#define UGT	34
+
+/*
+ * Branch nodes.
+ */
+#define CBRANCH	35
+
+/*
+ * Convert types.
+ */
+#define FLD	36
+#define SCONV	37
+#define PCONV	38
+#define PMCONV	39
+#define PVCONV	40
+
+/*
+ * Function calls.
+ */
+#define CALL	41
+#define	UCALL	42
+#define FORTCALL 43
+#define UFORTCALL 44
+#define STCALL	45
+#define USTCALL	46
+
+/*
+ *  Other used nodes.
+ */
+#define CCODES	47
+#define CM	48
+#define ASSIGN	49
+#define STASG	50
+#define STARG	51
+#define FORCE	52
+#define XASM	53
+#define	GOTO	54
+#define	RETURN	55
+#define STREF	56
+#define	FUNARG	57
+#define	ADDROF	58
+
+#define	MAXOP	58
+
+#endif
Index: uspace/app/pcc/mip/optim2.c
===================================================================
--- uspace/app/pcc/mip/optim2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/mip/optim2.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,2144 @@
+/*	$Id: optim2.c,v 1.79 2010/06/04 07:18:46 ragge Exp $	*/
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pass2.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#define	BDEBUG(x)	if (b2debug) printf x
+
+#define	mktemp(n, t)	mklnode(TEMP, 0, n, t)
+
+#define	CHADD(bb,c)	{ if (bb->ch[0] == 0) bb->ch[0] = c; \
+			  else if (bb->ch[1] == 0) bb->ch[1] = c; \
+			  else comperr("triple cfnodes"); }
+#define	FORCH(cn, chp)	\
+	for (cn = &chp[0]; cn < &chp[2] && cn[0]; cn++)
+
+/* main switch for new things not yet ready for all-day use */
+/* #define ENABLE_NEW */
+
+
+static int dfsnum;
+
+void saveip(struct interpass *ip);
+void deljumps(struct p2env *);
+void optdump(struct interpass *ip);
+void printip(struct interpass *pole);
+
+static struct varinfo defsites;
+struct interpass *storesave;
+
+void bblocks_build(struct p2env *);
+void cfg_build(struct p2env *);
+void cfg_dfs(struct basicblock *bb, unsigned int parent, 
+	     struct bblockinfo *bbinfo);
+void dominators(struct p2env *);
+struct basicblock *
+ancestorwithlowestsemi(struct basicblock *bblock, struct bblockinfo *bbinfo);
+void link(struct basicblock *parent, struct basicblock *child);
+void computeDF(struct p2env *, struct basicblock *bblock);
+void printDF(struct p2env *p2e);
+void findTemps(struct interpass *ip);
+void placePhiFunctions(struct p2env *);
+void renamevar(struct p2env *p2e,struct basicblock *bblock);
+void removephi(struct p2env *p2e);
+void remunreach(struct p2env *);
+static void liveanal(struct p2env *p2e);
+static void printip2(struct interpass *);
+
+/* create "proper" basic blocks, add labels where needed (so bblocks have labels) */
+/* run before bb generate */
+static void add_labels(struct p2env*) ;
+
+/* Perform trace scheduling, try to get rid of gotos as much as possible */
+void TraceSchedule(struct p2env*) ;
+
+#ifdef ENABLE_NEW
+static void do_cse(struct p2env* p2e) ;
+#endif
+
+/* Walk the complete set, performing a function on each node. 
+ * if type is given, apply function on only that type */
+void WalkAll(struct p2env* p2e, void (*f) (NODE*, void*), void* arg, int type) ;
+
+void BBLiveDead(struct basicblock* bblock, int what, unsigned int variable) ;
+
+/* Fill the live/dead code */
+void LiveDead(struct p2env* p2e, int what, unsigned int variable) ;
+
+#ifdef PCC_DEBUG
+void printflowdiagram(struct p2env *, char *);
+#endif
+
+void
+optimize(struct p2env *p2e)
+{
+	struct interpass *ipole = &p2e->ipole;
+
+	if (b2debug) {
+		printf("initial links\n");
+		printip(ipole);
+	}
+
+	if (xdeljumps)
+		deljumps(p2e); /* Delete redundant jumps and dead code */
+
+	if (xssaflag)
+		add_labels(p2e) ;
+#ifdef ENABLE_NEW
+	do_cse(p2e);
+#endif
+
+#ifdef PCC_DEBUG
+	if (b2debug) {
+		printf("links after deljumps\n");
+		printip(ipole);
+	}
+#endif
+	if (xssaflag || xtemps) {
+		bblocks_build(p2e);
+		BDEBUG(("Calling cfg_build\n"));
+		cfg_build(p2e);
+	
+#ifdef PCC_DEBUG
+		printflowdiagram(p2e, "first");
+#endif
+	}
+	if (xssaflag) {
+		BDEBUG(("Calling liveanal\n"));
+		liveanal(p2e);
+		BDEBUG(("Calling dominators\n"));
+		dominators(p2e);
+		BDEBUG(("Calling computeDF\n"));
+		computeDF(p2e, DLIST_NEXT(&p2e->bblocks, bbelem));
+
+		if (b2debug) {
+			printDF(p2e);
+		}
+
+		BDEBUG(("Calling placePhiFunctions\n"));
+
+		placePhiFunctions(p2e);
+
+		BDEBUG(("Calling renamevar\n"));
+
+		renamevar(p2e,DLIST_NEXT(&p2e->bblocks, bbelem));
+
+		BDEBUG(("Calling removephi\n"));
+
+#ifdef PCC_DEBUG
+		printflowdiagram(p2e, "ssa");
+#endif
+
+		removephi(p2e);
+
+		BDEBUG(("Calling remunreach\n"));
+/*		remunreach(p2e); */
+		
+		/*
+		 * Recalculate basic blocks and cfg that was destroyed
+		 * by removephi
+		 */
+		/* first, clean up all what deljumps should have done, and more */
+
+		/* TODO: add the basic blocks done by the ssa code by hand. 
+		 * The trace scheduler should not change the order in
+		 * which blocks are executed or what data is calculated.
+		 * Thus, the BBlock order should remain correct.
+		 */
+
+#ifdef ENABLE_NEW
+		bblocks_build(p2e, &labinfo, &bbinfo);
+		BDEBUG(("Calling cfg_build\n"));
+		cfg_build(p2e, &labinfo);
+
+		TraceSchedule(p2e);
+#ifdef PCC_DEBUG
+		printflowdiagram(p2e, &labinfo, &bbinfo,"sched_trace");
+
+		if (b2debug) {
+			printf("after tracesched\n");
+			printip(ipole);
+			fflush(stdout) ;
+		}
+#endif
+#endif
+
+		/* Now, clean up the gotos we do not need any longer */
+		if (xdeljumps)
+			deljumps(p2e); /* Delete redundant jumps and dead code */
+
+		bblocks_build(p2e);
+		BDEBUG(("Calling cfg_build\n"));
+		cfg_build(p2e);
+
+#ifdef PCC_DEBUG
+		printflowdiagram(p2e, "no_phi");
+
+		if (b2debug) {
+			printf("new tree\n");
+			printip(ipole);
+		}
+#endif
+	}
+
+#ifdef PCC_DEBUG
+	{
+		int i;
+		for (i = NIPPREGS; i--; )
+			if (p2e->epp->ipp_regs[i] != 0)
+				comperr("register error");
+	}
+#endif
+
+	myoptim(ipole);
+}
+
+/*
+ * Delete unused labels, excess of labels, gotos to gotos.
+ * This routine can be made much more efficient.
+ *
+ * Layout of the statement list here (_must_ look this way!):
+ *	PROLOG
+ *	LABEL	- states beginning of function argument moves
+ *	...code to save/move arguments
+ *	LABEL	- states beginning of execution code
+ *	...code + labels in function in function
+ *	EPILOG
+ *
+ * This version of deljumps is based on the c2 implementation
+ * that were included in 2BSD.
+ */
+#define	LABEL 1
+#define	JBR	2
+#define	CBR	3
+#define	STMT	4
+#define	EROU	5
+struct dlnod {
+	int op;
+	struct interpass *dlip;
+	struct dlnod *forw;
+	struct dlnod *back;
+	struct dlnod *ref;
+	int labno;
+	int refc;
+};
+
+#ifdef DLJDEBUG
+static void
+dumplink(struct dlnod *dl)
+{
+	printf("dumplink %p\n", dl);
+	for (; dl; dl = dl->forw) {
+		if (dl->op == STMT) {
+			printf("STMT(%p)\n", dl);
+			fwalk(dl->dlip->ip_node, e2print, 0);
+		} else if (dl->op == EROU) {
+			printf("EROU(%p)\n", dl);
+		} else {
+			static char *str[] = { 0, "LABEL", "JBR", "CBR" };
+			printf("%s(%p) %d refc %d ref %p\n", str[dl->op], 
+			    dl, dl->labno, dl->refc, dl->ref);
+		}
+	}
+	printf("end dumplink\n");
+}
+#endif
+
+/*
+ * Create the linked list that we can work on.
+ */
+static void
+listsetup(struct interpass *ipole, struct dlnod *dl)
+{
+	struct interpass *ip = DLIST_NEXT(ipole, qelem);
+	struct interpass *nip;
+	struct dlnod *p, *lastp;
+	NODE *q;
+
+	lastp = dl;
+	while (ip->type != IP_DEFLAB)
+		ip = DLIST_NEXT(ip,qelem);
+	ip = DLIST_NEXT(ip,qelem);
+	while (ip->type != IP_DEFLAB)
+		ip = DLIST_NEXT(ip,qelem);
+	/* Now ip is at the beginning */
+	for (;;) {
+		ip = DLIST_NEXT(ip,qelem);
+		if (ip == ipole)
+			break;
+		p = tmpalloc(sizeof(struct dlnod));
+		p->labno = 0;
+		p->dlip = ip;
+		switch (ip->type) {
+		case IP_DEFLAB:
+			p->op = LABEL;
+			p->labno = ip->ip_lbl;
+			break;
+
+		case IP_NODE:
+			q = ip->ip_node;
+			switch (q->n_op) {
+			case GOTO:
+				p->op = JBR;
+				p->labno = q->n_left->n_lval;
+				break;
+			case CBRANCH:
+				p->op = CBR;
+				p->labno = q->n_right->n_lval;
+				break;
+			case ASSIGN:
+				/* remove ASSIGN to self for regs */
+				if (q->n_left->n_op == REG && 
+				    q->n_right->n_op == REG &&
+				    regno(q->n_left) == regno(q->n_right)) {
+					nip = DLIST_PREV(ip, qelem);
+					tfree(q);
+					DLIST_REMOVE(ip, qelem);
+					ip = nip;
+					continue;
+				}
+				/* FALLTHROUGH */
+			default:
+				p->op = STMT;
+				break;
+			}
+			break;
+
+		case IP_ASM:
+			p->op = STMT;
+			break;
+
+		case IP_EPILOG:
+			p->op = EROU;
+			break;
+
+		default:
+			comperr("listsetup: bad ip node %d", ip->type);
+		}
+		p->forw = 0;
+		p->back = lastp;
+		lastp->forw = p;
+		lastp = p;
+		p->ref = 0;
+	}
+}
+
+static struct dlnod *
+nonlab(struct dlnod *p)
+{
+	while (p && p->op==LABEL)
+		p = p->forw;
+	return(p);
+}
+
+static void
+iprem(struct dlnod *p)
+{
+	if (p->dlip->type == IP_NODE)
+		tfree(p->dlip->ip_node);
+	DLIST_REMOVE(p->dlip, qelem);
+}
+
+static void
+decref(struct dlnod *p)
+{
+	if (--p->refc <= 0) {
+		iprem(p);
+		p->back->forw = p->forw;
+		p->forw->back = p->back;
+	}
+}
+
+static void
+setlab(struct dlnod *p, int labno)
+{
+	p->labno = labno;
+	if (p->op == JBR)
+		p->dlip->ip_node->n_left->n_lval = labno;
+	else if (p->op == CBR) {
+		p->dlip->ip_node->n_right->n_lval = labno;
+		p->dlip->ip_node->n_left->n_label = labno;
+	} else
+		comperr("setlab bad op %d", p->op);
+}
+
+/*
+ * Label reference counting and removal of unused labels.
+ */
+#define	LABHS 127
+static void
+refcount(struct p2env *p2e, struct dlnod *dl)
+{
+	struct dlnod *p, *lp;
+	struct dlnod *labhash[LABHS];
+	struct dlnod **hp, *tp;
+
+	/* Clear label hash */
+	for (hp = labhash; hp < &labhash[LABHS];)
+		*hp++ = 0;
+	/* Enter labels into hash.  Later overwrites earlier */
+	for (p = dl->forw; p!=0; p = p->forw)
+		if (p->op==LABEL) {
+			labhash[p->labno % LABHS] = p;
+			p->refc = 0;
+		}
+
+	/* search for jumps to labels and fill in reference */
+	for (p = dl->forw; p!=0; p = p->forw) {
+		if (p->op==JBR || p->op==CBR) {
+			p->ref = 0;
+			lp = labhash[p->labno % LABHS];
+			if (lp==0 || p->labno!=lp->labno)
+			    for (lp = dl->forw; lp!=0; lp = lp->forw) {
+				if (lp->op==LABEL && p->labno==lp->labno)
+					break;
+			    }
+			if (lp) {
+				tp = nonlab(lp)->back;
+				if (tp!=lp) {
+					setlab(p, tp->labno);
+					lp = tp;
+				}
+				p->ref = lp;
+				lp->refc++;
+			}
+		}
+	}
+	for (p = dl->forw; p!=0; p = p->forw)
+		if (p->op==LABEL && p->refc==0 && (lp = nonlab(p))->op)
+			decref(p);
+}
+
+static int nchange;
+
+static struct dlnod *
+codemove(struct dlnod *p)
+{
+	struct dlnod *p1, *p2, *p3;
+#ifdef notyet
+	struct dlnod *t, *tl;
+	int n;
+#endif
+
+	p1 = p;
+	if (p1->op!=JBR || (p2 = p1->ref)==0)
+		return(p1);
+	while (p2->op == LABEL)
+		if ((p2 = p2->back) == 0)
+			return(p1);
+	if (p2->op!=JBR)
+		goto ivloop;
+	if (p1==p2)
+		return(p1);
+	p2 = p2->forw;
+	p3 = p1->ref;
+	while (p3) {
+		if (p3->op==JBR) {
+			if (p1==p3 || p1->forw==p3 || p1->back==p3)
+				return(p1);
+			nchange++;
+			p1->back->forw = p2;
+			p1->dlip->qelem.q_back->qelem.q_forw = p2->dlip;
+
+			p1->forw->back = p3;
+			p1->dlip->qelem.q_forw->qelem.q_back = p3->dlip;
+
+
+			p2->back->forw = p3->forw;
+			p2->dlip->qelem.q_back->qelem.q_forw = p3->forw->dlip;
+
+			p3->forw->back = p2->back;
+			p3->dlip->qelem.q_forw->qelem.q_back = p2->back->dlip;
+
+			p2->back = p1->back;
+			p2->dlip->qelem.q_back = p1->dlip->qelem.q_back;
+
+			p3->forw = p1->forw;
+			p3->dlip->qelem.q_forw = p1->forw->dlip;
+
+			decref(p1->ref);
+			if (p1->dlip->type == IP_NODE)
+				tfree(p1->dlip->ip_node);
+
+			return(p2);
+		} else
+			p3 = p3->forw;
+	}
+	return(p1);
+
+ivloop:
+	if (p1->forw->op!=LABEL)
+		return(p1);
+	return(p1);
+
+#ifdef notyet
+	p3 = p2 = p2->forw;
+	n = 16;
+	do {
+		if ((p3 = p3->forw) == 0 || p3==p1 || --n==0)
+			return(p1);
+	} while (p3->op!=CBR || p3->labno!=p1->forw->labno);
+	do 
+		if ((p1 = p1->back) == 0)
+			return(p);
+	while (p1!=p3);
+	p1 = p;
+	tl = insertl(p1);
+	p3->subop = revbr[p3->subop];
+	decref(p3->ref);
+		p2->back->forw = p1;
+	p3->forw->back = p1;
+	p1->back->forw = p2;
+	p1->forw->back = p3;
+	t = p1->back;
+	p1->back = p2->back;
+	p2->back = t;
+	t = p1->forw;
+	p1->forw = p3->forw;
+	p3->forw = t;
+	p2 = insertl(p1->forw);
+	p3->labno = p2->labno;
+	p3->ref = p2;
+	decref(tl);
+	if (tl->refc<=0)
+		nrlab--;
+	nchange++;
+	return(p3);
+#endif
+}
+
+static void
+iterate(struct p2env *p2e, struct dlnod *dl)
+{
+	struct dlnod *p, *rp, *p1;
+	extern int negrel[];
+	extern size_t negrelsize;
+	int i;
+
+	nchange = 0;
+	for (p = dl->forw; p!=0; p = p->forw) {
+		if ((p->op==JBR||p->op==CBR) && p->ref) {
+			/* Resolves:
+			 * jbr L7
+			 * ...
+			 * L7: jbr L8
+			 */
+			rp = nonlab(p->ref);
+			if (rp->op==JBR && rp->labno && p->labno!=rp->labno) {
+				setlab(p, rp->labno);
+				decref(p->ref);
+				rp->ref->refc++;
+				p->ref = rp->ref;
+				nchange++;
+			}
+		}
+		if (p->op==CBR && (p1 = p->forw)->op==JBR) {
+			/* Resolves:
+			 * cbr L7
+			 * jbr L8
+			 * L7:
+			 */
+			rp = p->ref;
+			do
+				rp = rp->back;
+			while (rp->op==LABEL);
+			if (rp==p1) {
+				decref(p->ref);
+				p->ref = p1->ref;
+				setlab(p, p1->labno);
+
+				iprem(p1);
+
+				p1->forw->back = p;
+				p->forw = p1->forw;
+
+				i = p->dlip->ip_node->n_left->n_op;
+				if (i < EQ || i - EQ >= (int)negrelsize)
+					comperr("deljumps: unexpected op");
+				p->dlip->ip_node->n_left->n_op = negrel[i - EQ];
+				nchange++;
+			}
+		}
+		if (p->op == JBR) {
+			/* Removes dead code */
+			while (p->forw && p->forw->op!=LABEL &&
+			    p->forw->op!=EROU) {
+				nchange++;
+				if (p->forw->ref)
+					decref(p->forw->ref);
+
+				iprem(p->forw);
+
+				p->forw = p->forw->forw;
+				p->forw->back = p;
+			}
+			rp = p->forw;
+			while (rp && rp->op==LABEL) {
+				if (p->ref == rp) {
+					p->back->forw = p->forw;
+					p->forw->back = p->back;
+					iprem(p);
+					p = p->back;
+					decref(rp);
+					nchange++;
+					break;
+				}
+				rp = rp->forw;
+			}
+		}
+		if (p->op == JBR) {
+			/* xjump(p); * needs tree rewrite; not yet */
+			p = codemove(p);
+		}
+	}
+}
+
+void
+deljumps(struct p2env *p2e)
+{
+	struct interpass *ipole = &p2e->ipole;
+	struct dlnod dln;
+	MARK mark;
+
+	markset(&mark);
+
+	memset(&dln, 0, sizeof(dln));
+	listsetup(ipole, &dln);
+	do {
+		refcount(p2e, &dln);
+		do {
+			iterate(p2e, &dln);
+		} while (nchange);
+#ifdef notyet
+		comjump();
+#endif
+	} while (nchange);
+
+	markfree(&mark);
+}
+
+void
+optdump(struct interpass *ip)
+{
+	static char *nm[] = { "node", "prolog", "newblk", "epilog", "locctr",
+		"deflab", "defnam", "asm" };
+	printf("type %s\n", nm[ip->type-1]);
+	switch (ip->type) {
+	case IP_NODE:
+#ifdef PCC_DEBUG
+		fwalk(ip->ip_node, e2print, 0);
+#endif
+		break;
+	case IP_DEFLAB:
+		printf("label " LABFMT "\n", ip->ip_lbl);
+		break;
+	case IP_ASM:
+		printf(": %s\n", ip->ip_asm);
+		break;
+	}
+}
+
+/*
+ * Build the basic blocks, algorithm 9.1, pp 529 in Compilers.
+ *
+ * Also fills the labelinfo struct with information about which bblocks
+ * that contain which label.
+ */
+
+void
+bblocks_build(struct p2env *p2e)
+{
+	struct interpass *ipole = &p2e->ipole;
+	struct interpass *ip;
+	struct basicblock *bb = NULL;
+	int low, high;
+	int count = 0;
+	int i;
+
+	BDEBUG(("bblocks_build (%p, %p)\n", &p2e->labinfo, &p2e->bbinfo));
+	low = p2e->ipp->ip_lblnum;
+	high = p2e->epp->ip_lblnum;
+
+	/* 
+	 * First statement is a leader.
+	 * Any statement that is target of a jump is a leader.
+	 * Any statement that immediately follows a jump is a leader.
+	 */
+	DLIST_INIT(&p2e->bblocks, bbelem);
+	DLIST_FOREACH(ip, ipole, qelem) {
+		if (bb == NULL || (ip->type == IP_EPILOG) ||
+		    (ip->type == IP_DEFLAB) || (ip->type == IP_DEFNAM)) {
+			bb = tmpalloc(sizeof(struct basicblock));
+			bb->first = ip;
+			SLIST_INIT(&bb->parents);
+			bb->ch[0] = bb->ch[1] = NULL;
+			bb->dfnum = 0;
+			bb->dfparent = 0;
+			bb->semi = 0;
+			bb->ancestor = 0;
+			bb->idom = 0;
+			bb->samedom = 0;
+			bb->bucket = NULL;
+			bb->df = NULL;
+			bb->dfchildren = NULL;
+			bb->Aorig = NULL;
+			bb->Aphi = NULL;
+			SLIST_INIT(&bb->phi);
+			bb->bbnum = count;
+			DLIST_INSERT_BEFORE(&p2e->bblocks, bb, bbelem);
+			count++;
+		}
+		bb->last = ip;
+		if ((ip->type == IP_NODE) && (ip->ip_node->n_op == GOTO || 
+		    ip->ip_node->n_op == CBRANCH))
+			bb = NULL;
+		if (ip->type == IP_PROLOG)
+			bb = NULL;
+	}
+	p2e->nbblocks = count;
+
+	if (b2debug) {
+		printf("Basic blocks in func: %d, low %d, high %d\n",
+		    count, low, high);
+		DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+			printf("bb(%d) %p: first %p last %p\n", bb->bbnum, bb,
+			    bb->first, bb->last);
+		}
+	}
+
+	p2e->labinfo.low = low;
+	p2e->labinfo.size = high - low + 1;
+	p2e->labinfo.arr = tmpalloc(p2e->labinfo.size * sizeof(struct basicblock *));
+	for (i = 0; i < p2e->labinfo.size; i++) {
+		p2e->labinfo.arr[i] = NULL;
+	}
+	
+	p2e->bbinfo.size = count + 1;
+	p2e->bbinfo.arr = tmpalloc(p2e->bbinfo.size * sizeof(struct basicblock *));
+	for (i = 0; i < p2e->bbinfo.size; i++) {
+		p2e->bbinfo.arr[i] = NULL;
+	}
+
+	/* Build the label table */
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		if (bb->first->type == IP_DEFLAB)
+			p2e->labinfo.arr[bb->first->ip_lbl - low] = bb;
+	}
+
+	if (b2debug) {
+		DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+			printf("bblock %d\n", bb->bbnum);
+			for (ip = bb->first; ip != bb->last;
+			    ip = DLIST_NEXT(ip, qelem)) {
+				printip2(ip);
+			}
+			printip2(ip);
+		}
+
+		printf("Label table:\n");
+		for (i = 0; i < p2e->labinfo.size; i++)
+			if (p2e->labinfo.arr[i])
+				printf("Label %d bblock %p\n", i+low,
+				    p2e->labinfo.arr[i]);
+	}
+}
+
+/*
+ * Build the control flow graph.
+ */
+
+void
+cfg_build(struct p2env *p2e)
+{
+	/* Child and parent nodes */
+	struct cfgnode *cnode; 
+	struct cfgnode *pnode;
+	struct basicblock *bb;
+	
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+
+		if (bb->first->type == IP_EPILOG) {
+			break;
+		}
+
+		cnode = tmpalloc(sizeof(struct cfgnode));
+		pnode = tmpalloc(sizeof(struct cfgnode));
+		pnode->bblock = bb;
+
+		if ((bb->last->type == IP_NODE) && 
+		    (bb->last->ip_node->n_op == GOTO) &&
+		    (bb->last->ip_node->n_left->n_op == ICON))  {
+			if (bb->last->ip_node->n_left->n_lval - p2e->labinfo.low > 
+			    p2e->labinfo.size) {
+				comperr("Label out of range: %d, base %d", 
+					bb->last->ip_node->n_left->n_lval, 
+					p2e->labinfo.low);
+			}
+			cnode->bblock = p2e->labinfo.arr[bb->last->ip_node->n_left->n_lval - p2e->labinfo.low];
+			SLIST_INSERT_LAST(&cnode->bblock->parents, pnode, cfgelem);
+			CHADD(bb, cnode);
+			continue;
+		}
+		if ((bb->last->type == IP_NODE) && 
+		    (bb->last->ip_node->n_op == CBRANCH)) {
+			if (bb->last->ip_node->n_right->n_lval - p2e->labinfo.low > 
+			    p2e->labinfo.size) 
+				comperr("Label out of range: %d", 
+					bb->last->ip_node->n_left->n_lval);
+
+			cnode->bblock = p2e->labinfo.arr[bb->last->ip_node->n_right->n_lval - p2e->labinfo.low];
+			SLIST_INSERT_LAST(&cnode->bblock->parents, pnode, cfgelem);
+			CHADD(bb, cnode);
+			cnode = tmpalloc(sizeof(struct cfgnode));
+			pnode = tmpalloc(sizeof(struct cfgnode));
+			pnode->bblock = bb;
+		}
+
+		cnode->bblock = DLIST_NEXT(bb, bbelem);
+		SLIST_INSERT_LAST(&cnode->bblock->parents, pnode, cfgelem);
+		CHADD(bb, cnode);
+	}
+}
+
+void
+cfg_dfs(struct basicblock *bb, unsigned int parent, struct bblockinfo *bbinfo)
+{
+	struct cfgnode **cn;
+
+	if (bb->dfnum != 0)
+		return;
+
+	bb->dfnum = ++dfsnum;
+	bb->dfparent = parent;
+	bbinfo->arr[bb->dfnum] = bb;
+	FORCH(cn, bb->ch)
+		cfg_dfs((*cn)->bblock, bb->dfnum, bbinfo);
+	/* Don't bring in unreachable nodes in the future */
+	bbinfo->size = dfsnum + 1;
+}
+
+static bittype *
+setalloc(int nelem)
+{
+	bittype *b;
+	int sz = (nelem+NUMBITS-1)/NUMBITS;
+
+	b = tmpalloc(sz * sizeof(bittype));
+	memset(b, 0, sz * sizeof(bittype));
+	return b;
+}
+
+/*
+ * Algorithm 19.9, pp 414 from Appel.
+ */
+
+void
+dominators(struct p2env *p2e)
+{
+	struct cfgnode *cnode;
+	struct basicblock *bb, *y, *v;
+	struct basicblock *s, *sprime, *p;
+	int h, i;
+
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		bb->bucket = setalloc(p2e->bbinfo.size);
+		bb->df = setalloc(p2e->bbinfo.size);
+		bb->dfchildren = setalloc(p2e->bbinfo.size);
+	}
+
+	dfsnum = 0;
+	cfg_dfs(DLIST_NEXT(&p2e->bblocks, bbelem), 0, &p2e->bbinfo);
+
+	if (b2debug) {
+		struct basicblock *bbb;
+		struct cfgnode *ccnode, **cn;
+
+		DLIST_FOREACH(bbb, &p2e->bblocks, bbelem) {
+			printf("Basic block %d, parents: ", bbb->dfnum);
+			SLIST_FOREACH(ccnode, &bbb->parents, cfgelem) {
+				printf("%d, ", ccnode->bblock->dfnum);
+			}
+			printf("\nChildren: ");
+			FORCH(cn, bbb->ch)
+				printf("%d, ", (*cn)->bblock->dfnum);
+			printf("\n");
+		}
+	}
+
+	for(h = p2e->bbinfo.size - 1; h > 1; h--) {
+		bb = p2e->bbinfo.arr[h];
+		p = s = p2e->bbinfo.arr[bb->dfparent];
+		SLIST_FOREACH(cnode, &bb->parents, cfgelem) {
+			if (cnode->bblock->dfnum ==0)
+				continue; /* Ignore unreachable code */
+
+			if (cnode->bblock->dfnum <= bb->dfnum) 
+				sprime = cnode->bblock;
+			else 
+				sprime = p2e->bbinfo.arr[ancestorwithlowestsemi
+					      (cnode->bblock, &p2e->bbinfo)->semi];
+			if (sprime->dfnum < s->dfnum)
+				s = sprime;
+		}
+		bb->semi = s->dfnum;
+		BITSET(s->bucket, bb->dfnum);
+		link(p, bb);
+		for (i = 1; i < p2e->bbinfo.size; i++) {
+			if(TESTBIT(p->bucket, i)) {
+				v = p2e->bbinfo.arr[i];
+				y = ancestorwithlowestsemi(v, &p2e->bbinfo);
+				if (y->semi == v->semi) 
+					v->idom = p->dfnum;
+				else
+					v->samedom = y->dfnum;
+			}
+		}
+		memset(p->bucket, 0, (p2e->bbinfo.size + 7)/8);
+	}
+
+	if (b2debug) {
+		printf("Num\tSemi\tAncest\tidom\n");
+		DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+			printf("%d\t%d\t%d\t%d\n", bb->dfnum, bb->semi,
+			    bb->ancestor, bb->idom);
+		}
+	}
+
+	for(h = 2; h < p2e->bbinfo.size; h++) {
+		bb = p2e->bbinfo.arr[h];
+		if (bb->samedom != 0) {
+			bb->idom = p2e->bbinfo.arr[bb->samedom]->idom;
+		}
+	}
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		if (bb->idom != 0 && bb->idom != bb->dfnum) {
+			BDEBUG(("Setting child %d of %d\n",
+			    bb->dfnum, p2e->bbinfo.arr[bb->idom]->dfnum));
+			BITSET(p2e->bbinfo.arr[bb->idom]->dfchildren, bb->dfnum);
+		}
+	}
+}
+
+
+struct basicblock *
+ancestorwithlowestsemi(struct basicblock *bblock, struct bblockinfo *bbinfo)
+{
+	struct basicblock *u = bblock;
+	struct basicblock *v = bblock;
+
+	while (v->ancestor != 0) {
+		if (bbinfo->arr[v->semi]->dfnum < 
+		    bbinfo->arr[u->semi]->dfnum) 
+			u = v;
+		v = bbinfo->arr[v->ancestor];
+	}
+	return u;
+}
+
+void
+link(struct basicblock *parent, struct basicblock *child)
+{
+	child->ancestor = parent->dfnum;
+}
+
+void
+computeDF(struct p2env *p2e, struct basicblock *bblock)
+{
+	struct cfgnode **cn;
+	int h, i;
+	
+	FORCH(cn, bblock->ch) {
+		if ((*cn)->bblock->idom != bblock->dfnum)
+			BITSET(bblock->df, (*cn)->bblock->dfnum);
+	}
+	for (h = 1; h < p2e->bbinfo.size; h++) {
+		if (!TESTBIT(bblock->dfchildren, h))
+			continue;
+		computeDF(p2e, p2e->bbinfo.arr[h]);
+		for (i = 1; i < p2e->bbinfo.size; i++) {
+			if (TESTBIT(p2e->bbinfo.arr[h]->df, i) && 
+			    (p2e->bbinfo.arr[i] == bblock ||
+			     (bblock->dfnum != p2e->bbinfo.arr[i]->idom))) 
+			    BITSET(bblock->df, i);
+		}
+	}
+}
+
+void printDF(struct p2env *p2e)
+{
+	struct basicblock *bb;
+	int i;
+
+	printf("Dominance frontiers:\n");
+    
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		printf("bb %d : ", bb->dfnum);
+	
+		for (i=1; i < p2e->bbinfo.size;i++) {
+			if (TESTBIT(bb->df,i)) {
+				printf("%d ",i);
+			}
+		}
+	    
+		printf("\n");
+	}
+    
+}
+
+
+
+static struct basicblock *currbb;
+static struct interpass *currip;
+
+/* Helper function for findTemps, Find assignment nodes. */
+static void
+searchasg(NODE *p, void *arg)
+{
+	struct pvarinfo *pv;
+	int tempnr;
+	struct varstack *stacke;
+    
+	if (p->n_op != ASSIGN)
+		return;
+
+	if (p->n_left->n_op != TEMP)
+		return;
+
+	tempnr=regno(p->n_left)-defsites.low;
+    
+	BITSET(currbb->Aorig, tempnr);
+	
+	pv = tmpcalloc(sizeof(struct pvarinfo));
+	pv->next = defsites.arr[tempnr];
+	pv->bb = currbb;
+	pv->n_type = p->n_left->n_type;
+	
+	defsites.arr[tempnr] = pv;
+	
+	
+	if (SLIST_FIRST(&defsites.stack[tempnr])==NULL) {
+		stacke=tmpcalloc(sizeof (struct varstack));
+		stacke->tmpregno=0;
+		SLIST_INSERT_FIRST(&defsites.stack[tempnr],stacke,varstackelem);
+	}
+}
+
+/* Walk the interpass looking for assignment nodes. */
+void findTemps(struct interpass *ip)
+{
+	if (ip->type != IP_NODE)
+		return;
+
+	currip = ip;
+
+	walkf(ip->ip_node, searchasg, 0);
+}
+
+/*
+ * Algorithm 19.6 from Appel.
+ */
+
+void
+placePhiFunctions(struct p2env *p2e)
+{
+	struct basicblock *bb;
+	struct basicblock *y;
+	struct interpass *ip;
+	int maxtmp, i, j, k;
+	struct pvarinfo *n;
+	struct cfgnode *cnode;
+	TWORD ntype;
+	struct pvarinfo *pv;
+	struct phiinfo *phi;
+	int phifound;
+
+	bb = DLIST_NEXT(&p2e->bblocks, bbelem);
+	defsites.low = ((struct interpass_prolog *)bb->first)->ip_tmpnum;
+	bb = DLIST_PREV(&p2e->bblocks, bbelem);
+	maxtmp = ((struct interpass_prolog *)bb->first)->ip_tmpnum;
+	defsites.size = maxtmp - defsites.low + 1;
+	defsites.arr = tmpcalloc(defsites.size*sizeof(struct pvarinfo *));
+	defsites.stack = tmpcalloc(defsites.size*sizeof(SLIST_HEAD(, varstack)));
+	
+	for (i=0;i<defsites.size;i++)
+		SLIST_INIT(&defsites.stack[i]);	
+	
+	/* Find all defsites */
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		currbb = bb;
+		ip = bb->first;
+		bb->Aorig = setalloc(defsites.size);
+		bb->Aphi = setalloc(defsites.size);
+		
+		while (ip != bb->last) {
+			findTemps(ip);
+			ip = DLIST_NEXT(ip, qelem);
+		}
+		/* Make sure we get the last statement in the bblock */
+		findTemps(ip);
+	}
+
+	/* For each variable */
+	for (i = 0; i < defsites.size; i++) {
+		/* While W not empty */
+		while (defsites.arr[i] != NULL) {
+			/* Remove some node n from W */
+			n = defsites.arr[i];
+			defsites.arr[i] = n->next;
+			/* For each y in n->bb->df */
+			for (j = 0; j < p2e->bbinfo.size; j++) {
+				if (!TESTBIT(n->bb->df, j))
+					continue;
+				
+				if (TESTBIT(p2e->bbinfo.arr[j]->Aphi, i))
+					continue;
+
+				y=p2e->bbinfo.arr[j];
+				ntype = n->n_type;
+				k = 0;
+				/* Amount of predecessors for y */
+				SLIST_FOREACH(cnode, &y->parents, cfgelem) 
+					k++;
+				/* Construct phi(...) 
+				*/
+			    
+				phifound=0;
+			    
+				SLIST_FOREACH(phi, &y->phi, phielem) {
+				    if (phi->tmpregno==i+defsites.low)
+					phifound++;
+				}
+			    
+				if (phifound==0) {
+					if (b2debug)
+					    printf("Phi in %d(%d) (%p) for %d\n",
+					    y->dfnum,y->bbnum,y,i+defsites.low);
+
+					/* If no live in, no phi node needed */
+					if (!TESTBIT(y->in,
+					    (i+defsites.low-p2e->ipp->ip_tmpnum+MAXREGS))) {
+					if (b2debug)
+					printf("tmp %d bb %d unused, no phi\n",
+					    i+defsites.low, y->bbnum);
+						/* No live in */
+						BITSET(p2e->bbinfo.arr[j]->Aphi, i);
+						continue;
+					}
+
+					phi = tmpcalloc(sizeof(struct phiinfo));
+			    
+					phi->tmpregno=i+defsites.low;
+					phi->size=k;
+					phi->n_type=ntype;
+					phi->intmpregno=tmpcalloc(k*sizeof(int));
+			    
+					SLIST_INSERT_LAST(&y->phi,phi,phielem);
+				} else {
+				    if (b2debug)
+					printf("Phi already in %d for %d\n",y->dfnum,i+defsites.low);
+				}
+
+				BITSET(p2e->bbinfo.arr[j]->Aphi, i);
+				if (!TESTBIT(p2e->bbinfo.arr[j]->Aorig, i)) {
+					pv = tmpalloc(sizeof(struct pvarinfo));
+					pv->bb = y;
+				        pv->n_type=ntype;
+					pv->next = defsites.arr[i];
+					defsites.arr[i] = pv;
+				}
+			}
+		}
+	}
+}
+
+/* Helper function for renamevar. */
+static void
+renamevarhelper(struct p2env *p2e,NODE *t,void *poplistarg)
+{	
+	SLIST_HEAD(, varstack) *poplist=poplistarg;
+	int opty;
+	int tempnr;
+	int newtempnr;
+	int x;
+	struct varstack *stacke;
+	
+	if (t->n_op == ASSIGN && t->n_left->n_op == TEMP) {
+		renamevarhelper(p2e,t->n_right,poplist);
+				
+		tempnr=regno(t->n_left)-defsites.low;
+		
+		newtempnr=p2e->epp->ip_tmpnum++;
+		regno(t->n_left)=newtempnr;
+		
+		stacke=tmpcalloc(sizeof (struct varstack));
+		stacke->tmpregno=newtempnr;
+		SLIST_INSERT_FIRST(&defsites.stack[tempnr],stacke,varstackelem);
+		
+		stacke=tmpcalloc(sizeof (struct varstack));
+		stacke->tmpregno=tempnr;
+		SLIST_INSERT_FIRST(poplist,stacke,varstackelem);
+	} else {
+		if (t->n_op == TEMP) {
+			tempnr=regno(t)-defsites.low;
+		
+			if (SLIST_FIRST(&defsites.stack[tempnr])!=NULL) {
+				x=SLIST_FIRST(&defsites.stack[tempnr])->tmpregno;
+				regno(t)=x;
+			}
+		}
+		
+		opty = optype(t->n_op);
+		
+		if (opty != LTYPE)
+			renamevarhelper(p2e, t->n_left,poplist);
+		if (opty == BITYPE)
+			renamevarhelper(p2e, t->n_right,poplist);
+	}
+}
+
+
+void
+renamevar(struct p2env *p2e,struct basicblock *bb)
+{
+    	struct interpass *ip;
+	int h,j;
+	SLIST_HEAD(, varstack) poplist;
+	struct varstack *stacke;
+	struct cfgnode *cfgn2, **cn;
+	int tmpregno,newtmpregno;
+	struct phiinfo *phi;
+
+	SLIST_INIT(&poplist);
+
+	SLIST_FOREACH(phi,&bb->phi,phielem) {
+		tmpregno=phi->tmpregno-defsites.low;
+		
+		newtmpregno=p2e->epp->ip_tmpnum++;
+		phi->newtmpregno=newtmpregno;
+
+		stacke=tmpcalloc(sizeof (struct varstack));
+		stacke->tmpregno=newtmpregno;
+		SLIST_INSERT_FIRST(&defsites.stack[tmpregno],stacke,varstackelem);
+		
+		stacke=tmpcalloc(sizeof (struct varstack));
+		stacke->tmpregno=tmpregno;
+		SLIST_INSERT_FIRST(&poplist,stacke,varstackelem);		
+	}
+
+
+	ip=bb->first;
+
+	while (1) {		
+		if ( ip->type == IP_NODE) {
+			renamevarhelper(p2e,ip->ip_node,&poplist);
+		}
+
+		if (ip==bb->last)
+			break;
+
+		ip = DLIST_NEXT(ip, qelem);
+	}
+
+	FORCH(cn, bb->ch) {
+		j=0;
+
+		SLIST_FOREACH(cfgn2, &(*cn)->bblock->parents, cfgelem) { 
+			if (cfgn2->bblock->dfnum==bb->dfnum)
+				break;
+			
+			j++;
+		}
+
+		SLIST_FOREACH(phi,&(*cn)->bblock->phi,phielem) {
+			phi->intmpregno[j]=SLIST_FIRST(&defsites.stack[phi->tmpregno-defsites.low])->tmpregno;
+		}
+	}
+
+	for (h = 1; h < p2e->bbinfo.size; h++) {
+		if (!TESTBIT(bb->dfchildren, h))
+			continue;
+
+		renamevar(p2e,p2e->bbinfo.arr[h]);
+	}
+
+	SLIST_FOREACH(stacke,&poplist,varstackelem) {
+		tmpregno=stacke->tmpregno;
+		
+		defsites.stack[tmpregno].q_forw=defsites.stack[tmpregno].q_forw->varstackelem.q_forw;
+	}
+}
+
+enum pred_type {
+    pred_unknown    = 0,
+    pred_goto       = 1,
+    pred_cond       = 2,
+    pred_falltrough = 3,
+} ;
+
+void
+removephi(struct p2env *p2e)
+{
+	struct basicblock *bb,*bbparent;
+	struct cfgnode *cfgn;
+	struct phiinfo *phi;
+	int i;
+	struct interpass *ip;
+	struct interpass *pip;
+	TWORD n_type;
+
+	enum pred_type complex = pred_unknown ;
+
+	int label=0;
+	int newlabel;
+
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {		
+		SLIST_FOREACH(phi,&bb->phi,phielem) {
+			/* Look at only one, notice break at end */
+			i=0;
+			
+			SLIST_FOREACH(cfgn, &bb->parents, cfgelem) { 
+				bbparent=cfgn->bblock;
+				
+				pip=bbparent->last;
+				
+				complex = pred_unknown ;
+				
+				BDEBUG(("removephi: %p in %d",pip,bb->dfnum));
+
+				if (pip->type == IP_NODE && pip->ip_node->n_op == GOTO) {
+					BDEBUG((" GOTO "));
+					label = (int)pip->ip_node->n_left->n_lval;
+					complex = pred_goto ;
+				} else if (pip->type == IP_NODE && pip->ip_node->n_op == CBRANCH) {
+					BDEBUG((" CBRANCH "));
+					label = (int)pip->ip_node->n_right->n_lval;
+					
+					if (bb==p2e->labinfo.arr[label - p2e->ipp->ip_lblnum])
+						complex = pred_cond ;
+					else
+						complex = pred_falltrough ;
+
+				} else if (DLIST_PREV(bb, bbelem) == bbparent) {
+					complex = pred_falltrough ;
+				} else {
+					    /* PANIC */
+					comperr("Assumption blown in rem-phi") ;
+				}
+       
+				BDEBUG((" Complex: %d ",complex)) ;
+
+				switch (complex) {
+				  case pred_goto:
+					/* gotos can only go to this place. No bounce tab needed */
+					SLIST_FOREACH(phi,&bb->phi,phielem) {
+						if (phi->intmpregno[i]>0) {
+							n_type=phi->n_type;
+							ip = ipnode(mkbinode(ASSIGN,
+							     mktemp(phi->newtmpregno, n_type),
+							     mktemp(phi->intmpregno[i],n_type),
+							     n_type));
+							BDEBUG(("(%p, %d -> %d) ", ip, phi->intmpregno[i], phi->newtmpregno));
+				
+							DLIST_INSERT_BEFORE((bbparent->last), ip, qelem);
+						}
+					}
+					break ;
+				  case pred_cond:
+					/* Here, we need a jump pad */
+					newlabel=getlab2();
+			
+					ip = tmpalloc(sizeof(struct interpass));
+					ip->type = IP_DEFLAB;
+					/* Line number?? ip->lineno; */
+					ip->ip_lbl = newlabel;
+					DLIST_INSERT_BEFORE((bb->first), ip, qelem);
+
+					SLIST_FOREACH(phi,&bb->phi,phielem) {
+						if (phi->intmpregno[i]>0) {
+							n_type=phi->n_type;
+							ip = ipnode(mkbinode(ASSIGN,
+							     mktemp(phi->newtmpregno, n_type),
+							     mktemp(phi->intmpregno[i],n_type),
+							     n_type));
+
+							BDEBUG(("(%p, %d -> %d) ", ip, phi->intmpregno[i], phi->newtmpregno));
+							DLIST_INSERT_BEFORE((bb->first), ip, qelem);
+						}
+					}
+					/* add a jump to us */
+					ip = ipnode(mkunode(GOTO, mklnode(ICON, label, 0, INT), 0, INT));
+					DLIST_INSERT_BEFORE((bb->first), ip, qelem);
+					pip->ip_node->n_right->n_lval=newlabel;
+					if (!logop(pip->ip_node->n_left->n_op))
+						comperr("SSA not logop");
+					pip->ip_node->n_left->n_label=newlabel;
+					break ;
+				  case pred_falltrough:
+					if (bb->first->type == IP_DEFLAB) { 
+						label = bb->first->ip_lbl; 
+						BDEBUG(("falltrough label %d\n", label));
+					} else {
+						comperr("BBlock has no label?") ;
+					}
+
+					/* 
+					 * add a jump to us. We _will_ be, or already have, added code in between.
+					 * The code is created in the wrong order and switched at the insert, thus
+					 * comming out correctly
+					 */
+
+					ip = ipnode(mkunode(GOTO, mklnode(ICON, label, 0, INT), 0, INT));
+					DLIST_INSERT_AFTER((bbparent->last), ip, qelem);
+
+					/* Add the code to the end, add a jump to us. */
+					SLIST_FOREACH(phi,&bb->phi,phielem) {
+						if (phi->intmpregno[i]>0) {
+							n_type=phi->n_type;
+							ip = ipnode(mkbinode(ASSIGN,
+								mktemp(phi->newtmpregno, n_type),
+								mktemp(phi->intmpregno[i],n_type),
+								n_type));
+
+							BDEBUG(("(%p, %d -> %d) ", ip, phi->intmpregno[i], phi->newtmpregno));
+							DLIST_INSERT_AFTER((bbparent->last), ip, qelem);
+						}
+					}
+					break ;
+				default:
+					comperr("assumption blown, complex is %d\n", complex) ;
+				}
+				BDEBUG(("\n"));
+				i++;
+			}
+			break;
+		}
+	}
+}
+
+    
+/*
+ * Remove unreachable nodes in the CFG.
+ */ 
+
+void
+remunreach(struct p2env *p2e)
+{
+	struct basicblock *bb, *nbb;
+	struct interpass *next, *ctree;
+
+	bb = DLIST_NEXT(&p2e->bblocks, bbelem);
+	while (bb != &p2e->bblocks) {
+		nbb = DLIST_NEXT(bb, bbelem);
+
+		/* Code with dfnum 0 is unreachable */
+		if (bb->dfnum != 0) {
+			bb = nbb;
+			continue;
+		}
+
+		/* Need the epilogue node for other parts of the
+		   compiler, set its label to 0 and backend will
+		   handle it. */ 
+		if (bb->first->type == IP_EPILOG) {
+			bb->first->ip_lbl = 0;
+			bb = nbb;
+			continue;
+		}
+
+		next = bb->first;
+		do {
+			ctree = next;
+			next = DLIST_NEXT(ctree, qelem);
+			
+			if (ctree->type == IP_NODE)
+				tfree(ctree->ip_node);
+			DLIST_REMOVE(ctree, qelem);
+		} while (ctree != bb->last);
+			
+		DLIST_REMOVE(bb, bbelem);
+		bb = nbb;
+	}
+}
+
+static void
+printip2(struct interpass *ip)
+{
+	static char *foo[] = {
+	   0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" };
+	struct interpass_prolog *ipplg, *epplg;
+	unsigned i;
+
+	if (ip->type > MAXIP)
+		printf("IP(%d) (%p): ", ip->type, ip);
+	else
+		printf("%s (%p): ", foo[ip->type], ip);
+	switch (ip->type) {
+	case IP_NODE: printf("\n");
+#ifdef PCC_DEBUG
+	fwalk(ip->ip_node, e2print, 0); break;
+#endif
+	case IP_PROLOG:
+		ipplg = (struct interpass_prolog *)ip;
+		printf("%s %s regs",
+		    ipplg->ipp_name, ipplg->ipp_vis ? "(local)" : "");
+		for (i = 0; i < NIPPREGS; i++)
+			printf("%s0x%lx", i? ":" : " ",
+			    (long) ipplg->ipp_regs[i]);
+		printf(" autos %d mintemp %d minlbl %d\n",
+		    ipplg->ipp_autos, ipplg->ip_tmpnum, ipplg->ip_lblnum);
+		break;
+	case IP_EPILOG:
+		epplg = (struct interpass_prolog *)ip;
+		printf("%s %s regs",
+		    epplg->ipp_name, epplg->ipp_vis ? "(local)" : "");
+		for (i = 0; i < NIPPREGS; i++)
+			printf("%s0x%lx", i? ":" : " ",
+			    (long) epplg->ipp_regs[i]);
+		printf(" autos %d mintemp %d minlbl %d\n",
+		    epplg->ipp_autos, epplg->ip_tmpnum, epplg->ip_lblnum);
+		break;
+	case IP_DEFLAB: printf(LABFMT "\n", ip->ip_lbl); break;
+	case IP_DEFNAM: printf("\n"); break;
+	case IP_ASM: printf("%s\n", ip->ip_asm); break;
+	default:
+		break;
+	}
+}
+
+void
+printip(struct interpass *pole)
+{
+	struct interpass *ip;
+
+	DLIST_FOREACH(ip, pole, qelem)
+		printip2(ip);
+}
+
+#ifdef PCC_DEBUG
+void flownodeprint(NODE *p,FILE *flowdiagramfile);
+
+void
+flownodeprint(NODE *p,FILE *flowdiagramfile)
+{	
+	int opty;
+	char *o;
+
+	fprintf(flowdiagramfile,"{");
+
+	o=opst[p->n_op];
+	
+	while (*o != 0) {
+		if (*o=='<' || *o=='>')
+			fputc('\\',flowdiagramfile);
+		
+		fputc(*o,flowdiagramfile);
+		o++;
+	}
+	
+	
+	switch( p->n_op ) {			
+		case REG:
+			fprintf(flowdiagramfile, " %s", rnames[p->n_rval] );
+			break;
+			
+		case TEMP:
+			fprintf(flowdiagramfile, " %d", regno(p));
+			break;
+			
+		case XASM:
+		case XARG:
+			fprintf(flowdiagramfile, " '%s'", p->n_name);
+			break;
+			
+		case ICON:
+		case NAME:
+		case OREG:
+			fprintf(flowdiagramfile, " " );
+			adrput(flowdiagramfile, p );
+			break;
+			
+		case STCALL:
+		case USTCALL:
+		case STARG:
+		case STASG:
+			fprintf(flowdiagramfile, " size=%d", p->n_stsize );
+			fprintf(flowdiagramfile, " align=%d", p->n_stalign );
+			break;
+	}
+	
+	opty = optype(p->n_op);
+	
+	if (opty != LTYPE) {
+		fprintf(flowdiagramfile,"| {");
+	
+		flownodeprint(p->n_left,flowdiagramfile);
+	
+		if (opty == BITYPE) {
+			fprintf(flowdiagramfile,"|");
+			flownodeprint(p->n_right,flowdiagramfile);
+		}
+		fprintf(flowdiagramfile,"}");
+	}
+	
+	fprintf(flowdiagramfile,"}");
+}
+
+void
+printflowdiagram(struct p2env *p2e, char *type) {
+	struct basicblock *bbb;
+	struct cfgnode **cn;
+	struct interpass *ip;
+	struct interpass_prolog *plg;
+	struct phiinfo *phi;
+	char *name;
+	char *filename;
+	int filenamesize;
+	char *ext=".dot";
+	FILE *flowdiagramfile;
+	
+	if (!g2debug)
+		return;
+	
+	bbb=DLIST_NEXT(&p2e->bblocks, bbelem);
+	ip=bbb->first;
+
+	if (ip->type != IP_PROLOG)
+		return;
+	plg = (struct interpass_prolog *)ip;
+
+	name=plg->ipp_name;
+	
+	filenamesize=strlen(name)+1+strlen(type)+strlen(ext)+1;
+	filename=tmpalloc(filenamesize);
+	snprintf(filename,filenamesize,"%s-%s%s",name,type,ext);
+	
+	flowdiagramfile=fopen(filename,"w");
+	
+	fprintf(flowdiagramfile,"digraph {\n");
+	fprintf(flowdiagramfile,"rankdir=LR\n");
+	
+	DLIST_FOREACH(bbb, &p2e->bblocks, bbelem) {
+		ip=bbb->first;
+		
+		fprintf(flowdiagramfile,"bb%p [shape=record ",bbb);
+		
+		if (ip->type==IP_PROLOG)
+			fprintf(flowdiagramfile,"root ");
+
+		fprintf(flowdiagramfile,"label=\"");
+		
+		SLIST_FOREACH(phi,&bbb->phi,phielem) {
+			fprintf(flowdiagramfile,"Phi %d|",phi->tmpregno);
+		}		
+		
+		
+		while (1) {
+			switch (ip->type) {
+				case IP_NODE: 
+					flownodeprint(ip->ip_node,flowdiagramfile);
+					break;
+					
+				case IP_DEFLAB: 
+					fprintf(flowdiagramfile,"Label: %d", ip->ip_lbl);
+					break;
+					
+				case IP_PROLOG:
+					plg = (struct interpass_prolog *)ip;
+	
+					fprintf(flowdiagramfile,"%s %s",plg->ipp_name,type);
+					break;
+			}
+			
+			fprintf(flowdiagramfile,"|");
+			fprintf(flowdiagramfile,"|");
+			
+			if (ip==bbb->last)
+				break;
+			
+			ip = DLIST_NEXT(ip, qelem);
+		}
+		fprintf(flowdiagramfile,"\"]\n");
+		
+		FORCH(cn, bbb->ch) {
+			char *color="black";
+			struct interpass *pip=bbb->last;
+
+			if (pip->type == IP_NODE && pip->ip_node->n_op == CBRANCH) {
+				int label = (int)pip->ip_node->n_right->n_lval;
+				
+				if ((*cn)->bblock==p2e->labinfo.arr[label - p2e->ipp->ip_lblnum])
+					color="red";
+			}
+			
+			fprintf(flowdiagramfile,"bb%p -> bb%p [color=%s]\n", bbb,(*cn)->bblock,color);
+		}
+	}
+	
+	fprintf(flowdiagramfile,"}\n");
+	fclose(flowdiagramfile);
+}
+
+#endif
+
+/* walk all the programm */
+void WalkAll(struct p2env* p2e, void (*f) (NODE*, void*), void* arg, int type)
+{
+	struct interpass *ipole = &p2e->ipole;
+	struct interpass *ip ;
+	if (0 != type) {
+		DLIST_FOREACH(ip, ipole, qelem) {
+			if (ip->type == IP_NODE && ip->ip_node->n_op == type)
+				walkf(ip->ip_node, f, arg) ;
+		}
+	} else {
+		DLIST_FOREACH(ip, ipole, qelem) {
+			if (ip->type == IP_NODE)
+				walkf(ip->ip_node, f, arg) ;
+		}
+	}
+}
+#if 0
+static int is_goto_label(struct interpass*g, struct interpass* l)
+{
+	if (!g || !l)
+		return 0 ;
+	if (g->type != IP_NODE) return 0 ;
+	if (l->type != IP_DEFLAB) return 0 ;
+	if (g->ip_node->n_op != GOTO) return 0 ;
+	if (g->ip_node->n_left->n_lval != l->ip_lbl) return 0 ;
+	return 1 ;
+}
+#endif
+
+/*
+ * iterate over the basic blocks. 
+ * In case a block has only one successor and that one has only one pred, and the link is a goto:
+ * place the second one immediately behind the first one (in terms of nodes, means cut&resplice). 
+ * This should take care of a lot of jumps.
+ * one problem: Cannot move the first or last basic block (prolog/epilog). This is taken care of by
+ * moving block #1 to #2, not #2 to #1
+ * More complex (on the back cooker;) : first coalesc the inner loops (L1 cache), then go from inside out.
+ */
+
+static unsigned long count_blocks(struct p2env* p2e)
+{
+	struct basicblock* bb ;
+	unsigned long count = 0 ;
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		++count ;
+	}
+	return count ;
+}
+
+struct block_map {
+	struct basicblock* block ;
+	unsigned long index ;
+	unsigned long thread ;
+} ;
+
+static unsigned long map_blocks(struct p2env* p2e, struct block_map* map, unsigned long count)
+{
+	struct basicblock* bb ;
+	unsigned long indx = 0 ;
+	int ignore = 2 ;
+	unsigned long thread ;
+	unsigned long changes ;
+
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		map[indx].block = bb ;
+		map[indx].index = indx ;
+
+		/* ignore the first 2 labels, maybe up to 3 BBs */
+		if (ignore) {
+			if (bb->first->type == IP_DEFLAB) 
+				--ignore;
+
+			map[indx].thread = 1 ;	/* these are "fixed" */
+		} else
+			map[indx].thread = 0 ;
+
+		indx++ ;
+	}
+
+	thread = 1 ;
+	do {
+		changes = 0 ;
+		
+		for (indx=0; indx < count; indx++) {
+			/* find block without trace */
+			if (map[indx].thread == 0) {
+				/* do new thread */
+				struct cfgnode **cn ;
+				struct basicblock *block2 = 0;
+				unsigned long i ;
+				unsigned long added ;
+				
+				BDEBUG (("new thread %ld at block %ld\n", thread, indx)) ;
+
+				bb = map[indx].block ;
+				do {
+					added = 0 ;
+
+					for (i=0; i < count; i++) {
+						if (map[i].block == bb && map[i].thread == 0) {
+							map[i].thread = thread ;
+
+							BDEBUG(("adding block %ld to trace %ld\n", i, thread)) ;
+
+							changes ++ ;
+							added++ ;
+
+							/* 
+							 * pick one from followers. For now (simple), pick the 
+							 * one who is directly following us. If none of that exists,
+							 * this code picks the last one.
+							 */
+
+							FORCH(cn, bb->ch) {
+								block2=(*cn)->bblock ;
+#if 1
+								if (i+1 < count && map[i+1].block == block2)
+									break ; /* pick that one */
+#else
+								if (block2) break ;
+#endif
+							}
+
+							if (block2)
+								bb = block2 ;
+						}
+					}
+				} while (added) ;
+				thread++ ;
+			}
+		}
+	} while (changes);
+
+	/* Last block is also a thread on it's own, and the highest one. */
+/*
+	thread++ ;
+	map[count-1].thread = thread ;
+*/
+	if (b2debug) {
+		printf("Threads\n");
+		for (indx=0; indx < count; indx++) {
+			printf("Block #%ld (lbl %d) Thread %ld\n", indx, map[indx].block->first->ip_lbl, map[indx].thread);
+		}
+	}
+	return thread ;
+}
+
+
+void TraceSchedule(struct p2env* p2e)
+{
+	struct block_map* map ;
+	unsigned long block_count = count_blocks(p2e);
+	unsigned long i ;
+	unsigned long threads;
+	struct interpass *front, *back ;
+
+	map = tmpalloc(block_count * sizeof(struct block_map));
+
+	threads = map_blocks(p2e, map, block_count) ;
+
+	back = map[0].block->last ;
+	for (i=1; i < block_count; i++) {
+		/* collect the trace */
+		unsigned long j ;
+		unsigned long thread = map[i].thread ;
+		if (thread) {
+			BDEBUG(("Thread %ld\n", thread)) ;
+			for (j=i; j < block_count; j++) {
+				if (map[j].thread == thread) {
+					front = map[j].block->first ;
+
+					BDEBUG(("Trace %ld, old BB %ld, next BB %ld\t",
+						thread, i, j)) ;
+					BDEBUG(("Label %d\n", front->ip_lbl)) ;
+					DLIST_NEXT(back, qelem) = front ;
+					DLIST_PREV(front, qelem) = back ;
+					map[j].thread = 0 ;	/* done */
+					back = map[j].block->last ;
+					DLIST_NEXT(back, qelem) = 0 ;
+				}
+			}
+		}
+	}
+	DLIST_NEXT(back, qelem) = &(p2e->ipole) ;
+	DLIST_PREV(&p2e->ipole, qelem) = back ;
+}
+
+static void add_labels(struct p2env* p2e)
+{
+	struct interpass *ipole = &p2e->ipole ;
+	struct interpass *ip ;
+
+	DLIST_FOREACH(ip, ipole, qelem) {
+		if (ip->type == IP_NODE && ip->ip_node->n_op == CBRANCH) {
+			struct interpass *n = DLIST_NEXT(ip, qelem);
+			if (n && n->type != IP_DEFLAB) {
+				struct interpass* lab;
+				int newlabel=getlab2() ;
+
+				BDEBUG(("add_label L%d\n", newlabel));
+
+				lab = tmpalloc(sizeof(struct interpass));
+				lab->type = IP_DEFLAB;
+				/* Line number?? ip->lineno; */
+				lab->ip_lbl = newlabel;
+				DLIST_INSERT_AFTER(ip, lab, qelem);
+			}
+		}
+	}
+}
+
+/* node map */
+#ifdef ENABLE_NEW
+struct node_map {
+	NODE* node ;		/* the node */
+	unsigned int node_num ; /* node is equal to that one */
+	unsigned int var_num ;	/* node computes this variable */
+} ;
+
+static unsigned long nodes_counter ;
+static void node_map_count_walker(NODE* n, void* x)
+{
+	nodes_counter ++ ;
+}
+
+static void do_cse(struct p2env* p2e)
+{
+	nodes_counter = 0 ;
+	WalkAll(p2e, node_map_count_walker, 0, 0) ;
+	BDEBUG(("Found %ld nodes\n", nodes_counter)) ;
+}
+#endif
+
+#define BITALLOC(ptr,all,sz) { \
+	int sz__s = BIT2BYTE(sz); ptr = all(sz__s); memset(ptr, 0, sz__s); }
+#define VALIDREG(p)	(p->n_op == REG && TESTBIT(validregs, regno(p)))
+#define XCHECK(x) if (x < 0 || x >= xbits) printf("x out of range %d\n", x)
+#define RUP(x) (((x)+NUMBITS-1)/NUMBITS)
+#define SETCOPY(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] = f[i]
+#define SETSET(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] |= f[i]
+#define SETCLEAR(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] &= ~f[i]
+#define SETCMP(v,t,f,i,n) for (i = 0; i < RUP(n); i++) \
+	if (t[i] != f[i]) v = 1
+
+static int xxx, xbits;
+/*
+ * Set/clear long term liveness for regs and temps.
+ */
+static void
+unionize(NODE *p, struct basicblock *bb, int suboff)
+{
+	int o, ty;
+
+	if ((o = p->n_op) == TEMP || VALIDREG(p)) {
+		int b = regno(p);
+		if (o == TEMP)
+			b = b - suboff + MAXREGS;
+XCHECK(b);
+		BITSET(bb->gen, b);
+	}
+	if (asgop(o)) {
+		if (p->n_left->n_op == TEMP || VALIDREG(p)) {
+			int b = regno(p->n_left);
+			if (p->n_left->n_op == TEMP)
+				b = b - suboff + MAXREGS;
+XCHECK(b);
+			BITCLEAR(bb->gen, b);
+			BITSET(bb->killed, b);
+			unionize(p->n_right, bb, suboff);
+			return;
+		}
+	}
+	ty = optype(o);
+	if (ty != LTYPE)
+		unionize(p->n_left, bb, suboff);
+	if (ty == BITYPE)
+		unionize(p->n_right, bb, suboff);
+}
+
+/*
+ * Found an extended assembler node, so growel out gen/killed nodes.
+ */
+static void
+xasmionize(NODE *p, void *arg)
+{
+	struct basicblock *bb = arg;
+	int cw, b;
+
+	if (p->n_op == ICON && p->n_type == STRTY)
+		return; /* dummy end marker */
+
+	cw = xasmcode(p->n_name);
+	if (XASMVAL(cw) == 'n' || XASMVAL(cw) == 'm')
+		return; /* no flow analysis */
+	p = p->n_left;
+ 
+	if (XASMVAL(cw) == 'g' && p->n_op != TEMP && p->n_op != REG)
+		return; /* no flow analysis */
+
+	b = regno(p);
+#if 0
+	if (XASMVAL(cw) == 'r' && p->n_op == TEMP)
+		addnotspill(b);
+#endif
+#define MKTOFF(r)	((r) - xxx)
+	if (XASMISOUT(cw)) {
+		if (p->n_op == TEMP) {
+			BITCLEAR(bb->gen, MKTOFF(b));
+			BITSET(bb->killed, MKTOFF(b));
+		} else if (p->n_op == REG) {
+			BITCLEAR(bb->gen, b);
+			BITSET(bb->killed, b);	 
+		} else
+			uerror("bad xasm node type %d", p->n_op);
+	}
+	if (XASMISINP(cw)) {
+		if (p->n_op == TEMP) {
+			BITSET(bb->gen, MKTOFF(b));
+		} else if (p->n_op == REG) {
+			BITSET(bb->gen, b);
+		} else if (optype(p->n_op) != LTYPE) {
+			if (XASMVAL(cw) == 'r')
+				uerror("couldn't find available register");
+			else
+				uerror("bad xasm node type2");
+		}
+	}
+}
+
+/*
+ * Do variable liveness analysis.  Only analyze the long-lived
+ * variables, and save the live-on-exit temporaries in a bit-field
+ * at the end of each basic block. This bit-field is later used
+ * when doing short-range liveness analysis in Build().
+ */
+void
+liveanal(struct p2env *p2e)
+{
+	struct basicblock *bb;
+	struct interpass *ip;
+	bittype *saved;
+	int i, mintemp, again;
+
+	xbits = p2e->epp->ip_tmpnum - p2e->ipp->ip_tmpnum + MAXREGS;
+	mintemp = p2e->ipp->ip_tmpnum;
+
+	/* Just fetch space for the temporaries from heap */
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		BITALLOC(bb->gen,tmpalloc,xbits);
+		BITALLOC(bb->killed,tmpalloc,xbits);
+		BITALLOC(bb->in,tmpalloc,xbits);
+		BITALLOC(bb->out,tmpalloc,xbits);
+	}
+	BITALLOC(saved,tmpalloc,xbits);
+
+	xxx = mintemp;
+	/*
+	 * generate the gen-killed sets for all basic blocks.
+	 */
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) {
+			/* gen/killed is 'p', this node is 'n' */
+			if (ip->type == IP_NODE) {
+				if (ip->ip_node->n_op == XASM)
+					flist(ip->ip_node->n_left,
+					    xasmionize, bb);
+				else
+					unionize(ip->ip_node, bb, mintemp);
+			}
+			if (ip == bb->first)
+				break;
+		}
+		memcpy(bb->in, bb->gen, BIT2BYTE(xbits));
+#ifdef PCC_DEBUG
+#define PRTRG(x) printf("%d ", i < MAXREGS ? i : i + p2e->ipp->ip_tmpnum-MAXREGS)
+		if (b2debug > 1) {
+			printf("basic block %d\ngen: ", bb->bbnum);
+			for (i = 0; i < xbits; i++)
+				if (TESTBIT(bb->gen, i))
+					PRTRG(i);
+			printf("\nkilled: ");
+			for (i = 0; i < xbits; i++)
+				if (TESTBIT(bb->killed, i))
+					PRTRG(i);
+			printf("\n");
+		}
+#endif
+	}
+	/* do liveness analysis on basic block level */
+	do {
+		struct cfgnode **cn;
+		int j;
+
+		again = 0;
+		/* XXX - loop should be in reversed execution-order */
+		DLIST_FOREACH_REVERSE(bb, &p2e->bblocks, bbelem) {
+			SETCOPY(saved, bb->out, j, xbits);
+			FORCH(cn, bb->ch) {
+				SETSET(bb->out, cn[0]->bblock->in, j, xbits);
+			}
+			SETCMP(again, saved, bb->out, j, xbits);
+			SETCOPY(saved, bb->in, j, xbits);
+			SETCOPY(bb->in, bb->out, j, xbits);
+			SETCLEAR(bb->in, bb->killed, j, xbits);
+			SETSET(bb->in, bb->gen, j, xbits);
+			SETCMP(again, saved, bb->in, j, xbits);
+		}
+	} while (again);
+
+#ifdef PCC_DEBUG
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		if (b2debug) {
+			printf("all basic block %d\nin: ", bb->bbnum);
+			for (i = 0; i < xbits; i++)
+				if (TESTBIT(bb->in, i))
+					PRTRG(i);
+			printf("\nout: ");
+			for (i = 0; i < xbits; i++)
+				if (TESTBIT(bb->out, i))
+					PRTRG(i);
+			printf("\n");
+		}
+	}
+#endif
+}
Index: uspace/app/pcc/mip/pass2.h
===================================================================
--- uspace/app/pcc/mip/pass2.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/mip/pass2.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,546 @@
+/*	$Id: pass2.h,v 1.128 2011/01/11 12:48:23 ragge Exp $	*/
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/types.h>
+
+#ifndef MKEXT
+#include "external.h"
+#else
+typedef unsigned int bittype; /* XXX - for basicblock */
+#define	BIT2BYTE(a)	(((a) + 31) / 32)
+#endif
+#include "manifest.h"
+
+/* cookies, used as arguments to codgen */
+#define FOREFF	01		/* compute for effects only */
+#define INAREG	02		/* compute into a register */
+#define INBREG	04		/* compute into a register */
+#define INCREG	010		/* compute into a register */
+#define INDREG	020		/* compute into a register */
+#define	INREGS	(INAREG|INBREG|INCREG|INDREG)
+#define FORCC	040		/* compute for condition codes only */
+#define QUIET	0100		/* tell geninsn() to not complain if fail */
+#define INTEMP	010000		/* compute into a temporary location */
+#define FORREW	040000		/* search the table for a rewrite rule */
+#define INEREG	0x10000		/* compute into a register, > 16 bits */
+#define INFREG	0x20000		/* compute into a register, > 16 bits */
+#define INGREG	0x40000		/* compute into a register, > 16 bits */
+
+/*
+ * OP descriptors,
+ * the ASG operator may be used on some of these
+ */
+#define OPSIMP	010000		/* +, -, &, |, ^ */
+#define OPCOMM	010002		/* +, &, |, ^ */
+#define OPMUL	010004		/* *, / */
+#define OPDIV	010006		/* /, % */
+#define OPUNARY	010010		/* unary ops */
+#define OPLEAF	010012		/* leaves */
+#define OPANY	010014		/* any op... */
+#define OPLOG	010016		/* logical ops */
+#define OPFLOAT	010020		/* +, -, *, or / (for floats) */
+#define OPSHFT	010022		/* <<, >> */
+#define OPLTYPE	010024		/* leaf type nodes (e.g, NAME, ICON, etc.) */
+
+/* shapes */
+#define SANY	01		/* same as FOREFF */
+#define SAREG	02		/* same as INAREG */
+#define SBREG	04		/* same as INBREG */
+#define SCREG	010		/* same as INCREG */
+#define SDREG	020		/* same as INDREG */
+#define SCC	040		/* same as FORCC */
+#define SNAME	0100
+#define SCON	0200
+#define SFLD	0400
+#define SOREG	01000
+#define STARNM	02000
+#define STARREG	04000
+#define SWADD	040000
+#define SPECIAL	0100000
+#define SZERO	SPECIAL
+#define SONE	(SPECIAL|1)
+#define SMONE	(SPECIAL|2)
+#define SCCON	(SPECIAL|3)	/* -256 <= constant < 256 */
+#define SSCON	(SPECIAL|4)	/* -32768 <= constant < 32768 */
+#define SSOREG	(SPECIAL|5)	/* non-indexed OREG */
+#define	MAXSPECIAL	(SPECIAL|5)
+#define SEREG	0x10000		/* same as INEREG */
+#define SFREG	0x20000		/* same as INFREG */
+#define SGREG	0x40000		/* same as INGREG */
+
+/* These are used in rstatus[] in conjunction with SxREG */
+#define	TEMPREG	01000
+#define	PERMREG	02000
+
+/* tshape() return values */
+#define	SRNOPE	0		/* Cannot match any shape */
+#define	SRDIR	1		/* Direct match */
+#define	SROREG	2		/* Can convert into OREG */
+#define	SRREG	3		/* Must put into REG */
+
+/* find*() return values */
+#define	FRETRY	-2
+#define	FFAIL	-1
+
+/* INTEMP is carefully not conflicting with shapes */
+
+/* types */
+#define TCHAR		01	/* char */
+#define TSHORT		02	/* short */
+#define TINT		04	/* int */
+#define TLONG		010	/* long */
+#define TFLOAT		020	/* float */
+#define TDOUBLE		040	/* double */
+#define TPOINT		0100	/* pointer to something */
+#define TUCHAR		0200	/* unsigned char */
+#define TUSHORT		0400	/* unsigned short */
+#define TUNSIGNED	01000	/* unsigned int */
+#define TULONG		02000	/* unsigned long */
+#define TPTRTO		04000	/* pointer to one of the above */
+#define TANY		010000	/* matches anything within reason */
+#define TSTRUCT		020000	/* structure or union */
+#define	TLONGLONG	040000	/* long long */
+#define	TULONGLONG	0100000	/* unsigned long long */
+#define	TLDOUBLE	0200000	/* long double; exceeds 16 bit */
+#define	TFTN		0400000	/* function pointer; exceeds 16 bit */
+
+/* reclamation cookies */
+#define RNULL		0	/* clobber result */
+#define RLEFT		01
+#define RRIGHT		02
+#define RESC1		04
+#define RESC2		010
+#define RESC3		020
+#define RDEST		040
+#define RESCC		04000
+#define RNOP		010000	/* DANGER: can cause loops.. */
+
+/* needs */
+#define NASL		0x0001	/* may share left register */
+#define NASR		0x0002	/* may share right register */
+#define NAREG		0x0004
+#define NACOUNT		0x000c
+#define NBSL		0x0010
+#define NBSR		0x0020
+#define NBREG		0x0040
+#define NBCOUNT		0x00c0
+#define	NCSL		0x0100
+#define	NCSR		0x0200
+#define	NCREG		0x0400
+#define	NCCOUNT		0x0c00
+#define NTEMP		0x1000
+#define NTMASK		0x3000
+#define NSPECIAL	0x4000	/* need special register treatment */
+#define REWRITE		0x8000
+#define	NDSL		0x00010000	/* Above 16 bit */
+#define	NDSR		0x00020000	/* Above 16 bit */
+#define	NDREG		0x00040000	/* Above 16 bit */
+#define	NDCOUNT		0x000c0000
+#define	NESL		0x00100000	/* Above 16 bit */
+#define	NESR		0x00200000	/* Above 16 bit */
+#define	NEREG		0x00400000	/* Above 16 bit */
+#define	NECOUNT		0x00c00000
+#define	NFSL		0x01000000	/* Above 16 bit */
+#define	NFSR		0x02000000	/* Above 16 bit */
+#define	NFREG		0x04000000	/* Above 16 bit */
+#define	NFCOUNT		0x0c000000
+#define	NGSL		0x10000000	/* Above 16 bit */
+#define	NGSR		0x20000000	/* Above 16 bit */
+#undef	NGREG	/* XXX - linux exposes NGREG to public */
+#define	NGREG		0x40000000	/* Above 16 bit */
+#define	NGCOUNT		0xc0000000
+
+/* special treatment */
+#define	NLEFT		(0001)	/* left leg register (moveadd) */
+#define	NOLEFT		(0002)	/* avoid regs for left (addedge) */
+#define	NRIGHT		(0004)	/* right leg register */
+#define	NORIGHT		(0010)	/* avoid reg for right */
+#define	NEVER		(0020)	/* registers trashed (addalledges) */
+#define	NRES		(0040)	/* result register (moveadd) */
+#define	NMOVTO		(0100)	/* move between classes */
+
+
+#define MUSTDO		010000	/* force register requirements */
+#define NOPREF		020000	/* no preference for register assignment */
+
+#define	isreg(p)	(p->n_op == REG || p->n_op == TEMP)
+
+extern	int fregs;
+
+/* code tables */
+extern	struct optab {
+	int	op;
+	int	visit;
+	int	lshape;
+	int	ltype;
+	int	rshape;
+	int	rtype;
+	int	needs;
+	int	rewrite;
+	char	*cstring;
+} table[];
+
+/* Special needs for register allocations */
+struct rspecial {
+	int op, num;
+#if 0
+	int left;	/* left leg register */
+	int noleft;	/* avoid regs for left */
+	int right;	/* right leg register */
+	int noright;	/* avoid right leg register */
+	int *rmask;	/* array of destroyed registers */
+	int res;	/* Result ends up here */
+//	void (*rew)(struct optab *, NODE *);	/* special rewrite */
+#endif
+};
+
+struct p2env;
+extern	NODE resc[];
+extern	int p2autooff, p2maxautooff;
+
+extern	NODE
+	*talloc(void),
+	*eread(void),
+	*mklnode(int, CONSZ, int, TWORD),
+	*mkbinode(int, NODE *, NODE *, TWORD),
+	*mkunode(int, NODE *, int, TWORD),
+	*getlr(NODE *p, int);
+
+void eoftn(struct interpass_prolog *);
+void prologue(struct interpass_prolog *);
+void e2print(NODE *p, int down, int *a, int *b);
+void myoptim(struct interpass *);
+void cbgen(int op, int label);
+int match(NODE *p, int cookie);
+int acceptable(struct optab *);
+int special(NODE *, int);
+int setasg(NODE *, int);
+int setuni(NODE *, int);
+int sucomp(NODE *);
+int nsucomp(NODE *);
+int setorder(NODE *);
+int geninsn(NODE *, int cookie);
+void adrput(FILE *, NODE *);
+void comperr(char *str, ...);
+void genregs(NODE *p);
+void ngenregs(struct p2env *);
+NODE *store(NODE *);
+struct interpass *ipnode(NODE *);
+void deflab(int);
+void rmove(int, int, TWORD);
+int rspecial(struct optab *, int);
+struct rspecial *nspecial(struct optab *q);
+void printip(struct interpass *pole);
+int findops(NODE *p, int);
+int findasg(NODE *p, int);
+int finduni(NODE *p, int);
+int findumul(NODE *p, int);
+int findleaf(NODE *p, int);
+int relops(NODE *p);
+#ifdef FINDMOPS
+int findmops(NODE *p, int);
+int treecmp(NODE *p1, NODE *p2);
+#endif
+void offstar(NODE *p, int shape);
+int gclass(TWORD);
+void lastcall(NODE *);
+void myreader(struct interpass *pole);
+int oregok(NODE *p, int sharp);
+void myormake(NODE *);
+int *livecall(NODE *);
+void prtreg(FILE *, NODE *);
+char *prcook(int);
+int myxasm(struct interpass *ip, NODE *p);
+int xasmcode(char *s);
+int freetemp(int k);
+int rewfld(NODE *p);
+void canon(NODE *);
+void mycanon(NODE *);
+void oreg2(NODE *p, void *);
+int shumul(NODE *p, int);
+NODE *deluseless(NODE *p);
+int getlab2(void);
+int tshape(NODE *, int);
+void conput(FILE *, NODE *);
+int shtemp(NODE *p);
+int ttype(TWORD t, int tword);
+void expand(NODE *, int, char *);
+void hopcode(int, int);
+void adrcon(CONSZ);
+void zzzcode(NODE *, int);
+void insput(NODE *);
+void upput(NODE *, int);
+int tlen(NODE *p);
+int setbin(NODE *);
+int notoff(TWORD, int, CONSZ, char *);
+int fldexpand(NODE *, int, char **);
+void p2tree(NODE *p); 
+int flshape(NODE *p);
+
+extern	char *rnames[];
+extern	int rstatus[];
+extern	int roverlap[MAXREGS][MAXREGS];
+
+extern int classmask(int), tclassmask(int);
+extern void cmapinit(void);
+extern int aliasmap(int adjclass, int regnum);
+extern int regK[];
+#define	CLASSA	1
+#define	CLASSB	2
+#define	CLASSC	3
+#define	CLASSD	4
+#define	CLASSE	5
+#define	CLASSF	6
+#define	CLASSG	7
+
+/* used when parsing xasm codes */
+#define	XASMVAL(x)	((x) & 0377)		/* get val from codeword */
+#define	XASMVAL1(x)	(((x) >> 16) & 0377)	/* get val from codeword */
+#define	XASMVAL2(x)	(((x) >> 24) & 0377)	/* get val from codeword */
+#define	XASMASG		0x100	/* = */
+#define	XASMCONSTR	0x200	/* & */
+#define	XASMINOUT	0x400	/* + */
+#define XASMALL		(XASMASG|XASMCONSTR|XASMINOUT)
+#define	XASMISINP(cw)	(((cw) & XASMASG) == 0)		/* input operand */
+#define	XASMISOUT(cw)	((cw) & (XASMASG|XASMINOUT))	/* output operand */
+
+/* routines to handle double indirection */
+#ifdef R2REGS
+void makeor2(NODE *p, NODE *q, int, int);
+int base(NODE *);
+int offset(NODE *p, int);
+#endif
+
+extern	int lineno;
+extern	int fldshf, fldsz;
+extern	int lflag, x2debug, udebug, e2debug, odebug;
+extern	int rdebug, t2debug, s2debug, b2debug, c2debug;
+extern	int g2debug;
+extern	int kflag;
+#ifdef FORT
+extern	int Oflag;
+#endif
+
+#ifndef callchk
+#define callchk(x) allchk()
+#endif
+
+#ifndef PUTCHAR
+#define PUTCHAR(x) putchar(x)
+#endif
+
+extern	int dope[];	/* a vector containing operator information */
+extern	char *opst[];	/* a vector containing names for ops */
+
+#ifdef PCC_DEBUG
+
+static inline int
+optype(int o)
+{
+	if (o >= MAXOP+1)
+		cerror("optype");
+	return (dope[o]&TYFLG);
+}
+
+static inline int
+asgop(int o)
+{
+	if (o >= MAXOP+1)
+		cerror("asgop");
+	return (dope[o]&ASGFLG);
+}
+
+static inline int
+logop(int o)
+{
+	if (o >= MAXOP+1)
+		cerror("logop");
+	return (dope[o]&LOGFLG);
+}
+
+static inline int
+callop(int o)
+{
+	if (o >= MAXOP+1)
+		cerror("callop");
+	return (dope[o]&CALLFLG);
+}
+
+#else
+
+#define optype(o)	(dope[o]&TYFLG)
+#define asgop(o)	(dope[o]&ASGFLG) 
+#define logop(o)	(dope[o]&LOGFLG)
+#define callop(o)	(dope[o]&CALLFLG)
+
+#endif
+
+	/* macros for doing double indexing */
+#define R2PACK(x,y,z)	(0200*((x)+1)+y+040000*z)
+#define R2UPK1(x)	((((x)>>7)-1)&0177)
+#define R2UPK2(x)	((x)&0177)
+#define R2UPK3(x)	(x>>14)
+#define R2TEST(x)	((x)>=0200)
+
+/*
+ * Layout of findops() return value:
+ *      bit 0 whether left shall go into a register.
+ *      bit 1 whether right shall go into a register.
+ *      bit 2 entry is only used for side effects.
+ *      bit 3 if condition codes are used.
+ *
+ * These values should be synced with FOREFF/FORCC.
+ */
+#define LREG		001
+#define RREG		002
+#define	RVEFF		004
+#define	RVCC		010
+#define DORIGHT		020
+#define	SCLASS(v,x)	((v) |= ((x) << 5))
+#define	TCLASS(x)	(((x) >> 5) & 7)
+#define	TBSH		8
+#define TBLIDX(idx)	((idx) >> TBSH)
+#define MKIDX(tbl,mod)	(((tbl) << TBSH) | (mod))
+
+#ifndef	BREGS
+#define	BREGS	0
+#define	TBREGS	0
+#endif
+#define	REGBIT(x) (1 << (x))
+#ifndef PERMTYPE
+#define	PERMTYPE(a)	(INT)
+#endif
+
+/* Flags for the dataflow code */
+/* do the live/dead analysis */
+#define DO_LIVEDEAD  0x01
+/* compute avail expressions */
+#define DO_AVAILEXPR 0x02
+/* Do an update on the live/dead. One variable only */
+#define DO_UPDATELD  0x04
+/* Do an update on available expressions, one variable has changed */
+#define DO_UPDATEEX  0x08
+
+void emit(struct interpass *);
+void optimize(struct p2env *);
+
+struct basicblock {
+	DLIST_ENTRY(basicblock) bbelem;
+	SLIST_HEAD(, cfgnode) parents; /* CFG - parents to this node */
+	struct cfgnode *ch[2];		/* Child 1 (and 2) */
+	int bbnum;	/* this basic block number */
+	unsigned int dfnum; /* DFS-number */
+	unsigned int dfparent; /* Parent in DFS */
+	unsigned int semi;
+	unsigned int ancestor;
+	unsigned int idom;
+	unsigned int samedom;
+	bittype *bucket;
+	bittype *df;
+	bittype *dfchildren;
+	bittype *Aorig;
+	bittype *Aphi;
+	SLIST_HEAD(, phiinfo) phi;
+
+	bittype *gen, *killed, *in, *out;	/* Liveness analysis */
+
+	struct interpass *first; /* first element of basic block */
+	struct interpass *last;  /* last element of basic block */
+};
+
+struct labelinfo {
+	struct basicblock **arr;
+	int size;
+	unsigned int low;
+};
+
+struct bblockinfo {
+	int size;
+	struct basicblock **arr;
+};
+
+struct varinfo {
+	struct pvarinfo **arr;
+	SLIST_HEAD(, varstack) *stack;
+	int size;
+	int low;
+};
+
+struct pvarinfo {
+	struct pvarinfo *next;
+	struct basicblock *bb;
+	TWORD n_type;
+};
+
+struct varstack {
+	SLIST_ENTRY(varstack) varstackelem;
+	int tmpregno;
+};
+
+
+struct cfgnode {
+	SLIST_ENTRY(cfgnode) cfgelem;
+	struct basicblock *bblock;
+};
+
+struct phiinfo {
+	SLIST_ENTRY(phiinfo) phielem;
+	int tmpregno;
+	int newtmpregno;
+	TWORD n_type;
+	int size;
+	int *intmpregno;
+};
+
+/*
+ * Description of the pass2 environment.
+ * There will be only one of these structs.  It is used to keep
+ * all state descriptions during the compilation of a function
+ * in one place.
+ */
+struct p2env {
+	struct interpass ipole;			/* all statements */
+	struct interpass_prolog *ipp, *epp;	/* quick references */
+	struct bblockinfo bbinfo;
+	struct labelinfo labinfo;
+	struct basicblock bblocks;
+	int nbblocks;
+};
+
+extern struct p2env p2env;
+
+/*
+ * C compiler second pass extra defines.
+ */
+#define PHI (MAXOP + 1)		/* Used in SSA trees */
Index: uspace/app/pcc/mip/reader.c
===================================================================
--- uspace/app/pcc/mip/reader.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/mip/reader.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1663 @@
+/*	$Id: reader.c,v 1.268.2.1 2011/03/15 17:23:18 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.
+ */
+
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code and documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditionsand the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * 	This product includes software developed or owned by Caldera
+ *	International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of other
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Everything is entered via pass2_compile().  No functions are 
+ * allowed to recurse back into pass2_compile().
+ */
+
+# include "pass2.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+/*	some storage declarations */
+int nrecur;
+int lflag;
+int x2debug, udebug, odebug;
+int thisline;
+int fregs;
+int p2autooff, p2maxautooff;
+
+NODE *nodepole;
+FILE *prfil;
+struct interpass prepole;
+
+void saveip(struct interpass *ip);
+void deltemp(NODE *p, void *);
+static void cvtemps(struct interpass *ipole, int op, int off);
+NODE *store(NODE *);
+static void fixxasm(struct p2env *);
+
+static void gencode(NODE *p, int cookie);
+static void genxasm(NODE *p);
+
+struct p2env p2env;
+
+int
+getlab2(void)
+{
+	extern int getlab(void);
+	int rv = getlab();
+#ifdef PCC_DEBUG
+	if (p2env.epp->ip_lblnum != rv)
+		comperr("getlab2 error: %d != %d", p2env.epp->ip_lblnum, rv);
+#endif
+	p2env.epp->ip_lblnum++;
+	return rv;
+}
+
+#ifdef PCC_DEBUG
+static int *lbldef, *lbluse;
+static void
+cktree(NODE *p, void *arg)
+{
+	int i;
+
+	if (p->n_op > MAXOP)
+		cerror("%p) op %d slipped through", p, p->n_op);
+	if (BTYPE(p->n_type) > MAXTYPES)
+		cerror("%p) type %x slipped through", p, p->n_type);
+	if (p->n_op == CBRANCH) {
+		 if (!logop(p->n_left->n_op))
+			cerror("%p) not logop branch", p);
+		i = (int)p->n_right->n_lval;
+		if (i < p2env.ipp->ip_lblnum || i >= p2env.epp->ip_lblnum)
+			cerror("%p) label %d outside boundaries %d-%d",
+			    p, i, p2env.ipp->ip_lblnum, p2env.epp->ip_lblnum);
+		lbluse[i-p2env.ipp->ip_lblnum] = 1;
+	}
+	if ((dope[p->n_op] & ASGOPFLG) && p->n_op != RETURN)
+		cerror("%p) asgop %d slipped through", p, p->n_op);
+	if (p->n_op == TEMP &&
+	    (regno(p) < p2env.ipp->ip_tmpnum || regno(p) >= p2env.epp->ip_tmpnum))
+		cerror("%p) temporary %d outside boundaries %d-%d",
+		    p, regno(p), p2env.ipp->ip_tmpnum, p2env.epp->ip_tmpnum);
+	if (p->n_op == GOTO && p->n_left->n_op == ICON) {
+		i = (int)p->n_left->n_lval;
+		if (i < p2env.ipp->ip_lblnum || i >= p2env.epp->ip_lblnum)
+			cerror("%p) label %d outside boundaries %d-%d",
+			    p, i, p2env.ipp->ip_lblnum, p2env.epp->ip_lblnum);
+		lbluse[i-p2env.ipp->ip_lblnum] = 1;
+	}
+}
+
+/*
+ * Check that the trees are in a suitable state for pass2.
+ */
+static void
+sanitychecks(struct p2env *p2e)
+{
+	struct interpass *ip;
+	int i;
+#ifdef notyet
+	TMPMARK();
+#endif
+	lbldef = tmpcalloc(sizeof(int) * (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum));
+	lbluse = tmpcalloc(sizeof(int) * (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum));
+
+	DLIST_FOREACH(ip, &p2env.ipole, qelem) {
+		if (ip->type == IP_DEFLAB) {
+			i = ip->ip_lbl;
+			if (i < p2e->ipp->ip_lblnum || i >= p2e->epp->ip_lblnum)
+				cerror("label %d outside boundaries %d-%d",
+				    i, p2e->ipp->ip_lblnum, p2e->epp->ip_lblnum);
+			lbldef[i-p2e->ipp->ip_lblnum] = 1;
+		}
+		if (ip->type == IP_NODE)
+			walkf(ip->ip_node, cktree, 0);
+	}
+	for (i = 0; i < (p2e->epp->ip_lblnum - p2e->ipp->ip_lblnum); i++)
+		if (lbluse[i] != 0 && lbldef[i] == 0)
+			cerror("internal label %d not defined",
+			    i + p2e->ipp->ip_lblnum);
+
+#ifdef notyet
+	TMPFREE();
+#endif
+}
+#endif
+
+/*
+ * Look if a temporary comes from a on-stack argument, in that case
+ * use the already existing stack position instead of moving it to
+ * a new place, and remove the move-to-temp statement.
+ */
+static int
+stkarg(int tnr, int *soff)
+{
+	struct p2env *p2e = &p2env;
+	struct interpass *ip;
+	NODE *p;
+
+	ip = DLIST_NEXT((struct interpass *)p2e->ipp, qelem);
+	while (ip->type != IP_DEFLAB) /* search for first DEFLAB */
+		ip = DLIST_NEXT(ip, qelem);
+
+	ip = DLIST_NEXT(ip, qelem); /* first NODE */
+
+	for (; ip->type != IP_DEFLAB; ip = DLIST_NEXT(ip, qelem)) {
+		if (ip->type != IP_NODE)
+			continue;
+
+		p = ip->ip_node;
+		if (p->n_op == XASM)
+			continue; /* XXX - hack for x86 PIC */
+#ifdef notdef
+		if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
+			comperr("temparg");
+#endif
+		if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
+			continue; /* unknown tree */
+
+		if (p->n_right->n_op != OREG && p->n_right->n_op != UMUL)
+			continue; /* arg in register */
+		if (tnr != regno(p->n_left))
+			continue; /* wrong assign */
+		p = p->n_right;
+		if (p->n_op == UMUL &&
+		    p->n_left->n_op == PLUS &&
+		    p->n_left->n_left->n_op == REG &&
+		    p->n_left->n_right->n_op == ICON)
+			*soff = (int)p->n_left->n_right->n_lval;
+		else if (p->n_op == OREG)
+			*soff = (int)p->n_lval;
+		else
+			comperr("stkarg: bad arg");
+		tfree(ip->ip_node);
+		DLIST_REMOVE(ip, qelem);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * See if an ADDROF is somewhere inside the expression tree.
+ * If so, fill in the offset table.
+ */
+static void
+findaof(NODE *p, void *arg)
+{
+	int *aof = arg;
+	int tnr;
+
+	if (p->n_op != ADDROF || p->n_left->n_op != TEMP)
+		return;
+	tnr = regno(p->n_left);
+	if (aof[tnr])
+		return; /* already gotten stack address */
+	if (stkarg(tnr, &aof[tnr]))
+		return;	/* argument was on stack */
+	aof[tnr] = BITOOR(freetemp(szty(p->n_left->n_type)));
+}
+
+/*
+ * Check if a node has side effects.
+ */
+static int
+isuseless(NODE *n)
+{
+	switch (n->n_op) {
+	case XASM:
+	case FUNARG:
+	case UCALL:
+	case UFORTCALL:
+	case FORCE:
+	case ASSIGN:
+	case CALL:
+	case FORTCALL:
+	case CBRANCH:
+	case RETURN:
+	case GOTO:
+	case STCALL:
+	case USTCALL:
+	case STASG:
+	case STARG:
+		return 0;
+	default:
+		return 1;
+	}
+}
+
+/*
+ * Delete statements with no meaning (like a+b; or 513.4;)
+ */
+NODE *
+deluseless(NODE *p)
+{
+	struct interpass *ip;
+	NODE *l, *r;
+
+	if (optype(p->n_op) == LTYPE) {
+		nfree(p);
+		return NULL;
+	}
+	if (isuseless(p) == 0)
+		return p;
+
+	if (optype(p->n_op) == UTYPE) {
+		l = p->n_left;
+		nfree(p);
+		return deluseless(l);
+	}
+
+	/* Be sure that both leaves may be valid */
+	l = deluseless(p->n_left);
+	r = deluseless(p->n_right);
+	nfree(p);
+	if (l && r) {
+		ip = ipnode(l);
+		DLIST_INSERT_AFTER(&prepole, ip, qelem);
+		return r;
+	} else if (l)
+		return l;
+	else if (r)
+		return r;
+	return NULL;
+}
+
+/*
+ * Receives interpass structs from pass1.
+ */
+void
+pass2_compile(struct interpass *ip)
+{
+	void deljumps(struct p2env *);
+	struct p2env *p2e = &p2env;
+	int *addrp;
+	MARK mark;
+
+	if (ip->type == IP_PROLOG) {
+		memset(p2e, 0, sizeof(struct p2env));
+		p2e->ipp = (struct interpass_prolog *)ip;
+		DLIST_INIT(&p2e->ipole, qelem);
+	}
+	DLIST_INSERT_BEFORE(&p2e->ipole, ip, qelem);
+	if (ip->type != IP_EPILOG)
+		return;
+
+#ifdef PCC_DEBUG
+	if (e2debug) {
+		printf("Entering pass2\n");
+		printip(&p2e->ipole);
+	}
+#endif
+
+	p2e->epp = (struct interpass_prolog *)DLIST_PREV(&p2e->ipole, qelem);
+	p2maxautooff = p2autooff = p2e->epp->ipp_autos;
+
+#ifdef PCC_DEBUG
+	sanitychecks(p2e);
+#endif
+	myreader(&p2e->ipole); /* local massage of input */
+
+	/*
+	 * Do initial modification of the trees.  Two loops;
+	 * - first, search for ADDROF of TEMPs, these must be
+	 *   converterd to OREGs on stack.
+	 * - second, do the actual conversions, in case of not xtemps
+	 *   convert all temporaries to stack references.
+	 */
+	markset(&mark);
+	if (p2e->epp->ip_tmpnum != p2e->ipp->ip_tmpnum) {
+		addrp = tmpcalloc(sizeof(int) *
+		    (p2e->epp->ip_tmpnum - p2e->ipp->ip_tmpnum));
+		addrp -= p2e->ipp->ip_tmpnum;
+	} else
+		addrp = NULL;
+	if (xtemps) {
+		DLIST_FOREACH(ip, &p2e->ipole, qelem) {
+			if (ip->type == IP_NODE)
+				walkf(ip->ip_node, findaof, addrp);
+		}
+	}
+	DLIST_FOREACH(ip, &p2e->ipole, qelem)
+		if (ip->type == IP_NODE)
+			walkf(ip->ip_node, deltemp, addrp);
+	markfree(&mark);
+
+#ifdef PCC_DEBUG
+	if (e2debug) {
+		printf("Efter ADDROF/TEMP\n");
+		printip(&p2e->ipole);
+	}
+#endif
+
+	DLIST_INIT(&prepole, qelem);
+	DLIST_FOREACH(ip, &p2e->ipole, qelem) {
+		if (ip->type != IP_NODE)
+			continue;
+		canon(ip->ip_node);
+		if ((ip->ip_node = deluseless(ip->ip_node)) == NULL) {
+			DLIST_REMOVE(ip, qelem);
+		} else while (!DLIST_ISEMPTY(&prepole, qelem)) {
+			struct interpass *tipp;
+
+			tipp = DLIST_NEXT(&prepole, qelem);
+			DLIST_REMOVE(tipp, qelem);
+			DLIST_INSERT_BEFORE(ip, tipp, qelem);
+		}
+	}
+
+	fixxasm(p2e); /* setup for extended asm */
+
+	optimize(p2e);
+	ngenregs(p2e);
+
+	if (xssaflag && xtemps && xdeljumps)
+		deljumps(p2e);
+
+	DLIST_FOREACH(ip, &p2e->ipole, qelem)
+		emit(ip);
+}
+
+void
+emit(struct interpass *ip)
+{
+	NODE *p, *r;
+	struct optab *op;
+	int o;
+
+	switch (ip->type) {
+	case IP_NODE:
+		p = ip->ip_node;
+
+		nodepole = p;
+		canon(p); /* may convert stuff after genregs */
+		if (c2debug > 1) {
+			printf("emit IP_NODE:\n");
+			fwalk(p, e2print, 0);
+		}
+		switch (p->n_op) {
+		case CBRANCH:
+			/* Only emit branch insn if RESCC */
+			/* careful when an OPLOG has been elided */
+			if (p->n_left->n_su == 0 && p->n_left->n_left != NULL) {
+				op = &table[TBLIDX(p->n_left->n_left->n_su)];
+				r = p->n_left;
+			} else {
+				op = &table[TBLIDX(p->n_left->n_su)];
+				r = p;
+			}
+			if (op->rewrite & RESCC) {
+				o = p->n_left->n_op;
+				gencode(r, FORCC);
+				cbgen(o, p->n_right->n_lval);
+			} else {
+				gencode(r, FORCC);
+			}
+			break;
+		case FORCE:
+			gencode(p->n_left, INREGS);
+			break;
+		case XASM:
+			genxasm(p);
+			break;
+		default:
+			if (p->n_op != REG || p->n_type != VOID) /* XXX */
+				gencode(p, FOREFF); /* Emit instructions */
+		}
+
+		tfree(p);
+		break;
+	case IP_PROLOG:
+		prologue((struct interpass_prolog *)ip);
+		break;
+	case IP_EPILOG:
+		eoftn((struct interpass_prolog *)ip);
+		p2maxautooff = p2autooff = AUTOINIT/SZCHAR;
+		break;
+	case IP_DEFLAB:
+		deflab(ip->ip_lbl);
+		break;
+	case IP_ASM:
+		printf("%s", ip->ip_asm);
+		break;
+	default:
+		cerror("emit %d", ip->type);
+	}
+}
+
+#ifdef PCC_DEBUG
+char *cnames[] = {
+	"SANY",
+	"SAREG",
+	"SBREG",
+	"SCREG",
+	"SDREG",
+	"SCC",
+	"SNAME",
+	"SCON",
+	"SFLD",
+	"SOREG",
+	"STARNM",
+	"STARREG",
+	"INTEMP",
+	"FORARG",
+	"SWADD",
+	0,
+};
+
+/*
+ * print a nice-looking description of cookie
+ */
+char *
+prcook(int cookie)
+{
+	static char buf[50];
+	int i, flag;
+
+	if (cookie & SPECIAL) {
+		switch (cookie) {
+		case SZERO:
+			return "SZERO";
+		case SONE:
+			return "SONE";
+		case SMONE:
+			return "SMONE";
+		default:
+			snprintf(buf, sizeof(buf), "SPECIAL+%d", cookie & ~SPECIAL);
+			return buf;
+		}
+	}
+
+	flag = 0;
+	buf[0] = 0;
+	for (i = 0; cnames[i]; ++i) {
+		if (cookie & (1<<i)) {
+			if (flag)
+				strlcat(buf, "|", sizeof(buf));
+			++flag;
+			strlcat(buf, cnames[i], sizeof(buf));
+		}
+	}
+	return buf;
+}
+#endif
+
+int
+geninsn(NODE *p, int cookie)
+{
+	NODE *p1, *p2;
+	int q, o, rv = 0;
+
+#ifdef PCC_DEBUG
+	if (odebug) {
+		printf("geninsn(%p, %s)\n", p, prcook(cookie));
+		fwalk(p, e2print, 0);
+	}
+#endif
+
+	q = cookie & QUIET;
+	cookie &= ~QUIET; /* XXX - should not be necessary */
+
+again:	switch (o = p->n_op) {
+	case EQ:
+	case NE:
+	case LE:
+	case LT:
+	case GE:
+	case GT:
+	case ULE:
+	case ULT:
+	case UGE:
+	case UGT:
+		p1 = p->n_left;
+		p2 = p->n_right;
+		if (p2->n_op == ICON && p2->n_lval == 0 && *p2->n_name == 0 &&
+		    (dope[p1->n_op] & (FLOFLG|DIVFLG|SIMPFLG|SHFFLG))) {
+#ifdef mach_pdp11 /* XXX all targets? */
+			if ((rv = geninsn(p1, FORCC|QUIET)) != FFAIL)
+				break;
+#else
+			if (findops(p1, FORCC) > 0)
+				break;
+#endif
+		}
+		rv = relops(p);
+		break;
+
+	case PLUS:
+	case MINUS:
+	case MUL:
+	case DIV:
+	case MOD:
+	case AND:
+	case OR:
+	case ER:
+	case LS:
+	case RS:
+		rv = findops(p, cookie);
+		break;
+
+	case ASSIGN:
+#ifdef FINDMOPS
+		if ((rv = findmops(p, cookie)) != FFAIL)
+			break;
+		/* FALLTHROUGH */
+#endif
+	case STASG:
+		rv = findasg(p, cookie);
+		break;
+
+	case UMUL: /* May turn into an OREG */
+		rv = findumul(p, cookie);
+		break;
+
+	case REG:
+	case TEMP:
+	case NAME:
+	case ICON:
+	case FCON:
+	case OREG:
+		rv = findleaf(p, cookie);
+		break;
+
+	case STCALL:
+	case CALL:
+		/* CALL arguments are handled special */
+		for (p1 = p->n_right; p1->n_op == CM; p1 = p1->n_left)
+			(void)geninsn(p1->n_right, FOREFF);
+		(void)geninsn(p1, FOREFF);
+		/* FALLTHROUGH */
+	case FLD:
+	case COMPL:
+	case UMINUS:
+	case PCONV:
+	case SCONV:
+/*	case INIT: */
+	case GOTO:
+	case FUNARG:
+	case STARG:
+	case UCALL:
+	case USTCALL:
+	case ADDROF:
+		rv = finduni(p, cookie);
+		break;
+
+	case CBRANCH:
+		p1 = p->n_left;
+		p2 = p->n_right;
+		p1->n_label = (int)p2->n_lval;
+		(void)geninsn(p1, FORCC);
+		p->n_su = 0;
+		break;
+
+	case FORCE: /* XXX needed? */
+		(void)geninsn(p->n_left, INREGS);
+		p->n_su = 0; /* su calculations traverse left */
+		break;
+
+	case XASM:
+		for (p1 = p->n_left; p1->n_op == CM; p1 = p1->n_left)
+			(void)geninsn(p1->n_right, FOREFF);
+		(void)geninsn(p1, FOREFF);
+		break;	/* all stuff already done? */
+
+	case XARG:
+		/* generate code for correct class here */
+#if 0
+		geninsn(p->n_left, 1 << p->n_label);
+#endif
+		break;
+
+	default:
+		comperr("geninsn: bad op %s, node %p", opst[o], p);
+	}
+	if (rv == FFAIL && !q)
+		comperr("Cannot generate code, node %p op %s", p,opst[p->n_op]);
+	if (rv == FRETRY)
+		goto again;
+#ifdef PCC_DEBUG
+	if (odebug) {
+		printf("geninsn(%p, %s) rv %d\n", p, prcook(cookie), rv);
+		fwalk(p, e2print, 0);
+	}
+#endif
+	return rv;
+}
+
+/*
+ * Store a given subtree in a temporary location.
+ * Return an OREG node where it is located.
+ */
+NODE *
+store(NODE *p)
+{
+	extern struct interpass *storesave;
+	struct interpass *ip;
+	NODE *q, *r;
+	int s;
+
+	s = BITOOR(freetemp(szty(p->n_type)));
+	q = mklnode(OREG, s, FPREG, p->n_type);
+	r = mklnode(OREG, s, FPREG, p->n_type);
+	ip = ipnode(mkbinode(ASSIGN, q, p, p->n_type));
+
+	storesave = ip;
+	return r;
+}
+
+#ifdef PCC_DEBUG
+#define	CDEBUG(x) if (c2debug) printf x
+#else
+#define	CDEBUG(x)
+#endif
+
+/*
+ * Do a register-register move if necessary.
+ */
+static void
+ckmove(NODE *p, NODE *q)
+{
+	if (q->n_op != REG || p->n_reg == -1)
+		return; /* no register */
+	if (DECRA(p->n_reg, 0) == DECRA(q->n_reg, 0))
+		return; /* no move necessary */
+	CDEBUG(("rmove: node %p, %s -> %s\n", p, rnames[DECRA(q->n_reg, 0)],
+	    rnames[DECRA(p->n_reg, 0)]));
+	rmove(DECRA(q->n_reg, 0), DECRA(p->n_reg, 0), p->n_type);
+	q->n_reg = q->n_rval = DECRA(p->n_reg, 0);
+}
+
+/*
+ * Rewrite node to register after instruction emit.
+ */
+static void
+rewrite(NODE *p, int dorewrite, int cookie)
+{
+	NODE *l, *r;
+	int o;
+
+	l = getlr(p, 'L');
+	r = getlr(p, 'R');
+	o = p->n_op;
+	p->n_op = REG;
+	p->n_lval = 0;
+	p->n_name = "";
+
+	if (o == ASSIGN || o == STASG) {
+		/* special rewrite care */
+		int reg = DECRA(p->n_reg, 0);
+#define	TL(x) (TBLIDX(x->n_su) || x->n_op == REG)
+		if (p->n_reg == -1)
+			;
+		else if (TL(l) && (DECRA(l->n_reg, 0) == reg))
+			;
+		else if (TL(r) && (DECRA(r->n_reg, 0) == reg))
+			;
+		else if (TL(l))
+			rmove(DECRA(l->n_reg, 0), reg, p->n_type);
+		else if (TL(r))
+			rmove(DECRA(r->n_reg, 0), reg, p->n_type);
+#if 0
+		else
+			comperr("rewrite");
+#endif
+#undef TL
+	}
+	if (optype(o) != LTYPE)
+		tfree(l);
+	if (optype(o) == BITYPE)
+		tfree(r);
+	if (dorewrite == 0)
+		return;
+	CDEBUG(("rewrite: %p, reg %s\n", p,
+	    p->n_reg == -1? "<none>" : rnames[DECRA(p->n_reg, 0)]));
+	p->n_rval = DECRA(p->n_reg, 0);
+}
+
+#ifndef XASM_TARGARG
+#define	XASM_TARGARG(x,y) 0
+#endif
+
+/*
+ * printout extended assembler.
+ */
+void
+genxasm(NODE *p)
+{
+	NODE *q, **nary;
+	int n = 1, o = 0;
+	char *w;
+
+	if (p->n_left->n_op != ICON || p->n_left->n_type != STRTY) {
+		for (q = p->n_left; q->n_op == CM; q = q->n_left)
+			n++;
+		nary = tmpcalloc(sizeof(NODE *)*(n+1));
+		o = n;
+		for (q = p->n_left; q->n_op == CM; q = q->n_left) {
+			gencode(q->n_right->n_left, INREGS);
+			nary[--o] = q->n_right;
+		}
+		gencode(q->n_left, INREGS);
+		nary[--o] = q;
+	} else
+		nary = 0;
+
+	w = p->n_name;
+	putchar('\t');
+	while (*w != 0) {
+		if (*w == '%') {
+			if (w[1] == '%')
+				putchar('%');
+			else if (XASM_TARGARG(w, nary))
+				; /* handled by target */
+			else if (w[1] < '0' || w[1] > (n + '0'))
+				uerror("bad xasm arg number %c", w[1]);
+			else {
+				if (w[1] == (n + '0'))
+					q = nary[(int)w[1]-'0' - 1]; /* XXX */
+				else
+					q = nary[(int)w[1]-'0'];
+				adrput(stdout, q->n_left);
+			}
+			w++;
+		} else if (*w == '\\') { /* Always 3-digit octal */
+			int num = *++w - '0';
+			num = (num << 3) + *++w - '0';
+			num = (num << 3) + *++w - '0';
+			putchar(num);
+		} else
+			putchar(*w);
+		w++;
+	}
+	putchar('\n');
+}
+
+void
+gencode(NODE *p, int cookie)
+{
+	struct optab *q = &table[TBLIDX(p->n_su)];
+	NODE *p1, *l, *r;
+	int o = optype(p->n_op);
+#ifdef FINDMOPS
+	int ismops = (p->n_op == ASSIGN && (p->n_flags & 1));
+#endif
+
+	l = p->n_left;
+	r = p->n_right;
+
+	if (TBLIDX(p->n_su) == 0) {
+		if (o == BITYPE && (p->n_su & DORIGHT))
+			gencode(r, 0);
+		if (optype(p->n_op) != LTYPE)
+			gencode(l, 0);
+		if (o == BITYPE && !(p->n_su & DORIGHT))
+			gencode(r, 0);
+		return;
+	}
+
+	CDEBUG(("gencode: node %p\n", p));
+
+	if (p->n_op == REG && DECRA(p->n_reg, 0) == p->n_rval)
+		return; /* meaningless move to itself */
+
+	if (callop(p->n_op))
+		lastcall(p); /* last chance before function args */
+	if (p->n_op == CALL || p->n_op == FORTCALL || p->n_op == STCALL) {
+		/* Print out arguments first */
+		for (p1 = r; p1->n_op == CM; p1 = p1->n_left)
+			gencode(p1->n_right, FOREFF);
+		gencode(p1, FOREFF);
+		o = UTYPE; /* avoid going down again */
+	}
+
+	if (o == BITYPE && (p->n_su & DORIGHT)) {
+		gencode(r, INREGS);
+		if (q->rewrite & RRIGHT)
+			ckmove(p, r);
+	}
+	if (o != LTYPE) {
+		gencode(l, INREGS);
+#ifdef FINDMOPS
+		if (ismops)
+			;
+		else
+#endif
+		     if (q->rewrite & RLEFT)
+			ckmove(p, l);
+	}
+	if (o == BITYPE && !(p->n_su & DORIGHT)) {
+		gencode(r, INREGS);
+		if (q->rewrite & RRIGHT)
+			ckmove(p, r);
+	}
+
+#ifdef FINDMOPS
+	if (ismops) {
+		/* reduce right tree to make expand() work */
+		if (optype(r->n_op) != LTYPE) {
+			p->n_op = r->n_op;
+			r = tcopy(r->n_right);
+			tfree(p->n_right);
+			p->n_right = r;
+		}
+	}
+#endif
+
+	canon(p);
+
+	if (q->needs & NSPECIAL) {
+		int rr = rspecial(q, NRIGHT);
+		int lr = rspecial(q, NLEFT);
+
+		if (rr >= 0) {
+#ifdef PCC_DEBUG
+			if (optype(p->n_op) != BITYPE)
+				comperr("gencode: rspecial borked");
+#endif
+			if (r->n_op != REG)
+				comperr("gencode: rop != REG");
+			if (rr != r->n_rval)
+				rmove(r->n_rval, rr, r->n_type);
+			r->n_rval = r->n_reg = rr;
+		}
+		if (lr >= 0) {
+			if (l->n_op != REG)
+				comperr("gencode: %p lop != REG", p);
+			if (lr != l->n_rval)
+				rmove(l->n_rval, lr, l->n_type);
+			l->n_rval = l->n_reg = lr;
+		}
+		if (rr >= 0 && lr >= 0 && (l->n_reg == rr || r->n_reg == lr))
+			comperr("gencode: cross-reg-move");
+	}
+
+	if (p->n_op == ASSIGN &&
+	    p->n_left->n_op == REG && p->n_right->n_op == REG &&
+	    p->n_left->n_rval == p->n_right->n_rval &&
+	    (p->n_su & RVCC) == 0) { /* XXX should check if necessary */
+		/* do not emit anything */
+		CDEBUG(("gencode(%p) assign nothing\n", p));
+		rewrite(p, q->rewrite, cookie);
+		return;
+	}
+
+	CDEBUG(("emitting node %p\n", p));
+	if (TBLIDX(p->n_su) == 0)
+		return;
+
+	expand(p, cookie, q->cstring);
+#ifdef FINDMOPS
+	if (ismops && DECRA(p->n_reg, 0) != regno(l) && cookie != FOREFF) {
+		CDEBUG(("gencode(%p) rmove\n", p));
+		rmove(regno(l), DECRA(p->n_reg, 0), p->n_type);
+	} else
+#endif
+	if (callop(p->n_op) && cookie != FOREFF &&
+	    DECRA(p->n_reg, 0) != RETREG(p->n_type)) {
+		CDEBUG(("gencode(%p) retreg\n", p));
+		rmove(RETREG(p->n_type), DECRA(p->n_reg, 0), p->n_type);
+	} else if (q->needs & NSPECIAL) {
+		int rr = rspecial(q, NRES);
+
+		if (rr >= 0 && DECRA(p->n_reg, 0) != rr) {
+			CDEBUG(("gencode(%p) nspec retreg\n", p));
+			rmove(rr, DECRA(p->n_reg, 0), p->n_type);
+		}
+	} else if ((q->rewrite & RESC1) &&
+	    (DECRA(p->n_reg, 1) != DECRA(p->n_reg, 0))) {
+		CDEBUG(("gencode(%p) RESC1 retreg\n", p));
+		rmove(DECRA(p->n_reg, 1), DECRA(p->n_reg, 0), p->n_type);
+	}
+#if 0
+		/* XXX - kolla upp det h{r */
+	   else if (p->n_op == ASSIGN) {
+		/* may need move added if RLEFT/RRIGHT */
+		/* XXX should be handled in sucomp() */
+		if ((q->rewrite & RLEFT) && (p->n_left->n_op == REG) &&
+		    (p->n_left->n_rval != DECRA(p->n_reg, 0)) &&
+		    TCLASS(p->n_su)) {
+			rmove(p->n_left->n_rval, DECRA(p->n_reg, 0), p->n_type);
+		} else if ((q->rewrite & RRIGHT) && (p->n_right->n_op == REG) &&
+		    (p->n_right->n_rval != DECRA(p->n_reg, 0)) &&
+		    TCLASS(p->n_su)) {
+			rmove(p->n_right->n_rval, DECRA(p->n_reg, 0), p->n_type);
+		}
+	}
+#endif
+	rewrite(p, q->rewrite, cookie);
+}
+
+int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ;  /* negatives of relationals */
+size_t negrelsize = sizeof negrel / sizeof negrel[0];
+
+#ifdef PCC_DEBUG
+#undef	PRTABLE
+void
+e2print(NODE *p, int down, int *a, int *b)
+{
+#ifdef PRTABLE
+	extern int tablesize;
+#endif
+
+	prfil = stdout;
+	*a = *b = down+1;
+	while( down >= 2 ){
+		fprintf(prfil, "\t");
+		down -= 2;
+		}
+	if( down-- ) fprintf(prfil, "    " );
+
+
+	fprintf(prfil, "%p) %s", p, opst[p->n_op] );
+	switch( p->n_op ) { /* special cases */
+
+	case FLD:
+		fprintf(prfil, " sz=%d, shift=%d",
+		    UPKFSZ(p->n_rval), UPKFOFF(p->n_rval));
+		break;
+
+	case REG:
+		fprintf(prfil, " %s", rnames[p->n_rval] );
+		break;
+
+	case TEMP:
+		fprintf(prfil, " %d", regno(p));
+		break;
+
+	case XASM:
+	case XARG:
+		fprintf(prfil, " '%s'", p->n_name);
+		break;
+
+	case ICON:
+	case NAME:
+	case OREG:
+		fprintf(prfil, " " );
+		adrput(prfil, p );
+		break;
+
+	case STCALL:
+	case USTCALL:
+	case STARG:
+	case STASG:
+		fprintf(prfil, " size=%d", p->n_stsize );
+		fprintf(prfil, " align=%d", p->n_stalign );
+		break;
+		}
+
+	fprintf(prfil, ", " );
+	tprint(prfil, p->n_type, p->n_qual);
+	fprintf(prfil, ", " );
+
+	prtreg(prfil, p);
+	fprintf(prfil, ", SU= %d(%cREG,%s,%s,%s,%s,%s,%s)\n",
+	    TBLIDX(p->n_su), 
+	    TCLASS(p->n_su)+'@',
+#ifdef PRTABLE
+	    TBLIDX(p->n_su) >= 0 && TBLIDX(p->n_su) <= tablesize ?
+	    table[TBLIDX(p->n_su)].cstring : "",
+#else
+	    "",
+#endif
+	    p->n_su & LREG ? "LREG" : "", p->n_su & RREG ? "RREG" : "",
+	    p->n_su & RVEFF ? "RVEFF" : "", p->n_su & RVCC ? "RVCC" : "",
+	    p->n_su & DORIGHT ? "DORIGHT" : "");
+}
+#endif
+
+#ifndef FIELDOPS
+/*
+ * do this if there is no special hardware support for fields
+ */
+static void
+ffld(NODE *p, int down, int *down1, int *down2 )
+{
+	/*
+	 * look for fields that are not in an lvalue context,
+	 * and rewrite them...
+	 */
+	NODE *shp;
+	int s, o, v, ty;
+
+	*down1 =  asgop( p->n_op );
+	*down2 = 0;
+
+	if( !down && p->n_op == FLD ){ /* rewrite the node */
+
+		if( !rewfld(p) ) return;
+
+		ty = p->n_type;
+		v = p->n_rval;
+		s = UPKFSZ(v);
+# ifdef RTOLBYTES
+		o = UPKFOFF(v);  /* amount to shift */
+# else
+		o = szty(p->n_type)*SZINT - s - UPKFOFF(v);  /* amount to shift */
+#endif
+		/* make & mask part */
+
+		if (ISUNSIGNED(ty)) {
+
+			p->n_left->n_type = ty;
+			p->n_op = AND;
+			p->n_right = mklnode(ICON, ((CONSZ)1 << s)-1, 0, ty);
+
+			/* now, if a shift is needed, do it */
+			if( o != 0 ){
+				shp = mkbinode(RS, p->n_left,
+				    mklnode(ICON, o, 0, INT), ty);
+				p->n_left = shp;
+				/* whew! */
+			}
+		} else {
+			int mz;
+
+			mz = 0;
+#define	SZT(x) case x: mz = SZ ## x; break;
+			switch (ty) {
+			SZT(CHAR) SZT(SHORT) SZT(INT) SZT(LONG)
+			SZT(LONGLONG)
+			}
+			/* must sign-extend, assume RS will do */
+			/* if not, arch must use rewfld() */
+			p->n_left->n_type = ty;
+			p->n_op = RS;
+			p->n_right = mklnode(ICON, mz-s, 0, INT);
+			p->n_left = mkbinode(LS, p->n_left, 
+			    mklnode(ICON, mz-s-o, 0, INT), ty);
+		}
+	}
+}
+#endif
+
+/*
+ * change left TEMPs into OREGs
+ */
+void
+deltemp(NODE *p, void *arg)
+{
+	int *aor = arg;
+	NODE *l, *r;
+
+	if (p->n_op == TEMP) {
+		if (aor[regno(p)] == 0) {
+			if (xtemps)
+				return;
+			aor[regno(p)] = BITOOR(freetemp(szty(p->n_type)));
+		}
+		l = mklnode(REG, 0, FPREG, INCREF(p->n_type));
+		r = mklnode(ICON, aor[regno(p)], 0, INT);
+		p->n_left = mkbinode(PLUS, l, r, INCREF(p->n_type));
+		p->n_op = UMUL;
+	} else if (p->n_op == ADDROF && p->n_left->n_op == OREG) {
+		p->n_op = PLUS;
+		l = p->n_left;
+		l->n_op = REG;
+		l->n_type = INCREF(l->n_type);
+		p->n_right = mklnode(ICON, l->n_lval, 0, INT);
+	} else if (p->n_op == ADDROF && p->n_left->n_op == UMUL) {
+		l = p->n_left;
+		*p = *p->n_left->n_left;
+		nfree(l->n_left);
+		nfree(l);
+	}
+}
+
+/*
+ * for pointer/integer arithmetic, set pointer at left node
+ */
+static void
+setleft(NODE *p, void *arg)
+{        
+	NODE *q;
+
+	/* only additions for now */
+	if (p->n_op != PLUS)
+		return;
+	if (ISPTR(p->n_right->n_type) && !ISPTR(p->n_left->n_type)) {
+		q = p->n_right;
+		p->n_right = p->n_left;
+		p->n_left = q;
+	}
+}
+
+/* It is OK to have these as externals */
+static int oregr;
+static CONSZ oregtemp;
+static char *oregcp;
+/*
+ * look for situations where we can turn * into OREG
+ * If sharp then do not allow temps.
+ */
+int
+oregok(NODE *p, int sharp)
+{
+
+	NODE *q;
+	NODE *ql, *qr;
+	int r;
+	CONSZ temp;
+	char *cp;
+
+	q = p->n_left;
+#if 0
+	if ((q->n_op == REG || (q->n_op == TEMP && !sharp)) &&
+	    q->n_rval == DECRA(q->n_reg, 0)) {
+#endif
+	if (q->n_op == REG || (q->n_op == TEMP && !sharp)) {
+		temp = q->n_lval;
+		r = q->n_rval;
+		cp = q->n_name;
+		goto ormake;
+	}
+
+	if (q->n_op != PLUS && q->n_op != MINUS)
+		return 0;
+	ql = q->n_left;
+	qr = q->n_right;
+
+#ifdef R2REGS
+
+	/* look for doubly indexed expressions */
+	/* XXX - fix checks */
+
+	if( q->n_op == PLUS) {
+		int i;
+		if( (r=base(ql))>=0 && (i=offset(qr, tlen(p)))>=0) {
+			makeor2(p, ql, r, i);
+			return 1;
+		} else if((r=base(qr))>=0 && (i=offset(ql, tlen(p)))>=0) {
+			makeor2(p, qr, r, i);
+			return 1;
+		}
+	}
+
+
+#endif
+
+#if 0
+	if( (q->n_op==PLUS || q->n_op==MINUS) && qr->n_op == ICON &&
+			(ql->n_op==REG || (ql->n_op==TEMP && !sharp)) &&
+			szty(qr->n_type)==1 &&
+			(ql->n_rval == DECRA(ql->n_reg, 0) ||
+			/* XXX */
+			 ql->n_rval == FPREG || ql->n_rval == STKREG)) {
+#endif
+	if ((q->n_op==PLUS || q->n_op==MINUS) && qr->n_op == ICON &&
+	    (ql->n_op==REG || (ql->n_op==TEMP && !sharp))) {
+	    
+		temp = qr->n_lval;
+		if( q->n_op == MINUS ) temp = -temp;
+		r = ql->n_rval;
+		temp += ql->n_lval;
+		cp = qr->n_name;
+		if( *cp && ( q->n_op == MINUS || *ql->n_name ) )
+			return 0;
+		if( !*cp ) cp = ql->n_name;
+
+		ormake:
+		if( notoff( p->n_type, r, temp, cp ))
+			return 0;
+		oregtemp = temp;
+		oregr = r;
+		oregcp = cp;
+		return 1;
+	}
+	return 0;
+}
+
+static void
+ormake(NODE *p)
+{
+	NODE *q = p->n_left;
+
+	p->n_op = OREG;
+	p->n_rval = oregr;
+	p->n_lval = oregtemp;
+	p->n_name = oregcp;
+	tfree(q);
+}
+
+/*
+ * look for situations where we can turn * into OREG
+ */
+void
+oreg2(NODE *p, void *arg)
+{
+	if (p->n_op != UMUL)
+		return;
+	if (oregok(p, 1))
+		ormake(p);
+	if (p->n_op == UMUL)
+		myormake(p);
+}
+
+void
+canon(p) NODE *p; {
+	/* put p in canonical form */
+
+	walkf(p, setleft, 0);	/* ptrs at left node for arithmetic */
+	walkf(p, oreg2, 0);	/* look for and create OREG nodes */
+#ifndef FIELDOPS
+	fwalk(p, ffld, 0);	/* look for field operators */
+# endif
+	mycanon(p);		/* your own canonicalization routine(s) */
+
+}
+
+void
+comperr(char *str, ...)
+{
+	extern char *ftitle;
+	va_list ap;
+
+	if (nerrors) {
+		fprintf(stderr,
+		    "cannot recover from earlier errors: goodbye!\n");
+		exit(1);
+	}
+
+	va_start(ap, str);
+	fprintf(stderr, "%s, line %d: compiler error: ", ftitle, thisline);
+	vfprintf(stderr, str, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+	prfil = stderr;
+
+#ifdef PCC_DEBUG
+	if (nodepole && nodepole->n_op != FREE)
+		fwalk(nodepole, e2print, 0);
+#endif
+	exit(1);
+}
+
+/*
+ * allocate k integers worth of temp space
+ * we also make the convention that, if the number of words is
+ * more than 1, it must be aligned for storing doubles...
+ * Returns bits offset from base register.
+ * XXX - redo this.
+ */
+int
+freetemp(int k)
+{
+#ifndef BACKTEMP
+	int t;
+
+	if (k > 1)
+		SETOFF(p2autooff, ALDOUBLE/ALCHAR);
+
+	t = p2autooff;
+	p2autooff += k*(SZINT/SZCHAR);
+	if (p2autooff > p2maxautooff)
+		p2maxautooff = p2autooff;
+	return (t);
+
+#else
+	p2autooff += k*(SZINT/SZCHAR);
+	if (k > 1)
+		SETOFF(p2autooff, ALDOUBLE/ALCHAR);
+
+	if (p2autooff > p2maxautooff)
+		p2maxautooff = p2autooff;
+	return( -p2autooff );
+#endif
+	}
+
+NODE *
+mklnode(int op, CONSZ lval, int rval, TWORD type)
+{
+	NODE *p = talloc();
+
+	p->n_name = "";
+	p->n_qual = 0;
+	p->n_op = op;
+	p->n_label = 0;
+	p->n_lval = lval;
+	p->n_rval = rval;
+	p->n_type = type;
+	p->n_regw = NULL;
+	p->n_su = 0;
+	return p;
+}
+
+NODE *
+mkbinode(int op, NODE *left, NODE *right, TWORD type)
+{
+	NODE *p = talloc();
+
+	p->n_name = "";
+	p->n_qual = 0;
+	p->n_op = op;
+	p->n_label = 0;
+	p->n_left = left;
+	p->n_right = right;
+	p->n_type = type;
+	p->n_regw = NULL;
+	p->n_su = 0;
+	return p;
+}
+
+NODE *
+mkunode(int op, NODE *left, int rval, TWORD type)
+{
+	NODE *p = talloc();
+
+	p->n_name = "";
+	p->n_qual = 0;
+	p->n_op = op;
+	p->n_label = 0;
+	p->n_left = left;
+	p->n_rval = rval;
+	p->n_type = type;
+	p->n_regw = NULL;
+	p->n_su = 0;
+	return p;
+}
+
+struct interpass *
+ipnode(NODE *p)
+{
+	struct interpass *ip = tmpalloc(sizeof(struct interpass));
+
+	ip->ip_node = p;
+	ip->type = IP_NODE;
+	ip->lineno = thisline;
+	return ip;
+}
+
+int
+rspecial(struct optab *q, int what)
+{
+	struct rspecial *r = nspecial(q);
+	while (r->op) {
+		if (r->op == what)
+			return r->num;
+		r++;
+	}
+	return -1;
+}
+
+#ifndef XASM_NUMCONV
+#define	XASM_NUMCONV(x,y,z)	0
+#endif
+
+/*
+ * change numeric argument redirections to the correct node type after 
+ * cleaning up the other nodes.
+ * be careful about input operands that may have different value than output.
+ */
+static void
+delnums(NODE *p, void *arg)
+{
+	struct interpass *ip = arg, *ip2;
+	NODE *r = ip->ip_node->n_left;
+	NODE *q;
+	TWORD t;
+	int cnt, num;
+
+	if (p->n_name[0] < '0' || p->n_name[0] > '9')
+		return; /* not numeric */
+	if ((q = listarg(r, p->n_name[0] - '0', &cnt)) == NIL)
+		comperr("bad delnums");
+
+	/* target may have opinions whether to do this conversion */
+	if (XASM_NUMCONV(ip, p, q))
+		return;
+
+	/* Delete number by adding move-to/from-temp.  Later on */
+	/* the temps may be rewritten to other LTYPEs */
+	num = p2env.epp->ip_tmpnum++;
+
+	/* pre node */
+	t = p->n_left->n_type;
+	r = mklnode(TEMP, 0, num, t);
+	ip2 = ipnode(mkbinode(ASSIGN, tcopy(r), p->n_left, t));
+	DLIST_INSERT_BEFORE(ip, ip2, qelem);
+	p->n_left = r;
+
+	/* post node */
+	t = q->n_left->n_type;
+	r = mklnode(TEMP, 0, num, t);
+	ip2 = ipnode(mkbinode(ASSIGN, q->n_left, tcopy(r), t));
+	DLIST_INSERT_AFTER(ip, ip2, qelem);
+	q->n_left = r;
+
+	p->n_name = tmpstrdup(q->n_name);
+	if (*p->n_name == '=')
+		p->n_name++;
+}
+
+/*
+ * Ensure that a node is correct for the destination.
+ */
+static void
+ltypify(NODE *p, void *arg)
+{
+	struct interpass *ip = arg;
+	struct interpass *ip2;
+	TWORD t = p->n_left->n_type;
+	NODE *q, *r;
+	int cw, ooff, ww;
+	char *c;
+
+again:
+	if (myxasm(ip, p))
+		return;	/* handled by target-specific code */
+
+	cw = xasmcode(p->n_name);
+	switch (ww = XASMVAL(cw)) {
+	case 'p':
+		/* pointer */
+		/* just make register of it */
+		p->n_name = tmpstrdup(p->n_name);
+		c = strchr(p->n_name, XASMVAL(cw)); /* cannot fail */
+		*c = 'r';
+		/* FALLTHROUGH */
+	case 'g':  /* general; any operand */
+		if (ww == 'g' && p->n_left->n_op == ICON) {
+			/* should only be input */
+			p->n_name = "i";
+			break;
+		}
+	case 'r': /* general reg */
+		/* set register class */
+		p->n_label = gclass(p->n_left->n_type);
+		if (p->n_left->n_op == REG)
+			break;
+		q = p->n_left;
+		r = (cw & XASMINOUT ? tcopy(q) : q);
+		p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t);
+		if ((cw & XASMASG) == 0) {
+			ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), r, t));
+			DLIST_INSERT_BEFORE(ip, ip2, qelem);
+		}
+		if (cw & (XASMASG|XASMINOUT)) {
+			/* output parameter */
+			ip2 = ipnode(mkbinode(ASSIGN, q, tcopy(p->n_left), t));
+			DLIST_INSERT_AFTER(ip, ip2, qelem);
+		}
+		break;
+
+	case '0': case '1': case '2': case '3': case '4':
+	case '5': case '6': case '7': case '8': case '9':
+		break;
+
+	case 'm': /* memory operand */
+		/* store and reload value */
+		q = p->n_left;
+		if (optype(q->n_op) == LTYPE) {
+			if (q->n_op == TEMP) {
+				ooff = BITOOR(freetemp(szty(t)));
+				cvtemps(ip, q->n_rval, ooff);
+			} else if (q->n_op == REG)
+				comperr("xasm m and reg");
+		} else if (q->n_op == UMUL && 
+		    (q->n_left->n_op != TEMP && q->n_left->n_op != REG)) {
+			t = q->n_left->n_type;
+			ooff = p2env.epp->ip_tmpnum++;
+			ip2 = ipnode(mkbinode(ASSIGN,
+			    mklnode(TEMP, 0, ooff, t), q->n_left, t));
+			q->n_left = mklnode(TEMP, 0, ooff, t);
+			DLIST_INSERT_BEFORE(ip, ip2, qelem);
+		}
+		break;
+
+	case 'i': /* immediate constant */
+	case 'n': /* numeric constant */
+		if (p->n_left->n_op == ICON)
+			break;
+		p->n_name = tmpstrdup(p->n_name);
+		c = strchr(p->n_name, XASMVAL(cw)); /* cannot fail */
+		if (c[1]) {
+			c[0] = c[1], c[1] = 0;
+			goto again;
+		} else
+			uerror("constant required");
+		break;
+
+	default:
+		uerror("unsupported xasm option string '%s'", p->n_name);
+	}
+}
+
+/* Extended assembler hacks */
+static void
+fixxasm(struct p2env *p2e)
+{
+	struct interpass *pole = &p2e->ipole;
+	struct interpass *ip;
+	NODE *p;
+
+	DLIST_FOREACH(ip, pole, qelem) {
+		if (ip->type != IP_NODE || ip->ip_node->n_op != XASM)
+			continue;
+		thisline = ip->lineno;
+		p = ip->ip_node->n_left;
+
+		if (p->n_op == ICON && p->n_type == STRTY)
+			continue;
+
+		/* replace numeric redirections with its underlying type */
+		flist(p, delnums, ip);
+
+		/*
+		 * Ensure that the arg nodes can be directly addressable
+		 * We decide that everything shall be LTYPE here.
+		 */
+		flist(p, ltypify, ip);
+	}
+}
+
+/*
+ * Extract codeword from xasm string */
+int
+xasmcode(char *s)
+{
+	int cw = 0, nm = 0;
+
+	while (*s) {
+		switch ((int)*s) {
+		case '=': cw |= XASMASG; break;
+		case '&': cw |= XASMCONSTR; break;
+		case '+': cw |= XASMINOUT; break;
+		case '%': break;
+		default:
+			if ((*s >= 'a' && *s <= 'z') ||
+			    (*s >= 'A' && *s <= 'Z') ||
+			    (*s >= '0' && *s <= '9')) {
+				if (nm == 0)
+					cw |= *s;
+				else
+					cw |= (*s << ((nm + 1) * 8));
+				nm++;
+				break;
+			}
+			uerror("bad xasm constraint %c", *s);
+		}
+		s++;
+	}
+	return cw;
+}
+
+static int xasnum, xoffnum;
+
+static void
+xconv(NODE *p, void *arg)
+{
+	if (p->n_op != TEMP || p->n_rval != xasnum)
+		return;
+	p->n_op = OREG;
+	p->n_rval = FPREG;
+	p->n_lval = xoffnum;
+}
+
+/*
+ * Convert nodes of type TEMP to op with lval off.
+ */
+static void
+cvtemps(struct interpass *ipl, int tnum, int off)
+{
+	struct interpass *ip;
+
+	xasnum = tnum;
+	xoffnum = off;
+
+	DLIST_FOREACH(ip, ipl, qelem)
+		if (ip->type == IP_NODE)
+			walkf(ip->ip_node, xconv, 0);
+	walkf(ipl->ip_node, xconv, 0);
+}
Index: uspace/app/pcc/mip/regs.c
===================================================================
--- uspace/app/pcc/mip/regs.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/mip/regs.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,2869 @@
+/*	$Id: regs.c,v 1.216.2.1 2011/02/22 18:38:08 ragge Exp $	*/
+/*
+ * Copyright (c) 2005 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pass2.h"
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+
+#define	MAXLOOP	20 /* Max number of allocation loops XXX 3 should be enough */
+
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+ 
+/*
+ * New-style register allocator using graph coloring.
+ * The design is based on the George and Appel paper
+ * "Iterated Register Coalescing", ACM Transactions, No 3, May 1996.
+ */
+
+#define	BITALLOC(ptr,all,sz) { \
+	int sz__s = BIT2BYTE(sz); ptr = all(sz__s); memset(ptr, 0, sz__s); }
+
+#undef COMPERR_PERM_MOVE
+#ifdef PCC_DEBUG
+#define	RDEBUG(x)	if (rdebug) printf x
+#define	RRDEBUG(x)	if (rdebug > 1) printf x
+#define	RPRINTIP(x)	if (rdebug) printip(x)
+#define	RDEBUGX(x)		x
+#define UDEBUG(x)	if (udebug) printf x
+#define BDEBUG(x)	if (b2debug) printf x
+#define BBDEBUG(x)	if (b2debug > 1) printf x
+#else
+#define	RDEBUG(x)
+#define	RRDEBUG(x)
+#define	RPRINTIP(x)
+#define	RDEBUGX(x)
+#define UDEBUG(x)
+#define BDEBUG(x)
+#define BBDEBUG(x)
+#endif
+
+#define	VALIDREG(p)	(p->n_op == REG && TESTBIT(validregs, regno(p)))
+
+/*
+ * Data structure overview for this implementation of graph coloring:
+ *
+ * Each temporary (called "node") is described by the type REGW.  
+ * Space for all nodes is allocated initially as an array, so 
+ * the nodes can be can be referenced both by the node number and
+ * by pointer.
+ * 
+ * All moves are represented by the type REGM, allocated when needed. 
+ *
+ * The "live" set used during graph building is represented by a bitset.
+ *
+ * Interference edges are represented by struct AdjSet, hashed and linked
+ * from index into the edgehash array.
+ *
+ * A mapping from each node to the moves it is assiciated with is 
+ * maintained by an array moveList which for each node number has a linked
+ * list of MOVL types, each pointing to a REGM.
+ *
+ * Adjacency list is maintained by the adjList array, indexed by the
+ * node number. Each adjList entry points to an ADJL type, and is a
+ * single-linked list for all adjacent nodes.
+ *
+ * degree, alias and color are integer arrays indexed by node number.
+ */
+
+/*
+ * linked list of adjacent nodes.
+ */
+typedef struct regw3 {
+	struct regw3 *r_next;
+	struct regw *a_temp;
+} ADJL;
+
+/*
+ * Structure describing a move.
+ */
+typedef struct regm {
+	DLIST_ENTRY(regm) link;
+	struct regw *src, *dst;
+	int queue;
+} REGM;
+
+typedef struct movlink {
+	struct movlink *next;
+	REGM *regm;
+} MOVL;
+
+/*
+ * Structure describing a temporary.
+ */
+typedef struct regw {
+	DLIST_ENTRY(regw) link;
+	ADJL *r_adjList;	/* linked list of adjacent nodes */
+	int r_class;		/* this nodes class */
+	int r_nclass[NUMCLASS+1];	/* count of adjacent classes */
+	struct regw *r_alias;		/* aliased temporary */
+	int r_color;		/* final node color */
+	struct regw *r_onlist;	/* which work list this node belongs to */
+	MOVL *r_moveList;	/* moves associated with this node */
+#ifdef PCC_DEBUG
+	int nodnum;		/* Debug number */
+#endif
+} REGW;
+
+/*
+ * Worklists, a node is always on exactly one of these lists.
+ */
+static REGW precolored, simplifyWorklist, freezeWorklist, spillWorklist,
+	spilledNodes, coalescedNodes, coloredNodes, selectStack;
+static REGW initial, *nblock;
+static void insnwalk(NODE *p);
+#ifdef PCC_DEBUG
+int use_regw;
+int nodnum = 100;
+#define	SETNUM(x)	(x)->nodnum = nodnum++
+#define	ASGNUM(x)	(x)->nodnum
+#else
+#define SETNUM(x)
+#define ASGNUM(x)
+#endif
+
+#define	ALLNEEDS (NACOUNT|NBCOUNT|NCCOUNT|NDCOUNT|NECOUNT|NFCOUNT|NGCOUNT)
+
+/* XXX */
+REGW *ablock;
+
+static int tempmin, tempmax, basetemp, xbits;
+/*
+ * nsavregs is an array that matches the permregs array.
+ * Each entry in the array may have the values:
+ * 0	: register coalesced, just ignore.
+ * 1	: save register on stack
+ * If the entry is 0 but the resulting color differs from the 
+ * corresponding permregs index, add moves.
+ * XXX - should be a bitfield!
+ */
+static int *nsavregs, *ndontregs;
+
+/*
+ * Return the REGW struct for a temporary.
+ * If first time touched, enter into list for existing vars.
+ * Only called from sucomp().
+ */
+static REGW *
+newblock(NODE *p)
+{
+	REGW *nb;
+
+#ifdef PCC_DEBUG
+	if (regno(p) < tempmin || regno(p) >= tempmax)
+		comperr("temp %p(%d) outside limits (%d-%d)",
+		    p, regno(p), tempmin, tempmax);
+#endif
+	nb = &nblock[regno(p)];
+	if (nb->link.q_forw == 0) {
+		DLIST_INSERT_AFTER(&initial, nb, link);
+#ifdef PCC_DEBUG
+		ASGNUM(nb) = regno(p);
+		RDEBUG(("Adding longtime %d for tmp %d\n",
+		    nb->nodnum, regno(p)));
+#endif
+	}
+	if (nb->r_class == 0)
+		nb->r_class = gclass(p->n_type);
+#ifdef PCC_DEBUG
+	RDEBUG(("newblock: p %p, node %d class %d\n",
+	    p, nb->nodnum, nb->r_class));
+#endif
+	return nb;
+}
+
+/*
+ * Count the number of registers needed to evaluate a tree.
+ * This is only done to find the evaluation order of the tree.
+ * While here, assign temp numbers to the registers that will
+ * be needed when the tree is evaluated.
+ *
+ * While traversing the tree, assign REGW nodes to the registers
+ * used by all instructions:
+ *	- n_regw[0] is always set to the outgoing node. If the
+ *	  instruction is 2-op (addl r0,r1) then an implicit move
+ *	  is inserted just before the left (clobbered) operand.
+ *	- if the instruction has needs then REGW nodes are
+ *	  allocated as n_regw[1] etc.
+ */
+int
+nsucomp(NODE *p)
+{
+	struct optab *q;
+	int left, right;
+	int nreg, need, i, nxreg, o;
+	int nareg, nbreg, ncreg, ndreg, nereg, nfreg, ngreg;
+	REGW *w;
+
+	o = optype(p->n_op);
+
+	UDEBUG(("entering nsucomp, node %p\n", p));
+
+	if (TBLIDX(p->n_su) == 0) {
+		int a = 0, b;
+
+		p->n_regw = NULL;
+		if (o == LTYPE ) {
+			if (p->n_op == TEMP)
+				p->n_regw = newblock(p);
+			else if (p->n_op == REG)
+				p->n_regw = &ablock[regno(p)];
+		} else
+			a = nsucomp(p->n_left);
+		if (o == BITYPE) {
+			b = nsucomp(p->n_right);
+			if (b > a)
+				p->n_su |= DORIGHT;
+			a = MAX(a, b);
+		}
+		return a;
+	}
+
+	q = &table[TBLIDX(p->n_su)];
+
+	for (i = (q->needs & NACOUNT), nareg = 0; i; i -= NAREG)
+		nareg++;
+	for (i = (q->needs & NBCOUNT), nbreg = 0; i; i -= NBREG)
+		nbreg++;
+	for (i = (q->needs & NCCOUNT), ncreg = 0; i; i -= NCREG)
+		ncreg++;
+	for (i = (q->needs & NDCOUNT), ndreg = 0; i; i -= NDREG)
+		ndreg++;
+	for (i = (q->needs & NECOUNT), nereg = 0; i; i -= NEREG)
+		nereg++;
+	for (i = (q->needs & NFCOUNT), nfreg = 0; i; i -= NFREG)
+		nfreg++;
+	for (i = (q->needs & NGCOUNT), ngreg = 0; i; i -= NGREG)
+		ngreg++;
+
+	nxreg = nareg + nbreg + ncreg + ndreg + nereg + nfreg + ngreg;
+	nreg = nxreg;
+	if (callop(p->n_op))
+		nreg = MAX(fregs, nreg);
+
+	if (o == BITYPE) {
+		right = nsucomp(p->n_right);
+	} else
+		right = 0;
+
+	if (o != LTYPE)
+		left = nsucomp(p->n_left);
+	else
+		left = 0;
+
+	UDEBUG(("node %p left %d right %d\n", p, left, right));
+
+	if (o == BITYPE) {
+		/* Two children */
+		if (right == left) {
+			need = left + MAX(nreg, 1);
+		} else {
+			need = MAX(right, left);
+			need = MAX(need, nreg);
+		}
+		if (setorder(p) == 0) {
+			/* XXX - should take care of overlapping needs */
+			if (right > left) {
+				p->n_su |= DORIGHT;
+			} else if (right == left) {
+				/* A favor to 2-operand architectures */
+				if ((q->rewrite & RRIGHT) == 0)
+					p->n_su |= DORIGHT;
+			}
+		}
+	} else if (o != LTYPE) {
+		/* One child */
+		need = MAX(right, left) + nreg;
+	} else
+		need = nreg;
+
+	if (p->n_op == TEMP)
+		(void)newblock(p);
+
+	if (TCLASS(p->n_su) == 0 && nxreg == 0) {
+		UDEBUG(("node %p no class\n", p));
+		p->n_regw = NULL; /* may be set earlier */
+		return need;
+	}
+
+#ifdef PCC_DEBUG
+#define	ADCL(n, cl)	\
+	for (i = 0; i < n; i++, w++) {	w->r_class = cl; \
+		DLIST_INSERT_BEFORE(&initial, w, link);  SETNUM(w); \
+		UDEBUG(("Adding " #n " %d\n", w->nodnum)); \
+	}
+#else
+#define	ADCL(n, cl)	\
+	for (i = 0; i < n; i++, w++) {	w->r_class = cl; \
+		DLIST_INSERT_BEFORE(&initial, w, link);  SETNUM(w); \
+	}
+#endif
+
+	UDEBUG(("node %p numregs %d\n", p, nxreg+1));
+	w = p->n_regw = tmpalloc(sizeof(REGW) * (nxreg+1));
+	memset(w, 0, sizeof(REGW) * (nxreg+1));
+
+	w->r_class = TCLASS(p->n_su);
+	if (w->r_class == 0)
+		w->r_class = gclass(p->n_type);
+	w->r_nclass[0] = o == LTYPE; /* XXX store leaf info here */
+	SETNUM(w);
+	if (w->r_class)
+		DLIST_INSERT_BEFORE(&initial, w, link);
+#ifdef PCC_DEBUG
+	UDEBUG(("Adding short %d class %d\n", w->nodnum, w->r_class));
+#endif
+	w++;
+	ADCL(nareg, CLASSA);
+	ADCL(nbreg, CLASSB);
+	ADCL(ncreg, CLASSC);
+	ADCL(ndreg, CLASSD);
+	ADCL(nereg, CLASSE);
+	ADCL(nfreg, CLASSF);
+	ADCL(ngreg, CLASSG);
+
+	if (q->rewrite & RESC1) {
+		w = p->n_regw + 1;
+		w->r_class = -1;
+		DLIST_REMOVE(w,link);
+	} else if (q->rewrite & RESC2) {
+		w = p->n_regw + 2;
+		w->r_class = -1;
+		DLIST_REMOVE(w,link);
+	} else if (q->rewrite & RESC3) {
+		w = p->n_regw + 3;
+		w->r_class = -1;
+		DLIST_REMOVE(w,link);
+	}
+
+	UDEBUG(("node %p return regs %d\n", p, need));
+
+	return need;
+}
+
+#define	CLASS(x)	(x)->r_class
+#define	NCLASS(x,c)	(x)->r_nclass[c]
+#define	ADJLIST(x)	(x)->r_adjList
+#define	ALIAS(x)	(x)->r_alias
+#define	ONLIST(x)	(x)->r_onlist
+#define	MOVELIST(x)	(x)->r_moveList
+#define	COLOR(x)	(x)->r_color
+
+static bittype *live;
+
+#define	PUSHWLIST(w, l)	DLIST_INSERT_AFTER(&l, w, link); w->r_onlist = &l
+#define	POPWLIST(l)	popwlist(&l);
+#define	DELWLIST(w)	DLIST_REMOVE(w, link)
+#define WLISTEMPTY(h)	DLIST_ISEMPTY(&h,link)
+#define	PUSHMLIST(w, l, q)	DLIST_INSERT_AFTER(&l, w, link); w->queue = q
+#define	POPMLIST(l)	popmlist(&l);
+
+#define	trivially_colorable(x) \
+	trivially_colorable_p((x)->r_class, (x)->r_nclass)
+/*
+ * Determine if a node is trivially colorable ("degree < K").
+ * This implementation is a dumb one, without considering speed.
+ */
+static int
+trivially_colorable_p(int c, int *n)
+{
+	int r[NUMCLASS+1];
+	int i;
+
+	for (i = 1; i < NUMCLASS+1; i++)
+		r[i] = n[i] < regK[i] ? n[i] : regK[i];
+
+#if 0
+	/* add the exclusion nodes. */
+	/* XXX can we do someything smart here? */
+	/* worst-case for exclusion nodes are better than the `worst-case' */
+	for (; excl; excl >>= 1)
+		if (excl & 1)
+			r[c]++;
+#endif
+
+	i = COLORMAP(c, r);
+	if (i < 0 || i > 1)
+		comperr("trivially_colorable_p");
+#ifdef PCC_DEBUG
+	if (rdebug > 1)
+		printf("trivially_colorable_p: n[1] %d n[2] %d n[3] %d n[4] "
+		    "%d for class %d, triv %d\n", n[1], n[2], n[3], n[4], c, i);
+#endif
+	return i;
+}
+
+static int
+ncnt(int needs)
+{
+	int i = 0;
+
+	while (needs & NACOUNT)
+		needs -= NAREG, i++;
+	while (needs & NBCOUNT)
+		needs -= NBREG, i++;
+	while (needs & NCCOUNT)
+		needs -= NCREG, i++;
+	while (needs & NDCOUNT)
+		needs -= NDREG, i++;
+	while (needs & NECOUNT)
+		needs -= NEREG, i++;
+	while (needs & NFCOUNT)
+		needs -= NFREG, i++;
+	while (needs & NGCOUNT)
+		needs -= NGREG, i++;
+	return i;
+}
+
+static REGW *
+popwlist(REGW *l)
+{
+	REGW *w = DLIST_NEXT(l, link);
+
+	DLIST_REMOVE(w, link);
+	w->r_onlist = NULL;
+	return w;
+}
+
+/*
+ * Move lists, a move node is always on only one list.
+ */
+static REGM coalescedMoves, constrainedMoves, frozenMoves, 
+	worklistMoves, activeMoves;
+enum { COAL, CONSTR, FROZEN, WLIST, ACTIVE };
+
+static REGM *
+popmlist(REGM *l)
+{
+	REGM *w = DLIST_NEXT(l, link);
+
+	DLIST_REMOVE(w, link);
+	return w;
+}
+
+/*
+ * About data structures used in liveness analysis:
+ *
+ * The temporaries generated in pass1 are numbered between tempmin and
+ * tempmax.  Temporaries generated in pass2 are numbered above tempmax,
+ * so they are sequentially numbered.
+ *
+ * Bitfields are used for liveness.  Bit arrays are allocated on the
+ * heap for the "live" variable and on the stack for the in, out, gen
+ * and killed variables. Therefore, for a temp number, the bit number must
+ * be biased with tempmin.
+ *
+ * There may be an idea to use a different data structure to store 
+ * pass2 allocated temporaries, because they are very sparse.
+ */
+
+#ifdef PCC_DEBUG
+static void
+LIVEADD(int x)
+{
+	RDEBUG(("Liveadd: %d\n", x));
+	if (x >= MAXREGS && (x < tempmin || x >= tempmax))
+		comperr("LIVEADD: out of range");
+	if (x < MAXREGS) {
+		BITSET(live, x);
+	} else
+		BITSET(live, (x-tempmin+MAXREGS));
+}
+
+static void
+LIVEDEL(int x)
+{
+	RDEBUG(("Livedel: %d\n", x));
+
+	if (x >= MAXREGS && (x < tempmin || x >= tempmax))
+		comperr("LIVEDEL: out of range");
+	if (x < MAXREGS) {
+		BITCLEAR(live, x);
+	} else
+		BITCLEAR(live, (x-tempmin+MAXREGS));
+}
+#else
+#define LIVEADD(x) \
+	(x >= MAXREGS ? BITSET(live, (x-tempmin+MAXREGS)) : BITSET(live, x))
+#define LIVEDEL(x) \
+	(x >= MAXREGS ? BITCLEAR(live, (x-tempmin+MAXREGS)) : BITCLEAR(live, x))
+#endif
+
+static struct lives {
+	DLIST_ENTRY(lives) link;
+	REGW *var;
+} lused, lunused;
+
+static void
+LIVEADDR(REGW *x)
+{
+	struct lives *l;
+
+#ifdef PCC_DEBUG
+	RDEBUG(("LIVEADDR: %d\n", x->nodnum));
+	DLIST_FOREACH(l, &lused, link)
+		if (l->var == x)
+			return;
+#if 0
+			comperr("LIVEADDR: multiple %d", ASGNUM(x));
+#endif
+#endif
+	if (!DLIST_ISEMPTY(&lunused, link)) {
+		l = DLIST_NEXT(&lunused, link);
+		DLIST_REMOVE(l, link);
+	} else
+		l = tmpalloc(sizeof(struct lives));
+
+	l->var = x;
+	DLIST_INSERT_AFTER(&lused, l, link);
+}
+
+static void
+LIVEDELR(REGW *x)
+{
+	struct lives *l;
+
+#ifdef PCC_DEBUG
+	RDEBUG(("LIVEDELR: %d\n", x->nodnum));
+#endif
+	DLIST_FOREACH(l, &lused, link) {
+		if (l->var != x)
+			continue;
+		DLIST_REMOVE(l, link);
+		DLIST_INSERT_AFTER(&lunused, l, link);
+		return;
+	}
+#if 0
+	comperr("LIVEDELR: %p not found", x);
+#endif
+}
+
+#define	MOVELISTADD(t, p) movelistadd(t, p)
+#define WORKLISTMOVEADD(s,d) worklistmoveadd(s,d)
+
+static void
+movelistadd(REGW *t, REGM *p)
+{
+	MOVL *w = tmpalloc(sizeof(MOVL));
+
+	w->regm = p;
+	w->next = t->r_moveList;
+	t->r_moveList = w;
+}
+
+static REGM *
+worklistmoveadd(REGW *src, REGW *dst)
+{
+	REGM *w = tmpalloc(sizeof(REGM));
+
+	DLIST_INSERT_AFTER(&worklistMoves, w, link);
+	w->src = src;
+	w->dst = dst;
+	w->queue = WLIST;
+	return w;
+}
+
+#define	HASHSZ	16384
+struct AdjSet {
+	struct AdjSet *next;
+	REGW *u, *v;
+} *edgehash[HASHSZ];
+
+/* Check if a node pair is adjacent */
+static int
+adjSet(REGW *u, REGW *v)
+{
+	struct AdjSet *w;
+	REGW *t;
+
+	if (ONLIST(u) == &precolored) {
+		ADJL *a = ADJLIST(v);
+		/*
+		 * Check if any of the registers that have edges against v
+		 * alias to u.
+		 */
+		for (; a; a = a->r_next) {
+			if (ONLIST(a->a_temp) != &precolored)
+				continue;
+			t = a->a_temp;
+			if (interferes(t - ablock, u - ablock))
+				return 1;
+		}
+	}
+#ifdef notdef
+	if (u > v)
+		t = v, v = u, u = t;
+	w = edgehash[((intptr_t)u+(intptr_t)v) & (HASHSZ-1)];
+#else
+	w = edgehash[(u->nodnum+v->nodnum)& (HASHSZ-1)];
+#endif
+	for (; w; w = w->next) {
+		if ((u == w->u && v == w->v) || (u == w->v && v == w->u))
+			return 1;
+	}
+	return 0;
+}
+
+/* Add a pair to adjset.  No check for dups */
+static void
+adjSetadd(REGW *u, REGW *v)
+{
+	struct AdjSet *w;
+	int x;
+
+#ifdef notdef
+	if (u > v)
+		t = v, v = u, u = t;
+	x = ((intptr_t)u+(intptr_t)v) & (HASHSZ-1);
+#else
+	x = (u->nodnum+v->nodnum)& (HASHSZ-1);
+#endif
+	w = tmpalloc(sizeof(struct AdjSet));
+	w->u = u, w->v = v;
+	w->next = edgehash[x];
+	edgehash[x] = w;
+}
+
+/*
+ * Add an interference edge between two nodes.
+ */
+static void
+AddEdge(REGW *u, REGW *v)
+{
+	ADJL *x;
+
+#ifdef PCC_DEBUG
+	RRDEBUG(("AddEdge: u %d v %d\n", ASGNUM(u), ASGNUM(v)));
+
+#if 0
+	if (ASGNUM(u) == 0)
+		comperr("AddEdge 0");
+#endif
+	if (CLASS(u) == 0 || CLASS(v) == 0)
+		comperr("AddEdge class == 0 (%d=%d, %d=%d)",
+		    CLASS(u), ASGNUM(u), CLASS(v), ASGNUM(v));
+#endif
+
+	if (u == v)
+		return;
+	if (adjSet(u, v))
+		return;
+
+	adjSetadd(u, v);
+
+#if 0
+	if (ONLIST(u) == &precolored || ONLIST(v) == &precolored)
+		comperr("precolored node in AddEdge");
+#endif
+
+	if (ONLIST(u) != &precolored) {
+		x = tmpalloc(sizeof(ADJL));
+		x->a_temp = v;
+		x->r_next = u->r_adjList;
+		u->r_adjList = x;
+		NCLASS(u, CLASS(v))++;
+	}
+
+	if (ONLIST(v) != &precolored) {
+		x = tmpalloc(sizeof(ADJL));
+		x->a_temp = u;
+		x->r_next = v->r_adjList;
+		v->r_adjList = x;
+		NCLASS(v, CLASS(u))++;
+	}
+
+#if 0
+	RDEBUG(("AddEdge: u %d(d %d) v %d(d %d)\n", u, DEGREE(u), v, DEGREE(v)));
+#endif
+}
+
+static int
+MoveRelated(REGW *n)
+{
+	MOVL *l;
+	REGM *w;
+
+	for (l = MOVELIST(n); l; l = l->next) {
+		w = l->regm;
+		if (w->queue == ACTIVE || w->queue == WLIST)
+			return 1;
+	}
+	return 0;
+}
+
+static void
+MkWorklist(void)
+{
+	REGW *w;
+
+	RDEBUGX(int s=0);
+	RDEBUGX(int f=0);
+	RDEBUGX(int d=0);
+
+	DLIST_INIT(&precolored, link);
+	DLIST_INIT(&simplifyWorklist, link);
+	DLIST_INIT(&freezeWorklist, link);
+	DLIST_INIT(&spillWorklist, link);
+	DLIST_INIT(&spilledNodes, link);
+	DLIST_INIT(&coalescedNodes, link);
+	DLIST_INIT(&coloredNodes, link);
+	DLIST_INIT(&selectStack, link);
+
+	/*
+	 * Remove all nodes from the initial list and put them on 
+	 * one of the worklists.
+	 */
+	while (!DLIST_ISEMPTY(&initial, link)) {
+		w = DLIST_NEXT(&initial, link);
+		DLIST_REMOVE(w, link);
+		if (!trivially_colorable(w)) {
+			PUSHWLIST(w, spillWorklist);
+			RDEBUGX(s++);
+		} else if (MoveRelated(w)) {
+			PUSHWLIST(w, freezeWorklist);
+			RDEBUGX(f++);
+		} else {
+			PUSHWLIST(w, simplifyWorklist);
+			RDEBUGX(d++);
+		}
+	}
+	RDEBUG(("MkWorklist: spill %d freeze %d simplify %d\n", s,f,d));
+}
+
+static void
+addalledges(REGW *e)
+{
+	int i, j, k;
+	struct lives *l;
+
+#ifdef PCC_DEBUG
+	RDEBUG(("addalledges for %d\n", e->nodnum));
+#endif
+
+	if (e->r_class == -1)
+		return; /* unused */
+
+	if (ONLIST(e) != &precolored) {
+		for (i = 0; ndontregs[i] >= 0; i++)
+			AddEdge(e, &ablock[ndontregs[i]]);
+	}
+
+	/* First add to long-lived temps and hard regs */
+	RDEBUG(("addalledges longlived "));
+	for (i = 0; i < xbits; i += NUMBITS) {
+		if ((k = live[i/NUMBITS])) {
+			while (k) {
+				j = ffs(k)-1;
+				if (i+j < MAXREGS)
+					AddEdge(&ablock[i+j], e);
+				else
+					AddEdge(&nblock[i+j+tempmin-MAXREGS],e);
+				RRDEBUG(("%d ", i+j+tempmin));
+				k &= ~(1 << j);
+			}
+		}
+#if NUMBITS > 32 /* XXX hack for LP64 */
+		k = (live[i/NUMBITS] >> 32);
+		while (k) {
+			j = ffs(k)-1;
+			if (i+j+32 < MAXREGS)
+				AddEdge(&ablock[i+j+32], e);
+			else
+				AddEdge(&nblock[i+j+tempmin-MAXREGS+32], e);
+			RRDEBUG(("%d ", i+j+tempmin+32));
+			k &= ~(1 << j);
+		}
+#endif
+	}
+	RDEBUG(("done\n"));
+	/* short-lived temps */
+	RDEBUG(("addalledges shortlived "));
+	DLIST_FOREACH(l, &lused, link) {
+#ifdef PCC_DEBUG
+		RRDEBUG(("%d ", ASGNUM(l->var)));
+#endif
+		AddEdge(l->var, e);
+	}
+	RDEBUG(("done\n"));
+}
+
+/*
+ * Add a move edge between def and use.
+ */
+static void
+moveadd(REGW *def, REGW *use)
+{
+	REGM *r;
+	MOVL *w;
+
+	if (def == use)
+		return; /* no move to itself XXX - ``shouldn't happen'' */
+#ifdef PCC_DEBUG
+	RDEBUG(("moveadd: def %d use %d\n", ASGNUM(def), ASGNUM(use)));
+#endif
+
+	/*
+	 * Check if we are already on move list.
+	 * XXX How can that happen ???
+	 */
+	for (w = MOVELIST(def); w; w = w->next) {
+		if ((w->regm->src == def && w->regm->dst == use) ||
+		    (w->regm->src == use && w->regm->dst == def))
+			return; /* already there XXX reverse? */
+	}
+
+	r = WORKLISTMOVEADD(use, def);
+	MOVELISTADD(def, r);
+	MOVELISTADD(use, r);
+}
+
+/*
+ * Traverse arguments backwards.
+ * XXX - can this be tricked in some other way?
+ */
+static void
+argswalk(NODE *p)
+{
+
+	if (p->n_op == CM) {
+		argswalk(p->n_left);
+		insnwalk(p->n_right);
+	} else
+		insnwalk(p);
+}
+
+/*
+ * Add to (or remove from) live set variables that must not
+ * be clobbered when traversing down on the other leg for 
+ * a BITYPE node.
+ */
+static void
+setlive(NODE *p, int set, REGW *rv)
+{
+	if (rv != NULL) {
+		if (rv->nodnum < MAXREGS &&
+		    TESTBIT(validregs, rv->nodnum) == 0)
+			return;
+		set ? LIVEADDR(rv) : LIVEDELR(rv);
+		return;
+	}
+
+	if (p->n_regw != NULL) {
+		if (p->n_regw->nodnum < MAXREGS &&
+		    TESTBIT(validregs, p->n_regw->nodnum) == 0)
+			return;
+		set ? LIVEADDR(p->n_regw) : LIVEDELR(p->n_regw);
+		return;
+	}
+
+	switch (optype(p->n_op)) {
+	case LTYPE:
+		if (p->n_op == TEMP || VALIDREG(p))
+			set ? LIVEADD(regno(p)) : LIVEDEL(regno(p));
+		break;
+	case BITYPE:
+		setlive(p->n_right, set, rv);
+		/* FALLTHROUGH */
+	case UTYPE:
+		setlive(p->n_left, set, rv);
+		break;
+	}
+}
+
+/*
+ * Add edges for temporary w against all temporaries that may be
+ * used simultaneously (like index registers).
+ */
+static void
+addedge_r(NODE *p, REGW *w)
+{
+	RRDEBUG(("addedge_r: node %p regw %p\n", p, w));
+
+	if (p->n_regw != NULL) {
+		if (p->n_regw->nodnum < MAXREGS &&
+		    TESTBIT(validregs, p->n_regw->nodnum) == 0)
+			return;
+		AddEdge(p->n_regw, w);
+		return;
+	}
+
+	if (optype(p->n_op) == BITYPE)
+		addedge_r(p->n_right, w);
+	if (optype(p->n_op) != LTYPE)
+		addedge_r(p->n_left, w);
+}
+
+/*
+ * add/del parameter from live set.
+ */
+static void
+setxarg(NODE *p)
+{
+	int i, ut = 0, in = 0;
+	REGW *rw;
+	int c, cw;
+
+	if (p->n_op == ICON && p->n_type == STRTY)
+		return;
+
+	RDEBUG(("setxarg %p %s\n", p, p->n_name));
+	cw = xasmcode(p->n_name);
+	if (XASMISINP(cw))
+		in = 1;
+	if (XASMISOUT(cw))
+		ut = 1;
+
+	c = XASMVAL(cw);
+
+#ifdef MYSETXARG
+	MYSETXARG;
+#endif
+
+	switch (c) {
+	case 'm':
+	case 'g':
+		/* must find all TEMPs/REGs and set them live */
+		if (p->n_left->n_op != REG && p->n_left->n_op != TEMP) {
+			insnwalk(p->n_left);
+			break;
+		}
+		/* FALLTHROUGH */
+	case 'r':
+		i = regno(p->n_left);
+		rw = p->n_left->n_op == REG ? ablock : nblock;
+		if (ut) {
+			LIVEDEL(i);
+		}
+		if (in) {
+			LIVEADD(i);
+		}
+		addalledges(&rw[i]);
+		break;
+
+	case 'i':
+	case 'n':
+		break;
+	default:
+		comperr("bad ixarg %s", p->n_name);
+	}
+#ifdef MYSETXARG
+	MYSETXARG;
+#endif
+}
+
+/*
+ * Do the in-tree part of liveness analysis. (the difficult part)
+ *
+ * Walk down the tree in reversed-evaluation order (backwards).
+ * The moves and edges inserted and evaluation order for
+ * instructions when code is emitted is described here, hence
+ * this code runs the same but backwards.
+ *
+ * 2-op reclaim LEFT: eval L, move to DEST, eval R.
+ *	moveadd L,DEST; addedge DEST,R
+ * 2-op reclaim LEFT DORIGHT: eval R, eval L, move to DEST.
+ *	moveadd L,DEST; addedge DEST,R; addedge L,R
+ * 2-op reclaim RIGHT; eval L, eval R, move to DEST.
+ *	moveadd R,DEST; addedge DEST,L; addedge L,R
+ * 2-op reclaim RIGHT DORIGHT: eval R, move to DEST, eval L.
+ *	moveadd R,DEST; addedge DEST,L
+ * 3-op: eval L, eval R
+ *	addedge L,R
+ * 3-op DORIGHT: eval R, eval L
+ *	addedge L,R
+ *
+ * Instructions with special needs are handled just like these variants,
+ * with the exception of extra added moves and edges.
+ * Moves to special regs are scheduled after the evaluation of both legs.
+ */
+
+static void
+insnwalk(NODE *p)
+{
+	int o = p->n_op;
+	struct optab *q = &table[TBLIDX(p->n_su)];
+	REGW *lr, *rr, *rv, *r, *rrv, *lrv;
+	NODE *lp, *rp;
+	int i, n;
+
+	RDEBUG(("insnwalk %p\n", p));
+
+	rv = p->n_regw;
+
+	rrv = lrv = NULL;
+	if (p->n_op == ASSIGN &&
+	    (p->n_left->n_op == TEMP || VALIDREG(p->n_left))) {
+		lr = p->n_left->n_op == TEMP ? nblock : ablock;
+		i = regno(p->n_left);
+		LIVEDEL(i);	/* remove assigned temp from live set */
+		addalledges(&lr[i]);
+	}
+
+	/* Add edges for the result of this node */
+	if (rv && (q->visit & INREGS || o == TEMP || VALIDREG(p)))	
+		addalledges(rv);
+
+	/* special handling of CALL operators */
+	if (callop(o)) {
+		if (rv)
+			moveadd(rv, &ablock[RETREG(p->n_type)]);
+		for (i = 0; tempregs[i] >= 0; i++)
+			addalledges(&ablock[tempregs[i]]);
+	}
+
+	/* for special return value registers add moves */
+	if ((q->needs & NSPECIAL) && (n = rspecial(q, NRES)) >= 0) {
+		rv = &ablock[n];
+		moveadd(p->n_regw, rv);
+	}
+
+	/* Check leaves for results in registers */
+	lr = optype(o) != LTYPE ? p->n_left->n_regw : NULL;
+	lp = optype(o) != LTYPE ? p->n_left : NULL;
+	rr = optype(o) == BITYPE ? p->n_right->n_regw : NULL;
+	rp = optype(o) == BITYPE ? p->n_right : NULL;
+
+	/* simple needs */
+	n = ncnt(q->needs);
+	for (i = 0; i < n; i++) {
+#if 1
+		static int ncl[] =
+		    { 0, NASL, NBSL, NCSL, NDSL, NESL, NFSL, NGSL };
+		static int ncr[] =
+		    { 0, NASR, NBSR, NCSR, NDSR, NESR, NFSR, NGSR };
+		int j;
+
+		/* edges are already added */
+		if ((r = &p->n_regw[1+i])->r_class == -1) {
+			r = p->n_regw;
+		} else {
+			AddEdge(r, p->n_regw);
+			addalledges(r);
+		}
+		if (optype(o) != LTYPE && (q->needs & ncl[CLASS(r)]) == 0)
+			addedge_r(p->n_left, r);
+		if (optype(o) == BITYPE && (q->needs & ncr[CLASS(r)]) == 0)
+			addedge_r(p->n_right, r);
+		for (j = i + 1; j < n; j++) {
+			if (p->n_regw[j+1].r_class == -1)
+				continue;
+			AddEdge(r, &p->n_regw[j+1]);
+		}
+#else
+		if ((r = &p->n_regw[1+i])->r_class == -1)
+			continue;
+		addalledges(r);
+		if (optype(o) != LTYPE && (q->needs & NASL) == 0)
+			addedge_r(p->n_left, r);
+		if (optype(o) == BITYPE && (q->needs & NASR) == 0)
+			addedge_r(p->n_right, r);
+#endif
+	}
+
+	/* special needs */
+	if (q->needs & NSPECIAL) {
+		struct rspecial *rc;
+		for (rc = nspecial(q); rc->op; rc++) {
+			switch (rc->op) {
+#define	ONLY(c,s) if (c) s(c, &ablock[rc->num])
+			case NLEFT:
+				addalledges(&ablock[rc->num]);
+				ONLY(lr, moveadd);
+				break;
+			case NOLEFT:
+				addedge_r(p->n_left, &ablock[rc->num]);
+				break;
+			case NRIGHT:
+				addalledges(&ablock[rc->num]);
+				ONLY(rr, moveadd);
+				break;
+			case NORIGHT:
+				addedge_r(p->n_right, &ablock[rc->num]);
+				break;
+			case NEVER:
+				addalledges(&ablock[rc->num]);
+				break;
+#undef ONLY
+			}
+		}
+	}
+
+	if (o == ASSIGN) {
+		/* avoid use of unhandled registers */
+		if (p->n_left->n_op == REG &&
+		    !TESTBIT(validregs, regno(p->n_left)))
+			lr = NULL;
+		if (p->n_right->n_op == REG &&
+		    !TESTBIT(validregs, regno(p->n_right)))
+			rr = NULL;
+		/* needs special treatment */
+		if (lr && rr)
+			moveadd(lr, rr);
+		if (lr && rv)
+			moveadd(lr, rv);
+		if (rr && rv)
+			moveadd(rr, rv);
+	} else if (callop(o)) {
+		int *c;
+
+		for (c = livecall(p); *c != -1; c++) {
+			addalledges(ablock + *c);
+			LIVEADD(*c);
+		}
+	} else if (q->rewrite & (RESC1|RESC2|RESC3)) {
+		if (lr && rr)
+			AddEdge(lr, rr);
+	} else if (q->rewrite & RLEFT) {
+		if (lr && rv)
+			moveadd(rv, lr), lrv = rv;
+		if (rv && rp)
+			addedge_r(rp, rv);
+	} else if (q->rewrite & RRIGHT) {
+		if (rr && rv)
+			moveadd(rv, rr), rrv = rv;
+		if (rv && lp)
+			addedge_r(lp, rv);
+	}
+
+	switch (optype(o)) {
+	case BITYPE:
+		if (p->n_op == ASSIGN &&
+		    (p->n_left->n_op == TEMP || p->n_left->n_op == REG)) {
+			/* only go down right node */
+			insnwalk(p->n_right);
+		} else if (callop(o)) {
+			insnwalk(p->n_left);
+			/* Do liveness analysis on arguments (backwards) */
+			argswalk(p->n_right);
+		} else if ((p->n_su & DORIGHT) == 0) {
+			setlive(p->n_left, 1, lrv);
+			insnwalk(p->n_right);
+			setlive(p->n_left, 0, lrv);
+			insnwalk(p->n_left);
+		} else {
+			setlive(p->n_right, 1, rrv);
+			insnwalk(p->n_left);
+			setlive(p->n_right, 0, rrv);
+			insnwalk(p->n_right);
+		}
+		break;
+
+	case UTYPE:
+		insnwalk(p->n_left);
+		break;
+
+	case LTYPE:
+		switch (o) {
+		case REG:
+			if (!TESTBIT(validregs, regno(p)))
+				break; /* never add moves */
+			/* FALLTHROUGH */
+		case TEMP:
+			i = regno(p);
+			rr = (o == TEMP ? &nblock[i] :  &ablock[i]);
+			if (rv != rr) {
+				addalledges(rr);
+				moveadd(rv, rr);
+			}
+			LIVEADD(i);
+			break;
+
+		case OREG: /* XXX - not yet */
+			break; 
+
+		default:
+			break;
+		}
+		break;
+	}
+}
+
+static bittype **gen, **killed, **in, **out;
+
+struct notspill {
+	SLIST_ENTRY(notspill) link;
+	int spnum;
+};
+SLIST_HEAD(, notspill) nothead;
+
+static int
+innotspill(int n)
+{
+	struct notspill *nsp;
+
+	SLIST_FOREACH(nsp, &nothead, link)
+		if (nsp->spnum == n)
+			return 1;
+	return 0;
+}
+
+static void
+addnotspill(int n)
+{
+	struct notspill *nsp;
+
+	if (innotspill(n))
+		return;
+	nsp = tmpalloc(sizeof(struct notspill));
+	nsp->spnum = n;
+	SLIST_INSERT_LAST(&nothead, nsp, link);
+}
+
+/*
+ * Found an extended assembler node, so growel out gen/killed nodes.
+ */
+static void
+xasmionize(NODE *p, void *arg)
+{
+	int bb = *(int *)arg;
+	int cw, b;
+
+	if (p->n_op == ICON && p->n_type == STRTY)
+		return; /* dummy end marker */
+
+	cw = xasmcode(p->n_name);
+	if (XASMVAL(cw) == 'n' /* || XASMVAL(cw) == 'm' */)
+		return; /* no flow analysis */
+	p = p->n_left;
+
+	if (XASMVAL(cw) == 'g' && p->n_op != TEMP && p->n_op != REG)
+		return; /* no flow analysis */
+
+	b = regno(p);
+	if (XASMVAL(cw) == 'r' && p->n_op == TEMP)
+		addnotspill(b);
+	if (XASMVAL(cw) == 'm') {
+		if (p->n_op == UMUL && p->n_left->n_op == TEMP) {
+			p = p->n_left;
+			b = regno(p);
+			addnotspill(b);
+		} else
+			return;
+	}
+#define	MKTOFF(r)	((r) - tempmin + MAXREGS)
+	if (XASMISOUT(cw)) {
+		if (p->n_op == TEMP) {
+			BITCLEAR(gen[bb], MKTOFF(b));
+			BITSET(killed[bb], MKTOFF(b));
+		} else if (p->n_op == REG) {
+			BITCLEAR(gen[bb], b);
+			BITSET(killed[bb], b);
+		} else
+			uerror("bad xasm node type %d", p->n_op);
+	}
+	if (XASMISINP(cw)) {
+		if (p->n_op == TEMP) {
+			BITSET(gen[bb], MKTOFF(b));
+		} else if (p->n_op == REG) {
+			BITSET(gen[bb], b);
+		} else if (optype(p->n_op) != LTYPE) {
+			if (XASMVAL(cw) == 'r')
+				uerror("couldn't find available register");
+			else
+				uerror("bad xasm node type2");
+		}
+	}
+}
+
+#ifndef XASMCONSTREGS
+#define	XASMCONSTREGS(x) (-1)
+#endif
+
+/*
+ * Check that given constraints are valid.
+ */
+static void
+xasmconstr(NODE *p, void *arg)
+{
+	int i;
+
+	if (p->n_op == ICON && p->n_type == STRTY)
+		return; /* no constraints */
+
+	if (strcmp(p->n_name, "cc") == 0 || strcmp(p->n_name, "memory") == 0)
+		return;
+
+	for (i = 0; i < MAXREGS; i++)
+		if (strcmp(rnames[i], p->n_name) == 0) {
+			addalledges(&ablock[i]);
+			return;
+		}
+	if ((i = XASMCONSTREGS(p->n_name)) < 0)
+		comperr("unsupported xasm constraint %s", p->n_name);
+	addalledges(&ablock[i]);
+}
+
+#define	RUP(x) (((x)+NUMBITS-1)/NUMBITS)
+#define	SETCOPY(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] = f[i]
+#define	SETSET(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] |= f[i]
+#define	SETCLEAR(t,f,i,n) for (i = 0; i < RUP(n); i++) t[i] &= ~f[i]
+#define	SETCMP(v,t,f,i,n) for (i = 0; i < RUP(n); i++) \
+	if (t[i] != f[i]) v = 1
+#define	SETEMPTY(t,sz)	memset(t, 0, BIT2BYTE(sz))
+
+static int
+deldead(NODE *p, bittype *lvar)
+{
+	NODE *q;
+	int ty, rv = 0;
+
+#define	BNO(p) (regno(p) - tempmin+MAXREGS)
+	if (p->n_op == TEMP)
+		BITSET(lvar, BNO(p));
+	if (asgop(p->n_op) && p->n_left->n_op == TEMP &&
+	    TESTBIT(lvar, BNO(p->n_left)) == 0) {
+		/*
+		 * Not live, must delete the right tree at least 
+		 * down to next statement with side effects.
+		 */
+		BDEBUG(("DCE deleting temp %d\n", regno(p->n_left)));
+		nfree(p->n_left);
+		q = p->n_right;
+		*p = *q;
+		nfree(q);
+		rv = 1;
+	}
+	ty = optype(p->n_op);
+	if (ty != LTYPE)
+		rv |= deldead(p->n_left, lvar);
+	if (ty == BITYPE)
+		rv |= deldead(p->n_right, lvar);
+	return rv;
+}
+
+/*
+ * Do dead code elimination.
+ */
+static int
+dce(struct p2env *p2e)
+{
+	extern struct interpass prepole;
+	struct basicblock *bb;
+	struct interpass *ip;
+	NODE *p;
+	bittype *lvar;
+	int i, bbnum, fix = 0;
+
+	BDEBUG(("Entering DCE\n"));
+	/*
+	 * Traverse over the basic blocks.
+	 * if an assignment is found that writes to a temporary
+	 * that is not live out, remove that assignment and its legs.
+	 */
+	DLIST_INIT(&prepole, qelem);
+	BITALLOC(lvar, tmpalloc, xbits);
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		bbnum = bb->bbnum;
+		BBDEBUG(("DCE bblock %d, start %p last %p\n",
+		    bbnum, bb->first, bb->last));
+		SETCOPY(lvar, out[bbnum], i, xbits);
+		for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) {
+			if (ip->type == IP_NODE && deldead(ip->ip_node, lvar)) {
+				if ((p = deluseless(ip->ip_node)) == NULL) {
+					struct interpass *previp;
+					struct basicblock *prevbb;
+
+					if (ip == bb->first && ip == bb->last) {
+						/* Remove basic block */
+						previp = DLIST_PREV(ip, qelem);
+						DLIST_REMOVE(ip, qelem);
+						prevbb = DLIST_PREV(bb, bbelem);
+						DLIST_REMOVE(bb, bbelem);
+						bb = prevbb;
+					} else if (ip == bb->first) {
+						bb->first =
+						    DLIST_NEXT(ip, qelem);
+						DLIST_REMOVE(ip, qelem);
+					} else if (ip == bb->last) {
+						previp = DLIST_PREV(ip, qelem);
+						DLIST_REMOVE(ip, qelem);
+						bb->last = previp;
+						bb = DLIST_PREV(bb, bbelem);
+					} else {
+						previp = DLIST_NEXT(ip, qelem);
+						DLIST_REMOVE(ip, qelem);
+						ip = previp;
+						fix++;
+						continue;
+					}
+					fix++;
+					BDEBUG(("bb %d: DCE ip %p deleted\n",
+					    bbnum, ip));
+					break;
+				} else while (!DLIST_ISEMPTY(&prepole, qelem)) {
+
+					BDEBUG(("bb %d: DCE doing ip prepend\n", bbnum));
+#ifdef notyet
+					struct interpass *tipp;
+					tipp = DLIST_NEXT(&prepole, qelem);
+					DLIST_REMOVE(tipp, qelem);
+					DLIST_INSERT_BEFORE(ip, tipp, qelem);
+					if (ip == bb->first)
+						bb->first = tipp;
+					fix++;
+#else
+					comperr("dce needs bb fixup");
+#endif
+					BDEBUG(("DCE ip prepended\n"));
+				}
+				if (ip->type == IP_NODE) {
+					geninsn(p, FOREFF);
+					nsucomp(p);
+					ip->ip_node = p;
+				}
+			}
+			if (ip == bb->first)
+				break;
+		}
+	}
+	BDEBUG(("DCE fix %d\n", fix));
+	return fix;
+}
+
+/*
+ * Set/clear long term liveness for regs and temps.
+ */
+static void
+unionize(NODE *p, int bb)
+{
+	int i, o, ty;
+
+	if ((o = p->n_op) == TEMP) {
+#ifdef notyet
+		for (i = 0; i < szty(p->n_type); i++) {
+			BITSET(gen[bb], (regno(p) - tempmin+i+MAXREGS));
+		}
+#else
+		i = 0;
+		BITSET(gen[bb], (regno(p) - tempmin+i+MAXREGS));
+#endif
+	} else if (VALIDREG(p)) {
+		BITSET(gen[bb], regno(p));
+	}
+	if (asgop(o)) {
+		if (p->n_left->n_op == TEMP) {
+			int b = regno(p->n_left) - tempmin+MAXREGS;
+#ifdef notyet
+			for (i = 0; i < szty(p->n_type); i++) {
+				BITCLEAR(gen[bb], (b+i));
+				BITSET(killed[bb], (b+i));
+			}
+#else
+			i = 0;
+			BITCLEAR(gen[bb], (b+i));
+			BITSET(killed[bb], (b+i));
+#endif
+			unionize(p->n_right, bb);
+			return;
+		} else if (VALIDREG(p->n_left)) {
+			int b = regno(p->n_left);
+			BITCLEAR(gen[bb], b);
+			BITSET(killed[bb], b);
+			unionize(p->n_right, bb);
+			return;
+		}
+	}
+	ty = optype(o);
+	if (ty != LTYPE)
+		unionize(p->n_left, bb);
+	if (ty == BITYPE)
+		unionize(p->n_right, bb);
+}
+
+/*
+ * Do variable liveness analysis.  Only analyze the long-lived 
+ * variables, and save the live-on-exit temporaries in a bit-field
+ * at the end of each basic block. This bit-field is later used
+ * when doing short-range liveness analysis in Build().
+ */
+static void
+LivenessAnalysis(struct p2env *p2e)
+{
+	struct basicblock *bb;
+	struct interpass *ip;
+	int i, bbnum;
+
+	/*
+	 * generate the gen-killed sets for all basic blocks.
+	 */
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		bbnum = bb->bbnum;
+		for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) {
+			/* gen/killed is 'p', this node is 'n' */
+			if (ip->type == IP_NODE) {
+				if (ip->ip_node->n_op == XASM)
+					flist(ip->ip_node->n_left,
+					    xasmionize, &bbnum);
+				else
+					unionize(ip->ip_node, bbnum);
+			}
+			if (ip == bb->first)
+				break;
+		}
+		memcpy(in[bbnum], gen[bbnum], BIT2BYTE(xbits));
+#ifdef PCC_DEBUG
+#define	PRTRG(x) printf("%d ", i < MAXREGS ? i : i + tempmin-MAXREGS)
+		if (rdebug) {
+			printf("basic block %d\ngen: ", bbnum);
+			for (i = 0; i < xbits; i++)
+				if (TESTBIT(gen[bbnum], i))
+					PRTRG(i);
+			printf("\nkilled: ");
+			for (i = 0; i < xbits; i++)
+				if (TESTBIT(killed[bbnum], i))
+					PRTRG(i);
+			printf("\n");
+		}
+#endif
+	}
+}
+
+/*
+ * Build the set of interference edges and adjacency list.
+ */
+static void
+Build(struct p2env *p2e)
+{
+	struct interpass *ipole = &p2e->ipole;
+	struct basicblock bbfake;
+	struct interpass *ip;
+	struct basicblock *bb;
+	bittype *saved;
+	int i, j, again;
+
+	if (xtemps == 0) {
+		/*
+		 * No basic block splitup is done if not optimizing,
+		 * so fake one basic block to keep the liveness analysis 
+		 * happy.
+		 */
+		p2e->nbblocks = 1;
+		bbfake.bbnum = 0;
+		bbfake.last = DLIST_PREV(ipole, qelem);
+		bbfake.first = DLIST_NEXT(ipole, qelem);
+		DLIST_INIT(&p2e->bblocks, bbelem);
+		DLIST_INSERT_AFTER(&p2e->bblocks, &bbfake, bbelem);
+		bbfake.ch[0] = bbfake.ch[1] = NULL;
+	}
+
+	/* Just fetch space for the temporaries from stack */
+	gen = tmpalloc(p2e->nbblocks*sizeof(bittype*));
+	killed = tmpalloc(p2e->nbblocks*sizeof(bittype*));
+	in = tmpalloc(p2e->nbblocks*sizeof(bittype*));
+	out = tmpalloc(p2e->nbblocks*sizeof(bittype*));
+	for (i = 0; i < p2e->nbblocks; i++) {
+		BITALLOC(gen[i],tmpalloc,xbits);
+		BITALLOC(killed[i],tmpalloc,xbits);
+		BITALLOC(in[i],tmpalloc,xbits);
+		BITALLOC(out[i],tmpalloc,xbits);
+	}
+	BITALLOC(saved,tmpalloc,xbits);
+
+	SLIST_INIT(&nothead);
+livagain:
+	LivenessAnalysis(p2e);
+
+	/* register variable temporaries are live */
+	for (i = 0; i < NPERMREG-1; i++) {
+		if (nsavregs[i])
+			continue;
+		BITSET(out[p2e->nbblocks-1], (i+MAXREGS));
+		for (j = i+1; j < NPERMREG-1; j++) {
+			if (nsavregs[j])
+				continue;
+			AddEdge(&nblock[i+tempmin], &nblock[j+tempmin]);
+		}
+	}
+
+	/* do liveness analysis on basic block level */
+	do {
+		again = 0;
+		/* XXX - loop should be in reversed execution-order */
+		DLIST_FOREACH_REVERSE(bb, &p2e->bblocks, bbelem) {
+			i = bb->bbnum;
+			SETCOPY(saved, out[i], j, xbits);
+			if (bb->ch[0])
+				SETSET(out[i], in[bb->ch[0]->bblock->bbnum], j, xbits);
+			if (bb->ch[1])
+				SETSET(out[i], in[bb->ch[1]->bblock->bbnum], j, xbits);
+			SETCMP(again, saved, out[i], j, xbits);
+			SETCOPY(saved, in[i], j, xbits);
+			SETCOPY(in[i], out[i], j, xbits);
+			SETCLEAR(in[i], killed[i], j, xbits);
+			SETSET(in[i], gen[i], j, xbits);
+			SETCMP(again, saved, in[i], j, xbits);
+		}
+	} while (again);
+
+#ifdef PCC_DEBUG
+	if (rdebug) {
+		DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+			printf("basic block %d\nin: ", bb->bbnum);
+			for (i = 0; i < xbits; i++)
+				if (TESTBIT(in[bb->bbnum], i))
+					PRTRG(i);
+			printf("\nout: ");
+			for (i = 0; i < xbits; i++)
+				if (TESTBIT(out[bb->bbnum], i))
+					PRTRG(i);
+			printf("\n");
+		}
+	}
+#endif
+	if (xtemps && xdce) {
+		/*
+		 * Do dead code elimination by using live out.
+		 * Ignores if any variable read from is marked volatile,
+		 * but what it should do is unspecified anyway.
+		 * Liveness Analysis should be done in optim2 instead.
+		 *
+		 * This should recalculate the basic block structure.
+		 */
+		if (dce(p2e)) {
+			/* Clear bitfields */
+			for (i = 0; i < p2e->nbblocks; i++) {
+				SETEMPTY(gen[i],xbits);
+				SETEMPTY(killed[i],xbits);
+				SETEMPTY(in[i],xbits);
+				SETEMPTY(out[i],xbits);
+			}
+			SETEMPTY(saved,xbits);
+			goto livagain;
+		}
+	}
+
+	DLIST_FOREACH(bb, &p2e->bblocks, bbelem) {
+		RDEBUG(("liveadd bb %d\n", bb->bbnum));
+		i = bb->bbnum;
+		for (j = 0; j < xbits; j += NUMBITS)
+			live[j/NUMBITS] = 0;
+		SETCOPY(live, out[i], j, xbits);
+		for (ip = bb->last; ; ip = DLIST_PREV(ip, qelem)) {
+			if (ip->type == IP_NODE) {
+				if (ip->ip_node->n_op == XASM) {
+					flist(ip->ip_node->n_right,
+					    xasmconstr, 0);
+					listf(ip->ip_node->n_left, setxarg);
+				} else
+					insnwalk(ip->ip_node);
+			}
+			if (ip == bb->first)
+				break;
+		}
+	}
+
+#ifdef PCC_DEBUG
+	if (rdebug) {
+		struct AdjSet *w;
+		ADJL *x;
+		REGW *y;
+		MOVL *m;
+
+		printf("Interference edges\n");
+		for (i = 0; i < HASHSZ; i++) {
+			if ((w = edgehash[i]) == NULL)
+				continue;
+			for (; w; w = w->next)
+				printf("%d <-> %d\n", ASGNUM(w->u), ASGNUM(w->v));
+		}
+		printf("Degrees\n");
+		DLIST_FOREACH(y, &initial, link) {
+			printf("%d (%c): trivial [%d] ", ASGNUM(y),
+			    CLASS(y)+'@', trivially_colorable(y));
+			i = 0;
+			for (x = ADJLIST(y); x; x = x->r_next) {
+				if (ONLIST(x->a_temp) != &selectStack &&
+				    ONLIST(x->a_temp) != &coalescedNodes)
+					printf("%d ", ASGNUM(x->a_temp));
+				else
+					printf("(%d) ", ASGNUM(x->a_temp));
+				i++;
+			}
+			printf(": n=%d\n", i);
+		}
+		printf("Move nodes\n");
+		DLIST_FOREACH(y, &initial, link) {
+			if (MOVELIST(y) == NULL)
+				continue;
+			printf("%d: ", ASGNUM(y));
+			for (m = MOVELIST(y); m; m = m->next) {
+				REGW *yy = m->regm->src == y ?
+				    m->regm->dst : m->regm->src;
+				printf("%d ", ASGNUM(yy));
+			}
+			printf("\n");
+		}
+	}
+#endif
+
+}
+
+static void
+EnableMoves(REGW *n)
+{
+	MOVL *l;
+	REGM *m;
+
+	for (l = MOVELIST(n); l; l = l->next) {
+		m = l->regm;
+		if (m->queue != ACTIVE)
+			continue;
+		DLIST_REMOVE(m, link);
+		PUSHMLIST(m, worklistMoves, WLIST);
+	}
+}
+
+static void
+EnableAdjMoves(REGW *nodes)
+{
+	ADJL *w;
+	REGW *n;
+
+	EnableMoves(nodes);
+	for (w = ADJLIST(nodes); w; w = w->r_next) {
+		n = w->a_temp;
+		if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes)
+			continue;
+		EnableMoves(w->a_temp);
+	}
+}
+
+/*
+ * Decrement the degree of node w for class c.
+ */
+static void
+DecrementDegree(REGW *w, int c)
+{
+	int wast;
+
+#ifdef PCC_DEBUG
+	RRDEBUG(("DecrementDegree: w %d, c %d\n", ASGNUM(w), c));
+#endif
+
+	wast = trivially_colorable(w);
+	NCLASS(w, c)--;
+	if (wast == trivially_colorable(w))
+		return;
+
+	EnableAdjMoves(w);
+	DELWLIST(w);
+	ONLIST(w) = 0;
+	if (MoveRelated(w)) {
+		PUSHWLIST(w, freezeWorklist);
+	} else {
+		PUSHWLIST(w, simplifyWorklist);
+	}
+}
+
+static void
+Simplify(void)
+{
+	REGW *w;
+	ADJL *l;
+
+	w = POPWLIST(simplifyWorklist);
+	PUSHWLIST(w, selectStack);
+#ifdef PCC_DEBUG
+	RDEBUG(("Simplify: node %d class %d\n", ASGNUM(w), w->r_class));
+#endif
+
+	l = w->r_adjList;
+	for (; l; l = l->r_next) {
+		if (ONLIST(l->a_temp) == &selectStack ||
+		    ONLIST(l->a_temp) == &coalescedNodes)
+			continue;
+		DecrementDegree(l->a_temp, w->r_class);
+	}
+}
+
+static REGW *
+GetAlias(REGW *n)
+{
+	if (ONLIST(n) == &coalescedNodes)
+		return GetAlias(ALIAS(n));
+	return n;
+}
+
+static int
+OK(REGW *t, REGW *r)
+{
+#ifdef PCC_DEBUG
+	RDEBUG(("OK: t %d CLASS(t) %d adjSet(%d,%d)=%d\n",
+	    ASGNUM(t), CLASS(t), ASGNUM(t), ASGNUM(r), adjSet(t, r)));
+
+	if (rdebug > 1) {
+		ADJL *w;
+		int ndeg = 0;
+		printf("OK degree: ");
+		for (w = ADJLIST(t); w; w = w->r_next) {
+			if (ONLIST(w->a_temp) != &selectStack &&
+			    ONLIST(w->a_temp) != &coalescedNodes)
+				printf("%c%d ", CLASS(w->a_temp)+'@',
+				    ASGNUM(w->a_temp)), ndeg++;
+			else
+				printf("(%d) ", ASGNUM(w->a_temp));
+		}
+		printf("\n");
+#if 0
+		if (ndeg != DEGREE(t) && DEGREE(t) >= 0)
+			printf("!!!ndeg %d != DEGREE(t) %d\n", ndeg, DEGREE(t));
+#endif
+	}
+#endif
+
+	if (trivially_colorable(t) || ONLIST(t) == &precolored || 
+	    (adjSet(t, r) || !aliasmap(CLASS(t), COLOR(r))))/* XXX - check aliasmap */
+		return 1;
+	return 0;
+}
+
+static int
+adjok(REGW *v, REGW *u)
+{
+	ADJL *w;
+	REGW *t;
+
+	RDEBUG(("adjok\n"));
+	for (w = ADJLIST(v); w; w = w->r_next) {
+		t = w->a_temp;
+		if (ONLIST(t) == &selectStack || ONLIST(t) == &coalescedNodes)
+			continue;
+		if (OK(t, u) == 0)
+			return 0;
+	}
+	RDEBUG(("adjok returns OK\n"));
+	return 1;
+}
+
+/*
+ * Do a conservative estimation of whether two temporaries can 
+ * be coalesced.  This is "Briggs-style" check.
+ * Neither u nor v is precolored when called.
+ */
+static int
+Conservative(REGW *u, REGW *v)
+{
+	ADJL *w, *ww;
+	REGW *n;
+	int xncl[NUMCLASS+1], mcl = 0, j;
+
+	for (j = 0; j < NUMCLASS+1; j++)
+		xncl[j] = 0;
+	/*
+	 * Increment xncl[class] up to K for each class.
+	 * If all classes has reached K then check colorability and return.
+	 */
+	for (w = ADJLIST(u); w; w = w->r_next) {
+		n = w->a_temp;
+		if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes)
+			continue;
+		if (xncl[CLASS(n)] == regK[CLASS(n)])
+			continue;
+		if (!trivially_colorable(n) || ONLIST(n) == &precolored)
+			xncl[CLASS(n)]++;
+		if (xncl[CLASS(n)] < regK[CLASS(n)])
+			continue;
+		if (++mcl == NUMCLASS)
+			goto out; /* cannot get more out of it */
+	}
+	for (w = ADJLIST(v); w; w = w->r_next) {
+		n = w->a_temp;
+		if (ONLIST(n) == &selectStack || ONLIST(n) == &coalescedNodes)
+			continue;
+		if (xncl[CLASS(n)] == regK[CLASS(n)])
+			continue;
+		/* ugly: have we been here already? */
+		for (ww = ADJLIST(u); ww; ww = ww->r_next)
+			if (ww->a_temp == n)
+				break;
+		if (ww)
+			continue;
+		if (!trivially_colorable(n) || ONLIST(n) == &precolored)
+			xncl[CLASS(n)]++;
+		if (xncl[CLASS(n)] < regK[CLASS(n)])
+			continue;
+		if (++mcl == NUMCLASS)
+			break;
+	}
+out:	j = trivially_colorable_p(CLASS(u), xncl);
+	return j;
+}
+
+static void
+AddWorkList(REGW *w)
+{
+
+	if (ONLIST(w) != &precolored && !MoveRelated(w) &&
+	    trivially_colorable(w)) {
+		DELWLIST(w);
+		PUSHWLIST(w, simplifyWorklist);
+	}
+}
+
+static void
+Combine(REGW *u, REGW *v)
+{
+	MOVL *m;
+	ADJL *l;
+	REGW *t;
+
+#ifdef PCC_DEBUG
+	RDEBUG(("Combine (%d,%d)\n", ASGNUM(u), ASGNUM(v)));
+#endif
+
+	if (ONLIST(v) == &freezeWorklist) {
+		DELWLIST(v);
+	} else {
+		DELWLIST(v);
+	}
+	PUSHWLIST(v, coalescedNodes);
+	ALIAS(v) = u;
+#ifdef PCC_DEBUG
+	if (rdebug) { 
+		printf("adjlist(%d): ", ASGNUM(v));
+		for (l = ADJLIST(v); l; l = l->r_next)
+			printf("%d ", l->a_temp->nodnum);
+		printf("\n");
+	}
+#endif
+#if 1
+{
+	MOVL *m0 = MOVELIST(v);
+
+	for (m0 = MOVELIST(v); m0; m0 = m0->next) {
+		for (m = MOVELIST(u); m; m = m->next)
+			if (m->regm == m0->regm)
+				break; /* Already on list */
+		if (m)
+			continue; /* already on list */
+		MOVELISTADD(u, m0->regm);
+	}
+}
+#else
+
+	if ((m = MOVELIST(u))) {
+		while (m->next)
+			m = m->next;
+		m->next = MOVELIST(v);
+	} else
+		MOVELIST(u) = MOVELIST(v);
+#endif
+	EnableMoves(v);
+	for (l = ADJLIST(v); l; l = l->r_next) {
+		t = l->a_temp;
+		if (ONLIST(t) == &selectStack || ONLIST(t) == &coalescedNodes)
+			continue;
+		/* Do not add edge if u cannot affect the colorability of t */
+		/* XXX - check aliasmap */
+		if (ONLIST(u) != &precolored || aliasmap(CLASS(t), COLOR(u)))
+			AddEdge(t, u);
+		DecrementDegree(t, CLASS(v));
+	}
+	if (!trivially_colorable(u) && ONLIST(u) == &freezeWorklist) {
+		DELWLIST(u);
+		PUSHWLIST(u, spillWorklist);
+	}
+#ifdef PCC_DEBUG
+if (rdebug) {
+	ADJL *w;
+	printf("Combine %d class (%d): ", ASGNUM(u), CLASS(u));
+	for (w = ADJLIST(u); w; w = w->r_next) {
+		if (ONLIST(w->a_temp) != &selectStack &&
+		    ONLIST(w->a_temp) != &coalescedNodes)
+			printf("%d ", ASGNUM(w->a_temp));
+		else
+			printf("(%d) ", ASGNUM(w->a_temp));
+	}
+	printf("\n");
+}
+#endif
+}
+
+static void
+Coalesce(void)
+{
+	REGM *m;
+	REGW *x, *y, *u, *v;
+
+	m = POPMLIST(worklistMoves);
+	x = GetAlias(m->src);
+	y = GetAlias(m->dst);
+
+	if (ONLIST(y) == &precolored)
+		u = y, v = x;
+	else
+		u = x, v = y;
+
+#ifdef PCC_DEBUG
+	RDEBUG(("Coalesce: src %d dst %d u %d v %d x %d y %d\n",
+	    ASGNUM(m->src), ASGNUM(m->dst), ASGNUM(u), ASGNUM(v),
+	    ASGNUM(x), ASGNUM(y)));
+#endif
+
+	if (CLASS(m->src) != CLASS(m->dst))
+		comperr("Coalesce: src class %d, dst class %d",
+		    CLASS(m->src), CLASS(m->dst));
+
+	if (u == v) {
+		RDEBUG(("Coalesce: u == v\n"));
+		PUSHMLIST(m, coalescedMoves, COAL);
+		AddWorkList(u);
+	} else if (ONLIST(v) == &precolored || adjSet(u, v)) {
+		RDEBUG(("Coalesce: constrainedMoves\n"));
+		PUSHMLIST(m, constrainedMoves, CONSTR);
+		AddWorkList(u);
+		AddWorkList(v);
+	} else if ((ONLIST(u) == &precolored && adjok(v, u)) ||
+	    (ONLIST(u) != &precolored && Conservative(u, v))) {
+		RDEBUG(("Coalesce: Conservative\n"));
+		PUSHMLIST(m, coalescedMoves, COAL);
+		Combine(u, v);
+		AddWorkList(u);
+	} else {
+		RDEBUG(("Coalesce: activeMoves\n"));
+		PUSHMLIST(m, activeMoves, ACTIVE);
+	}
+}
+
+static void
+FreezeMoves(REGW *u)
+{
+	MOVL *w, *o;
+	REGM *m;
+	REGW *z;
+	REGW *x, *y, *v;
+
+	for (w = MOVELIST(u); w; w = w->next) {
+		m = w->regm;
+		if (m->queue != WLIST && m->queue != ACTIVE)
+			continue;
+		x = m->src;
+		y = m->dst;
+		if (GetAlias(y) == GetAlias(u))
+			v = GetAlias(x);
+		else
+			v = GetAlias(y);
+#ifdef PCC_DEBUG
+		RDEBUG(("FreezeMoves: u %d (%d,%d) v %d\n",
+		    ASGNUM(u),ASGNUM(x),ASGNUM(y),ASGNUM(v)));
+#endif
+		DLIST_REMOVE(m, link);
+		PUSHMLIST(m, frozenMoves, FROZEN);
+		if (ONLIST(v) != &freezeWorklist)
+			continue;
+		for (o = MOVELIST(v); o; o = o->next)
+			if (o->regm->queue == WLIST || o->regm->queue == ACTIVE)
+				break;
+		if (o == NULL) {
+			z = v;
+			DELWLIST(z);
+			PUSHWLIST(z, simplifyWorklist);
+		}
+	}
+}
+
+static void
+Freeze(void)
+{
+	REGW *u;
+
+	/*
+	 * To find out:
+	 * Check if the moves to freeze have exactly the same 
+	 * interference edges.  If they do, coalesce them instead, it
+	 * may free up other nodes that they interfere with.
+	 */
+
+	/*
+	 * Select nodes to freeze first by using following criteria:
+	 * - Trivially colorable
+	 * - Single or few moves to less trivial nodes.
+	 */
+	DLIST_FOREACH(u, &freezeWorklist, link) {
+		if (u >= &nblock[tempmax] || u < &nblock[tempmin])
+			continue; /* No short range temps */
+		if (!trivially_colorable(u))
+			continue; /* Prefer colorable nodes */
+		/* Check for at most two move-related nodes */
+		if (u->r_moveList->next && u->r_moveList->next->next)
+			continue;
+		/* Ok, remove node */
+		DLIST_REMOVE(u, link);
+		u->r_onlist = 0;
+		break;
+	}
+	if (u == &freezeWorklist) /* Nothing matched criteria, just take one */
+		u = POPWLIST(freezeWorklist);
+	PUSHWLIST(u, simplifyWorklist);
+#ifdef PCC_DEBUG
+	RDEBUG(("Freeze %d\n", ASGNUM(u)));
+#endif
+	FreezeMoves(u);
+}
+
+static void
+SelectSpill(void)
+{
+	REGW *w;
+
+	RDEBUG(("SelectSpill\n"));
+#ifdef PCC_DEBUG
+	if (rdebug)
+		DLIST_FOREACH(w, &spillWorklist, link)
+			printf("SelectSpill: %d\n", ASGNUM(w));
+#endif
+
+	/* First check if we can spill register variables */
+	DLIST_FOREACH(w, &spillWorklist, link) {
+		if (w >= &nblock[tempmin] && w < &nblock[basetemp])
+			break;
+	}
+
+	if (w == &spillWorklist) {
+		/* try to find another long-range variable */
+		DLIST_FOREACH(w, &spillWorklist, link) {
+			if (innotspill(w - nblock))
+				continue;
+			if (w >= &nblock[tempmin] && w < &nblock[tempmax])
+				break;
+		}
+	}
+
+	if (w == &spillWorklist) {
+		/* no heuristics, just fetch first element */
+		/* but not if leaf */
+		DLIST_FOREACH(w, &spillWorklist, link) {
+			if (w->r_nclass[0] == 0)
+				break;
+		}
+	}
+
+	if (w == &spillWorklist) {
+		/* Eh, only leaves :-/ Try anyway */
+		/* May not be useable */
+		w = DLIST_NEXT(&spillWorklist, link);
+	}
+ 
+        DLIST_REMOVE(w, link);
+
+	PUSHWLIST(w, simplifyWorklist);
+#ifdef PCC_DEBUG
+	RDEBUG(("Freezing node %d\n", ASGNUM(w)));
+#endif
+	FreezeMoves(w);
+}
+
+/*
+ * Set class on long-lived temporaries based on its type.
+ */
+static void
+traclass(NODE *p, void *arg)
+{
+	REGW *nb;
+
+	if (p->n_op != TEMP)
+		return;
+
+	nb = &nblock[regno(p)];
+	if (CLASS(nb) == 0)
+		CLASS(nb) = gclass(p->n_type);
+}
+
+static void
+paint(NODE *p, void *arg)
+{
+	struct optab *q;
+	REGW *w, *ww;
+	int i;
+
+#ifdef notyet
+	/* XXX - trashes rewrite of trees (short) */
+	if (!DLIST_ISEMPTY(&spilledNodes, link)) {
+		p->n_reg = 0;
+		return;
+	}
+#endif
+	if (p->n_regw != NULL) {
+		/* Must color all allocated regs also */
+		ww = w = p->n_regw;
+		q = &table[TBLIDX(p->n_su)];
+		p->n_reg = COLOR(w);
+		w++;
+		if (q->needs & ALLNEEDS)
+			for (i = 0; i < ncnt(q->needs); i++) {
+				if (w->r_class == -1)
+					p->n_reg |= ENCRA(COLOR(ww), i);
+				else
+					p->n_reg |= ENCRA(COLOR(w), i);
+				w++;
+			}
+	} else
+		p->n_reg = -1;
+	if (p->n_op == TEMP) {
+		REGW *nb = &nblock[regno(p)];
+		regno(p) = COLOR(nb);
+		if (TCLASS(p->n_su) == 0)
+			SCLASS(p->n_su, CLASS(nb));
+		p->n_op = REG;
+		p->n_lval = 0;
+	}
+}
+
+/*
+ * See if this node have a move that has been removed in Freeze
+ * but as we can make use of anyway.
+ */
+static int
+colfind(int okColors, REGW *r)
+{
+	REGW *w;
+	MOVL *m;
+	int c;
+
+	for (m = MOVELIST(r); m; m = m->next) {
+		if ((w = m->regm->src) == r)
+			w = m->regm->dst;
+		w = GetAlias(w);
+		if (ONLIST(w) != &coloredNodes && ONLIST(w) != &precolored)
+			continue; /* Not yet colored */
+		c = aliasmap(CLASS(w), COLOR(w));
+		if ((c & okColors) == 0) {
+			RDEBUG(("colfind: Failed coloring from %d\n", ASGNUM(w)));
+			continue;
+		}
+		okColors &= c;
+		RDEBUG(("colfind: Recommend color from %d\n", ASGNUM(w)));
+		break;
+		
+	}
+	return ffs(okColors)-1;
+}
+
+static void
+AssignColors(struct interpass *ip)
+{
+	struct interpass *ip2;
+	int okColors, c;
+	REGW *o, *w;
+	ADJL *x;
+
+	RDEBUG(("AssignColors\n"));
+	while (!WLISTEMPTY(selectStack)) {
+		w = POPWLIST(selectStack);
+		okColors = classmask(CLASS(w));
+#ifdef PCC_DEBUG
+		RDEBUG(("classmask av %d, class %d: %x\n",
+		    w->nodnum, CLASS(w), okColors));
+#endif
+
+		for (x = ADJLIST(w); x; x = x->r_next) {
+			o = GetAlias(x->a_temp);
+#ifdef PCC_DEBUG
+			RRDEBUG(("Adj(%d): %d (%d)\n",
+			    ASGNUM(w), ASGNUM(o), ASGNUM(x->a_temp)));
+#endif
+
+			if (ONLIST(o) == &coloredNodes ||
+			    ONLIST(o) == &precolored) {
+				c = aliasmap(CLASS(w), COLOR(o));
+				RRDEBUG(("aliasmap in class %d by color %d: "
+				    "%x, okColors %x\n",
+				    CLASS(w), COLOR(o), c, okColors));
+
+				okColors &= ~c;
+			}
+		}
+		if (okColors == 0) {
+			PUSHWLIST(w, spilledNodes);
+#ifdef PCC_DEBUG
+			RDEBUG(("Spilling node %d\n", ASGNUM(w)));
+#endif
+		} else {
+			c = colfind(okColors, w);
+			COLOR(w) = color2reg(c, CLASS(w));
+			PUSHWLIST(w, coloredNodes);
+#ifdef PCC_DEBUG
+			RDEBUG(("Coloring %d with %s, free %x\n",
+			    ASGNUM(w), rnames[COLOR(w)], okColors));
+#endif
+		}
+	}
+	DLIST_FOREACH(w, &coalescedNodes, link) {
+		REGW *ww = GetAlias(w);
+		COLOR(w) = COLOR(ww);
+		if (ONLIST(ww) == &spilledNodes) {
+#ifdef PCC_DEBUG
+			RDEBUG(("coalesced node %d spilled\n", w->nodnum));
+#endif
+			ww = DLIST_PREV(w, link);
+			DLIST_REMOVE(w, link);
+			PUSHWLIST(w, spilledNodes);
+			w = ww;
+		} else {
+#ifdef PCC_DEBUG
+			RDEBUG(("Giving coalesced node %d color %s\n",
+			    w->nodnum, rnames[COLOR(w)]));
+#endif
+		}
+	}
+
+#ifdef PCC_DEBUG
+	if (rdebug)
+		DLIST_FOREACH(w, &coloredNodes, link)
+			printf("%d: color %s\n", ASGNUM(w), rnames[COLOR(w)]);
+#endif
+	if (DLIST_ISEMPTY(&spilledNodes, link)) {
+		DLIST_FOREACH(ip2, ip, qelem)
+			if (ip2->type == IP_NODE)
+				walkf(ip2->ip_node, paint, 0);
+	}
+}
+
+static REGW *spole;
+/*
+ * Store all spilled nodes in memory by fetching a temporary on the stack.
+ * Will never end up here if not optimizing.
+ */
+static void
+longtemp(NODE *p, void *arg)
+{
+	NODE *l, *r;
+	REGW *w;
+
+	if (p->n_op != TEMP)
+		return;
+	/* XXX - should have a bitmask to find temps to convert */
+	DLIST_FOREACH(w, spole, link) {
+		if (w != &nblock[regno(p)])
+			continue;
+		if (w->r_class == 0) {
+			w->r_color = BITOOR(freetemp(szty(p->n_type)));
+			w->r_class = 1;
+		}
+		l = mklnode(REG, 0, FPREG, INCREF(p->n_type));
+		r = mklnode(ICON, w->r_color, 0, INT);
+		p->n_left = mkbinode(PLUS, l, r, INCREF(p->n_type));
+		p->n_op = UMUL;
+		p->n_regw = NULL;
+		break;
+	}
+}
+
+static struct interpass *cip;
+/*
+ * Rewrite a tree by storing a variable in memory.
+ * XXX - must check if basic block structure is destroyed!
+ */
+static void
+shorttemp(NODE *p, void *arg)
+{
+	struct interpass *nip;
+	struct optab *q;
+	REGW *w;
+	NODE *l, *r;
+	int off;
+
+	/* XXX - optimize this somewhat */
+	DLIST_FOREACH(w, spole, link) {
+		if (w != p->n_regw)
+			continue;
+		/* XXX - use canaddr() */
+		if (p->n_op == OREG || p->n_op == NAME) {
+			DLIST_REMOVE(w, link);
+#ifdef PCC_DEBUG
+			RDEBUG(("Node %d already in memory\n", ASGNUM(w)));
+#endif
+			break;
+		}
+#ifdef PCC_DEBUG
+		RDEBUG(("rewriting node %d\n", ASGNUM(w)));
+#endif
+
+		off = BITOOR(freetemp(szty(p->n_type)));
+		l = mklnode(OREG, off, FPREG, p->n_type);
+		r = talloc();
+		/*
+		 * If this is a binode which reclaim a leg, and it had
+		 * to walk down the other leg first, then it must be
+		 * split below this node instead.
+		 */
+		q = &table[TBLIDX(p->n_su)];
+		if (optype(p->n_op) == BITYPE &&
+		    (q->rewrite & RLEFT && (p->n_su & DORIGHT) == 0) &&
+		    (TBLIDX(p->n_right->n_su) != 0)) {
+			*r = *l;
+			nip = ipnode(mkbinode(ASSIGN, l,
+			    p->n_left, p->n_type));
+			p->n_left = r;
+		} else if (optype(p->n_op) == BITYPE &&
+		    (q->rewrite & RRIGHT && (p->n_su & DORIGHT) != 0) &&
+		    (TBLIDX(p->n_left->n_su) != 0)) {
+			*r = *l;
+			nip = ipnode(mkbinode(ASSIGN, l,
+			    p->n_right, p->n_type));
+			p->n_right = r;
+		} else {
+			*r = *p;
+			nip = ipnode(mkbinode(ASSIGN, l, r, p->n_type));
+			*p = *l;
+		}
+		DLIST_INSERT_BEFORE(cip, nip, qelem);
+		DLIST_REMOVE(w, link);
+		break;
+	}
+}
+
+/*
+ * Change the TEMPs in the ipole list to stack variables.
+ */
+static void
+treerewrite(struct interpass *ipole, REGW *rpole)
+{
+	struct interpass *ip;
+
+	spole = rpole;
+
+	DLIST_FOREACH(ip, ipole, qelem) {
+		if (ip->type != IP_NODE)
+			continue;
+		cip = ip;
+		walkf(ip->ip_node, shorttemp, 0); /* convert temps to oregs */
+	}
+	if (!DLIST_ISEMPTY(spole, link))
+		comperr("treerewrite not empty");
+}
+
+/*
+ * Change the TEMPs in the ipole list to stack variables.
+ */
+static void
+leafrewrite(struct interpass *ipole, REGW *rpole)
+{
+	extern NODE *nodepole;
+	extern int thisline;
+	struct interpass *ip;
+
+	spole = rpole;
+	DLIST_FOREACH(ip, ipole, qelem) {
+		if (ip->type != IP_NODE)
+			continue;
+		nodepole = ip->ip_node;
+		thisline = ip->lineno;
+		walkf(ip->ip_node, longtemp, 0); /* convert temps to oregs */
+	}
+	nodepole = NIL;
+}
+
+/*
+ * Avoid copying spilled argument to new position on stack.
+ */
+static int
+temparg(struct interpass *ipole, REGW *w)
+{
+	struct interpass *ip;
+	NODE *p;
+
+	ip = DLIST_NEXT(ipole, qelem); /* PROLOG */
+	while (ip->type != IP_DEFLAB)
+		ip = DLIST_NEXT(ip, qelem);
+	ip = DLIST_NEXT(ip, qelem); /* first NODE */
+	for (; ip->type != IP_DEFLAB; ip = DLIST_NEXT(ip, qelem)) {
+		if (ip->type == IP_ASM)
+			continue;
+		p = ip->ip_node;
+#ifdef notdef
+		/* register args may already have been put on stack */
+		if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
+			comperr("temparg");
+#endif
+		if (p->n_op != ASSIGN || p->n_left->n_op != TEMP)
+			continue; /* unknown tree */
+
+		if (p->n_right->n_op != OREG)
+			continue; /* arg in register */
+		if (w != &nblock[regno(p->n_left)])
+			continue;
+		w->r_color = (int)p->n_right->n_lval;
+		tfree(p);
+		/* Cannot DLIST_REMOVE here, would break basic blocks */
+		/* Make it a nothing instead */
+		ip->type = IP_ASM;
+		ip->ip_asm="";
+		return 1;
+	}
+	return 0;
+}
+
+#define	ONLYPERM 1
+#define	LEAVES	 2
+#define	SMALL	 3
+
+/*
+ * Scan the whole function and search for temporaries to be stored
+ * on-stack.
+ *
+ * Be careful to not destroy the basic block structure in the first scan.
+ */
+static int
+RewriteProgram(struct interpass *ip)
+{
+	REGW shortregs, longregs, saveregs, *q;
+	REGW *w;
+	int rwtyp;
+
+	RDEBUG(("RewriteProgram\n"));
+	DLIST_INIT(&shortregs, link);
+	DLIST_INIT(&longregs, link);
+	DLIST_INIT(&saveregs, link);
+
+	/* sort the temporaries in three queues, short, long and perm */
+	while (!DLIST_ISEMPTY(&spilledNodes, link)) {
+		w = DLIST_NEXT(&spilledNodes, link);
+		DLIST_REMOVE(w, link);
+
+		if (w >= &nblock[tempmin] && w < &nblock[basetemp]) {
+			q = &saveregs;
+		} else if (w >= &nblock[basetemp] && w < &nblock[tempmax]) {
+			q = &longregs;
+		} else
+			q = &shortregs;
+		DLIST_INSERT_AFTER(q, w, link);
+	}
+#ifdef PCC_DEBUG
+	if (rdebug) {
+		printf("permanent: ");
+		DLIST_FOREACH(w, &saveregs, link)
+			printf("%d ", ASGNUM(w));
+		printf("\nlong-lived: ");
+		DLIST_FOREACH(w, &longregs, link)
+			printf("%d ", ASGNUM(w));
+		printf("\nshort-lived: ");
+		DLIST_FOREACH(w, &shortregs, link)
+			printf("%d ", ASGNUM(w));
+		printf("\n");
+	}
+#endif
+	rwtyp = 0;
+
+	if (!DLIST_ISEMPTY(&saveregs, link)) {
+		rwtyp = ONLYPERM;
+		DLIST_FOREACH(w, &saveregs, link) {
+			int num = w - nblock - tempmin;
+			nsavregs[num] = 1;
+		}
+	}
+	if (!DLIST_ISEMPTY(&longregs, link)) {
+		rwtyp = LEAVES;
+		DLIST_FOREACH(w, &longregs, link) {
+			w->r_class = xtemps ? temparg(ip, w) : 0;
+		}
+	}
+
+	if (rwtyp == LEAVES) {
+		leafrewrite(ip, &longregs);
+		rwtyp = ONLYPERM;
+	}
+
+	if (rwtyp == 0 && !DLIST_ISEMPTY(&shortregs, link)) {
+		/* Must rewrite the trees */
+		treerewrite(ip, &shortregs);
+#if 0
+		if (xtemps)
+			comperr("treerewrite");
+#endif
+		rwtyp = SMALL;
+	}
+
+	RDEBUG(("savregs %x rwtyp %d\n", 0, rwtyp));
+
+	return rwtyp;
+}
+
+#ifdef PCC_DEBUG
+/*
+ * Print TEMP/REG contents in a node.
+ */
+void
+prtreg(FILE *fp, NODE *p)
+{
+	int i, n = p->n_su == -1 ? 0 : ncnt(table[TBLIDX(p->n_su)].needs);
+if (p->n_reg == -1) goto foo;
+	if (use_regw || p->n_reg > 0x40000000 || p->n_reg < 0) {
+		fprintf(fp, "TEMP ");
+		if (p->n_regw != NULL) {
+			for (i = 0; i < n+1; i++)
+				fprintf(fp, "%d ", p->n_regw[i].nodnum);
+		} else
+			fprintf(fp, "<undef>");
+	} else {
+foo:		fprintf(fp, "REG ");
+		if (p->n_reg != -1) {
+			for (i = 0; i < n+1; i++) {
+				int r = DECRA(p->n_reg, i);
+				if (r >= MAXREGS)
+					fprintf(fp, "<badreg> ");
+				else
+					fprintf(fp, "%s ", rnames[r]);
+			}
+		} else
+			fprintf(fp, "<undef>");
+	}
+}
+#endif
+
+#ifdef notyet
+/*
+ * Assign instructions, calculate evaluation order and
+ * set temporary register numbers.
+ */
+static void
+insgen()
+{
+	geninsn(); /* instruction assignment */
+	sucomp();  /* set evaluation order */
+	slong();   /* set long temp types */
+	sshort();  /* set short temp numbers */
+}
+#endif
+
+/*
+ * Do register allocation for trees by graph-coloring.
+ */
+void
+ngenregs(struct p2env *p2e)
+{
+	struct interpass *ipole = &p2e->ipole;
+	extern NODE *nodepole;
+	struct interpass *ip;
+	int i, j, tbits;
+	int uu[NPERMREG] = { -1 };
+	int xnsavregs[NPERMREG];
+	int beenhere = 0;
+	TWORD type;
+
+	DLIST_INIT(&lunused, link);
+	DLIST_INIT(&lused, link);
+
+	/*
+	 * Do some setup before doing the real thing.
+	 */
+	tempmin = p2e->ipp->ip_tmpnum;
+	tempmax = p2e->epp->ip_tmpnum;
+
+	/*
+	 * Allocate space for the permanent registers in the
+	 * same block as the long-lived temporaries.
+	 * These temporaries will be handled the same way as 
+	 * all other variables.
+	 */
+	basetemp = tempmin;
+	nsavregs = xnsavregs;
+	for (i = 0; i < NPERMREG; i++)
+		xnsavregs[i] = 0;
+	ndontregs = uu; /* currently never avoid any regs */
+
+	tempmin -= (NPERMREG-1);
+#ifdef notyet
+	if (xavoidfp)
+		dontregs |= REGBIT(FPREG);
+#endif
+
+#ifdef PCC_DEBUG
+	nodnum = tempmax;
+#endif
+	tbits = tempmax - tempmin;	/* # of temporaries */
+	xbits = tbits + MAXREGS;	/* total size of live array */
+	if (tbits) {
+		nblock = tmpalloc(tbits * sizeof(REGW));
+
+		nblock -= tempmin;
+#ifdef HAVE_C99_FORMAT
+		RDEBUG(("nblock %p num %d size %zu\n",
+		    nblock, tbits, (size_t)(tbits * sizeof(REGW))));
+#endif
+	}
+	live = tmpalloc(BIT2BYTE(xbits));
+
+	/* Block for precolored nodes */
+	ablock = tmpalloc(sizeof(REGW)*MAXREGS);
+	memset(ablock, 0, sizeof(REGW)*MAXREGS);
+	for (i = 0; i < MAXREGS; i++) {
+		ablock[i].r_onlist = &precolored;
+		ablock[i].r_class = GCLASS(i); /* XXX */
+		ablock[i].r_color = i;
+#ifdef PCC_DEBUG
+		ablock[i].nodnum = i;
+#endif
+	}
+#ifdef notyet
+	TMPMARK();
+#endif
+
+
+recalc:
+onlyperm: /* XXX - should not have to redo all */
+	memset(edgehash, 0, sizeof(edgehash));
+
+	if (tbits) {
+		memset(nblock+tempmin, 0, tbits * sizeof(REGW));
+#ifdef PCC_DEBUG
+		for (i = tempmin; i < tempmax; i++)
+			nblock[i].nodnum = i;
+#endif
+	}
+	memset(live, 0, BIT2BYTE(xbits));
+	RPRINTIP(ipole);
+	DLIST_INIT(&initial, link);
+	DLIST_FOREACH(ip, ipole, qelem) {
+		extern int thisline;
+		if (ip->type != IP_NODE)
+			continue;
+		nodepole = ip->ip_node;
+		thisline = ip->lineno;
+		if (ip->ip_node->n_op != XASM)
+			geninsn(ip->ip_node, FOREFF);
+		nsucomp(ip->ip_node);
+		walkf(ip->ip_node, traclass, 0);
+	}
+	nodepole = NIL;
+	RDEBUG(("nsucomp allocated %d temps (%d,%d)\n", 
+	    tempmax-tempmin, tempmin, tempmax));
+
+#ifdef PCC_DEBUG
+	use_regw = 1;
+	RPRINTIP(ipole);
+	use_regw = 0;
+#endif
+	RDEBUG(("ngenregs: numtemps %d (%d, %d)\n", tempmax-tempmin,
+		    tempmin, tempmax));
+
+	DLIST_INIT(&coalescedMoves, link);
+	DLIST_INIT(&constrainedMoves, link);
+	DLIST_INIT(&frozenMoves, link);
+	DLIST_INIT(&worklistMoves, link);
+	DLIST_INIT(&activeMoves, link);
+
+	/* Set class and move-related for perm regs */
+	for (i = 0; i < (NPERMREG-1); i++) {
+		if (nsavregs[i])
+			continue;
+		nblock[i+tempmin].r_class = GCLASS(permregs[i]);
+		DLIST_INSERT_AFTER(&initial, &nblock[i+tempmin], link);
+		moveadd(&nblock[i+tempmin], &ablock[permregs[i]]);
+		addalledges(&nblock[i+tempmin]);
+	}
+
+	Build(p2e);
+	RDEBUG(("Build done\n"));
+	MkWorklist();
+	RDEBUG(("MkWorklist done\n"));
+	do {
+		if (!WLISTEMPTY(simplifyWorklist))
+			Simplify();
+		else if (!WLISTEMPTY(worklistMoves))
+			Coalesce();
+		else if (!WLISTEMPTY(freezeWorklist))
+			Freeze();
+		else if (!WLISTEMPTY(spillWorklist))
+			SelectSpill();
+	} while (!WLISTEMPTY(simplifyWorklist) || !WLISTEMPTY(worklistMoves) ||
+	    !WLISTEMPTY(freezeWorklist) || !WLISTEMPTY(spillWorklist));
+	AssignColors(ipole);
+
+	RDEBUG(("After AssignColors\n"));
+	RPRINTIP(ipole);
+
+	if (!WLISTEMPTY(spilledNodes)) {
+		switch (RewriteProgram(ipole)) {
+		case ONLYPERM:
+			goto onlyperm;
+		case SMALL:
+			optimize(p2e);
+			if (beenhere++ == MAXLOOP)
+				comperr("cannot color graph - COLORMAP() bug?");
+			goto recalc;
+		}
+	}
+
+	/* fill in regs to save */
+	memset(p2e->ipp->ipp_regs, 0, sizeof(p2e->ipp->ipp_regs));
+	for (i = 0; i < NPERMREG-1; i++) {
+		NODE *p;
+
+		if (nsavregs[i]) {
+			BITSET(p2e->ipp->ipp_regs, permregs[i]);
+			continue; /* Spilled */
+		}
+		if (nblock[i+tempmin].r_color == permregs[i])
+			continue; /* Coalesced */
+		/*
+		 * If the original color of this permreg is used for
+		 * coloring another register, swap them to avoid
+		 * unnecessary moves.
+		 */
+		for (j = i+1; j < NPERMREG-1; j++) {
+			if (nblock[j+tempmin].r_color != permregs[i])
+				continue;
+			nblock[j+tempmin].r_color = nblock[i+tempmin].r_color;
+			break;
+		}
+		if (j != NPERMREG-1)
+			continue;
+
+		/* Generate reg-reg move nodes for save */
+		type = PERMTYPE(permregs[i]);
+#ifdef PCC_DEBUG
+		if (PERMTYPE(nblock[i+tempmin].r_color) != type)
+			comperr("permreg botch");
+#endif
+		p = mkbinode(ASSIGN,
+		    mklnode(REG, 0, nblock[i+tempmin].r_color, type),
+		    mklnode(REG, 0, permregs[i], type), type);
+		p->n_reg = p->n_left->n_reg = p->n_right->n_reg = -1;
+		p->n_left->n_su = p->n_right->n_su = 0;
+		geninsn(p, FOREFF);
+		ip = ipnode(p);
+		DLIST_INSERT_AFTER(ipole->qelem.q_forw, ip, qelem);
+		p = mkbinode(ASSIGN, mklnode(REG, 0, permregs[i], type),
+		    mklnode(REG, 0, nblock[i+tempmin].r_color, type), type);
+		p->n_reg = p->n_left->n_reg = p->n_right->n_reg = -1;
+		p->n_left->n_su = p->n_right->n_su = 0;
+		geninsn(p, FOREFF);
+		ip = ipnode(p);
+		DLIST_INSERT_BEFORE(ipole->qelem.q_back, ip, qelem);
+	}
+	memcpy(p2e->epp->ipp_regs, p2e->ipp->ipp_regs, sizeof(p2e->epp->ipp_regs));
+	/* Done! */
+}
Index: uspace/app/pcc/os/bsd/ccconfig.h
===================================================================
--- uspace/app/pcc/os/bsd/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/bsd/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,53 @@
+/*	$Id: ccconfig.h,v 1.1 2008/09/27 07:39:14 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+#ifndef LIBDIR
+#define LIBDIR "/usr/lib/"
+#endif
+
+/* common cpp predefines */
+#define	CPPADD	{ "-D__BSD2_11__", "-DBSD2_11", NULL }
+
+/* host-dependent */
+#define CRT0FILE LIBDIR "crt0.o"
+#define CRT0FILE_PROFILE LIBDIR "gcrt0.o"
+
+#ifdef LANG_F77
+#define F77LIBLIST { "-L/usr/lib", "-lF77", "-lI77", "-lm", "-lc", NULL };
+#endif
+
+#if defined(mach_pdp11)
+#define	CPPMDADD { "-D__pdp11__", "-Dpdp11", NULL, }
+#else
+#error defines for arch missing
+#endif
Index: uspace/app/pcc/os/darwin/ccconfig.h
===================================================================
--- uspace/app/pcc/os/darwin/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/darwin/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,65 @@
+/*	$Id: ccconfig.h,v 1.12 2009/05/21 09:35:00 gmcgarry Exp $	*/
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+#ifndef LIBDIR
+#define LIBDIR "/usr/lib/"
+#endif
+
+/* common cpp predefines */
+#define	CPPADD	{ "-D__Darwin__", "-D__APPLE__", NULL }
+#define	DYNLINKER { NULL }
+#define CRT0FILE PCCLIBDIR "crt1.o"
+#define CRT0FILE_PROFILE PCCLIBDIR "gcrt1.o"
+#define STARTFILES { NULL }
+#define ENDFILES { NULL }
+#define STARTFILES_S { PCCLIBDIR "dylib1.o" }
+#define ENDFILES_S { NULL }
+#define LIBCLIBS { "-lSystem", "-lpcc", NULL }
+#define LIBCLIBS_PROFILE { "-lSystem_profile", "-lpcc", NULL }
+#define STARTLABEL "start"
+
+/*
+ld -arch ppc -weak_reference_mismatches non-weak -o a.out -lcrt1.o -lcrt2.o -L/usr/lib/gcc/powerpc-apple-darwin8/4.0.1 hello_ppc.o -lgcc -lSystemStubs -lSystem
+*/
+
+#if defined(mach_i386)
+#define	CPPMDADD { "-D__i386__", "-D__LITTLE_ENDIAN__", NULL }
+#elif defined(mach_powerpc)
+#define	CPPMDADD { "-D__ppc__", "-D__BIG_ENDIAN__", NULL }
+#elif defined(mach_amd64)
+#define	CPPMDADD { "-D__x86_64__", "-D__LITTLE_ENDIAN__", NULL }
+#else
+#error defines for arch missing
+#endif
+
+#define	STABS
Index: uspace/app/pcc/os/dragonfly/ccconfig.h
===================================================================
--- uspace/app/pcc/os/dragonfly/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/dragonfly/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,66 @@
+/*	$Id: ccconfig.h,v 1.6.2.1 2011/02/26 07:35:32 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+#include <sys/param.h>
+
+/* common cpp predefines */
+#define	CPPADD	{ "-D__DragonFly__", "-D__ELF__", NULL, }
+#define	DYNLINKER { "-dynamic-linker", "/usr/libexec/ld-elf.so.2", NULL }
+
+#if __DragonFly_version < 200202
+#define CRT0FILE "/usr/lib/gcc34/crt1.o"
+#define CRT0FILE_PROFILE "/usr/lib/gcc34/gcrt1.o"
+#define STARTFILES { "/usr/lib/gcc34/crti.o", "/usr/lib/gcc34/crtbegin.o", NULL }
+#define LIBCLIBS { "-lc", "-L/usr/lib/gcc34", "-lgcc", NULL }
+#define	ENDFILES { "/usr/lib/gcc34/crtend.o", "/usr/lib/gcc34/crtn.o", NULL }
+#else
+#define	CRT0FILE "/usr/lib/crt1.o"
+#define	CRT0FILE_PROFILE "/usr/lib/gcrt1.o"
+#define	STARTFILES { "/usr/lib/crti.o", "/usr/lib/gcc41/crtbegin.o", NULL }
+#define	LIBCLIBS { "-lc", "-L/usr/lib/gcc41", "-lgcc", NULL }
+#define	ENDFILES { "/usr/lib/gcc41/crtend.o", "/usr/lib/crtn.o", NULL }
+#endif
+
+#define STARTLABEL "_start"
+
+#if defined(mach_i386)
+#define	CPPMDADD { "-D__i386__", NULL, }
+#elif defined(mach_amd64)
+#define CPPMDADD \
+	{ "-D__x86_64__", "-D__x86_64", "-D__amd64__", "-D__amd64", \
+	  "-D__LP64__=1", "-D_LP64=1", NULL, }
+#else
+#error defines for arch missing
+#endif
+
+#define	STABS
Index: uspace/app/pcc/os/freebsd/ccconfig.h
===================================================================
--- uspace/app/pcc/os/freebsd/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/freebsd/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2007 David O'Brien <obrien@FreeBSD.org>
+ * Copyright (c) 2007 Ed Schouten <ed@fxq.nl>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef LIBDIR
+#define LIBDIR "/usr/lib/"
+#endif
+
+#define CPPADD { "-D__FreeBSD__=" MKS(TARGOSVER), "-D__ELF__", \
+	"-D__unix__=1", "-D__unix=1", NULL, }
+
+/* host-dependent */
+#define CRT0FILE LIBDIR "crt1.o"
+#define CRT0FILE_PROFILE LIBDIR "gcrt1.o"
+#define STARTFILES { LIBDIR "crti.o", LIBDIR "crtbegin.o", NULL }
+#define ENDFILES { LIBDIR "crtend.o", LIBDIR "crtn.o", NULL }
+#define STARTFILES_S { LIBDIR "crti.o", LIBDIR "crtbeginS.o", NULL }
+#define ENDFILES_S { LIBDIR "crtendS.o", LIBDIR "crtn.o", NULL }
+#define LIBCLIBS { "-lc", "-lpcc", NULL }
+#define STARTLABEL "_start"
+
+/* host-independent */
+#define DYNLINKER { "-dynamic-linker", "/libexec/ld-elf.so.1", NULL }
+
+#if defined(mach_i386)
+#define CPPMDADD { "-D__i386__", "-D__i386", NULL, }
+#elif defined(mach_amd64)
+#define CPPMDADD \
+	{ "-D__x86_64__", "-D__x86_64", "-D__amd64__", "-D__amd64", \
+	  "-D__LP64__=1", "-D_LP64=1", NULL, }
+#else
+#error defines for arch missing
+#endif
+
+#ifdef LANG_F77
+#define F77LIBLIST { "-lF77", "-lI77", "-lm", "-lc", NULL };
+#endif
+
+#define STABS
Index: uspace/app/pcc/os/helenos/ccconfig.h
===================================================================
--- uspace/app/pcc/os/helenos/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/helenos/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,87 @@
+/*	$Id: ccconfig.h,v 1.19 2010/11/09 08:40:50 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/* common cpp predefines */
+#define CPPADD	{ "-D__helenos__", "-D__ELF__", NULL, }
+
+#undef CRT0FILE
+#undef CRT0FILE_PROFILE
+
+#define LIBCLIBS { "/lib/libc.a", "/lib/libsoftfloat.a", "/lib/libsoftint.a", NULL }
+#define LIBCLIBS_PROFILE LIBCLIBS
+
+#define STARTFILES { NULL }
+#define ENDFILES { NULL }
+
+#define STARTFILES_S { NULL }
+#define ENDFILES_S { NULL }
+
+#define STARTLABEL "__entry"
+
+#if defined(mach_ia32)
+#define CPPMDADD { "-D__i386__", NULL, }
+#define DYNLINKER { NULL }
+#elif defined(mach_ppc32)
+#define CPPMDADD { "-D__ppc__", NULL, }
+#define DYNLINKER { NULL }
+#elif defined(mach_amd64)
+#define CPPMDADD { "-D__x86_64__", NULL, }
+#define	DYNLINKER { NULL }
+#elif defined(mach_mips32)
+#define CPPMDADD { "-D__mips__", NULL, }
+#define DYNLINKER { NULL }
+#else
+#error defines for arch missing
+#endif
+
+#ifndef LIBDIR
+#define LIBDIR "/lib/"
+#endif
+
+#ifndef LIBEXECDIR
+#define LIBEXECDIR "/app/"
+#endif
+
+#ifndef STDINC
+#define STDINC "/inc/c/"
+#endif
+
+#ifndef INCLUDEDIR
+#define INCLUDEDIR STDINC
+#endif
+
+// XXX: what's STABS?
+// #define STABS
+#ifndef ELFABI
+#define ELFABI
+#endif
Index: uspace/app/pcc/os/linux/ccconfig.h
===================================================================
--- uspace/app/pcc/os/linux/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/linux/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,75 @@
+/*	$Id: ccconfig.h,v 1.19 2010/11/09 08:40:50 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/* common cpp predefines */
+#define CPPADD	{ "-D__linux__", "-D__ELF__", NULL, }
+
+#define CRT0FILE LIBDIR "crt1.o"
+#define CRT0FILE_PROFILE LIBDIR "gcrt1.o"
+
+#define LIBCLIBS { "-lc", "-lpcc", NULL }
+#define LIBCLIBS_PROFILE LIBCLIBS
+
+#define STARTFILES { LIBDIR "crti.o", PCCLIBDIR "crtbegin.o", NULL }
+#define ENDFILES { PCCLIBDIR "crtend.o", LIBDIR "crtn.o", NULL }
+
+#define STARTFILES_S { LIBDIR "crti.o", PCCLIBDIR "crtbegin.o", NULL }
+#define ENDFILES_S { PCCLIBDIR "crtend.o", LIBDIR "crtn.o", NULL }
+
+#define STARTLABEL "_start"
+
+#if defined(mach_i386)
+#define CPPMDADD { "-D__i386__", NULL, }
+#define DYNLINKER { "-dynamic-linker", "/lib/ld-linux.so.2", NULL }
+#elif defined(mach_powerpc)
+#define CPPMDADD { "-D__ppc__", NULL, }
+#define DYNLINKER { "-dynamic-linker", "/lib/ld-linux.so.2", NULL }
+#elif defined(mach_amd64)
+#define CPPMDADD { "-D__x86_64__", NULL, }
+#define	DYNLINKER { "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", NULL }
+#ifndef LIBDIR
+#define	LIBDIR "/usr/lib64/"
+#endif
+#elif defined(mach_mips)
+#define CPPMDADD { "-D__mips__", NULL, }
+#define DYNLINKER { "-dynamic-linker", "/lib/ld.so.1", NULL }
+#else
+#error defines for arch missing
+#endif
+
+#ifndef LIBDIR
+#define LIBDIR "/usr/lib/"
+#endif
+
+#define STABS
+#define ELFABI
Index: uspace/app/pcc/os/midnightbsd/ccconfig.h
===================================================================
--- uspace/app/pcc/os/midnightbsd/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/midnightbsd/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,131 @@
+/* $Id: ccconfig.h,v 1.4 2008/07/18 06:53:48 gmcgarry Exp $ */
+/*-
+ * Copyright (c) 2007, 2008
+ *	Thorsten Glaser <tg@mirbsd.de>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
+/**
+ * Configuration for pcc on a MidnightBSD (amd64, i386 or sparc64) target
+ */
+
+/* === mi part === */
+
+#ifndef LIBDIR
+#define LIBDIR			"/usr/lib/"
+#endif
+
+/* cpp MI defines */
+#define CPPADD			{		\
+	"-D__MidnightBSD__",			\
+	"-D__FreeBSD__",			\
+	"-D__unix__",				\
+	"-D__unix",				\
+	"-Dunix",				\
+	"-D__ELF__",				\
+	"-D_LONGLONG",				\
+	NULL					\
+}
+
+/* for dynamically linked binaries */
+#define DYNLINKER		{		\
+	"-dynamic-linker",			\
+	"/libexec/ld-elf.so.1",			\
+	NULL					\
+}
+#define STARTFILES		{		\
+	LIBDIR "crti.o",			\
+	LIBDIR "crtbegin.o",			\
+	NULL					\
+}
+#define ENDFILES		{		\
+	LIBDIR "crtend.o",			\
+	LIBDIR "crtn.o",			\
+	NULL					\
+}
+
+/* for shared libraries */
+#define STARTFILES_S		{		\
+	LIBDIR "crti.o",			\
+	LIBDIR "crtbeginS.o",			\
+	NULL					\
+}
+#define ENDFILES_S		{		\
+	LIBDIR "crtendS.o",			\
+	LIBDIR "crtn.o",			\
+	NULL					\
+}
+
+/* for statically linked binaries */
+#define STARTFILES_T		{		\
+	LIBDIR "crti.o",			\
+	LIBDIR "crtbeginT.o",			\
+	NULL					\
+}
+#define ENDFILES_T		{		\
+	LIBDIR "crtend.o",			\
+	LIBDIR "crtn.o",			\
+	NULL					\
+}
+
+#define LIBCLIBS		{		\
+	"-lc",					\
+	"-lpcc",				\
+	NULL					\
+}
+#define LIBCLIBS_PROFILE	{		\
+	"-lc_p",				\
+	"-lpcc",				\
+	NULL					\
+}
+
+
+/* C run-time startup */
+#define CRT0FILE		LIBDIR "crt1.o"
+#define CRT0FILE_PROFILE	LIBDIR "gcrt1.o"
+#define STARTLABEL		"_start"
+
+/* debugging info */
+#define STABS
+
+/* === md part === */
+
+#if defined(mach_i386)
+#define CPPMDADD		{		\
+	"-D__i386__",				\
+	"-D__i386",				\
+	"-Di386",				\
+	NULL,					\
+}
+#elif defined(mach_sparc64)
+#define CPPMDADD		{		\
+	"-D__sparc64__",			\
+	"-D__sparc_v9__",			\
+	"-D__sparcv9",				\
+	"-D__sparc__",				\
+	"-D__sparc",				\
+	"-Dsparc",				\
+	"-D__arch64__",				\
+	"-D__LP64__",				\
+	"-D_LP64",				\
+	NULL,					\
+}
+#elif defined(mach_amd64)
+#error pcc does not support amd64 yet
+#else
+#error this architecture is not supported by MidnightBSD
+#endif
Index: uspace/app/pcc/os/mirbsd/ccconfig.h
===================================================================
--- uspace/app/pcc/os/mirbsd/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/mirbsd/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,108 @@
+/* $Id: ccconfig.h,v 1.7 2009/01/24 21:43:49 gmcgarry Exp $ */
+/*-
+ * Copyright (c) 2007, 2008
+ *	Thorsten Glaser <tg@mirbsd.de>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
+/**
+ * Configuration for pcc on a MirOS BSD (i386 or sparc) target
+ */
+
+/* === mi part === */
+
+#ifndef LIBDIR
+#define LIBDIR			"/usr/lib/"
+#endif
+
+/* cpp MI defines */
+#define CPPADD			{		\
+	"-D__MirBSD__",				\
+	"-D__OpenBSD__",			\
+	"-D__unix__",				\
+	"-D__ELF__",				\
+	NULL					\
+}
+
+/* for dynamically linked binaries */
+#define DYNLINKER		{		\
+	"-dynamic-linker",			\
+	"/usr/libexec/ld.so",			\
+	NULL					\
+}
+#define STARTFILES		{		\
+	LIBDIR "crti.o",			\
+	LIBDIR "crtbegin.o",			\
+	NULL					\
+}
+#define ENDFILES		{		\
+	LIBDIR "crtend.o",			\
+	LIBDIR "crtn.o",			\
+	NULL					\
+}
+
+/* for shared libraries */
+#define STARTFILES_S		{		\
+	LIBDIR "crti.o",			\
+	LIBDIR "crtbeginS.o",			\
+	NULL					\
+}
+#define ENDFILES_S		{		\
+	LIBDIR "crtendS.o",			\
+	LIBDIR "crtn.o",			\
+	NULL					\
+}
+
+/* for statically linked binaries */
+#define STARTFILES_T		{		\
+	LIBDIR "crti.o",			\
+	LIBDIR "crtbeginT.o",			\
+	NULL					\
+}
+#define ENDFILES_T		{		\
+	LIBDIR "crtend.o",			\
+	LIBDIR "crtn.o",			\
+	NULL					\
+}
+
+/* libc contains helper functions, so -lpcc is not needed */
+#define LIBCLIBS		{		\
+	"-lc",					\
+	NULL					\
+}
+
+/* C run-time startup */
+#define CRT0FILE		LIBDIR "crt0.o"
+#define STARTLABEL		"__start"
+
+/* debugging info */
+#define STABS
+
+/* === md part === */
+
+#if defined(mach_i386)
+#define CPPMDADD		{		\
+	"-D__i386__",				\
+	"-D__i386",				\
+	"-Di386",				\
+	NULL,					\
+}
+#elif defined(mach_sparc)
+#error pcc does not support sparc yet
+#else
+#error this architecture is not supported by MirOS BSD
+#endif
Index: uspace/app/pcc/os/netbsd/ccconfig.h
===================================================================
--- uspace/app/pcc/os/netbsd/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/netbsd/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,91 @@
+/*	$Id: ccconfig.h,v 1.17 2010/11/09 08:50:40 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+#ifndef LIBDIR
+#define LIBDIR "/usr/lib/"
+#endif
+
+/* common cpp predefines */
+#define	CPPADD	{ "-D__NetBSD__", "-D__ELF__", NULL, }
+
+/* host-dependent */
+#define CRT0FILE LIBDIR "crt0.o"
+#define CRT0FILE_PROFILE LIBDIR "gcrt0.o"
+
+#if TARGOSVER == 1
+#define STARTFILES { LIBDIR "crtbegin.o", NULL }
+#define	ENDFILES { LIBDIR "crtend.o", NULL }
+#else
+#define STARTFILES { LIBDIR "crti.o", LIBDIR "crtbegin.o", NULL }
+#define	ENDFILES { LIBDIR "crtend.o", LIBDIR "crtn.o", NULL }
+#endif
+
+/* shared libraries linker files */
+#if TARGOSVER == 1
+#define STARTFILES_S { LIBDIR "crtbeginS.o", NULL }
+#define	ENDFILES_S { LIBDIR "crtendS.o", NULL }
+#else
+#define STARTFILES_S { LIBDIR "crti.o", LIBDIR "crtbeginS.o", NULL }
+#define	ENDFILES_S { LIBDIR "crtendS.o", LIBDIR "crtn.o", NULL }
+#endif
+
+#ifdef LANG_F77
+#define F77LIBLIST { "-L/usr/local/lib", "-lF77", "-lI77", "-lm", "-lc", NULL };
+#endif
+
+/* host-independent */
+#define	DYNLINKER { "-dynamic-linker", "/usr/libexec/ld.elf_so", NULL }
+
+#if defined(mach_amd64)
+#define CPPMDADD \
+	{ "-D__x86_64__", "-D__x86_64", "-D__amd64__", "-D__amd64", NULL, }
+#elif defined(mach_arm)
+#define	CPPMDADD { "-D__arm__", NULL, }
+#elif defined(mach_i386)
+#define	CPPMDADD { "-D__i386__", NULL, }
+#elif defined(mach_mips)
+#define	CPPMDADD { "-D__mips__", NULL, }
+#elif defined(mach_pdp10)
+#define CPPMDADD { "-D__pdp10__", NULL, }
+#elif defined(mach_powerpc)
+#define	CPPMDADD { "-D__ppc__", NULL, }
+#define STARTLABEL "_start"
+#elif defined(mach_vax)
+#define CPPMDADD { "-D__vax__", NULL, }
+#elif defined(mach_sparc64)
+#define CPPMDADD { "-D__sparc64__", NULL, }
+#else
+#error defines for arch missing
+#endif
+
+#define	STABS
Index: uspace/app/pcc/os/nextstep/ccconfig.h
===================================================================
--- uspace/app/pcc/os/nextstep/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/nextstep/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,66 @@
+/*	$Id: ccconfig.h,v 1.2 2009/05/19 05:15:37 gmcgarry Exp $	*/
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+#ifndef LIBDIR
+#define LIBDIR "/usr/lib/"
+#endif
+
+/* common cpp predefines */
+#define	CPPADD	{		\
+	"-D__NeXT__",		\
+	"-I" LIBDIR "ansi",	\
+	"-I" LIBDIR "bsd",	\
+	NULL			\
+}
+#define	DYNLINKER { NULL }
+#define CRT0FILE LIBDIR "crt1.o"
+#define CRT0FILE_PROFILE LIBDIR "gcrt1.o"
+#define STARTFILES { NULL }
+#define	ENDFILES { NULL }
+#define LIBCLIBS { "-lc", "-lpcc", NULL }
+#define LIBCLIBS_PROFILE { "-lc", "-lpcc", NULL }
+#define STARTLABEL "start"
+
+/*
+ld -arch ppc -weak_reference_mismatches non-weak -o a.out -lcrt1.o -lcrt2.o -L/usr/lib/gcc/powerpc-apple-darwin8/4.0.1 hello_ppc.o -lgcc -lSystemStubs -lSystem
+*/
+
+#if defined(mach_i386)
+#define	CPPMDADD { "-D__i386__", "-D__LITTLE_ENDIAN__", NULL }
+#elif defined(mach_powerpc)
+#define	CPPMDADD { "-D__ppc__", "-D__BIG_ENDIAN__", NULL }
+#else
+#error defines for arch missing
+#endif
+
+#define	STABS
Index: uspace/app/pcc/os/none/ccconfig.h
===================================================================
--- uspace/app/pcc/os/none/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/none/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,50 @@
+/*	$Id: ccconfig.h,v 1.2 2006/07/30 09:29:27 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/*
+ * This file is for targets where there is no OS
+ */
+
+/* common cpp predefines */
+#define	CPPADD	{ NULL, }
+#define	DYNLINKER { NULL }
+#define CRT0FILE ""
+#define STARTFILES { NULL }
+#define	ENDFILES { NULL }
+
+#if defined(mach_m16c)
+#define	CPPMDADD { "-D__m16c__", NULL, }
+#elif defined(mach_nova)
+#define	CPPMDADD { "-D__nova__", NULL, }
+#endif
+
Index: uspace/app/pcc/os/openbsd/ccconfig.h
===================================================================
--- uspace/app/pcc/os/openbsd/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/openbsd/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,61 @@
+/*	$Id: ccconfig.h,v 1.8 2008/12/19 08:08:48 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+/* common cpp predefines */
+#define	CPPADD	{ "-D__OpenBSD__", "-D__ELF__", NULL, }
+#define	DYNLINKER { "-dynamic-linker", "/usr/libexec/ld.so", NULL }
+#define CRT0FILE "/usr/lib/crt0.o"
+#define CRT0FILE_PROFILE "/usr/lib/gcrt0.o"
+#define STARTFILES { "/usr/lib/crtbegin.o", NULL }
+#define	ENDFILES { "/usr/lib/crtend.o", NULL }
+
+#ifdef LANG_F77
+#define F77LIBLIST { "-L/usr/local/lib", "-lF77", "-lI77", "-lm", "-lc", NULL };
+#endif
+
+#if defined(mach_amd64)
+#define	CPPMDADD { "-D__amd64__", NULL, }
+#elif defined(mach_i386)
+#define	CPPMDADD { "-D__i386__", NULL, }
+#elif defined(mach_vax)
+#define CPPMDADD { "-D__vax__", NULL, } 
+#elif defined(mach_powerpc)
+#define CPPMDADD { "-D__powerpc__", NULL }
+#elif defined(mach_sparc64)
+#define CPPMDADD { "-D__sparc64__", NULL }
+#else
+#error defines for arch missing
+#endif
+
+#define ELFABI
+#define	STABS
Index: uspace/app/pcc/os/openbsd/f77config.h
===================================================================
--- uspace/app/pcc/os/openbsd/f77config.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/openbsd/f77config.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,46 @@
+/*	$Id: f77config.h,v 1.1 2007/09/15 07:37:49 ragge Exp $	*/
+
+/*
+ * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the f77 compiler works.
+ */
+
+#define PASS1NAME	"/usr/lib/f77pass1"
+#define PASS2NAME	"/lib/f1"
+#define PASS2OPT	"/lib/c2"
+#define NOFLPASS2	"/lib/fc1"
+
+#define ASMNAME		"/usr/bin/as"
+#define LDNAME		"/usr/bin/ld"
+#define FOOTNAME	"/usr/lib/crt0.o"
+#define PROFFOOT	"/usr/lib/mcrt0.o"
+#define NOFLFOOT	"/usr/lib/fcrt0.o"
+#define NOFLPROFFOOT	"/usr/lib/fmcrt0.o"
+#define LIBLIST		{ "-lF77", "-lI77", "-lm", "-lc", "-l", NULL };
+
Index: uspace/app/pcc/os/sunos/ccconfig.h
===================================================================
--- uspace/app/pcc/os/sunos/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/sunos/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,71 @@
+/*	$Id: ccconfig.h,v 1.3 2009/05/19 05:15:38 gmcgarry Exp $	*/
+
+/*
+ * Copyright (c) 2008 Adam Hoka.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various settings that controls how the C compiler works.
+ */
+
+#ifndef LIBDIR
+#define LIBDIR "/usr/lib/"
+#endif
+
+/* common cpp predefines */
+#define	CPPADD	{ "-Dunix", "-Dsun", "-D__SVR4", "-D__unix", "-D__sun", "-D__SunOS", "-D__ELF__", NULL }
+
+/* TODO: _ _SunOS_5_6, _ _SunOS_5_7, _ _SunOS_5_8, _ _SunOS_5_9, _ _SunOS_5_10 */
+
+/* host-dependent */
+#define CRT0FILE LIBDIR "crt1.o"
+#define CRT0FILE_PROFILE LIBDIR "gcrt1.o"
+#define STARTFILES { LIBDIR "crti.o", NULL }
+#define	ENDFILES { LIBDIR "crtn.o", NULL }
+/* shared libraries linker files */
+#define STARTFILES_S { LIBDIR "crti.o", NULL }
+#define	ENDFILES_S { LIBDIR "crtn.o", NULL }
+#define LIBCLIBS { "-lc", "-lpcc", NULL }
+
+#ifdef LANG_F77
+#define F77LIBLIST { "-L/usr/local/lib", "-lF77", "-lI77", "-lm", "-lc", NULL };
+#endif
+
+/* host-independent */
+#define	DYNLINKER { "-Bdynamic", "/usr/lib/ld.so", NULL }
+
+#if defined(mach_i386)
+#define	CPPMDADD { "-D__i386__", "-D__i386", NULL, }
+/* Let's keep it here in case of Polaris. ;) */
+#elif defined(mach_powerpc)
+#define	CPPMDADD { "-D__ppc__", NULL, }
+#elif defined(mach_sparc64)
+#define CPPMDADD { "-D__sparc64__", "-D__sparc", NULL, }
+#else
+#error defines for arch missing
+#endif
+
+#define	STABS
Index: uspace/app/pcc/os/win32/build.bat
===================================================================
--- uspace/app/pcc/os/win32/build.bat	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/win32/build.bat	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,205 @@
+rem @echo off
+
+set PCCDIR=
+set PREFIX=
+set usecl=
+set doinstall=false
+
+:parsecommandline
+if '%1' == '/h' goto dispinfo
+if '%1' == '/pcc' goto usepcc
+if '%1' == '/cl' goto usecl
+if '%1' == '/prefix' goto prefix
+if '%1' == '/pccdir' goto pccdir
+if '%1' == '/pccsrcdir' goto pccsrcdir
+if '%1' == '/pcclibssrcdir' goto pcclibssrcdir
+if '%1' == '/install' set doinstall=true
+goto build
+
+:dispinfo
+echo build.bat [/h] { /pcc or /cl } [/prefix -dir-] [/pccdir -dir-] [/pccsrcdir -dir-] [/pcclibssrcdir -dir-] [/install]
+goto end
+
+:prefix
+shift
+set PREFIX=%1
+shift
+goto parsecommandline
+
+:pccdir
+shift
+set PCCDIR=%1
+shift
+goto parsecommandline
+
+:pccsrcdir
+shift
+set PCCSRCDIR=%1
+shift
+goto parsecommandline
+
+:pcclibssrcdir
+shift
+set PCCLIBSSRCDIR=%1
+shift
+goto parsecommandline
+
+:usecl
+set CC=cl.exe -D__MSC__
+set CFLAGS=/nologo /Zi /MT /W2
+set CFLAGS2=/nologo /Zi /MD /Za /Wall /GS-
+set OBJ=obj
+set AR=lib.exe /nologo
+set AR_OUT=/OUT:libpcc.a
+set usecl=true
+shift
+goto parsecommandline
+
+:usepcc
+set CC=pcc.exe
+set CFLAGS=-g
+set CFLAGS2=-fno-stack-protector-all
+set OBJ=o
+set AR=ar.exe
+set AR_OUT=r libpcc.a
+set usecl=false
+shift
+goto parsecommandline
+
+:build
+
+if '%usecl%' == '' goto dispinfo
+
+set PREFIX=###%PREFIX%###
+set PREFIX=%PREFIX:"###=%
+set PREFIX=%PREFIX:###"=%
+set PREFIX=%PREFIX:###=%
+
+set PCCDIR=###%PCCDIR%###
+set PCCDIR=%PCCDIR:"###=%
+set PCCDIR=%PCCDIR:###"=%
+set PCCDIR=%PCCDIR:###=%
+
+set PCCSRCDIR=###%PCCSRCDIR%###
+set PCCSRCDIR=%PCCSRCDIR:"###=%
+set PCCSRCDIR=%PCCSRCDIR:###"=%
+set PCCSRCDIR=%PCCSRCDIR:###=%
+
+set PCCLIBSSRCDIR=###%PCCLIBSSRCDIR%###
+set PCCLIBSSRCDIR=%PCCLIBSSRCDIR:"###=%
+set PCCLIBSSRCDIR=%PCCLIBSSRCDIR:###"=%
+set PCCLIBSSRCDIR=%PCCLIBSSRCDIR:###=%
+
+if not '%PCCDIR%' == '' goto pccdirset
+set PCCDIR=C:\Program Files\pcc
+:pccdirset
+
+if not '%PCCSRCDIR%' == '' goto pccsrcdirset
+set PCCSRCDIR=..\..
+:pccsrcdirset
+
+if not '%PCCLIBSSRCDIR%' == '' goto pcclibssrcdirset
+set PCCLIBSSRCDIR=..\..\..\pcc-libs
+:pcclibssrcdirset
+
+if '%usecl%' == 'true' goto ccprefixed
+set CC="%PCCDIR%\bin\%CC%"
+set AR="%PCCDIR%\bin\%AR%"
+:ccprefixed
+
+set TARGOS=win32
+set MACH=i386
+set LIBEXECDIR=""
+
+set MIPDIR=%PCCSRCDIR%\mip
+set CPPDIR=%PCCSRCDIR%\cc\cpp
+set CCOMDIR=%PCCSRCDIR%\cc\ccom
+set CCDIR=%PCCSRCDIR%\cc\cc
+set OSDIR=%PCCSRCDIR%\os\%TARGOS%
+set MACHDIR=%PCCSRCDIR%\arch\%MACH%
+set BISON_SIMPLE=%OSDIR%\bison.simple
+set CPPFLAGS=-DWIN32 -DGCC_COMPAT -DPCC_DEBUG -DCPP_DEBUG -DTARGOS=%TARGOS% -Dos_%TARGOS% -Dmach_%MACH% -DLIBEXECDIR=%LIBEXECDIR% -D_CRT_SECURE_NO_WARNINGS
+
+del *.obj *.o *.exe
+
+%CC% -o pcc.exe %CPPFLAGS% %CFLAGS% -I%CCDIR% -I%OSDIR% -I%MACHDIR% -I%MIPDIR% %CCDIR%\cc.c %MIPDIR%\compat.c
+
+bison -y -t -d --no-lines %CPPDIR%\cpy.y
+rem flex %CPPDIR%\scanner.l
+rem %CC% -o cpp.exe %CPPFLAGS% %CFLAGS% -I%CPPDIR% -I%OSDIR% -I%MACHDIR% -I%MIPDIR% -I. %CPPDIR%\cpp.c %MIPDIR%\compat.c y.tab.c lex.yy.c "C:\Program Files\UnxUtils\usr\local\lib\libfl.lib"
+%CC% -o cpp.exe %CPPFLAGS% %CFLAGS% -I%CPPDIR% -I%OSDIR% -I%MACHDIR% -I%MIPDIR% -I. %CPPDIR%\cpp.c %CPPDIR%\token.c %MIPDIR%\compat.c y.tab.c "C:\Program Files\UnxUtils\usr\local\lib\libfl.lib"
+
+%CC% -o mkext.exe -DMKEXT %CPPFLAGS% %CFLAGS% -I%CCOMDIR% -I%OSDIR% -I%MACHDIR% -I%MIPDIR% %MIPDIR%\mkext.c %MACHDIR%\table.c %MIPDIR%\common.c
+mkext
+bison -y -t -d --no-lines %CCOMDIR%\cgram.y
+move y.tab.c cgram.c
+move y.tab.h cgram.h
+flex %CCOMDIR%\scan.l
+move lex.yy.c scan.c
+
+%CC% -o ccom.exe %CPPFLAGS% %CFLAGS% -I%CCOMDIR% -I%OSDIR% -I%MACHDIR% -I%MIPDIR% -I. %CCOMDIR%\main.c %MIPDIR%\compat.c scan.c cgram.c external.c %CCOMDIR%\optim.c %CCOMDIR%\pftn.c %CCOMDIR%\trees.c %CCOMDIR%\inline.c %CCOMDIR%\symtabs.c %CCOMDIR%\init.c %MACHDIR%\local.c %MACHDIR%\code.c %CCOMDIR%\stabs.c %CCOMDIR%\gcc_compat.c %MIPDIR%\match.c %MIPDIR%\reader.c %MIPDIR%\optim2.c %MIPDIR%\regs.c %MACHDIR%\local2.c %MACHDIR%\order.c %MACHDIR%\table.c %MIPDIR%\common.c "C:\Program Files\UnxUtils\usr\local\lib\libfl.lib"
+
+if not '%PREFIX%' == '' goto prefixset
+set PREFIX=C:\Program Files\pcc
+:prefixset
+
+set PCCDESTDIR=%PREFIX%
+set LIBPCCDESTDIR=%PREFIX%\lib\i386-win32\0.9.9
+
+set LIBPCCDIR=%PCCLIBSSRCDIR%\libpcc
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\_alloca.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\adddi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\anddi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\ashldi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\ashrdi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\cmpdi2.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\divdi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\fixdfdi.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\fixsfdi.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\fixunsdfdi.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\fixunssfdi.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\floatdidf.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\floatdisf.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\floatunsdidf.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\iordi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\lshldi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\lshrdi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\moddi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\muldi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\negdi2.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\notdi2.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\qdivrem.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\ssp.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\subdi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\ucmpdi2.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\udivdi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\umoddi3.c
+%CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\xordi3.c
+
+if '%usecl%' == 'false' %CC% -c %CPPFLAGS% %CFLAGS2% -I%LIBPCCDIR% %LIBPCCDIR%\_ftol.c
+if '%usecl%' == 'true' ml /nologo -c %LIBPCCDIR%\_ftol.asm
+
+%AR% %AR_OUT% _ftol.%OBJ% adddi3.%OBJ% anddi3.%OBJ% ashldi3.%OBJ% ashrdi3.%OBJ% cmpdi2.%OBJ% divdi3.%OBJ% fixdfdi.%OBJ% fixsfdi.%OBJ% fixunsdfdi.%OBJ% fixunssfdi.%OBJ% floatdidf.%OBJ% floatdisf.%OBJ% floatunsdidf.%OBJ% iordi3.%OBJ% lshldi3.%OBJ% lshrdi3.%OBJ% moddi3.%OBJ% muldi3.%OBJ% negdi2.%OBJ% notdi2.%OBJ% qdivrem.%OBJ% ssp.%OBJ% subdi3.%OBJ% ucmpdi2.%OBJ% udivdi3.%OBJ% umoddi3.%OBJ% xordi3.%OBJ%
+
+if not '%doinstall%' == 'true' goto end
+
+md "%PCCDESTDIR%"
+md "%PCCDESTDIR%\bin"
+md "%PCCDESTDIR%\libexec"
+md "%PCCDESTDIR%\man"
+md "%PCCDESTDIR%\man\man1"
+md "%LIBPCCDESTDIR%\lib"
+md "%LIBPCCDESTDIR%\include"
+
+copy pcc.exe "%PCCDESTDIR%\bin"
+copy cpp.exe "%PCCDESTDIR%\libexec"
+copy ccom.exe "%PCCDESTDIR%\libexec"
+
+copy libpcc.a "%LIBPCCDESTDIR%\lib"
+copy "%LIBPCCDIR%\include\*.h" "%LIBPCCDESTDIR%\include"
+
+copy "%CCDIR%\cc.1" "%PCCDESTDIR%\man\man1"
+copy "%CPPDIR%\cpp.1" "%PCCDESTDIR%\man\man1"
+copy "%CCOMDIR%\ccom.1" "%PCCDESTDIR%\man\man1"
+
+:end
Index: uspace/app/pcc/os/win32/build_installer.bat
===================================================================
--- uspace/app/pcc/os/win32/build_installer.bat	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/win32/build_installer.bat	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,1 @@
+"C:\Program Files\Inno Setup 5\ISCC.exe" /DAppName="PCC" /DAppVersion="0.9.9" /DAppNameLower="pcc" pcc.iss
Index: uspace/app/pcc/os/win32/ccconfig.h
===================================================================
--- uspace/app/pcc/os/win32/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/win32/ccconfig.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,23 @@
+#ifndef LIBDIR
+#define LIBDIR "/usr/lib/"
+#endif
+
+/*
+ * Currently only supports console applications.
+ */
+
+#if defined(WIN32) && defined(MSLINKER)
+/* requires microsoft toolkit headers and llnker */
+#define	CPPADD { "-DWIN32", NULL }
+#define LIBCLIBS { "/subsystem:console", "msvcrt.lib", "libpcc.a", NULL }
+#else
+/* requires w32api-3.2.tar.gz and mingw-runtime-3.14.tar.gz */
+#define	CPPADD { "-DWIN32", "-D__MSVCRT__", "-D__MINGW32__", NULL }
+#define STARTFILES { LIBDIR "crt2.o", NULL }
+#define ENDFILES { NULL }
+#define STARTFILES_S { LIBDIR "dllcrt2.o", NULL }
+#define ENDFILES_S { NULL }
+#define LIBCLIBS { "-lmoldname", "-lmingwex", "-lmsvcrt", "-lmingw32", "-luser32", "-lkernel32", "-lpcc", "-lmoldname", "-lmingwex", "-lmsvcrt", NULL }
+#endif
+
+#define CPPMDADD { "-D__i386__", NULL }
Index: uspace/app/pcc/os/win32/config.h
===================================================================
--- uspace/app/pcc/os/win32/config.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/win32/config.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,81 @@
+/*
+ * Config file for visual studio build
+ */
+#define PREPROCESSOR "%PCCDIR%\\libexec\\cpp.exe"
+#define COMPILER "%PCCDIR%\\libexec\\ccom.exe"
+
+#define USE_YASM
+
+#ifdef USE_YASM
+#define ASSEMBLER "yasm.exe"
+#else
+#define ASSEMBLER "gas.exe"
+#endif
+
+#ifdef USE_MSLINKER
+#define LINKER "link.exe /nologo"
+#define MSLINKER
+#else
+#define LINKER "ld.exe"
+#endif
+
+
+#define PECOFFABI
+
+#define STDINC "%PCCDIR%\\include\\"
+#define LIBDIR "%PCCDIR%\\lib\\"
+#define INCLUDEDIR STDINC
+#define PCCLIBDIR "%PCCDIR%\\lib\\i386-win32\\0.9.9\\lib\\"
+#define PCCINCDIR "%PCCDIR%\\lib\\i386-win32\\0.9.9\\include\\"
+
+#if !defined(vsnprintf)
+#define vsnprintf _vsnprintf
+#endif
+/* windows defines (u)uintptr_t in stddef.h, not inttypes.h */
+#include <stddef.h>
+#if !defined(snprintf)
+#define snprintf _snprintf
+#endif
+
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+#define inline __inline
+
+/* #define HAVE_INTTYPES_H 1 */
+#define HAVE_MEMORY_H 1
+/* #define HAVE_MKSTEMP 1 */
+
+#ifndef __MSC__
+#define HAVE_STDINT_H 1
+#endif
+
+#define HAVE_STDLIB_H 1
+/* #define HAVE_STRINGS_H 1 */
+#define HAVE_STRING_H 1
+/* #define HAVE_STRLCAT 1 */
+/* #define HAVE_STRLCPY 1 */
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SNPRINTF 1
+#define HAVE_VSNPRINTF 1
+/* #define HAVE_UNISTD_H 1 */
+/* #define HOST_BIG_ENDIAN  */
+#define HOST_LITTLE_ENDIAN
+#define ISFLEX 1
+
+#define PACKAGE_NAME "pcc"
+#define PACKAGE_STRING "pcc 0.9.9"
+#define PACKAGE_TARNAME "pcc"
+#define PACKAGE_VERSION "0.9.9"
+#define PCC_MAJOR 0
+#define PCC_MINOR 9
+#define PCC_MINORMINOR 9
+#define STDC_HEADERS 1
+#define TARGET_LITTLE_ENDIAN 1
+/* #define TARGOS win32 */
+#define VERSSTR "pcc 0.9.9 for win32, gmcgarry@pcc.ludd.ltu.se"
+#define WCHAR_SIZE 2
+#define WCHAR_TYPE USHORT
+#define YYTEXT_POINTER 1
Index: uspace/app/pcc/os/win32/pcc.iss
===================================================================
--- uspace/app/pcc/os/win32/pcc.iss	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/app/pcc/os/win32/pcc.iss	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,93 @@
+[Setup]
+AppName={#AppName}
+AppID={#AppNameLower}
+AppVerName={#AppName} {#AppVersion}
+AppPublisher=PCC Project
+AppPublisherURL=http://pcc.ludd.ltu.se/
+DefaultDirName={pf}\{#AppNameLower}
+DefaultGroupName={#AppName}
+Compression=lzma/ultra
+InternalCompressLevel=ultra
+SolidCompression=yes
+OutputDir=.
+OutputBaseFilename={#AppNameLower}-{#AppVersion}-win32
+ChangesEnvironment=yes
+
+[Files]
+Source: "c:\Program Files\{#AppNameLower}\*.*"; DestDir: {app}; Flags: recursesubdirs
+
+[Icons]
+Name: {group}\{cm:UninstallProgram, {#AppName}}; FileName: {uninstallexe}
+
+[Registry]
+Root: HKLM; Subkey: System\CurrentControlSet\Control\Session Manager\Environment; ValueName: {#AppName}DIR; ValueType: string; ValueData: {app}; Flags: deletevalue
+
+[Tasks]
+Name: modifypath; Description: Add application directory to your system path; Flags: unchecked
+
+[Code]
+
+// Jared Breland <jbreland@legroom.net>
+// http://www.legroom.net/software/modpath
+
+procedure ModPath(BinDir : String);
+var
+	oldpath : String;
+	newpath : String;
+	pathArr : TArrayOfString;
+	i : Integer;
+begin
+	RegQueryStringValue(HKEY_LOCAL_MACHINE, 'System\CurrentControlSet\Control\Session Manager\Environment', 'Path', oldpath);
+	oldpath := oldpath + ';';
+	i := 0;
+	while (Pos(';', oldpath) > 0) do begin
+		SetArrayLength(pathArr, i+1);
+		pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath) - 1);
+		oldpath := Copy(oldpath, Pos(';', oldpath) + 1, Length(oldpath));
+		i := i + 1;
+
+		if BinDir = pathArr[i-1] then
+			if IsUninstaller() = true then begin
+				continue;
+			end else begin
+				abort;
+			end;
+
+		if i = 1 then begin
+			newpath := pathArr[i-1];
+		end else begin
+			newpath := newpath + ';' + pathArr[i-1];
+		end;
+	end;
+
+	if IsUninstaller() = false then
+		newpath := newpath + ';' + BinDir;
+
+	RegWriteStringValue(HKEY_LOCAL_MACHINE, 'System\CurrentControlSet\Control\Session Manager\Environment', 'Path', newpath);
+end;
+		
+procedure CurStepChanged(CurStep : TSetupStep);
+var
+	appdir : String;
+begin
+	if CurStep = ssPostInstall then
+		if IsTaskSelected('modifypath') then begin
+			appdir := ExpandConstant('{app}');
+			ModPath(appdir + '\bin');
+			SaveStringToFile(appdir + '\uninsTasks.txt', WizardSelectedTasks(False), False);
+		end;
+end;
+
+procedure CurUninstallStepChanged(CurUninstallStep : TUninstallStep);
+var
+	appdir : String;
+	selectedTasks : String;
+begin
+	if CurUninstallStep = usUninstall then begin
+		appdir := ExpandConstant('{app}');
+		if LoadStringFromFile(appdir + '\uninsTasks.txt', selectedTasks) then
+			if (Pos('modifypath', selectedTasks) > 0) then
+				ModPath(appdir + '\bin');
+			DeleteFile(appdir + '\uninsTasks.txt')
+	end;
+end;
Index: uspace/drv/bus/usb/usbmast/scsi.h
===================================================================
--- uspace/drv/bus/usb/usbmast/scsi.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/drv/bus/usb/usbmast/scsi.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - 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.
+ */
+
+/** @addtogroup drvusbmast
+ * @{
+ */
+/** @file
+ * SCSI related structures.
+ */
+
+#ifndef USB_USBMAST_SCSI_H_
+#define USB_USBMAST_SCSI_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+
+typedef struct {
+	uint8_t op_code;
+	uint8_t lun_evpd;
+	uint8_t page_code;
+	uint16_t alloc_length;
+	uint8_t ctrl;
+} __attribute__((packed)) scsi_cmd_inquiry_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/c/arch/abs32le/include/types.h
===================================================================
--- uspace/lib/c/arch/abs32le/include/types.h	(revision e6165bed4794b3ee0af1ee32530fbf6bebde35bf)
+++ uspace/lib/c/arch/abs32le/include/types.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -51,4 +51,5 @@
 typedef uint32_t size_t;
 
+typedef int32_t intptr_t;
 typedef uint32_t uintptr_t;
 typedef uint32_t atomic_count_t;
Index: uspace/lib/c/arch/amd64/include/types.h
===================================================================
--- uspace/lib/c/arch/amd64/include/types.h	(revision e6165bed4794b3ee0af1ee32530fbf6bebde35bf)
+++ uspace/lib/c/arch/amd64/include/types.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -51,4 +51,5 @@
 typedef uint64_t size_t;
 
+typedef int64_t intptr_t;
 typedef uint64_t uintptr_t;
 typedef uint64_t atomic_count_t;
Index: uspace/lib/c/arch/arm32/include/types.h
===================================================================
--- uspace/lib/c/arch/arm32/include/types.h	(revision e6165bed4794b3ee0af1ee32530fbf6bebde35bf)
+++ uspace/lib/c/arch/arm32/include/types.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -52,4 +52,5 @@
 typedef uint32_t size_t;
 
+typedef int32_t intptr_t;
 typedef uint32_t uintptr_t;
 typedef uint32_t atomic_count_t;
Index: uspace/lib/c/arch/ia32/include/types.h
===================================================================
--- uspace/lib/c/arch/ia32/include/types.h	(revision e6165bed4794b3ee0af1ee32530fbf6bebde35bf)
+++ uspace/lib/c/arch/ia32/include/types.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -51,4 +51,5 @@
 typedef uint32_t size_t;
 
+typedef int32_t intptr_t;
 typedef uint32_t uintptr_t;
 typedef uint32_t atomic_count_t;
Index: uspace/lib/c/arch/ia64/include/types.h
===================================================================
--- uspace/lib/c/arch/ia64/include/types.h	(revision e6165bed4794b3ee0af1ee32530fbf6bebde35bf)
+++ uspace/lib/c/arch/ia64/include/types.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -61,4 +61,5 @@
 typedef uint64_t size_t;
 
+typedef int64_t intptr_t;
 typedef uint64_t uintptr_t;
 typedef uint64_t atomic_count_t;
Index: uspace/lib/c/arch/mips32/include/types.h
===================================================================
--- uspace/lib/c/arch/mips32/include/types.h	(revision e6165bed4794b3ee0af1ee32530fbf6bebde35bf)
+++ uspace/lib/c/arch/mips32/include/types.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -52,4 +52,5 @@
 typedef uint32_t size_t;
 
+typedef int32_t intptr_t;
 typedef uint32_t uintptr_t;
 typedef uint32_t atomic_count_t;
Index: uspace/lib/c/arch/ppc32/include/types.h
===================================================================
--- uspace/lib/c/arch/ppc32/include/types.h	(revision e6165bed4794b3ee0af1ee32530fbf6bebde35bf)
+++ uspace/lib/c/arch/ppc32/include/types.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -51,4 +51,5 @@
 typedef uint32_t size_t;
 
+typedef int32_t intptr_t;
 typedef uint32_t uintptr_t;
 typedef uint32_t atomic_count_t;
Index: uspace/lib/c/arch/sparc64/include/types.h
===================================================================
--- uspace/lib/c/arch/sparc64/include/types.h	(revision e6165bed4794b3ee0af1ee32530fbf6bebde35bf)
+++ uspace/lib/c/arch/sparc64/include/types.h	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -51,4 +51,5 @@
 typedef uint64_t size_t;
 
+typedef int64_t intptr_t;
 typedef uint64_t uintptr_t;
 typedef uint64_t atomic_count_t;
Index: uspace/srv/hid/input/port/sgcn.c
===================================================================
--- uspace/srv/hid/input/port/sgcn.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/srv/hid/input/port/sgcn.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2008 Pavel Rimsky
+ * 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 must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - 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.
+ */
+
+/** @addtogroup kbd_port
+ * @ingroup  kbd
+ * @{
+ */
+/** @file
+ * @brief SGCN (Serengeti Console) keyboard port driver.
+ */
+
+#include <as.h>
+#include <ddi.h>
+#include <async.h>
+#include <kbd.h>
+#include <kbd_port.h>
+#include <sysinfo.h>
+#include <stdio.h>
+#include <thread.h>
+#include <bool.h>
+#include <errno.h>
+
+#define POLL_INTERVAL  10000
+
+/**
+ * SGCN buffer header. It is placed at the very beginning of the SGCN
+ * buffer.
+ */
+typedef struct {
+	/** hard-wired to "CON" */
+	char magic[4];
+	
+	/** we don't need this */
+	char unused[8];
+	
+	/** offset within the SGCN buffer of the input buffer start */
+	uint32_t in_begin;
+	
+	/** offset within the SGCN buffer of the input buffer end */
+	uint32_t in_end;
+	
+	/** offset within the SGCN buffer of the input buffer read pointer */
+	uint32_t in_rdptr;
+	
+	/** offset within the SGCN buffer of the input buffer write pointer */
+	uint32_t in_wrptr;
+} __attribute__ ((packed)) sgcn_buffer_header_t;
+
+/*
+ * Returns a pointer to the object of a given type which is placed at the given
+ * offset from the console buffer beginning.
+ */
+#define SGCN_BUFFER(type, offset) \
+		((type *) (sram_virt_addr + sram_buffer_offset + (offset)))
+
+/** Returns a pointer to the console buffer header. */
+#define SGCN_BUFFER_HEADER	(SGCN_BUFFER(sgcn_buffer_header_t, 0))
+
+/**
+ * Virtual address mapped to SRAM.
+ */
+static uintptr_t sram_virt_addr;
+
+/**
+ * SGCN buffer offset within SGCN.
+ */
+static uintptr_t sram_buffer_offset;
+
+/* polling thread */
+static void sgcn_thread_impl(void *arg);
+
+static volatile bool polling_disabled = false;
+
+/**
+ * Initializes the SGCN driver.
+ * Maps the physical memory (SRAM) and creates the polling thread. 
+ */
+int kbd_port_init(void)
+{
+	sysarg_t sram_paddr;
+	if (sysinfo_get_value("sram.address.physical", &sram_paddr) != EOK)
+		return -1;
+	
+	sysarg_t sram_size;
+	if (sysinfo_get_value("sram.area.size", &sram_size) != EOK)
+		return -1;
+	
+	if (sysinfo_get_value("sram.buffer.offset", &sram_buffer_offset) != EOK)
+		sram_buffer_offset = 0;
+	
+	sram_virt_addr = (uintptr_t) as_get_mappable_page(sram_size);
+	
+	if (physmem_map((void *) sram_paddr, (void *) sram_virt_addr,
+	    sram_size / PAGE_SIZE, AS_AREA_READ | AS_AREA_WRITE) != 0) {
+		printf("SGCN: uspace driver could not map physical memory.");
+		return -1;
+	}
+	
+	thread_id_t tid;
+	int rc = thread_create(sgcn_thread_impl, NULL, "kbd_poll", &tid);
+	if (rc != 0)
+		return rc;
+	
+	return 0;
+}
+
+void kbd_port_yield(void)
+{
+	polling_disabled = true;
+}
+
+void kbd_port_reclaim(void)
+{
+	polling_disabled = false;
+}
+
+void kbd_port_write(uint8_t data)
+{
+	(void) data;
+}
+
+/**
+ * Handler of the "key pressed" event. Reads codes of all the pressed keys from
+ * the buffer. 
+ */
+static void sgcn_key_pressed(void)
+{
+	char c;
+	
+	uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
+	uint32_t end = SGCN_BUFFER_HEADER->in_end;
+	uint32_t size = end - begin;
+	
+	volatile char *buf_ptr = (volatile char *)
+		SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
+	volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
+	volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
+	
+	while (*in_rdptr_ptr != *in_wrptr_ptr) {
+		c = *buf_ptr;
+		*in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
+		buf_ptr = (volatile char *)
+			SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
+		kbd_push_scancode(c);
+	}
+}
+
+/**
+ * Thread to poll SGCN for keypresses.
+ */
+static void sgcn_thread_impl(void *arg)
+{
+	(void) arg;
+
+	while (1) {
+		if (polling_disabled == false)
+			sgcn_key_pressed();
+		usleep(POLL_INTERVAL);
+	}
+}
+
+/** @}
+ */
Index: uspace/srv/hid/input/port/z8530.c
===================================================================
--- uspace/srv/hid/input/port/z8530.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
+++ uspace/srv/hid/input/port/z8530.c	(revision 3e01316fd558e3235487a9cfe2a4fe29615ff69a)
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2006 Martin Decky
+ * 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 must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - 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.
+ */
+
+/** @addtogroup kbd_port
+ * @ingroup  kbd
+ * @{
+ */
+/** @file
+ * @brief Z8530 keyboard port driver.
+ */
+
+#include <ipc/irc.h>
+#include <async.h>
+#include <async_obsolete.h>
+#include <sysinfo.h>
+#include <kbd.h>
+#include <kbd_port.h>
+#include <sun.h>
+#include <sys/types.h>
+#include <ddi.h>
+#include <errno.h>
+
+#define CHAN_A_STATUS  4
+#define CHAN_A_DATA    6
+
+#define RR0_RCA  1
+
+static irq_cmd_t z8530_cmds[] = {
+	{
+		.cmd = CMD_PIO_READ_8,
+		.addr = (void *) 0,     /* Will be patched in run-time */
+		.dstarg = 1
+	},
+	{
+		.cmd = CMD_BTEST,
+		.value = RR0_RCA,
+		.srcarg = 1,
+		.dstarg = 3
+	},
+	{
+		.cmd = CMD_PREDICATE,
+		.value = 2,
+		.srcarg = 3
+	},
+	{
+		.cmd = CMD_PIO_READ_8,
+		.addr = (void *) 0,     /* Will be patched in run-time */
+		.dstarg = 2
+	},
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+	
+irq_code_t z8530_kbd = {
+	sizeof(z8530_cmds) / sizeof(irq_cmd_t),
+	z8530_cmds
+};
+
+static void z8530_irq_handler(ipc_callid_t iid, ipc_call_t *call);
+
+int z8530_port_init(void)
+{
+	sysarg_t kaddr;
+	if (sysinfo_get_value("kbd.address.kernel", &kaddr) != EOK)
+		return -1;
+	
+	sysarg_t inr;
+	if (sysinfo_get_value("kbd.inr", &inr) != EOK)
+		return -1;
+	
+	z8530_cmds[0].addr = (void *) kaddr + CHAN_A_STATUS;
+	z8530_cmds[3].addr = (void *) kaddr + CHAN_A_DATA;
+	
+	async_set_interrupt_received(z8530_irq_handler);
+	register_irq(inr, device_assign_devno(), inr, &z8530_kbd);
+	
+	return 0;
+}
+
+static void z8530_irq_handler(ipc_callid_t iid, ipc_call_t *call)
+{
+	int scan_code = IPC_GET_ARG2(*call);
+	kbd_push_scancode(scan_code);
+	
+	if (irc_service)
+		async_obsolete_msg_1(irc_phone, IRC_CLEAR_INTERRUPT,
+		    IPC_GET_IMETHOD(*call));
+}
+
+/** @}
+ */
