]> Cypherpunks repositories - gostls13.git/commitdiff
Add compiler source to new directory structure
authorRob Pike <r@golang.org>
Wed, 4 Jun 2008 21:37:38 +0000 (14:37 -0700)
committerRob Pike <r@golang.org>
Wed, 4 Jun 2008 21:37:38 +0000 (14:37 -0700)
SVN=121164

65 files changed:
src/cmd/6a/a.h [new file with mode: 0644]
src/cmd/6a/a.y [new file with mode: 0644]
src/cmd/6a/lex.c [new file with mode: 0644]
src/cmd/6c/cgen.c [new file with mode: 0644]
src/cmd/6c/div.c [new file with mode: 0644]
src/cmd/6c/gc.h [new file with mode: 0644]
src/cmd/6c/list.c [new file with mode: 0644]
src/cmd/6c/machcap.c [new file with mode: 0644]
src/cmd/6c/mul.c [new file with mode: 0644]
src/cmd/6c/peep.c [new file with mode: 0644]
src/cmd/6c/pgen.c [new file with mode: 0644]
src/cmd/6c/pswt.c [new file with mode: 0644]
src/cmd/6c/reg.c [new file with mode: 0644]
src/cmd/6c/sgen.c [new file with mode: 0644]
src/cmd/6c/swt.c [new file with mode: 0644]
src/cmd/6c/txt.c [new file with mode: 0644]
src/cmd/6g/align.c [new file with mode: 0644]
src/cmd/6g/cgen.c [new file with mode: 0644]
src/cmd/6g/gen.c [new file with mode: 0644]
src/cmd/6g/gg.h [new file with mode: 0644]
src/cmd/6g/gsubr.c [new file with mode: 0644]
src/cmd/6g/list.c [new file with mode: 0644]
src/cmd/6g/obj.c [new file with mode: 0644]
src/cmd/6g/runtime.c [new file with mode: 0644]
src/cmd/6g/runtime.h [new file with mode: 0644]
src/cmd/6l/6.out.h [new file with mode: 0644]
src/cmd/6l/asm.c [new file with mode: 0644]
src/cmd/6l/l.h [new file with mode: 0644]
src/cmd/6l/list.c [new file with mode: 0644]
src/cmd/6l/mkenam [new file with mode: 0644]
src/cmd/6l/obj.c [new file with mode: 0644]
src/cmd/6l/optab.c [new file with mode: 0644]
src/cmd/6l/pass.c [new file with mode: 0644]
src/cmd/6l/span.c [new file with mode: 0644]
src/cmd/cc/acid.c [new file with mode: 0644]
src/cmd/cc/bits.c [new file with mode: 0644]
src/cmd/cc/cc.h [new file with mode: 0644]
src/cmd/cc/cc.y [new file with mode: 0644]
src/cmd/cc/com.c [new file with mode: 0644]
src/cmd/cc/com64.c [new file with mode: 0644]
src/cmd/cc/dcl.c [new file with mode: 0644]
src/cmd/cc/dpchk.c [new file with mode: 0644]
src/cmd/cc/funct.c [new file with mode: 0644]
src/cmd/cc/lex.c [new file with mode: 0644]
src/cmd/cc/lexbody [new file with mode: 0644]
src/cmd/cc/mac.c [new file with mode: 0644]
src/cmd/cc/macbody [new file with mode: 0644]
src/cmd/cc/omachcap.c [new file with mode: 0644]
src/cmd/cc/pgen.c [new file with mode: 0644]
src/cmd/cc/pickle.c [new file with mode: 0644]
src/cmd/cc/pswt.c [new file with mode: 0644]
src/cmd/cc/scon.c [new file with mode: 0644]
src/cmd/cc/sub.c [new file with mode: 0644]
src/cmd/gc/const.c [new file with mode: 0644]
src/cmd/gc/dcl.c [new file with mode: 0644]
src/cmd/gc/export.c [new file with mode: 0644]
src/cmd/gc/go.h [new file with mode: 0644]
src/cmd/gc/go.y [new file with mode: 0644]
src/cmd/gc/lex.c [new file with mode: 0644]
src/cmd/gc/mksys.bash [new file with mode: 0644]
src/cmd/gc/mpatof.c [new file with mode: 0644]
src/cmd/gc/subr.c [new file with mode: 0644]
src/cmd/gc/sys.go [new file with mode: 0644]
src/cmd/gc/sysimport.c [new file with mode: 0644]
src/cmd/gc/walk.c [new file with mode: 0644]

diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
new file mode 100644 (file)
index 0000000..47adbc8
--- /dev/null
@@ -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 (file)
index 0000000..698e73e
--- /dev/null
@@ -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 (file)
index 0000000..ff0a0d5
--- /dev/null
@@ -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 (file)
index 0000000..7463aa6
--- /dev/null
@@ -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 (file)
index 0000000..4b63ddc
--- /dev/null
@@ -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 (file)
index 0000000..dee9966
--- /dev/null
@@ -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 (file)
index 0000000..4aae5a3
--- /dev/null
@@ -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 (file)
index 0000000..d4f6bfa
--- /dev/null
@@ -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 (file)
index 0000000..7fd2012
--- /dev/null
@@ -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 (file)
index 0000000..77c034b
--- /dev/null
@@ -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 (file)
index 0000000..ae0b1b4
--- /dev/null
@@ -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 (file)
index 0000000..f4149f1
--- /dev/null
@@ -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 (file)
index 0000000..a03d1ca
--- /dev/null
@@ -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 (file)
index 0000000..63a86ba
--- /dev/null
@@ -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 (file)
index 0000000..5b2a6ca
--- /dev/null
@@ -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 (file)
index 0000000..eb560f5
--- /dev/null
@@ -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 (file)
index 0000000..6538d3c
--- /dev/null
@@ -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 (file)
index 0000000..7a00688
--- /dev/null
@@ -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 (file)
index 0000000..7000574
--- /dev/null
@@ -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 (file)
index 0000000..5cd31b4
--- /dev/null
@@ -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 (file)
index 0000000..9ced8fe
--- /dev/null
@@ -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 (file)
index 0000000..361eb3c
--- /dev/null
@@ -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 (file)
index 0000000..47ae0ab
--- /dev/null
@@ -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 (file)
index 0000000..482e013
--- /dev/null
@@ -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 (file)
index 0000000..6220a03
--- /dev/null
@@ -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 (file)
index 0000000..8006826
--- /dev/null
@@ -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 (file)
index 0000000..4d1e9d9
--- /dev/null
@@ -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 (file)
index 0000000..137474b
--- /dev/null
@@ -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 (file)
index 0000000..3af0192
--- /dev/null
@@ -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 (file)
index 0000000..fc91828
--- /dev/null
@@ -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 (file)
index 0000000..55dcaac
--- /dev/null
@@ -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 (file)
index 0000000..d997971
--- /dev/null
@@ -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 (file)
index 0000000..5884022
--- /dev/null
@@ -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 (file)
index 0000000..4b225da
--- /dev/null
@@ -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 (file)
index 0000000..62be5e8
--- /dev/null
@@ -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 (file)
index 0000000..31e788c
--- /dev/null
@@ -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 (file)
index 0000000..db1cf94
--- /dev/null
@@ -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 (file)
index 0000000..1abcddd
--- /dev/null
@@ -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 (file)
index 0000000..b0b1620
--- /dev/null
@@ -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 (file)
index 0000000..8d6e07d
--- /dev/null
@@ -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 (file)
index 0000000..f44c340
--- /dev/null
@@ -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 (file)
index 0000000..6a81934
--- /dev/null
@@ -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 (file)
index 0000000..21d8625
--- /dev/null
@@ -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 (file)
index 0000000..e3a8e44
--- /dev/null
@@ -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 (file)
index 0000000..f7ba6d0
--- /dev/null
@@ -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 (file)
index 0000000..c08cd9c
--- /dev/null
@@ -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 (file)
index 0000000..9d309c1
--- /dev/null
@@ -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 (file)
index 0000000..ec5aa86
--- /dev/null
@@ -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 (file)
index 0000000..ae0b1b4
--- /dev/null
@@ -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 (file)
index 0000000..3626e4a
--- /dev/null
@@ -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 (file)
index 0000000..f4149f1
--- /dev/null
@@ -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 (file)
index 0000000..3047ca4
--- /dev/null
@@ -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 (file)
index 0000000..fcf915c
--- /dev/null
@@ -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 (file)
index 0000000..cc8e732
--- /dev/null
@@ -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 (file)
index 0000000..3eae5f3
--- /dev/null
@@ -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 (file)
index 0000000..336ad63
--- /dev/null
@@ -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 (file)
index 0000000..ecd33a8
--- /dev/null
@@ -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 (file)
index 0000000..a3f8e98
--- /dev/null
@@ -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 (file)
index 0000000..b44540c
--- /dev/null
@@ -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 (file)
index 0000000..edd1c9d
--- /dev/null
@@ -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 (file)
index 0000000..07bcf4a
--- /dev/null
@@ -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 (file)
index 0000000..6f1ad12
--- /dev/null
@@ -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 (file)
index 0000000..19b5c2e
--- /dev/null
@@ -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 (file)
index 0000000..f6ff105
--- /dev/null
@@ -0,0 +1,2 @@
+;
+
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
new file mode 100644 (file)
index 0000000..995c641
--- /dev/null
@@ -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;
+}