Add compiler source to new directory structure

SVN=121164
diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
new file mode 100644
index 0000000..47adbc8
--- /dev/null
+++ b/src/cmd/6a/a.h
@@ -0,0 +1,206 @@
+// Inferno utils/6a/a.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "../6l/6.out.h"
+#include "compat.h"
+
+
+#ifndef	EXTERN
+#define	EXTERN	extern
+#endif
+
+typedef	struct	Sym	Sym;
+typedef	struct	Ref	Ref;
+typedef	struct	Gen	Gen;
+typedef	struct	Io	Io;
+typedef	struct	Hist	Hist;
+typedef	struct	Gen2 	Gen2;
+
+#define	MAXALIGN	7
+#define	FPCHIP		1
+#define	NSYMB		500
+#define	BUFSIZ		8192
+#define	HISTSZ		20
+#define	NINCLUDE	10
+#define	NHUNK		10000
+#define	EOF		(-1)
+#define	IGN		(-2)
+#define	GETC()		((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define	NHASH		503
+#define	STRINGSZ	200
+#define	NMACRO		10
+
+struct	Sym
+{
+	Sym*	link;
+	Ref*	ref;
+	char*	macro;
+	vlong	value;
+	ushort	type;
+	char	*name;
+	char	sym;
+};
+#define	S	((Sym*)0)
+
+struct	Ref
+{
+	int	class;
+};
+
+EXTERN struct
+{
+	char*	p;
+	int	c;
+} fi;
+
+struct	Io
+{
+	Io*	link;
+	char	b[BUFSIZ];
+	char*	p;
+	short	c;
+	short	f;
+};
+#define	I	((Io*)0)
+
+EXTERN struct
+{
+	Sym*	sym;
+	short	type;
+} h[NSYM];
+
+struct	Gen
+{
+	double	dval;
+	char	sval[8];
+	vlong	offset;
+	Sym*	sym;
+	short	type;
+	short	index;
+	short	scale;
+};
+struct	Gen2
+{
+	Gen	from;
+	Gen	to;
+};
+
+struct	Hist
+{
+	Hist*	link;
+	char*	name;
+	long	line;
+	vlong	offset;
+};
+#define	H	((Hist*)0)
+
+enum
+{
+	CLAST,
+	CMACARG,
+	CMACRO,
+	CPREPROC,
+};
+
+
+EXTERN	char	debug[256];
+EXTERN	Sym*	hash[NHASH];
+EXTERN	char*	Dlist[30];
+EXTERN	int	nDlist;
+EXTERN	Hist*	ehist;
+EXTERN	int	newflag;
+EXTERN	Hist*	hist;
+EXTERN	char*	hunk;
+EXTERN	char*	include[NINCLUDE];
+EXTERN	Io*	iofree;
+EXTERN	Io*	ionext;
+EXTERN	Io*	iostack;
+EXTERN	long	lineno;
+EXTERN	int	nerrors;
+EXTERN	long	nhunk;
+EXTERN	int	ninclude;
+EXTERN	Gen	nullgen;
+EXTERN	char*	outfile;
+EXTERN	int	pass;
+EXTERN	char*	pathname;
+EXTERN	long	pc;
+EXTERN	int	peekc;
+EXTERN	int	sym;
+EXTERN	char	symb[NSYMB];
+EXTERN	int	thechar;
+EXTERN	char*	thestring;
+EXTERN	long	thunk;
+EXTERN	Biobuf	obuf;
+
+void*	allocn(void*, long, long);
+void	errorexit(void);
+void	pushio(void);
+void	newio(void);
+void	newfile(char*, int);
+Sym*	slookup(char*);
+Sym*	lookup(void);
+void	syminit(Sym*);
+long	yylex(void);
+int	getc(void);
+int	getnsc(void);
+void	unget(int);
+int	escchar(int);
+void	cinit(void);
+void	checkscale(int);
+void	pinit(char*);
+void	cclean(void);
+int	isreg(Gen*);
+void	outcode(int, Gen2*);
+void	outhist(void);
+void	zaddr(Gen*, int);
+void	zname(char*, int, int);
+void	ieeedtod(Ieee*, double);
+int	filbuf(void);
+Sym*	getsym(void);
+void	domacro(void);
+void	macund(void);
+void	macdef(void);
+void	macexpand(Sym*, char*);
+void	macinc(void);
+void	macprag(void);
+void	maclin(void);
+void	macif(int);
+void	macend(void);
+void	dodefine(char*);
+void	prfile(long);
+void	linehist(char*, int);
+void	gethunk(void);
+void	yyerror(char*, ...);
+int	yyparse(void);
+void	setinclude(char*);
+int	assemble(char*);
diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y
new file mode 100644
index 0000000..698e73e
--- /dev/null
+++ b/src/cmd/6a/a.y
@@ -0,0 +1,592 @@
+// Inferno utils/6a/a.y
+// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.y
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+%{
+#include "a.h"
+%}
+%union	{
+	Sym	*sym;
+	vlong	lval;
+	double	dval;
+	char	sval[8];
+	Gen	gen;
+	Gen2	gen2;
+}
+%left	'|'
+%left	'^'
+%left	'&'
+%left	'<' '>'
+%left	'+' '-'
+%left	'*' '/' '%'
+%token	<lval>	LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
+%token	<lval>	LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEXC LTYPEX LTYPERT
+%token	<lval>	LCONST LFP LPC LSB
+%token	<lval>	LBREG LLREG LSREG LFREG LMREG LXREG
+%token	<dval>	LFCONST
+%token	<sval>	LSCONST LSP
+%token	<sym>	LNAME LLAB LVAR
+%type	<lval>	con expr pointer offset
+%type	<gen>	mem imm reg nam rel rem rim rom omem nmem
+%type	<gen2>	nonnon nonrel nonrem rimnon rimrem remrim spec10
+%type	<gen2>	spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
+%%
+prog:
+|	prog line
+
+line:
+	LLAB ':'
+	{
+		if($1->value != pc)
+			yyerror("redeclaration of %s", $1->name);
+		$1->value = pc;
+	}
+	line
+|	LNAME ':'
+	{
+		$1->type = LLAB;
+		$1->value = pc;
+	}
+	line
+|	';'
+|	inst ';'
+|	error ';'
+
+inst:
+	LNAME '=' expr
+	{
+		$1->type = LVAR;
+		$1->value = $3;
+	}
+|	LVAR '=' expr
+	{
+		if($1->value != $3)
+			yyerror("redeclaration of %s", $1->name);
+		$1->value = $3;
+	}
+|	LTYPE0 nonnon	{ outcode($1, &$2); }
+|	LTYPE1 nonrem	{ outcode($1, &$2); }
+|	LTYPE2 rimnon	{ outcode($1, &$2); }
+|	LTYPE3 rimrem	{ outcode($1, &$2); }
+|	LTYPE4 remrim	{ outcode($1, &$2); }
+|	LTYPER nonrel	{ outcode($1, &$2); }
+|	LTYPED spec1	{ outcode($1, &$2); }
+|	LTYPET spec2	{ outcode($1, &$2); }
+|	LTYPEC spec3	{ outcode($1, &$2); }
+|	LTYPEN spec4	{ outcode($1, &$2); }
+|	LTYPES spec5	{ outcode($1, &$2); }
+|	LTYPEM spec6	{ outcode($1, &$2); }
+|	LTYPEI spec7	{ outcode($1, &$2); }
+|	LTYPEXC spec8	{ outcode($1, &$2); }
+|	LTYPEX spec9	{ outcode($1, &$2); }
+|	LTYPERT spec10	{ outcode($1, &$2); }
+
+nonnon:
+	{
+		$$.from = nullgen;
+		$$.to = nullgen;
+	}
+|	','
+	{
+		$$.from = nullgen;
+		$$.to = nullgen;
+	}
+
+rimrem:
+	rim ',' rem
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+remrim:
+	rem ',' rim
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+rimnon:
+	rim ','
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+|	rim
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+
+nonrem:
+	',' rem
+	{
+		$$.from = nullgen;
+		$$.to = $2;
+	}
+|	rem
+	{
+		$$.from = nullgen;
+		$$.to = $1;
+	}
+
+nonrel:
+	',' rel
+	{
+		$$.from = nullgen;
+		$$.to = $2;
+	}
+|	rel
+	{
+		$$.from = nullgen;
+		$$.to = $1;
+	}
+
+spec1:	/* DATA */
+	nam '/' con ',' imm
+	{
+		$$.from = $1;
+		$$.from.scale = $3;
+		$$.to = $5;
+	}
+
+spec2:	/* TEXT */
+	mem ',' imm
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+|	mem ',' con ',' imm
+	{
+		$$.from = $1;
+		$$.from.scale = $3;
+		$$.to = $5;
+	}
+
+spec3:	/* JMP/CALL */
+	',' rom
+	{
+		$$.from = nullgen;
+		$$.to = $2;
+	}
+|	rom
+	{
+		$$.from = nullgen;
+		$$.to = $1;
+	}
+
+spec4:	/* NOP */
+	nonnon
+|	nonrem
+
+spec5:	/* SHL/SHR */
+	rim ',' rem
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+|	rim ',' rem ':' LLREG
+	{
+		$$.from = $1;
+		$$.to = $3;
+		if($$.from.index != D_NONE)
+			yyerror("dp shift with lhs index");
+		$$.from.index = $5;
+	}
+
+spec6:	/* MOVW/MOVL */
+	rim ',' rem
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+|	rim ',' rem ':' LSREG
+	{
+		$$.from = $1;
+		$$.to = $3;
+		if($$.to.index != D_NONE)
+			yyerror("dp move with lhs index");
+		$$.to.index = $5;
+	}
+
+spec7:
+	rim ','
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+|	rim
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+|	rim ',' rem
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+spec8:	/* CMPPS/CMPPD */
+	reg ',' rem ',' con
+	{
+		$$.from = $1;
+		$$.to = $3;
+		$$.from.offset = $5;
+	}
+
+spec9:	/* shufl */
+	imm ',' rem ',' reg
+	{
+		$$.from = $3;
+		$$.to = $5;
+		if($1.type != D_CONST)
+			yyerror("illegal constant");
+		$$.to.offset = $1.offset;
+	}
+
+spec10:	/* RET/RETF */
+	{
+		$$.from = nullgen;
+		$$.to = nullgen;
+	}
+|	imm
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+
+rem:
+	reg
+|	mem
+
+rom:
+	rel
+|	nmem
+|	'*' reg
+	{
+		$$ = $2;
+	}
+|	'*' omem
+	{
+		$$ = $2;
+	}
+|	reg
+|	omem
+
+rim:
+	rem
+|	imm
+
+rel:
+	con '(' LPC ')'
+	{
+		$$ = nullgen;
+		$$.type = D_BRANCH;
+		$$.offset = $1 + pc;
+	}
+|	LNAME offset
+	{
+		$$ = nullgen;
+		if(pass == 2)
+			yyerror("undefined label: %s", $1->name);
+		$$.type = D_BRANCH;
+		$$.sym = $1;
+		$$.offset = $2;
+	}
+|	LLAB offset
+	{
+		$$ = nullgen;
+		$$.type = D_BRANCH;
+		$$.sym = $1;
+		$$.offset = $1->value + $2;
+	}
+
+reg:
+	LBREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LFREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LLREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LMREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LSP
+	{
+		$$ = nullgen;
+		$$.type = D_SP;
+	}
+|	LSREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LXREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+
+imm:
+	'$' con
+	{
+		$$ = nullgen;
+		$$.type = D_CONST;
+		$$.offset = $2;
+	}
+|	'$' nam
+	{
+		$$ = $2;
+		$$.index = $2.type;
+		$$.type = D_ADDR;
+		/*
+		if($2.type == D_AUTO || $2.type == D_PARAM)
+			yyerror("constant cannot be automatic: %s",
+				$2.sym->name);
+		 */
+	}
+|	'$' LSCONST
+	{
+		$$ = nullgen;
+		$$.type = D_SCONST;
+		memcpy($$.sval, $2, sizeof($$.sval));
+	}
+|	'$' LFCONST
+	{
+		$$ = nullgen;
+		$$.type = D_FCONST;
+		$$.dval = $2;
+	}
+|	'$' '(' LFCONST ')'
+	{
+		$$ = nullgen;
+		$$.type = D_FCONST;
+		$$.dval = $3;
+	}
+|	'$' '-' LFCONST
+	{
+		$$ = nullgen;
+		$$.type = D_FCONST;
+		$$.dval = -$3;
+	}
+
+mem:
+	omem
+|	nmem
+
+omem:
+	con
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_NONE;
+		$$.offset = $1;
+	}
+|	con '(' LLREG ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$3;
+		$$.offset = $1;
+	}
+|	con '(' LSP ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_SP;
+		$$.offset = $1;
+	}
+|	con '(' LLREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_NONE;
+		$$.offset = $1;
+		$$.index = $3;
+		$$.scale = $5;
+		checkscale($$.scale);
+	}
+|	con '(' LLREG ')' '(' LLREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$3;
+		$$.offset = $1;
+		$$.index = $6;
+		$$.scale = $8;
+		checkscale($$.scale);
+	}
+|	'(' LLREG ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$2;
+	}
+|	'(' LSP ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_SP;
+	}
+|	'(' LLREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_NONE;
+		$$.index = $2;
+		$$.scale = $4;
+		checkscale($$.scale);
+	}
+|	'(' LLREG ')' '(' LLREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$2;
+		$$.index = $5;
+		$$.scale = $7;
+		checkscale($$.scale);
+	}
+
+nmem:
+	nam
+	{
+		$$ = $1;
+	}
+|	nam '(' LLREG '*' con ')'
+	{
+		$$ = $1;
+		$$.index = $3;
+		$$.scale = $5;
+		checkscale($$.scale);
+	}
+
+nam:
+	LNAME offset '(' pointer ')'
+	{
+		$$ = nullgen;
+		$$.type = $4;
+		$$.sym = $1;
+		$$.offset = $2;
+	}
+|	LNAME '<' '>' offset '(' LSB ')'
+	{
+		$$ = nullgen;
+		$$.type = D_STATIC;
+		$$.sym = $1;
+		$$.offset = $4;
+	}
+
+offset:
+	{
+		$$ = 0;
+	}
+|	'+' con
+	{
+		$$ = $2;
+	}
+|	'-' con
+	{
+		$$ = -$2;
+	}
+
+pointer:
+	LSB
+|	LSP
+	{
+		$$ = D_AUTO;
+	}
+|	LFP
+
+con:
+	LCONST
+|	LVAR
+	{
+		$$ = $1->value;
+	}
+|	'-' con
+	{
+		$$ = -$2;
+	}
+|	'+' con
+	{
+		$$ = $2;
+	}
+|	'~' con
+	{
+		$$ = ~$2;
+	}
+|	'(' expr ')'
+	{
+		$$ = $2;
+	}
+
+expr:
+	con
+|	expr '+' expr
+	{
+		$$ = $1 + $3;
+	}
+|	expr '-' expr
+	{
+		$$ = $1 - $3;
+	}
+|	expr '*' expr
+	{
+		$$ = $1 * $3;
+	}
+|	expr '/' expr
+	{
+		$$ = $1 / $3;
+	}
+|	expr '%' expr
+	{
+		$$ = $1 % $3;
+	}
+|	expr '<' '<' expr
+	{
+		$$ = $1 << $4;
+	}
+|	expr '>' '>' expr
+	{
+		$$ = $1 >> $4;
+	}
+|	expr '&' expr
+	{
+		$$ = $1 & $3;
+	}
+|	expr '^' expr
+	{
+		$$ = $1 ^ $3;
+	}
+|	expr '|' expr
+	{
+		$$ = $1 | $3;
+	}
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
new file mode 100644
index 0000000..ff0a0d5
--- /dev/null
+++ b/src/cmd/6a/lex.c
@@ -0,0 +1,1337 @@
+// Inferno utils/6a/lex.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#define	EXTERN
+#include "a.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+void
+main(int argc, char *argv[])
+{
+	char *p;
+	int nout, nproc, status, i, c;
+
+	thechar = '6';
+	thestring = "amd64";
+	memset(debug, 0, sizeof(debug));
+	cinit();
+	outfile = 0;
+	include[ninclude++] = ".";
+	ARGBEGIN {
+	default:
+		c = ARGC();
+		if(c >= 0 || c < sizeof(debug))
+			debug[c] = 1;
+		break;
+
+	case 'o':
+		outfile = ARGF();
+		break;
+
+	case 'D':
+		p = ARGF();
+		if(p)
+			Dlist[nDlist++] = p;
+		break;
+
+	case 'I':
+		p = ARGF();
+		setinclude(p);
+		break;
+	} ARGEND
+	if(*argv == 0) {
+		print("usage: %ca [-options] file.s\n", thechar);
+		errorexit();
+	}
+	if(argc > 1 && systemtype(Windows)){
+		print("can't assemble multiple files on windows\n");
+		errorexit();
+	}
+	if(argc > 1 && !systemtype(Windows)) {
+		nproc = 1;
+		if(p = getenv("NPROC"))
+			nproc = atol(p);	/* */
+		c = 0;
+		nout = 0;
+		for(;;) {
+			while(nout < nproc && argc > 0) {
+				i = myfork();
+				if(i < 0) {
+					i = mywait(&status);
+					if(i < 0)
+						errorexit();
+					if(status)
+						c++;
+					nout--;
+					continue;
+				}
+				if(i == 0) {
+					print("%s:\n", *argv);
+					if(assemble(*argv))
+						errorexit();
+					exits(0);
+				}
+				nout++;
+				argc--;
+				argv++;
+			}
+			i = mywait(&status);
+			if(i < 0) {
+				if(c)
+					errorexit();
+				exits(0);
+			}
+			if(status)
+				c++;
+			nout--;
+		}
+	}
+	if(assemble(argv[0]))
+		errorexit();
+	exits(0);
+}
+
+int
+assemble(char *file)
+{
+	char ofile[100], incfile[20], *p;
+	int i, of;
+
+	strcpy(ofile, file);
+	p = utfrrune(ofile, pathchar());
+	if(p) {
+		include[0] = ofile;
+		*p++ = 0;
+	} else
+		p = ofile;
+	if(outfile == 0) {
+		outfile = p;
+		if(outfile){
+			p = utfrrune(outfile, '.');
+			if(p)
+				if(p[1] == 's' && p[2] == 0)
+					p[0] = 0;
+			p = utfrune(outfile, 0);
+			p[0] = '.';
+			p[1] = thechar;
+			p[2] = 0;
+		} else
+			outfile = "/dev/null";
+	}
+	p = getenv("INCLUDE");
+	if(p) {
+		setinclude(p);
+	} else {
+		if(systemtype(Plan9)) {
+			sprint(incfile,"/%s/include", thestring);
+			setinclude(strdup(incfile));
+		}
+	}
+
+	of = mycreate(outfile, 0664);
+	if(of < 0) {
+		yyerror("%ca: cannot create %s", thechar, outfile);
+		errorexit();
+	}
+	Binit(&obuf, of, OWRITE);
+
+	pass = 1;
+	pinit(file);
+
+	Bprint(&obuf, "x86-64\n");
+
+	for(i=0; i<nDlist; i++)
+		dodefine(Dlist[i]);
+	yyparse();
+	if(nerrors) {
+		cclean();
+		return nerrors;
+	}
+
+	Bprint(&obuf, "\n!\n");
+
+	pass = 2;
+	outhist();
+	pinit(file);
+	for(i=0; i<nDlist; i++)
+		dodefine(Dlist[i]);
+	yyparse();
+	cclean();
+	return nerrors;
+}
+
+struct
+{
+	char	*name;
+	ushort	type;
+	ushort	value;
+} itab[] =
+{
+	"SP",		LSP,	D_AUTO,
+	"SB",		LSB,	D_EXTERN,
+	"FP",		LFP,	D_PARAM,
+	"PC",		LPC,	D_BRANCH,
+
+	"AL",		LBREG,	D_AL,
+	"CL",		LBREG,	D_CL,
+	"DL",		LBREG,	D_DL,
+	"BL",		LBREG,	D_BL,
+/*	"SPB",		LBREG,	D_SPB,	*/
+	"SIB",		LBREG,	D_SIB,
+	"DIB",		LBREG,	D_DIB,
+	"BPB",		LBREG,	D_BPB,
+	"R8B",		LBREG,	D_R8B,
+	"R9B",		LBREG,	D_R9B,
+	"R10B",		LBREG,	D_R10B,
+	"R11B",		LBREG,	D_R11B,
+	"R12B",		LBREG,	D_R12B,
+	"R13B",		LBREG,	D_R13B,
+	"R14B",		LBREG,	D_R14B,
+	"R15B",		LBREG,	D_R15B,
+
+	"AH",		LBREG,	D_AH,
+	"CH",		LBREG,	D_CH,
+	"DH",		LBREG,	D_DH,
+	"BH",		LBREG,	D_BH,
+
+	"AX",		LLREG,	D_AX,
+	"CX",		LLREG,	D_CX,
+	"DX",		LLREG,	D_DX,
+	"BX",		LLREG,	D_BX,
+/*	"SP",		LLREG,	D_SP,	*/
+	"BP",		LLREG,	D_BP,
+	"SI",		LLREG,	D_SI,
+	"DI",		LLREG,	D_DI,
+	"R8",		LLREG,	D_R8,
+	"R9",		LLREG,	D_R9,
+	"R10",		LLREG,	D_R10,
+	"R11",		LLREG,	D_R11,
+	"R12",		LLREG,	D_R12,
+	"R13",		LLREG,	D_R13,
+	"R14",		LLREG,	D_R14,
+	"R15",		LLREG,	D_R15,
+
+	"RARG",		LLREG,	REGARG,
+
+	"F0",		LFREG,	D_F0+0,
+	"F1",		LFREG,	D_F0+1,
+	"F2",		LFREG,	D_F0+2,
+	"F3",		LFREG,	D_F0+3,
+	"F4",		LFREG,	D_F0+4,
+	"F5",		LFREG,	D_F0+5,
+	"F6",		LFREG,	D_F0+6,
+	"F7",		LFREG,	D_F0+7,
+
+	"M0",		LMREG,	D_M0+0,
+	"M1",		LMREG,	D_M0+1,
+	"M2",		LMREG,	D_M0+2,
+	"M3",		LMREG,	D_M0+3,
+	"M4",		LMREG,	D_M0+4,
+	"M5",		LMREG,	D_M0+5,
+	"M6",		LMREG,	D_M0+6,
+	"M7",		LMREG,	D_M0+7,
+
+	"X0",		LXREG,	D_X0+0,
+	"X1",		LXREG,	D_X0+1,
+	"X2",		LXREG,	D_X0+2,
+	"X3",		LXREG,	D_X0+3,
+	"X4",		LXREG,	D_X0+4,
+	"X5",		LXREG,	D_X0+5,
+	"X6",		LXREG,	D_X0+6,
+	"X7",		LXREG,	D_X0+7,
+	"X8",		LXREG,	D_X0+8,
+	"X9",		LXREG,	D_X0+9,
+	"X10",		LXREG,	D_X0+10,
+	"X11",		LXREG,	D_X0+11,
+	"X12",		LXREG,	D_X0+12,
+	"X13",		LXREG,	D_X0+13,
+	"X14",		LXREG,	D_X0+14,
+	"X15",		LXREG,	D_X0+15,
+
+	"CS",		LSREG,	D_CS,
+	"SS",		LSREG,	D_SS,
+	"DS",		LSREG,	D_DS,
+	"ES",		LSREG,	D_ES,
+	"FS",		LSREG,	D_FS,
+	"GS",		LSREG,	D_GS,
+
+	"GDTR",		LBREG,	D_GDTR,
+	"IDTR",		LBREG,	D_IDTR,
+	"LDTR",		LBREG,	D_LDTR,
+	"MSW",		LBREG,	D_MSW,
+	"TASK",		LBREG,	D_TASK,
+
+	"CR0",		LBREG,	D_CR+0,
+	"CR1",		LBREG,	D_CR+1,
+	"CR2",		LBREG,	D_CR+2,
+	"CR3",		LBREG,	D_CR+3,
+	"CR4",		LBREG,	D_CR+4,
+	"CR5",		LBREG,	D_CR+5,
+	"CR6",		LBREG,	D_CR+6,
+	"CR7",		LBREG,	D_CR+7,
+	"CR8",		LBREG,	D_CR+8,
+	"CR9",		LBREG,	D_CR+9,
+	"CR10",		LBREG,	D_CR+10,
+	"CR11",		LBREG,	D_CR+11,
+	"CR12",		LBREG,	D_CR+12,
+	"CR13",		LBREG,	D_CR+13,
+	"CR14",		LBREG,	D_CR+14,
+	"CR15",		LBREG,	D_CR+15,
+
+	"DR0",		LBREG,	D_DR+0,
+	"DR1",		LBREG,	D_DR+1,
+	"DR2",		LBREG,	D_DR+2,
+	"DR3",		LBREG,	D_DR+3,
+	"DR4",		LBREG,	D_DR+4,
+	"DR5",		LBREG,	D_DR+5,
+	"DR6",		LBREG,	D_DR+6,
+	"DR7",		LBREG,	D_DR+7,
+
+	"TR0",		LBREG,	D_TR+0,
+	"TR1",		LBREG,	D_TR+1,
+	"TR2",		LBREG,	D_TR+2,
+	"TR3",		LBREG,	D_TR+3,
+	"TR4",		LBREG,	D_TR+4,
+	"TR5",		LBREG,	D_TR+5,
+	"TR6",		LBREG,	D_TR+6,
+	"TR7",		LBREG,	D_TR+7,
+
+	"AAA",		LTYPE0,	AAAA,
+	"AAD",		LTYPE0,	AAAD,
+	"AAM",		LTYPE0,	AAAM,
+	"AAS",		LTYPE0,	AAAS,
+	"ADCB",		LTYPE3,	AADCB,
+	"ADCL",		LTYPE3,	AADCL,
+	"ADCQ",		LTYPE3,	AADCQ,
+	"ADCW",		LTYPE3,	AADCW,
+	"ADDB",		LTYPE3,	AADDB,
+	"ADDL",		LTYPE3,	AADDL,
+	"ADDQ",		LTYPE3,	AADDQ,
+	"ADDW",		LTYPE3,	AADDW,
+	"ADJSP",	LTYPE2,	AADJSP,
+	"ANDB",		LTYPE3,	AANDB,
+	"ANDL",		LTYPE3,	AANDL,
+	"ANDQ",		LTYPE3,	AANDQ,
+	"ANDW",		LTYPE3,	AANDW,
+	"ARPL",		LTYPE3,	AARPL,
+	"BOUNDL",	LTYPE3,	ABOUNDL,
+	"BOUNDW",	LTYPE3,	ABOUNDW,
+	"BSFL",		LTYPE3,	ABSFL,
+	"BSFQ",		LTYPE3,	ABSFQ,
+	"BSFW",		LTYPE3,	ABSFW,
+	"BSRL",		LTYPE3,	ABSRL,
+	"BSRQ",		LTYPE3,	ABSRQ,
+	"BSRW",		LTYPE3,	ABSRW,
+	"BTCL",		LTYPE3,	ABTCL,
+	"BTCQ",		LTYPE3,	ABTCQ,
+	"BTCW",		LTYPE3,	ABTCW,
+	"BTL",		LTYPE3,	ABTL,
+	"BTQ",		LTYPE3,	ABTQ,
+	"BTRL",		LTYPE3,	ABTRL,
+	"BTRQ",		LTYPE3,	ABTRQ,
+	"BTRW",		LTYPE3,	ABTRW,
+	"BTSL",		LTYPE3,	ABTSL,
+	"BTSQ",		LTYPE3,	ABTSQ,
+	"BTSW",		LTYPE3,	ABTSW,
+	"BTW",		LTYPE3,	ABTW,
+	"BYTE",		LTYPE2,	ABYTE,
+	"CALL",		LTYPEC,	ACALL,
+	"CLC",		LTYPE0,	ACLC,
+	"CLD",		LTYPE0,	ACLD,
+	"CLI",		LTYPE0,	ACLI,
+	"CLTS",		LTYPE0,	ACLTS,
+	"CMC",		LTYPE0,	ACMC,
+	"CMPB",		LTYPE4,	ACMPB,
+	"CMPL",		LTYPE4,	ACMPL,
+	"CMPQ",		LTYPE4,	ACMPQ,
+	"CMPW",		LTYPE4,	ACMPW,
+	"CMPSB",	LTYPE0,	ACMPSB,
+	"CMPSL",	LTYPE0,	ACMPSL,
+	"CMPSQ",	LTYPE0,	ACMPSQ,
+	"CMPSW",	LTYPE0,	ACMPSW,
+	"CMPXCHG8B",	LTYPE1,	ACMPXCHG8B,
+	"CMPXCHGB",	LTYPE3,	ACMPXCHGB,	/* LTYPE3? */
+	"CMPXCHGL",	LTYPE3,	ACMPXCHGL,
+	"CMPXCHGQ",	LTYPE3,	ACMPXCHGQ,
+	"CMPXCHGW",	LTYPE3,	ACMPXCHGW,
+	"CPUID",	LTYPE0,	ACPUID,
+	"DAA",		LTYPE0,	ADAA,
+	"DAS",		LTYPE0,	ADAS,
+	"DATA",		LTYPED,	ADATA,
+	"DECB",		LTYPE1,	ADECB,
+	"DECL",		LTYPE1,	ADECL,
+	"DECQ",		LTYPE1,	ADECQ,
+	"DECW",		LTYPE1,	ADECW,
+	"DIVB",		LTYPE2,	ADIVB,
+	"DIVL",		LTYPE2,	ADIVL,
+	"DIVQ",		LTYPE2,	ADIVQ,
+	"DIVW",		LTYPE2,	ADIVW,
+	"EMMS",		LTYPE0,	AEMMS,
+	"END",		LTYPE0,	AEND,
+	"ENTER",	LTYPE2,	AENTER,
+	"GLOBL",	LTYPET,	AGLOBL,
+	"HLT",		LTYPE0,	AHLT,
+	"IDIVB",	LTYPE2,	AIDIVB,
+	"IDIVL",	LTYPE2,	AIDIVL,
+	"IDIVQ",	LTYPE2,	AIDIVQ,
+	"IDIVW",	LTYPE2,	AIDIVW,
+	"IMULB",	LTYPEI,	AIMULB,
+	"IMULL",	LTYPEI,	AIMULL,
+	"IMULQ",	LTYPEI,	AIMULQ,
+	"IMULW",	LTYPEI,	AIMULW,
+	"INB",		LTYPE0,	AINB,
+	"INL",		LTYPE0,	AINL,
+	"INW",		LTYPE0,	AINW,
+	"INCB",		LTYPE1,	AINCB,
+	"INCL",		LTYPE1,	AINCL,
+	"INCQ",		LTYPE1,	AINCQ,
+	"INCW",		LTYPE1,	AINCW,
+	"INSB",		LTYPE0,	AINSB,
+	"INSL",		LTYPE0,	AINSL,
+	"INSW",		LTYPE0,	AINSW,
+	"INT",		LTYPE2,	AINT,
+	"INTO",		LTYPE0,	AINTO,
+	"INVD",		LTYPE0,	AINVD,
+	"INVLPG",	LTYPE2,	AINVLPG,
+	"IRETL",	LTYPE0,	AIRETL,
+	"IRETQ",	LTYPE0,	AIRETQ,
+	"IRETW",	LTYPE0,	AIRETW,
+
+	"JOS",		LTYPER,	AJOS,
+	"JO",		LTYPER,	AJOS,	/* alternate */
+	"JOC",		LTYPER,	AJOC,
+	"JNO",		LTYPER,	AJOC,	/* alternate */
+	"JCS",		LTYPER,	AJCS,
+	"JB",		LTYPER,	AJCS,	/* alternate */
+	"JC",		LTYPER,	AJCS,	/* alternate */
+	"JNAE",		LTYPER,	AJCS,	/* alternate */
+	"JLO",		LTYPER,	AJCS,	/* alternate */
+	"JCC",		LTYPER,	AJCC,
+	"JAE",		LTYPER,	AJCC,	/* alternate */
+	"JNB",		LTYPER,	AJCC,	/* alternate */
+	"JNC",		LTYPER,	AJCC,	/* alternate */
+	"JHS",		LTYPER,	AJCC,	/* alternate */
+	"JEQ",		LTYPER,	AJEQ,
+	"JE",		LTYPER,	AJEQ,	/* alternate */
+	"JZ",		LTYPER,	AJEQ,	/* alternate */
+	"JNE",		LTYPER,	AJNE,
+	"JNZ",		LTYPER,	AJNE,	/* alternate */
+	"JLS",		LTYPER,	AJLS,
+	"JBE",		LTYPER,	AJLS,	/* alternate */
+	"JNA",		LTYPER,	AJLS,	/* alternate */
+	"JHI",		LTYPER,	AJHI,
+	"JA",		LTYPER,	AJHI,	/* alternate */
+	"JNBE",		LTYPER,	AJHI,	/* alternate */
+	"JMI",		LTYPER,	AJMI,
+	"JS",		LTYPER,	AJMI,	/* alternate */
+	"JPL",		LTYPER,	AJPL,
+	"JNS",		LTYPER,	AJPL,	/* alternate */
+	"JPS",		LTYPER,	AJPS,
+	"JP",		LTYPER,	AJPS,	/* alternate */
+	"JPE",		LTYPER,	AJPS,	/* alternate */
+	"JPC",		LTYPER,	AJPC,
+	"JNP",		LTYPER,	AJPC,	/* alternate */
+	"JPO",		LTYPER,	AJPC,	/* alternate */
+	"JLT",		LTYPER,	AJLT,
+	"JL",		LTYPER,	AJLT,	/* alternate */
+	"JNGE",		LTYPER,	AJLT,	/* alternate */
+	"JGE",		LTYPER,	AJGE,
+	"JNL",		LTYPER,	AJGE,	/* alternate */
+	"JLE",		LTYPER,	AJLE,
+	"JNG",		LTYPER,	AJLE,	/* alternate */
+	"JGT",		LTYPER,	AJGT,
+	"JG",		LTYPER,	AJGT,	/* alternate */
+	"JNLE",		LTYPER,	AJGT,	/* alternate */
+
+	"JCXZ",		LTYPER,	AJCXZ,
+	"JMP",		LTYPEC,	AJMP,
+	"LAHF",		LTYPE0,	ALAHF,
+	"LARL",		LTYPE3,	ALARL,
+	"LARW",		LTYPE3,	ALARW,
+	"LEAL",		LTYPE3,	ALEAL,
+	"LEAQ",		LTYPE3,	ALEAQ,
+	"LEAW",		LTYPE3,	ALEAW,
+	"LEAVEL",	LTYPE0,	ALEAVEL,
+	"LEAVEQ",	LTYPE0,	ALEAVEQ,
+	"LEAVEW",	LTYPE0,	ALEAVEW,
+	"LFENCE",	LTYPE0,	ALFENCE,
+	"LOCK",		LTYPE0,	ALOCK,
+	"LODSB",	LTYPE0,	ALODSB,
+	"LODSL",	LTYPE0,	ALODSL,
+	"LODSQ",	LTYPE0,	ALODSQ,
+	"LODSW",	LTYPE0,	ALODSW,
+	"LONG",		LTYPE2,	ALONG,
+	"LOOP",		LTYPER,	ALOOP,
+	"LOOPEQ",	LTYPER,	ALOOPEQ,
+	"LOOPNE",	LTYPER,	ALOOPNE,
+	"LSLL",		LTYPE3,	ALSLL,
+	"LSLW",		LTYPE3,	ALSLW,
+	"MFENCE",	LTYPE0,	AMFENCE,
+	"MODE",		LTYPE2,	AMODE,
+	"MOVB",		LTYPE3,	AMOVB,
+	"MOVL",		LTYPEM,	AMOVL,
+	"MOVQ",		LTYPEM,	AMOVQ,
+	"MOVW",		LTYPEM,	AMOVW,
+	"MOVBLSX",	LTYPE3, AMOVBLSX,
+	"MOVBLZX",	LTYPE3, AMOVBLZX,
+	"MOVBQSX",	LTYPE3,	AMOVBQSX,
+	"MOVBQZX",	LTYPE3,	AMOVBQZX,
+	"MOVBWSX",	LTYPE3, AMOVBWSX,
+	"MOVBWZX",	LTYPE3, AMOVBWZX,
+	"MOVLQSX",	LTYPE3, AMOVLQSX,
+	"MOVLQZX",	LTYPE3, AMOVLQZX,
+	"MOVNTIL",	LTYPE3,	AMOVNTIL,
+	"MOVNTIQ",	LTYPE3,	AMOVNTIQ,
+	"MOVWLSX",	LTYPE3, AMOVWLSX,
+	"MOVWLZX",	LTYPE3, AMOVWLZX,
+	"MOVWQSX",	LTYPE3,	AMOVWQSX,
+	"MOVWQZX",	LTYPE3,	AMOVWQZX,
+	"MOVSB",	LTYPE0,	AMOVSB,
+	"MOVSL",	LTYPE0,	AMOVSL,
+	"MOVSQ",	LTYPE0,	AMOVSQ,
+	"MOVSW",	LTYPE0,	AMOVSW,
+	"MULB",		LTYPE2,	AMULB,
+	"MULL",		LTYPE2,	AMULL,
+	"MULQ",		LTYPE2,	AMULQ,
+	"MULW",		LTYPE2,	AMULW,
+	"NEGB",		LTYPE1,	ANEGB,
+	"NEGL",		LTYPE1,	ANEGL,
+	"NEGQ",		LTYPE1,	ANEGQ,
+	"NEGW",		LTYPE1,	ANEGW,
+	"NOP",		LTYPEN,	ANOP,
+	"NOTB",		LTYPE1,	ANOTB,
+	"NOTL",		LTYPE1,	ANOTL,
+	"NOTQ",		LTYPE1,	ANOTQ,
+	"NOTW",		LTYPE1,	ANOTW,
+	"ORB",		LTYPE3,	AORB,
+	"ORL",		LTYPE3,	AORL,
+	"ORQ",		LTYPE3,	AORQ,
+	"ORW",		LTYPE3,	AORW,
+	"OUTB",		LTYPE0,	AOUTB,
+	"OUTL",		LTYPE0,	AOUTL,
+	"OUTW",		LTYPE0,	AOUTW,
+	"OUTSB",	LTYPE0,	AOUTSB,
+	"OUTSL",	LTYPE0,	AOUTSL,
+	"OUTSW",	LTYPE0,	AOUTSW,
+	"POPAL",	LTYPE0,	APOPAL,
+	"POPAW",	LTYPE0,	APOPAW,
+	"POPFL",	LTYPE0,	APOPFL,
+	"POPFQ",	LTYPE0,	APOPFQ,
+	"POPFW",	LTYPE0,	APOPFW,
+	"POPL",		LTYPE1,	APOPL,
+	"POPQ",		LTYPE1,	APOPQ,
+	"POPW",		LTYPE1,	APOPW,
+	"PUSHAL",	LTYPE0,	APUSHAL,
+	"PUSHAW",	LTYPE0,	APUSHAW,
+	"PUSHFL",	LTYPE0,	APUSHFL,
+	"PUSHFQ",	LTYPE0,	APUSHFQ,
+	"PUSHFW",	LTYPE0,	APUSHFW,
+	"PUSHL",	LTYPE2,	APUSHL,
+	"PUSHQ",	LTYPE2,	APUSHQ,
+	"PUSHW",	LTYPE2,	APUSHW,
+	"RCLB",		LTYPE3,	ARCLB,
+	"RCLL",		LTYPE3,	ARCLL,
+	"RCLQ",		LTYPE3,	ARCLQ,
+	"RCLW",		LTYPE3,	ARCLW,
+	"RCRB",		LTYPE3,	ARCRB,
+	"RCRL",		LTYPE3,	ARCRL,
+	"RCRQ",		LTYPE3,	ARCRQ,
+	"RCRW",		LTYPE3,	ARCRW,
+	"RDMSR",	LTYPE0,	ARDMSR,
+	"RDPMC",	LTYPE0,	ARDPMC,
+	"RDTSC",	LTYPE0,	ARDTSC,
+	"REP",		LTYPE0,	AREP,
+	"REPN",		LTYPE0,	AREPN,
+	"RET",		LTYPE0,	ARET,
+	"RETFL",	LTYPERT,ARETFL,
+	"RETFW",	LTYPERT,ARETFW,
+	"RETFQ",	LTYPERT,ARETFQ,
+	"ROLB",		LTYPE3,	AROLB,
+	"ROLL",		LTYPE3,	AROLL,
+	"ROLQ",		LTYPE3,	AROLQ,
+	"ROLW",		LTYPE3,	AROLW,
+	"RORB",		LTYPE3,	ARORB,
+	"RORL",		LTYPE3,	ARORL,
+	"RORQ",		LTYPE3,	ARORQ,
+	"RORW",		LTYPE3,	ARORW,
+	"RSM",		LTYPE0,	ARSM,
+	"SAHF",		LTYPE0,	ASAHF,
+	"SALB",		LTYPE3,	ASALB,
+	"SALL",		LTYPE3,	ASALL,
+	"SALQ",		LTYPE3,	ASALQ,
+	"SALW",		LTYPE3,	ASALW,
+	"SARB",		LTYPE3,	ASARB,
+	"SARL",		LTYPE3,	ASARL,
+	"SARQ",		LTYPE3,	ASARQ,
+	"SARW",		LTYPE3,	ASARW,
+	"SBBB",		LTYPE3,	ASBBB,
+	"SBBL",		LTYPE3,	ASBBL,
+	"SBBQ",		LTYPE3,	ASBBQ,
+	"SBBW",		LTYPE3,	ASBBW,
+	"SCASB",	LTYPE0,	ASCASB,
+	"SCASL",	LTYPE0,	ASCASL,
+	"SCASQ",	LTYPE0,	ASCASQ,
+	"SCASW",	LTYPE0,	ASCASW,
+	"SETCC",	LTYPE1,	ASETCC,
+	"SETCS",	LTYPE1,	ASETCS,
+	"SETEQ",	LTYPE1,	ASETEQ,
+	"SETGE",	LTYPE1,	ASETGE,
+	"SETGT",	LTYPE1,	ASETGT,
+	"SETHI",	LTYPE1,	ASETHI,
+	"SETLE",	LTYPE1,	ASETLE,
+	"SETLS",	LTYPE1,	ASETLS,
+	"SETLT",	LTYPE1,	ASETLT,
+	"SETMI",	LTYPE1,	ASETMI,
+	"SETNE",	LTYPE1,	ASETNE,
+	"SETOC",	LTYPE1,	ASETOC,
+	"SETOS",	LTYPE1,	ASETOS,
+	"SETPC",	LTYPE1,	ASETPC,
+	"SETPL",	LTYPE1,	ASETPL,
+	"SETPS",	LTYPE1,	ASETPS,
+	"SFENCE",	LTYPE0,	ASFENCE,
+	"CDQ",		LTYPE0,	ACDQ,
+	"CWD",		LTYPE0,	ACWD,
+	"CQO",		LTYPE0,	ACQO,
+	"SHLB",		LTYPE3,	ASHLB,
+	"SHLL",		LTYPES,	ASHLL,
+	"SHLQ",		LTYPES,	ASHLQ,
+	"SHLW",		LTYPES,	ASHLW,
+	"SHRB",		LTYPE3,	ASHRB,
+	"SHRL",		LTYPES,	ASHRL,
+	"SHRQ",		LTYPES,	ASHRQ,
+	"SHRW",		LTYPES,	ASHRW,
+	"STC",		LTYPE0,	ASTC,
+	"STD",		LTYPE0,	ASTD,
+	"STI",		LTYPE0,	ASTI,
+	"STOSB",	LTYPE0,	ASTOSB,
+	"STOSL",	LTYPE0,	ASTOSL,
+	"STOSQ",	LTYPE0,	ASTOSQ,
+	"STOSW",	LTYPE0,	ASTOSW,
+	"SUBB",		LTYPE3,	ASUBB,
+	"SUBL",		LTYPE3,	ASUBL,
+	"SUBQ",		LTYPE3,	ASUBQ,
+	"SUBW",		LTYPE3,	ASUBW,
+	"SYSCALL",	LTYPE0,	ASYSCALL,
+	"SYSRET",	LTYPE0,	ASYSRET,
+	"SWAPGS",	LTYPE0,	ASWAPGS,
+	"TESTB",	LTYPE3,	ATESTB,
+	"TESTL",	LTYPE3,	ATESTL,
+	"TESTQ",	LTYPE3,	ATESTQ,
+	"TESTW",	LTYPE3,	ATESTW,
+	"TEXT",		LTYPET,	ATEXT,
+	"VERR",		LTYPE2,	AVERR,
+	"VERW",		LTYPE2,	AVERW,
+	"QUAD",		LTYPE2,	AQUAD,
+	"WAIT",		LTYPE0,	AWAIT,
+	"WBINVD",	LTYPE0,	AWBINVD,
+	"WRMSR",	LTYPE0,	AWRMSR,
+	"WORD",		LTYPE2,	AWORD,
+	"XADDB",	LTYPE3,	AXADDB,
+	"XADDL",	LTYPE3,	AXADDL,
+	"XADDQ",	LTYPE3,	AXADDQ,
+	"XADDW",	LTYPE3,	AXADDW,
+	"XCHGB",	LTYPE3,	AXCHGB,
+	"XCHGL",	LTYPE3,	AXCHGL,
+	"XCHGQ",	LTYPE3,	AXCHGQ,
+	"XCHGW",	LTYPE3,	AXCHGW,
+	"XLAT",		LTYPE2,	AXLAT,
+	"XORB",		LTYPE3,	AXORB,
+	"XORL",		LTYPE3,	AXORL,
+	"XORQ",		LTYPE3,	AXORQ,
+	"XORW",		LTYPE3,	AXORW,
+
+	"CMOVLCC",	LTYPE3,	ACMOVLCC,
+	"CMOVLCS",	LTYPE3,	ACMOVLCS,
+	"CMOVLEQ",	LTYPE3,	ACMOVLEQ,
+	"CMOVLGE",	LTYPE3,	ACMOVLGE,
+	"CMOVLGT",	LTYPE3,	ACMOVLGT,
+	"CMOVLHI",	LTYPE3,	ACMOVLHI,
+	"CMOVLLE",	LTYPE3,	ACMOVLLE,
+	"CMOVLLS",	LTYPE3,	ACMOVLLS,
+	"CMOVLLT",	LTYPE3,	ACMOVLLT,
+	"CMOVLMI",	LTYPE3,	ACMOVLMI,
+	"CMOVLNE",	LTYPE3,	ACMOVLNE,
+	"CMOVLOC",	LTYPE3,	ACMOVLOC,
+	"CMOVLOS",	LTYPE3,	ACMOVLOS,
+	"CMOVLPC",	LTYPE3,	ACMOVLPC,
+	"CMOVLPL",	LTYPE3,	ACMOVLPL,
+	"CMOVLPS",	LTYPE3,	ACMOVLPS,
+	"CMOVQCC",	LTYPE3,	ACMOVQCC,
+	"CMOVQCS",	LTYPE3,	ACMOVQCS,
+	"CMOVQEQ",	LTYPE3,	ACMOVQEQ,
+	"CMOVQGE",	LTYPE3,	ACMOVQGE,
+	"CMOVQGT",	LTYPE3,	ACMOVQGT,
+	"CMOVQHI",	LTYPE3,	ACMOVQHI,
+	"CMOVQLE",	LTYPE3,	ACMOVQLE,
+	"CMOVQLS",	LTYPE3,	ACMOVQLS,
+	"CMOVQLT",	LTYPE3,	ACMOVQLT,
+	"CMOVQMI",	LTYPE3,	ACMOVQMI,
+	"CMOVQNE",	LTYPE3,	ACMOVQNE,
+	"CMOVQOC",	LTYPE3,	ACMOVQOC,
+	"CMOVQOS",	LTYPE3,	ACMOVQOS,
+	"CMOVQPC",	LTYPE3,	ACMOVQPC,
+	"CMOVQPL",	LTYPE3,	ACMOVQPL,
+	"CMOVQPS",	LTYPE3,	ACMOVQPS,
+	"CMOVWCC",	LTYPE3,	ACMOVWCC,
+	"CMOVWCS",	LTYPE3,	ACMOVWCS,
+	"CMOVWEQ",	LTYPE3,	ACMOVWEQ,
+	"CMOVWGE",	LTYPE3,	ACMOVWGE,
+	"CMOVWGT",	LTYPE3,	ACMOVWGT,
+	"CMOVWHI",	LTYPE3,	ACMOVWHI,
+	"CMOVWLE",	LTYPE3,	ACMOVWLE,
+	"CMOVWLS",	LTYPE3,	ACMOVWLS,
+	"CMOVWLT",	LTYPE3,	ACMOVWLT,
+	"CMOVWMI",	LTYPE3,	ACMOVWMI,
+	"CMOVWNE",	LTYPE3,	ACMOVWNE,
+	"CMOVWOC",	LTYPE3,	ACMOVWOC,
+	"CMOVWOS",	LTYPE3,	ACMOVWOS,
+	"CMOVWPC",	LTYPE3,	ACMOVWPC,
+	"CMOVWPL",	LTYPE3,	ACMOVWPL,
+	"CMOVWPS",	LTYPE3,	ACMOVWPS,
+
+	"FMOVB",	LTYPE3, AFMOVB,
+	"FMOVBP",	LTYPE3, AFMOVBP,
+	"FMOVD",	LTYPE3, AFMOVD,
+	"FMOVDP",	LTYPE3, AFMOVDP,
+	"FMOVF",	LTYPE3, AFMOVF,
+	"FMOVFP",	LTYPE3, AFMOVFP,
+	"FMOVL",	LTYPE3, AFMOVL,
+	"FMOVLP",	LTYPE3, AFMOVLP,
+	"FMOVV",	LTYPE3, AFMOVV,
+	"FMOVVP",	LTYPE3, AFMOVVP,
+	"FMOVW",	LTYPE3, AFMOVW,
+	"FMOVWP",	LTYPE3, AFMOVWP,
+	"FMOVX",	LTYPE3, AFMOVX,
+	"FMOVXP",	LTYPE3, AFMOVXP,
+	"FCOMB",	LTYPE3, AFCOMB,
+	"FCOMBP",	LTYPE3, AFCOMBP,
+	"FCOMD",	LTYPE3, AFCOMD,
+	"FCOMDP",	LTYPE3, AFCOMDP,
+	"FCOMDPP",	LTYPE3, AFCOMDPP,
+	"FCOMF",	LTYPE3, AFCOMF,
+	"FCOMFP",	LTYPE3, AFCOMFP,
+	"FCOML",	LTYPE3, AFCOML,
+	"FCOMLP",	LTYPE3, AFCOMLP,
+	"FCOMW",	LTYPE3, AFCOMW,
+	"FCOMWP",	LTYPE3, AFCOMWP,
+	"FUCOM",	LTYPE3, AFUCOM,
+	"FUCOMP",	LTYPE3, AFUCOMP,
+	"FUCOMPP",	LTYPE3, AFUCOMPP,
+	"FADDW",	LTYPE3, AFADDW,
+	"FADDL",	LTYPE3, AFADDL,
+	"FADDF",	LTYPE3, AFADDF,
+	"FADDD",	LTYPE3, AFADDD,
+	"FADDDP",	LTYPE3, AFADDDP,
+	"FSUBDP",	LTYPE3, AFSUBDP,
+	"FSUBW",	LTYPE3, AFSUBW,
+	"FSUBL",	LTYPE3, AFSUBL,
+	"FSUBF",	LTYPE3, AFSUBF,
+	"FSUBD",	LTYPE3, AFSUBD,
+	"FSUBRDP",	LTYPE3, AFSUBRDP,
+	"FSUBRW",	LTYPE3, AFSUBRW,
+	"FSUBRL",	LTYPE3, AFSUBRL,
+	"FSUBRF",	LTYPE3, AFSUBRF,
+	"FSUBRD",	LTYPE3, AFSUBRD,
+	"FMULDP",	LTYPE3, AFMULDP,
+	"FMULW",	LTYPE3, AFMULW,
+	"FMULL",	LTYPE3, AFMULL,
+	"FMULF",	LTYPE3, AFMULF,
+	"FMULD",	LTYPE3, AFMULD,
+	"FDIVDP",	LTYPE3, AFDIVDP,
+	"FDIVW",	LTYPE3, AFDIVW,
+	"FDIVL",	LTYPE3, AFDIVL,
+	"FDIVF",	LTYPE3, AFDIVF,
+	"FDIVD",	LTYPE3, AFDIVD,
+	"FDIVRDP",	LTYPE3, AFDIVRDP,
+	"FDIVRW",	LTYPE3, AFDIVRW,
+	"FDIVRL",	LTYPE3, AFDIVRL,
+	"FDIVRF",	LTYPE3, AFDIVRF,
+	"FDIVRD",	LTYPE3, AFDIVRD,
+	"FXCHD",	LTYPE3, AFXCHD,
+	"FFREE",	LTYPE1, AFFREE,
+	"FLDCW",	LTYPE2, AFLDCW,
+	"FLDENV",	LTYPE1, AFLDENV,
+	"FRSTOR",	LTYPE2, AFRSTOR,
+	"FSAVE",	LTYPE1, AFSAVE,
+	"FSTCW",	LTYPE1, AFSTCW,
+	"FSTENV",	LTYPE1, AFSTENV,
+	"FSTSW",	LTYPE1, AFSTSW,
+	"F2XM1",	LTYPE0, AF2XM1,
+	"FABS",		LTYPE0, AFABS,
+	"FCHS",		LTYPE0, AFCHS,
+	"FCLEX",	LTYPE0, AFCLEX,
+	"FCOS",		LTYPE0, AFCOS,
+	"FDECSTP",	LTYPE0, AFDECSTP,
+	"FINCSTP",	LTYPE0, AFINCSTP,
+	"FINIT",	LTYPE0, AFINIT,
+	"FLD1",		LTYPE0, AFLD1,
+	"FLDL2E",	LTYPE0, AFLDL2E,
+	"FLDL2T",	LTYPE0, AFLDL2T,
+	"FLDLG2",	LTYPE0, AFLDLG2,
+	"FLDLN2",	LTYPE0, AFLDLN2,
+	"FLDPI",	LTYPE0, AFLDPI,
+	"FLDZ",		LTYPE0, AFLDZ,
+	"FNOP",		LTYPE0, AFNOP,
+	"FPATAN",	LTYPE0, AFPATAN,
+	"FPREM",	LTYPE0, AFPREM,
+	"FPREM1",	LTYPE0, AFPREM1,
+	"FPTAN",	LTYPE0, AFPTAN,
+	"FRNDINT",	LTYPE0, AFRNDINT,
+	"FSCALE",	LTYPE0, AFSCALE,
+	"FSIN",		LTYPE0, AFSIN,
+	"FSINCOS",	LTYPE0, AFSINCOS,
+	"FSQRT",	LTYPE0, AFSQRT,
+	"FTST",		LTYPE0, AFTST,
+	"FXAM",		LTYPE0, AFXAM,
+	"FXTRACT",	LTYPE0, AFXTRACT,
+	"FYL2X",	LTYPE0, AFYL2X,
+	"FYL2XP1",	LTYPE0, AFYL2XP1,
+
+	"ADDPD",	LTYPE3,	AADDPD,
+	"ADDPS",	LTYPE3,	AADDPS,
+	"ADDSD",	LTYPE3,	AADDSD,
+	"ADDSS",	LTYPE3,	AADDSS,
+	"ANDNPD",	LTYPE3,	AANDNPD,
+	"ANDNPS",	LTYPE3,	AANDNPS,
+	"ANDPD",	LTYPE3,	AANDPD,
+	"ANDPS",	LTYPE3,	AANDPS,
+	"CMPPD",	LTYPEXC,ACMPPD,
+	"CMPPS",	LTYPEXC,ACMPPS,
+	"CMPSD",	LTYPEXC,ACMPSD,
+	"CMPSS",	LTYPEXC,ACMPSS,
+	"COMISD",	LTYPE3,	ACOMISD,
+	"COMISS",	LTYPE3,	ACOMISS,
+	"CVTPL2PD",	LTYPE3,	ACVTPL2PD,
+	"CVTPL2PS",	LTYPE3,	ACVTPL2PS,
+	"CVTPD2PL",	LTYPE3,	ACVTPD2PL,
+	"CVTPD2PS",	LTYPE3,	ACVTPD2PS,
+	"CVTPS2PL",	LTYPE3,	ACVTPS2PL,
+	"PF2IW",	LTYPE3,	APF2IW,
+	"PF2IL",	LTYPE3,	APF2IL,
+	"PF2ID",	LTYPE3,	APF2IL,	/* syn */
+	"PI2FL",	LTYPE3,	API2FL,
+	"PI2FD",	LTYPE3,	API2FL,	/* syn */
+	"PI2FW",	LTYPE3,	API2FW,
+	"CVTPS2PD",	LTYPE3,	ACVTPS2PD,
+	"CVTSD2SL",	LTYPE3,	ACVTSD2SL,
+	"CVTSD2SQ",	LTYPE3,	ACVTSD2SQ,
+	"CVTSD2SS",	LTYPE3,	ACVTSD2SS,
+	"CVTSL2SD",	LTYPE3,	ACVTSL2SD,
+	"CVTSQ2SD",	LTYPE3,	ACVTSQ2SD,
+	"CVTSL2SS",	LTYPE3,	ACVTSL2SS,
+	"CVTSQ2SS",	LTYPE3,	ACVTSQ2SS,
+	"CVTSS2SD",	LTYPE3,	ACVTSS2SD,
+	"CVTSS2SL",	LTYPE3,	ACVTSS2SL,
+	"CVTSS2SQ",	LTYPE3,	ACVTSS2SQ,
+	"CVTTPD2PL",	LTYPE3,	ACVTTPD2PL,
+	"CVTTPS2PL",	LTYPE3,	ACVTTPS2PL,
+	"CVTTSD2SL",	LTYPE3,	ACVTTSD2SL,
+	"CVTTSD2SQ",	LTYPE3,	ACVTTSD2SQ,
+	"CVTTSS2SL",	LTYPE3,	ACVTTSS2SL,
+	"CVTTSS2SQ",	LTYPE3,	ACVTTSS2SQ,
+	"DIVPD",	LTYPE3,	ADIVPD,
+	"DIVPS",	LTYPE3,	ADIVPS,
+	"DIVSD",	LTYPE3,	ADIVSD,
+	"DIVSS",	LTYPE3,	ADIVSS,
+	"FXRSTOR",	LTYPE2,	AFXRSTOR,
+	"FXRSTOR64",	LTYPE2,	AFXRSTOR64,
+	"FXSAVE",	LTYPE1,	AFXSAVE,
+	"FXSAVE64",	LTYPE1,	AFXSAVE64,
+	"LDMXCSR",	LTYPE2,	ALDMXCSR,
+	"MASKMOVOU",	LTYPE3,	AMASKMOVOU,
+	"MASKMOVDQU",	LTYPE3,	AMASKMOVOU,	/* syn */
+	"MASKMOVQ",	LTYPE3,	AMASKMOVQ,
+	"MAXPD",	LTYPE3,	AMAXPD,
+	"MAXPS",	LTYPE3,	AMAXPS,
+	"MAXSD",	LTYPE3,	AMAXSD,
+	"MAXSS",	LTYPE3,	AMAXSS,
+	"MINPD",	LTYPE3,	AMINPD,
+	"MINPS",	LTYPE3,	AMINPS,
+	"MINSD",	LTYPE3,	AMINSD,
+	"MINSS",	LTYPE3,	AMINSS,
+	"MOVAPD",	LTYPE3,	AMOVAPD,
+	"MOVAPS",	LTYPE3,	AMOVAPS,
+	"MOVD",		LTYPE3,	AMOVQ,	/* syn */
+	"MOVDQ2Q",	LTYPE3,	AMOVQ,	/* syn */
+	"MOVO",		LTYPE3,	AMOVO,
+	"MOVOA",	LTYPE3,	AMOVO,	/* syn */
+	"MOVOU",	LTYPE3,	AMOVOU,
+	"MOVHLPS",	LTYPE3,	AMOVHLPS,
+	"MOVHPD",	LTYPE3,	AMOVHPD,
+	"MOVHPS",	LTYPE3,	AMOVHPS,
+	"MOVLHPS",	LTYPE3,	AMOVLHPS,
+	"MOVLPD",	LTYPE3,	AMOVLPD,
+	"MOVLPS",	LTYPE3,	AMOVLPS,
+	"MOVMSKPD",	LTYPE3,	AMOVMSKPD,
+	"MOVMSKPS",	LTYPE3,	AMOVMSKPS,
+	"MOVNTO",	LTYPE3,	AMOVNTO,
+	"MOVNTDQ",	LTYPE3,	AMOVNTO,	/* syn */
+	"MOVNTPD",	LTYPE3,	AMOVNTPD,
+	"MOVNTPS",	LTYPE3,	AMOVNTPS,
+	"MOVNTQ",	LTYPE3,	AMOVNTQ,
+	"MOVQOZX",	LTYPE3,	AMOVQOZX,
+	"MOVSD",	LTYPE3,	AMOVSD,
+	"MOVSS",	LTYPE3,	AMOVSS,
+	"MOVUPD",	LTYPE3,	AMOVUPD,
+	"MOVUPS",	LTYPE3,	AMOVUPS,
+	"MULPD",	LTYPE3,	AMULPD,
+	"MULPS",	LTYPE3,	AMULPS,
+	"MULSD",	LTYPE3,	AMULSD,
+	"MULSS",	LTYPE3,	AMULSS,
+	"ORPD",		LTYPE3,	AORPD,
+	"ORPS",		LTYPE3,	AORPS,
+	"PACKSSLW",	LTYPE3,	APACKSSLW,
+	"PACKSSWB",	LTYPE3,	APACKSSWB,
+	"PACKUSWB",	LTYPE3,	APACKUSWB,
+	"PADDB",	LTYPE3,	APADDB,
+	"PADDL",	LTYPE3,	APADDL,
+	"PADDQ",	LTYPE3,	APADDQ,
+	"PADDSB",	LTYPE3,	APADDSB,
+	"PADDSW",	LTYPE3,	APADDSW,
+	"PADDUSB",	LTYPE3,	APADDUSB,
+	"PADDUSW",	LTYPE3,	APADDUSW,
+	"PADDW",	LTYPE3,	APADDW,
+	"PAND",		LTYPE3, APAND,
+	"PANDB",	LTYPE3,	APANDB,
+	"PANDL",	LTYPE3,	APANDL,
+	"PANDSB",	LTYPE3,	APANDSB,
+	"PANDSW",	LTYPE3,	APANDSW,
+	"PANDUSB",	LTYPE3,	APANDUSB,
+	"PANDUSW",	LTYPE3,	APANDUSW,
+	"PANDW",	LTYPE3,	APANDW,
+	"PANDN",	LTYPE3, APANDN,
+	"PAVGB",	LTYPE3,	APAVGB,
+	"PAVGW",	LTYPE3,	APAVGW,
+	"PCMPEQB",	LTYPE3,	APCMPEQB,
+	"PCMPEQL",	LTYPE3,	APCMPEQL,
+	"PCMPEQW",	LTYPE3,	APCMPEQW,
+	"PCMPGTB",	LTYPE3,	APCMPGTB,
+	"PCMPGTL",	LTYPE3,	APCMPGTL,	
+	"PCMPGTW",	LTYPE3,	APCMPGTW,
+	"PEXTRW",	LTYPEX,	APEXTRW,
+	"PINSRW",	LTYPEX,	APINSRW,
+	"PMADDWL",	LTYPE3,	APMADDWL,
+	"PMAXSW",	LTYPE3,	APMAXSW,
+	"PMAXUB",	LTYPE3,	APMAXUB,
+	"PMINSW",	LTYPE3,	APMINSW,
+	"PMINUB",	LTYPE3,	APMINUB,
+	"PMOVMSKB",	LTYPE3,	APMOVMSKB,
+	"PMULHRW",	LTYPE3,	APMULHRW,
+	"PMULHUW",	LTYPE3,	APMULHUW,
+	"PMULHW",	LTYPE3,	APMULHW,
+	"PMULLW",	LTYPE3,	APMULLW,
+	"PMULULQ",	LTYPE3,	APMULULQ,
+	"POR",		LTYPE3,	APOR,
+	"PSADBW",	LTYPE3,	APSADBW,
+	"PSHUFHW",	LTYPEX,	APSHUFHW,
+	"PSHUFL",	LTYPEX,	APSHUFL,
+	"PSHUFLW",	LTYPEX,	APSHUFLW,
+	"PSHUFW",	LTYPEX, APSHUFW,
+	"PSLLO",	LTYPE3,	APSLLO,
+	"PSLLDQ",	LTYPE3,	APSLLO,	/* syn */
+	"PSLLL",	LTYPE3,	APSLLL,
+	"PSLLQ",	LTYPE3,	APSLLQ,
+	"PSLLW",	LTYPE3,	APSLLW,
+	"PSRAL",	LTYPE3,	APSRAL,
+	"PSRAW",	LTYPE3,	APSRAW,
+	"PSRLO",	LTYPE3,	APSRLO,
+	"PSRLDQ",	LTYPE3,	APSRLO,	/* syn */
+	"PSRLL",	LTYPE3,	APSRLL,
+	"PSRLQ",	LTYPE3,	APSRLQ,
+	"PSRLW",	LTYPE3,	APSRLW,
+	"PSUBB",	LTYPE3,	APSUBB,
+	"PSUBL",	LTYPE3,	APSUBL,
+	"PSUBQ",	LTYPE3,	APSUBQ,
+	"PSUBSB",	LTYPE3,	APSUBSB,
+	"PSUBSW",	LTYPE3,	APSUBSW,
+	"PSUBUSB",	LTYPE3,	APSUBUSB,
+	"PSUBUSW",	LTYPE3,	APSUBUSW,
+	"PSUBW",	LTYPE3,	APSUBW,
+	"PUNPCKHBW",	LTYPE3,	APUNPCKHBW,
+	"PUNPCKHLQ",	LTYPE3,	APUNPCKHLQ,
+	"PUNPCKHQDQ",	LTYPE3,	APUNPCKHQDQ,
+	"PUNPCKHWL",	LTYPE3,	APUNPCKHWL,
+	"PUNPCKLBW",	LTYPE3,	APUNPCKLBW,
+	"PUNPCKLLQ",	LTYPE3,	APUNPCKLLQ,
+	"PUNPCKLQDQ",	LTYPE3,	APUNPCKLQDQ,
+	"PUNPCKLWL",	LTYPE3,	APUNPCKLWL,
+	"PXOR",		LTYPE3,	APXOR,
+	"RCPPS",	LTYPE3,	ARCPPS,
+	"RCPSS",	LTYPE3,	ARCPSS,
+	"RSQRTPS",	LTYPE3,	ARSQRTPS,
+	"RSQRTSS",	LTYPE3,	ARSQRTSS,
+	"SHUFPD",	LTYPEX,	ASHUFPD,
+	"SHUFPS",	LTYPEX,	ASHUFPS,
+	"SQRTPD",	LTYPE3,	ASQRTPD,
+	"SQRTPS",	LTYPE3,	ASQRTPS,
+	"SQRTSD",	LTYPE3,	ASQRTSD,
+	"SQRTSS",	LTYPE3,	ASQRTSS,
+	"STMXCSR",	LTYPE1,	ASTMXCSR,
+	"SUBPD",	LTYPE3,	ASUBPD,
+	"SUBPS",	LTYPE3,	ASUBPS,
+	"SUBSD",	LTYPE3,	ASUBSD,
+	"SUBSS",	LTYPE3,	ASUBSS,
+	"UCOMISD",	LTYPE3,	AUCOMISD,
+	"UCOMISS",	LTYPE3,	AUCOMISS,
+	"UNPCKHPD",	LTYPE3,	AUNPCKHPD,
+	"UNPCKHPS",	LTYPE3,	AUNPCKHPS,
+	"UNPCKLPD",	LTYPE3,	AUNPCKLPD,
+	"UNPCKLPS",	LTYPE3,	AUNPCKLPS,
+	"XORPD",	LTYPE3,	AXORPD,
+	"XORPS",	LTYPE3,	AXORPS,
+
+	0
+};
+
+void
+cinit(void)
+{
+	Sym *s;
+	int i;
+
+	nullgen.sym = S;
+	nullgen.offset = 0;
+	if(FPCHIP)
+		nullgen.dval = 0;
+	for(i=0; i<sizeof(nullgen.sval); i++)
+		nullgen.sval[i] = 0;
+	nullgen.type = D_NONE;
+	nullgen.index = D_NONE;
+	nullgen.scale = 0;
+
+	nerrors = 0;
+	iostack = I;
+	iofree = I;
+	peekc = IGN;
+	nhunk = 0;
+	for(i=0; i<NHASH; i++)
+		hash[i] = S;
+	for(i=0; itab[i].name; i++) {
+		s = slookup(itab[i].name);
+		if(s->type != LNAME)
+			yyerror("double initialization %s", itab[i].name);
+		s->type = itab[i].type;
+		s->value = itab[i].value;
+	}
+
+	pathname = allocn(pathname, 0, 100);
+	if(mygetwd(pathname, 99) == 0) {
+		pathname = allocn(pathname, 100, 900);
+		if(mygetwd(pathname, 999) == 0)
+			strcpy(pathname, "/???");
+	}
+}
+
+void
+checkscale(int scale)
+{
+
+	switch(scale) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		return;
+	}
+	yyerror("scale must be 1248: %d", scale);
+}
+
+void
+syminit(Sym *s)
+{
+
+	s->type = LNAME;
+	s->value = 0;
+}
+
+void
+cclean(void)
+{
+	Gen2 g2;
+
+	g2.from = nullgen;
+	g2.to = nullgen;
+	outcode(AEND, &g2);
+	Bflush(&obuf);
+}
+
+void
+zname(char *n, int t, int s)
+{
+
+	Bputc(&obuf, ANAME);		/* as(2) */
+	Bputc(&obuf, ANAME>>8);
+	Bputc(&obuf, t);		/* type */
+	Bputc(&obuf, s);		/* sym */
+	while(*n) {
+		Bputc(&obuf, *n);
+		n++;
+	}
+	Bputc(&obuf, 0);
+}
+
+void
+zaddr(Gen *a, int s)
+{
+	long l;
+	int i, t;
+	char *n;
+	Ieee e;
+
+	t = 0;
+	if(a->index != D_NONE || a->scale != 0)
+		t |= T_INDEX;
+	if(a->offset != 0) {
+		t |= T_OFFSET;
+		l = a->offset;
+		if((vlong)l != a->offset)
+			t |= T_64;
+	}
+	if(s != 0)
+		t |= T_SYM;
+
+	switch(a->type) {
+	default:
+		t |= T_TYPE;
+		break;
+	case D_FCONST:
+		t |= T_FCONST;
+		break;
+	case D_SCONST:
+		t |= T_SCONST;
+		break;
+	case D_NONE:
+		break;
+	}
+	Bputc(&obuf, t);
+
+	if(t & T_INDEX) {	/* implies index, scale */
+		Bputc(&obuf, a->index);
+		Bputc(&obuf, a->scale);
+	}
+	if(t & T_OFFSET) {	/* implies offset */
+		l = a->offset;
+		Bputc(&obuf, l);
+		Bputc(&obuf, l>>8);
+		Bputc(&obuf, l>>16);
+		Bputc(&obuf, l>>24);
+		if(t & T_64) {
+			l = a->offset>>32;
+			Bputc(&obuf, l);
+			Bputc(&obuf, l>>8);
+			Bputc(&obuf, l>>16);
+			Bputc(&obuf, l>>24);
+		}
+	}
+	if(t & T_SYM)		/* implies sym */
+		Bputc(&obuf, s);
+	if(t & T_FCONST) {
+		ieeedtod(&e, a->dval);
+		l = e.l;
+		Bputc(&obuf, l);
+		Bputc(&obuf, l>>8);
+		Bputc(&obuf, l>>16);
+		Bputc(&obuf, l>>24);
+		l = e.h;
+		Bputc(&obuf, l);
+		Bputc(&obuf, l>>8);
+		Bputc(&obuf, l>>16);
+		Bputc(&obuf, l>>24);
+		return;
+	}
+	if(t & T_SCONST) {
+		n = a->sval;
+		for(i=0; i<NSNAME; i++) {
+			Bputc(&obuf, *n);
+			n++;
+		}
+		return;
+	}
+	if(t & T_TYPE)
+		Bputc(&obuf, a->type);
+}
+
+void
+outcode(int a, Gen2 *g2)
+{
+	int sf, st, t;
+	Sym *s;
+
+	if(pass == 1)
+		goto out;
+
+jackpot:
+	sf = 0;
+	s = g2->from.sym;
+	while(s != S) {
+		sf = s->sym;
+		if(sf < 0 || sf >= NSYM)
+			sf = 0;
+		t = g2->from.type;
+		if(t == D_ADDR)
+			t = g2->from.index;
+		if(h[sf].type == t)
+		if(h[sf].sym == s)
+			break;
+		zname(s->name, t, sym);
+		s->sym = sym;
+		h[sym].sym = s;
+		h[sym].type = t;
+		sf = sym;
+		sym++;
+		if(sym >= NSYM)
+			sym = 1;
+		break;
+	}
+	st = 0;
+	s = g2->to.sym;
+	while(s != S) {
+		st = s->sym;
+		if(st < 0 || st >= NSYM)
+			st = 0;
+		t = g2->to.type;
+		if(t == D_ADDR)
+			t = g2->to.index;
+		if(h[st].type == t)
+		if(h[st].sym == s)
+			break;
+		zname(s->name, t, sym);
+		s->sym = sym;
+		h[sym].sym = s;
+		h[sym].type = t;
+		st = sym;
+		sym++;
+		if(sym >= NSYM)
+			sym = 1;
+		if(st == sf)
+			goto jackpot;
+		break;
+	}
+	Bputc(&obuf, a);
+	Bputc(&obuf, a>>8);
+	Bputc(&obuf, lineno);
+	Bputc(&obuf, lineno>>8);
+	Bputc(&obuf, lineno>>16);
+	Bputc(&obuf, lineno>>24);
+	zaddr(&g2->from, sf);
+	zaddr(&g2->to, st);
+
+out:
+	if(a != AGLOBL && a != ADATA)
+		pc++;
+}
+
+void
+outhist(void)
+{
+	Gen g;
+	Hist *h;
+	char *p, *q, *op, c;
+	int n;
+
+	g = nullgen;
+	c = pathchar();
+	for(h = hist; h != H; h = h->link) {
+		p = h->name;
+		op = 0;
+		/* on windows skip drive specifier in pathname */
+		if(systemtype(Windows) && p && p[1] == ':'){
+			p += 2;
+			c = *p;
+		}
+		if(p && p[0] != c && h->offset == 0 && pathname){
+			/* on windows skip drive specifier in pathname */
+			if(systemtype(Windows) && pathname[1] == ':') {
+				op = p;
+				p = pathname+2;
+				c = *p;
+			} else if(pathname[0] == c){
+				op = p;
+				p = pathname;
+			}
+		}
+		while(p) {
+			q = strchr(p, c);
+			if(q) {
+				n = q-p;
+				if(n == 0){
+					n = 1;	/* leading "/" */
+					*p = '/';	/* don't emit "\" on windows */
+				}
+				q++;
+			} else {
+				n = strlen(p);
+				q = 0;
+			}
+			if(n) {
+				Bputc(&obuf, ANAME);
+				Bputc(&obuf, ANAME>>8);
+				Bputc(&obuf, D_FILE);	/* type */
+				Bputc(&obuf, 1);	/* sym */
+				Bputc(&obuf, '<');
+				Bwrite(&obuf, p, n);
+				Bputc(&obuf, 0);
+			}
+			p = q;
+			if(p == 0 && op) {
+				p = op;
+				op = 0;
+			}
+		}
+		g.offset = h->offset;
+
+		Bputc(&obuf, AHISTORY);
+		Bputc(&obuf, AHISTORY>>8);
+		Bputc(&obuf, h->line);
+		Bputc(&obuf, h->line>>8);
+		Bputc(&obuf, h->line>>16);
+		Bputc(&obuf, h->line>>24);
+		zaddr(&nullgen, 0);
+		zaddr(&g, 0);
+	}
+}
+
+void
+pragbldicks(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void
+praghjdicks(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c
new file mode 100644
index 0000000..7463aa6
--- /dev/null
+++ b/src/cmd/6c/cgen.c
@@ -0,0 +1,1971 @@
+// Inferno utils/6c/cgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/cgen.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+/* ,x/^(print|prtree)\(/i/\/\/ */
+int castup(Type*, Type*);
+
+void
+cgen(Node *n, Node *nn)
+{
+	Node *l, *r, *t;
+	Prog *p1;
+	Node nod, nod1, nod2, nod3, nod4;
+	int o, hardleft;
+	long v, curs;
+	vlong c;
+
+	if(debug['g']) {
+		prtree(nn, "cgen lhs");
+		prtree(n, "cgen");
+	}
+	if(n == Z || n->type == T)
+		return;
+	if(typesu[n->type->etype]) {
+		sugen(n, nn, n->type->width);
+		return;
+	}
+	l = n->left;
+	r = n->right;
+	o = n->op;
+	if(n->addable >= INDEXED) {
+		if(nn == Z) {
+			switch(o) {
+			default:
+				nullwarn(Z, Z);
+				break;
+			case OINDEX:
+				nullwarn(l, r);
+				break;
+			}
+			return;
+		}
+		gmove(n, nn);
+		return;
+	}
+	curs = cursafe;
+
+	if(l->complex >= FNX)
+	if(r != Z && r->complex >= FNX)
+	switch(o) {
+	default:
+		if(cond(o) && typesu[l->type->etype])
+			break;
+
+		regret(&nod, r);
+		cgen(r, &nod);
+
+		regsalloc(&nod1, r);
+		gmove(&nod, &nod1);
+
+		regfree(&nod);
+		nod = *n;
+		nod.right = &nod1;
+
+		cgen(&nod, nn);
+		return;
+
+	case OFUNC:
+	case OCOMMA:
+	case OANDAND:
+	case OOROR:
+	case OCOND:
+	case ODOT:
+		break;
+	}
+
+	hardleft = l->addable < INDEXED || l->complex >= FNX;
+	switch(o) {
+	default:
+		diag(n, "unknown op in cgen: %O", o);
+		break;
+
+	case ONEG:
+	case OCOM:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		regalloc(&nod, l, nn);
+		cgen(l, &nod);
+		gopcode(o, n->type, Z, &nod);
+		gmove(&nod, nn);
+		regfree(&nod);
+		break;
+
+	case OAS:
+		if(l->op == OBIT)
+			goto bitas;
+		if(!hardleft) {
+			if(nn != Z || r->addable < INDEXED || hardconst(r)) {
+				if(r->complex >= FNX && nn == Z)
+					regret(&nod, r);
+				else
+					regalloc(&nod, r, nn);
+				cgen(r, &nod);
+				gmove(&nod, l);
+				if(nn != Z)
+					gmove(&nod, nn);
+				regfree(&nod);
+			} else
+				gmove(r, l);
+			break;
+		}
+		if(l->complex >= r->complex) {
+			if(l->op == OINDEX && immconst(r)) {
+				gmove(r, l);
+				break;
+			}
+			reglcgen(&nod1, l, Z);
+			if(r->addable >= INDEXED && !hardconst(r)) {
+				gmove(r, &nod1);
+				if(nn != Z)
+					gmove(r, nn);
+				regfree(&nod1);
+				break;
+			}
+			regalloc(&nod, r, nn);
+			cgen(r, &nod);
+		} else {
+			regalloc(&nod, r, nn);
+			cgen(r, &nod);
+			reglcgen(&nod1, l, Z);
+		}
+		gmove(&nod, &nod1);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	bitas:
+		n = l->left;
+		regalloc(&nod, r, nn);
+		if(l->complex >= r->complex) {
+			reglcgen(&nod1, n, Z);
+			cgen(r, &nod);
+		} else {
+			cgen(r, &nod);
+			reglcgen(&nod1, n, Z);
+		}
+		regalloc(&nod2, n, Z);
+		gmove(&nod1, &nod2);
+		bitstore(l, &nod, &nod1, &nod2, nn);
+		break;
+
+	case OBIT:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		bitload(n, &nod, Z, Z, nn);
+		gmove(&nod, nn);
+		regfree(&nod);
+		break;
+
+	case OLSHR:
+	case OASHL:
+	case OASHR:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		if(r->op == OCONST) {
+			if(r->vconst == 0) {
+				cgen(l, nn);
+				break;
+			}
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			if(o == OASHL && r->vconst == 1)
+				gopcode(OADD, n->type, &nod, &nod);
+			else
+				gopcode(o, n->type, r, &nod);
+			gmove(&nod, nn);
+			regfree(&nod);
+			break;
+		}
+
+		/*
+		 * get nod to be D_CX
+		 */
+		if(nodreg(&nod, nn, D_CX)) {
+			regsalloc(&nod1, n);
+			gmove(&nod, &nod1);
+			cgen(n, &nod);		/* probably a bug */
+			gmove(&nod, nn);
+			gmove(&nod1, &nod);
+			break;
+		}
+		reg[D_CX]++;
+		if(nn->op == OREGISTER && nn->reg == D_CX)
+			regalloc(&nod1, l, Z);
+		else
+			regalloc(&nod1, l, nn);
+		if(r->complex >= l->complex) {
+			cgen(r, &nod);
+			cgen(l, &nod1);
+		} else {
+			cgen(l, &nod1);
+			cgen(r, &nod);
+		}
+		gopcode(o, n->type, &nod, &nod1);
+		gmove(&nod1, nn);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	case OADD:
+	case OSUB:
+	case OOR:
+	case OXOR:
+	case OAND:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		if(typefd[n->type->etype])
+			goto fop;
+		if(r->op == OCONST) {
+			if(r->vconst == 0 && o != OAND) {
+				cgen(l, nn);
+				break;
+			}
+		}
+		if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
+		&& (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
+			c = l->right->vconst;
+			if(c > 0 && c <= 3) {
+				if(l->left->complex >= r->complex) {
+					regalloc(&nod, l->left, nn);
+					cgen(l->left, &nod);
+					if(r->addable < INDEXED) {
+						regalloc(&nod1, r, Z);
+						cgen(r, &nod1);
+						genmuladd(&nod, &nod, 1 << c, &nod1);
+						regfree(&nod1);
+					}
+					else
+						genmuladd(&nod, &nod, 1 << c, r);
+				}
+				else {
+					regalloc(&nod, r, nn);
+					cgen(r, &nod);
+					regalloc(&nod1, l->left, Z);
+					cgen(l->left, &nod1);
+					genmuladd(&nod, &nod1, 1 << c, &nod);
+					regfree(&nod1);
+				}
+				gmove(&nod, nn);
+				regfree(&nod);
+				break;
+			}
+		}
+		if(r->addable >= INDEXED && !hardconst(r)) {
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			gopcode(o, n->type, r, &nod);
+			gmove(&nod, nn);
+			regfree(&nod);
+			break;
+		}
+		if(l->complex >= r->complex) {
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			regalloc(&nod1, r, Z);
+			cgen(r, &nod1);
+			gopcode(o, n->type, &nod1, &nod);
+		} else {
+			regalloc(&nod1, r, nn);
+			cgen(r, &nod1);
+			regalloc(&nod, l, Z);
+			cgen(l, &nod);
+			gopcode(o, n->type, &nod1, &nod);
+		}
+		gmove(&nod, nn);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	case OLMOD:
+	case OMOD:
+	case OLMUL:
+	case OLDIV:
+	case OMUL:
+	case ODIV:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		if(typefd[n->type->etype])
+			goto fop;
+		if(r->op == OCONST && typechl[n->type->etype]) {	/* TO DO */
+			SET(v);
+			switch(o) {
+			case ODIV:
+			case OMOD:
+				c = r->vconst;
+				if(c < 0)
+					c = -c;
+				v = log2(c);
+				if(v < 0)
+					break;
+				/* fall thru */
+			case OMUL:
+			case OLMUL:
+				regalloc(&nod, l, nn);
+				cgen(l, &nod);
+				switch(o) {
+				case OMUL:
+				case OLMUL:
+					mulgen(n->type, r, &nod);
+					break;
+				case ODIV:
+					sdiv2(r->vconst, v, l, &nod);
+					break;
+				case OMOD:
+					smod2(r->vconst, v, l, &nod);
+					break;
+				}
+				gmove(&nod, nn);
+				regfree(&nod);
+				goto done;
+			case OLDIV:
+				c = r->vconst;
+				if((c & 0x80000000) == 0)
+					break;
+				regalloc(&nod1, l, Z);
+				cgen(l, &nod1);
+				regalloc(&nod, l, nn);
+				zeroregm(&nod);
+				gins(ACMPL, &nod1, nodconst(c));
+				gins(ASBBL, nodconst(-1), &nod);
+				regfree(&nod1);
+				gmove(&nod, nn);
+				regfree(&nod);
+				goto done;
+			}
+		}
+
+		if(o == OMUL) {
+			if(l->addable >= INDEXED) {
+				t = l;
+				l = r;
+				r = t;
+			}
+			/* should favour AX */
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			if(r->addable < INDEXED || hardconst(r)) {
+				regalloc(&nod1, r, Z);
+				cgen(r, &nod1);
+				gopcode(OMUL, n->type, &nod1, &nod);
+				regfree(&nod1);
+			}else
+				gopcode(OMUL, n->type, r, &nod);	/* addressible */
+			gmove(&nod, nn);
+			regfree(&nod);
+			break;
+		}
+
+		/*
+		 * get nod to be D_AX
+		 * get nod1 to be D_DX
+		 */
+		if(nodreg(&nod, nn, D_AX)) {
+			regsalloc(&nod2, n);
+			gmove(&nod, &nod2);
+			v = reg[D_AX];
+			reg[D_AX] = 0;
+
+			if(isreg(l, D_AX)) {
+				nod3 = *n;
+				nod3.left = &nod2;
+				cgen(&nod3, nn);
+			} else
+			if(isreg(r, D_AX)) {
+				nod3 = *n;
+				nod3.right = &nod2;
+				cgen(&nod3, nn);
+			} else
+				cgen(n, nn);
+
+			gmove(&nod2, &nod);
+			reg[D_AX] = v;
+			break;
+		}
+		if(nodreg(&nod1, nn, D_DX)) {
+			regsalloc(&nod2, n);
+			gmove(&nod1, &nod2);
+			v = reg[D_DX];
+			reg[D_DX] = 0;
+
+			if(isreg(l, D_DX)) {
+				nod3 = *n;
+				nod3.left = &nod2;
+				cgen(&nod3, nn);
+			} else
+			if(isreg(r, D_DX)) {
+				nod3 = *n;
+				nod3.right = &nod2;
+				cgen(&nod3, nn);
+			} else
+				cgen(n, nn);
+
+			gmove(&nod2, &nod1);
+			reg[D_DX] = v;
+			break;
+		}
+		reg[D_AX]++;
+
+		if(r->op == OCONST && (o == ODIV || o == OLDIV) && immconst(r) && typechl[r->type->etype]) {
+			reg[D_DX]++;
+			if(l->addable < INDEXED) {
+				regalloc(&nod2, l, Z);
+				cgen(l, &nod2);
+				l = &nod2;
+			}
+			if(o == ODIV)
+				sdivgen(l, r, &nod, &nod1);
+			else
+				udivgen(l, r, &nod, &nod1);
+			gmove(&nod1, nn);
+			if(l == &nod2)
+				regfree(l);
+			goto freeaxdx;
+		}
+
+		if(l->complex >= r->complex) {
+			cgen(l, &nod);
+			reg[D_DX]++;
+			if(o == ODIV || o == OMOD)
+				gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+			if(o == OLDIV || o == OLMOD)
+				zeroregm(&nod1);
+			if(r->addable < INDEXED || r->op == OCONST) {
+				regsalloc(&nod3, r);
+				cgen(r, &nod3);
+				gopcode(o, n->type, &nod3, Z);
+			} else
+				gopcode(o, n->type, r, Z);
+		} else {
+			regsalloc(&nod3, r);
+			cgen(r, &nod3);
+			cgen(l, &nod);
+			reg[D_DX]++;
+			if(o == ODIV || o == OMOD)
+				gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+			if(o == OLDIV || o == OLMOD)
+				zeroregm(&nod1);
+			gopcode(o, n->type, &nod3, Z);
+		}
+		if(o == OMOD || o == OLMOD)
+			gmove(&nod1, nn);
+		else
+			gmove(&nod, nn);
+	freeaxdx:
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	case OASLSHR:
+	case OASASHL:
+	case OASASHR:
+		if(r->op == OCONST)
+			goto asand;
+		if(l->op == OBIT)
+			goto asbitop;
+		if(typefd[n->type->etype])
+			goto asand;	/* can this happen? */
+
+		/*
+		 * get nod to be D_CX
+		 */
+		if(nodreg(&nod, nn, D_CX)) {
+			regsalloc(&nod1, n);
+			gmove(&nod, &nod1);
+			cgen(n, &nod);
+			if(nn != Z)
+				gmove(&nod, nn);
+			gmove(&nod1, &nod);
+			break;
+		}
+		reg[D_CX]++;
+
+		if(r->complex >= l->complex) {
+			cgen(r, &nod);
+			if(hardleft)
+				reglcgen(&nod1, l, Z);
+			else
+				nod1 = *l;
+		} else {
+			if(hardleft)
+				reglcgen(&nod1, l, Z);
+			else
+				nod1 = *l;
+			cgen(r, &nod);
+		}
+
+		gopcode(o, l->type, &nod, &nod1);
+		regfree(&nod);
+		if(nn != Z)
+			gmove(&nod1, nn);
+		if(hardleft)
+			regfree(&nod1);
+		break;
+
+	case OASAND:
+	case OASADD:
+	case OASSUB:
+	case OASXOR:
+	case OASOR:
+	asand:
+		if(l->op == OBIT)
+			goto asbitop;
+		if(typefd[l->type->etype] || typefd[r->type->etype])
+			goto asfop;
+		if(l->complex >= r->complex) {
+			if(hardleft)
+				reglcgen(&nod, l, Z);
+			else
+				nod = *l;
+			if(!immconst(r)) {
+				regalloc(&nod1, r, nn);
+				cgen(r, &nod1);
+				gopcode(o, l->type, &nod1, &nod);
+				regfree(&nod1);
+			} else
+				gopcode(o, l->type, r, &nod);
+		} else {
+			regalloc(&nod1, r, nn);
+			cgen(r, &nod1);
+			if(hardleft)
+				reglcgen(&nod, l, Z);
+			else
+				nod = *l;
+			gopcode(o, l->type, &nod1, &nod);
+			regfree(&nod1);
+		}
+		if(nn != Z)
+			gmove(&nod, nn);
+		if(hardleft)
+			regfree(&nod);
+		break;
+
+	asfop:
+		if(l->complex >= r->complex) {
+			if(hardleft)
+				reglcgen(&nod, l, Z);
+			else
+				nod = *l;
+			if(r->addable < INDEXED){
+				regalloc(&nod1, r, nn);
+				cgen(r, &nod1);
+			}else
+				nod1 = *r;
+			regalloc(&nod2, r, Z);
+			gmove(&nod, &nod2);
+			gopcode(o, r->type, &nod1, &nod2);
+			gmove(&nod2, &nod);
+			regfree(&nod2);
+			if(r->addable < INDEXED)
+				regfree(&nod1);
+		} else {
+			regalloc(&nod1, r, nn);
+			cgen(r, &nod1);
+			if(hardleft)
+				reglcgen(&nod, l, Z);
+			else
+				nod = *l;
+			if(o != OASMUL && o != OASADD) {
+				regalloc(&nod2, r, Z);
+				gmove(&nod, &nod2);
+				gopcode(o, r->type, &nod1, &nod2);
+				regfree(&nod1);
+				gmove(&nod2, &nod);
+				regfree(&nod2);
+			} else {
+				gopcode(o, r->type, &nod, &nod1);
+				gmove(&nod1, &nod);
+				regfree(&nod1);
+			}
+		}
+		if(nn != Z)
+			gmove(&nod, nn);
+		if(hardleft)
+			regfree(&nod);
+		break;
+
+	case OASLMUL:
+	case OASLDIV:
+	case OASLMOD:
+	case OASMUL:
+	case OASDIV:
+	case OASMOD:
+		if(l->op == OBIT)
+			goto asbitop;
+		if(typefd[n->type->etype] || typefd[r->type->etype])
+			goto asfop;
+		if(r->op == OCONST && typechl[n->type->etype]) {
+			SET(v);
+			switch(o) {
+			case OASDIV:
+			case OASMOD:
+				c = r->vconst;
+				if(c < 0)
+					c = -c;
+				v = log2(c);
+				if(v < 0)
+					break;
+				/* fall thru */
+			case OASMUL:
+			case OASLMUL:
+				if(hardleft)
+					reglcgen(&nod2, l, Z);
+				else
+					nod2 = *l;
+				regalloc(&nod, l, nn);
+				cgen(&nod2, &nod);
+				switch(o) {
+				case OASMUL:
+				case OASLMUL:
+					mulgen(n->type, r, &nod);
+					break;
+				case OASDIV:
+					sdiv2(r->vconst, v, l, &nod);
+					break;
+				case OASMOD:
+					smod2(r->vconst, v, l, &nod);
+					break;
+				}
+			havev:
+				gmove(&nod, &nod2);
+				if(nn != Z)
+					gmove(&nod, nn);
+				if(hardleft)
+					regfree(&nod2);
+				regfree(&nod);
+				goto done;
+			case OASLDIV:
+				c = r->vconst;
+				if((c & 0x80000000) == 0)
+					break;
+				if(hardleft)
+					reglcgen(&nod2, l, Z);
+				else
+					nod2 = *l;
+				regalloc(&nod1, l, nn);
+				cgen(&nod2, &nod1);
+				regalloc(&nod, l, nn);
+				zeroregm(&nod);
+				gins(ACMPL, &nod1, nodconst(c));
+				gins(ASBBL, nodconst(-1), &nod);
+				regfree(&nod1);
+				goto havev;
+			}
+		}
+
+		if(o == OASMUL) {
+			/* should favour AX */
+			regalloc(&nod, l, nn);
+			if(r->complex >= FNX) {
+				regalloc(&nod1, r, Z);
+				cgen(r, &nod1);
+				r = &nod1;
+			}
+			if(hardleft)
+				reglcgen(&nod2, l, Z);
+			else
+				nod2 = *l;
+			cgen(&nod2, &nod);
+			if(r->addable < INDEXED || hardconst(r)) {
+				if(r->complex < FNX) {
+					regalloc(&nod1, r, Z);
+					cgen(r, &nod1);
+				}
+				gopcode(OASMUL, n->type, &nod1, &nod);
+				regfree(&nod1);
+			}
+			else
+				gopcode(OASMUL, n->type, r, &nod);
+			if(r == &nod1)
+				regfree(r);
+			gmove(&nod, &nod2);
+			if(nn != Z)
+				gmove(&nod, nn);
+			regfree(&nod);
+			if(hardleft)
+				regfree(&nod2);
+			break;
+		}
+
+		/*
+		 * get nod to be D_AX
+		 * get nod1 to be D_DX
+		 */
+		if(nodreg(&nod, nn, D_AX)) {
+			regsalloc(&nod2, n);
+			gmove(&nod, &nod2);
+			v = reg[D_AX];
+			reg[D_AX] = 0;
+
+			if(isreg(l, D_AX)) {
+				nod3 = *n;
+				nod3.left = &nod2;
+				cgen(&nod3, nn);
+			} else
+			if(isreg(r, D_AX)) {
+				nod3 = *n;
+				nod3.right = &nod2;
+				cgen(&nod3, nn);
+			} else
+				cgen(n, nn);
+
+			gmove(&nod2, &nod);
+			reg[D_AX] = v;
+			break;
+		}
+		if(nodreg(&nod1, nn, D_DX)) {
+			regsalloc(&nod2, n);
+			gmove(&nod1, &nod2);
+			v = reg[D_DX];
+			reg[D_DX] = 0;
+
+			if(isreg(l, D_DX)) {
+				nod3 = *n;
+				nod3.left = &nod2;
+				cgen(&nod3, nn);
+			} else
+			if(isreg(r, D_DX)) {
+				nod3 = *n;
+				nod3.right = &nod2;
+				cgen(&nod3, nn);
+			} else
+				cgen(n, nn);
+
+			gmove(&nod2, &nod1);
+			reg[D_DX] = v;
+			break;
+		}
+		reg[D_AX]++;
+		reg[D_DX]++;
+
+		if(l->complex >= r->complex) {
+			if(hardleft)
+				reglcgen(&nod2, l, Z);
+			else
+				nod2 = *l;
+			cgen(&nod2, &nod);
+			if(r->op == OCONST && typechl[r->type->etype]) {
+				switch(o) {
+				case OASDIV:
+					sdivgen(&nod2, r, &nod, &nod1);
+					goto divdone;
+				case OASLDIV:
+					udivgen(&nod2, r, &nod, &nod1);
+				divdone:
+					gmove(&nod1, &nod2);
+					if(nn != Z)
+						gmove(&nod1, nn);
+					goto freelxaxdx;
+				}
+			}
+			if(o == OASDIV || o == OASMOD)
+				gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+			if(o == OASLDIV || o == OASLMOD)
+				zeroregm(&nod1);
+			if(r->addable < INDEXED || r->op == OCONST ||
+			   !typeil[r->type->etype]) {
+				regalloc(&nod3, r, Z);
+				cgen(r, &nod3);
+				gopcode(o, l->type, &nod3, Z);
+				regfree(&nod3);
+			} else
+				gopcode(o, n->type, r, Z);
+		} else {
+			regalloc(&nod3, r, Z);
+			cgen(r, &nod3);
+			if(hardleft)
+				reglcgen(&nod2, l, Z);
+			else
+				nod2 = *l;
+			cgen(&nod2, &nod);
+			if(o == OASDIV || o == OASMOD)
+				gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+			if(o == OASLDIV || o == OASLMOD)
+				zeroregm(&nod1);
+			gopcode(o, l->type, &nod3, Z);
+			regfree(&nod3);
+		}
+		if(o == OASMOD || o == OASLMOD) {
+			gmove(&nod1, &nod2);
+			if(nn != Z)
+				gmove(&nod1, nn);
+		} else {
+			gmove(&nod, &nod2);
+			if(nn != Z)
+				gmove(&nod, nn);
+		}
+	freelxaxdx:
+		if(hardleft)
+			regfree(&nod2);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	fop:
+		if(l->complex >= r->complex) {
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			if(r->addable < INDEXED) {
+				regalloc(&nod1, r, Z);
+				cgen(r, &nod1);
+				gopcode(o, n->type, &nod1, &nod);
+				regfree(&nod1);
+			} else
+				gopcode(o, n->type, r, &nod);
+		} else {
+			/* TO DO: could do better with r->addable >= INDEXED */
+			regalloc(&nod1, r, Z);
+			cgen(r, &nod1);
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			gopcode(o, n->type, &nod1, &nod);
+			regfree(&nod1);
+		}
+		gmove(&nod, nn);
+		regfree(&nod);
+		break;
+
+	asbitop:
+		regalloc(&nod4, n, nn);
+		if(l->complex >= r->complex) {
+			bitload(l, &nod, &nod1, &nod2, &nod4);
+			regalloc(&nod3, r, Z);
+			cgen(r, &nod3);
+		} else {
+			regalloc(&nod3, r, Z);
+			cgen(r, &nod3);
+			bitload(l, &nod, &nod1, &nod2, &nod4);
+		}
+		gmove(&nod, &nod4);
+
+		{	/* TO DO: check floating point source */
+			Node onod;
+
+			/* incredible grot ... */
+			onod = nod3;
+			onod.op = o;
+			onod.complex = 2;
+			onod.addable = 0;
+			onod.type = tfield;
+			onod.left = &nod4;
+			onod.right = &nod3;
+			cgen(&onod, Z);
+		}
+		regfree(&nod3);
+		gmove(&nod4, &nod);
+		regfree(&nod4);
+		bitstore(l, &nod, &nod1, &nod2, nn);
+		break;
+
+	case OADDR:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		lcgen(l, nn);
+		break;
+
+	case OFUNC:
+		if(l->complex >= FNX) {
+			if(l->op != OIND)
+				diag(n, "bad function call");
+
+			regret(&nod, l->left);
+			cgen(l->left, &nod);
+			regsalloc(&nod1, l->left);
+			gmove(&nod, &nod1);
+			regfree(&nod);
+
+			nod = *n;
+			nod.left = &nod2;
+			nod2 = *l;
+			nod2.left = &nod1;
+			nod2.complex = 1;
+			cgen(&nod, nn);
+
+			return;
+		}
+		o = reg[REGARG];
+		gargs(r, &nod, &nod1);
+		if(l->addable < INDEXED) {
+			reglcgen(&nod, l, nn);
+			nod.op = OREGISTER;
+			gopcode(OFUNC, n->type, Z, &nod);
+			regfree(&nod);
+		} else
+			gopcode(OFUNC, n->type, Z, l);
+		if(REGARG)
+			if(o != reg[REGARG])
+				reg[REGARG]--;
+		if(nn != Z) {
+			regret(&nod, n);
+			gmove(&nod, nn);
+			regfree(&nod);
+		}
+		break;
+
+	case OIND:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		regialloc(&nod, n, nn);
+		r = l;
+		while(r->op == OADD)
+			r = r->right;
+		if(sconst(r)) {
+			v = r->vconst;
+			r->vconst = 0;
+			cgen(l, &nod);
+			nod.xoffset += v;
+			r->vconst = v;
+		} else
+			cgen(l, &nod);
+		regind(&nod, n);
+		gmove(&nod, nn);
+		regfree(&nod);
+		break;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OLO:
+	case OLS:
+	case OHI:
+	case OHS:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		boolgen(n, 1, nn);
+		break;
+
+	case OANDAND:
+	case OOROR:
+		boolgen(n, 1, nn);
+		if(nn == Z)
+			patch(p, pc);
+		break;
+
+	case ONOT:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		boolgen(n, 1, nn);
+		break;
+
+	case OCOMMA:
+		cgen(l, Z);
+		cgen(r, nn);
+		break;
+
+	case OCAST:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		/*
+		 * convert from types l->n->nn
+		 */
+		if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
+			/* both null, gen l->nn */
+			cgen(l, nn);
+			break;
+		}
+		if(ewidth[n->type->etype] < ewidth[l->type->etype]){
+			if(l->type->etype == TIND && typechlp[n->type->etype])
+				warn(n, "conversion of pointer to shorter integer");
+		}else if(0){
+			if(nocast(n->type, nn->type) || castup(n->type, nn->type)){
+				if(typefd[l->type->etype] != typefd[nn->type->etype])
+					regalloc(&nod, l, nn);
+				else
+					regalloc(&nod, nn, nn);
+				cgen(l, &nod);
+				gmove(&nod, nn);
+				regfree(&nod);
+				break;
+			}
+		}
+		regalloc(&nod, l, nn);
+		cgen(l, &nod);
+		regalloc(&nod1, n, &nod);
+		gmove(&nod, &nod1);
+		gmove(&nod1, nn);
+		regfree(&nod1);
+		regfree(&nod);
+		break;
+
+	case ODOT:
+		sugen(l, nodrat, l->type->width);
+		if(nn == Z)
+			break;
+		warn(n, "non-interruptable temporary");
+		nod = *nodrat;
+		if(!r || r->op != OCONST) {
+			diag(n, "DOT and no offset");
+			break;
+		}
+		nod.xoffset += (long)r->vconst;
+		nod.type = n->type;
+		cgen(&nod, nn);
+		break;
+
+	case OCOND:
+		bcgen(l, 1);
+		p1 = p;
+		cgen(r->left, nn);
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		cgen(r->right, nn);
+		patch(p1, pc);
+		break;
+
+	case OPOSTINC:
+	case OPOSTDEC:
+		v = 1;
+		if(l->type->etype == TIND)
+			v = l->type->link->width;
+		if(o == OPOSTDEC)
+			v = -v;
+		if(l->op == OBIT)
+			goto bitinc;
+		if(nn == Z)
+			goto pre;
+
+		if(hardleft)
+			reglcgen(&nod, l, Z);
+		else
+			nod = *l;
+
+		gmove(&nod, nn);
+		if(typefd[n->type->etype]) {
+			regalloc(&nod1, l, Z);
+			gmove(&nod, &nod1);
+			if(v < 0)
+				gopcode(OSUB, n->type, nodfconst(-v), &nod1);
+			else
+				gopcode(OADD, n->type, nodfconst(v), &nod1);
+			gmove(&nod1, &nod);
+			regfree(&nod1);
+		} else
+			gopcode(OADD, n->type, nodconst(v), &nod);
+		if(hardleft)
+			regfree(&nod);
+		break;
+
+	case OPREINC:
+	case OPREDEC:
+		v = 1;
+		if(l->type->etype == TIND)
+			v = l->type->link->width;
+		if(o == OPREDEC)
+			v = -v;
+		if(l->op == OBIT)
+			goto bitinc;
+
+	pre:
+		if(hardleft)
+			reglcgen(&nod, l, Z);
+		else
+			nod = *l;
+		if(typefd[n->type->etype]) {
+			regalloc(&nod1, l, Z);
+			gmove(&nod, &nod1);
+			if(v < 0)
+				gopcode(OSUB, n->type, nodfconst(-v), &nod1);
+			else
+				gopcode(OADD, n->type, nodfconst(v), &nod1);
+			gmove(&nod1, &nod);
+			regfree(&nod1);
+		} else
+			gopcode(OADD, n->type, nodconst(v), &nod);
+		if(nn != Z)
+			gmove(&nod, nn);
+		if(hardleft)
+			regfree(&nod);
+		break;
+
+	bitinc:
+		if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+			bitload(l, &nod, &nod1, &nod2, Z);
+			gmove(&nod, nn);
+			gopcode(OADD, tfield, nodconst(v), &nod);
+			bitstore(l, &nod, &nod1, &nod2, Z);
+			break;
+		}
+		bitload(l, &nod, &nod1, &nod2, nn);
+		gopcode(OADD, tfield, nodconst(v), &nod);
+		bitstore(l, &nod, &nod1, &nod2, nn);
+		break;
+	}
+done:
+	cursafe = curs;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+	Node *r;
+	long v;
+
+	regialloc(t, n, nn);
+	if(n->op == OIND) {
+		r = n->left;
+		while(r->op == OADD)
+			r = r->right;
+		if(sconst(r)) {
+			v = r->vconst;
+			r->vconst = 0;
+			lcgen(n, t);
+			t->xoffset += v;
+			r->vconst = v;
+			regind(t, n);
+			return;
+		}
+	}
+	lcgen(n, t);
+	regind(t, n);
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+	Prog *p1;
+	Node nod;
+
+	if(debug['g']) {
+		prtree(nn, "lcgen lhs");
+		prtree(n, "lcgen");
+	}
+	if(n == Z || n->type == T)
+		return;
+	if(nn == Z) {
+		nn = &nod;
+		regalloc(&nod, n, Z);
+	}
+	switch(n->op) {
+	default:
+		if(n->addable < INDEXED) {
+			diag(n, "unknown op in lcgen: %O", n->op);
+			break;
+		}
+		gopcode(OADDR, n->type, n, nn);
+		break;
+
+	case OCOMMA:
+		cgen(n->left, n->left);
+		lcgen(n->right, nn);
+		break;
+
+	case OIND:
+		cgen(n->left, nn);
+		break;
+
+	case OCOND:
+		bcgen(n->left, 1);
+		p1 = p;
+		lcgen(n->right->left, nn);
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		lcgen(n->right->right, nn);
+		patch(p1, pc);
+		break;
+	}
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+	if(n->type == T)
+		gbranch(OGOTO);
+	else
+		boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+	int o;
+	Prog *p1, *p2;
+	Node *l, *r, nod, nod1;
+	long curs;
+
+	if(debug['g']) {
+		prtree(nn, "boolgen lhs");
+		prtree(n, "boolgen");
+	}
+	curs = cursafe;
+	l = n->left;
+	r = n->right;
+	switch(n->op) {
+
+	default:
+		o = ONE;
+		if(true)
+			o = OEQ;
+		/* bad, 13 is address of external that becomes constant */
+		if(n->addable >= INDEXED && n->addable != 13) {
+			if(typefd[n->type->etype]) {
+				regalloc(&nod1, n, Z);
+				gmove(nodfconst(0.0), &nod1);	/* TO DO: FREGZERO */
+				gopcode(o, n->type, n, &nod1);
+				regfree(&nod1);
+			} else
+				gopcode(o, n->type, n, nodconst(0));
+			goto com;
+		}
+		regalloc(&nod, n, nn);
+		cgen(n, &nod);
+		if(typefd[n->type->etype]) {
+			regalloc(&nod1, n, Z);
+			gmove(nodfconst(0.0), &nod1);	/* TO DO: FREGZERO */
+			gopcode(o, n->type, &nod, &nod1);
+			regfree(&nod1);
+		} else
+			gopcode(o, n->type, &nod, nodconst(0));
+		regfree(&nod);
+		goto com;
+
+	case OCONST:
+		o = vconst(n);
+		if(!true)
+			o = !o;
+		gbranch(OGOTO);
+		if(o) {
+			p1 = p;
+			gbranch(OGOTO);
+			patch(p1, pc);
+		}
+		goto com;
+
+	case OCOMMA:
+		cgen(l, Z);
+		boolgen(r, true, nn);
+		break;
+
+	case ONOT:
+		boolgen(l, !true, nn);
+		break;
+
+	case OCOND:
+		bcgen(l, 1);
+		p1 = p;
+		bcgen(r->left, true);
+		p2 = p;
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		bcgen(r->right, !true);
+		patch(p2, pc);
+		p2 = p;
+		gbranch(OGOTO);
+		patch(p1, pc);
+		patch(p2, pc);
+		goto com;
+
+	case OANDAND:
+		if(!true)
+			goto caseor;
+
+	caseand:
+		bcgen(l, true);
+		p1 = p;
+		bcgen(r, !true);
+		p2 = p;
+		patch(p1, pc);
+		gbranch(OGOTO);
+		patch(p2, pc);
+		goto com;
+
+	case OOROR:
+		if(!true)
+			goto caseand;
+
+	caseor:
+		bcgen(l, !true);
+		p1 = p;
+		bcgen(r, !true);
+		p2 = p;
+		gbranch(OGOTO);
+		patch(p1, pc);
+		patch(p2, pc);
+		goto com;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OHI:
+	case OHS:
+	case OLO:
+	case OLS:
+		o = n->op;
+		if(true)
+			o = comrel[relindex(o)];
+		if(l->complex >= FNX && r->complex >= FNX) {
+			regret(&nod, r);
+			cgen(r, &nod);
+			regsalloc(&nod1, r);
+			gmove(&nod, &nod1);
+			regfree(&nod);
+			nod = *n;
+			nod.right = &nod1;
+			boolgen(&nod, true, nn);
+			break;
+		}
+		if(immconst(l)) {
+			o = invrel[relindex(o)];
+			/* bad, 13 is address of external that becomes constant */
+			if(r->addable < INDEXED || r->addable == 13) {
+				regalloc(&nod, r, nn);
+				cgen(r, &nod);
+				gopcode(o, l->type, &nod, l);
+				regfree(&nod);
+			} else
+				gopcode(o, l->type, r, l);
+			goto com;
+		}
+		if(typefd[l->type->etype])
+			o = invrel[relindex(logrel[relindex(o)])];
+		if(l->complex >= r->complex) {
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			if(r->addable < INDEXED || hardconst(r) || typefd[l->type->etype]) {
+				regalloc(&nod1, r, Z);
+				cgen(r, &nod1);
+				gopcode(o, l->type, &nod, &nod1);
+				regfree(&nod1);
+			} else
+				gopcode(o, l->type, &nod, r);
+			regfree(&nod);
+			goto com;
+		}
+		regalloc(&nod, r, nn);
+		cgen(r, &nod);
+		if(l->addable < INDEXED || l->addable == 13 || hardconst(l)) {
+			regalloc(&nod1, l, Z);
+			cgen(l, &nod1);
+			if(typechl[l->type->etype] && ewidth[l->type->etype] <= ewidth[TINT])
+				gopcode(o, types[TINT], &nod1, &nod);
+			else
+				gopcode(o, l->type, &nod1, &nod);
+			regfree(&nod1);
+		} else
+			gopcode(o, l->type, l, &nod);
+		regfree(&nod);
+
+	com:
+		if(nn != Z) {
+			p1 = p;
+			gmove(nodconst(1L), nn);
+			gbranch(OGOTO);
+			p2 = p;
+			patch(p1, pc);
+			gmove(nodconst(0L), nn);
+			patch(p2, pc);
+		}
+		break;
+	}
+	cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, long w)
+{
+	Prog *p1;
+	Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+	Type *t;
+	int c, mt, mo;
+	vlong o0, o1;
+
+	if(n == Z || n->type == T)
+		return;
+	if(debug['g']) {
+		prtree(nn, "sugen lhs");
+		prtree(n, "sugen");
+	}
+	if(nn == nodrat)
+		if(w > nrathole)
+			nrathole = w;
+	switch(n->op) {
+	case OIND:
+		if(nn == Z) {
+			nullwarn(n->left, Z);
+			break;
+		}
+
+	default:
+		goto copy;
+
+	case OCONST:
+		goto copy;
+
+	case ODOT:
+		l = n->left;
+		sugen(l, nodrat, l->type->width);
+		if(nn == Z)
+			break;
+		warn(n, "non-interruptable temporary");
+		nod1 = *nodrat;
+		r = n->right;
+		if(!r || r->op != OCONST) {
+			diag(n, "DOT and no offset");
+			break;
+		}
+		nod1.xoffset += (long)r->vconst;
+		nod1.type = n->type;
+		sugen(&nod1, nn, w);
+		break;
+
+	case OSTRUCT:
+		/*
+		 * rewrite so lhs has no fn call
+		 */
+		if(nn != Z && side(nn)) {
+			nod1 = *n;
+			nod1.type = typ(TIND, n->type);
+			regret(&nod2, &nod1);
+			lcgen(nn, &nod2);
+			regsalloc(&nod0, &nod1);
+			cgen(&nod2, &nod0);
+			regfree(&nod2);
+
+			nod1 = *n;
+			nod1.op = OIND;
+			nod1.left = &nod0;
+			nod1.right = Z;
+			nod1.complex = 1;
+
+			sugen(n, &nod1, w);
+			return;
+		}
+
+		r = n->left;
+		for(t = n->type->link; t != T; t = t->down) {
+			l = r;
+			if(r->op == OLIST) {
+				l = r->left;
+				r = r->right;
+			}
+			if(nn == Z) {
+				cgen(l, nn);
+				continue;
+			}
+			/*
+			 * hand craft *(&nn + o) = l
+			 */
+			nod0 = znode;
+			nod0.op = OAS;
+			nod0.type = t;
+			nod0.left = &nod1;
+			nod0.right = nil;
+
+			nod1 = znode;
+			nod1.op = OIND;
+			nod1.type = t;
+			nod1.left = &nod2;
+
+			nod2 = znode;
+			nod2.op = OADD;
+			nod2.type = typ(TIND, t);
+			nod2.left = &nod3;
+			nod2.right = &nod4;
+
+			nod3 = znode;
+			nod3.op = OADDR;
+			nod3.type = nod2.type;
+			nod3.left = nn;
+
+			nod4 = znode;
+			nod4.op = OCONST;
+			nod4.type = nod2.type;
+			nod4.vconst = t->offset;
+
+			ccom(&nod0);
+			acom(&nod0);
+			xcom(&nod0);
+			nod0.addable = 0;
+			nod0.right = l;
+
+			/* prtree(&nod0, "hand craft"); /* */
+			cgen(&nod0, Z);
+		}
+		break;
+
+	case OAS:
+		if(nn == Z) {
+			if(n->addable < INDEXED)
+				sugen(n->right, n->left, w);
+			break;
+		}
+
+		sugen(n->right, nodrat, w);
+		warn(n, "non-interruptable temporary");
+		sugen(nodrat, n->left, w);
+		sugen(nodrat, nn, w);
+		break;
+
+	case OFUNC:
+		if(nn == Z) {
+			sugen(n, nodrat, w);
+			break;
+		}
+		if(nn->op != OIND) {
+			nn = new1(OADDR, nn, Z);
+			nn->type = types[TIND];
+			nn->addable = 0;
+		} else
+			nn = nn->left;
+		n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+		n->type = types[TVOID];
+		n->left->type = types[TVOID];
+		cgen(n, Z);
+		break;
+
+	case OCOND:
+		bcgen(n->left, 1);
+		p1 = p;
+		sugen(n->right->left, nn, w);
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		sugen(n->right->right, nn, w);
+		patch(p1, pc);
+		break;
+
+	case OCOMMA:
+		cgen(n->left, Z);
+		sugen(n->right, nn, w);
+		break;
+	}
+	return;
+
+copy:
+	if(nn == Z) {
+		switch(n->op) {
+		case OASADD:
+		case OASSUB:
+		case OASAND:
+		case OASOR:
+		case OASXOR:
+
+		case OASMUL:
+		case OASLMUL:
+
+
+		case OASASHL:
+		case OASASHR:
+		case OASLSHR:
+			break;
+
+		case OPOSTINC:
+		case OPOSTDEC:
+		case OPREINC:
+		case OPREDEC:
+			break;
+
+		default:
+			return;
+		}
+	}
+
+	if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
+		t = nn->type;
+		nn->type = types[TLONG];
+		regialloc(&nod1, nn, Z);
+		lcgen(nn, &nod1);
+		regsalloc(&nod2, nn);
+		nn->type = t;
+
+		gins(AMOVL, &nod1, &nod2);
+		regfree(&nod1);
+
+		nod2.type = typ(TIND, t);
+
+		nod1 = nod2;
+		nod1.op = OIND;
+		nod1.left = &nod2;
+		nod1.right = Z;
+		nod1.complex = 1;
+		nod1.type = t;
+
+		sugen(n, &nod1, w);
+		return;
+	}
+
+	if(w <= 32) {
+		c = cursafe;
+		if(n->left != Z && n->left->complex >= FNX
+		&& n->right != Z && n->right->complex >= FNX) {
+			regsalloc(&nod1, n->right);
+			cgen(n->right, &nod1);
+			nod2 = *n;
+			nod2.right = &nod1;
+			cgen(&nod2, nn);
+			cursafe = c;
+			return;
+		}
+		if(w & 7) {
+			mt = TLONG;
+			mo = AMOVL;
+		} else {
+			mt = TVLONG;
+			mo = AMOVQ;
+		}
+		if(n->complex > nn->complex) {
+			t = n->type;
+			n->type = types[mt];
+			regalloc(&nod0, n, Z);
+			if(!vaddr(n, 0)) {
+				reglcgen(&nod1, n, Z);
+				n->type = t;
+				n = &nod1;
+			}
+			else
+				n->type = t;
+
+			t = nn->type;
+			nn->type = types[mt];
+			if(!vaddr(nn, 0)) {
+				reglcgen(&nod2, nn, Z);
+				nn->type = t;
+				nn = &nod2;
+			}
+			else
+				nn->type = t;
+		} else {
+			t = nn->type;
+			nn->type = types[mt];
+			regalloc(&nod0, nn, Z);
+			if(!vaddr(nn, 0)) {
+				reglcgen(&nod2, nn, Z);
+				nn->type = t;
+				nn = &nod2;
+			}
+			else
+				nn->type = t;
+
+			t = n->type;
+			n->type = types[mt];
+			if(!vaddr(n, 0)) {
+				reglcgen(&nod1, n, Z);
+				n->type = t;
+				n = &nod1;
+			}
+			else
+				n->type = t;
+		}
+		o0 = n->xoffset;
+		o1 = nn->xoffset;
+		w /= ewidth[mt];
+		while(--w >= 0) {
+			gins(mo, n, &nod0);
+			gins(mo, &nod0, nn);
+			n->xoffset += ewidth[mt];
+			nn->xoffset += ewidth[mt];
+		}
+		n->xoffset = o0;
+		nn->xoffset = o1;
+		if(nn == &nod2)
+			regfree(&nod2);
+		if(n == &nod1)
+			regfree(&nod1);
+		regfree(&nod0);
+		return;
+	}
+
+	/* botch, need to save in .safe */
+	c = 0;
+	if(n->complex > nn->complex) {
+		t = n->type;
+		n->type = types[TLONG];
+		nodreg(&nod1, n, D_SI);
+		if(reg[D_SI]) {
+			gins(APUSHQ, &nod1, Z);
+			c |= 1;
+			reg[D_SI]++;
+		}
+		lcgen(n, &nod1);
+		n->type = t;
+
+		t = nn->type;
+		nn->type = types[TLONG];
+		nodreg(&nod2, nn, D_DI);
+		if(reg[D_DI]) {
+warn(Z, "DI botch");
+			gins(APUSHQ, &nod2, Z);
+			c |= 2;
+			reg[D_DI]++;
+		}
+		lcgen(nn, &nod2);
+		nn->type = t;
+	} else {
+		t = nn->type;
+		nn->type = types[TLONG];
+		nodreg(&nod2, nn, D_DI);
+		if(reg[D_DI]) {
+warn(Z, "DI botch");
+			gins(APUSHQ, &nod2, Z);
+			c |= 2;
+			reg[D_DI]++;
+		}
+		lcgen(nn, &nod2);
+		nn->type = t;
+
+		t = n->type;
+		n->type = types[TLONG];
+		nodreg(&nod1, n, D_SI);
+		if(reg[D_SI]) {
+			gins(APUSHQ, &nod1, Z);
+			c |= 1;
+			reg[D_SI]++;
+		}
+		lcgen(n, &nod1);
+		n->type = t;
+	}
+	nodreg(&nod3, n, D_CX);
+	if(reg[D_CX]) {
+		gins(APUSHQ, &nod3, Z);
+		c |= 4;
+		reg[D_CX]++;
+	}
+	gins(AMOVL, nodconst(w/SZ_INT), &nod3);
+	gins(ACLD, Z, Z);
+	gins(AREP, Z, Z);
+	gins(AMOVSL, Z, Z);
+	if(c & 4) {
+		gins(APOPQ, Z, &nod3);
+		reg[D_CX]--;
+	}
+	if(c & 2) {
+		gins(APOPQ, Z, &nod2);
+		reg[nod2.reg]--;
+	}
+	if(c & 1) {
+		gins(APOPQ, Z, &nod1);
+		reg[nod1.reg]--;
+	}
+}
+
+/*
+ * TO DO
+ */
+void
+layout(Node *f, Node *t, int c, int cv, Node *cn)
+{
+	Node t1, t2;
+
+	while(c > 3) {
+		layout(f, t, 2, 0, Z);
+		c -= 2;
+	}
+
+	regalloc(&t1, &lregnode, Z);
+	regalloc(&t2, &lregnode, Z);
+	if(c > 0) {
+		gmove(f, &t1);
+		f->xoffset += SZ_INT;
+	}
+	if(cn != Z)
+		gmove(nodconst(cv), cn);
+	if(c > 1) {
+		gmove(f, &t2);
+		f->xoffset += SZ_INT;
+	}
+	if(c > 0) {
+		gmove(&t1, t);
+		t->xoffset += SZ_INT;
+	}
+	if(c > 2) {
+		gmove(f, &t1);
+		f->xoffset += SZ_INT;
+	}
+	if(c > 1) {
+		gmove(&t2, t);
+		t->xoffset += SZ_INT;
+	}
+	if(c > 2) {
+		gmove(&t1, t);
+		t->xoffset += SZ_INT;
+	}
+	regfree(&t1);
+	regfree(&t2);
+}
+
+/*
+ * constant is not vlong or fits as 32-bit signed immediate
+ */
+int
+immconst(Node *n)
+{
+	long v;
+
+	if(n->op != OCONST || !typechlpv[n->type->etype])
+		return 0;
+	if(typechl[n->type->etype])
+		return 1;
+	v = n->vconst;
+	return n->vconst == (vlong)v;
+}
+
+/*
+ * if a constant and vlong, doesn't fit as 32-bit signed immediate
+ */
+int
+hardconst(Node *n)
+{
+	return n->op == OCONST && !immconst(n);
+}
+
+/*
+ * casting up to t2 covers an intermediate cast to t1
+ */
+int
+castup(Type *t1, Type *t2)
+{
+	int ft;
+
+	if(!nilcast(t1, t2))
+		return 0;
+	/* known to be small to large */
+	ft = t1->etype;
+	switch(t2->etype){
+	case TINT:
+	case TLONG:
+		return ft == TLONG || ft == TINT || ft == TSHORT || ft == TCHAR;
+	case TUINT:
+	case TULONG:
+		return ft == TULONG || ft == TUINT || ft == TUSHORT || ft == TUCHAR;
+	case TVLONG:
+		return ft == TLONG || ft == TINT || ft == TSHORT;
+	case TUVLONG:
+		return ft == TULONG || ft == TUINT || ft == TUSHORT;
+	}
+	return 0;
+}
+
+void
+zeroregm(Node *n)
+{
+	gins(AMOVL, nodconst(0), n);
+}
+
+/* do we need to load the address of a vlong? */
+int
+vaddr(Node *n, int a)
+{
+	switch(n->op) {
+	case ONAME:
+		if(a)
+			return 1;
+		return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
+
+	case OCONST:
+	case OREGISTER:
+	case OINDREG:
+		return 1;
+	}
+	return 0;
+}
+
+long
+hi64v(Node *n)
+{
+	if(align(0, types[TCHAR], Aarg1))	/* isbigendian */
+		return (long)(n->vconst) & ~0L;
+	else
+		return (long)((uvlong)n->vconst>>32) & ~0L;
+}
+
+long
+lo64v(Node *n)
+{
+	if(align(0, types[TCHAR], Aarg1))	/* isbigendian */
+		return (long)((uvlong)n->vconst>>32) & ~0L;
+	else
+		return (long)(n->vconst) & ~0L;
+}
+
+Node *
+hi64(Node *n)
+{
+	return nodconst(hi64v(n));
+}
+
+Node *
+lo64(Node *n)
+{
+	return nodconst(lo64v(n));
+}
+
+int
+cond(int op)
+{
+	switch(op) {
+	case OANDAND:
+	case OOROR:
+	case ONOT:
+		return 1;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OHI:
+	case OHS:
+	case OLO:
+	case OLS:
+		return 1;
+	}
+	return 0;
+}
diff --git a/src/cmd/6c/div.c b/src/cmd/6c/div.c
new file mode 100644
index 0000000..4b63ddc
--- /dev/null
+++ b/src/cmd/6c/div.c
@@ -0,0 +1,236 @@
+// Inferno utils/6c/div.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/div.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+/*
+ * Based on: Granlund, T.; Montgomery, P.L.
+ * "Division by Invariant Integers using Multiplication".
+ * SIGPLAN Notices, Vol. 29, June 1994, page 61.
+ */
+
+#define	TN(n)	((uvlong)1 << (n))
+#define	T31	TN(31)
+#define	T32	TN(32)
+
+int
+multiplier(ulong d, int p, uvlong *mp)
+{
+	int l;
+	uvlong mlo, mhi, tlo, thi;
+
+	l = topbit(d - 1) + 1;
+	mlo = (((TN(l) - d) << 32) / d) + T32;
+	if(l + p == 64)
+		mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
+	else
+		mhi = (TN(32 + l) + TN(32 + l - p)) / d;
+	/*assert(mlo < mhi);*/
+	while(l > 0) {
+		tlo = mlo >> 1;
+		thi = mhi >> 1;
+		if(tlo == thi)
+			break;
+		mlo = tlo;
+		mhi = thi;
+		l--;
+	}
+	*mp = mhi;
+	return l;
+}
+
+int
+sdiv(ulong d, ulong *mp, int *sp)
+{
+	int s;
+	uvlong m;
+
+	s = multiplier(d, 32 - 1, &m);
+	*mp = m;
+	*sp = s;
+	if(m >= T31)
+		return 1;
+	else
+		return 0;
+}
+
+int
+udiv(ulong d, ulong *mp, int *sp, int *pp)
+{
+	int p, s;
+	uvlong m;
+
+	s = multiplier(d, 32, &m);
+	p = 0;
+	if(m >= T32) {
+		while((d & 1) == 0) {
+			d >>= 1;
+			p++;
+		}
+		s = multiplier(d, 32 - p, &m);
+	}
+	*mp = m;
+	*pp = p;
+	if(m >= T32) {
+		/*assert(p == 0);*/
+		*sp = s - 1;
+		return 1;
+	}
+	else {
+		*sp = s;
+		return 0;
+	}
+}
+
+void
+sdivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+	int a, s;
+	ulong m;
+	vlong c;
+
+	c = r->vconst;
+	if(c < 0)
+		c = -c;
+	a = sdiv(c, &m, &s);
+//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m);
+	gins(AMOVL, nodconst(m), ax);
+	gins(AIMULL, l, Z);
+	gins(AMOVL, l, ax);
+	if(a)
+		gins(AADDL, ax, dx);
+	gins(ASHRL, nodconst(31), ax);
+	gins(ASARL, nodconst(s), dx);
+	gins(AADDL, ax, dx);
+	if(r->vconst < 0)
+		gins(ANEGL, Z, dx);
+}
+
+void
+udivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+	int a, s, t;
+	ulong m;
+	Node nod;
+
+	a = udiv(r->vconst, &m, &s, &t);
+//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m);
+	if(t != 0) {
+		gins(AMOVL, l, ax);
+		gins(ASHRL, nodconst(t), ax);
+		gins(AMOVL, nodconst(m), dx);
+		gins(AMULL, dx, Z);
+	}
+	else if(a) {
+		if(l->op != OREGISTER) {
+			regalloc(&nod, l, Z);
+			gins(AMOVL, l, &nod);
+			l = &nod;
+		}
+		gins(AMOVL, nodconst(m), ax);
+		gins(AMULL, l, Z);
+		gins(AADDL, l, dx);
+		gins(ARCRL, nodconst(1), dx);
+		if(l == &nod)
+			regfree(l);
+	}
+	else {
+		gins(AMOVL, nodconst(m), ax);
+		gins(AMULL, l, Z);
+	}
+	if(s != 0)
+		gins(ASHRL, nodconst(s), dx);
+}
+
+void
+sext(Node *d, Node *s, Node *l)
+{
+	if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
+		reg[D_DX]++;
+		gins(ACDQ, Z, Z);
+	}
+	else {
+		regalloc(d, l, Z);
+		gins(AMOVL, s, d);
+		gins(ASARL, nodconst(31), d);
+	}
+}
+
+void
+sdiv2(long c, int v, Node *l, Node *n)
+{
+	Node nod;
+
+	if(v > 0) {
+		if(v > 1) {
+			sext(&nod, n, l);
+			gins(AANDL, nodconst((1 << v) - 1), &nod);
+			gins(AADDL, &nod, n);
+			regfree(&nod);
+		}
+		else {
+			gins(ACMPL, n, nodconst(0x80000000));
+			gins(ASBBL, nodconst(-1), n);
+		}
+		gins(ASARL, nodconst(v), n);
+	}
+	if(c < 0)
+		gins(ANEGL, Z, n);
+}
+
+void
+smod2(long c, int v, Node *l, Node *n)
+{
+	Node nod;
+
+	if(c == 1) {
+		zeroregm(n);
+		return;
+	}
+
+	sext(&nod, n, l);
+	if(v == 0) {
+		zeroregm(n);
+		gins(AXORL, &nod, n);
+		gins(ASUBL, &nod, n);
+	}
+	else if(v > 1) {
+		gins(AANDL, nodconst((1 << v) - 1), &nod);
+		gins(AADDL, &nod, n);
+		gins(AANDL, nodconst((1 << v) - 1), n);
+		gins(ASUBL, &nod, n);
+	}
+	else {
+		gins(AANDL, nodconst(1), n);
+		gins(AXORL, &nod, n);
+		gins(ASUBL, &nod, n);
+	}
+	regfree(&nod);
+}
diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h
new file mode 100644
index 0000000..dee9966
--- /dev/null
+++ b/src/cmd/6c/gc.h
@@ -0,0 +1,411 @@
+// Inferno utils/6c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	"../cc/cc.h"
+#include	"../6l/6.out.h"
+
+/*
+ * 6c/amd64
+ * Intel 386 with AMD64 extensions
+ */
+#define	SZ_CHAR		1
+#define	SZ_SHORT	2
+#define	SZ_INT		4
+#define	SZ_LONG		4
+#define	SZ_IND		8
+#define	SZ_FLOAT	4
+#define	SZ_VLONG	8
+#define	SZ_DOUBLE	8
+#define	FNX		100
+
+typedef	struct	Adr	Adr;
+typedef	struct	Prog	Prog;
+typedef	struct	Case	Case;
+typedef	struct	C1	C1;
+typedef	struct	Var	Var;
+typedef	struct	Reg	Reg;
+typedef	struct	Rgn	Rgn;
+typedef	struct	Renv	Renv;
+
+EXTERN	struct
+{
+	Node*	regtree;
+	Node*	basetree;
+	short	scale;
+	short	reg;
+	short	ptr;
+} idx;
+
+struct	Adr
+{
+	vlong	offset;
+	double	dval;
+	char	sval[NSNAME];
+
+	Sym*	sym;
+	uchar	type;
+	uchar	index;
+	uchar	etype;
+	uchar	scale;	/* doubles as width in DATA op */
+};
+#define	A	((Adr*)0)
+
+#define	INDEXED	9
+struct	Prog
+{
+	Adr	from;
+	Adr	to;
+	Prog*	link;
+	long	lineno;
+	short	as;
+};
+#define	P	((Prog*)0)
+
+struct	Case
+{
+	Case*	link;
+	vlong	val;
+	long	label;
+	char	def;
+	char	isv;
+};
+#define	C	((Case*)0)
+
+struct	C1
+{
+	vlong	val;
+	long	label;
+};
+
+struct	Var
+{
+	vlong	offset;
+	Sym*	sym;
+	char	name;
+	char	etype;
+};
+
+struct	Reg
+{
+	long	pc;
+	long	rpo;		/* reverse post ordering */
+
+	Bits	set;
+	Bits	use1;
+	Bits	use2;
+
+	Bits	refbehind;
+	Bits	refahead;
+	Bits	calbehind;
+	Bits	calahead;
+	Bits	regdiff;
+	Bits	act;
+
+	long	regu;
+	long	loop;		/* could be shorter */
+
+	Reg*	log5;
+	long	active;
+
+	Reg*	p1;
+	Reg*	p2;
+	Reg*	p2link;
+	Reg*	s1;
+	Reg*	s2;
+	Reg*	link;
+	Prog*	prog;
+};
+#define	R	((Reg*)0)
+
+struct	Renv
+{
+	int	safe;
+	Node	base;
+	Node*	saved;
+	Node*	scope;
+};
+
+#define	NRGN	600
+struct	Rgn
+{
+	Reg*	enter;
+	short	cost;
+	short	varno;
+	short	regno;
+};
+
+EXTERN	long	breakpc;
+EXTERN	long	nbreak;
+EXTERN	Case*	cases;
+EXTERN	Node	constnode;
+EXTERN	Node	fconstnode;
+EXTERN	Node	vconstnode;
+EXTERN	long	continpc;
+EXTERN	long	curarg;
+EXTERN	long	cursafe;
+EXTERN	Prog*	firstp;
+EXTERN	Prog*	lastp;
+EXTERN	long	maxargsafe;
+EXTERN	int	mnstring;
+EXTERN	Node*	nodrat;
+EXTERN	Node*	nodret;
+EXTERN	Node*	nodsafe;
+EXTERN	long	nrathole;
+EXTERN	long	nstring;
+EXTERN	Prog*	p;
+EXTERN	long	pc;
+EXTERN	Node	lregnode;
+EXTERN	Node	qregnode;
+EXTERN	char	string[NSNAME];
+EXTERN	Sym*	symrathole;
+EXTERN	Node	znode;
+EXTERN	Prog	zprog;
+EXTERN	int	reg[D_NONE];
+EXTERN	long	exregoffset;
+EXTERN	long	exfregoffset;
+EXTERN	uchar	typechlpv[NTYPE];
+
+#define	BLOAD(r)	band(bnot(r->refbehind), r->refahead)
+#define	BSTORE(r)	band(bnot(r->calbehind), r->calahead)
+#define	LOAD(r)		(~r->refbehind.b[z] & r->refahead.b[z])
+#define	STORE(r)	(~r->calbehind.b[z] & r->calahead.b[z])
+
+#define	bset(a,n)	((a).b[(n)/32]&(1L<<(n)%32))
+
+#define	CLOAD	5
+#define	CREF	5
+#define	CINF	1000
+#define	LOOP	3
+
+EXTERN	Rgn	region[NRGN];
+EXTERN	Rgn*	rgp;
+EXTERN	int	nregion;
+EXTERN	int	nvar;
+
+EXTERN	Bits	externs;
+EXTERN	Bits	params;
+EXTERN	Bits	consts;
+EXTERN	Bits	addrs;
+
+EXTERN	long	regbits;
+EXTERN	long	exregbits;
+
+EXTERN	int	change;
+EXTERN	int	suppress;
+
+EXTERN	Reg*	firstr;
+EXTERN	Reg*	lastr;
+EXTERN	Reg	zreg;
+EXTERN	Reg*	freer;
+EXTERN	Var	var[NVAR];
+EXTERN	long*	idom;
+EXTERN	Reg**	rpo2r;
+EXTERN	long	maxnr;
+
+extern	char*	anames[];
+
+/*
+ * sgen.c
+ */
+void	codgen(Node*, Node*);
+void	gen(Node*);
+void	noretval(int);
+void	usedset(Node*, int);
+void	xcom(Node*);
+void	indx(Node*);
+int	bcomplex(Node*, Node*);
+
+/*
+ * cgen.c
+ */
+void	zeroregm(Node*);
+void	cgen(Node*, Node*);
+void	reglcgen(Node*, Node*, Node*);
+void	lcgen(Node*, Node*);
+void	bcgen(Node*, int);
+void	boolgen(Node*, int, Node*);
+void	sugen(Node*, Node*, long);
+int	needreg(Node*, int);
+int	hardconst(Node*);
+int	immconst(Node*);
+
+/*
+ * cgen64.c
+ */
+int	vaddr(Node*, int);
+void	loadpair(Node*, Node*);
+int	cgen64(Node*, Node*);
+void	testv(Node*, int);
+
+/*
+ * txt.c
+ */
+void	ginit(void);
+void	gclean(void);
+void	nextpc(void);
+void	gargs(Node*, Node*, Node*);
+void	garg1(Node*, Node*, Node*, int, Node**);
+Node*	nodconst(long);
+Node*	nodfconst(double);
+Node*	nodgconst(vlong, Type*);
+int	nodreg(Node*, Node*, int);
+int	isreg(Node*, int);
+void	regret(Node*, Node*);
+void	regalloc(Node*, Node*, Node*);
+void	regfree(Node*);
+void	regialloc(Node*, Node*, Node*);
+void	regsalloc(Node*, Node*);
+void	regaalloc1(Node*, Node*);
+void	regaalloc(Node*, Node*);
+void	regind(Node*, Node*);
+void	gprep(Node*, Node*);
+void	naddr(Node*, Adr*);
+void	gcmp(int, Node*, vlong);
+void	gmove(Node*, Node*);
+void	gins(int a, Node*, Node*);
+void	gopcode(int, Type*, Node*, Node*);
+int	samaddr(Node*, Node*);
+void	gbranch(int);
+void	patch(Prog*, long);
+int	sconst(Node*);
+void	gpseudo(int, Sym*, Node*);
+
+/*
+ * swt.c
+ */
+int	swcmp(const void*, const void*);
+void	doswit(Node*);
+void	swit1(C1*, int, long, Node*);
+void	cas(void);
+void	bitload(Node*, Node*, Node*, Node*, Node*);
+void	bitstore(Node*, Node*, Node*, Node*, Node*);
+long	outstring(char*, long);
+void	nullwarn(Node*, Node*);
+void	sextern(Sym*, Node*, long, long);
+void	gextern(Sym*, Node*, long, long);
+void	outcode(void);
+void	ieeedtod(Ieee*, double);
+
+/*
+ * list
+ */
+void	listinit(void);
+int	Pconv(Fmt*);
+int	Aconv(Fmt*);
+int	Dconv(Fmt*);
+int	Sconv(Fmt*);
+int	Rconv(Fmt*);
+int	Xconv(Fmt*);
+int	Bconv(Fmt*);
+
+/*
+ * reg.c
+ */
+Reg*	rega(void);
+int	rcmp(const void*, const void*);
+void	regopt(Prog*);
+void	addmove(Reg*, int, int, int);
+Bits	mkvar(Reg*, Adr*);
+void	prop(Reg*, Bits, Bits);
+void	loopit(Reg*, long);
+void	synch(Reg*, Bits);
+ulong	allreg(ulong, Rgn*);
+void	paint1(Reg*, int);
+ulong	paint2(Reg*, int);
+void	paint3(Reg*, int, long, int);
+void	addreg(Adr*, int);
+
+/*
+ * peep.c
+ */
+void	peep(void);
+void	excise(Reg*);
+Reg*	uniqp(Reg*);
+Reg*	uniqs(Reg*);
+int	regtyp(Adr*);
+int	anyvar(Adr*);
+int	subprop(Reg*);
+int	copyprop(Reg*);
+int	copy1(Adr*, Adr*, Reg*, int);
+int	copyu(Prog*, Adr*, Adr*);
+
+int	copyas(Adr*, Adr*);
+int	copyau(Adr*, Adr*);
+int	copysub(Adr*, Adr*, Adr*, int);
+int	copysub1(Prog*, Adr*, Adr*, int);
+
+long	RtoB(int);
+long	FtoB(int);
+int	BtoR(long);
+int	BtoF(long);
+
+#define	D_HI	D_NONE
+#define	D_LO	D_NONE
+
+#define	isregtype(t)	((t)>= D_AX && (t)<=D_R15)
+
+/*
+ * bound
+ */
+void	comtarg(void);
+
+/*
+ * com64
+ */
+int	cond(int);
+int	com64(Node*);
+void	com64init(void);
+void	bool64(Node*);
+long	lo64v(Node*);
+long	hi64v(Node*);
+Node*	lo64(Node*);
+Node*	hi64(Node*);
+
+/*
+ * div/mul
+ */
+void	sdivgen(Node*, Node*, Node*, Node*);
+void	udivgen(Node*, Node*, Node*, Node*);
+void	sdiv2(long, int, Node*, Node*);
+void	smod2(long, int, Node*, Node*);
+void	mulgen(Type*, Node*, Node*);
+void	genmuladd(Node*, Node*, int, Node*);
+void	shiftit(Type*, Node*, Node*);
+
+#pragma	varargck	type	"A"	int
+#pragma	varargck	type	"B"	Bits
+#pragma	varargck	type	"D"	Adr*
+#pragma	varargck	type	"P"	Prog*
+#pragma	varargck	type	"R"	int
+#pragma	varargck	type	"S"	char*
+
+#define	D_X7	(D_X0+7)
+
+void	fgopcode(int, Node*, Node*, int, int);
diff --git a/src/cmd/6c/list.c b/src/cmd/6c/list.c
new file mode 100644
index 0000000..4aae5a3
--- /dev/null
+++ b/src/cmd/6c/list.c
@@ -0,0 +1,372 @@
+// Inferno utils/6c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+
+	fmtinstall('A', Aconv);
+	fmtinstall('B', Bconv);
+	fmtinstall('P', Pconv);
+	fmtinstall('S', Sconv);
+	fmtinstall('D', Dconv);
+	fmtinstall('R', Rconv);
+}
+
+int
+Bconv(Fmt *fp)
+{
+	char str[STRINGSZ], ss[STRINGSZ], *s;
+	Bits bits;
+	int i;
+
+	str[0] = 0;
+	bits = va_arg(fp->args, Bits);
+	while(bany(&bits)) {
+		i = bnum(bits);
+		if(str[0])
+			strcat(str, " ");
+		if(var[i].sym == S) {
+			sprint(ss, "$%lld", var[i].offset);
+			s = ss;
+		} else
+			s = var[i].sym->name;
+		if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
+			break;
+		strcat(str, s);
+		bits.b[i/32] &= ~(1L << (i%32));
+	}
+	return fmtstrcpy(fp, str);
+}
+
+int
+Pconv(Fmt *fp)
+{
+	char str[STRINGSZ];
+	Prog *p;
+
+	p = va_arg(fp->args, Prog*);
+	if(p->as == ADATA)
+		sprint(str, "	%A	%D/%d,%D",
+			p->as, &p->from, p->from.scale, &p->to);
+	else if(p->as == ATEXT)
+		sprint(str, "	%A	%D,%d,%D",
+			p->as, &p->from, p->from.scale, &p->to);
+	else
+		sprint(str, "	%A	%D,%D",
+			p->as, &p->from, &p->to);
+	return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+	int i;
+
+	i = va_arg(fp->args, int);
+	return fmtstrcpy(fp, anames[i]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+	char str[40], s[20];
+	Adr *a;
+	int i;
+
+	a = va_arg(fp->args, Adr*);
+	i = a->type;
+	if(i >= D_INDIR) {
+		if(a->offset)
+			sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
+		else
+			sprint(str, "(%R)", i-D_INDIR);
+		goto brk;
+	}
+	switch(i) {
+
+	default:
+		if(a->offset)
+			sprint(str, "$%lld,%R", a->offset, i);
+		else
+			sprint(str, "%R", i);
+		break;
+
+	case D_NONE:
+		str[0] = 0;
+		break;
+
+	case D_BRANCH:
+		sprint(str, "%lld(PC)", a->offset-pc);
+		break;
+
+	case D_EXTERN:
+		sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
+		break;
+
+	case D_STATIC:
+		sprint(str, "%s<>+%lld(SB)", a->sym->name,
+			a->offset);
+		break;
+
+	case D_AUTO:
+		if(a->sym) {
+			sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
+			break;
+		}
+		sprint(str, "%lld(SP)", a->offset);
+		break;
+
+	case D_PARAM:
+		if(a->sym) {
+			sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
+			break;
+		}
+		sprint(str, "%lld(FP)", a->offset);
+		break;
+
+	case D_CONST:
+		sprint(str, "$%lld", a->offset);
+		break;
+
+	case D_FCONST:
+		sprint(str, "$(%.17e)", a->dval);
+		break;
+
+	case D_SCONST:
+		sprint(str, "$\"%S\"", a->sval);
+		break;
+
+	case D_ADDR:
+		a->type = a->index;
+		a->index = D_NONE;
+		sprint(str, "$%D", a);
+		a->index = a->type;
+		a->type = D_ADDR;
+		goto conv;
+	}
+brk:
+	if(a->index != D_NONE) {
+		sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
+		strcat(str, s);
+	}
+conv:
+	return fmtstrcpy(fp, str);
+}
+
+char*	regstr[] =
+{
+	"AL",		/* [D_AL] */
+	"CL",
+	"DL",
+	"BL",
+	"SPB",
+	"BPB",
+	"SIB",
+	"DIB",
+	"R8B",
+	"R9B",
+	"R10B",
+	"R11B",
+	"R12B",
+	"R13B",
+	"R14B",
+	"R15B",
+
+	"AX",		/* [D_AX] */
+	"CX",
+	"DX",
+	"BX",
+	"SP",
+	"BP",
+	"SI",
+	"DI",
+	"R8",
+	"R9",
+	"R10",
+	"R11",
+	"R12",
+	"R13",
+	"R14",
+	"R15",
+
+	"AH",
+	"CH",
+	"DH",
+	"BH",
+
+	"F0",		/* [D_F0] */
+	"F1",
+	"F2",
+	"F3",
+	"F4",
+	"F5",
+	"F6",
+	"F7",
+
+	"M0",
+	"M1",
+	"M2",
+	"M3",
+	"M4",
+	"M5",
+	"M6",
+	"M7",
+
+	"X0",
+	"X1",
+	"X2",
+	"X3",
+	"X4",
+	"X5",
+	"X6",
+	"X7",
+	"X8",
+	"X9",
+	"X10",
+	"X11",
+	"X12",
+	"X13",
+	"X14",
+	"X15",
+
+	"CS",		/* [D_CS] */
+	"SS",
+	"DS",
+	"ES",
+	"FS",
+	"GS",
+
+	"GDTR",		/* [D_GDTR] */
+	"IDTR",		/* [D_IDTR] */
+	"LDTR",		/* [D_LDTR] */
+	"MSW",		/* [D_MSW] */
+	"TASK",		/* [D_TASK] */
+
+	"CR0",		/* [D_CR] */
+	"CR1",
+	"CR2",
+	"CR3",
+	"CR4",
+	"CR5",
+	"CR6",
+	"CR7",
+	"CR8",
+	"CR9",
+	"CR10",
+	"CR11",
+	"CR12",
+	"CR13",
+	"CR14",
+	"CR15",
+
+	"DR0",		/* [D_DR] */
+	"DR1",
+	"DR2",
+	"DR3",
+	"DR4",
+	"DR5",
+	"DR6",
+	"DR7",
+
+	"TR0",		/* [D_TR] */
+	"TR1",
+	"TR2",
+	"TR3",
+	"TR4",
+	"TR5",
+	"TR6",
+	"TR7",
+
+	"NONE",		/* [D_NONE] */
+};
+
+int
+Rconv(Fmt *fp)
+{
+	char str[20];
+	int r;
+
+	r = va_arg(fp->args, int);
+	if(r >= D_AL && r <= D_NONE)
+		sprint(str, "%s", regstr[r-D_AL]);
+	else
+		sprint(str, "gok(%d)", r);
+
+	return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+	int i, c;
+	char str[30], *p, *a;
+
+	a = va_arg(fp->args, char*);
+	p = str;
+	for(i=0; i<sizeof(double); i++) {
+		c = a[i] & 0xff;
+		if(c >= 'a' && c <= 'z' ||
+		   c >= 'A' && c <= 'Z' ||
+		   c >= '0' && c <= '9') {
+			*p++ = c;
+			continue;
+		}
+		*p++ = '\\';
+		switch(c) {
+		default:
+			if(c < 040 || c >= 0177)
+				break;	/* not portable */
+			p[-1] = c;
+			continue;
+		case 0:
+			*p++ = 'z';
+			continue;
+		case '\\':
+		case '"':
+			*p++ = c;
+			continue;
+		case '\n':
+			*p++ = 'n';
+			continue;
+		case '\t':
+			*p++ = 't';
+			continue;
+		}
+		*p++ = (c>>6) + '0';
+		*p++ = ((c>>3) & 7) + '0';
+		*p++ = (c & 7) + '0';
+	}
+	*p = 0;
+	return fmtstrcpy(fp, str);
+}
diff --git a/src/cmd/6c/machcap.c b/src/cmd/6c/machcap.c
new file mode 100644
index 0000000..d4f6bfa
--- /dev/null
+++ b/src/cmd/6c/machcap.c
@@ -0,0 +1,108 @@
+// Inferno utils/6c/machcap.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/machcap.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+int
+machcap(Node *n)
+{
+
+	if(n == Z)
+		return 1;	/* test */
+
+	switch(n->op) {
+	case OMUL:
+	case OLMUL:
+	case OASMUL:
+	case OASLMUL:
+		if(typechl[n->type->etype])
+			return 1;
+		if(typev[n->type->etype]) {
+				return 1;
+		}
+		break;
+
+	case OCOM:
+	case ONEG:
+	case OADD:
+	case OAND:
+	case OOR:
+	case OSUB:
+	case OXOR:
+	case OASHL:
+	case OLSHR:
+	case OASHR:
+		if(typechlv[n->left->type->etype])
+			return 1;
+		break;
+
+	case OCAST:
+		return 1;
+
+	case OCOND:
+	case OCOMMA:
+	case OLIST:
+	case OANDAND:
+	case OOROR:
+	case ONOT:
+		return 1;
+
+	case OASADD:
+	case OASSUB:
+	case OASAND:
+	case OASOR:
+	case OASXOR:
+		return 1;
+
+	case OASASHL:
+	case OASASHR:
+	case OASLSHR:
+		return 1;
+
+	case OPOSTINC:
+	case OPOSTDEC:
+	case OPREINC:
+	case OPREDEC:
+		return 1;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OGT:
+	case OLT:
+	case OGE:
+	case OHI:
+	case OHS:
+	case OLO:
+	case OLS:
+		return 1;
+	}
+	return 0;
+}
diff --git a/src/cmd/6c/mul.c b/src/cmd/6c/mul.c
new file mode 100644
index 0000000..7fd2012
--- /dev/null
+++ b/src/cmd/6c/mul.c
@@ -0,0 +1,458 @@
+// Inferno utils/6c/mul.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/mul.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+typedef struct	Malg	Malg;
+typedef struct	Mparam	Mparam;
+
+struct	Malg
+{
+	char	vals[10];
+};
+
+struct	Mparam
+{
+	ulong	value;
+	char	alg;
+	char	neg;
+	char	shift;
+	char	arg;
+	char	off;
+};
+
+static	Mparam	multab[32];
+static	int	mulptr;
+
+static	Malg	malgs[]	=
+{
+	{0, 100},
+	{-1, 1, 100},
+	{-9, -5, -3, 3, 5, 9, 100},
+	{6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
+	{-8, -4, -2, 2, 4, 8, 100},
+};
+
+/*
+ * return position of lowest 1
+ */
+int
+lowbit(ulong v)
+{
+	int s, i;
+	ulong m;
+
+	s = 0;
+	m = 0xFFFFFFFFUL;
+	for(i = 16; i > 0; i >>= 1) {
+		m >>= i;
+		if((v & m) == 0) {
+			v >>= i;
+			s += i;
+		}
+	}
+	return s;
+}
+
+void
+genmuladd(Node *d, Node *s, int m, Node *a)
+{
+	Node nod;
+
+	nod.op = OINDEX;
+	nod.left = a;
+	nod.right = s;
+	nod.scale = m;
+	nod.type = types[TIND];
+	nod.xoffset = 0;
+	xcom(&nod);
+	gopcode(OADDR, d->type, &nod, d);
+}
+
+void
+mulparam(ulong m, Mparam *mp)
+{
+	int c, i, j, n, o, q, s;
+	int bc, bi, bn, bo, bq, bs, bt;
+	char *p;
+	long u;
+	ulong t;
+
+	bc = bq = 10;
+	bi = bn = bo = bs = bt = 0;
+	for(i = 0; i < nelem(malgs); i++) {
+		for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
+		for(s = 0; s < 2; s++) {
+			c = 10;
+			q = 10;
+			u = m - o;
+			if(u == 0)
+				continue;
+			if(s) {
+				o = -o;
+				if(o > 0)
+					continue;
+				u = -u;
+			}
+			n = lowbit(u);
+			t = (ulong)u >> n;
+			switch(i) {
+			case 0:
+				if(t == 1) {
+					c = s + 1;
+					q = 0;
+					break;
+				}
+				switch(t) {
+				case 3:
+				case 5:
+				case 9:
+					c = s + 1;
+					if(n)
+						c++;
+					q = 0;
+					break;
+				}
+				if(s)
+					break;
+				switch(t) {
+				case 15:
+				case 25:
+				case 27:
+				case 45:
+				case 81:
+					c = 2;
+					if(n)
+						c++;
+					q = 1;
+					break;
+				}
+				break;
+			case 1:
+				if(t == 1) {
+					c = 3;
+					q = 3;
+					break;
+				}
+				switch(t) {
+				case 3:
+				case 5:
+				case 9:
+					c = 3;
+					q = 2;
+					break;
+				}
+				break;
+			case 2:
+				if(t == 1) {
+					c = 3;
+					q = 2;
+					break;
+				}
+				break;
+			case 3:
+				if(s)
+					break;
+				if(t == 1) {
+					c = 3;
+					q = 1;
+					break;
+				}
+				break;
+			case 4:
+				if(t == 1) {
+					c = 3;
+					q = 0;
+					break;
+				}
+				break;
+			}
+			if(c < bc || (c == bc && q > bq)) {
+				bc = c;
+				bi = i;
+				bn = n;
+				bo = o;
+				bq = q;
+				bs = s;
+				bt = t;
+			}
+		}
+	}
+	mp->value = m;
+	if(bc <= 3) {
+		mp->alg = bi;
+		mp->shift = bn;
+		mp->off = bo;
+		mp->neg = bs;
+		mp->arg = bt;
+	}
+	else
+		mp->alg = -1;
+}
+
+int
+m0(int a)
+{
+	switch(a) {
+	case -2:
+	case 2:
+		return 2;
+	case -3:
+	case 3:
+		return 2;
+	case -4:
+	case 4:
+		return 4;
+	case -5:
+	case 5:
+		return 4;
+	case 6:
+		return 2;
+	case -8:
+	case 8:
+		return 8;
+	case -9:
+	case 9:
+		return 8;
+	case 10:
+		return 4;
+	case 12:
+		return 2;
+	case 15:
+		return 2;
+	case 18:
+		return 8;
+	case 20:
+		return 4;
+	case 24:
+		return 2;
+	case 25:
+		return 4;
+	case 27:
+		return 2;
+	case 36:
+		return 8;
+	case 40:
+		return 4;
+	case 45:
+		return 4;
+	case 72:
+		return 8;
+	case 81:
+		return 8;
+	}
+	diag(Z, "bad m0");
+	return 0;
+}
+
+int
+m1(int a)
+{
+	switch(a) {
+	case 15:
+		return 4;
+	case 25:
+		return 4;
+	case 27:
+		return 8;
+	case 45:
+		return 8;
+	case 81:
+		return 8;
+	}
+	diag(Z, "bad m1");
+	return 0;
+}
+
+int
+m2(int a)
+{
+	switch(a) {
+	case 6:
+		return 2;
+	case 10:
+		return 2;
+	case 12:
+		return 4;
+	case 18:
+		return 2;
+	case 20:
+		return 4;
+	case 24:
+		return 8;
+	case 36:
+		return 4;
+	case 40:
+		return 8;
+	case 72:
+		return 8;
+	}
+	diag(Z, "bad m2");
+	return 0;
+}
+
+void
+shiftit(Type *t, Node *s, Node *d)
+{
+	long c;
+
+	c = (long)s->vconst & 31;
+	switch(c) {
+	case 0:
+		break;
+	case 1:
+		gopcode(OADD, t, d, d);
+		break;
+	default:
+		gopcode(OASHL, t, s, d);
+	}
+}
+
+static int
+mulgen1(ulong v, Node *n)
+{
+	int i, o;
+	Mparam *p;
+	Node nod, nods;
+
+	for(i = 0; i < nelem(multab); i++) {
+		p = &multab[i];
+		if(p->value == v)
+			goto found;
+	}
+
+	p = &multab[mulptr];
+	if(++mulptr == nelem(multab))
+		mulptr = 0;
+
+	mulparam(v, p);
+
+found:
+//	print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
+	if(p->alg < 0)
+		return 0;
+
+	nods = *nodconst(p->shift);
+
+	o = OADD;
+	if(p->alg > 0) {
+		regalloc(&nod, n, Z);
+		if(p->off < 0)
+			o = OSUB;
+	}
+
+	switch(p->alg) {
+	case 0:
+		switch(p->arg) {
+		case 1:
+			shiftit(n->type, &nods, n);
+			break;
+		case 15:
+		case 25:
+		case 27:
+		case 45:
+		case 81:
+			genmuladd(n, n, m1(p->arg), n);
+			/* fall thru */
+		case 3:
+		case 5:
+		case 9:
+			genmuladd(n, n, m0(p->arg), n);
+			shiftit(n->type, &nods, n);
+			break;
+		default:
+			goto bad;
+		}
+		if(p->neg == 1)
+			gins(ANEGL, Z, n);
+		break;
+	case 1:
+		switch(p->arg) {
+		case 1:
+			gmove(n, &nod);
+			shiftit(n->type, &nods, &nod);
+			break;
+		case 3:
+		case 5:
+		case 9:
+			genmuladd(&nod, n, m0(p->arg), n);
+			shiftit(n->type, &nods, &nod);
+			break;
+		default:
+			goto bad;
+		}
+		if(p->neg)
+			gopcode(o, n->type, &nod, n);
+		else {
+			gopcode(o, n->type, n, &nod);
+			gmove(&nod, n);
+		}
+		break;
+	case 2:
+		genmuladd(&nod, n, m0(p->off), n);
+		shiftit(n->type, &nods, n);
+		goto comop;
+	case 3:
+		genmuladd(&nod, n, m0(p->off), n);
+		shiftit(n->type, &nods, n);
+		genmuladd(n, &nod, m2(p->off), n);
+		break;
+	case 4:
+		genmuladd(&nod, n, m0(p->off), nodconst(0));
+		shiftit(n->type, &nods, n);
+		goto comop;
+	default:
+		diag(Z, "bad mul alg");
+		break;
+	comop:
+		if(p->neg) {
+			gopcode(o, n->type, n, &nod);
+			gmove(&nod, n);
+		}
+		else
+			gopcode(o, n->type, &nod, n);
+	}
+
+	if(p->alg > 0)
+		regfree(&nod);
+
+	return 1;
+
+bad:
+	diag(Z, "mulgen botch");
+	return 1;
+}
+
+void
+mulgen(Type *t, Node *r, Node *n)
+{
+	if(!mulgen1(r->vconst, n))
+		gopcode(OMUL, t, r, n);
+}
diff --git a/src/cmd/6c/peep.c b/src/cmd/6c/peep.c
new file mode 100644
index 0000000..77c034b
--- /dev/null
+++ b/src/cmd/6c/peep.c
@@ -0,0 +1,876 @@
+// Inferno utils/6c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+static int
+needc(Prog *p)
+{
+	while(p != P) {
+		switch(p->as) {
+		case AADCL:
+		case AADCQ:
+		case ASBBL:
+		case ASBBQ:
+		case ARCRL:
+		case ARCRQ:
+			return 1;
+		case AADDL:
+		case AADDQ:
+		case ASUBL:
+		case ASUBQ:
+		case AJMP:
+		case ARET:
+		case ACALL:
+			return 0;
+		default:
+			if(p->to.type == D_BRANCH)
+				return 0;
+		}
+		p = p->link;
+	}
+	return 0;
+}
+
+static Reg*
+rnops(Reg *r)
+{
+	Prog *p;
+	Reg *r1;
+
+	if(r != R)
+	for(;;){
+		p = r->prog;
+		if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
+			break;
+		r1 = uniqs(r);
+		if(r1 == R)
+			break;
+		r = r1;
+	}
+	return r;
+}
+
+void
+peep(void)
+{
+	Reg *r, *r1, *r2;
+	Prog *p, *p1;
+	int t;
+
+	/*
+	 * complete R structure
+	 */
+	t = 0;
+	for(r=firstr; r!=R; r=r1) {
+		r1 = r->link;
+		if(r1 == R)
+			break;
+		p = r->prog->link;
+		while(p != r1->prog)
+		switch(p->as) {
+		default:
+			r2 = rega();
+			r->link = r2;
+			r2->link = r1;
+
+			r2->prog = p;
+			r2->p1 = r;
+			r->s1 = r2;
+			r2->s1 = r1;
+			r1->p1 = r2;
+
+			r = r2;
+			t++;
+
+		case ADATA:
+		case AGLOBL:
+		case ANAME:
+		case ASIGNAME:
+			p = p->link;
+		}
+	}
+
+	pc = 0;	/* speculating it won't kill */
+
+loop1:
+
+	t = 0;
+	for(r=firstr; r!=R; r=r->link) {
+		p = r->prog;
+		switch(p->as) {
+		case AMOVL:
+		case AMOVQ:
+		case AMOVSS:
+		case AMOVSD:
+			if(regtyp(&p->to))
+			if(regtyp(&p->from)) {
+				if(copyprop(r)) {
+					excise(r);
+					t++;
+				} else
+				if(subprop(r) && copyprop(r)) {
+					excise(r);
+					t++;
+				}
+			}
+			break;
+
+		case AMOVBLZX:
+		case AMOVWLZX:
+		case AMOVBLSX:
+		case AMOVWLSX:
+			if(regtyp(&p->to)) {
+				r1 = rnops(uniqs(r));
+				if(r1 != R) {
+					p1 = r1->prog;
+					if(p->as == p1->as && p->to.type == p1->from.type){
+						p1->as = AMOVL;
+						t++;
+					}
+				}
+			}
+			break;
+
+		case AMOVBQSX:
+		case AMOVBQZX:
+		case AMOVWQSX:
+		case AMOVWQZX:
+		case AMOVLQSX:
+		case AMOVLQZX:
+			if(regtyp(&p->to)) {
+				r1 = rnops(uniqs(r));
+				if(r1 != R) {
+					p1 = r1->prog;
+					if(p->as == p1->as && p->to.type == p1->from.type){
+						p1->as = AMOVQ;
+						t++;
+					}
+				}
+			}
+			break;
+
+		case AADDL:
+		case AADDQ:
+		case AADDW:
+			if(p->from.type != D_CONST || needc(p->link))
+				break;
+			if(p->from.offset == -1){
+				if(p->as == AADDQ)
+					p->as = ADECQ;
+				else if(p->as == AADDL)
+					p->as = ADECL;
+				else
+					p->as = ADECW;
+				p->from = zprog.from;
+			}
+			else if(p->from.offset == 1){
+				if(p->as == AADDQ)
+					p->as = AINCQ;
+				else if(p->as == AADDL)
+					p->as = AINCL;
+				else
+					p->as = AINCW;
+				p->from = zprog.from;
+			}
+			break;
+
+		case ASUBL:
+		case ASUBQ:
+		case ASUBW:
+			if(p->from.type != D_CONST || needc(p->link))
+				break;
+			if(p->from.offset == -1) {
+				if(p->as == ASUBQ)
+					p->as = AINCQ;
+				else if(p->as == ASUBL)
+					p->as = AINCL;
+				else
+					p->as = AINCW;
+				p->from = zprog.from;
+			}
+			else if(p->from.offset == 1){
+				if(p->as == ASUBQ)
+					p->as = ADECQ;
+				else if(p->as == ASUBL)
+					p->as = ADECL;
+				else
+					p->as = ADECW;
+				p->from = zprog.from;
+			}
+			break;
+		}
+	}
+	if(t)
+		goto loop1;
+}
+
+void
+excise(Reg *r)
+{
+	Prog *p;
+
+	p = r->prog;
+	p->as = ANOP;
+	p->from = zprog.from;
+	p->to = zprog.to;
+}
+
+Reg*
+uniqp(Reg *r)
+{
+	Reg *r1;
+
+	r1 = r->p1;
+	if(r1 == R) {
+		r1 = r->p2;
+		if(r1 == R || r1->p2link != R)
+			return R;
+	} else
+		if(r->p2 != R)
+			return R;
+	return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+	Reg *r1;
+
+	r1 = r->s1;
+	if(r1 == R) {
+		r1 = r->s2;
+		if(r1 == R)
+			return R;
+	} else
+		if(r->s2 != R)
+			return R;
+	return r1;
+}
+
+int
+regtyp(Adr *a)
+{
+	int t;
+
+	t = a->type;
+	if(t >= D_AX && t <= D_R15)
+		return 1;
+	if(t >= D_X0 && t <= D_X0+15)
+		return 1;
+	return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ *	MOV	a, R0
+ *	ADD	b, R0	/ no use of R1
+ *	MOV	R0, R1
+ * would be converted to
+ *	MOV	a, R1
+ *	ADD	b, R1
+ *	MOV	R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+	Prog *p;
+	Adr *v1, *v2;
+	Reg *r;
+	int t;
+
+	p = r0->prog;
+	v1 = &p->from;
+	if(!regtyp(v1))
+		return 0;
+	v2 = &p->to;
+	if(!regtyp(v2))
+		return 0;
+	for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+		if(uniqs(r) == R)
+			break;
+		p = r->prog;
+		switch(p->as) {
+		case ACALL:
+			return 0;
+
+		case AIMULL:
+		case AIMULQ:
+		case AIMULW:
+			if(p->to.type != D_NONE)
+				break;
+
+		case ADIVB:
+		case ADIVL:
+		case ADIVQ:
+		case ADIVW:
+		case AIDIVB:
+		case AIDIVL:
+		case AIDIVQ:
+		case AIDIVW:
+		case AIMULB:
+		case AMULB:
+		case AMULL:
+		case AMULQ:
+		case AMULW:
+
+		case AROLB:
+		case AROLL:
+		case AROLQ:
+		case AROLW:
+		case ARORB:
+		case ARORL:
+		case ARORQ:
+		case ARORW:
+		case ASALB:
+		case ASALL:
+		case ASALQ:
+		case ASALW:
+		case ASARB:
+		case ASARL:
+		case ASARQ:
+		case ASARW:
+		case ASHLB:
+		case ASHLL:
+		case ASHLQ:
+		case ASHLW:
+		case ASHRB:
+		case ASHRL:
+		case ASHRQ:
+		case ASHRW:
+
+		case AREP:
+		case AREPN:
+
+		case ACWD:
+		case ACDQ:
+		case ACQO:
+
+		case AMOVSL:
+		case AMOVSQ:
+			return 0;
+
+		case AMOVL:
+		case AMOVQ:
+			if(p->to.type == v1->type)
+				goto gotit;
+			break;
+		}
+		if(copyau(&p->from, v2) ||
+		   copyau(&p->to, v2))
+			break;
+		if(copysub(&p->from, v1, v2, 0) ||
+		   copysub(&p->to, v1, v2, 0))
+			break;
+	}
+	return 0;
+
+gotit:
+	copysub(&p->to, v1, v2, 1);
+	if(debug['P']) {
+		print("gotit: %D->%D\n%P", v1, v2, r->prog);
+		if(p->from.type == v2->type)
+			print(" excise");
+		print("\n");
+	}
+	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+		p = r->prog;
+		copysub(&p->from, v1, v2, 1);
+		copysub(&p->to, v1, v2, 1);
+		if(debug['P'])
+			print("%P\n", r->prog);
+	}
+	t = v1->type;
+	v1->type = v2->type;
+	v2->type = t;
+	if(debug['P'])
+		print("%P last\n", r->prog);
+	return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	use v2	return fail
+ *	-----------------
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	set v2	return success
+ */
+int
+copyprop(Reg *r0)
+{
+	Prog *p;
+	Adr *v1, *v2;
+	Reg *r;
+
+	p = r0->prog;
+	v1 = &p->from;
+	v2 = &p->to;
+	if(copyas(v1, v2))
+		return 1;
+	for(r=firstr; r!=R; r=r->link)
+		r->active = 0;
+	return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+	int t;
+	Prog *p;
+
+	if(r->active) {
+		if(debug['P'])
+			print("act set; return 1\n");
+		return 1;
+	}
+	r->active = 1;
+	if(debug['P'])
+		print("copy %D->%D f=%d\n", v1, v2, f);
+	for(; r != R; r = r->s1) {
+		p = r->prog;
+		if(debug['P'])
+			print("%P", p);
+		if(!f && uniqp(r) == R) {
+			f = 1;
+			if(debug['P'])
+				print("; merge; f=%d", f);
+		}
+		t = copyu(p, v2, A);
+		switch(t) {
+		case 2:	/* rar, cant split */
+			if(debug['P'])
+				print("; %D rar; return 0\n", v2);
+			return 0;
+
+		case 3:	/* set */
+			if(debug['P'])
+				print("; %D set; return 1\n", v2);
+			return 1;
+
+		case 1:	/* used, substitute */
+		case 4:	/* use and set */
+			if(f) {
+				if(!debug['P'])
+					return 0;
+				if(t == 4)
+					print("; %D used+set and f=%d; return 0\n", v2, f);
+				else
+					print("; %D used and f=%d; return 0\n", v2, f);
+				return 0;
+			}
+			if(copyu(p, v2, v1)) {
+				if(debug['P'])
+					print("; sub fail; return 0\n");
+				return 0;
+			}
+			if(debug['P'])
+				print("; sub %D/%D", v2, v1);
+			if(t == 4) {
+				if(debug['P'])
+					print("; %D used+set; return 1\n", v2);
+				return 1;
+			}
+			break;
+		}
+		if(!f) {
+			t = copyu(p, v1, A);
+			if(!f && (t == 2 || t == 3 || t == 4)) {
+				f = 1;
+				if(debug['P'])
+					print("; %D set and !f; f=%d", v1, f);
+			}
+		}
+		if(debug['P'])
+			print("\n");
+		if(r->s2)
+			if(!copy1(v1, v2, r->s2, f))
+				return 0;
+	}
+	return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+
+	switch(p->as) {
+
+	default:
+		if(debug['P'])
+			print("unknown op %A\n", p->as);
+		/* SBBL; ADCL; FLD1; SAHF */
+		return 2;
+
+
+	case ANEGB:
+	case ANEGW:
+	case ANEGL:
+	case ANEGQ:
+	case ANOTB:
+	case ANOTW:
+	case ANOTL:
+	case ANOTQ:
+		if(copyas(&p->to, v))
+			return 2;
+		break;
+
+	case ALEAL:	/* lhs addr, rhs store */
+	case ALEAQ:
+		if(copyas(&p->from, v))
+			return 2;
+
+
+	case ANOP:	/* rhs store */
+	case AMOVL:
+	case AMOVQ:
+	case AMOVBLSX:
+	case AMOVBLZX:
+	case AMOVBQSX:
+	case AMOVBQZX:
+	case AMOVLQSX:
+	case AMOVLQZX:
+	case AMOVWLSX:
+	case AMOVWLZX:
+	case AMOVWQSX:
+	case AMOVWQZX:
+
+	case AMOVSS:
+	case AMOVSD:
+	case ACVTSD2SL:
+	case ACVTSD2SQ:
+	case ACVTSD2SS:
+	case ACVTSL2SD:
+	case ACVTSL2SS:
+	case ACVTSQ2SD:
+	case ACVTSQ2SS:
+	case ACVTSS2SD:
+	case ACVTSS2SL:
+	case ACVTSS2SQ:
+	case ACVTTSD2SL:
+	case ACVTTSD2SQ:
+	case ACVTTSS2SL:
+	case ACVTTSS2SQ:
+		if(copyas(&p->to, v)) {
+			if(s != A)
+				return copysub(&p->from, v, s, 1);
+			if(copyau(&p->from, v))
+				return 4;
+			return 3;
+		}
+		goto caseread;
+
+	case AROLB:
+	case AROLL:
+	case AROLQ:
+	case AROLW:
+	case ARORB:
+	case ARORL:
+	case ARORQ:
+	case ARORW:
+	case ASALB:
+	case ASALL:
+	case ASALQ:
+	case ASALW:
+	case ASARB:
+	case ASARL:
+	case ASARQ:
+	case ASARW:
+	case ASHLB:
+	case ASHLL:
+	case ASHLQ:
+	case ASHLW:
+	case ASHRB:
+	case ASHRL:
+	case ASHRQ:
+	case ASHRW:
+		if(copyas(&p->to, v))
+			return 2;
+		if(copyas(&p->from, v))
+			if(p->from.type == D_CX)
+				return 2;
+		goto caseread;
+
+	case AADDB:	/* rhs rar */
+	case AADDL:
+	case AADDQ:
+	case AADDW:
+	case AANDB:
+	case AANDL:
+	case AANDQ:
+	case AANDW:
+	case ADECL:
+	case ADECQ:
+	case ADECW:
+	case AINCL:
+	case AINCQ:
+	case AINCW:
+	case ASUBB:
+	case ASUBL:
+	case ASUBQ:
+	case ASUBW:
+	case AORB:
+	case AORL:
+	case AORQ:
+	case AORW:
+	case AXORB:
+	case AXORL:
+	case AXORQ:
+	case AXORW:
+	case AMOVB:
+	case AMOVW:
+
+	case AADDSD:
+	case AADDSS:
+	case ACMPSD:
+	case ACMPSS:
+	case ADIVSD:
+	case ADIVSS:
+	case AMAXSD:
+	case AMAXSS:
+	case AMINSD:
+	case AMINSS:
+	case AMULSD:
+	case AMULSS:
+	case ARCPSS:
+	case ARSQRTSS:
+	case ASQRTSD:
+	case ASQRTSS:
+	case ASUBSD:
+	case ASUBSS:
+	case AXORPD:
+		if(copyas(&p->to, v))
+			return 2;
+		goto caseread;
+
+	case ACMPL:	/* read only */
+	case ACMPW:
+	case ACMPB:
+	case ACMPQ:
+
+	case ACOMISD:
+	case ACOMISS:
+	case AUCOMISD:
+	case AUCOMISS:
+	caseread:
+		if(s != A) {
+			if(copysub(&p->from, v, s, 1))
+				return 1;
+			return copysub(&p->to, v, s, 1);
+		}
+		if(copyau(&p->from, v))
+			return 1;
+		if(copyau(&p->to, v))
+			return 1;
+		break;
+
+	case AJGE:	/* no reference */
+	case AJNE:
+	case AJLE:
+	case AJEQ:
+	case AJHI:
+	case AJLS:
+	case AJMI:
+	case AJPL:
+	case AJGT:
+	case AJLT:
+	case AJCC:
+	case AJCS:
+
+	case AADJSP:
+	case AWAIT:
+	case ACLD:
+		break;
+
+	case AIMULL:
+	case AIMULQ:
+	case AIMULW:
+		if(p->to.type != D_NONE) {
+			if(copyas(&p->to, v))
+				return 2;
+			goto caseread;
+		}
+
+	case ADIVB:
+	case ADIVL:
+	case ADIVQ:
+	case ADIVW:
+	case AIDIVB:
+	case AIDIVL:
+	case AIDIVQ:
+	case AIDIVW:
+	case AIMULB:
+	case AMULB:
+	case AMULL:
+	case AMULQ:
+	case AMULW:
+
+	case ACWD:
+	case ACDQ:
+	case ACQO:
+		if(v->type == D_AX || v->type == D_DX)
+			return 2;
+		goto caseread;
+
+	case AMOVSL:
+	case AMOVSQ:
+	case AREP:
+	case AREPN:
+		if(v->type == D_CX || v->type == D_DI || v->type == D_SI)
+			return 2;
+		goto caseread;
+
+	case AJMP:	/* funny */
+		if(s != A) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		if(copyau(&p->to, v))
+			return 1;
+		return 0;
+
+	case ARET:	/* funny */
+		if(v->type == REGRET || v->type == FREGRET)
+			return 2;
+		if(s != A)
+			return 1;
+		return 3;
+
+	case ACALL:	/* funny */
+		if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
+			return 2;
+		if(REGARG && v->type == REGARG)
+			return 2;
+
+		if(s != A) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		if(copyau(&p->to, v))
+			return 4;
+		return 3;
+
+	case ATEXT:	/* funny */
+		if(REGARG && v->type == REGARG)
+			return 3;
+		return 0;
+	}
+	return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+	if(a->type != v->type)
+		return 0;
+	if(regtyp(v))
+		return 1;
+	if(v->type == D_AUTO || v->type == D_PARAM)
+		if(v->offset == a->offset)
+			return 1;
+	return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+	if(copyas(a, v))
+		return 1;
+	if(regtyp(v)) {
+		if(a->type-D_INDIR == v->type)
+			return 1;
+		if(a->index == v->type)
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+	int t;
+
+	if(copyas(a, v)) {
+		t = s->type;
+		if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
+			if(f)
+				a->type = t;
+		}
+		return 0;
+	}
+	if(regtyp(v)) {
+		t = v->type;
+		if(a->type == t+D_INDIR) {
+			if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
+				return 1;	/* can't use BP-base with index */
+			if(f)
+				a->type = s->type+D_INDIR;
+//			return 0;
+		}
+		if(a->index == t) {
+			if(f)
+				a->index = s->type;
+			return 0;
+		}
+		return 0;
+	}
+	return 0;
+}
diff --git a/src/cmd/6c/pgen.c b/src/cmd/6c/pgen.c
new file mode 100644
index 0000000..ae0b1b4
--- /dev/null
+++ b/src/cmd/6c/pgen.c
@@ -0,0 +1,550 @@
+// Inferno utils/6c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+	Prog *sp;
+	Node *n1, nod, nod1;
+
+	cursafe = 0;
+	curarg = 0;
+	maxargsafe = 0;
+
+	/*
+	 * isolate name
+	 */
+	for(n1 = nn;; n1 = n1->left) {
+		if(n1 == Z) {
+			diag(nn, "cant find function name");
+			return;
+		}
+		if(n1->op == ONAME)
+			break;
+	}
+	nearln = nn->lineno;
+	gpseudo(ATEXT, n1->sym, nodconst(stkoff));
+	sp = p;
+
+	/*
+	 * isolate first argument
+	 */
+	if(REGARG) {	
+		if(typecmplx[thisfn->link->etype]) {
+			nod1 = *nodret->left;
+			nodreg(&nod, &nod1, REGARG);
+			gmove(&nod, &nod1);
+		} else
+		if(firstarg && typeword[firstargtype->etype]) {
+			nod1 = *nodret->left;
+			nod1.sym = firstarg;
+			nod1.type = firstargtype;
+			nod1.xoffset = align(0, firstargtype, Aarg1);
+			nod1.etype = firstargtype->etype;
+			nodreg(&nod, &nod1, REGARG);
+			gmove(&nod, &nod1);
+		}
+	}
+
+	canreach = 1;
+	warnreach = 1;
+	gen(n);
+	if(canreach && thisfn->link->etype != TVOID)
+		warn(Z, "no return at end of function: %s", n1->sym->name);
+	noretval(3);
+	gbranch(ORETURN);
+
+	if(!debug['N'] || debug['R'] || debug['P'])
+		regopt(sp);
+	
+	if(thechar=='6' || thechar=='7')	/* [sic] */
+		maxargsafe = xround(maxargsafe, 8);
+	sp->to.offset += maxargsafe;
+}
+
+void
+supgen(Node *n)
+{
+	int owarn;
+	long spc;
+	Prog *sp;
+
+	if(n == Z)
+		return;
+	suppress++;
+	owarn = warnreach;
+	warnreach = 0;
+	spc = pc;
+	sp = lastp;
+	gen(n);
+	lastp = sp;
+	pc = spc;
+	sp->link = nil;
+	suppress--;
+	warnreach = owarn;
+}
+
+void
+gen(Node *n)
+{
+	Node *l, nod;
+	Prog *sp, *spc, *spb;
+	Case *cn;
+	long sbc, scc;
+	int snbreak, sncontin;
+	int f, o, oldreach;
+
+loop:
+	if(n == Z)
+		return;
+	nearln = n->lineno;
+	o = n->op;
+	if(debug['G'])
+		if(o != OLIST)
+			print("%L %O\n", nearln, o);
+
+	if(!canreach) {
+		switch(o) {
+		case OLABEL:
+		case OCASE:
+		case OLIST:
+		case OBREAK:
+		case OFOR:
+		case OWHILE:
+		case ODWHILE:
+			/* all handled specially - see switch body below */
+			break;
+		default:
+			if(warnreach) {
+				warn(n, "unreachable code %O", o);
+				warnreach = 0;
+			}
+		}
+	}
+
+	switch(o) {
+
+	default:
+		complex(n);
+		cgen(n, Z);
+		break;
+
+	case OLIST:
+		gen(n->left);
+
+	rloop:
+		n = n->right;
+		goto loop;
+
+	case ORETURN:
+		canreach = 0;
+		warnreach = !suppress;
+		complex(n);
+		if(n->type == T)
+			break;
+		l = n->left;
+		if(l == Z) {
+			noretval(3);
+			gbranch(ORETURN);
+			break;
+		}
+		if(typecmplx[n->type->etype]) {
+			sugen(l, nodret, n->type->width);
+			noretval(3);
+			gbranch(ORETURN);
+			break;
+		}
+		regret(&nod, n);
+		cgen(l, &nod);
+		regfree(&nod);
+		if(typefd[n->type->etype])
+			noretval(1);
+		else
+			noretval(2);
+		gbranch(ORETURN);
+		break;
+
+	case OLABEL:
+		canreach = 1;
+		l = n->left;
+		if(l) {
+			l->pc = pc;
+			if(l->label)
+				patch(l->label, pc);
+		}
+		gbranch(OGOTO);	/* prevent self reference in reg */
+		patch(p, pc);
+		goto rloop;
+
+	case OGOTO:
+		canreach = 0;
+		warnreach = !suppress;
+		n = n->left;
+		if(n == Z)
+			return;
+		if(n->complex == 0) {
+			diag(Z, "label undefined: %s", n->sym->name);
+			return;
+		}
+		if(suppress)
+			return;
+		gbranch(OGOTO);
+		if(n->pc) {
+			patch(p, n->pc);
+			return;
+		}
+		if(n->label)
+			patch(n->label, pc-1);
+		n->label = p;
+		return;
+
+	case OCASE:
+		canreach = 1;
+		l = n->left;
+		if(cases == C)
+			diag(n, "case/default outside a switch");
+		if(l == Z) {
+			cas();
+			cases->val = 0;
+			cases->def = 1;
+			cases->label = pc;
+			cases->isv = 0;
+			goto rloop;
+		}
+		complex(l);
+		if(l->type == T)
+			goto rloop;
+		if(l->op == OCONST)
+		if(typeword[l->type->etype] && l->type->etype != TIND) {
+			cas();
+			cases->val = l->vconst;
+			cases->def = 0;
+			cases->label = pc;
+			cases->isv = typev[l->type->etype];
+			goto rloop;
+		}
+		diag(n, "case expression must be integer constant");
+		goto rloop;
+
+	case OSWITCH:
+		l = n->left;
+		complex(l);
+		if(l->type == T)
+			break;
+		if(!typeword[l->type->etype] || l->type->etype == TIND) {
+			diag(n, "switch expression must be integer");
+			break;
+		}
+
+		gbranch(OGOTO);		/* entry */
+		sp = p;
+
+		cn = cases;
+		cases = C;
+		cas();
+
+		sbc = breakpc;
+		breakpc = pc;
+		snbreak = nbreak;
+		nbreak = 0;
+		gbranch(OGOTO);
+		spb = p;
+
+		gen(n->right);		/* body */
+		if(canreach){
+			gbranch(OGOTO);
+			patch(p, breakpc);
+			nbreak++;
+		}
+
+		patch(sp, pc);
+		regalloc(&nod, l, Z);
+		/* always signed */
+		if(typev[l->type->etype])
+			nod.type = types[TVLONG];
+		else
+			nod.type = types[TLONG];
+		cgen(l, &nod);
+		doswit(&nod);
+		regfree(&nod);
+		patch(spb, pc);
+
+		cases = cn;
+		breakpc = sbc;
+		canreach = nbreak!=0;
+		if(canreach == 0)
+			warnreach = !suppress;
+		nbreak = snbreak;
+		break;
+
+	case OWHILE:
+	case ODWHILE:
+		l = n->left;
+		gbranch(OGOTO);		/* entry */
+		sp = p;
+
+		scc = continpc;
+		continpc = pc;
+		gbranch(OGOTO);
+		spc = p;
+
+		sbc = breakpc;
+		breakpc = pc;
+		snbreak = nbreak;
+		nbreak = 0;
+		gbranch(OGOTO);
+		spb = p;
+
+		patch(spc, pc);
+		if(n->op == OWHILE)
+			patch(sp, pc);
+		bcomplex(l, Z);		/* test */
+		patch(p, breakpc);
+		if(l->op != OCONST || vconst(l) == 0)
+			nbreak++;
+
+		if(n->op == ODWHILE)
+			patch(sp, pc);
+		gen(n->right);		/* body */
+		gbranch(OGOTO);
+		patch(p, continpc);
+
+		patch(spb, pc);
+		continpc = scc;
+		breakpc = sbc;
+		canreach = nbreak!=0;
+		if(canreach == 0)
+			warnreach = !suppress;
+		nbreak = snbreak;
+		break;
+
+	case OFOR:
+		l = n->left;
+		if(!canreach && l->right->left && warnreach) {
+			warn(n, "unreachable code FOR");
+			warnreach = 0;
+		}
+		gen(l->right->left);	/* init */
+		gbranch(OGOTO);		/* entry */
+		sp = p;
+
+		/* 
+		 * if there are no incoming labels in the 
+		 * body and the top's not reachable, warn
+		 */
+		if(!canreach && warnreach && deadheads(n)) {
+			warn(n, "unreachable code %O", o);
+			warnreach = 0;
+		}
+
+		scc = continpc;
+		continpc = pc;
+		gbranch(OGOTO);
+		spc = p;
+
+		sbc = breakpc;
+		breakpc = pc;
+		snbreak = nbreak;
+		nbreak = 0;
+		sncontin = ncontin;
+		ncontin = 0;
+		gbranch(OGOTO);
+		spb = p;
+
+		patch(spc, pc);
+		gen(l->right->right);	/* inc */
+		patch(sp, pc);	
+		if(l->left != Z) {	/* test */
+			bcomplex(l->left, Z);
+			patch(p, breakpc);
+			if(l->left->op != OCONST || vconst(l->left) == 0)
+				nbreak++;
+		}
+		canreach = 1;
+		gen(n->right);		/* body */
+		if(canreach){
+			gbranch(OGOTO);
+			patch(p, continpc);
+			ncontin++;
+		}
+		if(!ncontin && l->right->right && warnreach) {
+			warn(l->right->right, "unreachable FOR inc");
+			warnreach = 0;
+		}
+
+		patch(spb, pc);
+		continpc = scc;
+		breakpc = sbc;
+		canreach = nbreak!=0;
+		if(canreach == 0)
+			warnreach = !suppress;
+		nbreak = snbreak;
+		ncontin = sncontin;
+		break;
+
+	case OCONTINUE:
+		if(continpc < 0) {
+			diag(n, "continue not in a loop");
+			break;
+		}
+		gbranch(OGOTO);
+		patch(p, continpc);
+		ncontin++;
+		canreach = 0;
+		warnreach = !suppress;
+		break;
+
+	case OBREAK:
+		if(breakpc < 0) {
+			diag(n, "break not in a loop");
+			break;
+		}
+		/*
+		 * Don't complain about unreachable break statements.
+		 * There are breaks hidden in yacc's output and some people
+		 * write return; break; in their switch statements out of habit.
+		 * However, don't confuse the analysis by inserting an 
+		 * unreachable reference to breakpc either.
+		 */
+		if(!canreach)
+			break;
+		gbranch(OGOTO);
+		patch(p, breakpc);
+		nbreak++;
+		canreach = 0;
+		warnreach = !suppress;
+		break;
+
+	case OIF:
+		l = n->left;
+		if(bcomplex(l, n->right)) {
+			if(typefd[l->type->etype])
+				f = !l->fconst;
+			else
+				f = !l->vconst;
+			if(debug['c'])
+				print("%L const if %s\n", nearln, f ? "false" : "true");
+			if(f) {
+				canreach = 1;
+				supgen(n->right->left);
+				oldreach = canreach;
+				canreach = 1;
+				gen(n->right->right);
+				/*
+				 * treat constant ifs as regular ifs for 
+				 * reachability warnings.
+				 */
+				if(!canreach && oldreach && debug['w'] < 2)
+					warnreach = 0;
+			}
+			else {
+				canreach = 1;
+				gen(n->right->left);
+				oldreach = canreach;
+				canreach = 1;
+				supgen(n->right->right);
+				/*
+				 * treat constant ifs as regular ifs for 
+				 * reachability warnings.
+				 */
+				if(!oldreach && canreach && debug['w'] < 2)
+					warnreach = 0;
+				canreach = oldreach;
+			}
+		}
+		else {
+			sp = p;
+			canreach = 1;
+			if(n->right->left != Z)
+				gen(n->right->left);
+			oldreach = canreach;
+			canreach = 1;
+			if(n->right->right != Z) {
+				gbranch(OGOTO);
+				patch(sp, pc);
+				sp = p;
+				gen(n->right->right);
+			}
+			patch(sp, pc);
+			canreach = canreach || oldreach;
+			if(canreach == 0)
+				warnreach = !suppress;
+		}
+		break;
+
+	case OSET:
+	case OUSED:
+		usedset(n->left, o);
+		break;
+	}
+}
+
+void
+usedset(Node *n, int o)
+{
+	if(n->op == OLIST) {
+		usedset(n->left, o);
+		usedset(n->right, o);
+		return;
+	}
+	complex(n);
+	switch(n->op) {
+	case OADDR:	/* volatile */
+		gins(ANOP, n, Z);
+		break;
+	case ONAME:
+		if(o == OSET)
+			gins(ANOP, Z, n);
+		else
+			gins(ANOP, n, Z);
+		break;
+	}
+}
+
+int
+bcomplex(Node *n, Node *c)
+{
+
+	complex(n);
+	if(n->type != T)
+	if(tcompat(n, T, n->type, tnot))
+		n->type = T;
+	if(n->type == T) {
+		gbranch(OGOTO);
+		return 0;
+	}
+	if(c != Z && n->op == OCONST && deadheads(c))
+		return 1;
+	bool64(n);
+	boolgen(n, 1, Z);
+	return 0;
+}
diff --git a/src/cmd/6c/pswt.c b/src/cmd/6c/pswt.c
new file mode 100644
index 0000000..f4149f1
--- /dev/null
+++ b/src/cmd/6c/pswt.c
@@ -0,0 +1,168 @@
+// Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+	C1 *p1, *p2;
+
+	p1 = (C1*)a1;
+	p2 = (C1*)a2;
+	if(p1->val < p2->val)
+		return -1;
+	return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+	Case *c;
+	C1 *q, *iq;
+	long def, nc, i, isv;
+
+	def = 0;
+	nc = 0;
+	isv = 0;
+	for(c = cases; c->link != C; c = c->link) {
+		if(c->def) {
+			if(def)
+				diag(n, "more than one default in switch");
+			def = c->label;
+			continue;
+		}
+		isv |= c->isv;
+		nc++;
+	}
+	if(isv && !typev[n->type->etype])
+		warn(n, "32-bit switch expression with 64-bit case constant");
+
+	iq = alloc(nc*sizeof(C1));
+	q = iq;
+	for(c = cases; c->link != C; c = c->link) {
+		if(c->def)
+			continue;
+		q->label = c->label;
+		if(isv)
+			q->val = c->val;
+		else
+			q->val = (long)c->val;	/* cast ensures correct value for 32-bit switch on 64-bit architecture */
+		q++;
+	}
+	qsort(iq, nc, sizeof(C1), swcmp);
+	if(debug['W'])
+	for(i=0; i<nc; i++)
+		print("case %2ld: = %.8llux\n", i, (vlong)iq[i].val);
+	for(i=0; i<nc-1; i++)
+		if(iq[i].val == iq[i+1].val)
+			diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val);
+	if(def == 0) {
+		def = breakpc;
+		nbreak++;
+	}
+	swit1(iq, nc, def, n);
+}
+
+void
+cas(void)
+{
+	Case *c;
+
+	c = alloc(sizeof(*c));
+	c->link = cases;
+	cases = c;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+	char buf[2];
+	int c;
+	long r;
+
+	if(suppress)
+		return nstring;
+	while(nstring & 1)
+		outstring("", 1);
+	r = nstring;
+	while(n > 0) {
+		c = *s++;
+		if(align(0, types[TCHAR], Aarg1)) {
+			buf[0] = c>>8;
+			buf[1] = c;
+		} else {
+			buf[0] = c;
+			buf[1] = c>>8;
+		}
+		outstring(buf, 2);
+		n -= sizeof(ushort);
+	}
+	return r;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+	warn(Z, "result of operation not used");
+	if(l != Z)
+		cgen(l, Z);
+	if(r != Z)
+		cgen(r, Z);
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+	double fr, ho, f;
+	int exp;
+
+	if(native < 0) {
+		ieeedtod(ieee, -native);
+		ieee->h |= 0x80000000L;
+		return;
+	}
+	if(native == 0) {
+		ieee->l = 0;
+		ieee->h = 0;
+		return;
+	}
+	fr = frexp(native, &exp);
+	f = 2097152L;		/* shouldnt use fp constants here */
+	fr = modf(fr*f, &ho);
+	ieee->h = ho;
+	ieee->h &= 0xfffffL;
+	ieee->h |= (exp+1022L) << 20;
+	f = 65536L;
+	fr = modf(fr*f, &ho);
+	ieee->l = ho;
+	ieee->l <<= 16;
+	ieee->l |= (long)(fr*f);
+}
diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c
new file mode 100644
index 0000000..a03d1ca
--- /dev/null
+++ b/src/cmd/6c/reg.c
@@ -0,0 +1,1386 @@
+// Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+Reg*
+rega(void)
+{
+	Reg *r;
+
+	r = freer;
+	if(r == R) {
+		r = alloc(sizeof(*r));
+	} else
+		freer = r->link;
+
+	*r = zreg;
+	return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+	Rgn *p1, *p2;
+	int c1, c2;
+
+	p1 = (Rgn*)a1;
+	p2 = (Rgn*)a2;
+	c1 = p2->cost;
+	c2 = p1->cost;
+	if(c1 -= c2)
+		return c1;
+	return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+	Reg *r, *r1, *r2;
+	Prog *p1;
+	int i, z;
+	long initpc, val, npc;
+	ulong vreg;
+	Bits bit;
+	struct
+	{
+		long	m;
+		long	c;
+		Reg*	p;
+	} log5[6], *lp;
+
+	firstr = R;
+	lastr = R;
+	nvar = 0;
+	regbits = RtoB(D_SP) | RtoB(D_AX) | RtoB(D_X0);
+	for(z=0; z<BITS; z++) {
+		externs.b[z] = 0;
+		params.b[z] = 0;
+		consts.b[z] = 0;
+		addrs.b[z] = 0;
+	}
+
+	/*
+	 * pass 1
+	 * build aux data structure
+	 * allocate pcs
+	 * find use and set of variables
+	 */
+	val = 5L * 5L * 5L * 5L * 5L;
+	lp = log5;
+	for(i=0; i<5; i++) {
+		lp->m = val;
+		lp->c = 0;
+		lp->p = R;
+		val /= 5L;
+		lp++;
+	}
+	val = 0;
+	for(; p != P; p = p->link) {
+		switch(p->as) {
+		case ADATA:
+		case AGLOBL:
+		case ANAME:
+		case ASIGNAME:
+			continue;
+		}
+		r = rega();
+		if(firstr == R) {
+			firstr = r;
+			lastr = r;
+		} else {
+			lastr->link = r;
+			r->p1 = lastr;
+			lastr->s1 = r;
+			lastr = r;
+		}
+		r->prog = p;
+		r->pc = val;
+		val++;
+
+		lp = log5;
+		for(i=0; i<5; i++) {
+			lp->c--;
+			if(lp->c <= 0) {
+				lp->c = lp->m;
+				if(lp->p != R)
+					lp->p->log5 = r;
+				lp->p = r;
+				(lp+1)->c = 0;
+				break;
+			}
+			lp++;
+		}
+
+		r1 = r->p1;
+		if(r1 != R)
+		switch(r1->prog->as) {
+		case ARET:
+		case AJMP:
+		case AIRETL:
+		case AIRETQ:
+			r->p1 = R;
+			r1->s1 = R;
+		}
+
+		bit = mkvar(r, &p->from);
+		if(bany(&bit))
+		switch(p->as) {
+		/*
+		 * funny
+		 */
+		case ALEAL:
+		case ALEAQ:
+			for(z=0; z<BITS; z++)
+				addrs.b[z] |= bit.b[z];
+			break;
+
+		/*
+		 * left side read
+		 */
+		default:
+			for(z=0; z<BITS; z++)
+				r->use1.b[z] |= bit.b[z];
+			break;
+		}
+
+		bit = mkvar(r, &p->to);
+		if(bany(&bit))
+		switch(p->as) {
+		default:
+			diag(Z, "reg: unknown op: %A", p->as);
+			break;
+
+		/*
+		 * right side read
+		 */
+		case ACMPB:
+		case ACMPL:
+		case ACMPQ:
+		case ACMPW:
+		case ACOMISS:
+		case ACOMISD:
+		case AUCOMISS:
+		case AUCOMISD:
+			for(z=0; z<BITS; z++)
+				r->use2.b[z] |= bit.b[z];
+			break;
+
+		/*
+		 * right side write
+		 */
+		case ANOP:
+		case AMOVL:
+		case AMOVQ:
+		case AMOVB:
+		case AMOVW:
+		case AMOVBLSX:
+		case AMOVBLZX:
+		case AMOVBQSX:
+		case AMOVBQZX:
+		case AMOVLQSX:
+		case AMOVLQZX:
+		case AMOVWLSX:
+		case AMOVWLZX:
+		case AMOVWQSX:
+		case AMOVWQZX:
+
+		case AMOVSS:
+		case AMOVSD:
+		case ACVTSD2SL:
+		case ACVTSD2SQ:
+		case ACVTSD2SS:
+		case ACVTSL2SD:
+		case ACVTSL2SS:
+		case ACVTSQ2SD:
+		case ACVTSQ2SS:
+		case ACVTSS2SD:
+		case ACVTSS2SL:
+		case ACVTSS2SQ:
+		case ACVTTSD2SL:
+		case ACVTTSD2SQ:
+		case ACVTTSS2SL:
+		case ACVTTSS2SQ:
+			for(z=0; z<BITS; z++)
+				r->set.b[z] |= bit.b[z];
+			break;
+
+		/*
+		 * right side read+write
+		 */
+		case AADDB:
+		case AADDL:
+		case AADDQ:
+		case AADDW:
+		case AANDB:
+		case AANDL:
+		case AANDQ:
+		case AANDW:
+		case ASUBB:
+		case ASUBL:
+		case ASUBQ:
+		case ASUBW:
+		case AORB:
+		case AORL:
+		case AORQ:
+		case AORW:
+		case AXORB:
+		case AXORL:
+		case AXORQ:
+		case AXORW:
+		case ASALB:
+		case ASALL:
+		case ASALQ:
+		case ASALW:
+		case ASARB:
+		case ASARL:
+		case ASARQ:
+		case ASARW:
+		case AROLB:
+		case AROLL:
+		case AROLQ:
+		case AROLW:
+		case ARORB:
+		case ARORL:
+		case ARORQ:
+		case ARORW:
+		case ASHLB:
+		case ASHLL:
+		case ASHLQ:
+		case ASHLW:
+		case ASHRB:
+		case ASHRL:
+		case ASHRQ:
+		case ASHRW:
+		case AIMULL:
+		case AIMULQ:
+		case AIMULW:
+		case ANEGL:
+		case ANEGQ:
+		case ANOTL:
+		case ANOTQ:
+		case AADCL:
+		case AADCQ:
+		case ASBBL:
+		case ASBBQ:
+
+		case AADDSD:
+		case AADDSS:
+		case ACMPSD:
+		case ACMPSS:
+		case ADIVSD:
+		case ADIVSS:
+		case AMAXSD:
+		case AMAXSS:
+		case AMINSD:
+		case AMINSS:
+		case AMULSD:
+		case AMULSS:
+		case ARCPSS:
+		case ARSQRTSS:
+		case ASQRTSD:
+		case ASQRTSS:
+		case ASUBSD:
+		case ASUBSS:
+		case AXORPD:
+			for(z=0; z<BITS; z++) {
+				r->set.b[z] |= bit.b[z];
+				r->use2.b[z] |= bit.b[z];
+			}
+			break;
+
+		/*
+		 * funny
+		 */
+		case ACALL:
+			for(z=0; z<BITS; z++)
+				addrs.b[z] |= bit.b[z];
+			break;
+		}
+
+		switch(p->as) {
+		case AIMULL:
+		case AIMULQ:
+		case AIMULW:
+			if(p->to.type != D_NONE)
+				break;
+
+		case AIDIVB:
+		case AIDIVL:
+		case AIDIVQ:
+		case AIDIVW:
+		case AIMULB:
+		case ADIVB:
+		case ADIVL:
+		case ADIVQ:
+		case ADIVW:
+		case AMULB:
+		case AMULL:
+		case AMULQ:
+		case AMULW:
+
+		case ACWD:
+		case ACDQ:
+		case ACQO:
+			r->regu |= RtoB(D_AX) | RtoB(D_DX);
+			break;
+
+		case AREP:
+		case AREPN:
+		case ALOOP:
+		case ALOOPEQ:
+		case ALOOPNE:
+			r->regu |= RtoB(D_CX);
+			break;
+
+		case AMOVSB:
+		case AMOVSL:
+		case AMOVSQ:
+		case AMOVSW:
+		case ACMPSB:
+		case ACMPSL:
+		case ACMPSQ:
+		case ACMPSW:
+			r->regu |= RtoB(D_SI) | RtoB(D_DI);
+			break;
+
+		case ASTOSB:
+		case ASTOSL:
+		case ASTOSQ:
+		case ASTOSW:
+		case ASCASB:
+		case ASCASL:
+		case ASCASQ:
+		case ASCASW:
+			r->regu |= RtoB(D_AX) | RtoB(D_DI);
+			break;
+
+		case AINSB:
+		case AINSL:
+		case AINSW:
+		case AOUTSB:
+		case AOUTSL:
+		case AOUTSW:
+			r->regu |= RtoB(D_DI) | RtoB(D_DX);
+			break;
+		}
+	}
+	if(firstr == R)
+		return;
+	initpc = pc - val;
+	npc = val;
+
+	/*
+	 * pass 2
+	 * turn branch references to pointers
+	 * build back pointers
+	 */
+	for(r = firstr; r != R; r = r->link) {
+		p = r->prog;
+		if(p->to.type == D_BRANCH) {
+			val = p->to.offset - initpc;
+			r1 = firstr;
+			while(r1 != R) {
+				r2 = r1->log5;
+				if(r2 != R && val >= r2->pc) {
+					r1 = r2;
+					continue;
+				}
+				if(r1->pc == val)
+					break;
+				r1 = r1->link;
+			}
+			if(r1 == R) {
+				nearln = p->lineno;
+				diag(Z, "ref not found\n%P", p);
+				continue;
+			}
+			if(r1 == r) {
+				nearln = p->lineno;
+				diag(Z, "ref to self\n%P", p);
+				continue;
+			}
+			r->s2 = r1;
+			r->p2link = r1->p2;
+			r1->p2 = r;
+		}
+	}
+	if(debug['R']) {
+		p = firstr->prog;
+		print("\n%L %D\n", p->lineno, &p->from);
+	}
+
+	/*
+	 * pass 2.5
+	 * find looping structure
+	 */
+	for(r = firstr; r != R; r = r->link)
+		r->active = 0;
+	change = 0;
+	loopit(firstr, npc);
+	if(debug['R'] && debug['v']) {
+		print("\nlooping structure:\n");
+		for(r = firstr; r != R; r = r->link) {
+			print("%ld:%P", r->loop, r->prog);
+			for(z=0; z<BITS; z++)
+				bit.b[z] = r->use1.b[z] |
+					   r->use2.b[z] |
+					   r->set.b[z];
+			if(bany(&bit)) {
+				print("\t");
+				if(bany(&r->use1))
+					print(" u1=%B", r->use1);
+				if(bany(&r->use2))
+					print(" u2=%B", r->use2);
+				if(bany(&r->set))
+					print(" st=%B", r->set);
+			}
+			print("\n");
+		}
+	}
+
+	/*
+	 * pass 3
+	 * iterate propagating usage
+	 * 	back until flow graph is complete
+	 */
+loop1:
+	change = 0;
+	for(r = firstr; r != R; r = r->link)
+		r->active = 0;
+	for(r = firstr; r != R; r = r->link)
+		if(r->prog->as == ARET)
+			prop(r, zbits, zbits);
+loop11:
+	/* pick up unreachable code */
+	i = 0;
+	for(r = firstr; r != R; r = r1) {
+		r1 = r->link;
+		if(r1 && r1->active && !r->active) {
+			prop(r, zbits, zbits);
+			i = 1;
+		}
+	}
+	if(i)
+		goto loop11;
+	if(change)
+		goto loop1;
+
+
+	/*
+	 * pass 4
+	 * iterate propagating register/variable synchrony
+	 * 	forward until graph is complete
+	 */
+loop2:
+	change = 0;
+	for(r = firstr; r != R; r = r->link)
+		r->active = 0;
+	synch(firstr, zbits);
+	if(change)
+		goto loop2;
+
+
+	/*
+	 * pass 5
+	 * isolate regions
+	 * calculate costs (paint1)
+	 */
+	r = firstr;
+	if(r) {
+		for(z=0; z<BITS; z++)
+			bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+			  ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+		if(bany(&bit)) {
+			nearln = r->prog->lineno;
+			warn(Z, "used and not set: %B", bit);
+			if(debug['R'] && !debug['w'])
+				print("used and not set: %B\n", bit);
+		}
+	}
+	if(debug['R'] && debug['v'])
+		print("\nprop structure:\n");
+	for(r = firstr; r != R; r = r->link)
+		r->act = zbits;
+	rgp = region;
+	nregion = 0;
+	for(r = firstr; r != R; r = r->link) {
+		if(debug['R'] && debug['v']) {
+			print("%P\t", r->prog);
+			if(bany(&r->set))
+				print("s:%B ", r->set);
+			if(bany(&r->refahead))
+				print("ra:%B ", r->refahead);
+			if(bany(&r->calahead))
+				print("ca:%B ", r->calahead);
+			print("\n");
+		}
+		for(z=0; z<BITS; z++)
+			bit.b[z] = r->set.b[z] &
+			  ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+		if(bany(&bit)) {
+			nearln = r->prog->lineno;
+			warn(Z, "set and not used: %B", bit);
+			if(debug['R'])
+				print("set and not used: %B\n", bit);
+			excise(r);
+		}
+		for(z=0; z<BITS; z++)
+			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+		while(bany(&bit)) {
+			i = bnum(bit);
+			rgp->enter = r;
+			rgp->varno = i;
+			change = 0;
+			if(debug['R'] && debug['v'])
+				print("\n");
+			paint1(r, i);
+			bit.b[i/32] &= ~(1L<<(i%32));
+			if(change <= 0) {
+				if(debug['R'])
+					print("%L$%d: %B\n",
+						r->prog->lineno, change, blsh(i));
+				continue;
+			}
+			rgp->cost = change;
+			nregion++;
+			if(nregion >= NRGN) {
+				warn(Z, "too many regions");
+				goto brk;
+			}
+			rgp++;
+		}
+	}
+brk:
+	qsort(region, nregion, sizeof(region[0]), rcmp);
+
+	/*
+	 * pass 6
+	 * determine used registers (paint2)
+	 * replace code (paint3)
+	 */
+	rgp = region;
+	for(i=0; i<nregion; i++) {
+		bit = blsh(rgp->varno);
+		vreg = paint2(rgp->enter, rgp->varno);
+		vreg = allreg(vreg, rgp);
+		if(debug['R']) {
+			print("%L$%d %R: %B\n",
+				rgp->enter->prog->lineno,
+				rgp->cost,
+				rgp->regno,
+				bit);
+		}
+		if(rgp->regno != 0)
+			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+		rgp++;
+	}
+	/*
+	 * pass 7
+	 * peep-hole on basic block
+	 */
+	if(!debug['R'] || debug['P'])
+		peep();
+
+	/*
+	 * pass 8
+	 * recalculate pc
+	 */
+	val = initpc;
+	for(r = firstr; r != R; r = r1) {
+		r->pc = val;
+		p = r->prog;
+		p1 = P;
+		r1 = r->link;
+		if(r1 != R)
+			p1 = r1->prog;
+		for(; p != p1; p = p->link) {
+			switch(p->as) {
+			default:
+				val++;
+				break;
+
+			case ANOP:
+			case ADATA:
+			case AGLOBL:
+			case ANAME:
+			case ASIGNAME:
+				break;
+			}
+		}
+	}
+	pc = val;
+
+	/*
+	 * fix up branches
+	 */
+	if(debug['R'])
+		if(bany(&addrs))
+			print("addrs: %B\n", addrs);
+
+	r1 = 0; /* set */
+	for(r = firstr; r != R; r = r->link) {
+		p = r->prog;
+		if(p->to.type == D_BRANCH)
+			p->to.offset = r->s2->pc;
+		r1 = r;
+	}
+
+	/*
+	 * last pass
+	 * eliminate nops
+	 * free aux structures
+	 */
+	for(p = firstr->prog; p != P; p = p->link){
+		while(p->link && p->link->as == ANOP)
+			p->link = p->link->link;
+	}
+	if(r1 != R) {
+		r1->link = freer;
+		freer = firstr;
+	}
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+	Prog *p, *p1;
+	Adr *a;
+	Var *v;
+
+	p1 = alloc(sizeof(*p1));
+	*p1 = zprog;
+	p = r->prog;
+
+	p1->link = p->link;
+	p->link = p1;
+	p1->lineno = p->lineno;
+
+	v = var + bn;
+
+	a = &p1->to;
+	a->sym = v->sym;
+	a->offset = v->offset;
+	a->etype = v->etype;
+	a->type = v->name;
+
+	p1->as = AMOVL;
+	if(v->etype == TCHAR || v->etype == TUCHAR)
+		p1->as = AMOVB;
+	if(v->etype == TSHORT || v->etype == TUSHORT)
+		p1->as = AMOVW;
+	if(v->etype == TVLONG || v->etype == TUVLONG || v->etype == TIND)
+		p1->as = AMOVQ;
+	if(v->etype == TFLOAT)
+		p1->as = AMOVSS;
+	if(v->etype == TDOUBLE)
+		p1->as = AMOVSD;
+
+	p1->from.type = rn;
+	if(!f) {
+		p1->from = *a;
+		*a = zprog.from;
+		a->type = rn;
+		if(v->etype == TUCHAR)
+			p1->as = AMOVB;
+		if(v->etype == TUSHORT)
+			p1->as = AMOVW;
+	}
+	if(debug['R'])
+		print("%P\t.a%P\n", p, p1);
+}
+
+ulong
+doregbits(int r)
+{
+	ulong b;
+
+	b = 0;
+	if(r >= D_INDIR)
+		r -= D_INDIR;
+	if(r >= D_AX && r <= D_R15)
+		b |= RtoB(r);
+	else
+	if(r >= D_AL && r <= D_R15B)
+		b |= RtoB(r-D_AL+D_AX);
+	else
+	if(r >= D_AH && r <= D_BH)
+		b |= RtoB(r-D_AH+D_AX);
+	else
+	if(r >= D_X0 && r <= D_X0+15)
+		b |= FtoB(r);
+	return b;
+}
+
+Bits
+mkvar(Reg *r, Adr *a)
+{
+	Var *v;
+	int i, t, n, et, z;
+	long o;
+	Bits bit;
+	Sym *s;
+
+	/*
+	 * mark registers used
+	 */
+	t = a->type;
+	r->regu |= doregbits(t);
+	r->regu |= doregbits(a->index);
+
+	switch(t) {
+	default:
+		goto none;
+	case D_ADDR:
+		a->type = a->index;
+		bit = mkvar(r, a);
+		for(z=0; z<BITS; z++)
+			addrs.b[z] |= bit.b[z];
+		a->type = t;
+		goto none;
+	case D_EXTERN:
+	case D_STATIC:
+	case D_PARAM:
+	case D_AUTO:
+		n = t;
+		break;
+	}
+	s = a->sym;
+	if(s == S)
+		goto none;
+	if(s->name[0] == '.')
+		goto none;
+	et = a->etype;
+	o = a->offset;
+	v = var;
+	for(i=0; i<nvar; i++) {
+		if(s == v->sym)
+		if(n == v->name)
+		if(o == v->offset)
+			goto out;
+		v++;
+	}
+	if(nvar >= NVAR) {
+		if(debug['w'] > 1 && s)
+			warn(Z, "variable not optimized: %s", s->name);
+		goto none;
+	}
+	i = nvar;
+	nvar++;
+	v = &var[i];
+	v->sym = s;
+	v->offset = o;
+	v->name = n;
+	v->etype = et;
+	if(debug['R'])
+		print("bit=%2d et=%2d %D\n", i, et, a);
+
+out:
+	bit = blsh(i);
+	if(n == D_EXTERN || n == D_STATIC)
+		for(z=0; z<BITS; z++)
+			externs.b[z] |= bit.b[z];
+	if(n == D_PARAM)
+		for(z=0; z<BITS; z++)
+			params.b[z] |= bit.b[z];
+	if(v->etype != et || !(typechlpfd[et] || typev[et]))	/* funny punning */
+		for(z=0; z<BITS; z++)
+			addrs.b[z] |= bit.b[z];
+	return bit;
+
+none:
+	return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+	Reg *r1, *r2;
+	int z;
+
+	for(r1 = r; r1 != R; r1 = r1->p1) {
+		for(z=0; z<BITS; z++) {
+			ref.b[z] |= r1->refahead.b[z];
+			if(ref.b[z] != r1->refahead.b[z]) {
+				r1->refahead.b[z] = ref.b[z];
+				change++;
+			}
+			cal.b[z] |= r1->calahead.b[z];
+			if(cal.b[z] != r1->calahead.b[z]) {
+				r1->calahead.b[z] = cal.b[z];
+				change++;
+			}
+		}
+		switch(r1->prog->as) {
+		case ACALL:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] |= ref.b[z] | externs.b[z];
+				ref.b[z] = 0;
+			}
+			break;
+
+		case ATEXT:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = 0;
+				ref.b[z] = 0;
+			}
+			break;
+
+		case ARET:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = externs.b[z];
+				ref.b[z] = 0;
+			}
+		}
+		for(z=0; z<BITS; z++) {
+			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+				r1->use1.b[z] | r1->use2.b[z];
+			cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+			r1->refbehind.b[z] = ref.b[z];
+			r1->calbehind.b[z] = cal.b[z];
+		}
+		if(r1->active)
+			break;
+		r1->active = 1;
+	}
+	for(; r != r1; r = r->p1)
+		for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+			prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ *	the actual dominators if the flow graph is reducible
+ *	otherwise, dominators plus some other non-dominators.
+ *	See Matthew S. Hecht and Jeffrey D. Ullman,
+ *	"Analysis of a Simple Algorithm for Global Data Flow Problems",
+ *	Conf.  Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ *	Oct. 1-3, 1973, pp.  207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ *	such a node is a loop head.
+ *	recursively, all preds with a greater rpo number are in the loop
+ */
+long
+postorder(Reg *r, Reg **rpo2r, long n)
+{
+	Reg *r1;
+
+	r->rpo = 1;
+	r1 = r->s1;
+	if(r1 && !r1->rpo)
+		n = postorder(r1, rpo2r, n);
+	r1 = r->s2;
+	if(r1 && !r1->rpo)
+		n = postorder(r1, rpo2r, n);
+	rpo2r[n] = r;
+	n++;
+	return n;
+}
+
+long
+rpolca(long *idom, long rpo1, long rpo2)
+{
+	long t;
+
+	if(rpo1 == -1)
+		return rpo2;
+	while(rpo1 != rpo2){
+		if(rpo1 > rpo2){
+			t = rpo2;
+			rpo2 = rpo1;
+			rpo1 = t;
+		}
+		while(rpo1 < rpo2){
+			t = idom[rpo2];
+			if(t >= rpo2)
+				fatal(Z, "bad idom");
+			rpo2 = t;
+		}
+	}
+	return rpo1;
+}
+
+int
+doms(long *idom, long r, long s)
+{
+	while(s > r)
+		s = idom[s];
+	return s == r;
+}
+
+int
+loophead(long *idom, Reg *r)
+{
+	long src;
+
+	src = r->rpo;
+	if(r->p1 != R && doms(idom, src, r->p1->rpo))
+		return 1;
+	for(r = r->p2; r != R; r = r->p2link)
+		if(doms(idom, src, r->rpo))
+			return 1;
+	return 0;
+}
+
+void
+loopmark(Reg **rpo2r, long head, Reg *r)
+{
+	if(r->rpo < head || r->active == head)
+		return;
+	r->active = head;
+	r->loop += LOOP;
+	if(r->p1 != R)
+		loopmark(rpo2r, head, r->p1);
+	for(r = r->p2; r != R; r = r->p2link)
+		loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, long nr)
+{
+	Reg *r1;
+	long i, d, me;
+
+	if(nr > maxnr) {
+		rpo2r = alloc(nr * sizeof(Reg*));
+		idom = alloc(nr * sizeof(long));
+		maxnr = nr;
+	}
+
+	d = postorder(r, rpo2r, 0);
+	if(d > nr)
+		fatal(Z, "too many reg nodes");
+	nr = d;
+	for(i = 0; i < nr / 2; i++){
+		r1 = rpo2r[i];
+		rpo2r[i] = rpo2r[nr - 1 - i];
+		rpo2r[nr - 1 - i] = r1;
+	}
+	for(i = 0; i < nr; i++)
+		rpo2r[i]->rpo = i;
+
+	idom[0] = 0;
+	for(i = 0; i < nr; i++){
+		r1 = rpo2r[i];
+		me = r1->rpo;
+		d = -1;
+		if(r1->p1 != R && r1->p1->rpo < me)
+			d = r1->p1->rpo;
+		for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+			if(r1->rpo < me)
+				d = rpolca(idom, d, r1->rpo);
+		idom[i] = d;
+	}
+
+	for(i = 0; i < nr; i++){
+		r1 = rpo2r[i];
+		r1->loop++;
+		if(r1->p2 != R && loophead(idom, r1))
+			loopmark(rpo2r, i, r1);
+	}
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+	Reg *r1;
+	int z;
+
+	for(r1 = r; r1 != R; r1 = r1->s1) {
+		for(z=0; z<BITS; z++) {
+			dif.b[z] = (dif.b[z] &
+				~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+					r1->set.b[z] | r1->regdiff.b[z];
+			if(dif.b[z] != r1->regdiff.b[z]) {
+				r1->regdiff.b[z] = dif.b[z];
+				change++;
+			}
+		}
+		if(r1->active)
+			break;
+		r1->active = 1;
+		for(z=0; z<BITS; z++)
+			dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+		if(r1->s2 != R)
+			synch(r1->s2, dif);
+	}
+}
+
+ulong
+allreg(ulong b, Rgn *r)
+{
+	Var *v;
+	int i;
+
+	v = var + r->varno;
+	r->regno = 0;
+	switch(v->etype) {
+
+	default:
+		diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+		break;
+
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+	case TVLONG:
+	case TUVLONG:
+	case TIND:
+	case TARRAY:
+		i = BtoR(~b);
+		if(i && r->cost > 0) {
+			r->regno = i;
+			return RtoB(i);
+		}
+		break;
+
+	case TDOUBLE:
+	case TFLOAT:
+		i = BtoF(~b);
+		if(i && r->cost > 0) {
+			r->regno = i;
+			return FtoB(i);
+		}
+		break;
+	}
+	return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+	Reg *r1;
+	Prog *p;
+	int z;
+	ulong bb;
+
+	z = bn/32;
+	bb = 1L<<(bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = r->p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+		change -= CLOAD * r->loop;
+		if(debug['R'] && debug['v'])
+			print("%ld%P\tld %B $%d\n", r->loop,
+				r->prog, blsh(bn), change);
+	}
+	for(;;) {
+		r->act.b[z] |= bb;
+		p = r->prog;
+
+		if(r->use1.b[z] & bb) {
+			change += CREF * r->loop;
+			if(debug['R'] && debug['v'])
+				print("%ld%P\tu1 %B $%d\n", r->loop,
+					p, blsh(bn), change);
+		}
+
+		if((r->use2.b[z]|r->set.b[z]) & bb) {
+			change += CREF * r->loop;
+			if(debug['R'] && debug['v'])
+				print("%ld%P\tu2 %B $%d\n", r->loop,
+					p, blsh(bn), change);
+		}
+
+		if(STORE(r) & r->regdiff.b[z] & bb) {
+			change -= CLOAD * r->loop;
+			if(debug['R'] && debug['v'])
+				print("%ld%P\tst %B $%d\n", r->loop,
+					p, blsh(bn), change);
+		}
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+				if(r1->refahead.b[z] & bb)
+					paint1(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = r->s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint1(r1, bn);
+		r = r->s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+ulong
+regset(Reg *r, ulong bb)
+{
+	ulong b, set;
+	Adr v;
+	int c;
+
+	set = 0;
+	v = zprog.from;
+	while(b = bb & ~(bb-1)) {
+		v.type = b & 0xFFFF? BtoR(b): BtoF(b);
+		if(v.type == 0)
+			diag(Z, "zero v.type for %#lux", b);
+		c = copyu(r->prog, &v, A);
+		if(c == 3)
+			set |= b;
+		bb &= ~b;
+	}
+	return set;
+}
+
+ulong
+reguse(Reg *r, ulong bb)
+{
+	ulong b, set;
+	Adr v;
+	int c;
+
+	set = 0;
+	v = zprog.from;
+	while(b = bb & ~(bb-1)) {
+		v.type = b & 0xFFFF? BtoR(b): BtoF(b);
+		c = copyu(r->prog, &v, A);
+		if(c == 1 || c == 2 || c == 4)
+			set |= b;
+		bb &= ~b;
+	}
+	return set;
+}
+
+ulong
+paint2(Reg *r, int bn)
+{
+	Reg *r1;
+	int z;
+	ulong bb, vreg, x;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	vreg = regbits;
+	if(!(r->act.b[z] & bb))
+		return vreg;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = r->p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(!(r1->act.b[z] & bb))
+			break;
+		r = r1;
+	}
+	for(;;) {
+		r->act.b[z] &= ~bb;
+
+		vreg |= r->regu;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+				if(r1->refahead.b[z] & bb)
+					vreg |= paint2(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = r->s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				vreg |= paint2(r1, bn);
+		r = r->s1;
+		if(r == R)
+			break;
+		if(!(r->act.b[z] & bb))
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+
+	bb = vreg;
+	for(; r; r=r->s1) {
+		x = r->regu & ~bb;
+		if(x) {
+			vreg |= reguse(r, x);
+			bb |= regset(r, x);
+		}
+	}
+	return vreg;
+}
+
+void
+paint3(Reg *r, int bn, long rb, int rn)
+{
+	Reg *r1;
+	Prog *p;
+	int z;
+	ulong bb;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = r->p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+		addmove(r, bn, rn, 0);
+	for(;;) {
+		r->act.b[z] |= bb;
+		p = r->prog;
+
+		if(r->use1.b[z] & bb) {
+			if(debug['R'])
+				print("%P", p);
+			addreg(&p->from, rn);
+			if(debug['R'])
+				print("\t.c%P\n", p);
+		}
+		if((r->use2.b[z]|r->set.b[z]) & bb) {
+			if(debug['R'])
+				print("%P", p);
+			addreg(&p->to, rn);
+			if(debug['R'])
+				print("\t.c%P\n", p);
+		}
+
+		if(STORE(r) & r->regdiff.b[z] & bb)
+			addmove(r, bn, rn, 1);
+		r->regu |= rb;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+				if(r1->refahead.b[z] & bb)
+					paint3(r1, bn, rb, rn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = r->s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint3(r1, bn, rb, rn);
+		r = r->s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+void
+addreg(Adr *a, int rn)
+{
+
+	a->sym = 0;
+	a->offset = 0;
+	a->type = rn;
+}
+
+long
+RtoB(int r)
+{
+
+	if(r < D_AX || r > D_R15)
+		return 0;
+	return 1L << (r-D_AX);
+}
+
+int
+BtoR(long b)
+{
+
+	b &= 0xffffL;
+	if(b == 0)
+		return 0;
+	return bitno(b) + D_AX;
+}
+
+/*
+ *	bit	reg
+ *	16	X5
+ *	17	X6
+ *	18	X7
+ */
+long
+FtoB(int f)
+{
+	if(f < FREGMIN || f > FREGEXT)
+		return 0;
+	return 1L << (f - FREGMIN + 16);
+}
+
+int
+BtoF(long b)
+{
+
+	b &= 0x70000L;
+	if(b == 0)
+		return 0;
+	return bitno(b) - 16 + FREGMIN;
+}
diff --git a/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c
new file mode 100644
index 0000000..63a86ba
--- /dev/null
+++ b/src/cmd/6c/sgen.c
@@ -0,0 +1,465 @@
+// Inferno utils/6c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+void
+noretval(int n)
+{
+
+	if(n & 1) {
+		gins(ANOP, Z, Z);
+		p->to.type = REGRET;
+	}
+	if(n & 2) {
+		gins(ANOP, Z, Z);
+		p->to.type = FREGRET;
+	}
+}
+
+/* welcome to commute */
+static void
+commute(Node *n)
+{
+	Node *l, *r;
+
+	l = n->left;
+	r = n->right;
+	if(r->complex > l->complex) {
+		n->left = r;
+		n->right = l;
+	}
+}
+
+void
+indexshift(Node *n)
+{
+	int g;
+
+	if(!typechlpv[n->type->etype])
+		return;
+	simplifyshift(n);
+	if(n->op == OASHL && n->right->op == OCONST){
+		g = vconst(n->right);
+		if(g >= 0 && g <= 3)
+			n->addable = 7;
+	}
+}
+
+/*
+ *	calculate addressability as follows
+ *		NAME ==> 10/11		name+value(SB/SP)
+ *		REGISTER ==> 12		register
+ *		CONST ==> 20		$value
+ *		*(20) ==> 21		value
+ *		&(10) ==> 13		$name+value(SB)
+ *		&(11) ==> 1		$name+value(SP)
+ *		(13) + (20) ==> 13	fold constants
+ *		(1) + (20) ==> 1	fold constants
+ *		*(13) ==> 10		back to name
+ *		*(1) ==> 11		back to name
+ *
+ *		(20) * (X) ==> 7	multiplier in indexing
+ *		(X,7) + (13,1) ==> 8	adder in indexing (addresses)
+ *		(8) ==> &9(OINDEX)	index, almost addressable
+ *
+ *	calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+	Node *l, *r;
+	int g;
+
+	if(n == Z)
+		return;
+	l = n->left;
+	r = n->right;
+	n->complex = 0;
+	n->addable = 0;
+	switch(n->op) {
+	case OCONST:
+		n->addable = 20;
+		break;
+
+	case ONAME:
+		n->addable = 10;
+		if(n->class == CPARAM || n->class == CAUTO)
+			n->addable = 11;
+		break;
+
+	case OREGISTER:
+		n->addable = 12;
+		break;
+
+	case OINDREG:
+		n->addable = 12;
+		break;
+
+	case OADDR:
+		xcom(l);
+		if(l->addable == 10)
+			n->addable = 13;
+		else
+		if(l->addable == 11)
+			n->addable = 1;
+		break;
+
+	case OADD:
+		xcom(l);
+		xcom(r);
+		if(n->type->etype != TIND)
+			break;
+
+		switch(r->addable) {
+		case 20:
+			switch(l->addable) {
+			case 1:
+			case 13:
+			commadd:
+				l->type = n->type;
+				*n = *l;
+				l = new(0, Z, Z);
+				*l = *(n->left);
+				l->xoffset += r->vconst;
+				n->left = l;
+				r = n->right;
+				goto brk;
+			}
+			break;
+
+		case 1:
+		case 13:
+		case 10:
+		case 11:
+			/* l is the base, r is the index */
+			if(l->addable != 20)
+				n->addable = 8;
+			break;
+		}
+		switch(l->addable) {
+		case 20:
+			switch(r->addable) {
+			case 13:
+			case 1:
+				r = n->left;
+				l = n->right;
+				n->left = l;
+				n->right = r;
+				goto commadd;
+			}
+			break;
+
+		case 13:
+		case 1:
+		case 10:
+		case 11:
+			/* r is the base, l is the index */
+			if(r->addable != 20)
+				n->addable = 8;
+			break;
+		}
+		if(n->addable == 8 && !side(n)) {
+			indx(n);
+			l = new1(OINDEX, idx.basetree, idx.regtree);
+			l->scale = idx.scale;
+			l->addable = 9;
+			l->complex = l->right->complex;
+			l->type = l->left->type;
+			n->op = OADDR;
+			n->left = l;
+			n->right = Z;
+			n->addable = 8;
+			break;
+		}
+		break;
+
+	case OINDEX:
+		xcom(l);
+		xcom(r);
+		n->addable = 9;
+		break;
+
+	case OIND:
+		xcom(l);
+		if(l->op == OADDR) {
+			l = l->left;
+			l->type = n->type;
+			*n = *l;
+			return;
+		}
+		switch(l->addable) {
+		case 20:
+			n->addable = 21;
+			break;
+		case 1:
+			n->addable = 11;
+			break;
+		case 13:
+			n->addable = 10;
+			break;
+		}
+		break;
+
+	case OASHL:
+		xcom(l);
+		xcom(r);
+		indexshift(n);
+		break;
+
+	case OMUL:
+	case OLMUL:
+		xcom(l);
+		xcom(r);
+		g = vlog(l);
+		if(g >= 0) {
+			n->left = r;
+			n->right = l;
+			l = r;
+			r = n->right;
+		}
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OASHL;
+			r->vconst = g;
+			r->type = types[TINT];
+			indexshift(n);
+			break;
+		}
+		commute(n);
+		break;
+
+	case OASLDIV:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OASLSHR;
+			r->vconst = g;
+			r->type = types[TINT];
+		}
+		break;
+
+	case OLDIV:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OLSHR;
+			r->vconst = g;
+			r->type = types[TINT];
+			indexshift(n);
+			break;
+		}
+		break;
+
+	case OASLMOD:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OASAND;
+			r->vconst--;
+		}
+		break;
+
+	case OLMOD:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OAND;
+			r->vconst--;
+		}
+		break;
+
+	case OASMUL:
+	case OASLMUL:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OASASHL;
+			r->vconst = g;
+		}
+		break;
+
+	case OLSHR:
+	case OASHR:
+		xcom(l);
+		xcom(r);
+		indexshift(n);
+		break;
+
+	default:
+		if(l != Z)
+			xcom(l);
+		if(r != Z)
+			xcom(r);
+		break;
+	}
+brk:
+	if(n->addable >= 10)
+		return;
+	if(l != Z)
+		n->complex = l->complex;
+	if(r != Z) {
+		if(r->complex == n->complex)
+			n->complex = r->complex+1;
+		else
+		if(r->complex > n->complex)
+			n->complex = r->complex;
+	}
+	if(n->complex == 0)
+		n->complex++;
+
+	switch(n->op) {
+
+	case OFUNC:
+		n->complex = FNX;
+		break;
+
+	case OCAST:
+		if(l->type->etype == TUVLONG && typefd[n->type->etype])
+			n->complex += 2;
+		break;
+
+	case OLMOD:
+	case OMOD:
+	case OLMUL:
+	case OLDIV:
+	case OMUL:
+	case ODIV:
+	case OASLMUL:
+	case OASLDIV:
+	case OASLMOD:
+	case OASMUL:
+	case OASDIV:
+	case OASMOD:
+		if(r->complex >= l->complex) {
+			n->complex = l->complex + 3;
+			if(r->complex > n->complex)
+				n->complex = r->complex;
+		} else {
+			n->complex = r->complex + 3;
+			if(l->complex > n->complex)
+				n->complex = l->complex;
+		}
+		break;
+
+	case OLSHR:
+	case OASHL:
+	case OASHR:
+	case OASLSHR:
+	case OASASHL:
+	case OASASHR:
+		if(r->complex >= l->complex) {
+			n->complex = l->complex + 2;
+			if(r->complex > n->complex)
+				n->complex = r->complex;
+		} else {
+			n->complex = r->complex + 2;
+			if(l->complex > n->complex)
+				n->complex = l->complex;
+		}
+		break;
+
+	case OADD:
+	case OXOR:
+	case OAND:
+	case OOR:
+		/*
+		 * immediate operators, make const on right
+		 */
+		if(l->op == OCONST) {
+			n->left = r;
+			n->right = l;
+		}
+		break;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OHI:
+	case OHS:
+	case OLO:
+	case OLS:
+		/*
+		 * compare operators, make const on left
+		 */
+		if(r->op == OCONST) {
+			n->left = r;
+			n->right = l;
+			n->op = invrel[relindex(n->op)];
+		}
+		break;
+	}
+}
+
+void
+indx(Node *n)
+{
+	Node *l, *r;
+
+	if(debug['x'])
+		prtree(n, "indx");
+
+	l = n->left;
+	r = n->right;
+	if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
+		n->right = l;
+		n->left = r;
+		l = r;
+		r = n->right;
+	}
+	if(l->addable != 7) {
+		idx.regtree = l;
+		idx.scale = 1;
+	} else
+	if(l->right->addable == 20) {
+		idx.regtree = l->left;
+		idx.scale = 1 << l->right->vconst;
+	} else
+	if(l->left->addable == 20) {
+		idx.regtree = l->right;
+		idx.scale = 1 << l->left->vconst;
+	} else
+		diag(n, "bad index");
+
+	idx.basetree = r;
+	if(debug['x']) {
+		print("scale = %d\n", idx.scale);
+		prtree(idx.regtree, "index");
+		prtree(idx.basetree, "base");
+	}
+}
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
new file mode 100644
index 0000000..5b2a6ca
--- /dev/null
+++ b/src/cmd/6c/swt.c
@@ -0,0 +1,566 @@
+// Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+void
+swit1(C1 *q, int nc, long def, Node *n)
+{
+	C1 *r;
+	int i;
+	Prog *sp;
+
+	if(nc < 5) {
+		for(i=0; i<nc; i++) {
+			if(debug['W'])
+				print("case = %.8llux\n", q->val);
+			gcmp(OEQ, n, q->val);
+			patch(p, q->label);
+			q++;
+		}
+		gbranch(OGOTO);
+		patch(p, def);
+		return;
+	}
+	i = nc / 2;
+	r = q+i;
+	if(debug['W'])
+		print("case > %.8llux\n", r->val);
+	gcmp(OGT, n, r->val);
+	sp = p;
+	gbranch(OGOTO);
+	p->as = AJEQ;
+	patch(p, r->label);
+	swit1(q, i, def, n);
+
+	if(debug['W'])
+		print("case < %.8llux\n", r->val);
+	patch(sp, pc);
+	swit1(r+1, nc-i-1, def, n);
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+	int sh;
+	long v;
+	Node *l;
+
+	/*
+	 * n1 gets adjusted/masked value
+	 * n2 gets address of cell
+	 * n3 gets contents of cell
+	 */
+	l = b->left;
+	if(n2 != Z) {
+		regalloc(n1, l, nn);
+		reglcgen(n2, l, Z);
+		regalloc(n3, l, Z);
+		gmove(n2, n3);
+		gmove(n3, n1);
+	} else {
+		regalloc(n1, l, nn);
+		cgen(l, n1);
+	}
+	if(b->type->shift == 0 && typeu[b->type->etype]) {
+		v = ~0 + (1L << b->type->nbits);
+		gopcode(OAND, tfield, nodconst(v), n1);
+	} else {
+		sh = 32 - b->type->shift - b->type->nbits;
+		if(sh > 0)
+			gopcode(OASHL, tfield, nodconst(sh), n1);
+		sh += b->type->shift;
+		if(sh > 0)
+			if(typeu[b->type->etype])
+				gopcode(OLSHR, tfield, nodconst(sh), n1);
+			else
+				gopcode(OASHR, tfield, nodconst(sh), n1);
+	}
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+	long v;
+	Node nod;
+	int sh;
+
+	regalloc(&nod, b->left, Z);
+	v = ~0 + (1L << b->type->nbits);
+	gopcode(OAND, types[TLONG], nodconst(v), n1);
+	gmove(n1, &nod);
+	if(nn != Z)
+		gmove(n1, nn);
+	sh = b->type->shift;
+	if(sh > 0)
+		gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
+	v <<= sh;
+	gopcode(OAND, types[TLONG], nodconst(~v), n3);
+	gopcode(OOR, types[TLONG], n3, &nod);
+	gmove(&nod, n2);
+
+	regfree(&nod);
+	regfree(n1);
+	regfree(n2);
+	regfree(n3);
+}
+
+long
+outstring(char *s, long n)
+{
+	long r;
+
+	if(suppress)
+		return nstring;
+	r = nstring;
+	while(n) {
+		string[mnstring] = *s++;
+		mnstring++;
+		nstring++;
+		if(mnstring >= NSNAME) {
+			gpseudo(ADATA, symstring, nodconst(0L));
+			p->from.offset += nstring - NSNAME;
+			p->from.scale = NSNAME;
+			p->to.type = D_SCONST;
+			memmove(p->to.sval, string, NSNAME);
+			mnstring = 0;
+		}
+		n--;
+	}
+	return r;
+}
+
+void
+sextern(Sym *s, Node *a, long o, long w)
+{
+	long e, lw;
+
+	for(e=0; e<w; e+=NSNAME) {
+		lw = NSNAME;
+		if(w-e < lw)
+			lw = w-e;
+		gpseudo(ADATA, s, nodconst(0L));
+		p->from.offset += o+e;
+		p->from.scale = lw;
+		p->to.type = D_SCONST;
+		memmove(p->to.sval, a->cstring+e, lw);
+	}
+}
+
+void
+gextern(Sym *s, Node *a, long o, long w)
+{
+	if(0 && a->op == OCONST && typev[a->type->etype]) {
+		gpseudo(ADATA, s, lo64(a));
+		p->from.offset += o;
+		p->from.scale = 4;
+		gpseudo(ADATA, s, hi64(a));
+		p->from.offset += o + 4;
+		p->from.scale = 4;
+		return;
+	}
+	gpseudo(ADATA, s, a);
+	p->from.offset += o;
+	p->from.scale = w;
+	switch(p->to.type) {
+	default:
+		p->to.index = p->to.type;
+		p->to.type = D_ADDR;
+	case D_CONST:
+	case D_FCONST:
+	case D_ADDR:
+		break;
+	}
+}
+
+void	zname(Biobuf*, Sym*, int);
+void	zaddr(Biobuf*, Adr*, int);
+void	outhist(Biobuf*);
+
+void
+outcode(void)
+{
+	struct { Sym *sym; short type; } h[NSYM];
+	Prog *p;
+	Sym *s;
+	int f, sf, st, t, sym;
+	Biobuf b;
+
+	if(debug['S']) {
+		for(p = firstp; p != P; p = p->link)
+			if(p->as != ADATA && p->as != AGLOBL)
+				pc--;
+		for(p = firstp; p != P; p = p->link) {
+			print("%P\n", p);
+			if(p->as != ADATA && p->as != AGLOBL)
+				pc++;
+		}
+	}
+
+	f = open(outfile, OWRITE);
+	if(f < 0) {
+		diag(Z, "cannot open %s", outfile);
+		return;
+	}
+	Binit(&b, f, OWRITE);
+
+	Bprint(&b, "x86-64\n");
+	Bprint(&b, "!\n");
+
+	outhist(&b);
+	for(sym=0; sym<NSYM; sym++) {
+		h[sym].sym = S;
+		h[sym].type = 0;
+	}
+	sym = 1;
+	for(p = firstp; p != P; p = p->link) {
+	jackpot:
+		sf = 0;
+		s = p->from.sym;
+		while(s != S) {
+			sf = s->sym;
+			if(sf < 0 || sf >= NSYM)
+				sf = 0;
+			t = p->from.type;
+			if(t == D_ADDR)
+				t = p->from.index;
+			if(h[sf].type == t)
+			if(h[sf].sym == s)
+				break;
+			s->sym = sym;
+			zname(&b, s, t);
+			h[sym].sym = s;
+			h[sym].type = t;
+			sf = sym;
+			sym++;
+			if(sym >= NSYM)
+				sym = 1;
+			break;
+		}
+		st = 0;
+		s = p->to.sym;
+		while(s != S) {
+			st = s->sym;
+			if(st < 0 || st >= NSYM)
+				st = 0;
+			t = p->to.type;
+			if(t == D_ADDR)
+				t = p->to.index;
+			if(h[st].type == t)
+			if(h[st].sym == s)
+				break;
+			s->sym = sym;
+			zname(&b, s, t);
+			h[sym].sym = s;
+			h[sym].type = t;
+			st = sym;
+			sym++;
+			if(sym >= NSYM)
+				sym = 1;
+			if(st == sf)
+				goto jackpot;
+			break;
+		}
+		Bputc(&b, p->as);
+		Bputc(&b, p->as>>8);
+		Bputc(&b, p->lineno);
+		Bputc(&b, p->lineno>>8);
+		Bputc(&b, p->lineno>>16);
+		Bputc(&b, p->lineno>>24);
+		zaddr(&b, &p->from, sf);
+		zaddr(&b, &p->to, st);
+	}
+	Bflush(&b);
+	close(f);
+	firstp = P;
+	lastp = P;
+}
+
+void
+outhist(Biobuf *b)
+{
+	Hist *h;
+	char *p, *q, *op, c;
+	Prog pg;
+	int n;
+
+	pg = zprog;
+	pg.as = AHISTORY;
+	c = pathchar();
+	for(h = hist; h != H; h = h->link) {
+		p = h->name;
+		op = 0;
+		/* on windows skip drive specifier in pathname */
+		if(systemtype(Windows) && p && p[1] == ':'){
+			p += 2;
+			c = *p;
+		}
+		if(p && p[0] != c && h->offset == 0 && pathname){
+			/* on windows skip drive specifier in pathname */
+			if(systemtype(Windows) && pathname[1] == ':') {
+				op = p;
+				p = pathname+2;
+				c = *p;
+			} else if(pathname[0] == c){
+				op = p;
+				p = pathname;
+			}
+		}
+		while(p) {
+			q = utfrune(p, c);
+			if(q) {
+				n = q-p;
+				if(n == 0){
+					n = 1;	/* leading "/" */
+					*p = '/';	/* don't emit "\" on windows */
+				}
+				q++;
+			} else {
+				n = strlen(p);
+				q = 0;
+			}
+			if(n) {
+				Bputc(b, ANAME);
+				Bputc(b, ANAME>>8);
+				Bputc(b, D_FILE);
+				Bputc(b, 1);
+				Bputc(b, '<');
+				Bwrite(b, p, n);
+				Bputc(b, 0);
+			}
+			p = q;
+			if(p == 0 && op) {
+				p = op;
+				op = 0;
+			}
+		}
+		pg.lineno = h->line;
+		pg.to.type = zprog.to.type;
+		pg.to.offset = h->offset;
+		if(h->offset)
+			pg.to.type = D_CONST;
+
+		Bputc(b, pg.as);
+		Bputc(b, pg.as>>8);
+		Bputc(b, pg.lineno);
+		Bputc(b, pg.lineno>>8);
+		Bputc(b, pg.lineno>>16);
+		Bputc(b, pg.lineno>>24);
+		zaddr(b, &pg.from, 0);
+		zaddr(b, &pg.to, 0);
+	}
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+	char *n;
+	ulong sig;
+
+	if(debug['T'] && t == D_EXTERN && s->sig != SIGDONE && s->type != types[TENUM] && s != symrathole){
+		sig = sign(s);
+		Bputc(b, ASIGNAME);
+		Bputc(b, ASIGNAME>>8);
+		Bputc(b, sig);
+		Bputc(b, sig>>8);
+		Bputc(b, sig>>16);
+		Bputc(b, sig>>24);
+		s->sig = SIGDONE;
+	}
+	else{
+		Bputc(b, ANAME);	/* as */
+		Bputc(b, ANAME>>8);	/* as */
+	}
+	Bputc(b, t);			/* type */
+	Bputc(b, s->sym);		/* sym */
+	n = s->name;
+	while(*n) {
+		Bputc(b, *n);
+		n++;
+	}
+	Bputc(b, 0);
+}
+
+void
+zaddr(Biobuf *b, Adr *a, int s)
+{
+	long l;
+	int i, t;
+	char *n;
+	Ieee e;
+
+	t = 0;
+	if(a->index != D_NONE || a->scale != 0)
+		t |= T_INDEX;
+	if(s != 0)
+		t |= T_SYM;
+
+	switch(a->type) {
+	default:
+		t |= T_TYPE;
+	case D_NONE:
+		if(a->offset != 0) {
+			t |= T_OFFSET;
+			l = a->offset;
+			if((vlong)l != a->offset)
+				t |= T_64;
+		}
+		break;
+	case D_FCONST:
+		t |= T_FCONST;
+		break;
+	case D_SCONST:
+		t |= T_SCONST;
+		break;
+	}
+	Bputc(b, t);
+
+	if(t & T_INDEX) {	/* implies index, scale */
+		Bputc(b, a->index);
+		Bputc(b, a->scale);
+	}
+	if(t & T_OFFSET) {	/* implies offset */
+		l = a->offset;
+		Bputc(b, l);
+		Bputc(b, l>>8);
+		Bputc(b, l>>16);
+		Bputc(b, l>>24);
+		if(t & T_64) {
+			l = a->offset>>32;
+			Bputc(b, l);
+			Bputc(b, l>>8);
+			Bputc(b, l>>16);
+			Bputc(b, l>>24);
+		}
+	}
+	if(t & T_SYM)		/* implies sym */
+		Bputc(b, s);
+	if(t & T_FCONST) {
+		ieeedtod(&e, a->dval);
+		l = e.l;
+		Bputc(b, l);
+		Bputc(b, l>>8);
+		Bputc(b, l>>16);
+		Bputc(b, l>>24);
+		l = e.h;
+		Bputc(b, l);
+		Bputc(b, l>>8);
+		Bputc(b, l>>16);
+		Bputc(b, l>>24);
+		return;
+	}
+	if(t & T_SCONST) {
+		n = a->sval;
+		for(i=0; i<NSNAME; i++) {
+			Bputc(b, *n);
+			n++;
+		}
+		return;
+	}
+	if(t & T_TYPE)
+		Bputc(b, a->type);
+}
+
+long
+align(long i, Type *t, int op)
+{
+	long o;
+	Type *v;
+	int w;
+
+	o = i;
+	w = 1;
+	switch(op) {
+	default:
+		diag(Z, "unknown align opcode %d", op);
+		break;
+
+	case Asu2:	/* padding at end of a struct */
+		w = SZ_VLONG;
+		if(packflg)
+			w = packflg;
+		break;
+
+	case Ael1:	/* initial align of struct element */
+		for(v=t; v->etype==TARRAY; v=v->link)
+			;
+		w = ewidth[v->etype];
+		if(w <= 0 || w >= SZ_VLONG)
+			w = SZ_VLONG;
+		if(packflg)
+			w = packflg;
+		break;
+
+	case Ael2:	/* width of a struct element */
+		o += t->width;
+		break;
+
+	case Aarg0:	/* initial passbyptr argument in arg list */
+		if(typesu[t->etype]) {
+			o = align(o, types[TIND], Aarg1);
+			o = align(o, types[TIND], Aarg2);
+		}
+		break;
+
+	case Aarg1:	/* initial align of parameter */
+		w = ewidth[t->etype];
+		if(w <= 0 || w >= SZ_VLONG) {
+			w = SZ_VLONG;
+			break;
+		}
+		w = 1;		/* little endian no adjustment */
+		break;
+
+	case Aarg2:	/* width of a parameter */
+		o += t->width;
+		w = t->width;
+		if(w > SZ_VLONG)
+			w = SZ_VLONG;
+		break;
+
+	case Aaut3:	/* total allign of automatic */
+		o = align(o, t, Ael1);
+		o = align(o, t, Ael2);
+		break;
+	}
+	o = xround(o, w);
+	if(debug['A'])
+		print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+	return o;
+}
+
+long
+maxround(long max, long v)
+{
+	v += SZ_VLONG-1;
+	if(v > max)
+		max = xround(v, SZ_VLONG);
+	return max;
+}
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
new file mode 100644
index 0000000..eb560f5
--- /dev/null
+++ b/src/cmd/6c/txt.c
@@ -0,0 +1,1546 @@
+// Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+void
+ginit(void)
+{
+	int i;
+	Type *t;
+
+	thechar = '6';
+	thestring = "amd64";
+	exregoffset = REGEXT;
+	exfregoffset = FREGEXT;
+	listinit();
+	nstring = 0;
+	mnstring = 0;
+	nrathole = 0;
+	pc = 0;
+	breakpc = -1;
+	continpc = -1;
+	cases = C;
+	firstp = P;
+	lastp = P;
+	tfield = types[TINT];
+
+	typeword = typechlvp;
+	typecmplx = typesu;
+
+	/* TO DO */
+	memmove(typechlpv, typechlp, sizeof(typechlpv));
+	typechlpv[TVLONG] = 1;
+	typechlpv[TUVLONG] = 1;
+
+	zprog.link = P;
+	zprog.as = AGOK;
+	zprog.from.type = D_NONE;
+	zprog.from.index = D_NONE;
+	zprog.from.scale = 0;
+	zprog.to = zprog.from;
+
+	lregnode.op = OREGISTER;
+	lregnode.class = CEXREG;
+	lregnode.reg = REGTMP;
+	lregnode.complex = 0;
+	lregnode.addable = 11;
+	lregnode.type = types[TLONG];
+
+	qregnode = lregnode;
+	qregnode.type = types[TVLONG];
+
+	constnode.op = OCONST;
+	constnode.class = CXXX;
+	constnode.complex = 0;
+	constnode.addable = 20;
+	constnode.type = types[TLONG];
+
+	vconstnode = constnode;
+	vconstnode.type = types[TVLONG];
+
+	fconstnode.op = OCONST;
+	fconstnode.class = CXXX;
+	fconstnode.complex = 0;
+	fconstnode.addable = 20;
+	fconstnode.type = types[TDOUBLE];
+
+	nodsafe = new(ONAME, Z, Z);
+	nodsafe->sym = slookup(".safe");
+	nodsafe->type = types[TINT];
+	nodsafe->etype = types[TINT]->etype;
+	nodsafe->class = CAUTO;
+	complex(nodsafe);
+
+	t = typ(TARRAY, types[TCHAR]);
+	symrathole = slookup(".rathole");
+	symrathole->class = CGLOBL;
+	symrathole->type = t;
+
+	nodrat = new(ONAME, Z, Z);
+	nodrat->sym = symrathole;
+	nodrat->type = types[TIND];
+	nodrat->etype = TVOID;
+	nodrat->class = CGLOBL;
+	complex(nodrat);
+	nodrat->type = t;
+
+	nodret = new(ONAME, Z, Z);
+	nodret->sym = slookup(".ret");
+	nodret->type = types[TIND];
+	nodret->etype = TIND;
+	nodret->class = CPARAM;
+	nodret = new(OIND, nodret, Z);
+	complex(nodret);
+
+	if(0)
+		com64init();
+
+	for(i=0; i<nelem(reg); i++) {
+		reg[i] = 1;
+		if(i >= D_AX && i <= D_R15 && i != D_SP)
+			reg[i] = 0;
+		if(i >= D_X0 && i <= D_X7)
+			reg[i] = 0;
+	}
+}
+
+void
+gclean(void)
+{
+	int i;
+	Sym *s;
+
+	reg[D_SP]--;
+	for(i=D_AX; i<=D_R15; i++)
+		if(reg[i])
+			diag(Z, "reg %R left allocated", i);
+	for(i=D_X0; i<=D_X7; i++)
+		if(reg[i])
+			diag(Z, "reg %R left allocated", i);
+	while(mnstring)
+		outstring("", 1L);
+	symstring->type->width = nstring;
+	symrathole->type->width = nrathole;
+	for(i=0; i<NHASH; i++)
+	for(s = hash[i]; s != S; s = s->link) {
+		if(s->type == T)
+			continue;
+		if(s->type->width == 0)
+			continue;
+		if(s->class != CGLOBL && s->class != CSTATIC)
+			continue;
+		if(s->type == types[TENUM])
+			continue;
+		gpseudo(AGLOBL, s, nodconst(s->type->width));
+	}
+	nextpc();
+	p->as = AEND;
+	outcode();
+}
+
+void
+nextpc(void)
+{
+
+	p = alloc(sizeof(*p));
+	*p = zprog;
+	p->lineno = nearln;
+	pc++;
+	if(firstp == P) {
+		firstp = p;
+		lastp = p;
+		return;
+	}
+	lastp->link = p;
+	lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+	long regs;
+	Node fnxargs[20], *fnxp;
+
+	regs = cursafe;
+
+	fnxp = fnxargs;
+	garg1(n, tn1, tn2, 0, &fnxp);	/* compile fns to temps */
+
+	curarg = 0;
+	fnxp = fnxargs;
+	garg1(n, tn1, tn2, 1, &fnxp);	/* compile normal args and temps */
+
+	cursafe = regs;
+}
+
+int
+nareg(void)
+{
+	int i, n;
+
+	n = 0;
+	for(i=D_AX; i<=D_R15; i++)
+		if(reg[i] == 0)
+			n++;
+	return n;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+	Node nod;
+
+	if(n == Z)
+		return;
+	if(n->op == OLIST) {
+		garg1(n->left, tn1, tn2, f, fnxp);
+		garg1(n->right, tn1, tn2, f, fnxp);
+		return;
+	}
+	if(f == 0) {
+		if(n->complex >= FNX) {
+			regsalloc(*fnxp, n);
+			nod = znode;
+			nod.op = OAS;
+			nod.left = *fnxp;
+			nod.right = n;
+			nod.type = n->type;
+			cgen(&nod, Z);
+			(*fnxp)++;
+		}
+		return;
+	}
+	if(typesu[n->type->etype]) {
+		regaalloc(tn2, n);
+		if(n->complex >= FNX) {
+			sugen(*fnxp, tn2, n->type->width);
+			(*fnxp)++;
+		} else
+			sugen(n, tn2, n->type->width);
+		return;
+	}
+	if(REGARG && curarg == 0 && typechlpv[n->type->etype]) {
+		regaalloc1(tn1, n);
+		if(n->complex >= FNX) {
+			cgen(*fnxp, tn1);
+			(*fnxp)++;
+		} else
+			cgen(n, tn1);
+		return;
+	}
+	if(vconst(n) == 0) {
+		regaalloc(tn2, n);
+		gmove(n, tn2);
+		return;
+	}
+	regalloc(tn1, n, Z);
+	if(n->complex >= FNX) {
+		cgen(*fnxp, tn1);
+		(*fnxp)++;
+	} else
+		cgen(n, tn1);
+	regaalloc(tn2, n);
+	gmove(tn1, tn2);
+	regfree(tn1);
+}
+
+Node*
+nodgconst(vlong v, Type *t)
+{
+	if(!typev[t->etype])
+		return nodconst((long)v);
+	vconstnode.vconst = v;
+	return &vconstnode;
+}
+
+Node*
+nodconst(long v)
+{
+	constnode.vconst = v;
+	return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+	fconstnode.fconst = d;
+	return &fconstnode;
+}
+
+int
+isreg(Node *n, int r)
+{
+
+	if(n->op == OREGISTER)
+		if(n->reg == r)
+			return 1;
+	return 0;
+}
+
+int
+nodreg(Node *n, Node *nn, int r)
+{
+	int et;
+
+	*n = qregnode;
+	n->reg = r;
+	if(nn != Z){
+		et = nn->type->etype;
+		if(!typefd[et] && nn->type->width <= SZ_LONG && 0)
+			n->type = typeu[et]? types[TUINT]: types[TINT];
+		else
+			n->type = nn->type;
+//print("nodreg %s [%s]\n", tnames[et], tnames[n->type->etype]);
+		n->lineno = nn->lineno;
+	}
+	if(reg[r] == 0)
+		return 0;
+	if(nn != Z) {
+		if(nn->op == OREGISTER)
+		if(nn->reg == r)
+			return 0;
+	}
+	return 1;
+}
+
+void
+regret(Node *n, Node *nn)
+{
+	int r;
+
+	r = REGRET;
+	if(typefd[nn->type->etype])
+		r = FREGRET;
+	nodreg(n, nn, r);
+	reg[r]++;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+	int i;
+
+	switch(tn->type->etype) {
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+	case TVLONG:
+	case TUVLONG:
+	case TIND:
+		if(o != Z && o->op == OREGISTER) {
+			i = o->reg;
+			if(i >= D_AX && i <= D_R15)
+				goto out;
+		}
+		for(i=D_AX; i<=D_R15; i++)
+			if(reg[i] == 0)
+				goto out;
+		diag(tn, "out of fixed registers");
+		goto err;
+
+	case TFLOAT:
+	case TDOUBLE:
+		if(o != Z && o->op == OREGISTER) {
+			i = o->reg;
+			if(i >= D_X0 && i <= D_X7)
+				goto out;
+		}
+		for(i=D_X0; i<=D_X7; i++)
+			if(reg[i] == 0)
+				goto out;
+		diag(tn, "out of float registers");
+		goto out;
+	}
+	diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+	i = 0;
+out:
+	if(i)
+		reg[i]++;
+	nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+	Node nod;
+
+	nod = *tn;
+	nod.type = types[TIND];
+	regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+	int i;
+
+	i = 0;
+	if(n->op != OREGISTER && n->op != OINDREG)
+		goto err;
+	i = n->reg;
+	if(i < 0 || i >= sizeof(reg))
+		goto err;
+	if(reg[i] <= 0)
+		goto err;
+	reg[i]--;
+	return;
+err:
+	diag(n, "error in regfree: %R", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+	cursafe = align(cursafe, nn->type, Aaut3);
+	maxargsafe = maxround(maxargsafe, cursafe+curarg);
+	*n = *nodsafe;
+	n->xoffset = -(stkoff + cursafe);
+	n->type = nn->type;
+	n->etype = nn->type->etype;
+	n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+	if(REGARG == 0)
+		diag(n, "regaalloc1 and REGARG==0");
+	nodreg(n, nn, REGARG);
+	reg[REGARG]++;
+	curarg = align(curarg, nn->type, Aarg1);
+	curarg = align(curarg, nn->type, Aarg2);
+	maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+	curarg = align(curarg, nn->type, Aarg1);
+	*n = *nn;
+	n->op = OINDREG;
+	n->reg = REGSP;
+	n->xoffset = curarg;
+	n->complex = 0;
+	n->addable = 20;
+	curarg = align(curarg, nn->type, Aarg2);
+	maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+	if(n->op != OREGISTER) {
+		diag(n, "regind not OREGISTER");
+		return;
+	}
+	n->op = OINDREG;
+	n->type = nn->type;
+}
+
+void
+naddr(Node *n, Adr *a)
+{
+	long v;
+
+	a->type = D_NONE;
+	if(n == Z)
+		return;
+	switch(n->op) {
+	default:
+	bad:
+		diag(n, "bad in naddr: %O %D", n->op, a);
+		break;
+
+	case OREGISTER:
+		a->type = n->reg;
+		a->sym = S;
+		break;
+
+
+	case OIND:
+		naddr(n->left, a);
+		if(a->type >= D_AX && a->type <= D_R15)
+			a->type += D_INDIR;
+		else
+		if(a->type == D_CONST)
+			a->type = D_NONE+D_INDIR;
+		else
+		if(a->type == D_ADDR) {
+			a->type = a->index;
+			a->index = D_NONE;
+		} else
+			goto bad;
+		break;
+
+	case OINDEX:
+		a->type = idx.ptr;
+		if(n->left->op == OADDR || n->left->op == OCONST)
+			naddr(n->left, a);
+		if(a->type >= D_AX && a->type <= D_R15)
+			a->type += D_INDIR;
+		else
+		if(a->type == D_CONST)
+			a->type = D_NONE+D_INDIR;
+		else
+		if(a->type == D_ADDR) {
+			a->type = a->index;
+			a->index = D_NONE;
+		} else
+			goto bad;
+		a->index = idx.reg;
+		a->scale = n->scale;
+		a->offset += n->xoffset;
+		break;
+
+	case OINDREG:
+		a->type = n->reg+D_INDIR;
+		a->sym = S;
+		a->offset = n->xoffset;
+		break;
+
+	case ONAME:
+		a->etype = n->etype;
+		a->type = D_STATIC;
+		a->sym = n->sym;
+		a->offset = n->xoffset;
+		if(n->class == CSTATIC)
+			break;
+		if(n->class == CEXTERN || n->class == CGLOBL) {
+			a->type = D_EXTERN;
+			break;
+		}
+		if(n->class == CAUTO) {
+			a->type = D_AUTO;
+			break;
+		}
+		if(n->class == CPARAM) {
+			a->type = D_PARAM;
+			break;
+		}
+		goto bad;
+
+	case OCONST:
+		if(typefd[n->type->etype]) {
+			a->type = D_FCONST;
+			a->dval = n->fconst;
+			break;
+		}
+		a->sym = S;
+		a->type = D_CONST;
+		if(typev[n->type->etype] || n->type->etype == TIND)
+			a->offset = n->vconst;
+		else
+			a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG);
+		break;
+
+	case OADDR:
+		naddr(n->left, a);
+		if(a->type >= D_INDIR) {
+			a->type -= D_INDIR;
+			break;
+		}
+		if(a->type == D_EXTERN || a->type == D_STATIC ||
+		   a->type == D_AUTO || a->type == D_PARAM)
+			if(a->index == D_NONE) {
+				a->index = a->type;
+				a->type = D_ADDR;
+				break;
+			}
+		goto bad;
+
+	case OADD:
+		if(n->right->op == OCONST) {
+			v = n->right->vconst;
+			naddr(n->left, a);
+		} else
+		if(n->left->op == OCONST) {
+			v = n->left->vconst;
+			naddr(n->right, a);
+		} else
+			goto bad;
+		a->offset += v;
+		break;
+
+	}
+}
+
+void
+gcmp(int op, Node *n, vlong val)
+{
+	Node *cn, nod;
+
+	cn = nodgconst(val, n->type);
+	if(!immconst(cn)){
+		regalloc(&nod, n, Z);
+		gmove(cn, &nod);
+		gopcode(op, n->type, n, &nod);
+		regfree(&nod);
+	}else
+		gopcode(op, n->type, n, cn);
+}
+
+#define	CASE(a,b)	((a<<8)|(b<<0))
+
+void
+gmove(Node *f, Node *t)
+{
+	int ft, tt, t64, a;
+	Node nod, nod1, nod2, nod3;
+	Prog *p1, *p2;
+
+	ft = f->type->etype;
+	tt = t->type->etype;
+	t64 = tt == TVLONG || tt == TUVLONG || tt == TIND;
+	if(debug['M'])
+		print("gop: %O %O[%s],%O[%s]\n", OAS,
+			f->op, tnames[ft], t->op, tnames[tt]);
+	if(typefd[ft] && f->op == OCONST) {
+		/* TO DO: pick up special constants, possibly preloaded */
+		if(f->fconst == 0.0){
+			regalloc(&nod, t, t);
+			gins(AXORPD, &nod, &nod);
+			gmove(&nod, t);
+			regfree(&nod);
+			return;
+		}
+	}
+/*
+ * load
+ */
+	if(f->op == ONAME || f->op == OINDREG ||
+	   f->op == OIND || f->op == OINDEX)
+	switch(ft) {
+	case TCHAR:
+		a = AMOVBLSX;
+		if(t64)
+			a = AMOVBQSX;
+		goto ld;
+	case TUCHAR:
+		a = AMOVBLZX;
+		if(t64)
+			a = AMOVBQZX;
+		goto ld;
+	case TSHORT:
+		a = AMOVWLSX;
+		if(t64)
+			a = AMOVWQSX;
+		goto ld;
+	case TUSHORT:
+		a = AMOVWLZX;
+		if(t64)
+			a = AMOVWQZX;
+		goto ld;
+	case TINT:
+	case TLONG:
+		if(typefd[tt]) {
+			regalloc(&nod, t, t);
+			if(tt == TDOUBLE)
+				a = ACVTSL2SD;
+			else
+				a = ACVTSL2SS;
+			gins(a, f, &nod);
+			gmove(&nod, t);
+			regfree(&nod);
+			return;
+		}
+		a = AMOVL;
+		if(t64)
+			a = AMOVLQSX;
+		goto ld;
+	case TUINT:
+	case TULONG:
+		a = AMOVL;
+		if(t64)
+			a = AMOVLQZX;	/* could probably use plain MOVL */
+		goto ld;
+	case TVLONG:
+		if(typefd[tt]) {
+			regalloc(&nod, t, t);
+			if(tt == TDOUBLE)
+				a = ACVTSQ2SD;
+			else
+				a = ACVTSQ2SS;
+			gins(a, f, &nod);
+			gmove(&nod, t);
+			regfree(&nod);
+			return;
+		}
+	case TUVLONG:
+		a = AMOVQ;
+		goto ld;
+	case TIND:
+		a = AMOVQ;
+
+	ld:
+		regalloc(&nod, f, t);
+		nod.type = t64? types[TVLONG]: types[TINT];
+		gins(a, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+	case TFLOAT:
+		a = AMOVSS;
+		goto fld;
+	case TDOUBLE:
+		a = AMOVSD;
+	fld:
+		regalloc(&nod, f, t);
+		if(tt != TDOUBLE && tt != TFLOAT){	/* TO DO: why is this here */
+			prtree(f, "odd tree");
+			nod.type = t64? types[TVLONG]: types[TINT];
+		}
+		gins(a, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+	}
+
+/*
+ * store
+ */
+	if(t->op == ONAME || t->op == OINDREG ||
+	   t->op == OIND || t->op == OINDEX)
+	switch(tt) {
+	case TCHAR:
+	case TUCHAR:
+		a = AMOVB;	goto st;
+	case TSHORT:
+	case TUSHORT:
+		a = AMOVW;	goto st;
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+		a = AMOVL;	goto st;
+	case TVLONG:
+	case TUVLONG:
+	case TIND:
+		a = AMOVQ;	goto st;
+
+	st:
+		if(f->op == OCONST) {
+			gins(a, f, t);
+			return;
+		}
+	fst:
+		regalloc(&nod, t, f);
+		gmove(f, &nod);
+		gins(a, &nod, t);
+		regfree(&nod);
+		return;
+
+	case TFLOAT:
+		a = AMOVSS;
+		goto fst;
+	case TDOUBLE:
+		a = AMOVSD;
+		goto fst;
+	}
+
+/*
+ * convert
+ */
+	switch(CASE(ft,tt)) {
+	default:
+/*
+ * integer to integer
+ ********
+		a = AGOK;	break;
+
+	case CASE(	TCHAR,	TCHAR):
+	case CASE(	TUCHAR,	TCHAR):
+	case CASE(	TSHORT,	TCHAR):
+	case CASE(	TUSHORT,TCHAR):
+	case CASE(	TINT,	TCHAR):
+	case CASE(	TUINT,	TCHAR):
+	case CASE(	TLONG,	TCHAR):
+	case CASE(	TULONG,	TCHAR):
+	case CASE(	TIND,	TCHAR):
+
+	case CASE(	TCHAR,	TUCHAR):
+	case CASE(	TUCHAR,	TUCHAR):
+	case CASE(	TSHORT,	TUCHAR):
+	case CASE(	TUSHORT,TUCHAR):
+	case CASE(	TINT,	TUCHAR):
+	case CASE(	TUINT,	TUCHAR):
+	case CASE(	TLONG,	TUCHAR):
+	case CASE(	TULONG,	TUCHAR):
+	case CASE(	TIND,	TUCHAR):
+
+	case CASE(	TSHORT,	TSHORT):
+	case CASE(	TUSHORT,TSHORT):
+	case CASE(	TINT,	TSHORT):
+	case CASE(	TUINT,	TSHORT):
+	case CASE(	TLONG,	TSHORT):
+	case CASE(	TULONG,	TSHORT):
+	case CASE(	TIND,	TSHORT):
+
+	case CASE(	TSHORT,	TUSHORT):
+	case CASE(	TUSHORT,TUSHORT):
+	case CASE(	TINT,	TUSHORT):
+	case CASE(	TUINT,	TUSHORT):
+	case CASE(	TLONG,	TUSHORT):
+	case CASE(	TULONG,	TUSHORT):
+	case CASE(	TIND,	TUSHORT):
+
+	case CASE(	TINT,	TINT):
+	case CASE(	TUINT,	TINT):
+	case CASE(	TLONG,	TINT):
+	case CASE(	TULONG,	TINT):
+	case CASE(	TIND,	TINT):
+
+	case CASE(	TINT,	TUINT):
+	case CASE(	TUINT,	TUINT):
+	case CASE(	TLONG,	TUINT):
+	case CASE(	TULONG,	TUINT):
+	case CASE(	TIND,	TUINT):
+
+	case CASE(	TUINT,	TIND):
+	case CASE(	TVLONG,	TUINT):
+	case CASE(	TVLONG,	TULONG):
+	case CASE(	TUVLONG, TUINT):
+	case CASE(	TUVLONG, TULONG):
+ *****/
+		a = AMOVL;
+		break;
+
+	case CASE(	TVLONG,	TCHAR):
+	case	CASE(	TVLONG,	TSHORT):
+	case CASE(	TVLONG,	TINT):
+	case CASE(	TVLONG,	TLONG):
+	case CASE(	TUVLONG, TCHAR):
+	case	CASE(	TUVLONG, TSHORT):
+	case CASE(	TUVLONG, TINT):
+	case CASE(	TUVLONG, TLONG):
+	case CASE(	TINT,	TVLONG):
+	case CASE(	TINT,	TUVLONG):
+	case CASE(	TLONG,	TVLONG):
+	case CASE(	TINT,	TIND):
+	case CASE(	TLONG,	TIND):
+		a = AMOVLQSX;
+		if(f->op == OCONST) {
+			f->vconst &= (uvlong)0xffffffffU;
+			if(f->vconst & 0x80000000)
+				f->vconst |= (vlong)0xffffffff << 32;
+			a = AMOVQ;
+		}
+		break;
+
+	case CASE(	TUINT,	TIND):
+	case CASE(	TUINT,	TVLONG):
+	case CASE(	TUINT,	TUVLONG):
+	case CASE(	TULONG,	TVLONG):
+	case CASE(	TULONG,	TUVLONG):
+	case CASE(	TULONG,	TIND):
+		a = AMOVL;	/* same effect as AMOVLQZX */
+		if(f->op == OCONST) {
+			f->vconst &= (uvlong)0xffffffffU;
+			a = AMOVQ;
+		}
+		break;
+
+	case CASE(	TIND,	TVLONG):
+	case CASE(	TVLONG,	TVLONG):
+	case CASE(	TUVLONG,	TVLONG):
+	case CASE(	TVLONG,	TUVLONG):
+	case CASE(	TUVLONG,	TUVLONG):
+	case CASE(	TIND,	TUVLONG):
+	case CASE(	TVLONG,	TIND):
+	case CASE(	TUVLONG,	TIND):
+	case CASE(	TIND,	TIND):
+		a = AMOVQ;
+		break;
+
+	case CASE(	TSHORT,	TINT):
+	case CASE(	TSHORT,	TUINT):
+	case CASE(	TSHORT,	TLONG):
+	case CASE(	TSHORT,	TULONG):
+		a = AMOVWLSX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xffff;
+			if(f->vconst & 0x8000)
+				f->vconst |= 0xffff0000;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(	TSHORT,	TVLONG):
+	case CASE(	TSHORT,	TUVLONG):
+	case CASE(	TSHORT,	TIND):
+		a = AMOVWQSX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xffff;
+			if(f->vconst & 0x8000){
+				f->vconst |= 0xffff0000;
+				f->vconst |= (vlong)~0 << 32;
+			}
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(	TUSHORT,TINT):
+	case CASE(	TUSHORT,TUINT):
+	case CASE(	TUSHORT,TLONG):
+	case CASE(	TUSHORT,TULONG):
+		a = AMOVWLZX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xffff;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(	TUSHORT,TVLONG):
+	case CASE(	TUSHORT,TUVLONG):
+	case CASE(	TUSHORT,TIND):
+		a = AMOVWQZX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xffff;
+			a = AMOVL;	/* MOVL also zero-extends to 64 bits */
+		}
+		break;
+
+	case CASE(	TCHAR,	TSHORT):
+	case CASE(	TCHAR,	TUSHORT):
+	case CASE(	TCHAR,	TINT):
+	case CASE(	TCHAR,	TUINT):
+	case CASE(	TCHAR,	TLONG):
+	case CASE(	TCHAR,	TULONG):
+		a = AMOVBLSX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xff;
+			if(f->vconst & 0x80)
+				f->vconst |= 0xffffff00;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(	TCHAR,	TVLONG):
+	case CASE(	TCHAR,	TUVLONG):
+	case CASE(	TCHAR,	TIND):
+		a = AMOVBQSX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xff;
+			if(f->vconst & 0x80){
+				f->vconst |= 0xffffff00;
+				f->vconst |= (vlong)~0 << 32;
+			}
+			a = AMOVQ;
+		}
+		break;
+
+	case CASE(	TUCHAR,	TSHORT):
+	case CASE(	TUCHAR,	TUSHORT):
+	case CASE(	TUCHAR,	TINT):
+	case CASE(	TUCHAR,	TUINT):
+	case CASE(	TUCHAR,	TLONG):
+	case CASE(	TUCHAR,	TULONG):
+		a = AMOVBLZX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xff;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(	TUCHAR,	TVLONG):
+	case CASE(	TUCHAR,	TUVLONG):
+	case CASE(	TUCHAR,	TIND):
+		a = AMOVBQZX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xff;
+			a = AMOVL;	/* zero-extends to 64-bits */
+		}
+		break;
+
+/*
+ * float to fix
+ */
+	case CASE(	TFLOAT,	TCHAR):
+	case CASE(	TFLOAT,	TUCHAR):
+	case CASE(	TFLOAT,	TSHORT):
+	case CASE(	TFLOAT,	TUSHORT):
+	case CASE(	TFLOAT,	TINT):
+	case CASE(	TFLOAT,	TUINT):
+	case CASE(	TFLOAT,	TLONG):
+	case CASE(	TFLOAT,	TULONG):
+	case CASE(	TFLOAT,	TVLONG):
+	case CASE(	TFLOAT,	TUVLONG):
+	case CASE(	TFLOAT,	TIND):
+
+	case CASE(	TDOUBLE,TCHAR):
+	case CASE(	TDOUBLE,TUCHAR):
+	case CASE(	TDOUBLE,TSHORT):
+	case CASE(	TDOUBLE,TUSHORT):
+	case CASE(	TDOUBLE,TINT):
+	case CASE(	TDOUBLE,TUINT):
+	case CASE(	TDOUBLE,TLONG):
+	case CASE(	TDOUBLE,TULONG):
+	case CASE(	TDOUBLE,TVLONG):
+	case CASE(	TDOUBLE,TUVLONG):
+	case CASE(	TDOUBLE,TIND):
+		regalloc(&nod, t, Z);
+		if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){
+			if(ft == TFLOAT)
+				a = ACVTTSS2SQ;
+			else
+				a = ACVTTSD2SQ;
+		}else{
+			if(ft == TFLOAT)
+				a = ACVTTSS2SL;
+			else
+				a = ACVTTSD2SL;
+		}
+		gins(a, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+/*
+ * ulong to float
+ */
+	case CASE(	TUVLONG,	TDOUBLE):
+	case CASE(	TUVLONG,	TFLOAT):
+		a = ACVTSQ2SS;
+		if(tt == TDOUBLE)
+			a = ACVTSQ2SD;
+		regalloc(&nod, f, f);
+		gmove(f, &nod);
+		regalloc(&nod1, t, t);
+		gins(ACMPQ, &nod, nodconst(0));
+		gins(AJLT, Z, Z);
+		p1 = p;
+		gins(a, &nod, &nod1);
+		gins(AJMP, Z, Z);
+		p2 = p;
+		patch(p1, pc);
+		regalloc(&nod2, f, Z);
+		regalloc(&nod3, f, Z);
+		gmove(&nod, &nod2);
+		gins(ASHRQ, nodconst(1), &nod2);
+		gmove(&nod, &nod3);
+		gins(AANDL, nodconst(1), &nod3);
+		gins(AORQ, &nod3, &nod2);
+		gins(a, &nod2, &nod1);
+		gins(tt == TDOUBLE? AADDSD: AADDSS, &nod1, &nod1);
+		regfree(&nod2);
+		regfree(&nod3);
+		patch(p2, pc);
+		regfree(&nod);
+		regfree(&nod1);
+		return;
+
+	case CASE(	TULONG,	TDOUBLE):
+	case CASE(	TUINT,	TDOUBLE):
+	case CASE(	TULONG,	TFLOAT):
+	case CASE(	TUINT,	TFLOAT):
+		a = ACVTSQ2SS;
+		if(tt == TDOUBLE)
+			a = ACVTSQ2SD;
+		regalloc(&nod, f, f);
+		gins(AMOVLQZX, f, &nod);
+		regalloc(&nod1, t, t);
+		gins(a, &nod, &nod1);
+		gmove(&nod1, t);
+		regfree(&nod);
+		regfree(&nod1);
+		return;
+
+/*
+ * fix to float
+ */
+	case CASE(	TCHAR,	TFLOAT):
+	case CASE(	TUCHAR,	TFLOAT):
+	case CASE(	TSHORT,	TFLOAT):
+	case CASE(	TUSHORT,TFLOAT):
+	case CASE(	TINT,	TFLOAT):
+	case CASE(	TLONG,	TFLOAT):
+	case	CASE(	TVLONG,	TFLOAT):
+	case CASE(	TIND,	TFLOAT):
+
+	case CASE(	TCHAR,	TDOUBLE):
+	case CASE(	TUCHAR,	TDOUBLE):
+	case CASE(	TSHORT,	TDOUBLE):
+	case CASE(	TUSHORT,TDOUBLE):
+	case CASE(	TINT,	TDOUBLE):
+	case CASE(	TLONG,	TDOUBLE):
+	case CASE(	TVLONG,	TDOUBLE):
+	case CASE(	TIND,	TDOUBLE):
+		regalloc(&nod, t, t);
+		if(ewidth[ft] == SZ_VLONG){
+			if(tt == TFLOAT)
+				a = ACVTSQ2SS;
+			else
+				a = ACVTSQ2SD;
+		}else{
+			if(tt == TFLOAT)
+				a = ACVTSL2SS;
+			else
+				a = ACVTSL2SD;
+		}
+		gins(a, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+/*
+ * float to float
+ */
+	case CASE(	TFLOAT,	TFLOAT):
+		a = AMOVSS;
+		break;
+	case CASE(	TDOUBLE,TFLOAT):
+		a = ACVTSD2SS;
+		break;
+	case CASE(	TFLOAT,	TDOUBLE):
+		a = ACVTSS2SD;
+		break;
+	case CASE(	TDOUBLE,TDOUBLE):
+		a = AMOVSD;
+		break;
+	}
+	if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt])	/* TO DO: check AMOVL */
+	if(samaddr(f, t))
+		return;
+	gins(a, f, t);
+}
+
+void
+doindex(Node *n)
+{
+	Node nod, nod1;
+	long v;
+
+if(debug['Y'])
+prtree(n, "index");
+
+if(n->left->complex >= FNX)
+print("botch in doindex\n");
+
+	regalloc(&nod, &qregnode, Z);
+	v = constnode.vconst;
+	cgen(n->right, &nod);
+	idx.ptr = D_NONE;
+	if(n->left->op == OCONST)
+		idx.ptr = D_CONST;
+	else if(n->left->op == OREGISTER)
+		idx.ptr = n->left->reg;
+	else if(n->left->op != OADDR) {
+		reg[D_BP]++;	// cant be used as a base
+		regalloc(&nod1, &qregnode, Z);
+		cgen(n->left, &nod1);
+		idx.ptr = nod1.reg;
+		regfree(&nod1);
+		reg[D_BP]--;
+	}
+	idx.reg = nod.reg;
+	regfree(&nod);
+	constnode.vconst = v;
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+	if(f != Z && f->op == OINDEX)
+		doindex(f);
+	if(t != Z && t->op == OINDEX)
+		doindex(t);
+	nextpc();
+	p->as = a;
+	if(f != Z)
+		naddr(f, &p->from);
+	if(t != Z)
+		naddr(t, &p->to);
+	if(debug['g'])
+		print("%P\n", p);
+}
+
+void
+gopcode(int o, Type *ty, Node *f, Node *t)
+{
+	int a, et;
+
+	et = TLONG;
+	if(ty != T)
+		et = ty->etype;
+	if(debug['M']) {
+		if(f != Z && f->type != T)
+			print("gop: %O %O[%s],", o, f->op, tnames[et]);
+		else
+			print("gop: %O Z,", o);
+		if(t != Z && t->type != T)
+			print("%O[%s]\n", t->op, tnames[t->type->etype]);
+		else
+			print("Z\n");
+	}
+	a = AGOK;
+	switch(o) {
+	case OCOM:
+		a = ANOTL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ANOTB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ANOTW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ANOTQ;
+		break;
+
+	case ONEG:
+		a = ANEGL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ANEGB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ANEGW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ANEGQ;
+		break;
+
+	case OADDR:
+		a = ALEAQ;
+		break;
+
+	case OASADD:
+	case OADD:
+		a = AADDL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AADDB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AADDW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AADDQ;
+		if(et == TFLOAT)
+			a = AADDSS;
+		if(et == TDOUBLE)
+			a = AADDSD;
+		break;
+
+	case OASSUB:
+	case OSUB:
+		a = ASUBL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ASUBB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ASUBW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ASUBQ;
+		if(et == TFLOAT)
+			a = ASUBSS;
+		if(et == TDOUBLE)
+			a = ASUBSD;
+		break;
+
+	case OASOR:
+	case OOR:
+		a = AORL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AORB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AORW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AORQ;
+		break;
+
+	case OASAND:
+	case OAND:
+		a = AANDL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AANDB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AANDW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AANDQ;
+		break;
+
+	case OASXOR:
+	case OXOR:
+		a = AXORL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AXORB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AXORW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AXORQ;
+		break;
+
+	case OASLSHR:
+	case OLSHR:
+		a = ASHRL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ASHRB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ASHRW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ASHRQ;
+		break;
+
+	case OASASHR:
+	case OASHR:
+		a = ASARL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ASARB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ASARW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ASARQ;
+		break;
+
+	case OASASHL:
+	case OASHL:
+		a = ASALL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ASALB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ASALW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ASALQ;
+		break;
+
+	case OFUNC:
+		a = ACALL;
+		break;
+
+	case OASMUL:
+	case OMUL:
+		if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
+			t = Z;
+		a = AIMULL;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AIMULQ;
+		if(et == TFLOAT)
+			a = AMULSS;
+		if(et == TDOUBLE)
+			a = AMULSD;
+		break;
+
+	case OASMOD:
+	case OMOD:
+	case OASDIV:
+	case ODIV:
+		a = AIDIVL;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AIDIVQ;
+		if(et == TFLOAT)
+			a = ADIVSS;
+		if(et == TDOUBLE)
+			a = ADIVSD;
+		break;
+
+	case OASLMUL:
+	case OLMUL:
+		a = AMULL;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AMULQ;
+		break;
+
+	case OASLMOD:
+	case OLMOD:
+	case OASLDIV:
+	case OLDIV:
+		a = ADIVL;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ADIVQ;
+		break;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OLE:
+	case OGE:
+	case OGT:
+	case OLO:
+	case OLS:
+	case OHS:
+	case OHI:
+		a = ACMPL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ACMPB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ACMPW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ACMPQ;
+		if(et == TFLOAT)
+			a = AUCOMISS;
+		if(et == TDOUBLE)
+			a = AUCOMISD;
+		gins(a, f, t);
+		switch(o) {
+		case OEQ:	a = AJEQ; break;
+		case ONE:	a = AJNE; break;
+		case OLT:	a = AJLT; break;
+		case OLE:	a = AJLE; break;
+		case OGE:	a = AJGE; break;
+		case OGT:	a = AJGT; break;
+		case OLO:	a = AJCS; break;
+		case OLS:	a = AJLS; break;
+		case OHS:	a = AJCC; break;
+		case OHI:	a = AJHI; break;
+		}
+		gins(a, Z, Z);
+		return;
+	}
+	if(a == AGOK)
+		diag(Z, "bad in gopcode %O", o);
+	gins(a, f, t);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+	return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg;
+}
+
+void
+gbranch(int o)
+{
+	int a;
+
+	a = AGOK;
+	switch(o) {
+	case ORETURN:
+		a = ARET;
+		break;
+	case OGOTO:
+		a = AJMP;
+		break;
+	}
+	nextpc();
+	if(a == AGOK) {
+		diag(Z, "bad in gbranch %O",  o);
+		nextpc();
+	}
+	p->as = a;
+}
+
+void
+patch(Prog *op, long pc)
+{
+
+	op->to.offset = pc;
+	op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+	nextpc();
+	p->as = a;
+	p->from.type = D_EXTERN;
+	p->from.sym = s;
+	p->from.scale = (profileflg ? 0 : NOPROF);
+	if(s->class == CSTATIC)
+		p->from.type = D_STATIC;
+	naddr(n, &p->to);
+	if(a == ADATA || a == AGLOBL)
+		pc--;
+}
+
+int
+sconst(Node *n)
+{
+	long v;
+
+	if(n->op == OCONST && !typefd[n->type->etype]) {
+		v = n->vconst;
+		if(v >= -32766L && v < 32766L)
+			return 1;
+	}
+	return 0;
+}
+
+long
+exreg(Type *t)
+{
+	long o;
+
+	if(typechlpv[t->etype]) {
+		if(exregoffset <= REGEXT-4)
+			return 0;
+		o = exregoffset;
+		exregoffset--;
+		return o;
+	}
+	return 0;
+}
+
+schar	ewidth[NTYPE] =
+{
+	-1,		/*[TXXX]*/	
+	SZ_CHAR,	/*[TCHAR]*/	
+	SZ_CHAR,	/*[TUCHAR]*/
+	SZ_SHORT,	/*[TSHORT]*/
+	SZ_SHORT,	/*[TUSHORT]*/
+	SZ_INT,		/*[TINT]*/
+	SZ_INT,		/*[TUINT]*/
+	SZ_LONG,	/*[TLONG]*/
+	SZ_LONG,	/*[TULONG]*/
+	SZ_VLONG,	/*[TVLONG]*/
+	SZ_VLONG,	/*[TUVLONG]*/
+	SZ_FLOAT,	/*[TFLOAT]*/
+	SZ_DOUBLE,	/*[TDOUBLE]*/
+	SZ_IND,		/*[TIND]*/
+	0,		/*[TFUNC]*/
+	-1,		/*[TARRAY]*/
+	0,		/*[TVOID]*/
+	-1,		/*[TSTRUCT]*/
+	-1,		/*[TUNION]*/
+	SZ_INT,		/*[TENUM]*/
+};
+long	ncast[NTYPE] =
+{
+	0,				/*[TXXX]*/
+	BCHAR|BUCHAR,			/*[TCHAR]*/
+	BCHAR|BUCHAR,			/*[TUCHAR]*/	
+	BSHORT|BUSHORT,			/*[TSHORT]*/
+	BSHORT|BUSHORT,			/*[TUSHORT]*/
+	BINT|BUINT|BLONG|BULONG,	/*[TINT]*/		
+	BINT|BUINT|BLONG|BULONG,	/*[TUINT]*/
+	BINT|BUINT|BLONG|BULONG,	/*[TLONG]*/
+	BINT|BUINT|BLONG|BULONG,	/*[TULONG]*/
+	BVLONG|BUVLONG|BIND,			/*[TVLONG]*/
+	BVLONG|BUVLONG|BIND,			/*[TUVLONG]*/
+	BFLOAT,				/*[TFLOAT]*/
+	BDOUBLE,			/*[TDOUBLE]*/
+	BVLONG|BUVLONG|BIND,		/*[TIND]*/
+	0,				/*[TFUNC]*/
+	0,				/*[TARRAY]*/
+	0,				/*[TVOID]*/
+	BSTRUCT,			/*[TSTRUCT]*/
+	BUNION,				/*[TUNION]*/
+	0,				/*[TENUM]*/
+};
diff --git a/src/cmd/6g/align.c b/src/cmd/6g/align.c
new file mode 100644
index 0000000..6538d3c
--- /dev/null
+++ b/src/cmd/6g/align.c
@@ -0,0 +1,210 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "gg.h"
+
+/*
+ * machine size and rounding
+ * alignment is dictated around
+ * the size of a pointer.
+ * the size of the generic types
+ * are pulled from the typedef table.
+ */
+
+static	int	wptr	= 8;	// width of a pointer
+static	int	wmax	= 8;	// max rounding
+
+static char*
+typedefs[] =
+{
+	"short",	"int16",	// shorts
+	"ushort",	"uint16",
+
+	"int",		"int32",	// ints
+	"uint",		"uint32",
+	"rune",		"uint32",
+
+	"long",		"int64",	// longs
+	"ulong",	"uint64",
+
+	"vlong",	"int64",	// vlongs
+	"uvlong",	"uint64",
+
+	"float",	"float32",	// floats
+	"double",	"float64",
+
+};
+
+ulong
+rnd(ulong o, ulong r)
+{
+	if(r > wmax)
+		r = wmax;
+	if(r != 0)
+		while(o%r != 0)
+			o++;
+	return o;
+}
+
+void
+offmod(Type *t)
+{
+	Type *f;
+	long o;
+
+	o = 0;
+	for(f=t->type; f!=T; f=f->down) {
+		if(f->etype != TFIELD)
+			fatal("widstruct: not TFIELD: %lT", f);
+		if(f->type->etype != TFUNC)
+			continue;
+		f->width = o;
+		o += wptr;
+	}
+}
+
+ulong
+widstruct(Type *t, ulong o, int flag)
+{
+	Type *f;
+	long w;
+
+	for(f=t->type; f!=T; f=f->down) {
+		if(f->etype != TFIELD)
+			fatal("widstruct: not TFIELD: %lT", f);
+		dowidth(f->type);
+		w = f->type->width;
+		o = rnd(o, w);
+		f->width = o;	// really offset for TFIELD
+		o += w;
+	}
+	// final width is rounded
+	if(flag)
+		o = rnd(o, maxround);
+	t->width = o;
+	return o;
+}
+
+void
+dowidth(Type *t)
+{
+	ulong w;
+
+	w = 0;
+	if(t == T)
+		return;
+
+	switch(t->etype) {
+	default:
+		fatal("dowidth: unknown type: %E", t->etype);
+		break;
+
+	case TINT8:
+	case TUINT8:
+	case TBOOL:		// bool is int8
+		w = 1;
+		break;
+	case TINT16:
+	case TUINT16:
+		w = 2;
+		break;
+	case TINT32:
+	case TUINT32:
+	case TFLOAT32:
+	case TPTR32:
+		w = 4;
+		break;
+	case TINT64:
+	case TUINT64:
+	case TFLOAT64:
+	case TPTR64:
+		w = 8;
+		break;
+	case TFLOAT80:
+		w = 10;
+		break;
+	case TINTER:		// implemented as 2 pointers
+		offmod(t);
+		w = 2*wptr;
+		break;
+	case TCHAN:		// implemented as pointer
+		dowidth(t->type);
+		dowidth(t->down);
+		w = wptr;
+		break;
+	case TMAP:		// implemented as pointer
+		dowidth(t->type);
+		w = wptr;
+		break;
+	case TFORW:		// implemented as pointer
+		w = wptr;
+		break;
+	case TANY:		// implemented as pointer
+		w = wptr;
+		break;
+	case TSTRING:		// implemented as pointer
+		w = wptr;
+		break;
+	case TARRAY:
+	case TDARRAY:
+		if(t->type == T)
+			break;
+		dowidth(t->type);
+		w = t->bound * t->type->width;
+		break;
+
+	case TSTRUCT:
+		w = widstruct(t, 0, 1);
+		offmod(t);
+		break;
+
+	case TFUNC:
+		// function is 3 cated structures
+		w = widstruct(*getthis(t), 0, 0);
+		w = widstruct(*getinarg(t), w, 0);
+		w = widstruct(*getoutarg(t), w, 1);
+		w = 0;
+		break;
+	}
+	t->width = w;
+}
+
+void
+besetptr(void)
+{
+	maxround = wmax;
+	widthptr = wptr;
+
+	types[TPTR32] = typ(TPTR32);
+	dowidth(types[TPTR32]);
+
+	types[TPTR64] = typ(TPTR64);
+	dowidth(types[TPTR64]);
+
+	tptr = TPTR32;
+	if(wptr == 8)
+		tptr = TPTR64;
+}
+
+void
+belexinit(int lextype)
+{
+	int i;
+	Sym *s0, *s1;
+
+	for(i=0; i<nelem(typedefs); i+=2) {
+		s1 = lookup(typedefs[i+1]);
+		if(s1->lexical != lextype)
+			yyerror("need %s to define %s",
+				typedefs[i+1], typedefs[i+0]);
+		s0 = lookup(typedefs[i+0]);
+		s0->lexical = s1->lexical;
+		s0->otype = s1->otype;
+	}
+
+	symstringo = lookup(".stringo");	// strings
+
+	listinit();
+	buildtxt();
+}
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
new file mode 100644
index 0000000..7a00688
--- /dev/null
+++ b/src/cmd/6g/cgen.c
@@ -0,0 +1,638 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "gg.h"
+
+void
+cgen(Node *n, Node *res)
+{
+	long lno;
+	Node *nl, *nr, *r;
+	Node n1, tmp;
+	int a;
+	Prog *p1, *p2, *p3;
+
+	if(debug['g']) {
+		dump("\ncgen-l", res);
+		dump("cgen-r", n);
+	}
+	if(n == N || n->type == T)
+		return;
+	if(res == N || res->type == T)
+		fatal("cgen: res nil");
+
+	lno = dynlineno;
+	if(n->op != ONAME)
+		dynlineno = n->lineno;	// for diagnostics
+
+	if(isfat(n->type)) {
+		sgen(n, res, n->type->width);
+		goto ret;
+	}
+
+	if(!res->addable) {
+		igen(res, &n1, N);
+		cgen(n, &n1);
+		regfree(&n1);
+		goto ret;
+	}
+
+	if(n->addable) {
+		gmove(n, res);
+		goto ret;
+	}
+
+	nl = n->left;
+	nr = n->right;
+	if(nl != N && nl->ullman >= UINF)
+	if(nr != N && nr->ullman >= UINF) {
+		fatal("cgen: both sides functions");
+		goto ret;
+	}
+
+	switch(n->op) {
+	default:
+		dump("cgen", n);
+		fatal("cgen: unknown op %N", n);
+		break;
+
+	// these call bgen to get a bool value
+	case OOROR:
+	case OANDAND:
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OLE:
+	case OGE:
+	case OGT:
+	case ONOT:
+		p1 = gbranch(AJMP, T);
+		p2 = pc;
+		gmove(booltrue, res);
+		p3 = gbranch(AJMP, T);
+		patch(p1, pc);
+		bgen(n, 1, p2);
+		gmove(boolfalse, res);
+		patch(p3, pc);
+		goto ret;
+
+	case OPLUS:
+		cgen(nl, res);
+		goto ret;
+
+	// unary
+	case OMINUS:
+	case OCOM:
+		a = optoas(n->op, nl->type);
+		goto uop;
+
+	// symmetric binary
+	case OAND:
+	case OOR:
+	case OXOR:
+	case OADD:
+	case OMUL:
+		a = optoas(n->op, nl->type);
+		goto sbop;
+
+	// asymmetric binary
+	case OMOD:
+	case OSUB:
+	case ODIV:
+	case OLSH:
+	case ORSH:
+		a = optoas(n->op, nl->type);
+		goto abop;
+
+	case OCONV:
+		if(eqtype(n->type, nl->type, 0)) {
+			cgen(nl, res);
+			break;
+		}
+		regalloc(&n1, nl->type, res);
+		cgen(nl, &n1);
+		gmove(&n1, res);
+		regfree(&n1);
+		break;
+
+//	case OINDEXPTRSTR:
+//		nl = n->left;
+//		nr = n->right;
+//		if(nl->addable) {
+//			cgen(nr);
+//			cgen(nl);
+//			gopcode(P_LOADI, T_ADDR, N);
+//			gopcodet(P_INDEXZ, nr->type, N);
+//			break;
+//		}
+//		break;
+
+//	case OINDEXSTR:
+//		nl = n->left;
+//		nr = n->right;
+//		if(nl->addable) {
+//			cgen(nr);
+//			gopcodet(P_INDEXZ, nr->type, nl);
+//			break;
+//		}
+//		cgen(nl);
+//		r = tempname(nl->type);
+//		gopcodet(P_STORE, nl->type, r);
+//		cgen(nr);
+//		gopcodet(P_INDEXZ, nr->type, r);
+//		break;
+
+//	case OSLICESTR:
+//	case OSLICEPTRSTR:
+//		nl = n->left;	// name
+//		nr = n->right;
+//
+//		r = nr->right;	// index2
+//		if(!r->addable) {
+//			cgen(r);
+//			r = tempname(r->type);
+//			gopcodet(P_STORE, r->type, r);
+//		}
+//
+//		// string into T_ADDR
+//		if(!nl->addable) {
+//			cgen(nl);
+//			gconv(T_ADDR, nl->type->etype);
+//		} else
+//			gopcode(P_LOAD, T_ADDR, nl);
+//
+//		if(n->op == OSLICEPTRSTR)
+//			gopcode(P_LOADI, T_ADDR, N);
+//
+//		// offset in int reg
+//		cgen(nr->left);
+//
+//		// index 2 addressed
+//		gopcodet(P_SLICE, r->type, r);
+//		break;
+
+	case OS2I:
+	case OI2I:
+	case OI2S:
+
+	case OINDEXPTR:
+	case OINDEX:
+	case ODOT:
+	case ODOTPTR:
+	case OIND:
+		igen(n, &n1, res);
+		gmove(&n1, res);
+		regfree(&n1);
+		break;
+
+	case OLEN:
+		if(isptrto(nl->type, TSTRING)) {
+			regalloc(&n1, types[tptr], res);
+			cgen(nl, res);
+			n1.op = OINDREG;
+			n1.type = types[TINT32];
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		fatal("cgen: OLEN: unknown type %lT", nl->type);
+		break;
+
+//	case ODOTMETH:
+//	case ODOTINTER:
+//		cgen(n->left);
+//		break;
+
+	case OADDR:
+		agen(nl, res);
+		break;
+
+	case OCALLMETH:
+		cgen_callmeth(n);
+		cgen_callret(n, res);
+		break;
+
+	case OCALLINTER:
+		cgen_callinter(n, res);
+		cgen_callret(n, res);
+		break;
+
+	case OCALL:
+		cgen_call(n);
+		cgen_callret(n, res);
+		break;
+	}
+	goto ret;
+
+sbop:	// symmetric binary
+	if(nl->ullman < nr->ullman) {
+		r = nl;
+		nl = nr;
+		nr = r;
+	}
+
+abop:	// asymmetric binary
+	if(nr->addable) {
+		regalloc(&n1, nl->type, res);
+		cgen(nl, &n1);
+		gins(a, nr, &n1);
+		gmove(&n1, res);
+		regfree(&n1);
+		goto ret;
+	}
+
+	tempname(&tmp, nr->type);
+	regalloc(&n1, nr->type, res);
+	cgen(nr, &n1);
+	gmove(&n1, &tmp);
+	regfree(&n1);
+
+	regalloc(&n1, nl->type, res);
+	cgen(nl, &n1);
+	gins(a, &tmp, &n1);
+	gmove(&n1, res);
+	regfree(&n1);
+	goto ret;
+
+uop:	// unary
+	regalloc(&n1, nl->type, res);
+	cgen(nl, &n1);
+	gins(a, N, &n1);
+	gmove(&n1, res);
+	regfree(&n1);
+	goto ret;
+
+ret:
+	dynlineno = lno;
+}
+
+void
+agen(Node *n, Node *res)
+{
+	Node *nl, *nr;
+	Node n1, n2, n3, tmp;
+	ulong w;
+	Type *t;
+
+	if(n == N || n->type == T)
+		return;
+
+	if(!isptr[res->type->etype])
+		fatal("agen: not tptr: %T", res->type);
+
+	if(n->addable) {
+		regalloc(&n1, types[tptr], res);
+		gins(ALEAQ, n, &n1);
+		gmove(&n1, res);
+		regfree(&n1);
+		return;
+	}
+
+	switch(n->op) {
+	default:
+		fatal("agen: unknown op %N", n);
+		break;
+
+//	case ONAME:
+//		regalloc(&n1, types[tptr], res);
+//		gins(optoas(OADDR, types[tptr]), n, &n1);
+//		gmove(&n1, res);
+//		regfree(&n1);
+//		break;
+
+	case OINDEXPTR:
+		nl = n->left;
+		nr = n->right;
+		w = n->type->width;
+		if(nr->addable)
+			goto iprad;
+		if(nl->addable) {
+			regalloc(&n1, nr->type, N);
+			cgen(nr, &n1);
+			cgen(nl, res);
+			goto index;
+		}
+		cgen(nr, res);
+		tempname(&tmp, nr->type);
+		gmove(res, &tmp);
+
+	iprad:
+		cgen(nl, res);
+		regalloc(&n1, nr->type, N);
+		cgen(nr, &n1);
+		goto index;
+
+	case OS2I:
+	case OI2I:
+	case OI2S:
+		agen_inter(n, res);
+		break;
+
+//	case OINDREG:
+
+	case OINDEX:
+		nl = n->left;
+		nr = n->right;
+		w = n->type->width;
+		if(nr->addable)
+			goto irad;
+		if(nl->addable) {
+			regalloc(&n1, nr->type, N);
+			cgen(nr, &n1);
+			agen(nl, res);
+			goto index;
+		}
+		cgen(nr, res);
+		tempname(&tmp, nr->type);
+		gmove(res, &tmp);
+
+	irad:
+		agen(nl, res);
+		regalloc(&n1, nr->type, N);
+		cgen(nr, &n1);
+		goto index;
+
+	index:
+		// &a is in res
+		// i is in &n1
+		// w is width
+		if(issigned[n1.type->etype]) {
+			nodconst(&n3, types[TINT64], w);	// w/tint64
+			regalloc(&n2, types[TINT64], &n1);	// i/int64
+			gmove(&n1, &n2);
+			gins(optoas(OMUL, types[TINT64]), &n3, &n2);
+			gins(optoas(OADD, types[tptr]), &n2, res);
+			regfree(&n1);
+			regfree(&n2);
+			break;
+		}
+		// unsigned multiply is a pain in the ass
+		fatal("agen: unsigned index");
+		break;
+
+//	case OIND:
+//		nl = n->left;
+//		if(nl->addable) {
+//			gopcode(P_LOAD, T_ADDR, nl);
+//			break;
+//		}
+//		cgen(nl);
+//		gconv(T_ADDR, nl->type->etype);
+//		break;
+		
+	case ODOT:
+		nl = n->left;
+		t = nl->type;
+		agen(nl, res);
+		if(n->xoffset != 0) {
+			nodconst(&n1, types[TINT64], n->xoffset);
+			gins(optoas(OADD, types[tptr]), &n1, res);
+		}
+		break;
+
+	case ODOTPTR:
+		nl = n->left;
+		t = nl->type;
+		if(!isptr[t->etype])
+			fatal("agen: not ptr %N", n);
+		cgen(nl, res);
+		if(n->xoffset != 0) {
+			nodconst(&n1, types[TINT64], n->xoffset);
+			gins(optoas(OADD, types[tptr]), &n1, res);
+		}
+		break;
+	}
+}
+
+vlong
+fieldoffset(Type *t, Node *n)
+{
+	if(t->etype != TSTRUCT)
+		fatal("fieldoffset: not struct %lT", t);
+	if(n->op != ONAME)
+		fatal("fieldoffset: not field name %N", n);
+	return 0;
+}
+
+void
+igen(Node *n, Node *a, Node *res)
+{
+	regalloc(a, types[tptr], res);
+	agen(n, a);
+	a->op = OINDREG;
+	a->type = n->type;
+}
+
+void
+bgen(Node *n, int true, Prog *to)
+{
+	long lno;
+	int et, a, b;
+	Node *nl, *nr, *r;
+	Node n1, n2, tmp;
+	Prog *p1, *p2;
+
+	if(n == N)
+		n = booltrue;
+
+	lno = dynlineno;
+	if(n->op != ONAME)
+		dynlineno = n->lineno;	// for diagnostics
+
+	if(n->type == T) {
+		convlit(n, types[TBOOL]);
+		if(n->type == T)
+			goto ret;
+	}
+
+	et = n->type->etype;
+	if(et != TBOOL) {
+		yyerror("cgen: bad type %T for %O", n->type, n->op);
+		patch(gins(AEND, N, N), to);
+		goto ret;
+	}
+	nl = N;
+	nr = N;
+
+	switch(n->op) {
+	default:
+		regalloc(&n1, n->type, N);
+		cgen(n, &n1);
+		nodconst(&n2, n->type, 0);
+		gins(optoas(OCMP, n->type), &n1, &n2);
+		a = AJNE;
+		if(!true)
+			a = AJEQ;
+		patch(gbranch(a, n->type), to);
+		regfree(&n1);
+		goto ret;
+
+	case OLITERAL:
+		if(!true == !n->val.vval)
+			patch(gbranch(AJMP, T), to);
+		goto ret;
+
+	case ONAME:
+		nodconst(&n1, n->type, 0);
+		gins(optoas(OCMP, n->type), n, &n1);
+		a = AJNE;
+		if(!true)
+			a = AJEQ;
+		patch(gbranch(a, n->type), to);
+		goto ret;
+
+	case OANDAND:
+		if(!true)
+			goto caseor;
+
+	caseand:
+		p1 = gbranch(AJMP, T);
+		p2 = gbranch(AJMP, T);
+		patch(p1, pc);
+		bgen(n->left, !true, p2);
+		bgen(n->right, !true, p2);
+		p1 = gbranch(AJMP, T);
+		patch(p1, to);
+		patch(p2, pc);
+		goto ret;
+
+	case OOROR:
+		if(!true)
+			goto caseand;
+
+	caseor:
+		bgen(n->left, true, to);
+		bgen(n->right, true, to);
+		goto ret;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OGT:
+	case OLE:
+	case OGE:
+		nr = n->right;
+		if(nr == N || nr->type == T)
+			goto ret;
+
+	case ONOT:	// unary
+		nl = n->left;
+		if(nl == N || nl->type == T)
+			goto ret;
+	}
+
+	switch(n->op) {
+
+	case ONOT:
+		bgen(nl, !true, to);
+		goto ret;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OGT:
+	case OLE:
+	case OGE:
+		a = n->op;
+		if(!true)
+			a = brcom(a);
+
+		// make simplest on right
+		if(nl->ullman < nr->ullman) {
+			a = brrev(a);
+			r = nl;
+			nl = nr;
+			nr = r;
+		}
+		a = optoas(a, nr->type);
+
+		if(nr->addable) {
+			regalloc(&n1, nl->type, N);
+			cgen(nl, &n1);
+			b = optoas(OCMP, nr->type);
+
+			switch(b) {
+			case ACMPQ:
+				if(nr->op == OLITERAL)
+				if(nr->val.vval >= (1LL<<32))
+					goto dolit;
+
+			case AUCOMISS:
+				if(nr->op == OLITERAL)
+					goto dolit;
+				if(nr->op == ONAME)
+					goto dolit;
+			}
+
+			gins(b, &n1, nr);
+			patch(gbranch(a, nr->type), to);
+			regfree(&n1);
+			break;
+
+		dolit:
+			regalloc(&n2, nr->type, N);
+			cgen(nr, &n2);
+			gins(b, &n1, &n2);
+			patch(gbranch(a, nr->type), to);
+			regfree(&n2);
+			regfree(&n1);
+			break;
+		}
+
+		tempname(&tmp, nr->type);
+		cgen(nr, &tmp);
+
+		regalloc(&n1, nl->type, N);
+		cgen(nl, &n1);
+
+		gins(optoas(OCMP, nr->type), &n1, &tmp);
+		patch(gbranch(a, nr->type), to);
+		regfree(&n1);
+		break;
+	}
+	goto ret;
+
+ret:
+	dynlineno = lno;
+}
+
+void
+sgen(Node *n, Node *ns, ulong w)
+{
+	Node nodl, nodr;
+	long c;
+
+	if(w == 0)
+		return;
+	if(n->ullman >= UINF && ns->ullman >= UINF) {
+		fatal("sgen UINF");
+	}
+
+	nodreg(&nodl, types[tptr], D_DI);
+	nodreg(&nodr, types[tptr], D_SI);
+
+	if(n->ullman >= ns->ullman) {
+		agen(n, &nodr);
+		agen(ns, &nodl);
+	} else {
+		agen(ns, &nodl);
+		agen(n, &nodr);
+	}
+
+	gins(ACLD, N, N);	// clear direction flag
+
+	c = w / 8;
+	if(c > 0) {
+		gconreg(AMOVQ, c, D_CX);
+		gins(AREP, N, N);	// repeat
+		gins(AMOVSQ, N, N);	// MOVQ *(SI)+,*(DI)+
+	}
+
+	c = w % 8;
+	if(c > 0) {
+		gconreg(AMOVQ, c, D_CX);
+		gins(AREP, N, N);	// repeat
+		gins(AMOVSB, N, N);	// MOVB *(SI)+,*(DI)+
+	}
+}
diff --git a/src/cmd/6g/gen.c b/src/cmd/6g/gen.c
new file mode 100644
index 0000000..7000574
--- /dev/null
+++ b/src/cmd/6g/gen.c
@@ -0,0 +1,820 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+#undef	EXTERN
+#define	EXTERN
+#include "gg.h"
+
+enum
+{
+	// random unused opcode
+	AJMPX	= AADDPD,
+};
+
+static	Node*	curfn;
+
+void
+compile(Node *fn)
+{
+	Plist *pl;
+	Node nod1;
+	Prog *ptxt;
+
+	if(fn->nbody == N)
+		return;
+
+	curfn = fn;
+	dowidth(curfn->type);
+
+	if(nerrors != 0) {
+		walk(curfn);
+		return;
+	}
+
+	if(debug['w'])
+		dump("--- pre walk ---", curfn->nbody);
+
+	maxarg = 0;
+	stksize = 0;
+
+	walk(curfn);
+	if(nerrors != 0)
+		return;
+
+	if(debug['w'])
+		dump("--- post walk ---", curfn->nbody);
+
+	allocparams();
+
+	continpc = P;
+	breakpc = P;
+
+	pl = newplist();
+	pl->name = curfn->nname;
+	pl->locals = autodcl;
+
+	nodconst(&nod1, types[TINT32], 0);
+	ptxt = gins(ATEXT, curfn->nname, &nod1);
+
+//	inarggen();
+
+	ginit();
+	gen(curfn->nbody);
+	gclean();
+
+//	if(curfn->type->outtuple != 0)
+//		gins(AGOK, N, N);
+
+	pc->as = ARET;	// overwrite AEND
+
+	// fill in final stack size
+	ptxt->to.offset = rnd(stksize+maxarg, maxround);
+
+	if(debug['f'])
+		frame(0);
+}
+
+void
+allocparams(void)
+{
+	Dcl *d;
+	Iter list;
+	Type *t;
+	Node *n;
+	ulong w;
+
+	/*
+	 * allocate (set xoffset) the stack
+	 * slots for this, inargs, outargs
+	 * these are allocated positavely
+	 * from 0 up.
+	 * note that this uses the 'width'
+	 * field, which, in the OFIELD of the
+	 * parameters, is the offset in the
+	 * parameter list.
+	 */
+	d = autodcl;
+	t = funcfirst(&list, curfn->type);
+	while(t != T) {
+		if(d == D)
+			fatal("allocparams: this nil");
+		if(d->op != ONAME) {
+			d = d->forw;
+			continue;
+		}
+
+		n = d->dnode;
+		if(n->class != PPARAM)
+			fatal("allocparams: this class");
+
+		n->xoffset = t->width;
+		d = d->forw;
+		t = funcnext(&list);
+	}
+
+	/*
+	 * allocate (set xoffset) the stack
+	 * slots for all automatics.
+	 * allocated starting at -w down.
+	 */
+	for(d=autodcl; d!=D; d=d->forw) {
+		if(d->op != ONAME)
+			continue;
+
+		n = d->dnode;
+		if(n->class != PAUTO)
+			continue;
+
+		dowidth(n->type);
+		w = n->type->width;
+		stksize += w;
+		stksize = rnd(stksize, w);
+
+		n->xoffset = -stksize;
+	}
+}
+
+/*
+ * compile statements
+ */
+void
+gen(Node *n)
+{
+	long lno;
+	Prog *scontin, *sbreak;
+	Prog *p1, *p2, *p3;
+	Sym *s;
+
+	lno = dynlineno;
+
+loop:
+	if(n == N)
+		goto ret;
+	dynlineno = n->lineno;	// for diagnostics
+
+	switch(n->op) {
+	default:
+		fatal("gen: unknown op %N", n);
+		break;
+
+	case OLIST:
+		gen(n->left);
+		n = n->right;
+		goto loop;
+
+	case OPANIC:
+		genpanic();
+		break;
+
+	case OCASE:
+	case OFALL:
+	case OXCASE:
+	case OXFALL:
+	case OEMPTY:
+		break;
+
+	case OLABEL:
+		// before declaration, s->label points at
+		// a link list of PXGOTO instructions.
+		// after declaration, s->label points
+		// at a AJMP to .+1
+
+		s = n->left->sym;
+		p1 = (Prog*)s->label;
+
+		if(p1 != P) {
+			if(p1->as == AJMP) {
+				yyerror("label redeclared: %S", s);
+				break;
+			}
+			while(p1 != P) {
+				if(p1->as != AJMPX)
+					fatal("bad label pointer: %S", s);
+				p1->as = AJMP;
+				p2 = p1->to.branch;
+				patch(p1, pc);
+				p1 = p2;
+			}
+		}
+
+		s->label = pc;
+		p1 = gbranch(AJMP, T);
+		patch(p1, pc);
+		break;
+
+	case OGOTO:
+		s = n->left->sym;
+		p1 = (Prog*)s->label;
+		if(p1 != P && p1->as == AJMP) {
+			// already declared
+			p2 = gbranch(AJMP, T);
+			patch(p2, p1->to.branch);
+			break;
+		}
+
+		// link thru to.branch
+		p2 = gbranch(AJMPX, T);
+		p2->to.branch = p1;
+		s->label = p2;
+		break;
+
+	case OBREAK:
+		if(breakpc == P) {
+			yyerror("gen: break is not in a loop");
+			break;
+		}
+		patch(gbranch(AJMP, T), breakpc);
+		break;
+
+	case OCONTINUE:
+		if(continpc == P) {
+			yyerror("gen: continue is not in a loop");
+			break;
+		}
+		patch(gbranch(AJMP, T), continpc);
+		break;
+
+	case OFOR:
+		gen(n->ninit);				// 		init
+		p1 = gbranch(AJMP, T);			// 		goto test
+		sbreak = breakpc;
+		breakpc = gbranch(AJMP, T);		// break:	goto done
+		scontin = continpc;
+		continpc = pc;
+		gen(n->nincr);				// contin:	incr
+		patch(p1, pc);				// test:
+		bgen(n->ntest, 0, breakpc);		//		if(!test) goto break
+		gen(n->nbody);				//		body
+		patch(gbranch(AJMP, T), continpc);	//		goto contin
+		patch(breakpc, pc);			// done:
+		continpc = scontin;
+		breakpc = sbreak;
+		break;
+
+	case OIF:
+		gen(n->ninit);				//		init
+		p1 = gbranch(AJMP, T);			//		goto test
+		p2 = gbranch(AJMP, T);			// p2:		goto else
+		patch(p1, pc);				// test:
+		bgen(n->ntest, 0, p2);			// 		if(!test) goto p2
+		gen(n->nbody);				//		then
+		p3 = gbranch(AJMP, T);			//		goto done
+		patch(p2, pc);				// else:
+		gen(n->nelse);				//		else
+		patch(p3, pc);				// done:
+		break;
+
+	case OSWITCH:
+		gen(n->ninit);				// 		init
+		p1 = gbranch(AJMP, T);			// 		goto test
+		sbreak = breakpc;
+		breakpc = gbranch(AJMP, T);		// break:	goto done
+		patch(p1, pc);				// test:
+		swgen(n);				//		switch(test) body
+		patch(breakpc, pc);			// done:
+		breakpc = sbreak;
+		break;
+
+	case OASOP:
+		cgen_asop(n->left, n->right, n->etype);
+		break;
+
+	case OAS:
+		cgen_as(n->left, n->right, n->op);
+		break;
+
+	case OCALLMETH:
+		cgen_callmeth(n);
+		break;
+
+	case OCALLINTER:
+		cgen_callinter(n, N);
+		break;
+
+	case OCALL:
+		cgen_call(n);
+		break;
+
+	case ORETURN:
+		cgen_ret(n);
+		break;
+	}
+
+ret:
+	dynlineno = lno;
+}
+
+void
+agen_inter(Node *n, Node *res)
+{
+	Node nodo, nodr, nodt;
+	Sym *s;
+	char *e;
+	long o;
+
+	// stack offset
+	memset(&nodo, 0, sizeof(nodo));
+	nodo.op = OINDREG;
+	nodo.val.vval = D_SP;
+	nodo.addable = 1;
+	nodo.type = types[tptr];
+
+	// pointer register
+	regalloc(&nodr, types[tptr], res);
+
+	switch(n->op) {
+	default:
+		fatal("agen_inter %O\n", n->op);
+
+	case OS2I:
+		// ifaces2i(*sigi, *sigs, i.map, i.s)
+		// i.s is input
+		// (i.map, i.s) is output
+
+		cgen(n->left, &nodr);
+		nodo.xoffset = 3*widthptr;
+		cgen_as(&nodo, &nodr, 0);
+
+		nodtypesig(&nodt, n->type);
+		agen(&nodt, &nodr);
+		nodo.xoffset = 0*widthptr;
+		cgen_as(&nodo, &nodr, 0);
+
+		nodtypesig(&nodt, n->left->type);
+		agen(&nodt, &nodr);
+		nodo.xoffset = 1*widthptr;
+		cgen_as(&nodo, &nodr, 0);
+
+		e = "ifaces2i";
+		if(maxarg < 4*widthptr)
+			maxarg = 4*widthptr;
+		o = 2*widthptr;
+		break;
+
+	case OI2I:
+		// ifacei2i(*sigi, i.map, i.s)
+		// (i.map, i.s) is input
+		// (i.map, i.s) is output
+
+		nodo.xoffset = 1*widthptr;
+		if(!n->left->addable) {
+			agen(n->left, &nodr);
+			gmove(&nodr, &nodo);
+			fatal("agen_inter i2i");
+		} else {
+			cgen(n->left, &nodo);
+		}
+
+		nodtypesig(&nodt, n->type);
+		agen(&nodt, &nodr);
+		nodo.xoffset = 0*widthptr;
+		cgen_as(&nodo, &nodr, 0);
+
+		e = "ifacei2i";
+		if(maxarg < 3*widthptr)
+			maxarg = 3*widthptr;
+		o = 1*widthptr;
+		break;
+
+	case OI2S:
+		// ifacei2s(*sigs, i.map, i.s)
+		// (i.map, i.s) is input
+		// i.s is output
+
+		nodo.xoffset = 1*widthptr;
+		if(!n->left->addable) {
+			agen(n->left, &nodr);
+			gmove(&nodr, &nodo);
+			fatal("agen_inter i2s");
+		} else
+			gmove(n->left, &nodo);
+
+		nodtypesig(&nodt, n->type);
+		agen(&nodt, &nodr);
+		nodo.xoffset = 0*widthptr;
+		cgen_as(&nodo, &nodr, 0);
+
+		e = "ifacei2s";
+		if(maxarg < 3*widthptr)
+			maxarg = 3*widthptr;
+		o = 2*widthptr;
+		break;
+	}
+
+	s = pkglookup(e, "sys");
+	if(s->oname == N) {
+		s->oname = newname(s);
+		s->oname->class = PEXTERN;
+	}
+	gins(ACALL, N, s->oname);
+
+	nodo.xoffset = o;
+	gins(ALEAQ, &nodo, res);
+
+	regfree(&nodr);
+}
+
+void
+swgen(Node *n)
+{
+	Node *c1, *c2;
+	Node n1, tmp;
+	Case *s0, *se, *s;
+	Prog *p1, *dflt;
+	long lno;
+	int any;
+	Iter save1, save2;
+
+// botch - put most of this code in
+// walk. gen binary search for
+// sequence of constant cases
+
+	lno = dynlineno;
+
+	p1 = gbranch(AJMP, T);
+	s0 = C;
+	se = C;
+
+	// walk thru the body placing breaks
+	// and labels into the case statements
+
+	any = 0;
+	dflt = P;
+	c1 = listfirst(&save1, &n->nbody);
+	while(c1 != N) {
+		dynlineno = c1->lineno;	// for diagnostics
+		if(c1->op != OCASE) {
+			if(s0 == C)
+				yyerror("unreachable statements in a switch");
+			gen(c1);
+
+			any = 1;
+			if(c1->op == OFALL)
+				any = 0;
+			c1 = listnext(&save1);
+			continue;
+		}
+
+		// put in the break between cases
+		if(any) {
+			patch(gbranch(AJMP, T), breakpc);
+			any = 0;
+		}
+
+		// over case expressions
+		c2 = listfirst(&save2, &c1->left);
+		if(c2 == N)
+			dflt = pc;
+
+		while(c2 != N) {
+
+			s = mal(sizeof(*s));
+			if(s0 == C)
+				s0 = s;
+			else
+				se->slink = s;
+			se = s;
+
+			s->scase = c2;		// case expression
+			s->sprog = pc;		// where to go
+
+			c2 = listnext(&save2);
+		}
+
+		c1 = listnext(&save1);
+	}
+
+	if(any)
+		patch(gbranch(AJMP, T), breakpc);
+
+	patch(p1, pc);
+
+	tempname(&tmp, n->ntest->type);
+	cgen(n->ntest, &tmp);
+
+	for(s=s0; s!=C; s=s->slink) {
+		memset(&n1, 0, sizeof(n1));
+		n1.op = OEQ;
+		n1.left = &tmp;
+		n1.right = s->scase;
+		walktype(&n1, 0);
+		bgen(&n1, 1, s->sprog);
+	}
+	if(dflt != P) {
+		patch(gbranch(AJMP, T), dflt);
+		goto ret;
+	}
+	patch(gbranch(AJMP, T), breakpc);
+
+ret:
+	dynlineno = lno;
+}
+
+void
+inarggen(void)
+{
+	fatal("inarggen");
+}
+
+void
+genpanic(void)
+{
+	Node n1, n2;
+	Prog *p;
+
+	nodconst(&n1, types[TINT64], 0xf0);
+	nodreg(&n2, types[TINT64], D_AX);
+	gins(AMOVL, &n1, &n2);
+	p = pc;
+	gins(AMOVQ, &n2, N);
+	p->to.type = D_INDIR+D_AX;
+}
+
+void
+cgen_callinter(Node *n, Node *res)
+{
+	Node *i, *f;
+	Node tmpi, nodo, nodr, nodsp;
+
+	i = n->left;
+	if(i->op != ODOTINTER)
+		fatal("cgen_callinter: not ODOTINTER %O", i->op);
+
+	f = i->right;		// field
+	if(f->op != ONAME)
+		fatal("cgen_callinter: not ONAME %O", f->op);
+
+	i = i->left;		// interface
+
+	if(!i->addable) {
+		tempname(&tmpi, i->type);
+		cgen(i, &tmpi);
+		i = &tmpi;
+	}
+
+	gen(n->right);		// args
+
+	regalloc(&nodr, types[tptr], res);
+	regalloc(&nodo, types[tptr], &nodr);
+	nodo.op = OINDREG;
+
+	agen(i, &nodr);		// REG = &inter
+
+	nodindreg(&nodsp, types[tptr], D_SP);
+	nodo.xoffset += widthptr;
+	cgen(&nodo, &nodsp);	// 0(SP) = 8(REG) -- i.s
+
+	nodo.xoffset -= widthptr;
+	cgen(&nodo, &nodr);	// REG = 0(REG) -- i.m
+
+//print("field = %N\n", f);
+//print("offset = %ld\n", n->left->xoffset);
+
+	nodo.xoffset = n->left->xoffset + 4*widthptr;
+	cgen(&nodo, &nodr);	// REG = 32+offset(REG) -- i.m->fun[f]
+
+	gins(ACALL, N, &nodr);
+	regfree(&nodr);
+	regfree(&nodr);
+
+	setmaxarg(n->left->type);
+}
+
+void
+cgen_callmeth(Node *n)
+{
+	Node *l;
+
+	// generate a rewrite for method call
+	// (p.f)(...) goes to (f)(p,...)
+
+	l = n->left;
+
+	n->op = OCALL;
+	n->left = n->left->right;
+	n->left->type = l->type;
+
+	if(n->left->op == ONAME)
+		n->left->class = PEXTERN;
+	cgen_call(n);
+}
+
+void
+cgen_call(Node *n)
+{
+	Type *t;
+	Node nod, afun;
+
+	if(n == N)
+		return;
+
+	if(n->left->ullman >= UINF) {
+		// if name involves a fn call
+		// precompute the address of the fn
+		tempname(&afun, types[tptr]);
+		if(isptr[n->left->type->etype])
+			cgen(n->left, &afun);
+		else
+			agen(n->left, &afun);
+	}
+
+	gen(n->right);	// assign the args
+	t = n->left->type;
+	if(isptr[t->etype])
+		t = t->type;
+
+	setmaxarg(t);
+
+	// call tempname pointer
+	if(n->left->ullman >= UINF) {
+		regalloc(&nod, types[tptr], N);
+		cgen_as(&nod, &afun, 0);
+		gins(ACALL, N, &nod);
+		regfree(&nod);
+		return;
+	}
+
+	// call pointer
+	if(isptr[n->left->type->etype]) {
+		regalloc(&nod, types[tptr], N);
+		cgen_as(&nod, n->left, 0);
+		gins(ACALL, N, &nod);
+		regfree(&nod);
+		return;
+	}
+
+	// call direct
+	gins(ACALL, N, n->left);
+}
+
+void
+cgen_callret(Node *n, Node *res)
+{
+	Node nod;
+	Type *fp, *t;
+	Iter flist;
+
+	t = n->left->type;
+	if(t->etype == TPTR32 || t->etype == TPTR64)
+		t = t->type;
+
+	fp = structfirst(&flist, getoutarg(t));
+	if(fp == T)
+		fatal("cgen_callret: nil");
+
+	memset(&nod, 0, sizeof(nod));
+	nod.op = OINDREG;
+	nod.val.vval = D_SP;
+	nod.addable = 1;
+
+	nod.xoffset = fp->width;
+	nod.type = fp->type;
+	cgen_as(res, &nod, 0);
+}
+
+void
+cgen_ret(Node *n)
+{
+	gen(n->left);	// copy out args
+	gins(ARET, N, N);
+}
+
+void
+cgen_asop(Node *nl, Node *nr, int op)
+{
+	Node n1, n2;
+	int a;
+
+	// botch compare ullman numbers
+	// and use temp for functions
+
+	a = optoas(op, nl->type);
+	regalloc(&n1, nl->type, N);
+	if(nl->addable) {
+		cgen(nr, &n1);
+		gins(a, nl, &n1);
+		gmove(&n1, nl);
+		regfree(&n1);
+		return;
+	}
+
+	igen(nl, &n2, N);
+	cgen(nr, &n1);
+	gins(a, &n2, &n1);
+	gmove(&n1, &n2);
+	regfree(&n1);
+	regfree(&n2);
+}
+
+void
+cgen_as(Node *nl, Node *nr, int op)
+{
+	Node nc, n1;
+	Type *tl;
+	ulong w, c;
+
+	if(nl == N)
+		return;
+
+	tl = nl->type;
+	if(tl == T)
+		return;
+
+	if(nr == N) {
+		if(isfat(tl)) {
+			/* clear a fat object */
+			if(debug['g'])
+				dump("\nclearfat", nl);
+
+			w = nl->type->width;
+			if(w > 0)
+				gconreg(AMOVQ, 0, D_AX);
+
+			if(w > 0) {
+				nodreg(&n1, types[tptr], D_DI);
+				agen(nl, &n1);
+				gins(ACLD, N, N);	// clear direction flag
+			}
+
+			c = w / 8;
+			if(c > 0) {
+				gconreg(AMOVQ, c, D_CX);
+				gins(AREP, N, N);	// repeat
+				gins(ASTOSQ, N, N);	// STOQ AL,*(DI)+
+			}
+
+			c = w % 8;
+			if(c > 0) {
+				gconreg(AMOVQ, c, D_CX);
+				gins(AREP, N, N);	// repeat
+				gins(ASTOSB, N, N);	// STOB AL,*(DI)+
+			}
+			return;
+		}
+
+		/* invent a "zero" for the rhs */
+		nr = &nc;
+		memset(nr, 0, sizeof(*nr));
+		switch(tl->etype) {
+		default:
+			fatal("cgen_as: tl %T", tl);
+			break;
+
+		case TINT8:
+		case TUINT8:
+		case TINT16:
+		case TUINT16:
+		case TINT32:
+		case TUINT32:
+		case TINT64:
+		case TUINT64:
+			nr->val.ctype = CTINT;
+			nr->val.vval = 0;
+			break;
+
+		case TFLOAT32:
+		case TFLOAT64:
+		case TFLOAT80:
+			nr->val.ctype = CTFLT;
+			nr->val.dval = 0.0;
+			break;
+
+		case TBOOL:
+			nr->val.ctype = CTBOOL;
+			nr->val.vval = 0;
+			break;
+
+		case TPTR32:
+		case TPTR64:
+			if(isptrto(nl->type, TSTRING)) {
+				nr->val.ctype = CTSTR;
+				nr->val.sval = &emptystring;
+				break;
+			}
+			nr->val.ctype = CTNIL;
+			nr->val.vval = 0;
+			break;
+
+//		case TINTER:
+//			nodreg(&n1, types[tptr], D_DI);
+//			agen(nl, &n1);
+//			n1.op = OINDREG;
+//
+//			nodreg(&nc, types[tptr], D_AX);
+//			gconreg(AMOVQ, 0, D_AX);
+//
+//			gins(AMOVQ, &nc, &n1);
+//			n1.xoffset += widthptr;
+//			gins(AMOVQ, &nc, &n1);
+//			return;
+
+		}
+		nr->op = OLITERAL;
+		nr->type = tl;
+		nr->addable = 1;
+		ullmancalc(nr);
+	}
+	cgen(nr, nl);
+}
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
new file mode 100644
index 0000000..5cd31b4
--- /dev/null
+++ b/src/cmd/6g/gg.h
@@ -0,0 +1,203 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+#include <u.h>
+#include <libc.h>
+
+#include "../gc/go.h"
+#include "../6l/6.out.h"
+
+#ifndef	EXTERN
+#define EXTERN	extern
+#endif
+
+typedef	struct	Prog	Prog;
+typedef	struct	Addr	Addr;
+
+struct	Addr
+{
+	vlong	offset;
+	double	dval;
+	Prog*	branch;
+	char	sval[NSNAME];
+
+	Sym*	sym;
+	uchar	type;
+	uchar	index;
+	uchar	etype;
+	uchar	scale;	/* doubles as width in DATA op */
+};
+#define	A	((Addr*)0)
+
+struct	Prog
+{
+	short	as;		// opcode
+	ulong	loc;		// pc offset in this func
+	ulong	lineno;		// source line that generated this
+	Addr	from;		// src address
+	Addr	to;		// dst address
+	Prog*	link;		// next instruction in this func
+};
+#define	P	((Prog*)0)
+
+typedef	struct	Plist	Plist;
+struct	Plist
+{
+	Node*	name;
+	Dcl*	locals;
+	Prog*	firstpc;
+	int	recur;
+	Plist*	link;
+};
+
+typedef	struct	Sig	Sig;
+struct Sig
+{
+	char*	name;
+	Sym*	sym;
+	ulong	hash;
+	long	offset;
+	Sig*	link;
+};
+
+typedef	struct	Case Case;
+struct	Case
+{
+	Prog*	sprog;
+	Node*	scase;
+	Case*	slink;
+};
+#define	C	((Case*)0)
+
+typedef	struct	Pool Pool;
+struct	Pool
+{
+	String*	sval;
+	Pool*	link;
+};
+
+EXTERN	Prog*	continpc;
+EXTERN	Prog*	breakpc;
+EXTERN	Prog*	pc;
+EXTERN	Prog*	firstpc;
+EXTERN	Plist*	plist;
+EXTERN	Plist*	plast;
+EXTERN	Pool*	poolist;
+EXTERN	Pool*	poolast;
+EXTERN	Biobuf*	bout;
+EXTERN	long	dynloc;
+EXTERN	uchar	reg[D_NONE];
+EXTERN	ushort	txt[NTYPE*NTYPE];
+EXTERN	long	maxround;
+EXTERN	long	widthptr;
+EXTERN	long	maxarg;
+EXTERN	long	stksize;
+EXTERN	Sym*	symstringo;	// string objects
+EXTERN	long	stringo;	// size of string objects
+EXTERN	long	pcloc;		// instruction counter
+EXTERN	String	emptystring;
+extern	char*	anames[];
+
+/*
+ * gen.c
+ */
+void	compile(Node*);
+void	proglist(void);
+void	gen(Node*);
+void	swgen(Node*);
+Node*	lookdot(Node*, Node*, int);
+void	inarggen(void);
+void	agen_inter(Node*, Node*);
+void	cgen_as(Node*, Node*, int);
+void	cgen_asop(Node*, Node*, int);
+void	cgen_ret(Node*);
+void	cgen_call(Node*);
+void	cgen_callmeth(Node*);
+void	cgen_callinter(Node*, Node*);
+void	cgen_callret(Node*, Node*);
+void	genpanic(void);
+int	needconvert(Type*, Type*);
+void	genconv(Type*, Type*);
+void	allocparams(void);
+
+/*
+ * cgen
+ */
+void	cgen(Node*, Node*);
+void	agen(Node*, Node*);
+void	igen(Node*, Node*, Node*);
+vlong	fieldoffset(Type*, Node*);
+void	bgen(Node*, int, Prog*);
+void	sgen(Node*, Node*, ulong);
+void	gmove(Node*, Node*);
+Prog*	gins(int, Node*, Node*);
+int	samaddr(Node*, Node*);
+void	naddr(Node*, Addr*);
+
+/*
+ * gsubr.c
+ */
+void	clearp(Prog*);
+void	proglist(void);
+Prog*	gbranch(int, Type*);
+void	patch(Prog*, Prog*);
+Prog*	prog(int);
+void	gaddoffset(Node*);
+void	gconv(int, int);
+int	conv2pt(Type*);
+void	belexinit(int);
+vlong	convvtox(vlong, int);
+int	brcom(int);
+int	brrev(int);
+void	fnparam(Type*, int, int);
+Sig*	lsort(Sig*, int(*)(Sig*, Sig*));
+Prog*	gop(int, Node*, Node*, Node*);
+void	setconst(Addr*, vlong);
+void	setaddr(Addr*, Node*);
+int	optoas(int, Type*);
+void	ginit(void);
+void	gclean(void);
+void	regalloc(Node*, Type*, Node*);
+void	regfree(Node*);
+void	regsalloc(Node*, Type*);	// replace w tmpvar
+void	regret(Node*, Type*);
+Node*	nodarg(Type*, int);
+void	nodreg(Node*, Type*, int);
+void	nodindreg(Node*, Type*, int);
+void	nodconst(Node*, Type*, vlong);
+Sym*	signame(Type*);
+void	nodtypesig(Node*, Type*);
+void	gconreg(int, vlong, int);
+void	buildtxt(void);
+void	stringpool(Node*);
+void	tempname(Node*, Type*);
+Plist*	newplist(void);
+int	isfat(Type*);
+void	setmaxarg(Type*);
+
+/*
+ * list.c
+ */
+int	Aconv(Fmt*);
+int	Dconv(Fmt*);
+int	Pconv(Fmt*);
+int	Rconv(Fmt*);
+int	Yconv(Fmt*);
+void	listinit(void);
+
+/*
+ * obj
+ */
+void	zname(Biobuf*, Sym*, int);
+void	zaddr(Biobuf*, Addr*, int);
+void	ieeedtod(Ieee*, double);
+void	dumpstrings(void);
+void	dumpsignatures(void);
+
+/*
+ * align
+ */
+void	dowidth(Type*);
+ulong	rnd(ulong, ulong);
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
new file mode 100644
index 0000000..9ced8fe
--- /dev/null
+++ b/src/cmd/6g/gsubr.c
@@ -0,0 +1,1649 @@
+// Derived from Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gg.h"
+
+void
+clearp(Prog *p)
+{
+	p->as = AEND;
+	p->from.type = D_NONE;
+	p->from.index = D_NONE;
+	p->to.type = D_NONE;
+	p->to.index = D_NONE;
+	p->loc = pcloc;
+	pcloc++;
+}
+
+Prog*
+prog(int as)
+{
+	Prog *p;
+
+	p = pc;
+	pc = mal(sizeof(*pc));
+
+	clearp(pc);
+
+	p->as = as;
+	p->lineno = dynlineno;
+	p->link = pc;
+	return p;
+}
+
+Prog*
+gbranch(int as, Type *t)
+{
+	Prog *p;
+
+	p = prog(as);
+	p->to.type = D_BRANCH;
+	p->to.branch = P;
+	return p;
+}
+
+void
+patch(Prog *p, Prog *to)
+{
+	if(p->to.type != D_BRANCH)
+		fatal("patch: not a branch");
+	p->to.branch = to;
+	p->to.offset = to->loc;
+}
+
+Plist*
+newplist(void)
+{
+	Plist *pl;
+
+	pl = mal(sizeof(*pl));
+	if(plist == nil)
+		plist = pl;
+	else
+		plast->link = pl;
+	plast = pl;
+
+	pc = mal(sizeof(*pc));
+	clearp(pc);
+	pl->firstpc = pc;
+
+	return pl;
+}
+
+void
+ginit(void)
+{
+	int i;
+
+	for(i=0; i<nelem(reg); i++)
+		reg[i] = 1;
+	for(i=D_AX; i<=D_R15; i++)
+		reg[i] = 0;
+	for(i=D_X0; i<=D_X7; i++)
+		reg[i] = 0;
+	reg[D_SP]++;
+}
+
+void
+gclean(void)
+{
+	int i;
+
+	reg[D_SP]--;
+	for(i=D_AX; i<=D_R15; i++)
+		if(reg[i])
+			yyerror("reg %R left allocated\n", i);
+	for(i=D_X0; i<=D_X7; i++)
+		if(reg[i])
+			yyerror("reg %R left allocated\n", i);
+}
+
+void
+regalloc(Node *n, Type *t, Node *o)
+{
+	int i;
+
+	if(t == T)
+		fatal("regalloc: t nil");
+
+	switch(t->etype) {
+	case TINT8:
+	case TUINT8:
+	case TINT16:
+	case TUINT16:
+	case TINT32:
+	case TUINT32:
+	case TINT64:
+	case TUINT64:
+	case TPTR32:
+	case TPTR64:
+	case TBOOL:
+		if(o != N && o->op == OREGISTER) {
+			i = o->val.vval;
+			if(i >= D_AX && i <= D_R15)
+				goto out;
+		}
+		for(i=D_AX; i<=D_R15; i++)
+			if(reg[i] == 0)
+				goto out;
+
+		yyerror("out of fixed registers");
+		goto err;
+
+	case TFLOAT32:
+	case TFLOAT64:
+	case TFLOAT80:
+		if(o != N && o->op == OREGISTER) {
+			i = o->val.vval;
+			if(i >= D_X0 && i <= D_X7)
+				goto out;
+		}
+		for(i=D_X0; i<=D_X7; i++)
+			if(reg[i] == 0)
+				goto out;
+		yyerror("out of floating registers");
+		goto err;
+	}
+	yyerror("regalloc: unknown type %T", t);
+
+err:
+	nodreg(n, t, 0);
+	return;
+
+out:
+	reg[i]++;
+	nodreg(n, t, i);
+}
+
+void
+regfree(Node *n)
+{
+	int i;
+
+	if(n->op != OREGISTER && n->op != OINDREG)
+		fatal("regfree: not a register");
+	i = n->val.vval;
+	if(i < 0 || i >= sizeof(reg))
+		fatal("regfree: reg out of range");
+	if(reg[i] <= 0)
+		fatal("regfree: reg not allocated");
+	reg[i]--;
+}
+
+void
+regret(Node *n, Type *t)
+{
+	if(t == T)
+		fatal("regret: t nil");
+	fatal("regret");
+}
+
+void
+nodreg(Node *n, Type *t, int r)
+{
+	if(t == T)
+		fatal("nodreg: t nil");
+
+	memset(n, 0, sizeof(*n));
+	n->op = OREGISTER;
+	n->addable = 1;
+	ullmancalc(n);
+	n->val.vval = r;
+	n->type = t;
+}
+
+void
+nodindreg(Node *n, Type *t, int r)
+{
+	nodreg(n, t, r);
+	n->op = OINDREG;
+}
+
+Node*
+nodarg(Type *t, int fp)
+{
+	Node *n;
+
+	if(t->etype != TFIELD)
+		fatal("nodarg: not field %T", t);
+
+	n = nod(ONAME, N, N);
+	n->type = t->type;
+	n->sym = t->sym;
+	n->xoffset = t->width;
+	n->addable = 1;
+
+	switch(fp) {
+	case 0:		// output arg
+		n->op = OINDREG;
+		n->val.vval = D_SP;
+		break;
+
+	case 1:		// input arg
+		n->class = PPARAM;
+		break;
+
+	case 2:		// offset output arg
+fatal("shpuldnt be used");
+		n->op = OINDREG;
+		n->val.vval = D_SP;
+		n->xoffset += types[tptr]->width;
+		break;
+	}
+	return n;
+}
+
+void
+nodconst(Node *n, Type *t, vlong v)
+{
+	memset(n, 0, sizeof(*n));
+	n->op = OLITERAL;
+	n->addable = 1;
+	ullmancalc(n);
+	n->val.vval = v;
+	n->val.ctype = CTINT;
+	n->type = t;
+
+	switch(t->etype) {
+	case TFLOAT32:
+	case TFLOAT64:
+	case TFLOAT80:
+		fatal("nodconst: bad type %T", t);
+
+	case TPTR32:
+	case TPTR64:
+	case TUINT8:
+	case TUINT16:
+	case TUINT32:
+	case TUINT64:
+		n->val.ctype = CTUINT;
+		break;
+	}
+}
+
+Sym*
+signame(Type *t)
+{
+	Sym *s;
+	char *e;
+
+loop:
+	if(t == T)
+		fatal("signame: nil type");
+
+	switch(t->etype) {
+	default:
+		fatal("signame: unknown type %T", t);
+
+	case TPTR32:
+	case TPTR64:
+		t = t->type;
+		goto loop;
+	case TSTRUCT:
+		e = "sigs";
+		break;
+	case TINTER:
+		e = "sigi";
+		break;
+	}
+
+	s = t->sym;
+	if(s == S)
+		fatal("nodtypesig: no sym for type");
+
+	snprint(namebuf, sizeof(namebuf), "%s_%s", e, s->name);
+	s = pkglookup(namebuf, s->package);
+	return s;
+}
+
+void
+nodtypesig(Node *n, Type *t)
+{
+	memset(n, 0, sizeof(*n));
+	n->op = ONAME;
+	n->type = types[TUINT8];
+	n->etype = TUINT8;
+	n->xoffset = 0;
+	n->sym = signame(t);
+	n->class = PEXTERN;
+	n->addable = 1;
+	n->ullman = 0;
+}
+
+void
+gconreg(int as, vlong c, int reg)
+{
+	Node n1, n2;
+
+	nodconst(&n1, types[TINT64], c);
+	nodreg(&n2, types[TINT64], reg);
+	gins(as, &n1, &n2);
+}
+
+#define	CASE(a,b)	(((a)<<16)|((b)<<0))
+
+void
+gmove(Node *f, Node *t)
+{
+	int ft, tt, t64, a;
+	Node nod, nod1, nod2, nod3, nodc;
+	Prog *p1, *p2;
+
+	ft = f->type->etype;
+	tt = t->type->etype;
+
+	t64 = 0;
+	if(tt == TINT64 || tt == TUINT64 || tt == TPTR64)
+		t64 = 1;
+
+	if(debug['M'])
+		print("gop: %O %O[%E],%O[%E]\n", OAS,
+			f->op, ft, t->op, tt);
+	if(isfloat[ft] && f->op == OCONST) {
+		/* TO DO: pick up special constants, possibly preloaded */
+		if(f->val.dval == 0.0){
+			regalloc(&nod, t->type, t);
+			gins(AXORPD, &nod, &nod);
+			gmove(&nod, t);
+			regfree(&nod);
+			return;
+		}
+	}
+/*
+ * load
+ */
+	if(f->op == ONAME || f->op == OINDREG ||
+	   f->op == OIND || f->op == OINDEX)
+	switch(ft) {
+	case TINT8:
+		a = AMOVBLSX;
+		if(t64)
+			a = AMOVBQSX;
+		goto ld;
+	case TBOOL:
+	case TUINT8:
+		a = AMOVBLZX;
+		if(t64)
+			a = AMOVBQZX;
+		goto ld;
+	case TINT16:
+		a = AMOVWLSX;
+		if(t64)
+			a = AMOVWQSX;
+		goto ld;
+	case TUINT16:
+		a = AMOVWLZX;
+		if(t64)
+			a = AMOVWQZX;
+		goto ld;
+	case TINT32:
+		if(isfloat[tt]) {
+			regalloc(&nod, t->type, t);
+			if(tt == TFLOAT64)
+				a = ACVTSL2SD;
+			else
+				a = ACVTSL2SS;
+			gins(a, f, &nod);
+			gmove(&nod, t);
+			regfree(&nod);
+			return;
+		}
+		a = AMOVL;
+		if(t64)
+			a = AMOVLQSX;
+		goto ld;
+	case TUINT32:
+	case TPTR32:
+		a = AMOVL;
+		if(t64)
+			a = AMOVLQZX;	/* could probably use plain MOVL */
+		goto ld;
+	case TINT64:
+		if(isfloat[tt]) {
+			regalloc(&nod, t->type, t);
+			if(tt == TFLOAT64)
+				a = ACVTSQ2SD;
+			else
+				a = ACVTSQ2SS;
+			gins(a, f, &nod);
+			gmove(&nod, t);
+			regfree(&nod);
+			return;
+		}
+	case TUINT64:
+	case TPTR64:
+		a = AMOVQ;
+
+	ld:
+		regalloc(&nod, f->type, t);
+		nod.type = t64? types[TINT64]: types[TINT32];
+		gins(a, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+	case TFLOAT32:
+		a = AMOVSS;
+		goto fld;
+	case TFLOAT64:
+		a = AMOVSD;
+	fld:
+		regalloc(&nod, f->type, t);
+		if(tt != TFLOAT64 && tt != TFLOAT32){	/* TO DO: why is this here */
+			dump("odd tree", f);
+			nod.type = t64? types[TINT64]: types[TINT32];
+		}
+		gins(a, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+	}
+
+/*
+ * store
+ */
+	if(t->op == ONAME || t->op == OINDREG ||
+	   t->op == OIND || t->op == OINDEX)
+	switch(tt) {
+	case TBOOL:
+	case TINT8:
+	case TUINT8:
+		a = AMOVB;
+		goto st;
+	case TINT16:
+	case TUINT16:
+		a = AMOVW;
+		goto st;
+	case TINT32:
+	case TUINT32:
+	case TPTR32:
+		a = AMOVL;
+		goto st;
+	case TINT64:
+	case TUINT64:
+	case TPTR64:
+		a = AMOVQ;
+		goto st;
+
+	st:
+		if(f->op == OCONST) {
+			gins(a, f, t);
+			return;
+		}
+	fst:
+		regalloc(&nod, t->type, f);
+		gmove(f, &nod);
+		gins(a, &nod, t);
+		regfree(&nod);
+		return;
+
+	case TFLOAT32:
+		a = AMOVSS;
+		goto fst;
+	case TFLOAT64:
+		a = AMOVSD;
+		goto fst;
+	}
+
+/*
+ * convert
+ */
+	switch(CASE(ft, tt)) {
+	default:
+/*
+ * integer to integer
+ ********
+		a = AGOK;	break;
+
+	case CASE(TBOOL, TBOOL):
+	case CASE(TINT8, TBOOL):
+	case CASE(TUINT8, TBOOL):
+	case CASE(TINT16, TBOOL):
+	case CASE(TUINT16, TBOOL):
+	case CASE(TINT32, TBOOL):
+	case CASE(TUINT32, TBOOL):
+	case CASE(TPTR64, TBOOL):
+
+	case CASE(TBOOL, TINT8):
+	case CASE(TINT8, TINT8):
+	case CASE(TUINT8, TINT8):
+	case CASE(TINT16, TINT8):
+	case CASE(TUINT16, TINT8):
+	case CASE(TINT32, TINT8):
+	case CASE(TUINT32, TINT8):
+	case CASE(TPTR64, TINT8):
+
+	case CASE(TBOOL, TUINT8):
+	case CASE(TINT8, TUINT8):
+	case CASE(TUINT8, TUINT8):
+	case CASE(TINT16, TUINT8):
+	case CASE(TUINT16, TUINT8):
+	case CASE(TINT32, TUINT8):
+	case CASE(TUINT32, TUINT8):
+	case CASE(TPTR64, TUINT8):
+
+	case CASE(TINT16, TINT16):
+	case CASE(TUINT16, TINT16):
+	case CASE(TINT32, TINT16):
+	case CASE(TUINT32, TINT16):
+	case CASE(TPTR64, TINT16):
+
+	case CASE(TINT16, TUINT16):
+	case CASE(TUINT16, TUINT16):
+	case CASE(TINT32, TUINT16):
+	case CASE(TUINT32, TUINT16):
+	case CASE(TPTR64, TUINT16):
+
+	case CASE(TINT64, TUINT):
+	case CASE(TINT64, TUINT32):
+	case CASE(TUINT64, TUINT32):
+ *****/
+		a = AMOVL;
+		break;
+
+	case CASE(TINT64, TINT8):
+	case CASE(TINT64, TINT16):
+	case CASE(TINT64, TINT32):
+	case CASE(TUINT64, TINT8):
+	case CASE(TUINT64, TINT16):
+	case CASE(TUINT64, TINT32):
+	case CASE(TINT32, TINT64):
+	case CASE(TINT32, TPTR64):
+		a = AMOVLQSX;
+		if(f->op == OCONST) {
+			f->val.vval &= (uvlong)0xffffffffU;
+			if(f->val.vval & 0x80000000)
+				f->val.vval |= (vlong)0xffffffff << 32;
+			a = AMOVQ;
+		}
+		break;
+
+	case CASE(TUINT32, TINT64):
+	case CASE(TUINT32, TUINT64):
+	case CASE(TUINT32, TPTR64):
+		a = AMOVL;	/* same effect as AMOVLQZX */
+		if(f->op == OCONST) {
+			f->val.vval &= (uvlong)0xffffffffU;
+			a = AMOVQ;
+		}
+		break;
+
+	case CASE(TPTR64, TINT64):
+	case CASE(TINT64, TINT64):
+	case CASE(TUINT64, TINT64):
+	case CASE(TINT64, TUINT64):
+	case CASE(TUINT64, TUINT64):
+	case CASE(TPTR64, TUINT64):
+	case CASE(TINT64, TPTR64):
+	case CASE(TUINT64, TPTR64):
+	case CASE(TPTR64, TPTR64):
+		a = AMOVQ;
+		break;
+
+	case CASE(TINT16, TINT32):
+	case CASE(TINT16, TUINT32):
+		a = AMOVWLSX;
+		if(f->op == OCONST) {
+			f->val.vval &= 0xffff;
+			if(f->val.vval & 0x8000)
+				f->val.vval |= 0xffff0000;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(TINT16, TINT64):
+	case CASE(TINT16, TUINT64):
+	case CASE(TINT16, TPTR64):
+		a = AMOVWQSX;
+		if(f->op == OCONST) {
+			f->val.vval &= 0xffff;
+			if(f->val.vval & 0x8000){
+				f->val.vval |= 0xffff0000;
+				f->val.vval |= (vlong)~0 << 32;
+			}
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(TUINT16, TINT32):
+	case CASE(TUINT16, TUINT32):
+		a = AMOVWLZX;
+		if(f->op == OCONST) {
+			f->val.vval &= 0xffff;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(TUINT16, TINT64):
+	case CASE(TUINT16, TUINT64):
+	case CASE(TUINT16, TPTR64):
+		a = AMOVWQZX;
+		if(f->op == OCONST) {
+			f->val.vval &= 0xffff;
+			a = AMOVL;	/* MOVL also zero-extends to 64 bits */
+		}
+		break;
+
+	case CASE(TINT8, TINT16):
+	case CASE(TINT8, TUINT16):
+	case CASE(TINT8, TINT32):
+	case CASE(TINT8, TUINT32):
+		a = AMOVBLSX;
+		if(f->op == OCONST) {
+			f->val.vval &= 0xff;
+			if(f->val.vval & 0x80)
+				f->val.vval |= 0xffffff00;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(TINT8, TINT64):
+	case CASE(TINT8, TUINT64):
+	case CASE(TINT8, TPTR64):
+		a = AMOVBQSX;
+		if(f->op == OCONST) {
+			f->val.vval &= 0xff;
+			if(f->val.vval & 0x80){
+				f->val.vval |= 0xffffff00;
+				f->val.vval |= (vlong)~0 << 32;
+			}
+			a = AMOVQ;
+		}
+		break;
+
+	case CASE(TBOOL, TINT16):
+	case CASE(TBOOL, TUINT16):
+	case CASE(TBOOL, TINT32):
+	case CASE(TBOOL, TUINT32):
+	case CASE(TUINT8, TINT16):
+	case CASE(TUINT8, TUINT16):
+	case CASE(TUINT8, TINT32):
+	case CASE(TUINT8, TUINT32):
+		a = AMOVBLZX;
+		if(f->op == OCONST) {
+			f->val.vval &= 0xff;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(TBOOL, TINT64):
+	case CASE(TBOOL, TUINT64):
+	case CASE(TBOOL, TPTR64):
+	case CASE(TUINT8, TINT64):
+	case CASE(TUINT8, TUINT64):
+	case CASE(TUINT8, TPTR64):
+		a = AMOVBQZX;
+		if(f->op == OCONST) {
+			f->val.vval &= 0xff;
+			a = AMOVL;	/* zero-extends to 64-bits */
+		}
+		break;
+
+/*
+ * float to fix
+ */
+	case CASE(TFLOAT32, TINT8):
+	case CASE(TFLOAT32, TINT16):
+	case CASE(TFLOAT32, TINT32):
+		regalloc(&nod, t->type, N);
+		gins(ACVTTSS2SL, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+	case CASE(TFLOAT32, TBOOL):
+	case CASE(TFLOAT32, TUINT8):
+	case CASE(TFLOAT32, TUINT16):
+	case CASE(TFLOAT32, TUINT32):
+	case CASE(TFLOAT32, TINT64):
+	case CASE(TFLOAT32, TUINT64):
+	case CASE(TFLOAT32, TPTR64):
+		regalloc(&nod, t->type, N);
+		gins(ACVTTSS2SQ, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+	case CASE(TFLOAT64, TINT8):
+	case CASE(TFLOAT64, TINT16):
+	case CASE(TFLOAT64, TINT32):
+		regalloc(&nod, t->type, N);
+		gins(ACVTTSD2SL, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+	case CASE(TFLOAT64, TBOOL):
+	case CASE(TFLOAT64, TUINT8):
+	case CASE(TFLOAT64, TUINT16):
+	case CASE(TFLOAT64, TUINT32):
+	case CASE(TFLOAT64, TINT64):
+	case CASE(TFLOAT64, TUINT64):
+	case CASE(TFLOAT64, TPTR64):
+		regalloc(&nod, t->type, N);
+		gins(ACVTTSD2SQ, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+/*
+ * ulong to float
+ */
+	case CASE(TUINT64, TFLOAT64):
+	case CASE(TUINT64, TFLOAT32):
+		a = ACVTSQ2SS;
+		if(tt == TFLOAT64)
+			a = ACVTSQ2SD;
+		regalloc(&nod, f->type, f);
+		gmove(f, &nod);
+		regalloc(&nod1, t->type, t);
+nodconst(&nodc, types[TUINT64], 0);
+		gins(ACMPQ, &nod, &nodc);
+		p1 = pc;
+		gins(AJLT, N, N);
+		gins(a, &nod, &nod1);
+		p2 = pc;
+		gins(AJMP, N, N);
+		patch(p1, pc);
+		regalloc(&nod2, f->type, N);
+		regalloc(&nod3, f->type, N);
+		gmove(&nod, &nod2);
+nodconst(&nodc, types[TUINT64], 1);
+		gins(ASHRQ, &nodc, &nod2);
+		gmove(&nod, &nod3);
+		gins(AANDL, &nodc, &nod3);
+		gins(AORQ, &nod3, &nod2);
+		gins(a, &nod2, &nod1);
+		gins(tt == TFLOAT64? AADDSD: AADDSS, &nod1, &nod1);
+		regfree(&nod2);
+		regfree(&nod3);
+		patch(p2, pc);
+		regfree(&nod);
+		regfree(&nod1);
+		return;
+
+	case CASE(TUINT32, TFLOAT64):
+	case CASE(TUINT32, TFLOAT32):
+		a = ACVTSQ2SS;
+		if(tt == TFLOAT64)
+			a = ACVTSQ2SD;
+		regalloc(&nod, f->type, f);
+		gins(AMOVLQZX, f, &nod);
+		regalloc(&nod1, t->type, t);
+		gins(a, &nod, &nod1);
+		gmove(&nod1, t);
+		regfree(&nod);
+		regfree(&nod1);
+		return;
+
+/*
+ * fix to float
+ */
+	case CASE(TINT64, TFLOAT32):
+	case CASE(TPTR64, TFLOAT32):
+		regalloc(&nod, t->type, t);
+		gins(ACVTSQ2SS, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+	case CASE(TINT64, TFLOAT64):
+	case CASE(TPTR64, TFLOAT64):
+		regalloc(&nod, t->type, t);
+		gins(ACVTSQ2SD, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+	case CASE(TBOOL, TFLOAT32):
+	case CASE(TINT8, TFLOAT32):
+	case CASE(TUINT8, TFLOAT32):
+	case CASE(TINT16, TFLOAT32):
+	case CASE(TUINT16, TFLOAT32):
+	case CASE(TINT32, TFLOAT32):
+		regalloc(&nod, t->type, t);
+		gins(ACVTSL2SS, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+	case CASE(TBOOL, TFLOAT64):
+	case CASE(TINT8, TFLOAT64):
+	case CASE(TUINT8, TFLOAT64):
+	case CASE(TINT16, TFLOAT64):
+	case CASE(TUINT16, TFLOAT64):
+	case CASE(TINT32, TFLOAT64):
+		regalloc(&nod, t->type, t);
+		gins(ACVTSL2SD, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+/*
+ * float to float
+ */
+	case CASE(TFLOAT32, TFLOAT32):
+		a = AMOVSS;
+		break;
+	case CASE(TFLOAT64, TFLOAT32):
+		a = ACVTSD2SS;
+		break;
+	case CASE(TFLOAT32, TFLOAT64):
+		a = ACVTSS2SD;
+		break;
+	case CASE(TFLOAT64, TFLOAT64):
+		a = AMOVSD;
+		break;
+	}
+	if(a == AMOVQ ||
+	   a == AMOVSD ||
+	   a == AMOVSS ||
+	   a == AMOVL && f->type->width == t->type->width)	/* TO DO: check AMOVL */
+		if(samaddr(f, t))
+			return;
+	gins(a, f, t);
+}
+
+void
+buildtxt(void)
+{
+	Type t1, t2;
+	int i, j, a;
+
+	memset(&t1, 0, sizeof(t1));
+	memset(&t2, 0, sizeof(t2));
+
+	for(i=0; i<NTYPE; i++)
+	for(j=0; j<NTYPE; j++) {
+		a = AGOK;
+		txt[i*NTYPE+j] = a;
+		t1.etype = i;
+		t2.etype = j;
+
+		if(isint[i] || isptr[i] || i==TBOOL) {
+			if(isint[j] || isptr[j] || j==TBOOL) {
+				dowidth(&t1);
+				dowidth(&t2);
+				if(t1.width >= t2.width) {
+					a = AMOVL;
+					if(t1.width >= 8)
+						a = AMOVQ;
+					txt[i*NTYPE+j] = a;
+					continue;
+				}
+				switch(i) {
+				case TINT8:
+					a = AMOVBLSX;
+					if(t1.width >= 8)
+						a = AMOVBQSX;
+					break;
+				case TINT16:
+					a = AMOVWLSX;
+					if(t1.width >= 8)
+						a = AMOVWQSX;
+					break;
+				case TINT32:
+					a = AMOVLQSX;
+					break;
+				case TBOOL:
+				case TUINT8:
+					a = AMOVBLZX;
+					if(t1.width >= 8)
+						a = AMOVBQZX;
+					break;
+				case TUINT16:
+					a = AMOVWLZX;
+					if(t1.width >= 8)
+						a = AMOVLQZX;
+					break;
+				case TPTR32:
+				case TUINT32:
+					a = AMOVWQZX;
+					break;
+				}
+				txt[i*NTYPE+j] = a;
+				continue;
+			}
+			if(isfloat[j]) {
+			}
+		}
+		if(isint[j] || isptr[j] || j==TBOOL) {
+			if(isfloat[i]) {
+			}
+		}
+	}
+}
+
+void
+regsalloc(Node *f, Type *t)
+{
+	fatal("regsalloc");
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+	if(f->op != t->op)
+		return 0;
+
+	switch(f->op) {
+	case OREGISTER:
+		if(f->val.vval != t->val.vval)
+			break;
+		return 1;
+	}
+	return 0;
+}
+
+Prog*
+gins(int as, Node *f, Node *t)
+{
+//	Node nod;
+//	long v;
+	Prog *p;
+
+//	if(f != N && f->op == OINDEX) {
+//		regalloc(&nod, &regnode, Z);
+//		v = constnode.vconst;
+//		cgen(f->right, &nod);
+//		constnode.vconst = v;
+//		idx.reg = nod.reg;
+//		regfree(&nod);
+//	}
+//	if(t != N && t->op == OINDEX) {
+//		regalloc(&nod, &regnode, Z);
+//		v = constnode.vconst;
+//		cgen(t->right, &nod);
+//		constnode.vconst = v;
+//		idx.reg = nod.reg;
+//		regfree(&nod);
+//	}
+
+	p = prog(as);
+	if(f != N)
+		naddr(f, &p->from);
+	if(t != N)
+		naddr(t, &p->to);
+	if(debug['g'])
+		print("%P\n", p);
+	return p;
+}
+
+void
+naddr(Node *n, Addr *a)
+{
+
+	a->type = D_NONE;
+	if(n == N)
+		return;
+
+	switch(n->op) {
+	default:
+		fatal("naddr: bad %O %D", n->op, a);
+		break;
+
+	case OREGISTER:
+		a->type = n->val.vval;
+		a->sym = S;
+		break;
+
+//	case OINDEX:
+//	case OIND:
+//		naddr(n->left, a);
+//		if(a->type >= D_AX && a->type <= D_DI)
+//			a->type += D_INDIR;
+//		else
+//		if(a->type == D_CONST)
+//			a->type = D_NONE+D_INDIR;
+//		else
+//		if(a->type == D_ADDR) {
+//			a->type = a->index;
+//			a->index = D_NONE;
+//		} else
+//			goto bad;
+//		if(n->op == OINDEX) {
+//			a->index = idx.reg;
+//			a->scale = n->scale;
+//		}
+//		break;
+
+	case OINDREG:
+		a->type = n->val.vval+D_INDIR;
+		a->sym = n->sym;
+		a->offset = n->xoffset;
+		break;
+
+	case ONAME:
+		a->etype = n->etype;
+		a->offset = n->xoffset;
+		a->sym = n->sym;
+		if(a->sym == S)
+			a->sym = lookup(".noname");
+
+		switch(n->class) {
+		default:
+			fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
+		case PEXTERN:
+			a->type = D_EXTERN;
+			break;
+		case PAUTO:
+			a->type = D_AUTO;
+			break;
+		case PPARAM:
+			a->type = D_PARAM;
+			break;
+		case PSTATIC:
+			a->type = D_STATIC;
+			break;
+		}
+		break;
+
+	case OLITERAL:
+		if(isfloat[n->type->etype]) {
+			a->type = D_FCONST;
+			a->dval = n->val.dval;
+			break;
+		}
+		if(isptrto(n->type, TSTRING)) {
+			a->etype = n->etype;
+			a->sym = symstringo;
+			a->type = D_ADDR;
+			a->index = D_STATIC;
+			a->offset = symstringo->offset;
+			stringpool(n);
+			break;
+		}
+		if(isint[n->type->etype] ||
+		   isptr[n->type->etype] ||
+		   n->type->etype == TBOOL) {
+			a->sym = S;
+			a->type = D_CONST;
+			a->offset = n->val.vval;
+			break;
+		}
+		fatal("naddr: const %lT", n->type);
+		break;
+
+//	case OADDR:
+//		naddr(n->left, a);
+//		if(a->type >= D_INDIR) {
+//			a->type -= D_INDIR;
+//			break;
+//		}
+//		if(a->type == D_EXTERN || a->type == D_STATIC ||
+//		   a->type == D_AUTO || a->type == D_PARAM)
+//			if(a->index == D_NONE) {
+//				a->index = a->type;
+//				a->type = D_ADDR;
+//				break;
+//			}
+//		goto bad;
+
+//	case OADD:
+//		if(n->right->op == OLITERAL) {
+//			v = n->right->vconst;
+//			naddr(n->left, a);
+//		} else
+//		if(n->left->op == OLITERAL) {
+//			v = n->left->vconst;
+//			naddr(n->right, a);
+//		} else
+//			goto bad;
+//		a->offset += v;
+//		break;
+
+	}
+}
+
+int
+optoas(int op, Type *t)
+{
+	int a;
+
+	if(t == T)
+		fatal("optoas: t is nil");
+
+	a = AGOK;
+	switch(CASE(op, t->etype)) {
+	default:
+		fatal("optoas: no entry %O-%T", op, t);
+		break;
+
+	case CASE(OADDR, TPTR32):
+		a = ALEAL;
+		break;
+
+	case CASE(OADDR, TPTR64):
+		a = ALEAQ;
+		break;
+
+	case CASE(OEQ, TBOOL):
+	case CASE(OEQ, TINT8):
+	case CASE(OEQ, TUINT8):
+	case CASE(OEQ, TINT16):
+	case CASE(OEQ, TUINT16):
+	case CASE(OEQ, TINT32):
+	case CASE(OEQ, TUINT32):
+	case CASE(OEQ, TINT64):
+	case CASE(OEQ, TUINT64):
+	case CASE(OEQ, TFLOAT32):
+	case CASE(OEQ, TFLOAT64):
+	case CASE(OEQ, TPTR32):
+	case CASE(OEQ, TPTR64):
+		a = AJEQ;
+		break;
+
+	case CASE(ONE, TBOOL):
+	case CASE(ONE, TINT8):
+	case CASE(ONE, TUINT8):
+	case CASE(ONE, TINT16):
+	case CASE(ONE, TUINT16):
+	case CASE(ONE, TINT32):
+	case CASE(ONE, TUINT32):
+	case CASE(ONE, TINT64):
+	case CASE(ONE, TUINT64):
+	case CASE(ONE, TFLOAT32):
+	case CASE(ONE, TFLOAT64):
+	case CASE(ONE, TPTR32):
+	case CASE(ONE, TPTR64):
+		a = AJNE;
+		break;
+
+	case CASE(OLT, TINT8):
+	case CASE(OLT, TINT16):
+	case CASE(OLT, TINT32):
+	case CASE(OLT, TINT64):
+	case CASE(OLT, TFLOAT32):
+	case CASE(OLT, TFLOAT64):
+		a = AJLT;
+		break;
+
+	case CASE(OLT, TUINT8):
+	case CASE(OLT, TUINT16):
+	case CASE(OLT, TUINT32):
+	case CASE(OLT, TUINT64):
+		a = AJCS;
+		break;
+
+	case CASE(OLE, TINT8):
+	case CASE(OLE, TINT16):
+	case CASE(OLE, TINT32):
+	case CASE(OLE, TINT64):
+	case CASE(OLE, TFLOAT32):
+	case CASE(OLE, TFLOAT64):
+		a = AJLE;
+		break;
+
+	case CASE(OLE, TUINT8):
+	case CASE(OLE, TUINT16):
+	case CASE(OLE, TUINT32):
+	case CASE(OLE, TUINT64):
+		a = AJLS;
+		break;
+
+	case CASE(OGT, TINT8):
+	case CASE(OGT, TINT16):
+	case CASE(OGT, TINT32):
+	case CASE(OGT, TINT64):
+	case CASE(OGT, TFLOAT32):
+	case CASE(OGT, TFLOAT64):
+		a = AJGT;
+		break;
+
+	case CASE(OGT, TUINT8):
+	case CASE(OGT, TUINT16):
+	case CASE(OGT, TUINT32):
+	case CASE(OGT, TUINT64):
+		a = AJHI;
+		break;
+
+	case CASE(OGE, TINT8):
+	case CASE(OGE, TINT16):
+	case CASE(OGE, TINT32):
+	case CASE(OGE, TINT64):
+	case CASE(OGE, TFLOAT32):
+	case CASE(OGE, TFLOAT64):
+		a = AJGE;
+		break;
+
+	case CASE(OGE, TUINT8):
+	case CASE(OGE, TUINT16):
+	case CASE(OGE, TUINT32):
+	case CASE(OGE, TUINT64):
+		a = AJCC;
+		break;
+
+	case CASE(OCMP, TBOOL):
+	case CASE(OCMP, TINT8):
+	case CASE(OCMP, TUINT8):
+		a = ACMPB;
+		break;
+
+	case CASE(OCMP, TINT16):
+	case CASE(OCMP, TUINT16):
+		a = ACMPW;
+		break;
+
+	case CASE(OCMP, TINT32):
+	case CASE(OCMP, TUINT32):
+	case CASE(OCMP, TPTR32):
+		a = ACMPL;
+		break;
+
+	case CASE(OCMP, TINT64):
+	case CASE(OCMP, TUINT64):
+	case CASE(OCMP, TPTR64):
+		a = ACMPQ;
+		break;
+
+	case CASE(OCMP, TFLOAT32):
+		a = AUCOMISS;
+		break;
+
+	case CASE(OCMP, TFLOAT64):
+		a = AUCOMISD;
+		break;
+
+	case CASE(OADD, TINT8):
+	case CASE(OADD, TUINT8):
+		a = AADDB;
+		break;
+
+	case CASE(OADD, TINT16):
+	case CASE(OADD, TUINT16):
+		a = AADDW;
+		break;
+
+	case CASE(OADD, TINT32):
+	case CASE(OADD, TUINT32):
+	case CASE(OADD, TPTR32):
+		a = AADDL;
+		break;
+
+	case CASE(OADD, TINT64):
+	case CASE(OADD, TUINT64):
+	case CASE(OADD, TPTR64):
+		a = AADDQ;
+		break;
+
+	case CASE(OADD, TFLOAT32):
+		a = AADDSS;
+		break;
+
+	case CASE(OADD, TFLOAT64):
+		a = AADDSD;
+		break;
+
+	case CASE(OSUB, TINT8):
+	case CASE(OSUB, TUINT8):
+		a = ASUBB;
+		break;
+
+	case CASE(OSUB, TINT16):
+	case CASE(OSUB, TUINT16):
+		a = ASUBW;
+		break;
+
+	case CASE(OSUB, TINT32):
+	case CASE(OSUB, TUINT32):
+	case CASE(OSUB, TPTR32):
+		a = ASUBL;
+		break;
+
+	case CASE(OSUB, TINT64):
+	case CASE(OSUB, TUINT64):
+	case CASE(OSUB, TPTR64):
+		a = ASUBQ;
+		break;
+
+	case CASE(OSUB, TFLOAT32):
+		a = ASUBSS;
+		break;
+
+	case CASE(OSUB, TFLOAT64):
+		a = ASUBSD;
+		break;
+
+	case CASE(OMINUS, TINT8):
+	case CASE(OMINUS, TUINT8):
+		a = ANEGB;
+		break;
+
+	case CASE(OMINUS, TINT16):
+	case CASE(OMINUS, TUINT16):
+		a = ANEGW;
+		break;
+
+	case CASE(OMINUS, TINT32):
+	case CASE(OMINUS, TUINT32):
+	case CASE(OMINUS, TPTR32):
+		a = ANEGL;
+		break;
+
+	case CASE(OMINUS, TINT64):
+	case CASE(OMINUS, TUINT64):
+	case CASE(OMINUS, TPTR64):
+		a = ANEGQ;
+		break;
+
+	case CASE(OMUL, TINT8):
+		a = AIMULB;
+		break;
+
+	case CASE(OMUL, TUINT8):
+		a = AMULB;
+		break;
+
+	case CASE(OMUL, TINT16):
+		a = AIMULW;
+		break;
+
+	case CASE(OMUL, TUINT16):
+		a = AMULW;
+		break;
+
+	case CASE(OMUL, TINT32):
+		a = AIMULL;
+		break;
+
+	case CASE(OMUL, TUINT32):
+	case CASE(OMUL, TPTR32):
+		a = AMULL;
+		break;
+
+	case CASE(OMUL, TINT64):
+		a = AIMULQ;
+		break;
+
+	case CASE(OMUL, TUINT64):
+	case CASE(OMUL, TPTR64):
+		a = AMULQ;
+		break;
+
+	case CASE(OMUL, TFLOAT32):
+		a = AMULSS;
+		break;
+
+	case CASE(OMUL, TFLOAT64):
+		a = AMULSD;
+		break;
+
+	case CASE(ODIV, TINT8):
+		a = AIDIVB;
+		break;
+
+	case CASE(ODIV, TUINT8):
+		a = ADIVB;
+		break;
+
+	case CASE(ODIV, TINT16):
+		a = AIDIVW;
+		break;
+
+	case CASE(ODIV, TUINT16):
+		a = ADIVW;
+		break;
+
+	case CASE(ODIV, TINT32):
+		a = AIDIVL;
+		break;
+
+	case CASE(ODIV, TUINT32):
+	case CASE(ODIV, TPTR32):
+		a = ADIVL;
+		break;
+
+	case CASE(ODIV, TINT64):
+		a = AIDIVQ;
+		break;
+
+	case CASE(ODIV, TUINT64):
+	case CASE(ODIV, TPTR64):
+		a = ADIVQ;
+		break;
+
+	case CASE(ODIV, TFLOAT32):
+		a = ADIVSS;
+		break;
+
+	case CASE(ODIV, TFLOAT64):
+		a = ADIVSD;
+		break;
+
+	}
+	return a;
+}
+
+int
+isfat(Type *t)
+{
+	if(t != T)
+	switch(t->etype) {
+	case TSTRUCT:
+	case TARRAY:
+	case TDARRAY:
+	case TINTER:	// maybe remove later
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * return unsigned(op)
+ * eg GT -> HS
+ */
+int
+brunsigned(int a)
+{
+	switch(a) {
+	case AJLT:	return AJGE;
+	case AJGT:	return AJLE;
+	case AJLE:	return AJGT;
+	case AJGE:	return AJLT;
+	}
+	return a;
+}
+
+/*
+ * return !(op)
+ * eg == <=> !=
+ */
+int
+brcom(int a)
+{
+	switch(a) {
+	case OEQ:	return ONE;
+	case ONE:	return OEQ;
+	case OLT:	return OGE;
+	case OGT:	return OLE;
+	case OLE:	return OGT;
+	case OGE:	return OLT;
+	}
+	fatal("brcom: no com for %A\n", a);
+	return a;
+}
+
+/*
+ * return reverse(op)
+ * eg a op b <=> b r(op) a
+ */
+int
+brrev(int a)
+{
+	switch(a) {
+	case OEQ:	return OEQ;
+	case ONE:	return ONE;
+	case OLT:	return OGT;
+	case OGT:	return OLT;
+	case OLE:	return OGE;
+	case OGE:	return OLE;
+	}
+	fatal("brcom: no rev for %A\n", a);
+	return a;
+}
+
+/*
+ * make a new off the books
+ */
+void
+tempname(Node *n, Type *t)
+{
+	Sym *s;
+	ulong w;
+
+	if(t == T) {
+		yyerror("tempname called with nil type");
+		t = types[TINT32];
+	}
+
+	s = lookup("!tmpname!");
+
+	memset(n, 0, sizeof(*n));
+	n->op = ONAME;
+	n->sym = s;
+	n->type = t;
+	n->sym = s;
+	n->etype = t->etype;
+	n->class = PAUTO;
+	n->addable = 1;
+	n->ullman = 0;
+
+	dowidth(t);
+	w = t->width;
+	stksize += w;
+	stksize = rnd(stksize, w);
+	n->xoffset = -stksize;
+}
+
+void
+stringpool(Node *n)
+{
+	Pool *p;
+	int w;
+
+	if(n->op != OLITERAL || n->val.ctype != CTSTR)
+		fatal("stringpool: not string");
+
+	p = mal(sizeof(*p));
+
+	p->sval = n->val.sval;
+	p->link = nil;
+
+	if(poolist == nil)
+		poolist = p;
+	else
+		poolast->link = p;
+	poolast = p;
+
+	w = types[TINT32]->width;
+	symstringo->offset += w;		// len
+	symstringo->offset += p->sval->len;	// str[len]
+	symstringo->offset = rnd(symstringo->offset, w);
+}
+
+Sig*
+lsort(Sig *l, int(*f)(Sig*, Sig*))
+{
+	Sig *l1, *l2, *le;
+
+	if(l == 0 || l->link == 0)
+		return l;
+
+	l1 = l;
+	l2 = l;
+	for(;;) {
+		l2 = l2->link;
+		if(l2 == 0)
+			break;
+		l2 = l2->link;
+		if(l2 == 0)
+			break;
+		l1 = l1->link;
+	}
+
+	l2 = l1->link;
+	l1->link = 0;
+	l1 = lsort(l, f);
+	l2 = lsort(l2, f);
+
+	/* set up lead element */
+	if((*f)(l1, l2) < 0) {
+		l = l1;
+		l1 = l1->link;
+	} else {
+		l = l2;
+		l2 = l2->link;
+	}
+	le = l;
+
+	for(;;) {
+		if(l1 == 0) {
+			while(l2) {
+				le->link = l2;
+				le = l2;
+				l2 = l2->link;
+			}
+			le->link = 0;
+			break;
+		}
+		if(l2 == 0) {
+			while(l1) {
+				le->link = l1;
+				le = l1;
+				l1 = l1->link;
+			}
+			break;
+		}
+		if((*f)(l1, l2) < 0) {
+			le->link = l1;
+			le = l1;
+			l1 = l1->link;
+		} else {
+			le->link = l2;
+			le = l2;
+			l2 = l2->link;
+		}
+	}
+	le->link = 0;
+	return l;
+}
+
+void
+setmaxarg(Type *t)
+{
+	Type *to;
+	long w;
+
+	to = *getoutarg(t);
+	w = to->width;
+	if(w > maxarg)
+		maxarg = w;
+}
diff --git a/src/cmd/6g/list.c b/src/cmd/6g/list.c
new file mode 100644
index 0000000..361eb3c
--- /dev/null
+++ b/src/cmd/6g/list.c
@@ -0,0 +1,336 @@
+// Derived from Inferno utils/6c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gg.h"
+
+static	int	sconsize;
+void
+listinit(void)
+{
+
+	fmtinstall('A', Aconv);		// as
+	fmtinstall('P', Pconv);		// Prog*
+	fmtinstall('D', Dconv);		// Addr*
+	fmtinstall('R', Rconv);		// reg
+	fmtinstall('Y', Yconv);		// sconst
+}
+
+int
+Pconv(Fmt *fp)
+{
+	char str[STRINGSZ];
+	Prog *p;
+
+	p = va_arg(fp->args, Prog*);
+	sconsize = 8;
+	if(p->as == ADATA) {
+		sconsize = p->from.scale;
+		snprint(str, sizeof(str), "%.4ld %-7A %D/%d,%D",
+			p->loc, p->as, &p->from, sconsize, &p->to);
+		return fmtstrcpy(fp, str);
+	}
+	snprint(str, sizeof(str), "%.4ld %-7A %D,%D",
+		p->loc, p->as, &p->from, &p->to);
+	return fmtstrcpy(fp, str);
+}
+
+int
+Dconv(Fmt *fp)
+{
+	char str[40], s[20];
+	Addr *a;
+	int i;
+
+	a = va_arg(fp->args, Addr*);
+	i = a->type;
+	if(i >= D_INDIR) {
+		if(a->offset)
+			sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
+		else
+			sprint(str, "(%R)", i-D_INDIR);
+		goto brk;
+	}
+	switch(i) {
+
+	default:
+		if(a->offset)
+			sprint(str, "$%lld,%R", a->offset, i);
+		else
+			sprint(str, "%R", i);
+		break;
+
+	case D_NONE:
+		str[0] = 0;
+		break;
+
+	case D_BRANCH:
+		snprint(str, sizeof(str), "%ld", a->branch->loc);
+		break;
+
+	case D_EXTERN:
+		sprint(str, "%S+%lld(SB)", a->sym, a->offset);
+		break;
+
+	case D_STATIC:
+		sprint(str, "%S<>+%lld(SB)", a->sym, a->offset);
+		break;
+
+	case D_AUTO:
+		sprint(str, "%S+%lld(SP)", a->sym, a->offset);
+		break;
+
+	case D_PARAM:
+		sprint(str, "%S+%lld(FP)", a->sym, a->offset);
+		break;
+
+	case D_CONST:
+		sprint(str, "$%lld", a->offset);
+		break;
+
+	case D_FCONST:
+		sprint(str, "$(%.17e)", a->dval);
+		break;
+
+	case D_SCONST:
+		sprint(str, "$\"%Y\"", a->sval);
+		break;
+
+	case D_ADDR:
+		a->type = a->index;
+		a->index = D_NONE;
+		sprint(str, "$%D", a);
+		a->index = a->type;
+		a->type = D_ADDR;
+		goto conv;
+	}
+brk:
+	if(a->index != D_NONE) {
+		sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
+		strcat(str, s);
+	}
+conv:
+	return fmtstrcpy(fp, str);
+}
+
+static	char*	regstr[] =
+{
+	"AL",		/* [D_AL] */
+	"CL",
+	"DL",
+	"BL",
+	"SPB",
+	"BPB",
+	"SIB",
+	"DIB",
+	"R8B",
+	"R9B",
+	"R10B",
+	"R11B",
+	"R12B",
+	"R13B",
+	"R14B",
+	"R15B",
+
+	"AX",		/* [D_AX] */
+	"CX",
+	"DX",
+	"BX",
+	"SP",
+	"BP",
+	"SI",
+	"DI",
+	"R8",
+	"R9",
+	"R10",
+	"R11",
+	"R12",
+	"R13",
+	"R14",
+	"R15",
+
+	"AH",
+	"CH",
+	"DH",
+	"BH",
+
+	"F0",		/* [D_F0] */
+	"F1",
+	"F2",
+	"F3",
+	"F4",
+	"F5",
+	"F6",
+	"F7",
+
+	"M0",
+	"M1",
+	"M2",
+	"M3",
+	"M4",
+	"M5",
+	"M6",
+	"M7",
+
+	"X0",
+	"X1",
+	"X2",
+	"X3",
+	"X4",
+	"X5",
+	"X6",
+	"X7",
+	"X8",
+	"X9",
+	"X10",
+	"X11",
+	"X12",
+	"X13",
+	"X14",
+	"X15",
+
+	"CS",		/* [D_CS] */
+	"SS",
+	"DS",
+	"ES",
+	"FS",
+	"GS",
+
+	"GDTR",		/* [D_GDTR] */
+	"IDTR",		/* [D_IDTR] */
+	"LDTR",		/* [D_LDTR] */
+	"MSW",		/* [D_MSW] */
+	"TASK",		/* [D_TASK] */
+
+	"CR0",		/* [D_CR] */
+	"CR1",
+	"CR2",
+	"CR3",
+	"CR4",
+	"CR5",
+	"CR6",
+	"CR7",
+	"CR8",
+	"CR9",
+	"CR10",
+	"CR11",
+	"CR12",
+	"CR13",
+	"CR14",
+	"CR15",
+
+	"DR0",		/* [D_DR] */
+	"DR1",
+	"DR2",
+	"DR3",
+	"DR4",
+	"DR5",
+	"DR6",
+	"DR7",
+
+	"TR0",		/* [D_TR] */
+	"TR1",
+	"TR2",
+	"TR3",
+	"TR4",
+	"TR5",
+	"TR6",
+	"TR7",
+
+	"NONE",		/* [D_NONE] */
+};
+
+int
+Rconv(Fmt *fp)
+{
+	char str[STRINGSZ];
+	int r;
+
+	r = va_arg(fp->args, int);
+	if(r < 0 || r >= nelem(regstr) || regstr[r] == nil) {
+		snprint(str, sizeof(str), "BAD_R(%d)", r);
+		return fmtstrcpy(fp, str);
+	}
+	return fmtstrcpy(fp, regstr[r]);
+}
+
+int
+Aconv(Fmt *fp)
+{
+	int i;
+
+	i = va_arg(fp->args, int);
+	return fmtstrcpy(fp, anames[i]);
+}
+
+
+int
+Yconv(Fmt *fp)
+{
+	int i, c;
+	char str[30], *p, *a;
+
+	a = va_arg(fp->args, char*);
+	p = str;
+	for(i=0; i<sconsize; i++) {
+		c = a[i] & 0xff;
+		if(c >= 'a' && c <= 'z' ||
+		   c >= 'A' && c <= 'Z' ||
+		   c >= '0' && c <= '9') {
+			*p++ = c;
+			continue;
+		}
+		*p++ = '\\';
+		switch(c) {
+		default:
+			if(c < 040 || c >= 0177)
+				break;	/* not portable */
+			p[-1] = c;
+			continue;
+		case 0:
+			*p++ = 'z';
+			continue;
+		case '\\':
+		case '"':
+			*p++ = c;
+			continue;
+		case '\n':
+			*p++ = 'n';
+			continue;
+		case '\t':
+			*p++ = 't';
+			continue;
+		}
+		*p++ = (c>>6) + '0';
+		*p++ = ((c>>3) & 7) + '0';
+		*p++ = (c & 7) + '0';
+	}
+	*p = 0;
+	return fmtstrcpy(fp, str);
+}
diff --git a/src/cmd/6g/obj.c b/src/cmd/6g/obj.c
new file mode 100644
index 0000000..47ae0ab
--- /dev/null
+++ b/src/cmd/6g/obj.c
@@ -0,0 +1,604 @@
+// Derived from Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gg.h"
+
+void
+dumpobj(void)
+{
+	Plist *pl;
+	Prog *p;
+	Dcl *d;
+	Sym *s;
+	Node *n;
+	struct { Sym *sym; short type; } h[NSYM];
+	int sf, st, t, sym;
+	Node n1;
+
+	// add nil plist w AEND
+	newplist();
+
+	bout = Bopen(outfile, OWRITE);
+	if(bout == nil)
+		fatal("cant open %s", outfile);
+
+	Bprint(bout, "x86-64\n");
+	Bprint(bout, "  exports automatically generated from\n");
+	Bprint(bout, "  %s in package \"%s\"\n", curio.infile, package);
+	dumpexport();
+	Bprint(bout, "\n!\n");
+
+	// add globals
+	nodconst(&n1, types[TINT32], 0);
+	for(d=externdcl; d!=D; d=d->forw) {
+		if(d->op != ONAME)
+			continue;
+
+		s = d->dsym;
+		if(s == S)
+			fatal("external nil");
+		n = d->dnode;
+		if(n == N || n->type == T)
+			fatal("external %S nil\n", s);
+
+		if(n->type->etype == TFUNC)
+			continue;
+
+		dowidth(n->type);
+		n1.val.vval = n->type->width;
+
+		p = pc;
+		gins(AGLOBL, s->oname, &n1);
+		p->lineno = s->oname->lineno;
+	}
+
+	dumpstrings();
+	dumpsignatures();
+
+	for(sym=0; sym<NSYM; sym++) {
+		h[sym].sym = S;
+		h[sym].type = 0;
+	}
+	sym = 1;
+
+	// put out functions
+	for(pl=plist; pl!=nil; pl=pl->link) {
+
+		if(debug['S']) {
+			s = S;
+			if(pl->name != N)
+				s = pl->name->sym;
+			print("\n--- prog list \"%S\" ---\n", s);
+			for(p=pl->firstpc; p!=P; p=p->link)
+				print("%P\n", p);
+		}
+
+		for(p=pl->firstpc; p!=P; p=p->link) {
+		jackpot:
+			sf = 0;
+			s = p->from.sym;
+			while(s != S) {
+				sf = s->sym;
+				if(sf < 0 || sf >= NSYM)
+					sf = 0;
+				t = p->from.type;
+				if(t == D_ADDR)
+					t = p->from.index;
+				if(h[sf].type == t)
+				if(h[sf].sym == s)
+					break;
+				s->sym = sym;
+				zname(bout, s, t);
+				h[sym].sym = s;
+				h[sym].type = t;
+				sf = sym;
+				sym++;
+				if(sym >= NSYM)
+					sym = 1;
+				break;
+			}
+			st = 0;
+			s = p->to.sym;
+			while(s != S) {
+				st = s->sym;
+				if(st < 0 || st >= NSYM)
+					st = 0;
+				t = p->to.type;
+				if(t == D_ADDR)
+					t = p->to.index;
+				if(h[st].type == t)
+				if(h[st].sym == s)
+					break;
+				s->sym = sym;
+				zname(bout, s, t);
+				h[sym].sym = s;
+				h[sym].type = t;
+				st = sym;
+				sym++;
+				if(sym >= NSYM)
+					sym = 1;
+				if(st == sf)
+					goto jackpot;
+				break;
+			}
+			Bputc(bout, p->as);
+			Bputc(bout, p->as>>8);
+			Bputc(bout, p->lineno);
+			Bputc(bout, p->lineno>>8);
+			Bputc(bout, p->lineno>>16);
+			Bputc(bout, p->lineno>>24);
+			zaddr(bout, &p->from, sf);
+			zaddr(bout, &p->to, st);
+		}
+	}
+}
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+	char *n;
+
+	Bputc(b, ANAME);	/* as */
+	Bputc(b, ANAME>>8);	/* as */
+	Bputc(b, t);		/* type */
+	Bputc(b, s->sym);	/* sym */
+
+	for(n=s->opackage; *n; n++)
+		Bputc(b, *n);
+	Bputc(b, '_');
+	for(n=s->name; *n; n++)
+		Bputc(b, *n);
+	Bputc(b, 0);
+}
+
+void
+zaddr(Biobuf *b, Addr *a, int s)
+{
+	long l;
+	int i, t;
+	char *n;
+	Ieee e;
+
+	t = 0;
+	if(a->index != D_NONE || a->scale != 0)
+		t |= T_INDEX;
+	if(s != 0)
+		t |= T_SYM;
+
+	switch(a->type) {
+	default:
+		t |= T_TYPE;
+	case D_NONE:
+		if(a->offset != 0) {
+			t |= T_OFFSET;
+			l = a->offset;
+			if((vlong)l != a->offset)
+				t |= T_64;
+		}
+		break;
+	case D_FCONST:
+		t |= T_FCONST;
+		break;
+	case D_SCONST:
+		t |= T_SCONST;
+		break;
+	}
+	Bputc(b, t);
+
+	if(t & T_INDEX) {	/* implies index, scale */
+		Bputc(b, a->index);
+		Bputc(b, a->scale);
+	}
+	if(t & T_OFFSET) {	/* implies offset */
+		l = a->offset;
+		Bputc(b, l);
+		Bputc(b, l>>8);
+		Bputc(b, l>>16);
+		Bputc(b, l>>24);
+		if(t & T_64) {
+			l = a->offset>>32;
+			Bputc(b, l);
+			Bputc(b, l>>8);
+			Bputc(b, l>>16);
+			Bputc(b, l>>24);
+		}
+	}
+	if(t & T_SYM)		/* implies sym */
+		Bputc(b, s);
+	if(t & T_FCONST) {
+		ieeedtod(&e, a->dval);
+		l = e.l;
+		Bputc(b, l);
+		Bputc(b, l>>8);
+		Bputc(b, l>>16);
+		Bputc(b, l>>24);
+		l = e.h;
+		Bputc(b, l);
+		Bputc(b, l>>8);
+		Bputc(b, l>>16);
+		Bputc(b, l>>24);
+		return;
+	}
+	if(t & T_SCONST) {
+		n = a->sval;
+		for(i=0; i<NSNAME; i++) {
+			Bputc(b, *n);
+			n++;
+		}
+		return;
+	}
+	if(t & T_TYPE)
+		Bputc(b, a->type);
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+	double fr, ho, f;
+	int exp;
+
+	if(native < 0) {
+		ieeedtod(ieee, -native);
+		ieee->h |= 0x80000000L;
+		return;
+	}
+	if(native == 0) {
+		ieee->l = 0;
+		ieee->h = 0;
+		return;
+	}
+	fr = frexp(native, &exp);
+	f = 2097152L;		/* shouldnt use fp constants here */
+	fr = modf(fr*f, &ho);
+	ieee->h = ho;
+	ieee->h &= 0xfffffL;
+	ieee->h |= (exp+1022L) << 20;
+	f = 65536L;
+	fr = modf(fr*f, &ho);
+	ieee->l = ho;
+	ieee->l <<= 16;
+	ieee->l |= (long)(fr*f);
+}
+
+void
+datastring(char *s, int len)
+{
+	int w;
+	Prog *p;
+	Addr ac, ao;
+
+	// string
+	memset(&ao, 0, sizeof(ao));
+	ao.type = D_STATIC;
+	ao.index = D_NONE;
+	ao.etype = TINT32;
+	ao.sym = symstringo;
+	ao.offset = 0;		// fill in
+
+	// constant
+	memset(&ac, 0, sizeof(ac));
+	ac.type = D_CONST;
+	ac.index = D_NONE;
+	ac.offset = 0;		// fill in
+
+	for(w=0; w<len; w+=8) {
+		p = pc;
+		gins(ADATA, N, N);
+
+		// .stringo<>+oo, [NSNAME], $"xxx"
+		p->from = ao;
+		p->from.offset = stringo;
+
+		p->from.scale = NSNAME;
+		if(w+8 > len)
+			p->from.scale = len-w;
+
+		p->to = ac;
+		p->to.type = D_SCONST;
+		p->to.offset = len;
+		memmove(p->to.sval, s+w, p->from.scale);
+		stringo += p->from.scale;
+	}
+}
+
+void
+dumpstrings(void)
+{
+	Pool *l;
+	Prog *p;
+	Addr ac, ao;
+	long wi;
+
+	if(poolist == nil)
+		return;
+
+	memset(&ac, 0, sizeof(ac));
+	memset(&ao, 0, sizeof(ao));
+
+	// constant
+	ac.type = D_CONST;
+	ac.index = D_NONE;
+	ac.offset = 0;			// fill in
+
+	// string len+ptr
+	ao.type = D_STATIC;
+	ao.index = D_NONE;
+	ao.etype = TINT32;
+	ao.sym = symstringo;
+	ao.offset = 0;			// fill in
+
+	wi = types[TINT32]->width;
+
+	// lay out (count+string)
+	for(l=poolist; l!=nil; l=l->link) {
+
+		p = pc;
+		gins(ADATA, N, N);
+
+		// .stringo<>+xx, wi, $len
+		stringo = rnd(stringo, wi);
+		p->from = ao;
+		p->from.offset = stringo;
+		p->from.scale = wi;
+		p->to = ac;
+		p->to.offset = l->sval->len;
+		stringo += wi;
+
+		datastring(l->sval->s, l->sval->len);
+	}
+}
+
+static int
+sigcmp(Sig *a, Sig *b)
+{
+	return strcmp(a->name, b->name);
+}
+
+void
+dumpsignatures(void)
+{
+	Dcl *d;
+	Type *t, *f;
+	Sym *s1, *s;
+	int et, o, wi, ot;
+	Sig *a, *b;
+	Addr at, ao, ac, ad;
+	Prog *p;
+	char *sp;
+
+	/*
+	 * put all the names into a linked
+	 * list so that it may be generated in sorted order.
+	 * the runtime will be linear rather than quadradic
+	 */
+
+	memset(&at, 0, sizeof(at));
+	memset(&ao, 0, sizeof(ao));
+	memset(&ac, 0, sizeof(ac));
+	memset(&ad, 0, sizeof(ad));
+
+	// sig structure
+	at.type = D_EXTERN;
+	at.index = D_NONE;
+	at.sym = S;			// fill in
+	at.offset = 0;			// fill in
+
+	// $string
+	ao.type = D_ADDR;
+	ao.index = D_STATIC;
+	ao.etype = TINT32;
+	ao.sym = symstringo;
+	ao.offset = 0;			// fill in
+
+	// constant
+	ac.type = D_CONST;
+	ac.index = D_NONE;
+	ac.offset = 0;			// fill in
+
+	// $method
+	ad.type = D_ADDR;
+	ad.index = D_EXTERN;
+	ad.sym = S;			// fill in
+	ad.offset = 0;
+
+	wi = types[TINT32]->width;
+
+	for(d=externdcl; d!=D; d=d->forw) {
+		if(d->op != OTYPE)
+			continue;
+
+		t = d->dtype;
+		et = t->etype;
+		if(et != TSTRUCT && et != TINTER)
+			continue;
+
+		s = d->dsym;
+		if(s == S)
+			continue;
+
+		if(s->name[0] == '_')
+			continue;
+
+		if(strcmp(s->opackage, package) != 0)
+			continue;
+
+		at.sym = signame(t);
+
+		a = nil;
+		o = 0;
+		for(f=t->type; f!=T; f=f->down) {
+			if(f->type->etype != TFUNC)
+				continue;
+
+			if(f->etype != TFIELD)
+				fatal("dumpsignatures: not field");
+
+			s1 = f->sym;
+			if(s1 == nil)
+				continue;
+			if(s1->name[0] == '_')
+				continue;
+
+			b = mal(sizeof(*b));
+			b->link = a;
+			a = b;
+
+			a->name = s1->name;
+			sp = strchr(s1->name, '_');
+			if(sp != nil)
+				a->name = sp+1;
+			
+			a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0);
+			a->sym = f->sym;
+			a->offset = o;
+			o++;
+		}
+
+		a = lsort(a, sigcmp);
+		ot = 0;
+
+		if(et == TINTER) {
+			o = 0;
+			for(b=a; b!=nil; b=b->link)
+				o++;
+
+			// sigi[0].name = ""
+			ot = rnd(ot, maxround);
+			p = pc;
+			gins(ADATA, N, N);
+			p->from = at;
+			p->from.offset = ot;
+			p->from.scale = widthptr;
+			p->to = ao;
+			p->to.offset = stringo;
+			ot += widthptr;
+
+			// sigi[0].hash = 0
+			ot = rnd(ot, wi);
+			p = pc;
+			gins(ADATA, N, N);
+			p->from = at;
+			p->from.offset = ot;
+			p->from.scale = wi;
+			p->to = ac;
+			p->to.offset = 0;
+			ot += wi;
+
+			// sigi[0].offset = count
+			ot = rnd(ot, wi);
+			p = pc;
+			gins(ADATA, N, N);
+			p->from = at;
+			p->from.offset = ot;
+			p->from.scale = wi;
+			p->to = ac;
+			p->to.offset = o;
+			ot += wi;
+
+			datastring("", 1);
+
+		}
+
+		for(b=a; b!=nil; b=b->link) {
+
+			// sigx[++].name = "fieldname"
+			ot = rnd(ot, maxround);
+			p = pc;
+			gins(ADATA, N, N);
+			p->from = at;
+			p->from.offset = ot;
+			p->from.scale = widthptr;
+			p->to = ao;
+			p->to.offset = stringo;
+			ot += widthptr;
+
+			// sigx[++].hash = hashcode
+			ot = rnd(ot, wi);
+			p = pc;
+			gins(ADATA, N, N);
+			p->from = at;
+			p->from.offset = ot;
+			p->from.scale = wi;
+			p->to = ac;
+			p->to.offset = b->hash;
+			ot += wi;
+
+			if(et == TINTER) {
+				// sigi[++].offset = offset of method
+				ot = rnd(ot, wi);
+				p = pc;
+				gins(ADATA, N, N);
+				p->from = at;
+				p->from.offset = ot;
+				p->from.scale = wi;
+				p->to = ac;
+				p->to.offset = b->offset;
+				ot += wi;
+			} else {
+				// sigs[++].fun = &method
+				ot = rnd(ot, widthptr);
+				p = pc;
+				gins(ADATA, N, N);
+				p->from = at;
+				p->from.offset = ot;
+				p->from.scale = widthptr;
+				p->to = ad;
+				p->to.sym = b->sym;
+				ot += widthptr;
+			}
+			datastring(b->name, strlen(b->name)+1);
+		}
+
+		// nil field name at end
+		ot = rnd(ot, maxround);
+		p = pc;
+		gins(ADATA, N, N);
+		p->from = at;
+		p->from.offset = ot;
+		p->from.scale = widthptr;
+		p->to = ac;
+		p->to.offset = 0;
+		ot += widthptr;
+
+		p = pc;
+		gins(AGLOBL, N, N);
+		p->from = at;
+		p->to = ac;
+		p->to.offset = ot;
+	}
+
+	if(stringo > 0) {
+		p = pc;
+		gins(AGLOBL, N, N);
+		p->from = ao;
+		p->to = ac;
+		p->to.offset = stringo;
+	}
+}
diff --git a/src/cmd/6g/runtime.c b/src/cmd/6g/runtime.c
new file mode 100644
index 0000000..482e013
--- /dev/null
+++ b/src/cmd/6g/runtime.c
@@ -0,0 +1,595 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+
+int32	debug	= 0;
+
+void
+sys_printbool(bool v)
+{
+	if(v) {
+		sys_write(1, (byte*)"true", 4);
+		return;
+	}
+	sys_write(1, (byte*)"false", 5);
+}
+
+void
+sys_printfloat(float64 v)
+{
+	sys_write(1, "printfloat", 10);
+}
+
+void
+sys_printint(int64 v)
+{
+	byte buf[100];
+	int32 i, s;
+
+	s = 0;
+	if(v < 0) {
+		v = -v;
+		s = 1;
+		if(v < 0) {
+			sys_write(1, (byte*)"-oo", 3);
+			return;
+		}
+	}
+
+	for(i=nelem(buf)-1; i>0; i--) {
+		buf[i] = v%10 + '0';
+		if(v < 10)
+			break;
+		v = v/10;
+	}
+	if(s) {
+		i--;
+		buf[i] = '-';
+	}
+	sys_write(1, buf+i, nelem(buf)-i);
+}
+
+void
+sys_printpointer(void *p)
+{
+	uint64 v;
+	byte buf[100];
+	int32 i;
+
+	v = (int64)p;
+	for(i=nelem(buf)-1; i>0; i--) {
+		buf[i] = v%16 + '0';
+		if(buf[i] > '9')
+			buf[i] += 'a'-'0'-10;
+		if(v < 16)
+			break;
+		v = v/16;
+	}
+	sys_write(1, buf+i, nelem(buf)-i);
+}
+
+void
+sys_panicl(int32 lno)
+{
+	prints("\npanic on line ");
+	sys_printint(lno);
+	prints("\n");
+	*(int32*)0 = 0;
+}
+
+void
+sys_printstring(string v)
+{
+	sys_write(1, v->str, v->len);
+}
+
+int32
+strlen(int8 *s)
+{
+	int32 l;
+
+	for(l=0; s[l]!=0; l++)
+		;
+	return l;
+}
+
+void
+prints(int8 *s)
+{
+	sys_write(1, s, strlen(s));
+}
+
+dump(byte *p, int32 n)
+{
+	uint32 v;
+	int32 i;
+
+	for(i=0; i<n; i++) {
+		sys_printpointer((byte*)(p[i]>>4));
+		sys_printpointer((byte*)(p[i]&0xf));
+		if((i&15) == 15)
+			prints("\n");
+		else
+			prints(" ");
+	}
+	if(n & 15)
+		prints("\n");
+}
+
+static	uint8*	hunk;
+static	uint32	nhunk;
+static	uint64	nmmap;
+static	uint64	nmal;
+enum
+{
+	NHUNK		= 20<<20,
+
+	PROT_NONE	= 0x00,
+	PROT_READ	= 0x01,
+	PROT_WRITE	= 0x02,
+	PROT_EXEC	= 0x04,
+
+	MAP_FILE	= 0x0000,
+	MAP_SHARED	= 0x0001,
+	MAP_PRIVATE	= 0x0002,
+	MAP_FIXED	= 0x0010,
+	MAP_ANON	= 0x1000,
+};
+
+static void
+throw(int8 *s)
+{
+	prints("throw: ");
+	prints(s);
+	prints("\n");
+	sys_exit(1);
+}
+
+static void
+mcpy(byte *t, byte *f, uint32 n)
+{
+	while(n > 0) {
+		*t = *f;
+		t++;
+		f++;
+		n--;
+	}
+}
+
+static byte*
+brk(uint32 n)
+{
+	byte* v;
+
+	v = sys_mmap(nil, NHUNK, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0);
+	sys_memclr(v, n);
+	nmmap += n;
+	return v;
+}
+
+static void*
+mal(uint32 n)
+{
+	byte* v;
+
+	// round to keep everything 64-bit alligned
+	while(n & 7)
+		n++;
+
+	nmal += n;
+
+	// do we have enough in contiguous hunk
+	if(n > nhunk) {
+
+		// if it is big allocate it separately
+		if(n > NHUNK)
+			return brk(n);
+
+		// allocate a new contiguous hunk
+		hunk = brk(NHUNK);
+		nhunk = NHUNK;
+	}
+
+	// allocate from the contiguous hunk
+	v = hunk;
+	hunk += n;
+	nhunk -= n;
+	return v;
+}
+
+void
+sys_mal(uint32 n, uint8 *ret)
+{
+	ret = mal(n);
+	FLUSH(&ret);
+}
+
+void
+sys_catstring(string s1, string s2, string s3)
+{
+	uint32 l;
+
+	if(s1->len == 0) {
+		s3 = s2;
+		goto out;
+	}
+	if(s2->len == 0) {
+		s3 = s1;
+		goto out;
+	}
+
+	l = s1->len + s2->len;
+
+	s3 = mal(sizeof(s3->len)+l);
+	s3->len = l;
+	mcpy(s3->str, s1->str, s1->len);
+	mcpy(s3->str+s1->len, s2->str, s2->len);
+
+out:
+	FLUSH(&s3);
+}
+
+void
+sys_cmpstring(string s1, string s2, int32 v)
+{
+	uint32 i, l;
+	byte c1, c2;
+
+	l = s1->len;
+	if(s2->len < l)
+		l = s2->len;
+	for(i=0; i<l; i++) {
+		c1 = s1->str[i];
+		c2 = s2->str[i];
+		if(c1 < c2) {
+			v = -1;
+			goto out;
+		}
+		if(c1 > c2) {
+			v = +1;
+			goto out;
+		}
+	}
+	if(s1->len < s2->len) {
+		v = -1;
+		goto out;
+	}
+	if(s1->len > s2->len) {
+		v = +1;
+		goto out;
+	}
+	v = 0;
+
+out:
+	FLUSH(&v);
+}
+
+static int32
+strcmp(byte *s1, byte *s2)
+{
+	uint32 i;
+	byte c1, c2;
+
+	for(i=0;; i++) {
+		c1 = s1[i];
+		c2 = s2[i];
+		if(c1 < c2)
+			return -1;
+		if(c1 > c2)
+			return +1;
+		if(c1 == 0)
+			return 0;
+	}
+}
+
+static void
+prbounds(int8* s, int32 a, int32 b, int32 c)
+{
+	int32 i;
+
+	prints(s);
+	prints(" ");
+	sys_printint(a);
+	prints("<");
+	sys_printint(b);
+	prints(">");
+	sys_printint(c);
+	prints("\n");
+	throw("bounds");
+}
+
+void
+sys_slicestring(string si, int32 lindex, int32 hindex, string so)
+{
+	string s, str;
+	int32 l;
+
+	if(lindex < 0 || lindex > si->len ||
+	   hindex < lindex || hindex > si->len)
+		prbounds("slice", lindex, si->len, hindex);
+
+	l = hindex-lindex;
+	so = mal(sizeof(so->len)+l);
+	so->len = l;
+	mcpy(so->str, si->str+lindex, l);
+	FLUSH(&so);
+}
+
+void
+sys_indexstring(string s, int32 i, byte b)
+{
+	if(i < 0 || i >= s->len)
+		prbounds("index", 0, i, s->len);
+
+	b = s->str[i];
+	FLUSH(&b);
+}
+
+/*
+ * this is the plan9 runetochar
+ * extended for 36 bits in 7 bytes
+ * note that it truncates to 32 bits
+ * through the argument passing.
+ */
+static int32
+runetochar(byte *str, uint32 c)
+{
+	int32 i, n;
+	uint32 mask, mark;
+
+	/*
+	 * one character in 7 bits
+	 */
+	if(c <= 0x07FUL) {
+		str[0] = c;
+		return 1;
+	}
+
+	/*
+	 * every new character picks up 5 bits
+	 * one less in the first byte and
+	 * six more in an extension byte
+	 */
+	mask = 0x7ffUL;
+	mark = 0xC0UL;
+	for(n=1;; n++) {
+		if(c <= mask)
+			break;
+		mask = (mask<<5) | 0x1fUL;
+		mark = (mark>>1) | 0x80UL;
+	}
+
+	/*
+	 * lay down the bytes backwards
+	 * n is the number of extension bytes
+	 * mask is the max codepoint
+	 * mark is the zeroth byte indicator
+	 */
+	for(i=n; i>0; i--) {
+		str[i] = 0x80UL | (c&0x3fUL);
+		c >>= 6;
+	}
+
+	str[0] = mark|c;
+	return n+1;
+}
+
+void
+sys_intstring(int64 v, string s)
+{
+	int32 l;
+
+	s = mal(sizeof(s->len)+8);
+	s->len = runetochar(s->str, v);
+	FLUSH(&s);
+}
+
+void
+sys_byteastring(byte *a, int32 l, string s)
+{
+	s = mal(sizeof(s->len)+l);
+	s->len = l;
+	mcpy(s->str, a, l);
+	FLUSH(&s);
+}
+
+static	Map*	hash[1009];
+
+static Map*
+hashmap(Sigi *si, Sigs *ss)
+{
+	int32 ns, ni;
+	uint32 ihash, h;
+	byte *sname, *iname;
+	Map *m;
+
+	h = ((uint32)si + (uint32)ss) % nelem(hash);
+	for(m=hash[h]; m!=nil; m=m->link) {
+		if(m->si == si && m->ss == ss) {
+			if(m->bad) {
+				throw("bad hashmap");
+				m = nil;
+			}
+			// prints("old hashmap\n");
+			return m;
+		}
+	}
+
+	ni = si[0].offset;	// first word has size
+	m = mal(sizeof(*m) + ni*sizeof(m->fun[0]));
+	m->si = si;
+	m->ss = ss;
+
+	ni = 1;			// skip first word
+	ns = 0;
+
+loop1:
+	// pick up next name from
+	// interface signature
+	iname = si[ni].name;
+	if(iname == nil) {
+		m->link = hash[h];
+		hash[h] = m;
+		// prints("new hashmap\n");
+		return m;
+	}
+	ihash = si[ni].hash;
+
+loop2:
+	// pick up and comapre next name
+	// from structure signature
+	sname = ss[ns].name;
+	if(sname == nil) {
+		prints((int8*)iname);
+		prints(": ");
+		throw("hashmap: failed to find method");
+		m->bad = 1;
+		m->link = hash[h];
+		hash[h] = m;
+		return nil;
+	}
+	if(ihash != ss[ns].hash ||
+	   strcmp(sname, iname) != 0) {
+		ns++;
+		goto loop2;
+	}
+
+	m->fun[si[ni].offset] = ss[ns].fun;
+	ni++;
+	goto loop1;
+}
+
+void
+sys_ifaces2i(Sigi *si, Sigs *ss, Map *m, void *s)
+{
+
+	if(debug) {
+		prints("s2i sigi=");
+		sys_printpointer(si);
+		prints(" sigs=");
+		sys_printpointer(ss);
+		prints(" s=");
+		sys_printpointer(s);
+	}
+
+	if(s == nil) {
+		throw("ifaces2i: nil pointer");
+		m = nil;
+		FLUSH(&m);
+		return;
+	}
+
+	m = hashmap(si, ss);
+
+	if(debug) {
+		prints(" returning m=");
+		sys_printpointer(m);
+		prints(" s=");
+		sys_printpointer(s);
+		prints("\n");
+		dump((byte*)m, 64);
+	}
+
+	FLUSH(&m);
+}
+
+void
+sys_ifacei2i(Sigi *si, Map *m, void *s)
+{
+
+	if(debug) {
+		prints("i2i sigi=");
+		sys_printpointer(si);
+		prints(" m=");
+		sys_printpointer(m);
+		prints(" s=");
+		sys_printpointer(s);
+	}
+
+	if(m == nil) {
+		throw("ifacei2i: nil map");
+		s = nil;
+		FLUSH(&s);
+		return;
+	}
+
+	if(m->si == nil) {
+		throw("ifacei2i: nil pointer");
+		return;
+	}
+
+	if(m->si != si) {
+		m = hashmap(si, m->ss);
+		FLUSH(&m);
+	}
+
+	if(debug) {
+		prints(" returning m=");
+		sys_printpointer(m);
+		prints(" s=");
+		sys_printpointer(s);
+		prints("\n");
+		dump((byte*)m, 64);
+	}
+}
+
+void
+sys_ifacei2s(Sigs *ss, Map *m, void *s)
+{
+
+	if(debug) {
+		prints("i2s m=");
+		sys_printpointer(m);
+		prints(" s=");
+		sys_printpointer(s);
+		prints("\n");
+	}
+
+	if(m == nil) {
+		throw("ifacei2s: nil map");
+		s = nil;
+		FLUSH(&s);
+		return;
+	}
+
+	if(m->ss != ss) {
+		dump((byte*)m, 64);
+		throw("ifacei2s: wrong pointer");
+		s = nil;
+		FLUSH(&s);
+		return;
+	}
+}
+
+void
+check(void)
+{
+	int8 a;
+	uint8 b;
+	int16 c;
+	uint16 d;
+	int32 e;
+	uint32 f;
+	int64 g;
+	uint64 h;
+	float32 i;
+	float64 j;
+	void* k;
+	uint16* l;
+
+	if(sizeof(a) != 1) throw("bad a");
+	if(sizeof(b) != 1) throw("bad b");
+	if(sizeof(c) != 2) throw("bad c");
+	if(sizeof(d) != 2) throw("bad d");
+	if(sizeof(e) != 4) throw("bad e");
+	if(sizeof(f) != 4) throw("bad f");
+	if(sizeof(g) != 8) throw("bad g");
+	if(sizeof(h) != 8) throw("bad h");
+	if(sizeof(i) != 4) throw("bad i");
+	if(sizeof(j) != 8) throw("bad j");
+	if(sizeof(k) != 8) throw("bad k");
+	if(sizeof(l) != 8) throw("bad l");
+//	prints(1"check ok\n");
+}
diff --git a/src/cmd/6g/runtime.h b/src/cmd/6g/runtime.h
new file mode 100644
index 0000000..6220a03
--- /dev/null
+++ b/src/cmd/6g/runtime.h
@@ -0,0 +1,107 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+/*
+ * basic types
+ */
+typedef	signed char		int8;
+typedef	unsigned char		uint8;
+typedef	signed short		int16;
+typedef	unsigned short		uint16;
+typedef	signed int		int32;
+typedef	unsigned int		uint32;
+typedef	signed long long int	int64;
+typedef	unsigned long long int	uint64;
+typedef	float			float32;
+typedef	double			float64;
+
+/*
+ * get rid of C types
+ */
+#define	unsigned		XXunsigned
+#define	signed			XXsigned
+#define	char			XXchar
+#define	short			XXshort
+#define	int			XXint
+#define	long			XXlong
+#define	float			XXfloat
+#define	double			XXdouble
+
+/*
+ * defined types
+ */
+typedef	uint8			bool;
+typedef	uint8			byte;
+typedef	struct
+{
+	int32	len;
+	byte	str[1];
+}				*string;
+typedef	struct
+{
+	byte*	name;
+	uint32	hash;
+	void	(*fun)(void);
+}				Sigs;
+typedef	struct
+{
+	byte*	name;
+	uint32	hash;
+	uint32	offset;
+}				Sigi;
+typedef	struct	Map		Map;
+struct	Map
+{
+	Sigi*	si;
+	Sigs*	ss;
+	Map*	link;
+	int32	bad;
+	int32	unused;
+	void	(*fun[])(void);
+};
+
+/*
+ * defined constants
+ */
+enum
+{
+	true	= 1,
+	false	= 0,
+};
+
+/*
+ * defined macros
+ *    you need super-goru privilege
+ *    to add this list.
+ */
+#define	nelem(x)	(sizeof(x)/sizeof((x)[0]))
+#define	nil		((void*)0)
+
+/*
+ * very low level
+ */
+void	FLUSH(void*);
+void	prints(int8*);
+void	sys_exit(int32);
+void	sys_write(int32, void*, int32);
+void	sys_breakpoint(void);
+uint8*	sys_mmap(byte*, uint32, int32, int32, int32, uint32);
+void	sys_memclr(byte*, uint32);
+
+/*
+ * runtime
+ */
+void	sys_printbool(bool);
+void	sys_printfloat(float64);
+void	sys_printint(int64);
+void	sys_printstring(string);
+void	sys_catstring(string, string, string);
+void	sys_cmpstring(string, string, int32);
+void	sys_slicestring(string, int32, int32, string);
+void	sys_indexstring(string, int32, byte);
+void	sys_intstring(int64, string);
+void	sys_ifaces2i(Sigi*, Sigs*, Map*, void*);
+void	sys_ifacei2i(Sigi*, Map*, void*);
+void	sys_ifacei2s(Sigs*, Map*, void*);
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
new file mode 100644
index 0000000..8006826
--- /dev/null
+++ b/src/cmd/6l/6.out.h
@@ -0,0 +1,857 @@
+// Inferno utils/6c/6.out.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/6.out.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#define	NSYM	50
+#define	NSNAME	8
+#define NOPROF	(1<<0)
+#define DUPOK	(1<<1)
+
+/*
+ *	amd64
+ */
+
+enum	as
+{
+	AXXX,
+	AAAA,
+	AAAD,
+	AAAM,
+	AAAS,
+	AADCB,
+	AADCL,
+	AADCW,
+	AADDB,
+	AADDL,
+	AADDW,
+	AADJSP,
+	AANDB,
+	AANDL,
+	AANDW,
+	AARPL,
+	ABOUNDL,
+	ABOUNDW,
+	ABSFL,
+	ABSFW,
+	ABSRL,
+	ABSRW,
+	ABTL,
+	ABTW,
+	ABTCL,
+	ABTCW,
+	ABTRL,
+	ABTRW,
+	ABTSL,
+	ABTSW,
+	ABYTE,
+	ACALL,
+	ACLC,
+	ACLD,
+	ACLI,
+	ACLTS,
+	ACMC,
+	ACMPB,
+	ACMPL,
+	ACMPW,
+	ACMPSB,
+	ACMPSL,
+	ACMPSW,
+	ADAA,
+	ADAS,
+	ADATA,
+	ADECB,
+	ADECL,
+	ADECQ,
+	ADECW,
+	ADIVB,
+	ADIVL,
+	ADIVW,
+	AENTER,
+	AGLOBL,
+	AGOK,
+	AHISTORY,
+	AHLT,
+	AIDIVB,
+	AIDIVL,
+	AIDIVW,
+	AIMULB,
+	AIMULL,
+	AIMULW,
+	AINB,
+	AINL,
+	AINW,
+	AINCB,
+	AINCL,
+	AINCQ,
+	AINCW,
+	AINSB,
+	AINSL,
+	AINSW,
+	AINT,
+	AINTO,
+	AIRETL,
+	AIRETW,
+	AJCC,
+	AJCS,
+	AJCXZ,
+	AJEQ,
+	AJGE,
+	AJGT,
+	AJHI,
+	AJLE,
+	AJLS,
+	AJLT,
+	AJMI,
+	AJMP,
+	AJNE,
+	AJOC,
+	AJOS,
+	AJPC,
+	AJPL,
+	AJPS,
+	ALAHF,
+	ALARL,
+	ALARW,
+	ALEAL,
+	ALEAW,
+	ALEAVEL,
+	ALEAVEW,
+	ALOCK,
+	ALODSB,
+	ALODSL,
+	ALODSW,
+	ALONG,
+	ALOOP,
+	ALOOPEQ,
+	ALOOPNE,
+	ALSLL,
+	ALSLW,
+	AMOVB,
+	AMOVL,
+	AMOVW,
+	AMOVBLSX,
+	AMOVBLZX,
+	AMOVBQSX,
+	AMOVBQZX,
+	AMOVBWSX,
+	AMOVBWZX,
+	AMOVWLSX,
+	AMOVWLZX,
+	AMOVWQSX,
+	AMOVWQZX,
+	AMOVSB,
+	AMOVSL,
+	AMOVSW,
+	AMULB,
+	AMULL,
+	AMULW,
+	ANAME,
+	ANEGB,
+	ANEGL,
+	ANEGW,
+	ANOP,
+	ANOTB,
+	ANOTL,
+	ANOTW,
+	AORB,
+	AORL,
+	AORW,
+	AOUTB,
+	AOUTL,
+	AOUTW,
+	AOUTSB,
+	AOUTSL,
+	AOUTSW,
+	APOPAL,
+	APOPAW,
+	APOPFL,
+	APOPFW,
+	APOPL,
+	APOPW,
+	APUSHAL,
+	APUSHAW,
+	APUSHFL,
+	APUSHFW,
+	APUSHL,
+	APUSHW,
+	ARCLB,
+	ARCLL,
+	ARCLW,
+	ARCRB,
+	ARCRL,
+	ARCRW,
+	AREP,
+	AREPN,
+	ARET,
+	AROLB,
+	AROLL,
+	AROLW,
+	ARORB,
+	ARORL,
+	ARORW,
+	ASAHF,
+	ASALB,
+	ASALL,
+	ASALW,
+	ASARB,
+	ASARL,
+	ASARW,
+	ASBBB,
+	ASBBL,
+	ASBBW,
+	ASCASB,
+	ASCASL,
+	ASCASW,
+	ASETCC,
+	ASETCS,
+	ASETEQ,
+	ASETGE,
+	ASETGT,
+	ASETHI,
+	ASETLE,
+	ASETLS,
+	ASETLT,
+	ASETMI,
+	ASETNE,
+	ASETOC,
+	ASETOS,
+	ASETPC,
+	ASETPL,
+	ASETPS,
+	ACDQ,
+	ACWD,
+	ASHLB,
+	ASHLL,
+	ASHLW,
+	ASHRB,
+	ASHRL,
+	ASHRW,
+	ASTC,
+	ASTD,
+	ASTI,
+	ASTOSB,
+	ASTOSL,
+	ASTOSW,
+	ASUBB,
+	ASUBL,
+	ASUBW,
+	ASYSCALL,
+	ATESTB,
+	ATESTL,
+	ATESTW,
+	ATEXT,
+	AVERR,
+	AVERW,
+	AWAIT,
+	AWORD,
+	AXCHGB,
+	AXCHGL,
+	AXCHGW,
+	AXLAT,
+	AXORB,
+	AXORL,
+	AXORW,
+
+	AFMOVB,
+	AFMOVBP,
+	AFMOVD,
+	AFMOVDP,
+	AFMOVF,
+	AFMOVFP,
+	AFMOVL,
+	AFMOVLP,
+	AFMOVV,
+	AFMOVVP,
+	AFMOVW,
+	AFMOVWP,
+	AFMOVX,
+	AFMOVXP,
+
+	AFCOMB,
+	AFCOMBP,
+	AFCOMD,
+	AFCOMDP,
+	AFCOMDPP,
+	AFCOMF,
+	AFCOMFP,
+	AFCOML,
+	AFCOMLP,
+	AFCOMW,
+	AFCOMWP,
+	AFUCOM,
+	AFUCOMP,
+	AFUCOMPP,
+
+	AFADDDP,
+	AFADDW,
+	AFADDL,
+	AFADDF,
+	AFADDD,
+
+	AFMULDP,
+	AFMULW,
+	AFMULL,
+	AFMULF,
+	AFMULD,
+
+	AFSUBDP,
+	AFSUBW,
+	AFSUBL,
+	AFSUBF,
+	AFSUBD,
+
+	AFSUBRDP,
+	AFSUBRW,
+	AFSUBRL,
+	AFSUBRF,
+	AFSUBRD,
+
+	AFDIVDP,
+	AFDIVW,
+	AFDIVL,
+	AFDIVF,
+	AFDIVD,
+
+	AFDIVRDP,
+	AFDIVRW,
+	AFDIVRL,
+	AFDIVRF,
+	AFDIVRD,
+
+	AFXCHD,
+	AFFREE,
+
+	AFLDCW,
+	AFLDENV,
+	AFRSTOR,
+	AFSAVE,
+	AFSTCW,
+	AFSTENV,
+	AFSTSW,
+
+	AF2XM1,
+	AFABS,
+	AFCHS,
+	AFCLEX,
+	AFCOS,
+	AFDECSTP,
+	AFINCSTP,
+	AFINIT,
+	AFLD1,
+	AFLDL2E,
+	AFLDL2T,
+	AFLDLG2,
+	AFLDLN2,
+	AFLDPI,
+	AFLDZ,
+	AFNOP,
+	AFPATAN,
+	AFPREM,
+	AFPREM1,
+	AFPTAN,
+	AFRNDINT,
+	AFSCALE,
+	AFSIN,
+	AFSINCOS,
+	AFSQRT,
+	AFTST,
+	AFXAM,
+	AFXTRACT,
+	AFYL2X,
+	AFYL2XP1,
+
+	AEND,
+
+	ADYNT,
+	AINIT,
+
+	ASIGNAME,
+
+	/* extra 32-bit operations */
+	ACMPXCHGB,
+	ACMPXCHGL,
+	ACMPXCHGW,
+	ACMPXCHG8B,
+	ACPUID,
+	AINVD,
+	AINVLPG,
+	ALFENCE,
+	AMFENCE,
+	AMOVNTIL,
+	ARDMSR,
+	ARDPMC,
+	ARDTSC,
+	ARSM,
+	ASFENCE,
+	ASYSRET,
+	AWBINVD,
+	AWRMSR,
+	AXADDB,
+	AXADDL,
+	AXADDW,
+
+	/* conditional move */
+	ACMOVLCC,
+	ACMOVLCS,
+	ACMOVLEQ,
+	ACMOVLGE,
+	ACMOVLGT,
+	ACMOVLHI,
+	ACMOVLLE,
+	ACMOVLLS,
+	ACMOVLLT,
+	ACMOVLMI,
+	ACMOVLNE,
+	ACMOVLOC,
+	ACMOVLOS,
+	ACMOVLPC,
+	ACMOVLPL,
+	ACMOVLPS,
+	ACMOVQCC,
+	ACMOVQCS,
+	ACMOVQEQ,
+	ACMOVQGE,
+	ACMOVQGT,
+	ACMOVQHI,
+	ACMOVQLE,
+	ACMOVQLS,
+	ACMOVQLT,
+	ACMOVQMI,
+	ACMOVQNE,
+	ACMOVQOC,
+	ACMOVQOS,
+	ACMOVQPC,
+	ACMOVQPL,
+	ACMOVQPS,
+	ACMOVWCC,
+	ACMOVWCS,
+	ACMOVWEQ,
+	ACMOVWGE,
+	ACMOVWGT,
+	ACMOVWHI,
+	ACMOVWLE,
+	ACMOVWLS,
+	ACMOVWLT,
+	ACMOVWMI,
+	ACMOVWNE,
+	ACMOVWOC,
+	ACMOVWOS,
+	ACMOVWPC,
+	ACMOVWPL,
+	ACMOVWPS,
+
+	/* 64-bit */
+	AADCQ,
+	AADDQ,
+	AANDQ,
+	ABSFQ,
+	ABSRQ,
+	ABTCQ,
+	ABTQ,
+	ABTRQ,
+	ABTSQ,
+	ACMPQ,
+	ACMPSQ,
+	ACMPXCHGQ,
+	ACQO,
+	ADIVQ,
+	AIDIVQ,
+	AIMULQ,
+	AIRETQ,
+	ALEAQ,
+	ALEAVEQ,
+	ALODSQ,
+	AMOVQ,
+	AMOVLQSX,
+	AMOVLQZX,
+	AMOVNTIQ,
+	AMOVSQ,
+	AMULQ,
+	ANEGQ,
+	ANOTQ,
+	AORQ,
+	APOPFQ,
+	APOPQ,
+	APUSHFQ,
+	APUSHQ,
+	ARCLQ,
+	ARCRQ,
+	AROLQ,
+	ARORQ,
+	AQUAD,
+	ASALQ,
+	ASARQ,
+	ASBBQ,
+	ASCASQ,
+	ASHLQ,
+	ASHRQ,
+	ASTOSQ,
+	ASUBQ,
+	ATESTQ,
+	AXADDQ,
+	AXCHGQ,
+	AXORQ,
+
+	/* media */
+	AADDPD,
+	AADDPS,
+	AADDSD,
+	AADDSS,
+	AANDNPD,
+	AANDNPS,
+	AANDPD,
+	AANDPS,
+	ACMPPD,
+	ACMPPS,
+	ACMPSD,
+	ACMPSS,
+	ACOMISD,
+	ACOMISS,
+	ACVTPD2PL,
+	ACVTPD2PS,
+	ACVTPL2PD,
+	ACVTPL2PS,
+	ACVTPS2PD,
+	ACVTPS2PL,
+	ACVTSD2SL,
+	ACVTSD2SQ,
+	ACVTSD2SS,
+	ACVTSL2SD,
+	ACVTSL2SS,
+	ACVTSQ2SD,
+	ACVTSQ2SS,
+	ACVTSS2SD,
+	ACVTSS2SL,
+	ACVTSS2SQ,
+	ACVTTPD2PL,
+	ACVTTPS2PL,
+	ACVTTSD2SL,
+	ACVTTSD2SQ,
+	ACVTTSS2SL,
+	ACVTTSS2SQ,
+	ADIVPD,
+	ADIVPS,
+	ADIVSD,
+	ADIVSS,
+	AEMMS,
+	AFXRSTOR,
+	AFXRSTOR64,
+	AFXSAVE,
+	AFXSAVE64,
+	ALDMXCSR,
+	AMASKMOVOU,
+	AMASKMOVQ,
+	AMAXPD,
+	AMAXPS,
+	AMAXSD,
+	AMAXSS,
+	AMINPD,
+	AMINPS,
+	AMINSD,
+	AMINSS,
+	AMOVAPD,
+	AMOVAPS,
+	AMOVOU,
+	AMOVHLPS,
+	AMOVHPD,
+	AMOVHPS,
+	AMOVLHPS,
+	AMOVLPD,
+	AMOVLPS,
+	AMOVMSKPD,
+	AMOVMSKPS,
+	AMOVNTO,
+	AMOVNTPD,
+	AMOVNTPS,
+	AMOVNTQ,
+	AMOVO,
+	AMOVQOZX,
+	AMOVSD,
+	AMOVSS,
+	AMOVUPD,
+	AMOVUPS,
+	AMULPD,
+	AMULPS,
+	AMULSD,
+	AMULSS,
+	AORPD,
+	AORPS,
+	APACKSSLW,
+	APACKSSWB,
+	APACKUSWB,
+	APADDB,
+	APADDL,
+	APADDQ,
+	APADDSB,
+	APADDSW,
+	APADDUSB,
+	APADDUSW,
+	APADDW,
+	APANDB,
+	APANDL,
+	APANDSB,
+	APANDSW,
+	APANDUSB,
+	APANDUSW,
+	APANDW,
+	APAND,
+	APANDN,
+	APAVGB,
+	APAVGW,
+	APCMPEQB,
+	APCMPEQL,
+	APCMPEQW,
+	APCMPGTB,
+	APCMPGTL,
+	APCMPGTW,
+	APEXTRW,
+	APFACC,
+	APFADD,
+	APFCMPEQ,
+	APFCMPGE,
+	APFCMPGT,
+	APFMAX,
+	APFMIN,
+	APFMUL,
+	APFNACC,
+	APFPNACC,
+	APFRCP,
+	APFRCPIT1,
+	APFRCPI2T,
+	APFRSQIT1,
+	APFRSQRT,
+	APFSUB,
+	APFSUBR,
+	APINSRW,
+	APMADDWL,
+	APMAXSW,
+	APMAXUB,
+	APMINSW,
+	APMINUB,
+	APMOVMSKB,
+	APMULHRW,
+	APMULHUW,
+	APMULHW,
+	APMULLW,
+	APMULULQ,
+	APOR,
+	APSADBW,
+	APSHUFHW,
+	APSHUFL,
+	APSHUFLW,
+	APSHUFW,
+	APSLLO,
+	APSLLL,
+	APSLLQ,
+	APSLLW,
+	APSRAL,
+	APSRAW,
+	APSRLO,
+	APSRLL,
+	APSRLQ,
+	APSRLW,
+	APSUBB,
+	APSUBL,
+	APSUBQ,
+	APSUBSB,
+	APSUBSW,
+	APSUBUSB,
+	APSUBUSW,
+	APSUBW,
+	APSWAPL,
+	APUNPCKHBW,
+	APUNPCKHLQ,
+	APUNPCKHQDQ,
+	APUNPCKHWL,
+	APUNPCKLBW,
+	APUNPCKLLQ,
+	APUNPCKLQDQ,
+	APUNPCKLWL,
+	APXOR,
+	ARCPPS,
+	ARCPSS,
+	ARSQRTPS,
+	ARSQRTSS,
+	ASHUFPD,
+	ASHUFPS,
+	ASQRTPD,
+	ASQRTPS,
+	ASQRTSD,
+	ASQRTSS,
+	ASTMXCSR,
+	ASUBPD,
+	ASUBPS,
+	ASUBSD,
+	ASUBSS,
+	AUCOMISD,
+	AUCOMISS,
+	AUNPCKHPD,
+	AUNPCKHPS,
+	AUNPCKLPD,
+	AUNPCKLPS,
+	AXORPD,
+	AXORPS,
+
+	APF2IW,
+	APF2IL,
+	API2FW,
+	API2FL,
+	ARETFW,
+	ARETFL,
+	ARETFQ,
+	ASWAPGS,
+
+	AMODE,
+
+	ALAST
+};
+
+enum
+{
+
+	D_AL		= 0,
+	D_CL,
+	D_DL,
+	D_BL,
+	D_SPB,
+	D_BPB,
+	D_SIB,
+	D_DIB,
+	D_R8B,
+	D_R9B,
+	D_R10B,
+	D_R11B,
+	D_R12B,
+	D_R13B,
+	D_R14B,
+	D_R15B,
+
+	D_AX		= 16,
+	D_CX,
+	D_DX,
+	D_BX,
+	D_SP,
+	D_BP,
+	D_SI,
+	D_DI,
+	D_R8,
+	D_R9,
+	D_R10,
+	D_R11,
+	D_R12,
+	D_R13,
+	D_R14,
+	D_R15,
+
+	D_AH		= 32,
+	D_CH,
+	D_DH,
+	D_BH,
+
+	D_F0		= 36,
+
+	D_M0		= 44,
+
+	D_X0		= 52,
+	D_X1,
+	D_X2,
+	D_X3,
+	D_X4,
+	D_X5,
+	D_X6,
+	D_X7,
+
+	D_CS		= 68,
+	D_SS,
+	D_DS,
+	D_ES,
+	D_FS,
+	D_GS,
+
+	D_GDTR,		/* global descriptor table register */
+	D_IDTR,		/* interrupt descriptor table register */
+	D_LDTR,		/* local descriptor table register */
+	D_MSW,		/* machine status word */
+	D_TASK,		/* task register */
+
+	D_CR		= 79,
+	D_DR		= 95,
+	D_TR		= 103,
+
+	D_NONE		= 111,
+
+	D_BRANCH	= 112,
+	D_EXTERN	= 113,
+	D_STATIC	= 114,
+	D_AUTO		= 115,
+	D_PARAM		= 116,
+	D_CONST		= 117,
+	D_FCONST	= 118,
+	D_SCONST	= 119,
+	D_ADDR		= 120,
+
+	D_FILE,
+	D_FILE1,
+
+	D_INDIR,	/* additive */
+
+	T_TYPE		= 1<<0,
+	T_INDEX		= 1<<1,
+	T_OFFSET	= 1<<2,
+	T_FCONST	= 1<<3,
+	T_SYM		= 1<<4,
+	T_SCONST	= 1<<5,
+	T_64		= 1<<6,
+
+	REGARG		= 0,
+	REGRET		= D_AX,
+	FREGRET		= D_X0,
+	REGSP		= D_SP,
+	REGTMP		= D_DI,
+	REGEXT		= D_R15,	/* compiler allocates external registers R15 down */
+	FREGMIN		= D_X0+5,	/* first register variable */
+	FREGEXT		= D_X0+7	/* first external register */
+};
+
+/*
+ * this is the ranlib header
+ */
+#define	SYMDEF	"__.SYMDEF"
+
+/*
+ * this is the simulated IEEE floating point
+ */
+typedef	struct	ieee	Ieee;
+struct	ieee
+{
+	long	l;	/* contains ls-man	0xffffffff */
+	long	h;	/* contains sign	0x80000000
+				    exp		0x7ff00000
+				    ms-man	0x000fffff */
+};
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
new file mode 100644
index 0000000..4d1e9d9
--- /dev/null
+++ b/src/cmd/6l/asm.c
@@ -0,0 +1,617 @@
+// Inferno utils/6l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	"l.h"
+
+#define	Dbufslop	100
+
+#define PADDR(a)	((ulong)(a) & ~0x80000000)
+
+vlong
+entryvalue(void)
+{
+	char *a;
+	Sym *s;
+
+	a = INITENTRY;
+	if(*a >= '0' && *a <= '9')
+		return atolwhex(a);
+	s = lookup(a, 0);
+	if(s->type == 0)
+		return INITTEXT;
+	switch(s->type) {
+	case STEXT:
+		break;
+	case SDATA:
+		if(dlm)
+			return s->value+INITDAT;
+	default:
+		diag("entry not text: %s", s->name);
+	}
+	return s->value;
+}
+
+void
+wputl(ushort w)
+{
+	cput(w);
+	cput(w>>8);
+}
+
+void
+wput(ushort w)
+{
+	cput(w>>8);
+	cput(w);
+}
+
+void
+lput(long l)
+{
+	cput(l>>24);
+	cput(l>>16);
+	cput(l>>8);
+	cput(l);
+}
+
+void
+llput(vlong v)
+{
+	lput(v>>32);
+	lput(v);
+}
+
+void
+lputl(long l)
+{
+	cput(l);
+	cput(l>>8);
+	cput(l>>16);
+	cput(l>>24);
+}
+
+void
+strnput(char *s, int n)
+{
+	int i;
+
+	for(i=0; i<n; i++) {
+		cput(*s);
+		if(*s != 0)
+			s++;
+	}
+}
+
+void
+asmb(void)
+{
+	Prog *p;
+	long v, magic, w;
+	int a;
+	uchar *op1;
+	vlong vl, va;
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f asmb\n", cputime());
+	Bflush(&bso);
+
+	seek(cout, HEADR, 0);
+	pc = INITTEXT;
+	curp = firstp;
+	for(p = firstp; p != P; p = p->link) {
+		if(p->as == ATEXT)
+			curtext = p;
+		if(p->pc != pc) {
+			if(!debug['a'])
+				print("%P\n", curp);
+			diag("phase error %llux sb %llux in %s", p->pc, pc, TNAME);
+			pc = p->pc;
+		}
+		curp = p;
+		asmins(p);
+		a = (andptr - and);
+		if(cbc < a)
+			cflush();
+		if(debug['a']) {
+			Bprint(&bso, pcstr, pc);
+			for(op1 = and; op1 < andptr; op1++)
+				Bprint(&bso, "%.2ux", *op1);
+			for(; op1 < and+Maxand; op1++)
+				Bprint(&bso, "  ");
+			Bprint(&bso, "%P\n", curp);
+		}
+		if(dlm) {
+			if(p->as == ATEXT)
+				reloca = nil;
+			else if(reloca != nil)
+				diag("reloc failure: %P", curp);
+		}
+		memmove(cbp, and, a);
+		cbp += a;
+		pc += a;
+		cbc -= a;
+	}
+	cflush();
+	switch(HEADTYPE) {
+	default:
+		diag("unknown header type %ld", HEADTYPE);
+	case 2:
+	case 5:
+		seek(cout, HEADR+textsize, 0);
+		break;
+	case 6:
+		v = HEADR+textsize;
+		myseek(cout, v);
+		v = rnd(v, 4096) - v;
+		while(v > 0) {
+			cput(0);
+			v--;
+		}
+		cflush();
+		break;
+	}
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f datblk\n", cputime());
+	Bflush(&bso);
+
+	if(dlm){
+		char buf[8];
+
+		write(cout, buf, INITDAT-textsize);
+		textsize = INITDAT;
+	}
+
+	for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) {
+		if(datsize-v > sizeof(buf)-Dbufslop)
+			datblk(v, sizeof(buf)-Dbufslop);
+		else
+			datblk(v, datsize-v);
+	}
+
+	symsize = 0;
+	spsize = 0;
+	lcsize = 0;
+	if(!debug['s']) {
+		if(debug['v'])
+			Bprint(&bso, "%5.2f sym\n", cputime());
+		Bflush(&bso);
+		switch(HEADTYPE) {
+		default:
+		case 2:
+		case 5:
+			seek(cout, HEADR+textsize+datsize, 0);
+			break;
+		case 6:
+			debug['s'] = 1;
+			break;
+		}
+		if(!debug['s'])
+			asmsym();
+		if(debug['v'])
+			Bprint(&bso, "%5.2f sp\n", cputime());
+		Bflush(&bso);
+		if(debug['v'])
+			Bprint(&bso, "%5.2f pc\n", cputime());
+		Bflush(&bso);
+		if(!debug['s'])
+			asmlc();
+		if(dlm)
+			asmdyn();
+		cflush();
+	}
+	else if(dlm){
+		seek(cout, HEADR+textsize+datsize, 0);
+		asmdyn();
+		cflush();
+	}
+	if(debug['v'])
+		Bprint(&bso, "%5.2f headr\n", cputime());
+	Bflush(&bso);
+	seek(cout, 0L, 0);
+	switch(HEADTYPE) {
+	default:
+	case 2:	/* plan9 */
+		magic = 4*26*26+7;
+		magic |= 0x00008000;		/* fat header */
+		if(dlm)
+			magic |= 0x80000000;	/* dlm */
+		lput(magic);			/* magic */
+		lput(textsize);			/* sizes */
+		lput(datsize);
+		lput(bsssize);
+		lput(symsize);			/* nsyms */
+		vl = entryvalue();
+		lput(PADDR(vl));		/* va of entry */
+		lput(spsize);			/* sp offsets */
+		lput(lcsize);			/* line offsets */
+		llput(vl);			/* va of entry */
+		break;
+	case 3:	/* plan9 */
+		magic = 4*26*26+7;
+		if(dlm)
+			magic |= 0x80000000;
+		lput(magic);			/* magic */
+		lput(textsize);			/* sizes */
+		lput(datsize);
+		lput(bsssize);
+		lput(symsize);			/* nsyms */
+		lput(entryvalue());		/* va of entry */
+		lput(spsize);			/* sp offsets */
+		lput(lcsize);			/* line offsets */
+		break;
+	case 5:
+		strnput("\177ELF", 4);		/* e_ident */
+		cput(1);			/* class = 32 bit */
+		cput(1);			/* data = LSB */
+		cput(1);			/* version = CURRENT */
+		strnput("", 9);
+		wputl(2);			/* type = EXEC */
+		wputl(62);			/* machine = AMD64 */
+		lputl(1L);			/* version = CURRENT */
+		lputl(PADDR(entryvalue()));	/* entry vaddr */
+		lputl(52L);			/* offset to first phdr */
+		lputl(0L);			/* offset to first shdr */
+		lputl(0L);			/* processor specific flags */
+		wputl(52);			/* Ehdr size */
+		wputl(32);			/* Phdr size */
+		wputl(3);			/* # of Phdrs */
+		wputl(0);			/* Shdr size */
+		wputl(0);			/* # of Shdrs */
+		wputl(0);			/* Shdr string size */
+
+		lputl(1L);			/* text - type = PT_LOAD */
+		lputl(HEADR);			/* file offset */
+		lputl(INITTEXT);		/* vaddr */
+		lputl(PADDR(INITTEXT));		/* paddr */
+		lputl(textsize);		/* file size */
+		lputl(textsize);		/* memory size */
+		lputl(0x05L);			/* protections = RX */
+		lputl(INITRND);			/* alignment */
+
+		lputl(1L);			/* data - type = PT_LOAD */
+		lputl(HEADR+textsize);		/* file offset */
+		lputl(INITDAT);			/* vaddr */
+		lputl(PADDR(INITDAT));		/* paddr */
+		lputl(datsize);			/* file size */
+		lputl(datsize+bsssize);		/* memory size */
+		lputl(0x06L);			/* protections = RW */
+		lputl(INITRND);			/* alignment */
+
+		lputl(0L);			/* data - type = PT_NULL */
+		lputl(HEADR+textsize+datsize);	/* file offset */
+		lputl(0L);
+		lputl(0L);
+		lputl(symsize);			/* symbol table size */
+		lputl(lcsize);			/* line number size */
+		lputl(0x04L);			/* protections = R */
+		lputl(0x04L);			/* alignment */
+		break;
+	case 6:
+		/* apple MACH */
+		va = 4096;
+
+		lputl(0xfeedfacf);		/* 64-bit */
+		lputl((1<<24)|7);		/* cputype - x86/ABI64 */
+		lputl(3);			/* subtype - x86 */
+		lputl(2);			/* file type - mach executable */
+		lputl(4);			/* number of loads */
+		lputl(machheadr()-32);		/* size of loads */
+		lputl(1);			/* flags - no undefines */
+		lputl(0);			/* reserved */
+
+		machseg("__PAGEZERO",
+			0,va,			/* vaddr vsize */
+			0,0,			/* fileoffset filesize */
+			0,0,			/* protects */
+			0,0);			/* sections flags */
+
+		v = rnd(HEADR+textsize, INITRND);
+		machseg("__TEXT",
+			va,			/* vaddr */
+			v,			/* vsize */
+			0,v,			/* fileoffset filesize */
+			7,5,			/* protects */
+			1,0);			/* sections flags */
+		machsect("__text", "__TEXT",
+			va+HEADR,v-HEADR,	/* addr size */
+			HEADR,0,0,0,		/* offset align reloc nreloc */
+			0|0x400);		/* flag - some instructions */
+
+		w = datsize+bsssize;
+		machseg("__DATA",
+			va+v,			/* vaddr */
+			w,			/* vsize */
+			v,datsize,		/* fileoffset filesize */
+			7,3,			/* protects */
+			2,0);			/* sections flags */
+		machsect("__data", "__DATA",
+			va+v,datsize,		/* addr size */
+			v,0,0,0,		/* offset align reloc nreloc */
+			0);			/* flag */
+		machsect("__bss", "__DATA",
+			va+v+datsize,bsssize,	/* addr size */
+			0,0,0,0,		/* offset align reloc nreloc */
+			1);			/* flag - zero fill */
+		machstack(va+HEADR);
+		break;
+	}
+	cflush();
+}
+
+void
+cflush(void)
+{
+	int n;
+
+	n = sizeof(buf.cbuf) - cbc;
+	if(n)
+		write(cout, buf.cbuf, n);
+	cbp = buf.cbuf;
+	cbc = sizeof(buf.cbuf);
+}
+
+void
+outa(int n, uchar *cast, uchar *map, vlong l)
+{
+	int i, j;
+
+	Bprint(&bso, pcstr, l);
+	for(i=0; i<n; i++) {
+		j = i;
+		if(map != nil)
+			j = map[j];
+		Bprint(&bso, "%.2ux", cast[j]);
+	}
+	for(; i<Maxand; i++)
+		Bprint(&bso, "  ");
+	Bprint(&bso, "%P\n", curp);
+}
+
+void
+datblk(long s, long n)
+{
+	Prog *p;
+	uchar *cast;
+	long l, fl, j;
+	vlong o;
+	int i, c;
+
+	memset(buf.dbuf, 0, n+Dbufslop);
+	for(p = datap; p != P; p = p->link) {
+		curp = p;
+		l = p->from.sym->value + p->from.offset - s;
+		c = p->from.scale;
+		i = 0;
+		if(l < 0) {
+			if(l+c <= 0)
+				continue;
+			while(l < 0) {
+				l++;
+				i++;
+			}
+		}
+		if(l >= n)
+			continue;
+		if(p->as != AINIT && p->as != ADYNT) {
+			for(j=l+(c-i)-1; j>=l; j--)
+				if(buf.dbuf[j]) {
+					print("%P\n", p);
+					diag("multiple initialization");
+					break;
+				}
+		}
+
+		switch(p->to.type) {
+		case D_FCONST:
+			switch(c) {
+			default:
+			case 4:
+				fl = ieeedtof(&p->to.ieee);
+				cast = (uchar*)&fl;
+				if(debug['a'] && i == 0)
+					outa(c, cast, fnuxi4, l+s+INITDAT);
+				for(; i<c; i++) {
+					buf.dbuf[l] = cast[fnuxi4[i]];
+					l++;
+				}
+				break;
+			case 8:
+				cast = (uchar*)&p->to.ieee;
+				if(debug['a'] && i == 0)
+					outa(c, cast, fnuxi8, l+s+INITDAT);
+				for(; i<c; i++) {
+					buf.dbuf[l] = cast[fnuxi8[i]];
+					l++;
+				}
+				break;
+			}
+			break;
+
+		case D_SCONST:
+			if(debug['a'] && i == 0)
+				outa(c, (uchar*)p->to.scon, nil, l+s+INITDAT);
+			for(; i<c; i++) {
+				buf.dbuf[l] = p->to.scon[i];
+				l++;
+			}
+			break;
+		default:
+			o = p->to.offset;
+			if(p->to.type == D_ADDR) {
+				if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
+					diag("DADDR type%P", p);
+				if(p->to.sym) {
+					if(p->to.sym->type == SUNDEF)
+						ckoff(p->to.sym, o);
+					o += p->to.sym->value;
+					if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
+						o += INITDAT;
+					if(dlm)
+						dynreloc(p->to.sym, l+s+INITDAT, 1);
+				}
+			}
+			fl = o;
+			cast = (uchar*)&fl;
+			switch(c) {
+			default:
+				diag("bad nuxi %d %d\n%P", c, i, curp);
+				break;
+			case 1:
+				if(debug['a'] && i == 0)
+					outa(c, cast, inuxi1, l+s+INITDAT);
+				for(; i<c; i++) {
+					buf.dbuf[l] = cast[inuxi1[i]];
+					l++;
+				}
+				break;
+			case 2:
+				if(debug['a'] && i == 0)
+					outa(c, cast, inuxi2, l+s+INITDAT);
+				for(; i<c; i++) {
+					buf.dbuf[l] = cast[inuxi2[i]];
+					l++;
+				}
+				break;
+			case 4:
+				if(debug['a'] && i == 0)
+					outa(c, cast, inuxi4, l+s+INITDAT);
+				for(; i<c; i++) {
+					buf.dbuf[l] = cast[inuxi4[i]];
+					l++;
+				}
+				break;
+			case 8:
+				cast = (uchar*)&o;
+				if(debug['a'] && i == 0)
+					outa(c, cast, inuxi8, l+s+INITDAT);
+				for(; i<c; i++) {
+					buf.dbuf[l] = cast[inuxi8[i]];
+					l++;
+				}
+				break;
+			}
+			break;
+		}
+	}
+	write(cout, buf.dbuf, n);
+}
+
+vlong
+rnd(vlong v, vlong r)
+{
+	vlong c;
+
+	if(r <= 0)
+		return v;
+	v += r - 1;
+	c = v % r;
+	if(c < 0)
+		c += r;
+	v -= c;
+	return v;
+}
+
+void
+vputl(vlong v)
+{
+	lputl(v);
+	lputl(v>>32);
+}
+
+void
+machseg(char *name, vlong vaddr, vlong vsize, vlong foff, vlong fsize,
+	ulong prot1, ulong prot2, ulong nsect, ulong flag)
+{
+	lputl(25);	// section
+	lputl(72 + 80*nsect);
+	strnput(name, 16);
+	vputl(vaddr);
+	vputl(vsize);
+	vputl(foff);
+	vputl(fsize);
+	lputl(prot1);
+	lputl(prot2);
+	lputl(nsect);
+	lputl(flag);
+}
+
+void
+machsect(char *name, char *seg, vlong addr, vlong size, ulong off,
+	ulong align, ulong reloc, ulong nreloc, ulong flag)
+{
+	strnput(name, 16);
+	strnput(seg, 16);
+	vputl(addr);
+	vputl(size);
+	lputl(off);
+	lputl(align);
+	lputl(reloc);
+	lputl(nreloc);
+	lputl(flag);
+	lputl(0);	/* reserved */
+	lputl(0);	/* reserved */
+	lputl(0);	/* reserved */
+}
+
+void
+machstack(vlong e)
+{
+	int i;
+
+	lputl(5);			/* unix thread */
+	lputl((42+4)*4);		/* total byte count */
+
+	lputl(4);			/* thread type */
+	lputl(42);			/* word count */
+
+	for(i=0; i<32; i++)
+		lputl(0);
+	vputl(e);
+	for(i=0; i<8; i++)
+		lputl(0);
+}
+
+ulong
+machheadr(void)
+{
+	ulong a;
+
+	a = 8;		/* a.out header */
+	a += 18;	/* page zero seg */
+	a += 18;	/* text seg */
+	a += 20;	/* text sect */
+	a += 18;	/* data seg */
+	a += 20;	/* data sect */
+	a += 20;	/* bss sect */
+	a += 46;	/* stack sect */
+
+	return a*4;
+}
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
new file mode 100644
index 0000000..137474b
--- /dev/null
+++ b/src/cmd/6l/l.h
@@ -0,0 +1,430 @@
+// Inferno utils/6l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	<u.h>
+#include	<libc.h>
+#include	<bio.h>
+#include	"../6l/6.out.h"
+#include	"compat.h"
+
+#ifndef	EXTERN
+#define	EXTERN	extern
+#endif
+
+#define	P		((Prog*)0)
+#define	S		((Sym*)0)
+#define	TNAME		(curtext?curtext->from.sym->name:noname)
+#define	cput(c)\
+	{ *cbp++ = c;\
+	if(--cbc <= 0)\
+		cflush(); }
+
+typedef	struct	Adr	Adr;
+typedef	struct	Prog	Prog;
+typedef	struct	Sym	Sym;
+typedef	struct	Auto	Auto;
+typedef	struct	Optab	Optab;
+typedef	struct	Movtab	Movtab;
+
+struct	Adr
+{
+	union
+	{
+		vlong	u0offset;
+		char	u0scon[8];
+		Prog	*u0cond;	/* not used, but should be D_BRANCH */
+		Ieee	u0ieee;
+	} u0;
+	union
+	{
+		Auto*	u1autom;
+		Sym*	u1sym;
+	} u1;
+	short	type;
+	char	index;
+	char	scale;
+};
+
+#define	offset	u0.u0offset
+#define	scon	u0.u0scon
+#define	cond	u0.u0cond
+#define	ieee	u0.u0ieee
+
+#define	autom	u1.u1autom
+#define	sym	u1.u1sym
+
+struct	Prog
+{
+	Adr	from;
+	Adr	to;
+	Prog	*forwd;
+	Prog*	link;
+	Prog*	pcond;	/* work on this */
+	vlong	pc;
+	long	line;
+	uchar	mark;	/* work on these */
+	uchar	back;
+
+	short	as;
+	char	width;		/* fake for DATA */
+	char	mode;	/* 16, 32, or 64 */
+};
+struct	Auto
+{
+	Sym*	asym;
+	Auto*	link;
+	long	aoffset;
+	short	type;
+};
+struct	Sym
+{
+	char	*name;
+	short	type;
+	short	version;
+	short	become;
+	short	frame;
+	uchar	subtype;
+	ushort	file;
+	vlong	value;
+	long	sig;
+	Sym*	link;
+};
+struct	Optab
+{
+	short	as;
+	uchar*	ytab;
+	uchar	prefix;
+	uchar	op[20];
+};
+struct	Movtab
+{
+	short	as;
+	uchar	ft;
+	uchar	tt;
+	uchar	code;
+	uchar	op[4];
+};
+
+enum
+{
+	STEXT		= 1,
+	SDATA,
+	SBSS,
+	SDATA1,
+	SXREF,
+	SFILE,
+	SCONST,
+	SUNDEF,
+
+	SIMPORT,
+	SEXPORT,
+
+	NHASH		= 10007,
+	NHUNK		= 100000,
+	MINSIZ		= 8,
+	STRINGSZ	= 200,
+	MINLC		= 1,
+	MAXIO		= 8192,
+	MAXHIST		= 20,				/* limit of path elements for history symbols */
+
+	Yxxx		= 0,
+	Ynone,
+	Yi0,
+	Yi1,
+	Yi8,
+	Ys32,
+	Yi32,
+	Yi64,
+	Yiauto,
+	Yal,
+	Ycl,
+	Yax,
+	Ycx,
+	Yrb,
+	Yrl,
+	Yrf,
+	Yf0,
+	Yrx,
+	Ymb,
+	Yml,
+	Ym,
+	Ybr,
+	Ycol,
+
+	Ycs,	Yss,	Yds,	Yes,	Yfs,	Ygs,
+	Ygdtr,	Yidtr,	Yldtr,	Ymsw,	Ytask,
+	Ycr0,	Ycr1,	Ycr2,	Ycr3,	Ycr4,	Ycr5,	Ycr6,	Ycr7,	Ycr8,
+	Ydr0,	Ydr1,	Ydr2,	Ydr3,	Ydr4,	Ydr5,	Ydr6,	Ydr7,
+	Ytr0,	Ytr1,	Ytr2,	Ytr3,	Ytr4,	Ytr5,	Ytr6,	Ytr7,	Yrl32,	Yrl64,
+	Ymr, Ymm,
+	Yxr, Yxm,
+	Ymax,
+
+	Zxxx		= 0,
+
+	Zlit,
+	Z_rp,
+	Zbr,
+	Zcall,
+	Zib_,
+	Zib_rp,
+	Zibo_m,
+	Zibo_m_xm,
+	Zil_,
+	Zil_rp,
+	Ziq_rp,
+	Zilo_m,
+	Ziqo_m,
+	Zjmp,
+	Zloop,
+	Zo_iw,
+	Zm_o,
+	Zm_r,
+	Zm_r_xm,
+	Zm_r_i_xm,
+	Zm_r_3d,
+	Zm_r_xm_nr,
+	Zr_m_xm_nr,
+	Zibm_r,	/* mmx1,mmx2/mem64,imm8 */
+	Zmb_r,
+	Zaut_r,
+	Zo_m,
+	Zo_m64,
+	Zpseudo,
+	Zr_m,
+	Zr_m_xm,
+	Zr_m_i_xm,
+	Zrp_,
+	Z_ib,
+	Z_il,
+	Zm_ibo,
+	Zm_ilo,
+	Zib_rr,
+	Zil_rr,
+	Zclr,
+	Zbyte,
+	Zmax,
+
+	Px		= 0,
+	P32		= 0x32,	/* 32-bit only */
+	Pe		= 0x66,	/* operand escape */
+	Pm		= 0x0f,	/* 2byte opcode escape */
+	Pq		= 0xff,	/* both escape */
+	Pb		= 0xfe,	/* byte operands */
+	Pf2		= 0xf2,	/* xmm escape 1 */
+	Pf3		= 0xf3,	/* xmm escape 2 */
+	Pw		= 0x48,	/* Rex.w */
+	Py		= 0x80,	/* defaults to 64-bit mode */
+
+	Rxf		= 1<<9,	/* internal flag for Rxr on from */
+	Rxt		= 1<<8,	/* internal flag for Rxr on to */
+	Rxw		= 1<<3,	/* =1, 64-bit operand size */
+	Rxr		= 1<<2,	/* extend modrm reg */
+	Rxx		= 1<<1,	/* extend sib index */
+	Rxb		= 1<<0,	/* extend modrm r/m, sib base, or opcode reg */
+
+	Roffset	= 22,		/* no. bits for offset in relocation address */
+	Rindex	= 10,		/* no. bits for index in relocation address */
+	Maxand	= 10,		/* in -a output width of the byte codes */
+};
+
+EXTERN union
+{
+	struct
+	{
+		char	obuf[MAXIO];			/* output buffer */
+		uchar	ibuf[MAXIO];			/* input buffer */
+	} u;
+	char	dbuf[1];
+} buf;
+
+#define	cbuf	u.obuf
+#define	xbuf	u.ibuf
+
+#pragma	varargck	type	"A"	uint
+#pragma	varargck	type	"D"	Adr*
+#pragma	varargck	type	"P"	Prog*
+#pragma	varargck	type	"R"	int
+#pragma	varargck	type	"S"	char*
+
+EXTERN	long	HEADR;
+EXTERN	long	HEADTYPE;
+EXTERN	vlong	INITDAT;
+EXTERN	long	INITRND;
+EXTERN	vlong	INITTEXT;
+EXTERN	char*	INITENTRY;		/* entry point */
+EXTERN	Biobuf	bso;
+EXTERN	long	bsssize;
+EXTERN	int	cbc;
+EXTERN	char*	cbp;
+EXTERN	char*	pcstr;
+EXTERN	int	cout;
+EXTERN	Auto*	curauto;
+EXTERN	Auto*	curhist;
+EXTERN	Prog*	curp;
+EXTERN	Prog*	curtext;
+EXTERN	Prog*	datap;
+EXTERN	Prog*	edatap;
+EXTERN	vlong	datsize;
+EXTERN	char	debug[128];
+EXTERN	char	literal[32];
+EXTERN	Prog*	etextp;
+EXTERN	Prog*	firstp;
+EXTERN	uchar	fnuxi8[8];
+EXTERN	uchar	fnuxi4[4];
+EXTERN	Sym*	hash[NHASH];
+EXTERN	Sym*	histfrog[MAXHIST];
+EXTERN	int	histfrogp;
+EXTERN	int	histgen;
+EXTERN	char*	library[50];
+EXTERN	char*	libraryobj[50];
+EXTERN	int	libraryp;
+EXTERN	int	xrefresolv;
+EXTERN	char*	hunk;
+EXTERN	uchar	inuxi1[1];
+EXTERN	uchar	inuxi2[2];
+EXTERN	uchar	inuxi4[4];
+EXTERN	uchar	inuxi8[8];
+EXTERN	char	ycover[Ymax*Ymax];
+EXTERN	uchar*	andptr;
+EXTERN	uchar*	rexptr;
+EXTERN	uchar	and[30];
+EXTERN	int	reg[D_NONE];
+EXTERN	int	regrex[D_NONE+1];
+EXTERN	Prog*	lastp;
+EXTERN	long	lcsize;
+EXTERN	int	nerrors;
+EXTERN	long	nhunk;
+EXTERN	long	nsymbol;
+EXTERN	char*	noname;
+EXTERN	char*	outfile;
+EXTERN	vlong	pc;
+EXTERN	long	spsize;
+EXTERN	Sym*	symlist;
+EXTERN	long	symsize;
+EXTERN	Prog*	textp;
+EXTERN	vlong	textsize;
+EXTERN	long	thunk;
+EXTERN	int	version;
+EXTERN	Prog	zprg;
+EXTERN	int	dtype;
+EXTERN	char*	paramspace;
+
+EXTERN	Adr*	reloca;
+EXTERN	int	doexp, dlm;
+EXTERN	int	imports, nimports;
+EXTERN	int	exports, nexports;
+EXTERN	char*	EXPTAB;
+EXTERN	Prog	undefp;
+
+#define	UP	(&undefp)
+
+extern	Optab	optab[];
+extern	Optab*	opindex[];
+extern	char*	anames[];
+
+int	Aconv(Fmt*);
+int	Dconv(Fmt*);
+int	Pconv(Fmt*);
+int	Rconv(Fmt*);
+int	Sconv(Fmt*);
+void	addhist(long, int);
+Prog*	appendp(Prog*);
+void	asmb(void);
+void	asmdyn(void);
+void	asmins(Prog*);
+void	asmlc(void);
+void	asmsp(void);
+void	asmsym(void);
+vlong	atolwhex(char*);
+Prog*	brchain(Prog*);
+Prog*	brloop(Prog*);
+void	buildop(void);
+void	cflush(void);
+void	ckoff(Sym*, long);
+Prog*	copyp(Prog*);
+double	cputime(void);
+void	datblk(long, long);
+void	diag(char*, ...);
+void	dodata(void);
+void	doinit(void);
+void	doprof1(void);
+void	doprof2(void);
+void	dostkoff(void);
+void	dynreloc(Sym*, ulong, int);
+vlong	entryvalue(void);
+void	errorexit(void);
+void	export(void);
+int	find1(long, int);
+int	find2(long, int);
+void	follow(void);
+void	gethunk(void);
+void	histtoauto(void);
+double	ieeedtod(Ieee*);
+long	ieeedtof(Ieee*);
+void	import(void);
+void	ldobj(int, long, char*);
+void	loadlib(void);
+void	listinit(void);
+Sym*	lookup(char*, int);
+void	lput(long);
+void	lputl(long);
+void	main(int, char*[]);
+void	mkfwd(void);
+void*	mysbrk(ulong);
+void	nuxiinit(void);
+void	objfile(char*);
+int	opsize(Prog*);
+void	patch(void);
+Prog*	prg(void);
+void	readundefs(char*, int);
+int	relinv(int);
+long	reuse(Prog*, Sym*);
+vlong	rnd(vlong, vlong);
+void	span(void);
+void	undef(void);
+void	undefsym(Sym*);
+vlong	vaddr(Adr*);
+void	wput(ushort);
+void	xdefine(char*, int, vlong);
+void	xfol(Prog*);
+int	zaddr(uchar*, Adr*, Sym*[]);
+void	zerosig(char*);
+
+void	machseg(char*, vlong, vlong, vlong, vlong, ulong, ulong, ulong, ulong);
+void	machsect(char*, char*, vlong, vlong, ulong, ulong, ulong, ulong, ulong);
+void	machstack(vlong);
+ulong	machheadr(void);
+
+#pragma	varargck	type	"D"	Adr*
+#pragma	varargck	type	"P"	Prog*
+#pragma	varargck	type	"R"	int
+#pragma	varargck	type	"A"	int
+#pragma	varargck	argpos	diag 1
diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c
new file mode 100644
index 0000000..3af0192
--- /dev/null
+++ b/src/cmd/6l/list.c
@@ -0,0 +1,397 @@
+// Inferno utils/6l/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/list.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	"l.h"
+
+static	Prog*	bigP;
+
+void
+listinit(void)
+{
+
+	fmtinstall('R', Rconv);
+	fmtinstall('A', Aconv);
+	fmtinstall('D', Dconv);
+	fmtinstall('S', Sconv);
+	fmtinstall('P', Pconv);
+}
+
+int
+Pconv(Fmt *fp)
+{
+	char str[STRINGSZ], str1[STRINGSZ];
+	Prog *p;
+
+	p = va_arg(fp->args, Prog*);
+	bigP = p;
+
+	sprint(str1, "(%ld)", p->line);
+	switch(p->as) {
+	case ATEXT:
+		if(p->from.scale) {
+			sprint(str, "%-7s %-7A %D,%d,%D",
+				str1, p->as, &p->from, p->from.scale, &p->to);
+			break;
+		}
+
+	default:
+		sprint(str, "%-7s %-7A %D,%D",
+			str1, p->as, &p->from, &p->to);
+		break;
+
+	case ADATA:
+	case AINIT:
+	case ADYNT:
+		sprint(str, "%-7s %-7A %D/%d,%D",
+			str1, p->as, &p->from, p->from.scale, &p->to);
+		break;
+	}
+	bigP = P;
+	return fmtstrcpy(fp, str);
+}
+
+int
+Aconv(Fmt *fp)
+{
+	int i;
+
+	i = va_arg(fp->args, int);
+	return fmtstrcpy(fp, anames[i]);
+}
+
+int
+Dconv(Fmt *fp)
+{
+	char str[40], s[20];
+	Adr *a;
+	int i;
+
+	a = va_arg(fp->args, Adr*);
+	i = a->type;
+	if(i >= D_INDIR) {
+		if(a->offset)
+			sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
+		else
+			sprint(str, "(%R)", i-D_INDIR);
+		goto brk;
+	}
+	switch(i) {
+
+	default:
+		if(a->offset)
+			sprint(str, "$%lld,%R", a->offset, i);
+		else
+			sprint(str, "%R", i);
+		break;
+
+	case D_NONE:
+		str[0] = 0;
+		break;
+
+	case D_BRANCH:
+		if(bigP != P && bigP->pcond != P)
+			if(a->sym != S)
+				sprint(str, "%llux+%s", bigP->pcond->pc,
+					a->sym->name);
+			else
+				sprint(str, "%llux", bigP->pcond->pc);
+		else
+			sprint(str, "%lld(PC)", a->offset);
+		break;
+
+	case D_EXTERN:
+		if(a->sym) {
+			sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
+			break;
+		}
+		sprint(str, "!!noname!!+%lld(SB)", a->offset);
+		break;
+
+	case D_STATIC:
+		if(a->sym) {
+			sprint(str, "%s<%d>+%lld(SB)", a->sym->name,
+				a->sym->version, a->offset);
+			break;
+		}
+		sprint(str, "!!noname!!<999>+%lld(SB)", a->offset);
+		break;
+
+	case D_AUTO:
+		if(a->sym) {
+			sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
+			break;
+		}
+		sprint(str, "!!noname!!+%lld(SP)", a->offset);
+		break;
+
+	case D_PARAM:
+		if(a->sym) {
+			sprint(str, "%s+%lld(%s)", a->sym->name, a->offset, paramspace);
+			break;
+		}
+		sprint(str, "!!noname!!+%lld(%s)", a->offset, paramspace);
+		break;
+
+	case D_CONST:
+		sprint(str, "$%lld", a->offset);
+		break;
+
+	case D_FCONST:
+		sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l);
+		break;
+
+	case D_SCONST:
+		sprint(str, "$\"%S\"", a->scon);
+		break;
+
+	case D_ADDR:
+		a->type = a->index;
+		a->index = D_NONE;
+		sprint(str, "$%D", a);
+		a->index = a->type;
+		a->type = D_ADDR;
+		goto conv;
+	}
+brk:
+	if(a->index != D_NONE) {
+		sprint(s, "(%R*%d)", a->index, a->scale);
+		strcat(str, s);
+	}
+conv:
+	return fmtstrcpy(fp, str);
+}
+
+char*	regstr[] =
+{
+	"AL",		/* [D_AL] */
+	"CL",
+	"DL",
+	"BL",
+	"SPB",
+	"BPB",
+	"SIB",
+	"DIB",
+	"R8B",
+	"R9B",
+	"R10B",
+	"R11B",
+	"R12B",
+	"R13B",
+	"R14B",
+	"R15B",
+
+	"AX",		/* [D_AX] */
+	"CX",
+	"DX",
+	"BX",
+	"SP",
+	"BP",
+	"SI",
+	"DI",
+	"R8",
+	"R9",
+	"R10",
+	"R11",
+	"R12",
+	"R13",
+	"R14",
+	"R15",
+
+	"AH",
+	"CH",
+	"DH",
+	"BH",
+
+	"F0",		/* [D_F0] */
+	"F1",
+	"F2",
+	"F3",
+	"F4",
+	"F5",
+	"F6",
+	"F7",
+
+	"M0",
+	"M1",
+	"M2",
+	"M3",
+	"M4",
+	"M5",
+	"M6",
+	"M7",
+
+	"X0",
+	"X1",
+	"X2",
+	"X3",
+	"X4",
+	"X5",
+	"X6",
+	"X7",
+	"X8",
+	"X9",
+	"X10",
+	"X11",
+	"X12",
+	"X13",
+	"X14",
+	"X15",
+
+	"CS",		/* [D_CS] */
+	"SS",
+	"DS",
+	"ES",
+	"FS",
+	"GS",
+
+	"GDTR",		/* [D_GDTR] */
+	"IDTR",		/* [D_IDTR] */
+	"LDTR",		/* [D_LDTR] */
+	"MSW",		/* [D_MSW] */
+	"TASK",		/* [D_TASK] */
+
+	"CR0",		/* [D_CR] */
+	"CR1",
+	"CR2",
+	"CR3",
+	"CR4",
+	"CR5",
+	"CR6",
+	"CR7",
+	"CR8",
+	"CR9",
+	"CR10",
+	"CR11",
+	"CR12",
+	"CR13",
+	"CR14",
+	"CR15",
+
+	"DR0",		/* [D_DR] */
+	"DR1",
+	"DR2",
+	"DR3",
+	"DR4",
+	"DR5",
+	"DR6",
+	"DR7",
+
+	"TR0",		/* [D_TR] */
+	"TR1",
+	"TR2",
+	"TR3",
+	"TR4",
+	"TR5",
+	"TR6",
+	"TR7",
+
+	"NONE",		/* [D_NONE] */
+};
+
+int
+Rconv(Fmt *fp)
+{
+	char str[20];
+	int r;
+
+	r = va_arg(fp->args, int);
+	if(r >= D_AL && r <= D_NONE)
+		sprint(str, "%s", regstr[r-D_AL]);
+	else
+		sprint(str, "gok(%d)", r);
+
+	return fmtstrcpy(fp, str);
+}
+
+int
+Sconv(Fmt *fp)
+{
+	int i, c;
+	char str[30], *p, *a;
+
+	a = va_arg(fp->args, char*);
+	p = str;
+	for(i=0; i<sizeof(double); i++) {
+		c = a[i] & 0xff;
+		if(c >= 'a' && c <= 'z' ||
+		   c >= 'A' && c <= 'Z' ||
+		   c >= '0' && c <= '9') {
+			*p++ = c;
+			continue;
+		}
+		*p++ = '\\';
+		switch(c) {
+		default:
+			if(c < 040 || c >= 0177)
+				break;	/* not portable */
+			p[-1] = c;
+			continue;
+		case 0:
+			*p++ = 'z';
+			continue;
+		case '\\':
+		case '"':
+			*p++ = c;
+			continue;
+		case '\n':
+			*p++ = 'n';
+			continue;
+		case '\t':
+			*p++ = 't';
+			continue;
+		}
+		*p++ = (c>>6) + '0';
+		*p++ = ((c>>3) & 7) + '0';
+		*p++ = (c & 7) + '0';
+	}
+	*p = 0;
+	return fmtstrcpy(fp, str);
+}
+
+void
+diag(char *fmt, ...)
+{
+	char buf[STRINGSZ], *tn;
+	va_list arg;
+
+	tn = "??none??";
+	if(curtext != P && curtext->from.sym != S)
+		tn = curtext->from.sym->name;
+	va_start(arg, fmt);
+	vseprint(buf, buf+sizeof(buf), fmt, arg);
+	va_end(arg);
+	print("%s: %s\n", tn, buf);
+
+	nerrors++;
+	if(nerrors > 20) {
+		print("too many errors\n");
+		errorexit();
+	}
+}
diff --git a/src/cmd/6l/mkenam b/src/cmd/6l/mkenam
new file mode 100644
index 0000000..fc91828
--- /dev/null
+++ b/src/cmd/6l/mkenam
@@ -0,0 +1,45 @@
+# Inferno utils/6c/mkenam
+# http://code.google.com/p/inferno-os/source/browse/utils/6c/mkenam
+#
+#	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+#	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+#	Portions Copyright © 1997-1999 Vita Nuova Limited
+#	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+#	Portions Copyright © 2004,2006 Bruce Ellis
+#	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+#	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+#	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+#
+# 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
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+ed - ../6l/6.out.h <<'!'
+v/^	A/d
+,s/^	A/	"/
+g/ .*$/s///
+,s/,*$/",/
+1i
+char*	anames[] =
+{
+.
+$a
+};
+.
+w enam.c
+Q
+!
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
new file mode 100644
index 0000000..55dcaac
--- /dev/null
+++ b/src/cmd/6l/obj.c
@@ -0,0 +1,1595 @@
+// Inferno utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#define	EXTERN
+#include	"l.h"
+#include	<ar.h>
+
+#ifndef	DEFAULT
+#define	DEFAULT	'9'
+#endif
+
+char	*noname		= "<none>";
+char	symname[]	= SYMDEF;
+char	thechar		= '6';
+char	*thestring 	= "amd64";
+char	*paramspace	= "FP";
+
+/*
+ *	-H2 -T4136 -R4096		is plan9 64-bit format
+ *	-H3 -T4128 -R4096		is plan9 32-bit format
+ *	-H5 -T0x80110000 -R4096		is ELF32
+ *	-H6 -Tx -Rx			is apple MH-exec
+ *
+ *	options used: 189BLQSWabcjlnpsvz
+ */
+
+static int
+isobjfile(char *f)
+{
+	int n, v;
+	Biobuf *b;
+	char buf1[5], buf2[SARMAG];
+
+	b = Bopen(f, OREAD);
+	if(b == nil)
+		return 0;
+	n = Bread(b, buf1, 5);
+	if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
+		v = 1;	/* good enough for our purposes */
+	else{
+		Bseek(b, 0, 0);
+		n = Bread(b, buf2, SARMAG);
+		v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
+	}
+	Bterm(b);
+	return v;
+}
+
+void
+main(int argc, char *argv[])
+{
+	int i, c;
+	char *a;
+
+	Binit(&bso, 1, OWRITE);
+	cout = -1;
+	listinit();
+	memset(debug, 0, sizeof(debug));
+	nerrors = 0;
+	outfile = "6.out";
+	HEADTYPE = -1;
+	INITTEXT = -1;
+	INITDAT = -1;
+	INITRND = -1;
+	INITENTRY = 0;
+HEADTYPE = 6;	// botch
+	ARGBEGIN {
+	default:
+		c = ARGC();
+		if(c >= 0 && c < sizeof(debug))
+			debug[c]++;
+		break;
+	case 'o': /* output to (next arg) */
+		outfile = ARGF();
+		break;
+	case 'E':
+		a = ARGF();
+		if(a)
+			INITENTRY = a;
+		break;
+	case 'H':
+		a = ARGF();
+		if(a)
+			HEADTYPE = atolwhex(a);
+		break;
+	case 'T':
+		a = ARGF();
+		if(a)
+			INITTEXT = atolwhex(a);
+		break;
+	case 'D':
+		a = ARGF();
+		if(a)
+			INITDAT = atolwhex(a);
+		break;
+	case 'R':
+		a = ARGF();
+		if(a)
+			INITRND = atolwhex(a);
+		break;
+	case 'x':	/* produce export table */
+		doexp = 1;
+		if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
+			readundefs(ARGF(), SEXPORT);
+		break;
+	case 'u':	/* produce dynamically loadable module */
+		dlm = 1;
+		debug['l']++;
+		if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
+			readundefs(ARGF(), SIMPORT);
+		break;
+	} ARGEND
+	USED(argc);
+	if(*argv == 0) {
+		diag("usage: 6l [-options] objects");
+		errorexit();
+	}
+	if(!debug['9'] && !debug['U'] && !debug['B'])
+		debug[DEFAULT] = 1;
+	if(HEADTYPE == -1) {
+		if(debug['B'])
+			HEADTYPE = 2;
+		if(debug['9'])
+			HEADTYPE = 2;
+	}
+	switch(HEADTYPE) {
+	default:
+		diag("unknown -H option");
+		errorexit();
+	case 2:	/* plan 9 */
+		HEADR = 32L+8L;
+		if(INITTEXT == -1)
+			INITTEXT = 4096+HEADR;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		if(INITRND == -1)
+			INITRND = 4096;
+		break;
+	case 3:	/* plan 9 */
+		HEADR = 32L;
+		if(INITTEXT == -1)
+			INITTEXT = 4096+32;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		if(INITRND == -1)
+			INITRND = 4096;
+		break;
+	case 5:	/* elf32 executable */
+		HEADR = rnd(52L+3*32L, 16);
+		if(INITTEXT == -1)
+			INITTEXT = 0x80110000L;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		if(INITRND == -1)
+			INITRND = 4096;
+		break;
+	case 6:	/* apple MACH */
+		HEADR = machheadr();
+		if(INITTEXT == -1)
+			INITTEXT = 4096+HEADR;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		if(INITRND == -1)
+			INITRND = 4096;
+		break;
+	}
+	if(INITDAT != 0 && INITRND != 0)
+		print("warning: -D0x%llux is ignored because of -R0x%lux\n",
+			INITDAT, INITRND);
+	if(debug['v'])
+		Bprint(&bso, "HEADER = -H%ld -T0x%llux -D0x%llux -R0x%lux\n",
+			HEADTYPE, INITTEXT, INITDAT, INITRND);
+	Bflush(&bso);
+	for(i=1; optab[i].as; i++) {
+		c = optab[i].as;
+		if(opindex[c] != nil) {
+			diag("phase error in optab: %d (%A)", i, c);
+			errorexit();
+		}
+		opindex[c] = &optab[i];
+	}
+
+	for(i=0; i<Ymax; i++)
+		ycover[i*Ymax + i] = 1;
+
+	ycover[Yi0*Ymax + Yi8] = 1;
+	ycover[Yi1*Ymax + Yi8] = 1;
+
+	ycover[Yi0*Ymax + Ys32] = 1;
+	ycover[Yi1*Ymax + Ys32] = 1;
+	ycover[Yi8*Ymax + Ys32] = 1;
+
+	ycover[Yi0*Ymax + Yi32] = 1;
+	ycover[Yi1*Ymax + Yi32] = 1;
+	ycover[Yi8*Ymax + Yi32] = 1;
+	ycover[Ys32*Ymax + Yi32] = 1;
+
+	ycover[Yi0*Ymax + Yi64] = 1;
+	ycover[Yi1*Ymax + Yi64] = 1;
+	ycover[Yi8*Ymax + Yi64] = 1;
+	ycover[Ys32*Ymax + Yi64] = 1;
+	ycover[Yi32*Ymax + Yi64] = 1;
+
+	ycover[Yal*Ymax + Yrb] = 1;
+	ycover[Ycl*Ymax + Yrb] = 1;
+	ycover[Yax*Ymax + Yrb] = 1;
+	ycover[Ycx*Ymax + Yrb] = 1;
+	ycover[Yrx*Ymax + Yrb] = 1;
+	ycover[Yrl*Ymax + Yrb] = 1;
+
+	ycover[Ycl*Ymax + Ycx] = 1;
+
+	ycover[Yax*Ymax + Yrx] = 1;
+	ycover[Ycx*Ymax + Yrx] = 1;
+
+	ycover[Yax*Ymax + Yrl] = 1;
+	ycover[Ycx*Ymax + Yrl] = 1;
+	ycover[Yrx*Ymax + Yrl] = 1;
+
+	ycover[Yf0*Ymax + Yrf] = 1;
+
+	ycover[Yal*Ymax + Ymb] = 1;
+	ycover[Ycl*Ymax + Ymb] = 1;
+	ycover[Yax*Ymax + Ymb] = 1;
+	ycover[Ycx*Ymax + Ymb] = 1;
+	ycover[Yrx*Ymax + Ymb] = 1;
+	ycover[Yrb*Ymax + Ymb] = 1;
+	ycover[Yrl*Ymax + Ymb] = 1;
+	ycover[Ym*Ymax + Ymb] = 1;
+
+	ycover[Yax*Ymax + Yml] = 1;
+	ycover[Ycx*Ymax + Yml] = 1;
+	ycover[Yrx*Ymax + Yml] = 1;
+	ycover[Yrl*Ymax + Yml] = 1;
+	ycover[Ym*Ymax + Yml] = 1;
+
+	ycover[Yax*Ymax + Ymm] = 1;
+	ycover[Ycx*Ymax + Ymm] = 1;
+	ycover[Yrx*Ymax + Ymm] = 1;
+	ycover[Yrl*Ymax + Ymm] = 1;
+	ycover[Ym*Ymax + Ymm] = 1;
+	ycover[Ymr*Ymax + Ymm] = 1;
+
+	ycover[Yax*Ymax + Yxm] = 1;
+	ycover[Ycx*Ymax + Yxm] = 1;
+	ycover[Yrx*Ymax + Yxm] = 1;
+	ycover[Yrl*Ymax + Yxm] = 1;
+	ycover[Ym*Ymax + Yxm] = 1;
+	ycover[Yxr*Ymax + Yxm] = 1;
+
+	for(i=0; i<D_NONE; i++) {
+		reg[i] = -1;
+		if(i >= D_AL && i <= D_R15B) {
+			reg[i] = (i-D_AL) & 7;
+			if(i >= D_SPB && i <= D_DIB)
+				regrex[i] = 0x40;
+			if(i >= D_R8B && i <= D_R15B)
+				regrex[i] = Rxr | Rxx | Rxb;
+		}
+		if(i >= D_AH && i<= D_BH)
+			reg[i] = 4 + ((i-D_AH) & 7);
+		if(i >= D_AX && i <= D_R15) {
+			reg[i] = (i-D_AX) & 7;
+			if(i >= D_R8)
+				regrex[i] = Rxr | Rxx | Rxb;
+		}
+		if(i >= D_F0 && i <= D_F0+7)
+			reg[i] = (i-D_F0) & 7;
+		if(i >= D_M0 && i <= D_M0+7)
+			reg[i] = (i-D_M0) & 7;
+		if(i >= D_X0 && i <= D_X0+15) {
+			reg[i] = (i-D_X0) & 7;
+			if(i >= D_X0+8)
+				regrex[i] = Rxr | Rxx | Rxb;
+		}
+		if(i >= D_CR+8 && i <= D_CR+15) 
+			regrex[i] = Rxr;
+	}
+
+	zprg.link = P;
+	zprg.pcond = P;
+	zprg.back = 2;
+	zprg.as = AGOK;
+	zprg.from.type = D_NONE;
+	zprg.from.index = D_NONE;
+	zprg.from.scale = 1;
+	zprg.to = zprg.from;
+	zprg.mode = 64;
+
+	pcstr = "%.6llux ";
+	nuxiinit();
+	histgen = 0;
+	textp = P;
+	datap = P;
+	edatap = P;
+	pc = 0;
+	dtype = 4;
+	cout = create(outfile, 1, 0775);
+	if(cout < 0) {
+		diag("cannot create %s", outfile);
+		errorexit();
+	}
+	version = 0;
+	cbp = buf.cbuf;
+	cbc = sizeof(buf.cbuf);
+	firstp = prg();
+	lastp = firstp;
+
+	if(INITENTRY == 0) {
+		INITENTRY = "_main";
+		if(debug['p'])
+			INITENTRY = "_mainp";
+		if(!debug['l'])
+			lookup(INITENTRY, 0)->type = SXREF;
+	} else if(!(*INITENTRY >= '0' && *INITENTRY <= '9'))
+		lookup(INITENTRY, 0)->type = SXREF;
+
+	while(*argv)
+		objfile(*argv++);
+	if(!debug['l'])
+		loadlib();
+	firstp = firstp->link;
+	if(firstp == P)
+		errorexit();
+	if(doexp || dlm){
+		EXPTAB = "_exporttab";
+		zerosig(EXPTAB);
+		zerosig("etext");
+		zerosig("edata");
+		zerosig("end");
+		if(dlm){
+			import();
+			HEADTYPE = 2;
+			INITTEXT = 0;
+			INITDAT = 0;
+			INITRND = 8;
+			INITENTRY = EXPTAB;
+		}
+		export();
+	}
+	patch();
+	follow();
+	dodata();
+	dostkoff();
+	paramspace = "SP";	/* (FP) now (SP) on output */
+	if(debug['p'])
+		if(debug['1'])
+			doprof1();
+		else
+			doprof2();
+	span();
+	doinit();
+	asmb();
+	undef();
+	if(debug['v']) {
+		Bprint(&bso, "%5.2f cpu time\n", cputime());
+		Bprint(&bso, "%ld symbols\n", nsymbol);
+		Bprint(&bso, "%ld memory used\n", thunk);
+		Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
+		Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
+	}
+	Bflush(&bso);
+
+	errorexit();
+}
+
+void
+loadlib(void)
+{
+	int i;
+	long h;
+	Sym *s;
+
+loop:
+	xrefresolv = 0;
+	for(i=0; i<libraryp; i++) {
+		if(debug['v'])
+			Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
+		objfile(library[i]);
+	}
+	if(xrefresolv)
+	for(h=0; h<nelem(hash); h++)
+	for(s = hash[h]; s != S; s = s->link)
+		if(s->type == SXREF)
+			goto loop;
+}
+
+void
+errorexit(void)
+{
+
+	if(nerrors) {
+		if(cout >= 0)
+			remove(outfile);
+		exits("error");
+	}
+	exits(0);
+}
+
+void
+objfile(char *file)
+{
+	long off, esym, cnt, l;
+	int f, work;
+	Sym *s;
+	char magbuf[SARMAG];
+	char name[100], pname[150];
+	struct ar_hdr arhdr;
+	char *e, *start, *stop;
+
+	if(file[0] == '-' && file[1] == 'l') {
+		if(debug['9'])
+			sprint(name, "/%s/lib/lib", thestring);
+		else
+			sprint(name, "/usr/%clib/lib", thechar);
+		strcat(name, file+2);
+		strcat(name, ".a");
+		file = name;
+	}
+	if(debug['v'])
+		Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
+	Bflush(&bso);
+	f = open(file, 0);
+	if(f < 0) {
+		diag("cannot open file: %s", file);
+		errorexit();
+	}
+	l = read(f, magbuf, SARMAG);
+	if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+		/* load it as a regular file */
+		l = seek(f, 0L, 2);
+		seek(f, 0L, 0);
+		ldobj(f, l, file);
+		close(f);
+		return;
+	}
+
+	l = read(f, &arhdr, SAR_HDR);
+	if(l != SAR_HDR) {
+		diag("%s: short read on archive file symbol header", file);
+		goto out;
+	}
+	if(strncmp(arhdr.name, symname, strlen(symname))) {
+		diag("%s: first entry not symbol header", file);
+		goto out;
+	}
+
+	esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
+	off = SARMAG + SAR_HDR;
+
+	/*
+	 * just bang the whole symbol file into memory
+	 */
+	seek(f, off, 0);
+	cnt = esym - off;
+	start = malloc(cnt + 10);
+	cnt = read(f, start, cnt);
+	if(cnt <= 0){
+		close(f);
+		return;
+	}
+	stop = &start[cnt];
+	memset(stop, 0, 10);
+
+	work = 1;
+	while(work) {
+		if(debug['v'])
+			Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
+		Bflush(&bso);
+		work = 0;
+		for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
+			s = lookup(e+5, 0);
+			if(s->type != SXREF)
+				continue;
+			sprint(pname, "%s(%s)", file, s->name);
+			if(debug['v'])
+				Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
+			Bflush(&bso);
+			l = e[1] & 0xff;
+			l |= (e[2] & 0xff) << 8;
+			l |= (e[3] & 0xff) << 16;
+			l |= (e[4] & 0xff) << 24;
+			seek(f, l, 0);
+			l = read(f, &arhdr, SAR_HDR);
+			if(l != SAR_HDR)
+				goto bad;
+			if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
+				goto bad;
+			l = atolwhex(arhdr.size);
+			ldobj(f, l, pname);
+			if(s->type == SXREF) {
+				diag("%s: failed to load: %s", file, s->name);
+				errorexit();
+			}
+			work = 1;
+			xrefresolv = 1;
+		}
+	}
+	return;
+
+bad:
+	diag("%s: bad or out of date archive", file);
+out:
+	close(f);
+}
+
+int
+zaddr(uchar *p, Adr *a, Sym *h[])
+{
+	int c, t, i;
+	long l;
+	Sym *s;
+	Auto *u;
+
+	t = p[0];
+	c = 1;
+	if(t & T_INDEX) {
+		a->index = p[c];
+		a->scale = p[c+1];
+		c += 2;
+	} else {
+		a->index = D_NONE;
+		a->scale = 0;
+	}
+	a->offset = 0;
+	if(t & T_OFFSET) {
+		/*
+		 * Hack until Charles fixes the compiler.
+		a->offset = (long)(p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24));
+		 */
+		l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+		a->offset = l;
+		c += 4;
+		if(t & T_64) {
+			l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+			a->offset = ((vlong)l<<32) | (a->offset & 0xFFFFFFFFUL);
+			c += 4;
+		}
+	}
+	a->sym = S;
+	if(t & T_SYM) {
+		a->sym = h[p[c]];
+		c++;
+	}
+	a->type = D_NONE;
+	if(t & T_FCONST) {
+		a->ieee.l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
+		a->ieee.h = p[c+4] | (p[c+5]<<8) | (p[c+6]<<16) | (p[c+7]<<24);
+		c += 8;
+		a->type = D_FCONST;
+	} else
+	if(t & T_SCONST) {
+		for(i=0; i<NSNAME; i++)
+			a->scon[i] = p[c+i];
+		c += NSNAME;
+		a->type = D_SCONST;
+	}
+	if(t & T_TYPE) {
+		a->type = p[c];
+		c++;
+	}
+	s = a->sym;
+	if(s == S)
+		return c;
+
+	t = a->type;
+	if(t != D_AUTO && t != D_PARAM)
+		return c;
+	l = a->offset;
+	for(u=curauto; u; u=u->link) {
+		if(u->asym == s)
+		if(u->type == t) {
+			if(u->aoffset > l)
+				u->aoffset = l;
+			return c;
+		}
+	}
+
+	u = mal(sizeof(*u));
+	u->link = curauto;
+	curauto = u;
+	u->asym = s;
+	u->aoffset = l;
+	u->type = t;
+	return c;
+}
+
+void
+addlib(char *obj)
+{
+	char name[1024], comp[256], *p;
+	int i;
+
+	if(histfrogp <= 0)
+		return;
+
+	if(histfrog[0]->name[1] == '/') {
+		sprint(name, "");
+		i = 1;
+	} else
+	if(histfrog[0]->name[1] == '.') {
+		sprint(name, ".");
+		i = 0;
+	} else {
+		if(debug['9'])
+			sprint(name, "/%s/lib", thestring);
+		else
+			sprint(name, "/usr/%clib", thechar);
+		i = 0;
+	}
+
+	for(; i<histfrogp; i++) {
+		snprint(comp, sizeof comp, histfrog[i]->name+1);
+		for(;;) {
+			p = strstr(comp, "$O");
+			if(p == 0)
+				break;
+			memmove(p+1, p+2, strlen(p+2)+1);
+			p[0] = thechar;
+		}
+		for(;;) {
+			p = strstr(comp, "$M");
+			if(p == 0)
+				break;
+			if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
+				diag("library component too long");
+				return;
+			}
+			memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
+			memmove(p, thestring, strlen(thestring));
+		}
+		if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
+			diag("library component too long");
+			return;
+		}
+		strcat(name, "/");
+		strcat(name, comp);
+	}
+	for(i=0; i<libraryp; i++)
+		if(strcmp(name, library[i]) == 0)
+			return;
+	if(libraryp == nelem(library)){
+		diag("too many autolibs; skipping %s", name);
+		return;
+	}
+
+	p = malloc(strlen(name) + 1);
+	strcpy(p, name);
+	library[libraryp] = p;
+	p = malloc(strlen(obj) + 1);
+	strcpy(p, obj);
+	libraryobj[libraryp] = p;
+	libraryp++;
+}
+
+void
+addhist(long line, int type)
+{
+	Auto *u;
+	Sym *s;
+	int i, j, k;
+
+	u = malloc(sizeof(Auto));
+	s = malloc(sizeof(Sym));
+	s->name = malloc(2*(histfrogp+1) + 1);
+
+	u->asym = s;
+	u->type = type;
+	u->aoffset = line;
+	u->link = curhist;
+	curhist = u;
+
+	j = 1;
+	for(i=0; i<histfrogp; i++) {
+		k = histfrog[i]->value;
+		s->name[j+0] = k>>8;
+		s->name[j+1] = k;
+		j += 2;
+	}
+}
+
+void
+histtoauto(void)
+{
+	Auto *l;
+
+	while(l = curhist) {
+		curhist = l->link;
+		l->link = curauto;
+		curauto = l;
+	}
+}
+
+void
+collapsefrog(Sym *s)
+{
+	int i;
+
+	/*
+	 * bad encoding of path components only allows
+	 * MAXHIST components. if there is an overflow,
+	 * first try to collapse xxx/..
+	 */
+	for(i=1; i<histfrogp; i++)
+		if(strcmp(histfrog[i]->name+1, "..") == 0) {
+			memmove(histfrog+i-1, histfrog+i+1,
+				(histfrogp-i-1)*sizeof(histfrog[0]));
+			histfrogp--;
+			goto out;
+		}
+
+	/*
+	 * next try to collapse .
+	 */
+	for(i=0; i<histfrogp; i++)
+		if(strcmp(histfrog[i]->name+1, ".") == 0) {
+			memmove(histfrog+i, histfrog+i+1,
+				(histfrogp-i-1)*sizeof(histfrog[0]));
+			goto out;
+		}
+
+	/*
+	 * last chance, just truncate from front
+	 */
+	memmove(histfrog+0, histfrog+1,
+		(histfrogp-1)*sizeof(histfrog[0]));
+
+out:
+	histfrog[histfrogp-1] = s;
+}
+
+void
+nopout(Prog *p)
+{
+	p->as = ANOP;
+	p->from.type = D_NONE;
+	p->to.type = D_NONE;
+}
+
+uchar*
+readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
+{
+	int n;
+
+	n = stop - good;
+	memmove(buf, good, stop - good);
+	stop = buf + n;
+	n = MAXIO - n;
+	if(n > max)
+		n = max;
+	n = read(f, stop, n);
+	if(n <= 0)
+		return 0;
+	return stop + n;
+}
+
+void
+ldobj(int f, long c, char *pn)
+{
+	vlong ipc;
+	Prog *p, *t;
+	uchar *bloc, *bsize, *stop;
+	int v, o, r, skip, mode;
+	Sym *h[NSYM], *s, *di;
+	ulong sig;
+	static int files;
+	static char **filen;
+	char **nfilen;
+
+	if((files&15) == 0){
+		nfilen = malloc((files+16)*sizeof(char*));
+		memmove(nfilen, filen, files*sizeof(char*));
+		free(filen);
+		filen = nfilen;
+	}
+	filen[files++] = strdup(pn);
+
+	di = S;
+
+	/* check the header */
+	bsize = readsome(f, buf.xbuf, buf.xbuf, buf.xbuf, c);
+	if(bsize == 0)
+		goto eof;
+	bloc = buf.xbuf;
+	r = bsize - bloc;
+	if(r < 7)
+		goto eof;
+	if(memcmp(bloc, "x86-64\n", 7) != 0) {
+		diag("file not x86-64: %s\n", pn);
+		return;
+	}
+
+hloop:
+	/* skip over exports */
+	while(bloc+3 <= bsize) {
+		if(bloc[0] == '\n' && bloc[1] == '!' && bloc[2] == '\n') {
+			bloc += 3;
+			c -= 3;
+			goto newloop;
+		}
+		bloc++;
+		c--;
+	}
+	bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+	if(bsize == 0)
+		goto eof;
+	bloc = buf.xbuf;
+	r = bsize - bloc;
+	if(r < 3)
+		goto eof;
+	goto hloop;
+
+newloop:
+	memset(h, 0, sizeof(h));
+	version++;
+	histfrogp = 0;
+	ipc = pc;
+	skip = 0;
+	mode = 64;
+
+loop:
+	if(c <= 0)
+		goto eof;
+	r = bsize - bloc;
+	if(r < 100 && r < c) {		/* enough for largest prog */
+		bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+		if(bsize == 0)
+			goto eof;
+		bloc = buf.xbuf;
+		goto loop;
+	}
+	o = bloc[0] | (bloc[1] << 8);
+	if(o <= AXXX || o >= ALAST) {
+		if(o < 0)
+			goto eof;
+		diag("%s: opcode out of range %d", pn, o);
+		print("	probably not a .6 file\n");
+		errorexit();
+	}
+
+	if(o == ANAME || o == ASIGNAME) {
+		sig = 0;
+		if(o == ASIGNAME) {
+			sig = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24);
+			bloc += 4;
+			c -= 4;
+		}
+		stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
+		if(stop == 0){
+			bsize = readsome(f, buf.xbuf, bloc, bsize, c);
+			if(bsize == 0)
+				goto eof;
+			bloc = buf.xbuf;
+			stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
+			if(stop == 0){
+				fprint(2, "%s: name too long\n", pn);
+				errorexit();
+			}
+		}
+		v = bloc[2];	/* type */
+		o = bloc[3];	/* sym */
+		bloc += 4;
+		c -= 4;
+
+		r = 0;
+		if(v == D_STATIC)
+			r = version;
+		s = lookup((char*)bloc, r);
+		c -= &stop[1] - bloc;
+		bloc = stop + 1;
+
+		if(debug['S'] && r == 0)
+			sig = 1729;
+		if(sig != 0){
+			if(s->sig != 0 && s->sig != sig)
+				diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name);
+			s->sig = sig;
+			s->file = files-1;
+		}
+
+		if(debug['W'])
+			print("	ANAME	%s\n", s->name);
+		h[o] = s;
+		if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
+			s->type = SXREF;
+		if(v == D_FILE) {
+			if(s->type != SFILE) {
+				histgen++;
+				s->type = SFILE;
+				s->value = histgen;
+			}
+			if(histfrogp < MAXHIST) {
+				histfrog[histfrogp] = s;
+				histfrogp++;
+			} else
+				collapsefrog(s);
+		}
+		goto loop;
+	}
+
+	p = mal(sizeof(*p));
+	p->as = o;
+	p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24);
+	p->back = 2;
+	p->mode = mode;
+	r = zaddr(bloc+6, &p->from, h) + 6;
+	r += zaddr(bloc+r, &p->to, h);
+	bloc += r;
+	c -= r;
+
+	if(debug['W'])
+		print("%P\n", p);
+
+	switch(p->as) {
+	case AHISTORY:
+		if(p->to.offset == -1) {
+			addlib(pn);
+			histfrogp = 0;
+			goto loop;
+		}
+		addhist(p->line, D_FILE);		/* 'z' */
+		if(p->to.offset)
+			addhist(p->to.offset, D_FILE1);	/* 'Z' */
+		histfrogp = 0;
+		goto loop;
+
+	case AEND:
+		histtoauto();
+		if(curtext != P)
+			curtext->to.autom = curauto;
+		curauto = 0;
+		curtext = P;
+		if(c)
+			goto newloop;
+		return;
+
+	case AGLOBL:
+		s = p->from.sym;
+		if(s->type == 0 || s->type == SXREF) {
+			s->type = SBSS;
+			s->value = 0;
+		}
+		if(s->type != SBSS) {
+			diag("%s: redefinition: %s in %s",
+				pn, s->name, TNAME);
+			s->type = SBSS;
+			s->value = 0;
+		}
+		if(p->to.offset > s->value)
+			s->value = p->to.offset;
+		goto loop;
+
+	case ADYNT:
+		if(p->to.sym == S) {
+			diag("DYNT without a sym\n%P", p);
+			break;
+		}
+		di = p->to.sym;
+		p->from.scale = 4;
+		if(di->type == SXREF) {
+			if(debug['z'])
+				Bprint(&bso, "%P set to %d\n", p, dtype);
+			di->type = SCONST;
+			di->value = dtype;
+			dtype += 4;
+		}
+		if(p->from.sym == S)
+			break;
+
+		p->from.offset = di->value;
+		p->from.sym->type = SDATA;
+		if(curtext == P) {
+			diag("DYNT not in text: %P", p);
+			break;
+		}
+		p->to.sym = curtext->from.sym;
+		p->to.type = D_ADDR;
+		p->to.index = D_EXTERN;
+		goto data;
+
+	case AINIT:
+		if(p->from.sym == S) {
+			diag("INIT without a sym\n%P", p);
+			break;
+		}
+		if(di == S) {
+			diag("INIT without previous DYNT\n%P", p);
+			break;
+		}
+		p->from.offset = di->value;
+		p->from.sym->type = SDATA;
+		goto data;
+
+	case ADATA:
+	data:
+		if(edatap == P)
+			datap = p;
+		else
+			edatap->link = p;
+		edatap = p;
+		p->link = P;
+		goto loop;
+
+	case AGOK:
+		diag("%s: GOK opcode in %s", pn, TNAME);
+		pc++;
+		goto loop;
+
+	case ATEXT:
+		if(curtext != P) {
+			histtoauto();
+			curtext->to.autom = curauto;
+			curauto = 0;
+		}
+		skip = 0;
+		curtext = p;
+		s = p->from.sym;
+		if(s == S) {
+			diag("%s: no TEXT symbol: %P", pn, p);
+			errorexit();
+		}
+		if(s->type != 0 && s->type != SXREF) {
+			if(p->from.scale & DUPOK) {
+				skip = 1;
+				goto casdef;
+			}
+			diag("%s: redefinition: %s\n%P", pn, s->name, p);
+		}
+		s->type = STEXT;
+		s->value = pc;
+		lastp->link = p;
+		lastp = p;
+		p->pc = pc;
+		pc++;
+		if(textp == P) {
+			textp = p;
+			etextp = p;
+			goto loop;
+		}
+		etextp->pcond = p;
+		etextp = p;
+		goto loop;
+
+	case AMODE:
+		if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){
+			switch((int)p->from.offset){
+			case 16: case 32: case 64:
+				mode = p->from.offset;
+				break;
+			}
+		}
+		goto loop;
+
+	case AFMOVF:
+	case AFADDF:
+	case AFSUBF:
+	case AFSUBRF:
+	case AFMULF:
+	case AFDIVF:
+	case AFDIVRF:
+	case AFCOMF:
+	case AFCOMFP:
+	case AMOVSS:
+	case AADDSS:
+	case ASUBSS:
+	case AMULSS:
+	case ADIVSS:
+	case ACOMISS:
+	case AUCOMISS:
+		if(skip)
+			goto casdef;
+		if(p->from.type == D_FCONST) {
+			/* size sb 9 max */
+			sprint(literal, "$%lux", ieeedtof(&p->from.ieee));
+			s = lookup(literal, 0);
+			if(s->type == 0) {
+				s->type = SBSS;
+				s->value = 4;
+				t = prg();
+				t->as = ADATA;
+				t->line = p->line;
+				t->from.type = D_EXTERN;
+				t->from.sym = s;
+				t->from.scale = 4;
+				t->to = p->from;
+				if(edatap == P)
+					datap = t;
+				else
+					edatap->link = t;
+				edatap = t;
+				t->link = P;
+			}
+			p->from.type = D_EXTERN;
+			p->from.sym = s;
+			p->from.offset = 0;
+		}
+		goto casdef;
+
+	case AFMOVD:
+	case AFADDD:
+	case AFSUBD:
+	case AFSUBRD:
+	case AFMULD:
+	case AFDIVD:
+	case AFDIVRD:
+	case AFCOMD:
+	case AFCOMDP:
+	case AMOVSD:
+	case AADDSD:
+	case ASUBSD:
+	case AMULSD:
+	case ADIVSD:
+	case ACOMISD:
+	case AUCOMISD:
+		if(skip)
+			goto casdef;
+		if(p->from.type == D_FCONST) {
+			/* size sb 18 max */
+			sprint(literal, "$%lux.%lux",
+				p->from.ieee.l, p->from.ieee.h);
+			s = lookup(literal, 0);
+			if(s->type == 0) {
+				s->type = SBSS;
+				s->value = 8;
+				t = prg();
+				t->as = ADATA;
+				t->line = p->line;
+				t->from.type = D_EXTERN;
+				t->from.sym = s;
+				t->from.scale = 8;
+				t->to = p->from;
+				if(edatap == P)
+					datap = t;
+				else
+					edatap->link = t;
+				edatap = t;
+				t->link = P;
+			}
+			p->from.type = D_EXTERN;
+			p->from.sym = s;
+			p->from.offset = 0;
+		}
+		goto casdef;
+
+	casdef:
+	default:
+		if(skip)
+			nopout(p);
+
+		if(p->to.type == D_BRANCH)
+			p->to.offset += ipc;
+		lastp->link = p;
+		lastp = p;
+		p->pc = pc;
+		pc++;
+		goto loop;
+	}
+	goto loop;
+
+eof:
+	diag("truncated object file: %s", pn);
+}
+
+Sym*
+lookup(char *symb, int v)
+{
+	Sym *s;
+	char *p;
+	long h;
+	int l, c;
+
+	h = v;
+	for(p=symb; c = *p; p++)
+		h = h+h+h + c;
+	l = (p - symb) + 1;
+	if(h < 0)
+		h = ~h;
+	h %= NHASH;
+	for(s = hash[h]; s != S; s = s->link)
+		if(s->version == v)
+		if(memcmp(s->name, symb, l) == 0)
+			return s;
+
+	s = mal(sizeof(*s));
+
+	s->name = malloc(l + 1);
+	memmove(s->name, symb, l);
+
+	s->link = hash[h];
+	s->type = 0;
+	s->version = v;
+	s->value = 0;
+	s->sig = 0;
+	hash[h] = s;
+	nsymbol++;
+	return s;
+}
+
+Prog*
+prg(void)
+{
+	Prog *p;
+
+	p = mal(sizeof(*p));
+
+	*p = zprg;
+	return p;
+}
+
+Prog*
+copyp(Prog *q)
+{
+	Prog *p;
+
+	p = prg();
+	*p = *q;
+	return p;
+}
+
+Prog*
+appendp(Prog *q)
+{
+	Prog *p;
+
+	p = prg();
+	p->link = q->link;
+	q->link = p;
+	p->line = q->line;
+	p->mode = q->mode;
+	return p;
+}
+
+void
+doprof1(void)
+{
+	Sym *s;
+	long n;
+	Prog *p, *q;
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f profile 1\n", cputime());
+	Bflush(&bso);
+	s = lookup("__mcount", 0);
+	n = 1;
+	for(p = firstp->link; p != P; p = p->link) {
+		if(p->as == ATEXT) {
+			q = prg();
+			q->line = p->line;
+			q->link = datap;
+			datap = q;
+			q->as = ADATA;
+			q->from.type = D_EXTERN;
+			q->from.offset = n*4;
+			q->from.sym = s;
+			q->from.scale = 4;
+			q->to = p->from;
+			q->to.type = D_CONST;
+
+			q = prg();
+			q->line = p->line;
+			q->pc = p->pc;
+			q->link = p->link;
+			p->link = q;
+			p = q;
+			p->as = AADDL;
+			p->from.type = D_CONST;
+			p->from.offset = 1;
+			p->to.type = D_EXTERN;
+			p->to.sym = s;
+			p->to.offset = n*4 + 4;
+
+			n += 2;
+			continue;
+		}
+	}
+	q = prg();
+	q->line = 0;
+	q->link = datap;
+	datap = q;
+
+	q->as = ADATA;
+	q->from.type = D_EXTERN;
+	q->from.sym = s;
+	q->from.scale = 4;
+	q->to.type = D_CONST;
+	q->to.offset = n;
+
+	s->type = SBSS;
+	s->value = n*4;
+}
+
+void
+doprof2(void)
+{
+	Sym *s2, *s4;
+	Prog *p, *q, *ps2, *ps4;
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f profile 2\n", cputime());
+	Bflush(&bso);
+
+	s2 = lookup("_profin", 0);
+	s4 = lookup("_profout", 0);
+	if(s2->type != STEXT || s4->type != STEXT) {
+		diag("_profin/_profout not defined");
+		return;
+	}
+
+	ps2 = P;
+	ps4 = P;
+	for(p = firstp; p != P; p = p->link) {
+		if(p->as == ATEXT) {
+			if(p->from.sym == s2) {
+				p->from.scale = 1;
+				ps2 = p;
+			}
+			if(p->from.sym == s4) {
+				p->from.scale = 1;
+				ps4 = p;
+			}
+		}
+	}
+	for(p = firstp; p != P; p = p->link) {
+		if(p->as == ATEXT) {
+			curtext = p;
+
+			if(p->from.scale & NOPROF) {	/* dont profile */
+				for(;;) {
+					q = p->link;
+					if(q == P)
+						break;
+					if(q->as == ATEXT)
+						break;
+					p = q;
+				}
+				continue;
+			}
+
+			/*
+			 * JMPL	profin
+			 */
+			q = prg();
+			q->line = p->line;
+			q->pc = p->pc;
+			q->link = p->link;
+			p->link = q;
+			p = q;
+			p->as = ACALL;
+			p->to.type = D_BRANCH;
+			p->pcond = ps2;
+			p->to.sym = s2;
+
+			continue;
+		}
+		if(p->as == ARET) {
+			/*
+			 * RET
+			 */
+			q = prg();
+			q->as = ARET;
+			q->from = p->from;
+			q->to = p->to;
+			q->link = p->link;
+			p->link = q;
+
+			/*
+			 * JAL	profout
+			 */
+			p->as = ACALL;
+			p->from = zprg.from;
+			p->to = zprg.to;
+			p->to.type = D_BRANCH;
+			p->pcond = ps4;
+			p->to.sym = s4;
+
+			p = q;
+
+			continue;
+		}
+	}
+}
+
+void
+nuxiinit(void)
+{
+	int i, c;
+
+	for(i=0; i<4; i++) {
+		c = find1(0x04030201L, i+1);
+		if(i < 2)
+			inuxi2[i] = c;
+		if(i < 1)
+			inuxi1[i] = c;
+		inuxi4[i] = c;
+		inuxi8[i] = c;
+		inuxi8[i+4] = c+4;
+		fnuxi4[i] = c;
+		fnuxi8[i] = c;
+		fnuxi8[i+4] = c+4;
+	}
+	if(debug['v']) {
+		Bprint(&bso, "inuxi = ");
+		for(i=0; i<1; i++)
+			Bprint(&bso, "%d", inuxi1[i]);
+		Bprint(&bso, " ");
+		for(i=0; i<2; i++)
+			Bprint(&bso, "%d", inuxi2[i]);
+		Bprint(&bso, " ");
+		for(i=0; i<4; i++)
+			Bprint(&bso, "%d", inuxi4[i]);
+		Bprint(&bso, " ");
+		for(i=0; i<8; i++)
+			Bprint(&bso, "%d", inuxi8[i]);
+		Bprint(&bso, "\nfnuxi = ");
+		for(i=0; i<4; i++)
+			Bprint(&bso, "%d", fnuxi4[i]);
+		Bprint(&bso, " ");
+		for(i=0; i<8; i++)
+			Bprint(&bso, "%d", fnuxi8[i]);
+		Bprint(&bso, "\n");
+	}
+	Bflush(&bso);
+}
+
+int
+find1(long l, int c)
+{
+	char *p;
+	int i;
+
+	p = (char*)&l;
+	for(i=0; i<4; i++)
+		if(*p++ == c)
+			return i;
+	return 0;
+}
+
+int
+find2(long l, int c)
+{
+	short *p;
+	int i;
+
+	p = (short*)&l;
+	for(i=0; i<4; i+=2) {
+		if(((*p >> 8) & 0xff) == c)
+			return i;
+		if((*p++ & 0xff) == c)
+			return i+1;
+	}
+	return 0;
+}
+
+long
+ieeedtof(Ieee *e)
+{
+	int exp;
+	long v;
+
+	if(e->h == 0)
+		return 0;
+	exp = (e->h>>20) & ((1L<<11)-1L);
+	exp -= (1L<<10) - 2L;
+	v = (e->h & 0xfffffL) << 3;
+	v |= (e->l >> 29) & 0x7L;
+	if((e->l >> 28) & 1) {
+		v++;
+		if(v & 0x800000L) {
+			v = (v & 0x7fffffL) >> 1;
+			exp++;
+		}
+	}
+	if(exp <= -126 || exp >= 130)
+		diag("double fp to single fp overflow");
+	v |= ((exp + 126) & 0xffL) << 23;
+	v |= e->h & 0x80000000L;
+	return v;
+}
+
+double
+ieeedtod(Ieee *ieeep)
+{
+	Ieee e;
+	double fr;
+	int exp;
+
+	if(ieeep->h & (1L<<31)) {
+		e.h = ieeep->h & ~(1L<<31);
+		e.l = ieeep->l;
+		return -ieeedtod(&e);
+	}
+	if(ieeep->l == 0 && ieeep->h == 0)
+		return 0;
+	fr = ieeep->l & ((1L<<16)-1L);
+	fr /= 1L<<16;
+	fr += (ieeep->l>>16) & ((1L<<16)-1L);
+	fr /= 1L<<16;
+	fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
+	fr /= 1L<<21;
+	exp = (ieeep->h>>20) & ((1L<<11)-1L);
+	exp -= (1L<<10) - 2L;
+	return ldexp(fr, exp);
+}
+
+void
+undefsym(Sym *s)
+{
+	int n;
+
+	n = imports;
+	if(s->value != 0)
+		diag("value != 0 on SXREF");
+	if(n >= 1<<Rindex)
+		diag("import index %d out of range", n);
+	s->value = n<<Roffset;
+	s->type = SUNDEF;
+	imports++;
+}
+
+void
+zerosig(char *sp)
+{
+	Sym *s;
+
+	s = lookup(sp, 0);
+	s->sig = 0;
+}
+
+void
+readundefs(char *f, int t)
+{
+	int i, n;
+	Sym *s;
+	Biobuf *b;
+	char *l, buf[256], *fields[64];
+
+	if(f == nil)
+		return;
+	b = Bopen(f, OREAD);
+	if(b == nil){
+		diag("could not open %s: %r", f);
+		errorexit();
+	}
+	while((l = Brdline(b, '\n')) != nil){
+		n = Blinelen(b);
+		if(n >= sizeof(buf)){
+			diag("%s: line too long", f);
+			errorexit();
+		}
+		memmove(buf, l, n);
+		buf[n-1] = '\0';
+		n = getfields(buf, fields, nelem(fields), 1, " \t\r\n");
+		if(n == nelem(fields)){
+			diag("%s: bad format", f);
+			errorexit();
+		}
+		for(i = 0; i < n; i++){
+			s = lookup(fields[i], 0);
+			s->type = SXREF;
+			s->subtype = t;
+			if(t == SIMPORT)
+				nimports++;
+			else
+				nexports++;
+		}
+	}
+	Bterm(b);
+}
diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c
new file mode 100644
index 0000000..d997971
--- /dev/null
+++ b/src/cmd/6l/optab.c
@@ -0,0 +1,1213 @@
+// Inferno utils/6l/optab.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/optab.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	"l.h"
+
+uchar	ynone[] =
+{
+	Ynone,	Ynone,	Zlit,	1,
+	0
+};
+uchar	ytext[] =
+{
+	Ymb,	Yi32,	Zpseudo,1,
+	0
+};
+uchar	ynop[] =
+{
+	Ynone,	Ynone,	Zpseudo,1,
+	Ynone,	Yml,	Zpseudo,1,
+	Ynone,	Yrf,	Zpseudo,1,
+	Yml,	Ynone,	Zpseudo,1,
+	Yrf,	Ynone,	Zpseudo,1,
+	0
+};
+uchar	yxorb[] =
+{
+	Yi32,	Yal,	Zib_,	1,
+	Yi32,	Ymb,	Zibo_m,	2,
+	Yrb,	Ymb,	Zr_m,	1,
+	Ymb,	Yrb,	Zm_r,	1,
+	0
+};
+uchar	yxorl[] =
+{
+	Yi8,	Yml,	Zibo_m,	2,
+	Yi32,	Yax,	Zil_,	1,
+	Yi32,	Yml,	Zilo_m,	2,
+	Yrl,	Yml,	Zr_m,	1,
+	Yml,	Yrl,	Zm_r,	1,
+	0
+};
+uchar	yaddl[] =
+{
+	Yi8,	Yml,	Zibo_m,	2,
+	Yi32,	Yax,	Zil_,	1,
+	Yi32,	Yml,	Zilo_m,	2,
+	Yrl,	Yml,	Zr_m,	1,
+	Yml,	Yrl,	Zm_r,	1,
+	0
+};
+uchar	yincb[] =
+{
+	Ynone,	Ymb,	Zo_m,	2,
+	0
+};
+uchar	yincw[] =
+{
+	Ynone,	Yml,	Zo_m,	2,
+	0
+};
+uchar	yincl[] =
+{
+	Ynone,	Yml,	Zo_m,	2,
+	0
+};
+uchar	ycmpb[] =
+{
+	Yal,	Yi32,	Z_ib,	1,
+	Ymb,	Yi32,	Zm_ibo,	2,
+	Ymb,	Yrb,	Zm_r,	1,
+	Yrb,	Ymb,	Zr_m,	1,
+	0
+};
+uchar	ycmpl[] =
+{
+	Yml,	Yi8,	Zm_ibo,	2,
+	Yax,	Yi32,	Z_il,	1,
+	Yml,	Yi32,	Zm_ilo,	2,
+	Yml,	Yrl,	Zm_r,	1,
+	Yrl,	Yml,	Zr_m,	1,
+	0
+};
+uchar	yshb[] =
+{
+	Yi1,	Ymb,	Zo_m,	2,
+	Yi32,	Ymb,	Zibo_m,	2,
+	Ycx,	Ymb,	Zo_m,	2,
+	0
+};
+uchar	yshl[] =
+{
+	Yi1,	Yml,	Zo_m,	2,
+	Yi32,	Yml,	Zibo_m,	2,
+	Ycl,	Yml,	Zo_m,	2,
+	Ycx,	Yml,	Zo_m,	2,
+	0
+};
+uchar	ytestb[] =
+{
+	Yi32,	Yal,	Zib_,	1,
+	Yi32,	Ymb,	Zibo_m,	2,
+	Yrb,	Ymb,	Zr_m,	1,
+	Ymb,	Yrb,	Zm_r,	1,
+	0
+};
+uchar	ytestl[] =
+{
+	Yi32,	Yax,	Zil_,	1,
+	Yi32,	Yml,	Zilo_m,	2,
+	Yrl,	Yml,	Zr_m,	1,
+	Yml,	Yrl,	Zm_r,	1,
+	0
+};
+uchar	ymovb[] =
+{
+	Yrb,	Ymb,	Zr_m,	1,
+	Ymb,	Yrb,	Zm_r,	1,
+	Yi32,	Yrb,	Zib_rp,	1,
+	Yi32,	Ymb,	Zibo_m,	2,
+	0
+};
+uchar	ymbs[] =
+{
+	Ymb,	Ynone,	Zm_o,	2,
+	0
+};
+uchar	ybtl[] =
+{
+	Yi8,	Yml,	Zibo_m,	2,
+	Yrl,	Yml,	Zr_m,	1,
+	0
+};
+uchar	ymovw[] =
+{
+	Yrl,	Yml,	Zr_m,	1,
+	Yml,	Yrl,	Zm_r,	1,
+	Yi0,	Yrl,	Zclr,	1,
+	Yi32,	Yrl,	Zil_rp,	1,
+	Yi32,	Yml,	Zilo_m,	2,
+	Yiauto,	Yrl,	Zaut_r,	2,
+	0
+};
+uchar	ymovl[] =
+{
+	Yrl,	Yml,	Zr_m,	1,
+	Yml,	Yrl,	Zm_r,	1,
+	Yi0,	Yrl,	Zclr,	1,
+	Yi32,	Yrl,	Zil_rp,	1,
+	Yi32,	Yml,	Zilo_m,	2,
+	Yml,	Ymr,	Zm_r_xm,	1,	// MMX MOVD
+	Ymr,	Yml,	Zr_m_xm,	1,	// MMX MOVD
+	Yml,	Yxr,	Zm_r_xm,	2,	// XMM MOVD (32 bit)
+	Yxr,	Yml,	Zr_m_xm,	2,	// XMM MOVD (32 bit)
+	Yiauto,	Yrl,	Zaut_r,	2,
+	0
+};
+uchar	yret[] =
+{
+	Ynone,	Ynone,	Zo_iw,	1,
+	Yi32,	Ynone,	Zo_iw,	1,
+	0
+};
+uchar	ymovq[] =
+{
+	Yrl,	Yml,	Zr_m,	1,	// 0x89
+	Yml,	Yrl,	Zm_r,	1,	// 0x8b
+	Yi0,	Yrl,	Zclr,	1,	// 0x31
+	Ys32,	Yrl,	Zilo_m,	2,	// 32 bit signed 0xc7,(0)
+	Yi64,	Yrl,	Ziq_rp,	1,	// 0xb8 -- 32/64 bit immediate
+	Yi32,	Yml,	Zilo_m,	2,	// 0xc7,(0)
+	Ym,	Ymr,	Zm_r_xm_nr,	1,	// MMX MOVQ (shorter encoding)
+	Ymr,	Ym,	Zr_m_xm_nr,	1,	// MMX MOVQ
+	Ymm,	Ymr,	Zm_r_xm,	1,	// MMX MOVD
+	Ymr,	Ymm,	Zr_m_xm,	1,	// MMX MOVD
+	Yxr,	Ymr,	Zm_r_xm_nr,	2,	// MOVDQ2Q
+	Yxr,	Ym,	Zr_m_xm_nr,	2,	// MOVQ xmm store
+	Yml,	Yxr,	Zm_r_xm,	2,	// MOVD xmm load
+	Yxr,	Yml,	Zr_m_xm,	2,	// MOVD xmm store
+	Yiauto,	Yrl,	Zaut_r,	2,	// built-in LEAQ
+	0
+};
+uchar	ym_rl[] =
+{
+	Ym,	Yrl,	Zm_r,	1,
+	0
+};
+uchar	yrl_m[] =
+{
+	Yrl,	Ym,	Zr_m,	1,
+	0
+};
+uchar	ymb_rl[] =
+{
+	Ymb,	Yrl,	Zmb_r,	1,
+	0
+};
+uchar	yml_rl[] =
+{
+	Yml,	Yrl,	Zm_r,	1,
+	0
+};
+uchar	yrl_ml[] =
+{
+	Yrl,	Yml,	Zr_m,	1,
+	0
+};
+uchar	yml_mb[] =
+{
+	Yrb,	Ymb,	Zr_m,	1,
+	Ymb,	Yrb,	Zm_r,	1,
+	0
+};
+uchar	yrb_mb[] =
+{
+	Yrb,	Ymb,	Zr_m,	1,
+	0
+};
+uchar	yml_ml[] =
+{
+	Yrl,	Yml,	Zr_m,	1,
+	Yml,	Yrl,	Zm_r,	1,
+	0
+};
+uchar	ydivl[] =
+{
+	Yml,	Ynone,	Zm_o,	2,
+	0
+};
+uchar	ydivb[] =
+{
+	Ymb,	Ynone,	Zm_o,	2,
+	0
+};
+uchar	yimul[] =
+{
+	Yml,	Ynone,	Zm_o,	2,
+	Yi8,	Yrl,	Zib_rr,	1,
+	Yi32,	Yrl,	Zil_rr,	1,
+	Yml,	Yrl,	Zm_r,	2,
+	0
+};
+uchar	ybyte[] =
+{
+	Yi64,	Ynone,	Zbyte,	1,
+	0
+};
+uchar	yin[] =
+{
+	Yi32,	Ynone,	Zib_,	1,
+	Ynone,	Ynone,	Zlit,	1,
+	0
+};
+uchar	yint[] =
+{
+	Yi32,	Ynone,	Zib_,	1,
+	0
+};
+uchar	ypushl[] =
+{
+	Yrl,	Ynone,	Zrp_,	1,
+	Ym,	Ynone,	Zm_o,	2,
+	Yi8,	Ynone,	Zib_,	1,
+	Yi32,	Ynone,	Zil_,	1,
+	0
+};
+uchar	ypopl[] =
+{
+	Ynone,	Yrl,	Z_rp,	1,
+	Ynone,	Ym,	Zo_m,	2,
+	0
+};
+uchar	yscond[] =
+{
+	Ynone,	Ymb,	Zo_m,	2,
+	0
+};
+uchar	yjcond[] =
+{
+	Ynone,	Ybr,	Zbr,	1,
+	0
+};
+uchar	yloop[] =
+{
+	Ynone,	Ybr,	Zloop,	1,
+	0
+};
+uchar	ycall[] =
+{
+	Ynone,	Yml,	Zo_m64,	2,
+	Ynone,	Ybr,	Zcall,	1,
+	0
+};
+uchar	yjmp[] =
+{
+	Ynone,	Yml,	Zo_m64,	2,
+	Ynone,	Ybr,	Zjmp,	1,
+	0
+};
+
+uchar	yfmvd[] =
+{
+	Ym,	Yf0,	Zm_o,	2,
+	Yf0,	Ym,	Zo_m,	2,
+	Yrf,	Yf0,	Zm_o,	2,
+	Yf0,	Yrf,	Zo_m,	2,
+	0
+};
+uchar	yfmvdp[] =
+{
+	Yf0,	Ym,	Zo_m,	2,
+	Yf0,	Yrf,	Zo_m,	2,
+	0
+};
+uchar	yfmvf[] =
+{
+	Ym,	Yf0,	Zm_o,	2,
+	Yf0,	Ym,	Zo_m,	2,
+	0
+};
+uchar	yfmvx[] =
+{
+	Ym,	Yf0,	Zm_o,	2,
+	0
+};
+uchar	yfmvp[] =
+{
+	Yf0,	Ym,	Zo_m,	2,
+	0
+};
+uchar	yfadd[] =
+{
+	Ym,	Yf0,	Zm_o,	2,
+	Yrf,	Yf0,	Zm_o,	2,
+	Yf0,	Yrf,	Zo_m,	2,
+	0
+};
+uchar	yfaddp[] =
+{
+	Yf0,	Yrf,	Zo_m,	2,
+	0
+};
+uchar	yfxch[] =
+{
+	Yf0,	Yrf,	Zo_m,	2,
+	Yrf,	Yf0,	Zm_o,	2,
+	0
+};
+uchar	ycompp[] =
+{
+	Yf0,	Yrf,	Zo_m,	2,	/* botch is really f0,f1 */
+	0
+};
+uchar	ystsw[] =
+{
+	Ynone,	Ym,	Zo_m,	2,
+	Ynone,	Yax,	Zlit,	1,
+	0
+};
+uchar	ystcw[] =
+{
+	Ynone,	Ym,	Zo_m,	2,
+	Ym,	Ynone,	Zm_o,	2,
+	0
+};
+uchar	ysvrs[] =
+{
+	Ynone,	Ym,	Zo_m,	2,
+	Ym,	Ynone,	Zm_o,	2,
+	0
+};
+uchar	ymm[] = 
+{
+	Ymm,	Ymr,	Zm_r_xm,	1,
+	Yxm,	Yxr,	Zm_r_xm,	2,
+	0
+};
+uchar	yxm[] = 
+{
+	Yxm,	Yxr,	Zm_r_xm,	1,
+	0
+};
+uchar	yxcvm1[] = 
+{
+	Yxm,	Yxr,	Zm_r_xm,	2,
+	Yxm,	Ymr,	Zm_r_xm,	2,
+	0
+};
+uchar	yxcvm2[] =
+{
+	Yxm,	Yxr,	Zm_r_xm,	2,
+	Ymm,	Yxr,	Zm_r_xm,	2,
+	0
+};
+uchar	yxmq[] = 
+{
+	Yxm,	Yxr,	Zm_r_xm,	2,
+	0
+};
+uchar	yxr[] = 
+{
+	Yxr,	Yxr,	Zm_r_xm,	1,
+	0
+};
+uchar	yxr_ml[] =
+{
+	Yxr,	Yml,	Zr_m_xm,	1,
+	0
+};
+uchar	ymr[] =
+{
+	Ymr,	Ymr,	Zm_r,	1,
+	0
+};
+uchar	ymr_ml[] =
+{
+	Ymr,	Yml,	Zr_m_xm,	1,
+	0
+};
+uchar	yxcmp[] =
+{
+	Yxm,	Yxr, Zm_r_xm,	1,
+	0
+};
+uchar	yxcmpi[] =
+{
+	Yxm,	Yxr, Zm_r_i_xm,	2,
+	0
+};
+uchar	yxmov[] =
+{
+	Yxm,	Yxr,	Zm_r_xm,	1,
+	Yxr,	Yxm,	Zr_m_xm,	1,
+	0
+};
+uchar	yxcvfl[] = 
+{
+	Yxm,	Yrl,	Zm_r_xm,	1,
+	0
+};
+uchar	yxcvlf[] =
+{
+	Yml,	Yxr,	Zm_r_xm,	1,
+	0
+};
+uchar	yxcvfq[] = 
+{
+	Yxm,	Yrl,	Zm_r_xm,	2,
+	0
+};
+uchar	yxcvqf[] =
+{
+	Yml,	Yxr,	Zm_r_xm,	2,
+	0
+};
+uchar	yps[] = 
+{
+	Ymm,	Ymr,	Zm_r_xm,	1,
+	Yi8,	Ymr,	Zibo_m_xm,	2,
+	Yxm,	Yxr,	Zm_r_xm,	2,
+	Yi8,	Yxr,	Zibo_m_xm,	3,
+	0
+};
+uchar	yxrrl[] =
+{
+	Yxr,	Yrl,	Zm_r,	1,
+	0
+};
+uchar	ymfp[] =
+{
+	Ymm,	Ymr,	Zm_r_3d,	1,
+	0,
+};
+uchar	ymrxr[] =
+{
+	Ymr,	Yxr,	Zm_r,	1,
+	Yxm,	Yxr,	Zm_r_xm,	1,
+	0
+};
+uchar	ymshuf[] =
+{
+	Ymm,	Ymr,	Zibm_r,	1,
+	0
+};
+uchar	yxshuf[] =
+{
+	Yxm,	Yxr,	Zibm_r,	1,
+	0
+};
+uchar	yextrw[] =
+{
+	Yxr,	Yrl,	Zibm_r,	1,
+	0
+};
+uchar	ypsdq[] =
+{
+	Yi8,	Yxr,	Zibo_m,	2,
+	0
+};
+uchar	ymskb[] =
+{
+	Yxr,	Yrl,	Zm_r_xm,	2,
+	Ymr,	Yrl,	Zm_r_xm,	1,
+	0
+};
+
+Optab optab[] =
+/*	as, ytab, andproto, opcode */
+{
+	{ AXXX },
+	{ AAAA,		ynone,	P32, 0x37 },
+	{ AAAD,		ynone,	P32, 0xd5,0x0a },
+	{ AAAM,		ynone,	P32, 0xd4,0x0a },
+	{ AAAS,		ynone,	P32, 0x3f },
+	{ AADCB,	yxorb,	Pb, 0x14,0x80,(02),0x10,0x10 },
+	{ AADCL,	yxorl,	Px, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+	{ AADCQ,	yxorl,	Pw, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+	{ AADCW,	yxorl,	Pe, 0x83,(02),0x15,0x81,(02),0x11,0x13 },
+	{ AADDB,	yxorb,	Pb, 0x04,0x80,(00),0x00,0x02 },
+	{ AADDL,	yaddl,	Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+	{ AADDPD,	yxm,	Pq, 0x58 },
+	{ AADDPS,	yxm,	Pm, 0x58 },
+	{ AADDQ,	yaddl,	Pw, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+	{ AADDSD,	yxm,	Pf2, 0x58 },
+	{ AADDSS,	yxm,	Pf3, 0x58 },
+	{ AADDW,	yaddl,	Pe, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+	{ AADJSP },
+	{ AANDB,	yxorb,	Pb, 0x24,0x80,(04),0x20,0x22 },
+	{ AANDL,	yxorl,	Px, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+	{ AANDNPD,	yxm,	Pq, 0x55 },
+	{ AANDNPS,	yxm,	Pm, 0x55 },
+	{ AANDPD,	yxm,	Pq, 0x54 },
+	{ AANDPS,	yxm,	Pq, 0x54 },
+	{ AANDQ,	yxorl,	Pw, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+	{ AANDW,	yxorl,	Pe, 0x83,(04),0x25,0x81,(04),0x21,0x23 },
+	{ AARPL,	yrl_ml,	P32, 0x63 },
+	{ ABOUNDL,	yrl_m,	P32, 0x62 },
+	{ ABOUNDW,	yrl_m,	Pe, 0x62 },
+	{ ABSFL,	yml_rl,	Pm, 0xbc },
+	{ ABSFQ,	yml_rl,	Pw, 0x0f,0xbc },
+	{ ABSFW,	yml_rl,	Pq, 0xbc },
+	{ ABSRL,	yml_rl,	Pm, 0xbd },
+	{ ABSRQ,	yml_rl,	Pw, 0x0f,0xbd },
+	{ ABSRW,	yml_rl,	Pq, 0xbd },
+	{ ABTCL,	ybtl,	Pm, 0xba,(07),0xbb },
+	{ ABTCQ,	ybtl,	Pw, 0x0f,0xba,(07),0x0f,0xbb },
+	{ ABTCW,	ybtl,	Pq, 0xba,(07),0xbb },
+	{ ABTL,		ybtl,	Pm, 0xba,(04),0xa3 },
+	{ ABTQ,		ybtl,	Pw, 0x0f,0xba,(04),0x0f,0xa3},
+	{ ABTRL,	ybtl,	Pm, 0xba,(06),0xb3 },
+	{ ABTRQ,	ybtl,	Pw, 0x0f,0xba,(06),0x0f,0xb3 },
+	{ ABTRW,	ybtl,	Pq, 0xba,(06),0xb3 },
+	{ ABTSL,	ybtl,	Pm, 0xba,(05),0xab  },
+	{ ABTSQ,	ybtl,	Pw, 0x0f,0xba,(05),0x0f,0xab },
+	{ ABTSW,	ybtl,	Pq, 0xba,(05),0xab  },
+	{ ABTW,		ybtl,	Pq, 0xba,(04),0xa3 },
+	{ ABYTE,	ybyte,	Px, 1 },
+	{ ACALL,	ycall,	Px, 0xff,(02),0xe8 },
+	{ ACDQ,		ynone,	Px, 0x99 },
+	{ ACLC,		ynone,	Px, 0xf8 },
+	{ ACLD,		ynone,	Px, 0xfc },
+	{ ACLI,		ynone,	Px, 0xfa },
+	{ ACLTS,	ynone,	Pm, 0x06 },
+	{ ACMC,		ynone,	Px, 0xf5 },
+	{ ACMOVLCC,	yml_rl,	Pm, 0x43 },
+	{ ACMOVLCS,	yml_rl,	Pm, 0x42 },
+	{ ACMOVLEQ,	yml_rl,	Pm, 0x44 },
+	{ ACMOVLGE,	yml_rl,	Pm, 0x4d },
+	{ ACMOVLGT,	yml_rl,	Pm, 0x4f },
+	{ ACMOVLHI,	yml_rl,	Pm, 0x47 },
+	{ ACMOVLLE,	yml_rl,	Pm, 0x4e },
+	{ ACMOVLLS,	yml_rl,	Pm, 0x46 },
+	{ ACMOVLLT,	yml_rl,	Pm, 0x4c },
+	{ ACMOVLMI,	yml_rl,	Pm, 0x48 },
+	{ ACMOVLNE,	yml_rl,	Pm, 0x45 },
+	{ ACMOVLOC,	yml_rl,	Pm, 0x41 },
+	{ ACMOVLOS,	yml_rl,	Pm, 0x40 },
+	{ ACMOVLPC,	yml_rl,	Pm, 0x4b },
+	{ ACMOVLPL,	yml_rl,	Pm, 0x49 },
+	{ ACMOVLPS,	yml_rl,	Pm, 0x4a },
+	{ ACMOVQCC,	yml_rl,	Pw, 0x0f,0x43 },
+	{ ACMOVQCS,	yml_rl,	Pw, 0x0f,0x42 },
+	{ ACMOVQEQ,	yml_rl,	Pw, 0x0f,0x44 },
+	{ ACMOVQGE,	yml_rl,	Pw, 0x0f,0x4d },
+	{ ACMOVQGT,	yml_rl,	Pw, 0x0f,0x4f },
+	{ ACMOVQHI,	yml_rl,	Pw, 0x0f,0x47 },
+	{ ACMOVQLE,	yml_rl,	Pw, 0x0f,0x4e },
+	{ ACMOVQLS,	yml_rl,	Pw, 0x0f,0x46 },
+	{ ACMOVQLT,	yml_rl,	Pw, 0x0f,0x4c },
+	{ ACMOVQMI,	yml_rl,	Pw, 0x0f,0x48 },
+	{ ACMOVQNE,	yml_rl,	Pw, 0x0f,0x45 },
+	{ ACMOVQOC,	yml_rl,	Pw, 0x0f,0x41 },
+	{ ACMOVQOS,	yml_rl,	Pw, 0x0f,0x40 },
+	{ ACMOVQPC,	yml_rl,	Pw, 0x0f,0x4b },
+	{ ACMOVQPL,	yml_rl,	Pw, 0x0f,0x49 },
+	{ ACMOVQPS,	yml_rl,	Pw, 0x0f,0x4a },
+	{ ACMOVWCC,	yml_rl,	Pq, 0x43 },
+	{ ACMOVWCS,	yml_rl,	Pq, 0x42 },
+	{ ACMOVWEQ,	yml_rl,	Pq, 0x44 },
+	{ ACMOVWGE,	yml_rl,	Pq, 0x4d },
+	{ ACMOVWGT,	yml_rl,	Pq, 0x4f },
+	{ ACMOVWHI,	yml_rl,	Pq, 0x47 },
+	{ ACMOVWLE,	yml_rl,	Pq, 0x4e },
+	{ ACMOVWLS,	yml_rl,	Pq, 0x46 },
+	{ ACMOVWLT,	yml_rl,	Pq, 0x4c },
+	{ ACMOVWMI,	yml_rl,	Pq, 0x48 },
+	{ ACMOVWNE,	yml_rl,	Pq, 0x45 },
+	{ ACMOVWOC,	yml_rl,	Pq, 0x41 },
+	{ ACMOVWOS,	yml_rl,	Pq, 0x40 },
+	{ ACMOVWPC,	yml_rl,	Pq, 0x4b },
+	{ ACMOVWPL,	yml_rl,	Pq, 0x49 },
+	{ ACMOVWPS,	yml_rl,	Pq, 0x4a },
+	{ ACMPB,	ycmpb,	Pb, 0x3c,0x80,(07),0x38,0x3a },
+	{ ACMPL,	ycmpl,	Px, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+	{ ACMPPD,	yxcmpi,	Px, Pe,0xc2 },
+	{ ACMPPS,	yxcmpi,	Pm, 0xc2,0 },
+	{ ACMPQ,	ycmpl,	Pw, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+	{ ACMPSB,	ynone,	Pb, 0xa6 },
+	{ ACMPSD,	yxcmpi,	Px, Pf2,0xc2 },
+	{ ACMPSL,	ynone,	Px, 0xa7 },
+	{ ACMPSQ,	ynone,	Pw, 0xa7 },
+	{ ACMPSS,	yxcmpi,	Px, Pf3,0xc2 },
+	{ ACMPSW,	ynone,	Pe, 0xa7 },
+	{ ACMPW,	ycmpl,	Pe, 0x83,(07),0x3d,0x81,(07),0x39,0x3b },
+	{ ACOMISD,	yxcmp,	Pe, 0x2f },
+	{ ACOMISS,	yxcmp,	Pm, 0x2f },
+	{ ACPUID,	ynone,	Pm, 0xa2 },
+	{ ACVTPL2PD,	yxcvm2,	Px, Pf3,0xe6,Pe,0x2a },
+	{ ACVTPL2PS,	yxcvm2,	Pm, 0x5b,0,0x2a,0, },
+	{ ACVTPD2PL,	yxcvm1,	Px, Pf2,0xe6,Pe,0x2d },
+	{ ACVTPD2PS,	yxm,	Pe, 0x5a },
+	{ ACVTPS2PL,	yxcvm1, Px, Pe,0x5b,Pm,0x2d },
+	{ ACVTPS2PD,	yxm,	Pm, 0x5a },
+	{ API2FW,	ymfp,	Px, 0x0c },
+	{ ACVTSD2SL,	yxcvfl, Pf2, 0x2d },
+	{ ACVTSD2SQ,	yxcvfq, Pw, Pf2,0x2d },
+	{ ACVTSD2SS,	yxm,	Pf2, 0x5a },
+	{ ACVTSL2SD,	yxcvlf, Pf2, 0x2a },
+	{ ACVTSQ2SD,	yxcvqf, Pw, Pf2,0x2a },
+	{ ACVTSL2SS,	yxcvlf, Pf3, 0x2a },
+	{ ACVTSQ2SS,	yxcvqf, Pw, Pf3,0x2a },
+	{ ACVTSS2SD,	yxm,	Pf3, 0x5a },
+	{ ACVTSS2SL,	yxcvfl, Pf3, 0x2d },
+	{ ACVTSS2SQ,	yxcvfq, Pw, Pf3,0x2d },
+	{ ACVTTPD2PL,	yxcvm1,	Px, Pe,0xe6,Pe,0x2c },
+	{ ACVTTPS2PL,	yxcvm1,	Px, Pf3,0x5b,Pm,0x2c },
+	{ ACVTTSD2SL,	yxcvfl, Pf2, 0x2c },
+	{ ACVTTSD2SQ,	yxcvfq, Pw, Pf2,0x2c },
+	{ ACVTTSS2SL,	yxcvfl,	Pf3, 0x2c },
+	{ ACVTTSS2SQ,	yxcvfq, Pw, Pf3,0x2c },
+	{ ACWD,		ynone,	Pe, 0x99 },
+	{ ACQO,		ynone,	Pw, 0x99 },
+	{ ADAA,		ynone,	P32, 0x27 },
+	{ ADAS,		ynone,	P32, 0x2f },
+	{ ADATA },
+	{ ADECB,	yincb,	Pb, 0xfe,(01) },
+	{ ADECL,	yincl,	Px, 0xff,(01) },
+	{ ADECQ,	yincl,	Pw, 0xff,(01) },
+	{ ADECW,	yincw,	Pe, 0xff,(01) },
+	{ ADIVB,	ydivb,	Pb, 0xf6,(06) },
+	{ ADIVL,	ydivl,	Px, 0xf7,(06) },
+	{ ADIVPD,	yxm,	Pe, 0x5e },
+	{ ADIVPS,	yxm,	Pm, 0x5e },
+	{ ADIVQ,	ydivl,	Pw, 0xf7,(06) },
+	{ ADIVSD,	yxm,	Pf2, 0x5e },
+	{ ADIVSS,	yxm,	Pf3, 0x5e },
+	{ ADIVW,	ydivl,	Pe, 0xf7,(06) },
+	{ AEMMS,	ynone,	Pm, 0x77 },
+	{ AENTER },				/* botch */
+	{ AFXRSTOR,	ysvrs,	Pm, 0xae,(01),0xae,(01) },
+	{ AFXSAVE,	ysvrs,	Pm, 0xae,(00),0xae,(00) },
+	{ AFXRSTOR64,	ysvrs,	Pw, 0x0f,0xae,(01),0x0f,0xae,(01) },
+	{ AFXSAVE64,	ysvrs,	Pw, 0x0f,0xae,(00),0x0f,0xae,(00) },
+	{ AGLOBL },
+	{ AGOK },
+	{ AHISTORY },
+	{ AHLT,		ynone,	Px, 0xf4 },
+	{ AIDIVB,	ydivb,	Pb, 0xf6,(07) },
+	{ AIDIVL,	ydivl,	Px, 0xf7,(07) },
+	{ AIDIVQ,	ydivl,	Pw, 0xf7,(07) },
+	{ AIDIVW,	ydivl,	Pe, 0xf7,(07) },
+	{ AIMULB,	ydivb,	Pb, 0xf6,(05) },
+	{ AIMULL,	yimul,	Px, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+	{ AIMULQ,	yimul,	Pw, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+	{ AIMULW,	yimul,	Pe, 0xf7,(05),0x6b,0x69,Pm,0xaf },
+	{ AINB,		yin,	Pb, 0xe4,0xec },
+	{ AINCB,	yincb,	Pb, 0xfe,(00) },
+	{ AINCL,	yincl,	Px, 0xff,(00) },
+	{ AINCQ,	yincl,	Pw, 0xff,(00) },
+	{ AINCW,	yincw,	Pe, 0xff,(00) },
+	{ AINL,		yin,	Px, 0xe5,0xed },
+	{ AINSB,	ynone,	Pb, 0x6c },
+	{ AINSL,	ynone,	Px, 0x6d },
+	{ AINSW,	ynone,	Pe, 0x6d },
+	{ AINT,		yint,	Px, 0xcd },
+	{ AINTO,	ynone,	P32, 0xce },
+	{ AINW,		yin,	Pe, 0xe5,0xed },
+	{ AIRETL,	ynone,	Px, 0xcf },
+	{ AIRETQ,	ynone,	Pw, 0xcf },
+	{ AIRETW,	ynone,	Pe, 0xcf },
+	{ AJCC,		yjcond,	Px, 0x73,0x83,(00) },
+	{ AJCS,		yjcond,	Px, 0x72,0x82 },
+	{ AJCXZ,	yloop,	Px, 0xe3 },
+	{ AJEQ,		yjcond,	Px, 0x74,0x84 },
+	{ AJGE,		yjcond,	Px, 0x7d,0x8d },
+	{ AJGT,		yjcond,	Px, 0x7f,0x8f },
+	{ AJHI,		yjcond,	Px, 0x77,0x87 },
+	{ AJLE,		yjcond,	Px, 0x7e,0x8e },
+	{ AJLS,		yjcond,	Px, 0x76,0x86 },
+	{ AJLT,		yjcond,	Px, 0x7c,0x8c },
+	{ AJMI,		yjcond,	Px, 0x78,0x88 },
+	{ AJMP,		yjmp,	Px, 0xff,(04),0xeb,0xe9 },
+	{ AJNE,		yjcond,	Px, 0x75,0x85 },
+	{ AJOC,		yjcond,	Px, 0x71,0x81,(00) },
+	{ AJOS,		yjcond,	Px, 0x70,0x80,(00) },
+	{ AJPC,		yjcond,	Px, 0x7b,0x8b },
+	{ AJPL,		yjcond,	Px, 0x79,0x89 },
+	{ AJPS,		yjcond,	Px, 0x7a,0x8a },
+	{ ALAHF,	ynone,	Px, 0x9f },
+	{ ALARL,	yml_rl,	Pm, 0x02 },
+	{ ALARW,	yml_rl,	Pq, 0x02 },
+	{ ALDMXCSR,	ysvrs,	Pm, 0xae,(02),0xae,(02) },
+	{ ALEAL,	ym_rl,	Px, 0x8d },
+	{ ALEAQ,	ym_rl,	Pw, 0x8d },
+	{ ALEAVEL,	ynone,	P32, 0xc9 },
+	{ ALEAVEQ,	ynone,	Py, 0xc9 },
+	{ ALEAVEW,	ynone,	Pe, 0xc9 },
+	{ ALEAW,	ym_rl,	Pe, 0x8d },
+	{ ALOCK,	ynone,	Px, 0xf0 },
+	{ ALODSB,	ynone,	Pb, 0xac },
+	{ ALODSL,	ynone,	Px, 0xad },
+	{ ALODSQ,	ynone,	Pw, 0xad },
+	{ ALODSW,	ynone,	Pe, 0xad },
+	{ ALONG,	ybyte,	Px, 4 },
+	{ ALOOP,	yloop,	Px, 0xe2 },
+	{ ALOOPEQ,	yloop,	Px, 0xe1 },
+	{ ALOOPNE,	yloop,	Px, 0xe0 },
+	{ ALSLL,	yml_rl,	Pm, 0x03  },
+	{ ALSLW,	yml_rl,	Pq, 0x03  },
+	{ AMASKMOVOU,	yxr,	Pe, 0xf7 },
+	{ AMASKMOVQ,	ymr,	Pm, 0xf7 },
+	{ AMAXPD,	yxm,	Pe, 0x5f },
+	{ AMAXPS,	yxm,	Pm, 0x5f },
+	{ AMAXSD,	yxm,	Pf2, 0x5f },
+	{ AMAXSS,	yxm,	Pf3, 0x5f },
+	{ AMINPD,	yxm,	Pe, 0x5d },
+	{ AMINPS,	yxm,	Pm, 0x5d },
+	{ AMINSD,	yxm,	Pf2, 0x5d },
+	{ AMINSS,	yxm,	Pf3, 0x5d },
+	{ AMOVAPD,	yxmov,	Pe, 0x28,0x29 },
+	{ AMOVAPS,	yxmov,	Pm, 0x28,0x29 },
+	{ AMOVB,	ymovb,	Pb, 0x88,0x8a,0xb0,0xc6,(00) },
+	{ AMOVBLSX,	ymb_rl,	Pm, 0xbe },
+	{ AMOVBLZX,	ymb_rl,	Pm, 0xb6 },
+	{ AMOVBQSX,	ymb_rl,	Pw, 0x0f,0xbe },
+	{ AMOVBQZX,	ymb_rl,	Pw, 0x0f,0xb6 },
+	{ AMOVBWSX,	ymb_rl,	Pq, 0xbe },
+	{ AMOVBWZX,	ymb_rl,	Pq, 0xb6 },
+	{ AMOVO,	yxmov,	Pe, 0x6f,0x7f },
+	{ AMOVOU,	yxmov,	Pf2, 0x6f,0x7f },
+	{ AMOVHLPS,	yxr,	Pm, 0x12 },
+	{ AMOVHPD,	yxmov,	Pe, 0x16,0x17 },
+	{ AMOVHPS,	yxmov,	Pm, 0x16,0x17 },
+	{ AMOVL,	ymovl,	Px, 0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e },
+	{ AMOVLHPS,	yxr,	Pm, 0x16 },
+	{ AMOVLPD,	yxmov,	Pe, 0x12,0x13 },
+	{ AMOVLPS,	yxmov,	Pm, 0x12,0x13 },
+	{ AMOVLQSX,	yml_rl,	Pw, 0x63 },
+	{ AMOVLQZX,	yml_rl,	Px, 0x63 },
+	{ AMOVMSKPD,	yxrrl,	Pq, 0x50 },
+	{ AMOVMSKPS,	yxrrl,	Pm, 0x50 },
+	{ AMOVNTO,	yxr_ml,	Pe, 0xe7 },
+	{ AMOVNTPD,	yxr_ml,	Pe, 0x2b },
+	{ AMOVNTPS,	yxr_ml,	Pm, 0x2b },
+	{ AMOVNTQ,	ymr_ml,	Pm, 0xe7 },
+	{ AMOVQ,	ymovq,	Pw, 0x89,0x8b,0x31,0xc7,(00),0xb8,0xc7,(00),0x6f,0x7f,0x6e,0x7e,Pf2,0xd6,Pe,0xd6,Pe,0x6e,Pe,0x7e },
+	{ AMOVQOZX,	ymrxr,	Pf3, 0xd6,0x7e },
+	{ AMOVSB,	ynone,	Pb, 0xa4 },
+	{ AMOVSD,	yxmov,	Pf2, 0x10,0x11 },
+	{ AMOVSL,	ynone,	Px, 0xa5 },
+	{ AMOVSQ,	ynone,	Pw, 0xa5 },
+	{ AMOVSS,	yxmov,	Pf3, 0x10,0x11 },
+	{ AMOVSW,	ynone,	Pe, 0xa5 },
+	{ AMOVUPD,	yxmov,	Pe, 0x10,0x11 },
+	{ AMOVUPS,	yxmov,	Pm, 0x10,0x11 },
+	{ AMOVW,	ymovw,	Pe, 0x89,0x8b,0x31,0xb8,0xc7,(00) },
+	{ AMOVWLSX,	yml_rl,	Pm, 0xbf },
+	{ AMOVWLZX,	yml_rl,	Pm, 0xb7 },
+	{ AMOVWQSX,	yml_rl,	Pw, 0x0f,0xbf },
+	{ AMOVWQZX,	yml_rl,	Pw, 0x0f,0xb7 },
+	{ AMULB,	ydivb,	Pb, 0xf6,(04) },
+	{ AMULL,	ydivl,	Px, 0xf7,(04) },
+	{ AMULPD,	yxm,	Pe, 0x59 },
+	{ AMULPS,	yxm,	Ym, 0x59 },
+	{ AMULQ,	ydivl,	Pw, 0xf7,(04) },
+	{ AMULSD,	yxm,	Pf2, 0x59 },
+	{ AMULSS,	yxm,	Pf3, 0x59 },
+	{ AMULW,	ydivl,	Pe, 0xf7,(04) },
+	{ ANAME },
+	{ ANEGB,	yscond,	Pb, 0xf6,(03) },
+	{ ANEGL,	yscond,	Px, 0xf7,(03) },
+	{ ANEGQ,	yscond,	Pw, 0xf7,(03) },
+	{ ANEGW,	yscond,	Pe, 0xf7,(03) },
+	{ ANOP,		ynop,	Px, 0,0 },
+	{ ANOTB,	yscond,	Pb, 0xf6,(02) },
+	{ ANOTL,	yscond,	Px, 0xf7,(02) },
+	{ ANOTQ,	yscond,	Pw, 0xf7,(02) },
+	{ ANOTW,	yscond,	Pe, 0xf7,(02) },
+	{ AORB,		yxorb,	Pb, 0x0c,0x80,(01),0x08,0x0a },
+	{ AORL,		yxorl,	Px, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+	{ AORPD,	yxm,	Pq, 0x56 },
+	{ AORPS,	yxm,	Pm, 0x56 },
+	{ AORQ,		yxorl,	Pw, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+	{ AORW,		yxorl,	Pe, 0x83,(01),0x0d,0x81,(01),0x09,0x0b },
+	{ AOUTB,	yin,	Pb, 0xe6,0xee },
+	{ AOUTL,	yin,	Px, 0xe7,0xef },
+	{ AOUTSB,	ynone,	Pb, 0x6e },
+	{ AOUTSL,	ynone,	Px, 0x6f },
+	{ AOUTSW,	ynone,	Pe, 0x6f },
+	{ AOUTW,	yin,	Pe, 0xe7,0xef },
+	{ APACKSSLW,	ymm,	Py, 0x6b,Pe,0x6b },
+	{ APACKSSWB,	ymm,	Py, 0x63,Pe,0x63 },
+	{ APACKUSWB,	ymm,	Py, 0x67,Pe,0x67 },
+	{ APADDB,	ymm,	Py, 0xfc,Pe,0xfc },
+	{ APADDL,	ymm,	Py, 0xfe,Pe,0xfe },
+	{ APADDQ,	yxm,	Pe, 0xd4 },
+	{ APADDSB,	ymm,	Py, 0xec,Pe,0xec },
+	{ APADDSW,	ymm,	Py, 0xed,Pe,0xed },
+	{ APADDUSB,	ymm,	Py, 0xdc,Pe,0xdc },
+	{ APADDUSW,	ymm,	Py, 0xdd,Pe,0xdd },
+	{ APADDW,	ymm,	Py, 0xfd,Pe,0xfd },
+	{ APAND,	ymm,	Py, 0xdb,Pe,0xdb },
+	{ APANDN,	ymm,	Py, 0xdf,Pe,0xdf },
+	{ APAVGB,	ymm,	Py, 0xe0,Pe,0xe0 },
+	{ APAVGW,	ymm,	Py, 0xe3,Pe,0xe3 },
+	{ APCMPEQB,	ymm,	Py, 0x74,Pe,0x74 },
+	{ APCMPEQL,	ymm,	Py, 0x76,Pe,0x76 },
+	{ APCMPEQW,	ymm,	Py, 0x75,Pe,0x75 },
+	{ APCMPGTB,	ymm,	Py, 0x64,Pe,0x64 },
+	{ APCMPGTL,	ymm,	Py, 0x66,Pe,0x66 },
+	{ APCMPGTW,	ymm,	Py, 0x65,Pe,0x65 },
+	{ APEXTRW,	yextrw,	Pq, 0xc5 },
+	{ APF2IL,	ymfp,	Px, 0x1d },
+	{ APF2IW,	ymfp,	Px, 0x1c },
+	{ API2FL,	ymfp,	Px, 0x0d },
+	{ APFACC,	ymfp,	Px, 0xae },
+	{ APFADD,	ymfp,	Px, 0x9e },
+	{ APFCMPEQ,	ymfp,	Px, 0xb0 },
+	{ APFCMPGE,	ymfp,	Px, 0x90 },
+	{ APFCMPGT,	ymfp,	Px, 0xa0 },
+	{ APFMAX,	ymfp,	Px, 0xa4 },
+	{ APFMIN,	ymfp,	Px, 0x94 },
+	{ APFMUL,	ymfp,	Px, 0xb4 },
+	{ APFNACC,	ymfp,	Px, 0x8a },
+	{ APFPNACC,	ymfp,	Px, 0x8e },
+	{ APFRCP,	ymfp,	Px, 0x96 },
+	{ APFRCPIT1,	ymfp,	Px, 0xa6 },
+	{ APFRCPI2T,	ymfp,	Px, 0xb6 },
+	{ APFRSQIT1,	ymfp,	Px, 0xa7 },
+	{ APFRSQRT,	ymfp,	Px, 0x97 },
+	{ APFSUB,	ymfp,	Px, 0x9a },
+	{ APFSUBR,	ymfp,	Px, 0xaa },
+	{ APINSRW,	yextrw,	Pq, 0xc4 },
+	{ APMADDWL,	ymm,	Py, 0xf5,Pe,0xf5 },
+	{ APMAXSW,	yxm,	Pe, 0xee },
+	{ APMAXUB,	yxm,	Pe, 0xde },
+	{ APMINSW,	yxm,	Pe, 0xea },
+	{ APMINUB,	yxm,	Pe, 0xda },
+	{ APMOVMSKB,	ymskb,	Px, Pe,0xd7,0xd7 },
+	{ APMULHRW,	ymfp,	Px, 0xb7 },
+	{ APMULHUW,	ymm,	Py, 0xe4,Pe,0xe4 },
+	{ APMULHW,	ymm,	Py, 0xe5,Pe,0xe5 },
+	{ APMULLW,	ymm,	Py, 0xd5,Pe,0xd5 },
+	{ APMULULQ,	ymm,	Py, 0xf4,Pe,0xf4 },
+	{ APOPAL,	ynone,	P32, 0x61 },
+	{ APOPAW,	ynone,	Pe, 0x61 },
+	{ APOPFL,	ynone,	P32, 0x9d },
+	{ APOPFQ,	ynone,	Py, 0x9d },
+	{ APOPFW,	ynone,	Pe, 0x9d },
+	{ APOPL,	ypopl,	P32, 0x58,0x8f,(00) },
+	{ APOPQ,	ypopl,	Py, 0x58,0x8f,(00) },
+	{ APOPW,	ypopl,	Pe, 0x58,0x8f,(00) },
+	{ APOR,		ymm,	Py, 0xeb,Pe,0xeb },
+	{ APSADBW,	yxm,	Pw, Pe,0xf6 },
+	{ APSHUFHW,	yxshuf,	Pf3, 0x70 },
+	{ APSHUFL,	yxm,	Pw, Pe,0x70 },
+	{ APSHUFLW,	yxshuf,	Pf2, 0x70 },
+	{ APSHUFW,	ymshuf,	Pm, 0x70 },
+	{ APSLLO,	ypsdq,	Pq, 0x73,(07) },
+	{ APSLLL,	yps,	Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) },
+	{ APSLLQ,	yps,	Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x7e,(06) },
+	{ APSLLW,	yps,	Py, 0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06) },
+	{ APSRAL,	yps,	Py, 0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04) },
+	{ APSRAW,	yps,	Py, 0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04) },
+	{ APSRLO,	ypsdq,	Pq, 0x73,(03) },
+	{ APSRLL,	yps,	Py, 0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02) },
+	{ APSRLQ,	yps,	Py, 0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02) },
+	{ APSRLW,	yps,	Py, 0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02) },
+	{ APSUBB,	yxm,	Pe, 0xf8 },
+	{ APSUBL,	yxm,	Pe, 0xfa },
+	{ APSUBQ,	yxm,	Pe, 0xfb },
+	{ APSUBSB,	yxm,	Pe, 0xe8 },
+	{ APSUBSW,	yxm,	Pe, 0xe9 },
+	{ APSUBUSB,	yxm,	Pe, 0xd8 },
+	{ APSUBUSW,	yxm,	Pe, 0xd9 },
+	{ APSUBW,	yxm,	Pe, 0xf9 },
+	{ APSWAPL,	ymfp,	Px, 0xbb },
+	{ APUNPCKHBW,	ymm,	Py, 0x68,Pe,0x68 },
+	{ APUNPCKHLQ,	ymm,	Py, 0x6a,Pe,0x6a },
+	{ APUNPCKHQDQ,	yxm,	Pe, 0x6d },
+	{ APUNPCKHWL,	ymm,	Py, 0x69,Pe,0x69 },
+	{ APUNPCKLBW,	ymm,	Py, 0x60,Pe,0x60 },
+	{ APUNPCKLLQ,	ymm,	Py, 0x62,Pe,0x62 },
+	{ APUNPCKLQDQ,	yxm,	Pe, 0x6c },
+	{ APUNPCKLWL,	ymm,	Py, 0x61,Pe,0x61 },
+	{ APUSHAL,	ynone,	P32, 0x60 },
+	{ APUSHAW,	ynone,	Pe, 0x60 },
+	{ APUSHFL,	ynone,	P32, 0x9c },
+	{ APUSHFQ,	ynone,	Py, 0x9c },
+	{ APUSHFW,	ynone,	Pe, 0x9c },
+	{ APUSHL,	ypushl,	P32, 0x50,0xff,(06),0x6a,0x68 },
+	{ APUSHQ,	ypushl,	Py, 0x50,0xff,(06),0x6a,0x68 },
+	{ APUSHW,	ypushl,	Pe, 0x50,0xff,(06),0x6a,0x68 },
+	{ APXOR,	ymm,	Py, 0xef,Pe,0xef },
+	{ AQUAD,	ybyte,	Px, 8 },
+	{ ARCLB,	yshb,	Pb, 0xd0,(02),0xc0,(02),0xd2,(02) },
+	{ ARCLL,	yshl,	Px, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+	{ ARCLQ,	yshl,	Pw, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+	{ ARCLW,	yshl,	Pe, 0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02) },
+	{ ARCPPS,	yxm,	Pm, 0x53 },
+	{ ARCPSS,	yxm,	Pf3, 0x53 },
+	{ ARCRB,	yshb,	Pb, 0xd0,(03),0xc0,(03),0xd2,(03) },
+	{ ARCRL,	yshl,	Px, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+	{ ARCRQ,	yshl,	Pw, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+	{ ARCRW,	yshl,	Pe, 0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03) },
+	{ AREP,		ynone,	Px, 0xf3 },
+	{ AREPN,	ynone,	Px, 0xf2 },
+	{ ARET,		ynone,	Px, 0xc3 },
+	{ ARETFW,	yret,	Pe, 0xcb,0xca },
+	{ ARETFL,	yret,	Px, 0xcb,0xca },
+	{ ARETFQ,	yret,	Pw, 0xcb,0xca },
+	{ AROLB,	yshb,	Pb, 0xd0,(00),0xc0,(00),0xd2,(00) },
+	{ AROLL,	yshl,	Px, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+	{ AROLQ,	yshl,	Pw, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+	{ AROLW,	yshl,	Pe, 0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00) },
+	{ ARORB,	yshb,	Pb, 0xd0,(01),0xc0,(01),0xd2,(01) },
+	{ ARORL,	yshl,	Px, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+	{ ARORQ,	yshl,	Pw, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+	{ ARORW,	yshl,	Pe, 0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01) },
+	{ ARSQRTPS,	yxm,	Pm, 0x52 },
+	{ ARSQRTSS,	yxm,	Pf3, 0x52 },
+	{ ASAHF,	ynone,	Px, 0x86,0xe0,0x50,0x9d },	/* XCHGB AH,AL; PUSH AX; POPFL */
+	{ ASALB,	yshb,	Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+	{ ASALL,	yshl,	Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+	{ ASALQ,	yshl,	Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+	{ ASALW,	yshl,	Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+	{ ASARB,	yshb,	Pb, 0xd0,(07),0xc0,(07),0xd2,(07) },
+	{ ASARL,	yshl,	Px, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+	{ ASARQ,	yshl,	Pw, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+	{ ASARW,	yshl,	Pe, 0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07) },
+	{ ASBBB,	yxorb,	Pb, 0x1c,0x80,(03),0x18,0x1a },
+	{ ASBBL,	yxorl,	Px, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+	{ ASBBQ,	yxorl,	Pw, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+	{ ASBBW,	yxorl,	Pe, 0x83,(03),0x1d,0x81,(03),0x19,0x1b },
+	{ ASCASB,	ynone,	Pb, 0xae },
+	{ ASCASL,	ynone,	Px, 0xaf },
+	{ ASCASQ,	ynone,	Pw, 0xaf },
+	{ ASCASW,	ynone,	Pe, 0xaf },
+	{ ASETCC,	yscond,	Pm, 0x93,(00) },
+	{ ASETCS,	yscond,	Pm, 0x92,(00) },
+	{ ASETEQ,	yscond,	Pm, 0x94,(00) },
+	{ ASETGE,	yscond,	Pm, 0x9d,(00) },
+	{ ASETGT,	yscond,	Pm, 0x9f,(00) },
+	{ ASETHI,	yscond,	Pm, 0x97,(00) },
+	{ ASETLE,	yscond,	Pm, 0x9e,(00) },
+	{ ASETLS,	yscond,	Pm, 0x96,(00) },
+	{ ASETLT,	yscond,	Pm, 0x9c,(00) },
+	{ ASETMI,	yscond,	Pm, 0x98,(00) },
+	{ ASETNE,	yscond,	Pm, 0x95,(00) },
+	{ ASETOC,	yscond,	Pm, 0x91,(00) },
+	{ ASETOS,	yscond,	Pm, 0x90,(00) },
+	{ ASETPC,	yscond,	Pm, 0x96,(00) },
+	{ ASETPL,	yscond,	Pm, 0x99,(00) },
+	{ ASETPS,	yscond,	Pm, 0x9a,(00) },
+	{ ASHLB,	yshb,	Pb, 0xd0,(04),0xc0,(04),0xd2,(04) },
+	{ ASHLL,	yshl,	Px, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+	{ ASHLQ,	yshl,	Pw, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+	{ ASHLW,	yshl,	Pe, 0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04) },
+	{ ASHRB,	yshb,	Pb, 0xd0,(05),0xc0,(05),0xd2,(05) },
+	{ ASHRL,	yshl,	Px, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+	{ ASHRQ,	yshl,	Pw, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+	{ ASHRW,	yshl,	Pe, 0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05) },
+	{ ASHUFPD,	yxshuf,	Pq, 0xc6 },
+	{ ASHUFPS,	yxshuf,	Pm, 0xc6 },
+	{ ASQRTPD,	yxm,	Pe, 0x51 },
+	{ ASQRTPS,	yxm,	Pm, 0x51 },
+	{ ASQRTSD,	yxm,	Pf2, 0x51 },
+	{ ASQRTSS,	yxm,	Pf3, 0x51 },
+	{ ASTC,		ynone,	Px, 0xf9 },
+	{ ASTD,		ynone,	Px, 0xfd },
+	{ ASTI,		ynone,	Px, 0xfb },
+	{ ASTMXCSR,	ysvrs,	Pm, 0xae,(03),0xae,(03) },
+	{ ASTOSB,	ynone,	Pb, 0xaa },
+	{ ASTOSL,	ynone,	Px, 0xab },
+	{ ASTOSQ,	ynone,	Pw, 0xab },
+	{ ASTOSW,	ynone,	Pe, 0xab },
+	{ ASUBB,	yxorb,	Pb, 0x2c,0x80,(05),0x28,0x2a },
+	{ ASUBL,	yaddl,	Px, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+	{ ASUBPD,	yxm,	Pe, 0x5c },
+	{ ASUBPS,	yxm,	Pm, 0x5c },
+	{ ASUBQ,	yaddl,	Pw, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+	{ ASUBSD,	yxm,	Pf2, 0x5c },
+	{ ASUBSS,	yxm,	Pf3, 0x5c },
+	{ ASUBW,	yaddl,	Pe, 0x83,(05),0x2d,0x81,(05),0x29,0x2b },
+	{ ASWAPGS,	ynone,	Pm, 0x01,0xf8 },
+	{ ASYSCALL,	ynone,	Px, 0x0f,0x05 },	/* fast syscall */
+	{ ATESTB,	ytestb,	Pb, 0xa8,0xf6,(00),0x84,0x84 },
+	{ ATESTL,	ytestl,	Px, 0xa9,0xf7,(00),0x85,0x85 },
+	{ ATESTQ,	ytestl,	Pw, 0xa9,0xf7,(00),0x85,0x85 },
+	{ ATESTW,	ytestl,	Pe, 0xa9,0xf7,(00),0x85,0x85 },
+	{ ATEXT,	ytext,	Px },
+	{ AUCOMISD,	yxcmp,	Pe, 0x2e },
+	{ AUCOMISS,	yxcmp,	Pm, 0x2e },
+	{ AUNPCKHPD,	yxm,	Pe, 0x15 },
+	{ AUNPCKHPS,	yxm,	Pm, 0x15 },
+	{ AUNPCKLPD,	yxm,	Pe, 0x14 },
+	{ AUNPCKLPS,	yxm,	Pm, 0x14 },
+	{ AVERR,	ydivl,	Pm, 0x00,(04) },
+	{ AVERW,	ydivl,	Pm, 0x00,(05) },
+	{ AWAIT,	ynone,	Px, 0x9b },
+	{ AWORD,	ybyte,	Px, 2 },
+	{ AXCHGB,	yml_mb,	Pb, 0x86,0x86 },
+	{ AXCHGL,	yml_ml,	Px, 0x87,0x87 },
+	{ AXCHGQ,	yml_ml,	Pw, 0x87,0x87 },
+	{ AXCHGW,	yml_ml,	Pe, 0x87,0x87 },
+	{ AXLAT,	ynone,	Px, 0xd7 },
+	{ AXORB,	yxorb,	Pb, 0x34,0x80,(06),0x30,0x32 },
+	{ AXORL,	yxorl,	Px, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+	{ AXORPD,	yxm,	Pe, 0x57 },
+	{ AXORPS,	yxm,	Pm, 0x57 },
+	{ AXORQ,	yxorl,	Pw, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+	{ AXORW,	yxorl,	Pe, 0x83,(06),0x35,0x81,(06),0x31,0x33 },
+
+	{ AFMOVB,	yfmvx,	Px, 0xdf,(04) },
+	{ AFMOVBP,	yfmvp,	Px, 0xdf,(06) },
+	{ AFMOVD,	yfmvd,	Px, 0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02) },
+	{ AFMOVDP,	yfmvdp,	Px, 0xdd,(03),0xdd,(03) },
+	{ AFMOVF,	yfmvf,	Px, 0xd9,(00),0xd9,(02) },
+	{ AFMOVFP,	yfmvp,	Px, 0xd9,(03) },
+	{ AFMOVL,	yfmvf,	Px, 0xdb,(00),0xdb,(02) },
+	{ AFMOVLP,	yfmvp,	Px, 0xdb,(03) },
+	{ AFMOVV,	yfmvx,	Px, 0xdf,(05) },
+	{ AFMOVVP,	yfmvp,	Px, 0xdf,(07) },
+	{ AFMOVW,	yfmvf,	Px, 0xdf,(00),0xdf,(02) },
+	{ AFMOVWP,	yfmvp,	Px, 0xdf,(03) },
+	{ AFMOVX,	yfmvx,	Px, 0xdb,(05) },
+	{ AFMOVXP,	yfmvp,	Px, 0xdb,(07) },
+
+	{ AFCOMB },
+	{ AFCOMBP },
+	{ AFCOMD,	yfadd,	Px, 0xdc,(02),0xd8,(02),0xdc,(02) },	/* botch */
+	{ AFCOMDP,	yfadd,	Px, 0xdc,(03),0xd8,(03),0xdc,(03) },	/* botch */
+	{ AFCOMDPP,	ycompp,	Px, 0xde,(03) },
+	{ AFCOMF,	yfmvx,	Px, 0xd8,(02) },
+	{ AFCOMFP,	yfmvx,	Px, 0xd8,(03) },
+	{ AFCOML,	yfmvx,	Px, 0xda,(02) },
+	{ AFCOMLP,	yfmvx,	Px, 0xda,(03) },
+	{ AFCOMW,	yfmvx,	Px, 0xde,(02) },
+	{ AFCOMWP,	yfmvx,	Px, 0xde,(03) },
+
+	{ AFUCOM,	ycompp,	Px, 0xdd,(04) },
+	{ AFUCOMP,	ycompp, Px, 0xdd,(05) },
+	{ AFUCOMPP,	ycompp,	Px, 0xda,(13) },
+
+	{ AFADDDP,	yfaddp,	Px, 0xde,(00) },
+	{ AFADDW,	yfmvx,	Px, 0xde,(00) },
+	{ AFADDL,	yfmvx,	Px, 0xda,(00) },
+	{ AFADDF,	yfmvx,	Px, 0xd8,(00) },
+	{ AFADDD,	yfadd,	Px, 0xdc,(00),0xd8,(00),0xdc,(00) },
+
+	{ AFMULDP,	yfaddp,	Px, 0xde,(01) },
+	{ AFMULW,	yfmvx,	Px, 0xde,(01) },
+	{ AFMULL,	yfmvx,	Px, 0xda,(01) },
+	{ AFMULF,	yfmvx,	Px, 0xd8,(01) },
+	{ AFMULD,	yfadd,	Px, 0xdc,(01),0xd8,(01),0xdc,(01) },
+
+	{ AFSUBDP,	yfaddp,	Px, 0xde,(05) },
+	{ AFSUBW,	yfmvx,	Px, 0xde,(04) },
+	{ AFSUBL,	yfmvx,	Px, 0xda,(04) },
+	{ AFSUBF,	yfmvx,	Px, 0xd8,(04) },
+	{ AFSUBD,	yfadd,	Px, 0xdc,(04),0xd8,(04),0xdc,(05) },
+
+	{ AFSUBRDP,	yfaddp,	Px, 0xde,(04) },
+	{ AFSUBRW,	yfmvx,	Px, 0xde,(05) },
+	{ AFSUBRL,	yfmvx,	Px, 0xda,(05) },
+	{ AFSUBRF,	yfmvx,	Px, 0xd8,(05) },
+	{ AFSUBRD,	yfadd,	Px, 0xdc,(05),0xd8,(05),0xdc,(04) },
+
+	{ AFDIVDP,	yfaddp,	Px, 0xde,(07) },
+	{ AFDIVW,	yfmvx,	Px, 0xde,(06) },
+	{ AFDIVL,	yfmvx,	Px, 0xda,(06) },
+	{ AFDIVF,	yfmvx,	Px, 0xd8,(06) },
+	{ AFDIVD,	yfadd,	Px, 0xdc,(06),0xd8,(06),0xdc,(07) },
+
+	{ AFDIVRDP,	yfaddp,	Px, 0xde,(06) },
+	{ AFDIVRW,	yfmvx,	Px, 0xde,(07) },
+	{ AFDIVRL,	yfmvx,	Px, 0xda,(07) },
+	{ AFDIVRF,	yfmvx,	Px, 0xd8,(07) },
+	{ AFDIVRD,	yfadd,	Px, 0xdc,(07),0xd8,(07),0xdc,(06) },
+
+	{ AFXCHD,	yfxch,	Px, 0xd9,(01),0xd9,(01) },
+	{ AFFREE },
+	{ AFLDCW,	ystcw,	Px, 0xd9,(05),0xd9,(05) },
+	{ AFLDENV,	ystcw,	Px, 0xd9,(04),0xd9,(04) },
+	{ AFRSTOR,	ysvrs,	Px, 0xdd,(04),0xdd,(04) },
+	{ AFSAVE,	ysvrs,	Px, 0xdd,(06),0xdd,(06) },
+	{ AFSTCW,	ystcw,	Px, 0xd9,(07),0xd9,(07) },
+	{ AFSTENV,	ystcw,	Px, 0xd9,(06),0xd9,(06) },
+	{ AFSTSW,	ystsw,	Px, 0xdd,(07),0xdf,0xe0 },
+	{ AF2XM1,	ynone,	Px, 0xd9, 0xf0 },
+	{ AFABS,	ynone,	Px, 0xd9, 0xe1 },
+	{ AFCHS,	ynone,	Px, 0xd9, 0xe0 },
+	{ AFCLEX,	ynone,	Px, 0xdb, 0xe2 },
+	{ AFCOS,	ynone,	Px, 0xd9, 0xff },
+	{ AFDECSTP,	ynone,	Px, 0xd9, 0xf6 },
+	{ AFINCSTP,	ynone,	Px, 0xd9, 0xf7 },
+	{ AFINIT,	ynone,	Px, 0xdb, 0xe3 },
+	{ AFLD1,	ynone,	Px, 0xd9, 0xe8 },
+	{ AFLDL2E,	ynone,	Px, 0xd9, 0xea },
+	{ AFLDL2T,	ynone,	Px, 0xd9, 0xe9 },
+	{ AFLDLG2,	ynone,	Px, 0xd9, 0xec },
+	{ AFLDLN2,	ynone,	Px, 0xd9, 0xed },
+	{ AFLDPI,	ynone,	Px, 0xd9, 0xeb },
+	{ AFLDZ,	ynone,	Px, 0xd9, 0xee },
+	{ AFNOP,	ynone,	Px, 0xd9, 0xd0 },
+	{ AFPATAN,	ynone,	Px, 0xd9, 0xf3 },
+	{ AFPREM,	ynone,	Px, 0xd9, 0xf8 },
+	{ AFPREM1,	ynone,	Px, 0xd9, 0xf5 },
+	{ AFPTAN,	ynone,	Px, 0xd9, 0xf2 },
+	{ AFRNDINT,	ynone,	Px, 0xd9, 0xfc },
+	{ AFSCALE,	ynone,	Px, 0xd9, 0xfd },
+	{ AFSIN,	ynone,	Px, 0xd9, 0xfe },
+	{ AFSINCOS,	ynone,	Px, 0xd9, 0xfb },
+	{ AFSQRT,	ynone,	Px, 0xd9, 0xfa },
+	{ AFTST,	ynone,	Px, 0xd9, 0xe4 },
+	{ AFXAM,	ynone,	Px, 0xd9, 0xe5 },
+	{ AFXTRACT,	ynone,	Px, 0xd9, 0xf4 },
+	{ AFYL2X,	ynone,	Px, 0xd9, 0xf1 },
+	{ AFYL2XP1,	ynone,	Px, 0xd9, 0xf9 },
+
+	{ ACMPXCHGB,	yrb_mb,	Pb, 0x0f,0xb0 },
+	{ ACMPXCHGL,	yrl_ml,	Px, 0x0f,0xb1 },
+	{ ACMPXCHGW,	yrl_ml,	Pe, 0x0f,0xb1 },
+	{ ACMPXCHGQ,	yrl_ml,	Pw, 0x0f,0xb1 },
+	{ ACMPXCHG8B,	yscond,	Pm, 0xc7,(01) },
+	{ AINVD,	ynone,	Pm, 0x08 },
+	{ AINVLPG,	ymbs,	Pm, 0x01,(07) },
+	{ ALFENCE,	ynone,	Pm, 0xae,0xe8 },
+	{ AMFENCE,	ynone,	Pm, 0xae,0xf0 },
+	{ AMOVNTIL,	yrl_ml,	Pm, 0xc3 },
+	{ AMOVNTIQ,	yrl_ml, Pw, 0x0f,0xc3 },
+	{ ARDMSR,	ynone,	Pm, 0x32 },
+	{ ARDPMC,	ynone,	Pm, 0x33 },
+	{ ARDTSC,	ynone,	Pm, 0x31 },
+	{ ARSM,		ynone,	Pm, 0xaa },
+	{ ASFENCE,	ynone,	Pm, 0xae,0xf8 },
+	{ ASYSRET,	ynone,	Pm, 0x07 },
+	{ AWBINVD,	ynone,	Pm, 0x09 },
+	{ AWRMSR,	ynone,	Pm, 0x30 },
+
+	{ AXADDB,	yrb_mb,	Pb, 0x0f,0xc0 },
+	{ AXADDL,	yrl_ml,	Px, 0x0f,0xc1 },
+	{ AXADDQ,	yrl_ml,	Pw, 0x0f,0xc1 },
+	{ AXADDW,	yrl_ml,	Pe, 0x0f,0xc1 },
+
+	{ AEND },
+	0
+};
+
+Optab*	opindex[ALAST+1];
+
+/*
+AMOVD	0f 6e/r	mmx,reg/mem32[mem64-rex?]
+AMOVD	0f 7e/r	reg/mem32[64],mmx	STORE
+AMOVQ	0f 6f/r	mmx1,mmx2/mem64
+AMOVQ	0f 7f/r	mmx1/mem64,mmx2
+*/
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
new file mode 100644
index 0000000..5884022
--- /dev/null
+++ b/src/cmd/6l/pass.c
@@ -0,0 +1,820 @@
+// Inferno utils/6l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	"l.h"
+
+void
+dodata(void)
+{
+	int i;
+	Sym *s;
+	Prog *p;
+	long t, u;
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f dodata\n", cputime());
+	Bflush(&bso);
+	for(p = datap; p != P; p = p->link) {
+		s = p->from.sym;
+		if(p->as == ADYNT || p->as == AINIT)
+			s->value = dtype;
+		if(s->type == SBSS)
+			s->type = SDATA;
+		if(s->type != SDATA)
+			diag("initialize non-data (%d): %s\n%P",
+				s->type, s->name, p);
+		t = p->from.offset + p->width;
+		if(t > s->value)
+			diag("initialize bounds (%lld): %s\n%P",
+				s->value, s->name, p);
+	}
+	/* allocate small guys */
+	datsize = 0;
+	for(i=0; i<NHASH; i++)
+	for(s = hash[i]; s != S; s = s->link) {
+		if(s->type != SDATA)
+		if(s->type != SBSS)
+			continue;
+		t = s->value;
+		if(t == 0) {
+			diag("%s: no size", s->name);
+			t = 1;
+		}
+		t = rnd(t, 4);
+		s->value = t;
+		if(t > MINSIZ)
+			continue;
+		if(t >= 8)
+			datsize = rnd(datsize, 8);
+		s->value = datsize;
+		datsize += t;
+		s->type = SDATA1;
+	}
+
+	/* allocate the rest of the data */
+	for(i=0; i<NHASH; i++)
+	for(s = hash[i]; s != S; s = s->link) {
+		if(s->type != SDATA) {
+			if(s->type == SDATA1)
+				s->type = SDATA;
+			continue;
+		}
+		t = s->value;
+		if(t >= 8)
+			datsize = rnd(datsize, 8);
+		s->value = datsize;
+		datsize += t;
+	}
+	if(datsize)
+		datsize = rnd(datsize, 8);
+
+	if(debug['j']) {
+		/*
+		 * pad data with bss that fits up to next
+		 * 8k boundary, then push data to 8k
+		 */
+		u = rnd(datsize, 8192);
+		u -= datsize;
+		for(i=0; i<NHASH; i++)
+		for(s = hash[i]; s != S; s = s->link) {
+			if(s->type != SBSS)
+				continue;
+			t = s->value;
+			if(t > u)
+				continue;
+			u -= t;
+			s->value = datsize;
+			s->type = SDATA;
+			datsize += t;
+		}
+		datsize += u;
+	}
+
+	/* now the bss */
+	bsssize = 0;
+	for(i=0; i<NHASH; i++)
+	for(s = hash[i]; s != S; s = s->link) {
+		if(s->type != SBSS)
+			continue;
+		t = s->value;
+		if(t >= 8)
+			bsssize = rnd(bsssize, 8);
+		s->value = bsssize + datsize;
+		bsssize += t;
+	}
+	xdefine("edata", SBSS, datsize);
+	xdefine("end", SBSS, bsssize + datsize);
+}
+
+Prog*
+brchain(Prog *p)
+{
+	int i;
+
+	for(i=0; i<20; i++) {
+		if(p == P || p->as != AJMP)
+			return p;
+		p = p->pcond;
+	}
+	return P;
+}
+
+void
+follow(void)
+{
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f follow\n", cputime());
+	Bflush(&bso);
+	firstp = prg();
+	lastp = firstp;
+	xfol(textp);
+	lastp->link = P;
+	firstp = firstp->link;
+}
+
+void
+xfol(Prog *p)
+{
+	Prog *q;
+	int i;
+	enum as a;
+
+loop:
+	if(p == P)
+		return;
+	if(p->as == ATEXT)
+		curtext = p;
+	if(p->as == AJMP)
+	if((q = p->pcond) != P) {
+		p->mark = 1;
+		p = q;
+		if(p->mark == 0)
+			goto loop;
+	}
+	if(p->mark) {
+		/* copy up to 4 instructions to avoid branch */
+		for(i=0,q=p; i<4; i++,q=q->link) {
+			if(q == P)
+				break;
+			if(q == lastp)
+				break;
+			a = q->as;
+			if(a == ANOP) {
+				i--;
+				continue;
+			}
+			switch(a) {
+			case AJMP:
+			case ARET:
+			case AIRETL:
+			case AIRETQ:
+			case AIRETW:
+			case ARETFL:
+			case ARETFQ:
+			case ARETFW:
+
+			case APUSHL:
+			case APUSHFL:
+			case APUSHQ:
+			case APUSHFQ:
+			case APUSHW:
+			case APUSHFW:
+			case APOPL:
+			case APOPFL:
+			case APOPQ:
+			case APOPFQ:
+			case APOPW:
+			case APOPFW:
+				goto brk;
+			}
+			if(q->pcond == P || q->pcond->mark)
+				continue;
+			if(a == ACALL || a == ALOOP)
+				continue;
+			for(;;) {
+				if(p->as == ANOP) {
+					p = p->link;
+					continue;
+				}
+				q = copyp(p);
+				p = p->link;
+				q->mark = 1;
+				lastp->link = q;
+				lastp = q;
+				if(q->as != a || q->pcond == P || q->pcond->mark)
+					continue;
+
+				q->as = relinv(q->as);
+				p = q->pcond;
+				q->pcond = q->link;
+				q->link = p;
+				xfol(q->link);
+				p = q->link;
+				if(p->mark)
+					return;
+				goto loop;
+			}
+		} /* */
+	brk:;
+		q = prg();
+		q->as = AJMP;
+		q->line = p->line;
+		q->to.type = D_BRANCH;
+		q->to.offset = p->pc;
+		q->pcond = p;
+		p = q;
+	}
+	p->mark = 1;
+	lastp->link = p;
+	lastp = p;
+	a = p->as;
+	if(a == AJMP || a == ARET || a == AIRETL || a == AIRETQ || a == AIRETW ||
+	   a == ARETFL || a == ARETFQ || a == ARETFW)
+		return;
+	if(p->pcond != P)
+	if(a != ACALL) {
+		q = brchain(p->link);
+		if(q != P && q->mark)
+		if(a != ALOOP) {
+			p->as = relinv(a);
+			p->link = p->pcond;
+			p->pcond = q;
+		}
+		xfol(p->link);
+		q = brchain(p->pcond);
+		if(q->mark) {
+			p->pcond = q;
+			return;
+		}
+		p = q;
+		goto loop;
+	}
+	p = p->link;
+	goto loop;
+}
+
+int
+relinv(int a)
+{
+
+	switch(a) {
+	case AJEQ:	return AJNE;
+	case AJNE:	return AJEQ;
+	case AJLE:	return AJGT;
+	case AJLS:	return AJHI;
+	case AJLT:	return AJGE;
+	case AJMI:	return AJPL;
+	case AJGE:	return AJLT;
+	case AJPL:	return AJMI;
+	case AJGT:	return AJLE;
+	case AJHI:	return AJLS;
+	case AJCS:	return AJCC;
+	case AJCC:	return AJCS;
+	case AJPS:	return AJPC;
+	case AJPC:	return AJPS;
+	case AJOS:	return AJOC;
+	case AJOC:	return AJOS;
+	}
+	diag("unknown relation: %s in %s", anames[a], TNAME);
+	return a;
+}
+
+void
+doinit(void)
+{
+	Sym *s;
+	Prog *p;
+	int x;
+
+	for(p = datap; p != P; p = p->link) {
+		x = p->to.type;
+		if(x != D_EXTERN && x != D_STATIC)
+			continue;
+		s = p->to.sym;
+		if(s->type == 0 || s->type == SXREF)
+			diag("undefined %s initializer of %s",
+				s->name, p->from.sym->name);
+		p->to.offset += s->value;
+		p->to.type = D_CONST;
+		if(s->type == SDATA || s->type == SBSS)
+			p->to.offset += INITDAT;
+	}
+}
+
+void
+patch(void)
+{
+	long c;
+	Prog *p, *q;
+	Sym *s;
+	long vexit;
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f mkfwd\n", cputime());
+	Bflush(&bso);
+	mkfwd();
+	if(debug['v'])
+		Bprint(&bso, "%5.2f patch\n", cputime());
+	Bflush(&bso);
+	s = lookup("exit", 0);
+	vexit = s->value;
+	for(p = firstp; p != P; p = p->link) {
+		if(p->as == ATEXT)
+			curtext = p;
+		if(p->as == ACALL || p->as == ARET) {
+			s = p->to.sym;
+			if(s) {
+				if(debug['c'])
+					Bprint(&bso, "%s calls %s\n", TNAME, s->name);
+				switch(s->type) {
+				default:
+					diag("undefined: %s in %s", s->name, TNAME);
+					s->type = STEXT;
+					s->value = vexit;
+					break;	/* or fall through to set offset? */
+				case STEXT:
+					p->to.offset = s->value;
+					break;
+				case SUNDEF:
+					p->pcond = UP;
+					p->to.offset = 0;
+					break;
+				}
+				p->to.type = D_BRANCH;
+			}
+		}
+		if(p->to.type != D_BRANCH || p->pcond == UP)
+			continue;
+		c = p->to.offset;
+		for(q = firstp; q != P;) {
+			if(q->forwd != P)
+			if(c >= q->forwd->pc) {
+				q = q->forwd;
+				continue;
+			}
+			if(c == q->pc)
+				break;
+			q = q->link;
+		}
+		if(q == P) {
+			diag("branch out of range in %s\n%P", TNAME, p);
+			p->to.type = D_NONE;
+		}
+		p->pcond = q;
+	}
+
+	for(p = firstp; p != P; p = p->link) {
+		if(p->as == ATEXT)
+			curtext = p;
+		p->mark = 0;	/* initialization for follow */
+		if(p->pcond != P && p->pcond != UP) {
+			p->pcond = brloop(p->pcond);
+			if(p->pcond != P)
+			if(p->to.type == D_BRANCH)
+				p->to.offset = p->pcond->pc;
+		}
+	}
+}
+
+#define	LOG	5
+void
+mkfwd(void)
+{
+	Prog *p;
+	int i;
+	long dwn[LOG], cnt[LOG];
+	Prog *lst[LOG];
+
+	for(i=0; i<LOG; i++) {
+		if(i == 0)
+			cnt[i] = 1; else
+			cnt[i] = LOG * cnt[i-1];
+		dwn[i] = 1;
+		lst[i] = P;
+	}
+	i = 0;
+	for(p = firstp; p != P; p = p->link) {
+		if(p->as == ATEXT)
+			curtext = p;
+		i--;
+		if(i < 0)
+			i = LOG-1;
+		p->forwd = P;
+		dwn[i]--;
+		if(dwn[i] <= 0) {
+			dwn[i] = cnt[i];
+			if(lst[i] != P)
+				lst[i]->forwd = p;
+			lst[i] = p;
+		}
+	}
+}
+
+Prog*
+brloop(Prog *p)
+{
+	int c;
+	Prog *q;
+
+	c = 0;
+	for(q = p; q != P; q = q->pcond) {
+		if(q->as != AJMP)
+			break;
+		c++;
+		if(c >= 5000)
+			return P;
+	}
+	return q;
+}
+
+void
+dostkoff(void)
+{
+	Prog *p, *q;
+	long autoffset, deltasp;
+	int a, f, curframe, curbecome, maxbecome, pcsize;
+
+	curframe = 0;
+	curbecome = 0;
+	maxbecome = 0;
+	curtext = 0;
+	for(p = firstp; p != P; p = p->link) {
+
+		/* find out how much arg space is used in this TEXT */
+		if(p->to.type == (D_INDIR+D_SP))
+			if(p->to.offset > curframe)
+				curframe = p->to.offset;
+
+		switch(p->as) {
+		case ATEXT:
+			if(curtext && curtext->from.sym) {
+				curtext->from.sym->frame = curframe;
+				curtext->from.sym->become = curbecome;
+				if(curbecome > maxbecome)
+					maxbecome = curbecome;
+			}
+			curframe = 0;
+			curbecome = 0;
+
+			curtext = p;
+			break;
+
+		case ARET:
+			/* special form of RET is BECOME */
+			if(p->from.type == D_CONST)
+				if(p->from.offset > curbecome)
+					curbecome = p->from.offset;
+			break;
+		}
+	}
+	if(curtext && curtext->from.sym) {
+		curtext->from.sym->frame = curframe;
+		curtext->from.sym->become = curbecome;
+		if(curbecome > maxbecome)
+			maxbecome = curbecome;
+	}
+
+	if(debug['b'])
+		print("max become = %d\n", maxbecome);
+	xdefine("ALEFbecome", STEXT, maxbecome);
+
+	curtext = 0;
+	for(p = firstp; p != P; p = p->link) {
+		switch(p->as) {
+		case ATEXT:
+			curtext = p;
+			break;
+		case ACALL:
+			if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
+				f = maxbecome - curtext->from.sym->frame;
+				if(f <= 0)
+					break;
+				/* calling a become or calling a variable */
+				if(p->to.sym == S || p->to.sym->become) {
+					curtext->to.offset += f;
+					if(debug['b']) {
+						curp = p;
+						print("%D calling %D increase %d\n",
+							&curtext->from, &p->to, f);
+					}
+				}
+			}
+			break;
+		}
+	}
+
+	autoffset = 0;
+	deltasp = 0;
+	for(p = firstp; p != P; p = p->link) {
+		if(p->as == ATEXT) {
+			curtext = p;
+			autoffset = p->to.offset;
+			if(autoffset < 0)
+				autoffset = 0;
+			if(autoffset) {
+				p = appendp(p);
+				p->as = AADJSP;
+				p->from.type = D_CONST;
+				p->from.offset = autoffset;
+			}
+			deltasp = autoffset;
+		}
+		pcsize = p->mode/8;
+		a = p->from.type;
+		if(a == D_AUTO)
+			p->from.offset += deltasp;
+		if(a == D_PARAM)
+			p->from.offset += deltasp + pcsize;
+		a = p->to.type;
+		if(a == D_AUTO)
+			p->to.offset += deltasp;
+		if(a == D_PARAM)
+			p->to.offset += deltasp + pcsize;
+
+		switch(p->as) {
+		default:
+			continue;
+		case APUSHL:
+		case APUSHFL:
+			deltasp += 4;
+			continue;
+		case APUSHQ:
+		case APUSHFQ:
+			deltasp += 8;
+			continue;
+		case APUSHW:
+		case APUSHFW:
+			deltasp += 2;
+			continue;
+		case APOPL:
+		case APOPFL:
+			deltasp -= 4;
+			continue;
+		case APOPQ:
+		case APOPFQ:
+			deltasp -= 8;
+			continue;
+		case APOPW:
+		case APOPFW:
+			deltasp -= 2;
+			continue;
+		case ARET:
+			break;
+		}
+
+		if(autoffset != deltasp)
+			diag("unbalanced PUSH/POP");
+		if(p->from.type == D_CONST)
+			goto become;
+
+		if(autoffset) {
+			q = p;
+			p = appendp(p);
+			p->as = ARET;
+
+			q->as = AADJSP;
+			q->from.type = D_CONST;
+			q->from.offset = -autoffset;
+		}
+		continue;
+
+	become:
+		q = p;
+		p = appendp(p);
+		p->as = AJMP;
+		p->to = q->to;
+		p->pcond = q->pcond;
+
+		q->as = AADJSP;
+		q->from = zprg.from;
+		q->from.type = D_CONST;
+		q->from.offset = -autoffset;
+		q->to = zprg.to;
+		continue;
+	}
+}
+
+vlong
+atolwhex(char *s)
+{
+	vlong n;
+	int f;
+
+	n = 0;
+	f = 0;
+	while(*s == ' ' || *s == '\t')
+		s++;
+	if(*s == '-' || *s == '+') {
+		if(*s++ == '-')
+			f = 1;
+		while(*s == ' ' || *s == '\t')
+			s++;
+	}
+	if(s[0]=='0' && s[1]){
+		if(s[1]=='x' || s[1]=='X'){
+			s += 2;
+			for(;;){
+				if(*s >= '0' && *s <= '9')
+					n = n*16 + *s++ - '0';
+				else if(*s >= 'a' && *s <= 'f')
+					n = n*16 + *s++ - 'a' + 10;
+				else if(*s >= 'A' && *s <= 'F')
+					n = n*16 + *s++ - 'A' + 10;
+				else
+					break;
+			}
+		} else
+			while(*s >= '0' && *s <= '7')
+				n = n*8 + *s++ - '0';
+	} else
+		while(*s >= '0' && *s <= '9')
+			n = n*10 + *s++ - '0';
+	if(f)
+		n = -n;
+	return n;
+}
+
+void
+undef(void)
+{
+	int i;
+	Sym *s;
+
+	for(i=0; i<NHASH; i++)
+	for(s = hash[i]; s != S; s = s->link)
+		if(s->type == SXREF)
+			diag("%s: not defined", s->name);
+}
+
+void
+import(void)
+{
+	int i;
+	Sym *s;
+
+	for(i = 0; i < NHASH; i++)
+		for(s = hash[i]; s != S; s = s->link)
+			if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
+				if(s->value != 0)
+					diag("value != 0 on SXREF");
+				undefsym(s);
+				Bprint(&bso, "IMPORT: %s sig=%lux v=%lld\n", s->name, s->sig, s->value);
+				if(debug['S'])
+					s->sig = 0;
+			}
+}
+
+void
+ckoff(Sym *s, long v)
+{
+	if(v < 0 || v >= 1<<Roffset)
+		diag("relocation offset %ld for %s out of range", v, s->name);
+}
+
+static Prog*
+newdata(Sym *s, int o, int w, int t)
+{
+	Prog *p;
+
+	p = prg();
+	if(edatap == P)
+		datap = p;
+	else
+		edatap->link = p;
+	edatap = p;
+	p->as = ADATA;
+	p->width = w;
+	p->from.scale = w;
+	p->from.type = t;
+	p->from.sym = s;
+	p->from.offset = o;
+	p->to.type = D_CONST;
+	return p;
+}
+
+void
+export(void)
+{
+	int i, j, n, off, nb, sv, ne;
+	Sym *s, *et, *str, **esyms;
+	Prog *p;
+	char buf[NSNAME], *t;
+
+	n = 0;
+	for(i = 0; i < NHASH; i++)
+		for(s = hash[i]; s != S; s = s->link)
+			if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
+				n++;
+	esyms = malloc(n*sizeof(Sym*));
+	ne = n;
+	n = 0;
+	for(i = 0; i < NHASH; i++)
+		for(s = hash[i]; s != S; s = s->link)
+			if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
+				esyms[n++] = s;
+	for(i = 0; i < ne-1; i++)
+		for(j = i+1; j < ne; j++)
+			if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
+				s = esyms[i];
+				esyms[i] = esyms[j];
+				esyms[j] = s;
+			}
+
+	nb = 0;
+	off = 0;
+	et = lookup(EXPTAB, 0);
+	if(et->type != 0 && et->type != SXREF)
+		diag("%s already defined", EXPTAB);
+	et->type = SDATA;
+	str = lookup(".string", 0);
+	if(str->type == 0)
+		str->type = SDATA;
+	sv = str->value;
+	for(i = 0; i < ne; i++){
+		s = esyms[i];
+		if(debug['S'])
+			s->sig = 0;
+		/* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */
+
+		/* signature */
+		p = newdata(et, off, sizeof(long), D_EXTERN);
+		off += sizeof(long);
+		p->to.offset = s->sig;
+
+		/* address */
+		p = newdata(et, off, sizeof(long), D_EXTERN);
+		off += sizeof(long);
+		p->to.type = D_ADDR;
+		p->to.index = D_EXTERN;
+		p->to.sym = s;
+
+		/* string */
+		t = s->name;
+		n = strlen(t)+1;
+		for(;;){
+			buf[nb++] = *t;
+			sv++;
+			if(nb >= NSNAME){
+				p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
+				p->to.type = D_SCONST;
+				memmove(p->to.scon, buf, NSNAME);
+				nb = 0;
+			}
+			if(*t++ == 0)
+				break;
+		}
+
+		/* name */
+		p = newdata(et, off, sizeof(long), D_EXTERN);
+		off += sizeof(long);
+		p->to.type = D_ADDR;
+		p->to.index = D_STATIC;
+		p->to.sym = str;
+		p->to.offset = sv-n;
+	}
+
+	if(nb > 0){
+		p = newdata(str, sv-nb, nb, D_STATIC);
+		p->to.type = D_SCONST;
+		memmove(p->to.scon, buf, nb);
+	}
+
+	for(i = 0; i < 3; i++){
+		newdata(et, off, sizeof(long), D_EXTERN);
+		off += sizeof(long);
+	}
+	et->value = off;
+	if(sv == 0)
+		sv = 1;
+	str->value = sv;
+	exports = ne;
+	free(esyms);
+}
diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c
new file mode 100644
index 0000000..4b225da
--- /dev/null
+++ b/src/cmd/6l/span.c
@@ -0,0 +1,1776 @@
+// Inferno utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	"l.h"
+
+static int	rexflag;
+static int	asmode;
+
+void
+span(void)
+{
+	Prog *p, *q;
+	long v;
+	vlong c, idat;
+	int m, n, again;
+
+	xdefine("etext", STEXT, 0L);
+	idat = INITDAT;
+	for(p = firstp; p != P; p = p->link) {
+		if(p->as == ATEXT)
+			curtext = p;
+		n = 0;
+		if(p->to.type == D_BRANCH)
+			if(p->pcond == P)
+				p->pcond = p;
+		if((q = p->pcond) != P)
+			if(q->back != 2)
+				n = 1;
+		p->back = n;
+		if(p->as == AADJSP) {
+			p->to.type = D_SP;
+			v = -p->from.offset;
+			p->from.offset = v;
+			p->as = p->mode != 64? AADDL: AADDQ;
+			if(v < 0) {
+				p->as = p->mode != 64? ASUBL: ASUBQ;
+				v = -v;
+				p->from.offset = v;
+			}
+			if(v == 0)
+				p->as = ANOP;
+		}
+	}
+	n = 0;
+
+start:
+	if(debug['v'])
+		Bprint(&bso, "%5.2f span\n", cputime());
+	Bflush(&bso);
+	c = INITTEXT;
+	for(p = firstp; p != P; p = p->link) {
+		if(p->as == ATEXT)
+			curtext = p;
+		if(p->to.type == D_BRANCH)
+			if(p->back)
+				p->pc = c;
+		asmins(p);
+		p->pc = c;
+		m = andptr-and;
+		p->mark = m;
+		c += m;
+	}
+
+loop:
+	n++;
+	if(debug['v'])
+		Bprint(&bso, "%5.2f span %d\n", cputime(), n);
+	Bflush(&bso);
+	if(n > 50) {
+		print("span must be looping\n");
+		errorexit();
+	}
+	again = 0;
+	c = INITTEXT;
+	for(p = firstp; p != P; p = p->link) {
+		if(p->as == ATEXT)
+			curtext = p;
+		if(p->to.type == D_BRANCH || p->back & 0100) {
+			if(p->back)
+				p->pc = c;
+			asmins(p);
+			m = andptr-and;
+			if(m != p->mark) {
+				p->mark = m;
+				again++;
+			}
+		}
+		p->pc = c;
+		c += p->mark;
+	}
+	if(again) {
+		textsize = c;
+		goto loop;
+	}
+	if(INITRND) {
+		INITDAT = rnd(c, INITRND);
+		if(INITDAT != idat) {
+			idat = INITDAT;
+			goto start;
+		}
+	}
+	xdefine("etext", STEXT, c);
+	if(debug['v'])
+		Bprint(&bso, "etext = %llux\n", c);
+	Bflush(&bso);
+	for(p = textp; p != P; p = p->pcond)
+		p->from.sym->value = p->pc;
+	textsize = c - INITTEXT;
+}
+
+void
+xdefine(char *p, int t, vlong v)
+{
+	Sym *s;
+
+	s = lookup(p, 0);
+	if(s->type == 0 || s->type == SXREF) {
+		s->type = t;
+		s->value = v;
+	}
+	if(s->type == STEXT && s->value == 0)
+		s->value = v;
+}
+
+void
+putsymb(char *s, int t, vlong v, int ver)
+{
+	int i, f, l;
+
+	if(t == 'f')
+		s++;
+	l = 4;
+	if(!debug['8']){
+		lput(v>>32);
+		l = 8;
+	}
+	lput(v);
+	if(ver)
+		t += 'a' - 'A';
+	cput(t+0x80);			/* 0x80 is variable length */
+
+	if(t == 'Z' || t == 'z') {
+		cput(s[0]);
+		for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
+			cput(s[i]);
+			cput(s[i+1]);
+		}
+		cput(0);
+		cput(0);
+		i++;
+	}
+	else {
+		for(i=0; s[i]; i++)
+			cput(s[i]);
+		cput(0);
+	}
+	symsize += l + 1 + i + 1;
+
+	if(debug['n']) {
+		if(t == 'z' || t == 'Z') {
+			Bprint(&bso, "%c %.8llux ", t, v);
+			for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
+				f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
+				Bprint(&bso, "/%x", f);
+			}
+			Bprint(&bso, "\n");
+			return;
+		}
+		if(ver)
+			Bprint(&bso, "%c %.8llux %s<%d>\n", t, v, s, ver);
+		else
+			Bprint(&bso, "%c %.8llux %s\n", t, v, s);
+	}
+}
+
+void
+asmsym(void)
+{
+	Prog *p;
+	Auto *a;
+	Sym *s;
+	int h;
+
+	s = lookup("etext", 0);
+	if(s->type == STEXT)
+		putsymb(s->name, 'T', s->value, s->version);
+
+	for(h=0; h<NHASH; h++)
+		for(s=hash[h]; s!=S; s=s->link)
+			switch(s->type) {
+			case SCONST:
+				putsymb(s->name, 'D', s->value, s->version);
+				continue;
+
+			case SDATA:
+				putsymb(s->name, 'D', s->value+INITDAT, s->version);
+				continue;
+
+			case SBSS:
+				putsymb(s->name, 'B', s->value+INITDAT, s->version);
+				continue;
+
+			case SFILE:
+				putsymb(s->name, 'f', s->value, s->version);
+				continue;
+			}
+
+	for(p=textp; p!=P; p=p->pcond) {
+		s = p->from.sym;
+		if(s->type != STEXT)
+			continue;
+
+		/* filenames first */
+		for(a=p->to.autom; a; a=a->link)
+			if(a->type == D_FILE)
+				putsymb(a->asym->name, 'z', a->aoffset, 0);
+			else
+			if(a->type == D_FILE1)
+				putsymb(a->asym->name, 'Z', a->aoffset, 0);
+
+		putsymb(s->name, 'T', s->value, s->version);
+
+		/* frame, auto and param after */
+		putsymb(".frame", 'm', p->to.offset+8, 0);
+
+		for(a=p->to.autom; a; a=a->link)
+			if(a->type == D_AUTO)
+				putsymb(a->asym->name, 'a', -a->aoffset, 0);
+			else
+			if(a->type == D_PARAM)
+				putsymb(a->asym->name, 'p', a->aoffset, 0);
+	}
+	if(debug['v'] || debug['n'])
+		Bprint(&bso, "symsize = %lud\n", symsize);
+	Bflush(&bso);
+}
+
+void
+asmlc(void)
+{
+	vlong oldpc;
+	Prog *p;
+	long oldlc, v, s;
+
+	oldpc = INITTEXT;
+	oldlc = 0;
+	for(p = firstp; p != P; p = p->link) {
+		if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+			if(p->as == ATEXT)
+				curtext = p;
+			if(debug['L'])
+				Bprint(&bso, "%6llux %P\n",
+					p->pc, p);
+			continue;
+		}
+		if(debug['L'])
+			Bprint(&bso, "\t\t%6ld", lcsize);
+		v = (p->pc - oldpc) / MINLC;
+		while(v) {
+			s = 127;
+			if(v < 127)
+				s = v;
+			cput(s+128);	/* 129-255 +pc */
+			if(debug['L'])
+				Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
+			v -= s;
+			lcsize++;
+		}
+		s = p->line - oldlc;
+		oldlc = p->line;
+		oldpc = p->pc + MINLC;
+		if(s > 64 || s < -64) {
+			cput(0);	/* 0 vv +lc */
+			cput(s>>24);
+			cput(s>>16);
+			cput(s>>8);
+			cput(s);
+			if(debug['L']) {
+				if(s > 0)
+					Bprint(&bso, " lc+%ld(%d,%ld)\n",
+						s, 0, s);
+				else
+					Bprint(&bso, " lc%ld(%d,%ld)\n",
+						s, 0, s);
+				Bprint(&bso, "%6llux %P\n",
+					p->pc, p);
+			}
+			lcsize += 5;
+			continue;
+		}
+		if(s > 0) {
+			cput(0+s);	/* 1-64 +lc */
+			if(debug['L']) {
+				Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
+				Bprint(&bso, "%6llux %P\n",
+					p->pc, p);
+			}
+		} else {
+			cput(64-s);	/* 65-128 -lc */
+			if(debug['L']) {
+				Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
+				Bprint(&bso, "%6llux %P\n",
+					p->pc, p);
+			}
+		}
+		lcsize++;
+	}
+	while(lcsize & 1) {
+		s = 129;
+		cput(s);
+		lcsize++;
+	}
+	if(debug['v'] || debug['L'])
+		Bprint(&bso, "lcsize = %ld\n", lcsize);
+	Bflush(&bso);
+}
+
+int
+oclass(Adr *a)
+{
+	vlong v;
+	long l;
+
+	if(a->type >= D_INDIR || a->index != D_NONE) {
+		if(a->index != D_NONE && a->scale == 0) {
+			if(a->type == D_ADDR) {
+				switch(a->index) {
+				case D_EXTERN:
+				case D_STATIC:
+					return Yi32;	/* TO DO: Yi64 */
+				case D_AUTO:
+				case D_PARAM:
+					return Yiauto;
+				}
+				return Yxxx;
+			}
+			return Ycol;
+		}
+		return Ym;
+	}
+	switch(a->type)
+	{
+	case D_AL:
+		return Yal;
+
+	case D_AX:
+		return Yax;
+
+/*
+	case D_SPB:
+*/
+	case D_BPB:
+	case D_SIB:
+	case D_DIB:
+	case D_R8B:
+	case D_R9B:
+	case D_R10B:
+	case D_R11B:
+	case D_R12B:
+	case D_R13B:
+	case D_R14B:
+	case D_R15B:
+		if(asmode != 64)
+			return Yxxx;
+	case D_DL:
+	case D_BL:
+	case D_AH:
+	case D_CH:
+	case D_DH:
+	case D_BH:
+		return Yrb;
+
+	case D_CL:
+		return Ycl;
+
+	case D_CX:
+		return Ycx;
+
+	case D_DX:
+	case D_BX:
+		return Yrx;
+
+	case D_R8:	/* not really Yrl */
+	case D_R9:
+	case D_R10:
+	case D_R11:
+	case D_R12:
+	case D_R13:
+	case D_R14:
+	case D_R15:
+		if(asmode != 64)
+			return Yxxx;
+	case D_SP:
+	case D_BP:
+	case D_SI:
+	case D_DI:
+		return Yrl;
+
+	case D_F0+0:
+		return	Yf0;
+
+	case D_F0+1:
+	case D_F0+2:
+	case D_F0+3:
+	case D_F0+4:
+	case D_F0+5:
+	case D_F0+6:
+	case D_F0+7:
+		return	Yrf;
+
+	case D_M0+0:
+	case D_M0+1:
+	case D_M0+2:
+	case D_M0+3:
+	case D_M0+4:
+	case D_M0+5:
+	case D_M0+6:
+	case D_M0+7:
+		return	Ymr;
+
+	case D_X0+0:
+	case D_X0+1:
+	case D_X0+2:
+	case D_X0+3:
+	case D_X0+4:
+	case D_X0+5:
+	case D_X0+6:
+	case D_X0+7:
+	case D_X0+8:
+	case D_X0+9:
+	case D_X0+10:
+	case D_X0+11:
+	case D_X0+12:
+	case D_X0+13:
+	case D_X0+14:
+	case D_X0+15:
+		return	Yxr;
+
+	case D_NONE:
+		return Ynone;
+
+	case D_CS:	return	Ycs;
+	case D_SS:	return	Yss;
+	case D_DS:	return	Yds;
+	case D_ES:	return	Yes;
+	case D_FS:	return	Yfs;
+	case D_GS:	return	Ygs;
+
+	case D_GDTR:	return	Ygdtr;
+	case D_IDTR:	return	Yidtr;
+	case D_LDTR:	return	Yldtr;
+	case D_MSW:	return	Ymsw;
+	case D_TASK:	return	Ytask;
+
+	case D_CR+0:	return	Ycr0;
+	case D_CR+1:	return	Ycr1;
+	case D_CR+2:	return	Ycr2;
+	case D_CR+3:	return	Ycr3;
+	case D_CR+4:	return	Ycr4;
+	case D_CR+5:	return	Ycr5;
+	case D_CR+6:	return	Ycr6;
+	case D_CR+7:	return	Ycr7;
+	case D_CR+8:	return	Ycr8;
+
+	case D_DR+0:	return	Ydr0;
+	case D_DR+1:	return	Ydr1;
+	case D_DR+2:	return	Ydr2;
+	case D_DR+3:	return	Ydr3;
+	case D_DR+4:	return	Ydr4;
+	case D_DR+5:	return	Ydr5;
+	case D_DR+6:	return	Ydr6;
+	case D_DR+7:	return	Ydr7;
+
+	case D_TR+0:	return	Ytr0;
+	case D_TR+1:	return	Ytr1;
+	case D_TR+2:	return	Ytr2;
+	case D_TR+3:	return	Ytr3;
+	case D_TR+4:	return	Ytr4;
+	case D_TR+5:	return	Ytr5;
+	case D_TR+6:	return	Ytr6;
+	case D_TR+7:	return	Ytr7;
+
+	case D_EXTERN:
+	case D_STATIC:
+	case D_AUTO:
+	case D_PARAM:
+		return Ym;
+
+	case D_CONST:
+	case D_ADDR:
+		if(a->sym == S) {
+			v = a->offset;
+			if(v == 0)
+				return Yi0;
+			if(v == 1)
+				return Yi1;
+			if(v >= -128 && v <= 127)
+				return Yi8;
+			l = v;
+			if((vlong)l == v)
+				return Ys32;	/* can sign extend */
+			if((v>>32) == 0)
+				return Yi32;	/* unsigned */
+			return Yi64;
+		}
+		return Yi32;	/* TO DO: D_ADDR as Yi64 */
+
+	case D_BRANCH:
+		return Ybr;
+	}
+	return Yxxx;
+}
+
+void
+asmidx(Adr *a, int base)
+{
+	int i;
+
+	switch(a->index) {
+	default:
+		goto bad;
+
+	case D_NONE:
+		i = 4 << 3;
+		goto bas;
+
+	case D_R8:
+	case D_R9:
+	case D_R10:
+	case D_R11:
+	case D_R12:
+	case D_R13:
+	case D_R14:
+	case D_R15:
+		if(asmode != 64)
+			goto bad;
+	case D_AX:
+	case D_CX:
+	case D_DX:
+	case D_BX:
+	case D_BP:
+	case D_SI:
+	case D_DI:
+		i = reg[(int)a->index] << 3;
+		break;
+	}
+	switch(a->scale) {
+	default:
+		goto bad;
+	case 1:
+		break;
+	case 2:
+		i |= (1<<6);
+		break;
+	case 4:
+		i |= (2<<6);
+		break;
+	case 8:
+		i |= (3<<6);
+		break;
+	}
+bas:
+	switch(base) {
+	default:
+		goto bad;
+	case D_NONE:	/* must be mod=00 */
+		i |= 5;
+		break;
+	case D_R8:
+	case D_R9:
+	case D_R10:
+	case D_R11:
+	case D_R12:
+	case D_R13:
+	case D_R14:
+	case D_R15:
+		if(asmode != 64)
+			goto bad;
+	case D_AX:
+	case D_CX:
+	case D_DX:
+	case D_BX:
+	case D_SP:
+	case D_BP:
+	case D_SI:
+	case D_DI:
+		i |= reg[base];
+		break;
+	}
+	*andptr++ = i;
+	return;
+bad:
+	diag("asmidx: bad address %D", a);
+	*andptr++ = 0;
+	return;
+}
+
+static void
+put4(long v)
+{
+	if(dlm && curp != P && reloca != nil){
+		dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1);
+		reloca = nil;
+	}
+	andptr[0] = v;
+	andptr[1] = v>>8;
+	andptr[2] = v>>16;
+	andptr[3] = v>>24;
+	andptr += 4;
+}
+
+static void
+put8(vlong v)
+{
+	if(dlm && curp != P && reloca != nil){
+		dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1);	/* TO DO */
+		reloca = nil;
+	}
+	andptr[0] = v;
+	andptr[1] = v>>8;
+	andptr[2] = v>>16;
+	andptr[3] = v>>24;
+	andptr[4] = v>>32;
+	andptr[5] = v>>40;
+	andptr[6] = v>>48;
+	andptr[7] = v>>56;
+	andptr += 8;
+}
+
+vlong
+vaddr(Adr *a)
+{
+	int t;
+	vlong v;
+	Sym *s;
+
+	t = a->type;
+	v = a->offset;
+	if(t == D_ADDR)
+		t = a->index;
+	switch(t) {
+	case D_STATIC:
+	case D_EXTERN:
+		s = a->sym;
+		if(s != nil) {
+			if(dlm && curp != P)
+				reloca = a;
+			switch(s->type) {
+			case SUNDEF:
+				ckoff(s, v);
+			case STEXT:
+			case SCONST:
+				if((uvlong)s->value < (uvlong)INITTEXT)
+					v += INITTEXT;	/* TO DO */
+				v += s->value;
+				break;
+			default:
+				v += INITDAT + s->value;
+			}
+		}
+	}
+	return v;
+}
+
+static void
+asmandsz(Adr *a, int r, int rex, int m64)
+{
+	long v;
+	int t;
+	Adr aa;
+
+	rex &= (0x40 | Rxr);
+	v = a->offset;
+	t = a->type;
+	if(a->index != D_NONE) {
+		if(t >= D_INDIR) {
+			t -= D_INDIR;
+			rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
+			if(t == D_NONE) {
+				*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+				asmidx(a, t);
+				put4(v);
+				return;
+			}
+			if(v == 0 && t != D_BP && t != D_R13) {
+				*andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+				asmidx(a, t);
+				return;
+			}
+			if(v >= -128 && v < 128) {
+				*andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+				asmidx(a, t);
+				*andptr++ = v;
+				return;
+			}
+			*andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+			asmidx(a, t);
+			put4(v);
+			return;
+		}
+		switch(t) {
+		default:
+			goto bad;
+		case D_STATIC:
+		case D_EXTERN:
+			aa.type = D_NONE+D_INDIR;
+			break;
+		case D_AUTO:
+		case D_PARAM:
+			aa.type = D_SP+D_INDIR;
+			break;
+		}
+		aa.offset = vaddr(a);
+		aa.index = a->index;
+		aa.scale = a->scale;
+		asmandsz(&aa, r, rex, m64);
+		return;
+	}
+	if(t >= D_AL && t <= D_X0+15) {
+		if(v)
+			goto bad;
+		*andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
+		rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
+		return;
+	}
+	if(t >= D_INDIR) {
+		t -= D_INDIR;
+		rexflag |= (regrex[t] & Rxb) | rex;
+		if(t == D_NONE) {
+			if(asmode != 64){
+				*andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+				put4(v);
+				return;
+			}
+			/* temporary */
+			*andptr++ = (0 <<  6) | (4 << 0) | (r << 3);	/* sib present */
+			*andptr++ = (0 << 6) | (4 << 3) | (5 << 0);	/* DS:d32 */
+			put4(v);
+			return;
+		}
+		if(t == D_SP || t == D_R12) {
+			if(v == 0) {
+				*andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+				asmidx(a, t);
+				return;
+			}
+			if(v >= -128 && v < 128) {
+				*andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
+				asmidx(a, t);
+				*andptr++ = v;
+				return;
+			}
+			*andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+			asmidx(a, t);
+			put4(v);
+			return;
+		}
+		if(t >= D_AX && t <= D_R15) {
+			if(v == 0 && t != D_BP && t != D_R13) {
+				*andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+				return;
+			}
+			if(v >= -128 && v < 128) {
+				andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+				andptr[1] = v;
+				andptr += 2;
+				return;
+			}
+			*andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+			put4(v);
+			return;
+		}
+		goto bad;
+	}
+	switch(a->type) {
+	default:
+		goto bad;
+	case D_STATIC:
+	case D_EXTERN:
+		aa.type = D_NONE+D_INDIR;
+		break;
+	case D_AUTO:
+	case D_PARAM:
+		aa.type = D_SP+D_INDIR;
+		break;
+	}
+	aa.index = D_NONE;
+	aa.scale = 1;
+	aa.offset = vaddr(a);
+	asmandsz(&aa, r, rex, m64);
+	return;
+bad:
+	diag("asmand: bad address %D", a);
+	return;
+}
+
+void
+asmand(Adr *a, Adr *ra)
+{
+	asmandsz(a, reg[ra->type], regrex[ra->type], 0);
+}
+
+void
+asmando(Adr *a, int o)
+{
+	asmandsz(a, o, 0, 0);
+}
+
+static void
+bytereg(Adr *a)
+{
+	if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15))
+		a->type = D_AL + (a->type-D_AX);
+}
+
+#define	E	0xff
+Movtab	ymovtab[] =
+{
+/* push */
+	{APUSHL,	Ycs,	Ynone,	0,	0x0e,E,0,0},
+	{APUSHL,	Yss,	Ynone,	0,	0x16,E,0,0},
+	{APUSHL,	Yds,	Ynone,	0,	0x1e,E,0,0},
+	{APUSHL,	Yes,	Ynone,	0,	0x06,E,0,0},
+	{APUSHL,	Yfs,	Ynone,	0,	0x0f,0xa0,E,0},
+	{APUSHL,	Ygs,	Ynone,	0,	0x0f,0xa8,E,0},
+	{APUSHQ,	Yfs,	Ynone,	0,	0x0f,0xa0,E,0},
+	{APUSHQ,	Ygs,	Ynone,	0,	0x0f,0xa8,E,0},
+
+	{APUSHW,	Ycs,	Ynone,	0,	Pe,0x0e,E,0},
+	{APUSHW,	Yss,	Ynone,	0,	Pe,0x16,E,0},
+	{APUSHW,	Yds,	Ynone,	0,	Pe,0x1e,E,0},
+	{APUSHW,	Yes,	Ynone,	0,	Pe,0x06,E,0},
+	{APUSHW,	Yfs,	Ynone,	0,	Pe,0x0f,0xa0,E},
+	{APUSHW,	Ygs,	Ynone,	0,	Pe,0x0f,0xa8,E},
+
+/* pop */
+	{APOPL,	Ynone,	Yds,	0,	0x1f,E,0,0},
+	{APOPL,	Ynone,	Yes,	0,	0x07,E,0,0},
+	{APOPL,	Ynone,	Yss,	0,	0x17,E,0,0},
+	{APOPL,	Ynone,	Yfs,	0,	0x0f,0xa1,E,0},
+	{APOPL,	Ynone,	Ygs,	0,	0x0f,0xa9,E,0},
+	{APOPQ,	Ynone,	Yfs,	0,	0x0f,0xa1,E,0},
+	{APOPQ,	Ynone,	Ygs,	0,	0x0f,0xa9,E,0},
+
+	{APOPW,	Ynone,	Yds,	0,	Pe,0x1f,E,0},
+	{APOPW,	Ynone,	Yes,	0,	Pe,0x07,E,0},
+	{APOPW,	Ynone,	Yss,	0,	Pe,0x17,E,0},
+	{APOPW,	Ynone,	Yfs,	0,	Pe,0x0f,0xa1,E},
+	{APOPW,	Ynone,	Ygs,	0,	Pe,0x0f,0xa9,E},
+
+/* mov seg */
+	{AMOVW,	Yes,	Yml,	1,	0x8c,0,0,0},
+	{AMOVW,	Ycs,	Yml,	1,	0x8c,1,0,0},
+	{AMOVW,	Yss,	Yml,	1,	0x8c,2,0,0},
+	{AMOVW,	Yds,	Yml,	1,	0x8c,3,0,0},
+	{AMOVW,	Yfs,	Yml,	1,	0x8c,4,0,0},
+	{AMOVW,	Ygs,	Yml,	1,	0x8c,5,0,0},
+
+	{AMOVW,	Yml,	Yes,	2,	0x8e,0,0,0},
+	{AMOVW,	Yml,	Ycs,	2,	0x8e,1,0,0},
+	{AMOVW,	Yml,	Yss,	2,	0x8e,2,0,0},
+	{AMOVW,	Yml,	Yds,	2,	0x8e,3,0,0},
+	{AMOVW,	Yml,	Yfs,	2,	0x8e,4,0,0},
+	{AMOVW,	Yml,	Ygs,	2,	0x8e,5,0,0},
+
+/* mov cr */
+	{AMOVL,	Ycr0,	Yml,	3,	0x0f,0x20,0,0},
+	{AMOVL,	Ycr2,	Yml,	3,	0x0f,0x20,2,0},
+	{AMOVL,	Ycr3,	Yml,	3,	0x0f,0x20,3,0},
+	{AMOVL,	Ycr4,	Yml,	3,	0x0f,0x20,4,0},
+	{AMOVL,	Ycr8,	Yml,	3,	0x0f,0x20,8,0},
+	{AMOVQ,	Ycr0,	Yml,	3,	0x0f,0x20,0,0},
+	{AMOVQ,	Ycr2,	Yml,	3,	0x0f,0x20,2,0},
+	{AMOVQ,	Ycr3,	Yml,	3,	0x0f,0x20,3,0},
+	{AMOVQ,	Ycr4,	Yml,	3,	0x0f,0x20,4,0},
+	{AMOVQ,	Ycr8,	Yml,	3,	0x0f,0x20,8,0},
+
+	{AMOVL,	Yml,	Ycr0,	4,	0x0f,0x22,0,0},
+	{AMOVL,	Yml,	Ycr2,	4,	0x0f,0x22,2,0},
+	{AMOVL,	Yml,	Ycr3,	4,	0x0f,0x22,3,0},
+	{AMOVL,	Yml,	Ycr4,	4,	0x0f,0x22,4,0},
+	{AMOVL,	Yml,	Ycr8,	4,	0x0f,0x22,8,0},
+	{AMOVQ,	Yml,	Ycr0,	4,	0x0f,0x22,0,0},
+	{AMOVQ,	Yml,	Ycr2,	4,	0x0f,0x22,2,0},
+	{AMOVQ,	Yml,	Ycr3,	4,	0x0f,0x22,3,0},
+	{AMOVQ,	Yml,	Ycr4,	4,	0x0f,0x22,4,0},
+	{AMOVQ,	Yml,	Ycr8,	4,	0x0f,0x22,8,0},
+
+/* mov dr */
+	{AMOVL,	Ydr0,	Yml,	3,	0x0f,0x21,0,0},
+	{AMOVL,	Ydr6,	Yml,	3,	0x0f,0x21,6,0},
+	{AMOVL,	Ydr7,	Yml,	3,	0x0f,0x21,7,0},
+	{AMOVQ,	Ydr0,	Yml,	3,	0x0f,0x21,0,0},
+	{AMOVQ,	Ydr6,	Yml,	3,	0x0f,0x21,6,0},
+	{AMOVQ,	Ydr7,	Yml,	3,	0x0f,0x21,7,0},
+
+	{AMOVL,	Yml,	Ydr0,	4,	0x0f,0x23,0,0},
+	{AMOVL,	Yml,	Ydr6,	4,	0x0f,0x23,6,0},
+	{AMOVL,	Yml,	Ydr7,	4,	0x0f,0x23,7,0},
+	{AMOVQ,	Yml,	Ydr0,	4,	0x0f,0x23,0,0},
+	{AMOVQ,	Yml,	Ydr6,	4,	0x0f,0x23,6,0},
+	{AMOVQ,	Yml,	Ydr7,	4,	0x0f,0x23,7,0},
+
+/* mov tr */
+	{AMOVL,	Ytr6,	Yml,	3,	0x0f,0x24,6,0},
+	{AMOVL,	Ytr7,	Yml,	3,	0x0f,0x24,7,0},
+
+	{AMOVL,	Yml,	Ytr6,	4,	0x0f,0x26,6,E},
+	{AMOVL,	Yml,	Ytr7,	4,	0x0f,0x26,7,E},
+
+/* lgdt, sgdt, lidt, sidt */
+	{AMOVL,	Ym,	Ygdtr,	4,	0x0f,0x01,2,0},
+	{AMOVL,	Ygdtr,	Ym,	3,	0x0f,0x01,0,0},
+	{AMOVL,	Ym,	Yidtr,	4,	0x0f,0x01,3,0},
+	{AMOVL,	Yidtr,	Ym,	3,	0x0f,0x01,1,0},
+	{AMOVQ,	Ym,	Ygdtr,	4,	0x0f,0x01,2,0},
+	{AMOVQ,	Ygdtr,	Ym,	3,	0x0f,0x01,0,0},
+	{AMOVQ,	Ym,	Yidtr,	4,	0x0f,0x01,3,0},
+	{AMOVQ,	Yidtr,	Ym,	3,	0x0f,0x01,1,0},
+
+/* lldt, sldt */
+	{AMOVW,	Yml,	Yldtr,	4,	0x0f,0x00,2,0},
+	{AMOVW,	Yldtr,	Yml,	3,	0x0f,0x00,0,0},
+
+/* lmsw, smsw */
+	{AMOVW,	Yml,	Ymsw,	4,	0x0f,0x01,6,0},
+	{AMOVW,	Ymsw,	Yml,	3,	0x0f,0x01,4,0},
+
+/* ltr, str */
+	{AMOVW,	Yml,	Ytask,	4,	0x0f,0x00,3,0},
+	{AMOVW,	Ytask,	Yml,	3,	0x0f,0x00,1,0},
+
+/* load full pointer */
+	{AMOVL,	Yml,	Ycol,	5,	0,0,0,0},
+	{AMOVW,	Yml,	Ycol,	5,	Pe,0,0,0},
+
+/* double shift */
+	{ASHLL,	Ycol,	Yml,	6,	0xa4,0xa5,0,0},
+	{ASHRL,	Ycol,	Yml,	6,	0xac,0xad,0,0},
+	{ASHLQ,	Ycol,	Yml,	6,	Pw,0xa4,0xa5,0},
+	{ASHRQ,	Ycol,	Yml,	6,	Pw,0xac,0xad,0},
+	{ASHLW,	Ycol,	Yml,	6,	Pe,0xa4,0xa5,0},
+	{ASHRW,	Ycol,	Yml,	6,	Pe,0xac,0xad,0},
+	0
+};
+
+int
+isax(Adr *a)
+{
+
+	switch(a->type) {
+	case D_AX:
+	case D_AL:
+	case D_AH:
+	case D_INDIR+D_AX:
+		return 1;
+	}
+	if(a->index == D_AX)
+		return 1;
+	return 0;
+}
+
+void
+subreg(Prog *p, int from, int to)
+{
+
+	if(debug['Q'])
+		print("\n%P	s/%R/%R/\n", p, from, to);
+
+	if(p->from.type == from)
+		p->from.type = to;
+	if(p->to.type == from)
+		p->to.type = to;
+
+	if(p->from.index == from)
+		p->from.index = to;
+	if(p->to.index == from)
+		p->to.index = to;
+
+	from += D_INDIR;
+	if(p->from.type == from)
+		p->from.type = to+D_INDIR;
+	if(p->to.type == from)
+		p->to.type = to+D_INDIR;
+
+	if(debug['Q'])
+		print("%P\n", p);
+}
+
+static int
+mediaop(Optab *o, int op, int osize, int z)
+{
+	switch(op){
+	case Pm:
+	case Pe:
+	case Pf2:
+	case Pf3:
+		if(osize != 1){
+			if(op != Pm)
+				*andptr++ = op;
+			*andptr++ = Pm;
+			op = o->op[++z];
+			break;
+		}
+	default:
+		if(andptr == and || andptr[-1] != Pm)
+			*andptr++ = Pm;
+		break;
+	}
+	*andptr++ = op;
+	return z;
+}
+
+void
+doasm(Prog *p)
+{
+	Optab *o;
+	Prog *q, pp;
+	uchar *t;
+	Movtab *mo;
+	int z, op, ft, tt, xo, l;
+	vlong v;
+
+	o = opindex[p->as];
+	if(o == nil) {
+		diag("asmins: missing op %P", p);
+		return;
+	}
+	ft = oclass(&p->from) * Ymax;
+	tt = oclass(&p->to) * Ymax;
+	t = o->ytab;
+	if(t == 0) {
+		diag("asmins: noproto %P", p);
+		return;
+	}
+	xo = o->op[0] == 0x0f;
+	for(z=0; *t; z+=t[3]+xo,t+=4)
+		if(ycover[ft+t[0]])
+		if(ycover[tt+t[1]])
+			goto found;
+	goto domov;
+
+found:
+	switch(o->prefix) {
+	case Pq:	/* 16 bit escape and opcode escape */
+		*andptr++ = Pe;
+		*andptr++ = Pm;
+		break;
+
+	case Pf2:	/* xmm opcode escape */
+	case Pf3:
+		*andptr++ = o->prefix;
+		*andptr++ = Pm;
+		break;
+
+	case Pm:	/* opcode escape */
+		*andptr++ = Pm;
+		break;
+
+	case Pe:	/* 16 bit escape */
+		*andptr++ = Pe;
+		break;
+
+	case Pw:	/* 64-bit escape */
+		if(p->mode != 64)
+			diag("asmins: illegal 64: %P", p);
+		rexflag |= Pw;
+		break;
+
+	case Pb:	/* botch */
+		bytereg(&p->from);
+		bytereg(&p->to);
+		break;
+
+	case P32:	/* 32 bit but illegal if 64-bit mode */
+		if(p->mode == 64)
+			diag("asmins: illegal in 64-bit mode: %P", p);
+		break;
+
+	case Py:	/* 64-bit only, no prefix */
+		if(p->mode != 64)
+			diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
+		break;
+	}
+	v = vaddr(&p->from);
+	op = o->op[z];
+	if(op == 0x0f) {
+		*andptr++ = op;
+		op = o->op[++z];
+	}
+	switch(t[2]) {
+	default:
+		diag("asmins: unknown z %d %P", t[2], p);
+		return;
+
+	case Zpseudo:
+		break;
+
+	case Zlit:
+		for(; op = o->op[z]; z++)
+			*andptr++ = op;
+		break;
+
+	case Zmb_r:
+		bytereg(&p->from);
+		/* fall through */
+	case Zm_r:
+		*andptr++ = op;
+		asmand(&p->from, &p->to);
+		break;
+
+	case Zm_r_xm:
+		mediaop(o, op, t[3], z);
+		asmand(&p->from, &p->to);
+		break;
+
+	case Zm_r_xm_nr:
+		rexflag = 0;
+		mediaop(o, op, t[3], z);
+		asmand(&p->from, &p->to);
+		break;
+
+	case Zm_r_i_xm:
+		mediaop(o, op, t[3], z);
+		asmand(&p->from, &p->to);
+		*andptr++ = p->to.offset;
+		break;
+
+	case Zm_r_3d:
+		*andptr++ = 0x0f;
+		*andptr++ = 0x0f;
+		asmand(&p->from, &p->to);
+		*andptr++ = op;
+		break;
+
+	case Zibm_r:
+		*andptr++ = op;
+		asmand(&p->from, &p->to);
+		*andptr++ = p->to.offset;
+		break;
+
+	case Zaut_r:
+		*andptr++ = 0x8d;	/* leal */
+		if(p->from.type != D_ADDR)
+			diag("asmins: Zaut sb type ADDR");
+		p->from.type = p->from.index;
+		p->from.index = D_NONE;
+		asmand(&p->from, &p->to);
+		p->from.index = p->from.type;
+		p->from.type = D_ADDR;
+		break;
+
+	case Zm_o:
+		*andptr++ = op;
+		asmando(&p->from, o->op[z+1]);
+		break;
+
+	case Zr_m:
+		*andptr++ = op;
+		asmand(&p->to, &p->from);
+		break;
+
+	case Zr_m_xm:
+		mediaop(o, op, t[3], z);
+		asmand(&p->to, &p->from);
+		break;
+
+	case Zr_m_xm_nr:
+		rexflag = 0;
+		mediaop(o, op, t[3], z);
+		asmand(&p->to, &p->from);
+		break;
+
+	case Zr_m_i_xm:
+		mediaop(o, op, t[3], z);
+		asmand(&p->to, &p->from);
+		*andptr++ = p->from.offset;
+		break;
+
+	case Zo_m:
+		*andptr++ = op;
+		asmando(&p->to, o->op[z+1]);
+		break;
+
+	case Zo_m64:
+		*andptr++ = op;
+		asmandsz(&p->to, o->op[z+1], 0, 1);
+		break;
+
+	case Zm_ibo:
+		v = vaddr(&p->to);
+		*andptr++ = op;
+		asmando(&p->from, o->op[z+1]);
+		*andptr++ = v;
+		break;
+
+	case Zibo_m:
+		*andptr++ = op;
+		asmando(&p->to, o->op[z+1]);
+		*andptr++ = v;
+		break;
+
+	case Zibo_m_xm:
+		z = mediaop(o, op, t[3], z);
+		asmando(&p->to, o->op[z+1]);
+		*andptr++ = v;
+		break;
+
+	case Z_ib:
+		v = vaddr(&p->to);
+	case Zib_:
+		*andptr++ = op;
+		*andptr++ = v;
+		break;
+
+	case Zib_rp:
+		rexflag |= regrex[p->to.type] & (Rxb|0x40);
+		*andptr++ = op + reg[p->to.type];
+		*andptr++ = v;
+		break;
+
+	case Zil_rp:
+		rexflag |= regrex[p->to.type] & Rxb;
+		*andptr++ = op + reg[p->to.type];
+		if(o->prefix == Pe) {
+			*andptr++ = v;
+			*andptr++ = v>>8;
+		}
+		else
+			put4(v);
+		break;
+
+	case Zo_iw:
+		*andptr++ = op;
+		if(p->from.type != D_NONE){
+			*andptr++ = v;
+			*andptr++ = v>>8;
+		}
+		break;
+
+	case Ziq_rp:
+		l = v>>32;
+		if(l == 0){
+			//p->mark |= 0100;
+			//print("zero: %llux %P\n", v, p);
+			rexflag &= ~(0x40|Rxw);
+			rexflag |= regrex[p->to.type] & Rxb;
+			*andptr++ = 0xb8 + reg[p->to.type];
+			put4(v);
+		}else if(l == -1 && (v&((uvlong)1<<31))!=0){	/* sign extend */
+			//p->mark |= 0100;
+			//print("sign: %llux %P\n", v, p);
+			*andptr ++ = 0xc7;
+			asmando(&p->to, 0);
+			put4(v);
+		}else{	/* need all 8 */
+			//print("all: %llux %P\n", v, p);
+			rexflag |= regrex[p->to.type] & Rxb;
+			*andptr++ = op + reg[p->to.type];
+			put8(v);
+		}
+		break;
+
+	case Zib_rr:
+		*andptr++ = op;
+		asmand(&p->to, &p->to);
+		*andptr++ = v;
+		break;
+
+	case Z_il:
+		v = vaddr(&p->to);
+	case Zil_:
+		*andptr++ = op;
+		if(o->prefix == Pe) {
+			*andptr++ = v;
+			*andptr++ = v>>8;
+		}
+		else
+			put4(v);
+		break;
+
+	case Zm_ilo:
+		v = vaddr(&p->to);
+		*andptr++ = op;
+		asmando(&p->from, o->op[z+1]);
+		if(o->prefix == Pe) {
+			*andptr++ = v;
+			*andptr++ = v>>8;
+		}
+		else
+			put4(v);
+		break;
+
+	case Zilo_m:
+		*andptr++ = op;
+		asmando(&p->to, o->op[z+1]);
+		if(o->prefix == Pe) {
+			*andptr++ = v;
+			*andptr++ = v>>8;
+		}
+		else
+			put4(v);
+		break;
+
+	case Zil_rr:
+		*andptr++ = op;
+		asmand(&p->to, &p->to);
+		if(o->prefix == Pe) {
+			*andptr++ = v;
+			*andptr++ = v>>8;
+		}
+		else
+			put4(v);
+		break;
+
+	case Z_rp:
+		rexflag |= regrex[p->to.type] & (Rxb|0x40);
+		*andptr++ = op + reg[p->to.type];
+		break;
+
+	case Zrp_:
+		rexflag |= regrex[p->from.type] & (Rxb|0x40);
+		*andptr++ = op + reg[p->from.type];
+		break;
+
+	case Zclr:
+		*andptr++ = op;
+		asmand(&p->to, &p->to);
+		break;
+
+	case Zbr:
+		q = p->pcond;
+		if(q) {
+			v = q->pc - p->pc - 2;
+			if(v >= -128 && v <= 127) {
+				*andptr++ = op;
+				*andptr++ = v;
+			} else {
+				v -= 6-2;
+				*andptr++ = 0x0f;
+				*andptr++ = o->op[z+1];
+				*andptr++ = v;
+				*andptr++ = v>>8;
+				*andptr++ = v>>16;
+				*andptr++ = v>>24;
+			}
+		}
+		break;
+
+	case Zcall:
+		q = p->pcond;
+		if(q) {
+			v = q->pc - p->pc - 5;
+			if(dlm && curp != P && p->to.sym->type == SUNDEF){
+				/* v = 0 - p->pc - 5; */
+				v = 0;
+				ckoff(p->to.sym, v);
+				v += p->to.sym->value;
+				dynreloc(p->to.sym, p->pc+1, 0);
+			}
+			*andptr++ = op;
+			*andptr++ = v;
+			*andptr++ = v>>8;
+			*andptr++ = v>>16;
+			*andptr++ = v>>24;
+		}
+		break;
+
+	case Zjmp:
+		q = p->pcond;
+		if(q) {
+			v = q->pc - p->pc - 2;
+			if(v >= -128 && v <= 127) {
+				*andptr++ = op;
+				*andptr++ = v;
+			} else {
+				v -= 5-2;
+				*andptr++ = o->op[z+1];
+				*andptr++ = v;
+				*andptr++ = v>>8;
+				*andptr++ = v>>16;
+				*andptr++ = v>>24;
+			}
+		}
+		break;
+
+	case Zloop:
+		q = p->pcond;
+		if(q) {
+			v = q->pc - p->pc - 2;
+			if(v < -128 && v > 127)
+				diag("loop too far: %P", p);
+			*andptr++ = op;
+			*andptr++ = v;
+		}
+		break;
+
+	case Zbyte:
+		*andptr++ = v;
+		if(op > 1) {
+			*andptr++ = v>>8;
+			if(op > 2) {
+				*andptr++ = v>>16;
+				*andptr++ = v>>24;
+				if(op > 4) {
+					*andptr++ = v>>32;
+					*andptr++ = v>>40;
+					*andptr++ = v>>48;
+					*andptr++ = v>>56;
+				}
+			}
+		}
+		break;
+	}
+	return;
+
+domov:
+	for(mo=ymovtab; mo->as; mo++)
+		if(p->as == mo->as)
+		if(ycover[ft+mo->ft])
+		if(ycover[tt+mo->tt]){
+			t = mo->op;
+			goto mfound;
+		}
+bad:
+	if(p->mode != 64){
+		/*
+		 * here, the assembly has failed.
+		 * if its a byte instruction that has
+		 * unaddressable registers, try to
+		 * exchange registers and reissue the
+		 * instruction with the operands renamed.
+		 */
+		pp = *p;
+		z = p->from.type;
+		if(z >= D_BP && z <= D_DI) {
+			if(isax(&p->to)) {
+				*andptr++ = 0x87;			/* xchg lhs,bx */
+				asmando(&p->from, reg[D_BX]);
+				subreg(&pp, z, D_BX);
+				doasm(&pp);
+				*andptr++ = 0x87;			/* xchg lhs,bx */
+				asmando(&p->from, reg[D_BX]);
+			} else {
+				*andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
+				subreg(&pp, z, D_AX);
+				doasm(&pp);
+				*andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
+			}
+			return;
+		}
+		z = p->to.type;
+		if(z >= D_BP && z <= D_DI) {
+			if(isax(&p->from)) {
+				*andptr++ = 0x87;			/* xchg rhs,bx */
+				asmando(&p->to, reg[D_BX]);
+				subreg(&pp, z, D_BX);
+				doasm(&pp);
+				*andptr++ = 0x87;			/* xchg rhs,bx */
+				asmando(&p->to, reg[D_BX]);
+			} else {
+				*andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
+				subreg(&pp, z, D_AX);
+				doasm(&pp);
+				*andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
+			}
+			return;
+		}
+	}
+	diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p);
+	return;
+
+mfound:
+	switch(mo->code) {
+	default:
+		diag("asmins: unknown mov %d %P", mo->code, p);
+		break;
+
+	case 0:	/* lit */
+		for(z=0; t[z]!=E; z++)
+			*andptr++ = t[z];
+		break;
+
+	case 1:	/* r,m */
+		*andptr++ = t[0];
+		asmando(&p->to, t[1]);
+		break;
+
+	case 2:	/* m,r */
+		*andptr++ = t[0];
+		asmando(&p->from, t[1]);
+		break;
+
+	case 3:	/* r,m - 2op */
+		*andptr++ = t[0];
+		*andptr++ = t[1];
+		asmando(&p->to, t[2]);
+		rexflag |= regrex[p->from.type] & (Rxr|0x40);
+		break;
+
+	case 4:	/* m,r - 2op */
+		*andptr++ = t[0];
+		*andptr++ = t[1];
+		asmando(&p->from, t[2]);
+		rexflag |= regrex[p->to.type] & (Rxr|0x40);
+		break;
+
+	case 5:	/* load full pointer, trash heap */
+		if(t[0])
+			*andptr++ = t[0];
+		switch(p->to.index) {
+		default:
+			goto bad;
+		case D_DS:
+			*andptr++ = 0xc5;
+			break;
+		case D_SS:
+			*andptr++ = 0x0f;
+			*andptr++ = 0xb2;
+			break;
+		case D_ES:
+			*andptr++ = 0xc4;
+			break;
+		case D_FS:
+			*andptr++ = 0x0f;
+			*andptr++ = 0xb4;
+			break;
+		case D_GS:
+			*andptr++ = 0x0f;
+			*andptr++ = 0xb5;
+			break;
+		}
+		asmand(&p->from, &p->to);
+		break;
+
+	case 6:	/* double shift */
+		if(t[0] == Pw){
+			if(p->mode != 64)
+				diag("asmins: illegal 64: %P", p);
+			rexflag |= Pw;
+			t++;
+		}else if(t[0] == Pe){
+			*andptr++ = Pe;
+			t++;
+		}
+		z = p->from.type;
+		switch(z) {
+		default:
+			goto bad;
+		case D_CONST:
+			*andptr++ = 0x0f;
+			*andptr++ = t[0];
+			asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
+			*andptr++ = p->from.offset;
+			break;
+		case D_CL:
+		case D_CX:
+			*andptr++ = 0x0f;
+			*andptr++ = t[1];
+			asmandsz(&p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
+			break;
+		}
+		break;
+	}
+}
+
+void
+asmins(Prog *p)
+{
+	int n, np, c;
+
+	rexflag = 0;
+	andptr = and;
+	asmode = p->mode;
+	doasm(p);
+	if(rexflag){
+		/*
+		 * as befits the whole approach of the architecture,
+		 * the rex prefix must appear before the first opcode byte
+		 * (and thus after any 66/67/f2/f3 prefix bytes, but
+		 * before the 0f opcode escape!), or it might be ignored.
+		 * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
+		 */
+		if(p->mode != 64)
+			diag("asmins: illegal in mode %d: %P", p->mode, p);
+		n = andptr - and;
+		for(np = 0; np < n; np++) {
+			c = and[np];
+			if(c != 0x66 && c != 0xf2 && c != 0xf3 && c != 0x67)
+				break;
+		}
+		memmove(and+np+1, and+np, n-np);
+		and[np] = 0x40 | rexflag;
+		andptr++;
+	}
+}
+
+enum{
+	ABSD = 0,
+	ABSU = 1,
+	RELD = 2,
+	RELU = 3,
+};
+
+int modemap[4] = { 0, 1, -1, 2, };
+
+typedef struct Reloc Reloc;
+
+struct Reloc
+{
+	int n;
+	int t;
+	uchar *m;
+	ulong *a;
+};
+
+Reloc rels;
+
+static void
+grow(Reloc *r)
+{
+	int t;
+	uchar *m, *nm;
+	ulong *a, *na;
+
+	t = r->t;
+	r->t += 64;
+	m = r->m;
+	a = r->a;
+	r->m = nm = malloc(r->t*sizeof(uchar));
+	r->a = na = malloc(r->t*sizeof(ulong));
+	memmove(nm, m, t*sizeof(uchar));
+	memmove(na, a, t*sizeof(ulong));
+	free(m);
+	free(a);
+}
+
+void
+dynreloc(Sym *s, ulong v, int abs)
+{
+	int i, k, n;
+	uchar *m;
+	ulong *a;
+	Reloc *r;
+
+	if(s->type == SUNDEF)
+		k = abs ? ABSU : RELU;
+	else
+		k = abs ? ABSD : RELD;
+	/* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */
+	k = modemap[k];
+	r = &rels;
+	n = r->n;
+	if(n >= r->t)
+		grow(r);
+	m = r->m;
+	a = r->a;
+	for(i = n; i > 0; i--){
+		if(v < a[i-1]){	/* happens occasionally for data */
+			m[i] = m[i-1];
+			a[i] = a[i-1];
+		}
+		else
+			break;
+	}
+	m[i] = k;
+	a[i] = v;
+	r->n++;
+}
+
+static int
+sput(char *s)
+{
+	char *p;
+
+	p = s;
+	while(*s)
+		cput(*s++);
+	cput(0);
+	return s-p+1;
+}
+
+void
+asmdyn()
+{
+	int i, n, t, c;
+	Sym *s;
+	ulong la, ra, *a;
+	vlong off;
+	uchar *m;
+	Reloc *r;
+
+	cflush();
+	off = seek(cout, 0, 1);
+	lput(0);
+	t = 0;
+	lput(imports);
+	t += 4;
+	for(i = 0; i < NHASH; i++)
+		for(s = hash[i]; s != S; s = s->link)
+			if(s->type == SUNDEF){
+				lput(s->sig);
+				t += 4;
+				t += sput(s->name);
+			}
+
+	la = 0;
+	r = &rels;
+	n = r->n;
+	m = r->m;
+	a = r->a;
+	lput(n);
+	t += 4;
+	for(i = 0; i < n; i++){
+		ra = *a-la;
+		if(*a < la)
+			diag("bad relocation order");
+		if(ra < 256)
+			c = 0;
+		else if(ra < 65536)
+			c = 1;
+		else
+			c = 2;
+		cput((c<<6)|*m++);
+		t++;
+		if(c == 0){
+			cput(ra);
+			t++;
+		}
+		else if(c == 1){
+			wput(ra);
+			t += 2;
+		}
+		else{
+			lput(ra);
+			t += 4;
+		}
+		la = *a++;
+	}
+
+	cflush();
+	seek(cout, off, 0);
+	lput(t);
+
+	if(debug['v']){
+		Bprint(&bso, "import table entries = %d\n", imports);
+		Bprint(&bso, "export table entries = %d\n", exports);
+	}
+}
diff --git a/src/cmd/cc/acid.c b/src/cmd/cc/acid.c
new file mode 100644
index 0000000..62be5e8
--- /dev/null
+++ b/src/cmd/cc/acid.c
@@ -0,0 +1,331 @@
+// Inferno utils/cc/acid.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/acid.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+static char *kwd[] =
+{
+	"$adt", "$aggr", "$append", "$complex", "$defn",
+	"$delete", "$do", "$else", "$eval", "$head", "$if",
+	"$local", "$loop", "$return", "$tail", "$then",
+	"$union", "$whatis", "$while",
+};
+
+char*
+amap(char *s)
+{
+	int i, bot, top, new;
+
+	bot = 0;
+	top = bot + nelem(kwd) - 1;
+	while(bot <= top){
+		new = bot + (top - bot)/2;
+		i = strcmp(kwd[new]+1, s);
+		if(i == 0)
+			return kwd[new];
+
+		if(i < 0)
+			bot = new + 1;
+		else
+			top = new - 1;
+	}
+	return s;
+}
+
+Sym*
+acidsue(Type *t)
+{
+	int h;
+	Sym *s;
+
+	if(t != T)
+	for(h=0; h<nelem(hash); h++)
+		for(s = hash[h]; s != S; s = s->link)
+			if(s->suetag && s->suetag->link == t)
+				return s;
+	return 0;
+}
+
+Sym*
+acidfun(Type *t)
+{
+	int h;
+	Sym *s;
+
+	for(h=0; h<nelem(hash); h++)
+		for(s = hash[h]; s != S; s = s->link)
+			if(s->type == t)
+				return s;
+	return 0;
+}
+
+char	acidchar[NTYPE];
+Init	acidcinit[] =
+{
+	TCHAR,		'C',	0,
+	TUCHAR,		'b',	0,
+	TSHORT,		'd',	0,
+	TUSHORT,	'u',	0,
+	TLONG,		'D',	0,
+	TULONG,		'U',	0,
+	TVLONG,		'V',	0,
+	TUVLONG,	'W',	0,
+	TFLOAT,		'f',	0,
+	TDOUBLE,	'F',	0,
+	TARRAY,		'a',	0,
+	TIND,		'X',	0,
+	-1,		0,	0,
+};
+
+static void
+acidinit(void)
+{
+	Init *p;
+
+	for(p=acidcinit; p->code >= 0; p++)
+		acidchar[p->code] = p->value;
+
+	acidchar[TINT] = acidchar[TLONG];
+	acidchar[TUINT] = acidchar[TULONG];
+	if(types[TINT]->width != types[TLONG]->width) {
+		acidchar[TINT] = acidchar[TSHORT];
+		acidchar[TUINT] = acidchar[TUSHORT];
+		if(types[TINT]->width != types[TSHORT]->width)
+			warn(Z, "acidmember int not long or short");
+	}
+	
+}
+
+void
+acidmember(Type *t, long off, int flag)
+{
+	Sym *s, *s1;
+	Type *l;
+	static int acidcharinit = 0;
+
+	if(acidcharinit == 0) {
+		acidinit();
+		acidcharinit = 1;
+	}
+	s = t->sym;
+	switch(t->etype) {
+	default:
+		Bprint(&outbuf, "	T%d\n", t->etype);
+		break;
+
+	case TIND:
+		if(s == S)
+			break;
+		if(flag) {
+			for(l=t; l->etype==TIND; l=l->link)
+				;
+			if(typesu[l->etype]) {
+				s1 = acidsue(l->link);
+				if(s1 != S) {
+					Bprint(&outbuf, "	'A' %s %ld %s;\n",
+						amap(s1->name),
+						t->offset+off, amap(s->name));
+					break;
+				}
+			}
+		} else {
+			Bprint(&outbuf,
+				"\tprint(\"\t%s\t\", addr.%s\\X, \"\\n\");\n",
+				amap(s->name), amap(s->name));
+			break;
+		}
+
+	case TINT:
+	case TUINT:
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TLONG:
+	case TULONG:
+	case TVLONG:
+	case TUVLONG:
+	case TFLOAT:
+	case TDOUBLE:
+	case TARRAY:
+		if(s == S)
+			break;
+		if(flag) {
+			Bprint(&outbuf, "	'%c' %ld %s;\n",
+			acidchar[t->etype], t->offset+off, amap(s->name));
+		} else {
+			Bprint(&outbuf, "\tprint(\"\t%s\t\", addr.%s, \"\\n\");\n",
+				amap(s->name), amap(s->name));
+		}
+		break;
+
+	case TSTRUCT:
+	case TUNION:
+		s1 = acidsue(t->link);
+		if(s1 == S)
+			break;
+		if(flag) {
+			if(s == S) {
+				Bprint(&outbuf, "	{\n");
+				for(l = t->link; l != T; l = l->down)
+					acidmember(l, t->offset+off, flag);
+				Bprint(&outbuf, "	};\n");
+			} else {
+				Bprint(&outbuf, "	%s %ld %s;\n",
+					amap(s1->name),
+					t->offset+off, amap(s->name));
+			}
+		} else {
+			if(s != S) {
+				Bprint(&outbuf, "\tprint(\"%s %s {\\n\");\n",
+					amap(s1->name), amap(s->name));
+				Bprint(&outbuf, "\t%s(addr.%s);\n",
+					amap(s1->name), amap(s->name));
+				Bprint(&outbuf, "\tprint(\"}\\n\");\n");
+			} else {
+				Bprint(&outbuf, "\tprint(\"%s {\\n\");\n",
+					amap(s1->name));
+				Bprint(&outbuf, "\t\t%s(addr+%ld);\n",
+					amap(s1->name), t->offset+off);
+				Bprint(&outbuf, "\tprint(\"}\\n\");\n");
+			}
+		}
+		break;
+	}
+}
+
+void
+acidtype(Type *t)
+{
+	Sym *s;
+	Type *l;
+	Io *i;
+	int n;
+	char *an;
+
+	if(!debug['a'])
+		return;
+	if(debug['a'] > 1) {
+		n = 0;
+		for(i=iostack; i; i=i->link)
+			n++;
+		if(n > 1)
+			return;
+	}
+	s = acidsue(t->link);
+	if(s == S)
+		return;
+	switch(t->etype) {
+	default:
+		Bprint(&outbuf, "T%d\n", t->etype);
+		return;
+
+	case TUNION:
+	case TSTRUCT:
+		if(debug['s'])
+			goto asmstr;
+		an = amap(s->name);
+		Bprint(&outbuf, "sizeof%s = %ld;\n", an, t->width);
+		Bprint(&outbuf, "aggr %s\n{\n", an);
+		for(l = t->link; l != T; l = l->down)
+			acidmember(l, 0, 1);
+		Bprint(&outbuf, "};\n\n");
+
+		Bprint(&outbuf, "defn\n%s(addr) {\n\tcomplex %s addr;\n", an, an);
+		for(l = t->link; l != T; l = l->down)
+			acidmember(l, 0, 0);
+		Bprint(&outbuf, "};\n\n");
+		break;
+	asmstr:
+		if(s == S)
+			break;
+		for(l = t->link; l != T; l = l->down)
+			if(l->sym != S)
+				Bprint(&outbuf, "#define\t%s.%s\t%ld\n",
+					s->name,
+					l->sym->name,
+					l->offset);
+		break;
+	}
+}
+
+void
+acidvar(Sym *s)
+{
+	int n;
+	Io *i;
+	Type *t;
+	Sym *s1, *s2;
+
+	if(!debug['a'] || debug['s'])
+		return;
+	if(debug['a'] > 1) {
+		n = 0;
+		for(i=iostack; i; i=i->link)
+			n++;
+		if(n > 1)
+			return;
+	}
+	t = s->type;
+	while(t && t->etype == TIND)
+		t = t->link;
+	if(t == T)
+		return;
+	if(t->etype == TENUM) {
+		Bprint(&outbuf, "%s = ", amap(s->name));
+		if(!typefd[t->etype])
+			Bprint(&outbuf, "%lld;\n", s->vconst);
+		else
+			Bprint(&outbuf, "%f\n;", s->fconst);
+		return;
+	}
+	if(!typesu[t->etype])
+		return;
+	s1 = acidsue(t->link);
+	if(s1 == S)
+		return;
+	switch(s->class) {
+	case CAUTO:
+	case CPARAM:
+		s2 = acidfun(thisfn);
+		if(s2)
+			Bprint(&outbuf, "complex %s %s:%s;\n",
+				amap(s1->name), amap(s2->name), amap(s->name));
+		break;
+	
+	case CSTATIC:
+	case CEXTERN:
+	case CGLOBL:
+	case CLOCAL:
+		Bprint(&outbuf, "complex %s %s;\n",
+			amap(s1->name), amap(s->name));
+		break;
+	}
+}
diff --git a/src/cmd/cc/bits.c b/src/cmd/cc/bits.c
new file mode 100644
index 0000000..31e788c
--- /dev/null
+++ b/src/cmd/cc/bits.c
@@ -0,0 +1,119 @@
+// Inferno utils/cc/bits.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	"cc.h"
+
+Bits
+bor(Bits a, Bits b)
+{
+	Bits c;
+	int i;
+
+	for(i=0; i<BITS; i++)
+		c.b[i] = a.b[i] | b.b[i];
+	return c;
+}
+
+Bits
+band(Bits a, Bits b)
+{
+	Bits c;
+	int i;
+
+	for(i=0; i<BITS; i++)
+		c.b[i] = a.b[i] & b.b[i];
+	return c;
+}
+
+/*
+Bits
+bnot(Bits a)
+{
+	Bits c;
+	int i;
+
+	for(i=0; i<BITS; i++)
+		c.b[i] = ~a.b[i];
+	return c;
+}
+*/
+
+int
+bany(Bits *a)
+{
+	int i;
+
+	for(i=0; i<BITS; i++)
+		if(a->b[i])
+			return 1;
+	return 0;
+}
+
+int
+beq(Bits a, Bits b)
+{
+	int i;
+
+	for(i=0; i<BITS; i++)
+		if(a.b[i] != b.b[i])
+			return 0;
+	return 1;
+}
+
+int
+bnum(Bits a)
+{
+	int i;
+	long b;
+
+	for(i=0; i<BITS; i++)
+		if(b = a.b[i])
+			return 32*i + bitno(b);
+	diag(Z, "bad in bnum");
+	return 0;
+}
+
+Bits
+blsh(uint n)
+{
+	Bits c;
+
+	c = zbits;
+	c.b[n/32] = 1L << (n%32);
+	return c;
+}
+
+int
+bset(Bits a, uint n)
+{
+	if(a.b[n/32] & (1L << (n%32)))
+		return 1;
+	return 0;
+}
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
new file mode 100644
index 0000000..db1cf94
--- /dev/null
+++ b/src/cmd/cc/cc.h
@@ -0,0 +1,795 @@
+// Inferno utils/cc/cc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include "compat.h"
+
+#pragma	lib	"../cc/cc.a$O"
+
+#ifndef	EXTERN
+#define EXTERN	extern
+#endif
+
+typedef	struct	Node	Node;
+typedef	struct	Sym	Sym;
+typedef	struct	Type	Type;
+typedef	struct	Funct	Funct;
+typedef	struct	Decl	Decl;
+typedef	struct	Io	Io;
+typedef	struct	Hist	Hist;
+typedef	struct	Term	Term;
+typedef	struct	Init	Init;
+typedef	struct	Bits	Bits;
+
+#define	NHUNK		50000L
+#define	BUFSIZ		8192
+#define	NSYMB		500
+#define	NHASH		1024
+#define	STRINGSZ	200
+#define	HISTSZ		20
+#define YYMAXDEPTH	500
+#define	NTERM		10
+#define	MAXALIGN	7
+
+#define	SIGN(n)		((vlong)1<<(n-1))
+#define	MASK(n)		(SIGN(n)|(SIGN(n)-1))
+
+#define	BITS	5
+#define	NVAR	(BITS*sizeof(ulong)*8)
+struct	Bits
+{
+	ulong	b[BITS];
+};
+
+struct	Node
+{
+	Node*	left;
+	Node*	right;
+	void*	label;
+	long	pc;
+	int	reg;
+	long	xoffset;
+	double	fconst;		/* fp constant */
+	vlong	vconst;		/* non fp const */
+	char*	cstring;	/* character string */
+	ushort*	rstring;	/* rune string */
+
+	Sym*	sym;
+	Type*	type;
+	long	lineno;
+	uchar	op;
+	uchar	oldop;
+	uchar	xcast;
+	uchar	class;
+	uchar	etype;
+	uchar	complex;
+	uchar	addable;
+	uchar	scale;
+	uchar	garb;
+};
+#define	Z	((Node*)0)
+
+struct	Sym
+{
+	Sym*	link;
+	Type*	type;
+	Type*	suetag;
+	Type*	tenum;
+	char*	macro;
+	long	varlineno;
+	long	offset;
+	vlong	vconst;
+	double	fconst;
+	Node*	label;
+	ushort	lexical;
+	char	*name;
+	ushort	block;
+	ushort	sueblock;
+	uchar	class;
+	uchar	sym;
+	uchar	aused;
+	uchar	sig;
+};
+#define	S	((Sym*)0)
+
+enum{
+	SIGNONE = 0,
+	SIGDONE = 1,
+	SIGINTERN = 2,
+
+	SIGNINTERN = 1729*325*1729,
+};
+
+struct	Decl
+{
+	Decl*	link;
+	Sym*	sym;
+	Type*	type;
+	long	varlineno;
+	long	offset;
+	short	val;
+	ushort	block;
+	uchar	class;
+	uchar	aused;
+};
+#define	D	((Decl*)0)
+
+struct	Type
+{
+	Sym*	sym;
+	Sym*	tag;
+	Funct*	funct;
+	Type*	link;
+	Type*	down;
+	long	width;
+	long	offset;
+	long	lineno;
+	uchar	shift;
+	uchar	nbits;
+	uchar	etype;
+	uchar	garb;
+};
+
+#define	T	((Type*)0)
+#define	NODECL	((void(*)(int, Type*, Sym*))0)
+
+struct	Init			/* general purpose initialization */
+{
+	int	code;
+	ulong	value;
+	char*	s;
+};
+
+EXTERN struct
+{
+	char*	p;
+	int	c;
+} fi;
+
+struct	Io
+{
+	Io*	link;
+	char*	p;
+	char	b[BUFSIZ];
+	short	c;
+	short	f;
+};
+#define	I	((Io*)0)
+
+struct	Hist
+{
+	Hist*	link;
+	char*	name;
+	long	line;
+	long	offset;
+};
+#define	H	((Hist*)0)
+EXTERN Hist*	hist;
+
+struct	Term
+{
+	vlong	mult;
+	Node	*node;
+};
+
+enum
+{
+	Axxx,
+	Ael1,
+	Ael2,
+	Asu2,
+	Aarg0,
+	Aarg1,
+	Aarg2,
+	Aaut3,
+	NALIGN,
+};
+
+enum
+{
+	DMARK,
+	DAUTO,
+	DSUE,
+	DLABEL,
+};
+enum
+{
+	OXXX,
+	OADD,
+	OADDR,
+	OAND,
+	OANDAND,
+	OARRAY,
+	OAS,
+	OASI,
+	OASADD,
+	OASAND,
+	OASASHL,
+	OASASHR,
+	OASDIV,
+	OASHL,
+	OASHR,
+	OASLDIV,
+	OASLMOD,
+	OASLMUL,
+	OASLSHR,
+	OASMOD,
+	OASMUL,
+	OASOR,
+	OASSUB,
+	OASXOR,
+	OBIT,
+	OBREAK,
+	OCASE,
+	OCAST,
+	OCOMMA,
+	OCOND,
+	OCONST,
+	OCONTINUE,
+	ODIV,
+	ODOT,
+	ODOTDOT,
+	ODWHILE,
+	OENUM,
+	OEQ,
+	OFOR,
+	OFUNC,
+	OGE,
+	OGOTO,
+	OGT,
+	OHI,
+	OHS,
+	OIF,
+	OIND,
+	OINDREG,
+	OINIT,
+	OLABEL,
+	OLDIV,
+	OLE,
+	OLIST,
+	OLMOD,
+	OLMUL,
+	OLO,
+	OLS,
+	OLSHR,
+	OLT,
+	OMOD,
+	OMUL,
+	ONAME,
+	ONE,
+	ONOT,
+	OOR,
+	OOROR,
+	OPOSTDEC,
+	OPOSTINC,
+	OPREDEC,
+	OPREINC,
+	OPROTO,
+	OREGISTER,
+	ORETURN,
+	OSET,
+	OSIGN,
+	OSIZE,
+	OSTRING,
+	OLSTRING,
+	OSTRUCT,
+	OSUB,
+	OSWITCH,
+	OUNION,
+	OUSED,
+	OWHILE,
+	OXOR,
+	ONEG,
+	OCOM,
+	OPOS,
+	OELEM,
+
+	OTST,		/* used in some compilers */
+	OINDEX,
+	OFAS,
+	OREGPAIR,
+
+	OEND
+};
+enum
+{
+	TXXX,
+	TCHAR,
+	TUCHAR,
+	TSHORT,
+	TUSHORT,
+	TINT,
+	TUINT,
+	TLONG,
+	TULONG,
+	TVLONG,
+	TUVLONG,
+	TFLOAT,
+	TDOUBLE,
+	TIND,
+	TFUNC,
+	TARRAY,
+	TVOID,
+	TSTRUCT,
+	TUNION,
+	TENUM,
+	NTYPE,
+
+	TAUTO	= NTYPE,
+	TEXTERN,
+	TSTATIC,
+	TTYPEDEF,
+	TTYPESTR,
+	TREGISTER,
+	TCONSTNT,
+	TVOLATILE,
+	TUNSIGNED,
+	TSIGNED,
+	TDOT,
+	TFILE,
+	TOLD,
+	NALLTYPES,
+};
+enum
+{
+	CXXX,
+	CAUTO,
+	CEXTERN,
+	CGLOBL,
+	CSTATIC,
+	CLOCAL,
+	CTYPEDEF,
+	CTYPESTR,
+	CPARAM,
+	CSELEM,
+	CLABEL,
+	CEXREG,
+	NCTYPES,
+};
+enum
+{
+	GXXX		= 0,
+	GCONSTNT	= 1<<0,
+	GVOLATILE	= 1<<1,
+	NGTYPES		= 1<<2,
+
+	GINCOMPLETE	= 1<<2,
+};
+enum
+{
+	BCHAR		= 1L<<TCHAR,
+	BUCHAR		= 1L<<TUCHAR,
+	BSHORT		= 1L<<TSHORT,
+	BUSHORT		= 1L<<TUSHORT,
+	BINT		= 1L<<TINT,
+	BUINT		= 1L<<TUINT,
+	BLONG		= 1L<<TLONG,
+	BULONG		= 1L<<TULONG,
+	BVLONG		= 1L<<TVLONG,
+	BUVLONG		= 1L<<TUVLONG,
+	BFLOAT		= 1L<<TFLOAT,
+	BDOUBLE		= 1L<<TDOUBLE,
+	BIND		= 1L<<TIND,
+	BFUNC		= 1L<<TFUNC,
+	BARRAY		= 1L<<TARRAY,
+	BVOID		= 1L<<TVOID,
+	BSTRUCT		= 1L<<TSTRUCT,
+	BUNION		= 1L<<TUNION,
+	BENUM		= 1L<<TENUM,
+	BFILE		= 1L<<TFILE,
+	BDOT		= 1L<<TDOT,
+	BCONSTNT	= 1L<<TCONSTNT,
+	BVOLATILE	= 1L<<TVOLATILE,
+	BUNSIGNED	= 1L<<TUNSIGNED,
+	BSIGNED		= 1L<<TSIGNED,
+	BAUTO		= 1L<<TAUTO,
+	BEXTERN		= 1L<<TEXTERN,
+	BSTATIC		= 1L<<TSTATIC,
+	BTYPEDEF	= 1L<<TTYPEDEF,
+	BTYPESTR	= 1L<<TTYPESTR,
+	BREGISTER	= 1L<<TREGISTER,
+
+	BINTEGER	= BCHAR|BUCHAR|BSHORT|BUSHORT|BINT|BUINT|
+				BLONG|BULONG|BVLONG|BUVLONG,
+	BNUMBER		= BINTEGER|BFLOAT|BDOUBLE,
+
+/* these can be overloaded with complex types */
+
+	BCLASS		= BAUTO|BEXTERN|BSTATIC|BTYPEDEF|BTYPESTR|BREGISTER,
+	BGARB		= BCONSTNT|BVOLATILE,
+};
+
+struct	Funct
+{
+	Sym*	sym[OEND];
+	Sym*	castto[NTYPE];
+	Sym*	castfr[NTYPE];
+};
+
+EXTERN struct
+{
+	Type*	tenum;		/* type of entire enum */
+	Type*	cenum;		/* type of current enum run */
+	vlong	lastenum;	/* value of current enum */
+	double	floatenum;	/* value of current enum */
+} en;
+
+EXTERN	int	autobn;
+EXTERN	long	autoffset;
+EXTERN	int	blockno;
+EXTERN	Decl*	dclstack;
+EXTERN	char	debug[256];
+EXTERN	Hist*	ehist;
+EXTERN	long	firstbit;
+EXTERN	Sym*	firstarg;
+EXTERN	Type*	firstargtype;
+EXTERN	Decl*	firstdcl;
+EXTERN	int	fperror;
+EXTERN	Sym*	hash[NHASH];
+EXTERN	char*	hunk;
+EXTERN	char*	include[20];
+EXTERN	Io*	iofree;
+EXTERN	Io*	ionext;
+EXTERN	Io*	iostack;
+EXTERN	long	lastbit;
+EXTERN	char	lastclass;
+EXTERN	Type*	lastdcl;
+EXTERN	long	lastfield;
+EXTERN	Type*	lasttype;
+EXTERN	long	lineno;
+EXTERN	long	nearln;
+EXTERN	int	nerrors;
+EXTERN	int	newflag;
+EXTERN	long	nhunk;
+EXTERN	int	ninclude;
+EXTERN	Node*	nodproto;
+EXTERN	Node*	nodcast;
+EXTERN	Biobuf	outbuf;
+EXTERN	Biobuf	diagbuf;
+EXTERN	char*	outfile;
+EXTERN	char*	pathname;
+EXTERN	int	peekc;
+EXTERN	long	stkoff;
+EXTERN	Type*	strf;
+EXTERN	Type*	strl;
+EXTERN	char	symb[NSYMB];
+EXTERN	Sym*	symstring;
+EXTERN	int	taggen;
+EXTERN	Type*	tfield;
+EXTERN	Type*	tufield;
+EXTERN	int	thechar;
+EXTERN	char*	thestring;
+EXTERN	Type*	thisfn;
+EXTERN	long	thunk;
+EXTERN	Type*	types[NTYPE];
+EXTERN	Type*	fntypes[NTYPE];
+EXTERN	Node*	initlist;
+EXTERN	Term	term[NTERM];
+EXTERN	int	nterm;
+EXTERN	int	packflg;
+EXTERN	int	fproundflg;
+EXTERN	int	profileflg;
+EXTERN	int	ncontin;
+EXTERN	int	canreach;
+EXTERN	int	warnreach;
+EXTERN	Bits	zbits;
+
+extern	char	*onames[], *tnames[], *gnames[];
+extern	char	*cnames[], *qnames[], *bnames[];
+extern	uchar	tab[NTYPE][NTYPE];
+extern	uchar	comrel[], invrel[], logrel[];
+extern	long	ncast[], tadd[], tand[];
+extern	long	targ[], tasadd[], tasign[], tcast[];
+extern	long	tdot[], tfunct[], tindir[], tmul[];
+extern	long	tnot[], trel[], tsub[];
+
+extern	uchar	typeaf[];
+extern	uchar	typefd[];
+extern	uchar	typei[];
+extern	uchar	typesu[];
+extern	uchar	typesuv[];
+extern	uchar	typeu[];
+extern	uchar	typev[];
+extern	uchar	typec[];
+extern	uchar	typeh[];
+extern	uchar	typeil[];
+extern	uchar	typeilp[];
+extern	uchar	typechl[];
+extern	uchar	typechlv[];
+extern	uchar	typechlvp[];
+extern	uchar	typechlp[];
+extern	uchar	typechlpfd[];
+
+EXTERN	uchar*	typeword;
+EXTERN	uchar*	typecmplx;
+
+extern	ulong	thash1;
+extern	ulong	thash2;
+extern	ulong	thash3;
+extern	ulong	thash[];
+
+/*
+ *	compat.c/unix.c/windows.c
+ */
+int	mywait(int*);
+int	mycreat(char*, int);
+int	systemtype(int);
+int	pathchar(void);
+int	myaccess(char*);
+char*	mygetwd(char*, int);
+int	myexec(char*, char*[]);
+int	mydup(int, int);
+int	myfork(void);
+int	mypipe(int*);
+void*	mysbrk(ulong);
+
+/*
+ *	parser
+ */
+int	yyparse(void);
+int	mpatov(char*, vlong*);
+
+/*
+ *	lex.c
+ */
+void*	allocn(void*, long, long);
+void*	alloc(long);
+void	cinit(void);
+int	compile(char*, char**, int);
+void	errorexit(void);
+int	filbuf(void);
+int	getc(void);
+long	getr(void);
+int	getnsc(void);
+Sym*	lookup(void);
+void	main(int, char*[]);
+void	newfile(char*, int);
+void	newio(void);
+void	pushio(void);
+long	escchar(long, int, int);
+Sym*	slookup(char*);
+void	syminit(Sym*);
+void	unget(int);
+long	yylex(void);
+int	Lconv(Fmt*);
+int	Tconv(Fmt*);
+int	FNconv(Fmt*);
+int	Oconv(Fmt*);
+int	Qconv(Fmt*);
+int	VBconv(Fmt*);
+void	setinclude(char*);
+
+/*
+ * mac.c
+ */
+void	dodefine(char*);
+void	domacro(void);
+Sym*	getsym(void);
+long	getnsn(void);
+void	linehist(char*, int);
+void	macdef(void);
+void	macprag(void);
+void	macend(void);
+void	macexpand(Sym*, char*);
+void	macif(int);
+void	macinc(void);
+void	maclin(void);
+void	macund(void);
+
+/*
+ * dcl.c
+ */
+Node*	doinit(Sym*, Type*, long, Node*);
+Type*	tcopy(Type*);
+Node*	init1(Sym*, Type*, long, int);
+Node*	newlist(Node*, Node*);
+void	adecl(int, Type*, Sym*);
+int	anyproto(Node*);
+void	argmark(Node*, int);
+void	dbgdecl(Sym*);
+Node*	dcllabel(Sym*, int);
+Node*	dodecl(void(*)(int, Type*, Sym*), int, Type*, Node*);
+Sym*	mkstatic(Sym*);
+void	doenum(Sym*, Node*);
+void	snap(Type*);
+Type*	dotag(Sym*, int, int);
+void	edecl(int, Type*, Sym*);
+Type*	fnproto(Node*);
+Type*	fnproto1(Node*);
+void	markdcl(void);
+Type*	paramconv(Type*, int);
+void	pdecl(int, Type*, Sym*);
+Decl*	push(void);
+Decl*	push1(Sym*);
+Node*	revertdcl(void);
+long	xround(long, int);
+int	rsametype(Type*, Type*, int, int);
+int	sametype(Type*, Type*);
+ulong	sign(Sym*);
+ulong	signature(Type*);
+void	suallign(Type*);
+void	tmerge(Type*, Sym*);
+void	walkparam(Node*, int);
+void	xdecl(int, Type*, Sym*);
+Node*	contig(Sym*, Node*, long);
+
+/*
+ * com.c
+ */
+void	ccom(Node*);
+void	complex(Node*);
+int	tcom(Node*);
+int	tcoma(Node*, Node*, Type*, int);
+int	tcomd(Node*);
+int	tcomo(Node*, int);
+int	tcomx(Node*);
+int	tlvalue(Node*);
+void	constas(Node*, Type*, Type*);
+
+/*
+ * con.c
+ */
+void	acom(Node*);
+void	acom1(vlong, Node*);
+void	acom2(Node*, Type*);
+int	acomcmp1(const void*, const void*);
+int	acomcmp2(const void*, const void*);
+int	addo(Node*);
+void	evconst(Node*);
+
+/*
+ * funct.c
+ */
+int	isfunct(Node*);
+void	dclfunct(Type*, Sym*);
+
+/*
+ * sub.c
+ */
+void	arith(Node*, int);
+int	deadheads(Node*);
+Type*	dotsearch(Sym*, Type*, Node*, long*);
+long	dotoffset(Type*, Type*, Node*);
+void	gethunk(void);
+Node*	invert(Node*);
+int	bitno(long);
+void	makedot(Node*, Type*, long);
+int	mixedasop(Type*, Type*);
+Node*	new(int, Node*, Node*);
+Node*	new1(int, Node*, Node*);
+int	nilcast(Type*, Type*);
+int	nocast(Type*, Type*);
+void	prtree(Node*, char*);
+void	prtree1(Node*, int, int);
+void	relcon(Node*, Node*);
+int	relindex(int);
+int	simpleg(long);
+Type*	garbt(Type*, long);
+int	simplec(long);
+Type*	simplet(long);
+int	stcompat(Node*, Type*, Type*, long[]);
+int	tcompat(Node*, Type*, Type*, long[]);
+void	tinit(void);
+Type*	typ(int, Type*);
+Type*	copytyp(Type*);
+void	typeext(Type*, Node*);
+void	typeext1(Type*, Node*);
+int	side(Node*);
+int	vconst(Node*);
+int	xlog2(uvlong);
+int	vlog(Node*);
+int	topbit(ulong);
+void	simplifyshift(Node*);
+long	typebitor(long, long);
+void	diag(Node*, char*, ...);
+void	warn(Node*, char*, ...);
+void	yyerror(char*, ...);
+void	fatal(Node*, char*, ...);
+
+/*
+ * acid.c
+ */
+void	acidtype(Type*);
+void	acidvar(Sym*);
+
+/*
+ * pickle.c
+ */
+void	pickletype(Type*);
+
+/*
+ * bits.c
+ */
+Bits	bor(Bits, Bits);
+Bits	band(Bits, Bits);
+Bits	bnot(Bits);
+int	bany(Bits*);
+int	bnum(Bits);
+Bits	blsh(uint);
+int	beq(Bits, Bits);
+int	bset(Bits, uint);
+
+/*
+ * dpchk.c
+ */
+void	dpcheck(Node*);
+void	arginit(void);
+void	pragvararg(void);
+void	pragpack(void);
+void	pragfpround(void);
+void pragprofile(void);
+void	pragincomplete(void);
+
+/*
+ * calls to machine depend part
+ */
+void	codgen(Node*, Node*);
+void	gclean(void);
+void	gextern(Sym*, Node*, long, long);
+void	ginit(void);
+long	outstring(char*, long);
+long	outlstring(ushort*, long);
+void	sextern(Sym*, Node*, long, long);
+void	xcom(Node*);
+long	exreg(Type*);
+long	align(long, Type*, int);
+long	maxround(long, long);
+
+extern	schar	ewidth[];
+
+/*
+ * com64
+ */
+int	com64(Node*);
+void	com64init(void);
+void	bool64(Node*);
+double	convvtof(vlong);
+vlong	convftov(double);
+double	convftox(double, int);
+vlong	convvtox(vlong, int);
+
+/*
+ * machcap
+ */
+int	machcap(Node*);
+
+#pragma	varargck	argpos	warn	2
+#pragma	varargck	argpos	diag	2
+#pragma	varargck	argpos	yyerror	1
+
+#pragma	varargck	type	"F"	Node*
+#pragma	varargck	type	"L"	long
+#pragma	varargck	type	"Q"	long
+#pragma	varargck	type	"O"	int
+#pragma	varargck	type	"T"	Type*
+#pragma	varargck	type	"|"	int
diff --git a/src/cmd/cc/cc.y b/src/cmd/cc/cc.y
new file mode 100644
index 0000000..1abcddd
--- /dev/null
+++ b/src/cmd/cc/cc.y
@@ -0,0 +1,1205 @@
+// Inferno utils/cc/cc.y
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.y
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+%{
+#include "cc.h"
+%}
+%union	{
+	Node*	node;
+	Sym*	sym;
+	Type*	type;
+	struct
+	{
+		Type*	t;
+		uchar	c;
+	} tycl;
+	struct
+	{
+		Type*	t1;
+		Type*	t2;
+	} tyty;
+	struct
+	{
+		char*	s;
+		long	l;
+	} sval;
+	long	lval;
+	double	dval;
+	vlong	vval;
+}
+%type	<sym>	ltag
+%type	<lval>	gctname gcname cname gname tname
+%type	<lval>	gctnlist gcnlist zgnlist
+%type	<type>	tlist sbody complex
+%type	<tycl>	types
+%type	<node>	zarglist arglist zcexpr
+%type	<node>	name block stmnt cexpr expr xuexpr pexpr
+%type	<node>	zelist elist adecl slist uexpr string lstring
+%type	<node>	xdecor xdecor2 labels label ulstmnt
+%type	<node>	adlist edecor tag qual qlist
+%type	<node>	abdecor abdecor1 abdecor2 abdecor3
+%type	<node>	zexpr lexpr init ilist forexpr
+
+%left	';'
+%left	','
+%right	'=' LPE LME LMLE LDVE LMDE LRSHE LLSHE LANDE LXORE LORE
+%right	'?' ':'
+%left	LOROR
+%left	LANDAND
+%left	'|'
+%left	'^'
+%left	'&'
+%left	LEQ LNE
+%left	'<' '>' LLE LGE
+%left	LLSH LRSH
+%left	'+' '-'
+%left	'*' '/' '%'
+%right	LMM LPP LMG '.' '[' '('
+
+%token	<sym>	LNAME LTYPE
+%token	<dval>	LFCONST LDCONST
+%token	<vval>	LCONST LLCONST LUCONST LULCONST LVLCONST LUVLCONST
+%token	<sval>	LSTRING LLSTRING
+%token		LAUTO LBREAK LCASE LCHAR LCONTINUE LDEFAULT LDO
+%token		LDOUBLE LELSE LEXTERN LFLOAT LFOR LGOTO
+%token	LIF LINT LLONG LREGISTER LRETURN LSHORT LSIZEOF LUSED
+%token	LSTATIC LSTRUCT LSWITCH LTYPEDEF LTYPESTR LUNION LUNSIGNED
+%token	LWHILE LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF
+%token	LRESTRICT LINLINE
+%%
+prog:
+|	prog xdecl
+
+/*
+ * external declarator
+ */
+xdecl:
+	zctlist ';'
+	{
+		dodecl(xdecl, lastclass, lasttype, Z);
+	}
+|	zctlist xdlist ';'
+|	zctlist xdecor
+	{
+		lastdcl = T;
+		firstarg = S;
+		dodecl(xdecl, lastclass, lasttype, $2);
+		if(lastdcl == T || lastdcl->etype != TFUNC) {
+			diag($2, "not a function");
+			lastdcl = types[TFUNC];
+		}
+		thisfn = lastdcl;
+		markdcl();
+		firstdcl = dclstack;
+		argmark($2, 0);
+	}
+	pdecl
+	{
+		argmark($2, 1);
+	}
+	block
+	{
+		Node *n;
+
+		n = revertdcl();
+		if(n)
+			$6 = new(OLIST, n, $6);
+		if(!debug['a'] && !debug['Z'])
+			codgen($6, $2);
+	}
+
+xdlist:
+	xdecor
+	{
+		dodecl(xdecl, lastclass, lasttype, $1);
+	}
+|	xdecor
+	{
+		$1 = dodecl(xdecl, lastclass, lasttype, $1);
+	}
+	'=' init
+	{
+		doinit($1->sym, $1->type, 0L, $4);
+	}
+|	xdlist ',' xdlist
+
+xdecor:
+	xdecor2
+|	'*' zgnlist xdecor
+	{
+		$$ = new(OIND, $3, Z);
+		$$->garb = simpleg($2);
+	}
+
+xdecor2:
+	tag
+|	'(' xdecor ')'
+	{
+		$$ = $2;
+	}
+|	xdecor2 '(' zarglist ')'
+	{
+		$$ = new(OFUNC, $1, $3);
+	}
+|	xdecor2 '[' zexpr ']'
+	{
+		$$ = new(OARRAY, $1, $3);
+	}
+
+/*
+ * automatic declarator
+ */
+adecl:
+	ctlist ';'
+	{
+		$$ = dodecl(adecl, lastclass, lasttype, Z);
+	}
+|	ctlist adlist ';'
+	{
+		$$ = $2;
+	}
+
+adlist:
+	xdecor
+	{
+		dodecl(adecl, lastclass, lasttype, $1);
+		$$ = Z;
+	}
+|	xdecor
+	{
+		$1 = dodecl(adecl, lastclass, lasttype, $1);
+	}
+	'=' init
+	{
+		long w;
+
+		w = $1->sym->type->width;
+		$$ = doinit($1->sym, $1->type, 0L, $4);
+		$$ = contig($1->sym, $$, w);
+	}
+|	adlist ',' adlist
+	{
+		$$ = $1;
+		if($3 != Z) {
+			$$ = $3;
+			if($1 != Z)
+				$$ = new(OLIST, $1, $3);
+		}
+	}
+
+/*
+ * parameter declarator
+ */
+pdecl:
+|	pdecl ctlist pdlist ';'
+
+pdlist:
+	xdecor
+	{
+		dodecl(pdecl, lastclass, lasttype, $1);
+	}
+|	pdlist ',' pdlist
+
+/*
+ * structure element declarator
+ */
+edecl:
+	tlist
+	{
+		lasttype = $1;
+	}
+	zedlist ';'
+|	edecl tlist
+	{
+		lasttype = $2;
+	}
+	zedlist ';'
+
+zedlist:					/* extension */
+	{
+		lastfield = 0;
+		edecl(CXXX, lasttype, S);
+	}
+|	edlist
+
+edlist:
+	edecor
+	{
+		dodecl(edecl, CXXX, lasttype, $1);
+	}
+|	edlist ',' edlist
+
+edecor:
+	xdecor
+	{
+		lastbit = 0;
+		firstbit = 1;
+	}
+|	tag ':' lexpr
+	{
+		$$ = new(OBIT, $1, $3);
+	}
+|	':' lexpr
+	{
+		$$ = new(OBIT, Z, $2);
+	}
+
+/*
+ * abstract declarator
+ */
+abdecor:
+	{
+		$$ = (Z);
+	}
+|	abdecor1
+
+abdecor1:
+	'*' zgnlist
+	{
+		$$ = new(OIND, (Z), Z);
+		$$->garb = simpleg($2);
+	}
+|	'*' zgnlist abdecor1
+	{
+		$$ = new(OIND, $3, Z);
+		$$->garb = simpleg($2);
+	}
+|	abdecor2
+
+abdecor2:
+	abdecor3
+|	abdecor2 '(' zarglist ')'
+	{
+		$$ = new(OFUNC, $1, $3);
+	}
+|	abdecor2 '[' zexpr ']'
+	{
+		$$ = new(OARRAY, $1, $3);
+	}
+
+abdecor3:
+	'(' ')'
+	{
+		$$ = new(OFUNC, (Z), Z);
+	}
+|	'[' zexpr ']'
+	{
+		$$ = new(OARRAY, (Z), $2);
+	}
+|	'(' abdecor1 ')'
+	{
+		$$ = $2;
+	}
+
+init:
+	expr
+|	'{' ilist '}'
+	{
+		$$ = new(OINIT, invert($2), Z);
+	}
+
+qual:
+	'[' lexpr ']'
+	{
+		$$ = new(OARRAY, $2, Z);
+	}
+|	'.' ltag
+	{
+		$$ = new(OELEM, Z, Z);
+		$$->sym = $2;
+	}
+|	qual '='
+
+qlist:
+	init ','
+|	qlist init ','
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+|	qual
+|	qlist qual
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+
+ilist:
+	qlist
+|	init
+|	qlist init
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+
+zarglist:
+	{
+		$$ = Z;
+	}
+|	arglist
+	{
+		$$ = invert($1);
+	}
+
+
+arglist:
+	name
+|	tlist abdecor
+	{
+		$$ = new(OPROTO, $2, Z);
+		$$->type = $1;
+	}
+|	tlist xdecor
+	{
+		$$ = new(OPROTO, $2, Z);
+		$$->type = $1;
+	}
+|	'.' '.' '.'
+	{
+		$$ = new(ODOTDOT, Z, Z);
+	}
+|	arglist ',' arglist
+	{
+		$$ = new(OLIST, $1, $3);
+	}
+
+block:
+	'{' slist '}'
+	{
+		$$ = invert($2);
+	//	if($2 != Z)
+	//		$$ = new(OLIST, $2, $$);
+		if($$ == Z)
+			$$ = new(OLIST, Z, Z);
+	}
+
+slist:
+	{
+		$$ = Z;
+	}
+|	slist adecl
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+|	slist stmnt
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+
+labels:
+	label
+|	labels label
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+
+label:
+	LCASE expr ':'
+	{
+		$$ = new(OCASE, $2, Z);
+	}
+|	LDEFAULT ':'
+	{
+		$$ = new(OCASE, Z, Z);
+	}
+|	LNAME ':'
+	{
+		$$ = new(OLABEL, dcllabel($1, 1), Z);
+	}
+
+stmnt:
+	error ';'
+	{
+		$$ = Z;
+	}
+|	ulstmnt
+|	labels ulstmnt
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+
+forexpr:
+	zcexpr
+|	ctlist adlist
+	{
+		$$ = $2;
+	}
+
+ulstmnt:
+	zcexpr ';'
+|	{
+		markdcl();
+	}
+	block
+	{
+		$$ = revertdcl();
+		if($$)
+			$$ = new(OLIST, $$, $2);
+		else
+			$$ = $2;
+	}
+|	LIF '(' cexpr ')' stmnt
+	{
+		$$ = new(OIF, $3, new(OLIST, $5, Z));
+		if($5 == Z)
+			warn($3, "empty if body");
+	}
+|	LIF '(' cexpr ')' stmnt LELSE stmnt
+	{
+		$$ = new(OIF, $3, new(OLIST, $5, $7));
+		if($5 == Z)
+			warn($3, "empty if body");
+		if($7 == Z)
+			warn($3, "empty else body");
+	}
+|	{ markdcl(); } LFOR '(' forexpr ';' zcexpr ';' zcexpr ')' stmnt
+	{
+		$$ = revertdcl();
+		if($$){
+			if($4)
+				$4 = new(OLIST, $$, $4);
+			else
+				$4 = $$;
+		}
+		$$ = new(OFOR, new(OLIST, $6, new(OLIST, $4, $8)), $10);
+	}
+|	LWHILE '(' cexpr ')' stmnt
+	{
+		$$ = new(OWHILE, $3, $5);
+	}
+|	LDO stmnt LWHILE '(' cexpr ')' ';'
+	{
+		$$ = new(ODWHILE, $5, $2);
+	}
+|	LRETURN zcexpr ';'
+	{
+		$$ = new(ORETURN, $2, Z);
+		$$->type = thisfn->link;
+	}
+|	LSWITCH '(' cexpr ')' stmnt
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->vconst = 0;
+		$$->type = types[TINT];
+		$3 = new(OSUB, $$, $3);
+
+		$$ = new(OCONST, Z, Z);
+		$$->vconst = 0;
+		$$->type = types[TINT];
+		$3 = new(OSUB, $$, $3);
+
+		$$ = new(OSWITCH, $3, $5);
+	}
+|	LBREAK ';'
+	{
+		$$ = new(OBREAK, Z, Z);
+	}
+|	LCONTINUE ';'
+	{
+		$$ = new(OCONTINUE, Z, Z);
+	}
+|	LGOTO ltag ';'
+	{
+		$$ = new(OGOTO, dcllabel($2, 0), Z);
+	}
+|	LUSED '(' zelist ')' ';'
+	{
+		$$ = new(OUSED, $3, Z);
+	}
+|	LSET '(' zelist ')' ';'
+	{
+		$$ = new(OSET, $3, Z);
+	}
+
+zcexpr:
+	{
+		$$ = Z;
+	}
+|	cexpr
+
+zexpr:
+	{
+		$$ = Z;
+	}
+|	lexpr
+
+lexpr:
+	expr
+	{
+		$$ = new(OCAST, $1, Z);
+		$$->type = types[TLONG];
+	}
+
+cexpr:
+	expr
+|	cexpr ',' cexpr
+	{
+		$$ = new(OCOMMA, $1, $3);
+	}
+
+expr:
+	xuexpr
+|	expr '*' expr
+	{
+		$$ = new(OMUL, $1, $3);
+	}
+|	expr '/' expr
+	{
+		$$ = new(ODIV, $1, $3);
+	}
+|	expr '%' expr
+	{
+		$$ = new(OMOD, $1, $3);
+	}
+|	expr '+' expr
+	{
+		$$ = new(OADD, $1, $3);
+	}
+|	expr '-' expr
+	{
+		$$ = new(OSUB, $1, $3);
+	}
+|	expr LRSH expr
+	{
+		$$ = new(OASHR, $1, $3);
+	}
+|	expr LLSH expr
+	{
+		$$ = new(OASHL, $1, $3);
+	}
+|	expr '<' expr
+	{
+		$$ = new(OLT, $1, $3);
+	}
+|	expr '>' expr
+	{
+		$$ = new(OGT, $1, $3);
+	}
+|	expr LLE expr
+	{
+		$$ = new(OLE, $1, $3);
+	}
+|	expr LGE expr
+	{
+		$$ = new(OGE, $1, $3);
+	}
+|	expr LEQ expr
+	{
+		$$ = new(OEQ, $1, $3);
+	}
+|	expr LNE expr
+	{
+		$$ = new(ONE, $1, $3);
+	}
+|	expr '&' expr
+	{
+		$$ = new(OAND, $1, $3);
+	}
+|	expr '^' expr
+	{
+		$$ = new(OXOR, $1, $3);
+	}
+|	expr '|' expr
+	{
+		$$ = new(OOR, $1, $3);
+	}
+|	expr LANDAND expr
+	{
+		$$ = new(OANDAND, $1, $3);
+	}
+|	expr LOROR expr
+	{
+		$$ = new(OOROR, $1, $3);
+	}
+|	expr '?' cexpr ':' expr
+	{
+		$$ = new(OCOND, $1, new(OLIST, $3, $5));
+	}
+|	expr '=' expr
+	{
+		$$ = new(OAS, $1, $3);
+	}
+|	expr LPE expr
+	{
+		$$ = new(OASADD, $1, $3);
+	}
+|	expr LME expr
+	{
+		$$ = new(OASSUB, $1, $3);
+	}
+|	expr LMLE expr
+	{
+		$$ = new(OASMUL, $1, $3);
+	}
+|	expr LDVE expr
+	{
+		$$ = new(OASDIV, $1, $3);
+	}
+|	expr LMDE expr
+	{
+		$$ = new(OASMOD, $1, $3);
+	}
+|	expr LLSHE expr
+	{
+		$$ = new(OASASHL, $1, $3);
+	}
+|	expr LRSHE expr
+	{
+		$$ = new(OASASHR, $1, $3);
+	}
+|	expr LANDE expr
+	{
+		$$ = new(OASAND, $1, $3);
+	}
+|	expr LXORE expr
+	{
+		$$ = new(OASXOR, $1, $3);
+	}
+|	expr LORE expr
+	{
+		$$ = new(OASOR, $1, $3);
+	}
+
+xuexpr:
+	uexpr
+|	'(' tlist abdecor ')' xuexpr
+	{
+		$$ = new(OCAST, $5, Z);
+		dodecl(NODECL, CXXX, $2, $3);
+		$$->type = lastdcl;
+		$$->xcast = 1;
+	}
+|	'(' tlist abdecor ')' '{' ilist '}'	/* extension */
+	{
+		$$ = new(OSTRUCT, $6, Z);
+		dodecl(NODECL, CXXX, $2, $3);
+		$$->type = lastdcl;
+	}
+
+uexpr:
+	pexpr
+|	'*' xuexpr
+	{
+		$$ = new(OIND, $2, Z);
+	}
+|	'&' xuexpr
+	{
+		$$ = new(OADDR, $2, Z);
+	}
+|	'+' xuexpr
+	{
+		$$ = new(OPOS, $2, Z);
+	}
+|	'-' xuexpr
+	{
+		$$ = new(ONEG, $2, Z);
+	}
+|	'!' xuexpr
+	{
+		$$ = new(ONOT, $2, Z);
+	}
+|	'~' xuexpr
+	{
+		$$ = new(OCOM, $2, Z);
+	}
+|	LPP xuexpr
+	{
+		$$ = new(OPREINC, $2, Z);
+	}
+|	LMM xuexpr
+	{
+		$$ = new(OPREDEC, $2, Z);
+	}
+|	LSIZEOF uexpr
+	{
+		$$ = new(OSIZE, $2, Z);
+	}
+|	LSIGNOF uexpr
+	{
+		$$ = new(OSIGN, $2, Z);
+	}
+
+pexpr:
+	'(' cexpr ')'
+	{
+		$$ = $2;
+	}
+|	LSIZEOF '(' tlist abdecor ')'
+	{
+		$$ = new(OSIZE, Z, Z);
+		dodecl(NODECL, CXXX, $3, $4);
+		$$->type = lastdcl;
+	}
+|	LSIGNOF '(' tlist abdecor ')'
+	{
+		$$ = new(OSIGN, Z, Z);
+		dodecl(NODECL, CXXX, $3, $4);
+		$$->type = lastdcl;
+	}
+|	pexpr '(' zelist ')'
+	{
+		$$ = new(OFUNC, $1, Z);
+		if($1->op == ONAME)
+		if($1->type == T)
+			dodecl(xdecl, CXXX, types[TINT], $$);
+		$$->right = invert($3);
+	}
+|	pexpr '[' cexpr ']'
+	{
+		$$ = new(OIND, new(OADD, $1, $3), Z);
+	}
+|	pexpr LMG ltag
+	{
+		$$ = new(ODOT, new(OIND, $1, Z), Z);
+		$$->sym = $3;
+	}
+|	pexpr '.' ltag
+	{
+		$$ = new(ODOT, $1, Z);
+		$$->sym = $3;
+	}
+|	pexpr LPP
+	{
+		$$ = new(OPOSTINC, $1, Z);
+	}
+|	pexpr LMM
+	{
+		$$ = new(OPOSTDEC, $1, Z);
+	}
+|	name
+|	LCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TINT];
+		$$->vconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LLCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TLONG];
+		$$->vconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LUCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TUINT];
+		$$->vconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LULCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TULONG];
+		$$->vconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LDCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TDOUBLE];
+		$$->fconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LFCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TFLOAT];
+		$$->fconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LVLCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TVLONG];
+		$$->vconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LUVLCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TUVLONG];
+		$$->vconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	string
+|	lstring
+
+string:
+	LSTRING
+	{
+		$$ = new(OSTRING, Z, Z);
+		$$->type = typ(TARRAY, types[TCHAR]);
+		$$->type->width = $1.l + 1;
+		$$->cstring = $1.s;
+		$$->sym = symstring;
+		$$->etype = TARRAY;
+		$$->class = CSTATIC;
+	}
+|	string LSTRING
+	{
+		char *s;
+		int n;
+
+		n = $1->type->width - 1;
+		s = alloc(n+$2.l+MAXALIGN);
+
+		memcpy(s, $1->cstring, n);
+		memcpy(s+n, $2.s, $2.l);
+		s[n+$2.l] = 0;
+
+		$$ = $1;
+		$$->type->width += $2.l;
+		$$->cstring = s;
+	}
+
+lstring:
+	LLSTRING
+	{
+		$$ = new(OLSTRING, Z, Z);
+		$$->type = typ(TARRAY, types[TUSHORT]);
+		$$->type->width = $1.l + sizeof(ushort);
+		$$->rstring = (ushort*)$1.s;
+		$$->sym = symstring;
+		$$->etype = TARRAY;
+		$$->class = CSTATIC;
+	}
+|	lstring LLSTRING
+	{
+		char *s;
+		int n;
+
+		n = $1->type->width - sizeof(ushort);
+		s = alloc(n+$2.l+MAXALIGN);
+
+		memcpy(s, $1->rstring, n);
+		memcpy(s+n, $2.s, $2.l);
+		*(ushort*)(s+n+$2.l) = 0;
+
+		$$ = $1;
+		$$->type->width += $2.l;
+		$$->rstring = (ushort*)s;
+	}
+
+zelist:
+	{
+		$$ = Z;
+	}
+|	elist
+
+elist:
+	expr
+|	elist ',' elist
+	{
+		$$ = new(OLIST, $1, $3);
+	}
+
+sbody:
+	'{'
+	{
+		$<tyty>$.t1 = strf;
+		$<tyty>$.t2 = strl;
+		strf = T;
+		strl = T;
+		lastbit = 0;
+		firstbit = 1;
+	}
+	edecl '}'
+	{
+		$$ = strf;
+		strf = $<tyty>2.t1;
+		strl = $<tyty>2.t2;
+	}
+
+zctlist:
+	{
+		lastclass = CXXX;
+		lasttype = types[TINT];
+	}
+|	ctlist
+
+types:
+	complex
+	{
+		$$.t = $1;
+		$$.c = CXXX;
+	}
+|	tname
+	{
+		$$.t = simplet($1);
+		$$.c = CXXX;
+	}
+|	gcnlist
+	{
+		$$.t = simplet($1);
+		$$.c = simplec($1);
+		$$.t = garbt($$.t, $1);
+	}
+|	complex gctnlist
+	{
+		$$.t = $1;
+		$$.c = simplec($2);
+		$$.t = garbt($$.t, $2);
+		if($2 & ~BCLASS & ~BGARB)
+			diag(Z, "duplicate types given: %T and %Q", $1, $2);
+	}
+|	tname gctnlist
+	{
+		$$.t = simplet(typebitor($1, $2));
+		$$.c = simplec($2);
+		$$.t = garbt($$.t, $2);
+	}
+|	gcnlist complex zgnlist
+	{
+		$$.t = $2;
+		$$.c = simplec($1);
+		$$.t = garbt($$.t, $1|$3);
+	}
+|	gcnlist tname
+	{
+		$$.t = simplet($2);
+		$$.c = simplec($1);
+		$$.t = garbt($$.t, $1);
+	}
+|	gcnlist tname gctnlist
+	{
+		$$.t = simplet(typebitor($2, $3));
+		$$.c = simplec($1|$3);
+		$$.t = garbt($$.t, $1|$3);
+	}
+
+tlist:
+	types
+	{
+		$$ = $1.t;
+		if($1.c != CXXX)
+			diag(Z, "illegal combination of class 4: %s", cnames[$1.c]);
+	}
+
+ctlist:
+	types
+	{
+		lasttype = $1.t;
+		lastclass = $1.c;
+	}
+
+complex:
+	LSTRUCT ltag
+	{
+		dotag($2, TSTRUCT, 0);
+		$$ = $2->suetag;
+	}
+|	LSTRUCT ltag
+	{
+		dotag($2, TSTRUCT, autobn);
+	}
+	sbody
+	{
+		$$ = $2->suetag;
+		if($$->link != T)
+			diag(Z, "redeclare tag: %s", $2->name);
+		$$->link = $4;
+		suallign($$);
+	}
+|	LSTRUCT sbody
+	{
+		taggen++;
+		sprint(symb, "_%d_", taggen);
+		$$ = dotag(lookup(), TSTRUCT, autobn);
+		$$->link = $2;
+		suallign($$);
+	}
+|	LUNION ltag
+	{
+		dotag($2, TUNION, 0);
+		$$ = $2->suetag;
+	}
+|	LUNION ltag
+	{
+		dotag($2, TUNION, autobn);
+	}
+	sbody
+	{
+		$$ = $2->suetag;
+		if($$->link != T)
+			diag(Z, "redeclare tag: %s", $2->name);
+		$$->link = $4;
+		suallign($$);
+	}
+|	LUNION sbody
+	{
+		taggen++;
+		sprint(symb, "_%d_", taggen);
+		$$ = dotag(lookup(), TUNION, autobn);
+		$$->link = $2;
+		suallign($$);
+	}
+|	LENUM ltag
+	{
+		dotag($2, TENUM, 0);
+		$$ = $2->suetag;
+		if($$->link == T)
+			$$->link = types[TINT];
+		$$ = $$->link;
+	}
+|	LENUM ltag
+	{
+		dotag($2, TENUM, autobn);
+	}
+	'{'
+	{
+		en.tenum = T;
+		en.cenum = T;
+	}
+	enum '}'
+	{
+		$$ = $2->suetag;
+		if($$->link != T)
+			diag(Z, "redeclare tag: %s", $2->name);
+		if(en.tenum == T) {
+			diag(Z, "enum type ambiguous: %s", $2->name);
+			en.tenum = types[TINT];
+		}
+		$$->link = en.tenum;
+		$$ = en.tenum;
+	}
+|	LENUM '{'
+	{
+		en.tenum = T;
+		en.cenum = T;
+	}
+	enum '}'
+	{
+		$$ = en.tenum;
+	}
+|	LTYPE
+	{
+		$$ = tcopy($1->type);
+	}
+
+gctnlist:
+	gctname
+|	gctnlist gctname
+	{
+		$$ = typebitor($1, $2);
+	}
+
+zgnlist:
+	{
+		$$ = 0;
+	}
+|	zgnlist gname
+	{
+		$$ = typebitor($1, $2);
+	}
+
+gctname:
+	tname
+|	gname
+|	cname
+
+gcnlist:
+	gcname
+|	gcnlist gcname
+	{
+		$$ = typebitor($1, $2);
+	}
+
+gcname:
+	gname
+|	cname
+
+enum:
+	LNAME
+	{
+		doenum($1, Z);
+	}
+|	LNAME '=' expr
+	{
+		doenum($1, $3);
+	}
+|	enum ','
+|	enum ',' enum
+
+tname:	/* type words */
+	LCHAR { $$ = BCHAR; }
+|	LSHORT { $$ = BSHORT; }
+|	LINT { $$ = BINT; }
+|	LLONG { $$ = BLONG; }
+|	LSIGNED { $$ = BSIGNED; }
+|	LUNSIGNED { $$ = BUNSIGNED; }
+|	LFLOAT { $$ = BFLOAT; }
+|	LDOUBLE { $$ = BDOUBLE; }
+|	LVOID { $$ = BVOID; }
+
+cname:	/* class words */
+	LAUTO { $$ = BAUTO; }
+|	LSTATIC { $$ = BSTATIC; }
+|	LEXTERN { $$ = BEXTERN; }
+|	LTYPEDEF { $$ = BTYPEDEF; }
+|	LTYPESTR { $$ = BTYPESTR; }
+|	LREGISTER { $$ = BREGISTER; }
+|	LINLINE { $$ = 0; }
+
+gname:	/* garbage words */
+	LCONSTNT { $$ = BCONSTNT; }
+|	LVOLATILE { $$ = BVOLATILE; }
+|	LRESTRICT { $$ = 0; }
+
+name:
+	LNAME
+	{
+		$$ = new(ONAME, Z, Z);
+		if($1->class == CLOCAL)
+			$1 = mkstatic($1);
+		$$->sym = $1;
+		$$->type = $1->type;
+		$$->etype = TVOID;
+		if($$->type != T)
+			$$->etype = $$->type->etype;
+		$$->xoffset = $1->offset;
+		$$->class = $1->class;
+		$1->aused = 1;
+	}
+tag:
+	ltag
+	{
+		$$ = new(ONAME, Z, Z);
+		$$->sym = $1;
+		$$->type = $1->type;
+		$$->etype = TVOID;
+		if($$->type != T)
+			$$->etype = $$->type->etype;
+		$$->xoffset = $1->offset;
+		$$->class = $1->class;
+	}
+ltag:
+	LNAME
+|	LTYPE
+%%
diff --git a/src/cmd/cc/com.c b/src/cmd/cc/com.c
new file mode 100644
index 0000000..b0b1620
--- /dev/null
+++ b/src/cmd/cc/com.c
@@ -0,0 +1,1378 @@
+// Inferno utils/cc/com.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/com.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+int compar(Node*, int);
+
+void
+complex(Node *n)
+{
+
+	if(n == Z)
+		return;
+
+	nearln = n->lineno;
+	if(debug['t'])
+		if(n->op != OCONST)
+			prtree(n, "pre complex");
+	if(tcom(n))
+		return;
+	if(debug['t'])
+		if(n->op != OCONST)
+			prtree(n, "t complex");
+	ccom(n);
+	if(debug['t'])
+		if(n->op != OCONST)
+			prtree(n, "c complex");
+	acom(n);
+	if(debug['t'])
+		if(n->op != OCONST)
+			prtree(n, "a complex");
+	xcom(n);
+	if(debug['t'])
+		if(n->op != OCONST)
+			prtree(n, "x complex");
+}
+
+/*
+ * evaluate types
+ * evaluate lvalues (addable == 1)
+ */
+enum
+{
+	ADDROF	= 1<<0,
+	CASTOF	= 1<<1,
+	ADDROP	= 1<<2,
+};
+
+int
+tcom(Node *n)
+{
+
+	return tcomo(n, ADDROF);
+}
+
+int
+tcomo(Node *n, int f)
+{
+	Node *l, *r;
+	Type *t;
+	int o;
+
+	if(n == Z) {
+		diag(Z, "Z in tcom");
+		errorexit();
+	}
+	n->addable = 0;
+	l = n->left;
+	r = n->right;
+
+	switch(n->op) {
+	default:
+		diag(n, "unknown op in type complex: %O", n->op);
+		goto bad;
+
+	case ODOTDOT:
+		/*
+		 * tcom has already been called on this subtree
+		 */
+		*n = *n->left;
+		if(n->type == T)
+			goto bad;
+		break;
+
+	case OCAST:
+		if(n->type == T)
+			break;
+		if(n->type->width == types[TLONG]->width) {
+			if(tcomo(l, ADDROF|CASTOF))
+				goto bad;
+		} else
+			if(tcom(l))
+				goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, n->type, tcast))
+			goto bad;
+		break;
+
+	case ORETURN:
+		if(l == Z) {
+			if(n->type->etype != TVOID)
+				warn(n, "null return of a typed function");
+			break;
+		}
+		if(tcom(l))
+			goto bad;
+		typeext(n->type, l);
+		if(tcompat(n, n->type, l->type, tasign))
+			break;
+		constas(n, n->type, l->type);
+		if(!sametype(n->type, l->type)) {
+			l = new1(OCAST, l, Z);
+			l->type = n->type;
+			n->left = l;
+		}
+		break;
+
+	case OASI:	/* same as as, but no test for const */
+		n->op = OAS;
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+
+		typeext(l->type, r);
+		if(tlvalue(l) || tcompat(n, l->type, r->type, tasign))
+			goto bad;
+		if(!sametype(l->type, r->type)) {
+			r = new1(OCAST, r, Z);
+			r->type = l->type;
+			n->right = r;
+		}
+		n->type = l->type;
+		break;
+
+	case OAS:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		typeext(l->type, r);
+		if(tcompat(n, l->type, r->type, tasign))
+			goto bad;
+		constas(n, l->type, r->type);
+		if(!sametype(l->type, r->type)) {
+			r = new1(OCAST, r, Z);
+			r->type = l->type;
+			n->right = r;
+		}
+		n->type = l->type;
+		break;
+
+	case OASADD:
+	case OASSUB:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		typeext1(l->type, r);
+		if(tcompat(n, l->type, r->type, tasadd))
+			goto bad;
+		constas(n, l->type, r->type);
+		t = l->type;
+		arith(n, 0);
+		while(n->left->op == OCAST)
+			n->left = n->left->left;
+		if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+			r = new1(OCAST, n->right, Z);
+			r->type = t;
+			n->right = r;
+			n->type = t;
+		}
+		break;
+
+	case OASMUL:
+	case OASLMUL:
+	case OASDIV:
+	case OASLDIV:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		typeext1(l->type, r);
+		if(tcompat(n, l->type, r->type, tmul))
+			goto bad;
+		constas(n, l->type, r->type);
+		t = l->type;
+		arith(n, 0);
+		while(n->left->op == OCAST)
+			n->left = n->left->left;
+		if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+			r = new1(OCAST, n->right, Z);
+			r->type = t;
+			n->right = r;
+			n->type = t;
+		}
+		if(typeu[n->type->etype]) {
+			if(n->op == OASDIV)
+				n->op = OASLDIV;
+			if(n->op == OASMUL)
+				n->op = OASLMUL;
+		}
+		break;
+
+	case OASLSHR:
+	case OASASHR:
+	case OASASHL:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tand))
+			goto bad;
+		n->type = l->type;
+		if(typeu[n->type->etype]) {
+			if(n->op == OASASHR)
+				n->op = OASLSHR;
+		}
+		break;
+
+	case OASMOD:
+	case OASLMOD:
+	case OASOR:
+	case OASAND:
+	case OASXOR:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tand))
+			goto bad;
+		t = l->type;
+		arith(n, 0);
+		while(n->left->op == OCAST)
+			n->left = n->left->left;
+		if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+			r = new1(OCAST, n->right, Z);
+			r->type = t;
+			n->right = r;
+			n->type = t;
+		}
+		if(typeu[n->type->etype]) {
+			if(n->op == OASMOD)
+				n->op = OASLMOD;
+		}
+		break;
+
+	case OPREINC:
+	case OPREDEC:
+	case OPOSTINC:
+	case OPOSTDEC:
+		if(tcom(l))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, types[TINT], tadd))
+			goto bad;
+		n->type = l->type;
+		if(n->type->etype == TIND)
+		if(n->type->link->width < 1)
+			diag(n, "inc/dec of a void pointer");
+		break;
+
+	case OEQ:
+	case ONE:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		typeext(l->type, r);
+		typeext(r->type, l);
+		if(tcompat(n, l->type, r->type, trel))
+			goto bad;
+		arith(n, 0);
+		n->type = types[TINT];
+		break;
+
+	case OLT:
+	case OGE:
+	case OGT:
+	case OLE:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		typeext1(l->type, r);
+		typeext1(r->type, l);
+		if(tcompat(n, l->type, r->type, trel))
+			goto bad;
+		arith(n, 0);
+		if(typeu[n->type->etype])
+			n->op = logrel[relindex(n->op)];
+		n->type = types[TINT];
+		break;
+
+	case OCOND:
+		o = tcom(l);
+		o |= tcom(r->left);
+		if(o | tcom(r->right))
+			goto bad;
+		if(r->right->type->etype == TIND && vconst(r->left) == 0) {
+			r->left->type = r->right->type;
+			r->left->vconst = 0;
+		}
+		if(r->left->type->etype == TIND && vconst(r->right) == 0) {
+			r->right->type = r->left->type;
+			r->right->vconst = 0;
+		}
+		if(sametype(r->right->type, r->left->type)) {
+			r->type = r->right->type;
+			n->type = r->type;
+			break;
+		}
+		if(tcompat(r, r->left->type, r->right->type, trel))
+			goto bad;
+		arith(r, 0);
+		n->type = r->type;
+		break;
+
+	case OADD:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tadd))
+			goto bad;
+		arith(n, 1);
+		break;
+
+	case OSUB:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tsub))
+			goto bad;
+		arith(n, 1);
+		break;
+
+	case OMUL:
+	case OLMUL:
+	case ODIV:
+	case OLDIV:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tmul))
+			goto bad;
+		arith(n, 1);
+		if(typeu[n->type->etype]) {
+			if(n->op == ODIV)
+				n->op = OLDIV;
+			if(n->op == OMUL)
+				n->op = OLMUL;
+		}
+		break;
+
+	case OLSHR:
+	case OASHL:
+	case OASHR:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tand))
+			goto bad;
+		n->right = Z;
+		arith(n, 1);
+		n->right = new1(OCAST, r, Z);
+		n->right->type = types[TINT];
+		if(typeu[n->type->etype])
+			if(n->op == OASHR)
+				n->op = OLSHR;
+		break;
+
+	case OAND:
+	case OOR:
+	case OXOR:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tand))
+			goto bad;
+		arith(n, 1);
+		break;
+
+	case OMOD:
+	case OLMOD:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tand))
+			goto bad;
+		arith(n, 1);
+		if(typeu[n->type->etype])
+			n->op = OLMOD;
+		break;
+
+	case OPOS:
+		if(tcom(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+
+		r = l;
+		l = new(OCONST, Z, Z);
+		l->vconst = 0;
+		l->type = types[TINT];
+		n->op = OADD;
+		n->right = r;
+		n->left = l;
+
+		if(tcom(l))
+			goto bad;
+		if(tcompat(n, l->type, r->type, tsub))
+			goto bad;
+		arith(n, 1);
+		break;
+
+	case ONEG:
+		if(tcom(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+
+		if(!machcap(n)) {
+			r = l;
+			l = new(OCONST, Z, Z);
+			l->vconst = 0;
+			l->type = types[TINT];
+			n->op = OSUB;
+			n->right = r;
+			n->left = l;
+
+			if(tcom(l))
+				goto bad;
+			if(tcompat(n, l->type, r->type, tsub))
+				goto bad;
+		}
+		arith(n, 1);
+		break;
+
+	case OCOM:
+		if(tcom(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+
+		if(!machcap(n)) {
+			r = l;
+			l = new(OCONST, Z, Z);
+			l->vconst = -1;
+			l->type = types[TINT];
+			n->op = OXOR;
+			n->right = r;
+			n->left = l;
+
+			if(tcom(l))
+				goto bad;
+			if(tcompat(n, l->type, r->type, tand))
+				goto bad;
+		}
+		arith(n, 1);
+		break;
+
+	case ONOT:
+		if(tcom(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, T, l->type, tnot))
+			goto bad;
+		n->type = types[TINT];
+		break;
+
+	case OANDAND:
+	case OOROR:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(tcompat(n, T, l->type, tnot) |
+		   tcompat(n, T, r->type, tnot))
+			goto bad;
+		n->type = types[TINT];
+		break;
+
+	case OCOMMA:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		n->type = r->type;
+		break;
+
+
+	case OSIGN:	/* extension signof(type) returns a hash */
+		if(l != Z) {
+			if(l->op != OSTRING && l->op != OLSTRING)
+				if(tcomo(l, 0))
+					goto bad;
+			if(l->op == OBIT) {
+				diag(n, "signof bitfield");
+				goto bad;
+			}
+			n->type = l->type;
+		}
+		if(n->type == T)
+			goto bad;
+		if(n->type->width < 0) {
+			diag(n, "signof undefined type");
+			goto bad;
+		}
+		n->op = OCONST;
+		n->left = Z;
+		n->right = Z;
+		n->vconst = convvtox(signature(n->type), TULONG);
+		n->type = types[TULONG];
+		break;
+
+	case OSIZE:
+		if(l != Z) {
+			if(l->op != OSTRING && l->op != OLSTRING)
+				if(tcomo(l, 0))
+					goto bad;
+			if(l->op == OBIT) {
+				diag(n, "sizeof bitfield");
+				goto bad;
+			}
+			n->type = l->type;
+		}
+		if(n->type == T)
+			goto bad;
+		if(n->type->width <= 0) {
+			diag(n, "sizeof undefined type");
+			goto bad;
+		}
+		if(n->type->etype == TFUNC) {
+			diag(n, "sizeof function");
+			goto bad;
+		}
+		n->op = OCONST;
+		n->left = Z;
+		n->right = Z;
+		n->vconst = convvtox(n->type->width, TINT);
+		n->type = types[TINT];
+		break;
+
+	case OFUNC:
+		o = tcomo(l, 0);
+		if(o)
+			goto bad;
+		if(l->type->etype == TIND && l->type->link->etype == TFUNC) {
+			l = new1(OIND, l, Z);
+			l->type = l->left->type->link;
+			n->left = l;
+		}
+		if(tcompat(n, T, l->type, tfunct))
+			goto bad;
+		if(o | tcoma(l, r, l->type->down, 1))
+			goto bad;
+		n->type = l->type->link;
+		if(!debug['B'])
+			if(l->type->down == T || l->type->down->etype == TOLD) {
+				nerrors--;
+				diag(n, "function args not checked: %F", l);
+			}
+		dpcheck(n);
+		break;
+
+	case ONAME:
+		if(n->type == T) {
+			diag(n, "name not declared: %F", n);
+			goto bad;
+		}
+		if(n->type->etype == TENUM) {
+			n->op = OCONST;
+			n->type = n->sym->tenum;
+			if(!typefd[n->type->etype])
+				n->vconst = n->sym->vconst;
+			else
+				n->fconst = n->sym->fconst;
+			break;
+		}
+		n->addable = 1;
+		if(n->class == CEXREG) {
+			n->op = OREGISTER;
+			n->reg = n->sym->offset;
+			n->xoffset = 0;
+			break;
+		}
+		break;
+
+	case OLSTRING:
+		if(n->type->link != types[TUSHORT]) {
+			o = outstring(0, 0);
+			while(o & 3) {
+				ushort a[1];
+				a[0] = 0;
+				outlstring(a, sizeof(ushort));
+				o = outlstring(0, 0);
+			}
+		}
+		n->op = ONAME;
+		n->xoffset = outlstring(n->rstring, n->type->width);
+		n->addable = 1;
+		break;
+
+	case OSTRING:
+		if(n->type->link != types[TCHAR]) {
+			o = outstring(0, 0);
+			while(o & 3) {
+				outstring("", 1);
+				o = outstring(0, 0);
+			}
+		}
+		n->op = ONAME;
+		n->xoffset = outstring(n->cstring, n->type->width);
+		n->addable = 1;
+		break;
+
+	case OCONST:
+		break;
+
+	case ODOT:
+		if(tcom(l))
+			goto bad;
+		if(tcompat(n, T, l->type, tdot))
+			goto bad;
+		if(tcomd(n))
+			goto bad;
+		break;
+
+	case OADDR:
+		if(tcomo(l, ADDROP))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(l->type->nbits) {
+			diag(n, "address of a bit field");
+			goto bad;
+		}
+		if(l->op == OREGISTER) {
+			diag(n, "address of a register");
+			goto bad;
+		}
+		n->type = typ(TIND, l->type);
+		n->type->width = types[TIND]->width;
+		break;
+
+	case OIND:
+		if(tcom(l))
+			goto bad;
+		if(tcompat(n, T, l->type, tindir))
+			goto bad;
+		n->type = l->type->link;
+		n->addable = 1;
+		break;
+
+	case OSTRUCT:
+		if(tcomx(n))
+			goto bad;
+		break;
+	}
+	t = n->type;
+	if(t == T)
+		goto bad;
+	if(t->width < 0) {
+		snap(t);
+		if(t->width < 0) {
+			if(typesu[t->etype] && t->tag)
+				diag(n, "structure not fully declared %s", t->tag->name);
+			else
+				diag(n, "structure not fully declared");
+			goto bad;
+		}
+	}
+	if(typeaf[t->etype]) {
+		if(f & ADDROF)
+			goto addaddr;
+		if(f & ADDROP)
+			warn(n, "address of array/func ignored");
+	}
+	return 0;
+
+addaddr:
+	if(tlvalue(n))
+		goto bad;
+	l = new1(OXXX, Z, Z);
+	*l = *n;
+	n->op = OADDR;
+	if(l->type->etype == TARRAY)
+		l->type = l->type->link;
+	n->left = l;
+	n->right = Z;
+	n->addable = 0;
+	n->type = typ(TIND, l->type);
+	n->type->width = types[TIND]->width;
+	return 0;
+
+bad:
+	n->type = T;
+	return 1;
+}
+
+int
+tcoma(Node *l, Node *n, Type *t, int f)
+{
+	Node *n1;
+	int o;
+
+	if(t != T)
+	if(t->etype == TOLD || t->etype == TDOT)	/* .../old in prototype */
+		t = T;
+	if(n == Z) {
+		if(t != T && !sametype(t, types[TVOID])) {
+			diag(n, "not enough function arguments: %F", l);
+			return 1;
+		}
+		return 0;
+	}
+	if(n->op == OLIST) {
+		o = tcoma(l, n->left, t, 0);
+		if(t != T) {
+			t = t->down;
+			if(t == T)
+				t = types[TVOID];
+		}
+		return o | tcoma(l, n->right, t, 1);
+	}
+	if(f && t != T)
+		tcoma(l, Z, t->down, 0);
+	if(tcom(n) || tcompat(n, T, n->type, targ))
+		return 1;
+	if(sametype(t, types[TVOID])) {
+		diag(n, "too many function arguments: %F", l);
+		return 1;
+	}
+	if(t != T) {
+		typeext(t, n);
+		if(stcompat(nodproto, t, n->type, tasign)) {
+			diag(l, "argument prototype mismatch \"%T\" for \"%T\": %F",
+				n->type, t, l);
+			return 1;
+		}
+		switch(t->etype) {
+		case TCHAR:
+		case TSHORT:
+			t = types[TINT];
+			break;
+
+		case TUCHAR:
+		case TUSHORT:
+			t = types[TUINT];
+			break;
+		}
+	} else
+	switch(n->type->etype)
+	{
+	case TCHAR:
+	case TSHORT:
+		t = types[TINT];
+		break;
+
+	case TUCHAR:
+	case TUSHORT:
+		t = types[TUINT];
+		break;
+
+	case TFLOAT:
+		t = types[TDOUBLE];
+	}
+	if(t != T && !sametype(t, n->type)) {
+		n1 = new1(OXXX, Z, Z);
+		*n1 = *n;
+		n->op = OCAST;
+		n->left = n1;
+		n->right = Z;
+		n->type = t;
+		n->addable = 0;
+	}
+	return 0;
+}
+
+int
+tcomd(Node *n)
+{
+	Type *t;
+	long o;
+
+	o = 0;
+	t = dotsearch(n->sym, n->left->type->link, n, &o);
+	if(t == T) {
+		diag(n, "not a member of struct/union: %F", n);
+		return 1;
+	}
+	makedot(n, t, o);
+	return 0;
+}
+
+int
+tcomx(Node *n)
+{
+	Type *t;
+	Node *l, *r, **ar, **al;
+	int e;
+
+	e = 0;
+	if(n->type->etype != TSTRUCT) {
+		diag(n, "constructor must be a structure");
+		return 1;
+	}
+	l = invert(n->left);
+	n->left = l;
+	al = &n->left;
+	for(t = n->type->link; t != T; t = t->down) {
+		if(l == Z) {
+			diag(n, "constructor list too short");
+			return 1;
+		}
+		if(l->op == OLIST) {
+			r = l->left;
+			ar = &l->left;
+			al = &l->right;
+			l = l->right;
+		} else {
+			r = l;
+			ar = al;
+			l = Z;
+		}
+		if(tcom(r))
+			e++;
+		typeext(t, r);
+		if(tcompat(n, t, r->type, tasign))
+			e++;
+		constas(n, t, r->type);
+		if(!e && !sametype(t, r->type)) {
+			r = new1(OCAST, r, Z);
+			r->type = t;
+			*ar = r;
+		}
+	}
+	if(l != Z) {
+		diag(n, "constructor list too long");
+		return 1;
+	}
+	return e;
+}
+
+int
+tlvalue(Node *n)
+{
+
+	if(!n->addable) {
+		diag(n, "not an l-value");
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ *	general rewrite
+ *	(IND(ADDR x)) ==> x
+ *	(ADDR(IND x)) ==> x
+ *	remove some zero operands
+ *	remove no op casts
+ *	evaluate constants
+ */
+void
+ccom(Node *n)
+{
+	Node *l, *r;
+	int t;
+
+loop:
+	if(n == Z)
+		return;
+	l = n->left;
+	r = n->right;
+	switch(n->op) {
+
+	case OAS:
+	case OASXOR:
+	case OASAND:
+	case OASOR:
+	case OASMOD:
+	case OASLMOD:
+	case OASLSHR:
+	case OASASHR:
+	case OASASHL:
+	case OASDIV:
+	case OASLDIV:
+	case OASMUL:
+	case OASLMUL:
+	case OASSUB:
+	case OASADD:
+		ccom(l);
+		ccom(r);
+		if(n->op == OASLSHR || n->op == OASASHR || n->op == OASASHL)
+		if(r->op == OCONST) {
+			t = n->type->width * 8;	/* bits per byte */
+			if(r->vconst >= t || r->vconst < 0)
+				warn(n, "stupid shift: %lld", r->vconst);
+		}
+		break;
+
+	case OCAST:
+		ccom(l);
+		if(l->op == OCONST) {
+			evconst(n);
+			if(n->op == OCONST)
+				break;
+		}
+		if(nocast(l->type, n->type)) {
+			l->type = n->type;
+			*n = *l;
+		}
+		break;
+
+	case OCOND:
+		ccom(l);
+		ccom(r);
+		if(l->op == OCONST)
+			if(vconst(l) == 0)
+				*n = *r->right;
+			else
+				*n = *r->left;
+		break;
+
+	case OREGISTER:
+	case OINDREG:
+	case OCONST:
+	case ONAME:
+		break;
+
+	case OADDR:
+		ccom(l);
+		l->etype = TVOID;
+		if(l->op == OIND) {
+			l->left->type = n->type;
+			*n = *l->left;
+			break;
+		}
+		goto common;
+
+	case OIND:
+		ccom(l);
+		if(l->op == OADDR) {
+			l->left->type = n->type;
+			*n = *l->left;
+			break;
+		}
+		goto common;
+
+	case OEQ:
+	case ONE:
+
+	case OLE:
+	case OGE:
+	case OLT:
+	case OGT:
+
+	case OLS:
+	case OHS:
+	case OLO:
+	case OHI:
+		ccom(l);
+		ccom(r);
+		if(compar(n, 0) || compar(n, 1))
+			break;
+		relcon(l, r);
+		relcon(r, l);
+		goto common;
+
+	case OASHR:
+	case OASHL:
+	case OLSHR:
+		ccom(l);
+		if(vconst(l) == 0 && !side(r)) {
+			*n = *l;
+			break;
+		}
+		ccom(r);
+		if(vconst(r) == 0) {
+			*n = *l;
+			break;
+		}
+		if(r->op == OCONST) {
+			t = n->type->width * 8;	/* bits per byte */
+			if(r->vconst >= t || r->vconst <= -t)
+				warn(n, "stupid shift: %lld", r->vconst);
+		}
+		goto common;
+
+	case OMUL:
+	case OLMUL:
+		ccom(l);
+		t = vconst(l);
+		if(t == 0 && !side(r)) {
+			*n = *l;
+			break;
+		}
+		if(t == 1) {
+			*n = *r;
+			goto loop;
+		}
+		ccom(r);
+		t = vconst(r);
+		if(t == 0 && !side(l)) {
+			*n = *r;
+			break;
+		}
+		if(t == 1) {
+			*n = *l;
+			break;
+		}
+		goto common;
+
+	case ODIV:
+	case OLDIV:
+		ccom(l);
+		if(vconst(l) == 0 && !side(r)) {
+			*n = *l;
+			break;
+		}
+		ccom(r);
+		t = vconst(r);
+		if(t == 0) {
+			diag(n, "divide check");
+			*n = *r;
+			break;
+		}
+		if(t == 1) {
+			*n = *l;
+			break;
+		}
+		goto common;
+
+	case OSUB:
+		ccom(r);
+		if(r->op == OCONST) {
+			if(typefd[r->type->etype]) {
+				n->op = OADD;
+				r->fconst = -r->fconst;
+				goto loop;
+			} else {
+				n->op = OADD;
+				r->vconst = -r->vconst;
+				goto loop;
+			}
+		}
+		ccom(l);
+		goto common;
+
+	case OXOR:
+	case OOR:
+	case OADD:
+		ccom(l);
+		if(vconst(l) == 0) {
+			*n = *r;
+			goto loop;
+		}
+		ccom(r);
+		if(vconst(r) == 0) {
+			*n = *l;
+			break;
+		}
+		goto commute;
+
+	case OAND:
+		ccom(l);
+		ccom(r);
+		if(vconst(l) == 0 && !side(r)) {
+			*n = *l;
+			break;
+		}
+		if(vconst(r) == 0 && !side(l)) {
+			*n = *r;
+			break;
+		}
+
+	commute:
+		/* look for commutative constant */
+		if(r->op == OCONST) {
+			if(l->op == n->op) {
+				if(l->left->op == OCONST) {
+					n->right = l->right;
+					l->right = r;
+					goto loop;
+				}
+				if(l->right->op == OCONST) {
+					n->right = l->left;
+					l->left = r;
+					goto loop;
+				}
+			}
+		}
+		if(l->op == OCONST) {
+			if(r->op == n->op) {
+				if(r->left->op == OCONST) {
+					n->left = r->right;
+					r->right = l;
+					goto loop;
+				}
+				if(r->right->op == OCONST) {
+					n->left = r->left;
+					r->left = l;
+					goto loop;
+				}
+			}
+		}
+		goto common;
+
+	case OANDAND:
+		ccom(l);
+		if(vconst(l) == 0) {
+			*n = *l;
+			break;
+		}
+		ccom(r);
+		goto common;
+
+	case OOROR:
+		ccom(l);
+		if(l->op == OCONST && l->vconst != 0) {
+			*n = *l;
+			n->vconst = 1;
+			break;
+		}
+		ccom(r);
+		goto common;
+
+	default:
+		if(l != Z)
+			ccom(l);
+		if(r != Z)
+			ccom(r);
+	common:
+		if(l != Z)
+		if(l->op != OCONST)
+			break;
+		if(r != Z)
+		if(r->op != OCONST)
+			break;
+		evconst(n);
+	}
+}
+
+/*	OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
+static char *cmps[12] = 
+{
+	"==", "!=", "<=", "<=", "<", "<", ">=", ">=", ">", ">",
+};
+
+/* 128-bit numbers */
+typedef struct Big Big;
+struct Big
+{
+	vlong a;
+	uvlong b;
+};
+static int
+cmp(Big x, Big y)
+{
+	if(x.a != y.a){
+		if(x.a < y.a)
+			return -1;
+		return 1;
+	}
+	if(x.b != y.b){
+		if(x.b < y.b)
+			return -1;
+		return 1;
+	}
+	return 0;
+}
+static Big
+add(Big x, int y)
+{
+	uvlong ob;
+	
+	ob = x.b;
+	x.b += y;
+	if(y > 0 && x.b < ob)
+		x.a++;
+	if(y < 0 && x.b > ob)
+		x.a--;
+	return x;
+} 
+
+Big
+big(vlong a, uvlong b)
+{
+	Big x;
+
+	x.a = a;
+	x.b = b;
+	return x;
+}
+
+int
+compar(Node *n, int reverse)
+{
+	Big lo, hi, x;
+	int op;
+	char xbuf[40], cmpbuf[50];
+	Node *l, *r;
+	Type *lt, *rt;
+
+	/*
+	 * The point of this function is to diagnose comparisons 
+	 * that can never be true or that look misleading because
+	 * of the `usual arithmetic conversions'.  As an example 
+	 * of the latter, if x is a ulong, then if(x <= -1) really means
+	 * if(x <= 0xFFFFFFFF), while if(x <= -1LL) really means
+	 * what it says (but 8c compiles it wrong anyway).
+	 */
+
+	if(reverse){
+		r = n->left;
+		l = n->right;
+		op = comrel[relindex(n->op)];
+	}else{
+		l = n->left;
+		r = n->right;
+		op = n->op;
+	}
+
+	/*
+	 * Skip over left casts to find out the original expression range.
+	 */
+	while(l->op == OCAST)
+		l = l->left;
+	if(l->op == OCONST)
+		return 0;
+	lt = l->type;
+	if(l->op == ONAME && l->sym->type){
+		lt = l->sym->type;
+		if(lt->etype == TARRAY)
+			lt = lt->link;
+	}
+	if(lt == T)
+		return 0;
+	if(lt->etype == TXXX || lt->etype > TUVLONG)
+		return 0;
+	
+	/*
+	 * Skip over the right casts to find the on-screen value.
+	 */
+	if(r->op != OCONST)
+		return 0;
+	while(r->oldop == OCAST && !r->xcast)
+		r = r->left;
+	rt = r->type;
+	if(rt == T)
+		return 0;
+
+	x.b = r->vconst;
+	x.a = 0;
+	if((rt->etype&1) && r->vconst < 0)	/* signed negative */
+		x.a = ~0ULL;
+
+	if((lt->etype&1)==0){
+		/* unsigned */
+		lo = big(0, 0);
+		if(lt->width == 8)
+			hi = big(0, ~0ULL);
+		else
+			hi = big(0, (1LL<<(l->type->width*8))-1);
+	}else{
+		lo = big(~0ULL, -(1LL<<(l->type->width*8-1)));
+		hi = big(0, (1LL<<(l->type->width*8-1))-1);
+	}
+
+	switch(op){
+	case OLT:
+	case OLO:
+	case OGE:
+	case OHS:
+		if(cmp(x, lo) <= 0)
+			goto useless;
+		if(cmp(x, add(hi, 1)) >= 0)
+			goto useless;
+		break;
+	case OLE:
+	case OLS:
+	case OGT:
+	case OHI:
+		if(cmp(x, add(lo, -1)) <= 0)
+			goto useless;
+		if(cmp(x, hi) >= 0)
+			goto useless;
+		break;
+	case OEQ:
+	case ONE:
+		/*
+		 * Don't warn about comparisons if the expression
+		 * is as wide as the value: the compiler-supplied casts
+		 * will make both outcomes possible.
+		 */
+		if(lt->width >= rt->width && debug['w'] < 2)
+			return 0;
+		if(cmp(x, lo) < 0 || cmp(x, hi) > 0)
+			goto useless;
+		break;
+	}
+	return 0;
+
+useless:
+	if((x.a==0 && x.b<=9) || (x.a==~0LL && x.b >= -9ULL))
+		snprint(xbuf, sizeof xbuf, "%lld", x.b);
+	else if(x.a == 0)
+		snprint(xbuf, sizeof xbuf, "%#llux", x.b);
+	else
+		snprint(xbuf, sizeof xbuf, "%#llx", x.b);
+	if(reverse)
+		snprint(cmpbuf, sizeof cmpbuf, "%s %s %T",
+			xbuf, cmps[relindex(n->op)], lt);
+	else
+		snprint(cmpbuf, sizeof cmpbuf, "%T %s %s",
+			lt, cmps[relindex(n->op)], xbuf);
+	warn(n, "useless or misleading comparison: %s", cmpbuf);
+	return 0;
+}
+
diff --git a/src/cmd/cc/com64.c b/src/cmd/cc/com64.c
new file mode 100644
index 0000000..8d6e07d
--- /dev/null
+++ b/src/cmd/cc/com64.c
@@ -0,0 +1,643 @@
+// Inferno utils/cc/com64.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/com64.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+/*
+ * this is machine depend, but it is totally
+ * common on all of the 64-bit symulating machines.
+ */
+
+#define	FNX	100	/* botch -- redefinition */
+
+Node*	nodaddv;
+Node*	nodsubv;
+Node*	nodmulv;
+Node*	noddivv;
+Node*	noddivvu;
+Node*	nodmodv;
+Node*	nodmodvu;
+Node*	nodlshv;
+Node*	nodrshav;
+Node*	nodrshlv;
+Node*	nodandv;
+Node*	nodorv;
+Node*	nodxorv;
+Node*	nodnegv;
+Node*	nodcomv;
+
+Node*	nodtestv;
+Node*	nodeqv;
+Node*	nodnev;
+Node*	nodlev;
+Node*	nodltv;
+Node*	nodgev;
+Node*	nodgtv;
+Node*	nodhiv;
+Node*	nodhsv;
+Node*	nodlov;
+Node*	nodlsv;
+
+Node*	nodf2v;
+Node*	nodd2v;
+Node*	nodp2v;
+Node*	nodsi2v;
+Node*	nodui2v;
+Node*	nodsl2v;
+Node*	nodul2v;
+Node*	nodsh2v;
+Node*	noduh2v;
+Node*	nodsc2v;
+Node*	noduc2v;
+
+Node*	nodv2f;
+Node*	nodv2d;
+Node*	nodv2ui;
+Node*	nodv2si;
+Node*	nodv2ul;
+Node*	nodv2sl;
+Node*	nodv2uh;
+Node*	nodv2sh;
+Node*	nodv2uc;
+Node*	nodv2sc;
+
+Node*	nodvpp;
+Node*	nodppv;
+Node*	nodvmm;
+Node*	nodmmv;
+
+Node*	nodvasop;
+
+char	etconv[NTYPE];	/* for _vasop */
+Init	initetconv[] =
+{
+	TCHAR,		1,	0,
+	TUCHAR,		2,	0,
+	TSHORT,		3,	0,
+	TUSHORT,	4,	0,
+	TLONG,		5,	0,
+	TULONG,		6,	0,
+	TVLONG,		7,	0,
+	TUVLONG,	8,	0,
+	TINT,		9,	0,
+	TUINT,		10,	0,
+	-1,		0,	0,
+};
+
+Node*
+fvn(char *name, int type)
+{
+	Node *n;
+
+	n = new(ONAME, Z, Z);
+	n->sym = slookup(name);
+	n->sym->sig = SIGINTERN;
+	if(fntypes[type] == 0)
+		fntypes[type] = typ(TFUNC, types[type]);
+	n->type = fntypes[type];
+	n->etype = type;
+	n->class = CGLOBL;
+	n->addable = 10;
+	n->complex = 0;
+	return n;
+}
+
+void
+com64init(void)
+{
+	Init *p;
+
+	nodaddv = fvn("_addv", TVLONG);
+	nodsubv = fvn("_subv", TVLONG);
+	nodmulv = fvn("_mulv", TVLONG);
+	noddivv = fvn("_divv", TVLONG);
+	noddivvu = fvn("_divvu", TVLONG);
+	nodmodv = fvn("_modv", TVLONG);
+	nodmodvu = fvn("_modvu", TVLONG);
+	nodlshv = fvn("_lshv", TVLONG);
+	nodrshav = fvn("_rshav", TVLONG);
+	nodrshlv = fvn("_rshlv", TVLONG);
+	nodandv = fvn("_andv", TVLONG);
+	nodorv = fvn("_orv", TVLONG);
+	nodxorv = fvn("_xorv", TVLONG);
+	nodnegv = fvn("_negv", TVLONG);
+	nodcomv = fvn("_comv", TVLONG);
+
+	nodtestv = fvn("_testv", TLONG);
+	nodeqv = fvn("_eqv", TLONG);
+	nodnev = fvn("_nev", TLONG);
+	nodlev = fvn("_lev", TLONG);
+	nodltv = fvn("_ltv", TLONG);
+	nodgev = fvn("_gev", TLONG);
+	nodgtv = fvn("_gtv", TLONG);
+	nodhiv = fvn("_hiv", TLONG);
+	nodhsv = fvn("_hsv", TLONG);
+	nodlov = fvn("_lov", TLONG);
+	nodlsv = fvn("_lsv", TLONG);
+
+	nodf2v = fvn("_f2v", TVLONG);
+	nodd2v = fvn("_d2v", TVLONG);
+	nodp2v = fvn("_p2v", TVLONG);
+	nodsi2v = fvn("_si2v", TVLONG);
+	nodui2v = fvn("_ui2v", TVLONG);
+	nodsl2v = fvn("_sl2v", TVLONG);
+	nodul2v = fvn("_ul2v", TVLONG);
+	nodsh2v = fvn("_sh2v", TVLONG);
+	noduh2v = fvn("_uh2v", TVLONG);
+	nodsc2v = fvn("_sc2v", TVLONG);
+	noduc2v = fvn("_uc2v", TVLONG);
+
+	nodv2f = fvn("_v2f", TFLOAT);
+	nodv2d = fvn("_v2d", TDOUBLE);
+	nodv2sl = fvn("_v2sl", TLONG);
+	nodv2ul = fvn("_v2ul", TULONG);
+	nodv2si = fvn("_v2si", TINT);
+	nodv2ui = fvn("_v2ui", TUINT);
+	nodv2sh = fvn("_v2sh", TSHORT);
+	nodv2uh = fvn("_v2ul", TUSHORT);
+	nodv2sc = fvn("_v2sc", TCHAR);
+	nodv2uc = fvn("_v2uc", TUCHAR);
+
+	nodvpp = fvn("_vpp", TVLONG);
+	nodppv = fvn("_ppv", TVLONG);
+	nodvmm = fvn("_vmm", TVLONG);
+	nodmmv = fvn("_mmv", TVLONG);
+
+	nodvasop = fvn("_vasop", TVLONG);
+
+	for(p = initetconv; p->code >= 0; p++)
+		etconv[p->code] = p->value;
+}
+
+int
+com64(Node *n)
+{
+	Node *l, *r, *a, *t;
+	int lv, rv;
+
+	if(n->type == 0)
+		return 0;
+
+	l = n->left;
+	r = n->right;
+
+	lv = 0;
+	if(l && l->type && typev[l->type->etype])
+		lv = 1;
+	rv = 0;
+	if(r && r->type && typev[r->type->etype])
+		rv = 1;
+
+	if(lv) {
+		switch(n->op) {
+		case OEQ:
+			a = nodeqv;
+			goto setbool;
+		case ONE:
+			a = nodnev;
+			goto setbool;
+		case OLE:
+			a = nodlev;
+			goto setbool;
+		case OLT:
+			a = nodltv;
+			goto setbool;
+		case OGE:
+			a = nodgev;
+			goto setbool;
+		case OGT:
+			a = nodgtv;
+			goto setbool;
+		case OHI:
+			a = nodhiv;
+			goto setbool;
+		case OHS:
+			a = nodhsv;
+			goto setbool;
+		case OLO:
+			a = nodlov;
+			goto setbool;
+		case OLS:
+			a = nodlsv;
+			goto setbool;
+
+		case OANDAND:
+		case OOROR:
+			if(machcap(n))
+				return 1;
+
+			if(rv) {
+				r = new(OFUNC, nodtestv, r);
+				n->right = r;
+				r->complex = FNX;
+				r->op = OFUNC;
+				r->type = types[TLONG];
+			}
+
+		case OCOND:
+		case ONOT:
+			if(machcap(n))
+				return 1;
+
+			l = new(OFUNC, nodtestv, l);
+			n->left = l;
+			l->complex = FNX;
+			l->op = OFUNC;
+			l->type = types[TLONG];
+			n->complex = FNX;
+			return 1;
+		}
+	}
+
+	if(rv) {
+		if(machcap(n))
+			return 1;
+		switch(n->op) {
+		case OANDAND:
+		case OOROR:
+			r = new(OFUNC, nodtestv, r);
+			n->right = r;
+			r->complex = FNX;
+			r->op = OFUNC;
+			r->type = types[TLONG];
+			return 1;
+		}
+	}
+
+	if(typev[n->type->etype]) {
+		if(machcap(n))
+			return 1;
+		switch(n->op) {
+		default:
+			diag(n, "unknown vlong %O", n->op);
+		case OFUNC:
+			n->complex = FNX;
+		case ORETURN:
+		case OAS:
+		case OIND:
+			return 1;
+		case OADD:
+			a = nodaddv;
+			goto setbop;
+		case OSUB:
+			a = nodsubv;
+			goto setbop;
+		case OMUL:
+		case OLMUL:
+			a = nodmulv;
+			goto setbop;
+		case ODIV:
+			a = noddivv;
+			goto setbop;
+		case OLDIV:
+			a = noddivvu;
+			goto setbop;
+		case OMOD:
+			a = nodmodv;
+			goto setbop;
+		case OLMOD:
+			a = nodmodvu;
+			goto setbop;
+		case OASHL:
+			a = nodlshv;
+			goto setbop;
+		case OASHR:
+			a = nodrshav;
+			goto setbop;
+		case OLSHR:
+			a = nodrshlv;
+			goto setbop;
+		case OAND:
+			a = nodandv;
+			goto setbop;
+		case OOR:
+			a = nodorv;
+			goto setbop;
+		case OXOR:
+			a = nodxorv;
+			goto setbop;
+		case OPOSTINC:
+			a = nodvpp;
+			goto setvinc;
+		case OPOSTDEC:
+			a = nodvmm;
+			goto setvinc;
+		case OPREINC:
+			a = nodppv;
+			goto setvinc;
+		case OPREDEC:
+			a = nodmmv;
+			goto setvinc;
+		case ONEG:
+			a = nodnegv;
+			goto setfnx;
+		case OCOM:
+			a = nodcomv;
+			goto setfnx;
+		case OCAST:
+			switch(l->type->etype) {
+			case TCHAR:
+				a = nodsc2v;
+				goto setfnxl;
+			case TUCHAR:
+				a = noduc2v;
+				goto setfnxl;
+			case TSHORT:
+				a = nodsh2v;
+				goto setfnxl;
+			case TUSHORT:
+				a = noduh2v;
+				goto setfnxl;
+			case TINT:
+				a = nodsi2v;
+				goto setfnx;
+			case TUINT:
+				a = nodui2v;
+				goto setfnx;
+			case TLONG:
+				a = nodsl2v;
+				goto setfnx;
+			case TULONG:
+				a = nodul2v;
+				goto setfnx;
+			case TFLOAT:
+				a = nodf2v;
+				goto setfnx;
+			case TDOUBLE:
+				a = nodd2v;
+				goto setfnx;
+			case TIND:
+				a = nodp2v;
+				goto setfnx;
+			}
+			diag(n, "unknown %T->vlong cast", l->type);
+			return 1;
+		case OASADD:
+			a = nodaddv;
+			goto setasop;
+		case OASSUB:
+			a = nodsubv;
+			goto setasop;
+		case OASMUL:
+		case OASLMUL:
+			a = nodmulv;
+			goto setasop;
+		case OASDIV:
+			a = noddivv;
+			goto setasop;
+		case OASLDIV:
+			a = noddivvu;
+			goto setasop;
+		case OASMOD:
+			a = nodmodv;
+			goto setasop;
+		case OASLMOD:
+			a = nodmodvu;
+			goto setasop;
+		case OASASHL:
+			a = nodlshv;
+			goto setasop;
+		case OASASHR:
+			a = nodrshav;
+			goto setasop;
+		case OASLSHR:
+			a = nodrshlv;
+			goto setasop;
+		case OASAND:
+			a = nodandv;
+			goto setasop;
+		case OASOR:
+			a = nodorv;
+			goto setasop;
+		case OASXOR:
+			a = nodxorv;
+			goto setasop;
+		}
+	}
+
+	if(typefd[n->type->etype] && l && l->op == OFUNC) {
+		switch(n->op) {
+		case OASADD:
+		case OASSUB:
+		case OASMUL:
+		case OASLMUL:
+		case OASDIV:
+		case OASLDIV:
+		case OASMOD:
+		case OASLMOD:
+		case OASASHL:
+		case OASASHR:
+		case OASLSHR:
+		case OASAND:
+		case OASOR:
+		case OASXOR:
+			if(l->right && typev[l->right->etype]) {
+				diag(n, "sorry float <asop> vlong not implemented\n");
+			}
+		}
+	}
+
+	if(n->op == OCAST) {
+		if(l->type && typev[l->type->etype]) {
+			if(machcap(n))
+				return 1;
+			switch(n->type->etype) {
+			case TDOUBLE:
+				a = nodv2d;
+				goto setfnx;
+			case TFLOAT:
+				a = nodv2f;
+				goto setfnx;
+			case TLONG:
+				a = nodv2sl;
+				goto setfnx;
+			case TULONG:
+				a = nodv2ul;
+				goto setfnx;
+			case TINT:
+				a = nodv2si;
+				goto setfnx;
+			case TUINT:
+				a = nodv2ui;
+				goto setfnx;
+			case TSHORT:
+				a = nodv2sh;
+				goto setfnx;
+			case TUSHORT:
+				a = nodv2uh;
+				goto setfnx;
+			case TCHAR:
+				a = nodv2sc;
+				goto setfnx;
+			case TUCHAR:
+				a = nodv2uc;
+				goto setfnx;
+			case TIND:	// small pun here
+				a = nodv2ul;
+				goto setfnx;
+			}
+			diag(n, "unknown vlong->%T cast", n->type);
+			return 1;
+		}
+	}
+
+	return 0;
+
+setbop:
+	n->left = a;
+	n->right = new(OLIST, l, r);
+	n->complex = FNX;
+	n->op = OFUNC;
+	return 1;
+
+setfnxl:
+	l = new(OCAST, l, 0);
+	l->type = types[TLONG];
+	l->complex = l->left->complex;
+
+setfnx:
+	n->left = a;
+	n->right = l;
+	n->complex = FNX;
+	n->op = OFUNC;
+	return 1;
+
+setvinc:
+	n->left = a;
+	l = new(OADDR, l, Z);
+	l->type = typ(TIND, l->left->type);
+	n->right = new(OLIST, l, r);
+	n->complex = FNX;
+	n->op = OFUNC;
+	return 1;
+
+setbool:
+	if(machcap(n))
+		return 1;
+	n->left = a;
+	n->right = new(OLIST, l, r);
+	n->complex = FNX;
+	n->op = OFUNC;
+	n->type = types[TLONG];
+	return 1;
+
+setasop:
+	if(l->op == OFUNC) {
+		l = l->right;
+		goto setasop;
+	}
+
+	t = new(OCONST, 0, 0);
+	t->vconst = etconv[l->type->etype];
+	t->type = types[TLONG];
+	t->addable = 20;
+	r = new(OLIST, t, r);
+
+	t = new(OADDR, a, 0);
+	t->type = typ(TIND, a->type);
+	r = new(OLIST, t, r);
+
+	t = new(OADDR, l, 0);
+	t->type = typ(TIND, l->type);
+	r = new(OLIST, t, r);
+
+	n->left = nodvasop;
+	n->right = r;
+	n->complex = FNX;
+	n->op = OFUNC;
+
+	return 1;
+}
+
+void
+bool64(Node *n)
+{
+	Node *n1;
+
+	if(machcap(Z))
+		return;
+	if(typev[n->type->etype]) {
+		n1 = new(OXXX, 0, 0);
+		*n1 = *n;
+
+		n->right = n1;
+		n->left = nodtestv;
+		n->complex = FNX;
+		n->addable = 0;
+		n->op = OFUNC;
+		n->type = types[TLONG];
+	}
+}
+
+/*
+ * more machine depend stuff.
+ * this is common for 8,16,32,64 bit machines.
+ * this is common for ieee machines.
+ */
+double
+convvtof(vlong v)
+{
+	double d;
+
+	d = v;		/* BOTCH */
+	return d;
+}
+
+vlong
+convftov(double d)
+{
+	vlong v;
+
+
+	v = d;		/* BOTCH */
+	return v;
+}
+
+double
+convftox(double d, int et)
+{
+
+	if(!typefd[et])
+		diag(Z, "bad type in castftox %s", tnames[et]);
+	return d;
+}
+
+vlong
+convvtox(vlong c, int et)
+{
+	int n;
+
+	n = 8 * ewidth[et];
+	c &= MASK(n);
+	if(!typeu[et])
+		if(c & SIGN(n))
+			c |= ~MASK(n);
+	return c;
+}
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
new file mode 100644
index 0000000..f44c340
--- /dev/null
+++ b/src/cmd/cc/dcl.c
@@ -0,0 +1,1664 @@
+// Inferno utils/cc/dcl.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/dcl.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+Node*
+dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n)
+{
+	Sym *s;
+	Node *n1;
+	long v;
+
+	nearln = lineno;
+	lastfield = 0;
+
+loop:
+	if(n != Z)
+	switch(n->op) {
+	default:
+		diag(n, "unknown declarator: %O", n->op);
+		break;
+
+	case OARRAY:
+		t = typ(TARRAY, t);
+		t->width = 0;
+		n1 = n->right;
+		n = n->left;
+		if(n1 != Z) {
+			complex(n1);
+			v = -1;
+			if(n1->op == OCONST)
+				v = n1->vconst;
+			if(v <= 0) {
+				diag(n, "array size must be a positive constant");
+				v = 1;
+			}
+			t->width = v * t->link->width;
+		}
+		goto loop;
+
+	case OIND:
+		t = typ(TIND, t);
+		t->garb = n->garb;
+		n = n->left;
+		goto loop;
+
+	case OFUNC:
+		t = typ(TFUNC, t);
+		t->down = fnproto(n);
+		n = n->left;
+		goto loop;
+
+	case OBIT:
+		n1 = n->right;
+		complex(n1);
+		lastfield = -1;
+		if(n1->op == OCONST)
+			lastfield = n1->vconst;
+		if(lastfield < 0) {
+			diag(n, "field width must be non-negative constant");
+			lastfield = 1;
+		}
+		if(lastfield == 0) {
+			lastbit = 0;
+			firstbit = 1;
+			if(n->left != Z) {
+				diag(n, "zero width named field");
+				lastfield = 1;
+			}
+		}
+		if(!typei[t->etype]) {
+			diag(n, "field type must be int-like");
+			t = types[TINT];
+			lastfield = 1;
+		}
+		if(lastfield > tfield->width*8) {
+			diag(n, "field width larger than field unit");
+			lastfield = 1;
+		}
+		lastbit += lastfield;
+		if(lastbit > tfield->width*8) {
+			lastbit = lastfield;
+			firstbit = 1;
+		}
+		n = n->left;
+		goto loop;
+
+	case ONAME:
+		if(f == NODECL)
+			break;
+		s = n->sym;
+		(*f)(c, t, s);
+		if(s->class == CLOCAL)
+			s = mkstatic(s);
+		firstbit = 0;
+		n->sym = s;
+		n->type = s->type;
+		n->xoffset = s->offset;
+		n->class = s->class;
+		n->etype = TVOID;
+		if(n->type != T)
+			n->etype = n->type->etype;
+		if(debug['d'])
+			dbgdecl(s);
+		acidvar(s);
+		s->varlineno = lineno;
+		break;
+	}
+	lastdcl = t;
+	return n;
+}
+
+Sym*
+mkstatic(Sym *s)
+{
+	Sym *s1;
+
+	if(s->class != CLOCAL)
+		return s;
+	snprint(symb, NSYMB, "%s$%d", s->name, s->block);
+	s1 = lookup();
+	if(s1->class != CSTATIC) {
+		s1->type = s->type;
+		s1->offset = s->offset;
+		s1->block = s->block;
+		s1->class = CSTATIC;
+	}
+	return s1;
+}
+
+/*
+ * make a copy of a typedef
+ * the problem is to split out incomplete
+ * arrays so that it is in the variable
+ * rather than the typedef.
+ */
+Type*
+tcopy(Type *t)
+{
+	Type *tl, *tx;
+	int et;
+
+	if(t == T)
+		return t;
+	et = t->etype;
+	if(typesu[et])
+		return t;
+	tl = tcopy(t->link);
+	if(tl != t->link ||
+	  (et == TARRAY && t->width == 0)) {
+		tx = copytyp(t);
+		tx->link = tl;
+		return tx;
+	}
+	return t;
+}
+
+Node*
+doinit(Sym *s, Type *t, long o, Node *a)
+{
+	Node *n;
+
+	if(t == T)
+		return Z;
+	if(s->class == CEXTERN) {
+		s->class = CGLOBL;
+		if(debug['d'])
+			dbgdecl(s);
+	}
+	if(debug['i']) {
+		print("t = %T; o = %ld; n = %s\n", t, o, s->name);
+		prtree(a, "doinit value");
+	}
+
+
+	n = initlist;
+	if(a->op == OINIT)
+		a = a->left;
+	initlist = a;
+
+	a = init1(s, t, o, 0);
+	if(initlist != Z)
+		diag(initlist, "more initializers than structure: %s",
+			s->name);
+	initlist = n;
+
+	return a;
+}
+
+/*
+ * get next major operator,
+ * dont advance initlist.
+ */
+Node*
+peekinit(void)
+{
+	Node *a;
+
+	a = initlist;
+
+loop:
+	if(a == Z)
+		return a;
+	if(a->op == OLIST) {
+		a = a->left;
+		goto loop;
+	}
+	return a;
+}
+
+/*
+ * consume and return next element on
+ * initlist. expand strings.
+ */
+Node*
+nextinit(void)
+{
+	Node *a, *b, *n;
+
+	a = initlist;
+	n = Z;
+
+	if(a == Z)
+		return a;
+	if(a->op == OLIST) {
+		n = a->right;
+		a = a->left;
+	}
+	if(a->op == OUSED) {
+		a = a->left;
+		b = new(OCONST, Z, Z);
+		b->type = a->type->link;
+		if(a->op == OSTRING) {
+			b->vconst = convvtox(*a->cstring, TCHAR);
+			a->cstring++;
+		}
+		if(a->op == OLSTRING) {
+			b->vconst = convvtox(*a->rstring, TUSHORT);
+			a->rstring++;
+		}
+		a->type->width -= b->type->width;
+		if(a->type->width <= 0)
+			initlist = n;
+		return b;
+	}
+	initlist = n;
+	return a;
+}
+
+int
+isstruct(Node *a, Type *t)
+{
+	Node *n;
+
+	switch(a->op) {
+	case ODOTDOT:
+		n = a->left;
+		if(n && n->type && sametype(n->type, t))
+			return 1;
+	case OSTRING:
+	case OLSTRING:
+	case OCONST:
+	case OINIT:
+	case OELEM:
+		return 0;
+	}
+
+	n = new(ODOTDOT, Z, Z);
+	*n = *a;
+
+	/*
+	 * ODOTDOT is a flag for tcom
+	 * a second tcom will not be performed
+	 */
+	a->op = ODOTDOT;
+	a->left = n;
+	a->right = Z;
+
+	if(tcom(n))
+		return 0;
+
+	if(sametype(n->type, t))
+		return 1;
+	return 0;
+}
+
+Node*
+init1(Sym *s, Type *t, long o, int exflag)
+{
+	Node *a, *l, *r, nod;
+	Type *t1;
+	long e, w, so, mw;
+
+	a = peekinit();
+	if(a == Z)
+		return Z;
+
+	if(debug['i']) {
+		print("t = %T; o = %ld; n = %s\n", t, o, s->name);
+		prtree(a, "init1 value");
+	}
+
+	if(exflag && a->op == OINIT)
+		return doinit(s, t, o, nextinit());
+
+	switch(t->etype) {
+	default:
+		diag(Z, "unknown type in initialization: %T to: %s", t, s->name);
+		return Z;
+
+	case TCHAR:
+	case TUCHAR:
+	case TINT:
+	case TUINT:
+	case TSHORT:
+	case TUSHORT:
+	case TLONG:
+	case TULONG:
+	case TVLONG:
+	case TUVLONG:
+	case TFLOAT:
+	case TDOUBLE:
+	case TIND:
+	single:
+		if(a->op == OARRAY || a->op == OELEM)
+			return Z;
+
+		a = nextinit();
+		if(a == Z)
+			return Z;
+
+		if(t->nbits)
+			diag(Z, "cannot initialize bitfields");
+		if(s->class == CAUTO) {
+			l = new(ONAME, Z, Z);
+			l->sym = s;
+			l->type = t;
+			l->etype = TVOID;
+			if(s->type)
+				l->etype = s->type->etype;
+			l->xoffset = s->offset + o;
+			l->class = s->class;
+
+			l = new(OASI, l, a);
+			return l;
+		}
+
+		complex(a);
+		if(a->type == T)
+			return Z;
+
+		if(a->op == OCONST) {
+			if(vconst(a) && t->etype == TIND && a->type && a->type->etype != TIND){
+				diag(a, "initialize pointer to an integer: %s", s->name);
+				return Z;
+			}
+			if(!sametype(a->type, t)) {
+				/* hoop jumping to save malloc */
+				if(nodcast == Z)
+					nodcast = new(OCAST, Z, Z);
+				nod = *nodcast;
+				nod.left = a;
+				nod.type = t;
+				nod.lineno = a->lineno;
+				complex(&nod);
+				if(nod.type)
+					*a = nod;
+			}
+			if(a->op != OCONST) {
+				diag(a, "initializer is not a constant: %s",
+					s->name);
+				return Z;
+			}
+			if(vconst(a) == 0)
+				return Z;
+			goto gext;
+		}
+		if(t->etype == TIND) {
+			while(a->op == OCAST) {
+				warn(a, "CAST in initialization ignored");
+				a = a->left;
+			}
+			if(!sametype(t, a->type)) {
+				diag(a, "initialization of incompatible pointers: %s\n%T and %T",
+					s->name, t, a->type);
+			}
+			if(a->op == OADDR)
+				a = a->left;
+			goto gext;
+		}
+
+		while(a->op == OCAST)
+			a = a->left;
+		if(a->op == OADDR) {
+			warn(a, "initialize pointer to an integer: %s", s->name);
+			a = a->left;
+			goto gext;
+		}
+		diag(a, "initializer is not a constant: %s", s->name);
+		return Z;
+
+	gext:
+		gextern(s, a, o, t->width);
+
+		return Z;
+
+	case TARRAY:
+		w = t->link->width;
+		if(a->op == OSTRING || a->op == OLSTRING)
+		if(typei[t->link->etype]) {
+			/*
+			 * get rid of null if sizes match exactly
+			 */
+			a = nextinit();
+			mw = t->width/w;
+			so = a->type->width/a->type->link->width;
+			if(mw && so > mw) {
+				if(so != mw+1)
+					diag(a, "string initialization larger than array");
+				a->type->width -= a->type->link->width;
+			}
+
+			/*
+			 * arrange strings to be expanded
+			 * inside OINIT braces.
+			 */
+			a = new(OUSED, a, Z);
+			return doinit(s, t, o, a);
+		}
+
+		mw = -w;
+		l = Z;
+		for(e=0;;) {
+			/*
+			 * peek ahead for element initializer
+			 */
+			a = peekinit();
+			if(a == Z)
+				break;
+			if(a->op == OELEM && t->link->etype != TSTRUCT)
+				break;
+			if(a->op == OARRAY) {
+				if(e && exflag)
+					break;
+				a = nextinit();
+				r = a->left;
+				complex(r);
+				if(r->op != OCONST) {
+					diag(r, "initializer subscript must be constant");
+					return Z;
+				}
+				e = r->vconst;
+				if(t->width != 0)
+					if(e < 0 || e*w >= t->width) {
+						diag(a, "initialization index out of range: %ld", e);
+						continue;
+					}
+			}
+
+			so = e*w;
+			if(so > mw)
+				mw = so;
+			if(t->width != 0)
+				if(mw >= t->width)
+					break;
+			r = init1(s, t->link, o+so, 1);
+			l = newlist(l, r);
+			e++;
+		}
+		if(t->width == 0)
+			t->width = mw+w;
+		return l;
+
+	case TUNION:
+	case TSTRUCT:
+		/*
+		 * peek ahead to find type of rhs.
+		 * if its a structure, then treat
+		 * this element as a variable
+		 * rather than an aggregate.
+		 */
+		if(isstruct(a, t))
+			goto single;
+
+		if(t->width <= 0) {
+			diag(Z, "incomplete structure: %s", s->name);
+			return Z;
+		}
+		l = Z;
+
+	again:
+		for(t1 = t->link; t1 != T; t1 = t1->down) {
+			if(a->op == OARRAY && t1->etype != TARRAY)
+				break;
+			if(a->op == OELEM) {
+				if(t1->sym != a->sym)
+					continue;
+				nextinit();
+			}
+			r = init1(s, t1, o+t1->offset, 1);
+			l = newlist(l, r);
+			a = peekinit();
+			if(a == Z)
+				break;
+			if(a->op == OELEM)
+				goto again;
+		}
+		if(a && a->op == OELEM)
+			diag(a, "structure element not found %F", a);
+		return l;
+	}
+}
+
+Node*
+newlist(Node *l, Node *r)
+{
+	if(r == Z)
+		return l;
+	if(l == Z)
+		return r;
+	return new(OLIST, l, r);
+}
+
+void
+suallign(Type *t)
+{
+	Type *l;
+	long o, w;
+
+	o = 0;
+	switch(t->etype) {
+
+	case TSTRUCT:
+		t->offset = 0;
+		w = 0;
+		for(l = t->link; l != T; l = l->down) {
+			if(l->nbits) {
+				if(l->shift <= 0) {
+					l->shift = -l->shift;
+					w = xround(w, tfield->width);
+					o = w;
+					w += tfield->width;
+				}
+				l->offset = o;
+			} else {
+				if(l->width <= 0)
+				if(l->down != T)
+					if(l->sym)
+						diag(Z, "incomplete structure element: %s",
+							l->sym->name);
+					else
+						diag(Z, "incomplete structure element");
+				w = align(w, l, Ael1);
+				l->offset = w;
+				w = align(w, l, Ael2);
+			}
+		}
+		w = align(w, t, Asu2);
+		t->width = w;
+		acidtype(t);
+		pickletype(t);
+		return;
+
+	case TUNION:
+		t->offset = 0;
+		w = 0;
+		for(l = t->link; l != T; l = l->down) {
+			if(l->width <= 0)
+				if(l->sym)
+					diag(Z, "incomplete union element: %s",
+						l->sym->name);
+				else
+					diag(Z, "incomplete union element");
+			l->offset = 0;
+			l->shift = 0;
+			o = align(align(0, l, Ael1), l, Ael2);
+			if(o > w)
+				w = o;
+		}
+		w = align(w, t, Asu2);
+		t->width = w;
+		acidtype(t);
+		pickletype(t);
+		return;
+
+	default:
+		diag(Z, "unknown type in suallign: %T", t);
+		break;
+	}
+}
+
+long
+xround(long v, int w)
+{
+	int r;
+
+	if(w <= 0 || w > 8) {
+		diag(Z, "rounding by %d", w);
+		w = 1;
+	}
+	r = v%w;
+	if(r)
+		v += w-r;
+	return v;
+}
+
+Type*
+ofnproto(Node *n)
+{
+	Type *tl, *tr, *t;
+
+	if(n == Z)
+		return T;
+	switch(n->op) {
+	case OLIST:
+		tl = ofnproto(n->left);
+		tr = ofnproto(n->right);
+		if(tl == T)
+			return tr;
+		tl->down = tr;
+		return tl;
+
+	case ONAME:
+		t = copytyp(n->sym->type);
+		t->down = T;
+		return t;
+	}
+	return T;
+}
+
+#define	ANSIPROTO	1
+#define	OLDPROTO	2
+
+void
+argmark(Node *n, int pass)
+{
+	Type *t;
+
+	autoffset = align(0, thisfn->link, Aarg0);
+	stkoff = 0;
+	for(; n->left != Z; n = n->left) {
+		if(n->op != OFUNC || n->left->op != ONAME)
+			continue;
+		walkparam(n->right, pass);
+		if(pass != 0 && anyproto(n->right) == OLDPROTO) {
+			t = typ(TFUNC, n->left->sym->type->link);
+			t->down = typ(TOLD, T);
+			t->down->down = ofnproto(n->right);
+			tmerge(t, n->left->sym);
+			n->left->sym->type = t;
+		}
+		break;
+	}
+	autoffset = 0;
+	stkoff = 0;
+}
+
+void
+walkparam(Node *n, int pass)
+{
+	Sym *s;
+	Node *n1;
+
+	if(n != Z && n->op == OPROTO && n->left == Z && n->type == types[TVOID])
+		return;
+
+loop:
+	if(n == Z)
+		return;
+	switch(n->op) {
+	default:
+		diag(n, "argument not a name/prototype: %O", n->op);
+		break;
+
+	case OLIST:
+		walkparam(n->left, pass);
+		n = n->right;
+		goto loop;
+
+	case OPROTO:
+		for(n1 = n; n1 != Z; n1=n1->left)
+			if(n1->op == ONAME) {
+				if(pass == 0) {
+					s = n1->sym;
+					push1(s);
+					s->offset = -1;
+					break;
+				}
+				dodecl(pdecl, CPARAM, n->type, n->left);
+				break;
+			}
+		if(n1)
+			break;
+		if(pass == 0) {
+			/*
+			 * extension:
+			 *	allow no name in argument declaration
+			diag(Z, "no name in argument declaration");
+			 */
+			break;
+		}
+		dodecl(NODECL, CPARAM, n->type, n->left);
+		pdecl(CPARAM, lastdcl, S);
+		break;
+
+	case ODOTDOT:
+		break;
+	
+	case ONAME:
+		s = n->sym;
+		if(pass == 0) {
+			push1(s);
+			s->offset = -1;
+			break;
+		}
+		if(s->offset != -1) {
+			if(autoffset == 0) {
+				firstarg = s;
+				firstargtype = s->type;
+			}
+			autoffset = align(autoffset, s->type, Aarg1);
+			s->offset = autoffset;
+			autoffset = align(autoffset, s->type, Aarg2);
+		} else
+			dodecl(pdecl, CXXX, types[TINT], n);
+		break;
+	}
+}
+
+void
+markdcl(void)
+{
+	Decl *d;
+
+	blockno++;
+	d = push();
+	d->val = DMARK;
+	d->offset = autoffset;
+	d->block = autobn;
+	autobn = blockno;
+}
+
+Node*
+revertdcl(void)
+{
+	Decl *d;
+	Sym *s;
+	Node *n, *n1;
+
+	n = Z;
+	for(;;) {
+		d = dclstack;
+		if(d == D) {
+			diag(Z, "pop off dcl stack");
+			break;
+		}
+		dclstack = d->link;
+		s = d->sym;
+		switch(d->val) {
+		case DMARK:
+			autoffset = d->offset;
+			autobn = d->block;
+			return n;
+
+		case DAUTO:
+			if(debug['d'])
+				print("revert1 \"%s\"\n", s->name);
+			if(s->aused == 0) {
+				nearln = s->varlineno;
+				if(s->class == CAUTO)
+					warn(Z, "auto declared and not used: %s", s->name);
+				if(s->class == CPARAM)
+					warn(Z, "param declared and not used: %s", s->name);
+			}
+			if(s->type && (s->type->garb & GVOLATILE)) {
+				n1 = new(ONAME, Z, Z);
+				n1->sym = s;
+				n1->type = s->type;
+				n1->etype = TVOID;
+				if(n1->type != T)
+					n1->etype = n1->type->etype;
+				n1->xoffset = s->offset;
+				n1->class = s->class;
+
+				n1 = new(OADDR, n1, Z);
+				n1 = new(OUSED, n1, Z);
+				if(n == Z)
+					n = n1;
+				else
+					n = new(OLIST, n1, n);
+			}
+			s->type = d->type;
+			s->class = d->class;
+			s->offset = d->offset;
+			s->block = d->block;
+			s->varlineno = d->varlineno;
+			s->aused = d->aused;
+			break;
+
+		case DSUE:
+			if(debug['d'])
+				print("revert2 \"%s\"\n", s->name);
+			s->suetag = d->type;
+			s->sueblock = d->block;
+			break;
+
+		case DLABEL:
+			if(debug['d'])
+				print("revert3 \"%s\"\n", s->name);
+			if(s->label && s->label->addable == 0)
+				warn(s->label, "label declared and not used \"%s\"", s->name);
+			s->label = Z;
+			break;
+		}
+	}
+	return n;
+}
+
+Type*
+fnproto(Node *n)
+{
+	int r;
+
+	r = anyproto(n->right);
+	if(r == 0 || (r & OLDPROTO)) {
+		if(r & ANSIPROTO)
+			diag(n, "mixed ansi/old function declaration: %F", n->left);
+		return T;
+	}
+	return fnproto1(n->right);
+}
+
+int
+anyproto(Node *n)
+{
+	int r;
+
+	r = 0;
+
+loop:
+	if(n == Z)
+		return r;
+	switch(n->op) {
+	case OLIST:
+		r |= anyproto(n->left);
+		n = n->right;
+		goto loop;
+
+	case ODOTDOT:
+	case OPROTO:
+		return r | ANSIPROTO;
+	}
+	return r | OLDPROTO;
+}
+
+Type*
+fnproto1(Node *n)
+{
+	Type *t;
+
+	if(n == Z)
+		return T;
+	switch(n->op) {
+	case OLIST:
+		t = fnproto1(n->left);
+		if(t != T)
+			t->down = fnproto1(n->right);
+		return t;
+
+	case OPROTO:
+		lastdcl = T;
+		dodecl(NODECL, CXXX, n->type, n->left);
+		t = typ(TXXX, T);
+		if(lastdcl != T)
+			*t = *paramconv(lastdcl, 1);
+		return t;
+
+	case ONAME:
+		diag(n, "incomplete argument prototype");
+		return typ(TINT, T);
+
+	case ODOTDOT:
+		return typ(TDOT, T);
+	}
+	diag(n, "unknown op in fnproto");
+	return T;
+}
+
+void
+dbgdecl(Sym *s)
+{
+	print("decl \"%s\": C=%s [B=%d:O=%ld] T=%T\n",
+		s->name, cnames[s->class], s->block, s->offset, s->type);
+}
+
+Decl*
+push(void)
+{
+	Decl *d;
+
+	d = alloc(sizeof(*d));
+	d->link = dclstack;
+	dclstack = d;
+	return d;
+}
+
+Decl*
+push1(Sym *s)
+{
+	Decl *d;
+
+	d = push();
+	d->sym = s;
+	d->val = DAUTO;
+	d->type = s->type;
+	d->class = s->class;
+	d->offset = s->offset;
+	d->block = s->block;
+	d->varlineno = s->varlineno;
+	d->aused = s->aused;
+	return d;
+}
+
+int
+sametype(Type *t1, Type *t2)
+{
+
+	if(t1 == t2)
+		return 1;
+	return rsametype(t1, t2, 5, 1);
+}
+
+int
+rsametype(Type *t1, Type *t2, int n, int f)
+{
+	int et;
+
+	n--;
+	for(;;) {
+		if(t1 == t2)
+			return 1;
+		if(t1 == T || t2 == T)
+			return 0;
+		if(n <= 0)
+			return 1;
+		et = t1->etype;
+		if(et != t2->etype)
+			return 0;
+		if(et == TFUNC) {
+			if(!rsametype(t1->link, t2->link, n, 0))
+				return 0;
+			t1 = t1->down;
+			t2 = t2->down;
+			while(t1 != T && t2 != T) {
+				if(t1->etype == TOLD) {
+					t1 = t1->down;
+					continue;
+				}
+				if(t2->etype == TOLD) {
+					t2 = t2->down;
+					continue;
+				}
+				while(t1 != T || t2 != T) {
+					if(!rsametype(t1, t2, n, 0))
+						return 0;
+					t1 = t1->down;
+					t2 = t2->down;
+				}
+				break;
+			}
+			return 1;
+		}
+		if(et == TARRAY)
+			if(t1->width != t2->width && t1->width != 0 && t2->width != 0)
+				return 0;
+		if(typesu[et]) {
+			if(t1->link == T)
+				snap(t1);
+			if(t2->link == T)
+				snap(t2);
+			t1 = t1->link;
+			t2 = t2->link;
+			for(;;) {
+				if(t1 == t2)
+					return 1;
+				if(!rsametype(t1, t2, n, 0))
+					return 0;
+				t1 = t1->down;
+				t2 = t2->down;
+			}
+		}
+		t1 = t1->link;
+		t2 = t2->link;
+		if((f || !debug['V']) && et == TIND) {
+			if(t1 != T && t1->etype == TVOID)
+				return 1;
+			if(t2 != T && t2->etype == TVOID)
+				return 1;
+		}
+	}
+}
+
+typedef struct Typetab Typetab;
+
+struct Typetab{
+	int n;
+	Type **a;
+};
+
+static int
+sigind(Type *t, Typetab *tt)
+{
+	int n;
+	Type **a, **na, **p, **e;
+
+	n = tt->n;
+	a = tt->a;
+	e = a+n;
+	/* linear search seems ok */
+	for(p = a ; p < e; p++)
+		if(sametype(*p, t))
+			return p-a;
+	if((n&15) == 0){
+		na = malloc((n+16)*sizeof(Type*));
+		memmove(na, a, n*sizeof(Type*));
+		free(a);
+		a = tt->a = na;
+	}
+	a[tt->n++] = t;
+	return -1;
+}
+
+static ulong
+signat(Type *t, Typetab *tt)
+{
+	int i;
+	Type *t1;
+	long s;
+
+	s = 0;
+	for(; t; t=t->link) {
+		s = s*thash1 + thash[t->etype];
+		if(t->garb&GINCOMPLETE)
+			return s;
+		switch(t->etype) {
+		default:
+			return s;
+		case TARRAY:
+			s = s*thash2 + 0;	/* was t->width */
+			break;
+		case TFUNC:
+			for(t1=t->down; t1; t1=t1->down)
+				s = s*thash3 + signat(t1, tt);
+			break;
+		case TSTRUCT:
+		case TUNION:
+			if((i = sigind(t, tt)) >= 0){
+				s = s*thash2 + i;
+				return s;
+			}
+			for(t1=t->link; t1; t1=t1->down)
+				s = s*thash3 + signat(t1, tt);
+			return s;
+		case TIND:
+			break;
+		}
+	}
+	return s;
+}
+
+ulong
+signature(Type *t)
+{
+	ulong s;
+	Typetab tt;
+
+	tt.n = 0;
+	tt.a = nil;
+	s = signat(t, &tt);
+	free(tt.a);
+	return s;
+}
+
+ulong
+sign(Sym *s)
+{
+	ulong v;
+	Type *t;
+
+	if(s->sig == SIGINTERN)
+		return SIGNINTERN;
+	if((t = s->type) == T)
+		return 0;
+	v = signature(t);
+	if(v == 0)
+		v = SIGNINTERN;
+	return v;
+}
+
+void
+snap(Type *t)
+{
+	if(typesu[t->etype])
+	if(t->link == T && t->tag && t->tag->suetag) {
+		t->link = t->tag->suetag->link;
+		t->width = t->tag->suetag->width;
+	}
+}
+
+Type*
+dotag(Sym *s, int et, int bn)
+{
+	Decl *d;
+
+	if(bn != 0 && bn != s->sueblock) {
+		d = push();
+		d->sym = s;
+		d->val = DSUE;
+		d->type = s->suetag;
+		d->block = s->sueblock;
+		s->suetag = T;
+	}
+	if(s->suetag == T) {
+		s->suetag = typ(et, T);
+		s->sueblock = autobn;
+	}
+	if(s->suetag->etype != et)
+		diag(Z, "tag used for more than one type: %s",
+			s->name);
+	if(s->suetag->tag == S)
+		s->suetag->tag = s;
+	return s->suetag;
+}
+
+Node*
+dcllabel(Sym *s, int f)
+{
+	Decl *d, d1;
+	Node *n;
+
+	n = s->label;
+	if(n != Z) {
+		if(f) {
+			if(n->complex)
+				diag(Z, "label reused: %s", s->name);
+			n->complex = 1;	// declared
+		} else
+			n->addable = 1;	// used
+		return n;
+	}
+
+	d = push();
+	d->sym = s;
+	d->val = DLABEL;
+	dclstack = d->link;
+
+	d1 = *firstdcl;
+	*firstdcl = *d;
+	*d = d1;
+
+	firstdcl->link = d;
+	firstdcl = d;
+
+	n = new(OXXX, Z, Z);
+	n->sym = s;
+	n->complex = f;
+	n->addable = !f;
+	s->label = n;
+
+	if(debug['d'])
+		dbgdecl(s);
+	return n;
+}
+
+Type*
+paramconv(Type *t, int f)
+{
+
+	switch(t->etype) {
+	case TUNION:
+	case TSTRUCT:
+		if(t->width <= 0)
+			diag(Z, "incomplete structure: %s", t->tag->name);
+		break;
+
+	case TARRAY:
+		t = typ(TIND, t->link);
+		t->width = types[TIND]->width;
+		break;
+
+	case TFUNC:
+		t = typ(TIND, t);
+		t->width = types[TIND]->width;
+		break;
+
+	case TFLOAT:
+		if(!f)
+			t = types[TDOUBLE];
+		break;
+
+	case TCHAR:
+	case TSHORT:
+		if(!f)
+			t = types[TINT];
+		break;
+
+	case TUCHAR:
+	case TUSHORT:
+		if(!f)
+			t = types[TUINT];
+		break;
+	}
+	return t;
+}
+
+void
+adecl(int c, Type *t, Sym *s)
+{
+
+	if(c == CSTATIC)
+		c = CLOCAL;
+	if(t->etype == TFUNC) {
+		if(c == CXXX)
+			c = CEXTERN;
+		if(c == CLOCAL)
+			c = CSTATIC;
+		if(c == CAUTO || c == CEXREG)
+			diag(Z, "function cannot be %s %s", cnames[c], s->name);
+	}
+	if(c == CXXX)
+		c = CAUTO;
+	if(s) {
+		if(s->class == CSTATIC)
+			if(c == CEXTERN || c == CGLOBL) {
+				warn(Z, "just say static: %s", s->name);
+				c = CSTATIC;
+			}
+		if(s->class == CAUTO || s->class == CPARAM || s->class == CLOCAL)
+		if(s->block == autobn)
+			diag(Z, "auto redeclaration of: %s", s->name);
+		if(c != CPARAM)
+			push1(s);
+		s->block = autobn;
+		s->offset = 0;
+		s->type = t;
+		s->class = c;
+		s->aused = 0;
+	}
+	switch(c) {
+	case CAUTO:
+		autoffset = align(autoffset, t, Aaut3);
+		stkoff = maxround(stkoff, autoffset);
+		s->offset = -autoffset;
+		break;
+
+	case CPARAM:
+		if(autoffset == 0) {
+			firstarg = s;
+			firstargtype = t;
+		}
+		autoffset = align(autoffset, t, Aarg1);
+		if(s)
+			s->offset = autoffset;
+		autoffset = align(autoffset, t, Aarg2);
+		break;
+	}
+}
+
+void
+pdecl(int c, Type *t, Sym *s)
+{
+	if(s && s->offset != -1) {
+		diag(Z, "not a parameter: %s", s->name);
+		return;
+	}
+	t = paramconv(t, c==CPARAM);
+	if(c == CXXX)
+		c = CPARAM;
+	if(c != CPARAM) {
+		diag(Z, "parameter cannot have class: %s", s->name);
+		c = CPARAM;
+	}
+	adecl(c, t, s);
+}
+
+void
+xdecl(int c, Type *t, Sym *s)
+{
+	long o;
+
+	o = 0;
+	switch(c) {
+	case CEXREG:
+		o = exreg(t);
+		if(o == 0)
+			c = CEXTERN;
+		if(s->class == CGLOBL)
+			c = CGLOBL;
+		break;
+
+	case CEXTERN:
+		if(s->class == CGLOBL)
+			c = CGLOBL;
+		break;
+
+	case CXXX:
+		c = CGLOBL;
+		if(s->class == CEXTERN)
+			s->class = CGLOBL;
+		break;
+
+	case CAUTO:
+		diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
+		c = CEXTERN;
+		break;
+
+	case CTYPESTR:
+		if(!typesuv[t->etype]) {
+			diag(Z, "typestr must be struct/union: %s", s->name);
+			break;
+		}
+		dclfunct(t, s);
+		break;
+	}
+
+	if(s->class == CSTATIC)
+		if(c == CEXTERN || c == CGLOBL) {
+			warn(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
+			c = CSTATIC;
+		}
+	if(s->type != T)
+		if(s->class != c || !sametype(t, s->type) || t->etype == TENUM) {
+			diag(Z, "external redeclaration of: %s", s->name);
+			Bprint(&diagbuf, "	%s %T %L\n", cnames[c], t, nearln);
+			Bprint(&diagbuf, "	%s %T %L\n", cnames[s->class], s->type, s->varlineno);
+		}
+	tmerge(t, s);
+	s->type = t;
+	s->class = c;
+	s->block = 0;
+	s->offset = o;
+}
+
+void
+tmerge(Type *t1, Sym *s)
+{
+	Type *ta, *tb, *t2;
+
+	t2 = s->type;
+/*print("merge	%T; %T\n", t1, t2);/**/
+	for(;;) {
+		if(t1 == T || t2 == T || t1 == t2)
+			break;
+		if(t1->etype != t2->etype)
+			break;
+		switch(t1->etype) {
+		case TFUNC:
+			ta = t1->down;
+			tb = t2->down;
+			if(ta == T) {
+				t1->down = tb;
+				break;
+			}
+			if(tb == T)
+				break;
+			while(ta != T && tb != T) {
+				if(ta == tb)
+					break;
+				/* ignore old-style flag */
+				if(ta->etype == TOLD) {
+					ta = ta->down;
+					continue;
+				}
+				if(tb->etype == TOLD) {
+					tb = tb->down;
+					continue;
+				}
+				/* checking terminated by ... */
+				if(ta->etype == TDOT && tb->etype == TDOT) {
+					ta = T;
+					tb = T;
+					break;
+				}
+				if(!sametype(ta, tb))
+					break;
+				ta = ta->down;
+				tb = tb->down;
+			}
+			if(ta != tb)
+				diag(Z, "function inconsistently declared: %s", s->name);
+
+			/* take new-style over old-style */
+			ta = t1->down;
+			tb = t2->down;
+			if(ta != T && ta->etype == TOLD)
+				if(tb != T && tb->etype != TOLD)
+					t1->down = tb;
+			break;
+
+		case TARRAY:
+			/* should we check array size change? */
+			if(t2->width > t1->width)
+				t1->width = t2->width;
+			break;
+
+		case TUNION:
+		case TSTRUCT:
+			return;
+		}
+		t1 = t1->link;
+		t2 = t2->link;
+	}
+}
+
+void
+edecl(int c, Type *t, Sym *s)
+{
+	Type *t1;
+
+	if(s == S) {
+		if(!typesu[t->etype])
+			diag(Z, "unnamed structure element must be struct/union");
+		if(c != CXXX)
+			diag(Z, "unnamed structure element cannot have class");
+	} else
+		if(c != CXXX)
+			diag(Z, "structure element cannot have class: %s", s->name);
+	t1 = t;
+	t = copytyp(t1);
+	t->sym = s;
+	t->down = T;
+	if(lastfield) {
+		t->shift = lastbit - lastfield;
+		t->nbits = lastfield;
+		if(firstbit)
+			t->shift = -t->shift;
+		if(typeu[t->etype])
+			t->etype = tufield->etype;
+		else
+			t->etype = tfield->etype;
+	}
+	if(strf == T)
+		strf = t;
+	else
+		strl->down = t;
+	strl = t;
+}
+
+/*
+ * this routine is very suspect.
+ * ansi requires the enum type to
+ * be represented as an 'int'
+ * this means that 0x81234567
+ * would be illegal. this routine
+ * makes signed and unsigned go
+ * to unsigned.
+ */
+Type*
+maxtype(Type *t1, Type *t2)
+{
+
+	if(t1 == T)
+		return t2;
+	if(t2 == T)
+		return t1;
+	if(t1->etype > t2->etype)
+		return t1;
+	return t2;
+}
+
+void
+doenum(Sym *s, Node *n)
+{
+
+	if(n) {
+		complex(n);
+		if(n->op != OCONST) {
+			diag(n, "enum not a constant: %s", s->name);
+			return;
+		}
+		en.cenum = n->type;
+		en.tenum = maxtype(en.cenum, en.tenum);
+
+		if(!typefd[en.cenum->etype])
+			en.lastenum = n->vconst;
+		else
+			en.floatenum = n->fconst;
+	}
+	if(dclstack)
+		push1(s);
+	xdecl(CXXX, types[TENUM], s);
+
+	if(en.cenum == T) {
+		en.tenum = types[TINT];
+		en.cenum = types[TINT];
+		en.lastenum = 0;
+	}
+	s->tenum = en.cenum;
+
+	if(!typefd[s->tenum->etype]) {
+		s->vconst = convvtox(en.lastenum, s->tenum->etype);
+		en.lastenum++;
+	} else {
+		s->fconst = en.floatenum;
+		en.floatenum++;
+	}
+
+	if(debug['d'])
+		dbgdecl(s);
+	acidvar(s);
+}
+
+void
+symadjust(Sym *s, Node *n, long del)
+{
+
+	switch(n->op) {
+	default:
+		if(n->left)
+			symadjust(s, n->left, del);
+		if(n->right)
+			symadjust(s, n->right, del);
+		return;
+
+	case ONAME:
+		if(n->sym == s)
+			n->xoffset -= del;
+		return;
+
+	case OCONST:
+	case OSTRING:
+	case OLSTRING:
+	case OINDREG:
+	case OREGISTER:
+		return;
+	}
+}
+
+Node*
+contig(Sym *s, Node *n, long v)
+{
+	Node *p, *r, *q, *m;
+	long w;
+	Type *zt;
+
+	if(debug['i']) {
+		print("contig v = %ld; s = %s\n", v, s->name);
+		prtree(n, "doinit value");
+	}
+
+	if(n == Z)
+		goto no;
+	w = s->type->width;
+
+	/*
+	 * nightmare: an automatic array whose size
+	 * increases when it is initialized
+	 */
+	if(v != w) {
+		if(v != 0)
+			diag(n, "automatic adjustable array: %s", s->name);
+		v = s->offset;
+		autoffset = align(autoffset, s->type, Aaut3);
+		s->offset = -autoffset;
+		stkoff = maxround(stkoff, autoffset);
+		symadjust(s, n, v - s->offset);
+	}
+	if(w <= ewidth[TIND])
+		goto no;
+	if(n->op == OAS)
+		diag(Z, "oops in contig");
+/*ZZZ this appears incorrect
+need to check if the list completely covers the data.
+if not, bail
+ */
+	if(n->op == OLIST)
+		goto no;
+	if(n->op == OASI)
+		if(n->left->type)
+		if(n->left->type->width == w)
+			goto no;
+	while(w & (ewidth[TIND]-1))
+		w++;
+/*
+ * insert the following code, where long becomes vlong if pointers are fat
+ *
+	*(long**)&X = (long*)((char*)X + sizeof(X));
+	do {
+		*(long**)&X -= 1;
+		**(long**)&X = 0;
+	} while(*(long**)&X);
+ */
+
+	for(q=n; q->op != ONAME; q=q->left)
+		;
+
+	zt = ewidth[TIND] > ewidth[TLONG]? types[TVLONG]: types[TLONG];
+
+	p = new(ONAME, Z, Z);
+	*p = *q;
+	p->type = typ(TIND, zt);
+	p->xoffset = s->offset;
+
+	r = new(ONAME, Z, Z);
+	*r = *p;
+	r = new(OPOSTDEC, r, Z);
+
+	q = new(ONAME, Z, Z);
+	*q = *p;
+	q = new(OIND, q, Z);
+
+	m = new(OCONST, Z, Z);
+	m->vconst = 0;
+	m->type = zt;
+
+	q = new(OAS, q, m);
+
+	r = new(OLIST, r, q);
+
+	q = new(ONAME, Z, Z);
+	*q = *p;
+	r = new(ODWHILE, q, r);
+
+	q = new(ONAME, Z, Z);
+	*q = *p;
+	q->type = q->type->link;
+	q->xoffset += w;
+	q = new(OADDR, q, 0);
+
+	q = new(OASI, p, q);
+	r = new(OLIST, q, r);
+
+	n = new(OLIST, r, n);
+
+no:
+	return n;
+}
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
new file mode 100644
index 0000000..6a81934
--- /dev/null
+++ b/src/cmd/cc/dpchk.c
@@ -0,0 +1,524 @@
+// Inferno utils/cc/dpchk.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/dpchk.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	"cc.h"
+#include	"y.tab.h"
+
+enum
+{
+	Fnone	= 0,
+	Fl,
+	Fvl,
+	Fignor,
+	Fstar,
+	Fadj,
+
+	Fverb	= 10,
+};
+
+typedef	struct	Tprot	Tprot;
+struct	Tprot
+{
+	Type*	type;
+	Bits	flag;
+	Tprot*	link;
+};
+
+typedef	struct	Tname	Tname;
+struct	Tname
+{
+	char*	name;
+	int	param;
+	Tname*	link;
+};
+
+static	Type*	indchar;
+static	uchar	flagbits[512];
+static	char	fmtbuf[100];
+static	int	lastadj;
+static	int	lastverb;
+static	int	nstar;
+static	Tprot*	tprot;
+static	Tname*	tname;
+
+void
+argflag(int c, int v)
+{
+
+	switch(v) {
+	case Fignor:
+	case Fstar:
+	case Fl:
+	case Fvl:
+		flagbits[c] = v;
+		break;
+	case Fverb:
+		flagbits[c] = lastverb;
+/*print("flag-v %c %d\n", c, lastadj);*/
+		lastverb++;
+		break;
+	case Fadj:
+		flagbits[c] = lastadj;
+/*print("flag-l %c %d\n", c, lastadj);*/
+		lastadj++;
+		break;
+	}
+}
+
+Bits
+getflag(char *s)
+{
+	Bits flag;
+	int f;
+	char *fmt;
+	Rune c;
+
+	fmt = fmtbuf;
+	flag = zbits;
+	nstar = 0;
+	for(;;) {
+		s += chartorune(&c, s);
+		if(c == 0 || c >= nelem(flagbits))
+			break;
+		fmt += runetochar(fmt, &c);
+		f = flagbits[c];
+		switch(f) {
+		case Fnone:
+			argflag(c, Fverb);
+			f = flagbits[c];
+			break;
+		case Fstar:
+			nstar++;
+		case Fignor:
+			continue;
+		case Fl:
+			if(bset(flag, Fl))
+				flag = bor(flag, blsh(Fvl));
+		}
+		flag = bor(flag, blsh(f));
+		if(f >= Fverb)
+			break;
+	}
+	*fmt = 0;
+	return flag;
+}
+
+void
+newprot(Sym *m, Type *t, char *s)
+{
+	Bits flag;
+	Tprot *l;
+
+	if(t == T) {
+		warn(Z, "%s: newprot: type not defined", m->name);
+		return;
+	}
+	flag = getflag(s);
+	for(l=tprot; l; l=l->link)
+		if(beq(flag, l->flag) && sametype(t, l->type))
+			return;
+	l = alloc(sizeof(*l));
+	l->type = t;
+	l->flag = flag;
+	l->link = tprot;
+	tprot = l;
+}
+
+void
+newname(char *s, int p)
+{
+	Tname *l;
+
+	for(l=tname; l; l=l->link)
+		if(strcmp(l->name, s) == 0) {
+			if(l->param != p)
+				yyerror("vargck %s already defined\n", s);
+			return;
+		}
+	l = alloc(sizeof(*l));
+	l->name = s;
+	l->param = p;
+	l->link = tname;
+	tname = l;
+}
+
+void
+arginit(void)
+{
+	int i;
+
+/* debug['F'] = 1;*/
+/* debug['w'] = 1;*/
+
+	lastadj = Fadj;
+	lastverb = Fverb;
+	indchar = typ(TIND, types[TCHAR]);
+
+	memset(flagbits, Fnone, sizeof(flagbits));
+
+	for(i='0'; i<='9'; i++)
+		argflag(i, Fignor);
+	argflag('.', Fignor);
+	argflag('#', Fignor);
+	argflag('u', Fignor);
+	argflag('h', Fignor);
+	argflag('+', Fignor);
+	argflag('-', Fignor);
+
+	argflag('*', Fstar);
+	argflag('l', Fl);
+
+	argflag('o', Fverb);
+	flagbits['x'] = flagbits['o'];
+	flagbits['X'] = flagbits['o'];
+}
+
+void
+pragvararg(void)
+{
+	Sym *s;
+	int n, c;
+	char *t;
+	Rune r;
+	Type *ty;
+
+	if(!debug['F'])
+		goto out;
+	s = getsym();
+	if(s && strcmp(s->name, "argpos") == 0)
+		goto ckpos;
+	if(s && strcmp(s->name, "type") == 0)
+		goto cktype;
+	if(s && strcmp(s->name, "flag") == 0)
+		goto ckflag;
+	yyerror("syntax in #pragma varargck");
+	goto out;
+
+ckpos:
+/*#pragma	varargck	argpos	warn	2*/
+	s = getsym();
+	if(s == S)
+		goto bad;
+	n = getnsn();
+	if(n < 0)
+		goto bad;
+	newname(s->name, n);
+	goto out;
+
+ckflag:
+/*#pragma	varargck	flag	'c'*/
+	c = getnsc();
+	if(c != '\'')
+		goto bad;
+	c = getr();
+	if(c == '\\')
+		c = getr();
+	else if(c == '\'')
+		goto bad;
+	if(c == '\n')
+		goto bad;
+	if(getc() != '\'')
+		goto bad;
+	argflag(c, Fignor);
+	goto out;
+
+cktype:
+/*#pragma	varargck	type	O	int*/
+	c = getnsc();
+	if(c != '"')
+		goto bad;
+	t = fmtbuf;
+	for(;;) {
+		r = getr();
+		if(r == ' ' || r == '\n')
+			goto bad;
+		if(r == '"')
+			break;
+		t += runetochar(t, &r);
+	}
+	*t = 0;
+	t = strdup(fmtbuf);
+	s = getsym();
+	if(s == S)
+		goto bad;
+	ty = s->type;
+	while((c = getnsc()) == '*')
+		ty = typ(TIND, ty);
+	unget(c);
+	newprot(s, ty, t);
+	goto out;
+
+bad:
+	yyerror("syntax in #pragma varargck");
+
+out:
+	while(getnsc() != '\n')
+		;
+}
+
+Node*
+nextarg(Node *n, Node **a)
+{
+	if(n == Z) {
+		*a = Z;
+		return Z;
+	}
+	if(n->op == OLIST) {
+		*a = n->left;
+		return n->right;
+	}
+	*a = n;
+	return Z;
+}
+
+void
+checkargs(Node *nn, char *s, int pos)
+{
+	Node *a, *n;
+	Bits flag;
+	Tprot *l;
+
+	if(!debug['F'])
+		return;
+	n = nn;
+	for(;;) {
+		s = strchr(s, '%');
+		if(s == 0) {
+			nextarg(n, &a);
+			if(a != Z)
+				warn(nn, "more arguments than format %T",
+					a->type);
+			return;
+		}
+		s++;
+		flag = getflag(s);
+		while(nstar > 0) {
+			n = nextarg(n, &a);
+			pos++;
+			nstar--;
+			if(a == Z) {
+				warn(nn, "more format than arguments %s",
+					fmtbuf);
+				return;
+			}
+			if(a->type == T)
+				continue;
+			if(!sametype(types[TINT], a->type) &&
+			   !sametype(types[TUINT], a->type))
+				warn(nn, "format mismatch '*' in %s %T, arg %d",
+					fmtbuf, a->type, pos);
+		}
+		for(l=tprot; l; l=l->link)
+			if(sametype(types[TVOID], l->type)) {
+				if(beq(flag, l->flag)) {
+					s++;
+					goto loop;
+				}
+			}
+
+		n = nextarg(n, &a);
+		pos++;
+		if(a == Z) {
+			warn(nn, "more format than arguments %s",
+				fmtbuf);
+			return;
+		}
+		if(a->type == 0)
+			continue;
+		for(l=tprot; l; l=l->link)
+			if(sametype(a->type, l->type)) {
+/*print("checking %T/%ulx %T/%ulx\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/
+				if(beq(flag, l->flag))
+					goto loop;
+			}
+		warn(nn, "format mismatch %s %T, arg %d", fmtbuf, a->type, pos);
+	loop:;
+	}
+}
+
+void
+dpcheck(Node *n)
+{
+	char *s;
+	Node *a, *b;
+	Tname *l;
+	int i;
+
+	if(n == Z)
+		return;
+	b = n->left;
+	if(b == Z || b->op != ONAME)
+		return;
+	s = b->sym->name;
+	for(l=tname; l; l=l->link)
+		if(strcmp(s, l->name) == 0)
+			break;
+	if(l == 0)
+		return;
+
+	i = l->param;
+	b = n->right;
+	while(i > 0) {
+		b = nextarg(b, &a);
+		i--;
+	}
+	if(a == Z) {
+		warn(n, "cant find format arg");
+		return;
+	}
+	if(!sametype(indchar, a->type)) {
+		warn(n, "format arg type %T", a->type);
+		return;
+	}
+	if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) {
+/*		warn(n, "format arg not constant string");*/
+		return;
+	}
+	s = a->left->cstring;
+	checkargs(b, s, l->param);
+}
+
+void
+pragpack(void)
+{
+	Sym *s;
+
+	packflg = 0;
+	s = getsym();
+	if(s) {
+		packflg = atoi(s->name+1);
+		if(strcmp(s->name, "on") == 0 ||
+		   strcmp(s->name, "yes") == 0)
+			packflg = 1;
+	}
+	while(getnsc() != '\n')
+		;
+	if(debug['f'])
+		if(packflg)
+			print("%4ld: pack %d\n", lineno, packflg);
+		else
+			print("%4ld: pack off\n", lineno);
+}
+
+void
+pragfpround(void)
+{
+	Sym *s;
+
+	fproundflg = 0;
+	s = getsym();
+	if(s) {
+		fproundflg = atoi(s->name+1);
+		if(strcmp(s->name, "on") == 0 ||
+		   strcmp(s->name, "yes") == 0)
+			fproundflg = 1;
+	}
+	while(getnsc() != '\n')
+		;
+	if(debug['f'])
+		if(fproundflg)
+			print("%4ld: fproundflg %d\n", lineno, fproundflg);
+		else
+			print("%4ld: fproundflg off\n", lineno);
+}
+
+void
+pragprofile(void)
+{
+	Sym *s;
+
+	profileflg = 0;
+	s = getsym();
+	if(s) {
+		profileflg = atoi(s->name+1);
+		if(strcmp(s->name, "on") == 0 ||
+		   strcmp(s->name, "yes") == 0)
+			profileflg = 1;
+	}
+	while(getnsc() != '\n')
+		;
+	if(debug['f'])
+		if(profileflg)
+			print("%4ld: profileflg %d\n", lineno, profileflg);
+		else
+			print("%4ld: profileflg off\n", lineno);
+}
+
+void
+pragincomplete(void)
+{
+	Sym *s;
+	Type *t;
+	int istag, w, et;
+
+	istag = 0;
+	s = getsym();
+	if(s == nil)
+		goto out;
+	et = 0;
+	w = s->lexical;
+	if(w == LSTRUCT)
+		et = TSTRUCT;
+	else if(w == LUNION)
+		et = TUNION;
+	if(et != 0){
+		s = getsym();
+		if(s == nil){
+			yyerror("missing struct/union tag in pragma incomplete");
+			goto out;
+		}
+		if(s->lexical != LNAME && s->lexical != LTYPE){
+			yyerror("invalid struct/union tag: %s", s->name);
+			goto out;
+		}
+		dotag(s, et, 0);
+		istag = 1;
+	}else if(strcmp(s->name, "_off_") == 0){
+		debug['T'] = 0;
+		goto out;
+	}else if(strcmp(s->name, "_on_") == 0){
+		debug['T'] = 1;
+		goto out;
+	}
+	t = s->type;
+	if(istag)
+		t = s->suetag;
+	if(t == T)
+		yyerror("unknown type %s in pragma incomplete", s->name);
+	else if(!typesu[t->etype])
+		yyerror("not struct/union type in pragma incomplete: %s", s->name);
+	else
+		t->garb |= GINCOMPLETE;
+out:
+	while(getnsc() != '\n')
+		;
+	if(debug['f'])
+		print("%s incomplete\n", s->name);
+}
diff --git a/src/cmd/cc/funct.c b/src/cmd/cc/funct.c
new file mode 100644
index 0000000..21d8625
--- /dev/null
+++ b/src/cmd/cc/funct.c
@@ -0,0 +1,430 @@
+// Inferno utils/cc/funct.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/funct.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	"cc.h"
+
+typedef	struct	Ftab	Ftab;
+struct	Ftab
+{
+	char	op;
+	char*	name;
+	char	typ;
+};
+typedef	struct	Gtab	Gtab;
+struct	Gtab
+{
+	char	etype;
+	char*	name;
+};
+
+Ftab	ftabinit[OEND];
+Gtab	gtabinit[NTYPE];
+
+int
+isfunct(Node *n)
+{
+	Type *t, *t1;
+	Funct *f;
+	Node *l;
+	Sym *s;
+	int o;
+
+	o = n->op;
+	if(n->left == Z)
+		goto no;
+	t = n->left->type;
+	if(t == T)
+		goto no;
+	f = t->funct;
+
+	switch(o) {
+	case OAS:	// put cast on rhs
+	case OASI:
+	case OASADD:
+	case OASAND:
+	case OASASHL:
+	case OASASHR:
+	case OASDIV:
+	case OASLDIV:
+	case OASLMOD:
+	case OASLMUL:
+	case OASLSHR:
+	case OASMOD:
+	case OASMUL:
+	case OASOR:
+	case OASSUB:
+	case OASXOR:
+		if(n->right == Z)
+			goto no;
+		t1 = n->right->type;
+		if(t1 == T)
+			goto no;
+		if(t1->funct == f)
+			break;
+
+		l = new(OXXX, Z, Z);
+		*l = *n->right;
+
+		n->right->left = l;
+		n->right->right = Z;
+		n->right->type = t;
+		n->right->op = OCAST;
+
+		if(!isfunct(n->right))
+			prtree(n, "isfunc !");
+		break;
+
+	case OCAST:	// t f(T) or T f(t)
+		t1 = n->type;
+		if(t1 == T)
+			goto no;
+		if(f != nil) {
+			s = f->castfr[t1->etype];
+			if(s == S)
+				goto no;
+			n->right = n->left;
+			goto build;
+		}
+		f = t1->funct;
+		if(f != nil) {
+			s = f->castto[t->etype];
+			if(s == S)
+				goto no;
+			n->right = n->left;
+			goto build;
+		}
+		goto no;
+	}
+
+	if(f == nil)
+		goto no;
+	s = f->sym[o];
+	if(s == S)
+		goto no;
+
+	/*
+	 * the answer is yes,
+	 * now we rewrite the node
+	 * and give diagnostics
+	 */
+	switch(o) {
+	default:
+		diag(n, "isfunct op missing %O\n", o);
+		goto bad;
+
+	case OADD:	// T f(T, T)
+	case OAND:
+	case OASHL:
+	case OASHR:
+	case ODIV:
+	case OLDIV:
+	case OLMOD:
+	case OLMUL:
+	case OLSHR:
+	case OMOD:
+	case OMUL:
+	case OOR:
+	case OSUB:
+	case OXOR:
+
+	case OEQ:	// int f(T, T)
+	case OGE:
+	case OGT:
+	case OHI:
+	case OHS:
+	case OLE:
+	case OLO:
+	case OLS:
+	case OLT:
+	case ONE:
+		if(n->right == Z)
+			goto bad;
+		t1 = n->right->type;
+		if(t1 == T)
+			goto bad;
+		if(t1->funct != f)
+			goto bad;
+		n->right = new(OLIST, n->left, n->right);
+		break;
+
+	case OAS:	// structure copies done by the compiler
+	case OASI:
+		goto no;
+
+	case OASADD:	// T f(T*, T)
+	case OASAND:
+	case OASASHL:
+	case OASASHR:
+	case OASDIV:
+	case OASLDIV:
+	case OASLMOD:
+	case OASLMUL:
+	case OASLSHR:
+	case OASMOD:
+	case OASMUL:
+	case OASOR:
+	case OASSUB:
+	case OASXOR:
+		if(n->right == Z)
+			goto bad;
+		t1 = n->right->type;
+		if(t1 == T)
+			goto bad;
+		if(t1->funct != f)
+			goto bad;
+		n->right = new(OLIST, new(OADDR, n->left, Z), n->right);
+		break;
+
+	case OPOS:	// T f(T)
+	case ONEG:
+	case ONOT:
+	case OCOM:
+		n->right = n->left;
+		break;
+
+
+	}
+
+build:
+	l = new(ONAME, Z, Z);
+	l->sym = s;
+	l->type = s->type;
+	l->etype = s->type->etype;
+	l->xoffset = s->offset;
+	l->class = s->class;
+	tcomo(l, 0);
+
+	n->op = OFUNC;
+	n->left = l;
+	n->type = l->type->link;
+	if(tcompat(n, T, l->type, tfunct))
+		goto bad;
+	if(tcoma(n->left, n->right, l->type->down, 1))
+		goto bad;
+	return 1;
+
+no:
+	return 0;
+
+bad:
+	diag(n, "cant rewrite typestr for op %O\n", o);
+	prtree(n, "isfunct");
+	n->type = T;
+	return 1;
+}
+
+void
+dclfunct(Type *t, Sym *s)
+{
+	Funct *f;
+	Node *n;
+	Type *f1, *f2, *f3, *f4;
+	int o, i, c;
+	char str[100];
+
+	if(t->funct)
+		return;
+
+	// recognize generated tag of dorm _%d_
+	if(t->tag == S)
+		goto bad;
+	for(i=0; c = t->tag->name[i]; i++) {
+		if(c == '_') {
+			if(i == 0 || t->tag->name[i+1] == 0)
+				continue;
+			break;
+		}
+		if(c < '0' || c > '9')
+			break;
+	}
+	if(c == 0)
+		goto bad;
+
+	f = alloc(sizeof(*f));
+	for(o=0; o<sizeof(f->sym); o++)
+		f->sym[o] = S;
+
+	t->funct = f;
+
+	f1 = typ(TFUNC, t);
+	f1->down = copytyp(t);
+	f1->down->down = t;
+
+	f2 = typ(TFUNC, types[TINT]);
+	f2->down = copytyp(t);
+	f2->down->down = t;
+
+	f3 = typ(TFUNC, t);
+	f3->down = typ(TIND, t);
+	f3->down->down = t;
+
+	f4 = typ(TFUNC, t);
+	f4->down = t;
+
+	for(i=0;; i++) {
+		o = ftabinit[i].op;
+		if(o == OXXX)
+			break;
+		sprint(str, "%s_%s_", t->tag->name, ftabinit[i].name);
+		n = new(ONAME, Z, Z);
+		n->sym = slookup(str);
+		f->sym[o] = n->sym;
+		switch(ftabinit[i].typ) {
+		default:
+			diag(Z, "dclfunct op missing %d\n", ftabinit[i].typ);
+			break;
+
+		case 1:	// T f(T,T)	+
+			dodecl(xdecl, CEXTERN, f1, n);
+			break;
+
+		case 2:	// int f(T,T)	==
+			dodecl(xdecl, CEXTERN, f2, n);
+			break;
+
+		case 3:	// void f(T*,T)	+=
+			dodecl(xdecl, CEXTERN, f3, n);
+			break;
+
+		case 4:	// T f(T)	~
+			dodecl(xdecl, CEXTERN, f4, n);
+			break;
+		}
+	}
+	for(i=0;; i++) {
+		o = gtabinit[i].etype;
+		if(o == TXXX)
+			break;
+
+		/*
+		 * OCAST types T1 _T2_T1_(T2)
+		 */
+		sprint(str, "_%s%s_", gtabinit[i].name, t->tag->name);
+		n = new(ONAME, Z, Z);
+		n->sym = slookup(str);
+		f->castto[o] = n->sym;
+
+		f1 = typ(TFUNC, t);
+		f1->down = types[o];
+		dodecl(xdecl, CEXTERN, f1, n);
+
+		sprint(str, "%s_%s_", t->tag->name, gtabinit[i].name);
+		n = new(ONAME, Z, Z);
+		n->sym = slookup(str);
+		f->castfr[o] = n->sym;
+
+		f1 = typ(TFUNC, types[o]);
+		f1->down = t;
+		dodecl(xdecl, CEXTERN, f1, n);
+	}
+	return;
+bad:
+	diag(Z, "dclfunct bad %T %s\n", t, s->name);
+}
+
+Gtab	gtabinit[NTYPE] =
+{
+	TCHAR,		"c",
+	TUCHAR,		"uc",
+	TSHORT,		"h",
+	TUSHORT,	"uh",
+	TINT,		"i",
+	TUINT,		"ui",
+	TLONG,		"l",
+	TULONG,		"ul",
+	TVLONG,		"v",
+	TUVLONG,	"uv",
+	TFLOAT,		"f",
+	TDOUBLE,	"d",
+	TXXX
+};
+
+Ftab	ftabinit[OEND] =
+{
+	OADD,		"add",		1,
+	OAND,		"and",		1,
+	OASHL,		"ashl",		1,
+	OASHR,		"ashr",		1,
+	ODIV,		"div",		1,
+	OLDIV,		"ldiv",		1,
+	OLMOD,		"lmod",		1,
+	OLMUL,		"lmul",		1,
+	OLSHR,		"lshr",		1,
+	OMOD,		"mod",		1,
+	OMUL,		"mul",		1,
+	OOR,		"or",		1,
+	OSUB,		"sub",		1,
+	OXOR,		"xor",		1,
+
+	OEQ,		"eq",		2,
+	OGE,		"ge",		2,
+	OGT,		"gt",		2,
+	OHI,		"hi",		2,
+	OHS,		"hs",		2,
+	OLE,		"le",		2,
+	OLO,		"lo",		2,
+	OLS,		"ls",		2,
+	OLT,		"lt",		2,
+	ONE,		"ne",		2,
+
+	OASADD,		"asadd",	3,
+	OASAND,		"asand",	3,
+	OASASHL,	"asashl",	3,
+	OASASHR,	"asashr",	3,
+	OASDIV,		"asdiv",	3,
+	OASLDIV,	"asldiv",	3,
+	OASLMOD,	"aslmod",	3,
+	OASLMUL,	"aslmul",	3,
+	OASLSHR,	"aslshr",	3,
+	OASMOD,		"asmod",	3,
+	OASMUL,		"asmul",	3,
+	OASOR,		"asor",		3,
+	OASSUB,		"assub",	3,
+	OASXOR,		"asxor",	3,
+
+	OPOS,		"pos",		4,
+	ONEG,		"neg",		4,
+	OCOM,		"com",		4,
+	ONOT,		"not",		4,
+
+//	OPOSTDEC,
+//	OPOSTINC,
+//	OPREDEC,
+//	OPREINC,
+
+	OXXX,
+};
+
+//	Node*	nodtestv;
+
+//	Node*	nodvpp;
+//	Node*	nodppv;
+//	Node*	nodvmm;
+//	Node*	nodmmv;
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
new file mode 100644
index 0000000..e3a8e44
--- /dev/null
+++ b/src/cmd/cc/lex.c
@@ -0,0 +1,1542 @@
+// Inferno utils/cc/lex.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/lex.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	"cc.h"
+#include	"y.tab.h"
+
+#ifndef	CPP
+#define	CPP	"/bin/cpp"
+#endif
+
+/*
+ * known debug flags
+ *	-a		acid declaration output
+ *	-A		!B
+ *	-B		non ANSI
+ *	-d		print declarations
+ *	-D name		define
+ *	-F		format specification check
+ *	-i		print initialization
+ *	-I path		include
+ *	-l		generate little-endian code
+ *	-L		print every NAME symbol
+ *	-M		constant multiplication
+ *	-m		print add/sub/mul trees
+ *	-n		print acid to file (%.c=%.acid) (with -a or -aa)
+ *	-o file		output file
+ *	-p		use standard cpp ANSI preprocessor (not on windows)
+ *	-r		print registerization
+ *	-s		print structure offsets (with -a or -aa)
+ *	-S		print assembly
+ *	-t		print type trees
+ *	-V		enable void* conversion warnings
+ *	-v		verbose printing
+ *	-w		print warnings
+ *	-X		abort on error
+ *	-.		Inhibit search for includes in source directory
+ */
+
+void
+main(int argc, char *argv[])
+{
+	char *defs[50], *p;
+	int nproc, nout, status, i, c, ndef;
+
+	memset(debug, 0, sizeof(debug));
+	tinit();
+	cinit();
+	ginit();
+	arginit();
+
+	profileflg = 1;	/* #pragma can turn it off */
+	tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
+	ndef = 0;
+	outfile = 0;
+	include[ninclude++] = ".";
+	ARGBEGIN {
+	default:
+		c = ARGC();
+		if(c >= 0 && c < sizeof(debug))
+			debug[c]++;
+		break;
+
+	case 'l':			/* for little-endian mips */
+		if(thechar != 'v'){
+			print("can only use -l with vc");
+			errorexit();
+		}
+		thechar = '0';
+		thestring = "spim";
+		break;
+
+	case 'o':
+		outfile = ARGF();
+		break;
+
+	case 'D':
+		p = ARGF();
+		if(p) {
+			defs[ndef++] = p;
+			dodefine(p);
+		}
+		break;
+
+	case 'I':
+		p = ARGF();
+		setinclude(p);
+		break;
+	} ARGEND
+	if(argc < 1 && outfile == 0) {
+		print("usage: %cc [-options] files\n", thechar);
+		errorexit();
+	}
+	if(argc > 1 && systemtype(Windows)){
+		print("can't compile multiple files on windows\n");
+		errorexit();
+	}
+	if(argc > 1 && !systemtype(Windows)) {
+		nproc = 1;
+		/*
+		 * if we're writing acid to standard output, don't compile
+		 * concurrently, to avoid interleaving output.
+		 */
+		if(((!debug['a'] && !debug['Z']) || debug['n']) &&
+		    (p = getenv("NPROC")) != nil)
+			nproc = atol(p);	/* */
+		c = 0;
+		nout = 0;
+		for(;;) {
+			while(nout < nproc && argc > 0) {
+				i = myfork();
+				if(i < 0) {
+					i = mywait(&status);
+					if(i < 0) {
+						print("cannot create a process\n");
+						errorexit();
+					}
+					if(status)
+						c++;
+					nout--;
+					continue;
+				}
+				if(i == 0) {
+					fprint(2, "%s:\n", *argv);
+					if (compile(*argv, defs, ndef))
+						errorexit();
+					exits(0);
+				}
+				nout++;
+				argc--;
+				argv++;
+			}
+			i = mywait(&status);
+			if(i < 0) {
+				if(c)
+					errorexit();
+				exits(0);
+			}
+			if(status)
+				c++;
+			nout--;
+		}
+	}
+
+	if(argc == 0)
+		c = compile("stdin", defs, ndef);
+	else
+		c = compile(argv[0], defs, ndef);
+
+	if(c)
+		errorexit();
+	exits(0);
+}
+
+int
+compile(char *file, char **defs, int ndef)
+{
+	char ofile[400], incfile[20];
+	char *p, *av[100], opt[256];
+	int i, c, fd[2];
+	static int first = 1;
+
+	strcpy(ofile, file);
+	p = utfrrune(ofile, pathchar());
+	if(p) {
+		*p++ = 0;
+		if(!debug['.'])
+			include[0] = strdup(ofile);
+	} else
+		p = ofile;
+
+	if(outfile == 0) {
+		outfile = p;
+		if(outfile) {
+			if(p = utfrrune(outfile, '.'))
+				if(p[1] == 'c' && p[2] == 0)
+					p[0] = 0;
+			p = utfrune(outfile, 0);
+			if(debug['a'] && debug['n'])
+				strcat(p, ".acid");
+			else if(debug['Z'] && debug['n'])
+				strcat(p, "_pickle.c");
+			else {
+				p[0] = '.';
+				p[1] = thechar;
+				p[2] = 0;
+			}
+		} else
+			outfile = "/dev/null";
+	}
+
+	if(p = getenv("INCLUDE")) {
+		setinclude(p);
+	} else {
+		if(systemtype(Plan9)) {
+			sprint(incfile, "/%s/include", thestring);
+			setinclude(strdup(incfile));
+			setinclude("/sys/include");
+		}
+	}
+	if (first)
+		Binit(&diagbuf, 1, OWRITE);
+	/*
+	 * if we're writing acid to standard output, don't keep scratching
+	 * outbuf.
+	 */
+	if((debug['a'] || debug['Z']) && !debug['n']) {
+		if (first) {
+			outfile = 0;
+			Binit(&outbuf, dup(1, -1), OWRITE);
+			dup(2, 1);
+		}
+	} else {
+		c = mycreate(outfile, 0664);
+		if(c < 0) {
+			diag(Z, "cannot open %s - %r", outfile);
+			outfile = 0;
+			errorexit();
+		}
+		Binit(&outbuf, c, OWRITE);
+	}
+	newio();
+	first = 0;
+
+	/* Use an ANSI preprocessor */
+	if(debug['p']) {
+		if(systemtype(Windows)) {
+			diag(Z, "-p option not supported on windows");
+			errorexit();
+		}
+		if(myaccess(file) < 0) {
+			diag(Z, "%s does not exist", file);
+			errorexit();
+		}
+		if(mypipe(fd) < 0) {
+			diag(Z, "pipe failed");
+			errorexit();
+		}
+		switch(myfork()) {
+		case -1:
+			diag(Z, "fork failed");
+			errorexit();
+		case 0:
+			close(fd[0]);
+			mydup(fd[1], 1);
+			close(fd[1]);
+			av[0] = CPP;
+			i = 1;
+			if(debug['.']){
+				sprint(opt, "-.");
+				av[i++] = strdup(opt);
+			}
+			if(debug['+']) {
+				sprint(opt, "-+");
+				av[i++] = strdup(opt);
+			}
+			for(c = 0; c < ndef; c++) {
+				sprint(opt, "-D%s", defs[c]);
+				av[i++] = strdup(opt);
+			}
+			for(c = 0; c < ninclude; c++) {
+				sprint(opt, "-I%s", include[c]);
+				av[i++] = strdup(opt);
+			}
+			if(strcmp(file, "stdin") != 0)
+				av[i++] = file;
+			av[i] = 0;
+			if(debug['p'] > 1) {
+				for(c = 0; c < i; c++)
+					fprint(2, "%s ", av[c]);
+				fprint(2, "\n");
+			}
+			myexec(av[0], av);
+			fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
+			errorexit();
+		default:
+			close(fd[1]);
+			newfile(file, fd[0]);
+			break;
+		}
+	} else {
+		if(strcmp(file, "stdin") == 0)
+			newfile(file, 0);
+		else
+			newfile(file, -1);
+	}
+	yyparse();
+	if(!debug['a'] && !debug['Z'])
+		gclean();
+	return nerrors;
+}
+
+void
+errorexit(void)
+{
+	if(outfile)
+		remove(outfile);
+	exits("error");
+}
+
+void
+pushio(void)
+{
+	Io *i;
+
+	i = iostack;
+	if(i == I) {
+		yyerror("botch in pushio");
+		errorexit();
+	}
+	i->p = fi.p;
+	i->c = fi.c;
+}
+
+void
+newio(void)
+{
+	Io *i;
+	static int pushdepth = 0;
+
+	i = iofree;
+	if(i == I) {
+		pushdepth++;
+		if(pushdepth > 1000) {
+			yyerror("macro/io expansion too deep");
+			errorexit();
+		}
+		i = alloc(sizeof(*i));
+	} else
+		iofree = i->link;
+	i->c = 0;
+	i->f = -1;
+	ionext = i;
+}
+
+void
+newfile(char *s, int f)
+{
+	Io *i;
+
+	if(debug['e'])
+		print("%L: %s\n", lineno, s);
+
+	i = ionext;
+	i->link = iostack;
+	iostack = i;
+	i->f = f;
+	if(f < 0)
+		i->f = open(s, 0);
+	if(i->f < 0) {
+		yyerror("%cc: %r: %s", thechar, s);
+		errorexit();
+	}
+	fi.c = 0;
+	linehist(s, 0);
+}
+
+Sym*
+slookup(char *s)
+{
+
+	strcpy(symb, s);
+	return lookup();
+}
+
+Sym*
+lookup(void)
+{
+	Sym *s;
+	ulong h;
+	char *p;
+	int c, n;
+
+	h = 0;
+	for(p=symb; *p;) {
+		h = h * 3;
+		h += *p++;
+	}
+	n = (p - symb) + 1;
+	if((long)h < 0)
+		h = ~h;
+	h %= NHASH;
+	c = symb[0];
+	for(s = hash[h]; s != S; s = s->link) {
+		if(s->name[0] != c)
+			continue;
+		if(strcmp(s->name, symb) == 0)
+			return s;
+	}
+	s = alloc(sizeof(*s));
+	s->name = alloc(n);
+	memmove(s->name, symb, n);
+
+	strcpy(s->name, symb);
+	s->link = hash[h];
+	hash[h] = s;
+	syminit(s);
+
+	return s;
+}
+
+void
+syminit(Sym *s)
+{
+	s->lexical = LNAME;
+	s->block = 0;
+	s->offset = 0;
+	s->type = T;
+	s->suetag = T;
+	s->class = CXXX;
+	s->aused = 0;
+	s->sig = SIGNONE;
+}
+
+#define	EOF	(-1)
+#define	IGN	(-2)
+#define	ESC	(1<<20)
+#define	GETC()	((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
+
+enum
+{
+	Numdec		= 1<<0,
+	Numlong		= 1<<1,
+	Numuns		= 1<<2,
+	Numvlong	= 1<<3,
+	Numflt		= 1<<4,
+};
+
+long
+yylex(void)
+{
+	vlong vv;
+	long c, c1, t;
+	char *cp;
+	Rune rune;
+	Sym *s;
+
+	if(peekc != IGN) {
+		c = peekc;
+		peekc = IGN;
+		goto l1;
+	}
+l0:
+	c = GETC();
+
+l1:
+	if(c >= Runeself) {
+		/*
+		 * extension --
+		 *	all multibyte runes are alpha
+		 */
+		cp = symb;
+		goto talph;
+	}
+	if(isspace(c)) {
+		if(c == '\n')
+			lineno++;
+		goto l0;
+	}
+	if(isalpha(c)) {
+		cp = symb;
+		if(c != 'L')
+			goto talph;
+		*cp++ = c;
+		c = GETC();
+		if(c == '\'') {
+			/* L'x' */
+			c = escchar('\'', 1, 0);
+			if(c == EOF)
+				c = '\'';
+			c1 = escchar('\'', 1, 0);
+			if(c1 != EOF) {
+				yyerror("missing '");
+				peekc = c1;
+			}
+			yylval.vval = convvtox(c, TUSHORT);
+			return LUCONST;
+		}
+		if(c == '"') {
+			goto caselq;
+		}
+		goto talph;
+	}
+	if(isdigit(c))
+		goto tnum;
+	switch(c)
+	{
+
+	case EOF:
+		peekc = EOF;
+		return -1;
+
+	case '_':
+		cp = symb;
+		goto talph;
+
+	case '#':
+		domacro();
+		goto l0;
+
+	case '.':
+		c1 = GETC();
+		if(isdigit(c1)) {
+			cp = symb;
+			*cp++ = c;
+			c = c1;
+			c1 = 0;
+			goto casedot;
+		}
+		break;
+
+	case '"':
+		strcpy(symb, "\"<string>\"");
+		cp = alloc(0);
+		c1 = 0;
+
+		/* "..." */
+		for(;;) {
+			c = escchar('"', 0, 1);
+			if(c == EOF)
+				break;
+			if(c & ESC) {
+				cp = allocn(cp, c1, 1);
+				cp[c1++] = c;
+			} else {
+				rune = c;
+				c = runelen(rune);
+				cp = allocn(cp, c1, c);
+				runetochar(cp+c1, &rune);
+				c1 += c;
+			}
+		}
+		yylval.sval.l = c1;
+		do {
+			cp = allocn(cp, c1, 1);
+			cp[c1++] = 0;
+		} while(c1 & MAXALIGN);
+		yylval.sval.s = cp;
+		return LSTRING;
+
+	caselq:
+		/* L"..." */
+		strcpy(symb, "\"L<string>\"");
+		cp = alloc(0);
+		c1 = 0;
+		for(;;) {
+			c = escchar('"', 1, 0);
+			if(c == EOF)
+				break;
+			cp = allocn(cp, c1, sizeof(ushort));
+			*(ushort*)(cp + c1) = c;
+			c1 += sizeof(ushort);
+		}
+		yylval.sval.l = c1;
+		do {
+			cp = allocn(cp, c1, sizeof(ushort));
+			*(ushort*)(cp + c1) = 0;
+			c1 += sizeof(ushort);
+		} while(c1 & MAXALIGN);
+		yylval.sval.s = cp;
+		return LLSTRING;
+
+	case '\'':
+		/* '.' */
+		c = escchar('\'', 0, 0);
+		if(c == EOF)
+			c = '\'';
+		c1 = escchar('\'', 0, 0);
+		if(c1 != EOF) {
+			yyerror("missing '");
+			peekc = c1;
+		}
+		vv = c;
+		yylval.vval = convvtox(vv, TUCHAR);
+		if(yylval.vval != vv)
+			yyerror("overflow in character constant: 0x%lx", c);
+		else
+		if(c & 0x80){
+			nearln = lineno;
+			warn(Z, "sign-extended character constant");
+		}
+		yylval.vval = convvtox(vv, TCHAR);
+		return LCONST;
+
+	case '/':
+		c1 = GETC();
+		if(c1 == '*') {
+			for(;;) {
+				c = getr();
+				while(c == '*') {
+					c = getr();
+					if(c == '/')
+						goto l0;
+				}
+				if(c == EOF) {
+					yyerror("eof in comment");
+					errorexit();
+				}
+			}
+		}
+		if(c1 == '/') {
+			for(;;) {
+				c = getr();
+				if(c == '\n')
+					goto l0;
+				if(c == EOF) {
+					yyerror("eof in comment");
+					errorexit();
+				}
+			}
+		}
+		if(c1 == '=')
+			return LDVE;
+		break;
+
+	case '*':
+		c1 = GETC();
+		if(c1 == '=')
+			return LMLE;
+		break;
+
+	case '%':
+		c1 = GETC();
+		if(c1 == '=')
+			return LMDE;
+		break;
+
+	case '+':
+		c1 = GETC();
+		if(c1 == '+')
+			return LPP;
+		if(c1 == '=')
+			return LPE;
+		break;
+
+	case '-':
+		c1 = GETC();
+		if(c1 == '-')
+			return LMM;
+		if(c1 == '=')
+			return LME;
+		if(c1 == '>')
+			return LMG;
+		break;
+
+	case '>':
+		c1 = GETC();
+		if(c1 == '>') {
+			c = LRSH;
+			c1 = GETC();
+			if(c1 == '=')
+				return LRSHE;
+			break;
+		}
+		if(c1 == '=')
+			return LGE;
+		break;
+
+	case '<':
+		c1 = GETC();
+		if(c1 == '<') {
+			c = LLSH;
+			c1 = GETC();
+			if(c1 == '=')
+				return LLSHE;
+			break;
+		}
+		if(c1 == '=')
+			return LLE;
+		break;
+
+	case '=':
+		c1 = GETC();
+		if(c1 == '=')
+			return LEQ;
+		break;
+
+	case '!':
+		c1 = GETC();
+		if(c1 == '=')
+			return LNE;
+		break;
+
+	case '&':
+		c1 = GETC();
+		if(c1 == '&')
+			return LANDAND;
+		if(c1 == '=')
+			return LANDE;
+		break;
+
+	case '|':
+		c1 = GETC();
+		if(c1 == '|')
+			return LOROR;
+		if(c1 == '=')
+			return LORE;
+		break;
+
+	case '^':
+		c1 = GETC();
+		if(c1 == '=')
+			return LXORE;
+		break;
+
+	default:
+		return c;
+	}
+	peekc = c1;
+	return c;
+
+talph:
+	/*
+	 * cp is set to symb and some
+	 * prefix has been stored
+	 */
+	for(;;) {
+		if(c >= Runeself) {
+			for(c1=0;;) {
+				cp[c1++] = c;
+				if(fullrune(cp, c1))
+					break;
+				c = GETC();
+			}
+			cp += c1;
+			c = GETC();
+			continue;
+		}
+		if(!isalnum(c) && c != '_')
+			break;
+		*cp++ = c;
+		c = GETC();
+	}
+	*cp = 0;
+	if(debug['L'])
+		print("%L: %s\n", lineno, symb);
+	peekc = c;
+	s = lookup();
+	if(s->macro) {
+		newio();
+		cp = ionext->b;
+		macexpand(s, cp);
+		pushio();
+		ionext->link = iostack;
+		iostack = ionext;
+		fi.p = cp;
+		fi.c = strlen(cp);
+		if(peekc != IGN) {
+			cp[fi.c++] = peekc;
+			cp[fi.c] = 0;
+			peekc = IGN;
+		}
+		goto l0;
+	}
+	yylval.sym = s;
+	if(s->class == CTYPEDEF || s->class == CTYPESTR)
+		return LTYPE;
+	return s->lexical;
+
+tnum:
+	c1 = 0;
+	cp = symb;
+	if(c != '0') {
+		c1 |= Numdec;
+		for(;;) {
+			*cp++ = c;
+			c = GETC();
+			if(isdigit(c))
+				continue;
+			goto dc;
+		}
+	}
+	*cp++ = c;
+	c = GETC();
+	if(c == 'x' || c == 'X')
+		for(;;) {
+			*cp++ = c;
+			c = GETC();
+			if(isdigit(c))
+				continue;
+			if(c >= 'a' && c <= 'f')
+				continue;
+			if(c >= 'A' && c <= 'F')
+				continue;
+			if(cp == symb+2)
+				yyerror("malformed hex constant");
+			goto ncu;
+		}
+	if(c < '0' || c > '7')
+		goto dc;
+	for(;;) {
+		if(c >= '0' && c <= '7') {
+			*cp++ = c;
+			c = GETC();
+			continue;
+		}
+		goto ncu;
+	}
+
+dc:
+	if(c == '.')
+		goto casedot;
+	if(c == 'e' || c == 'E')
+		goto casee;
+
+ncu:
+	if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
+		c = GETC();
+		c1 |= Numuns;
+		goto ncu;
+	}
+	if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
+		c = GETC();
+		if(c1 & Numlong)
+			c1 |= Numvlong;
+		c1 |= Numlong;
+		goto ncu;
+	}
+	*cp = 0;
+	peekc = c;
+	if(mpatov(symb, &yylval.vval))
+		yyerror("overflow in constant");
+
+	vv = yylval.vval;
+	if(c1 & Numvlong) {
+		if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
+			c = LUVLCONST;
+			t = TUVLONG;
+			goto nret;
+		}
+		c = LVLCONST;
+		t = TVLONG;
+		goto nret;
+	}
+	if(c1 & Numlong) {
+		if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
+			c = LULCONST;
+			t = TULONG;
+			goto nret;
+		}
+		c = LLCONST;
+		t = TLONG;
+		goto nret;
+	}
+	if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
+		c = LUCONST;
+		t = TUINT;
+		goto nret;
+	}
+	c = LCONST;
+	t = TINT;
+	goto nret;
+
+nret:
+	yylval.vval = convvtox(vv, t);
+	if(yylval.vval != vv){
+		nearln = lineno;
+		warn(Z, "truncated constant: %T %s", types[t], symb);
+	}
+	return c;
+
+casedot:
+	for(;;) {
+		*cp++ = c;
+		c = GETC();
+		if(!isdigit(c))
+			break;
+	}
+	if(c != 'e' && c != 'E')
+		goto caseout;
+
+casee:
+	*cp++ = 'e';
+	c = GETC();
+	if(c == '+' || c == '-') {
+		*cp++ = c;
+		c = GETC();
+	}
+	if(!isdigit(c))
+		yyerror("malformed fp constant exponent");
+	while(isdigit(c)) {
+		*cp++ = c;
+		c = GETC();
+	}
+
+caseout:
+	if(c == 'L' || c == 'l') {
+		c = GETC();
+		c1 |= Numlong;
+	} else
+	if(c == 'F' || c == 'f') {
+		c = GETC();
+		c1 |= Numflt;
+	}
+	*cp = 0;
+	peekc = c;
+	yylval.dval = strtod(symb, nil);
+	if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) {
+		yyerror("overflow in float constant");
+		yylval.dval = 0;
+	}
+	if(c1 & Numflt)
+		return LFCONST;
+	return LDCONST;
+}
+
+/*
+ * convert a string, s, to vlong in *v
+ * return conversion overflow.
+ * required syntax is [0[x]]d*
+ */
+int
+mpatov(char *s, vlong *v)
+{
+	vlong n, nn;
+	int c;
+
+	n = 0;
+	c = *s;
+	if(c == '0')
+		goto oct;
+	while(c = *s++) {
+		if(c >= '0' && c <= '9')
+			nn = n*10 + c-'0';
+		else
+			goto bad;
+		if(n < 0 && nn >= 0)
+			goto bad;
+		n = nn;
+	}
+	goto out;
+
+oct:
+	s++;
+	c = *s;
+	if(c == 'x' || c == 'X')
+		goto hex;
+	while(c = *s++) {
+		if(c >= '0' || c <= '7')
+			nn = n*8 + c-'0';
+		else
+			goto bad;
+		if(n < 0 && nn >= 0)
+			goto bad;
+		n = nn;
+	}
+	goto out;
+
+hex:
+	s++;
+	while(c = *s++) {
+		if(c >= '0' && c <= '9')
+			c += 0-'0';
+		else
+		if(c >= 'a' && c <= 'f')
+			c += 10-'a';
+		else
+		if(c >= 'A' && c <= 'F')
+			c += 10-'A';
+		else
+			goto bad;
+		nn = n*16 + c;
+		if(n < 0 && nn >= 0)
+			goto bad;
+		n = nn;
+	}
+out:
+	*v = n;
+	return 0;
+
+bad:
+	*v = ~0;
+	return 1;
+}
+
+int
+getc(void)
+{
+	int c;
+
+	if(peekc != IGN) {
+		c = peekc;
+		peekc = IGN;
+	} else
+		c = GETC();
+	if(c == '\n')
+		lineno++;
+	if(c == EOF) {
+		yyerror("End of file");
+		errorexit();
+	}
+	return c;
+}
+
+long
+getr(void)
+{
+	int c, i;
+	char str[UTFmax+1];
+	Rune rune;
+
+
+	c = getc();
+	if(c < Runeself)
+		return c;
+	i = 0;
+	str[i++] = c;
+
+loop:
+	c = getc();
+	str[i++] = c;
+	if(!fullrune(str, i))
+		goto loop;
+	c = chartorune(&rune, str);
+	if(rune == Runeerror && c == 1) {
+		nearln = lineno;
+		diag(Z, "illegal rune in string");
+		for(c=0; c<i; c++)
+			print(" %.2x", *(uchar*)(str+c));
+		print("\n");
+	}
+	return rune;
+}
+
+int
+getnsc(void)
+{
+	int c;
+
+	if(peekc != IGN) {
+		c = peekc;
+		peekc = IGN;
+	} else
+		c = GETC();
+	for(;;) {
+		if(!isspace(c))
+			return c;
+		if(c == '\n') {
+			lineno++;
+			return c;
+		}
+		c = GETC();
+	}
+}
+
+void
+unget(int c)
+{
+
+	peekc = c;
+	if(c == '\n')
+		lineno--;
+}
+
+long
+escchar(long e, int longflg, int escflg)
+{
+	long c, l;
+	int i;
+
+loop:
+	c = getr();
+	if(c == '\n') {
+		yyerror("newline in string");
+		return EOF;
+	}
+	if(c != '\\') {
+		if(c == e)
+			c = EOF;
+		return c;
+	}
+	c = getr();
+	if(c == 'x') {
+		/*
+		 * note this is not ansi,
+		 * supposed to only accept 2 hex
+		 */
+		i = 2;
+		if(longflg)
+			i = 4;
+		l = 0;
+		for(; i>0; i--) {
+			c = getc();
+			if(c >= '0' && c <= '9') {
+				l = l*16 + c-'0';
+				continue;
+			}
+			if(c >= 'a' && c <= 'f') {
+				l = l*16 + c-'a' + 10;
+				continue;
+			}
+			if(c >= 'A' && c <= 'F') {
+				l = l*16 + c-'A' + 10;
+				continue;
+			}
+			unget(c);
+			break;
+		}
+		if(escflg)
+			l |= ESC;
+		return l;
+	}
+	if(c >= '0' && c <= '7') {
+		/*
+		 * note this is not ansi,
+		 * supposed to only accept 3 oct
+		 */
+		i = 2;
+		if(longflg)
+			i = 5;
+		l = c - '0';
+		for(; i>0; i--) {
+			c = getc();
+			if(c >= '0' && c <= '7') {
+				l = l*8 + c-'0';
+				continue;
+			}
+			unget(c);
+		}
+		if(escflg)
+			l |= ESC;
+		return l;
+	}
+	switch(c)
+	{
+	case '\n':	goto loop;
+	case 'n':	return '\n';
+	case 't':	return '\t';
+	case 'b':	return '\b';
+	case 'r':	return '\r';
+	case 'f':	return '\f';
+	case 'a':	return '\a';
+	case 'v':	return '\v';
+	}
+	return c;
+}
+
+struct
+{
+	char	*name;
+	ushort	lexical;
+	ushort	type;
+} itab[] =
+{
+	"auto",		LAUTO,		0,
+	"break",	LBREAK,		0,
+	"case",		LCASE,		0,
+	"char",		LCHAR,		TCHAR,
+	"const",	LCONSTNT,	0,
+	"continue",	LCONTINUE,	0,
+	"default",	LDEFAULT,	0,
+	"do",		LDO,		0,
+	"double",	LDOUBLE,	TDOUBLE,
+	"else",		LELSE,		0,
+	"enum",		LENUM,		0,
+	"extern",	LEXTERN,	0,
+	"float",	LFLOAT,		TFLOAT,
+	"for",		LFOR,		0,
+	"goto",		LGOTO,		0,
+	"if",		LIF,		0,
+	"inline",	LINLINE,	0,
+	"int",		LINT,		TINT,
+	"long",		LLONG,		TLONG,
+	"register",	LREGISTER,	0,
+	"restrict",	LRESTRICT,	0,
+	"return",	LRETURN,	0,
+	"SET",		LSET,		0,
+	"short",	LSHORT,		TSHORT,
+	"signed",	LSIGNED,	0,
+	"signof",	LSIGNOF,	0,
+	"sizeof",	LSIZEOF,	0,
+	"static",	LSTATIC,	0,
+	"struct",	LSTRUCT,	0,
+	"switch",	LSWITCH,	0,
+	"typedef",	LTYPEDEF,	0,
+	"typestr",	LTYPESTR,	0,
+	"union",	LUNION,		0,
+	"unsigned",	LUNSIGNED,	0,
+	"USED",		LUSED,		0,
+	"void",		LVOID,		TVOID,
+	"volatile",	LVOLATILE,	0,
+	"while",	LWHILE,		0,
+	0
+};
+
+void
+cinit(void)
+{
+	Sym *s;
+	int i;
+	Type *t;
+
+	nerrors = 0;
+	lineno = 1;
+	iostack = I;
+	iofree = I;
+	peekc = IGN;
+	nhunk = 0;
+
+	types[TXXX] = T;
+	types[TCHAR] = typ(TCHAR, T);
+	types[TUCHAR] = typ(TUCHAR, T);
+	types[TSHORT] = typ(TSHORT, T);
+	types[TUSHORT] = typ(TUSHORT, T);
+	types[TINT] = typ(TINT, T);
+	types[TUINT] = typ(TUINT, T);
+	types[TLONG] = typ(TLONG, T);
+	types[TULONG] = typ(TULONG, T);
+	types[TVLONG] = typ(TVLONG, T);
+	types[TUVLONG] = typ(TUVLONG, T);
+	types[TFLOAT] = typ(TFLOAT, T);
+	types[TDOUBLE] = typ(TDOUBLE, T);
+	types[TVOID] = typ(TVOID, T);
+	types[TENUM] = typ(TENUM, T);
+	types[TFUNC] = typ(TFUNC, types[TINT]);
+	types[TIND] = typ(TIND, types[TVOID]);
+
+	for(i=0; i<NHASH; i++)
+		hash[i] = S;
+	for(i=0; itab[i].name; i++) {
+		s = slookup(itab[i].name);
+		s->lexical = itab[i].lexical;
+		if(itab[i].type != 0)
+			s->type = types[itab[i].type];
+	}
+	blockno = 0;
+	autobn = 0;
+	autoffset = 0;
+
+	t = typ(TARRAY, types[TCHAR]);
+	t->width = 0;
+	symstring = slookup(".string");
+	symstring->class = CSTATIC;
+	symstring->type = t;
+
+	t = typ(TARRAY, types[TCHAR]);
+	t->width = 0;
+
+	nodproto = new(OPROTO, Z, Z);
+	dclstack = D;
+
+	pathname = allocn(pathname, 0, 100);
+	if(mygetwd(pathname, 99) == 0) {
+		pathname = allocn(pathname, 100, 900);
+		if(mygetwd(pathname, 999) == 0)
+			strcpy(pathname, "/???");
+	}
+
+	fmtinstall('O', Oconv);
+	fmtinstall('T', Tconv);
+	fmtinstall('F', FNconv);
+	fmtinstall('L', Lconv);
+	fmtinstall('Q', Qconv);
+	fmtinstall('|', VBconv);
+}
+
+int
+filbuf(void)
+{
+	Io *i;
+
+loop:
+	i = iostack;
+	if(i == I)
+		return EOF;
+	if(i->f < 0)
+		goto pop;
+	fi.c = read(i->f, i->b, BUFSIZ) - 1;
+	if(fi.c < 0) {
+		close(i->f);
+		linehist(0, 0);
+		goto pop;
+	}
+	fi.p = i->b + 1;
+	return i->b[0] & 0xff;
+
+pop:
+	iostack = i->link;
+	i->link = iofree;
+	iofree = i;
+	i = iostack;
+	if(i == I)
+		return EOF;
+	fi.p = i->p;
+	fi.c = i->c;
+	if(--fi.c < 0)
+		goto loop;
+	return *fi.p++ & 0xff;
+}
+
+int
+Oconv(Fmt *fp)
+{
+	int a;
+
+	a = va_arg(fp->args, int);
+	if(a < OXXX || a > OEND)
+		return fmtprint(fp, "***badO %d***", a);
+
+	return fmtstrcpy(fp, onames[a]);
+}
+
+int
+Lconv(Fmt *fp)
+{
+	char str[STRINGSZ], s[STRINGSZ];
+	Hist *h;
+	struct
+	{
+		Hist*	incl;	/* start of this include file */
+		long	idel;	/* delta line number to apply to include */
+		Hist*	line;	/* start of this #line directive */
+		long	ldel;	/* delta line number to apply to #line */
+	} a[HISTSZ];
+	long l, d;
+	int i, n;
+
+	l = va_arg(fp->args, long);
+	n = 0;
+	for(h = hist; h != H; h = h->link) {
+		if(l < h->line)
+			break;
+		if(h->name) {
+			if(h->offset != 0) {		/* #line directive, not #pragma */
+				if(n > 0 && n < HISTSZ && h->offset >= 0) {
+					a[n-1].line = h;
+					a[n-1].ldel = h->line - h->offset + 1;
+				}
+			} else {
+				if(n < HISTSZ) {	/* beginning of file */
+					a[n].incl = h;
+					a[n].idel = h->line;
+					a[n].line = 0;
+				}
+				n++;
+			}
+			continue;
+		}
+		n--;
+		if(n > 0 && n < HISTSZ) {
+			d = h->line - a[n].incl->line;
+			a[n-1].ldel += d;
+			a[n-1].idel += d;
+		}
+	}
+	if(n > HISTSZ)
+		n = HISTSZ;
+	str[0] = 0;
+	for(i=n-1; i>=0; i--) {
+		if(i != n-1) {
+			if(fp->flags & ~(FmtWidth|FmtPrec))	/* BUG ROB - was f3 */
+				break;
+			strcat(str, " ");
+		}
+		if(a[i].line)
+			snprint(s, STRINGSZ, "%s:%ld[%s:%ld]",
+				a[i].line->name, l-a[i].ldel+1,
+				a[i].incl->name, l-a[i].idel+1);
+		else
+			snprint(s, STRINGSZ, "%s:%ld",
+				a[i].incl->name, l-a[i].idel+1);
+		if(strlen(s)+strlen(str) >= STRINGSZ-10)
+			break;
+		strcat(str, s);
+		l = a[i].incl->line - 1;	/* now print out start of this file */
+	}
+	if(n == 0)
+		strcat(str, "<eof>");
+	return fmtstrcpy(fp, str);
+}
+
+int
+Tconv(Fmt *fp)
+{
+	char str[STRINGSZ+20], s[STRINGSZ+20];
+	Type *t, *t1;
+	int et;
+	long n;
+
+	str[0] = 0;
+	for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
+		et = t->etype;
+		if(str[0])
+			strcat(str, " ");
+		if(t->garb&~GINCOMPLETE) {
+			sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
+			if(strlen(str) + strlen(s) < STRINGSZ)
+				strcat(str, s);
+		}
+		sprint(s, "%s", tnames[et]);
+		if(strlen(str) + strlen(s) < STRINGSZ)
+			strcat(str, s);
+		if(et == TFUNC && (t1 = t->down)) {
+			sprint(s, "(%T", t1);
+			if(strlen(str) + strlen(s) < STRINGSZ)
+				strcat(str, s);
+			while(t1 = t1->down) {
+				sprint(s, ", %T", t1);
+				if(strlen(str) + strlen(s) < STRINGSZ)
+					strcat(str, s);
+			}
+			if(strlen(str) + strlen(s) < STRINGSZ)
+				strcat(str, ")");
+		}
+		if(et == TARRAY) {
+			n = t->width;
+			if(t->link && t->link->width)
+				n /= t->link->width;
+			sprint(s, "[%ld]", n);
+			if(strlen(str) + strlen(s) < STRINGSZ)
+				strcat(str, s);
+		}
+		if(t->nbits) {
+			sprint(s, " %d:%d", t->shift, t->nbits);
+			if(strlen(str) + strlen(s) < STRINGSZ)
+				strcat(str, s);
+		}
+		if(typesu[et]) {
+			if(t->tag) {
+				strcat(str, " ");
+				if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
+					strcat(str, t->tag->name);
+			} else
+				strcat(str, " {}");
+			break;
+		}
+	}
+	return fmtstrcpy(fp, str);
+}
+
+int
+FNconv(Fmt *fp)
+{
+	char *str;
+	Node *n;
+
+	n = va_arg(fp->args, Node*);
+	str = "<indirect>";
+	if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
+		str = n->sym->name;
+	return fmtstrcpy(fp, str);
+}
+
+int
+Qconv(Fmt *fp)
+{
+	char str[STRINGSZ+20], *s;
+	long b;
+	int i;
+
+	str[0] = 0;
+	for(b = va_arg(fp->args, long); b;) {
+		i = bitno(b);
+		if(str[0])
+			strcat(str, " ");
+		s = qnames[i];
+		if(strlen(str) + strlen(s) >= STRINGSZ)
+			break;
+		strcat(str, s);
+		b &= ~(1L << i);
+	}
+	return fmtstrcpy(fp, str);
+}
+
+int
+VBconv(Fmt *fp)
+{
+	char str[STRINGSZ];
+	int i, n, t, pc;
+
+	n = va_arg(fp->args, int);
+	pc = 0;	/* BUG: was printcol */
+	i = 0;
+	while(pc < n) {
+		t = (pc+4) & ~3;
+		if(t <= n) {
+			str[i++] = '\t';
+			pc = t;
+			continue;
+		}
+		str[i++] = ' ';
+		pc++;
+	}
+	str[i] = 0;
+
+	return fmtstrcpy(fp, str);
+}
+
+void
+setinclude(char *p)
+{
+	int i;
+	char *e;
+
+	while(*p != 0) {
+		e = strchr(p, ' ');
+		if(e != 0)
+			*e = '\0';
+
+		for(i=1; i < ninclude; i++)
+			if(strcmp(p, include[i]) == 0)
+				break;
+
+		if(i >= ninclude)
+			include[ninclude++] = p;
+
+		if(ninclude > nelem(include)) {
+			diag(Z, "ninclude too small %d", nelem(include));
+			exits("ninclude");
+		}
+
+		if(e == 0)
+			break;
+		p = e+1;
+	}
+}
diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody
new file mode 100644
index 0000000..f7ba6d0
--- /dev/null
+++ b/src/cmd/cc/lexbody
@@ -0,0 +1,723 @@
+// Inferno utils/cc/lexbody
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/lexbody
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * common code for all the assemblers
+ */
+
+void
+pragpack(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void
+pragvararg(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void
+pragfpround(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void
+pragprofile(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void
+pragincomplete(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void
+gethunk(void)
+{
+	hunk = malloc(NHUNK);
+	memset(hunk, 0, NHUNK);
+	nhunk = NHUNK;
+}
+
+void*
+alloc(long n)
+{
+	void *p;
+
+	while((uintptr)hunk & MAXALIGN) {
+		hunk++;
+		nhunk--;
+	}
+	while(nhunk < n)
+		gethunk();
+	p = hunk;
+	nhunk -= n;
+	hunk += n;
+	return p;
+}
+
+void*
+allocn(void *p, long on, long n)
+{
+	void *q;
+
+	q = (uchar*)p + on;
+	if(q != hunk || nhunk < n) {
+		while(nhunk < on+n)
+			gethunk();
+		memmove(hunk, p, on);
+		p = hunk;
+		hunk += on;
+		nhunk -= on;
+	}
+	hunk += n;
+	nhunk -= n;
+	return p;
+}
+
+void
+setinclude(char *p)
+{
+	int i;
+
+	if(p == 0)
+		return;
+	for(i=1; i < ninclude; i++)
+		if(strcmp(p, include[i]) == 0)
+			return;
+
+	if(ninclude >= nelem(include)) {
+		yyerror("ninclude too small %d", nelem(include));
+		exits("ninclude");
+	}
+	include[ninclude++] = p;
+}
+
+void
+errorexit(void)
+{
+
+	if(outfile)
+		remove(outfile);
+	exits("error");
+}
+
+void
+pushio(void)
+{
+	Io *i;
+
+	i = iostack;
+	if(i == I) {
+		yyerror("botch in pushio");
+		errorexit();
+	}
+	i->p = fi.p;
+	i->c = fi.c;
+}
+
+void
+newio(void)
+{
+	Io *i;
+	static int pushdepth = 0;
+
+	i = iofree;
+	if(i == I) {
+		pushdepth++;
+		if(pushdepth > 1000) {
+			yyerror("macro/io expansion too deep");
+			errorexit();
+		}
+		i = alloc(sizeof(*i));
+	} else
+		iofree = i->link;
+	i->c = 0;
+	i->f = -1;
+	ionext = i;
+}
+
+void
+newfile(char *s, int f)
+{
+	Io *i;
+
+	i = ionext;
+	i->link = iostack;
+	iostack = i;
+	i->f = f;
+	if(f < 0)
+		i->f = open(s, 0);
+	if(i->f < 0) {
+		yyerror("%ca: %r: %s", thechar, s);
+		errorexit();
+	}
+	fi.c = 0;
+	linehist(s, 0);
+}
+
+Sym*
+slookup(char *s)
+{
+
+	strcpy(symb, s);
+	return lookup();
+}
+
+Sym*
+lookup(void)
+{
+	Sym *s;
+	long h;
+	char *p;
+	int c, l;
+
+	h = 0;
+	for(p=symb; c = *p; p++)
+		h = h+h+h + c;
+	l = (p - symb) + 1;
+	if(h < 0)
+		h = ~h;
+	h %= NHASH;
+	c = symb[0];
+	for(s = hash[h]; s != S; s = s->link) {
+		if(s->name[0] != c)
+			continue;
+		if(memcmp(s->name, symb, l) == 0)
+			return s;
+	}
+	s = alloc(sizeof(*s));
+	s->name = alloc(l);
+	memmove(s->name, symb, l);
+
+	s->link = hash[h];
+	hash[h] = s;
+	syminit(s);
+	return s;
+}
+
+long
+yylex(void)
+{
+	int c, c1;
+	char *cp;
+	Sym *s;
+
+	c = peekc;
+	if(c != IGN) {
+		peekc = IGN;
+		goto l1;
+	}
+l0:
+	c = GETC();
+
+l1:
+	if(c == EOF) {
+		peekc = EOF;
+		return -1;
+	}
+	if(isspace(c)) {
+		if(c == '\n') {
+			lineno++;
+			return ';';
+		}
+		goto l0;
+	}
+	if(isalpha(c))
+		goto talph;
+	if(isdigit(c))
+		goto tnum;
+	switch(c)
+	{
+	case '\n':
+		lineno++;
+		return ';';
+
+	case '#':
+		domacro();
+		goto l0;
+
+	case '.':
+		c = GETC();
+		if(isalpha(c)) {
+			cp = symb;
+			*cp++ = '.';
+			goto aloop;
+		}
+		if(isdigit(c)) {
+			cp = symb;
+			*cp++ = '.';
+			goto casedot;
+		}
+		peekc = c;
+		return '.';
+
+	talph:
+	case '_':
+	case '@':
+		cp = symb;
+
+	aloop:
+		*cp++ = c;
+		c = GETC();
+		if(isalpha(c) || isdigit(c) || c == '_' || c == '$')
+			goto aloop;
+		*cp = 0;
+		peekc = c;
+		s = lookup();
+		if(s->macro) {
+			newio();
+			cp = ionext->b;
+			macexpand(s, cp);
+			pushio();
+			ionext->link = iostack;
+			iostack = ionext;
+			fi.p = cp;
+			fi.c = strlen(cp);
+			if(peekc != IGN) {
+				cp[fi.c++] = peekc;
+				cp[fi.c] = 0;
+				peekc = IGN;
+			}
+			goto l0;
+		}
+		if(s->type == 0)
+			s->type = LNAME;
+		if(s->type == LNAME ||
+		   s->type == LVAR ||
+		   s->type == LLAB) {
+			yylval.sym = s;
+			return s->type;
+		}
+		yylval.lval = s->value;
+		return s->type;
+
+	tnum:
+		cp = symb;
+		if(c != '0')
+			goto dc;
+		*cp++ = c;
+		c = GETC();
+		c1 = 3;
+		if(c == 'x' || c == 'X') {
+			c1 = 4;
+			c = GETC();
+		} else
+		if(c < '0' || c > '7')
+			goto dc;
+		yylval.lval = 0;
+		for(;;) {
+			if(c >= '0' && c <= '9') {
+				if(c > '7' && c1 == 3)
+					break;
+				yylval.lval <<= c1;
+				yylval.lval += c - '0';
+				c = GETC();
+				continue;
+			}
+			if(c1 == 3)
+				break;
+			if(c >= 'A' && c <= 'F')
+				c += 'a' - 'A';
+			if(c >= 'a' && c <= 'f') {
+				yylval.lval <<= c1;
+				yylval.lval += c - 'a' + 10;
+				c = GETC();
+				continue;
+			}
+			break;
+		}
+		goto ncu;
+
+	dc:
+		for(;;) {
+			if(!isdigit(c))
+				break;
+			*cp++ = c;
+			c = GETC();
+		}
+		if(c == '.')
+			goto casedot;
+		if(c == 'e' || c == 'E')
+			goto casee;
+		*cp = 0;
+		if(sizeof(yylval.lval) == sizeof(vlong))
+			yylval.lval = strtoll(symb, nil, 10);
+		else
+			yylval.lval = strtol(symb, nil, 10);
+
+	ncu:
+		while(c == 'U' || c == 'u' || c == 'l' || c == 'L')
+			c = GETC();
+		peekc = c;
+		return LCONST;
+
+	casedot:
+		for(;;) {
+			*cp++ = c;
+			c = GETC();
+			if(!isdigit(c))
+				break;
+		}
+		if(c == 'e' || c == 'E')
+			goto casee;
+		goto caseout;
+
+	casee:
+		*cp++ = 'e';
+		c = GETC();
+		if(c == '+' || c == '-') {
+			*cp++ = c;
+			c = GETC();
+		}
+		while(isdigit(c)) {
+			*cp++ = c;
+			c = GETC();
+		}
+
+	caseout:
+		*cp = 0;
+		peekc = c;
+		if(FPCHIP) {
+			yylval.dval = atof(symb);
+			return LFCONST;
+		}
+		yyerror("assembler cannot interpret fp constants");
+		yylval.lval = 1L;
+		return LCONST;
+
+	case '"':
+		memcpy(yylval.sval, nullgen.sval, sizeof(yylval.sval));
+		cp = yylval.sval;
+		c1 = 0;
+		for(;;) {
+			c = escchar('"');
+			if(c == EOF)
+				break;
+			if(c1 < sizeof(yylval.sval))
+				*cp++ = c;
+			c1++;
+		}
+		if(c1 > sizeof(yylval.sval))
+			yyerror("string constant too long");
+		return LSCONST;
+
+	case '\'':
+		c = escchar('\'');
+		if(c == EOF)
+			c = '\'';
+		if(escchar('\'') != EOF)
+			yyerror("missing '");
+		yylval.lval = c;
+		return LCONST;
+
+	case '/':
+		c1 = GETC();
+		if(c1 == '/') {
+			for(;;) {
+				c = GETC();
+				if(c == '\n') {
+					lineno++;
+					goto l1;
+				}
+				if(c == EOF) {
+					yyerror("eof in comment");
+					errorexit();
+				}
+			}
+		}
+		if(c1 == '*') {
+			for(;;) {
+				c = GETC();
+				while(c == '*') {
+					c = GETC();
+					if(c == '/')
+						goto l0;
+				}
+				if(c == EOF) {
+					yyerror("eof in comment");
+					errorexit();
+				}
+				if(c == '\n')
+					lineno++;
+			}
+		}
+		break;
+
+	default:
+		return c;
+	}
+	peekc = c1;
+	return c;
+}
+
+int
+getc(void)
+{
+	int c;
+
+	c = peekc;
+	if(c != IGN) {
+		peekc = IGN;
+		return c;
+	}
+	c = GETC();
+	if(c == '\n')
+		lineno++;
+	if(c == EOF) {
+		yyerror("End of file");
+		errorexit();
+	}
+	return c;
+}
+
+int
+getnsc(void)
+{
+	int c;
+
+	for(;;) {
+		c = getc();
+		if(!isspace(c) || c == '\n')
+			return c;
+	}
+}
+
+void
+unget(int c)
+{
+
+	peekc = c;
+	if(c == '\n')
+		lineno--;
+}
+
+int
+escchar(int e)
+{
+	int c, l;
+
+loop:
+	c = getc();
+	if(c == '\n') {
+		yyerror("newline in string");
+		return EOF;
+	}
+	if(c != '\\') {
+		if(c == e)
+			return EOF;
+		return c;
+	}
+	c = getc();
+	if(c >= '0' && c <= '7') {
+		l = c - '0';
+		c = getc();
+		if(c >= '0' && c <= '7') {
+			l = l*8 + c-'0';
+			c = getc();
+			if(c >= '0' && c <= '7') {
+				l = l*8 + c-'0';
+				return l;
+			}
+		}
+		peekc = c;
+		return l;
+	}
+	switch(c)
+	{
+	case '\n':	goto loop;
+	case 'n':	return '\n';
+	case 't':	return '\t';
+	case 'b':	return '\b';
+	case 'r':	return '\r';
+	case 'f':	return '\f';
+	case 'a':	return 0x07;
+	case 'v':	return 0x0b;
+	case 'z':	return 0x00;
+	}
+	return c;
+}
+
+void
+pinit(char *f)
+{
+	int i;
+	Sym *s;
+
+	lineno = 1;
+	newio();
+	newfile(f, -1);
+	pc = 0;
+	peekc = IGN;
+	sym = 1;
+	for(i=0; i<NSYM; i++) {
+		h[i].type = 0;
+		h[i].sym = S;
+	}
+	for(i=0; i<NHASH; i++)
+		for(s = hash[i]; s != S; s = s->link)
+			s->macro = 0;
+}
+
+int
+filbuf(void)
+{
+	Io *i;
+
+loop:
+	i = iostack;
+	if(i == I)
+		return EOF;
+	if(i->f < 0)
+		goto pop;
+	fi.c = read(i->f, i->b, BUFSIZ) - 1;
+	if(fi.c < 0) {
+		close(i->f);
+		linehist(0, 0);
+		goto pop;
+	}
+	fi.p = i->b + 1;
+	return i->b[0];
+
+pop:
+	iostack = i->link;
+	i->link = iofree;
+	iofree = i;
+	i = iostack;
+	if(i == I)
+		return EOF;
+	fi.p = i->p;
+	fi.c = i->c;
+	if(--fi.c < 0)
+		goto loop;
+	return *fi.p++;
+}
+
+void
+yyerror(char *a, ...)
+{
+	char buf[200];
+	va_list arg;
+
+	/*
+	 * hack to intercept message from yaccpar
+	 */
+	if(strcmp(a, "syntax error") == 0) {
+		yyerror("syntax error, last name: %s", symb);
+		return;
+	}
+	prfile(lineno);
+	va_start(arg, a);
+	vseprint(buf, buf+sizeof(buf), a, arg);
+	va_end(arg);
+	print("%s\n", buf);
+	nerrors++;
+	if(nerrors > 10) {
+		print("too many errors\n");
+		errorexit();
+	}
+}
+
+void
+prfile(long l)
+{
+	int i, n;
+	Hist a[HISTSZ], *h;
+	long d;
+
+	n = 0;
+	for(h = hist; h != H; h = h->link) {
+		if(l < h->line)
+			break;
+		if(h->name) {
+			if(h->offset == 0) {
+				if(n >= 0 && n < HISTSZ)
+					a[n] = *h;
+				n++;
+				continue;
+			}
+			if(n > 0 && n < HISTSZ)
+				if(a[n-1].offset == 0) {
+					a[n] = *h;
+					n++;
+				} else
+					a[n-1] = *h;
+			continue;
+		}
+		n--;
+		if(n >= 0 && n < HISTSZ) {
+			d = h->line - a[n].line;
+			for(i=0; i<n; i++)
+				a[i].line += d;
+		}
+	}
+	if(n > HISTSZ)
+		n = HISTSZ;
+	for(i=0; i<n; i++)
+		print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+	double fr, ho, f;
+	int exp;
+
+	if(native < 0) {
+		ieeedtod(ieee, -native);
+		ieee->h |= 0x80000000L;
+		return;
+	}
+	if(native == 0) {
+		ieee->l = 0;
+		ieee->h = 0;
+		return;
+	}
+	fr = frexp(native, &exp);
+	f = 2097152L;		/* shouldnt use fp constants here */
+	fr = modf(fr*f, &ho);
+	ieee->h = ho;
+	ieee->h &= 0xfffffL;
+	ieee->h |= (exp+1022L) << 20;
+	f = 65536L;
+	fr = modf(fr*f, &ho);
+	ieee->l = ho;
+	ieee->l <<= 16;
+	ieee->l |= (long)(fr*f);
+}
diff --git a/src/cmd/cc/mac.c b/src/cmd/cc/mac.c
new file mode 100644
index 0000000..c08cd9c
--- /dev/null
+++ b/src/cmd/cc/mac.c
@@ -0,0 +1,33 @@
+// Inferno utils/cc/mac.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/mac.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	"cc.h"
+
+#include	"macbody"
diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody
new file mode 100644
index 0000000..9d309c1
--- /dev/null
+++ b/src/cmd/cc/macbody
@@ -0,0 +1,842 @@
+// Inferno utils/cc/macbody
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#define VARMAC 0x80
+
+long
+getnsn(void)
+{
+	long n;
+	int c;
+
+	c = getnsc();
+	if(c < '0' || c > '9')
+		return -1;
+	n = 0;
+	while(c >= '0' && c <= '9') {
+		n = n*10 + c-'0';
+		c = getc();
+	}
+	unget(c);
+	return n;
+}
+
+Sym*
+getsym(void)
+{
+	int c;
+	char *cp;
+
+	c = getnsc();
+	if(!isalpha(c) && c != '_') {
+		unget(c);
+		return S;
+	}
+	for(cp = symb;;) {
+		if(cp <= symb+NSYMB-4)
+			*cp++ = c;
+		c = getc();
+		if(isalnum(c) || c == '_')
+			continue;
+		unget(c);
+		break;
+	}
+	*cp = 0;
+	if(cp > symb+NSYMB-4)
+		yyerror("symbol too large: %s", symb);
+	return lookup();
+}
+
+Sym*
+getsymdots(int *dots)
+{
+	int c;
+	Sym *s;
+
+	s = getsym();
+	if(s != S)
+		return s;
+
+	c = getnsc();
+	if(c != '.'){
+		unget(c);
+		return S;
+	}
+	if(getc() != '.' || getc() != '.')
+		yyerror("bad dots in macro");
+	*dots = 1;
+	return slookup("__VA_ARGS__");
+}
+
+int
+getcom(void)
+{
+	int c;
+
+	for(;;) {
+		c = getnsc();
+		if(c != '/')
+			break;
+		c = getc();
+		if(c == '/') {
+			while(c != '\n')
+				c = getc();
+			break;
+		}
+		if(c != '*')
+			break;
+		c = getc();
+		for(;;) {
+			if(c == '*') {
+				c = getc();
+				if(c != '/')
+					continue;
+				c = getc();
+				break;
+			}
+			if(c == '\n') {
+				yyerror("comment across newline");
+				break;
+			}
+			c = getc();
+		}
+		if(c == '\n')
+			break;
+	}
+	return c;
+}
+
+void
+dodefine(char *cp)
+{
+	Sym *s;
+	char *p;
+	long l;
+
+	strcpy(symb, cp);
+	p = strchr(symb, '=');
+	if(p) {
+		*p++ = 0;
+		s = lookup();
+		l = strlen(p) + 2;	/* +1 null, +1 nargs */
+		s->macro = alloc(l);
+		strcpy(s->macro+1, p);
+	} else {
+		s = lookup();
+		s->macro = "\0001";	/* \000 is nargs */
+	}
+	if(debug['m'])
+		print("#define (-D) %s %s\n", s->name, s->macro+1);
+}
+
+struct
+{
+	char	*macname;
+	void	(*macf)(void);
+} mactab[] =
+{
+	"ifdef",	0,	/* macif(0) */
+	"ifndef",	0,	/* macif(1) */
+	"else",		0,	/* macif(2) */
+
+	"line",		maclin,
+	"define",	macdef,
+	"include",	macinc,
+	"undef",	macund,
+
+	"pragma",	macprag,
+	"endif",	macend,
+	0
+};
+
+void
+domacro(void)
+{
+	int i;
+	Sym *s;
+
+	s = getsym();
+	if(s == S)
+		s = slookup("endif");
+	for(i=0; mactab[i].macname; i++)
+		if(strcmp(s->name, mactab[i].macname) == 0) {
+			if(mactab[i].macf)
+				(*mactab[i].macf)();
+			else
+				macif(i);
+			return;
+		}
+	yyerror("unknown #: %s", s->name);
+	macend();
+}
+
+void
+macund(void)
+{
+	Sym *s;
+
+	s = getsym();
+	macend();
+	if(s == S) {
+		yyerror("syntax in #undef");
+		return;
+	}
+	s->macro = 0;
+}
+
+#define	NARG	25
+void
+macdef(void)
+{
+	Sym *s, *a;
+	char *args[NARG], *np, *base;
+	int n, i, c, len, dots;
+	int ischr;
+
+	s = getsym();
+	if(s == S)
+		goto bad;
+	if(s->macro)
+		yyerror("macro redefined: %s", s->name);
+	c = getc();
+	n = -1;
+	dots = 0;
+	if(c == '(') {
+		n++;
+		c = getnsc();
+		if(c != ')') {
+			unget(c);
+			for(;;) {
+				a = getsymdots(&dots);
+				if(a == S)
+					goto bad;
+				if(n >= NARG) {
+					yyerror("too many arguments in #define: %s", s->name);
+					goto bad;
+				}
+				args[n++] = a->name;
+				c = getnsc();
+				if(c == ')')
+					break;
+				if(c != ',' || dots)
+					goto bad;
+			}
+		}
+		c = getc();
+	}
+	if(isspace(c))
+		if(c != '\n')
+			c = getnsc();
+	base = hunk;
+	len = 1;
+	ischr = 0;
+	for(;;) {
+		if(isalpha(c) || c == '_') {
+			np = symb;
+			*np++ = c;
+			c = getc();
+			while(isalnum(c) || c == '_') {
+				*np++ = c;
+				c = getc();
+			}
+			*np = 0;
+			for(i=0; i<n; i++)
+				if(strcmp(symb, args[i]) == 0)
+					break;
+			if(i >= n) {
+				i = strlen(symb);
+				base = allocn(base, len, i);
+				memcpy(base+len, symb, i);
+				len += i;
+				continue;
+			}
+			base = allocn(base, len, 2);
+			base[len++] = '#';
+			base[len++] = 'a' + i;
+			continue;
+		}
+		if(ischr){
+			if(c == '\\'){ 
+				base = allocn(base, len, 1);
+				base[len++] = c;
+				c = getc();
+			}else if(c == ischr)
+				ischr = 0;
+		}else{
+			if(c == '"' || c == '\''){
+				base = allocn(base, len, 1);
+				base[len++] = c;
+				ischr = c;
+				c = getc();
+				continue;
+			}
+			if(c == '/') {
+				c = getc();
+				if(c == '/'){
+					c = getc();
+					for(;;) {
+						if(c == '\n')
+							break;
+						c = getc();
+					}
+					continue;
+				}
+				if(c == '*'){
+					c = getc();
+					for(;;) {
+						if(c == '*') {
+							c = getc();
+							if(c != '/')
+								continue;
+							c = getc();
+							break;
+						}
+						if(c == '\n') {
+							yyerror("comment and newline in define: %s", s->name);
+							break;
+						}
+						c = getc();
+					}
+					continue;
+				}
+				base = allocn(base, len, 1);
+				base[len++] = '/';
+				continue;
+			}
+		}
+		if(c == '\\') {
+			c = getc();
+			if(c == '\n') {
+				c = getc();
+				continue;
+			}
+			else if(c == '\r') {
+				c = getc();
+				if(c == '\n') {
+					c = getc();
+					continue;
+				}
+			}
+			base = allocn(base, len, 1);
+			base[len++] = '\\';
+			continue;
+		}
+		if(c == '\n')
+			break;
+		if(c == '#')
+		if(n > 0) {
+			base = allocn(base, len, 1);
+			base[len++] = c;
+		}
+		base = allocn(base, len, 1);
+		base[len++] = c;
+		c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
+		if(c == '\n')
+			lineno++;
+		if(c == -1) {
+			yyerror("eof in a macro: %s", s->name);
+			break;
+		}
+	}
+	do {
+		base = allocn(base, len, 1);
+		base[len++] = 0;
+	} while(len & 3);
+
+	*base = n+1;
+	if(dots)
+		*base |= VARMAC;
+	s->macro = base;
+	if(debug['m'])
+		print("#define %s %s\n", s->name, s->macro+1);
+	return;
+
+bad:
+	if(s == S)
+		yyerror("syntax in #define");
+	else
+		yyerror("syntax in #define: %s", s->name);
+	macend();
+}
+
+void
+macexpand(Sym *s, char *b)
+{
+	char buf[2000];
+	int n, l, c, nargs;
+	char *arg[NARG], *cp, *ob, *ecp, dots;
+
+	ob = b;
+	if(*s->macro == 0) {
+		strcpy(b, s->macro+1);
+		if(debug['m'])
+			print("#expand %s %s\n", s->name, ob);
+		return;
+	}
+	
+	nargs = (char)(*s->macro & ~VARMAC) - 1;
+	dots = *s->macro & VARMAC;
+
+	c = getnsc();
+	if(c != '(')
+		goto bad;
+	n = 0;
+	c = getc();
+	if(c != ')') {
+		unget(c);
+		l = 0;
+		cp = buf;
+		ecp = cp + sizeof(buf)-4;
+		arg[n++] = cp;
+		for(;;) {
+			if(cp >= ecp)
+				goto toobig;
+			c = getc();
+			if(c == '"')
+				for(;;) {
+					if(cp >= ecp)
+						goto toobig;
+					*cp++ = c;
+					c = getc();
+					if(c == '\\') {
+						*cp++ = c;
+						c = getc();
+						continue;
+					}
+					if(c == '\n')
+						goto bad;
+					if(c == '"')
+						break;
+				}
+			if(c == '\'')
+				for(;;) {
+					if(cp >= ecp)
+						goto toobig;
+					*cp++ = c;
+					c = getc();
+					if(c == '\\') {
+						*cp++ = c;
+						c = getc();
+						continue;
+					}
+					if(c == '\n')
+						goto bad;
+					if(c == '\'')
+						break;
+				}
+			if(c == '/') {
+				c = getc();
+				switch(c) {
+				case '*':
+					for(;;) {
+						c = getc();
+						if(c == '*') {
+							c = getc();
+							if(c == '/')
+								break;
+						}
+					}
+					*cp++ = ' ';
+					continue;
+				case '/':
+					while((c = getc()) != '\n')
+						;
+					break;
+				default:
+					unget(c);
+					c = '/';
+				}
+			}
+			if(l == 0) {
+				if(c == ',') {
+					if(n == nargs && dots) {
+						*cp++ = ',';
+						continue;
+					}
+					*cp++ = 0;
+					arg[n++] = cp;
+					if(n > nargs)
+						break;
+					continue;
+				}
+				if(c == ')')
+					break;
+			}
+			if(c == '\n')
+				c = ' ';
+			*cp++ = c;
+			if(c == '(')
+				l++;
+			if(c == ')')
+				l--;
+		}
+		*cp = 0;
+	}
+	if(n != nargs) {
+		yyerror("argument mismatch expanding: %s", s->name);
+		*b = 0;
+		return;
+	}
+	cp = s->macro+1;
+	for(;;) {
+		c = *cp++;
+		if(c == '\n')
+			c = ' ';
+		if(c != '#') {
+			*b++ = c;
+			if(c == 0)
+				break;
+			continue;
+		}
+		c = *cp++;
+		if(c == 0)
+			goto bad;
+		if(c == '#') {
+			*b++ = c;
+			continue;
+		}
+		c -= 'a';
+		if(c < 0 || c >= n)
+			continue;
+		strcpy(b, arg[c]);
+		b += strlen(arg[c]);
+	}
+	*b = 0;
+	if(debug['m'])
+		print("#expand %s %s\n", s->name, ob);
+	return;
+
+bad:
+	yyerror("syntax in macro expansion: %s", s->name);
+	*b = 0;
+	return;
+
+toobig:
+	yyerror("too much text in macro expansion: %s", s->name);
+	*b = 0;
+}
+
+void
+macinc(void)
+{
+	int c0, c, i, f;
+	char str[STRINGSZ], *hp;
+
+	c0 = getnsc();
+	if(c0 != '"') {
+		c = c0;
+		if(c0 != '<')
+			goto bad;
+		c0 = '>';
+	}
+	for(hp = str;;) {
+		c = getc();
+		if(c == c0)
+			break;
+		if(c == '\n')
+			goto bad;
+		*hp++ = c;
+	}
+	*hp = 0;
+
+	c = getcom();
+	if(c != '\n')
+		goto bad;
+
+	f = -1;
+	for(i=0; i<ninclude; i++) {
+		if(i == 0 && c0 == '>')
+			continue;
+		strcpy(symb, include[i]);
+		strcat(symb, "/");
+		if(strcmp(symb, "./") == 0)
+			symb[0] = 0;
+		strcat(symb, str);
+		f = myopen(symb);
+		if(f >= 0)
+			break;
+	}
+	if(f < 0)
+		strcpy(symb, str);
+	c = strlen(symb) + 1;
+	hp = alloc(c);
+	memcpy(hp, symb, c);
+	newio();
+	pushio();
+	newfile(hp, f);
+	return;
+
+bad:
+	unget(c);
+	yyerror("syntax in #include");
+	macend();
+}
+
+void
+maclin(void)
+{
+	char *cp;
+	int c;
+	long n;
+
+	n = getnsn();
+	c = getc();
+	if(n < 0)
+		goto bad;
+
+	for(;;) {
+		if(c == ' ' || c == '\t') {
+			c = getc();
+			continue;
+		}
+		if(c == '"')
+			break;
+		if(c == '\n') {
+			strcpy(symb, "<noname>");
+			goto nn;
+		}
+		goto bad;
+	}
+	cp = symb;
+	for(;;) {
+		c = getc();
+		if(c == '"')
+			break;
+		*cp++ = c;
+	}
+	*cp = 0;
+	c = getcom();
+	if(c != '\n')
+		goto bad;
+
+nn:
+	c = strlen(symb) + 1;
+	cp = alloc(c);
+	memcpy(cp, symb, c);
+	linehist(cp, n);
+	return;
+
+bad:
+	unget(c);
+	yyerror("syntax in #line");
+	macend();
+}
+
+void
+macif(int f)
+{
+	int c, l, bol;
+	Sym *s;
+
+	if(f == 2)
+		goto skip;
+	s = getsym();
+	if(s == S)
+		goto bad;
+	if(getcom() != '\n')
+		goto bad;
+	if((s->macro != 0) ^ f)
+		return;
+
+skip:
+	bol = 1;
+	l = 0;
+	for(;;) {
+		c = getc();
+		if(c != '#') {
+			if(!isspace(c))
+				bol = 0;
+			if(c == '\n')
+				bol = 1;
+			continue;
+		}
+		if(!bol)
+			continue;
+		s = getsym();
+		if(s == S)
+			continue;
+		if(strcmp(s->name, "endif") == 0) {
+			if(l) {
+				l--;
+				continue;
+			}
+			macend();
+			return;
+		}
+		if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
+			l++;
+			continue;
+		}
+		if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
+			macend();
+			return;
+		}
+	}
+
+bad:
+	yyerror("syntax in #if(n)def");
+	macend();
+}
+
+void
+macprag(void)
+{
+	Sym *s;
+	int c0, c;
+	char *hp;
+	Hist *h;
+
+	s = getsym();
+
+	if(s && strcmp(s->name, "lib") == 0)
+		goto praglib;
+	if(s && strcmp(s->name, "pack") == 0) {
+		pragpack();
+		return;
+	}
+	if(s && strcmp(s->name, "fpround") == 0) {
+		pragfpround();
+		return;
+	}
+	if(s && strcmp(s->name, "profile") == 0) {
+		pragprofile();
+		return;
+	}
+	if(s && strcmp(s->name, "varargck") == 0) {
+		pragvararg();
+		return;
+	}
+	if(s && strcmp(s->name, "incomplete") == 0) {
+		pragincomplete();
+		return;
+	}
+	while(getnsc() != '\n')
+		;
+	return;
+
+praglib:
+	c0 = getnsc();
+	if(c0 != '"') {
+		c = c0;
+		if(c0 != '<')
+			goto bad;
+		c0 = '>';
+	}
+	for(hp = symb;;) {
+		c = getc();
+		if(c == c0)
+			break;
+		if(c == '\n')
+			goto bad;
+		*hp++ = c;
+	}
+	*hp = 0;
+	c = getcom();
+	if(c != '\n')
+		goto bad;
+
+	/*
+	 * put pragma-line in as a funny history 
+	 */
+	c = strlen(symb) + 1;
+	hp = alloc(c);
+	memcpy(hp, symb, c);
+
+	h = alloc(sizeof(Hist));
+	h->name = hp;
+	h->line = lineno;
+	h->offset = -1;
+	h->link = H;
+	if(ehist == H) {
+		hist = h;
+		ehist = h;
+		return;
+	}
+	ehist->link = h;
+	ehist = h;
+	return;
+
+bad:
+	unget(c);
+	yyerror("syntax in #pragma lib");
+	macend();
+}
+
+void
+macend(void)
+{
+	int c;
+
+	for(;;) {
+		c = getnsc();
+		if(c < 0 || c == '\n')
+			return;
+	}
+}
+
+void
+linehist(char *f, int offset)
+{
+	Hist *h;
+
+	/*
+	 * overwrite the last #line directive if
+	 * no alloc has happened since the last one
+	 */
+	if(newflag == 0 && ehist != H && offset != 0 && ehist->offset != 0)
+		if(f && ehist->name && strcmp(f, ehist->name) == 0) {
+			ehist->line = lineno;
+			ehist->offset = offset;
+			return;
+		}
+
+	if(debug['f'])
+		if(f) {
+			if(offset)
+				print("%4ld: %s (#line %d)\n", lineno, f, offset);
+			else
+				print("%4ld: %s\n", lineno, f);
+		} else
+			print("%4ld: <pop>\n", lineno);
+	newflag = 0;
+
+	h = alloc(sizeof(Hist));
+	h->name = f;
+	h->line = lineno;
+	h->offset = offset;
+	h->link = H;
+	if(ehist == H) {
+		hist = h;
+		ehist = h;
+		return;
+	}
+	ehist->link = h;
+	ehist = h;
+}
diff --git a/src/cmd/cc/omachcap.c b/src/cmd/cc/omachcap.c
new file mode 100644
index 0000000..ec5aa86
--- /dev/null
+++ b/src/cmd/cc/omachcap.c
@@ -0,0 +1,38 @@
+// Inferno utils/cc/machcap.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/machcap.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	"cc.h"
+
+/* default, like old cc */
+int
+machcap(Node *n)
+{
+	return 0;
+}
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c
new file mode 100644
index 0000000..ae0b1b4
--- /dev/null
+++ b/src/cmd/cc/pgen.c
@@ -0,0 +1,550 @@
+// Inferno utils/6c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+	Prog *sp;
+	Node *n1, nod, nod1;
+
+	cursafe = 0;
+	curarg = 0;
+	maxargsafe = 0;
+
+	/*
+	 * isolate name
+	 */
+	for(n1 = nn;; n1 = n1->left) {
+		if(n1 == Z) {
+			diag(nn, "cant find function name");
+			return;
+		}
+		if(n1->op == ONAME)
+			break;
+	}
+	nearln = nn->lineno;
+	gpseudo(ATEXT, n1->sym, nodconst(stkoff));
+	sp = p;
+
+	/*
+	 * isolate first argument
+	 */
+	if(REGARG) {	
+		if(typecmplx[thisfn->link->etype]) {
+			nod1 = *nodret->left;
+			nodreg(&nod, &nod1, REGARG);
+			gmove(&nod, &nod1);
+		} else
+		if(firstarg && typeword[firstargtype->etype]) {
+			nod1 = *nodret->left;
+			nod1.sym = firstarg;
+			nod1.type = firstargtype;
+			nod1.xoffset = align(0, firstargtype, Aarg1);
+			nod1.etype = firstargtype->etype;
+			nodreg(&nod, &nod1, REGARG);
+			gmove(&nod, &nod1);
+		}
+	}
+
+	canreach = 1;
+	warnreach = 1;
+	gen(n);
+	if(canreach && thisfn->link->etype != TVOID)
+		warn(Z, "no return at end of function: %s", n1->sym->name);
+	noretval(3);
+	gbranch(ORETURN);
+
+	if(!debug['N'] || debug['R'] || debug['P'])
+		regopt(sp);
+	
+	if(thechar=='6' || thechar=='7')	/* [sic] */
+		maxargsafe = xround(maxargsafe, 8);
+	sp->to.offset += maxargsafe;
+}
+
+void
+supgen(Node *n)
+{
+	int owarn;
+	long spc;
+	Prog *sp;
+
+	if(n == Z)
+		return;
+	suppress++;
+	owarn = warnreach;
+	warnreach = 0;
+	spc = pc;
+	sp = lastp;
+	gen(n);
+	lastp = sp;
+	pc = spc;
+	sp->link = nil;
+	suppress--;
+	warnreach = owarn;
+}
+
+void
+gen(Node *n)
+{
+	Node *l, nod;
+	Prog *sp, *spc, *spb;
+	Case *cn;
+	long sbc, scc;
+	int snbreak, sncontin;
+	int f, o, oldreach;
+
+loop:
+	if(n == Z)
+		return;
+	nearln = n->lineno;
+	o = n->op;
+	if(debug['G'])
+		if(o != OLIST)
+			print("%L %O\n", nearln, o);
+
+	if(!canreach) {
+		switch(o) {
+		case OLABEL:
+		case OCASE:
+		case OLIST:
+		case OBREAK:
+		case OFOR:
+		case OWHILE:
+		case ODWHILE:
+			/* all handled specially - see switch body below */
+			break;
+		default:
+			if(warnreach) {
+				warn(n, "unreachable code %O", o);
+				warnreach = 0;
+			}
+		}
+	}
+
+	switch(o) {
+
+	default:
+		complex(n);
+		cgen(n, Z);
+		break;
+
+	case OLIST:
+		gen(n->left);
+
+	rloop:
+		n = n->right;
+		goto loop;
+
+	case ORETURN:
+		canreach = 0;
+		warnreach = !suppress;
+		complex(n);
+		if(n->type == T)
+			break;
+		l = n->left;
+		if(l == Z) {
+			noretval(3);
+			gbranch(ORETURN);
+			break;
+		}
+		if(typecmplx[n->type->etype]) {
+			sugen(l, nodret, n->type->width);
+			noretval(3);
+			gbranch(ORETURN);
+			break;
+		}
+		regret(&nod, n);
+		cgen(l, &nod);
+		regfree(&nod);
+		if(typefd[n->type->etype])
+			noretval(1);
+		else
+			noretval(2);
+		gbranch(ORETURN);
+		break;
+
+	case OLABEL:
+		canreach = 1;
+		l = n->left;
+		if(l) {
+			l->pc = pc;
+			if(l->label)
+				patch(l->label, pc);
+		}
+		gbranch(OGOTO);	/* prevent self reference in reg */
+		patch(p, pc);
+		goto rloop;
+
+	case OGOTO:
+		canreach = 0;
+		warnreach = !suppress;
+		n = n->left;
+		if(n == Z)
+			return;
+		if(n->complex == 0) {
+			diag(Z, "label undefined: %s", n->sym->name);
+			return;
+		}
+		if(suppress)
+			return;
+		gbranch(OGOTO);
+		if(n->pc) {
+			patch(p, n->pc);
+			return;
+		}
+		if(n->label)
+			patch(n->label, pc-1);
+		n->label = p;
+		return;
+
+	case OCASE:
+		canreach = 1;
+		l = n->left;
+		if(cases == C)
+			diag(n, "case/default outside a switch");
+		if(l == Z) {
+			cas();
+			cases->val = 0;
+			cases->def = 1;
+			cases->label = pc;
+			cases->isv = 0;
+			goto rloop;
+		}
+		complex(l);
+		if(l->type == T)
+			goto rloop;
+		if(l->op == OCONST)
+		if(typeword[l->type->etype] && l->type->etype != TIND) {
+			cas();
+			cases->val = l->vconst;
+			cases->def = 0;
+			cases->label = pc;
+			cases->isv = typev[l->type->etype];
+			goto rloop;
+		}
+		diag(n, "case expression must be integer constant");
+		goto rloop;
+
+	case OSWITCH:
+		l = n->left;
+		complex(l);
+		if(l->type == T)
+			break;
+		if(!typeword[l->type->etype] || l->type->etype == TIND) {
+			diag(n, "switch expression must be integer");
+			break;
+		}
+
+		gbranch(OGOTO);		/* entry */
+		sp = p;
+
+		cn = cases;
+		cases = C;
+		cas();
+
+		sbc = breakpc;
+		breakpc = pc;
+		snbreak = nbreak;
+		nbreak = 0;
+		gbranch(OGOTO);
+		spb = p;
+
+		gen(n->right);		/* body */
+		if(canreach){
+			gbranch(OGOTO);
+			patch(p, breakpc);
+			nbreak++;
+		}
+
+		patch(sp, pc);
+		regalloc(&nod, l, Z);
+		/* always signed */
+		if(typev[l->type->etype])
+			nod.type = types[TVLONG];
+		else
+			nod.type = types[TLONG];
+		cgen(l, &nod);
+		doswit(&nod);
+		regfree(&nod);
+		patch(spb, pc);
+
+		cases = cn;
+		breakpc = sbc;
+		canreach = nbreak!=0;
+		if(canreach == 0)
+			warnreach = !suppress;
+		nbreak = snbreak;
+		break;
+
+	case OWHILE:
+	case ODWHILE:
+		l = n->left;
+		gbranch(OGOTO);		/* entry */
+		sp = p;
+
+		scc = continpc;
+		continpc = pc;
+		gbranch(OGOTO);
+		spc = p;
+
+		sbc = breakpc;
+		breakpc = pc;
+		snbreak = nbreak;
+		nbreak = 0;
+		gbranch(OGOTO);
+		spb = p;
+
+		patch(spc, pc);
+		if(n->op == OWHILE)
+			patch(sp, pc);
+		bcomplex(l, Z);		/* test */
+		patch(p, breakpc);
+		if(l->op != OCONST || vconst(l) == 0)
+			nbreak++;
+
+		if(n->op == ODWHILE)
+			patch(sp, pc);
+		gen(n->right);		/* body */
+		gbranch(OGOTO);
+		patch(p, continpc);
+
+		patch(spb, pc);
+		continpc = scc;
+		breakpc = sbc;
+		canreach = nbreak!=0;
+		if(canreach == 0)
+			warnreach = !suppress;
+		nbreak = snbreak;
+		break;
+
+	case OFOR:
+		l = n->left;
+		if(!canreach && l->right->left && warnreach) {
+			warn(n, "unreachable code FOR");
+			warnreach = 0;
+		}
+		gen(l->right->left);	/* init */
+		gbranch(OGOTO);		/* entry */
+		sp = p;
+
+		/* 
+		 * if there are no incoming labels in the 
+		 * body and the top's not reachable, warn
+		 */
+		if(!canreach && warnreach && deadheads(n)) {
+			warn(n, "unreachable code %O", o);
+			warnreach = 0;
+		}
+
+		scc = continpc;
+		continpc = pc;
+		gbranch(OGOTO);
+		spc = p;
+
+		sbc = breakpc;
+		breakpc = pc;
+		snbreak = nbreak;
+		nbreak = 0;
+		sncontin = ncontin;
+		ncontin = 0;
+		gbranch(OGOTO);
+		spb = p;
+
+		patch(spc, pc);
+		gen(l->right->right);	/* inc */
+		patch(sp, pc);	
+		if(l->left != Z) {	/* test */
+			bcomplex(l->left, Z);
+			patch(p, breakpc);
+			if(l->left->op != OCONST || vconst(l->left) == 0)
+				nbreak++;
+		}
+		canreach = 1;
+		gen(n->right);		/* body */
+		if(canreach){
+			gbranch(OGOTO);
+			patch(p, continpc);
+			ncontin++;
+		}
+		if(!ncontin && l->right->right && warnreach) {
+			warn(l->right->right, "unreachable FOR inc");
+			warnreach = 0;
+		}
+
+		patch(spb, pc);
+		continpc = scc;
+		breakpc = sbc;
+		canreach = nbreak!=0;
+		if(canreach == 0)
+			warnreach = !suppress;
+		nbreak = snbreak;
+		ncontin = sncontin;
+		break;
+
+	case OCONTINUE:
+		if(continpc < 0) {
+			diag(n, "continue not in a loop");
+			break;
+		}
+		gbranch(OGOTO);
+		patch(p, continpc);
+		ncontin++;
+		canreach = 0;
+		warnreach = !suppress;
+		break;
+
+	case OBREAK:
+		if(breakpc < 0) {
+			diag(n, "break not in a loop");
+			break;
+		}
+		/*
+		 * Don't complain about unreachable break statements.
+		 * There are breaks hidden in yacc's output and some people
+		 * write return; break; in their switch statements out of habit.
+		 * However, don't confuse the analysis by inserting an 
+		 * unreachable reference to breakpc either.
+		 */
+		if(!canreach)
+			break;
+		gbranch(OGOTO);
+		patch(p, breakpc);
+		nbreak++;
+		canreach = 0;
+		warnreach = !suppress;
+		break;
+
+	case OIF:
+		l = n->left;
+		if(bcomplex(l, n->right)) {
+			if(typefd[l->type->etype])
+				f = !l->fconst;
+			else
+				f = !l->vconst;
+			if(debug['c'])
+				print("%L const if %s\n", nearln, f ? "false" : "true");
+			if(f) {
+				canreach = 1;
+				supgen(n->right->left);
+				oldreach = canreach;
+				canreach = 1;
+				gen(n->right->right);
+				/*
+				 * treat constant ifs as regular ifs for 
+				 * reachability warnings.
+				 */
+				if(!canreach && oldreach && debug['w'] < 2)
+					warnreach = 0;
+			}
+			else {
+				canreach = 1;
+				gen(n->right->left);
+				oldreach = canreach;
+				canreach = 1;
+				supgen(n->right->right);
+				/*
+				 * treat constant ifs as regular ifs for 
+				 * reachability warnings.
+				 */
+				if(!oldreach && canreach && debug['w'] < 2)
+					warnreach = 0;
+				canreach = oldreach;
+			}
+		}
+		else {
+			sp = p;
+			canreach = 1;
+			if(n->right->left != Z)
+				gen(n->right->left);
+			oldreach = canreach;
+			canreach = 1;
+			if(n->right->right != Z) {
+				gbranch(OGOTO);
+				patch(sp, pc);
+				sp = p;
+				gen(n->right->right);
+			}
+			patch(sp, pc);
+			canreach = canreach || oldreach;
+			if(canreach == 0)
+				warnreach = !suppress;
+		}
+		break;
+
+	case OSET:
+	case OUSED:
+		usedset(n->left, o);
+		break;
+	}
+}
+
+void
+usedset(Node *n, int o)
+{
+	if(n->op == OLIST) {
+		usedset(n->left, o);
+		usedset(n->right, o);
+		return;
+	}
+	complex(n);
+	switch(n->op) {
+	case OADDR:	/* volatile */
+		gins(ANOP, n, Z);
+		break;
+	case ONAME:
+		if(o == OSET)
+			gins(ANOP, Z, n);
+		else
+			gins(ANOP, n, Z);
+		break;
+	}
+}
+
+int
+bcomplex(Node *n, Node *c)
+{
+
+	complex(n);
+	if(n->type != T)
+	if(tcompat(n, T, n->type, tnot))
+		n->type = T;
+	if(n->type == T) {
+		gbranch(OGOTO);
+		return 0;
+	}
+	if(c != Z && n->op == OCONST && deadheads(c))
+		return 1;
+	bool64(n);
+	boolgen(n, 1, Z);
+	return 0;
+}
diff --git a/src/cmd/cc/pickle.c b/src/cmd/cc/pickle.c
new file mode 100644
index 0000000..3626e4a
--- /dev/null
+++ b/src/cmd/cc/pickle.c
@@ -0,0 +1,298 @@
+// Inferno utils/cc/pickle.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/pickle.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+static char *kwd[] =
+{
+	"$adt", "$aggr", "$append", "$complex", "$defn",
+	"$delete", "$do", "$else", "$eval", "$head", "$if",
+	"$local", "$loop", "$return", "$tail", "$then",
+	"$union", "$whatis", "$while",
+};
+static char picklestr[] = "\tbp = pickle(bp, ep, un, ";
+
+static char*
+pmap(char *s)
+{
+	int i, bot, top, new;
+
+	bot = 0;
+	top = bot + nelem(kwd) - 1;
+	while(bot <= top){
+		new = bot + (top - bot)/2;
+		i = strcmp(kwd[new]+1, s);
+		if(i == 0)
+			return kwd[new];
+
+		if(i < 0)
+			bot = new + 1;
+		else
+			top = new - 1;
+	}
+	return s;
+}
+
+Sym*
+picklesue(Type *t)
+{
+	int h;
+	Sym *s;
+
+	if(t != T)
+	for(h=0; h<nelem(hash); h++)
+		for(s = hash[h]; s != S; s = s->link)
+			if(s->suetag && s->suetag->link == t)
+				return s;
+	return 0;
+}
+
+Sym*
+picklefun(Type *t)
+{
+	int h;
+	Sym *s;
+
+	for(h=0; h<nelem(hash); h++)
+		for(s = hash[h]; s != S; s = s->link)
+			if(s->type == t)
+				return s;
+	return 0;
+}
+
+char	picklechar[NTYPE];
+Init	picklecinit[] =
+{
+	TCHAR,		'C',	0,
+	TUCHAR,		'b',	0,
+	TSHORT,		'd',	0,
+	TUSHORT,		'u',	0,
+	TLONG,		'D',	0,
+	TULONG,		'U',	0,
+	TVLONG,		'V',	0,
+	TUVLONG,	'W',	0,
+	TFLOAT,		'f',	0,
+	TDOUBLE,		'F',	0,
+	TARRAY,		'a',	0,
+	TIND,		'X',	0,
+	-1,		0,	0,
+};
+
+static void
+pickleinit(void)
+{
+	Init *p;
+
+	for(p=picklecinit; p->code >= 0; p++)
+		picklechar[p->code] = p->value;
+
+	picklechar[TINT] = picklechar[TLONG];
+	picklechar[TUINT] = picklechar[TULONG];
+	if(types[TINT]->width != types[TLONG]->width) {
+		picklechar[TINT] = picklechar[TSHORT];
+		picklechar[TUINT] = picklechar[TUSHORT];
+		if(types[TINT]->width != types[TSHORT]->width)
+			warn(Z, "picklemember int not long or short");
+	}
+	
+}
+
+void
+picklemember(Type *t, long off)
+{
+	Sym *s, *s1;
+	static int picklecharinit = 0;
+
+	if(picklecharinit == 0) {
+		pickleinit();
+		picklecharinit = 1;
+	}
+	s = t->sym;
+	switch(t->etype) {
+	default:
+		Bprint(&outbuf, "	T%d\n", t->etype);
+		break;
+
+	case TIND:
+		if(s == S)
+			Bprint(&outbuf,
+				"%s\"p\", (char*)addr+%ld+_i*%ld);\n",
+				picklestr, t->offset+off, t->width);
+		else
+			Bprint(&outbuf,
+				"%s\"p\", &addr->%s);\n",
+				picklestr, pmap(s->name));
+		break;
+
+	case TINT:
+	case TUINT:
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TLONG:
+	case TULONG:
+	case TVLONG:
+	case TUVLONG:
+	case TFLOAT:
+	case TDOUBLE:
+		if(s == S)
+			Bprint(&outbuf, "%s\"%c\", (char*)addr+%ld+_i*%ld);\n",
+				picklestr, picklechar[t->etype], t->offset+off, t->width);
+		else
+			Bprint(&outbuf, "%s\"%c\", &addr->%s);\n",
+				picklestr, picklechar[t->etype], pmap(s->name));
+		break;
+	case TARRAY:
+		Bprint(&outbuf, "\tfor(_i = 0; _i < %ld; _i++) {\n\t",
+			t->width/t->link->width);
+		picklemember(t->link, t->offset+off);
+		Bprint(&outbuf, "\t}\n\t_i = 0;\n\tUSED(_i);\n");
+		break;
+
+	case TSTRUCT:
+	case TUNION:
+		s1 = picklesue(t->link);
+		if(s1 == S)
+			break;
+		if(s == S) {
+			Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%ld+_i*%ld));\n",
+				pmap(s1->name), pmap(s1->name), t->offset+off, t->width);
+		} else {
+			Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, &addr->%s);\n",
+				pmap(s1->name), pmap(s->name));
+		}
+		break;
+	}
+}
+
+void
+pickletype(Type *t)
+{
+	Sym *s;
+	Type *l;
+	Io *i;
+	int n;
+	char *an;
+
+	if(!debug['P'])
+		return;
+	if(debug['P'] > 1) {
+		n = 0;
+		for(i=iostack; i; i=i->link)
+			n++;
+		if(n > 1)
+			return;
+	}
+	s = picklesue(t->link);
+	if(s == S)
+		return;
+	switch(t->etype) {
+	default:
+		Bprint(&outbuf, "T%d\n", t->etype);
+		return;
+
+	case TUNION:
+	case TSTRUCT:
+		if(debug['s'])
+			goto asmstr;
+		an = pmap(s->name);
+
+		Bprint(&outbuf, "char *\npickle_%s(char *bp, char *ep, int un, %s *addr)\n{\n\tint _i = 0;\n\n\tUSED(_i);\n", an, an);
+		for(l = t->link; l != T; l = l->down)
+			picklemember(l, 0);
+		Bprint(&outbuf, "\treturn bp;\n}\n\n");
+		break;
+	asmstr:
+		if(s == S)
+			break;
+		for(l = t->link; l != T; l = l->down)
+			if(l->sym != S)
+				Bprint(&outbuf, "#define\t%s.%s\t%ld\n",
+					s->name,
+					l->sym->name,
+					l->offset);
+		break;
+	}
+}
+
+void
+picklevar(Sym *s)
+{
+	int n;
+	Io *i;
+	Type *t;
+	Sym *s1, *s2;
+
+	if(!debug['P'] || debug['s'])
+		return;
+	if(debug['P'] > 1) {
+		n = 0;
+		for(i=iostack; i; i=i->link)
+			n++;
+		if(n > 1)
+			return;
+	}
+	t = s->type;
+	while(t && t->etype == TIND)
+		t = t->link;
+	if(t == T)
+		return;
+	if(t->etype == TENUM) {
+		Bprint(&outbuf, "%s = ", pmap(s->name));
+		if(!typefd[t->etype])
+			Bprint(&outbuf, "%lld;\n", s->vconst);
+		else
+			Bprint(&outbuf, "%f\n;", s->fconst);
+		return;
+	}
+	if(!typesu[t->etype])
+		return;
+	s1 = picklesue(t->link);
+	if(s1 == S)
+		return;
+	switch(s->class) {
+	case CAUTO:
+	case CPARAM:
+		s2 = picklefun(thisfn);
+		if(s2)
+			Bprint(&outbuf, "complex %s %s:%s;\n",
+				pmap(s1->name), pmap(s2->name), pmap(s->name));
+		break;
+	
+	case CSTATIC:
+	case CEXTERN:
+	case CGLOBL:
+	case CLOCAL:
+		Bprint(&outbuf, "complex %s %s;\n",
+			pmap(s1->name), pmap(s->name));
+		break;
+	}
+}
diff --git a/src/cmd/cc/pswt.c b/src/cmd/cc/pswt.c
new file mode 100644
index 0000000..f4149f1
--- /dev/null
+++ b/src/cmd/cc/pswt.c
@@ -0,0 +1,168 @@
+// Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+	C1 *p1, *p2;
+
+	p1 = (C1*)a1;
+	p2 = (C1*)a2;
+	if(p1->val < p2->val)
+		return -1;
+	return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+	Case *c;
+	C1 *q, *iq;
+	long def, nc, i, isv;
+
+	def = 0;
+	nc = 0;
+	isv = 0;
+	for(c = cases; c->link != C; c = c->link) {
+		if(c->def) {
+			if(def)
+				diag(n, "more than one default in switch");
+			def = c->label;
+			continue;
+		}
+		isv |= c->isv;
+		nc++;
+	}
+	if(isv && !typev[n->type->etype])
+		warn(n, "32-bit switch expression with 64-bit case constant");
+
+	iq = alloc(nc*sizeof(C1));
+	q = iq;
+	for(c = cases; c->link != C; c = c->link) {
+		if(c->def)
+			continue;
+		q->label = c->label;
+		if(isv)
+			q->val = c->val;
+		else
+			q->val = (long)c->val;	/* cast ensures correct value for 32-bit switch on 64-bit architecture */
+		q++;
+	}
+	qsort(iq, nc, sizeof(C1), swcmp);
+	if(debug['W'])
+	for(i=0; i<nc; i++)
+		print("case %2ld: = %.8llux\n", i, (vlong)iq[i].val);
+	for(i=0; i<nc-1; i++)
+		if(iq[i].val == iq[i+1].val)
+			diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val);
+	if(def == 0) {
+		def = breakpc;
+		nbreak++;
+	}
+	swit1(iq, nc, def, n);
+}
+
+void
+cas(void)
+{
+	Case *c;
+
+	c = alloc(sizeof(*c));
+	c->link = cases;
+	cases = c;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+	char buf[2];
+	int c;
+	long r;
+
+	if(suppress)
+		return nstring;
+	while(nstring & 1)
+		outstring("", 1);
+	r = nstring;
+	while(n > 0) {
+		c = *s++;
+		if(align(0, types[TCHAR], Aarg1)) {
+			buf[0] = c>>8;
+			buf[1] = c;
+		} else {
+			buf[0] = c;
+			buf[1] = c>>8;
+		}
+		outstring(buf, 2);
+		n -= sizeof(ushort);
+	}
+	return r;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+	warn(Z, "result of operation not used");
+	if(l != Z)
+		cgen(l, Z);
+	if(r != Z)
+		cgen(r, Z);
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+	double fr, ho, f;
+	int exp;
+
+	if(native < 0) {
+		ieeedtod(ieee, -native);
+		ieee->h |= 0x80000000L;
+		return;
+	}
+	if(native == 0) {
+		ieee->l = 0;
+		ieee->h = 0;
+		return;
+	}
+	fr = frexp(native, &exp);
+	f = 2097152L;		/* shouldnt use fp constants here */
+	fr = modf(fr*f, &ho);
+	ieee->h = ho;
+	ieee->h &= 0xfffffL;
+	ieee->h |= (exp+1022L) << 20;
+	f = 65536L;
+	fr = modf(fr*f, &ho);
+	ieee->l = ho;
+	ieee->l <<= 16;
+	ieee->l |= (long)(fr*f);
+}
diff --git a/src/cmd/cc/scon.c b/src/cmd/cc/scon.c
new file mode 100644
index 0000000..3047ca4
--- /dev/null
+++ b/src/cmd/cc/scon.c
@@ -0,0 +1,636 @@
+// Inferno utils/cc/scon.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/scon.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+static Node*
+acast(Type *t, Node *n)
+{
+	if(n->type->etype != t->etype || n->op == OBIT) {
+		n = new1(OCAST, n, Z);
+		if(nocast(n->left->type, t))
+			*n = *n->left;
+		n->type = t;
+	}
+	return n;
+}
+
+
+void
+evconst(Node *n)
+{
+	Node *l, *r;
+	int et, isf;
+	vlong v;
+	double d;
+
+	if(n == Z || n->type == T)
+		return;
+
+	et = n->type->etype;
+	isf = typefd[et];
+
+	l = n->left;
+	r = n->right;
+
+	d = 0;
+	v = 0;
+
+	switch(n->op) {
+	default:
+		return;
+
+	case ONEG:
+		if(isf)
+			d = -l->fconst;
+		else
+			v = -l->vconst;
+		break;
+
+	case OCOM:
+		v = ~l->vconst;
+		break;
+
+	case OCAST:
+		if(et == TVOID)
+			return;
+		et = l->type->etype;
+		if(isf) {
+			if(typefd[et])
+				d = l->fconst;
+			else
+				d = l->vconst;
+		} else {
+			if(typefd[et])
+				v = l->fconst;
+			else
+				v = convvtox(l->vconst, n->type->etype);
+		}
+		break;
+
+	case OCONST:
+		break;
+
+	case OADD:
+		if(isf)
+			d = l->fconst + r->fconst;
+		else {
+			v = l->vconst + r->vconst;
+		}
+		break;
+
+	case OSUB:
+		if(isf)
+			d = l->fconst - r->fconst;
+		else
+			v = l->vconst - r->vconst;
+		break;
+
+	case OMUL:
+		if(isf)
+			d = l->fconst * r->fconst;
+		else {
+			v = l->vconst * r->vconst;
+		}
+		break;
+
+	case OLMUL:
+		v = (uvlong)l->vconst * (uvlong)r->vconst;
+		break;
+
+
+	case ODIV:
+		if(vconst(r) == 0) {
+			warn(n, "divide by zero");
+			return;
+		}
+		if(isf)
+			d = l->fconst / r->fconst;
+		else
+			v = l->vconst / r->vconst;
+		break;
+
+	case OLDIV:
+		if(vconst(r) == 0) {
+			warn(n, "divide by zero");
+			return;
+		}
+		v = (uvlong)l->vconst / (uvlong)r->vconst;
+		break;
+
+	case OMOD:
+		if(vconst(r) == 0) {
+			warn(n, "modulo by zero");
+			return;
+		}
+		v = l->vconst % r->vconst;
+		break;
+
+	case OLMOD:
+		if(vconst(r) == 0) {
+			warn(n, "modulo by zero");
+			return;
+		}
+		v = (uvlong)l->vconst % (uvlong)r->vconst;
+		break;
+
+	case OAND:
+		v = l->vconst & r->vconst;
+		break;
+
+	case OOR:
+		v = l->vconst | r->vconst;
+		break;
+
+	case OXOR:
+		v = l->vconst ^ r->vconst;
+		break;
+
+	case OLSHR:
+		v = (uvlong)l->vconst >> r->vconst;
+		break;
+
+	case OASHR:
+		v = l->vconst >> r->vconst;
+		break;
+
+	case OASHL:
+		v = l->vconst << r->vconst;
+		break;
+
+	case OLO:
+		v = (uvlong)l->vconst < (uvlong)r->vconst;
+		break;
+
+	case OLT:
+		if(typefd[l->type->etype])
+			v = l->fconst < r->fconst;
+		else
+			v = l->vconst < r->vconst;
+		break;
+
+	case OHI:
+		v = (uvlong)l->vconst > (uvlong)r->vconst;
+		break;
+
+	case OGT:
+		if(typefd[l->type->etype])
+			v = l->fconst > r->fconst;
+		else
+			v = l->vconst > r->vconst;
+		break;
+
+	case OLS:
+		v = (uvlong)l->vconst <= (uvlong)r->vconst;
+		break;
+
+	case OLE:
+		if(typefd[l->type->etype])
+			v = l->fconst <= r->fconst;
+		else
+			v = l->vconst <= r->vconst;
+		break;
+
+	case OHS:
+		v = (uvlong)l->vconst >= (uvlong)r->vconst;
+		break;
+
+	case OGE:
+		if(typefd[l->type->etype])
+			v = l->fconst >= r->fconst;
+		else
+			v = l->vconst >= r->vconst;
+		break;
+
+	case OEQ:
+		if(typefd[l->type->etype])
+			v = l->fconst == r->fconst;
+		else
+			v = l->vconst == r->vconst;
+		break;
+
+	case ONE:
+		if(typefd[l->type->etype])
+			v = l->fconst != r->fconst;
+		else
+			v = l->vconst != r->vconst;
+		break;
+
+	case ONOT:
+		if(typefd[l->type->etype])
+			v = !l->fconst;
+		else
+			v = !l->vconst;
+		break;
+
+	case OANDAND:
+		if(typefd[l->type->etype])
+			v = l->fconst && r->fconst;
+		else
+			v = l->vconst && r->vconst;
+		break;
+
+	case OOROR:
+		if(typefd[l->type->etype])
+			v = l->fconst || r->fconst;
+		else
+			v = l->vconst || r->vconst;
+		break;
+	}
+	if(isf) {
+		n->fconst = d;
+	} else {
+		n->vconst = convvtox(v, n->type->etype);
+	}
+	n->oldop = n->op;
+	n->op = OCONST;
+}
+
+void
+acom(Node *n)
+{
+	Type *t;
+	Node *l, *r;
+	int i;
+
+	switch(n->op)
+	{
+
+	case ONAME:
+	case OCONST:
+	case OSTRING:
+	case OINDREG:
+	case OREGISTER:
+		return;
+
+	case ONEG:
+		l = n->left;
+		if(addo(n) && addo(l))
+			break;
+		acom(l);
+		return;
+
+	case OADD:
+	case OSUB:
+	case OMUL:
+		l = n->left;
+		r = n->right;
+		if(addo(n)) {
+			if(addo(r))
+				break;
+			if(addo(l))
+				break;
+		}
+		acom(l);
+		acom(r);
+		return;
+
+	default:
+		l = n->left;
+		r = n->right;
+		if(l != Z)
+			acom(l);
+		if(r != Z)
+			acom(r);
+		return;
+	}
+
+	/* bust terms out */
+	t = n->type;
+	term[0].mult = 0;
+	term[0].node = Z;
+	nterm = 1;
+	acom1(1, n);
+	if(debug['m'])
+	for(i=0; i<nterm; i++) {
+		print("%d %3lld ", i, term[i].mult);
+		prtree1(term[i].node, 1, 0);
+	}
+	if(nterm < NTERM)
+		acom2(n, t);
+	n->type = t;
+}
+
+int
+acomcmp1(const void *a1, const void *a2)
+{
+	vlong c1, c2;
+	Term *t1, *t2;
+
+	t1 = (Term*)a1;
+	t2 = (Term*)a2;
+	c1 = t1->mult;
+	if(c1 < 0)
+		c1 = -c1;
+	c2 = t2->mult;
+	if(c2 < 0)
+		c2 = -c2;
+	if(c1 > c2)
+		return 1;
+	if(c1 < c2)
+		return -1;
+	c1 = 1;
+	if(t1->mult < 0)
+		c1 = 0;
+	c2 = 1;
+	if(t2->mult < 0)
+		c2 = 0;
+	if(c2 -= c1)
+		return c2;
+	if(t2 > t1)
+		return 1;
+	return -1;
+}
+
+int
+acomcmp2(const void *a1, const void *a2)
+{
+	vlong c1, c2;
+	Term *t1, *t2;
+
+	t1 = (Term*)a1;
+	t2 = (Term*)a2;
+	c1 = t1->mult;
+	c2 = t2->mult;
+	if(c1 > c2)
+		return 1;
+	if(c1 < c2)
+		return -1;
+	if(t2 > t1)
+		return 1;
+	return -1;
+}
+
+void
+acom2(Node *n, Type *t)
+{
+	Node *l, *r;
+	Term trm[NTERM];
+	int et, nt, i, j;
+	vlong c1, c2;
+
+	/*
+	 * copy into automatic
+	 */
+	c2 = 0;
+	nt = nterm;
+	for(i=0; i<nt; i++)
+		trm[i] = term[i];
+	/*
+	 * recur on subtrees
+	 */
+	j = 0;
+	for(i=1; i<nt; i++) {
+		c1 = trm[i].mult;
+		if(c1 == 0)
+			continue;
+		l = trm[i].node;
+		if(l != Z) {
+			j = 1;
+			acom(l);
+		}
+	}
+	c1 = trm[0].mult;
+	if(j == 0) {
+		n->oldop = n->op;
+		n->op = OCONST;
+		n->vconst = c1;
+		return;
+	}
+	et = t->etype;
+
+	/*
+	 * prepare constant term,
+	 * combine it with an addressing term
+	 */
+	if(c1 != 0) {
+		l = new1(OCONST, Z, Z);
+		l->type = t;
+		l->vconst = c1;
+		trm[0].mult = 1;
+		for(i=1; i<nt; i++) {
+			if(trm[i].mult != 1)
+				continue;
+			r = trm[i].node;
+			if(r->op != OADDR)
+				continue;
+			r->type = t;
+			l = new1(OADD, r, l);
+			l->type = t;
+			trm[i].mult = 0;
+			break;
+		}
+		trm[0].node = l;
+	}
+	/*
+	 * look for factorable terms
+	 * c1*i + c1*c2*j -> c1*(i + c2*j)
+	 */
+	qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp1);
+	for(i=nt-1; i>=0; i--) {
+		c1 = trm[i].mult;
+		if(c1 < 0)
+			c1 = -c1;
+		if(c1 <= 1)
+			continue;
+		for(j=i+1; j<nt; j++) {
+			c2 = trm[j].mult;
+			if(c2 < 0)
+				c2 = -c2;
+			if(c2 <= 1)
+				continue;
+			if(c2 % c1)
+				continue;
+			r = trm[j].node;
+			if(r->type->etype != et)
+				r = acast(t, r);
+			c2 = trm[j].mult/trm[i].mult;
+			if(c2 != 1 && c2 != -1) {
+				r = new1(OMUL, r, new(OCONST, Z, Z));
+				r->type = t;
+				r->right->type = t;
+				r->right->vconst = c2;
+			}
+			l = trm[i].node;
+			if(l->type->etype != et)
+				l = acast(t, l);
+			r = new1(OADD, l, r);
+			r->type = t;
+			if(c2 == -1)
+				r->op = OSUB;
+			trm[i].node = r;
+			trm[j].mult = 0;
+		}
+	}
+	if(debug['m']) {
+		print("\n");
+		for(i=0; i<nt; i++) {
+			print("%d %3lld ", i, trm[i].mult);
+			prtree1(trm[i].node, 1, 0);
+		}
+	}
+
+	/*
+	 * put it all back together
+	 */
+	qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp2);
+	l = Z;
+	for(i=nt-1; i>=0; i--) {
+		c1 = trm[i].mult;
+		if(c1 == 0)
+			continue;
+		r = trm[i].node;
+		if(r->type->etype != et || r->op == OBIT)
+			r = acast(t, r);
+		if(c1 != 1 && c1 != -1) {
+			r = new1(OMUL, r, new(OCONST, Z, Z));
+			r->type = t;
+			r->right->type = t;
+			if(c1 < 0) {
+				r->right->vconst = -c1;
+				c1 = -1;
+			} else {
+				r->right->vconst = c1;
+				c1 = 1;
+			}
+		}
+		if(l == Z) {
+			l = r;
+			c2 = c1;
+			continue;
+		}
+		if(c1 < 0)
+			if(c2 < 0)
+				l = new1(OADD, l, r);
+			else
+				l = new1(OSUB, l, r);
+		else
+			if(c2 < 0) {
+				l = new1(OSUB, r, l);
+				c2 = 1;
+			} else
+				l = new1(OADD, l, r);
+		l->type = t;
+	}
+	if(c2 < 0) {
+		r = new1(OCONST, 0, 0);
+		r->vconst = 0;
+		r->type = t;
+		l = new1(OSUB, r, l);
+		l->type = t;
+	}
+	*n = *l;
+}
+
+void
+acom1(vlong v, Node *n)
+{
+	Node *l, *r;
+
+	if(v == 0 || nterm >= NTERM)
+		return;
+	if(!addo(n)) {
+		if(n->op == OCONST)
+		if(!typefd[n->type->etype]) {
+			term[0].mult += v*n->vconst;
+			return;
+		}
+		term[nterm].mult = v;
+		term[nterm].node = n;
+		nterm++;
+		return;
+	}
+	switch(n->op) {
+
+	case OCAST:
+		acom1(v, n->left);
+		break;
+
+	case ONEG:
+		acom1(-v, n->left);
+		break;
+
+	case OADD:
+		acom1(v, n->left);
+		acom1(v, n->right);
+		break;
+
+	case OSUB:
+		acom1(v, n->left);
+		acom1(-v, n->right);
+		break;
+
+	case OMUL:
+		l = n->left;
+		r = n->right;
+		if(l->op == OCONST)
+		if(!typefd[n->type->etype]) {
+			acom1(v*l->vconst, r);
+			break;
+		}
+		if(r->op == OCONST)
+		if(!typefd[n->type->etype]) {
+			acom1(v*r->vconst, l);
+			break;
+		}
+		break;
+
+	default:
+		diag(n, "not addo");
+	}
+}
+
+int
+addo(Node *n)
+{
+
+	if(n != Z)
+	if(!typefd[n->type->etype])
+	if(!typev[n->type->etype] || ewidth[TVLONG] == ewidth[TIND])
+	switch(n->op) {
+
+	case OCAST:
+		if(nilcast(n->left->type, n->type))
+			return 1;
+		break;
+
+	case ONEG:
+	case OADD:
+	case OSUB:
+		return 1;
+
+	case OMUL:
+		if(n->left->op == OCONST)
+			return 1;
+		if(n->right->op == OCONST)
+			return 1;
+	}
+	return 0;
+}
diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c
new file mode 100644
index 0000000..fcf915c
--- /dev/null
+++ b/src/cmd/cc/sub.c
@@ -0,0 +1,2054 @@
+// Inferno utils/cc/sub.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/sub.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// 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
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include	"cc.h"
+
+Node*
+new(int t, Node *l, Node *r)
+{
+	Node *n;
+
+	n = alloc(sizeof(*n));
+	n->op = t;
+	n->left = l;
+	n->right = r;
+	if(l && t != OGOTO)
+		n->lineno = l->lineno;
+	else if(r)
+		n->lineno = r->lineno;
+	else
+		n->lineno = lineno;
+	newflag = 1;
+	return n;
+}
+
+Node*
+new1(int o, Node *l, Node *r)
+{
+	Node *n;
+
+	n = new(o, l, r);
+	n->lineno = nearln;
+	return n;
+}
+
+void
+prtree(Node *n, char *s)
+{
+
+	print(" == %s ==\n", s);
+	prtree1(n, 0, 0);
+	print("\n");
+}
+
+void
+prtree1(Node *n, int d, int f)
+{
+	int i;
+
+	if(f)
+	for(i=0; i<d; i++)
+		print("   ");
+	if(n == Z) {
+		print("Z\n");
+		return;
+	}
+	if(n->op == OLIST) {
+		prtree1(n->left, d, 0);
+		prtree1(n->right, d, 1);
+		return;
+	}
+	d++;
+	print("%O", n->op);
+	i = 3;
+	switch(n->op)
+	{
+	case ONAME:
+		print(" \"%F\"", n);
+		print(" %ld", n->xoffset);
+		i = 0;
+		break;
+
+	case OINDREG:
+		print(" %ld(R%d)", n->xoffset, n->reg);
+		i = 0;
+		break;
+
+	case OREGISTER:
+		if(n->xoffset)
+			print(" %ld+R%d", n->xoffset, n->reg);
+		else
+			print(" R%d", n->reg);
+		i = 0;
+		break;
+
+	case OSTRING:
+		print(" \"%s\"", n->cstring);
+		i = 0;
+		break;
+
+	case OLSTRING:
+		print(" \"%S\"", n->rstring);
+		i = 0;
+		break;
+
+	case ODOT:
+	case OELEM:
+		print(" \"%F\"", n);
+		break;
+
+	case OCONST:
+		if(typefd[n->type->etype])
+			print(" \"%.8e\"", n->fconst);
+		else
+			print(" \"%lld\"", n->vconst);
+		i = 0;
+		break;
+	}
+	if(n->addable != 0)
+		print(" <%d>", n->addable);
+	if(n->type != T)
+		print(" %T", n->type);
+	if(n->complex != 0)
+		print(" (%d)", n->complex);
+	print(" %L\n", n->lineno);
+	if(i & 2)
+		prtree1(n->left, d, 1);
+	if(i & 1)
+		prtree1(n->right, d, 1);
+}
+
+Type*
+typ(int et, Type *d)
+{
+	Type *t;
+
+	t = alloc(sizeof(*t));
+	t->etype = et;
+	t->link = d;
+	t->down = T;
+	t->sym = S;
+	t->width = ewidth[et];
+	t->offset = 0;
+	t->shift = 0;
+	t->nbits = 0;
+	t->garb = 0;
+	return t;
+}
+
+Type*
+copytyp(Type *t)
+{
+	Type *nt;
+
+	nt = typ(TXXX, T);
+	*nt = *t;
+	return nt;
+}
+
+Type*
+garbt(Type *t, long b)
+{
+	Type *t1;
+
+	if(b & BGARB) {
+		t1 = copytyp(t);
+		t1->garb = simpleg(b);
+		return t1;
+	}
+	return t;
+}
+
+int
+simpleg(long b)
+{
+
+	b &= BGARB;
+	switch(b) {
+	case BCONSTNT:
+		return GCONSTNT;
+	case BVOLATILE:
+		return GVOLATILE;
+	case BVOLATILE|BCONSTNT:
+		return GCONSTNT|GVOLATILE;
+	}
+	return GXXX;
+}
+
+int
+simplec(long b)
+{
+
+	b &= BCLASS;
+	switch(b) {
+	case 0:
+	case BREGISTER:
+		return CXXX;
+	case BAUTO:
+	case BAUTO|BREGISTER:
+		return CAUTO;
+	case BEXTERN:
+		return CEXTERN;
+	case BEXTERN|BREGISTER:
+		return CEXREG;
+	case BSTATIC:
+		return CSTATIC;
+	case BTYPEDEF:
+		return CTYPEDEF;
+	case BTYPESTR:
+		return CTYPESTR;
+	}
+	diag(Z, "illegal combination of classes %Q", b);
+	return CXXX;
+}
+
+Type*
+simplet(long b)
+{
+
+	b &= ~BCLASS & ~BGARB;
+	switch(b) {
+	case BCHAR:
+	case BCHAR|BSIGNED:
+		return types[TCHAR];
+
+	case BCHAR|BUNSIGNED:
+		return types[TUCHAR];
+
+	case BSHORT:
+	case BSHORT|BINT:
+	case BSHORT|BSIGNED:
+	case BSHORT|BINT|BSIGNED:
+		return types[TSHORT];
+
+	case BUNSIGNED|BSHORT:
+	case BUNSIGNED|BSHORT|BINT:
+		return types[TUSHORT];
+
+	case 0:
+	case BINT:
+	case BINT|BSIGNED:
+	case BSIGNED:
+		return types[TINT];
+
+	case BUNSIGNED:
+	case BUNSIGNED|BINT:
+		return types[TUINT];
+
+	case BLONG:
+	case BLONG|BINT:
+	case BLONG|BSIGNED:
+	case BLONG|BINT|BSIGNED:
+		return types[TLONG];
+
+	case BUNSIGNED|BLONG:
+	case BUNSIGNED|BLONG|BINT:
+		return types[TULONG];
+
+	case BVLONG|BLONG:
+	case BVLONG|BLONG|BINT:
+	case BVLONG|BLONG|BSIGNED:
+	case BVLONG|BLONG|BINT|BSIGNED:
+		return types[TVLONG];
+
+	case BVLONG|BLONG|BUNSIGNED:
+	case BVLONG|BLONG|BINT|BUNSIGNED:
+		return types[TUVLONG];
+
+	case BFLOAT:
+		return types[TFLOAT];
+
+	case BDOUBLE:
+	case BDOUBLE|BLONG:
+	case BFLOAT|BLONG:
+		return types[TDOUBLE];
+
+	case BVOID:
+		return types[TVOID];
+	}
+
+	diag(Z, "illegal combination of types %Q", b);
+	return types[TINT];
+}
+
+int
+stcompat(Node *n, Type *t1, Type *t2, long ttab[])
+{
+	int i;
+	ulong b;
+
+	i = 0;
+	if(t2 != T)
+		i = t2->etype;
+	b = 1L << i;
+	i = 0;
+	if(t1 != T)
+		i = t1->etype;
+	if(b & ttab[i]) {
+		if(ttab == tasign)
+			if(b == BSTRUCT || b == BUNION)
+				if(!sametype(t1, t2))
+					return 1;
+		if(n->op != OCAST)
+		 	if(b == BIND && i == TIND)
+				if(!sametype(t1, t2))
+					return 1;
+		return 0;
+	}
+	return 1;
+}
+
+int
+tcompat(Node *n, Type *t1, Type *t2, long ttab[])
+{
+
+	if(stcompat(n, t1, t2, ttab)) {
+		if(t1 == T)
+			diag(n, "incompatible type: \"%T\" for op \"%O\"",
+				t2, n->op);
+		else
+			diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"",
+				t1, t2, n->op);
+		return 1;
+	}
+	return 0;
+}
+
+void
+makedot(Node *n, Type *t, long o)
+{
+	Node *n1, *n2;
+
+	if(t->nbits) {
+		n1 = new(OXXX, Z, Z);
+		*n1 = *n;
+		n->op = OBIT;
+		n->left = n1;
+		n->right = Z;
+		n->type = t;
+		n->addable = n1->left->addable;
+		n = n1;
+	}
+	n->addable = n->left->addable;
+	if(n->addable == 0) {
+		n1 = new1(OCONST, Z, Z);
+		n1->vconst = o;
+		n1->type = types[TLONG];
+		n->right = n1;
+		n->type = t;
+		return;
+	}
+	n->left->type = t;
+	if(o == 0) {
+		*n = *n->left;
+		return;
+	}
+	n->type = t;
+	n1 = new1(OCONST, Z, Z);
+	n1->vconst = o;
+	t = typ(TIND, t);
+	t->width = types[TIND]->width;
+	n1->type = t;
+
+	n2 = new1(OADDR, n->left, Z);
+	n2->type = t;
+
+	n1 = new1(OADD, n1, n2);
+	n1->type = t;
+
+	n->op = OIND;
+	n->left = n1;
+	n->right = Z;
+}
+
+Type*
+dotsearch(Sym *s, Type *t, Node *n, long *off)
+{
+	Type *t1, *xt, *rt;
+
+	xt = T;
+
+	/*
+	 * look it up by name
+	 */
+	for(t1 = t; t1 != T; t1 = t1->down)
+		if(t1->sym == s) {
+			if(xt != T)
+				goto ambig;
+			xt = t1;
+		}
+
+	/*
+	 * look it up by type
+	 */
+	if(s->class == CTYPEDEF || s->class == CTYPESTR)
+		for(t1 = t; t1 != T; t1 = t1->down)
+			if(t1->sym == S && typesu[t1->etype])
+				if(sametype(s->type, t1)) {
+					if(xt != T)
+						goto ambig;
+					xt = t1;
+				}
+	if(xt != T) {
+		*off = xt->offset;
+		return xt;
+	}
+
+	/*
+	 * look it up in unnamed substructures
+	 */
+	for(t1 = t; t1 != T; t1 = t1->down)
+		if(t1->sym == S && typesu[t1->etype]){
+			rt = dotsearch(s, t1->link, n, off);
+			if(rt != T) {
+				if(xt != T)
+					goto ambig;
+				xt = rt;
+				*off += t1->offset;
+			}
+		}
+	return xt;
+
+ambig:
+	diag(n, "ambiguous structure element: %s", s->name);
+	return xt;
+}
+
+long
+dotoffset(Type *st, Type *lt, Node *n)
+{
+	Type *t;
+	Sym *g;
+	long o, o1;
+
+	o = -1;
+	/*
+	 * first try matching at the top level
+	 * for matching tag names
+	 */
+	g = st->tag;
+	if(g != S)
+		for(t=lt->link; t!=T; t=t->down)
+			if(t->sym == S)
+				if(g == t->tag) {
+					if(o >= 0)
+						goto ambig;
+					o = t->offset;
+				}
+	if(o >= 0)
+		return o;
+
+	/*
+	 * second try matching at the top level
+	 * for similar types
+	 */
+	for(t=lt->link; t!=T; t=t->down)
+		if(t->sym == S)
+			if(sametype(st, t)) {
+				if(o >= 0)
+					goto ambig;
+				o = t->offset;
+			}
+	if(o >= 0)
+		return o;
+
+	/*
+	 * last try matching sub-levels
+	 */
+	for(t=lt->link; t!=T; t=t->down)
+		if(t->sym == S)
+		if(typesu[t->etype]) {
+			o1 = dotoffset(st, t, n);
+			if(o1 >= 0) {
+				if(o >= 0)
+					goto ambig;
+				o = o1 + t->offset;
+			}
+		}
+	return o;
+
+ambig:
+	diag(n, "ambiguous unnamed structure element");
+	return o;
+}
+
+/*
+ * look into tree for floating point constant expressions
+ */
+int
+allfloat(Node *n, int flag)
+{
+
+	if(n != Z) {
+		if(n->type->etype != TDOUBLE)
+			return 1;
+		switch(n->op) {
+		case OCONST:
+			if(flag)
+				n->type = types[TFLOAT];
+			return 1;
+		case OADD:	/* no need to get more exotic than this */
+		case OSUB:
+		case OMUL:
+		case ODIV:
+			if(!allfloat(n->right, flag))
+				break;
+		case OCAST:
+			if(!allfloat(n->left, flag))
+				break;
+			if(flag)
+				n->type = types[TFLOAT];
+			return 1;
+		}
+	}
+	return 0;
+}
+
+void
+constas(Node *n, Type *il, Type *ir)
+{
+	Type *l, *r;
+
+	l = il;
+	r = ir;
+
+	if(l == T)
+		return;
+	if(l->garb & GCONSTNT) {
+		warn(n, "assignment to a constant type (%T)", il);
+		return;
+	}
+	if(r == T)
+		return;
+	for(;;) {
+		if(l->etype != TIND || r->etype != TIND)
+			break;
+		l = l->link;
+		r = r->link;
+		if(l == T || r == T)
+			break;
+		if(r->garb & GCONSTNT)
+			if(!(l->garb & GCONSTNT)) {
+				warn(n, "assignment of a constant pointer type (%T)", ir);
+				break;
+			}
+	}
+}
+
+void
+typeext1(Type *st, Node *l)
+{
+	if(st->etype == TFLOAT && allfloat(l, 0))
+		allfloat(l, 1);
+}
+
+void
+typeext(Type *st, Node *l)
+{
+	Type *lt;
+	Node *n1, *n2;
+	long o;
+
+	lt = l->type;
+	if(lt == T)
+		return;
+	if(st->etype == TIND && vconst(l) == 0) {
+		l->type = st;
+		l->vconst = 0;
+		return;
+	}
+	typeext1(st, l);
+
+	/*
+	 * extension of C
+	 * if assign of struct containing unnamed sub-struct
+	 * to type of sub-struct, insert the DOT.
+	 * if assign of *struct containing unnamed substruct
+	 * to type of *sub-struct, insert the add-offset
+	 */
+	if(typesu[st->etype] && typesu[lt->etype]) {
+		o = dotoffset(st, lt, l);
+		if(o >= 0) {
+			n1 = new1(OXXX, Z, Z);
+			*n1 = *l;
+			l->op = ODOT;
+			l->left = n1;
+			l->right = Z;
+			makedot(l, st, o);
+		}
+		return;
+	}
+	if(st->etype == TIND && typesu[st->link->etype])
+	if(lt->etype == TIND && typesu[lt->link->etype]) {
+		o = dotoffset(st->link, lt->link, l);
+		if(o >= 0) {
+			l->type = st;
+			if(o == 0)
+				return;
+			n1 = new1(OXXX, Z, Z);
+			*n1 = *l;
+			n2 = new1(OCONST, Z, Z);
+			n2->vconst = o;
+			n2->type = st;
+			l->op = OADD;
+			l->left = n1;
+			l->right = n2;
+		}
+		return;
+	}
+}
+
+/*
+ * a cast that generates no code
+ * (same size move)
+ */
+int
+nocast(Type *t1, Type *t2)
+{
+	int i, b;
+
+	if(t1->nbits)
+		return 0;
+	i = 0;
+	if(t2 != T)
+		i = t2->etype;
+	b = 1<<i;
+	i = 0;
+	if(t1 != T)
+		i = t1->etype;
+	if(b & ncast[i])
+		return 1;
+	return 0;
+}
+
+/*
+ * a cast that has a noop semantic
+ * (small to large, convert)
+ */
+int
+nilcast(Type *t1, Type *t2)
+{
+	int et1, et2;
+
+	if(t1 == T)
+		return 0;
+	if(t1->nbits)
+		return 0;
+	if(t2 == T)
+		return 0;
+	et1 = t1->etype;
+	et2 = t2->etype;
+	if(et1 == et2)
+		return 1;
+	if(typefd[et1] && typefd[et2]) {
+		if(ewidth[et1] < ewidth[et2])
+			return 1;
+		return 0;
+	}
+	if(typechlp[et1] && typechlp[et2]) {
+		if(ewidth[et1] < ewidth[et2])
+			return 1;
+		return 0;
+	}
+	return 0;
+}
+
+/*
+ * "the usual arithmetic conversions are performed"
+ */
+void
+arith(Node *n, int f)
+{
+	Type *t1, *t2;
+	int i, j, k;
+	Node *n1;
+	long w;
+
+	t1 = n->left->type;
+	if(n->right == Z)
+		t2 = t1;
+	else
+		t2 = n->right->type;
+	i = TXXX;
+	if(t1 != T)
+		i = t1->etype;
+	j = TXXX;
+	if(t2 != T)
+		j = t2->etype;
+	k = tab[i][j];
+	if(k == TIND) {
+		if(i == TIND)
+			n->type = t1;
+		else
+		if(j == TIND)
+			n->type = t2;
+	} else {
+		/* convert up to at least int */
+		if(f == 1)
+		while(k < TINT)
+			k += 2;
+		n->type = types[k];
+	}
+	if(n->op == OSUB)
+	if(i == TIND && j == TIND) {
+		w = n->right->type->link->width;
+		if(w < 1 || n->left->type->link == T || n->left->type->link->width < 1)
+			goto bad;
+		n->type = types[ewidth[TIND] <= ewidth[TLONG]? TLONG: TVLONG];
+		if(1 && ewidth[TIND] > ewidth[TLONG]){
+			n1 = new1(OXXX, Z, Z);
+			*n1 = *n;
+			n->op = OCAST;
+			n->left = n1;
+			n->right = Z;
+			n->type = types[TLONG];
+		}
+		if(w > 1) {
+			n1 = new1(OXXX, Z, Z);
+			*n1 = *n;
+			n->op = ODIV;
+			n->left = n1;
+			n1 = new1(OCONST, Z, Z);
+			n1->vconst = w;
+			n1->type = n->type;
+			n->right = n1;
+			w = vlog(n1);
+			if(w >= 0) {
+				n->op = OASHR;
+				n1->vconst = w;
+			}
+		}
+		return;
+	}
+	if(!sametype(n->type, n->left->type)) {
+		n->left = new1(OCAST, n->left, Z);
+		n->left->type = n->type;
+		if(n->type->etype == TIND) {
+			w = n->type->link->width;
+			if(w < 1) {
+				snap(n->type->link);
+				w = n->type->link->width;
+				if(w < 1)
+					goto bad;
+			}
+			if(w > 1) {
+				n1 = new1(OCONST, Z, Z);
+				n1->vconst = w;
+				n1->type = n->type;
+				n->left = new1(OMUL, n->left, n1);
+				n->left->type = n->type;
+			}
+		}
+	}
+	if(n->right != Z)
+	if(!sametype(n->type, n->right->type)) {
+		n->right = new1(OCAST, n->right, Z);
+		n->right->type = n->type;
+		if(n->type->etype == TIND) {
+			w = n->type->link->width;
+			if(w < 1) {
+				snap(n->type->link);
+				w = n->type->link->width;
+				if(w < 1)
+					goto bad;
+			}
+			if(w != 1) {
+				n1 = new1(OCONST, Z, Z);
+				n1->vconst = w;
+				n1->type = n->type;
+				n->right = new1(OMUL, n->right, n1);
+				n->right->type = n->type;
+			}
+		}
+	}
+	return;
+bad:
+	diag(n, "pointer addition not fully declared: %T", n->type->link);
+}
+
+/*
+ * try to rewrite shift & mask
+ */
+void
+simplifyshift(Node *n)
+{
+	ulong c3;
+	int o, s1, s2, c1, c2;
+
+	if(!typechlp[n->type->etype])
+		return;
+	switch(n->op) {
+	default:
+		return;
+	case OASHL:
+		s1 = 0;
+		break;
+	case OLSHR:
+		s1 = 1;
+		break;
+	case OASHR:
+		s1 = 2;
+		break;
+	}
+	if(n->right->op != OCONST)
+		return;
+	if(n->left->op != OAND)
+		return;
+	if(n->left->right->op != OCONST)
+		return;
+	switch(n->left->left->op) {
+	default:
+		return;
+	case OASHL:
+		s2 = 0;
+		break;
+	case OLSHR:
+		s2 = 1;
+		break;
+	case OASHR:
+		s2 = 2;
+		break;
+	}
+	if(n->left->left->right->op != OCONST)
+		return;
+
+	c1 = n->right->vconst;
+	c2 = n->left->left->right->vconst;
+	c3 = n->left->right->vconst;
+
+/*
+	if(debug['h'])
+		print("%.3o %ld %ld %d #%.lux\n",
+			(s1<<3)|s2, c1, c2, topbit(c3), c3);
+*/
+
+	o = n->op;
+	switch((s1<<3)|s2) {
+	case 000:	/* (((e <<u c2) & c3) <<u c1) */
+		c3 >>= c2;
+		c1 += c2;
+		if(c1 >= 32)
+			break;
+		goto rewrite1;
+
+	case 002:	/* (((e >>s c2) & c3) <<u c1) */
+		if(topbit(c3) >= (32-c2))
+			break;
+	case 001:	/* (((e >>u c2) & c3) <<u c1) */
+		if(c1 > c2) {
+			c3 <<= c2;
+			c1 -= c2;
+			o = OASHL;
+			goto rewrite1;
+		}
+		c3 <<= c1;
+		if(c1 == c2)
+			goto rewrite0;
+		c1 = c2-c1;
+		o = OLSHR;
+		goto rewrite2;
+
+	case 022:	/* (((e >>s c2) & c3) >>s c1) */
+		if(c2 <= 0)
+			break;
+	case 012:	/* (((e >>s c2) & c3) >>u c1) */
+		if(topbit(c3) >= (32-c2))
+			break;
+		goto s11;
+	case 021:	/* (((e >>u c2) & c3) >>s c1) */
+		if(topbit(c3) >= 31 && c2 <= 0)
+			break;
+		goto s11;
+	case 011:	/* (((e >>u c2) & c3) >>u c1) */
+	s11:
+		c3 <<= c2;
+		c1 += c2;
+		if(c1 >= 32)
+			break;
+		o = OLSHR;
+		goto rewrite1;
+
+	case 020:	/* (((e <<u c2) & c3) >>s c1) */
+		if(topbit(c3) >= 31)
+			break;
+	case 010:	/* (((e <<u c2) & c3) >>u c1) */
+		c3 >>= c1;
+		if(c1 == c2)
+			goto rewrite0;
+		if(c1 > c2) {
+			c1 -= c2;
+			goto rewrite2;
+		}
+		c1 = c2 - c1;
+		o = OASHL;
+		goto rewrite2;
+	}
+	return;
+
+rewrite0:	/* get rid of both shifts */
+if(debug['<'])prtree(n, "rewrite0");
+	*n = *n->left;
+	n->left = n->left->left;
+	n->right->vconst = c3;
+	return;
+rewrite1:	/* get rid of lower shift */
+if(debug['<'])prtree(n, "rewrite1");
+	n->left->left = n->left->left->left;
+	n->left->right->vconst = c3;
+	n->right->vconst = c1;
+	n->op = o;
+	return;
+rewrite2:	/* get rid of upper shift */
+if(debug['<'])prtree(n, "rewrite2");
+	*n = *n->left;
+	n->right->vconst = c3;
+	n->left->right->vconst = c1;
+	n->left->op = o;
+}
+
+int
+side(Node *n)
+{
+
+loop:
+	if(n != Z)
+	switch(n->op) {
+	case OCAST:
+	case ONOT:
+	case OADDR:
+	case OIND:
+		n = n->left;
+		goto loop;
+
+	case OCOND:
+		if(side(n->left))
+			break;
+		n = n->right;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OLE:
+	case OADD:
+	case OSUB:
+	case OMUL:
+	case OLMUL:
+	case ODIV:
+	case OLDIV:
+	case OLSHR:
+	case OASHL:
+	case OASHR:
+	case OAND:
+	case OOR:
+	case OXOR:
+	case OMOD:
+	case OLMOD:
+	case OANDAND:
+	case OOROR:
+	case OCOMMA:
+	case ODOT:
+		if(side(n->left))
+			break;
+		n = n->right;
+		goto loop;
+
+	case OSIGN:
+	case OSIZE:
+	case OCONST:
+	case OSTRING:
+	case OLSTRING:
+	case ONAME:
+		return 0;
+	}
+	return 1;
+}
+
+int
+vconst(Node *n)
+{
+	int i;
+
+	if(n == Z)
+		goto no;
+	if(n->op != OCONST)
+		goto no;
+	if(n->type == T)
+		goto no;
+	switch(n->type->etype)
+	{
+	case TFLOAT:
+	case TDOUBLE:
+		i = 100;
+		if(n->fconst > i || n->fconst < -i)
+			goto no;
+		i = n->fconst;
+		if(i != n->fconst)
+			goto no;
+		return i;
+
+	case TVLONG:
+	case TUVLONG:
+		i = n->vconst;
+		if(i != n->vconst)
+			goto no;
+		return i;
+
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+	case TIND:
+		i = n->vconst;
+		if(i != n->vconst)
+			goto no;
+		return i;
+	}
+no:
+	return -159;	/* first uninteresting constant */
+}
+
+/*
+ * return log(n) if n is a power of 2 constant
+ */
+int
+xlog2(uvlong v)
+{
+	int s, i;
+	uvlong m;
+
+	s = 0;
+	m = MASK(8*sizeof(uvlong));
+	for(i=32; i; i>>=1) {
+		m >>= i;
+		if(!(v & m)) {
+			v >>= i;
+			s += i;
+		}
+	}
+	if(v == 1)
+		return s;
+	return -1;
+}
+
+int
+vlog(Node *n)
+{
+	if(n->op != OCONST)
+		goto bad;
+	if(typefd[n->type->etype])
+		goto bad;
+
+	return xlog2(n->vconst);
+
+bad:
+	return -1;
+}
+
+int
+topbit(ulong v)
+{
+	int i;
+
+	for(i = -1; v; i++)
+		v >>= 1;
+	return i;
+}
+
+/*
+ * try to cast a constant down
+ * rather than cast a variable up
+ * example:
+ *	if(c == 'a')
+ */
+void
+relcon(Node *l, Node *r)
+{
+	vlong v;
+
+	if(l->op != OCONST)
+		return;
+	if(r->op != OCAST)
+		return;
+	if(!nilcast(r->left->type, r->type))
+		return;
+	switch(r->type->etype) {
+	default:
+		return;
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+		v = convvtox(l->vconst, r->type->etype);
+		if(v != l->vconst)
+			return;
+		break;
+	}
+	l->type = r->left->type;
+	*r = *r->left;
+}
+
+int
+relindex(int o)
+{
+
+	switch(o) {
+	default:
+		diag(Z, "bad in relindex: %O", o);
+	case OEQ: return 0;
+	case ONE: return 1;
+	case OLE: return 2;
+	case OLS: return 3;
+	case OLT: return 4;
+	case OLO: return 5;
+	case OGE: return 6;
+	case OHS: return 7;
+	case OGT: return 8;
+	case OHI: return 9;
+	}
+}
+
+Node*
+invert(Node *n)
+{
+	Node *i;
+
+	if(n == Z || n->op != OLIST)
+		return n;
+	i = n;
+	for(n = n->left; n != Z; n = n->left) {
+		if(n->op != OLIST)
+			break;
+		i->left = n->right;
+		n->right = i;
+		i = n;
+	}
+	i->left = n;
+	return i;
+}
+
+int
+bitno(long b)
+{
+	int i;
+
+	for(i=0; i<32; i++)
+		if(b & (1L<<i))
+			return i;
+	diag(Z, "bad in bitno");
+	return 0;
+}
+
+long
+typebitor(long a, long b)
+{
+	long c;
+
+	c = a | b;
+	if(a & b)
+		if((a & b) == BLONG)
+			c |= BVLONG;		/* long long => vlong */
+		else
+			warn(Z, "once is enough: %Q", a & b);
+	return c;
+}
+
+void
+diag(Node *n, char *fmt, ...)
+{
+	char buf[STRINGSZ];
+	va_list arg;
+
+	va_start(arg, fmt);
+	vseprint(buf, buf+sizeof(buf), fmt, arg);
+	va_end(arg);
+	Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+	if(debug['X']){
+		Bflush(&diagbuf);
+		abort();
+	}
+	if(n != Z)
+	if(debug['v'])
+		prtree(n, "diagnostic");
+
+	nerrors++;
+	if(nerrors > 10) {
+		Bprint(&diagbuf, "too many errors\n");
+		errorexit();
+	}
+}
+
+void
+warn(Node *n, char *fmt, ...)
+{
+	char buf[STRINGSZ];
+	va_list arg;
+
+	if(debug['w']) {
+		Bprint(&diagbuf, "warning: ");
+		va_start(arg, fmt);
+		vseprint(buf, buf+sizeof(buf), fmt, arg);
+		va_end(arg);
+		Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+		if(n != Z)
+		if(debug['v'])
+			prtree(n, "warning");
+	}
+}
+
+void
+yyerror(char *fmt, ...)
+{
+	char buf[STRINGSZ];
+	va_list arg;
+
+	/*
+	 * hack to intercept message from yaccpar
+	 */
+	if(strcmp(fmt, "syntax error") == 0) {
+		yyerror("syntax error, last name: %s", symb);
+		return;
+	}
+	va_start(arg, fmt);
+	vseprint(buf, buf+sizeof(buf), fmt, arg);
+	va_end(arg);
+	Bprint(&diagbuf, "%L %s\n", lineno, buf);
+	nerrors++;
+	if(nerrors > 10) {
+		Bprint(&diagbuf, "too many errors\n");
+		errorexit();
+	}
+}
+
+void
+fatal(Node *n, char *fmt, ...)
+{
+	char buf[STRINGSZ];
+	va_list arg;
+
+	va_start(arg, fmt);
+	vseprint(buf, buf+sizeof(buf), fmt, arg);
+	va_end(arg);
+	Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+	if(debug['X']){
+		Bflush(&diagbuf);
+		abort();
+	}
+	if(n != Z)
+	if(debug['v'])
+		prtree(n, "diagnostic");
+
+	nerrors++;
+	errorexit();
+}
+
+ulong	thash1	= 0x2edab8c9;
+ulong	thash2	= 0x1dc74fb8;
+ulong	thash3	= 0x1f241331;
+ulong	thash[NALLTYPES];
+Init	thashinit[] =
+{
+	TXXX,		0x17527bbd,	0,
+	TCHAR,		0x5cedd32b,	0,
+	TUCHAR,		0x552c4454,	0,
+	TSHORT,		0x63040b4b,	0,
+	TUSHORT,	0x32a45878,	0,
+	TINT,		0x4151d5bd,	0,
+	TUINT,		0x5ae707d6,	0,
+	TLONG,		0x5ef20f47,	0,
+	TULONG,		0x36d8eb8f,	0,
+	TVLONG,		0x6e5e9590,	0,
+	TUVLONG,	0x75910105,	0,
+	TFLOAT,		0x25fd7af1,	0,
+	TDOUBLE,	0x7c40a1b2,	0,
+	TIND,		0x1b832357,	0,
+	TFUNC,		0x6babc9cb,	0,
+	TARRAY,		0x7c50986d,	0,
+	TVOID,		0x44112eff,	0,
+	TSTRUCT,	0x7c2da3bf,	0,
+	TUNION,		0x3eb25e98,	0,
+	TENUM,		0x44b54f61,	0,
+	TFILE,		0x19242ac3,	0,
+	TOLD,		0x22b15988,	0,
+	TDOT,		0x0204f6b3,	0,
+	-1,		0,		0,
+};
+
+char*	bnames[NALIGN];
+Init	bnamesinit[] =
+{
+	Axxx,	0,	"Axxx",
+	Ael1,	0,	"el1",
+	Ael2,	0,	"el2",
+	Asu2,	0,	"su2",
+	Aarg0,	0,	"arg0",
+	Aarg1,	0,	"arg1",
+	Aarg2,	0,	"arg2",
+	Aaut3,	0,	"aut3",
+	-1,	0,	0,
+};
+
+char*	tnames[NALLTYPES];
+Init	tnamesinit[] =
+{
+	TXXX,		0,	"TXXX",
+	TCHAR,		0,	"CHAR",
+	TUCHAR,		0,	"UCHAR",
+	TSHORT,		0,	"SHORT",
+	TUSHORT,	0,	"USHORT",
+	TINT,		0,	"INT",
+	TUINT,		0,	"UINT",
+	TLONG,		0,	"LONG",
+	TULONG,		0,	"ULONG",
+	TVLONG,		0,	"VLONG",
+	TUVLONG,	0,	"UVLONG",
+	TFLOAT,		0,	"FLOAT",
+	TDOUBLE,	0,	"DOUBLE",
+	TIND,		0,	"IND",
+	TFUNC,		0,	"FUNC",
+	TARRAY,		0,	"ARRAY",
+	TVOID,		0,	"VOID",
+	TSTRUCT,	0,	"STRUCT",
+	TUNION,		0,	"UNION",
+	TENUM,		0,	"ENUM",
+	TFILE,		0,	"FILE",
+	TOLD,		0,	"OLD",
+	TDOT,		0,	"DOT",
+	-1,		0,	0,
+};
+
+char*	gnames[NGTYPES];
+Init	gnamesinit[] =
+{
+	GXXX,			0,	"GXXX",
+	GCONSTNT,		0,	"CONST",
+	GVOLATILE,		0,	"VOLATILE",
+	GVOLATILE|GCONSTNT,	0,	"CONST-VOLATILE",
+	-1,			0,	0,
+};
+
+char*	qnames[NALLTYPES];
+Init	qnamesinit[] =
+{
+	TXXX,		0,	"TXXX",
+	TCHAR,		0,	"CHAR",
+	TUCHAR,		0,	"UCHAR",
+	TSHORT,		0,	"SHORT",
+	TUSHORT,	0,	"USHORT",
+	TINT,		0,	"INT",
+	TUINT,		0,	"UINT",
+	TLONG,		0,	"LONG",
+	TULONG,		0,	"ULONG",
+	TVLONG,		0,	"VLONG",
+	TUVLONG,	0,	"UVLONG",
+	TFLOAT,		0,	"FLOAT",
+	TDOUBLE,	0,	"DOUBLE",
+	TIND,		0,	"IND",
+	TFUNC,		0,	"FUNC",
+	TARRAY,		0,	"ARRAY",
+	TVOID,		0,	"VOID",
+	TSTRUCT,	0,	"STRUCT",
+	TUNION,		0,	"UNION",
+	TENUM,		0,	"ENUM",
+
+	TAUTO,		0,	"AUTO",
+	TEXTERN,	0,	"EXTERN",
+	TSTATIC,	0,	"STATIC",
+	TTYPEDEF,	0,	"TYPEDEF",
+	TTYPESTR,	0,	"TYPESTR",
+	TREGISTER,	0,	"REGISTER",
+	TCONSTNT,	0,	"CONSTNT",
+	TVOLATILE,	0,	"VOLATILE",
+	TUNSIGNED,	0,	"UNSIGNED",
+	TSIGNED,	0,	"SIGNED",
+	TDOT,		0,	"DOT",
+	TFILE,		0,	"FILE",
+	TOLD,		0,	"OLD",
+	-1,		0,	0,
+};
+char*	cnames[NCTYPES];
+Init	cnamesinit[] =
+{
+	CXXX,		0,	"CXXX",
+	CAUTO,		0,	"AUTO",
+	CEXTERN,	0,	"EXTERN",
+	CGLOBL,		0,	"GLOBL",
+	CSTATIC,	0,	"STATIC",
+	CLOCAL,		0,	"LOCAL",
+	CTYPEDEF,	0,	"TYPEDEF",
+	CTYPESTR,	0,	"TYPESTR",
+	CPARAM,		0,	"PARAM",
+	CSELEM,		0,	"SELEM",
+	CLABEL,		0,	"LABEL",
+	CEXREG,		0,	"EXREG",
+	-1,		0,	0,
+};
+
+char*	onames[OEND+1];
+Init	onamesinit[] =
+{
+	OXXX,		0,	"OXXX",
+	OADD,		0,	"ADD",
+	OADDR,		0,	"ADDR",
+	OAND,		0,	"AND",
+	OANDAND,	0,	"ANDAND",
+	OARRAY,		0,	"ARRAY",
+	OAS,		0,	"AS",
+	OASI,		0,	"ASI",
+	OASADD,		0,	"ASADD",
+	OASAND,		0,	"ASAND",
+	OASASHL,	0,	"ASASHL",
+	OASASHR,	0,	"ASASHR",
+	OASDIV,		0,	"ASDIV",
+	OASHL,		0,	"ASHL",
+	OASHR,		0,	"ASHR",
+	OASLDIV,	0,	"ASLDIV",
+	OASLMOD,	0,	"ASLMOD",
+	OASLMUL,	0,	"ASLMUL",
+	OASLSHR,	0,	"ASLSHR",
+	OASMOD,		0,	"ASMOD",
+	OASMUL,		0,	"ASMUL",
+	OASOR,		0,	"ASOR",
+	OASSUB,		0,	"ASSUB",
+	OASXOR,		0,	"ASXOR",
+	OBIT,		0,	"BIT",
+	OBREAK,		0,	"BREAK",
+	OCASE,		0,	"CASE",
+	OCAST,		0,	"CAST",
+	OCOMMA,		0,	"COMMA",
+	OCOND,		0,	"COND",
+	OCONST,		0,	"CONST",
+	OCONTINUE,	0,	"CONTINUE",
+	ODIV,		0,	"DIV",
+	ODOT,		0,	"DOT",
+	ODOTDOT,	0,	"DOTDOT",
+	ODWHILE,	0,	"DWHILE",
+	OENUM,		0,	"ENUM",
+	OEQ,		0,	"EQ",
+	OFOR,		0,	"FOR",
+	OFUNC,		0,	"FUNC",
+	OGE,		0,	"GE",
+	OGOTO,		0,	"GOTO",
+	OGT,		0,	"GT",
+	OHI,		0,	"HI",
+	OHS,		0,	"HS",
+	OIF,		0,	"IF",
+	OIND,		0,	"IND",
+	OINDREG,	0,	"INDREG",
+	OINIT,		0,	"INIT",
+	OLABEL,		0,	"LABEL",
+	OLDIV,		0,	"LDIV",
+	OLE,		0,	"LE",
+	OLIST,		0,	"LIST",
+	OLMOD,		0,	"LMOD",
+	OLMUL,		0,	"LMUL",
+	OLO,		0,	"LO",
+	OLS,		0,	"LS",
+	OLSHR,		0,	"LSHR",
+	OLT,		0,	"LT",
+	OMOD,		0,	"MOD",
+	OMUL,		0,	"MUL",
+	ONAME,		0,	"NAME",
+	ONE,		0,	"NE",
+	ONOT,		0,	"NOT",
+	OOR,		0,	"OR",
+	OOROR,		0,	"OROR",
+	OPOSTDEC,	0,	"POSTDEC",
+	OPOSTINC,	0,	"POSTINC",
+	OPREDEC,	0,	"PREDEC",
+	OPREINC,	0,	"PREINC",
+	OPROTO,		0,	"PROTO",
+	OREGISTER,	0,	"REGISTER",
+	ORETURN,	0,	"RETURN",
+	OSET,		0,	"SET",
+	OSIGN,		0,	"SIGN",
+	OSIZE,		0,	"SIZE",
+	OSTRING,	0,	"STRING",
+	OLSTRING,	0,	"LSTRING",
+	OSTRUCT,	0,	"STRUCT",
+	OSUB,		0,	"SUB",
+	OSWITCH,	0,	"SWITCH",
+	OUNION,		0,	"UNION",
+	OUSED,		0,	"USED",
+	OWHILE,		0,	"WHILE",
+	OXOR,		0,	"XOR",
+	OPOS,		0,	"POS",
+	ONEG,		0,	"NEG",
+	OCOM,		0,	"COM",
+	OELEM,		0,	"ELEM",
+	OTST,		0,	"TST",
+	OINDEX,		0,	"INDEX",
+	OFAS,		0,	"FAS",
+	OREGPAIR,	0,	"REGPAIR",
+	OEND,		0,	"END",
+	-1,		0,	0,
+};
+
+/*	OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
+uchar	comrel[12] =
+{
+	ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS,
+};
+uchar	invrel[12] =
+{
+	OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO,
+};
+uchar	logrel[12] =
+{
+	OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI,
+};
+
+uchar	typei[NTYPE];
+int	typeiinit[] =
+{
+	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1,
+};
+uchar	typeu[NTYPE];
+int	typeuinit[] =
+{
+	TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1,
+};
+
+uchar	typesuv[NTYPE];
+int	typesuvinit[] =
+{
+	TVLONG, TUVLONG, TSTRUCT, TUNION, -1,
+};
+
+uchar	typeilp[NTYPE];
+int	typeilpinit[] =
+{
+	TINT, TUINT, TLONG, TULONG, TIND, -1
+};
+
+uchar	typechl[NTYPE];
+uchar	typechlv[NTYPE];
+uchar	typechlvp[NTYPE];
+int	typechlinit[] =
+{
+	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1,
+};
+
+uchar	typechlp[NTYPE];
+int	typechlpinit[] =
+{
+	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1,
+};
+
+uchar	typechlpfd[NTYPE];
+int	typechlpfdinit[] =
+{
+	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1,
+};
+
+uchar	typec[NTYPE];
+int	typecinit[] =
+{
+	TCHAR, TUCHAR, -1
+};
+
+uchar	typeh[NTYPE];
+int	typehinit[] =
+{
+	TSHORT, TUSHORT, -1,
+};
+
+uchar	typeil[NTYPE];
+int	typeilinit[] =
+{
+	TINT, TUINT, TLONG, TULONG, -1,
+};
+
+uchar	typev[NTYPE];
+int	typevinit[] =
+{
+	TVLONG,	TUVLONG, -1,
+};
+
+uchar	typefd[NTYPE];
+int	typefdinit[] =
+{
+	TFLOAT, TDOUBLE, -1,
+};
+
+uchar	typeaf[NTYPE];
+int	typeafinit[] =
+{
+	TFUNC, TARRAY, -1,
+};
+
+uchar	typesu[NTYPE];
+int	typesuinit[] =
+{
+	TSTRUCT, TUNION, -1,
+};
+
+long	tasign[NTYPE];
+Init	tasigninit[] =
+{
+	TCHAR,		BNUMBER,	0,
+	TUCHAR,		BNUMBER,	0,
+	TSHORT,		BNUMBER,	0,
+	TUSHORT,	BNUMBER,	0,
+	TINT,		BNUMBER,	0,
+	TUINT,		BNUMBER,	0,
+	TLONG,		BNUMBER,	0,
+	TULONG,		BNUMBER,	0,
+	TVLONG,		BNUMBER,	0,
+	TUVLONG,	BNUMBER,	0,
+	TFLOAT,		BNUMBER,	0,
+	TDOUBLE,	BNUMBER,	0,
+	TIND,		BIND,		0,
+	TSTRUCT,	BSTRUCT,	0,
+	TUNION,		BUNION,		0,
+	-1,		0,		0,
+};
+
+long	tasadd[NTYPE];
+Init	tasaddinit[] =
+{
+	TCHAR,		BNUMBER,	0,
+	TUCHAR,		BNUMBER,	0,
+	TSHORT,		BNUMBER,	0,
+	TUSHORT,	BNUMBER,	0,
+	TINT,		BNUMBER,	0,
+	TUINT,		BNUMBER,	0,
+	TLONG,		BNUMBER,	0,
+	TULONG,		BNUMBER,	0,
+	TVLONG,		BNUMBER,	0,
+	TUVLONG,	BNUMBER,	0,
+	TFLOAT,		BNUMBER,	0,
+	TDOUBLE,	BNUMBER,	0,
+	TIND,		BINTEGER,	0,
+	-1,		0,		0,
+};
+
+long	tcast[NTYPE];
+Init	tcastinit[] =
+{
+	TCHAR,		BNUMBER|BIND|BVOID,	0,
+	TUCHAR,		BNUMBER|BIND|BVOID,	0,
+	TSHORT,		BNUMBER|BIND|BVOID,	0,
+	TUSHORT,	BNUMBER|BIND|BVOID,	0,
+	TINT,		BNUMBER|BIND|BVOID,	0,
+	TUINT,		BNUMBER|BIND|BVOID,	0,
+	TLONG,		BNUMBER|BIND|BVOID,	0,
+	TULONG,		BNUMBER|BIND|BVOID,	0,
+	TVLONG,		BNUMBER|BIND|BVOID,	0,
+	TUVLONG,	BNUMBER|BIND|BVOID,	0,
+	TFLOAT,		BNUMBER|BVOID,		0,
+	TDOUBLE,	BNUMBER|BVOID,		0,
+	TIND,		BINTEGER|BIND|BVOID,	0,
+	TVOID,		BVOID,			0,
+	TSTRUCT,	BSTRUCT|BVOID,		0,
+	TUNION,		BUNION|BVOID,		0,
+	-1,		0,			0,
+};
+
+long	tadd[NTYPE];
+Init	taddinit[] =
+{
+	TCHAR,		BNUMBER|BIND,	0,
+	TUCHAR,		BNUMBER|BIND,	0,
+	TSHORT,		BNUMBER|BIND,	0,
+	TUSHORT,	BNUMBER|BIND,	0,
+	TINT,		BNUMBER|BIND,	0,
+	TUINT,		BNUMBER|BIND,	0,
+	TLONG,		BNUMBER|BIND,	0,
+	TULONG,		BNUMBER|BIND,	0,
+	TVLONG,		BNUMBER|BIND,	0,
+	TUVLONG,	BNUMBER|BIND,	0,
+	TFLOAT,		BNUMBER,	0,
+	TDOUBLE,	BNUMBER,	0,
+	TIND,		BINTEGER,	0,
+	-1,		0,		0,
+};
+
+long	tsub[NTYPE];
+Init	tsubinit[] =
+{
+	TCHAR,		BNUMBER,	0,
+	TUCHAR,		BNUMBER,	0,
+	TSHORT,		BNUMBER,	0,
+	TUSHORT,	BNUMBER,	0,
+	TINT,		BNUMBER,	0,
+	TUINT,		BNUMBER,	0,
+	TLONG,		BNUMBER,	0,
+	TULONG,		BNUMBER,	0,
+	TVLONG,		BNUMBER,	0,
+	TUVLONG,	BNUMBER,	0,
+	TFLOAT,		BNUMBER,	0,
+	TDOUBLE,	BNUMBER,	0,
+	TIND,		BINTEGER|BIND,	0,
+	-1,		0,		0,
+};
+
+long	tmul[NTYPE];
+Init	tmulinit[] =
+{
+	TCHAR,		BNUMBER,	0,
+	TUCHAR,		BNUMBER,	0,
+	TSHORT,		BNUMBER,	0,
+	TUSHORT,	BNUMBER,	0,
+	TINT,		BNUMBER,	0,
+	TUINT,		BNUMBER,	0,
+	TLONG,		BNUMBER,	0,
+	TULONG,		BNUMBER,	0,
+	TVLONG,		BNUMBER,	0,
+	TUVLONG,	BNUMBER,	0,
+	TFLOAT,		BNUMBER,	0,
+	TDOUBLE,	BNUMBER,	0,
+	-1,		0,		0,
+};
+
+long	tand[NTYPE];
+Init	tandinit[] =
+{
+	TCHAR,		BINTEGER,	0,
+	TUCHAR,		BINTEGER,	0,
+	TSHORT,		BINTEGER,	0,
+	TUSHORT,	BINTEGER,	0,
+	TINT,		BNUMBER,	0,
+	TUINT,		BNUMBER,	0,
+	TLONG,		BINTEGER,	0,
+	TULONG,		BINTEGER,	0,
+	TVLONG,		BINTEGER,	0,
+	TUVLONG,	BINTEGER,	0,
+	-1,		0,		0,
+};
+
+long	trel[NTYPE];
+Init	trelinit[] =
+{
+	TCHAR,		BNUMBER,	0,
+	TUCHAR,		BNUMBER,	0,
+	TSHORT,		BNUMBER,	0,
+	TUSHORT,	BNUMBER,	0,
+	TINT,		BNUMBER,	0,
+	TUINT,		BNUMBER,	0,
+	TLONG,		BNUMBER,	0,
+	TULONG,		BNUMBER,	0,
+	TVLONG,		BNUMBER,	0,
+	TUVLONG,	BNUMBER,	0,
+	TFLOAT,		BNUMBER,	0,
+	TDOUBLE,	BNUMBER,	0,
+	TIND,		BIND,		0,
+	-1,		0,		0,
+};
+
+long	tfunct[1] =
+{
+	BFUNC,
+};
+
+long	tindir[1] =
+{
+	BIND,
+};
+
+long	tdot[1] =
+{
+	BSTRUCT|BUNION,
+};
+
+long	tnot[1] =
+{
+	BNUMBER|BIND,
+};
+
+long	targ[1] =
+{
+	BNUMBER|BIND|BSTRUCT|BUNION,
+};
+
+uchar	tab[NTYPE][NTYPE] =
+{
+/*TXXX*/	{ 0,
+		},
+
+/*TCHAR*/	{ 0,	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+			TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TUCHAR*/	{ 0,	TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+			TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TSHORT*/	{ 0,	TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+			TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TUSHORT*/	{ 0,	TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+			TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TINT*/	{ 0,	TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG,
+			TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TUINT*/	{ 0,	TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG,
+			TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TLONG*/	{ 0,	TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG,
+			TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TULONG*/	{ 0,	TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG,
+			TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TVLONG*/	{ 0,	TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG,
+			TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TUVLONG*/	{ 0,	TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG,
+			TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TFLOAT*/	{ 0,	TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT,
+			TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND,
+		},
+/*TDOUBLE*/	{ 0,	TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE,
+			TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND,
+		},
+/*TIND*/	{ 0,	TIND, TIND, TIND, TIND, TIND, TIND, TIND,
+			 TIND, TIND, TIND, TIND, TIND, TIND,
+		},
+};
+
+void
+urk(char *name, int max, int i)
+{
+	if(i >= max) {
+		fprint(2, "bad tinit: %s %d>=%d\n", name, i, max);
+		exits("init");
+	}
+}
+
+void
+tinit(void)
+{
+	int *ip;
+	Init *p;
+
+	for(p=thashinit; p->code >= 0; p++) {
+		urk("thash", nelem(thash), p->code);
+		thash[p->code] = p->value;
+	}
+	for(p=bnamesinit; p->code >= 0; p++) {
+		urk("bnames", nelem(bnames), p->code);
+		bnames[p->code] = p->s;
+	}
+	for(p=tnamesinit; p->code >= 0; p++) {
+		urk("tnames", nelem(tnames), p->code);
+		tnames[p->code] = p->s;
+	}
+	for(p=gnamesinit; p->code >= 0; p++) {
+		urk("gnames", nelem(gnames), p->code);
+		gnames[p->code] = p->s;
+	}
+	for(p=qnamesinit; p->code >= 0; p++) {
+		urk("qnames", nelem(qnames), p->code);
+		qnames[p->code] = p->s;
+	}
+	for(p=cnamesinit; p->code >= 0; p++) {
+		urk("cnames", nelem(cnames), p->code);
+		cnames[p->code] = p->s;
+	}
+	for(p=onamesinit; p->code >= 0; p++) {
+		urk("onames", nelem(onames), p->code);
+		onames[p->code] = p->s;
+	}
+	for(ip=typeiinit; *ip>=0; ip++) {
+		urk("typei", nelem(typei), *ip);
+		typei[*ip] = 1;
+	}
+	for(ip=typeuinit; *ip>=0; ip++) {
+		urk("typeu", nelem(typeu), *ip);
+		typeu[*ip] = 1;
+	}
+	for(ip=typesuvinit; *ip>=0; ip++) {
+		urk("typesuv", nelem(typesuv), *ip);
+		typesuv[*ip] = 1;
+	}
+	for(ip=typeilpinit; *ip>=0; ip++) {
+		urk("typeilp", nelem(typeilp), *ip);
+		typeilp[*ip] = 1;
+	}
+	for(ip=typechlinit; *ip>=0; ip++) {
+		urk("typechl", nelem(typechl), *ip);
+		typechl[*ip] = 1;
+		typechlv[*ip] = 1;
+		typechlvp[*ip] = 1;
+	}
+	for(ip=typechlpinit; *ip>=0; ip++) {
+		urk("typechlp", nelem(typechlp), *ip);
+		typechlp[*ip] = 1;
+		typechlvp[*ip] = 1;
+	}
+	for(ip=typechlpfdinit; *ip>=0; ip++) {
+		urk("typechlpfd", nelem(typechlpfd), *ip);
+		typechlpfd[*ip] = 1;
+	}
+	for(ip=typecinit; *ip>=0; ip++) {
+		urk("typec", nelem(typec), *ip);
+		typec[*ip] = 1;
+	}
+	for(ip=typehinit; *ip>=0; ip++) {
+		urk("typeh", nelem(typeh), *ip);
+		typeh[*ip] = 1;
+	}
+	for(ip=typeilinit; *ip>=0; ip++) {
+		urk("typeil", nelem(typeil), *ip);
+		typeil[*ip] = 1;
+	}
+	for(ip=typevinit; *ip>=0; ip++) {
+		urk("typev", nelem(typev), *ip);
+		typev[*ip] = 1;
+		typechlv[*ip] = 1;
+		typechlvp[*ip] = 1;
+	}
+	for(ip=typefdinit; *ip>=0; ip++) {
+		urk("typefd", nelem(typefd), *ip);
+		typefd[*ip] = 1;
+	}
+	for(ip=typeafinit; *ip>=0; ip++) {
+		urk("typeaf", nelem(typeaf), *ip);
+		typeaf[*ip] = 1;
+	}
+	for(ip=typesuinit; *ip >= 0; ip++) {
+		urk("typesu", nelem(typesu), *ip);
+		typesu[*ip] = 1;
+	}
+	for(p=tasigninit; p->code >= 0; p++) {
+		urk("tasign", nelem(tasign), p->code);
+		tasign[p->code] = p->value;
+	}
+	for(p=tasaddinit; p->code >= 0; p++) {
+		urk("tasadd", nelem(tasadd), p->code);
+		tasadd[p->code] = p->value;
+	}
+	for(p=tcastinit; p->code >= 0; p++) {
+		urk("tcast", nelem(tcast), p->code);
+		tcast[p->code] = p->value;
+	}
+	for(p=taddinit; p->code >= 0; p++) {
+		urk("tadd", nelem(tadd), p->code);
+		tadd[p->code] = p->value;
+	}
+	for(p=tsubinit; p->code >= 0; p++) {
+		urk("tsub", nelem(tsub), p->code);
+		tsub[p->code] = p->value;
+	}
+	for(p=tmulinit; p->code >= 0; p++) {
+		urk("tmul", nelem(tmul), p->code);
+		tmul[p->code] = p->value;
+	}
+	for(p=tandinit; p->code >= 0; p++) {
+		urk("tand", nelem(tand), p->code);
+		tand[p->code] = p->value;
+	}
+	for(p=trelinit; p->code >= 0; p++) {
+		urk("trel", nelem(trel), p->code);
+		trel[p->code] = p->value;
+	}
+	
+	/* 32-bit defaults */
+	typeword = typechlp;
+	typecmplx = typesuv;
+}
+
+/*
+ * return 1 if it is impossible to jump into the middle of n.
+ */
+static int
+deadhead(Node *n, int caseok)
+{
+loop:
+	if(n == Z)
+		return 1;
+	switch(n->op) {
+	case OLIST:
+		if(!deadhead(n->left, caseok))
+			return 0;
+	rloop:
+		n = n->right;
+		goto loop;
+
+	case ORETURN:
+		break;
+
+	case OLABEL:
+		return 0;
+
+	case OGOTO:
+		break;
+
+	case OCASE:
+		if(!caseok)
+			return 0;
+		goto rloop;
+
+	case OSWITCH:
+		return deadhead(n->right, 1);
+
+	case OWHILE:
+	case ODWHILE:
+		goto rloop;
+
+	case OFOR:
+		goto rloop;
+
+	case OCONTINUE:
+		break;
+
+	case OBREAK:
+		break;
+
+	case OIF:
+		return deadhead(n->right->left, caseok) && deadhead(n->right->right, caseok);
+
+	case OSET:
+	case OUSED:
+		break;
+	}
+	return 1;
+}
+
+int
+deadheads(Node *c)
+{
+	return deadhead(c->left, 0) && deadhead(c->right, 0);
+}
+
+int
+mixedasop(Type *l, Type *r)
+{
+	return !typefd[l->etype] && typefd[r->etype];
+}
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
new file mode 100644
index 0000000..cc8e732
--- /dev/null
+++ b/src/cmd/gc/const.c
@@ -0,0 +1,370 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include	"go.h"
+#define	TUP(x,y)	(((x)<<16)|(y))
+
+void
+convlit(Node *n, Type *t)
+{
+	int et;
+
+	if(n->op != OLITERAL)
+		return;
+	if(t == T)
+		return;
+
+	n->type = t;
+	et = t->etype;
+
+	switch(whatis(n)) {
+	case Wlitint:
+		if(isptrto(t, TSTRING)) {
+			Rune rune;
+			int l;
+			String *s;
+
+			rune = n->val.vval;
+			l = runelen(rune);
+			s = mal(sizeof(*s)+l);
+			s->len = l;
+			runetochar((char*)(s->s), &rune);
+
+			n->val.sval = s;
+			n->val.ctype = CTSTR;
+			break;
+		}
+		if(isint[et]) {
+			if(n->val.vval < minintval[et])
+				goto bad2;
+			if(n->val.vval > maxintval[et])
+				goto bad2;
+			break;
+		}
+		if(isfloat[et]) {
+			if(n->val.vval < minfloatval[et])
+				goto bad2;
+			if(n->val.vval > maxfloatval[et])
+				goto bad2;
+			n->val.dval = n->val.vval;
+			n->val.ctype = CTFLT;
+			break;
+		}
+		goto bad1;
+
+	case Wlitfloat:
+		if(isint[et]) {
+			if(n->val.dval < minintval[et])
+				goto bad2;
+			if(n->val.dval > maxintval[et])
+				goto bad2;
+			n->val.vval = n->val.dval;
+			n->val.ctype = CTINT;
+			break;
+		}
+		if(isfloat[et]) {
+			if(n->val.dval < minfloatval[et])
+				goto bad2;
+			if(n->val.dval > maxfloatval[et])
+				goto bad2;
+			break;
+		}
+		goto bad1;
+	}
+	return;
+
+bad1:
+	yyerror("illegal conversion of constant to %T", t);
+	return;
+
+bad2:
+	yyerror("overflow converting constant to %T", t);
+	return;
+}
+
+void
+evconst(Node *n)
+{
+	Node *nl, *nr;
+	long len;
+	String *str;
+	int wl, wr;
+
+	nl = n->left;
+	if(nl == N)
+		return;
+
+	wl = whatis(nl);
+	switch(wl) {
+	default:
+		return;
+
+	case Wlitint:
+	case Wlitfloat:
+	case Wlitbool:
+	case Wlitstr:
+		break;
+	}
+
+	nr = n->right;
+	if(nr == N)
+		goto unary;
+
+	wr = whatis(nr);
+	switch(wr) {
+	default:
+		return;
+
+	case Wlitint:
+	case Wlitfloat:
+	case Wlitbool:
+	case Wlitstr:
+		break;
+	}
+	if(wl != wr) {
+		yyerror("illegal combination of literals %d %d", nl->etype, nr->etype);
+		return;
+	}
+
+	switch(TUP(n->op, wl)) {
+	default:
+		yyerror("illegal combination of literals %O %d", n->op, wl);
+		return;
+
+	case TUP(OADD, Wlitint):
+		nl->val.vval += nr->val.vval;
+		break;
+	case TUP(OSUB, Wlitint):
+		nl->val.vval -= nr->val.vval;
+		break;
+	case TUP(OMUL, Wlitint):
+		nl->val.vval *= nr->val.vval;
+		break;
+	case TUP(ODIV, Wlitint):
+		nl->val.vval /= nr->val.vval;
+		break;
+	case TUP(OMOD, Wlitint):
+		nl->val.vval %= nr->val.vval;
+		break;
+	case TUP(OLSH, Wlitint):
+		nl->val.vval <<= nr->val.vval;
+		break;
+	case TUP(ORSH, Wlitint):
+		nl->val.vval >>= nr->val.vval;
+		break;
+	case TUP(OOR, Wlitint):
+		nl->val.vval |= nr->val.vval;
+		break;
+	case TUP(OAND, Wlitint):
+		nl->val.vval &= nr->val.vval;
+		break;
+
+	case TUP(OADD, Wlitfloat):
+		nl->val.dval += nr->val.dval;
+		break;
+	case TUP(OSUB, Wlitfloat):
+		nl->val.dval -= nr->val.dval;
+		break;
+	case TUP(OMUL, Wlitfloat):
+		nl->val.dval *= nr->val.dval;
+		break;
+	case TUP(ODIV, Wlitfloat):
+		nl->val.dval /= nr->val.dval;
+		break;
+
+	case TUP(OEQ, Wlitint):
+		if(nl->val.vval == nr->val.vval)
+			goto settrue;
+		goto setfalse;
+	case TUP(ONE, Wlitint):
+		if(nl->val.vval != nr->val.vval)
+			goto settrue;
+		goto setfalse;
+	case TUP(OLT, Wlitint):
+		if(nl->val.vval < nr->val.vval)
+			goto settrue;
+		goto setfalse;
+	case TUP(OLE, Wlitint):
+		if(nl->val.vval <= nr->val.vval)
+			goto settrue;
+		goto setfalse;
+	case TUP(OGE, Wlitint):
+		if(nl->val.vval >= nr->val.vval)
+			goto settrue;
+		goto setfalse;
+	case TUP(OGT, Wlitint):
+		if(nl->val.vval > nr->val.vval)
+			goto settrue;
+		goto setfalse;
+
+	case TUP(OEQ, Wlitfloat):
+		if(nl->val.dval == nr->val.dval)
+			goto settrue;
+		goto setfalse;
+	case TUP(ONE, Wlitfloat):
+		if(nl->val.dval != nr->val.dval)
+			goto settrue;
+		goto setfalse;
+	case TUP(OLT, Wlitfloat):
+		if(nl->val.dval < nr->val.dval)
+			goto settrue;
+		goto setfalse;
+	case TUP(OLE, Wlitfloat):
+		if(nl->val.dval <= nr->val.dval)
+			goto settrue;
+		goto setfalse;
+	case TUP(OGE, Wlitfloat):
+		if(nl->val.dval >= nr->val.dval)
+			goto settrue;
+		goto setfalse;
+	case TUP(OGT, Wlitfloat):
+		if(nl->val.dval > nr->val.dval)
+			goto settrue;
+		goto setfalse;
+
+
+	case TUP(OEQ, Wlitstr):
+		if(cmpslit(nl, nr) == 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(ONE, Wlitstr):
+		if(cmpslit(nl, nr) != 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OLT, Wlitstr):
+		if(cmpslit(nl, nr) < 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OLE, Wlitstr):
+		if(cmpslit(nl, nr) <= 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OGE, Wlitstr):
+		if(cmpslit(nl, nr) >= 0l)
+			goto settrue;
+		goto setfalse;
+	case TUP(OGT, Wlitstr):
+		if(cmpslit(nl, nr) > 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OADD, Wlitstr):
+		len = nl->val.sval->len + nr->val.sval->len;
+		str = mal(sizeof(*str) + len);
+		str->len = len;
+		memcpy(str->s, nl->val.sval->s, nl->val.sval->len);
+		memcpy(str->s+nl->val.sval->len, nr->val.sval->s, nr->val.sval->len);
+		str->len = len;
+		nl->val.sval = str;
+		break;
+
+	case TUP(OOROR, Wlitbool):
+		if(nl->val.vval || nr->val.vval)
+			goto settrue;
+		goto setfalse;
+	case TUP(OANDAND, Wlitbool):
+		if(nl->val.vval && nr->val.vval)
+			goto settrue;
+		goto setfalse;
+	}
+	*n = *nl;
+	return;
+
+settrue:
+	*n = *booltrue;
+	return;
+
+setfalse:
+	*n = *boolfalse;
+	return;
+
+unary:
+	switch(TUP(n->op, wl)) {
+	default:
+		yyerror("illegal combination of literals %O %d", n->op, wl);
+		return;
+
+	case TUP(OPLUS, Wlitint):
+		nl->val.vval = +nl->val.vval;
+		break;
+	case TUP(OMINUS, Wlitint):
+		nl->val.vval = -nl->val.vval;
+		break;
+	case TUP(OCOM, Wlitint):
+		nl->val.vval = ~nl->val.vval;
+		break;
+
+	case TUP(OPLUS, Wlitfloat):
+		nl->val.dval = +nl->val.dval;
+		break;
+	case TUP(OMINUS, Wlitfloat):
+		nl->val.dval = -nl->val.dval;
+		break;
+
+	case TUP(ONOT, Wlitbool):
+		if(nl->val.vval)
+			goto settrue;
+		goto setfalse;
+	}
+	*n = *nl;
+}
+
+void
+defaultlit(Node *n)
+{
+	if(n == N)
+		return;
+	if(n->type != T)
+		return;
+	if(n->op != OLITERAL)
+		return;
+
+	switch(n->val.ctype) {
+	default:
+		yyerror("defaultlit: unknown literal: %N", n);
+		break;
+	case CTINT:
+	case CTSINT:
+	case CTUINT:
+		n->type = types[TINT32];
+		break;
+	case CTFLT:
+		n->type = types[TFLOAT64];
+		break;
+	case CTBOOL:
+		n->type = types[TBOOL];
+		break;
+	case CTSTR:
+		n->type = types[TSTRING];
+		break;
+	}
+}
+
+int
+cmpslit(Node *l, Node *r)
+{
+	long l1, l2, i, m;
+	char *s1, *s2;
+
+	l1 = l->val.sval->len;
+	l2 = r->val.sval->len;
+	s1 = l->val.sval->s;
+	s2 = r->val.sval->s;
+
+	m = l1;
+	if(l2 < m)
+		m = l2;
+
+	for(i=0; i<m; i++) {
+		if(s1[i] == s2[i])
+			continue;
+		if(s1[i] > s2[i])
+			return +1;
+		return -1;
+	}
+	if(l1 == l2)
+		return 0;
+	if(l1 > l2)
+		return +1;
+	return -1;
+}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
new file mode 100644
index 0000000..3eae5f3
--- /dev/null
+++ b/src/cmd/gc/dcl.c
@@ -0,0 +1,814 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include	"go.h"
+#include	"y.tab.h"
+
+void
+dodclvar(Node *n, Type *t)
+{
+
+loop:
+	if(n == N)
+		return;
+
+	if(n->op == OLIST) {
+		dodclvar(n->left, t);
+		n = n->right;
+		goto loop;
+	}
+
+	addvar(n, t, dclcontext);
+}
+
+void
+dodcltype(Type *n, Type *t)
+{
+
+	if(n == T)
+		return;
+	addtyp(n, t, dclcontext);
+}
+
+void
+dodclconst(Node *n, Node *e)
+{
+	Sym *s;
+	Dcl *r, *d;
+
+loop:
+	if(n == N)
+		return;
+	if(n->op == OLIST) {
+		dodclconst(n->left, e);
+		n = n->right;
+		goto loop;
+	}
+
+	if(n->op != ONAME)
+		fatal("dodclconst: not a name");
+
+	if(e->op != OLITERAL) {
+		yyerror("expression must be a constant");
+		goto loop;
+	}
+	s = n->sym;
+
+	s->oconst = e;
+	s->lexical = LACONST;
+
+	r = autodcl;
+	if(dclcontext == PEXTERN)
+		r = externdcl;
+
+	d = dcl();
+	d->dsym = s;
+	d->dnode = e;
+	d->op = OCONST;
+
+	r->back->forw = d;
+	r->back = d;
+
+	if(debug['d'])
+		print("const-dcl %S %N\n", n->sym, n->sym->oconst);
+}
+
+/*
+ * return nelem of list
+ */
+int
+listcount(Node *n)
+{
+	int v;
+
+	v = 0;
+	while(n != N) {
+		v++;
+		if(n->op != OLIST)
+			break;
+		n = n->right;
+	}
+	return v;
+}
+
+/*
+ * turn a parsed function declaration
+ * into a type
+ */
+Type*
+functype(Node *this, Node *in, Node *out)
+{
+	Type *t;
+
+	t = typ(TFUNC);
+
+	t->type = dostruct(this, TSTRUCT);
+	t->type->down = dostruct(out, TSTRUCT);
+	t->type->down->down = dostruct(in, TSTRUCT);
+
+	t->thistuple = listcount(this);
+	t->outtuple = listcount(out);
+	t->intuple = listcount(in);
+
+	dowidth(t);
+	return t;
+}
+
+void
+funcnam(Type *t, char *nam)
+{
+	Node *n;
+	Sym *s;
+	char buf[100];
+
+	if(nam == nil) {
+		vargen++;
+		snprint(buf, sizeof(buf), "_f%.3ld", vargen);
+		nam = buf;
+	}
+
+	if(t->etype != TFUNC)
+		fatal("funcnam: not func %T\n", t);
+
+	if(t->thistuple > 0) {
+		vargen++;
+		snprint(namebuf, sizeof(namebuf), "_t%.3ld", vargen);
+		s = lookup(namebuf);
+		addtyp(newtype(s), t->type, PEXTERN);
+		n = newname(s);
+		n->vargen = vargen;
+		t->type->nname = n;
+	}
+	if(t->outtuple > 0) {
+		vargen++;
+		snprint(namebuf, sizeof(namebuf), "_o%.3ld", vargen);
+		s = lookup(namebuf);
+		addtyp(newtype(s), t->type->down, PEXTERN);
+		n = newname(s);
+		n->vargen = vargen;
+		t->type->down->nname = n;
+	}
+	if(t->intuple > 0) {
+		vargen++;
+		snprint(namebuf, sizeof(namebuf), "_i%.3ld", vargen);
+		s = lookup(namebuf);
+		addtyp(newtype(s), t->type->down->down, PEXTERN);
+		n = newname(s);
+		n->vargen = vargen;
+		t->type->down->down->nname = n;
+	}
+}
+
+int
+methcmp(Type *t1, Type *t2)
+{
+	if(t1->etype != TFUNC)
+		return 0;
+	if(t2->etype != TFUNC)
+		return 0;
+
+	t1 = t1->type->down;	// skip this arg
+	t2 = t2->type->down;	// skip this arg
+	for(;;) {
+		if(t1 == t2)
+			break;
+		if(t1 == T || t2 == T)
+			return 0;
+		if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
+			return 0;
+
+		if(!eqtype(t1->type, t2->type, 0))
+			return 0;
+
+		t1 = t1->down;
+		t2 = t2->down;
+	}
+	return 1;
+}
+
+Node*
+methodname(Node *n, Type *t)
+{
+	if(isptr[t->etype])
+		t = t->type;
+	if(t->etype != TSTRUCT)
+		goto bad;
+	if(t->sym == S)
+		goto bad;
+
+	snprint(namebuf, sizeof(namebuf), "%s_%s", t->sym->name, n->sym->name);
+	return newname(lookup(namebuf));
+
+bad:
+	yyerror("illegal <this> pointer");
+	return n;
+}
+
+/*
+ * add a method, declared as a function,
+ * into the structure
+ */
+void
+addmethod(Node *n, Type *pa, Type *t)
+{
+	Type *f, *d, *p;
+	Sym *s;
+
+	if(n->op != ONAME)
+		goto bad;
+	s = n->sym;
+	if(s == S)
+		goto bad;
+	if(pa == T)
+		goto bad;
+	if(!isptr[pa->etype])
+		goto bad;
+	p = pa->type;
+	if(p == T)
+		goto bad;
+	if(p->etype != TSTRUCT)
+		goto bad;
+	if(p->sym == S)
+		goto bad;
+
+	if(p->type == T) {
+		n = nod(ODCLFIELD, newname(s), N);
+		n->type = t;
+
+		stotype(n, &p->type);
+		return;
+	}
+
+	d = T;	// last found
+	for(f=p->type; f!=T; f=f->down) {
+		if(f->etype != TFIELD)
+			fatal("addmethod: not TFIELD: %N", f);
+
+		if(strcmp(s->name, f->sym->name) != 0) {
+			d = f;
+			continue;
+		}
+
+		// if a field matches a non-this function
+		// then delete it and let it be redeclared
+		if(methcmp(t, f->type)) {
+			if(d == T) {
+				p->type = f->down;
+				continue;
+			}
+			d->down = f->down;
+			continue;
+		}
+		if(!eqtype(t, f->type, 0))
+			yyerror("field redeclared as method: %S", s);
+		return;
+	}
+
+	n = nod(ODCLFIELD, newname(s), N);
+	n->type = t;
+
+	if(d == T)
+		stotype(n, &p->type);
+	else
+		stotype(n, &d->down);
+	return;
+
+bad:
+	yyerror("unknown method pointer: %T", pa);
+}
+
+/*
+ * declare the function proper.
+ * and declare the arguments
+ * called in extern-declaration context
+ * returns in auto-declaration context.
+ */
+void
+funchdr(Node *n)
+{
+	Node *on;
+	Sym *s;
+
+	s = n->nname->sym;
+	on = s->oname;
+
+	// check for same types
+	if(on != N) {
+		if(eqtype(n->type, on->type, 0)) {
+			if(!eqargs(n->type, on->type))
+				yyerror("foreward declarations not the same: %S", s);
+		} else {
+			yyerror("redeclare of function: %S", s);
+			on = N;
+		}
+	}
+
+	// check for foreward declaration
+	if(on == N) {
+		// initial declaration or redeclaration
+		// declare fun name, argument types and argument names
+		funcnam(n->type, s->name);
+		n->nname->type = n->type;
+		if(n->type->thistuple == 0)
+			addvar(n->nname, n->type, PEXTERN);
+		else
+			n->nname->class = PEXTERN;
+	} else {
+		// identical redeclaration
+		// steal previous names
+		n->nname = on;
+		n->type = on->type;
+		n->class = on->class;
+		n->sym = s;
+		if(debug['d'])
+			print("forew  var-dcl %S %T\n", n->sym, n->type);
+	}
+
+	// change the declaration context from extern to auto
+	autodcl = dcl();
+	autodcl->back = autodcl;
+
+	if(dclcontext != PEXTERN)
+		fatal("funchdr: dclcontext");
+
+	dclcontext = PAUTO;
+	markdcl("func");
+	funcargs(n->type);
+
+	if(n->type->thistuple > 0) {
+		Type *t;
+		t = *getthis(n->type);
+		addmethod(n->nname, t->type->type, n->type);
+	}
+}
+
+void
+funcargs(Type *t)
+{
+	Type *n1;
+	Iter save;
+
+	// declare the this argument
+	n1 = funcfirst(&save, t);
+	while(n1 != T) {
+		if(n1->nname != N)
+			addvar(n1->nname, n1->type, PPARAM);
+		n1 = funcnext(&save);
+	}
+
+	// declare the outgoing arguments
+//	n1 = structfirst(&save, getoutarg(t));
+//	while(n1 != T) {
+//		n1->left = newname(n1->sym);
+//		if(n1->nname != N)
+//			addvar(n1->nname, n1->type, PPARAM);
+//		n1 = structnext(&save);
+//	}
+}
+
+/*
+ * compile the function.
+ * called in auto-declaration context.
+ * returns in extern-declaration context.
+ */
+void
+funcbody(Node *n)
+{
+
+	compile(n);
+
+	// change the declaration context from auto to extern
+	if(dclcontext != PAUTO)
+		fatal("funcbody: dclcontext");
+	popdcl("func");
+	dclcontext = PEXTERN;
+}
+
+/*
+ * turn a parsed struct into a type
+ */
+Type**
+stotype(Node *n, Type **t)
+{
+	Type *f;
+	Iter save;
+
+	n = listfirst(&save, &n);
+
+loop:
+	if(n == N) {
+		*t = T;
+		return t;
+	}
+
+	if(n->op == OLIST) {
+		// recursive because it can be lists of lists
+		t = stotype(n, t);
+		goto next;
+	}
+
+	if(n->op != ODCLFIELD || n->type == T)
+		fatal("stotype: oops %N\n", n);
+
+	if(n->type->etype == TDARRAY)
+		yyerror("type of a structure field cannot be an open array");
+
+	f = typ(TFIELD);
+	f->type = n->type;
+
+	if(n->left != N && n->left->op == ONAME) {
+		f->nname = n->left;
+	} else {
+		vargen++;
+		snprint(namebuf, sizeof(namebuf), "_e%.3ld", vargen);
+		f->nname = newname(lookup(namebuf));
+	}
+	f->sym = f->nname->sym;
+
+	*t = f;
+	t = &f->down;
+
+next:
+	n = listnext(&save);
+	goto loop;
+}
+
+Type*
+dostruct(Node *n, int et)
+{
+	Type *t;
+
+	/*
+	 * convert a parsed id/type list into
+	 * a type for struct/interface/arglist
+	 */
+
+	t = typ(et);
+	stotype(n, &t->type);
+	dowidth(t);
+	return t;
+}
+
+Type*
+sortinter(Type *t)
+{
+	return t;
+}
+
+void
+dcopy(Sym *a, Sym *b)
+{
+	a->name = b->name;
+	a->oname = b->oname;
+	a->otype = b->otype;
+	a->oconst = b->oconst;
+	a->package = b->package;
+	a->opackage = b->opackage;
+	a->forwtype = b->forwtype;
+	a->lexical = b->lexical;
+	a->undef = b->undef;
+	a->vargen = b->vargen;
+}
+
+Sym*
+push(void)
+{
+	Sym *d;
+
+	d = mal(sizeof(*d));
+	d->link = dclstack;
+	dclstack = d;
+	return d;
+}
+
+Sym*
+pushdcl(Sym *s)
+{
+	Sym *d;
+
+	d = push();
+	dcopy(d, s);
+	return d;
+}
+
+void
+popdcl(char *why)
+{
+	Sym *d, *s;
+
+//	if(debug['d'])
+//		print("revert\n");
+	for(d=dclstack; d!=S; d=d->link) {
+		if(d->name == nil)
+			break;
+		s = pkglookup(d->name, d->package);
+		dcopy(s, d);
+		if(debug['d'])
+			print("\t%ld pop %S\n", curio.lineno, s);
+	}
+	if(d == S)
+		fatal("popdcl: no mark");
+	if(strcmp(why, d->package) != 0)
+		fatal("popdcl: pushed as %s poped as %s", d->package, why);
+	dclstack = d->link;
+}
+
+void
+poptodcl(void)
+{
+	Sym *d, *s;
+
+	for(d=dclstack; d!=S; d=d->link) {
+		if(d->name == nil)
+			break;
+		s = pkglookup(d->name, d->package);
+		dcopy(s, d);
+		if(debug['d'])
+			print("\t%ld pop %S\n", curio.lineno, s);
+	}
+	if(d == S)
+		fatal("poptodcl: no mark");
+}
+
+void
+markdcl(char *why)
+{
+	Sym *d;
+
+	d = push();
+	d->name = nil;		// used as a mark in fifo
+	d->package = why;	// diagnostic for unmatched
+//	if(debug['d'])
+//		print("markdcl\n");
+}
+
+void
+markdclstack(void)
+{
+	Sym *d, *s;
+
+	markdcl("fnlit");
+
+	// copy the entire pop of the stack
+	// all the way back to block0.
+	// after this the symbol table is at
+	// block0 and popdcl will restore it.
+	for(d=dclstack; d!=S; d=d->link) {
+		if(d == b0stack)
+			break;
+		if(d->name != nil) {
+			s = pkglookup(d->name, d->package);
+			pushdcl(s);
+			dcopy(s, d);
+		}
+	}
+}
+
+void
+testdclstack(void)
+{
+	Sym *d;
+
+	for(d=dclstack; d!=S; d=d->link) {
+		if(d->name == nil) {
+			yyerror("mark left on the stack");
+			continue;
+		}
+	}
+}
+
+void
+addvar(Node *n, Type *t, int ctxt)
+{
+	Dcl *r, *d;
+	Sym *s;
+	Type *ot;
+	Node *on;
+	int gen;
+
+	if(n==N || n->sym == S || n->op != ONAME || t == T)
+		fatal("addvar: n=%N t=%T nil", n, t);
+
+	ot = t;
+	if(isptr[ot->etype])
+		ot = ot->type;
+
+	if(ot->etype == TSTRUCT && ot->vargen == 0) {
+		vargen++;
+		snprint(namebuf, sizeof(namebuf), "_s%.3ld", vargen);
+		s = lookup(namebuf);
+		addtyp(newtype(s), ot, PEXTERN);
+	}
+
+	s = n->sym;
+	vargen++;
+	gen = vargen;
+
+	r = autodcl;
+	if(ctxt == PEXTERN) {
+		on = s->oname;
+		if(on != N) {
+			if(eqtype(t, on->type, 0)) {
+				warn("%S redeclared", s);
+				return;
+			}
+			yyerror("%S redeclared (%T %T)", s,
+				on->type, t);
+		}
+		r = externdcl;
+		gen = 0;
+	}
+
+	if(ctxt != PEXTERN)
+		pushdcl(s);
+
+	s->vargen = gen;
+	s->oname = n;
+	s->offset = 0;
+
+	n->type = t;
+	n->vargen = gen;
+	n->class = ctxt;
+
+	d = dcl();
+	d->dsym = s;
+	d->dnode = n;
+	d->op = ONAME;
+
+	r->back->forw = d;
+	r->back = d;
+
+	if(debug['d']) {
+		if(ctxt == PEXTERN)
+			print("extern var-dcl %S G%ld %T\n", s, s->vargen, t);
+		else
+			print("auto   var-dcl %S G%ld %T\n", s, s->vargen, t);
+	}
+}
+
+void
+addtyp(Type *n, Type *t, int ctxt)
+{
+	Dcl *r, *d;
+	Sym *s;
+	Type *f, *ot;
+
+	if(n==T || n->sym == S || t == T)
+		fatal("addtyp: n=%T t=%T nil", n, t);
+
+	s = n->sym;
+
+	r = autodcl;
+	if(ctxt == PEXTERN) {
+		ot = s->otype;
+		if(ot != T) {
+			// allow nil interface to be
+			// redeclared as an interface
+			if(ot->etype == TINTER && ot->type == T && t->etype == TINTER) {
+				if(debug['d'])
+					print("forew  typ-dcl %S G%ld %T\n", s, s->vargen, t);
+				s->otype = t;
+				return;
+			}
+			if(eqtype(t, ot, 0)) {
+				warn("%S redeclared", s);
+				return;
+			}
+			yyerror("%S redeclared (%T %T)", s,
+				ot, t);
+		}
+		r = externdcl;
+	}
+
+	if(ctxt != PEXTERN)
+		pushdcl(s);
+
+	if(t->sym != S)
+		warn("addtyp: renaming %S/%lT to %S/%lT", t->sym, t->sym->otype, s, n);
+
+	vargen++;
+	s->vargen = vargen;
+	s->otype = t;
+	s->lexical = LATYPE;
+
+	t->sym = s;
+	t->vargen = vargen;
+
+	for(f=s->forwtype; f!=T; f=f->nforw) {
+		if(!isptr[f->etype])
+			fatal("addtyp: foreward");
+		f->type = t;
+	}
+	s->forwtype = T;
+
+	d = dcl();
+	d->dsym = s;
+	d->dtype = t;
+	d->op = OTYPE;
+
+	r->back->forw = d;
+	r->back = d;
+
+	if(debug['d']) {
+		if(ctxt == PEXTERN)
+			print("extern typ-dcl %S G%ld %T\n", s, s->vargen, t);
+		else
+			print("auto   typ-dcl %S G%ld %T\n", s, s->vargen, t);
+	}
+}
+
+Node*
+fakethis(void)
+{
+	Node *n;
+	Type *t;
+
+	n = nod(ODCLFIELD, N, N);
+	t = dostruct(N, TSTRUCT);
+	t = ptrto(t);
+	n->type = t;
+	return n;
+}
+
+/*
+ * this generates a new name that is
+ * pushed down on the declaration list.
+ * no diagnostics are produced as this
+ * name will soon be declared.
+ */
+Node*
+newname(Sym *s)
+{
+	Node *n;
+
+	n = nod(ONAME, N, N);
+	n->sym = s;
+	n->type = T;
+	n->addable = 1;
+	n->ullman = 0;
+	return n;
+}
+
+/*
+ * this will return an old name
+ * that has already been pushed on the
+ * declaration list. a diagnostic is
+ * generated if no name has been defined.
+ */
+Node*
+oldname(Sym *s)
+{
+	Node *n;
+
+	n = s->oname;
+	if(n == N) {
+		yyerror("%S undefined", s);
+		n = newname(s);
+		dodclvar(n, types[TINT32]);
+	}
+	return n;
+}
+
+/*
+ * same for types
+ */
+Type*
+newtype(Sym *s)
+{
+	Type *t;
+
+	t = typ(TFORW);
+	t->sym = s;
+	t->type = T;
+	return t;
+}
+
+Type*
+oldtype(Sym *s)
+{
+	Type *t;
+
+	t = s->otype;
+	if(t == T)
+		fatal("%S not a type", s); // cant happen
+	return t;
+}
+
+Type*
+forwdcl(Sym *s)
+{
+	Type *t;
+
+	// this type has no meaning and
+	// will cause an error if referenced.
+	// it will be patched when/if the
+	// type is ever assigned.
+
+	t = typ(TFORW);
+	t = ptrto(t);
+
+	t->nforw = s->forwtype;
+	s->forwtype = t;
+	return t;
+}
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
new file mode 100644
index 0000000..336ad63
--- /dev/null
+++ b/src/cmd/gc/export.c
@@ -0,0 +1,578 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include	"go.h"
+#include	"y.tab.h"
+
+void
+markexport(Node *n)
+{
+	Sym *s;
+	Dcl *d, *r;
+
+loop:
+	if(n == N)
+		return;
+	if(n->op == OLIST) {
+		markexport(n->left);
+		n = n->right;
+		goto loop;
+	}
+	if(n->op != OEXPORT)
+		fatal("markexport: op no OEXPORT: %O", n->op);
+
+	s = n->sym;
+	if(n->psym != S)
+		s = pkglookup(n->sym->name, n->psym->name);
+
+	if(s->export != 0)
+		return;
+	s->export = 1;
+
+	d = mal(sizeof(*d));
+	d->dsym = s;
+	d->dnode = N;
+	d->lineno = curio.lineno;
+
+	r = exportlist;
+	d->back = r->back;
+	r->back->forw = d;
+	r->back = d;
+}
+
+void
+reexport(Type *t)
+{
+	Sym *s;
+
+	if(t == T)
+		fatal("reexport: type nil\n");
+
+	s = t->sym;
+	if(s == S/* || s->name[0] == '_'*/) {
+		exportgen++;
+		snprint(namebuf, sizeof(namebuf), "_e%.3ld", exportgen);
+		s = lookup(namebuf);
+		s->lexical = LATYPE;
+		s->otype = t;
+		t->sym = s;
+	}
+	dumpexporttype(s);
+}
+
+void
+dumpexportconst(Sym *s)
+{
+	Node *n;
+	Type *t;
+
+	if(s->exported != 0)
+		return;
+	s->exported = 1;
+
+	n = s->oconst;
+	if(n == N || n->op != OLITERAL)
+		fatal("dumpexportconst: oconst nil: %S\n", s);
+
+	t = n->type;	// may or may not be specified
+	if(t != T)
+		reexport(t);
+
+	Bprint(bout, "\tconst ");
+	if(s->export != 0)
+		Bprint(bout, "!");
+	Bprint(bout, "%lS ", s);
+	if(t != T)
+		Bprint(bout, "%lS ", t->sym);
+
+	switch(n->val.ctype) {
+	default:
+		fatal("dumpexportconst: unknown ctype: %S\n", s);
+	case CTINT:
+	case CTSINT:
+	case CTUINT:
+	case CTBOOL:
+		Bprint(bout, "0x%llux\n", n->val.vval);
+		break;
+	case CTFLT:
+		Bprint(bout, "%.17e\n", n->val.dval);
+		break;
+	case CTSTR:
+		Bprint(bout, "\"%Z\"\n", n->val.sval);
+		break;
+	}
+}
+
+void
+dumpexportvar(Sym *s)
+{
+	Node *n;
+	Type *t;
+
+	if(s->exported != 0)
+		return;
+	s->exported = 1;
+
+	n = s->oname;
+	if(n == N || n->type == T)
+		fatal("dumpexportvar: oname nil: %S\n", s);
+
+	t = n->type;
+	reexport(t);
+
+	Bprint(bout, "\tvar ");
+	if(s->export != 0)
+		Bprint(bout, "!");
+	Bprint(bout, "%lS %lS\n", s, t->sym);
+}
+
+void
+dumpexporttype(Sym *s)
+{
+	Type *t, *f;
+	Sym *ts;
+	int et;
+
+	if(s->exported != 0)
+		return;
+	s->exported = 1;
+
+	t = s->otype;
+	if(t == T)
+		fatal("dumpexporttype: otype nil: %S\n", s);
+	if(t->sym != s)
+		fatal("dumpexporttype: cross reference: %S\n", s);
+
+	et = t->etype;
+	switch(et) {
+	default:
+		if(et < 0 || et >= nelem(types) || types[et] == T)
+			fatal("dumpexporttype: basic type: %S %E\n", s, et);
+		/* type 5 */
+		Bprint(bout, "\ttype %lS %d\n", s, et);
+		break;
+
+	case TARRAY:
+		reexport(t->type);
+
+		/* type 2 */
+		Bprint(bout, "\ttype ");
+		if(s->export != 0)
+			Bprint(bout, "!");
+		Bprint(bout, "%lS [%lud] %lS\n", s, t->bound, t->type->sym);
+		break;
+
+	case TPTR32:
+	case TPTR64:
+		reexport(t->type);
+
+		/* type 6 */
+		Bprint(bout, "\ttype ");
+		if(s->export != 0)
+			Bprint(bout, "!");
+		Bprint(bout, "%lS *%lS\n", s, t->type->sym);
+		break;
+
+	case TFUNC:
+		for(f=t->type; f!=T; f=f->down) {
+			if(f->etype != TSTRUCT)
+				fatal("dumpexporttype: funct not field: %T\n", f);
+			reexport(f);
+		}
+
+		/* type 3 */
+		Bprint(bout, "\ttype ");
+		if(s->export != 0)
+			Bprint(bout, "!");
+		Bprint(bout, "%lS (", s);
+		for(f=t->type; f!=T; f=f->down) {
+			if(f != t->type)
+				Bprint(bout, " ");
+			Bprint(bout, "%lS", f->sym);
+		}
+		Bprint(bout, ")\n");
+		break;
+
+	case TSTRUCT:
+	case TINTER:
+		for(f=t->type; f!=T; f=f->down) {
+			if(f->etype != TFIELD)
+				fatal("dumpexporttype: funct not field: %lT\n", f);
+			reexport(f->type);
+		}
+
+		/* type 4 */
+		Bprint(bout, "\ttype ");
+		if(s->export)
+			Bprint(bout, "!");
+		Bprint(bout, "%lS %c", s, (et==TSTRUCT)? '{': '<');
+		for(f=t->type; f!=T; f=f->down) {
+			ts = f->type->sym;
+			if(f != t->type)
+				Bprint(bout, " ");
+			Bprint(bout, "%s %lS", f->sym->name, ts);
+		}
+		Bprint(bout, "%c\n", (et==TSTRUCT)? '}': '>');
+		break;
+	}
+}
+
+void
+dumpe(Sym *s)
+{
+	switch(s->lexical) {
+	default:
+		yyerror("unknown export symbol: %S\n", s, s->lexical);
+		break;
+	case LPACK:
+		yyerror("package export symbol: %S\n", s);
+		break;
+	case LATYPE:
+	case LBASETYPE:
+		dumpexporttype(s);
+		break;
+	case LNAME:
+		dumpexportvar(s);
+		break;
+	case LACONST:
+		dumpexportconst(s);
+		break;
+	}
+}
+
+void
+dumpexport(void)
+{
+	Dcl *d;
+	long lno;
+
+	lno = dynlineno;
+
+	Bprint(bout, "   import\n");
+	Bprint(bout, "   ((\n");
+
+	// print it depth first
+	for(d=exportlist->forw; d!=D; d=d->forw) {
+		dynlineno = d->lineno;
+		dumpe(d->dsym);
+	}
+
+	Bprint(bout, "   ))\n");
+
+	dynlineno = lno;
+}
+
+/*
+ * ******* import *******
+ */
+Type*
+importlooktype(Node *n)
+{
+	Sym *s;
+
+	if(n->op != OIMPORT)
+		fatal("importlooktype: oops1 %N\n", n);
+
+	s = pkglookup(n->sym->name, n->psym->name);
+	if(s->otype == T)
+		fatal("importlooktype: oops2 %S\n", s);
+
+	return s->otype;
+}
+
+Type**
+importstotype(Node *fl, Type **t, Type *uber)
+{
+	Type *f;
+	Iter save;
+	Node *n;
+
+	n = listfirst(&save, &fl);
+
+loop:
+	if(n == N) {
+		*t = T;
+		return t;
+	}
+	f = typ(TFIELD);
+	f->type = importlooktype(n);
+
+	if(n->fsym != S) {
+		f->nname = newname(n->fsym);
+	} else {
+		vargen++;
+		snprint(namebuf, sizeof(namebuf), "_m%.3ld", vargen);
+		f->nname = newname(lookup(namebuf));
+	}
+	f->sym = f->nname->sym;
+
+	*t = f;
+	t = &f->down;
+
+	n = listnext(&save);
+	goto loop;
+}
+
+int
+importcount(Type *t)
+{
+	int i;
+	Type *f;
+
+	if(t == T || t->etype != TSTRUCT)
+		fatal("importcount: not a struct: %N", t);
+
+	i = 0;
+	for(f=t->type; f!=T; f=f->down)
+		i = i+1;
+	return i;
+}
+
+void
+importfuncnam(Type *t)
+{
+	Node *n;
+	Type *t1;
+
+	if(t->etype != TFUNC)
+		fatal("importfuncnam: not func %T\n", t);
+
+	if(t->thistuple > 0) {
+		t1 = t->type;
+		if(t1->sym == S)
+			fatal("importfuncnam: no this");
+		n = newname(t1->sym);
+		vargen++;
+		n->vargen = vargen;
+		t1->nname = n;
+	}
+	if(t->outtuple > 0) {
+		t1 = t->type->down;
+		if(t1->sym == S)
+			fatal("importfuncnam: no output");
+		n = newname(t1->sym);
+		vargen++;
+		n->vargen = vargen;
+		t1->nname = n;
+	}
+	if(t->intuple > 0) {
+		t1 = t->type->down->down;
+		if(t1->sym == S)
+			fatal("importfuncnam: no input");
+		n = newname(t1->sym);
+		vargen++;
+		n->vargen = vargen;
+		t1->nname = n;
+	}
+}
+
+Sym*
+getimportsym(Node *ss)
+{
+	char *pkg;
+	Sym *s;
+
+	pkg = ss->psym->name;
+	if(pkgmyname != S)
+		pkg = pkgmyname->name;
+
+	s = pkglookup(ss->sym->name, pkg);
+	/* botch - need some diagnostic checking for the following assignment */
+	s->opackage = ss->osym->name;
+	return s;
+}
+
+void
+importaddtyp(Node *ss, Type *t)
+{
+	Sym *s;
+
+	s = getimportsym(ss);
+	if(s->otype == T || !eqtype(t, s->otype, 0)) {
+		addtyp(newtype(s), t, PEXTERN);
+	}
+}
+
+/*
+ * LCONST importsym LITERAL
+ * untyped constant
+ */
+void
+doimportc1(Node *ss, Val *v)
+{
+	Node *n;
+	Sym *s;
+
+	n = nod(OLITERAL, N, N);
+	n->val = *v;
+
+	s = getimportsym(ss);
+	if(s->oconst == N) {
+		// botch sould ask if already declared the same
+		dodclconst(newname(s), n);
+	}
+}
+
+/*
+ * LCONST importsym importsym LITERAL
+ * typed constant
+ */
+void
+doimportc2(Node *ss, Node *st, Val *v)
+{
+	Node *n;
+	Type *t;
+	Sym *s;
+
+	n = nod(OLITERAL, N, N);
+	n->val = *v;
+
+	t = importlooktype(st);
+	n->type = t;
+
+	s = getimportsym(ss);
+	if(s->oconst == N) {
+		// botch sould ask if already declared the same
+		dodclconst(newname(s), n);
+	}
+}
+
+/*
+ * LVAR importsym importsym
+ * variable
+ */
+void
+doimportv1(Node *ss, Node *st)
+{
+	Type *t;
+	Sym *s;
+
+	t = importlooktype(st);
+	s = getimportsym(ss);
+	if(s->oname == N || !eqtype(t, s->oname->type, 0)) {
+		addvar(newname(s), t, dclcontext);
+	}
+}
+
+/*
+ * LTYPE importsym [ importsym ] importsym
+ * array type
+ */
+void
+doimport1(Node *ss, Node *ss1, Node *s)
+{
+	fatal("doimport1");
+}
+
+/*
+ * LTYPE importsym [ LLITERAL ] importsym
+ * array type
+ */
+void
+doimport2(Node *ss, Val *b, Node *st)
+{
+	Type *t;
+	Sym *s;
+
+	t = typ(TARRAY);
+	t->bound = b->vval;
+	s = pkglookup(st->sym->name, st->psym->name);
+	t->type = s->otype;
+
+	importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym '(' importsym_list ')'
+ * function/method type
+ */
+void
+doimport3(Node *ss, Node *n)
+{
+	Type *t;
+
+	t = typ(TFUNC);
+
+	t->type = importlooktype(n->left);
+	t->type->down = importlooktype(n->right->left);
+	t->type->down->down = importlooktype(n->right->right);
+
+	t->thistuple = importcount(t->type);
+	t->outtuple = importcount(t->type->down);
+	t->intuple = importcount(t->type->down->down);
+
+	importfuncnam(t);
+
+	importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym '{' importsym_list '}'
+ * structure type
+ */
+void
+doimport4(Node *ss, Node *n)
+{
+	Type *t;
+
+	t = typ(TSTRUCT);
+	importstotype(n, &t->type, t);
+
+	importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym LLITERAL
+ * basic type
+ */
+void
+doimport5(Node *ss, Val *v)
+{
+	int et;
+	Type *t;
+
+	et = v->vval;
+	if(et <= 0 || et >= nelem(types) || types[et] == T)
+		fatal("doimport5: bad type index: %E\n", et);
+
+	t = typ(et);
+	t->sym = S;
+
+	importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym * importsym
+ * pointer type
+ */
+void
+doimport6(Node *ss, Node *st)
+{
+	Type *t;
+	Sym *s;
+
+	s = pkglookup(st->sym->name, st->psym->name);
+	t = s->otype;
+	if(t == T)
+		t = forwdcl(s);
+	else
+		t = ptrto(t);
+
+	importaddtyp(ss, t);
+}
+
+/*
+ * LTYPE importsym '<' importsym '>'
+ * interface type
+ */
+void
+doimport7(Node *ss, Node *n)
+{
+	Type *t;
+
+	t = typ(TINTER);
+	importstotype(n, &t->type, t);
+
+	importaddtyp(ss, t);
+}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
new file mode 100644
index 0000000..ecd33a8
--- /dev/null
+++ b/src/cmd/gc/go.h
@@ -0,0 +1,553 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+todo:
+	1. dyn arrays
+	2. multi
+	3. block 0
+tothinkabout:
+	2. argument in import
+*/
+
+#include	<u.h>
+#include	<libc.h>
+#include	<bio.h>
+
+#ifndef	EXTERN
+#define EXTERN	extern
+#endif
+enum
+{
+	NHUNK		= 50000,
+	BUFSIZ		= 8192,
+	NSYMB		= 500,
+	NHASH		= 1024,
+	STRINGSZ	= 200,
+	YYMAXDEPTH	= 500,
+	MAXALIGN	= 7,
+	UINF		= 100,
+
+	PRIME1		= 3,
+	PRIME2		= 10007,
+	PRIME3		= 10009,
+	PRIME4		= 10037,
+	PRIME5		= 10039,
+	PRIME6		= 10061,
+	PRIME7		= 10067,
+	PRIME8		= 10079,
+	PRIME9		= 10091,
+};
+
+/*
+ * note this is the representation
+ * of the compilers string literals,
+ * it happens to also be the runtime
+ * representation, ignoring sizes and
+ * alignment, but that may change.
+ */
+typedef	struct	String	String;
+struct	String
+{
+	long	len;
+	char	s[3];	// variable
+};
+
+typedef	struct	Val	Val;
+struct	Val
+{
+	int	ctype;
+	double	dval;
+	vlong	vval;
+	String*	sval;
+};
+
+typedef	struct	Sym	Sym;
+typedef	struct	Node	Node;
+typedef	struct	Type	Type;
+
+struct	Type
+{
+	int	etype;
+	int	chan;
+	uchar	recur;		// to detect loops
+	uchar	trecur;		// to detect loops
+	Sym*	sym;
+	long	vargen;		// unique name for OTYPE/ONAME
+
+	// most nodes
+	Type*	type;
+	vlong	width;		// offset in TFIELD, width in all others
+
+	// TFIELD
+	Type*	down;		// also used in TMAP
+
+	// TPTR
+	Type*	nforw;
+
+	// TFUNCT
+	Type*	this;
+	Type*	argout;
+	Type*	argin;
+	Node*	nname;
+
+	uchar	thistuple;
+	uchar	outtuple;
+	uchar	intuple;
+
+	// TARRAY
+	long	bound;
+};
+#define	T	((Type*)0)
+
+struct	Node
+{
+	int	op;
+
+	// most nodes
+	Node*	left;
+	Node*	right;
+	Type*	type;
+
+	// for-body
+	Node*	ninit;
+	Node*	ntest;
+	Node*	nincr;
+	Node*	nbody;
+
+	// if-body
+	Node*	nelse;
+
+	// cases
+	Node*	ncase;
+
+	// func
+	Node*	nname;
+
+	// OLITERAL
+	Val	val;
+
+	Sym*	osym;		// import
+	Sym*	fsym;		// import
+	Sym*	psym;		// import
+	Sym*	sym;		// various
+	uchar	ullman;		// sethi/ullman number
+	uchar	addable;	// type of addressability - 0 is not addressable
+	uchar	trecur;		// to detect loops
+	uchar	etype;		// op for OASOP, etype for OTYPE, exclam for export
+	uchar	class;		// PPARAM, PAUTO, PEXTERN, PSTATIC
+	long	vargen;		// unique name for OTYPE/ONAME
+	ulong	lineno;
+	vlong	xoffset;
+};
+#define	N	((Node*)0)
+
+struct	Sym
+{
+	char*	opackage;	// original package name
+	char*	package;	// package name
+	char*	name;		// variable name
+	Node*	oname;		// ONAME node if a var
+	Type*	otype;		// TYPE node if a type
+	Node*	oconst;		// OLITERAL node if a const
+	Type*	forwtype;	// TPTR iff foreward declared
+	void*	label;		// pointer to Prog* of label
+	vlong	offset;		// stack location if automatic
+	long	lexical;
+	long	vargen;		// unique variable number
+	uchar	undef;		// a diagnostic has been generated
+	uchar	export;		// marked as export
+	uchar	exported;	// has been exported
+	uchar	sym;		// huffman encoding in object file
+	Sym*	link;
+};
+#define	S	((Sym*)0)
+
+typedef	struct	Dcl	Dcl;
+struct	Dcl
+{
+	int	op;
+	Sym*	dsym;		// for printing only
+	Node*	dnode;		// oname
+	Type*	dtype;		// otype
+	long	lineno;
+
+	Dcl*	forw;
+	Dcl*	back;		// sentinel has pointer to last
+};
+#define	D	((Dcl*)0)
+
+typedef	struct	Iter	Iter;
+struct	Iter
+{
+	int	done;
+	Type*	tfunc;
+	Type*	t;
+	Node**	an;
+	Node*	n;
+};
+
+enum
+{
+	OXXX,
+
+	OTYPE, OCONST, OVAR, OEXPORT, OIMPORT,
+
+	ONAME,
+	ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
+	ODCLFUNC, ODCLFIELD, ODCLARG,
+	OLIST, OCMP,
+	OPTR, OARRAY,
+	ORETURN, OFOR, OIF, OSWITCH, OI2S, OS2I, OI2I,
+	OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL,
+	OGOTO, OPROC, ONEW, OPANIC, OPRINT, OEMPTY,
+
+	OOROR,
+	OANDAND,
+	OEQ, ONE, OLT, OLE, OGE, OGT,
+	OADD, OSUB, OOR, OXOR,
+	OMUL, ODIV, OMOD, OLSH, ORSH, OAND,
+	ODEC, OINC,
+	OLEN,
+	OFUNC,
+	OLABEL,
+	OBREAK,
+	OCONTINUE,
+	OADDR,
+	OIND,
+	OCALL, OCALLMETH, OCALLINTER,
+	OINDEX, OINDEXPTR, OSLICE,
+	ONOT, OCOM, OPLUS, OMINUS, OSEND, ORECV,
+	OLITERAL, OREGISTER, OINDREG,
+	OCONV,
+	OBAD,
+
+	OEND,
+};
+enum
+{
+	Txxx,			// 0
+
+	TINT8,	TUINT8,		// 1
+	TINT16,	TUINT16,
+	TINT32,	TUINT32,
+	TINT64,	TUINT64,
+
+	TFLOAT32,		// 9
+	TFLOAT64,
+	TFLOAT80,
+
+	TBOOL,			// 12
+
+	TPTR32, TPTR64,		// 13
+
+	TFUNC,
+	TARRAY,
+	TDARRAY,
+	TSTRUCT,
+	TCHAN,
+	TMAP,
+	TINTER,
+	TFORW,
+	TFIELD,
+	TANY,
+	TSTRING,
+
+	NTYPE,			// 26
+};
+enum
+{
+	CTxxx,
+
+	CTINT,
+	CTSINT,
+	CTUINT,
+	CTFLT,
+
+	CTSTR,
+	CTBOOL,
+	CTNIL,
+};
+
+enum
+{
+	/* indications for whatis() */
+	Wnil	= 0,
+	Wtnil,
+
+	Wtfloat,
+	Wtint,
+	Wtbool,
+	Wtstr,
+
+	Wlitfloat,
+	Wlitint,
+	Wlitbool,
+	Wlitstr,
+
+	Wtunkn,
+};
+
+enum
+{
+	/* types of channel */
+	Cxxx,
+	Cboth,
+	Crecv,
+	Csend,
+};
+
+enum
+{
+	Pxxx,
+
+	PEXTERN,	// declaration context
+	PAUTO,
+	PPARAM,
+	PSTATIC,
+};
+
+typedef	struct	Io	Io;
+struct	Io
+{
+	char*	infile;
+	Biobuf*	bin;
+	long	lineno;
+	int	peekc;
+	char*	cp;	// used for content when bin==nil
+};
+
+EXTERN	Io	curio;
+EXTERN	Io	pushedio;
+
+EXTERN	char*	outfile;
+EXTERN	char*	package;
+EXTERN	Biobuf*	bout;
+EXTERN	int	nerrors;
+EXTERN	char	namebuf[NSYMB];
+EXTERN	char	debug[256];
+EXTERN	long	dynlineno;
+EXTERN	Sym*	hash[NHASH];
+EXTERN	Sym*	dclstack;
+EXTERN	Sym*	b0stack;
+EXTERN	Sym*	pkgmyname;	// my name for package
+EXTERN	int	tptr;		// either TPTR32 or TPTR64
+extern	char*	sysimport;
+
+EXTERN	Type*	types[NTYPE];
+EXTERN	uchar	isptr[NTYPE];
+EXTERN	uchar	isint[NTYPE];
+EXTERN	uchar	isfloat[NTYPE];
+EXTERN	uchar	issigned[NTYPE];
+EXTERN	uchar	okforeq[NTYPE];
+EXTERN	uchar	okforadd[NTYPE];
+EXTERN	uchar	okforand[NTYPE];
+EXTERN	double	minfloatval[NTYPE];
+EXTERN	double	maxfloatval[NTYPE];
+EXTERN	vlong	minintval[NTYPE];
+EXTERN	vlong	maxintval[NTYPE];
+
+EXTERN	Dcl*	autodcl;
+EXTERN	Dcl*	externdcl;
+EXTERN	Dcl*	exportlist;
+EXTERN	int	dclcontext;	// PEXTERN/PAUTO
+EXTERN	int	importflag;
+
+EXTERN	Node*	booltrue;
+EXTERN	Node*	boolfalse;
+EXTERN	ulong	iota;
+EXTERN	long	vargen;
+EXTERN	long	exportgen;
+
+EXTERN	Node*	retnil;
+EXTERN	Node*	fskel;
+
+EXTERN	char*	context;
+EXTERN	int	thechar;
+EXTERN	char*	thestring;
+EXTERN	char*	hunk;
+EXTERN	long	nhunk;
+EXTERN	long	thunk;
+
+/*
+ *	y.tab.c
+ */
+int	yyparse(void);
+
+/*
+ *	lex.c
+ */
+int	main(int, char*[]);
+void	importfile(Val*);
+void	cannedimports(void);
+void	unimportfile();
+long	yylex(void);
+void	lexinit(void);
+char*	lexname(int);
+long	getr(void);
+int	getnsc(void);
+long	escchar(long, int*);
+int	getc(void);
+void	ungetc(int);
+void	mkpackage(char*);
+
+/*
+ *	mpatof.c
+ */
+int	mpatof(char*, double*);
+int	mpatov(char*, vlong*);
+
+/*
+ *	subr.c
+ */
+void	myexit(int);
+void*	mal(long);
+void*	remal(void*, long, long);
+void	errorexit(void);
+ulong	stringhash(char*);
+Sym*	lookup(char*);
+Sym*	pkglookup(char*, char*);
+void	yyerror(char*, ...);
+void	warn(char*, ...);
+void	fatal(char*, ...);
+Node*	nod(int, Node*, Node*);
+Type*	typ(int);
+Dcl*	dcl(void);
+Node*	rev(Node*);
+Node*	unrev(Node*);
+void	dodump(Node*, int);
+void	dump(char*, Node*);
+Type*	aindex(Node*, Type*);
+int	isnil(Node*);
+int	isptrto(Type*, int);
+int	isinter(Type*);
+int	isbytearray(Type*);
+int	eqtype(Type*, Type*, int);
+int	eqargs(Type*, Type*);
+ulong	typehash(Type*, int);
+void	frame(int);
+Node*	literal(long);
+Node*	dobad(void);
+Node*	nodintconst(long);
+void	ullmancalc(Node*);
+void	badtype(int, Type*, Type*);
+Type*	ptrto(Type*);
+Node*	cleanidlist(Node*);
+
+Type**	getthis(Type*);
+Type**	getoutarg(Type*);
+Type**	getinarg(Type*);
+
+Type*	getthisx(Type*);
+Type*	getoutargx(Type*);
+Type*	getinargx(Type*);
+
+Node*	listfirst(Iter*, Node**);
+Node*	listnext(Iter*);
+Type*	structfirst(Iter*, Type**);
+Type*	structnext(Iter*);
+Type*	funcfirst(Iter*, Type*);
+Type*	funcnext(Iter*);
+
+int	Econv(Fmt*);
+int	Jconv(Fmt*);
+int	Oconv(Fmt*);
+int	Sconv(Fmt*);
+int	Tconv(Fmt*);
+int	Nconv(Fmt*);
+int	Zconv(Fmt*);
+
+/*
+ *	dcl.c
+ */
+void	dodclvar(Node*, Type*);
+void	dodcltype(Type*, Type*);
+void	dodclconst(Node*, Node*);
+void	defaultlit(Node*);
+int	listcount(Node*);
+Node*	methodname(Node*, Type*);
+Type*	functype(Node*, Node*, Node*);
+char*	thistypenam(Node*);
+void	funcnam(Type*, char*);
+void	funchdr(Node*);
+void	funcargs(Type*);
+void	funcbody(Node*);
+Type*	dostruct(Node*, int);
+Type**	stotype(Node*, Type**);
+Type*	sortinter(Type*);
+void	markdcl(char*);
+void	popdcl(char*);
+void	poptodcl(void);
+void	markdclstack(void);
+void	testdclstack(void);
+Sym*	pushdcl(Sym*);
+void	addvar(Node*, Type*, int);
+void	addtyp(Type*, Type*, int);
+Node*	fakethis(void);
+Node*	newname(Sym*);
+Node*	oldname(Sym*);
+Type*	newtype(Sym*);
+Type*	oldtype(Sym*);
+Type*	forwdcl(Sym*);
+
+/*
+ *	export.c
+ */
+void	markexport(Node*);
+void	dumpe(Sym*);
+void	dumpexport(void);
+void	dumpexporttype(Sym*);
+void	dumpexportvar(Sym*);
+void	dumpexportconst(Sym*);
+void	doimportv1(Node*, Node*);
+void	doimportc1(Node*, Val*);
+void	doimportc2(Node*, Node*, Val*);
+void	doimport1(Node*, Node*, Node*);
+void	doimport2(Node*, Val*, Node*);
+void	doimport3(Node*, Node*);
+void	doimport4(Node*, Node*);
+void	doimport5(Node*, Val*);
+void	doimport6(Node*, Node*);
+void	doimport7(Node*, Node*);
+
+/*
+ *	walk.c
+ */
+void	walk(Node*);
+void	walktype(Node*, int);
+Type*	walkswitch(Node*, Node*, Type*(*)(Node*, Type*));
+int	casebody(Node*);
+int	whatis(Node*);
+void	walkdot(Node*);
+Node*	ascompatee(int, Node**, Node**);
+Node*	ascompatet(int, Node**, Type**, int);
+Node*	ascompatte(int, Type**, Node**, int);
+int	ascompat(Type*, Type*);
+Node*	prcompat(Node*);
+Node*	nodpanic(long);
+Node*	newcompat(Node*);
+Node*	stringop(Node*);
+Node*	convas(Node*);
+Node*	reorder(Node*);
+
+/*
+ *	const.c
+ */
+void	convlit(Node*, Type*);
+void	evconst(Node*);
+int	cmpslit(Node *l, Node *r);
+
+/*
+ *	gen.c/gsubr.c/obj.c
+ */
+void	belexinit(int);
+void	besetptr(void);
+vlong	convvtox(vlong, int);
+void	compile(Node*);
+void	proglist(void);
+int	optopop(int);
+void	dumpobj(void);
+void	dowidth(Type*);
+void	argspace(long);
+Node*	nodarg(Type*, int);
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
new file mode 100644
index 0000000..a3f8e98
--- /dev/null
+++ b/src/cmd/gc/go.y
@@ -0,0 +1,1292 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+%{
+#include "go.h"
+%}
+%union	{
+	Node*		node;
+	Type*		type;
+	Sym*		sym;
+	struct	Val	val;
+	int		lint;
+}
+%token	<sym>		LNAME LBASETYPE LATYPE LANY LPACK LACONST
+%token	<val>		LLITERAL LASOP
+%token			LPACKAGE LIMPORT LEXPORT
+%token			LMAP LCHAN LINTERFACE LFUNC LSTRUCT
+%token			LCOLAS LFALL LRETURN
+%token			LNEW LLEN
+%token			LVAR LTYPE LCONST LCONVERT
+%token			LFOR LIF LELSE LSWITCH LCASE LDEFAULT
+%token			LBREAK LCONTINUE LGO LGOTO LRANGE
+%token			LOROR LANDAND LEQ LNE LLE LLT LGE LGT
+%token			LLSH LRSH LINC LDEC
+%token			LNIL LTRUE LFALSE LIOTA
+%token			LPANIC LPRINT LIGNORE
+
+%type	<sym>		sym laconst lname latype
+%type	<lint>		chandir
+%type	<node>		xdcl xdcl_list_r oxdcl_list common_dcl
+%type	<node>		oarg_type_list arg_type_list_r arg_type
+%type	<node>		stmt empty_stmt else_stmt
+%type	<node>		complex_stmt compound_stmt stmt_list_r ostmt_list
+%type	<node>		for_stmt for_body for_header
+%type	<node>		if_stmt if_body if_header
+%type	<node>		range_header range_body range_stmt
+%type	<node>		simple_stmt osimple_stmt
+%type	<node>		expr uexpr pexpr expr_list oexpr oexpr_list expr_list_r
+%type	<node>		name name_name new_name new_name_list_r
+%type	<node>		vardcl_list_r vardcl
+%type	<node>		interfacedcl_list_r interfacedcl
+%type	<node>		structdcl_list_r structdcl
+%type	<node>		export_list_r export
+%type	<node>		hidden_importsym_list_r ohidden_importsym_list hidden_importsym isym
+%type	<node>		hidden_importfield_list_r ohidden_importfield_list hidden_importfield
+%type	<node>		fnbody
+%type	<node>		fnres fnliteral xfndcl fndcl
+%type	<node>		keyval_list_r keyval
+
+%type	<type>		type fntypeh fntype fnlitdcl intype new_type
+
+%left			LOROR
+%left			LANDAND
+%left			LEQ LNE LLE LGE LLT LGT
+%left			'+' '-' '|' '^'
+%left			'*' '/' '%' '&' LLSH LRSH
+%%
+file:
+	package import_there imports oxdcl_list
+	{
+		if(debug['f'])
+			frame(1);
+		testdclstack();
+	}
+
+package:
+	{
+		yyerror("package statement must be first");
+		mkpackage("main");
+		cannedimports();
+	}
+|	LPACKAGE sym
+	{
+		mkpackage($2->name);
+		cannedimports();
+	}
+
+imports:
+|	imports import
+
+import:
+	LIMPORT import_stmt
+|	LIMPORT '(' import_stmt_list_r osemi ')'
+
+import_stmt:
+	import_here import_there
+
+import_here:
+	LLITERAL
+	{
+		// import with original name
+		pkgmyname = S;
+		importfile(&$1);
+	}
+|	sym LLITERAL
+	{
+		// import with given name
+		pkgmyname = $1;
+		pkgmyname->lexical = LPACK;
+		importfile(&$2);
+	}
+|	'.' LLITERAL
+	{
+		// import with my name
+		pkgmyname = lookup(package);
+		importfile(&$2);
+	}
+
+import_there:
+	hidden_import_list_r ')' ')'
+	{
+		unimportfile();
+	}
+|	LIMPORT '(' '(' hidden_import_list_r ')' ')'
+
+/*
+ * declarations
+ */
+xdcl:
+	common_dcl
+|	LEXPORT export_list_r
+	{
+		markexport(rev($2));
+	}
+|	LEXPORT '(' export_list_r ')'
+	{
+		markexport(rev($3));
+	}
+|	xfndcl
+|	';'
+	{
+		$$ = N;
+	}
+
+common_dcl:
+	LVAR vardcl
+	{
+		$$ = $2;
+	}
+|	LVAR '(' vardcl_list_r osemi ')'
+	{
+		$$ = rev($3);
+	}
+|	LCONST constdcl
+	{
+		$$ = N;
+		iota = 0;
+	}
+|	LCONST '(' constdcl_list_r osemi ')'
+	{
+		$$ = N;
+		iota = 0;
+	}
+|	LTYPE typedcl
+	{
+		$$ = N;
+	}
+|	LTYPE '(' typedcl_list_r osemi ')'
+	{
+		$$ = N;
+	}
+
+vardcl:
+	new_name_list_r type
+	{
+		$$ = rev($1);
+		dodclvar($$, $2);
+
+		$$ = nod(OAS, $$, N);
+	}
+|	new_name_list_r type '=' oexpr_list
+	{
+		$$ = rev($1);
+		dodclvar($$, $2);
+
+		$$ = nod(OAS, $$, $4);
+	}
+|	new_name '=' expr
+	{
+		walktype($3, 0);	// this is a little harry
+		defaultlit($3);
+		dodclvar($1, $3->type);
+
+		$$ = nod(OAS, $1, $3);
+	}
+
+constdcl:
+	new_name '=' expr
+	{
+		walktype($3, 0);
+		dodclconst($1, $3);
+		iota += 1;
+	}
+|	new_name type '=' expr
+	{
+		walktype($4, 0);
+		convlit($4, $2);
+		dodclconst($1, $4);
+		iota += 1;
+	}
+
+typedcl:
+	new_type type
+	{
+		dodcltype($1, $2);
+	}
+
+/*
+ * statements
+ */
+stmt:
+	error ';'
+	{
+		$$ = N;
+		context = nil;
+	}
+|	common_dcl ';'
+	{
+		$$ = $1;
+	}
+|	simple_stmt ';'
+|	complex_stmt
+|	compound_stmt
+|	empty_stmt
+
+empty_stmt:
+	';'
+	{
+		$$ = nod(OEMPTY, N, N);
+	}
+
+else_stmt:
+	stmt
+	{
+		$$ = $1;
+		switch($$->op) {
+		case OLABEL:
+		case OXCASE:
+		case OXFALL:
+			yyerror("statement cannot be labeled");
+		}
+	}
+
+simple_stmt:
+	expr
+	{
+		$$ = $1;
+	}
+|	expr LINC
+	{
+		$$ = nod(OASOP, $1, literal(1));
+		$$->etype = OADD;
+	}
+|	expr LDEC
+	{
+		$$ = nod(OASOP, $1, literal(1));
+		$$->etype = OSUB;
+	}
+|	expr LASOP expr
+	{
+		$$ = nod(OASOP, $1, $3);
+		$$->etype = $2.vval;	// rathole to pass opcode
+	}
+|	expr_list '=' expr_list
+	{
+		$$ = nod(OAS, $1, $3);
+	}
+|	new_name LCOLAS expr
+	{
+		walktype($3, 0);	// this is a little harry
+		defaultlit($3);
+		dodclvar($1, $3->type);
+
+		$$ = nod(OAS, $1, $3);
+	}
+
+complex_stmt:
+	LFOR for_stmt
+	{
+		/* FOR and WHILE are the same keyword */
+		popdcl("for/while");
+		$$ = $2;
+	}
+|	LSWITCH if_stmt
+	{
+		popdcl("if/switch");
+		if(!casebody($2->nbody))
+			yyerror("switch statement must have case labels");
+		$$ = $2;
+		$$->op = OSWITCH;
+	}
+|	LIF if_stmt
+	{
+		popdcl("if/switch");
+		$$ = $2;
+	}
+|	LIF if_stmt LELSE else_stmt
+	{
+		popdcl("if/switch");
+		$$ = $2;
+		$$->nelse = $4;
+	}
+|	LRANGE range_stmt
+	{
+		popdcl("range");
+		$$ = $2;
+	}
+|	LRETURN oexpr_list ';'
+	{
+		$$ = nod(ORETURN, $2, N);
+	}
+|	LCASE expr_list ':'
+	{
+		// will be converted to OCASE
+		// right will point to next case
+		// done in casebody()
+		poptodcl();
+		$$ = nod(OXCASE, $2, N);
+	}
+|	LDEFAULT ':'
+	{
+		poptodcl();
+		$$ = nod(OXCASE, N, N);
+	}
+|	LFALL ';'
+	{
+		// will be converted to OFALL
+		$$ = nod(OXFALL, N, N);
+	}
+|	LBREAK oexpr ';'
+	{
+		$$ = nod(OBREAK, $2, N);
+	}
+|	LCONTINUE oexpr ';'
+	{
+		$$ = nod(OCONTINUE, $2, N);
+	}
+|	LGO pexpr '(' oexpr_list ')' ';'
+	{
+		$$ = nod(OPROC, $2, $4);
+	}
+|	LPRINT expr_list ';'
+	{
+		$$ = nod(OPRINT, $2, N);
+	}
+|	LPANIC oexpr_list ';'
+	{
+		$$ = nod(OPANIC, $2, N);
+	}
+|	LGOTO new_name ';'
+	{
+		$$ = nod(OGOTO, $2, N);
+	}
+|	new_name ':'
+	{
+		$$ = nod(OLABEL, $1, N);
+	}
+
+compound_stmt:
+	'{'
+	{
+		markdcl("compound");
+	} ostmt_list '}'
+	{
+		$$ = $3;
+		if($$ == N)
+			$$ = nod(OEMPTY, N, N);
+		popdcl("compound");
+	}
+
+for_header:
+	osimple_stmt ';' osimple_stmt ';' osimple_stmt
+	{
+		// init ; test ; incr
+		$$ = nod(OFOR, N, N);
+		$$->ninit = $1;
+		$$->ntest = $3;
+		$$->nincr = $5;
+	}
+|	osimple_stmt
+	{
+		// test
+		$$ = nod(OFOR, N, N);
+		$$->ninit = N;
+		$$->ntest = $1;
+		$$->nincr = N;
+	}
+
+for_body:
+	for_header compound_stmt
+	{
+		$$ = $1;
+		$$->nbody = $2;
+	}
+
+for_stmt:
+	{
+		markdcl("for/while");
+	} for_body
+	{
+		$$ = $2;
+	}
+
+if_header:
+	osimple_stmt
+	{
+		// test
+		$$ = nod(OIF, N, N);
+		$$->ninit = N;
+		$$->ntest = $1;
+	}
+|	osimple_stmt ';' osimple_stmt
+	{
+		// init ; test
+		$$ = nod(OIF, N, N);
+		$$->ninit = $1;
+		$$->ntest = $3;
+	}
+
+if_body:
+	if_header compound_stmt
+	{
+		$$ = $1;
+		$$->nbody = $2;
+	}
+
+if_stmt:
+	{
+		markdcl("if/switch");
+	} if_body
+	{
+		$$ = $2;
+	}
+
+range_header:
+	new_name LCOLAS expr
+	{
+		$$ = N;
+	}
+|	new_name ',' new_name LCOLAS expr
+	{
+		$$ = N;
+	}
+|	new_name ',' new_name '=' expr
+	{
+		yyerror("range statement only allows := assignment");
+		$$ = N;
+	}
+
+range_body:
+	range_header compound_stmt
+	{
+		$$ = $1;
+		$$->nbody = $2;
+	}
+
+range_stmt:
+	{
+		markdcl("range");
+	} range_body
+	{
+		$$ = $2;
+	}
+
+/*
+ * expressions
+ */
+expr:
+	uexpr
+|	expr LOROR expr
+	{
+		$$ = nod(OOROR, $1, $3);
+	}
+|	expr LANDAND expr
+	{
+		$$ = nod(OANDAND, $1, $3);
+	}
+|	expr LEQ expr
+	{
+		$$ = nod(OEQ, $1, $3);
+	}
+|	expr LNE expr
+	{
+		$$ = nod(ONE, $1, $3);
+	}
+|	expr LLT expr
+	{
+		$$ = nod(OLT, $1, $3);
+	}
+|	expr LLE expr
+	{
+		$$ = nod(OLE, $1, $3);
+	}
+|	expr LGE expr
+	{
+		$$ = nod(OGE, $1, $3);
+	}
+|	expr LGT expr
+	{
+		$$ = nod(OGT, $1, $3);
+	}
+|	expr '+' expr
+	{
+		$$ = nod(OADD, $1, $3);
+	}
+|	expr '-' expr
+	{
+		$$ = nod(OSUB, $1, $3);
+	}
+|	expr '|' expr
+	{
+		$$ = nod(OOR, $1, $3);
+	}
+|	expr '^' expr
+	{
+		$$ = nod(OXOR, $1, $3);
+	}
+|	expr '*' expr
+	{
+		$$ = nod(OMUL, $1, $3);
+	}
+|	expr '/' expr
+	{
+		$$ = nod(ODIV, $1, $3);
+	}
+|	expr '%' expr
+	{
+		$$ = nod(OMOD, $1, $3);
+	}
+|	expr '&' expr
+	{
+		$$ = nod(OAND, $1, $3);
+	}
+|	expr LLSH expr
+	{
+		$$ = nod(OLSH, $1, $3);
+	}
+|	expr LRSH expr
+	{
+		$$ = nod(ORSH, $1, $3);
+	}
+
+uexpr:
+	pexpr
+|	'*' uexpr
+	{
+		$$ = nod(OIND, $2, N);
+	}
+|	'&' uexpr
+	{
+		$$ = nod(OADDR, $2, N);
+	}
+|	'+' uexpr
+	{
+		$$ = nod(OPLUS, $2, N);
+	}
+|	'-' uexpr
+	{
+		$$ = nod(OMINUS, $2, N);
+	}
+|	'!' uexpr
+	{
+		$$ = nod(ONOT, $2, N);
+	}
+|	'~' uexpr
+	{
+		yyerror("the OCOM operator is ^");
+		$$ = nod(OCOM, $2, N);
+	}
+|	'^' uexpr
+	{
+		$$ = nod(OCOM, $2, N);
+	}
+|	LLT uexpr
+	{
+		$$ = nod(ORECV, $2, N);
+	}
+|	LGT uexpr
+	{
+		$$ = nod(OSEND, $2, N);
+	}
+
+pexpr:
+	LLITERAL
+	{
+		$$ = nod(OLITERAL, N, N);
+		$$->val = $1;
+	}
+|	laconst
+	{
+		$$ = nod(OLITERAL, N, N);
+		$$->val = $1->oconst->val;
+		$$->type = $1->oconst->type;
+	}
+|	LNIL
+	{
+		$$ = nod(OLITERAL, N, N);
+		$$->val.ctype = CTNIL;
+		$$->val.vval = 0;
+	}
+|	LTRUE
+	{
+		$$ = booltrue;
+	}
+|	LFALSE
+	{
+		$$ = boolfalse;
+	}
+|	LIOTA
+	{
+		$$ = literal(iota);
+	}
+|	name
+|	'(' expr ')'
+	{
+		$$ = $2;
+	}
+|	pexpr '.' sym
+	{
+		$$ = nod(ODOT, $1, newname($3));
+	}
+|	pexpr '.' '(' type ')'
+	{
+		$$ = nod(OCONV, $1, N);
+		$$->type = $4;
+	}
+|	pexpr '[' expr ']'
+	{
+		$$ = nod(OINDEX, $1, $3);
+	}
+|	pexpr '[' keyval ']'
+	{
+		$$ = nod(OSLICE, $1, $3);
+	}
+|	pexpr '(' oexpr_list ')'
+	{
+		$$ = nod(OCALL, $1, $3);
+	}
+|	LLEN '(' name ')'
+	{
+		$$ = nod(OLEN, $3, N);
+	}
+|	LNEW '(' type ')'
+	{
+		$$ = nod(ONEW, N, N);
+		$$->type = ptrto($3);
+	}
+|	fnliteral
+|	'[' expr_list ']'
+	{
+		// array literal
+		$$ = N;
+	}
+|	'[' keyval_list_r ']'
+	{
+		// map literal
+		$$ = N;
+	}
+|	latype '(' oexpr_list ')'
+	{
+		// struct literal and conversions
+		$$ = nod(OCONV, $3, N);
+		$$->type = $1->otype;
+	}
+|	LCONVERT '(' type ',' expr ')'
+	{
+		$$ = nod(OCONV, $5, N);
+		$$->type = $3;
+	}
+
+/*
+ * lexical symbols that can be
+ * from other packages
+ */
+lpack:
+	LPACK 
+	{
+		context = $1->name;
+	}
+
+laconst:
+	LACONST
+|	lpack '.' LACONST
+	{
+		$$ = $3;
+		context = nil;
+	}
+
+lname:
+	LNAME
+|	lpack '.' LNAME
+	{
+		$$ = $3;
+		context = nil;
+	}
+
+latype:
+	LATYPE
+|	lpack '.' LATYPE
+	{
+		$$ = $3;
+		context = nil;
+	}
+
+/*
+ * names and types
+ *	newname is used before declared
+ *	oldname is used after declared
+ */
+name_name:
+	LNAME
+	{
+		$$ = newname($1);
+	}
+
+new_name:
+	sym
+	{
+		$$ = newname($1);
+	}
+
+new_type:
+	sym
+	{
+		$$ = newtype($1);
+	}
+
+sym:
+	LATYPE
+|	LNAME
+|	LACONST
+|	LPACK
+
+name:
+	lname
+	{
+		$$ = oldname($1);
+	}
+
+type:
+	latype
+	{
+		$$ = oldtype($1);
+	}
+|	'[' oexpr ']' type
+	{
+		$$ = aindex($2, $4);
+	}
+|	LCHAN chandir type
+	{
+		$$ = typ(TCHAN);
+		$$->type = $3;
+		$$->chan = $2;
+	}
+|	LMAP '[' type ']' type
+	{
+		$$ = typ(TMAP);
+		$$->down = $3;
+		$$->type = $5;
+	}
+|	LSTRUCT '{' structdcl_list_r osemi '}'
+	{
+		$$ = dostruct(rev($3), TSTRUCT);
+	}
+|	LSTRUCT '{' '}'
+	{
+		$$ = dostruct(N, TSTRUCT);
+	}
+|	LINTERFACE '{' interfacedcl_list_r osemi '}'
+	{
+		$$ = dostruct(rev($3), TINTER);
+		$$ = sortinter($$);
+	}
+|	LINTERFACE '{' '}'
+	{
+		$$ = dostruct(N, TINTER);
+	}
+|	LANY
+	{
+		$$ = typ(TANY);
+	}
+|	fntypeh
+|	'*' type
+	{
+		$$ = ptrto($2);
+	}
+|	'*' lname
+	{
+		// dont know if this is an error or not
+		if(dclcontext != PEXTERN)
+			yyerror("foreward type in function body %s", $2->name);
+		$$ = forwdcl($2);
+	}
+
+chandir:
+	{
+		$$ = Cboth;
+	}
+|	LLT
+	{
+		$$ = Crecv;
+	}
+|	LGT
+	{
+		$$ = Csend;
+	}
+
+keyval:
+	expr ':' expr
+	{
+		$$ = nod(OLIST, $1, $3);
+	}
+
+/*
+ * function stuff
+ * all in one place to show how crappy it all is
+ */
+xfndcl:
+	LFUNC fndcl fnbody
+	{
+		$$ = $2;
+		$$->nbody = $3;
+		funcbody($$);
+	}
+
+fndcl:
+	new_name '(' oarg_type_list ')' fnres
+	{
+		b0stack = dclstack;	// mark base for fn literals
+		$$ = nod(ODCLFUNC, N, N);
+		$$->nname = $1;
+		$$->type = functype(N, $3, $5);
+		funchdr($$);
+	}
+|	'(' oarg_type_list ')' new_name '(' oarg_type_list ')' fnres
+	{
+		b0stack = dclstack;	// mark base for fn literals
+		if($2 == N || $2->op == OLIST)
+			yyerror("syntax error in method receiver");
+		$$ = nod(ODCLFUNC, N, N);
+		$$->nname = methodname($4, $2->type);
+		$$->type = functype($2, $6, $8);
+		funchdr($$);
+	}
+
+fntypeh:
+	LFUNC '(' oarg_type_list ')' fnres
+	{
+		$$ = functype(N, $3, $5);
+		funcnam($$, nil);
+	}
+|	LFUNC '(' oarg_type_list ')' '.' '(' oarg_type_list ')' fnres
+	/* i dont believe that this form is useful for anything */
+	{
+		if($3 == N || $3->op == OLIST)
+			yyerror("syntax error in method receiver");
+		$$ = functype($3, $7, $9);
+		funcnam($$, nil);
+	}
+
+fntype:
+	fntypeh
+|	latype
+	{
+		$$ = oldtype($1);
+		if($$ == T || $$->etype != TFUNC)
+			yyerror("illegal type for function literal");
+	}
+
+fnlitdcl:
+	fntype
+	{
+		markdclstack();	// save dcl stack and revert to block0
+		$$ = $1;
+		funcargs($$);
+	}
+
+fnliteral:
+	fnlitdcl '{' ostmt_list '}'
+	{
+		popdcl("fnlit");
+
+		vargen++;
+		snprint(namebuf, sizeof(namebuf), "_f%.3ld", vargen);
+
+		$$ = newname(lookup(namebuf));
+		addvar($$, $1, PEXTERN);
+
+		{
+			Node *n;
+
+			n = nod(ODCLFUNC, N, N);
+			n->nname = $$;
+			n->type = $1;
+			n->nbody = $3;
+			if(n->nbody == N)
+				n->nbody = nod(ORETURN, N, N);
+			compile(n);
+		}
+
+		$$ = nod(OADDR, $$, N);
+	}
+
+fnbody:
+	compound_stmt
+	{
+		$$ = $1;
+		if($$->op == OEMPTY)
+			$$ = nod(ORETURN, N, N);
+	}
+|	';'
+	{
+		$$ = N;
+	}
+
+fnres:
+	{
+		$$ = N;
+	}
+|	type
+	{
+		$$ = nod(ODCLFIELD, N, N);
+		$$->type = $1;
+		$$ = cleanidlist($$);
+	}
+|	'(' oarg_type_list ')'
+	{
+		$$ = $2;
+	}
+
+/*
+ * lists of things
+ * note that they are left recursive
+ * to conserve yacc stack. they need to
+ * be reversed to interpret correctly
+ */
+xdcl_list_r:
+	xdcl
+|	xdcl_list_r xdcl
+	{
+		$$ = nod(OLIST, $1, $2);
+	}
+
+vardcl_list_r:
+	vardcl
+|	vardcl_list_r ';' vardcl
+	{
+		$$ = nod(OLIST, $1, $3);
+	}
+
+constdcl_list_r:
+	constdcl
+|	constdcl_list_r ';' constdcl
+
+typedcl_list_r:
+	typedcl
+|	typedcl_list_r ';' typedcl
+
+structdcl_list_r:
+	structdcl
+	{
+		$$ = cleanidlist($1);
+	}
+|	structdcl_list_r ';' structdcl
+	{
+		$$ = cleanidlist($3);
+		$$ = nod(OLIST, $1, $$);
+	}
+
+interfacedcl_list_r:
+	interfacedcl
+	{
+		$$ = cleanidlist($1);
+	}
+|	interfacedcl_list_r ';' interfacedcl
+	{
+		$$ = cleanidlist($3);
+		$$ = nod(OLIST, $1, $$);
+	}
+
+structdcl:
+	new_name ',' structdcl
+	{
+		$$ = nod(ODCLFIELD, $1, N);
+		$$ = nod(OLIST, $$, $3);
+	}
+|	new_name type
+	{
+		$$ = nod(ODCLFIELD, $1, N);
+		$$->type = $2;
+	}
+
+interfacedcl:
+	new_name ',' interfacedcl
+	{
+		$$ = nod(ODCLFIELD, $1, N);
+		$$ = nod(OLIST, $$, $3);
+	}
+|	new_name intype
+	{
+		$$ = nod(ODCLFIELD, $1, N);
+		$$->type = $2;
+	}
+
+intype:
+	'(' oarg_type_list ')' fnres
+	{
+		// without func keyword
+		$$ = functype(fakethis(), $2, $4);
+		funcnam($$, nil);
+	}
+|	LFUNC '(' oarg_type_list ')' fnres
+	{
+		// with func keyword
+		$$ = functype(fakethis(), $3, $5);
+		funcnam($$, nil);
+	}
+|	latype
+	{
+		$$ = oldtype($1);
+		if($$ == T || $$->etype != TFUNC)
+			yyerror("illegal type for function literal");
+	}
+
+arg_type:
+	name_name
+	{
+		$$ = nod(ODCLFIELD, $1, N);
+	}
+|	type
+	{
+		$$ = nod(ODCLFIELD, N, N);
+		$$->type = $1;
+	}
+|	new_name type
+	{
+		$$ = nod(ODCLFIELD, $1, N);
+		$$->type = $2;
+	}
+
+arg_type_list_r:
+	arg_type
+|	arg_type_list_r ',' arg_type
+	{
+		$$ = nod(OLIST, $1, $3);
+	}
+
+stmt_list_r:
+	stmt
+	{
+		$$ = $1;
+	}
+|	stmt_list_r stmt
+	{
+		$$ = nod(OLIST, $1, $2);
+	}
+
+expr_list_r:
+	expr
+|	expr_list_r ',' expr
+	{
+		$$ = nod(OLIST, $1, $3);
+	}
+
+new_name_list_r:
+	new_name
+|	new_name_list_r ',' new_name
+	{
+		$$ = nod(OLIST, $1, $3);
+	}
+
+export_list_r:
+	export
+|	export_list_r ocomma export
+	{
+		$$ = nod(OLIST, $1, $3);
+	}
+
+export:
+	sym
+	{
+		$$ = nod(OEXPORT, N, N);
+		$$->sym = $1;
+	}
+|	sym '.' sym
+	{
+		$$ = nod(OEXPORT, N, N);
+		$$->psym = $1;
+		$$->sym = $3;
+	}
+
+import_stmt_list_r:
+	import_stmt
+|	import_stmt_list_r osemi import_stmt
+
+hidden_import_list_r:
+	hidden_import
+|	hidden_import_list_r hidden_import
+
+hidden_importsym_list_r:
+	hidden_importsym
+|	hidden_importsym_list_r hidden_importsym
+	{
+		$$ = nod(OLIST, $1, $2);
+	}
+
+hidden_importfield_list_r:
+	hidden_importfield
+|	hidden_importfield_list_r hidden_importfield
+	{
+		$$ = nod(OLIST, $1, $2);
+	}
+
+keyval_list_r:
+	keyval
+|	keyval_list_r ',' keyval
+	{
+		$$ = nod(OLIST, $1, $3);
+	}
+
+/*
+ * the one compromise of a
+ * non-reversed list
+ */
+expr_list:
+	expr_list_r
+	{
+		$$ = rev($1);
+	}
+
+/*
+ * optional things
+ */
+osemi:
+|	';'
+
+ocomma:
+|	','
+
+oexpr:
+	{
+		$$ = N;
+	}
+|	expr
+
+oexpr_list:
+	{
+		$$ = N;
+	}
+|	expr_list
+
+osimple_stmt:
+	{
+		$$ = N;
+	}
+|	simple_stmt
+
+ostmt_list:
+	{
+		$$ = N;
+	}
+|	stmt_list_r
+	{
+		$$ = rev($1);
+	}
+
+oxdcl_list:
+	{
+		$$ = N;
+	}
+|	xdcl_list_r
+	{
+		$$ = rev($1);
+	}
+
+ohidden_importsym_list:
+	{
+		$$ = N;
+	}
+|	hidden_importsym_list_r
+	{
+		$$ = rev($1);
+	}
+
+ohidden_importfield_list:
+	{
+		$$ = N;
+	}
+|	hidden_importfield_list_r
+	{
+		$$ = rev($1);
+	}
+
+oarg_type_list:
+	{
+		$$ = N;
+	}
+|	arg_type_list_r
+	{
+		$$ = cleanidlist(rev($1));
+	}
+
+/*
+ * import syntax from header of
+ * an output package
+ */
+hidden_import:
+	/* variables */
+	LVAR hidden_importsym hidden_importsym
+	{
+		// var
+		doimportv1($2, $3);
+	}
+
+	/* constants */
+|	LCONST hidden_importsym LLITERAL
+	{
+		doimportc1($2, &$3);
+	}
+|	LCONST hidden_importsym hidden_importsym LLITERAL
+	{
+		doimportc2($2, $3, &$4);
+	}
+
+	/* types */
+|	LTYPE hidden_importsym '[' hidden_importsym ']' hidden_importsym
+	{
+		// type map
+		doimport1($2, $4, $6);
+	}
+|	LTYPE hidden_importsym '[' LLITERAL ']' hidden_importsym
+	{
+		// type array
+		doimport2($2, &$4, $6);
+	}
+|	LTYPE hidden_importsym '(' ohidden_importsym_list ')'
+	{
+		// type function
+		doimport3($2, $4);
+	}
+|	LTYPE hidden_importsym '{' ohidden_importfield_list '}'
+	{
+		// type structure
+		doimport4($2, $4);
+	}
+|	LTYPE hidden_importsym LLITERAL
+	{
+		// type basic
+		doimport5($2, &$3);
+	}
+|	LTYPE hidden_importsym '*' hidden_importsym
+	{
+		// type pointer
+		doimport6($2, $4);
+	}
+|	LTYPE hidden_importsym LLT ohidden_importfield_list LGT
+	{
+		// type interface
+		doimport7($2, $4);
+	}
+
+isym:
+	sym '.' sym
+	{
+		$1->lexical = LPACK;
+		$$ = nod(OIMPORT, N, N);
+		$$->osym = $1;
+		$$->psym = $1;
+		$$->sym = $3;
+	}
+|	'(' sym ')' sym '.' sym
+	{
+		$$ = nod(OIMPORT, N, N);
+		$$->osym = $2;
+		$$->psym = $4;
+		$$->sym = $6;
+	}
+
+hidden_importsym:
+	isym
+|	'!' isym
+	{
+		$$ = $2;
+	}
+
+hidden_importfield:
+	sym isym
+	{
+		$$ = $2;
+		$$->fsym = $1;
+	}
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
new file mode 100644
index 0000000..b44540c
--- /dev/null
+++ b/src/cmd/gc/lex.c
@@ -0,0 +1,1088 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+#define		EXTERN
+#include	"go.h"
+#include	"y.tab.h"
+
+#define	DBG	if(!debug['x']);else print
+enum
+{
+	EOF		= -1,
+};
+
+int
+main(int argc, char *argv[])
+{
+	int c;
+
+	outfile = nil;
+	package = "____";
+	ARGBEGIN {
+	default:
+		c = ARGC();
+		if(c >= 0 && c < sizeof(debug))
+			debug[c]++;
+		break;
+
+	case 'o':
+		outfile = ARGF();
+		break;
+
+	case 'k':
+		package = ARGF();
+		break;
+	} ARGEND
+
+	if(argc != 1)
+		goto usage;
+
+	fmtinstall('O', Oconv);		// node opcodes
+	fmtinstall('E', Econv);		// etype opcodes
+	fmtinstall('J', Jconv);		// all the node flags
+	fmtinstall('S', Sconv);		// sym pointer
+	fmtinstall('T', Tconv);		// type pointer
+	fmtinstall('N', Nconv);		// node pointer
+	fmtinstall('Z', Zconv);		// escaped string
+	
+	lexinit();
+
+	curio.infile = argv[0];
+
+	curio.bin = Bopen(curio.infile, OREAD);
+	if(curio.bin == nil)
+		fatal("cant open: %s", curio.infile);
+
+	externdcl = mal(sizeof(*externdcl));
+	externdcl->back = externdcl;
+	dclcontext = PEXTERN;
+
+	exportlist = mal(sizeof(*exportlist));
+	exportlist->back = exportlist;
+
+	// function field skeleton
+	fskel = nod(OLIST, N, nod(OLIST, N, N));
+	fskel->left = nod(ODCLFIELD, N, N);
+	fskel->right->left = nod(ODCLFIELD, N, N);
+	fskel->right->right = nod(ODCLFIELD, N, N);
+
+	curio.peekc = 0;
+	curio.lineno = 1;
+	nerrors = 0;
+	yyparse();
+
+	Bterm(curio.bin);
+	if(bout != nil)
+		Bterm(bout);
+
+	if(nerrors)
+		errorexit();
+
+	dumpobj();
+
+	myexit(0);
+	return 0;
+
+usage:
+	print("flags:\n");
+	print("  -d print declarations\n");
+	print("  -f print stack frame structure\n");
+	print("  -k name specify package name\n");
+	print("  -o file specify output file\n");
+	print("  -p print the assembly language\n");
+	print("  -w print the parse tree after typing\n");
+	print("  -x print lex tokens\n");
+	print("  -h panic on an error\n");
+	myexit(0);
+	return 0;
+}
+
+void
+importfile(Val *f)
+{
+	Biobuf *imp;
+	long c;
+
+	if(f->ctype != CTSTR) {
+		yyerror("import statement not a string");
+		return;
+	}
+	// BOTCH need to get .8 from backend
+	snprint(namebuf, sizeof(namebuf), "%Z.8", f->sval);
+
+	imp = Bopen(namebuf, OREAD);
+	if(imp == nil) {
+		yyerror("cant open import: %s", namebuf);
+		return;
+	}
+
+	/*
+	 * position the input right
+	 * after (( and return
+	 */
+	pushedio = curio;
+	curio.bin = imp;
+	curio.lineno = 1;
+	curio.peekc = 0;
+	curio.infile = strdup(namebuf);
+	for(;;) {
+		c = getc();
+		if(c == EOF)
+			break;
+		if(c != '(')
+			continue;
+		c = getc();
+		if(c == EOF)
+			break;
+		if(c != '(')
+			continue;
+		return;
+	}
+	yyerror("no import in: %Z", f->sval);
+	unimportfile();
+}
+
+void
+unimportfile(void)
+{
+	if(curio.bin != nil) {
+		Bterm(curio.bin);
+		curio.bin = nil;
+	}
+	curio = pushedio;
+	pushedio.bin = nil;
+}
+
+void
+cannedimports(void)
+{
+	pushedio = curio;
+	curio.bin = nil;
+	curio.lineno = 1;
+	curio.peekc = 0;
+	curio.infile = "internal sys.go";
+	curio.cp = sysimport;
+	pkgmyname = S;
+}
+
+long
+yylex(void)
+{
+	long c, c1;
+	char *cp;
+	Rune rune;
+	int escflag;
+	Sym *s;
+
+l0:
+	c = getc();
+	if(isspace(c))
+		goto l0;
+
+	if(c >= Runeself) {
+		/* all multibyte runes are alpha */
+		cp = namebuf;
+		goto talph;
+	}
+
+	if(isalpha(c)) {
+		cp = namebuf;
+		goto talph;
+	}
+
+	if(isdigit(c))
+		goto tnum;
+
+	switch(c) {
+	case EOF:
+		ungetc(EOF);
+		return -1;
+
+	case '_':
+		cp = namebuf;
+		goto talph;
+
+	case '.':
+		c1 = getc();
+		if(isdigit(c1)) {
+			cp = namebuf;
+			*cp++ = c;
+			c = c1;
+			c1 = 0;
+			goto casedot;
+		}
+		break;
+
+	case '"':
+		/* "..." */
+		strcpy(namebuf, "\"<string>\"");
+		cp = mal(sizeof(long));
+		c1 = 4;
+
+	caseq:
+		for(;;) {
+			c = escchar('"', &escflag);
+			if(c == EOF)
+				break;
+			if(escflag) {
+				cp = remal(cp, c1, 1);
+				cp[c1++] = c;
+			} else {
+				rune = c;
+				c = runelen(rune);
+				cp = remal(cp, c1, c);
+				runetochar(cp+c1, &rune);
+				c1 += c;
+			}
+		}
+		goto catem;
+
+	case '`':
+		/* `...` */
+		strcpy(namebuf, "`<string>`");
+		cp = mal(sizeof(long));
+		c1 = 4;
+
+	casebq:
+		for(;;) {
+			c = getc();
+			if(c == EOF || c == '`')
+				break;
+			cp = remal(cp, c1, 1);
+			cp[c1++] = c;
+		}
+
+	catem:
+		for(;;) {
+			/* it takes 2 peekc's to skip comments */
+			c = getc();
+			if(isspace(c))
+				continue;
+			if(c == '"')
+				goto caseq;
+			if(c == '`')
+				goto casebq;
+			ungetc(c);
+			break;
+		}
+
+		*(long*)cp = c1-4;	// length
+		do {
+			cp = remal(cp, c1, 1);
+			cp[c1++] = 0;
+		} while(c1 & MAXALIGN);
+		yylval.val.sval = (String*)cp;
+		yylval.val.ctype = CTSTR;
+		DBG("lex: string literal\n");
+		return LLITERAL;
+
+	case '\'':
+		/* '.' */
+		c = escchar('\'', &escflag);
+		if(c == EOF)
+			c = '\'';
+		c1 = escchar('\'', &escflag);
+		if(c1 != EOF) {
+			yyerror("missing '");
+			ungetc(c1);
+		}
+		yylval.val.vval = c;
+		yylval.val.ctype = CTINT;
+		DBG("lex: codepoint literal\n");
+		return LLITERAL;
+
+	case '/':
+		c1 = getc();
+		if(c1 == '*') {
+			for(;;) {
+				c = getr();
+				while(c == '*') {
+					c = getr();
+					if(c == '/')
+						goto l0;
+				}
+				if(c == EOF) {
+					yyerror("eof in comment");
+					errorexit();
+				}
+			}
+		}
+		if(c1 == '/') {
+			for(;;) {
+				c = getr();
+				if(c == '\n')
+					goto l0;
+				if(c == EOF) {
+					yyerror("eof in comment");
+					errorexit();
+				}
+			}
+		}
+		if(c1 == '=') {
+			c = ODIV;
+			goto asop;
+		}
+		break;
+
+	case ':':
+		c1 = getc();
+		if(c1 == '=') {
+			c = LCOLAS;
+			goto lx;
+		}
+		break;
+
+	case '*':
+		c1 = getc();
+		if(c1 == '=') {
+			c = OMUL;
+			goto asop;
+		}
+		break;
+
+	case '%':
+		c1 = getc();
+		if(c1 == '=') {
+			c = OMOD;
+			goto asop;
+		}
+		break;
+
+	case '+':
+		c1 = getc();
+		if(c1 == '+') {
+			c = LINC;
+			goto lx;
+		}
+		if(c1 == '=') {
+			c = OADD;
+			goto asop;
+		}
+		break;
+
+	case '-':
+		c1 = getc();
+		if(c1 == '-') {
+			c = LDEC;
+			goto lx;
+		}
+		if(c1 == '=') {
+			c = OSUB;
+			goto asop;
+		}
+		break;
+
+	case '>':
+		c1 = getc();
+		if(c1 == '>') {
+			c = LRSH;
+			c1 = getc();
+			if(c1 == '=') {
+				c = ORSH;
+				goto asop;
+			}
+			break;
+		}
+		if(c1 == '=') {
+			c = LGE;
+			goto lx;
+		}
+		c = LGT;
+		break;
+
+	case '<':
+		c1 = getc();
+		if(c1 == '<') {
+			c = LLSH;
+			c1 = getc();
+			if(c1 == '=') {
+				c = OLSH;
+				goto asop;
+			}
+			break;
+		}
+		if(c1 == '=') {
+			c = LLE;
+			goto lx;
+		}
+		c = LLT;
+		break;
+
+	case '=':
+		c1 = getc();
+		if(c1 == '=') {
+			c = LEQ;
+			goto lx;
+		}
+		break;
+
+	case '!':
+		c1 = getc();
+		if(c1 == '=') {
+			c = LNE;
+			goto lx;
+		}
+		break;
+
+	case '&':
+		c1 = getc();
+		if(c1 == '&') {
+			c = LANDAND;
+			goto lx;
+		}
+		if(c1 == '=') {
+			c = OAND;
+			goto asop;
+		}
+		break;
+
+	case '|':
+		c1 = getc();
+		if(c1 == '|') {
+			c = LOROR;
+			goto lx;
+		}
+		if(c1 == '=') {
+			c = OOR;
+			goto asop;
+		}
+		break;
+
+	case '^':
+		c1 = getc();
+		if(c1 == '=') {
+			c = OXOR;
+			goto asop;
+		}
+		break;
+
+	default:
+		goto lx;
+	}
+	ungetc(c1);
+
+lx:
+	if(c > 0xff)
+		DBG("lex: TOKEN %s\n", lexname(c));
+	else
+		DBG("lex: TOKEN '%c'\n", c);
+	return c;
+
+asop:
+	yylval.val.vval = c;	// rathole to hold which asop
+	DBG("lex: TOKEN ASOP %c\n", c);
+	return LASOP;
+
+talph:
+	/*
+	 * cp is set to namebuf and some
+	 * prefix has been stored
+	 */
+	for(;;) {
+		if(c >= Runeself) {
+			for(c1=0;;) {
+				cp[c1++] = c;
+				if(fullrune(cp, c1))
+					break;
+				c = getc();
+			}
+			cp += c1;
+			c = getc();
+			continue;
+		}
+		if(!isalnum(c) && c != '_')
+			break;
+		*cp++ = c;
+		c = getc();
+	}
+	*cp = 0;
+	ungetc(c);
+
+	s = lookup(namebuf);
+	if(s->lexical == LIGNORE)
+		goto l0;
+
+	if(context != nil) {
+		s = pkglookup(s->name, context);
+		if(s->lexical == LIGNORE)
+			goto l0;
+	}
+
+	DBG("lex: %S %s\n", s, lexname(s->lexical));
+	yylval.sym = s;
+	if(s->lexical == LBASETYPE)
+		return LATYPE;
+	return s->lexical;
+
+tnum:
+	c1 = 0;
+	cp = namebuf;
+	if(c != '0') {
+		for(;;) {
+			*cp++ = c;
+			c = getc();
+			if(isdigit(c))
+				continue;
+			goto dc;
+		}
+	}
+	*cp++ = c;
+	c = getc();
+	if(c == 'x' || c == 'X')
+		for(;;) {
+			*cp++ = c;
+			c = getc();
+			if(isdigit(c))
+				continue;
+			if(c >= 'a' && c <= 'f')
+				continue;
+			if(c >= 'A' && c <= 'F')
+				continue;
+			if(cp == namebuf+2)
+				yyerror("malformed hex constant");
+			goto ncu;
+		}
+	if(c < '0' || c > '7')
+		goto dc;
+	for(;;) {
+		if(c >= '0' && c <= '7') {
+			*cp++ = c;
+			c = getc();
+			continue;
+		}
+		goto ncu;
+	}
+
+dc:
+	if(c == '.')
+		goto casedot;
+	if(c == 'e' || c == 'E')
+		goto casee;
+
+ncu:
+	*cp = 0;
+	ungetc(c);
+	if(mpatov(namebuf, &yylval.val.vval)) {
+		yyerror("overflow in constant");
+		yylval.val.vval = 0;
+	}
+	yylval.val.ctype = CTINT;
+	DBG("lex: integer literal\n");
+	return LLITERAL;
+
+casedot:
+	for(;;) {
+		*cp++ = c;
+		c = getc();
+		if(!isdigit(c))
+			break;
+	}
+	if(c != 'e' && c != 'E')
+		goto caseout;
+
+casee:
+	*cp++ = 'e';
+	c = getc();
+	if(c == '+' || c == '-') {
+		*cp++ = c;
+		c = getc();
+	}
+	if(!isdigit(c))
+		yyerror("malformed fp constant exponent");
+	while(isdigit(c)) {
+		*cp++ = c;
+		c = getc();
+	}
+
+caseout:
+	*cp = 0;
+	ungetc(c);
+	if(mpatof(namebuf, &yylval.val.dval)) {
+		yyerror("overflow in float constant");
+		yylval.val.dval = 0;
+	}
+	yylval.val.ctype = CTFLT;
+	DBG("lex: floating literal\n");
+	return LLITERAL;
+}
+
+int
+getc(void)
+{
+	int c;
+
+	c = curio.peekc;
+	if(c != 0) {
+		curio.peekc = 0;
+		if(c == '\n')
+			curio.lineno++;
+		return c;
+	}
+
+	if(curio.bin == nil) {
+		c = *curio.cp & 0xff;
+		if(c != 0)
+			curio.cp++;
+	} else
+		c = Bgetc(curio.bin);
+
+	switch(c) {
+	case 0:
+	case EOF:
+		return EOF;
+
+	case '\n':
+		curio.lineno++;
+		break;
+	}
+	return c;
+}
+
+void
+ungetc(int c)
+{
+	curio.peekc = c;
+	if(c == '\n')
+		curio.lineno--;
+}
+
+long
+getr(void)
+{
+	int c, i;
+	char str[UTFmax+1];
+	Rune rune;
+
+	c = getc();
+	if(c < Runeself)
+		return c;
+	i = 0;
+	str[i++] = c;
+
+loop:
+	c = getc();
+	str[i++] = c;
+	if(!fullrune(str, i))
+		goto loop;
+	c = chartorune(&rune, str);
+	if(rune == Runeerror && c == 1) {
+		yyerror("illegal rune in string");
+		for(c=0; c<i; c++)
+			print(" %.2x", *(uchar*)(str+c));
+		print("\n");
+	}
+	return rune;
+}
+
+int
+getnsc(void)
+{
+	int c;
+
+	c = getc();
+	for(;;) {
+		if(!isspace(c))
+			return c;
+		if(c == '\n') {
+			curio.lineno++;
+			return c;
+		}
+		c = getc();
+	}
+	return 0;
+}
+
+
+long
+escchar(long e, int *escflg)
+{
+	long c, l;
+	int i;
+
+	*escflg = 0;
+
+loop:
+	c = getr();
+	if(c == '\n') {
+		yyerror("newline in string");
+		return EOF;
+	}
+	if(c != '\\') {
+		if(c == e)
+			c = EOF;
+		return c;
+	}
+	c = getr();
+	switch(c) {
+	case '\n':
+		goto loop;
+
+	case 'x':
+		i = 2;
+		goto hex;
+
+	case 'u':
+		i = 4;
+		goto hex;
+
+	case 'U':
+		i = 8;
+		goto hex;
+
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+		goto oct;
+
+	case 'a': return '\a';
+	case 'b': return '\b';
+	case 'f': return '\f';
+	case 'n': return '\n';
+	case 'r': return '\r';
+	case 't': return '\t';
+	case 'v': return '\v';
+
+	default:
+		if(c != e)
+		warn("unknown escape sequence: %c", c);
+	}
+	return c;
+
+hex:
+	l = 0;
+	for(; i>0; i--) {
+		c = getc();
+		if(c >= '0' && c <= '9') {
+			l = l*16 + c-'0';
+			continue;
+		}
+		if(c >= 'a' && c <= 'f') {
+			l = l*16 + c-'a' + 10;
+			continue;
+		}
+		if(c >= 'A' && c <= 'F') {
+			l = l*16 + c-'A' + 10;
+			continue;
+		}
+		warn("non-hex character in escape sequence: %c", c);
+		ungetc(c);
+		break;
+	}
+	*escflg = 1;
+	return l;
+
+oct:
+	l = c - '0';
+	for(i=2; i>0; i--) {
+		c = getc();
+		if(c >= '0' && c <= '7') {
+			l = l*8 + c-'0';
+			continue;
+		}
+		warn("non-oct character in escape sequence: %c", c);
+		ungetc(c);
+	}
+	if(l > 255)
+		warn("oct escape value > 255: %d", l);
+	*escflg = 1;
+	return l;
+}
+
+static	struct
+{
+	char*	name;
+	int	lexical;
+	int	etype;
+} syms[] =
+{
+/*	name		lexical		etype
+ */
+/* basic types */
+	"int8",		LBASETYPE,	TINT8,
+	"int16",	LBASETYPE,	TINT16,
+	"int32",	LBASETYPE,	TINT32,
+	"int64",	LBASETYPE,	TINT64,
+
+	"uint8",	LBASETYPE,	TUINT8,
+	"uint16",	LBASETYPE,	TUINT16,
+	"uint32",	LBASETYPE,	TUINT32,
+	"uint64",	LBASETYPE,	TUINT64,
+
+	"float32",	LBASETYPE,	TFLOAT32,
+	"float64",	LBASETYPE,	TFLOAT64,
+	"float80",	LBASETYPE,	TFLOAT80,
+
+	"bool",		LBASETYPE,	TBOOL,
+	"byte",		LBASETYPE,	TUINT8,
+	"char",		LBASETYPE,	TUINT8,		// temp??
+	"string",	LBASETYPE,	TSTRING,
+
+/* keywords */
+	"any",		LANY,		Txxx,
+	"break",	LBREAK,		Txxx,
+	"case",		LCASE,		Txxx,
+	"chan",		LCHAN,		Txxx,
+	"const",	LCONST,		Txxx,
+	"continue",	LCONTINUE,	Txxx,
+	"convert",	LCONVERT,	Txxx,
+	"default",	LDEFAULT,	Txxx,
+	"else",		LELSE,		Txxx,
+	"export",	LEXPORT,	Txxx,
+	"fallthrough",	LFALL,		Txxx,
+	"false",	LFALSE,		Txxx,
+	"for",		LFOR,		Txxx,
+	"func",		LFUNC,		Txxx,
+	"go",		LGO,		Txxx,
+	"goto",		LGOTO,		Txxx,
+	"if",		LIF,		Txxx,
+	"import",	LIMPORT,	Txxx,
+	"interface",	LINTERFACE,	Txxx,
+	"iota",		LIOTA,		Txxx,
+	"map",		LMAP,		Txxx,
+	"new",		LNEW,		Txxx,
+	"len",		LLEN,		Txxx,
+	"nil",		LNIL,		Txxx,
+	"package",	LPACKAGE,	Txxx,
+	"panic",	LPANIC,		Txxx,
+	"print",	LPRINT,		Txxx,
+	"range",	LRANGE,		Txxx,
+	"return",	LRETURN,	Txxx,
+	"struct",	LSTRUCT,	Txxx,
+	"switch",	LSWITCH,	Txxx,
+	"true",		LTRUE,		Txxx,
+	"type",		LTYPE,		Txxx,
+	"var",		LVAR,		Txxx,
+
+	"notwithstanding",		LIGNORE,	Txxx,
+	"thetruthofthematter",		LIGNORE,	Txxx,
+	"despiteallobjections",		LIGNORE,	Txxx,
+	"whereas",			LIGNORE,	Txxx,
+	"insofaras",			LIGNORE,	Txxx,
+};
+
+void
+lexinit(void)
+{
+	int i, etype, lex;
+	Sym *s;
+	Type *t;
+
+	besetptr();
+
+	for(i=TINT8; i<=TUINT64; i++)
+		isint[i] = 1;
+	for(i=TFLOAT32; i<=TFLOAT80; i++)
+		isfloat[i] = 1;
+	isptr[TPTR32] = 1;
+	isptr[TPTR64] = 1;
+
+	issigned[TINT8] = 1;
+	issigned[TINT16] = 1;
+	issigned[TINT32] = 1;
+	issigned[TINT64] = 1;
+
+	/*
+	 * initialize okfor
+	 */
+	for(i=0; i<NTYPE; i++) {
+		if(isint[i]) {
+			okforeq[i] = 1;
+			okforadd[i] = 1;
+			okforand[i] = 1;
+		}
+		if(isfloat[i]) {
+			okforeq[i] = 1;
+			okforadd[i] = 1;
+		}
+		switch(i) {
+		case TBOOL:
+		case TPTR32:
+		case TPTR64:
+			okforeq[i] = 1;
+			break;
+		}
+		minfloatval[i] = 0.0;
+		maxfloatval[i] = 0.0;
+		minintval[i] = 0;
+		maxintval[i] = 0;
+	}
+
+// this stuff smells - really need to do constants
+// in multi precision arithmetic
+
+	maxintval[TINT8] = 0x7f;
+	minintval[TINT8] = -maxintval[TINT8]-1;
+	maxintval[TINT16] = 0x7fff;
+	minintval[TINT16] = -maxintval[TINT16]-1;
+	maxintval[TINT32] = 0x7fffffffL;
+	minintval[TINT32] = -maxintval[TINT32]-1;
+	maxintval[TINT64] = 0x7fffffffffffffffLL;
+	minintval[TINT64] = -maxintval[TINT64]-1;
+	maxintval[TUINT8] = 0xff;
+	maxintval[TUINT16] = 0xffff;
+	maxintval[TUINT32] = 0xffffffffL;
+
+	/* special case until we got to multiple precision */
+	maxintval[TUINT64] = 0x7fffffffffffffffLL;
+	minintval[TUINT64] = -maxintval[TUINT64]-1;
+
+	maxfloatval[TFLOAT32] = 3.40282347e+38;
+	minfloatval[TFLOAT32] = -maxfloatval[TFLOAT32];
+	maxfloatval[TFLOAT64] = 1.7976931348623157e+308;
+	minfloatval[TFLOAT64] = -maxfloatval[TFLOAT64]-1;
+
+	/*
+	 * initialize basic types array
+	 * initialize known symbols
+	 */
+	for(i=0; i<nelem(syms); i++) {
+		lex = syms[i].lexical;
+		s = lookup(syms[i].name);
+		s->lexical = lex;
+
+		if(lex != LBASETYPE)
+			continue;
+
+		etype = syms[i].etype;
+		if(etype < 0 || etype >= nelem(types))
+			fatal("lexinit: %s bad etype", s->name);
+
+		t = types[etype];
+		if(t != T) {
+			s->otype = t;
+			continue;
+		}
+		t = typ(etype);
+		switch(etype) {
+		case TSTRING:
+		case TCHAN:
+		case TMAP:
+			t = ptrto(t);
+		}
+
+		t->sym = s;
+		t->recur = 1;	// supresses printing beyond name
+
+		dowidth(t);
+		types[etype] = t;
+		s->otype = t;
+	}
+
+	/* pick up the backend typedefs */
+	belexinit(LBASETYPE);
+
+	booltrue = nod(OLITERAL, N, N);
+	booltrue->val.ctype = CTBOOL;
+	booltrue->val.vval = 1;
+	booltrue->type = types[TBOOL];
+	booltrue->addable = 1;
+
+	boolfalse = nod(OLITERAL, N, N);
+	boolfalse->val.ctype = CTBOOL;
+	boolfalse->val.vval = 0;
+	boolfalse->type = types[TBOOL];
+	boolfalse->addable = 1;
+}
+
+struct
+{
+	int	lex;
+	char*	name;
+} lexn[] =
+{
+	LANDAND,	"ANDAND",
+	LASOP,		"ASOP",
+	LACONST,	"ACONST",
+	LATYPE,		"ATYPE",
+	LBASETYPE,	"BASETYPE",
+	LBREAK,		"BREAK",
+	LCASE,		"CASE",
+	LCHAN,		"CHAN",
+	LCOLAS,		"COLAS",
+	LCONST,		"CONST",
+	LCONTINUE,	"CONTINUE",
+	LDEC,		"DEC",
+	LELSE,		"ELSE",
+	LEQ,		"EQ",
+	LFUNC,		"FUNC",
+	LGE,		"GE",
+	LGO,		"GO",
+	LGOTO,		"GOTO",
+	LGT,		"GT",
+	LIF,		"IF",
+	LINC,		"INC",
+	LINTERFACE,	"INTERFACE",
+	LLE,		"LE",
+	LLITERAL,	"LITERAL",
+	LLSH,		"LSH",
+	LLT,		"LT",
+	LMAP,		"MAP",
+	LNAME,		"NAME",
+	LNE,		"NE",
+	LOROR,		"OROR",
+	LPACK,		"PACK",
+	LRANGE,		"RANGE",
+	LRETURN,	"RETURN",
+	LRSH,		"RSH",
+	LSTRUCT,	"STRUCT",
+	LSWITCH,	"SWITCH",
+	LTYPE,		"TYPE",
+	LVAR,		"VAR",
+	LFOR,		"FOR",
+	LNEW,		"NEW",
+	LLEN,		"LEN",
+	LFALL,		"FALL",
+	LCONVERT,	"CONVERT",
+	LIOTA,		"IOTA",
+	LPRINT,		"PRINT",
+	LPACKAGE,	"PACKAGE",
+	LIMPORT,	"IMPORT",
+	LEXPORT,	"EXPORT",
+	LPANIC,		"PANIC",
+};
+
+char*
+lexname(int lex)
+{
+	int i;
+	static char buf[100];
+
+	for(i=0; i<nelem(lexn); i++)
+		if(lexn[i].lex == lex)
+			return lexn[i].name;
+	snprint(buf, sizeof(buf), "LEX-%d", lex);
+	return buf;
+}
+
+void
+mkpackage(char* pkg)
+{
+	Sym *s;
+	long h;
+
+	if(bout != nil) {
+		yyerror("mkpackage: called again %s %s", pkg, package);
+		return;
+	}
+
+	// redefine all names to be this package
+	package = pkg;
+	for(h=0; h<NHASH; h++)
+		for(s = hash[h]; s != S; s = s->link) {
+			s->package = package;
+			s->opackage = package;
+		}
+
+	if(outfile == nil) {
+		// BOTCH need to get .6 from backend
+		snprint(namebuf, sizeof(namebuf), "%s.6", package);
+		outfile = strdup(namebuf);
+	}
+}
diff --git a/src/cmd/gc/mksys.bash b/src/cmd/gc/mksys.bash
new file mode 100644
index 0000000..edd1c9d
--- /dev/null
+++ b/src/cmd/gc/mksys.bash
@@ -0,0 +1,19 @@
+# Copyright 2009 The Go Authors.  All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+6g sys.go
+echo '1,/((/d
+/))/+1,$d
+1,$s/foop/sys/g
+1,$s/^[ 	]*/	"/g
+1,$s/$/\\n"/g
+1i
+char*	sysimport =
+.
+$a
+;
+
+.
+w sysimport.c
+q' | ed foop.6
diff --git a/src/cmd/gc/mpatof.c b/src/cmd/gc/mpatof.c
new file mode 100644
index 0000000..07bcf4a
--- /dev/null
+++ b/src/cmd/gc/mpatof.c
@@ -0,0 +1,342 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include	<u.h>
+#include	<libc.h>
+
+int	mpatof(char*, double*);
+int	mpatov(char *s, vlong *v);
+
+enum
+{
+	Mpscale	= 29,		/* safely smaller than bits in a long */
+	Mpprec	= 36,		/* Mpscale*Mpprec sb > largest fp exp */
+	Mpbase	= 1L<<Mpscale,
+};
+
+typedef
+struct
+{
+	long	a[Mpprec];
+	char	ovf;
+} Mp;
+
+static	void	mpint(Mp*, int);
+static	void	mppow(Mp*, int, int);
+static	void	mpmul(Mp*, int);
+static	void	mpadd(Mp*, Mp*);
+static	int	mptof(Mp*, double*);
+
+/*
+ * convert a string, s, to floating in *d
+ * return conversion overflow.
+ * required syntax is [+-]d*[.]d*[e[+-]d*]
+ */
+int
+mpatof(char *s, double *d)
+{
+	Mp a, b;
+	int dp, c, f, ef, ex, zer;
+	double d1, d2;
+
+	dp = 0;		/* digits after decimal point */
+	f = 0;		/* sign */
+	ex = 0;		/* exponent */
+	zer = 1;	/* zero */
+	memset(&a, 0, sizeof(a));
+	for(;;) {
+		switch(c = *s++) {
+		default:
+			goto bad;
+		case '-':
+			f = 1;
+		case ' ':
+		case  '\t':
+		case  '+':
+			continue;
+		case '.':
+			dp = 1;
+			continue;
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+			zer = 0;
+		case '0':
+			mpint(&b, c-'0');
+			mpmul(&a, 10);
+			mpadd(&a, &b);
+			if(dp)
+				dp++;
+			continue;
+		case 'E':
+		case 'e':
+			ex = 0;
+			ef = 0;
+			for(;;) {
+				c = *s++;
+				if(c == '+' || c == ' ' || c == '\t')
+					continue;
+				if(c == '-') {
+					ef = 1;
+					continue;
+				}
+				if(c >= '0' && c <= '9') {
+					ex = ex*10 + (c-'0');
+					continue;
+				}
+				break;
+			}
+			if(ef)
+				ex = -ex;
+		case 0:
+			break;
+		}
+		break;
+	}
+	if(a.ovf)
+		goto bad;
+	if(zer) {
+		*d = 0;
+		return 0;
+	}
+	if(dp)
+		dp--;
+	dp -= ex;
+	if(dp > 0) {
+		/*
+		 * must divide by 10**dp
+		 */
+		if(mptof(&a, &d1))
+			goto bad;
+
+		/*
+		 * trial exponent of 8**dp
+		 * 8 (being between 5 and 10)
+		 * should pick up all underflows
+		 * in the division of 5**dp.
+		 */
+		d2 = frexp(d1, &ex);
+		d2 = ldexp(d2, ex-3*dp);
+		if(d2 == 0)
+			goto bad;
+
+		/*
+		 * decompose each 10 into 5*2.
+		 * create 5**dp in fixed point
+		 * and then play with the exponent
+		 * for the remaining 2**dp.
+		 * note that 5**dp will overflow
+		 * with as few as 134 input digits.
+		 */
+		mpint(&a, 1);
+		mppow(&a, 5, dp);
+		if(mptof(&a, &d2))
+			goto bad;
+		d1 = frexp(d1/d2, &ex);
+		d1 = ldexp(d1, ex-dp);
+		if(d1 == 0)
+			goto bad;
+	} else {
+		/*
+		 * must multiply by 10**|dp| --
+		 * just do it in fixed point.
+		 */
+		mppow(&a, 10, -dp);
+		if(mptof(&a, &d1))
+			goto bad;
+	}
+	if(f)
+		d1 = -d1;
+	*d = d1;
+	return 0;
+
+bad:
+	return 1;
+}
+
+/*
+ * convert a to floating in *d
+ * return conversion overflow
+ */
+static int
+mptof(Mp *a, double *d)
+{
+	double f, g;
+	long x, *a1;
+	int i;
+
+	if(a->ovf)
+		return 1;
+	a1 = a->a;
+	f = ldexp(*a1++, 0);
+	for(i=Mpscale; i<Mpprec*Mpscale; i+=Mpscale)
+		if(x = *a1++) {
+			g = ldexp(x, i);
+			/*
+			 * NOTE: the test (g==0) is plan9
+			 * specific. ansi compliant overflow
+			 * is signaled by HUGE and errno==ERANGE.
+			 * change this for your particular ldexp.
+			 */
+			if(g == 0)
+				return 1;
+			f += g;		/* this could bomb! */
+		}
+	*d = f;
+	return 0;
+}
+
+/*
+ * return a += b
+ */
+static void
+mpadd(Mp *a, Mp *b)
+{
+	int i, c;
+	long x, *a1, *b1;
+
+	if(b->ovf)
+		a->ovf = 1;
+	if(a->ovf)
+		return;
+	c = 0;
+	a1 = a->a;
+	b1 = b->a;
+	for(i=0; i<Mpprec; i++) {
+		x = *a1 + *b1++ + c;
+		c = 0;
+		if(x >= Mpbase) {
+			x -= Mpbase;
+			c = 1;
+		}
+		*a1++ = x;
+	}
+	a->ovf = c;
+}
+
+/*
+ * return a = c
+ */
+static void
+mpint(Mp *a, int c)
+{
+
+	memset(a, 0, sizeof(*a));
+	a->a[0] = c;
+}
+
+/*
+ * return a *= c
+ */
+static void
+mpmul(Mp *a, int c)
+{
+	Mp p;
+	int b;
+	memmove(&p, a, sizeof(p));
+	if(!(c & 1))
+		memset(a, 0, sizeof(*a));
+	c &= ~1;
+	for(b=2; c; b<<=1) {
+		mpadd(&p, &p);
+		if(c & b) {
+			mpadd(a, &p);
+			c &= ~b;
+		}
+	}
+}
+
+/*
+ * return a *= b**e
+ */
+static void
+mppow(Mp *a, int b, int e)
+{
+	int b1;
+
+	b1 = b*b;
+	b1 = b1*b1;
+	while(e >= 4) {
+		mpmul(a, b1);
+		e -= 4;
+		if(a->ovf)
+			return;
+	}
+	while(e > 0) {
+		mpmul(a, b);
+		e--;
+	}
+}
+
+/*
+ * convert a string, s, to vlong in *v
+ * return conversion overflow.
+ * required syntax is [0[x]]d*
+ */
+int
+mpatov(char *s, vlong *v)
+{
+	vlong n, nn;
+	int c;
+	n = 0;
+	c = *s;
+	if(c == '0')
+		goto oct;
+	while(c = *s++) {
+		if(c >= '0' && c <= '9')
+			nn = n*10 + c-'0';
+		else
+			goto bad;
+		if(n < 0 && nn >= 0)
+			goto bad;
+		n = nn;
+	}
+	goto out;
+oct:
+	s++;
+	c = *s;
+	if(c == 'x' || c == 'X')
+		goto hex;
+	while(c = *s++) {
+		if(c >= '0' || c <= '7')
+			nn = n*8 + c-'0';
+		else
+			goto bad;
+		if(n < 0 && nn >= 0)
+			goto bad;
+		n = nn;
+	}
+	goto out;
+hex:
+	s++;
+	while(c = *s++) {
+		if(c >= '0' && c <= '9')
+			c += 0-'0';
+		else
+		if(c >= 'a' && c <= 'f')
+			c += 10-'a';
+		else
+		if(c >= 'A' && c <= 'F')
+			c += 10-'A';
+		else
+			goto bad;
+		nn = n*16 + c;
+		if(n < 0 && nn >= 0)
+			goto bad;
+		n = nn;
+	}
+out:
+	*v = n;
+	return 0;
+
+bad:
+	*v = ~0;
+	return 1;
+}
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
new file mode 100644
index 0000000..6f1ad12
--- /dev/null
+++ b/src/cmd/gc/subr.c
@@ -0,0 +1,1591 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include	"go.h"
+#include	"y.tab.h"
+
+void
+errorexit(void)
+{
+	if(outfile)
+		remove(outfile);
+	myexit(1);
+}
+
+void
+myexit(int x)
+{
+	if(x)
+		exits("error");
+	exits(nil);
+}
+
+void
+yyerror(char *fmt, ...)
+{
+	va_list arg;
+	long lno;
+
+	lno = dynlineno;
+	if(lno == 0)
+		lno = curio.lineno;
+
+	print("%s:%ld: ", curio.infile, lno);
+	va_start(arg, fmt);
+	vfprint(1, fmt, arg);
+	va_end(arg);
+	print("\n");
+	if(debug['h'])
+		*(int*)0 = 0;
+
+	nerrors++;
+	if(nerrors >= 10)
+		fatal("too many errors");
+}
+
+void
+warn(char *fmt, ...)
+{
+	va_list arg;
+	long lno;
+
+	lno = dynlineno;
+	if(lno == 0)
+		lno = curio.lineno;
+
+	print("%s:%ld: ", curio.infile, lno);
+	va_start(arg, fmt);
+	vfprint(1, fmt, arg);
+	va_end(arg);
+	print("\n");
+	if(debug['h'])
+		*(int*)0 = 0;
+}
+
+void
+fatal(char *fmt, ...)
+{
+	va_list arg;
+	long lno;
+
+	lno = dynlineno;
+	if(lno == 0)
+		lno = curio.lineno;
+
+	print("%s:%ld: fatal error: ", curio.infile, lno);
+	va_start(arg, fmt);
+	vfprint(1, fmt, arg);
+	va_end(arg);
+	print("\n");
+	if(debug['h'])
+		*(int*)0 = 0;
+	myexit(1);
+}
+
+ulong
+stringhash(char *p)
+{
+	long h;
+	int c;
+
+	h = 0;
+	for(;;) {
+		c = *p++;
+		if(c == 0)
+			break;
+		h = h*PRIME1 + c;
+	}
+
+	if(h < 0) {
+		h = -h;
+		if(h < 0)
+			h = 0;
+	}
+	return h;
+}
+
+Sym*
+lookup(char *p)
+{
+	Sym *s;
+	ulong h;
+	int c;
+
+	h = stringhash(p) % NHASH;
+	c = p[0];
+
+	for(s = hash[h]; s != S; s = s->link) {
+		if(s->name[0] != c)
+			continue;
+		if(strcmp(s->name, p) == 0)
+			if(strcmp(s->package, package) == 0)
+				return s;
+	}
+
+	s = mal(sizeof(*s));
+	s->lexical = LNAME;
+	s->name = mal(strlen(p)+1);
+	s->opackage = package;
+	s->package = package;
+
+	strcpy(s->name, p);
+
+	s->link = hash[h];
+	hash[h] = s;
+
+	return s;
+}
+
+Sym*
+pkglookup(char *p, char *k)
+{
+	Sym *s;
+	ulong h;
+	int c;
+
+	h = stringhash(p) % NHASH;
+	c = p[0];
+	for(s = hash[h]; s != S; s = s->link) {
+		if(s->name[0] != c)
+			continue;
+		if(strcmp(s->name, p) == 0)
+			if(strcmp(s->package, k) == 0)
+				return s;
+	}
+
+	s = mal(sizeof(*s));
+	s->lexical = LNAME;
+	s->name = mal(strlen(p)+1);
+	strcpy(s->name, p);
+
+	// botch - should probably try to reuse the pkg string
+	s->package = mal(strlen(k)+1);
+	s->opackage = s->package;
+	strcpy(s->package, k);
+
+	s->link = hash[h];
+	hash[h] = s;
+
+	return s;
+}
+
+void
+gethunk(void)
+{
+	char *h;
+	long nh;
+
+	nh = NHUNK;
+	if(thunk >= 10L*NHUNK)
+		nh = 10L*NHUNK;
+	h = (char*)malloc(nh);
+	if(h == (char*)-1) {
+		yyerror("out of memory");
+		errorexit();
+	}
+	hunk = h;
+	nhunk = nh;
+	thunk += nh;
+}
+
+void*
+mal(long n)
+{
+	void *p;
+
+	while((ulong)hunk & MAXALIGN) {
+		hunk++;
+		nhunk--;
+	}
+	while(nhunk < n)
+		gethunk();
+
+	p = hunk;
+	nhunk -= n;
+	hunk += n;
+	memset(p, 0, n);
+	return p;
+}
+
+void*
+remal(void *p, long on, long n)
+{
+	void *q;
+
+	q = (uchar*)p + on;
+	if(q != hunk || nhunk < n) {
+		while(nhunk < on+n)
+			gethunk();
+		memmove(hunk, p, on);
+		p = hunk;
+		hunk += on;
+		nhunk -= on;
+	}
+	hunk += n;
+	nhunk -= n;
+	return p;
+}
+
+Dcl*
+dcl(void)
+{
+	Dcl *d;
+
+	d = mal(sizeof(*d));
+	d->lineno = dynlineno;
+	return d;
+}
+
+Node*
+nod(int op, Node *nleft, Node *nright)
+{
+	Node *n;
+
+	n = mal(sizeof(*n));
+	n->op = op;
+	n->left = nleft;
+	n->right = nright;
+	n->lineno = dynlineno;
+	if(dynlineno == 0)
+		n->lineno = curio.lineno;
+	return n;
+}
+
+Type*
+typ(int et)
+{
+	Type *t;
+
+	t = mal(sizeof(*t));
+	t->etype = et;
+	return t;
+}
+
+Node*
+dobad(void)
+{
+	return nod(OBAD, N, N);
+}
+
+Node*
+nodintconst(long v)
+{
+	Node *c;
+
+	c = nod(OLITERAL, N, N);
+	c->addable = 1;
+	c->val.vval = v;
+	c->val.ctype = CTINT;
+	c->type = types[TINT32];
+	ullmancalc(c);
+	return c;
+}
+
+Node*
+rev(Node *na)
+{
+	Node *i, *n;
+
+	/*
+	 * since yacc wants to build lists
+	 * stacked down on the left -
+	 * this routine converts them to
+	 * stack down on the right -
+	 * in memory without recursion
+	 */
+
+	if(na == N || na->op != OLIST)
+		return na;
+	i = na;
+	for(n = na->left; n != N; n = n->left) {
+		if(n->op != OLIST)
+			break;
+		i->left = n->right;
+		n->right = i;
+		i = n;
+	}
+	i->left = n;
+	return i;
+}
+
+Node*
+unrev(Node *na)
+{
+	Node *i, *n;
+
+	/*
+	 * this restores a reverse list
+	 */
+	if(na == N || na->op != OLIST)
+		return na;
+	i = na;
+	for(n = na->right; n != N; n = n->right) {
+		if(n->op != OLIST)
+			break;
+		i->right = n->left;
+		n->left = i;
+		i = n;
+	}
+	i->right = n;
+	return i;
+}
+
+Type*
+aindex(Node *b, Type *t)
+{
+	Type *r;
+
+	r = typ(TARRAY);
+	r->type = t;
+
+	if(t->etype == TDARRAY)
+		yyerror("dynamic array type cannot be a dynamic array");
+
+	walktype(b, 0);
+	switch(whatis(b)) {
+	default:
+		yyerror("array bound must be a constant integer expression");
+		break;
+
+	case Wnil:	// default zero lb
+		r->bound = 0;
+		break;
+
+	case Wlitint:	// fixed lb
+		r->bound = b->val.vval;
+		break;
+	}
+	return r;
+}
+
+void
+indent(int dep)
+{
+	int i;
+
+	for(i=0; i<dep; i++)
+		print(".   ");
+}
+
+void
+dodump(Node *n, int dep)
+{
+
+loop:
+	if(n == N)
+		return;
+
+	switch(n->op) {
+	case OLIST:
+		if(n->left != N && n->left->op == OLIST)
+			dodump(n->left, dep+1);
+		else
+			dodump(n->left, dep);
+		n = n->right;
+		goto loop;
+
+//	case ODCLFUNC:
+//		dodump(n->nname, dep);
+//		if(n->this) {
+//			indent(dep);
+//			print("%O-this\n", n->op);
+//			dodump(n->this, dep+1);
+//		}
+//		if(n->argout) {
+//			indent(dep);
+//			print("%O-outarg\n", n->op);
+//			dodump(n->argout, dep+1);
+//		}
+//		if(n->argin) {
+//			indent(dep);
+//			print("%O-inarg\n", n->op);
+//			dodump(n->argin, dep+1);
+//		}
+//		n = n->nbody;
+//		goto loop;
+
+	case OIF:
+	case OSWITCH:
+	case OFOR:
+		dodump(n->ninit, dep);
+		break;
+	}
+
+	indent(dep);
+	if(dep > 10) {
+		print("...\n");
+		return;
+	}
+
+	switch(n->op) {
+	default:
+		print("%N\n", n);
+		break;
+
+	case OTYPE:
+		print("%O-%E %lT\n", n->op, n->etype, n);
+		break;
+
+	case OIF:
+		print("%O%J\n", n->op, n);
+		dodump(n->ntest, dep+1);
+		if(n->nbody != N) {
+			indent(dep);
+			print("%O-then\n", n->op);
+			dodump(n->nbody, dep+1);
+		}
+		if(n->nelse != N) {
+			indent(dep);
+			print("%O-else\n", n->op);
+			dodump(n->nelse, dep+1);
+		}
+		return;
+
+	case OSWITCH:
+	case OFOR:
+		print("%O%J\n", n->op, n);
+		dodump(n->ntest, dep+1);
+
+		if(n->nbody != N) {
+			indent(dep);
+			print("%O-body\n", n->op);
+			dodump(n->nbody, dep+1);
+		}
+
+		if(n->nincr != N) {
+			indent(dep);
+			print("%O-incr\n", n->op);
+			dodump(n->nincr, dep+1);
+		}
+		return;
+
+	case OCASE:
+		// the right side points to the next case
+		print("%O%J\n", n->op, n);
+		dodump(n->left, dep+1);
+		return;
+	}
+
+	dodump(n->left, dep+1);
+	n = n->right;
+	dep++;
+	goto loop;
+}
+
+void
+dump(char *s, Node *n)
+{
+	print("%s\n", s);
+	dodump(n, 1);
+}
+
+int
+whatis(Node *n)
+{
+	Type *t;
+
+	if(n == N)
+		return Wnil;
+
+	if(n->op == OLITERAL) {
+		switch(n->val.ctype) {
+		default:
+			break;
+		case CTINT:
+		case CTSINT:
+		case CTUINT:
+			return Wlitint;
+		case CTFLT:
+			return Wlitfloat;
+		case CTBOOL:
+			return Wlitbool;
+		case CTSTR:
+			return Wlitstr;
+		}
+		return Wtunkn;
+	}
+
+	t = n->type;
+	if(t == T)
+		return Wtnil;
+
+	switch(t->etype) {
+	case TINT8:
+	case TINT16:
+	case TINT32:
+	case TINT64:
+	case TUINT8:
+	case TUINT16:
+	case TUINT32:
+	case TUINT64:
+		return Wtint;
+	case TFLOAT32:
+	case TFLOAT64:
+	case TFLOAT80:
+		return Wtfloat;
+	case TBOOL:
+		return Wtbool;
+
+	case TPTR32:
+	case TPTR64:
+		if(isptrto(t, TSTRING))
+			return Wtstr;
+		break;
+	}
+	return Wtunkn;
+}
+
+/*
+s%,%,\n%g
+s%\n+%\n%g
+s%^[ 	]*O%%g
+s%,.*%%g
+s%.+%	[O&]		= "&",%g
+s%^	........*\]%&~%g
+s%~	%%g
+*/
+
+static char*
+opnames[] =
+{
+	[OADDR]		= "ADDR",
+	[OADD]		= "ADD",
+	[OANDAND]	= "ANDAND",
+	[OAND]		= "AND",
+	[OARRAY]	= "ARRAY",
+	[OASOP]		= "ASOP",
+	[OAS]		= "AS",
+	[OBAD]		= "BAD",
+	[OBREAK]	= "BREAK",
+	[OCALL]		= "CALL",
+	[OCALLMETH]	= "CALLMETH",
+	[OCALLINTER]	= "CALLINTER",
+	[OCASE]		= "CASE",
+	[OXCASE]	= "XCASE",
+	[OCMP]		= "CMP",
+	[OFALL]		= "FALL",
+	[OCONV]		= "CONV",
+	[OCOM]		= "COM",
+	[OCONST]	= "CONST",
+	[OCONTINUE]	= "CONTINUE",
+	[ODCLARG]	= "DCLARG",
+	[ODCLFIELD]	= "DCLFIELD",
+	[ODCLFUNC]	= "DCLFUNC",
+	[ODIV]		= "DIV",
+	[ODOT]		= "DOT",
+	[ODOTPTR]	= "DOTPTR",
+	[ODOTMETH]	= "DOTMETH",
+	[ODOTINTER]	= "DOTINTER",
+	[OEMPTY]	= "EMPTY",
+	[OEND]		= "END",
+	[OEQ]		= "EQ",
+	[OFOR]		= "FOR",
+	[OFUNC]		= "FUNC",
+	[OGE]		= "GE",
+	[OPROC]		= "PROC",
+	[OGOTO]		= "GOTO",
+	[OGT]		= "GT",
+	[OIF]		= "IF",
+	[OINDEX]	= "INDEX",
+	[OINDEXPTR]	= "INDEXPTR",
+	[OIND]		= "IND",
+	[OLABEL]	= "LABEL",
+	[OLE]		= "LE",
+	[OLEN]		= "LEN",
+	[OLIST]		= "LIST",
+	[OLITERAL]	= "LITERAL",
+	[OLSH]		= "LSH",
+	[OLT]		= "LT",
+	[OMINUS]	= "MINUS",
+	[OMOD]		= "MOD",
+	[OMUL]		= "MUL",
+	[ONAME]		= "NAME",
+	[ONE]		= "NE",
+	[ONOT]		= "NOT",
+	[OOROR]		= "OROR",
+	[OOR]		= "OR",
+	[OPLUS]		= "PLUS",
+	[ODEC]		= "DEC",
+	[OINC]		= "INC",
+	[OREGISTER]	= "REGISTER",
+	[OINDREG]	= "INDREG",
+	[OSEND]		= "SEND",
+	[ORECV]		= "RECV",
+	[OPTR]		= "PTR",
+	[ORETURN]	= "RETURN",
+	[ORSH]		= "RSH",
+	[OI2S]		= "I2S",
+	[OS2I]		= "S2I",
+	[OI2I]		= "I2I",
+	[OSLICE]	= "SLICE",
+	[OSUB]		= "SUB",
+	[OSWITCH]	= "SWITCH",
+	[OTYPE]		= "TYPE",
+	[OVAR]		= "VAR",
+	[OEXPORT]	= "EXPORT",
+	[OIMPORT]	= "IMPORT",
+	[OXOR]		= "XOR",
+	[ONEW]		= "NEW",
+	[OFALL]		= "FALL",
+	[OXFALL]	= "XFALL",
+	[OPANIC]	= "PANIC",
+	[OPRINT]	= "PRINT",
+	[OXXX]		= "XXX",
+};
+
+int
+Oconv(Fmt *fp)
+{
+	char buf[500];
+	int o;
+
+	o = va_arg(fp->args, int);
+	if(o < 0 || o >= nelem(opnames) || opnames[o] == nil) {
+		snprint(buf, sizeof(buf), "O-%d", o);
+		return fmtstrcpy(fp, buf);
+	}
+	return fmtstrcpy(fp, opnames[o]);
+}
+
+/*
+s%,%,\n%g
+s%\n+%\n%g
+s%^[ 	]*T%%g
+s%,.*%%g
+s%.+%	[T&]		= "&",%g
+s%^	........*\]%&~%g
+s%~	%%g
+*/
+
+static char*
+etnames[] =
+{
+	[TINT8]		= "INT8",
+	[TUINT8]	= "UINT8",
+	[TINT16]	= "INT16",
+	[TUINT16]	= "UINT16",
+	[TINT32]	= "INT32",
+	[TUINT32]	= "UINT32",
+	[TINT64]	= "INT64",
+	[TUINT64]	= "UINT64",
+	[TFLOAT32]	= "FLOAT32",
+	[TFLOAT64]	= "FLOAT64",
+	[TFLOAT80]	= "FLOAT80",
+	[TBOOL]		= "BOOL",
+	[TPTR32]	= "PTR32",
+	[TPTR64]	= "PTR64",
+	[TFUNC]		= "FUNC",
+	[TARRAY]	= "ARRAY",
+	[TDARRAY]	= "DARRAY",
+	[TSTRUCT]	= "STRUCT",
+	[TCHAN]		= "CHAN",
+	[TMAP]		= "MAP",
+	[TINTER]	= "INTER",
+	[TFORW]		= "FORW",
+	[TFIELD]	= "FIELD",
+	[TSTRING]	= "STRING",
+	[TCHAN]		= "CHAN",
+};
+
+int
+Econv(Fmt *fp)
+{
+	char buf[500];
+	int et;
+
+	et = va_arg(fp->args, int);
+	if(et < 0 || et >= nelem(etnames) || etnames[et] == nil) {
+		snprint(buf, sizeof(buf), "E-%d", et);
+		return fmtstrcpy(fp, buf);
+	}
+	return fmtstrcpy(fp, etnames[et]);
+}
+
+int
+Jconv(Fmt *fp)
+{
+	char buf[500], buf1[100];
+	Node *n;
+
+	n = va_arg(fp->args, Node*);
+	strcpy(buf, "");
+
+	if(n->ullman != 0) {
+		snprint(buf1, sizeof(buf1), " u(%d)", n->ullman);
+		strncat(buf, buf1, sizeof(buf));
+	}
+
+	if(n->addable != 0) {
+		snprint(buf1, sizeof(buf1), " a(%d)", n->addable);
+		strncat(buf, buf1, sizeof(buf));
+	}
+
+	if(n->vargen != 0) {
+		snprint(buf1, sizeof(buf1), " g(%ld)", n->vargen);
+		strncat(buf, buf1, sizeof(buf));
+	}
+
+	if(n->lineno != 0) {
+		snprint(buf1, sizeof(buf1), " l(%ld)", n->lineno);
+		strncat(buf, buf1, sizeof(buf));
+	}
+
+	return fmtstrcpy(fp, buf);
+}
+
+int
+Gconv(Fmt *fp)
+{
+	char buf[100];
+	Type *t;
+
+	t = va_arg(fp->args, Type*);
+
+	if(t->etype == TFUNC) {
+		if(t->vargen != 0) {
+			snprint(buf, sizeof(buf), "-%d%d%d g(%ld)",
+				t->thistuple, t->outtuple, t->intuple, t->vargen);
+			goto out;
+		}
+		snprint(buf, sizeof(buf), "-%d%d%d",
+			t->thistuple, t->outtuple, t->intuple);
+		goto out;
+	}
+	if(t->vargen != 0) {
+		snprint(buf, sizeof(buf), " g(%ld)", t->vargen);
+		goto out;
+	}
+	strcpy(buf, "");
+
+out:
+	return fmtstrcpy(fp, buf);
+}
+
+int
+Sconv(Fmt *fp)
+{
+	char buf[500];
+	Sym *s;
+	char *opk, *pkg, *nam;
+
+	s = va_arg(fp->args, Sym*);
+	if(s == S) {
+		snprint(buf, sizeof(buf), "<S>");
+		goto out;
+	}
+
+	pkg = "<nil>";
+	nam = pkg;
+	opk = pkg;
+
+	if(s->opackage != nil)
+		opk = s->opackage;
+	if(s->package != nil)
+		pkg = s->package;
+	if(s->name != nil)
+		nam = s->name;
+
+	if(strcmp(pkg, package) || strcmp(opk, package) || (fp->flags & FmtLong)) {
+		if(strcmp(opk, pkg) == 0) {
+			snprint(buf, sizeof(buf), "%s.%s", pkg, nam);
+			goto out;
+		}
+		snprint(buf, sizeof(buf), "(%s)%s.%s", opk, pkg, nam);
+		goto out;
+	}
+	snprint(buf, sizeof(buf), "%s", nam);
+
+out:
+	return fmtstrcpy(fp, buf);
+}
+
+int
+Tconv(Fmt *fp)
+{
+	char buf[500], buf1[500];
+	Type *t, *t1;
+	int et;
+
+	t = va_arg(fp->args, Type*);
+	if(t == T)
+		return fmtstrcpy(fp, "<T>");
+
+	t->trecur++;
+	et = t->etype;
+
+	strcpy(buf, "");
+	if(t->sym != S) {
+		snprint(buf, sizeof(buf), "<%S>", t->sym);
+	}
+	if(t->trecur > 5) {
+		strncat(buf, "...", sizeof(buf));
+		goto out;
+	}
+
+	switch(et) {
+	default:
+		snprint(buf1, sizeof(buf1), "%E", et);
+		strncat(buf, buf1, sizeof(buf));
+		if(t->type != T) {
+			snprint(buf1, sizeof(buf1), " %T", t->type);
+			strncat(buf, buf1, sizeof(buf));
+		}
+		break;
+
+	case TFIELD:
+		snprint(buf1, sizeof(buf1), "%T", t->type);
+		strncat(buf, buf1, sizeof(buf));
+		break;
+
+	case TFUNC:
+		if(fp->flags & FmtLong)
+			snprint(buf1, sizeof(buf1), "%d%d%d(%lT,%lT,%lT)",
+				t->thistuple, t->outtuple, t->intuple,
+				t->type, t->type->down, t->type->down->down);
+		else
+			snprint(buf1, sizeof(buf1), "%d%d%d(%T,%T,%T)",
+				t->thistuple, t->outtuple, t->intuple,
+				t->type, t->type->down, t->type->down->down);
+		strncat(buf, buf1, sizeof(buf));
+		break;
+
+	case TINTER:
+		strncat(buf, "I{", sizeof(buf));
+		if(fp->flags & FmtLong) {
+			for(t1=t->type; t1!=T; t1=t1->down) {
+				snprint(buf1, sizeof(buf1), "%lT;", t1);
+				strncat(buf, buf1, sizeof(buf));
+			}
+		}
+		strncat(buf, "}", sizeof(buf));
+		break;
+
+	case TSTRUCT:
+		strncat(buf, "{", sizeof(buf));
+		if(fp->flags & FmtLong) {
+			for(t1=t->type; t1!=T; t1=t1->down) {
+				snprint(buf1, sizeof(buf1), "%lT;", t1);
+				strncat(buf, buf1, sizeof(buf));
+			}
+		}
+		strncat(buf, "}", sizeof(buf));
+		break;
+
+	case TMAP:
+		snprint(buf, sizeof(buf), "[%T]%T", t->down, t->type);
+		break;
+
+	case TARRAY:
+		snprint(buf1, sizeof(buf1), "[%ld]%T", t->bound, t->type);
+		strncat(buf, buf1, sizeof(buf));
+		break;
+
+	case TDARRAY:
+		snprint(buf1, sizeof(buf1), "[]%T", t->type);
+		strncat(buf, buf1, sizeof(buf));
+		break;
+
+	case TPTR32:
+	case TPTR64:
+		snprint(buf1, sizeof(buf1), "*%T", t->type);
+		strncat(buf, buf1, sizeof(buf));
+		break;
+	}
+
+out:
+	t->trecur--;
+	return fmtstrcpy(fp, buf);
+}
+
+int
+Nconv(Fmt *fp)
+{
+	char buf[500], buf1[500];
+	Node *n;
+
+	n = va_arg(fp->args, Node*);
+	if(n == N) {
+		snprint(buf, sizeof(buf), "<N>");
+		goto out;
+	}
+
+	switch(n->op) {
+	default:
+		snprint(buf, sizeof(buf), "%O%J", n->op, n);
+		break;
+
+	case ONAME:
+		if(n->sym == S) {
+			snprint(buf, sizeof(buf), "%O%J", n->op, n);
+			break;
+		}
+		snprint(buf, sizeof(buf), "%O-%S G%ld%J", n->op,
+			n->sym, n->sym->vargen, n);
+		goto ptyp;
+
+	case OREGISTER:
+		snprint(buf, sizeof(buf), "%O-%R%J", n->op, (int)n->val.vval, n);
+		break;
+
+	case OLITERAL:
+		switch(n->val.ctype) {
+		default:
+			snprint(buf1, sizeof(buf1), "LITERAL-ctype=%d%lld", n->val.ctype, n->val.vval);
+			break;
+		case CTINT:
+			snprint(buf1, sizeof(buf1), "I%lld", n->val.vval);
+			break;
+		case CTSINT:
+			snprint(buf1, sizeof(buf1), "S%lld", n->val.vval);
+			break;
+		case CTUINT:
+			snprint(buf1, sizeof(buf1), "U%lld", n->val.vval);
+			break;
+		case CTFLT:
+			snprint(buf1, sizeof(buf1), "F%g", n->val.dval);
+			break;
+		case CTSTR:
+			snprint(buf1, sizeof(buf1), "S\"%Z\"", n->val.sval);
+			break;
+		case CTBOOL:
+			snprint(buf1, sizeof(buf1), "B%lld", n->val.vval);
+			break;
+		case CTNIL:
+			snprint(buf1, sizeof(buf1), "N");
+			break;
+		}
+		snprint(buf, sizeof(buf), "%O-%s%J", n->op, buf1, n);
+		break;
+		
+	case OASOP:
+		snprint(buf, sizeof(buf), "%O-%O%J", n->op, n->etype, n);
+		break;
+
+	case OTYPE:
+		snprint(buf, sizeof(buf), "%O-%E%J", n->op, n->etype, n);
+		break;
+	}
+	if(n->sym != S) {
+		snprint(buf1, sizeof(buf1), " %S G%ld", n->sym, n->sym->vargen);
+		strncat(buf, buf1, sizeof(buf));
+	}
+
+ptyp:
+	if(n->type != T) {
+		snprint(buf1, sizeof(buf1), " %T", n->type);
+		strncat(buf, buf1, sizeof(buf));
+	}
+
+out:
+	return fmtstrcpy(fp, buf);
+}
+
+int
+Zconv(Fmt *fp)
+{
+	char *s, *se;
+	char *p;
+	char buf[500];
+	int c;
+	String *sp;
+
+	sp = va_arg(fp->args, String*);
+	if(sp == nil) {
+		snprint(buf, sizeof(buf), "<nil>");
+		goto out;
+	}
+	s = sp->s;
+	se = s + sp->len;
+
+	p = buf;
+
+loop:
+	c = *s++;
+	if(s > se)
+		c = 0;
+	switch(c) {
+	default:
+		*p++ = c;
+		break;
+	case 0:
+		*p = 0;
+		goto out;
+	case '\t':
+		*p++ = '\\';
+		*p++ = 't';
+		break;
+	case '\n':
+		*p++ = '\\';
+		*p++ = 'n';
+		break;
+	}
+	goto loop;	
+
+out:
+	return fmtstrcpy(fp, buf);
+}
+
+int
+isnil(Node *n)
+{
+	if(n == N)
+		return 0;
+	if(n->op != OLITERAL)
+		return 0;
+	if(n->val.ctype != CTNIL)
+		return 0;
+	return 1;
+}
+
+int
+isptrto(Type *t, int et)
+{
+	if(t == T)
+		return 0;
+	if(!isptr[t->etype])
+		return 0;
+	t = t->type;
+	if(t == T)
+		return 0;
+	if(t->etype != et)
+		return 0;
+	return 1;
+}
+
+int
+isinter(Type *t)
+{
+	if(t != T && t->etype == TINTER)
+		return 1;
+	return 0;
+}
+
+int
+isbytearray(Type *t)
+{
+	if(t == T)
+		return 0;
+	if(isptr[t->etype]) {
+		t = t->type;
+		if(t == T)
+			return 0;
+	}
+	if(t->etype != TARRAY)
+		return 0;
+	return t->bound+1;
+}
+
+int
+eqtype(Type *t1, Type *t2, int d)
+{
+	if(d >= 10)
+		return 1;
+
+	if(t1 == t2)
+		return 1;
+	if(t1 == T || t2 == T)
+		return 0;
+
+	if(t1->etype != t2->etype)
+		return 0;
+
+	switch(t1->etype) {
+	case TINTER:
+	case TSTRUCT:
+		t1 = t1->type;
+		t2 = t2->type;
+		for(;;) {
+			if(!eqtype(t1, t2, 0))
+				return 0;
+			if(t1 == T)
+				return 1;
+			if(t1->nname != N && t1->nname->sym != S) {
+				if(t2->nname == N || t2->nname->sym == S)
+					return 0;
+				if(strcmp(t1->nname->sym->name, t2->nname->sym->name) != 0) {
+					// assigned names dont count
+					if(t1->nname->sym->name[0] != '_' ||
+				   	   t2->nname->sym->name[0] != '_')
+						return 0;
+				}
+			}
+			t1 = t1->down;
+			t2 = t2->down;
+		}
+		return 1;
+
+	case TFUNC:
+		t1 = t1->type;
+		t2 = t2->type;
+		for(;;) {
+			if(t1 == t2)
+				break;
+			if(t1 == T || t2 == T)
+				return 0;
+			if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
+				return 0;
+
+			if(!eqtype(t1->type, t2->type, 0))
+				return 0;
+
+			t1 = t1->down;
+			t2 = t2->down;
+		}
+		return 1;
+	}
+	return eqtype(t1->type, t2->type, d+1);
+}
+
+/*
+ * are the arg names of two
+ * functions the same. we know
+ * that eqtype has been called
+ * and has returned true.
+ */
+int
+eqargs(Type *t1, Type *t2)
+{
+	if(t1 == t2)
+		return 1;
+	if(t1 == T || t2 == T)
+		return 0;
+
+	if(t1->etype != t2->etype)
+		return 0;
+
+	if(t1->etype != TFUNC)
+		fatal("eqargs: oops %E", t1->etype);
+
+	t1 = t1->type;
+	t2 = t2->type;
+	for(;;) {
+		if(t1 == t2)
+			break;
+		if(!eqtype(t1, t2, 0))
+			return 0;
+		t1 = t1->down;
+		t2 = t2->down;
+	}
+	return 1;
+}
+
+ulong
+typehash(Type *at, int d)
+{
+	ulong h;
+	Type *t;
+
+	if(at == T)
+		return PRIME2;
+	if(d >= 5)
+		return PRIME3;
+
+	if(at->recur)
+		return 0;
+	at->recur = 1;
+
+	h = at->etype*PRIME4;
+
+	switch(at->etype) {
+	default:
+		h += PRIME5 * typehash(at->type, d+1);
+		break;
+
+	case TINTER:
+		// botch -- should be sorted?
+		for(t=at->type; t!=T; t=t->down)
+			h += PRIME6 * typehash(t, d+1);
+		break;
+
+	case TSTRUCT:
+		for(t=at->type; t!=T; t=t->down)
+			h += PRIME7 * typehash(t, d+1);
+		break;
+
+	case TFUNC:
+		t = at->type;
+		// skip this argument
+		if(t != T)
+			t = t->down;
+		for(; t!=T; t=t->down)
+			h += PRIME7 * typehash(t, d+1);
+		break;
+	}
+
+	at->recur = 0;
+	return h;
+}
+
+Type*
+ptrto(Type *t)
+{
+	Type *t1;
+
+	if(tptr == 0)
+		fatal("ptrto: nil");
+	t1 = typ(tptr);
+	t1->type = t;
+	return t1;
+}
+
+Node*
+literal(long v)
+{
+	Node *n;
+
+	n = nod(OLITERAL, N, N);
+	n->val.ctype = CTINT;
+	n->val.vval = v;
+	return n;
+}
+
+void
+frame(int context)
+{
+	char *p;
+	Dcl *d;
+	int flag;
+
+	p = "stack";
+	d = autodcl;
+	if(context) {
+		p = "external";
+		d = externdcl;
+	}
+
+	flag = 1;
+	for(; d!=D; d=d->forw) {
+		switch(d->op) {
+		case ONAME:
+			if(flag)
+				print("--- %s frame ---\n", p);
+			print("%O %S G%ld T\n", d->op, d->dsym, d->dnode->vargen, d->dnode->type);
+			flag = 0;
+			break;
+
+		case OTYPE:
+			if(flag)
+				print("--- %s frame ---\n", p);
+			print("%O %lT\n", d->op, d->dnode);
+			flag = 0;
+			break;
+		}
+	}
+}
+
+/*
+ * calculate sethi/ullman number
+ * roughly how many registers needed to
+ * compile a node. used to compile the
+ * hardest side first to minimize registers.
+ */
+void
+ullmancalc(Node *n)
+{
+	int ul, ur;
+
+	if(n == N)
+		return;
+
+	switch(n->op) {
+	case OLITERAL:
+	case ONAME:
+		ul = 0;
+		goto out;
+	case OS2I:
+	case OI2S:
+	case OI2I:
+	case OCALL:
+		ul = UINF;
+		goto out;
+	}
+	ul = 0;
+	if(n->left != N)
+		ul = n->left->ullman;
+	ur = 0;
+	if(n->right != N)
+		ur = n->right->ullman;
+	if(ul == ur)
+		ul += 1;
+	if(ur > ul)
+		ul = ur;
+
+out:
+	n->ullman = ul;
+}
+
+void
+badtype(int o, Type *tl, Type *tr)
+{
+	yyerror("illegal types for operand");
+	if(tl != T)
+		print("	(%T)", tl);
+	print(" %O ", o);
+	if(tr != T)
+		print("(%T)", tr);
+	print("\n");
+}
+
+/*
+ * this routine gets the parsing of
+ * a parameter list that can have
+ * name, type and name-type.
+ * it must distribute lone names
+ * with trailing types to give every
+ * name a type. (a,b,c int) comes out
+ * (a int, b int, c int).
+ */
+Node*
+cleanidlist(Node *r)
+{
+	Node *t, *n, *nn, *l;
+	Type *dt;
+
+	t = N;		// untyped name
+	nn = r;		// next node to take
+
+loop:
+	n = nn;
+	if(n == N) {
+		if(t != N) {
+			yyerror("syntax error in parameter list");
+			dt = types[TINT32];
+			goto distrib;
+		}
+		return r;
+	}
+
+	l = n;
+	nn = N;
+	if(l->op == OLIST) {
+		nn = l->right;
+		l = l->left;
+	}
+
+	if(l->op != ODCLFIELD)
+		fatal("cleanformal: %O", n->op);
+
+	if(l->type == T) {
+		if(t == N)
+			t = n;
+		goto loop;
+	}
+
+	if(t == N)
+		goto loop;
+
+	dt = l->type;	// type to be distributed
+
+distrib:
+	while(t != n) {
+		if(t->op != OLIST) {
+			if(t->type == T)
+				t->type = dt;
+			break;
+		}
+		if(t->left->type == T)
+			t->left->type = dt;
+		t = t->right;
+	}
+
+	t = N;
+	goto loop;
+}
+
+/*
+ * iterator to walk a structure declaration
+ */
+Type*
+structfirst(Iter *s, Type **nn)
+{
+	Type *n, *t;
+
+	n = *nn;
+	if(n == T)
+		goto bad;
+
+	switch(n->etype) {
+	default:
+		goto bad;
+
+	case TSTRUCT:
+	case TINTER:
+	case TFUNC:
+		break;
+	}
+
+	t = n->type;
+	if(t == T)
+		goto rnil;
+
+	if(t->etype != TFIELD)
+		fatal("structfirst: not field %T", t);
+
+	s->t = t;
+	return t;
+
+bad:
+	fatal("structfirst: not struct %T", n);
+
+rnil:
+	return T;
+}
+
+Type*
+structnext(Iter *s)
+{
+	Type *n, *t;
+
+	n = s->t;
+	t = n->down;
+	if(t == T)
+		goto rnil;
+
+	if(t->etype != TFIELD)
+		goto bad;
+
+	s->t = t;
+	return t;
+
+bad:
+	fatal("structnext: not struct %T", n);
+
+rnil:
+	return T;
+}
+
+/*
+ * iterator to this and inargs in a function
+ */
+Type*
+funcfirst(Iter *s, Type *t)
+{
+	Type *fp;
+
+	if(t == T)
+		goto bad;
+
+	if(t->etype != TFUNC)
+		goto bad;
+
+	s->tfunc = t;
+	s->done = 0;
+	fp = structfirst(s, getthis(t));
+	if(fp == T) {
+		s->done = 1;
+		fp = structfirst(s, getinarg(t));
+	}
+	return fp;
+
+bad:
+	fatal("funcfirst: not func %T", t);
+	return T;
+}
+
+Type*
+funcnext(Iter *s)
+{
+	Type *fp;
+
+	fp = structnext(s);
+	if(fp == T && !s->done) {
+		s->done = 1;
+		fp = structfirst(s, getinarg(s->tfunc));
+	}
+	return fp;
+}
+
+/*
+ * iterator to walk a list
+ */
+Node*
+listfirst(Iter *s, Node **nn)
+{
+	Node *n;
+
+	n = *nn;
+	if(n == N) {
+		s->done = 1;
+		s->an = &s->n;
+		s->n = N;
+		return N;
+	}
+
+	if(n->op == OLIST) {
+		s->done = 0;
+		s->n = n;
+		s->an = &n->left;
+		return n->left;
+	}
+
+	s->done = 1;
+	s->an = nn;
+	return n;
+}
+
+Node*
+listnext(Iter *s)
+{
+	Node *n, *r;
+
+	if(s->done) {
+		s->an = &s->n;
+		s->n = N;
+		return N;
+	}
+
+	n = s->n;
+	r = n->right;
+	if(r->op == OLIST) {
+		s->n = r;
+		s->an = &r->left;
+		return r->left;
+	}
+
+	s->done = 1;
+	s->an = &n->right;
+	return n->right;
+}
+
+Type**
+getthis(Type *t)
+{
+	if(t->etype != TFUNC)
+		fatal("getthis: not a func %N", t);
+	return &t->type;
+}
+
+Type**
+getoutarg(Type *t)
+{
+	if(t->etype != TFUNC)
+		fatal("getoutarg: not a func %N", t);
+	return &t->type->down;
+}
+
+Type**
+getinarg(Type *t)
+{
+	if(t->etype != TFUNC)
+		fatal("getinarg: not a func %N", t);
+	return &t->type->down->down;
+}
+
+Type*
+getthisx(Type *t)
+{
+	return *getthis(t);
+}
+
+Type*
+getoutargx(Type *t)
+{
+	return *getoutarg(t);
+}
+
+Type*
+getinargx(Type *t)
+{
+	return *getinarg(t);
+}
diff --git a/src/cmd/gc/sys.go b/src/cmd/gc/sys.go
new file mode 100644
index 0000000..19b5c2e
--- /dev/null
+++ b/src/cmd/gc/sys.go
@@ -0,0 +1,44 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+
+package foop	// rename to avoid redeclaration
+
+func	mal(uint32) *byte;
+func	breakpoint();
+func	panicl(int32);
+
+func	printbool(bool);
+func	printfloat(double);
+func	printint(int64);
+func	printstring(string);
+func	printpointer(*byte);
+
+func	catstring(string, string) string;
+func	cmpstring(string, string) int32;
+func	slicestring(string, int32, int32) string;
+func	indexstring(string, int32) byte;
+func	intstring(int64) string;
+func	byteastring(*byte, int32) string;
+func	mkiface(*byte, *byte, *struct{}) interface{};
+
+export
+	mal
+	breakpoint
+	panicl
+
+	printbool
+	printfloat
+	printint
+	printstring
+	printpointer
+
+	catstring
+	cmpstring
+	slicestring
+	indexstring
+	intstring
+	byteastring
+	mkiface
+	;
diff --git a/src/cmd/gc/sysimport.c b/src/cmd/gc/sysimport.c
new file mode 100644
index 0000000..f6ff105
--- /dev/null
+++ b/src/cmd/gc/sysimport.c
@@ -0,0 +1,2 @@
+;
+
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
new file mode 100644
index 0000000..995c641
--- /dev/null
+++ b/src/cmd/gc/walk.c
@@ -0,0 +1,1278 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include	"go.h"
+
+static	Type*	sw1(Node*, Type*);
+static	Type*	sw2(Node*, Type*);
+static	Type*	sw3(Node*, Type*);
+static	Node*	curfn;
+
+void
+walk(Node *fn)
+{
+	curfn = fn;
+	walktype(fn->nbody, 1);
+}
+
+void
+walktype(Node *n, int top)
+{
+	Node *r, *l;
+	Type *t;
+	Sym *s;
+	long lno;
+	int et;
+
+	/*
+	 * walk the whole tree of the body of a function.
+	 * the types expressions are calculated.
+	 * compile-time constants are evaluated.
+	 */
+
+	lno = dynlineno;
+
+loop:
+	if(n == N)
+		goto ret;
+	if(n->op != ONAME)
+		dynlineno = n->lineno;	// for diagnostics
+
+	t = T;
+	et = Txxx;
+
+	switch(n->op) {
+	default:
+		fatal("walktype: switch 1 unknown op %N", n);
+		goto ret;
+
+	case OPRINT:
+		walktype(n->left, 0);
+		*n = *prcompat(n->left);
+		goto ret;
+
+	case OPANIC:
+		walktype(n->left, 0);
+		*n = *nod(OLIST, prcompat(n->left), nodpanic(n->lineno));
+		goto ret;
+
+	case OLITERAL:
+		n->addable = 1;
+		ullmancalc(n);
+		goto ret;
+
+	case ONAME:
+		n->addable = 1;
+		ullmancalc(n);
+		if(n->type == T) {
+			s = n->sym;
+			if(s->undef == 0) {
+				yyerror("walktype: %N undeclared", n);
+				s->undef = 1;
+			}
+		}
+		goto ret;
+
+	case OLIST:
+		walktype(n->left, top);
+		n = n->right;
+		goto loop;
+
+	case OFOR:
+		if(!top)
+			goto nottop;
+		walktype(n->ninit, 1);
+		walktype(n->ntest, 1);
+		walktype(n->nincr, 1);
+		n = n->nbody;
+		goto loop;
+
+	case OSWITCH:
+		if(!top)
+			goto nottop;
+
+		if(n->ntest == N)
+			n->ntest = booltrue;
+		walktype(n->ninit, 1);
+		walktype(n->ntest, 1);
+		walktype(n->nbody, 1);
+
+		// find common type
+		if(n->ntest->type == T)
+			n->ntest->type = walkswitch(n->ntest, n->nbody, sw1);
+
+		// if that fails pick a type
+		if(n->ntest->type == T)
+			n->ntest->type = walkswitch(n->ntest, n->nbody, sw2);
+
+		// set the type on all literals
+		if(n->ntest->type != T)
+			walkswitch(n->ntest, n->nbody, sw3);
+
+		walktype(n->ntest, 1);
+
+		n = n->nincr;
+		goto loop;
+
+	case OEMPTY:
+		if(!top)
+			goto nottop;
+		goto ret;
+
+	case OIF:
+		if(!top)
+			goto nottop;
+		walktype(n->ninit, 1);
+		walktype(n->ntest, 1);
+		walktype(n->nelse, 1);
+		n = n->nbody;
+		goto loop;
+
+	case OCALLMETH:
+	case OCALLINTER:
+	case OCALL:
+		n->ullman = UINF;
+		if(n->type != T)
+			goto ret;
+
+		walktype(n->left, 0);
+		if(n->left == N)
+			goto ret;
+
+		t = n->left->type;
+		if(t == T)
+			goto ret;
+
+		dowidth(t);
+		if(n->left->op == ODOTMETH)
+			n->op = OCALLMETH;
+		if(n->left->op == ODOTINTER)
+			n->op = OCALLINTER;
+
+		if(isptr[t->etype])
+			t = t->type;
+
+		if(t->etype != TFUNC) {
+			yyerror("call of a non-function %T", t);
+			goto ret;
+		}
+
+		n->type = *getoutarg(t);
+		if(t->outtuple == 1)
+			n->type = n->type->type->type;
+		else
+		if(!top)
+			yyerror("function call must be single valued (%d)", t->outtuple);
+
+		walktype(n->right, 0);
+
+		switch(n->op) {
+		default:
+			fatal("walk: op: %O", n->op);
+
+		case OCALLINTER:
+			l = ascompatte(n->op, getinarg(t), &n->right, 0);
+			n->right = reorder(l);
+			break;
+
+		case OCALL:
+			l = ascompatte(n->op, getinarg(t), &n->right, 0);
+			n->right = reorder(l);
+			break;
+
+		case OCALLMETH:
+			// add this-pointer to the arg list
+			l = ascompatte(n->op, getinarg(t), &n->right, 0);
+			r = ascompatte(n->op, getthis(t), &n->left->left, 0);
+			if(l != N)
+				r = nod(OLIST, r, l);
+			n->right = reorder(r);
+			break;
+		}
+		goto ret;
+
+	case OAS:
+		if(!top)
+			goto nottop;
+
+		r = n->right;
+		if(r == N)
+			goto ret;
+		l = n->left;
+		if(l == N)
+			goto ret;
+
+		if(r->op == OCALL && l->op == OLIST) {
+			// botch callmulti - need to do more
+			walktype(l, 0);
+			walktype(r, 0);
+			l = ascompatet(n->op, &n->left, &r->type, 0);
+			if(l != N && l->op == OAS)
+				*n = *reorder(l);
+			goto ret;
+		}
+
+		walktype(l, 0);
+		walktype(r, 0);
+		l = ascompatee(n->op, &n->left, &n->right);
+		if(l != N)
+			*n = *reorder(l);
+		goto ret;
+
+	case OBREAK:
+	case OCONTINUE:
+	case OGOTO:
+	case OLABEL:
+		goto ret;
+
+	case OXCASE:
+		yyerror("case statement out of place");
+		n->op = OCASE;
+
+	case OCASE:
+		n = n->left;
+		goto loop;
+
+	case OXFALL:
+		yyerror("fallthrough statement out of place");
+		n->op = OFALL;
+
+	case OFALL:
+	case OINDREG:
+		goto ret;
+
+	case OS2I:
+	case OI2S:
+	case OI2I:
+		n->addable = 0;
+		walktype(n->left, 0);
+		goto ret;
+
+	case OCONV:
+		walktype(n->left, 0);
+		if(n->left == N)
+			goto ret;
+
+		convlit(n->left, n->type);
+
+		// nil conversion
+		if(eqtype(n->type, n->left->type, 0)) {
+			if(n->left->op != ONAME)
+				*n = *n->left;
+			goto ret;
+		}
+
+		// simple fix-float
+		if(isint[n->left->type->etype] || isfloat[n->left->type->etype])
+		if(isint[n->type->etype] || isfloat[n->type->etype]) {
+			evconst(n);
+			goto ret;
+		}
+
+		// to string
+		if(isptrto(n->type, TSTRING)) {
+			if(isint[n->left->type->etype]) {
+				*n = *stringop(n);
+				goto ret;
+			}
+			if(isbytearray(n->left->type) != 0) {
+				n->op = OARRAY;
+				*n = *stringop(n);
+				goto ret;
+			}
+		}
+
+		badtype(n->op, n->left->type, n->type);
+		goto ret;
+
+	case ORETURN:
+		walktype(n->left, 0);
+		l = ascompatte(n->op, getoutarg(curfn->type), &n->left, 1);
+		if(l != N)
+			n->left = reorder(l);
+		goto ret;
+
+	case ONOT:
+		walktype(n->left, 0);
+		if(n->left == N || n->left->type == T)
+			goto ret;
+		et = n->left->type->etype;
+		break;
+
+	case OASOP:
+		if(!top)
+			goto nottop;
+
+	case OLSH:
+	case ORSH:
+	case OMOD:
+	case OAND:
+	case OOR:
+	case OXOR:
+	case OANDAND:
+	case OOROR:
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OLE:
+	case OGE:
+	case OGT:
+	case OADD:
+	case OSUB:
+	case OMUL:
+	case ODIV:
+		walktype(n->left, 0);
+		walktype(n->right, 0);
+		if(n->left == N || n->right == N)
+			goto ret;
+		convlit(n->left, n->right->type);
+		convlit(n->right, n->left->type);
+		evconst(n);
+		if(n->op == OLITERAL)
+			goto ret;
+		if(n->left->type == T || n->right->type == T)
+			goto ret;
+		if(!ascompat(n->left->type, n->right->type))
+			goto badt;
+
+		switch(n->op) {
+		case OEQ:
+		case ONE:
+		case OLT:
+		case OLE:
+		case OGE:
+		case OGT:
+		case OADD:
+		case OASOP:
+			if(isptrto(n->left->type, TSTRING)) {
+				*n = *stringop(n);
+				goto ret;
+			}
+		}
+		break;
+
+	case OMINUS:
+	case OPLUS:
+	case OCOM:
+		walktype(n->left, 0);
+		if(n->left == N)
+			goto ret;
+		evconst(n);
+		ullmancalc(n);
+		if(n->op == OLITERAL)
+			goto ret;
+		break;
+
+	case OLEN:
+		walktype(n->left, 0);
+		evconst(n);
+		ullmancalc(n);
+		t = n->left->type;
+		if(t != T && isptr[t->etype])
+			t = t->type;
+		if(t == T)
+			goto ret;
+		switch(t->etype) {
+		default:
+			goto badt;
+		case TSTRING:
+			break;
+		}
+		n->type = types[TINT32];
+		goto ret;
+
+	case OINDEX:
+	case OINDEXPTR:
+		walktype(n->left, 0);
+		walktype(n->right, 0);
+		ullmancalc(n);
+		if(n->left == N || n->right == N)
+			goto ret;
+		t = n->left->type;
+		if(t == T)
+			goto ret;
+
+		// map
+		if(isptrto(t, TMAP)) {
+			fatal("index map");
+			goto ret;
+		}
+
+		// right side must be an int
+		if(n->right->type == T)
+			convlit(n->right, types[TINT32]);
+		if(n->left->type == T || n->right->type == T)
+			goto ret;
+		if(!isint[n->right->type->etype])
+			goto badt;
+
+		// left side is string
+		if(isptrto(t, TSTRING)) {
+			*n = *stringop(n);
+			goto ret;
+		}
+
+		// left side is array
+		if(isptr[t->etype]) {
+			t = t->type;
+			n->op = OINDEXPTR;
+		}
+		if(t->etype != TARRAY && t->etype != TDARRAY)
+			goto badt;
+		n->type = t->type;
+		goto ret;
+
+	case OSLICE:
+		walktype(n->left, 0);
+		walktype(n->right, 0);
+		if(n->left == N || n->right == N)
+			goto ret;
+		if(isptrto(n->left->type, TSTRING)) {
+			*n = *stringop(n);
+			goto ret;
+		}
+		badtype(OSLICE, n->left->type, T);
+		goto ret;
+
+	case ODOT:
+	case ODOTPTR:
+	case ODOTMETH:
+	case ODOTINTER:
+		walkdot(n);
+		goto ret;
+
+	case OADDR:
+		walktype(n->left, 0);
+		if(n->left == N)
+			goto ret;
+		t = n->left->type;
+		if(t == T)
+			goto ret;
+		n->type = ptrto(t);
+		goto ret;
+
+	case OIND:
+		walktype(n->left, 0);
+		if(n->left == N)
+			goto ret;
+		t = n->left->type;
+		if(t == T)
+			goto ret;
+		if(!isptr[t->etype])
+			goto badt;
+		n->type = t->type;
+		goto ret;
+
+	case ONEW:
+		*n = *newcompat(n);
+		goto ret;
+	}
+
+/*
+ * ======== second switch ========
+ */
+
+	switch(n->op) {
+	default:
+		fatal("walktype: switch 2 unknown op %N", n);
+		goto ret;
+
+	case OASOP:
+		break;
+
+	case ONOT:
+	case OANDAND:
+	case OOROR:
+		et = n->left->type->etype;
+		if(et != TBOOL)
+			goto badt;
+		t = types[TBOOL];
+		break;
+
+	case OEQ:
+	case ONE:
+		et = n->left->type->etype;
+		if(!okforeq[et])
+			goto badt;
+		t = types[TBOOL];
+		break;
+
+	case OLT:
+	case OLE:
+	case OGE:
+	case OGT:
+		et = n->left->type->etype;
+		if(!okforadd[et])
+			if(!isptrto(n->left->type, TSTRING))
+				goto badt;
+		t = types[TBOOL];
+		break;
+
+	case OADD:
+	case OSUB:
+	case OMUL:
+	case ODIV:
+	case OPLUS:
+		et = n->left->type->etype;
+		if(!okforadd[et])
+			goto badt;
+		break;
+
+	case OMINUS:
+		et = n->left->type->etype;
+		if(!okforadd[et])
+			goto badt;
+		if(!isfloat[et])
+			break;
+
+		l = nod(OLITERAL, N, N);
+		l->val.ctype = CTFLT;
+		l->val.dval = 0;
+
+		l = nod(OSUB, l, n->left);
+		*n = *l;
+		walktype(n, 0);
+		goto ret;
+
+	case OLSH:
+	case ORSH:
+	case OAND:
+	case OOR:
+	case OXOR:
+	case OMOD:
+	case OCOM:
+		et = n->left->type->etype;
+		if(!okforand[et])
+			goto badt;
+		break;
+	}
+
+	if(t == T)
+		t = n->left->type;
+	n->type = t;
+	goto ret;
+
+nottop:
+	fatal("walktype: not top %O", n->op);
+
+badt:
+	if(n->right == N) {
+		if(n->left == N) {
+			badtype(n->op, T, T);
+			goto ret;
+		}
+		badtype(n->op, n->left->type, T);
+		goto ret;
+	}
+	badtype(n->op, n->left->type, n->right->type);
+	goto ret;
+
+ret:
+	ullmancalc(n);
+	dynlineno = lno;
+}
+
+/*
+ * return the first type
+ */
+Type*
+sw1(Node *c, Type *place)
+{
+	if(place == T)
+		return c->type;
+	return place;
+}
+
+/*
+ * return a suitable type
+ */
+Type*
+sw2(Node *c, Type *place)
+{
+	return types[TINT32];	// botch
+}
+
+/*
+ * check that selected type
+ * is compat with all the cases
+ */
+Type*
+sw3(Node *c, Type *place)
+{
+	if(place == T)
+		return c->type;
+	if(c->type == T)
+		c->type = place;
+	convlit(c, place);
+	if(!ascompat(place, c->type))
+		badtype(OSWITCH, place, c->type);
+	return place;
+}
+
+Type*
+walkswitch(Node *test, Node *body, Type*(*call)(Node*, Type*))
+{
+	Node *n, *c;
+	Type *place;
+
+	place = call(test, T);
+
+	n = body;
+	if(n->op == OLIST)
+		n = n->left;
+
+	for(; n!=N; n=n->right) {
+		if(n->op != OCASE)
+			fatal("walkswitch: not case %O\n", n->op);
+		for(c=n->left; c!=N; c=c->right) {
+			if(c->op != OLIST) {
+				place = call(c, place);
+				break;
+			}
+			place = call(c->left, place);
+		}
+	}
+	return place;
+}
+
+int
+casebody(Node *n)
+{
+	Node *oc, *ot, *t;
+	Iter save;
+
+
+	/*
+	 * look to see if statements at top level have
+	 * case labels attached to them. convert the illegal
+	 * ops XFALL and XCASE into legal ops FALL and CASE.
+	 * all unconverted ops will thus be caught as illegal
+	 */
+
+	oc = N;		// last case statement
+	ot = N;		// last statement (look for XFALL)
+
+	t = listfirst(&save, &n);
+
+	if(t->op != OXCASE)
+		return 0;
+
+loop:
+	if(t == N) {
+		if(oc == N)
+			return 0;
+		return 1;
+	}
+	if(t->op == OXCASE) {
+		/* rewrite and link top level cases */
+		t->op = OCASE;
+		if(oc != N)
+			oc->right = t;
+		oc = t;
+
+		/* rewrite top fall that preceed case */
+		if(ot != N && ot->op == OXFALL)
+			ot->op = OFALL;
+	}
+
+	/* if first statement is not case then return 0 */
+	if(oc == N)
+		return 0;
+
+	ot = t;
+	t = listnext(&save);
+	goto loop;
+}
+
+/*
+ * allowable type combinations for
+ * normal binary operations.
+ */
+Type*
+lookdot(Node *n, Type *t, int d)
+{
+	Type *f, *r, *c;
+	Sym *s;
+
+//dowidth(t);
+//print("\nlookdot %T\n", t);
+//for(f=t->type; f!=T; f=f->down) {
+//print("   %3ld", f->width);
+//print(" %S\n", f->sym);
+//}
+
+	r = T;
+	s = n->sym;
+	if(d > 0)
+		goto deep;
+
+	for(f=t->type; f!=T; f=f->down) {
+		if(f->sym == S)
+			continue;
+		if(f->sym != s)
+			continue;
+		if(r != T) {
+			yyerror("ambiguous DOT reference %s", s->name);
+			break;
+		}
+		r = f;
+	}
+	return r;
+
+deep:
+	/* deeper look after shallow failed */
+	for(f=t->type; f!=T; f=f->down) {
+		// only look at unnamed sub-structures
+		// BOTCH no such thing -- all are assigned temp names
+		if(f->sym != S)
+			continue;
+		c = f->type;
+		if(c->etype != TSTRUCT)
+			continue;
+		c = lookdot(n, c, d-1);
+		if(c == T)
+			continue;
+		if(r != T) {
+			yyerror("ambiguous unnamed DOT reference %s", s->name);
+			break;
+		}
+		r = c;
+	}
+	return r;
+}
+
+void
+walkdot(Node *n)
+{
+	Node *mn;
+	Type *t, *f;
+	int i;
+
+	if(n->left == N || n->right == N)
+		return;
+
+	walktype(n->left, 0);
+	if(n->right->op != ONAME) {
+		yyerror("rhs of . must be a name");
+		return;
+	}
+
+	t = n->left->type;
+	if(t == T)
+		return;
+
+	if(isptr[t->etype]) {
+		t = t->type;
+		if(t == T)
+			return;
+		n->op = ODOTPTR;
+	}
+
+	if(n->right->op != ONAME)
+		fatal("walkdot: not name %O", n->right->op);
+
+	switch(t->etype) {
+	default:
+		badtype(ODOT, t, T);
+		return;
+
+	case TSTRUCT:
+	case TINTER:
+		for(i=0; i<5; i++) {
+			f = lookdot(n->right, t, i);
+			if(f != T)
+				break;
+		}
+
+		// look up the field as TYPE_name
+		// for a mothod. botch this should
+		// be done better.
+		if(f == T && t->etype == TSTRUCT) {
+			mn = methodname(n->right, t);
+			for(i=0; i<5; i++) {
+				f = lookdot(mn, t, i);
+				if(f != T)
+					break;
+			}
+		}
+
+		if(f == T) {
+			yyerror("undefined DOT reference %N", n->right);
+			break;
+		}
+
+		n->xoffset = f->width;
+		n->right = f->nname;		// substitute real name
+		n->type = f->type;
+		if(n->type->etype == TFUNC) {
+			n->op = ODOTMETH;
+			if(t->etype == TINTER) {
+				n->op = ODOTINTER;
+			}
+		}
+		break;
+	}
+}
+
+
+/*
+ * check assign expression list to
+ * a expression list. called in
+ *	expr-list = expr-list
+ */
+Node*
+ascompatee(int op, Node **nl, Node **nr)
+{
+	Node *l, *r, *nn, *a;
+	Iter savel, saver;
+
+	l = listfirst(&savel, nl);
+	r = listfirst(&saver, nr);
+	nn = N;
+	
+
+loop:
+	if(l == N || r == N) {
+		if(l != r)
+			yyerror("error in shape across assignment");
+		return nn;
+	}
+
+	convlit(r, l->type);
+	if(!ascompat(l->type, r->type)) {
+		badtype(op, l->type, r->type);
+		return N;
+	}
+
+	a = nod(OAS, l, r);
+	a = convas(a);
+	if(nn == N)
+		nn = a;
+	else
+		nn = nod(OLIST, nn, a);
+
+	l = listnext(&savel);
+	r = listnext(&saver);
+	goto loop;
+}
+
+/*
+ * check assign type list to
+ * a expression list. called in
+ *	expr-list = func()
+ */
+Node*
+ascompatet(int op, Node **nl, Type **nr, int fp)
+{
+	Node *l, *nn, *a;
+	Type *r;
+	Iter savel, saver;
+
+	l = listfirst(&savel, nl);
+	r = structfirst(&saver, nr);
+	nn = N;
+
+loop:
+	if(l == N || r == T) {
+		if(l != N || r != T)
+			yyerror("error in shape across assignment");
+		return nn;
+	}
+
+	if(!ascompat(l->type, r->type)) {
+		badtype(op, l->type, r->type);
+		return N;
+	}
+
+	a = nod(OAS, l, nodarg(r, fp));
+	a = convas(a);
+	if(nn == N)
+		nn = a;
+	else
+		nn = nod(OLIST, nn, a);
+
+	l = listnext(&savel);
+	r = structnext(&saver);
+
+	goto loop;
+}
+
+/*
+ * check assign expression list to
+ * a type list. called in
+ *	return expr-list
+ *	func(expr-list)
+ */
+Node*
+ascompatte(int op, Type **nl, Node **nr, int fp)
+{
+	Type *l;
+	Node *r, *nn, *a;
+	Iter savel, saver;
+
+	l = structfirst(&savel, nl);
+	r = listfirst(&saver, nr);
+	nn = N;
+
+loop:
+	if(l == T || r == N) {
+		if(l != T || r != N)
+			yyerror("error in shape across assignment");
+		return nn;
+	}
+
+	convlit(r, l->type);
+	if(!ascompat(l->type, r->type)) {
+		badtype(op, l->type, r->type);
+		return N;
+	}
+
+	a = nod(OAS, nodarg(l, fp), r);
+	a = convas(a);
+	if(nn == N)
+		nn = a;
+	else
+		nn = nod(OLIST, nn, a);
+
+	l = structnext(&savel);
+	r = listnext(&saver);
+
+	goto loop;
+}
+
+/*
+ * can we assign var of type t2 to var of type t1
+ */
+int
+ascompat(Type *t1, Type *t2)
+{
+	if(eqtype(t1, t2, 0))
+		return 1;
+
+//	if(eqtype(t1, nilptr, 0))
+//		return 1;
+//	if(eqtype(t2, nilptr, 0))
+//		return 1;
+
+	if(isinter(t1))
+		if(isptrto(t2, TSTRUCT) || isinter(t2))
+			return 1;
+
+	if(isinter(t2))
+		if(isptrto(t1, TSTRUCT))
+			return 1;
+
+	return 0;
+}
+
+Node*
+prcompat(Node *n)
+{
+	Node *l, *r;
+	Type *t;
+	Iter save;
+	int w;
+	char *name;
+	Sym *s;
+
+	r = N;
+	l = listfirst(&save, &n);
+
+loop:
+	if(l == N) {
+		walktype(r, 1);
+		return r;
+	}
+
+	w = whatis(l);
+	switch(w) {
+	default:
+		badtype(n->op, l->type, T);
+		l = listnext(&save);
+		goto loop;
+	case Wlitint:
+	case Wtint:
+		name = "printint";
+		break;
+	case Wlitfloat:
+	case Wtfloat:
+		name = "printfloat";
+		break;
+	case Wlitbool:
+	case Wtbool:
+		name = "printbool";
+		break;
+	case Wlitstr:
+	case Wtstr:
+		name = "printstring";
+		break;
+	}
+
+	s = pkglookup(name, "sys");
+	if(s == S || s->oname == N)
+		fatal("prcompat: cant find sys_%s", name);
+
+	t = *getinarg(s->oname->type);
+	if(t != nil)
+		t = t->type;
+	if(t != nil)
+		t = t->type;
+
+	if(!eqtype(t, l->type, 0)) {
+		l = nod(OCONV, l, N);
+		l->type = t;
+	}
+
+	if(r == N)
+		r = nod(OCALL, s->oname, l);
+	else
+		r = nod(OLIST, r, nod(OCALL, s->oname, l));
+
+	l = listnext(&save);
+	goto loop;
+}
+
+Node*
+nodpanic(long lineno)
+{
+	Sym *s;
+	char *name;
+	Node *n;
+
+	name = "panicl";
+	s = pkglookup(name, "sys");
+	if(s == S || s->oname == N)
+		fatal("prcompat: cant find sys_%s", name);
+
+	n = nodintconst(lineno);
+	n = nod(OCALL, s->oname, n);
+	walktype(n, 1);
+	return n;
+}
+
+Node*
+newcompat(Node *n)
+{
+	Node *r;
+	Type *t;
+	Sym *s;
+
+	if(n->left != N)
+		yyerror("dont know what new(,e) means");
+	t = n->type;
+	if(t == T || !isptr[t->etype])
+		fatal("NEW sb pointer %lT", t);
+
+	dowidth(t->type);
+
+	s = pkglookup("mal", "sys");
+	if(s == S || s->oname == N)
+		fatal("newcompat: cant find sys_mal");
+
+	r = nodintconst(t->type->width);
+	r = nod(OCALL, s->oname, r);
+	walktype(r, 0);
+
+//	r = nod(OCONV, r, N);
+	r->type = t;
+
+	return r;
+}
+
+Node*
+stringop(Node *n)
+{
+	Node *r, *c;
+	Sym *s;
+	long lno;
+	long l;
+
+	lno = dynlineno;
+	dynlineno = n->lineno;
+
+	switch(n->op) {
+	default:
+		fatal("stringop: unknown op %E", n->op);
+
+	case OEQ:
+	case ONE:
+	case OGE:
+	case OGT:
+	case OLE:
+	case OLT:
+		// sys_cmpstring(s1, s2) :: 0
+		s = pkglookup("cmpstring", "sys");
+		if(s == S || s->oname == N)
+			fatal("stringop: cant find sys_cmpstring");
+
+		r = nod(OLIST, n->left, n->right);
+		r = nod(OCALL, s->oname, r);
+		c = nodintconst(0);
+		r = nod(n->op, r, c);
+		break;
+
+	case OADD:
+		// sys_catstring(s1, s2)
+		s = pkglookup("catstring", "sys");
+		if(s == S || s->oname == N)
+			fatal("stringop: cant find sys_catstring");
+		r = nod(OLIST, n->left, n->right);
+		r = nod(OCALL, s->oname, r);
+		break;
+
+	case OASOP:
+		// sys_catstring(s1, s2)
+		switch(n->etype) {
+		default:
+			fatal("stringop: unknown op %E-%E", n->op, n->etype);
+
+		case OADD:
+			// s1 = sys_catstring(s1, s2)
+			s = pkglookup("catstring", "sys");
+			if(s == S || s->oname == N || n->etype != OADD)
+				fatal("stringop: cant find sys_catstring");
+			r = nod(OLIST, n->left, n->right);
+			r = nod(OCALL, s->oname, r);
+			r = nod(OAS, n->left, r);
+			break;
+		}
+		break;
+
+	case OSLICE:
+		// sys_slicestring(s, lb, hb)
+		s = pkglookup("slicestring", "sys");
+		if(s == S || s->oname == N)
+			fatal("stringop: cant find sys_slicestring");
+
+		r = nod(OCONV, n->right->left, N);
+		r->type = types[TINT32];
+
+		c = nod(OCONV, n->right->right, N);
+		c->type = types[TINT32];
+
+		r = nod(OLIST, r, c);
+
+		r = nod(OLIST, n->left, r);
+
+		r = nod(OCALL, s->oname, r);
+		break;
+
+	case OINDEX:
+		// sys_indexstring(s, i)
+		s = pkglookup("indexstring", "sys");
+		if(s == S || s->oname == N)
+			fatal("stringop: cant find sys_indexstring");
+
+		r = nod(OCONV, n->right, N);
+		r->type = types[TINT32];
+
+		r = nod(OLIST, n->left, r);
+		r = nod(OCALL, s->oname, r);
+		break;
+
+	case OCONV:
+		// sys_intstring(v)
+		s = pkglookup("intstring", "sys");
+		if(s == S || s->oname == N)
+			fatal("stringop: cant find sys_intstring");
+
+		r = nod(OCONV, n->left, N);
+		r->type = types[TINT64];
+
+		r = nod(OCALL, s->oname, r);
+		break;
+
+	case OARRAY:
+		// byteastring(a, l)
+		s = pkglookup("byteastring", "sys");
+		if(s == S || s->oname == N)
+			fatal("stringop: cant find sys_byteastring");
+
+		c = nodintconst(0);
+		r = nod(OINDEX, n->left, c);
+		r = nod(OADDR, r, N);
+
+		l = isbytearray(n->left->type);
+		c = nodintconst(l-1);
+
+		r = nod(OLIST, r, c);
+		r = nod(OCALL, s->oname, r);
+		break;
+	}
+
+	walktype(r, 1);
+	dynlineno = lno;
+	return r;
+}
+
+void
+diagnamed(Type *t)
+{
+	if(isinter(t))
+		if(t->sym == S)
+			yyerror("interface type must be named");
+	if(isptrto(t, TSTRUCT))
+		if(t->type == T || t->type->sym == S)
+			yyerror("structure type must be named");
+}
+
+Node*
+convas(Node *n)
+{
+	int o;
+	Node *l, *r;
+	Type *lt, *rt;
+
+	if(n->op != OAS)
+		fatal("convas: not as %O", n->op);
+
+	l = n->left;
+	r = n->right;
+	if(l == N || r == N)
+		return n;
+
+	lt = l->type;
+	rt = r->type;
+	if(lt == T || rt == T)
+		return n;
+
+	if(eqtype(lt, rt, 0))
+		return n;
+
+	if(isinter(lt)) {
+		if(isptrto(rt, TSTRUCT)) {
+			o = OS2I;
+			goto ret;
+		}
+		if(isinter(rt)) {
+			o = OI2I;
+			goto ret;
+		}
+	}
+
+	if(isptrto(lt, TSTRUCT)) {
+		if(isinter(rt)) {
+			o = OI2S;
+			goto ret;
+		}
+	}
+
+	badtype(n->op, lt, rt);
+	return n;
+
+ret:
+	diagnamed(lt);
+	diagnamed(rt);
+
+	n->right = nod(o, r, N);
+	n->right->type = l->type;
+	walktype(n, 1);
+	return n;
+}
+
+Node*
+reorder(Node *n)
+{
+	return n;
+}